Skip to content

Conversation

@timosachsenberg
Copy link
Collaborator

@timosachsenberg timosachsenberg commented Jan 14, 2026

Summary

This PR completes the nogil support for autowrap-generated code, building on PR #181. When a method is marked with nogil in the PXD file (e.g., void process() nogil), the generated wrapper will release Python's Global Interpreter Lock (GIL) before calling into C++, allowing true parallelism.

Key Changes

  • ConversionProvider API change: input_conversion() now returns a 4-tuple (code, call_as, cleanup, decl) where decl is a tuple (declaration, call_expression) for split declaration in nogil contexts
  • call_method() signature: Added with_cdef parameter to control whether to include cdef (not allowed inside nogil: blocks)
  • CodeGenerator: Updated to handle the new return values and generate proper nogil-compatible code
  • Cython requirement: Updated to >=3.1 for improved nogil support

Updated Converters

All TypeConverter classes now support nogil:

  • Primitive types (int, float, bool, char, etc.)
  • String types (libcpp_string, const_char*, string_view)
  • Container types (vector, map, set, list, deque, pair)
  • C++17 types (optional, unordered_map, unordered_set)
  • Wrapped class types
  • Enum types

nogil + OpenMP Thread Interaction Analysis

When a nogil-marked method (e.g., in pyOpenMS) internally uses OpenMP for parallelism:

How It Works

  1. GIL is released before entering the C++ code via with nogil: block
  2. OpenMP threads spawn inside the C++ library
  3. All OpenMP threads execute without competing for Python's GIL
  4. Threads complete, control returns
  5. GIL is reacquired when leaving the nogil block

Safety Considerations

Aspect Behavior
GIL during OpenMP Released - OpenMP threads run freely
Thread safety Safe as long as C++ code doesn't call back into Python
Python callbacks Would need with gil: to reacquire GIL first
Other Python threads Can run concurrently while OpenMP works

Example Flow

Python: call pyopenms.method()
  └─ Cython: "with nogil:" releases GIL
       └─ C++ code runs
            └─ #pragma omp parallel spawns threads
                 └─ All threads work without GIL contention
            └─ OpenMP threads complete
       └─ Returns to Cython
  └─ GIL reacquired
Python: continues

Bottom Line

This is safe and beneficial for libraries like OpenMS that use OpenMP internally:

  • The GIL doesn't block OpenMP threads
  • OpenMS's OpenMP code is pure C++ (no Python callbacks)
  • Other Python threads can run while the C++ library processes data
  • True multi-core parallelism is achieved

Test Plan

  • All existing tests pass (165 passed, 1 skipped due to environment)
  • C++17 STL containers test passes (optional, string_view, unordered_map, unordered_set)
  • GIL testing with gil_testing.hpp verifies GIL is properly released

References

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added comprehensive cross-platform support for fixed-width C++ integer types (int8_t, uint32_t, int64_t, etc.)
  • Documentation

    • Added development environment setup guide with installation and configuration instructions
    • Fixed typos and improved clarity in contributing guidelines
  • Tests

    • Enhanced GIL handling test coverage with additional scenarios
  • Chores

    • Improved development environment and dependency management

✏️ Tip: You can customize this high-level summary in your review settings.

jpfeuffer and others added 3 commits January 14, 2026 10:58
This requires a change in conversion providers.
+Some other cleanups.
Update all remaining TypeConverter classes to return the 4-tuple
(code, call_as, cleanup, decl) from input_conversion() and add
with_cdef parameter to call_method() for nogil compatibility.

Converters updated:
- StdVectorAsNumpyConverter
- StdUnorderedMapConverter
- StdUnorderedSetConverter
- StdDequeConverter
- StdListConverter
- StdOptionalConverter
- StdStringViewConverter

Also update environment.yml to require Cython>=3.1 for nogil support.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 14, 2026

📝 Walkthrough

Walkthrough

This PR refactors the code generation pipeline to support declaration splitting for nogil contexts by extending input_conversion to return declaration and call-argument information separately, enabling better code organization for thread-safe operations.

Changes

