Skip to content

Commit fef1e0d

Browse files
committed
update docs, prepare bump version.
1 parent 565d24c commit fef1e0d

File tree

4 files changed

+291
-1
lines changed

4 files changed

+291
-1
lines changed

docs/source/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Structs
88

99
.. autoclass:: Struct
1010

11+
.. autoclass:: StructMeta
12+
1113
.. autofunction:: field
1214

1315
.. autofunction:: defstruct

docs/source/changelog.rst

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,90 @@ Changelog
33

44
.. currentmodule:: msgspec
55

6+
Version 0.20.0 (2025-01-03)
7+
---------------------------
8+
9+
**🎉 MAJOR: Community Fork Release**
10+
11+
This is the first release of ``msgspec-x``, a community-driven fork of the original msgspec library by Jim Crist-Harif. This fork was created to accelerate community contributions and provide a platform for extended features while maintaining full backward compatibility.
12+
13+
**🚀 NEW MAJOR FEATURE: StructMeta Subclasses Support**
14+
15+
- **Add comprehensive support for StructMeta subclasses** - the primary feature that motivated this fork.
16+
- Enable custom metaclasses that inherit from `StructMeta` to work seamlessly with all msgspec functions.
17+
- **TECHNICAL**: Modified C code to use `PyType_IsSubtype()` instead of direct type comparison for StructMeta detection.
18+
- Affected functions now support StructMeta subclasses:
19+
20+
- `msgspec.structs.asdict` - Convert struct instances to dictionaries
21+
- `msgspec.structs.astuple` - Convert struct instances to tuples
22+
- `msgspec.structs.replace` - Create modified copies of struct instances
23+
- `msgspec.structs.force_setattr` - Force attribute setting on frozen structs
24+
- JSON encoding/decoding operations
25+
- MessagePack encoding/decoding operations
26+
- `msgspec.convert` - Type conversion operations
27+
- `msgspec.to_builtins` - Convert to builtin types
28+
29+
- Comprehensive test coverage for StructMeta subclasses including:
30+
31+
- Single-level StructMeta inheritance
32+
- Multi-level StructMeta inheritance chains
33+
- Integration with all struct utility functions
34+
- Encoder/decoder compatibility testing
35+
- Nested struct support with custom metaclasses
36+
37+
- **Use Cases**: This enables advanced users to create custom struct behaviors through metaclass programming while maintaining full compatibility with msgspec's serialization ecosystem.
38+
39+
**Project Rename and Fork**
40+
41+
- **BREAKING**: Project renamed from ``msgspec`` to ``msgspec-x``. Do not install both packages simultaneously.
42+
- Fork created due to slow upstream maintenance and to enable faster community contribution cycles.
43+
- All project metadata, URLs, and documentation updated to reflect the new ``msgspec-x`` identity.
44+
- Repository moved to ``https://github.com/nightsailer/msgspec-x``.
45+
- Maintainer changed to Night Sailer (nightsailer@gmail.com).
46+
47+
**Dual Namespace Architecture**
48+
49+
- Introduce dual namespace architecture to support both compatibility and extensions:
50+
51+
- ``msgspec`` namespace: 100% API compatibility with the original library for drop-in replacement.
52+
- ``msgspec_x`` namespace: Extended features and community contributions (placeholder structure created).
53+
54+
- All existing code using ``import msgspec`` will continue to work without changes.
55+
- New extended features will be available under ``msgspec_x`` namespace.
56+
57+
**Installation and Distribution**
58+
59+
- Package name changed to ``msgspec-x`` on PyPI.
60+
- Updated installation commands: ``pip install msgspec-x`` and ``conda install msgspec-x -c conda-forge``.
61+
- Added clear warnings about not installing both ``msgspec`` and ``msgspec-x`` in the same environment.
62+
- Updated versioneer configuration to use ``msgspec-x-`` prefix for source distributions.
63+
64+
**Documentation Overhaul**
65+
66+
- Comprehensive documentation update to reflect the project fork and new architecture.
67+
- Added explanation of the dual namespace system and community-driven development model.
68+
- Updated all GitHub links, issue tracker URLs, and example source references.
69+
- Enhanced installation documentation with compatibility warnings.
70+
- Updated contributing guidelines and security policies for the new project structure.
71+
72+
**Community and Development**
73+
74+
- Established faster review and merge cycles for community contributions.
75+
- Updated GitHub issue templates and workflows for the new repository.
76+
- Created placeholder structure for experimental features in ``msgspec_x`` namespace.
77+
- Enhanced project documentation to welcome community contributions.
78+
79+
**Technical Infrastructure**
80+
81+
- Updated build configuration (``setup.py``, ``setup.cfg``, ``MANIFEST.in``) for the new package structure.
82+
- Enhanced CI/CD workflows for the dual namespace architecture.
83+
- Updated type stub files and package metadata for both namespaces.
84+
- Maintained all existing performance characteristics and API compatibility.
85+
86+
**Acknowledgments**
87+
88+
This release acknowledges and thanks Jim Crist-Harif for creating the original msgspec library. This fork exists to complement and extend his excellent work, not to replace it.
89+
690
Version 0.19.0 (2024-12-27)
791
---------------------------
892

