-
Notifications
You must be signed in to change notification settings - Fork 25
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
[WIP] Added test of type checking and autoargs #71
base: master
Are you sure you want to change the base?
Changes from 3 commits
55ebbd7
eadeb86
e39922a
ab6cf4f
8377375
b4b9423
e12ccaf
e27b76a
0b8fa0d
9fff650
8c33818
28795a4
da7a09b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,10 @@ | |
""" | ||
import inspect | ||
import warnings | ||
import typing | ||
from collections.abc import Sequence | ||
import re | ||
|
||
|
||
codename = None | ||
|
||
|
@@ -26,8 +30,37 @@ def register_constants(implementation_constants): | |
def _get_constants(): | ||
return _implementation_constants | ||
|
||
|
||
VectorFloat3 = typing.NewType('VectorFloat3', Sequence[float]) | ||
VectorInt3 = typing.NewType('VectorInt3', Sequence[int]) | ||
Expression = typing.NewType('Expression', str) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you fell about moving this into a separate namespace (for python a module i.e. here a file)? This way every type will get a prefix and the distinction between python native & PICMI custom (and perhaps other types) will become clear. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I was considering that, so that all of the type declarations are in the same place. It is somewhat tricky though because of the circular imports that will happen since some of the types depend on PICMI classes which will depend on the types. I'll see what I can put together. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. had that problem too, PEP 484 allows using strings instead of literals for forward declarations But ultimately your call. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, thanks, using strings worked. I am clearly not the first person to come across this circular definition problem :) |
||
|
||
|
||
class _ClassWithInit(object): | ||
def _check_vector_lengths(self): | ||
for arg_name, arg_type in self.__init__.__annotations__.items(): | ||
if arg_type in [VectorFloat3, VectorInt3]: | ||
arg_value = getattr(self, arg_name) | ||
assert len(arg_value) == 3, Exception(f'{arg_name} must have a length of 3') | ||
|
||
def _process_expression_arguments(self, kw): | ||
"""For arguments that are of type Expression, save any keyword arguments used in | ||
the expression in the user_defined_kw dictionary. | ||
""" | ||
for arg_name, arg_type in self.__init__.__annotations__.items(): | ||
if arg_type == Expression: | ||
# Create the dictionary is needed | ||
self.user_defined_kw = getattr(self, 'user_defined_kw', {}) | ||
arg_value = getattr(self, arg_name) | ||
if arg_value is not None: | ||
for k in list(kw.keys()): | ||
if re.search(r'\b%s\b'%k, arg_value): | ||
self.user_defined_kw[k] = kw.pop(k) | ||
|
||
def handle_init(self, kw): | ||
self._check_vector_lengths() | ||
self._process_expression_arguments(kw) | ||
|
||
# --- Grab all keywords for the current code. | ||
# --- Arguments for other supported codes are ignored. | ||
# --- If there is anything left over, it is an error. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
numpy~=1.15 | ||
scipy~=1.5 | ||
autoclass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checked: pure python (incl. dependencies) & easy to install it seems |
||
typeguard | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checked: pure python (incl. dependencies) & easy to install it seems |
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 assigning a list as default argument value (old and new) actually possible?
Common Python bug:
https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
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.
Yes, this code works as is, and I am aware of the issue. In this case, however, it is not expected that the argument,
lower_bound
, will be modified, but only read. An alternative here would be to havelower_bound
default toNone
. This would be more consistent with other vectors that default toNone
. In this PR, I wanted to avoid changing the interface, but the change can be made.