Cohort / File(s) Summary
Core Converter Infrastructure
autowrap/ConversionProvider.py
Added public method init_as_call_arg() and extended input_conversion() return type from 3-tuple to 4-tuple with decl metadata. Introduced call_method_split() variant and with_cdef parameter to call_method(). Updated 20+ converter implementations (VoidConverter, EnumConverter, StdVectorConverter, StdSetConverter, StdMapConverter, etc.) to return additional decl tuple and support split-declaration paths.
Code Generator
autowrap/CodeGenerator.py
Extended internal return values from 4-tuple to 6-tuple (call_args, cleanups, in_types, stub, decls, decl_calls). Updated all unpacking call sites for attribute, function, and constructor wrappers. Enhanced nogil context handling to emit init block with declarations before nogil section and use decl_calls instead of call_args.
Type System & Annotations
autowrap/DeclResolver.py, autowrap/PXDParser.py
Added type annotation for result_type: Types.CppType in ResolvedMethod. Extended AnnotDict type alias to include Code in union: Dict[str, Union[bool, List[str], Code]].
Test Converters
tests/test_code_generator_minimal.py, tests/test_files/converters/IntHolderConverter.py
Updated SpecialIntConverter and IntHolderConverter to return 4-tuple from input_conversion() with new decl element containing declaration and variable name pair.
Test Files & Cases
tests/test_files/gil_testing.hpp, tests/test_files/gil_testing.pxd, tests/test_files/libcpp_stl_test.pxd, tests/test_code_generator.py
Added new method do_something2(const std::string& msg) to GilTesting class with nogil support. Extended test case for GIL unlock to verify multiple operations. Added nogil qualifier to two LibCppSTLTest method declarations.
Build & Configuration
environment.yml, requirements_dev.txt, setup.cfg
Added new Conda environment file specifying cython and pytest dependencies. Removed pytest/pytest-cov from requirements_dev.txt. Removed commented egg_info configuration lines.
Platform Support
autowrap/data_files/boost/cstdint.hpp
New 550+ line Boost header providing portable fixed-width integer types (int8_t, int16_t, int32_t, int64_t, intmax_t, intptr_t variants) in boost namespace with cross-platform support (GLIBC, HP-UX, FreeBSD, AIX, Solaris, NetBSD, OpenBSD, Cygwin) and macro definitions for integer literal suffixes.
Documentation
CONTRIBUTING.md
Added "Setting up dev environment" section with installation steps (conda/mamba/venv, C++ compiler, git, repo cloning). Fixed typos: "meber" → "member", "github" → "GitHub", "repoduce" → "reproduce".

Sequence Diagram(s)

sequenceDiagram
    participant Conv as TypeConverter
    participant CG as CodeGenerator
    participant Out as Output Code

    Note over Conv,Out: Extended Declaration Handling (New Flow)
    
    Conv->>CG: input_conversion() returns<br/>(code, call_as, cleanup, decl)
    
    alt With nogil && has declarations
        CG->>Out: emit init block with decls
        CG->>Out: emit with nogil context
        CG->>Out: use decl_calls instead of call_args<br/>inside nogil block
    else Without nogil
        CG->>Out: emit code + call_args directly<br/>as before
    end
    
    Out-->>Conv: Generated C/Cython code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • jpfeuffer
  • poshul

Poem

🐰 A rabbit's ode to declarations split,
No more monolithic tuples bit by bit,
With nogil's call, declarations bloom,
Declarations precede, in organized room,
Thread-safe and tidy, hoppy code indeed! 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Complete nogil support for all converters' directly and accurately describes the main objective of the PR, which is implementing full nogil support across all TypeConverter classes in the autowrap codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
autowrap/ConversionProvider.py (5)

2274-2276: Type annotation doesn't match actual return type.

The input_conversion type annotation shows Tuple[Code, str, Union[Code, str]] (3 elements), but the actual returns at lines 2314-2315 and 2343-2344 include a 4th decl element. The annotation should be Tuple[Code, str, Union[Code, str], Tuple[str, str]].

🔧 Suggested fix
     def input_conversion(
         self, cpp_type: CppType, argument_var: str, arg_num: int
-    ) -> Tuple[Code, str, Union[Code, str]]:
+    ) -> Tuple[Code, str, Union[Code, str], Tuple[str, str]]:

2773-2775: Type annotation missing decl tuple element.

Similar to StdVectorAsNumpyConverter, the return type annotation is missing the 4th Tuple[str, str] element for decl. The actual return at lines 2912-2913 correctly includes it.

🔧 Suggested fix
     def input_conversion(
         self, cpp_type: CppType, argument_var: str, arg_num: int
-    ) -> Tuple[Code, str, Union[Code, str]]:
+    ) -> Tuple[Code, str, Union[Code, str], Tuple[str, str]]:

3067-3069: Type annotation missing decl tuple element in StdUnorderedSetConverter.

Same issue - annotation shows 3-tuple but returns 4-tuple.


3278-3280: Type annotation missing decl tuple element in StdDequeConverter.

Same issue - annotation shows 3-tuple but returns 4-tuple.


3445-3447: Type annotation missing decl tuple element in StdListConverter.

Same issue - annotation shows 3-tuple but returns 4-tuple.

