Description
First off, thanks for this package, I appreciate having these bindings available.
I'm encountering an issue where the Identity
and Recipient
types are not available at runtime, even though they are defined in the source code.
Steps to Reproduce
-
Install the
pyrage
andpyrage-stubs
packages. -
Try to import
Identity
andRecipient
:from pyrage import Identity, Recipient
-
This results in the following error:
ImportError: cannot import name 'Identity' from 'pyrage'
What I've Tried
- I've checked the installed package, and it seems that
Identity
andRecipient
are not being exposed in the__init__.py
file. - The type checker (e.g., in VSCode with Pyright) can see these types, but they are not available at runtime.
- I've tried modifying the
pyrage-stubs
package (e.g., addingpy.typed
, converting*.py
files to*.pyi
, adding__all__
), but the issue persists. - I've also tried rebuilding the package using
maturin
and even starting fresh with a new project structure using rye, but no luck.
Additional Context
-
I'm working on an Apple M1 machine, but I don't think this issue is platform-specific.
-
I've pushed a fork of the repository with my attempts to resolve the issue: here
-
I have a temporary workaround in my project where I define the following:
from pyrage import ssh, x25519 Identity = ssh.Identity | x25519.Identity Recipient = ssh.Recipient | x25519.Recipient type IdentityT = ssh.Identity | x25519.Identity type RecipientT = ssh.Recipient | x25519.Recipient
Doing this allows for using the types as both annotations and for instance checking them, e.g.,
from collections.abc import Sequence from typing import Any, TypeGuard from pyrage import IdentityError, RecipientError, x25519 from .types.age import Identity, IdentityT, Recipient, RecipientT def _is_sequence(obj: Any) -> TypeGuard[Sequence]: return isinstance(obj, Sequence) and not isinstance(obj, str | bytes | bytearray) def ensure_recipient_sequence(obj: Any) -> Sequence[RecipientT]: try: if isinstance(obj, str) and (_recipient := x25519.Recipient.from_str(obj)): obj = _recipient if isinstance(obj, Recipient) and not _is_sequence(obj): return [obj] if _is_sequence(obj) and all(isinstance(_, Recipient) for _ in obj): return obj raise RecipientError except Exception as exc: raise RecipientError from exc
I am not very familiar with maturin
or Rust development in general, so any help or guidance on how to properly expose Identity
and Recipient
at runtime would be greatly appreciated! My best guess is that while these are certainly type annotations, they may just need to be defined as such Union
objects in the Rust source.