Skip to content

Commit d8dc6a0

Browse files
timosachsenbergCopilotposhul
authored
Cython3 migration (#200)
* update install instructions * Update TODO for current roadmap * Migrate to Cython 3 only * Remove workflow file changes * Remove MIGRATION_PLAN.MD (#203) * Initial plan * Remove MIGRATION_PLAN.MD as requested Co-authored-by: timosachsenberg <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: timosachsenberg <[email protected]> * Update CI matrix to remove old Cython versions Removed incompatible Cython and Python version combinations. * Remove obsolete Cython version check in test_enums (#206) * Initial plan * Remove obsolete Cython version check in test_enums Co-authored-by: timosachsenberg <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: timosachsenberg <[email protected]> --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Samuel Wein <[email protected]>
1 parent 93219e5 commit d8dc6a0

35 files changed

+129
-119
lines changed

.github/workflows/ci-autowrap.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ jobs:
1515
fail-fast: false
1616
matrix:
1717
include:
18-
- CYTHON: "<=0.29.21"
19-
python-version: "3.9" # Cython < 0.29.21 not compatible with 3.10, so neither are we
20-
- CYTHON: ">0.29.21"
21-
python-version: "3.10"
2218
- CYTHON: "==3.0.0"
2319
python-version: "3.10"
2420
- CYTHON: "==3.0.0"

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ autowrap 0.24.0 (unreleased)
88
autowrap 0.23.0
99

1010
Support for Cython 3.1! This means the removal of some py2 compatibility code, no more python distinction between long and int, some fixes to multiline comment processing.
11+
12+
- Dropped support for Cython versions older than 3.0; autowrap now requires Cython ≥ 3.0 and Python ≥ 3.9.

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ writing a wrapper can be learned easily. Further [Cython][] prevents you from
1414
many typical errors which might get in your way if you write such a wrapper in
1515
C++.
1616

17+
Requirements
18+
------------
19+
20+
- Python ≥ 3.9
21+
- Cython ≥ 3.0
22+
1723

1824
This wrapping process typically consist of four steps:
1925

README_DEVELOP

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,34 @@
1-
Activate the project in "development mode" first:
1+
Development setup
2+
=================
23

3-
$ python setup.py develop
4+
The recommended way to work on `autowrap` is to use a virtual environment,
5+
install the package in editable mode, and run the tests from the project root.
46

5-
For testing run
7+
1. Create and activate a virtual environment (optional but recommended):
68

7-
$ py.test tests
9+
$ python -m venv .venv
10+
$ source .venv/bin/activate # on Windows: .venv\Scripts\activate
11+
12+
2. Install `autowrap` with development dependencies:
13+
14+
$ python -m pip install -U pip
15+
$ python -m pip install -e .[dev]
16+
17+
(Use `python3` instead of `python` if needed on your system.)
18+
19+
3. Run the test suite from the project root:
20+
21+
$ pytest tests/ -v
22+
23+
For local coverage, you can also use:
24+
25+
$ ./run_test_coverage.sh
26+
27+
4. Verify the CLI is available:
28+
29+
$ autowrap --help
30+
31+
These commands have been verified to work with the current `pyproject.toml`
32+
configuration and are the preferred starting point for developing on `autowrap`.
833

934
from the projects directory.

TODO

Lines changed: 26 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,36 @@
1-
- mehr klassen wrappen
1+
Autowrap TODO
2+
=============
23

3-
- attribut zugriff ! ( ->ProteinIdentification::ProteinGroup z.b.)
4+
- Internal code generator refactor
45

5-
- wrap-attach auch für klassen !
6+
Consider splitting `CodeGenerator` into smaller, focused classes
7+
(e.g. for class generation, iterator support, reference handling)
8+
to improve maintainability and make future extensions easier.
69

7-
- codegen refak:
8-
extra klasse fürs eigentliche codegen.
9-
ziel: via vererbung auch iteratoren udn ref-zugriffen wrappen
10+
- Improved iterator support
1011

11-
- iteratoren und referenzen (siehe ungen)
12+
Support parameterized iterator ranges (e.g. methods like
13+
`beginRT(rtmin)` / `endRT(rtmax)` annotated with `wrap-iter-begin`
14+
/ `wrap-iter-end`) and expose them as dedicated Python iterator or
15+
range methods instead of only supporting parameterless `begin()` /
16+
`end()`.
1217

13-
- DPosition(mit numerischen template argument)
18+
- Reference semantics for methods returning references
1419

15-
- statische methoden direkt an die klassen hängen, bevor "wrap-inherits"
16-
aufgelöst wird !
20+
For methods that return references to other wrapped objects, explore
21+
using holder / proxy objects (using the existing
22+
`AutowrapRefHolder` / `AutowrapPtrHolder` infrastructure) to model
23+
true reference semantics, rather than always copying values into new
24+
wrapper instances. The goals are:
1725

18-
- config extra cimport statments
26+
- Preserve the lifetime of the referred-to object safely.
27+
- Allow attribute/method access on the referenced object to affect
28+
the original C++ object where appropriate.
1929

20-
- begin(), end() mit param, eg
21-
beginRT(rtmin) # wrap-iter-begin rtrange
22-
endRT(rtmax) # wrap-iter-end rtrange
30+
- Safe wrapping of non-const iterators
2331

24-
-> methode rtrange(rtmin, rtmax)
25-
26-
- neu: ClassGenerator (zum code erzeugen),
27-
RefProxyClassGenerator, IterProxyClassGenerator
28-
29-
ideen:
30-
31-
1) wenn methode M von X eine Ref auf Y zurückgibt:
32-
33-
idee: reference holder objekt als pointer sollte mit cython
34-
(cython schiebt variable dekl im c++ code nach vorne, z.b
35-
T & x;
36-
was so nicht geht, da referenz ja initalisierte werdne muss
37-
statt desen:
38-
holder[T] * X;
39-
40-
und später:
41-
42-
X.setReference(wrapped.inst.method_which_returns_ref(..))
43-
44-
als holder im wrappeb object.
45-
original objekt als shared_ptr mitspeichern damit die gespeicherte
46-
refernz (hoffentlich) erhalten bleibt.
47-
48-
-----------
49-
50-
- alle wrapped objekte haben shared_ptr
51-
- methode M returns Proxy mit shared_ptr to X und name von M
52-
- proxy wrapped methoden von R durch impliziten aufruf der methode M
53-
54-
der einfach heit halber: proxy objekt hat keine methoden die
55-
referenzen auf zu wrappende objekte zurückliefern
56-
ansonsten: --- chaining !?
57-
58-
59-
2) sicheres wrappen von non const iteratoren:
60-
61-
- iterobject speichert shared_ptr auf das orignal objekt
62-
63-
- iterobject speicher iterator selbst, damit kann man
64-
methoden des referenzierten objekts deim iterobjekt anhängen
65-
und so bleiben inplace modifiationen erhalten
32+
Investigate iterator wrappers that store both a reference to the
33+
original container and the iterator state, so that in-place
34+
modifications through iterator access are reflected in the
35+
underlying C++ container (instead of always iterating over copies).
6636

autowrap/Main.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,20 +172,14 @@ def register_converters(converters):
172172
def run_cython(inc_dirs, extra_opts, out, warn_level=1):
173173
from Cython.Compiler.Main import compile, CompilationOptions
174174
import Cython.Compiler.Errors
175+
import Cython.Compiler.Options as CythonOptions
175176

176177
Cython.Compiler.Errors.LEVEL = warn_level
177178

178-
# Try to get directive_defaults (API differs from 0.25 on)
179-
try:
180-
from Cython.Compiler.Options import directive_defaults
181-
except ImportError:
182-
# Cython 0.25
183-
import Cython.Compiler.Options
184-
185-
directive_defaults = Cython.Compiler.Options.get_directive_defaults()
186-
179+
# Start from Cython's default compiler directives
180+
directive_defaults = CythonOptions.get_directive_defaults()
187181
# TODO merge these options, if compiler_directives is given in extra_opts? Otherwise they are overwritten
188-
directive_defaults["binding"] = False # For backwards-compat to Cython 0.X
182+
directive_defaults["binding"] = False
189183
directive_defaults["boundscheck"] = False
190184
directive_defaults["wraparound"] = False
191185
directive_defaults["language_level"] = sys.version_info.major

autowrap/PXDParser.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -411,9 +411,7 @@ def parseTree(cls, node: Cython.Compiler.Nodes.CppClassNode, lines: Collection[s
411411
and isinstance(template_parameters, list)
412412
and isinstance(template_parameters[0], tuple)
413413
):
414-
# Cython 0.24 uses [(string, bool)] to indicate name and whether
415-
# template argument is required or optional.
416-
# For now, convert to pre-0.24 format
414+
# Convert Cython's (name, required_flag) tuples to just the name
417415
template_parameters = [t[0] for t in template_parameters]
418416
try:
419417
class_annotations = parse_class_annotations(node, lines)
@@ -624,10 +622,7 @@ def parse_pxd_file(path, warn_level=1):
624622
source = CompilationSource(source_desc, name, os.getcwd())
625623
result = create_default_resultobj(source, options)
626624

627-
try: # Cython 0.X
628-
context = options.create_context()
629-
except: # Cython 3.X
630-
context = Context.from_options(options)
625+
context = Context.from_options(options)
631626
pipeline = Pipeline.create_pyx_pipeline(context, options, result)
632627
context.setup_errors(options, result)
633628
root = pipeline[0](source) # only parser

autowrap/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@
4040
logger = L.getLogger(__name__)
4141
logger.setLevel(L.INFO)
4242

43+
try:
44+
from Cython.Compiler.Version import version as _cython_version
45+
except ImportError:
46+
_cython_version = "0"
47+
else:
48+
try:
49+
_major_str = str(_cython_version).split(".")[0]
50+
if int(_major_str) < 3:
51+
raise RuntimeError(
52+
"autowrap requires Cython >= 3.0; found Cython %s" % _cython_version
53+
)
54+
except Exception:
55+
# If parsing the version fails for some reason, do not block import here.
56+
pass
57+
4358
"""
4459
The autowrap process consists of two steps:
4560
i) parsing of files (done by DeclResolver, which in turn uses the PXDParser

docs/README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ annotations in the header files to generate correct Cython code. For an
99
example, please have a look at `examples/int_holder.h` and
1010
`example/int_holder.pxd` which together form the input to the program.
1111

12+
Requirements
13+
------------
14+
15+
- Python ≥ 3.9
16+
- Cython ≥ 3.0
17+
1218
Simple example
1319
---------------------
1420

@@ -84,12 +90,12 @@ You can build the final Python extension module by running
8490
And you can use the final module running
8591

8692
```python
87-
>>> import py_int_holder
88-
>>> ih = py_int_holder.IntHolder(42)
89-
>>> print ih.i_
90-
42
91-
>>> print ih.add(ih)
92-
84
93+
>>> import py_int_holder
94+
>>> ih = py_int_holder.IntHolder(42)
95+
>>> print(ih.i_)
96+
42
97+
>>> print(ih.add(ih))
98+
84
9399
```
94100

95101
To get some insight how `autowrap` works, you can inspect files

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ classifiers = [
2929
]
3030
requires-python = ">=3.9"
3131
dependencies = [
32-
"Cython>=0.19",
32+
"Cython>=3.0",
3333
"setuptools",
3434
]
3535

0 commit comments

Comments
 (0)