autowrap/CodeGenerator.py (1)

1456-1480: Multi-line init block loses indentation for declarations after the first.

When a nogil method has multiple arguments, init contains multiple lines (one per declaration). The template | $init only applies the 4-space indentation to the first line. Subsequent lines from the \n in init will start at column 0, producing invalid Cython code.

Example with two arguments:

# init = "cdef int c_x = (<int>x)\ncdef int c_y = (<int>y)\n"
# Results in:
    cdef int c_x = (<int>x)
cdef int c_y = (<int>y)    # <-- Wrong: no indentation

    with nogil:
🔧 Proposed fix: Pre-indent each declaration line
 init = ""
 c_call_args = []
 for decl, decl_call in zip(decls, decl_calls):
-    init = init + decl + "\n"
+    init = init + "    " + decl + "\n"
     c_call_args.append(decl_call)

 # call wrapped method and convert result value back to python
 cpp_name = method.cpp_decl.name

 if method.with_nogil and init.strip("\n"):
     call_args = c_call_args

 call_args_str = ", ".join(call_args)
 ...

 if method.with_nogil:
     meth_code.add(
         """
-      |    $init
+      |$init
       |    with nogil:
       |
       """, locals()
     )

Alternatively, build each declaration with the proper indentation at the source, or emit declarations individually via meth_code.add() calls.

🤖 Fix all issues with AI agents
In `@autowrap/ConversionProvider.py`:
- Around line 200-201: The VoidConverter.init_as_call_arg currently returns a
libcpp_string assignment (copied from StdStringConverter) which is incorrect for
void; update VoidConverter.init_as_call_arg to not emit that string and instead
raise NotImplementedError (or return an empty string if you prefer base-class
consistency) so void types cannot produce bogus call-arg initialization; edit
the method on the VoidConverter class (init_as_call_arg) to either raise
NotImplementedError("init_as_call_arg not applicable for void") or return "".

In `@environment.yml`:
- Line 5: Update the cython dependency entry "cython>=3.1" in environment.yml to
either pin a safe version and/or document the experimental nogil status: replace
with a pinned spec like "cython==3.1.0" (or "cython>=3.1,<3.2") if you want
reproducible installs, and add a short inline comment or adjacent README note
stating that Cython 3.1's nogil/free-threading is experimental and may
re-acquire the GIL for exceptions or Python object access so the team can review
limitations before production use.
🧹 Nitpick comments (2)
environment.yml (1)

4-6: Consider specifying a Python version constraint.

The environment configuration lacks a Python version specification, which could lead to compatibility issues across different Python versions. Consider adding a Python version constraint to ensure consistent behavior.

🐍 Proposed addition for Python version
 dependencies:
+  - python>=3.8
   - cython>=3.1
   - pytest

Note: Adjust the Python version as appropriate for your project's requirements.

tests/test_files/gil_testing.hpp (1)

53-57: Python 2.0 code is dead code.

Python 2 has been EOL since January 2020. The #else branch for Python 2.0 (lines 54-57) will never be compiled when using Python 3. Consider removing this dead code for maintainability.

This applies to both do_something (lines 24-28) and do_something2 (lines 53-57).

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6236c3d and 2306ff7.

📒 Files selected for processing (15)
  • CONTRIBUTING.md
  • autowrap/CodeGenerator.py
  • autowrap/ConversionProvider.py
  • autowrap/DeclResolver.py
  • autowrap/PXDParser.py
  • autowrap/data_files/boost/cstdint.hpp
  • environment.yml
  • requirements_dev.txt
  • setup.cfg
  • tests/test_code_generator.py
  • tests/test_code_generator_minimal.py
  • tests/test_files/converters/IntHolderConverter.py
  • tests/test_files/gil_testing.hpp
  • tests/test_files/gil_testing.pxd
  • tests/test_files/libcpp_stl_test.pxd
💤 Files with no reviewable changes (2)
  • setup.cfg
  • requirements_dev.txt
🧰 Additional context used
🧬 Code graph analysis (5)
autowrap/DeclResolver.py (1)
autowrap/Types.py (1)
  • CppType (42-289)
autowrap/PXDParser.py (1)
autowrap/Code.py (1)
  • Code (41-90)
tests/test_files/converters/IntHolderConverter.py (1)
autowrap/Code.py (2)
  • Code (41-90)
  • add (56-75)
autowrap/ConversionProvider.py (3)
autowrap/Types.py (2)
  • CppType (42-289)
  • toString (168-200)
autowrap/Code.py (2)
  • Code (41-90)
  • add (56-75)
tests/test_files/converters/IntHolderConverter.py (2)
  • matches (9-10)
  • input_conversion (18-32)
