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 #576

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# https://peps.python.org/pep-0517/
[build-system]
requires = ["setuptools>=64", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"

# https://peps.python.org/pep-0621/
[project]
name = "toolz"
description = "List processing tools and functional utilities"
readme = "README.rst"
requires-python = ">=3.8"
license = { text = "BSD 3-Clause License" }
maintainers = [{ name = "Erik Welch", email = "erik.n.welch@gmail.com" }]
authors = [
{ name = "Matthew Rocklin"},
{ name = "John Jacobsen"},
{ name = "Erik Welch"},
{ name = "John Crichton"},
{ name = "Han Semaj"},
{ name = "Graeme Coupar"},
{ name = "Leonid Shvechikov"},
{ name = "Lars Buitinck"},
{ name = "José Ricardo"},
{ name = "Tom Prince"},
{ name = "Bart van Merriënboer"},
{ name = "Nikolaos-Digenis Karagiannis"},
{ name = "Antonio Lima"},
{ name = "Joe Jevnik"},
{ name = "Rory Kirchner"},
{ name = "Steven Cutting"},
{ name = "Aric Coady"},
]
keywords = ["functional", "utility", "itertools", "functools"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Typing :: Typed",
]
dynamic = ["version"]
dependencies = ["typing_extensions"]

# extras
# https://peps.python.org/pep-0621/#dependencies-optional-dependencies
[project.optional-dependencies]
docs = [
"sphinx-build",
]
test = [
"pytest>=6.0",
"pytest-cov",
]

[project.urls]
homepage = "https://github.com/pytoolz/toolz/"
repository = "https://github.com/pytoolz/toolz/"
documentation = "https://toolz.readthedocs.io/"


[tool.setuptools]
packages = [
"toolz",
"toolz.sandbox",
"toolz.curried",
"tlz",
]
include-package-data = true

[tool.setuptools.package-data]
toolz = [
"py.typed",
"tests",
]


# https://docs.astral.sh/ruff/
[tool.ruff]
line-length = 80
src = ["toolz", "tlz"]
extend-exclude = [
"examples",
"doc",
"bench",
]

[tool.ruff.lint]
pydocstyle = { convention = "numpy" }
select = [
"E", # style errors
"F", # flakes
"W", # warnings
"D417", # Missing argument descriptions in Docstrings
"I", # isort
"UP", # pyupgrade
"S", # bandit
"C4", # flake8-comprehensions
"B", # flake8-bugbear
"A001", # flake8-builtins
"ARG", # flake8-unused-arguments
"RET", # flake8-return
"SIM", # flake8-simplify
"TCH", # flake8-typecheck
"TID", # flake8-tidy-imports
"RUF", # ruff-specific rules
]
exclude = [
"toolz/__init__.py",
"toolz/compatibility.py",
"**/tests/*",
]

[tool.ruff.lint.per-file-ignores]
"toolz/tests/*.py" = ["B", "S", "F401", "RUF012"]
"toolz/sandbox/tests/*.py" = ["S", "SIM", "RUF012"]
"examples/*.py" = ["S", "RUF012"]
"bench/*.py" = ["RUF012"]
"toolz/_signatures.py" = ["ARG005", "C408"]
"toolz/curried/*.py" = ["F401", "A001"]

# https://docs.astral.sh/ruff/formatter/
[tool.ruff.format]
docstring-code-format = false
quote-style = "preserve"
exclude = [
"toolz/__init__.py",
"toolz/compatibility.py",
"**/tests/*",
]

# https://mypy.readthedocs.io/en/stable/config_file.html
[tool.mypy]
files = "toolz/**/*.py"
exclude = ["/tests/"]
strict = true
disallow_any_generics = false
disallow_subclassing_any = false
show_error_codes = true
pretty = true

# https://docs.pytest.org/en/6.2.x/customize.html
[tool.pytest.ini_options]
minversion = "6.0"
testpaths = [
"toolz/tests",
"toolz/sandbox/tests",
]

# https://coverage.readthedocs.io/en/6.4/config.html
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"@overload",
"except ImportError",
"\\.\\.\\.",
"raise NotImplementedError()",
]
show_missing = true
[tool.coverage.run]
source = ["toolz"]
omit = [
"toolz/tests/test*",
"toolz/*/tests/test*",
"toolz/compatibility.py",
"toolz/_version.py",
]

[tool.setuptools_scm]
version_file = "toolz/_version.py"
version_scheme = "post-release"
local_scheme = "dirty-tag"
19 changes: 0 additions & 19 deletions setup.cfg