docs/source/index.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ support for JSON_, MessagePack_, YAML_, and TOML_. It features:
2525
use dataclasses_ or attrs_, :doc:`structs` should feel familiar. However,
2626
they're :ref:`5-60x <struct-benchmark>` faster for common operations.
2727

28+
- 🆕 **StructMeta subclasses support** for advanced metaclass programming.
29+
Create custom struct behaviors while maintaining full compatibility with
30+
all msgspec operations. See :ref:`struct-meta-subclasses` for details.
31+
2832
All of this is included in a :ref:`lightweight library
2933
<benchmark-library-size>` with no required dependencies.
3034

@@ -101,6 +105,11 @@ Highlights
101105
compliant with their respective specifications, providing stronger guarantees
102106
of compatibility with other systems.
103107

108+
- ``msgspec-x`` is **extensible**. The new :ref:`StructMeta subclasses
109+
<struct-meta-subclasses>` support enables advanced users to create custom
110+
struct behaviors through metaclass programming while maintaining full
111+
compatibility with all msgspec operations.
112+
104113
Used By
105114
-------
106115

@@ -201,4 +210,4 @@ few:
201210

202211
api.rst
203212
examples/index.rst
204-
changelog.rst
213+
changelog.rst

docs/source/structs.rst

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,201 @@ container types. It is your responsibility to ensure cycles with these objects
998998
don't occur, as a cycle containing only ``gc=False`` structs will *never* be
999999
collected (leading to a memory leak).
10001000

