Skip to content

Port module to Stable ABI + multi-phase module initialization - #641

Open
mistotebe wants to merge 12 commits into
python-ldap:mainfrom
mistotebe:module_startup
Open

mistotebe wants to merge 12 commits into
python-ldap:mainfrom
mistotebe:module_startup

Conversation

@mistotebe

Copy link
Copy Markdown
Contributor

Fixes: #540

@mistotebe mistotebe added this to the 3.5.0 milestone Sep 8, 2026
@mistotebe
mistotebe force-pushed the module_startup branch 2 times, most recently from 7f36b4a to 060c151 Compare September 8, 2026 13:01
mistotebe and others added 7 commits September 10, 2026 13:58
The `LDAP` type has been converted from a static type to a heap type.
The limited API does not support static types.

Heap types behave more closely like Python classes. They are allocated
on the heap and reference counted. Instances have a strong reference to
their type and must use GC protocol to track this reference.

The LDAP type can no longer be instantiated by Python code. This was
never supported and resulted in an invalid LDAP connection. Code like
`type(_ldap.initialize(""))()" now fails with a `TypeError`.

See: python-ldap#540
Signed-off-by: Christian Heimes <cheimes@redhat.com>
The `_ldap` module now uses modern multi-phase module initialization.

Replace `LDAPadd_methods` hack with proper PyMethodDef for
module-level functions. The old approache is incompatible with
multi-phase init. Module-level functions are now prefixed with
`LDAPMod_` and exported.

Use `PyModuleDef_Slot` to initialize the `_ldap` C extension.

See: python-ldap#540
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Signed-off-by: Ondřej Kuzník <ondra@mistotebe.net>
Replace unsafe macros and direct struct access with functions from
the subset of limited API functions.

* `PySequence_Fast_GET_ITEM` -> `PySequence_GetItem`
* `PyTuple_SET_ITEM` -> `PyTuple_SetItem`
* `PyList_SET_ITEM` -> `PyList_SetItem`
* `const char *tp_name` -> `Py_TYPE()` string representation

See: python-ldap#540
Signed-off-by: Christian Heimes <cheimes@redhat.com>
@mistotebe
mistotebe force-pushed the module_startup branch 2 times, most recently from 1049c04 to 37595c3 Compare September 10, 2026 13:22

@droideck droideck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I have a couple of concerns but otherwise, looks great!

Comment thread Modules/LDAPObject.c
goto error;
}
str = PyUnicode_AsUTF8AndSize(item, &strlen);
Py_DECREF(item);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should move this decref after memcpy and release item on the error paths too.
str points into item, so IIUC releasing our reference before copying leaves the buffer dependent on the caller’s list remaining unchanged during free-threaded execution.

Comment thread Modules/ldapmodule.c
static struct PyModuleDef ldap_moduledef = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_ldap",
.m_size = sizeof(LDAPModState),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIUC, this module/type reference cycle needs m_traverse, m_clear, and m_free so GC can collect it.
And add_err from constants.c similarly might need to release the previous array entry when another exception shares its error code.

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.

[feature] Port python-ldap to PEP 630 (Isolating Extension Modules)

3 participants