autowrap/CodeGenerator.py (1)
autowrap/ConversionProvider.py (16)
  • input_conversion (148-161)
  • input_conversion (218-221)
  • input_conversion (258-263)
  • input_conversion (294-299)
  • input_conversion (338-345)
  • input_conversion (372-379)
  • input_conversion (403-410)
  • input_conversion (472-484)
  • input_conversion (521-528)
  • input_conversion (558-567)
  • input_conversion (597-604)
  • input_conversion (644-655)
  • input_conversion (802-870)
  • input_conversion (980-1228)
  • input_conversion (1368-1470)
  • input_conversion (1802-2046)
🪛 Clang (14.0.6)
autowrap/data_files/boost/cstdint.hpp

[error] 36-36: 'boost/config.hpp' file not found

(clang-diagnostic-error)

🪛 markdownlint-cli2 (0.18.1)
CONTRIBUTING.md

34-34: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)


37-37: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

🪛 Ruff (0.14.11)
autowrap/ConversionProvider.py

60-60: Unused method argument: arg_num

(ARG002)


85-85: Unused method argument: res_type

(ARG002)


85-85: Unused method argument: with_const

(ARG002)


200-200: Unused method argument: cpp_type

(ARG002)


200-200: Unused method argument: arg_num

(ARG002)


206-206: Unused method argument: res_type

(ARG002)


206-206: Unused method argument: with_const

(ARG002)


206-206: Unused method argument: with_cdef

(ARG002)


258-258: Unused method argument: arg_num

(ARG002)


294-294: Unused method argument: arg_num

(ARG002)


530-530: Unused method argument: res_type

(ARG002)


530-530: Unused method argument: with_const

(ARG002)


569-569: Unused method argument: res_type

(ARG002)


569-569: Unused method argument: with_const

(ARG002)


606-606: Unused method argument: res_type

(ARG002)


606-606: Unused method argument: with_const

(ARG002)


622-622: Unused method argument: arg_num

(ARG002)


873-873: Unused method argument: res_type

(ARG002)


873-873: Unused method argument: with_const

(ARG002)


877-877: Unused method argument: res_type

(ARG002)


877-877: Unused method argument: with_const

(ARG002)


877-877: Unused method argument: with_cdef

(ARG002)


1231-1231: Unused method argument: res_type

(ARG002)


1231-1231: Unused method argument: with_const

(ARG002)


1235-1235: Unused method argument: res_type

(ARG002)


1235-1235: Unused method argument: with_const

(ARG002)


1235-1235: Unused method argument: with_cdef

(ARG002)


1473-1473: Unused method argument: res_type

(ARG002)


1473-1473: Unused method argument: with_const

(ARG002)


1477-1477: Unused method argument: res_type

(ARG002)


1477-1477: Unused method argument: with_const

(ARG002)


1477-1477: Unused method argument: with_cdef

(ARG002)


2049-2049: Unused method argument: with_const

(ARG002)


2057-2057: Unused method argument: with_const

(ARG002)


2057-2057: Unused method argument: with_cdef

(ARG002)


2545-2545: Unused method argument: cpp_type

(ARG002)


2545-2545: Unused method argument: arg_num

(ARG002)


2915-2915: Unused method argument: res_type

(ARG002)


2915-2915: Unused method argument: with_const

(ARG002)


2915-2915: Unused method argument: with_cdef

(ARG002)


3171-3171: Unused method argument: res_type

(ARG002)


3171-3171: Unused method argument: with_const

(ARG002)


3171-3171: Unused method argument: with_cdef

(ARG002)


3349-3349: Unused method argument: res_type

(ARG002)


3349-3349: Unused method argument: with_const

(ARG002)


3349-3349: Unused method argument: with_cdef

(ARG002)


3522-3522: Unused method argument: res_type

(ARG002)


3522-3522: Unused method argument: with_const

(ARG002)


3522-3522: Unused method argument: with_cdef

(ARG002)


3654-3654: Unused method argument: res_type

(ARG002)


3654-3654: Unused method argument: with_const

(ARG002)


3654-3654: Unused method argument: with_cdef

(ARG002)


3745-3745: Unused method argument: res_type

(ARG002)


3745-3745: Unused method argument: with_const

(ARG002)


3745-3745: Unused method argument: with_cdef

(ARG002)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: test (==3.2.0, 3.10)
  • GitHub Check: test (==3.2.0, 3.13)
  • GitHub Check: test (==3.2.0, 3.12)
  • GitHub Check: test (==3.1.0, 3.11)
  • GitHub Check: test (==3.1.0, 3.10)
  • GitHub Check: test (==3.1.0, 3.13)
  • GitHub Check: test (==3.2.0, 3.11)
  • GitHub Check: test (==3.1.0, 3.12)