1001+
1002+
.. _struct-meta-subclasses:
1003+
1004+
StructMeta Subclasses (Advanced)
1005+
-------------------------------
1006+
1007+
.. versionadded:: 0.20.0
1008+
1009+
``msgspec-x`` provides comprehensive support for custom metaclasses that inherit from `msgspec.StructMeta`. This advanced feature enables users to create custom struct behaviors through metaclass programming while maintaining full compatibility with msgspec's serialization ecosystem.
1010+
1011+
**What are StructMeta Subclasses?**
1012+
1013+
StructMeta subclasses allow you to extend or customize the behavior of struct creation and management by defining your own metaclass that inherits from `msgspec.StructMeta`. This enables advanced patterns like:
1014+
1015+
- Adding custom validation logic during struct class creation
1016+
- Implementing custom field processing or transformation
1017+
- Integrating with external frameworks or ORMs
1018+
- Creating domain-specific struct variants with specialized behaviors
1019+
1020+
**Basic Usage**
1021+
1022+
Here's a simple example of creating and using a custom StructMeta subclass:
1023+
1024+
.. code-block:: python
1025+
1026+
>>> import msgspec
1027+
>>> from msgspec import StructMeta
1028+
1029+
>>> class CustomMeta(StructMeta):
1030+
... """A custom metaclass that extends StructMeta"""
1031+
... def __new__(cls, name, bases, namespace):
1032+
... # Custom logic during class creation
1033+
... print(f"Creating struct class: {name}")
1034+
... return super().__new__(cls, name, bases, namespace)
1035+
1036+
>>> class CustomStruct(metaclass=CustomMeta):
1037+
... x: int
1038+
... y: str
1039+
... z: float = 3.14
1040+
Creating struct class: CustomStruct
1041+
1042+
>>> # Instances work exactly like regular structs
1043+
... obj = CustomStruct(x=42, y="hello")
1044+
>>> obj
1045+
CustomStruct(x=42, y='hello', z=3.14)
1046+
1047+
**Full Compatibility with msgspec Functions**
1048+
1049+
Structures created with StructMeta subclasses work seamlessly with all msgspec operations:
1050+
1051+
.. code-block:: python
1052+
1053+
>>> from msgspec.structs import asdict, astuple, replace, force_setattr
1054+
1055+
>>> # All struct utility functions work
1056+
>>> asdict(obj)
1057+
{'x': 42, 'y': 'hello', 'z': 3.14}
1058+
1059+
>>> astuple(obj)
1060+
(42, 'hello', 3.14)
1061+
1062+
>>> replace(obj, x=100)
1063+
CustomStruct(x=100, y='hello', z=3.14)
1064+
1065+
>>> # JSON encoding/decoding works
1066+
>>> import msgspec.json
1067+
>>> data = msgspec.json.encode(obj)
1068+
>>> msgspec.json.decode(data, type=CustomStruct)
1069+
CustomStruct(x=42, y='hello', z=3.14)
1070+
1071+
>>> # MessagePack encoding/decoding works
1072+
>>> import msgspec.msgpack
1073+
>>> data = msgspec.msgpack.encode(obj)
1074+
>>> msgspec.msgpack.decode(data, type=CustomStruct)
1075+
CustomStruct(x=42, y='hello', z=3.14)
1076+
1077+
>>> # Type conversion works
1078+
>>> msgspec.convert({'x': 1, 'y': 'test', 'z': 2.5}, type=CustomStruct)
1079+
CustomStruct(x=1, y='test', z=2.5)
1080+
1081+
**Multi-Level Inheritance**
1082+
1083+
StructMeta subclasses support inheritance chains, allowing for sophisticated metaclass hierarchies:
1084+
1085+
.. code-block:: python
1086+
1087+
>>> class BaseMeta(StructMeta):
1088+
... """Base custom metaclass"""
1089+
... pass
1090+
1091+
>>> class DerivedMeta(BaseMeta):
1092+
... """Derived custom metaclass"""
1093+
... def __new__(cls, name, bases, namespace):
1094+
... # Add custom behavior
1095+
... result = super().__new__(cls, name, bases, namespace)
1096+
... result._custom_attribute = f"Enhanced {name}"
1097+
... return result
1098+
1099+
>>> class EnhancedStruct(metaclass=DerivedMeta):
1100+
... value: int
1101+
... name: str
1102+
1103+
>>> obj = EnhancedStruct(value=123, name="test")
1104+
>>> obj._custom_attribute
1105+
'Enhanced EnhancedStruct'
1106+
1107+
>>> # All msgspec functions still work
1108+
>>> asdict(obj)
1109+
{'value': 123, 'name': 'test'}
1110+
1111+
**Nested Structures**
1112+
1113+
StructMeta subclasses work correctly with nested structures and complex serialization scenarios:
1114+
1115+
.. code-block:: python
1116+
1117+
>>> class ContainerMeta(StructMeta):
1118+
... """Metaclass for container structures"""
1119+
... pass
1120+
1121+
>>> class Item(metaclass=ContainerMeta):
1122+
... id: int
1123+
... name: str
1124+
1125+
>>> class Container(metaclass=ContainerMeta):
1126+
... items: list[Item]
1127+
... count: int
1128+
1129+
>>> container = Container(
1130+
... items=[Item(id=1, name="first"), Item(id=2, name="second")],
1131+
... count=2
1132+
... )
1133+
1134+
>>> # Complex nested encoding/decoding works
1135+
>>> data = msgspec.json.encode(container)
1136+
>>> decoded = msgspec.json.decode(data, type=Container)
1137+
>>> decoded.items[0].name
1138+
'first'
1139+
1140+
**Integration with Struct Options**
1141+
1142+
StructMeta subclasses work with all struct configuration options:
1143+
1144+
.. code-block:: python
1145+
1146+
>>> class FrozenMeta(StructMeta):
1147+
... """Metaclass for immutable structures"""
1148+
... pass
1149+
1150+
>>> class ImmutablePoint(metaclass=FrozenMeta, frozen=True, order=True):
1151+
... x: float
1152+
... y: float
1153+
1154+
>>> p1 = ImmutablePoint(1.0, 2.0)
1155+
>>> p2 = ImmutablePoint(3.0, 4.0)
1156+
1157+
>>> # Frozen behavior works
1158+
>>> try:
1159+
... p1.x = 5.0
1160+
... except AttributeError as e:
1161+
... print(f"Expected error: {e}")
1162+
Expected error: immutable type: 'ImmutablePoint'
1163+
1164+
>>> # Ordering works
1165+
>>> p1 < p2
1166+
True
1167+
1168+
>>> # All msgspec functions work
1169+
>>> replace(p1, x=10.0)
1170+
ImmutablePoint(x=10.0, y=2.0)
1171+
1172+
**Technical Implementation**
1173+
1174+
``msgspec-x`` achieves StructMeta subclass support by modifying the core C implementation to use `PyType_IsSubtype()` checks instead of direct type comparisons. This change affects all core msgspec operations including:
1175+
1176+
- Type validation during encoding/decoding
1177+
- Struct utility functions (asdict, astuple, replace, etc.)
1178+
- Type conversion operations
1179+
- Tagged union resolution
1180+
- Performance optimizations
1181+
1182+
The implementation maintains full backward compatibility - existing code continues to work unchanged, while new code can take advantage of the enhanced metaclass support.
1183+
1184+
**Use Cases**
1185+
1186+
StructMeta subclasses enable advanced patterns such as:
1187+
1188+
- **Framework Integration**: Creating structs that automatically integrate with web frameworks, ORMs, or validation libraries
1189+
- **Domain-Specific Languages**: Building specialized struct types for specific problem domains
1190+
- **Automatic Documentation**: Metaclasses that generate documentation or schema information
1191+
- **Validation Enhancement**: Adding complex validation logic at the class level
1192+
- **Serialization Customization**: Implementing custom serialization behaviors for specific use cases
1193+
1194+
This feature is particularly valuable for library authors who want to build higher-level abstractions on top of msgspec's fast serialization capabilities.
1195+
10011196
.. _type annotations: https://docs.python.org/3/library/typing.html
10021197
.. _pattern matching: https://docs.python.org/3/reference/compound_stmts.html#the-match-statement
10031198
.. _PEP 636: https://peps.python.org/pep-0636/

0 commit comments

Comments
 (0)