Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type checks #64

Merged
merged 1 commit into from
May 12, 2020
Merged

Add type checks #64

merged 1 commit into from
May 12, 2020

Conversation

mschmidt87
Copy link
Member

This PR adds type checks to the library and implements changes requested by the static type checker mypy. Eventually, it will also add mypy to the CI.

Note: This is a draft PR and was created now to raise awareness of this. To run mypy, execute:

pip install mypy
cd gp/
mypy *.py

This will currently raise a bunch of errors that need to be addressed before this PR can get merged. Also, the current state of the code introduces a circular import which will make importing the library fail.

@mschmidt87 mschmidt87 requested a review from jakobj April 3, 2020 11:58
@jakobj jakobj added this to the 0.1 milestone Apr 14, 2020
@jakobj jakobj linked an issue Apr 20, 2020 that may be closed by this pull request
Copy link
Member

@jakobj jakobj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a few comments, some of the code seems to be outdated, e.g., the use of prefixes or abstract classes. can you specify where exactly problems occur? for example, what makes the circular import necessary?

gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/genome.py Outdated Show resolved Hide resolved
gp/genome.py Outdated Show resolved Hide resolved
gp/node.py Outdated Show resolved Hide resolved
gp/node.py Outdated Show resolved Hide resolved
gp/node.py Outdated Show resolved Hide resolved
gp/node.py Outdated Show resolved Hide resolved
gp/population.py Outdated Show resolved Hide resolved
@mschmidt87
Copy link
Member Author

Thank you for your comments, I fixed most of them, the most important point and obstacle towards getting mypy passing is the problem with the imports, which is still mysterious to me.

@jakobj
Copy link
Member

jakobj commented Apr 26, 2020

thanks for the update! let's discuss the remaining issues per video.

@mschmidt87 mschmidt87 force-pushed the add_type_checks branch 2 times, most recently from 436ba5c to b1ff4cf Compare April 30, 2020 07:23
@mschmidt87 mschmidt87 marked this pull request as ready for review April 30, 2020 07:41
@mschmidt87
Copy link
Member Author

mschmidt87 commented Apr 30, 2020

After getting a reply in the mypy-issue, I now fixed all the imports to be relative instead of absolute.
Note that with this PR, the library is currently not usable due to some cyclic imports. My plan is to first make mypy pass and then deal with that. We will likely need to introduce some stub type definitions to avoid the cyclic imports.

To run mypy, do the following:

cd gp
cd ..
mypy gp

I am currently getting these errors:

gp/genome.py:127: error: List item 0 has incompatible type "None"; expected "int"
gp/genome.py:128: error: Incompatible return value type (got "List[int]", expected "List[Optional[int]]")
gp/genome.py:128: note: "List" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance
gp/genome.py:128: note: Consider using "Sequence" instead, which is covariant
gp/genome.py:128: note: Perhaps you need a type annotation for "region"? Suggestion: "List[Optional[int]]"
gp/genome.py:150: error: List item 0 has incompatible type "None"; expected "int"
gp/genome.py:170: error: Argument 1 to "__iadd__" of "list" has incompatible type "List[Optional[int]]"; expected "Iterable[int]"
gp/genome.py:431: error: Argument 6 to "Genome" has incompatible type "Primitives"; expected "List[Type[Node]]"
gp/cartesian_graph.py:12: error: Incompatible types in assignment (expression has type "None", variable has type Module)
gp/cartesian_graph.py:109: error: Argument 2 to "__call__" of "Node" has incompatible type "List[int]"; expected "CartesianGraph"
gp/cartesian_graph.py:161: error: Argument 1 to "_hidden_column_idx" of "CartesianGraph" has incompatible type "Optional[int]"; expected "int"
Found 8 errors in 2 files (checked 12 source files)

There are three main problems that need to be resolved:

  • This error: gp/genome.py:431: error: Argument 6 to "Genome" has incompatible type "Primitives"; expected "List[Type[Node]]" is because the clone() function of the Genome class puts its _primitives members as an input variable to its __init__ function to generate the cloned class. However, these types are incompatible since _primitives is an instance of Primitives, but in the __init__ functions, the instance of Primitives is generated from the input variable, thus this is somewhat circular. This should also fail at the moment, as far as I can see.
  • mypy doesn't like the construction about checking the availability of torch and sympy. I think the best way to solve this is to rather use a torch_found boolean variable and check for this than to directly check if torch.
  • mypy complains about the use of lists for indexing regions in the genome. The reason is that we use either integers of None and mypy demands lists to be invariant, i.e., to contain only one type. See this documentation for some explanation: https://mypy.readthedocs.io/en/latest/common_issues.html#invariance-vs-covariance
    Thus, we can either use something else than None for non-used genes (e.g. -1) or we refrain from using lists and replace them by an immutable object like e.g. a tuple.

@mschmidt87 mschmidt87 requested a review from jakobj April 30, 2020 07:55
@mschmidt87
Copy link
Member Author

mschmidt87 commented May 2, 2020