🔇 Additional comments (29)
environment.yml (1)

1-3: LGTM!

The environment name and channel configuration are appropriate for this project.

CONTRIBUTING.md (2)

7-17: LGTM! Helpful dev environment setup instructions.

The new section provides a clear, concise workflow for contributors to get started.


34-37: Documentation improvements look good.

The typo corrections ("meber"→"member", "github"→"GitHub", "repoduce"→"reproduce") improve readability.

Note: Static analysis flags MD007 (list indentation) on these lines, but the 2-space indent is consistent with the existing list style in lines 29-33.

tests/test_files/gil_testing.pxd (1)

3-3: LGTM! Proper extension of GIL testing infrastructure.

The new do_something2 method tests nogil behavior with libcpp_string parameters (vs. const_char* in the original method), which provides good coverage for the string conversion path in nogil contexts.

Also applies to: 10-10

tests/test_code_generator.py (1)

326-327: LGTM! Good test coverage for the new nogil method.

The test correctly exercises do_something2 with a string argument and verifies the expected behavior, providing coverage for nogil string conversions.

autowrap/DeclResolver.py (1)

231-231: LGTM! Type annotation improves code clarity.

The explicit Types.CppType annotation aligns with other typed attributes in ResolvedMethod and supports better IDE/type-checker integration.

tests/test_files/converters/IntHolderConverter.py (1)

18-32: LGTM! Correctly updated to the new 4-tuple API.

The changes properly align with the PR's input_conversion() API change:

  • Fixed typo in comment ("behavoir" → "behavior")
  • Added decl = ("", call_as) tuple where the empty string indicates the declaration is already embedded in code
  • Returns the new 4-tuple (code, call_as, cleanup, decl)

This pattern is appropriate since the cdef _Holder[int] declaration is handled inline within the code block.

tests/test_code_generator_minimal.py (1)

69-76: LGTM - Test converter correctly updated for new 4-tuple return.

The input_conversion method now returns the expected 4-tuple (code, call_as, cleanup, decl) where decl is ("cdef int c_<var> = <call_as>", "c_<var>"). This aligns with the PR's goal of supporting split declarations for nogil contexts.

tests/test_files/gil_testing.hpp (1)

41-68: New do_something2 method provides std::string parameter test coverage.

The method correctly tests GIL release behavior with const std::string& parameter type, complementing the existing const char* test. The GIL-check logic is appropriate for verifying that the GIL is released before entering C++ code.

tests/test_files/libcpp_stl_test.pxd (1)

51-53: LGTM - Test declarations correctly add nogil qualifiers.

The nogil qualifiers on process_8_map and process_9_map provide test coverage for:

  • Returning libcpp_map[IntWrapper, int] with nogil (line 51)
  • Accepting libcpp_map[int, IntWrapper]& with nogil (line 53)

This validates the extended input_conversion and call_method handling for map types in nogil contexts.

autowrap/PXDParser.py (2)

57-57: LGTM - Type annotation correctly expanded to include Code.

The AnnotDict type alias now accurately reflects that values can be Code objects (used for wrap-doc annotations), not just bool or List[str].


83-84: Good documentation of technical debt.

The TODO comment acknowledges the inconsistency between Code and List[str] value types. This helps future maintainers understand the design decision.

autowrap/ConversionProvider.py (8)

56-64: LGTM - Base class extended with nogil support infrastructure.

The __init__ method properly initializes enums_to_wrap and init_as_call_arg provides a sensible default for generating C variable declarations. The pattern cdef <type> c_<var> = <var> is appropriate for split declarations.


84-123: Well-designed call_method_split and with_cdef extension.

The call_method_split method returns a tuple of (declaration, assignment) enabling declarations to be placed before with nogil: blocks while assignments occur inside. The with_cdef parameter in call_method provides backward compatibility while supporting nogil contexts.

The detailed TODO comment (lines 89-96) is excellent documentation explaining the rationale and potential future improvements.


148-161: Clear documentation of the new 4-tuple return format.

The updated docstring correctly documents the decl tuple as containing (declaration, call_expression) for split-declaration paths, primarily used in nogil contexts.


258-263: Consistent 4-tuple pattern in IntegerConverter.

The input_conversion correctly returns the new format with decl = ("cdef <type> c_<var> = <call_as>", "c_<var>"). This pattern is consistently applied across all primitive type converters.


869-870: Correct decl handling for already-declared variables.

When the declaration is already included in the conversion code, returning ("", temp_var) for decl correctly indicates no additional declaration is needed while still providing the call expression. This pattern is consistently applied across container converters.


