Name | registro JSON |
Version |
0.2.2
JSON |
| download |
home_page | None |
Summary | Resource-based model system for SQLModel with automatic Resource creation and validation |
upload_time | 2025-10-13 20:54:04 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | MIT |
keywords |
models
pydantic
resources
sqlalchemy
sqlmodel
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Registro
[](https://badge.fury.io/py/registro)
[](https://pypi.org/project/registro/)
[](https://opensource.org/licenses/MIT)
## Overview
Registro is a resource management framework for Python applications that provides structured resource identification, validation, and lifecycle management. Built on SQLModel, it offers a consistent approach to defining, creating, and interacting with resources across applications and services.
## Key Features
- **Resource Identifiers (RIDs)**: Globally unique, structured identifiers (`{prefix}.{service}.{instance}.{resource_type}.{id}`) for all resources.
- **Configurable Validation:** Customize regex patterns and reserved words for RIDs and API names via settings or environment variables.
- **Dual Implementation Approaches**: Support for both decorator-based (`@resource`) and inheritance-based (`ResourceTypeBaseModel`) implementation.
- **SQLModel Integration**: Seamless integration with SQLModel and SQLAlchemy for database operations.
- **Validation**: Field and pattern validation through Pydantic using the configured rules.
- **Type Safety**: Comprehensive type hints for improved IDE support and runtime type checking.
- **Status Management**: Built-in resource status tracking with customizable status values.
- **Relationship Handling**: Tools for defining and navigating resource relationships.
- **Metadata Management**: Automatic tracking of creation, update, and lifecycle events.
- **Relationship Helpers**: Simplified resource linking and relationship management.
- **Enhanced Serialization**: Comprehensive `to_dict()` method with relationship support.
## Installation
### Standard Installation
```bash
pip install registro
```
### With Rye (Recommended)
```bash
rye add registro
```
## Configuration
Registro allows customization of default behaviors, validation patterns, and reserved words through the `registro.config.settings` object or environment variables. Configuration should typically be done **before** defining or importing your resource models.
**Precedence:** Environment variables override programmatic settings, which override library defaults.
**Configurable Items:**
1. **RID Prefix:**
* `settings.RID_PREFIX = "myprefix"`
* `export REGISTRO_RID_PREFIX="myprefix"` (Default: "ri")
2. **Default Service & Instance:**
* `settings.DEFAULT_SERVICE = "my-service"`
* `settings.DEFAULT_INSTANCE = "staging"`
* `export REGISTRO_DEFAULT_SERVICE="my-service"`
* `export REGISTRO_DEFAULT_INSTANCE="staging"` (Defaults: "default", "prod")
3. **Reserved Words:**
* `settings.RESERVED_WORDS = {"internal", "system", "config"}`
* `export REGISTRO_RESERVED_WORDS="internal,system,config"` (See `models/patterns.py` for defaults)
4. **Validation Patterns:** Define the regex used for validating RID components and API names.
* `settings.set_pattern("SERVICE", r"^[a-z]{3,10}$")` # Override service pattern
* `settings.set_pattern("API_NAME_OBJECT_TYPE", r"^[A-Z][a-zA-Z]*$")` # Override object type API name pattern
* `export REGISTRO_PATTERN_SERVICE="^[a-z]{3,10}$"`
* `export REGISTRO_PATTERN_API_NAME_OBJECT_TYPE="^[A-Z][a-zA-Z]*$"`
* *Pattern Names (used in `set_pattern` and env vars):* `RID_PREFIX`, `SERVICE`, `INSTANCE`, `TYPE`, `LOCATOR`, `API_NAME_OBJECT_TYPE`, `API_NAME_LINK_TYPE`, `API_NAME_ACTION_TYPE`, `API_NAME_QUERY_TYPE`. (See `config/settings.py` for defaults).
5. **API Name Pattern Mapping:** Map specific `resource_type` strings to the *name* of the pattern used for their `api_name` validation.
* ```python
settings.API_NAME_PATTERNS_BY_TYPE = {
"object-type": "API_NAME_OBJECT_TYPE", # Default mapping
"link-type": "API_NAME_LINK_TYPE", # Default mapping
"my-custom-type": "MY_CUSTOM_PATTERN_NAME", # Custom mapping
"default": "API_NAME_ACTION_TYPE" # Fallback pattern name
}
# Ensure "MY_CUSTOM_PATTERN_NAME" is also set via settings.set_pattern()
settings.set_pattern("MY_CUSTOM_PATTERN_NAME", r"^[a-z_]+$")
```
* `export REGISTRO_API_NAME_MAPPING='{"my-custom-type": "MY_CUSTOM_PATTERN_NAME"}'` (Overrides are merged with defaults).
## Usage
Registro offers two implementation approaches: inheritance-based and decorator-based.
### Inheritance Approach
Extend `ResourceTypeBaseModel` for explicit control and reliability when running scripts directly:
```python
from registro import ResourceTypeBaseModel
from sqlmodel import Field, Session, SQLModel, create_engine
class Book(ResourceTypeBaseModel, table=True):
__resource_type__ = "book" # Used in RID generation & API name validation mapping
# Define fields
title: str = Field()
author: str = Field()
# Optionally specify service and instance in constructor (overrides settings defaults)
def __init__(self, **data):
# You can pass service and instance directly to constructor
super().__init__(**data) # Handles setting _service and _instance
```
### Decorator Approach
Use the `@resource` decorator for a cleaner, more concise syntax:
```python
from registro import resource
from sqlmodel import Field
@resource(
resource_type="book", # Explicitly set resource type
service="library", # Optional: Override settings.DEFAULT_SERVICE
instance="main" # Optional: Override settings.DEFAULT_INSTANCE
)
class Book:
title: str = Field(...)
author: str = Field(...)
```
## Relationship Management
ResourceTypeBaseModel provides powerful relationship management tools:
```python
from typing import List, Optional
from registro import ResourceTypeBaseModel
from sqlmodel import Field, Relationship, Session
# Define models with relationships
class Author(ResourceTypeBaseModel, table=True):
__resource_type__ = "author"
name: str = Field()
books: List["Book"] = Relationship(back_populates="author")
class Book(ResourceTypeBaseModel, table=True):
__resource_type__ = "book"
title: str = Field()
author_rid: Optional[str] = Field(default=None, foreign_key="author.rid", index=True)
author_api_name: Optional[str] = Field(default=None, index=True) # Optional, for convenience
author: Optional[Author] = Relationship(back_populates="books")
def link_author(self, session: Session, author: Optional[Author] = None,
author_rid: Optional[str] = None, author_api_name: Optional[str] = None) -> Author:
"""Link to author using enhanced link_resource helper."""
# Example: Link by API name
return self.link_resource(
session=session,
resource=author, # Optional: pass fetched resource directly
model_class=Author,
rid_field="author_rid", # Field on Book to store Author's RID
api_name_field="author_api_name", # Field on Book to store Author's API name
rid_value=author_rid, # Optional: find author by RID
api_name_value=author_api_name # Optional: find author by API name
)
```
## Examples
See the `examples/` directory for complete working examples:
- **Basic Usage**: Simple resource creation and querying using both approaches.
- **Custom Resources**: Advanced resource types with relationships, custom base classes, and custom status values.
- **Integration Example**: Demonstrates using Registro with FastAPI.
## Advanced Features
### Resource Relationships
ResourceTypeBaseModel includes helper methods for relationship management:
```python
# Find related resources by RID or API name
related_author = book.get_related_resource(
Author,
api_name="john-doe",
session=session
)
# Link resources with a single method call
author = book.link_author(session=session, author_api_name="jane-roe")
```
### Data Serialization
Enhanced serialization with the `to_dict()` method, including RID components:
```python
# Get a dictionary representation of a resource
book_dict = book.to_dict()
print(book_dict["rid"]) # Full Resource ID (e.g., ri.library.main.book.ulid)
print(book_dict["service"]) # Service name (e.g., 'library')
print(book_dict["instance"]) # Instance name (e.g., 'main')
print(book_dict["resource_type"])# Resource type (e.g., 'book')
print(book_dict["resource_id"]) # ULID locator part
print(book_dict["title"]) # Model field
```
### Field Validation
Utility methods for common validation tasks:
```python
from pydantic import field_validator
class Department(ResourceTypeBaseModel, table=True):
# ...
code: str = Field()
@field_validator("code")
@classmethod
def validate_code(cls, v):
# Use built-in identifier validation
return cls.validate_identifier(v, "Department code")
# In another model or logic:
# Validate relationships
# employee.validate_related_field_match(department, "status", "ACTIVE")
```
Raw data
{
"_id": null,
"home_page": null,
"name": "registro",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "models, pydantic, resources, sqlalchemy, sqlmodel",
"author": null,
"author_email": "Kevin Saltarelli <kevinqz@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/06/57/e63153b7eff3f649bbaf0c179a09c18419943ab0928a5e9d40c841d11654/registro-0.2.2.tar.gz",
"platform": null,
"description": "# Registro\n\n[](https://badge.fury.io/py/registro)\n[](https://pypi.org/project/registro/)\n[](https://opensource.org/licenses/MIT)\n\n## Overview\n\nRegistro is a resource management framework for Python applications that provides structured resource identification, validation, and lifecycle management. Built on SQLModel, it offers a consistent approach to defining, creating, and interacting with resources across applications and services.\n\n## Key Features\n\n- **Resource Identifiers (RIDs)**: Globally unique, structured identifiers (`{prefix}.{service}.{instance}.{resource_type}.{id}`) for all resources.\n- **Configurable Validation:** Customize regex patterns and reserved words for RIDs and API names via settings or environment variables.\n- **Dual Implementation Approaches**: Support for both decorator-based (`@resource`) and inheritance-based (`ResourceTypeBaseModel`) implementation.\n- **SQLModel Integration**: Seamless integration with SQLModel and SQLAlchemy for database operations.\n- **Validation**: Field and pattern validation through Pydantic using the configured rules.\n- **Type Safety**: Comprehensive type hints for improved IDE support and runtime type checking.\n- **Status Management**: Built-in resource status tracking with customizable status values.\n- **Relationship Handling**: Tools for defining and navigating resource relationships.\n- **Metadata Management**: Automatic tracking of creation, update, and lifecycle events.\n- **Relationship Helpers**: Simplified resource linking and relationship management.\n- **Enhanced Serialization**: Comprehensive `to_dict()` method with relationship support.\n\n## Installation\n\n### Standard Installation\n\n```bash\npip install registro\n```\n\n### With Rye (Recommended)\n\n```bash\nrye add registro\n```\n\n## Configuration\n\nRegistro allows customization of default behaviors, validation patterns, and reserved words through the `registro.config.settings` object or environment variables. Configuration should typically be done **before** defining or importing your resource models.\n\n**Precedence:** Environment variables override programmatic settings, which override library defaults.\n\n**Configurable Items:**\n\n1. **RID Prefix:**\n * `settings.RID_PREFIX = \"myprefix\"`\n * `export REGISTRO_RID_PREFIX=\"myprefix\"` (Default: \"ri\")\n2. **Default Service & Instance:**\n * `settings.DEFAULT_SERVICE = \"my-service\"`\n * `settings.DEFAULT_INSTANCE = \"staging\"`\n * `export REGISTRO_DEFAULT_SERVICE=\"my-service\"`\n * `export REGISTRO_DEFAULT_INSTANCE=\"staging\"` (Defaults: \"default\", \"prod\")\n3. **Reserved Words:**\n * `settings.RESERVED_WORDS = {\"internal\", \"system\", \"config\"}`\n * `export REGISTRO_RESERVED_WORDS=\"internal,system,config\"` (See `models/patterns.py` for defaults)\n4. **Validation Patterns:** Define the regex used for validating RID components and API names.\n * `settings.set_pattern(\"SERVICE\", r\"^[a-z]{3,10}$\")` # Override service pattern\n * `settings.set_pattern(\"API_NAME_OBJECT_TYPE\", r\"^[A-Z][a-zA-Z]*$\")` # Override object type API name pattern\n * `export REGISTRO_PATTERN_SERVICE=\"^[a-z]{3,10}$\"`\n * `export REGISTRO_PATTERN_API_NAME_OBJECT_TYPE=\"^[A-Z][a-zA-Z]*$\"`\n * *Pattern Names (used in `set_pattern` and env vars):* `RID_PREFIX`, `SERVICE`, `INSTANCE`, `TYPE`, `LOCATOR`, `API_NAME_OBJECT_TYPE`, `API_NAME_LINK_TYPE`, `API_NAME_ACTION_TYPE`, `API_NAME_QUERY_TYPE`. (See `config/settings.py` for defaults).\n5. **API Name Pattern Mapping:** Map specific `resource_type` strings to the *name* of the pattern used for their `api_name` validation.\n * ```python\n settings.API_NAME_PATTERNS_BY_TYPE = {\n \"object-type\": \"API_NAME_OBJECT_TYPE\", # Default mapping\n \"link-type\": \"API_NAME_LINK_TYPE\", # Default mapping\n \"my-custom-type\": \"MY_CUSTOM_PATTERN_NAME\", # Custom mapping\n \"default\": \"API_NAME_ACTION_TYPE\" # Fallback pattern name\n }\n # Ensure \"MY_CUSTOM_PATTERN_NAME\" is also set via settings.set_pattern()\n settings.set_pattern(\"MY_CUSTOM_PATTERN_NAME\", r\"^[a-z_]+$\")\n ```\n * `export REGISTRO_API_NAME_MAPPING='{\"my-custom-type\": \"MY_CUSTOM_PATTERN_NAME\"}'` (Overrides are merged with defaults).\n\n## Usage\n\nRegistro offers two implementation approaches: inheritance-based and decorator-based.\n\n### Inheritance Approach\n\nExtend `ResourceTypeBaseModel` for explicit control and reliability when running scripts directly:\n\n```python\nfrom registro import ResourceTypeBaseModel\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\nclass Book(ResourceTypeBaseModel, table=True):\n __resource_type__ = \"book\" # Used in RID generation & API name validation mapping\n\n # Define fields\n title: str = Field()\n author: str = Field()\n\n # Optionally specify service and instance in constructor (overrides settings defaults)\n def __init__(self, **data):\n # You can pass service and instance directly to constructor\n super().__init__(**data) # Handles setting _service and _instance\n```\n\n### Decorator Approach\n\nUse the `@resource` decorator for a cleaner, more concise syntax:\n\n```python\nfrom registro import resource\nfrom sqlmodel import Field\n\n@resource(\n resource_type=\"book\", # Explicitly set resource type\n service=\"library\", # Optional: Override settings.DEFAULT_SERVICE\n instance=\"main\" # Optional: Override settings.DEFAULT_INSTANCE\n)\nclass Book:\n title: str = Field(...)\n author: str = Field(...)\n```\n\n## Relationship Management\n\nResourceTypeBaseModel provides powerful relationship management tools:\n\n```python\nfrom typing import List, Optional\nfrom registro import ResourceTypeBaseModel\nfrom sqlmodel import Field, Relationship, Session\n\n# Define models with relationships\nclass Author(ResourceTypeBaseModel, table=True):\n __resource_type__ = \"author\"\n name: str = Field()\n books: List[\"Book\"] = Relationship(back_populates=\"author\")\n\nclass Book(ResourceTypeBaseModel, table=True):\n __resource_type__ = \"book\"\n title: str = Field()\n author_rid: Optional[str] = Field(default=None, foreign_key=\"author.rid\", index=True)\n author_api_name: Optional[str] = Field(default=None, index=True) # Optional, for convenience\n author: Optional[Author] = Relationship(back_populates=\"books\")\n\n def link_author(self, session: Session, author: Optional[Author] = None,\n author_rid: Optional[str] = None, author_api_name: Optional[str] = None) -> Author:\n \"\"\"Link to author using enhanced link_resource helper.\"\"\"\n # Example: Link by API name\n return self.link_resource(\n session=session,\n resource=author, # Optional: pass fetched resource directly\n model_class=Author,\n rid_field=\"author_rid\", # Field on Book to store Author's RID\n api_name_field=\"author_api_name\", # Field on Book to store Author's API name\n rid_value=author_rid, # Optional: find author by RID\n api_name_value=author_api_name # Optional: find author by API name\n )\n```\n\n## Examples\n\nSee the `examples/` directory for complete working examples:\n\n- **Basic Usage**: Simple resource creation and querying using both approaches.\n- **Custom Resources**: Advanced resource types with relationships, custom base classes, and custom status values.\n- **Integration Example**: Demonstrates using Registro with FastAPI.\n\n## Advanced Features\n\n### Resource Relationships\n\nResourceTypeBaseModel includes helper methods for relationship management:\n\n```python\n# Find related resources by RID or API name\nrelated_author = book.get_related_resource(\n Author,\n api_name=\"john-doe\",\n session=session\n)\n\n# Link resources with a single method call\nauthor = book.link_author(session=session, author_api_name=\"jane-roe\")\n```\n\n### Data Serialization\n\nEnhanced serialization with the `to_dict()` method, including RID components:\n\n```python\n# Get a dictionary representation of a resource\nbook_dict = book.to_dict()\nprint(book_dict[\"rid\"]) # Full Resource ID (e.g., ri.library.main.book.ulid)\nprint(book_dict[\"service\"]) # Service name (e.g., 'library')\nprint(book_dict[\"instance\"]) # Instance name (e.g., 'main')\nprint(book_dict[\"resource_type\"])# Resource type (e.g., 'book')\nprint(book_dict[\"resource_id\"]) # ULID locator part\nprint(book_dict[\"title\"]) # Model field\n```\n\n### Field Validation\n\nUtility methods for common validation tasks:\n\n```python\nfrom pydantic import field_validator\n\nclass Department(ResourceTypeBaseModel, table=True):\n # ...\n code: str = Field()\n\n @field_validator(\"code\")\n @classmethod\n def validate_code(cls, v):\n # Use built-in identifier validation\n return cls.validate_identifier(v, \"Department code\")\n\n# In another model or logic:\n# Validate relationships\n# employee.validate_related_field_match(department, \"status\", \"ACTIVE\")\n```",
"bugtrack_url": null,
"license": "MIT",
"summary": "Resource-based model system for SQLModel with automatic Resource creation and validation",
"version": "0.2.2",
"project_urls": {
"Bug Tracker": "https://github.com/simbolico/registro/issues",
"Documentation": "https://simbolico.github.io/registro",
"Homepage": "https://github.com/simbolico/registro",
"Source Code": "https://github.com/simbolico/registro"
},
"split_keywords": [
"models",
" pydantic",
" resources",
" sqlalchemy",
" sqlmodel"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "279b2cdcceb36008a2c2511605ade6b5903b5a1eda84776827520fb6fd275849",
"md5": "95bf49727bd4fd7f04d4a122ddbcaa1c",
"sha256": "e50ae06af98d36b1995230a889a40e11b2144075294156a5e06c94e5becb5124"
},
"downloads": -1,
"filename": "registro-0.2.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "95bf49727bd4fd7f04d4a122ddbcaa1c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 27617,
"upload_time": "2025-10-13T20:54:01",
"upload_time_iso_8601": "2025-10-13T20:54:01.541456Z",
"url": "https://files.pythonhosted.org/packages/27/9b/2cdcceb36008a2c2511605ade6b5903b5a1eda84776827520fb6fd275849/registro-0.2.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "0657e63153b7eff3f649bbaf0c179a09c18419943ab0928a5e9d40c841d11654",
"md5": "069ec44058766c8ad77d73f989fbdd78",
"sha256": "1351d74957d28efc60ec51f9a1bfefde77d4306ec5cb68371362c6dbf1f17f21"
},
"downloads": -1,
"filename": "registro-0.2.2.tar.gz",
"has_sig": false,
"md5_digest": "069ec44058766c8ad77d73f989fbdd78",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 36367,
"upload_time": "2025-10-13T20:54:04",
"upload_time_iso_8601": "2025-10-13T20:54:04.645531Z",
"url": "https://files.pythonhosted.org/packages/06/57/e63153b7eff3f649bbaf0c179a09c18419943ab0928a5e9d40c841d11654/registro-0.2.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-13 20:54:04",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "simbolico",
"github_project": "registro",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "registro"
}