Skip to content

Commit

Permalink
Merge branch 'unionai-oss:main' into bugfix/1463
Browse files Browse the repository at this point in the history
  • Loading branch information
derinwalters authored Jan 25, 2024
2 parents 426f775 + 4df61da commit a252248
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 54 deletions.
15 changes: 5 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,13 @@ repos:
args: ["--disable=import-error"]
exclude: (^docs/|^scripts)

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.982
- repo: local
hooks:
- id: mypy
additional_dependencies:
- numpy
- pandas-stubs
- types-click
- types-pkg_resources
- types-pytz
- types-pyyaml
- types-requests
name: mypy
entry: mypy
language: python
types: [python]
args: ["pandera", "tests", "scripts"]
exclude: (^docs/|^tests/mypy/modules/)
pass_filenames: false
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ dependencies:

# testing
- isort >= 5.7.0
- mypy
- mypy = 0.982
- pylint <= 2.17.3
- pytest
- pytest-cov
Expand Down
98 changes: 86 additions & 12 deletions pandera/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,29 +692,103 @@ def _check_arg(arg_name: str, arg_value: Any) -> Any:

sig = inspect.signature(wrapped)

def validate_args(arguments: Dict[str, Any]) -> Dict[str, Any]:
return {
arg_name: _check_arg(arg_name, arg_value)
for arg_name, arg_value in arguments.items()
}
def validate_args(
named_arguments: Dict[str, Any], arguments: Tuple[Any, ...]
) -> List[Any]:
"""
Validates schemas of both explicit and *args-like function arguments.
:param named_arguments: Bundled function arguments. Organized as key-value pairs of the
argument name and value. *args-like arguments are bundled into a single tuple.
Example: OrderedDict({'arg1': 1, 'arg2': 2, 'star_args': (3, 4, 5)})
:param arguments: Unpacked function arguments, as written in the function call.
Example: (1, 2, 3, 4, 5)
:return: List of validated function arguments.
"""

# Check for an '*args'-like argument
if len(arguments) > len(named_arguments):
(
star_args_name,
star_args_values,
) = named_arguments.popitem() # *args is the last item

star_args_tuple = (
_check_arg(star_args_name, arg_value)
for arg_value in star_args_values
)

explicit_args_tuple = (
_check_arg(arg_name, arg_value)
for arg_name, arg_value in named_arguments.items()
)

return list((*explicit_args_tuple, *star_args_tuple))

else:
return list(
_check_arg(arg_name, arg_value)
for arg_name, arg_value in named_arguments.items()
)

def validate_kwargs(
named_kwargs: Dict[str, Any], kwargs: Dict[str, Any]
) -> Dict[str, Any]:
"""
Validates schemas of both explicit and **kwargs-like function arguments.
:param named_kwargs: Bundled function keyword arguments. Organized as key-value pairs of
the keyword argument name and value. **kwargs-like arguments are bundled into a single
dictionary.
Example: OrderedDict({'kwarg1': 1, 'kwarg2': 2, 'star_kwargs': {'kwarg3': 3, 'kwarg4': 4}})
:param kwargs: Unpacked function keyword arguments, as written in the function call.
Example: {'kwarg1': 1, 'kwarg2': 2, 'kwarg3': 3, 'kwarg4': 4}
:return: list of validated function keyword arguments.
"""

# Check for an '**kwargs'-like argument
if kwargs.keys() != named_kwargs.keys():
(
star_kwargs_name,
star_kwargs_dict,
) = named_kwargs.popitem() # **kwargs is the last item

explicit_kwargs_dict = {
arg_name: _check_arg(arg_name, arg_value)
for arg_name, arg_value in named_kwargs.items()
}

star_kwargs_dict = {
arg_name: _check_arg(star_kwargs_name, arg_value)
for arg_name, arg_value in star_kwargs_dict.items()
}

return {**explicit_kwargs_dict, **star_kwargs_dict}

else:
return {
arg_name: _check_arg(arg_name, arg_value)
for arg_name, arg_value in named_kwargs.items()
}

def validate_inputs(
instance: Optional[Any],
args: Tuple[Any, ...],
kwargs: Dict[str, Any],
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
) -> Tuple[List[Any], Dict[str, Any]]:
if instance is not None:
# If the wrapped function is a method -> add "self" as the first positional arg
args = (instance, *args)

validated_pos = validate_args(sig.bind_partial(*args).arguments)
validated_kwd = validate_args(sig.bind_partial(**kwargs).arguments)
validated_pos = validate_args(sig.bind_partial(*args).arguments, args)
validated_kwd = validate_kwargs(
sig.bind_partial(**kwargs).arguments, kwargs
)

if instance is not None:
# If the decorated func is a method, "wrapped" is a bound method
# -> remove "self" before passing positional args through
first_pos_arg = list(sig.parameters)[0]
del validated_pos[first_pos_arg]
del validated_pos[0]

return validated_pos, validated_kwd

Expand All @@ -733,7 +807,7 @@ async def _wrapper(
validated_pos, validated_kwd = validate_inputs(
instance, args, kwargs
)
out = await wrapped_(*validated_pos.values(), **validated_kwd)
out = await wrapped_(*validated_pos, **validated_kwd)
return _check_arg("return", out)

else:
Expand All @@ -751,7 +825,7 @@ def _wrapper(
validated_pos, validated_kwd = validate_inputs(
instance, args, kwargs
)
out = wrapped_(*validated_pos.values(), **validated_kwd)
out = wrapped_(*validated_pos, **validated_kwd)
return _check_arg("return", out)

wrapped_fn = _wrapper(wrapped) # pylint:disable=no-value-for-parameter
Expand Down
33 changes: 4 additions & 29 deletions requirements-docs.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --output-file=requirements-docs.txt requirements.in
# pip-compile --no-emit-index-url --output-file=requirements-docs.txt requirements.in
#
aiosignal==1.3.1
# via ray
Expand Down Expand Up @@ -53,9 +53,7 @@ certifi==2023.7.22
# pyproj
# requests
cffi==1.15.1
# via
# argon2-cffi-bindings
# cryptography
# via argon2-cffi-bindings
cfgv==3.4.0
# via pre-commit
chardet==5.2.0
Expand Down Expand Up @@ -92,8 +90,6 @@ coverage[toml]==7.3.1
# via
# coverage
# pytest-cov
cryptography==41.0.5
# via secretstorage
dask==2023.9.2
# via
# -r requirements.in
Expand All @@ -115,11 +111,6 @@ docutils==0.17.1
# sphinx-panels
doit==0.36.0
# via jupyterlite-core
exceptiongroup==1.1.3
# via
# anyio
# hypothesis
# pytest
execnet==2.0.2
# via pytest-xdist
fastapi==0.103.1
Expand Down Expand Up @@ -180,10 +171,6 @@ isort==5.12.0
# pylint
jaraco-classes==3.3.0
# via keyring
jeepney==0.8.0
# via
# keyring
# secretstorage
jinja2==3.1.2
# via
# distributed
Expand Down Expand Up @@ -276,7 +263,7 @@ msgpack==1.0.6
# ray
multimethod==1.10
# via -r requirements.in
mypy==1.5.1
mypy==0.982
# via -r requirements.in
mypy-extensions==1.0.0
# via
Expand Down Expand Up @@ -478,8 +465,6 @@ rpds-py==0.10.3
# referencing
scipy==1.11.2
# via -r requirements.in
secretstorage==3.3.3
# via keyring
send2trash==1.8.2
# via jupyter-server
shapely==2.0.1
Expand Down Expand Up @@ -556,13 +541,6 @@ text-unidecode==1.3
# via python-slugify
tinycss2==1.2.1
# via nbconvert
tomli==2.0.1
# via
# black
# coverage
# mypy
# pylint
# pytest
tomlkit==0.12.1
# via pylint
toolz==0.12.0
Expand Down Expand Up @@ -610,16 +588,13 @@ types-urllib3==1.26.25.14
typing-extensions==4.8.0
# via
# -r requirements.in
# astroid
# black
# fastapi
# mypy
# pydantic
# pydantic-core
# typeguard
# typer
# typing-inspect
# uvicorn
typing-inspect==0.9.0
# via -r requirements.in
tzdata==2023.3
Expand Down
2 changes: 1 addition & 1 deletion requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ shapely
fastapi
black >= 22.1.0
isort >= 5.7.0
mypy
mypy == 0.982
pylint <= 2.17.3
pytest
pytest-cov
Expand Down
1 change: 0 additions & 1 deletion scripts/generate_pip_deps_from_conda.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ def conda_package_to_pip(package: str) -> Optional[str]:
for compare in ("<=", ">=", "=="):
if compare not in package:
continue

pkg, version = package.split(compare)
if pkg in EXCLUDE:
return None
Expand Down
Loading

0 comments on commit a252248

Please sign in to comment.