3763-3786: LGTM - Cleaner ConverterRegistry initialization lifecycle.

The instance_mapping is now properly initialized once in __init__ (line 3764) and populated in process_and_set_type_mapping (lines 3784-3786). This is a cleaner pattern than potentially reinitializing the dict.


1160-1160: Minor style inconsistency in condition.

Line 1160 uses not in while similar conditions elsewhere use consistent spacing. This is a nitpick.

and tt_key.base_type not in self.converters.names_of_wrapper_classes

vs the expected pattern from other similar lines that use the same format. No action needed.


1695-1733: TypeToWrapConverter.call_method correctly handles with_cdef for wrapped types.

The method properly generates code with or without cdef declarations based on the with_cdef parameter. For pointer returns with null checking, both paths are handled correctly (lines 709-728).

autowrap/CodeGenerator.py (9)

1199-1216: LGTM!

The initialization and population of decls and decl_calls lists correctly mirrors the existing pattern for call_args and cleanups. The tuple unpacking aligns with the extended input_conversion() return signature.


1430-1441: LGTM on the conditional logic.

The condition at line 1439 correctly ensures call_args is only replaced with c_call_args when there are actual declarations to emit. The init.strip("\n") check handles edge cases where decls might be empty strings.


1305-1305: LGTM!

The extended return tuple correctly provides the declaration info needed for nogil context handling.


1454-1454: LGTM!

Setting with_cdef=not method.with_nogil correctly prevents cdef statements inside the with nogil: block, where they're syntactically invalid.


1663-1665: Consistent API unpacking for constructors.

The extended tuple is correctly unpacked for API consistency, even though constructors don't use nogil declarations.


1920-1920: LGTM!

Correctly unpacks the extended tuple from input_conversion() for consistency with the updated API.


1322-1322: LGTM!

Consistent API handling for the attribute wrapper.


1417-1428: LGTM!

The method signature correctly adds the ResolvedMethod type annotation, and the extended tuple unpacking aligns with the updated return from _create_fun_decl_and_input_conversion.


1549-1564: Clarify: Free functions don't support with_nogil but unpacking suggests API supports it.

In _create_wrapper_for_free_function, the decls and decl_calls variables are unpacked from _create_fun_decl_and_input_conversion but never used, unlike in create_wrapper_for_nonoverloaded_method (lines 1432-1434) where they initialize the call arguments.

Additionally, free functions don't check method.with_nogil and the call_method call at line 1564 uses default parameters, whereas class methods explicitly pass with_cdef = not method.with_nogil (line 1454) to handle nogil contexts.

This inconsistency suggests either:

  1. Free functions intentionally don't support nogil (in which case the unpacking can be removed to match the API contract), or
  2. Free function nogil support is incomplete and would require similar handling to class methods

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +200 to +201
def init_as_call_arg(self, cpp_type, argument_var, arg_num):
return "cdef libcpp_string c_%s = %s" % (argument_var, argument_var)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Suspicious init_as_call_arg implementation in VoidConverter.

The VoidConverter.init_as_call_arg returns "cdef libcpp_string c_%s = %s" which seems incorrect for a void type. This appears to be copy-pasted from StdStringConverter (line 2545-2546). While init_as_call_arg may never be called for void types in practice, this could lead to confusing errors if it ever is invoked.

Consider either:

  1. Raising NotImplementedError like other void-related methods
  2. Returning an empty string consistent with the base class pattern
🔧 Suggested fix
     def init_as_call_arg(self, cpp_type, argument_var, arg_num):
-        return "cdef libcpp_string c_%s = %s" % (argument_var, argument_var)
+        raise NotImplementedError("void has no call argument")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def init_as_call_arg(self, cpp_type, argument_var, arg_num):
return "cdef libcpp_string c_%s = %s" % (argument_var, argument_var)
def init_as_call_arg(self, cpp_type, argument_var, arg_num):
raise NotImplementedError("void has no call argument")
🧰 Tools
🪛 Ruff (0.14.11)

200-200: Unused method argument: cpp_type

(ARG002)


200-200: Unused method argument: arg_num

(ARG002)

🤖 Prompt for AI Agents
In `@autowrap/ConversionProvider.py` around lines 200 - 201, The
VoidConverter.init_as_call_arg currently returns a libcpp_string assignment
(copied from StdStringConverter) which is incorrect for void; update
VoidConverter.init_as_call_arg to not emit that string and instead raise
NotImplementedError (or return an empty string if you prefer base-class
consistency) so void types cannot produce bogus call-arg initialization; edit
the method on the VoidConverter class (init_as_call_arg) to either raise
NotImplementedError("init_as_call_arg not applicable for void") or return "".

