eth-utils icon indicating copy to clipboard operation
eth-utils copied to clipboard

Improve combomethod type hints

Open darwintree opened this issue 1 year ago • 7 comments

What was wrong?

Related to Issue #236 Closes #236

How was it fixed?

This commit adopts the solution from here. It uses ParamSpec and Concatenate added in python3.10. And in order to use this feature minor to 3.10, typing-extensions dependency is added in setup.py

Todo:

  • [x] Clean up commit history

  • [ ] Add or update documentation related to these changes

  • [x] Add entry to the release notes

Cute Animal Picture

image

darwintree avatar Jan 16 '24 02:01 darwintree

@kclowes hi, would know if this change could get merged or if anything more needs to do?

darwintree avatar Feb 25 '25 03:02 darwintree

Thanks for this, @darwintree. We'd need to hold this for our next breaking release cycle since it's used by other of our libs.

When I import your update into eth-account and run mypy, it throws a number of new Untyped decorator makes function "my_function" untyped errors. Can you tell why it's considering them untyped now and how we would clear the errors?

pacrob avatar Mar 01 '25 21:03 pacrob

Thanks for this, @darwintree. We'd need to hold this for our next breaking release cycle since it's used by other of our libs.

When I import your update into eth-account and run mypy, it throws a number of new Untyped decorator makes function "my_function" untyped errors. Can you tell why it's considering them untyped now and how we would clear the errors?

Hi, thank you for reply. I would inspect this might be a mypy version issue and would first check if current mypy version supports the used feature. It can currently work well in default pylance and bring expected hint, but sorry for I did not check mypy compatibility yet.

I would later check simple cases in mypy and tell you if there is any progress

darwintree avatar Mar 02 '25 00:03 darwintree

There is another possibility that eth_account is actually not a well type -hinted lib. Some type error is masked by legacy combomethod and now they are revealed

darwintree avatar Mar 02 '25 01:03 darwintree

@pacrob Hi, I just confirmed that after mypy 1.0.0, the Concatenate is available in mypy so this is not an issue. I also did what you stated but did not reproduce the error (other errors appeared but seemed easy to resolve). Would you tell how to reproduce it? Here is my steps:

  • create local env py3.12 using codna and activate
  • install eth-account
  • install local eth-utils
  • run make lint
image

dependency versions:

Package                       Version     Editable project location
----------------------------- ----------- ---------------------------------------
alabaster                     1.0.0
annotated-types               0.7.0
anyio                         4.8.0
asttokens                     3.0.0
attrs                         25.1.0
babel                         2.17.0
bitarray                      3.1.0
bracex                        2.5.post1
build                         1.2.2.post1
bump-my-version               1.0.0
cachetools                    5.5.2
certifi                       2025.1.31
cfgv                          3.4.0
chardet                       5.2.0
charset-normalizer            3.4.1
ckzg                          2.0.1
click                         8.1.8
colorama                      0.4.6
coverage                      7.6.12
cytoolz                       1.0.1
decorator                     5.2.1
distlib                       0.3.9
docutils                      0.21.2
eth_abi                       5.2.0
eth-account                   0.13.5
eth-hash                      0.7.1
eth-keyfile                   0.8.1
eth-keys                      0.6.1
eth-rlp                       2.2.0
eth-typing                    5.2.0
eth-utils                     5.2.0       /Users/a/Documents/code/eth-utils
execnet                       2.1.1
executing                     2.2.0
filelock                      3.17.0
h11                           0.14.0
hexbytes                      1.3.0
httpcore                      1.0.7
httpx                         0.28.1
hypothesis                    6.108.6
id                            1.5.0
identify                      2.6.8
idna                          3.10
imagesize                     1.4.1
iniconfig                     2.0.0
ipython                       9.0.0
ipython_pygments_lexers       1.1.1
jaraco.classes                3.4.0
jaraco.context                6.0.1
jaraco.functools              4.1.0
jedi                          0.19.2
Jinja2                        3.1.5
keyring                       25.6.0
markdown-it-py                3.0.0
MarkupSafe                    3.0.2
matplotlib-inline             0.1.7
mdurl                         0.1.2
more-itertools                10.6.0
mypy                          1.10.0
mypy-extensions               1.0.0
nh3                           0.2.21
nodeenv                       1.9.1
packaging                     24.2
parsimonious                  0.10.0
parso                         0.8.4
pexpect                       4.9.0
pip                           25.0
platformdirs                  4.3.6
pluggy                        1.5.0
pre_commit                    4.1.0
prompt_toolkit                3.0.50
ptyprocess                    0.7.0
pure_eval                     0.2.3
pycryptodome                  3.21.0
pydantic                      2.10.6
pydantic_core                 2.27.2
pydantic-settings             2.8.1
Pygments                      2.19.1
pyproject-api                 1.9.0
pyproject_hooks               1.2.0
pytest                        8.3.5
pytest-xdist                  3.6.1
python-dotenv                 1.0.1
PyYAML                        6.0.2
questionary                   2.1.0
readme_renderer               44.0
regex                         2024.11.6
requests                      2.32.3
requests-toolbelt             1.0.0
rfc3986                       2.0.0
rich                          13.9.4
rich-click                    1.8.6
rlp                           4.1.0
roman-numerals-py             3.1.0
setuptools                    75.8.0
sniffio                       1.3.1
snowballstemmer               2.2.0
sortedcontainers              2.4.0
Sphinx                        8.2.3
sphinx-autobuild              2024.10.3
sphinx-rtd-theme              3.0.2
sphinxcontrib-applehelp       2.0.0
sphinxcontrib-devhelp         2.0.0
sphinxcontrib-htmlhelp        2.1.0
sphinxcontrib-jquery          4.1
sphinxcontrib-jsmath          1.0.1
sphinxcontrib-qthelp          2.0.0
sphinxcontrib-serializinghtml 2.0.0
stack-data                    0.6.3
starlette                     0.46.0
tomlkit                       0.13.2
toolz                         1.0.0
towncrier                     24.8.0
tox                           4.24.1
traitlets                     5.14.3
twine                         6.1.0
typing_extensions             4.12.2
urllib3                       2.3.0
uvicorn                       0.34.0
virtualenv                    20.29.2
watchfiles                    1.0.4
wcmatch                       10.0
wcwidth                       0.2.13
websockets                    15.0
wheel                         0.45.1

darwintree avatar Mar 03 '25 02:03 darwintree

I also tried mypy in web3.py, here are the error list:

image

darwintree avatar Mar 03 '25 02:03 darwintree

Hey, guys! Any updates on that one? @combomethod decorator causes any IDE to ignore type hints of functions that use it (such as any web3.Web3 methods).

Would you consider one-liner solution if I was to propose it instead of this solution?

if TYPE_CHECKING:
    combomethod = Callable[[T], T]
else:
    class combomethod:
        def __init__(self, method: Callable[..., Any]) -> None:
            self.method = method

        def __get__(
            self, obj: Optional[T] = None, objtype: Optional[Type[T]] = None
        ) -> Callable[..., Any]:
            @functools.wraps(self.method)
            def _wrapper(*args: Any, **kwargs: Any) -> Any:
                if obj is not None:
                    return self.method(obj, *args, **kwargs)
                else:
                    return self.method(objtype, *args, **kwargs)

            return _wrapper

rudolf-del avatar Jul 11 '25 09:07 rudolf-del