-
Notifications
You must be signed in to change notification settings - Fork 36
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 typing to signac.core.json. #313
Conversation
Adding mypy checking is probably a good idea. For example, it caught this bug: signac/signac/contrib/filterparse.py Line 59 in 232d018
Note that the parentheses are in the wrong places. |
@bdice Cool! Did you have a specific reason to start with that module? |
@csadorf No specific reason to start there. @glotzerlab/signac-committers Can I get a couple opinions on this? Should we apply types? I think it is a good idea, and it is an automated safety check that we can use to ensure code quality going forward. It's a little bit like unit tests in that it can't/won't catch every potential problem but definitely reduces the "surface area" for potential problems. |
I am all in favor of slowly introducing typing to the code base. Is this already checked as part of the CI on this branch? |
We discussed adding types as part of glotzerlab/signac-flow#193. In that PR, I laid out what i think are the necessary preconditions for documenting parameter types. On that issue I pointed out that applying type hints could proceed independently of docs, and the basic CI setup for doc linting is already in place in this repo, so adding CI for types would be reasonable and not lead to any conflicting dev IMO. |
Codecov Report
@@ Coverage Diff @@
## master #313 +/- ##
==========================================
- Coverage 76.18% 76.18% -0.01%
==========================================
Files 43 43
Lines 7076 7075 -1
==========================================
- Hits 5391 5390 -1
Misses 1685 1685
Continue to review full report at Codecov.
|
I love this!!!! I'm not sure what any downside would be. It can help us catch bugs + make our code easier to maintain. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have annotated my PR with explanations for the benefit of the reader, since none of these changes are especially obvious without experience with type annotations / mypy
.
@@ -22,9 +22,5 @@ class ExportError(Error, RuntimeError): | |||
pass | |||
|
|||
|
|||
class FileNotFoundError(Error, FileNotFoundError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seemed like an unused compatibility layer for Python 2 (which did not have FileNotFoundError
). I removed it.
cls = H5Store # type: ignore | ||
suffix = '.h5' # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explanation for the ignore: These are overriding a default of None
in the DictManager
parent class, meaning that the type is changing. That raises an error.
@@ -11,14 +11,14 @@ | |||
|
|||
logger = logging.getLogger('sync') | |||
logging.addLevelName(LEVEL_MORE, 'MORE') | |||
logging.MORE = LEVEL_MORE | |||
logging.MORE = LEVEL_MORE # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explanation for the ignore: Assigning logging.MORE
(and logger.more
below) is setting a property that doesn't exist in the original module / class. This kind of monkey-patch raises an error:
signac/syncutil.py:14: error: Module has no attribute "MORE"
signac/syncutil.py:21: error: "Logger" has no attribute "more"
signac/syncutil.py
Outdated
# The following line must be ignored: https://github.com/python/mypy/issues/708 | ||
methodmap['same_files'] = methodmap['diff_files'] = phase3 # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explanation: This ignore is due to a long-standing issue in mypy. This is the "third case" described by Guido van Rossum in that issue.
signac/syncutil.py:57: error: Incompatible types in assignment (expression has type "Callable[[dircmp_deep], Any]", target has type "Callable[[], None]")
@@ -159,7 +159,7 @@ class RegexFileCrawler(BaseCrawler): | |||
MyCrawler.define('.*\/a_(?P<a>\d+)\.txt', 'TextFile') | |||
""" | |||
"Mapping of compiled regex objects and associated formats." | |||
definitions = dict() | |||
definitions = dict() # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explanation: This requests a type annotation for the dict
. I added ignores to all deprecated modules where necessary, without questioning it.
@@ -56,7 +56,7 @@ def _cast(x): | |||
"Attempt to interpret x with the correct type." | |||
try: | |||
if x in CAST_MAPPING_WARNING: | |||
print("Did you mean {}?".format(CAST_MAPPING_WARNING[x], file=sys.stderr)) | |||
print("Did you mean {}?".format(CAST_MAPPING_WARNING[x]), file=sys.stderr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mypy
caught a bug in the print statement! Fixed here.
@@ -17,7 +17,7 @@ | |||
|
|||
|
|||
SESSION_PASSWORD_HASH_CACHE = SimpleKeyring() | |||
SESSION_USERNAME_CACHE = dict() | |||
SESSION_USERNAME_CACHE = dict() # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explanation: This requests a type annotation for the dict
. I added ignores to all deprecated modules where necessary, without questioning it.
@@ -18,6 +18,9 @@ exclude = configobj,passlib,cite.py,conf.py | |||
match = jsondict.py | |||
ignore = D105, D107, D203, D213 | |||
|
|||
[mypy] | |||
ignore_missing_imports = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ignore_missing_imports
is enabled so that mypy
doesn't get mad about missing type annotations in dependencies like deprecation
or numpy
.
@csadorf Now it is in CI. This PR is ready for review. After this is approved/merged, I will add type annotations for other files. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two suggestions, otherwise LGTM!
Thank you very much @bdice !
.circleci/config.yml
Outdated
@@ -31,6 +31,11 @@ jobs: | |||
command: | | |||
pydocstyle | |||
|
|||
- run: | |||
name: style-check-type-hints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really a style check?
name: style-check-type-hints | |
name: check-type-hints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree -- I was just matching the existing pattern. I renamed the CI job to "pre-checks" so it's all-encompassing, and renamed the individual checks according to their purpose.
Co-Authored-By: Carl Simon Adorf <[email protected]>
Looks good, except should we leave the corrections in a168649 to another branch/PR since it is unrelated to typing, or is it not worth it? |
My mistake. |
I decided it wasn't worth putting in its own PR. That's a choice that could be debated but I think it's fine to merge in as-is in the interest of expediency. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided it wasn't worth putting in its own PR. That's a choice that could be debated but I think it's fine to merge in as-is in the interest of expediency.
Sounds good!
Description
This is an experimental PR adding types to
signac.core.json
. This was created using MonkeyType and modified slightly. Adding type validation seems like a simple process.To generate this, I installed
monkeytype
and then ran the following commands from the repository root:We'd need to validate the results with mypy, I think.
Motivation and Context
Just wanted to try it out.
Types of Changes
1The change breaks (or has the potential to break) existing functionality.
Checklist:
If necessary: