Skip to content

Commit

Permalink
feat/expand supported python versions (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbiseck3 authored Jul 3, 2024
1 parent b7fb254 commit 5bf23f1
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 50 deletions.
16 changes: 10 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true

env:
PYTHON_VERSION: "3.12"

jobs:
lint:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10", "3.11", "3.12" ]
steps:
- uses: actions/checkout@v3

- name: Set up Python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: make install-lint
Expand All @@ -41,13 +42,16 @@ jobs:

test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3

- name: Set up Python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: make install
Expand Down
16 changes: 10 additions & 6 deletions requirements/cli.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile requirements//cli.in
Expand All @@ -22,8 +22,10 @@ click==8.1.7
# uvicorn
dnspython==2.6.1
# via email-validator
email-validator==2.1.1
email-validator==2.2.0
# via fastapi
exceptiongroup==1.2.1
# via anyio
fastapi==0.111.0
# via -r requirements//cli.in
fastapi-cli==0.0.4
Expand Down Expand Up @@ -51,11 +53,11 @@ markupsafe==2.1.5
# via jinja2
mdurl==0.1.2
# via markdown-it-py
orjson==3.10.3
orjson==3.10.5
# via fastapi
pydantic==2.7.3
pydantic==2.8.0
# via fastapi
pydantic-core==2.18.4
pydantic-core==2.20.0
# via pydantic
pygments==2.18.0
# via rich
Expand All @@ -77,12 +79,14 @@ starlette==0.37.2
# via fastapi
typer==0.12.3
# via fastapi-cli
typing-extensions==4.12.1
typing-extensions==4.12.2
# via
# anyio
# fastapi
# pydantic
# pydantic-core
# typer
# uvicorn
ujson==5.10.0
# via fastapi
uvicorn[standard]==0.30.1
Expand Down
23 changes: 15 additions & 8 deletions requirements/lint.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile requirements//lint.in
Expand All @@ -10,35 +10,42 @@ black==24.4.2
# via -r requirements//lint.in
click==8.1.7
# via black
flake8==7.0.0
flake8==7.1.0
# via
# -r requirements//lint.in
# flake8-print
flake8-print==5.0.0
# via -r requirements//lint.in
mccabe==0.7.0
# via flake8
mypy==1.10.0
mypy==1.10.1
# via -r requirements//lint.in
mypy-extensions==1.0.0
# via
# black
# mypy
packaging==24.0
packaging==24.1
# via black
pathspec==0.12.1
# via black
platformdirs==4.2.2
# via black
pycodestyle==2.11.1
pycodestyle==2.12.0
# via
# flake8
# flake8-print
pyflakes==3.2.0
# via
# autoflake
# flake8
ruff==0.4.8
ruff==0.5.0
# via -r requirements//lint.in
typing-extensions==4.12.1
# via mypy
tomli==2.0.1
# via
# autoflake
# black
# mypy
typing-extensions==4.12.2
# via
# black
# mypy
10 changes: 7 additions & 3 deletions requirements/test.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile test.in
# pip-compile requirements//test.in
#
exceptiongroup==1.2.1
# via pytest
iniconfig==2.0.0
# via pytest
packaging==24.1
# via pytest
pluggy==1.5.0
# via pytest
pytest==8.2.2
# via -r test.in
# via -r requirements//test.in
tomli==2.0.1
# via pytest
10 changes: 5 additions & 5 deletions requirements/validate.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile validate.in
# pip-compile requirements//validate.in
#
certifi==2024.6.2
# via requests
charset-normalizer==3.3.2
# via requests
click==8.1.7
# via -r validate.in
# via -r requirements//validate.in
idna==3.7
# via requests
requests==2.32.3
# via -r validate.in
urllib3==2.2.1
# via -r requirements//validate.in
urllib3==2.2.2
# via requests
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def load_requirements(file: Union[str, Path]) -> List[str]:
setup(
name="unstructured-platform-plugins",
version="1.0.0",
python_requires=">=3.12,<3.13",
python_requires=">=3.10,<3.13",
url="https://github.com/Unstructured-IO/unstructured-platform-plugins", # noqa: 501
packages=find_packages(),
entry_points={
Expand Down
8 changes: 5 additions & 3 deletions test/test_schema.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import inspect
from dataclasses import dataclass
from enum import Enum
from typing import Any, Optional, TypedDict, Union, get_type_hints
from typing import Any, Optional, Union

import pytest
from pydantic import BaseModel
from typing_extensions import TypedDict

import unstructured_platform_plugins.schema.json_schema as js
from unstructured_platform_plugins.etl_uvicorn.utils import get_input_schema
from unstructured_platform_plugins.schema.model import is_valid_input_dict, is_valid_response_dict
from unstructured_platform_plugins.schema.utils import get_types_parameters
from unstructured_platform_plugins.schema.utils import get_typed_parameters
from unstructured_platform_plugins.type_hints import get_type_hints


def test_string_enum_fn():
Expand Down Expand Up @@ -442,7 +444,7 @@ def test_forward_reference_typing():
def fn(a: "MockInputClass") -> "MockOutputClass":
pass

parameters = get_types_parameters(fn)
parameters = get_typed_parameters(fn)
input_schema = js.parameters_to_json_schema(parameters=parameters)
expected_input_schema = {
"type": "object",
Expand Down
7 changes: 4 additions & 3 deletions unstructured_platform_plugins/etl_uvicorn/utils.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import inspect
from dataclasses import is_dataclass
from types import NoneType
from typing import Any, Callable, Optional, get_type_hints
from typing import Any, Callable, Optional

from pydantic import BaseModel

from unstructured_platform_plugins.schema.json_schema import (
parameters_to_json_schema,
response_to_json_schema,
)
from unstructured_platform_plugins.schema.utils import get_types_parameters
from unstructured_platform_plugins.schema.utils import get_typed_parameters
from unstructured_platform_plugins.type_hints import get_type_hints


def get_func(instance: Any, method_name: Optional[str] = None) -> Callable:
Expand Down Expand Up @@ -51,7 +52,7 @@ def get_plugin_id(instance: Any, method_name: Optional[str] = None) -> str:


def get_input_schema(func: Callable) -> dict:
parameters = get_types_parameters(func)
parameters = get_typed_parameters(func)
return parameters_to_json_schema(parameters)


Expand Down
22 changes: 15 additions & 7 deletions unstructured_platform_plugins/schema/json_schema.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import inspect
from dataclasses import MISSING, fields, is_dataclass
from enum import Enum, EnumMeta, EnumType
from enum import Enum, EnumMeta
from inspect import Parameter
from pathlib import Path
from types import GenericAlias, NoneType, UnionType
from typing import Any, Optional, Type, Union, get_type_hints
from typing import Any, Optional, Type, Union, _UnionGenericAlias

from pydantic import BaseModel, create_model
from pydantic.fields import FieldInfo, PydanticUndefined

from unstructured_platform_plugins.schema.utils import TypedParameter
from unstructured_platform_plugins.type_hints import get_type_hints

# https://json-schema.org/understanding-json-schema/reference/type
types_map: dict[Type, str] = {
Expand All @@ -29,7 +30,9 @@ def is_generic_alias(val: Any) -> bool:


def is_typed_dict(val: Any) -> bool:
return inspect.isclass(val) and dict in inspect.getmro(val) and dict != inspect.getmro(val)[0]
return (
inspect.isclass(val) and dict in inspect.getmro(val) and inspect.getmro(val)[0] is not dict
)


def type_to_json_schema(t: Type, args: Optional[tuple[Any, ...]] = None) -> dict:
Expand Down Expand Up @@ -171,7 +174,7 @@ def to_json_schema(val: Any) -> dict:
return parameter_to_json_schema(parameter=val)
if isinstance(val, UnionType):
return union_type_to_json_schema(t=val)
if isinstance(val, EnumType):
if isinstance(val, EnumMeta):
return enum_to_json_schema(e=val)
if is_generic_alias(val=val):
return generic_alias_to_json_schema(t=val)
Expand Down Expand Up @@ -237,8 +240,11 @@ def run_output_checks(return_annotation: Any):
return
if is_dataclass(return_annotation):
return
if inspect.isclass(return_annotation) and issubclass(return_annotation, BaseModel):
return
try:
if inspect.isclass(return_annotation) and issubclass(return_annotation, BaseModel):
return
except TypeError:
pass
if return_annotation is None:
return
if return_annotation is NoneType:
Expand Down Expand Up @@ -306,7 +312,9 @@ def schema_to_base_model(schema: dict, name: str = "reconstructed_model") -> Typ
)
for index, type_info in enumerate(any_of_entries)
]
t = Union[*type_info]
# To support python3.10, unpacking not supported
# t = Union[*type_info]
t = _UnionGenericAlias(Union, tuple(type_info))
else:
entry_info = any_of_entries[0]
json_type_name = entry_info["type"]
Expand Down
15 changes: 10 additions & 5 deletions unstructured_platform_plugins/schema/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import inspect
from inspect import Parameter, _empty
from typing import Callable, get_type_hints
from typing import Callable

from unstructured_platform_plugins.type_hints import get_type_hints


class TypedParameter(Parameter):
Expand All @@ -9,18 +11,21 @@ def __init__(self, *args, param_type=_empty, **kwargs):
self.param_type = param_type

@classmethod
def from_paramaeter(cls, param: Parameter) -> "TypedParameter":
def from_parameter(cls, param: Parameter) -> "TypedParameter":
return cls(
name=param.name, default=param.default, annotation=param.annotation, kind=param.kind
)


def get_types_parameters(fn: Callable) -> list[TypedParameter]:
def get_typed_parameters(fn: Callable) -> list[TypedParameter]:
type_hints = get_type_hints(fn)
parameters = list(inspect.signature(fn).parameters.values())
typed_params = []
for p in parameters:
typed_param = TypedParameter.from_paramaeter(param=p)
typed_param.param_type = type_hints[typed_param.name]
typed_param = TypedParameter.from_parameter(param=p)
if isinstance(typed_param.annotation, str):
typed_param.param_type = type_hints[typed_param.name]
else:
typed_param.param_type = typed_param.annotation
typed_params.append(typed_param)
return typed_params
Loading

0 comments on commit 5bf23f1

Please sign in to comment.