morphic 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,333 @@
1
+ Metadata-Version: 2.4
2
+ Name: morphic
3
+ Version: 0.1.0
4
+ Summary: Dynamic Python utilities for class registration, creation, and type checking
5
+ Author-email: Abhishek Divekar <adivekar@utexas.edu>
6
+ License-File: LICENSE
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.10.9
18
+ Requires-Dist: typing-extensions>=4.0.0
19
+ Provides-Extra: all
20
+ Requires-Dist: black>=23.0.0; extra == 'all'
21
+ Requires-Dist: mike>=2.0.0; extra == 'all'
22
+ Requires-Dist: mkdocs-material>=9.5.0; extra == 'all'
23
+ Requires-Dist: mkdocs>=1.6.0; extra == 'all'
24
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'all'
25
+ Requires-Dist: mypy>=1.0.0; extra == 'all'
26
+ Requires-Dist: pydantic>=2.0.0; extra == 'all'
27
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
28
+ Requires-Dist: pytest>=7.0.0; extra == 'all'
29
+ Requires-Dist: ruff>=0.1.0; extra == 'all'
30
+ Provides-Extra: dev
31
+ Requires-Dist: black>=23.0.0; extra == 'dev'
32
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
33
+ Requires-Dist: pydantic>=2.0.0; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
35
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
36
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
37
+ Provides-Extra: docs
38
+ Requires-Dist: mike>=2.0.0; extra == 'docs'
39
+ Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
40
+ Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
41
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
42
+ Description-Content-Type: text/markdown
43
+
44
+ # Morphic
45
+
46
+ [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://adivekar-utexas.github.io/morphic/)
47
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
48
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
49
+
50
+ Dynamic Python utilities for class registration, creation, and type checking.
51
+
52
+ ## Features
53
+
54
+ - **Registry**: Dynamic class registration and factory pattern for building extensible architectures
55
+ - **AutoEnum**: Automatic enumeration creation from class hierarchies with type safety
56
+ - **Typed**: Enhanced data modeling with validation and serialization capabilities
57
+
58
+ ## Installation
59
+
60
+ ### From PyPI
61
+
62
+ ```bash
63
+ pip install morphic
64
+ ```
65
+
66
+ ### From Source
67
+
68
+ ```bash
69
+ pip install git+https://github.com/adivekar-utexas/morphic.git
70
+ ```
71
+
72
+ ### Development Installation
73
+
74
+ ```bash
75
+ git clone https://github.com/adivekar-utexas/morphic.git
76
+ cd morphic
77
+
78
+ # Install with all dependencies (dev + docs)
79
+ pip install -e ".[all]"
80
+
81
+ # Or install specific dependency groups
82
+ pip install -e ".[dev]" # Development dependencies only
83
+ pip install -e ".[docs]" # Documentation dependencies only
84
+ pip install -e ".[dev,docs]" # Both dev and docs
85
+ ```
86
+
87
+ ## Quick Start
88
+
89
+ ### Registry System: Inheritance-Based Class Registration
90
+
91
+ ```python
92
+ from morphic import Registry
93
+ from abc import ABC, abstractmethod
94
+
95
+ # Create base registry class
96
+ class NotificationService(Registry, ABC):
97
+ @abstractmethod
98
+ def send(self, to: str, message: str) -> bool:
99
+ pass
100
+
101
+ # Classes automatically register when inheriting
102
+ class EmailService(NotificationService):
103
+ aliases = ["email", "mail"] # Multiple aliases supported
104
+
105
+ def __init__(self, smtp_server: str = "localhost"):
106
+ self.smtp_server = smtp_server
107
+
108
+ def send(self, to: str, message: str) -> bool:
109
+ print(f"Sending email to {to} via {self.smtp_server}")
110
+ return True
111
+
112
+ class SMSService(NotificationService):
113
+ aliases = ["sms", "text"]
114
+
115
+ def send(self, to: str, message: str) -> bool:
116
+ print(f"Sending SMS to {to}")
117
+ return True
118
+
119
+ # Hierarchical factory pattern - create instances through base class
120
+ email_service = NotificationService.of("EmailService", smtp_server="mail.example.com")
121
+ sms_service = NotificationService.of("sms") # Works with aliases too!
122
+
123
+ # Direct instantiation works for concrete classes
124
+ email_direct = EmailService.of(smtp_server="direct.mail.com")
125
+
126
+ # Use the services
127
+ email_service.send("user@example.com", "Hello!")
128
+ sms_service.send("+1234567890", "Hello!")
129
+ ```
130
+
131
+ ### AutoEnum: Ultra-Fast Fuzzy-Matching Enums
132
+
133
+ ```python
134
+ from morphic import AutoEnum, alias, auto
135
+ import json
136
+
137
+ # Create enum with fuzzy matching and aliases
138
+ class TaskStatus(AutoEnum):
139
+ PENDING = alias("waiting", "queued", "not_started")
140
+ RUNNING = alias("active", "in_progress", "executing")
141
+ COMPLETE = alias("done", "finished", "success")
142
+ FAILED = alias("error", "failure", "crashed")
143
+
144
+ # Fuzzy matching works with various formats
145
+ status1 = TaskStatus("pending") # Direct match
146
+ status2 = TaskStatus("IN PROGRESS") # Case insensitive + space handling
147
+ status3 = TaskStatus("not-started") # Alias with different formatting
148
+ status4 = TaskStatus("Done") # Alias with different case
149
+
150
+ # JSON compatibility (unlike standard enums!)
151
+ data = [TaskStatus.PENDING, TaskStatus.RUNNING]
152
+ json_str = json.dumps(data) # Works! -> '["PENDING", "RUNNING"]'
153
+ recovered = TaskStatus.convert_list(json.loads(json_str)) # Back to enums!
154
+
155
+ # Dynamic enum creation
156
+ Priority = AutoEnum.create("Priority", ["low", "medium", "high", "urgent"])
157
+ print(Priority.Low) # Low
158
+ print(Priority("MEDIUM")) # Medium (fuzzy matched)
159
+
160
+ # Perfect for configuration and user input
161
+ config_status = TaskStatus(user_input) # Handles "In Progress", "IN_PROGRESS", etc.
162
+ ```
163
+
164
+ ### Typed
165
+
166
+ ```python
167
+ from morphic import Typed
168
+ from typing import Optional, List
169
+
170
+ class User(Typed):
171
+ name: str
172
+ email: str
173
+ age: int
174
+ is_active: bool = True
175
+ bio: Optional[str] = None
176
+ tags: List[str] = [] # Default empty list
177
+
178
+ def validate(self):
179
+ if self.age < 0:
180
+ raise ValueError("Age must be non-negative")
181
+ if "@" not in self.email:
182
+ raise ValueError("Invalid email format")
183
+
184
+ # Instantiate like any class with auto type-conversion:
185
+ user = User(
186
+ name="Alice Johnson",
187
+ email="alice@example.com",
188
+ age="30", # String automatically converts to int
189
+ is_active="true", # String automatically converts to bool
190
+ tags=("python", "ai", "data"), # Tuple of strings converted to list of strings.
191
+ )
192
+ print(f"User: {user.name}, Age: {user.age} ({type(user.age)}), Tags: {user.tags}")
193
+ # Output:
194
+ # User: Alice Johnson, Age: 30 (<class 'int'>), Tags: ['python', 'ai', 'data']
195
+
196
+ # Create from dict:
197
+ user = User.from_dict({
198
+ "name": "Alice Johnson",
199
+ "email": "alice@example.com",
200
+ "age": "30", # String automatically converts to int
201
+ "is_active": "true", # String automatically converts to bool
202
+ "tags": ["python", "ai", "data"] # List of strings
203
+ })
204
+ print(f"User: {user.name}, Age: {user.age} ({type(user.age)}), Tags: {user.tags}")
205
+ # Output:
206
+ # Same as above.
207
+
208
+ # Hierarchical field handling for nested data
209
+ class Company(Typed):
210
+ name: str
211
+ employees: List[User] # Automatically converts dicts to User instances
212
+
213
+ company_data = {
214
+ "name": "TechCorp",
215
+ "employees": [
216
+ {"name": "Alice", "email": "alice@tech.com", "age": "30"},
217
+ {"name": "Bob", "email": "bob@tech.com", "age": "25"}
218
+ ]
219
+ }
220
+
221
+ company = Company.from_dict(company_data)
222
+ print(f"Company: {company.name}, Employees: {len(company.employees)}")
223
+ ```
224
+
225
+ ## Documentation
226
+
227
+ Comprehensive documentation is available at [https://adivekar.github.io/morphic/](https://adivekar.github.io/morphic/)
228
+
229
+ ### Building Documentation Locally
230
+
231
+ To build and serve the documentation locally:
232
+
233
+ ```bash
234
+ # Install documentation dependencies
235
+ pip install -e ".[docs]"
236
+
237
+ # Serve documentation locally
238
+ mkdocs serve
239
+ ```
240
+
241
+ The documentation will be available at http://localhost:8000
242
+
243
+ ### Documentation Structure
244
+
245
+ - **[User Guide](https://adivekar.github.io/morphic/user-guide/getting-started/)**: Comprehensive tutorials and examples
246
+ - **[API Reference](https://adivekar.github.io/morphic/api/)**: Detailed API documentation generated from docstrings
247
+ - **[Examples](https://adivekar.github.io/morphic/examples/)**: Real-world usage examples and patterns
248
+ - **[Contributing](https://adivekar.github.io/morphic/contributing/)**: Guidelines for contributors
249
+
250
+ ## Development
251
+
252
+ ### Setting Up Development Environment
253
+
254
+ 1. **Clone the repository**:
255
+ ```bash
256
+ git clone https://github.com/adivekar/morphic.git
257
+ cd morphic
258
+ ```
259
+
260
+ 2. **Create virtual environment**:
261
+ ```bash
262
+ python -m venv venv
263
+ source venv/bin/activate # On Windows: venv\Scripts\activate
264
+ ```
265
+
266
+ 3. **Install in development mode**:
267
+ ```bash
268
+ # Install all dependencies (recommended for contributors)
269
+ pip install -e ".[all]"
270
+
271
+ # Or install specific groups
272
+ pip install -e ".[dev]" # Just development tools
273
+ pip install -e ".[docs]" # Just documentation tools
274
+ ```
275
+
276
+ ### Running Tests
277
+
278
+ ```bash
279
+ # Run all tests
280
+ pytest
281
+
282
+ # Run with coverage
283
+ pytest --cov=morphic --cov-report=html
284
+
285
+ # Run specific test file
286
+ pytest tests/test_registry.py
287
+ ```
288
+
289
+ ### Code Quality
290
+
291
+ ```bash
292
+ # Format code
293
+ black src/ tests/
294
+
295
+ # Lint code
296
+ ruff check src/ tests/
297
+
298
+ # Type checking
299
+ mypy src/
300
+ ```
301
+
302
+ ### Documentation Deployment
303
+
304
+ Documentation is automatically deployed to GitHub Pages when changes are pushed to the main branch via GitHub Actions. The deployment workflow:
305
+
306
+ 1. **Builds documentation** using MkDocs with Material theme
307
+ 2. **Generates API documentation** automatically from docstrings using mkdocstrings
308
+ 3. **Deploys to GitHub Pages** at https://adivekar.github.io/morphic/
309
+
310
+ ## Performance
311
+
312
+ Morphic is optimized for production use:
313
+ - **AutoEnum**: 5.7M+ lookups/second with fuzzy matching
314
+ - **Registry**: O(1) class lookup with hierarchical inheritance
315
+ - **Typed**: Efficient type conversion with caching
316
+
317
+ ## Requirements
318
+
319
+ - Python 3.10.9 or higher
320
+ - typing-extensions >= 4.0.0
321
+
322
+ ## Contributing
323
+
324
+ We welcome contributions! Please see our [Contributing Guide](https://adivekar.github.io/morphic/contributing/) for details on:
325
+
326
+ - Setting up the development environment
327
+ - Running tests and quality checks
328
+ - Code style and documentation standards
329
+ - Pull request process
330
+
331
+ ## License
332
+
333
+ MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,8 @@
1
+ morphic/__init__.py,sha256=HzrUZ6uJDk6chMhHf9TxQcex_LPJ32a7rfAwFqxvf1Y,313
2
+ morphic/autoenum.py,sha256=1v31PMEyWkdVygsNkwSjpLZdHE99b3tVQDB371-k428,14887
3
+ morphic/registry.py,sha256=hT01NBkAYLVCvnU9A_NsrMFoc29q1zoICgh7PB6nmBE,38767
4
+ morphic/typed.py,sha256=b50sriDINA0Gtn5Pdd5-O1527PFNVDsWRzpYfEvUy2c,56218
5
+ morphic-0.1.0.dist-info/METADATA,sha256=-MPOE5oD7dV4_R4U9yDZ-Xmd00Kx9mgaHcgZEM0kiEs,10323
6
+ morphic-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ morphic-0.1.0.dist-info/licenses/LICENSE,sha256=Fu83sfpznMNp6N5-PYx62oGz7AhwUOgI7dWuRL-Hh3M,1072
8
+ morphic-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Abhishek Divekar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.