Skip to content

Commit

Permalink
Update to Cython 3 (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra authored Jul 25, 2023
1 parent ac31f7d commit 57c100f
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 62 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9, "3.10", "3.11", "3.12-dev"]
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Unreleased

* Drop support for Python 3.7
* Add support for Python 3.12
* Support building with Cython 3

## 1.9.1

* Pin to `Cython<3` to fix build
Expand Down
38 changes: 2 additions & 36 deletions qcore/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@
"decorator_of_context_manager",
]

# make sure qcore is still importable if this module has not been compiled with Cython and Cython
# is not installed
try:
from cython import compiled
except ImportError:
compiled = False

import functools
import inspect
import sys
Expand Down Expand Up @@ -69,42 +62,15 @@ def __str__(self):
def __repr__(self):
return self.__str__()

# This awkward implementation is necessary so that binders can be compared for equality across
# Cythonized and non-Cythonized Python 2 and 3. In pure-Python compiled classes, Cython only
# supports overriding __richcmp__, not __eq__ (https://github.com/cython/cython/issues/690),
# but if __eq__ is defined it throws an error.
if compiled:

def __richcmp__(self, other, op):
"""Compare objects for equality (so we can run tests that do an equality check)."""
if op in (2, 3): # ==, !=
if (
self.__class__ is other.__class__
and self.decorator == other.decorator
and self.instance == other.instance
):
equal = True
else:
equal = False
return equal if op == 2 else not equal
else:
return NotImplemented

def __hash__(self):
return hash(self.decorator) ^ hash(self.instance)


if not compiled:

def __eq__(self, other):
return (
self.__class__ is other.__class__
and self.decorator == other.decorator
and self.instance == other.instance
)

DecoratorBinder.__eq__ = __eq__
del __eq__
def __hash__(self):
return hash(self.decorator) ^ hash(self.instance)


class DecoratorBase:
Expand Down
2 changes: 1 addition & 1 deletion qcore/helpers.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ cdef dict empty_dict


cdef class MarkerObject:
cpdef unicode name
cdef unicode name

cdef MarkerObject none
cdef MarkerObject miss
Expand Down
29 changes: 17 additions & 12 deletions qcore/inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,18 @@ def get_full_name(src):
return str(get_original_fn(src))


def get_function_call_str(fn, args, kwargs):
"""Converts method call (function and its arguments) to a str(...)-like string."""

def str_converter(v):
def _str_converter(v):
try:
return str(v)
except Exception:
try:
return str(v)
return repr(v)
except Exception:
try:
return repr(v)
except Exception:
return "<n/a str raised>"
return "<n/a str raised>"


def get_function_call_str(fn, args, kwargs):
"""Converts method call (function and its arguments) to a str(...)-like string."""

result = get_full_name(fn) + "("
first = True
Expand All @@ -88,13 +89,13 @@ def str_converter(v):
first = False
else:
result += ","
result += str_converter(v)
result += _str_converter(v)
for k, v in kwargs.items():
if first:
first = False
else:
result += ","
result += str(k) + "=" + str_converter(v)
result += str(k) + "=" + _str_converter(v)
result += ")"
return result

Expand Down Expand Up @@ -194,14 +195,18 @@ def is_classmethod(fn):
return isinstance(im_self, type)


def _identity(wrapper):
return wrapper


def wraps(
wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES
):
"""Cython-compatible functools.wraps implementation."""
if not is_cython_function(wrapped):
return functools.wraps(wrapped, assigned, updated)
else:
return lambda wrapper: wrapper
return _identity


def get_subclass_tree(cls, ensure_unique=True):
Expand Down
8 changes: 3 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
Cython==0.29.35
pytest==7.3.1
pip==23.1.2
mypy==1.3.0
black==23.3.0
pytest==7.4.0
mypy==1.4.1
black==23.7.0
8 changes: 5 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@


if __name__ == "__main__":
for extension in EXTENSIONS:
extension.cython_directives = {"language_level": "3"}

with open("./README.rst", encoding="utf-8") as f:
long_description = f.read()

Expand All @@ -62,16 +65,15 @@
classifiers=[
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"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",
],
keywords="quora core common utility",
packages=["qcore", "qcore.tests"],
package_data={"qcore": DATA_FILES},
ext_modules=EXTENSIONS,
setup_requires=["Cython==0.29.36"],
install_requires=["Cython"],
setup_requires=["Cython"],
)
8 changes: 4 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tox]
minversion=2.3.1
envlist =
py37,py38,py39,py310,py311
py38,py39,py310,py311,py312
mypy
black
skip_missing_interpreters = True
Expand All @@ -14,7 +14,7 @@ commands =
pytest qcore

[testenv:mypy]
basepython = python3.7
basepython = python3.8
deps =
-rrequirements.txt

Expand All @@ -27,8 +27,8 @@ commands =

[gh-actions]
python =
3.7: py37, mypy
3.8: py38
3.8: py38, mypy
3.9: py39
3.10: py310
3.11: py311, black
3.12: py312

0 comments on commit 57c100f

Please sign in to comment.