Skip to content

ldap3: add types for Connection.unbind - #16243

Merged
srittau merged 2 commits into
python:mainfrom
MaicoTimmerman:ldap3-connection-unbind
Aug 20, 2026
Merged

ldap3: add types for Connection.unbind#16243
srittau merged 2 commits into
python:mainfrom
MaicoTimmerman:ldap3-connection-unbind

Conversation

@MaicoTimmerman

@MaicoTimmerman MaicoTimmerman commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

This PR adds types for Connection.unbind's controls argument, and propagates the types that become known from there to protocol.convert.build_controls_list and the BaseStrategy.send set of subclasses that unbind feeds its controls into.

Rationale for the types:

  • controls is a _ControlSequence | None. build_controls_list rejects anything that is not in SEQUENCE_TYPES (set, list, tuple, generator, dict_keys), so the alias enumerates those rather than using Iterable, mirroring the existing _ServerSequence alias. Items are a Control object or a (controlType, criticality, controlValue) triple, the two forms build_controls_list accepts.
  • The alias lives in protocol.convert next to build_controls_list, the function that defines the contract, and is imported by core.connection and the strategies.
  • build_controls_list returns Controls | None; it returns None for both None and an empty sequence.
  • unbind returns Literal[True] | tuple[...]: it hands a hardcoded True to _prepare_return_value, which returns that status directly, except on the thread-safe strategies (SAFE_SYNC, SAFE_RESTARTABLE), where it returns a
    (status, result, response, request) tuple.
  • The result, response and request members of that tuple use new _Result, _Response and _Request placeholder aliases, also used for the matching Connection attributes. Their real types are per-operation dicts, which is left for a follow-up.

Written with the help of Factory Droid (Opus 5), humanly curated.

Co-Authored-By: Factory Droid (Opus 5)
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

# Thread safe strategies return a (status, result, response, request) tuple instead of a bare status
def unbind(
self, controls: _ControlSequence | None = None
) -> Literal[True] | tuple[Literal[True], _Result, _Response, _Request]: ...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I assume sub-classes override this incompatibly? Union return types can be a bit problematic (obligatory link to python/typing#566), but let's keep this for now. We can always change it if it turns out to be a problem in practice.

@MaicoTimmerman MaicoTimmerman Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I assume sub-classes override this incompatibly?

No, the behavior sync vs async of the entire class actually depends on the value (and type) of Connection.strategy.

I believe then the Connection would need to become generic in terms of strategy? And then we'd overload unbind with explicit self: Connection[SyncStrategies] vs self: Connection[AsyncStrategies]?

Since runtime Connection is not generic, what's the policy towards making the stubs generic? Users can hit TypeError: type 'Connection' is not subscriptable during runtime

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We sometimes make classes generic, even if they are not generic at runtime.

Users can hit TypeError: type 'Connection' is not subscriptable during runtime

Yes, that's unfortunate, but often that's a tradeoff we are willing to make.

@srittau
srittau merged commit 8c21fb6 into python:main Aug 20, 2026
74 checks passed
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.

2 participants