One more point:
The __call__ method of the Node class has this signature:
https://github.com/Happy-Algorithms-League/python-gp/blob/c98cf32ca8b645c35ae6a6b74a370b19efef4456/gp/node.py#L168
However, the x appears to be unused in all child class of Node. Can it be removed?
Also, this __call__ method sets the output_ member of the Node class and seems to be used only in the CartesianGraph.parse_genome() method:
https://github.com/Happy-Algorithms-League/python-gp/blob/c98cf32ca8b645c35ae6a6b74a370b19efef4456/gp/cartesian_graph.py#L108

and in the __call__ method of the CartesianGraph.
The more relevant member for actually computing the function of the graph is _output_str if I'm not mistaken.
@jakobj

@jakobj
Copy link
Member

jakobj commented May 4, 2020

This error: gp/genome.py:431: error: Argument 6 to "Genome" has incompatible type "Primitives"; expected "List[Type[Node]]" is because the clone() function of the Genome class puts its _primitives members as an input variable to its __init__ function to generate the cloned class. However, these types are incompatible since _primitives is an instance of Primitives, but in the __init__ functions, the instance of Primitives is generated from the input variable, thus this is somewhat circular. This should also fail at the moment, as far as I can see.

how about supporting the list() constructor so we can call list(self._primitives) in Genome::clone?

mypy doesn't like the construction about checking the availability of torch and sympy. I think the best way to solve this is to rather use a torch_found boolean variable and check for this than to directly check if torch.

I find it less pretty than the current implementation that does not introduce an additional variable, but if mypy is unhappy otherwise, feel free to change it. i guess a comment would help there.

mypy complains about the use of lists for indexing regions in the genome. The reason is that we use either integers of None and mypy demands lists to be invariant, i.e., to contain only one type. See this documentation for some explanation: https://mypy.readthedocs.io/en/latest/common_issues.html#invariance-vs-covariance
Thus, we can either use something else than None for non-used genes (e.g. -1) or we refrain from using lists and replace them by an immutable object like e.g. a tuple.

we can use -3 for unused genes in the InpuNode/OutputNode sections. we've already introduced -1 and -2 as special values so why not an additional one ;)

@jakobj
Copy link
Member

jakobj commented May 4, 2020

One more point:
The __call__ method of the Node class has this signature:
[...snip...]

unfortunately i don't remember why we need the x there. input values seem to be retrieved by accessing input nodes via the graph instance. in the beginning we provided the option of calling the graph directly without calling any to...method. i am now wondering how input values are passed into the graph if x is never used? we can either add tests to make sure this functionality works as expected, or we force the user to always call one of the to... functions. i am inclined to follow the latter path, just because it reduces complexity without any significant drawback (that i'm currently aware of).

note that __call__ is not used in https://github.com/Happy-Algorithms-League/python-gp/blob/c98cf32ca8b645c35ae6a6b74a370b19efef4456/gp/cartesian_graph.py#L108 as primitives does not store instances, but classes, so this calls the constructor, not the __call__ function!

@mschmidt87 mschmidt87 force-pushed the add_type_checks branch 4 times, most recently from 140da25 to 100e445 Compare May 7, 2020 12:52
Copy link
Member

@jakobj jakobj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, thanks for the hard work! 🎉 🎉 i've reviewed until genome.py, will continue there later, here are already a few comments.

gp/cartesian_graph.py Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
Copy link
Member

@jakobj jakobj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getting better every time! ✨ added a few comments that should be addressed before merging.

gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Show resolved Hide resolved
gp/genome.py Show resolved Hide resolved
gp/node.py Outdated Show resolved Hide resolved
gp/primitives.py Show resolved Hide resolved
gp/primitives.py Show resolved Hide resolved
test/test_cartesian_graph.py Show resolved Hide resolved
test/test_genome.py Outdated Show resolved Hide resolved
@coveralls
Copy link
Collaborator

coveralls commented May 11, 2020

Coverage Status

Coverage increased (+0.02%) to 97.315% when pulling f07f926 on add_type_checks into a149430 on master.

@mschmidt87
Copy link
Member Author

I addressed all your comments, @jakobj . Please take another look.

Copy link
Member

@jakobj jakobj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appreciate the hard work 🙇 only some superficial comments left

gp/cartesian_graph.py Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/cartesian_graph.py Outdated Show resolved Hide resolved
gp/population.py Outdated Show resolved Hide resolved
gp/primitives.py Outdated Show resolved Hide resolved
gp/primitives.py Show resolved Hide resolved
gp/genome.py Show resolved Hide resolved
…by annotation process

Remove initialization of class attributes
Implement List constructor for primitives and adapt clone function of Genome
Add sympy_available and torch_available variables
Introduce global constants for special genes
Clarify if/else branch in parameter_update function of CartesianGraph

Add mypy to travis CI
Add mypy badge to README
Add mypy config file
Add mypy to extra-requirements file
Copy link
Member

@jakobj jakobj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome work! 🎉 ✨ 🎉 so 👍 conditional on travis passing

@mschmidt87 mschmidt87 merged commit 9835bd8 into master May 12, 2020
@mschmidt87 mschmidt87 deleted the add_type_checks branch May 12, 2020 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add type hints and static type checking in CI
3 participants