Watson time tracker code review


First contact

Get the latest code like this (or you can fork it previously if you plan to contribute):

git clone https://github.com/TailorDev/Watson.git

I had installed the Debian 10 packages (python3-watson and watson packages), but I wanted to review and use the latest version, preferably in a virtualenv or in my user account. That's why I cloned the original repository.

Looking at the Debian packages I can see by their names that Watson is running with Python3, so it must have support for it. Does it also support python2?

Let's take a look at tox.ini which is used for running tests in multiple python environments:

envlist = flake8,py27,py34,py35,py36,py37

We can see that Watson effectively supports python 2.7 which is pretty typical these days.



Being packaged in Debian, this means we can just look up for its runtime dependencies in a Debian system:

$ apt-cache depends watson python3-watson | awk '/Depends: [^<]/ {print $2}' | xargs dpkg -l | grep ii
ii  python3-arrow    0.12.1-2     all   Python3 library to manipulate dates, times, and timestamps
ii  python3-click    7.0-1        all   Wrapper around optparse for command line utilities - Python 3.x
ii  python3-requests 2.21.0-1     all   elegant and simple HTTP library for Python3, built for human beings
ii  python3-watson   1.6.0-6      all   Library for Watson (Python 3)


Besides this high-level info, there are two requirements files in the root folder, but why? Let's grep around and see if we can get more info:

# some results are not shown as seemed irrelevant to me
$ grep -r requirements
README.rst:   :target: https://requires.io/github/TailorDev/Watson/requirements/?branch=master
Makefile:   $(PIP) install -r requirements-dev.txt
MANIFEST.in:include requirements-dev.txt
MANIFEST.in:include requirements.txt
setup.py:    install_requires=parse_requirements('requirements.txt'),
setup.py:    tests_require=parse_requirements('requirements-dev.txt'),
docs/contributing/hack.md:        $ pip install -r requirements-dev.txt

In the first result we realize that all dependencies can be found in requires.io, which also includes references and latest version information.

As for the requirements-dev.txt, we can see tools for running the tests, generating the documentation, and more:

Folder organization

The file structure is pretty simple:

Code organization

$ cloc --by-file watson
File                              blank        comment           code
watson/cli.py                       237            445            848
watson/watson.py                    110             50            395
watson/fullmoon.py                    7              6            220
watson/utils.py                      53             63            168
watson/frames.py                     38              0            117
watson/config.py                     33             47             32
watson/__main__.py                    1              0              5
watson/__init__.py                    1              0              3
watson/version.py                     1              1              1
SUM:                                481            612           1789

$ cloc --by-file tests
File                                  blank        comment           code
tests/test_watson.py                    251             44            570
tests/test_utils.py                      56              4            170
tests/test_config.py                     24             47             82
tests/__init__.py                        15              1             28
tests/test_fullmoon.py                    6              1             19
tests/conftest.py                         6              1              8
SUM:                                    358             98            877


You can run all tests in all available Python environments in your system like this:

$ tox

Watson uses pytest along with unittest.mock to do unit testing.

Let's understand some testing constructs used in Watson:

# In tests/__init__.py
# path.object(target, attribute, new) with new being the new object to replace the target
return mock.patch.object(dt_module, 'datetime', MockedDateTime)
    $ pytest --fixtures
    --------------------------------------- fixtures defined from pytest_datafiles ----------------------------------------
        pytest fixture to define a 'tmpdir' containing files or directories
        specified with a 'datafiles' mark.

    ------------------------------------------ fixtures defined from pytest_mock ------------------------------------------
        return an object that has the same interface to the `mock` module, but
        takes care of automatically undoing all patches after each test method.
        Same as "mocker", but kept only for backward compatibility.

    ---------------------------------------- fixtures defined from tests.conftest -----------------------------------------
        tests/conftest.py:14: no docstring available
        tests/conftest.py:9: no docstring available

    --------------------------------------- fixtures defined from tests.test_watson ---------------------------------------
        tests/test_watson.py:31: no docstring available