-
Notifications
You must be signed in to change notification settings - Fork 39
Implement PEP 489 + other modernizations #267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
oschwald
commented
Oct 14, 2025
- Implement PEP 489 multi-phase initialization for C extension
- Add missing iter type hint
- Modernize setup.py for Python 3.10+
- Convert Metadata class to dataclass
- Make Metadata class readonly/immutable
- Convert MODE constants to IntEnum
- Improve type annotations for Record types and Decoder
- Remove Jython support
- Use single source of truth for version from pyproject.toml
This commit modernizes the C extension to use PEP 489 multi-phase initialization, enabling proper subinterpreter support and module isolation for Python 3.12+. Key changes: Module State Management: - Added maxminddb_state struct to store per-module state - Implemented get_maxminddb_state() helpers to access module state - Added module lifecycle functions (traverse, clear, free) Type Conversion: - Converted Reader_Type, Metadata_Type, and ReaderIter_Type from static types to heap types using PyType_FromModuleAndSpec() - Created PyType_Spec definitions for all three types - Removed static global type declarations State Threading: - Updated all functions to access module state instead of globals: - Reader_init(), get_record(), Reader_metadata() - Reader_iter(), ReaderIter_next() - from_entry_data_list(), from_map(), from_array() - Removed static global variables for MaxMindDB_error and ipaddress_ip_network Module Initialization: - Implemented maxminddb_exec() to initialize module state - Added module slots declaring: - Multi-phase initialization support (Py_mod_exec) - Multiple interpreter support (Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED) - GIL-free operation when available (Py_MOD_GIL_NOT_USED) - Updated PyModuleDef with m_size, m_slots, and GC functions - Simplified PyInit_extension() to use PyModuleDef_Init() Testing: - Updated test regex to handle fully qualified type names in error messages (heap types include module path) - All 278 tests pass Benefits: - Supports Python 3.12+ isolated subinterpreters - Enables multiple independent module instances - Complements existing free-threading support (PEP 703) - Follows modern Python C API best practices - Future-proof for Python 3.14's InterpreterPoolExecutor 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace sys.exc_info() with modern exception handling using 'from' clause - Use text mode when opening files instead of binary mode with manual decode - Update BuildFailed to accept exception parameter for proper chaining These are internal improvements with no user-visible changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Convert the pure Python `maxminddb.reader.Metadata` class to use @DataClass(kw_only=True) for cleaner, more maintainable code. Changes: - Added dataclass import and decorator - Removed manual __init__ method (15+ lines of boilerplate) - Removed custom __repr__ method - Preserved @Property methods for node_byte_size and search_tree_size - All functionality remains identical Breaking change: The __repr__ format changes from `maxminddb.reader.Metadata(...)` to `Metadata(...)`. This is documented in HISTORY.rst. The C extension's Metadata class is unchanged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Add frozen=True to the Metadata dataclass to make all attributes readonly after creation. This prevents accidental modification of metadata that represents the immutable properties of a database file. Changes: - Added frozen=True to @DataClass decorator - Updated HISTORY.rst to document the breaking change - Noted that C extension Metadata has always been readonly Benefits: - Consistent behavior between pure Python and C extension - Prevents bugs from accidental metadata modification - Better represents the immutable nature of database metadata Breaking change: Attempting to modify Metadata attributes after creation will now raise an AttributeError. This brings the pure Python implementation into consistency with the C extension, which has always had readonly attributes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Convert the MODE_* constants to an IntEnum class for better type safety, IDE support, and more descriptive string representations. Changes: - Created Mode IntEnum with AUTO, MMAP_EXT, MMAP, FILE, MEMORY, FD members - Added comprehensive documentation for the Mode class and each member - Maintained backward compatibility by exporting old-style constants (MODE_AUTO, MODE_FILE, etc.) as aliases to enum members - Added __all__ to explicitly define the public API Benefits: - Better IDE autocomplete and type hints - Descriptive repr: <Mode.FILE: 4> instead of just 4 - Access to .name and .value attributes - Full backward compatibility (IntEnum is int-compatible) - Modern Python 3.10+ idiom - Inline documentation for each mode visible in source and IDEs Backward compatibility: All existing code continues to work unchanged. Both Mode.FILE and MODE_FILE can be used interchangeably, and all numeric comparisons work as before since IntEnum is int-compatible. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Convert RecordList and RecordDict from class-based type definitions to explicit TypeAlias declarations. These types are only used for type annotations and were never instantiated as actual classes, so using TypeAlias makes their purpose more explicit and follows modern Python typing conventions. Add explicit type annotation to Decoder._type_decoder ClassVar. This provides better type checking for the decoder function map by fully specifying the callable signature. These are internal changes with no user-visible effects. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Remove Jython-specific code from setup.py. Jython does not support Python 3.10+, making this code unreachable given the package's minimum Python version requirement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Replace hardcoded module metadata in maxminddb/__init__.py with importlib.metadata.version() to get the version from pyproject.toml. This eliminates duplication and makes pyproject.toml the single source of truth for package metadata. Changes: - Remove __title__, __author__, __license__, and __copyright__ from __init__.py (redundant with pyproject.toml) - Replace hardcoded __version__ with importlib.metadata.version() - Remove version reading from setup.py (setuptools gets it from pyproject.toml automatically) - Update dev-bin/release.sh to only update pyproject.toml version 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
34a31d9
to
5648f66
Compare
The old constants (``MODE_AUTO``, ``MODE_FILE``, etc.) remain available for | ||
backward compatibility and are now aliases to the enum members. This provides | ||
better IDE support and type safety while maintaining full backward | ||
compatibility. You can now use either ``Mode.FILE`` or ``MODE_FILE`` - both |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would we want to update the readme to suggest the former style?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you change that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gah, sorry, too many issues going at once. Pushed.
Updated the README to suggest using the new Mode enum style (e.g., Mode.FILE) instead of the old constant style (e.g., MODE_FILE). The old constants remain available for backward compatibility, but the enum provides better IDE support and type safety. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>