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 hints and apply mypy fix for function attributes where needed #350

Closed
wants to merge 6 commits into from
Closed

Conversation

LegrandNico
Copy link
Contributor

This PR adds various type hints to increase type coverage. It also fixes the mypy errors raised by the use of function attributes, using the workaround described here.

It will contribute to #200.

Several of the remaining errors returned by mypy are related to inconsistent type inherited from core classes (e.g Variable) and I think this is the next thing to be fixed if we want to solve the rest. I saw what is proposed in #134, but I think I will need a bit more guidance for the next step.

@LegrandNico
Copy link
Contributor Author

This will require adding the typing_extensions at least to the CI dependencies, but I don't know where this should be declared exactly.

@brandonwillard
Copy link
Member

This will require adding the typing_extensions at least to the CI dependencies, but I don't know where this should be declared exactly.

You can add it to install_requires in setup.py.

@codecov
Copy link

codecov bot commented Apr 5, 2021

Codecov Report

Merging #350 (342c960) into master (1366221) will increase coverage by 0.06%.
The diff coverage is 99.63%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #350      +/-   ##
==========================================
+ Coverage   72.47%   72.53%   +0.06%     
==========================================
  Files         173      173              
  Lines       55631    55775     +144     
==========================================
+ Hits        40316    40459     +143     
- Misses      15315    15316       +1     
Impacted Files Coverage Δ
aesara/link/c/lazylinker_c.py 76.92% <ø> (ø)
aesara/graph/callcache.py 27.27% <83.33%> (+2.27%) ⬆️
aesara/_version.py 44.20% <100.00%> (ø)
aesara/compile/compilelock.py 97.14% <100.00%> (-2.86%) ⬇️
aesara/compile/function/types.py 84.91% <100.00%> (+0.10%) ⬆️
aesara/compile/io.py 94.44% <100.00%> (+0.10%) ⬆️
aesara/compile/sharedvalue.py 82.05% <100.00%> (+1.76%) ⬆️
aesara/configparser.py 90.03% <100.00%> (-0.04%) ⬇️
aesara/gpuarray/cudnn_defs.py 37.95% <100.00%> (+0.45%) ⬆️
aesara/gpuarray/dnn.py 24.84% <100.00%> (+1.05%) ⬆️
... and 21 more

@LegrandNico
Copy link
Contributor Author

The code coverage is slightly reduced, and the tests are therefore not completed, but this is due to the lines added after the if TYPE_CHECKING condition, which are not executed by the tests but by mypy directly.

@brandonwillard
Copy link
Member

The code coverage is slightly reduced, and the tests are therefore not completed, but this is due to the lines added after the if TYPE_CHECKING condition, which are not executed by the tests but by mypy directly.

Perhaps we can add something like the following to our .coveragerc:

[report]
exclude_lines = 
    if TYPE_CHECKING:

@michaelosthege
Copy link
Contributor

@LegrandNico can you rebase the branch to resolve conflicts?
If there is an easy fix to exclude those TYPE_CHECKING blocks from coverage calculation let's do it, but before anyone invests more than a few minutes there, we should just not worry about it. After all we know where the decrease comes from.

eigenfoo
eigenfoo previously approved these changes May 1, 2021
Copy link
Contributor

@eigenfoo eigenfoo left a comment

Choose a reason for hiding this comment

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

Great work! I'm not too familiar with the Protocol decorator workaround, but otherwise this PR looks good to me - I have some minor nitpicky comments, but since all tests pass I think this PR is good to go.


def persist(self, filename=None):
def persist(self, filename: Optional[str] = None) -> NoReturn:
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be -> None?

The NoReturn return type is for functions that never return normally, not functions that just don't return a value [1] [2].

[1] https://mypy.readthedocs.io/en/stable/more_types.html#the-noreturn-type
[2] https://www.python.org/dev/peps/pep-0484/#the-noreturn-type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have changed this to -> None.

@@ -46,7 +47,7 @@ def call(self, fn, args=(), key=None):
_logger.debug("cache hit %i", len(self.cache))
return self.cache[key]

def __del__(self):
def __del__(self) -> NoReturn:
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly here with NoReturn.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Idem

@@ -305,6 +313,8 @@ def get_scalar_constant_value(

Parameters
----------
orig_v :
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing docstring? We should at least add the type here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have added this:

"""
    orig_v : int, float, np.ndarray, Constant or None
        The variable `v` where to find the constant scalar(0-D).
"""

aesara/compile/function/__init__.py Show resolved Hide resolved
_is_nonzero = True
_is_nonzero: bool = True
real: Optional[property] = None
imag: Optional[property] = None
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what this is - this looks like new code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I remember correctly, I had to add imag and real so https://github.com/pymc-devs/aesara/blob/25162ed0f8949aa2509e0b1a04ddfe71b03c9fdb/aesara/tensor/math.py#L1410 does not return an error.

aesara/tensor/var.py Show resolved Hide resolved
Copy link
Contributor

@michaelosthege michaelosthege left a comment

Choose a reason for hiding this comment

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

This PR brings significant improvements of signatures in many places. I rebased it so we can get this going again 🚀

In one file I found type hints that I think are too restrictive.

@@ -45,15 +45,15 @@ def force_unlock(lock_dir: os.PathLike):


@contextmanager
def lock_ctx(lock_dir: os.PathLike = None, *, timeout: Optional[float] = None):
def lock_ctx(lock_dir: Optional[os.PathLike] = None, *, timeout: Optional[float] = -1):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
def lock_ctx(lock_dir: Optional[os.PathLike] = None, *, timeout: Optional[float] = -1):
def lock_ctx(lock_dir: Optional[os.PathLike] = None, *, timeout: Optional[float] = None):

It was intentionally None, because this way it defaults to the config setting.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

on_unused_input=None,
inputs: "List[Variable]",
outputs: "Optional[List[Variable]]" = None,
mode: Union[str] = None,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
mode: Union[str] = None,
mode: Union[str, "Mode"] = None,

And further above in the TYPE_CHECKING block from aesara.compile.mode import Mode

Copy link
Contributor

@ricardoV94 ricardoV94 May 27, 2021

Choose a reason for hiding this comment

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

Shouldn't the type-hint include Optional?

@@ -1079,7 +1098,7 @@ def grad(self, inp, grads):
_nonzero = Nonzero()


def nonzero(a, return_matrix=False):
def nonzero(a: np.array, return_matrix: bool = False) -> Tuple:
Copy link
Contributor

Choose a reason for hiding this comment

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

All these functions can take not only numpy arrays, but also TensorVariables or in some cases lists.
The type hint from line 1042 is probably a good candidate for most functions in this file.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

@LegrandNico LegrandNico deleted the master branch June 14, 2021 21:55
@LegrandNico
Copy link
Contributor Author

I accidentally closed this one by renaming the branch master to main, is there a way to reopen it?

@brandonwillard
Copy link
Member

I accidentally closed this one by renaming the branch master to main, is there a way to reopen it?

Looks like this branch itself was deleted because it was your master branch, so it can't be reopened. You can always create a new PR, but, in the future, be sure to create new branches for all of your work.

@brandonwillard brandonwillard added the typing Work related to type checking label Apr 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
typing Work related to type checking
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants