Repository URL to install this package:
|
Version:
3.0.5 ▾
|
| sincpro_framework |
| LICENSE.md |
| README.md |
| pyproject.toml |
| PKG-INFO |
Here's a quick example to get you started with the Sincpro Framework:
from sincpro_framework import UseFramework, Feature, DataTransferObject # 1. Initialize the framework framework = UseFramework("cybersource") # 2. Add Dependencies (Example dependencies) from sincpro_framework import Database db = Database() framework.add_dependency("db", db) # 3. Error Handler (Optional, use the built-in error handling feature) framework.set_global_error_handler(lambda e: print(f"Error: {e}")) # 4. Create a Use Case with DTOs class GreetingParams(DataTransferObject): name: str @framework.feature(GreetingParams) class GreetingFeature(Feature): def execute(self, dto: GreetingParams) -> str: self.db.store(f"Greeting {dto.name}") return f"Hello, {dto.name}!" # 5. Execute the Use Case if __name__ == "__main__": # Create an instance of the parameter DTO greeting_dto = GreetingParams(name="Alice") # Execute the feature result = framework(greeting_dto) print(result) # Output: Hello, Alice!
Now you are ready to explore more complex use cases! 🚀
Hexagonal Architecture, also known as Ports and Adapters, is an architectural approach that aims to decouple core business logic from external dependencies. It organizes the system into distinct layers: domain, application, and infrastructure, enhancing maintainability, scalability, and adaptability.
The Sincpro Framework adopts a unified bus pattern as a single point of entry for managing use cases, dependencies, and services within a bounded context. This simplifies the architecture by encapsulating all requirements of a given context, ensuring a clear and consistent structure.
Using a unified bus allows developers to access all dependencies through a single environment, eliminating the need for repeated imports or initialization. This approach ensures each bounded context is self-sufficient, independently scalable, and minimizes coupling while enhancing modularity.
The Sincpro Framework follows hexagonal architecture principles, promoting modularity, scalability, and development efficiency. Here are its core features:
contextvars for thread-safe context storage and isolation.# Simple context usage with app.context({"correlation_id": "123", "user.id": "admin"}) as app_with_context: result = app_with_context(some_dto) # Context automatically available in handlers # Nested contexts with overrides with app.context({"env": "prod", "user": "admin"}) as outer_app: with outer_app.context({"env": "staging"}) as inner_app: # Override env, inherit user inner_app(dto) # env="staging", user="admin" # Access context in Features and ApplicationServices class PaymentFeature(Feature): def execute(self, dto: PaymentDTO) -> PaymentResponse: correlation_id = self.context.get("correlation_id") user_id = self.context.get("user.id") # Use context in business logic...
The following example shows how to configure the Sincpro Framework for a payment gateway integration, such as CyberSource. It is recommended to name the framework instance to clearly represent the bounded context it serves.
To set up the Sincpro Framework, configuration should be performed at the application layer within the use_cases
directory of each bounded context.
sincpro_payments_sdk/ ├── pyproject.toml ├── README.md ├── apps/ │ ├── cybersource/ │ │ ├── adapters/ │ │ │ ├── cybersource_rest_api_adapter.py │ │ │ └── __init__.py │ │ ├── domain/ │ │ │ ├── card.py │ │ │ ├── customer.py │ │ │ └── __init__.py │ │ ├── infrastructure/ │ │ │ ├── logger.py │ │ │ ├── aws_services.py │ │ │ ├── orm.py │ │ │ └── __init__.py │ │ └── use_cases/ │ │ ├── tokenization/ │ │ │ ├── new_tokenization_feature.py │ │ │ └── __init__.py │ │ ├── payments/ │ │ │ ├── token_and_payment_service.py │ │ │ └── __init__.py │ │ └── __init__.py │ ├── qr/ │ ├── sms_payment/ │ ├── bank_api/ │ ├── online_payment_gateway/ │ └── paypal_integration/ └── tests
Each use case should import both the DTO for input parameters and the DTO for responses to maintain clarity and consistency.
__init__.pyfrom typing import Type from sincpro_framework import Feature as _Feature from sincpro_framework import UseFramework as _UseFramework from sincpro_framework import ApplicationService as _ApplicationService from sincpro_payments_sdk.apps.cybersource.adapters.cybersource_rest_api_adapter import ( ESupportedCardType, TokenizationAdapter, ) from sincpro_payments_sdk.infrastructure.orm import with_transaction as db_session from sincpro_payments_sdk.infrastructure.aws_services import AwsService as aws_service # Create an instance of the framework cybersource = _UseFramework() # Register dependencies cybersource.add_dependency("token_adapter", TokenizationAdapter()) cybersource.add_dependency("ECardType", ESupportedCardType) cybersource.add_dependency("db_session", db_session) cybersource.add_dependency("aws_service", aws_service) # Define a custom Feature class to access the dependencies class Feature(_Feature): token_adapter: TokenizationAdapter ECardType: Type[ESupportedCardType] db_session: ... aws_service: ... logger: ... # Define a custom Application Service class to access dependencies class ApplicationService(_ApplicationService): token_adapter: TokenizationAdapter ECardType: Type[ESupportedCardType] db_session: ... aws_service: ... logger: ... feature_bus: ... # Add use cases (Application Services and Features) from . import tokenization __all__ = ["cybersource", "tokenization", "Feature"]
To create a new Feature, follow these steps:
use_cases.DataTransferObject.DataTransferObject to create classes for input parameters and
responses.Feature class by inheriting from the custom Feature class.from sincpro_payments_sdk.apps.cybersource import cybersource, DataTransferObject, Feature # Define parameter DTO class TokenizationParams(DataTransferObject): card_number: str expiration_date: str cardholder_name: str # Define response DTO class TokenizationResponse(DataTransferObject): token: str status: str # Create the Feature class @cybersource.feature(TokenizationParams) class NewTokenizationFeature(Feature): def execute(self, dto: TokenizationParams) -> TokenizationResponse: # Example usage of dependencies cybersource.logger.info("Starting tokenization process") token = self.token_adapter.create_token( card_number=dto.card_number, expiration_date=dto.expiration_date, cardholder_name=dto.cardholder_name ) return TokenizationResponse(token=token, status="success")
ApplicationService is used to coordinate multiple features while maintaining reusability and consistency. It orchestrates features into cohesive workflows.
from sincpro_payments_sdk.apps.cybersource import cybersource, DataTransferObject, ApplicationService from sincpro_payments_sdk.apps.cybersource.use_cases.tokenization import TokenizationParams # Define parameter DTO class PaymentServiceParams(DataTransferObject): card_number: str expiration_date: str cardholder_name: str amount: float # Define response DTO class PaymentServiceResponse(DataTransferObject): status: str transaction_id: str # Create the Application Service class @cybersource.app_service(PaymentServiceParams) class PaymentOrchestrationService(ApplicationService): def execute(self, dto: PaymentServiceParams) -> PaymentServiceResponse: # Create the command DTO for tokenization tokenization_command = TokenizationParams( card_number=dto.card_number, expiration_date=dto.expiration_date, cardholder_name=dto.cardholder_name ) tokenization_result = self.feature_bus.execute(tokenization_command) # Example usage of dependencies cybersource.logger.info("Proceeding with payment after tokenization") # Proceed with payment using the token (pseudo code for payment processing) transaction_id = "12345" # Simulated transaction ID return PaymentServiceResponse(status="success", transaction_id=transaction_id)
Once a Feature or ApplicationService is defined, it can be executed by passing the appropriate DTO instance.
from sincpro_payments_sdk.apps.cybersource import cybersource from sincpro_payments_sdk.apps.cybersource.use_cases.tokenization import TokenizationParams, TokenizationResponse from sincpro_payments_sdk.apps.cybersource.use_cases.payments import PaymentServiceParams, PaymentServiceResponse # Example of executing a Feature feature_dto = TokenizationParams( card_number="4111111111111111", expiration_date="12/25", cardholder_name="John Doe" ) # Execute the feature feature_result = cybersource(feature_dto, TokenizationResponse) print(f"Tokenization Result: {feature_result.token}, Status: {feature_result.status}") # Example of executing an Application Service service_dto = PaymentServiceParams( card_number="4111111111111111", expiration_date="12/25", cardholder_name="John Doe", amount=100.00 ) # Execute the application service service_result = cybersource(service_dto, PaymentServiceResponse) print(f"Payment Status: {service_result.status}, Transaction ID: {service_result.transaction_id}")
The Sincpro Framework provides a robust solution for managing the application layer within a hexagonal architecture. By focusing on decoupling business logic from external dependencies, the framework promotes modularity, scalability, and maintainability.
This structured approach ensures high-quality, maintainable software that can adapt to evolving business needs. 🚀
The Sincpro Framework includes a powerful auto-documentation feature that automatically generates comprehensive documentation for your framework instances. This documentation includes all your DTOs, Features, Application Services, Dependencies, and Middlewares in multiple formats optimized for different use cases.
The easiest way to generate documentation for your project:
from sincpro_framework.generate_documentation import build_documentation # Import your framework instances from their respective modules from apps.payment_gateway import payment_framework from apps.user_management import user_framework # Generate traditional markdown documentation (default) build_documentation( [payment_framework, user_framework], output_dir="docs/generated" ) # Generate AI-optimized JSON schema build_documentation( [payment_framework, user_framework], output_dir="docs/generated", format="json" ) # Generate chunked JSON for optimal AI consumption (NEW!) build_documentation( [payment_framework, user_framework], output_dir="docs/generated", format="json", chunked=True ) # Generate both formats build_documentation( [payment_framework, user_framework], output_dir="docs/generated", format="both" )
docs/generated/
├── mkdocs.yml # MkDocs configuration
├── requirements.txt # Dependencies
├── framework_schema.json # AI-optimized JSON with framework context
├── site/ # Built HTML documentation
└── docs/ # Markdown content
├── index.md # Overview
├── features.md # Features documentation
├── dtos.md # DTOs documentation
└── application-services.md # Services documentation
docs/generated/ai_context/
├── 01_framework_context.json # Shared framework knowledge (70KB)
├── 01_payment_gateway_context.json # Instance overview (1-2KB)
├── 01_payment_gateway_dtos.json # DTO summaries (700B)
├── 01_payment_gateway_dtos_details.json # Full DTO details (1-3KB)
├── 01_payment_gateway_features.json # Feature summaries (700B)
├── 01_payment_gateway_features_details.json # Full feature details (1-3KB)
├── 01_payment_gateway_services.json # Service summaries (if any)
├── 01_payment_gateway_services_details.json # Full service details
├── 02_user_management_context.json # Second instance overview
├── 02_user_management_dtos.json # Second instance DTOs
└── ... # Additional instances
The enhanced JSON schema combines framework context with repository analysis for complete AI understanding:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Repository Schema with Framework Context", "schema_type": "ai_optimized_complete", "framework_context": { "framework_name": "Sincpro Framework", "core_principles": {/* Framework usage patterns and principles */}, "key_features": {/* Framework capabilities and features */}, "framework_execution_patterns": {/* How to execute features/services */} }, "repository_analysis": { "metadata": { "architecture_patterns": ["DDD", "Clean Architecture"], "component_summary": { /* counts and statistics */ } }, "components": { "dtos": [/* with AI hints for type classification */], "features": [/* with business domain inference */], "application_services": [/* with orchestration patterns */] } }, "ai_integration": { "framework_integration": { "execution_patterns": {/* How to use framework with repository components */}, "available_features": {/* Framework capabilities */} }, "complete_understanding": { "framework_knowledge": "Loaded from hardcoded guide", "repository_knowledge": "Generated from code analysis", "ai_capability": "Complete understanding of framework usage + repository components" }, "usage_synthesis": { "how_to_execute_features": {/* Real examples combining framework + repo */}, "how_to_execute_services": {/* Real examples combining framework + repo */} }, "embedding_suggestions": { "primary_entities": ["PaymentCommand", "UserCommand"], "business_capabilities": ["PaymentFeature", "UserFeature"] }, "code_generation_hints": { "framework_patterns": ["command_pattern", "dependency_injection"], "common_imports": ["from sincpro_framework import..."] }, "complexity_analysis": { "overall_complexity": "medium", "most_complex_components": ["ComplexService"] } } }
The new chunked approach provides significant advantages for AI systems:
Start with Framework Context (01_framework_context.json - 70KB)
Instance Overview (01_<name>_context.json - 1-2KB each)
Component Summaries (01_<name>_dtos.json - 700B each)
Detailed Information (01_<name>_dtos_details.json - 1-3KB each)
Example of well-documented code:
class PaymentCommand(DataTransferObject): """Command for processing credit card payments. This DTO contains all necessary information to process a payment transaction through the payment gateway. """ card_number: str # Credit card number (PCI compliant) amount: float # Payment amount in USD merchant_id: str # Unique merchant identifier @framework.feature(PaymentCommand) class PaymentFeature(Feature): """Process payment transactions through external gateway. This feature handles the complete payment flow including validation, gateway communication, and response processing. """ def execute(self, dto: PaymentCommand) -> PaymentResponse: """Execute payment processing. Args: dto: Payment command with card and amount information Returns: PaymentResponse: Transaction result with ID and status Raises: PaymentError: When payment fails or card is invalid """ # Implementation here...
The JSON schema format enables powerful AI integrations:
The framework comes with a module or component to allow us to create configuratio or settings based on files or
environment variables.
You need to inherit from SincproConfig from module sincpro_framework.sincpro_conf
from sincpro_framework.sincpro_conf import SincproConfig class PostgresConf(SincproConfig): host: str = "localhost" port: int = 5432 user: str = "my_user" class MyConfig(SincproConfig): log_level: str = "DEBUG" token: str = "defult_my_token" postgresql: PostgresConf = PostgresConf()
This class should be mapped based on yaml file like this, we have a feature to use ENV variables in the yaml file
using the prefix $ENV:
log_level: "INFO" token: "$ENV:MY_SECRET_TOKEN" postgresql: host: localhost port: 12345 user: custom_user
When using $ENV: prefix in your configuration files, the framework will:
$ENV:This behavior allows applications to run with partial configurations in development environments or when not all environment variables are available, while still logging appropriate warnings.
Example of fallback to default values:
# Configuration class with default class ApiConfig(SincproConfig): api_key: str = "dev_default_key" # Default value as fallback # In config.yml api_key: "$ENV:API_KEY" # References environment variable # If API_KEY environment variable is not set, the framework will: # 1. Log a warning: "Environment variable [API_KEY] is not set for field [api_key]. Using default value: dev_default_key" # 2. Use the default value "dev_default_key" # 3. Continue execution without error
Then you can use the config object in your code where it will be loaded all the settings from the yaml file
for that you will require use the following funciton build_config_obj
from sincpro_framework.sincpro_conf import build_config_obj from .my_config import MyConfig config = build_config_obj(MyConfig, '/path/to/your/config.yml') assert isinstance(config.log_level, str) assert isinstance(config.postgresql, PostgresConf)
The framework use a default setting file where live in the module folder inside of
sincpro_framework/conf/sincpro_framework_conf.yml
where you can define some behavior currently we support the following settings:
sincpro_framework_log_level): Define the log level for the logger, the default is DEBUGOverride the config file using another
export SINCPRO_FRAMEWORK_CONFIG_FILE = /path/to/your/config.yml