Comment on lines +1 to +24
// boost cstdint.hpp header file ------------------------------------------//

// (C) Copyright Beman Dawes 1999.
// (C) Copyright Jens Mauer 2001
// (C) Copyright John Maddock 2001
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// See http://www.boost.org/libs/integer for documentation.

// Revision History
// 31 Oct 01 use BOOST_HAS_LONG_LONG to check for "long long" (Jens M.)
// 16 Apr 01 check LONGLONG_MAX when looking for "long long" (Jens Maurer)
// 23 Jan 01 prefer "long" over "int" for int32_t and intmax_t (Jens Maurer)
// 12 Nov 00 Merged <boost/stdint.h> (Jens Maurer)
// 23 Sep 00 Added INTXX_C macro support (John Maddock).
// 22 Sep 00 Better 64-bit support (John Maddock)
// 29 Jun 00 Reimplement to avoid including stdint.h within namespace boost
// 8 Aug 99 Initial version (Beman Dawes)


#ifndef BOOST_CSTDINT_HPP
#define BOOST_CSTDINT_HPP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's read the cstdint.hpp file to see the actual includes and dependencies
cat -n autowrap/data_files/boost/cstdint.hpp | head -50

Repository: OpenMS/autowrap

Length of output: 2189


🏁 Script executed:

# Check for the includes mentioned at lines 36 and 204
sed -n '30,40p' autowrap/data_files/boost/cstdint.hpp
echo "---"
sed -n '200,210p' autowrap/data_files/boost/cstdint.hpp

Repository: OpenMS/autowrap

Length of output: 560


🏁 Script executed:

# Check if boost/config.hpp and boost/limits.hpp exist in the repository
find autowrap -name "config.hpp" -o -name "limits.hpp" | head -20

Repository: OpenMS/autowrap

Length of output: 41


🏁 Script executed:

# Check the entire directory structure of the vendored boost files
ls -la autowrap/data_files/boost/ 2>/dev/null | head -30

Repository: OpenMS/autowrap

Length of output: 234


🌐 Web query:

C++11 cstdint header vs boost cstdint differences capabilities

💡 Result:

Short comparison — main differences and capabilities

  • Standard vs Boost: is the C++ standard header (types in namespace std/global); <boost/cstdint.hpp> is Boost’s compatibility header (typedefs in namespace boost) intended for pre‑C++11 portability. [1] (manuals.quinngrier.com)

  • Availability on old compilers: Boost was written to provide stdint-like typedefs on older compilers that lacked <stdint.h>/; it may supply only the types the platform supports and avoid placing names in std. Use Boost when targeting pre‑C++11 toolchains. [1] (boost.org)

  • Exact contents: Both expose fixed-width (intN_t/uintN_t), least-/fast- types, intptr_t/uintptr_t, and intmax_t when supported — but is governed by the C/C++ standard rules (some types are optional if the implementation lacks that width). Boost mirrors the C99 <stdint.h> semantics but places names in boost::. [2][1] (manuals.quinngrier.com)

  • Additional Boost features: Boost.Integer offers related utilities (boost::integer_traits, type-selection helpers, safer/portable wrappers) beyond just typedefs; <boost/cstdint.hpp> is part of that ecosystem. provides only the types and the C-format macros (from C99). [1] (cs.brown.edu)

  • Portability/caveats:

    • is the standard choice for modern C++ (C++11 onward). Use it when targeting C++11+ compilers. [2] (manuals.quinngrier.com)
    • <boost/cstdint.hpp> may expose some C macro names as implementation artifacts and keeps all names in boost:: to avoid polluting std/global; it can be redundant on modern toolchains but remains useful for legacy portability. [1] (boost.org)

If you want, I can list concrete symbols provided by each header on a given compiler (e.g., GCC/Clang/MSVC) — tell me which compiler and version.

Citations:


🏁 Script executed:

# Check for C++ standard in CMakeLists.txt
rg -i "cxx_standard|c\+\+11|c\+\+14|c\+\+17|c\+\+20" --max-count 20

Repository: OpenMS/autowrap

Length of output: 3194


🏁 Script executed:

# Check if there are any references to this boost cstdint header in the code
rg "boost/cstdint|boost::int8_t|boost::uint" --type cpp --type hpp | head -20

Repository: OpenMS/autowrap

Length of output: 86


🏁 Script executed:

# Get the full size and context of the file to understand its actual usage
wc -l autowrap/data_files/boost/cstdint.hpp

Repository: OpenMS/autowrap

Length of output: 100


🏁 Script executed:

# Check if there are compilation attempts or test files that would indicate this is used
fd -e "test" -e "cmake" autowrap/data_files/boost/ 2>/dev/null

