Yesterday I said I would be spending all of today on getting the entries page done. I did work on the date parser part of the entries view function, but I didn’t fully implement the views function yet.
The idea is you can pass different types of dates in the URL and see/edit the entries for that date. For example: /entry/2017/04/15/ would show the entries for 15th of April, 2017. You can also goto /entry/today/ and /entry/yesterday/ as shortcuts for the corresponding days.
For tomorrow’s v0.1 milestone, I think I will implement just these types of dates. But for the next milestone (next week) I want to display all the entries for a month (/entry/2017/04/) and for an year (/entry/2017/). This makes it easy to generate reports for entire month or year.
While the date parser was easy to implement, I spent the most of my time writing unit test cases.
And Remember Kids..
Writing code: 1hrs
Fixing bugs: 3hrs
Writing code: 1hrs
Writing tests: 1hrs
Fixing bugs: 10mins
— Mahdi Yusuf (@myusuf3) January 9, 2016
Even though I spent most of today writing test cases, it would help a lot when I refactor the code base. Test cases is something that I haven’t given much attention to in my projects at work. But I do know that there is a much higher probability of catching and fixing bugs if you have proper test cases.
One example of such a bug was in the date parser function I just wrote. I was doing a check to see if the date was a future date as I don’t want to edit the future entries before the day. The code was pretty simple.
if date_obj - today > 0: raise FutureDateException("Trying to edit the future.")
The bug is that
date_obj - today returns a timedelta object and you can’t really compare it with int. I wouldn’t have caught this bug till I finished the views function and manually entered different types of dates. But since I wrote a test case to cover this line I found out the bug and handled it properly.
Testing Web Apps
Usually testing web apps are not that easy and that is one major reason I hate writing test cases. But flask has few helpful ways to make it easy. But I wanted to test whether a URL redirects properly. For that I ended up using the Flask-Testing extension. If you are writing flask apps, I would suggest using Flask-Testing.
Since I use Gitlab for hosting my code, I ended up setting up a Pipeline to run tests automatically whenever I push any code. I use Gitlab-CI for it. It is a bit different compared to the Github+Travis combo I used to use earlier. But the advantage of Gitlab-CI is you can specify what docker image to use to run your builds/tests. And I always felt that even with my sparing builds, travis was overloaded and had lot of downtime. Gitlab-CI seems to be quite fast in spinning up jobs as soon as a git push is done.
Moving to PostgreSQL
I was using SQLite for my development and tests, but I knew I had to move to PostgreSQL soon as I will be deploying on it. I didn’t want any surprises when I made the switch. Using an ORM does abstract out most of the pieces, but I did get couple of surprises.
- bcrypt’s hash function returns a byte object and SQLite doesn’t have any problem in storing a byte in a text column. In fact SQLite wouldn’t even complain about most data types. But Postgres kept saying that I was trying to store more than varchar(120) even though the hash value was just 60 characters long. Then I remembered that for python 3, I had to do a .decode(‘utf-8’) to convert it into a str type. Weird error message, but quite easy to google and figure out.
- Postgresql has it’s own Enum datatype and whenever you create a enum type, you have to give a name for it. In SQLite there is no Enum data type and there was no error even if you didn’t give a name. But when I moved to postgres, I had to pass a name param to the Enum.
All I had to do was
db.Enum('done', 'todo', 'blocking', name='entry_types')
Other than these two gotchas, there were no other issues in the database change.
Btw, I didn’t want to install postgresql on my Mac OS and ended up running a docker container for the DB. The commands to run the DB server was:
docker run --name nillu-pg -e POSTGRES_PASSWORD=foobar -p5432:5432 -d postgres
and the command to run the psql prompt was
docker run -it --rm --link nillu-pg:postgres postgres psql -h postgres -U postgres
For tomorrow, I definitely need to display the entry page and the edit screen for “today”. And I also need to send an email to the users. Those are the three things that are definitely needed for the app to be usable on Monday.