This file was deleted.

38 changes: 0 additions & 38 deletions setup.py

This file was deleted.

2 changes: 2 additions & 0 deletions tlz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
"""

from . import _build_tlz

__all__ = ["_build_tlz"]
54 changes: 36 additions & 18 deletions tlz/_build_tlz.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
from __future__ import annotations

import contextlib
import sys
import types
import toolz
from importlib import import_module
from importlib.abc import Loader
from importlib.machinery import ModuleSpec
from types import ModuleType
from typing import TYPE_CHECKING

import toolz

if TYPE_CHECKING:
from collections.abc import Sequence

class TlzLoader:

class TlzLoader(Loader):
Copy link
Author

Choose a reason for hiding this comment

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

Make it an explicit subclass of Loader

""" Finds and loads ``tlz`` modules when added to sys.meta_path"""
def __init__(self):
def __init__(self) -> None:
self.always_from_toolz = {
toolz.pipe,
}

def _load_toolz(self, fullname):
def _load_toolz(self, fullname: str) -> dict[str, ModuleType]:
rv = {}
package, dot, submodules = fullname.partition('.')
_, dot, submodules = fullname.partition('.')
try:
module_name = ''.join(['cytoolz', dot, submodules])
rv['cytoolz'] = import_module(module_name)
Expand All @@ -29,12 +38,17 @@ def _load_toolz(self, fullname):
raise ImportError(fullname)
return rv

def find_module(self, fullname, path=None): # pragma: py3 no cover
package, dot, submodules = fullname.partition('.')
def find_module(
self,
fullname: str,
path: Sequence[str] | None = None, # noqa: ARG002
) -> TlzLoader | None: # pragma: py3 no cover
package, _, __ = fullname.partition('.')
if package == 'tlz':
return self
return None
Copy link
Author

Choose a reason for hiding this comment

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

missing return


def load_module(self, fullname): # pragma: py3 no cover
def load_module(self, fullname: str) -> ModuleType: # pragma: py3 no cover
if fullname in sys.modules: # pragma: no cover
return sys.modules[fullname]
spec = ModuleSpec(fullname, self)
Expand All @@ -43,15 +57,21 @@ def load_module(self, fullname): # pragma: py3 no cover
self.exec_module(module)
return module

def find_spec(self, fullname, path, target=None): # pragma: no cover
package, dot, submodules = fullname.partition('.')
def find_spec(
self,
fullname: str,
path: Sequence[str] | None, # noqa: ARG002
target: ModuleType | None = None, # noqa: ARG002
) -> ModuleSpec | None: # pragma: no cover
package, _, __ = fullname.partition('.')
if package == 'tlz':
return ModuleSpec(fullname, self)
return None
Copy link
Author

Choose a reason for hiding this comment

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

Missing return


def create_module(self, spec):
return types.ModuleType(spec.name)
def create_module(self, spec: ModuleSpec) -> ModuleType:
return ModuleType(spec.name)

def exec_module(self, module):
def exec_module(self, module: ModuleType) -> None:
toolz_mods = self._load_toolz(module.__name__)
fast_mod = toolz_mods.get('cytoolz') or toolz_mods['toolz']
slow_mod = toolz_mods.get('toolz') or toolz_mods['cytoolz']
Expand All @@ -64,10 +84,8 @@ def exec_module(self, module):
module.__doc__ = fast_mod.__doc__

# show file from toolz during introspection
try:
with contextlib.suppress(AttributeError):
module.__file__ = slow_mod.__file__
except AttributeError:
pass

for k, v in fast_mod.__dict__.items():
tv = slow_mod.__dict__.get(k)
Expand All @@ -78,7 +96,7 @@ def exec_module(self, module):
if tv in self.always_from_toolz:
module.__dict__[k] = tv
elif (
isinstance(v, types.ModuleType)
isinstance(v, ModuleType)
and v.__package__ == fast_mod.__name__
):
package, dot, submodules = v.__name__.partition('.')
Expand Down
12 changes: 6 additions & 6 deletions toolz/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from functools import partial, reduce

from .itertoolz import *

from .functoolz import *
Expand All @@ -6,8 +8,6 @@

from .recipes import *

from functools import partial, reduce

sorted = sorted

map = map
Expand All @@ -19,8 +19,8 @@

from . import curried, sandbox

functoolz._sigs.create_signature_registry()
from .functoolz import _sigs # type: ignore[attr-defined]

_sigs.create_signature_registry()

from ._version import get_versions
__version__ = get_versions()['version']
del get_versions
from ._version import __version__
Loading