Repository: OpenMS/autowrap

Length of output: 41


Remove this incomplete vendored Boost header or ensure all transitive dependencies are included.

This file includes <boost/config.hpp> and <boost/limits.hpp> which are missing from the repository, making it non-functional. Since the project targets C++17 (per HISTORY.md and Utils.py), the standard <cstdint> header provides all necessary fixed-width integer types (int8_t, uint32_t, etc.) without external dependencies. Consider either:

  1. Removing this file if not actively used
  2. Using <cstdint> directly (available in C++11 and later)
  3. Including the complete Boost vendoring with all transitive dependencies

# define __STDC_CONSTANT_MACROS
#endif

#include <boost/config.hpp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for boost/config.hpp and boost/limits.hpp dependencies
echo "Searching for boost/config.hpp..."
fd -t f "config.hpp" | grep -i boost || echo "Not found"

echo ""
echo "Searching for boost/limits.hpp..."  
fd -t f "limits.hpp" | grep -i boost || echo "Not found"

echo ""
echo "Checking autowrap/data_files/boost directory contents..."
fd . autowrap/data_files/boost 2>/dev/null | head -20 || echo "Directory not found or empty"

Repository: OpenMS/autowrap

Length of output: 243


🏁 Script executed:

cat autowrap/data_files/boost/cstdint.hpp | head -100

Repository: OpenMS/autowrap

Length of output: 3552


🏁 Script executed:

# Check for usage of BOOST_ macros that would come from config.hpp
rg "BOOST_[A-Z_]+" autowrap/data_files/boost/cstdint.hpp | head -30

Repository: OpenMS/autowrap

Length of output: 1278


🏁 Script executed:

rg "limits.hpp" autowrap/data_files/boost/cstdint.hpp

Repository: OpenMS/autowrap

Length of output: 137


Missing Boost dependencies will prevent compilation.

This header includes boost/config.hpp (line 36) and boost/limits.hpp (line 204), both of which are not present in the repository. The file depends on macros from boost/config.hpp (BOOST_HAS_STDINT_H, BOOST_HAS_LONG_LONG, BOOST_MSVC, BOOST_HAS_MS_INT64, BOOST_WINDOWS, BOOST_NO_INT64_T) for conditional compilation. Without these dependencies, the file will fail to compile.

🧰 Tools
🪛 Clang (14.0.6)

[error] 36-36: 'boost/config.hpp' file not found

(clang-diagnostic-error)

channels:
- conda-forge
dependencies:
- cython>=3.1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Cython 3.1 release date stable version

💡 Result:

Cython 3.1.0 (stable) was released on May 8, 2025. [1][2]

Sources:

  • piwheels release listing. [1]
  • SourceForge / PyPI release files showing 3.1.0 uploaded May 8, 2025. [2]

🌐 Web query:

Cython 3.1 nogil support compatibility

💡 Result:

Short summary — Cython 3.1 nogil compatibility

  • Cython 3.1 adds basic/experimental support for Python’s free-threaded (nogil) build (the “free-threaded” mode introduced around Python 3.13). Support is explicitly labelled experimental and may have known pitfalls. (cython.readthedocs.io)
  • You can use nogil as a context manager or decorator in pure-Python mode (with cython.nogil / with cython.nogil) and mark cfuncs as nogil; Cython also provides cython.gil/with_gil helpers. (cython.readthedocs.io)
  • Cython will still re-acquire the GIL when needed (e.g., exceptions, Python object access), and some behaviors (thread-state handling, extension-type safety, and edge cases) remain delicate — read the “Free threading” notes before using in production. (docs.cython.org)

If you want, I can fetch the exact 3.1.x release notes or copy the relevant “Free threading” section for closer reading.

Citations:


Note that Cython 3.1's nogil support is experimental.

Cython 3.1.0 (released May 8, 2025) is stable and available, and it does include nogil/free-threading support. However, this support is explicitly marked as experimental with known limitations and pitfalls. The implementation will re-acquire the GIL when needed (e.g., for exceptions or Python object access). Consider documenting this experimental status or reviewing the free-threading limitations before use in production.

🤖 Prompt for AI Agents
In `@environment.yml` at line 5, Update the cython dependency entry "cython>=3.1"
in environment.yml to either pin a safe version and/or document the experimental
nogil status: replace with a pinned spec like "cython==3.1.0" (or
"cython>=3.1,<3.2") if you want reproducible installs, and add a short inline
comment or adjacent README note stating that Cython 3.1's nogil/free-threading
is experimental and may re-acquire the GIL for exceptions or Python object
access so the team can review limitations before production use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants