Skip to content

Commit

Permalink
Merge pull request #29 from DavidCEllis/fix_union_annotations
Browse files Browse the repository at this point in the history
Fix an issue with union annotations in Python 3.14
  • Loading branch information
DavidCEllis authored Oct 21, 2024
2 parents 7280965 + 7c7fe3e commit 6910b40
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/auto_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.13-dev", "3.12", "3.11", "3.10", "pypy-3.10", "3.9", "3.8"]
python-version: ["3.13", "3.12", "3.11", "3.10", "pypy-3.10", "3.9", "3.8"]

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -42,7 +42,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -e .[testing]
python -m pip install -e .[testing,type_checking]
- name: Check type stub files
run: |
python -m mypy.stubtest ducktools.classbuilder
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ classifiers = [
dynamic = ['version']
license = {file = "LICENSE.md"}

[project.optional-dependencies]
testing = ["pytest>=8.2", "pytest-cov", "typing_extensions"]
type_checking = ["mypy"]
performance_tests = ["attrs", "pydantic"]
docs = ["sphinx", "myst-parser", "sphinx_rtd_theme"]

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools_scm]
version_file = "src/ducktools/classbuilder/_version.py"
version_file_template = "__version__ = \"{version}\"\n__version_tuple__ = {version_tuple}\n"


[project.optional-dependencies]
testing = ["pytest>=8.2", "pytest-cov", "mypy", "typing_extensions"]
performance_tests = ["attrs", "pydantic"]
docs = ["sphinx", "myst-parser", "sphinx_rtd_theme"]

[project.urls]
"Homepage" = "https://github.com/davidcellis/ducktools-classbuilder"

Expand Down
41 changes: 39 additions & 2 deletions src/ducktools/classbuilder/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,36 @@ def f():
# End evil stuff from types.py


class _Stringlike(str):
# There are typing operators that are not supported by strings
# This adds the 'or' operator '|'

def __or__(self, other):
if isinstance(other, str):
other_r = other
elif name := getattr(other, "__name__", None):
other_r = name
else:
other_r = str(other)

return type(self)(f"{self} | {other_r}")

def __ror__(self, other):
if isinstance(other, str):
other_r = other
elif name := getattr(other, "__name__", None):
other_r = name
else:
other_r = str(other)

return type(self)(f"{other_r} | {self}")

def __repr__(self):
base = super().__repr__()
clsname = type(self).__name__
return f"{clsname}({base})"


class _StringGlobs(dict):
"""
Based on the fake globals dictionary used for annotations
Expand All @@ -47,7 +77,7 @@ class _StringGlobs(dict):
is not found.
"""
def __missing__(self, key):
return key
return _Stringlike(key)

def __repr__(self):
cls_name = self.__class__.__name__
Expand Down Expand Up @@ -165,7 +195,14 @@ def call_annotate_func(annotate):
closure = None

new_annotate = _FunctionType(annotate.__code__, globs, closure=closure)
return new_annotate(1)

# Convert _Stringlike back to str
annos = {
k: str(v) if isinstance(v, _Stringlike) else v
for k, v in new_annotate(1).items()
}

return annos


def get_ns_annotations(ns, eval_str=True):
Expand Down

0 comments on commit 6910b40

Please sign in to comment.