A Spring Boot-inspired Python web framework built on Starlette
Project description
StarSpring Framework
StarSpring is a production-grade, asynchronous web framework for Python that brings the robust architectural patterns of Spring Boot to the modern Python ecosystem. Built on top of Starlette and SQLAlchemy, it combines enterprise structure with Pythonic elegance.
🌟 Features
- Dependency Injection (IoC): Fully typed, automatic constructor injection. No more global state or manual wiring.
- Declarative Routing: Use
@GetMapping,@PostMappingdecorators for clean, readable controllers. - Enterprise ORM: Built on SQLAlchemy with Imperative Mapping. Define simple Python classes, and they become powerful database entities automatically.
- Magic Repositories: Define interfaces, and StarSpring implements the queries for you (e.g.,
find_by_email_and_active(email, True)). - Robust Transaction Management:
@Transactionaldecorators with support for robust nested transactions (SAVEPOINTs). - Production Ready: Built-in support for CORS, Exception Handling, Logging, and Configuration Management (
application.yaml).
📦 Installation
StarSpring requires Python 3.10+.
Using pip
pip install starspring
Using uv (Recommended for speed)
uv pip install starspring
Database Drivers
StarSpring uses SQLAlchemy. Install the driver for your database:
# SQLite (Standard)
pip install starspring
# PostgreSQL
pip install psycopg2-binary
# or
pip install asyncpg
🚀 Building Your First Application
Here is a complete walkthrough of building a User Management API.
1. Project Structure
We recommend a standard layered architecture:
my_app/
├── __init__.py
├── main.py # Entry point
├── application.yaml # Configuration
├── entities.py # Database Models
├── repositories.py # Data Access
├── services.py # Business Logic
└── controllers.py # REST Endpoints
2. Configuration (application.yaml)
Configure your server and database connection.
server:
port: 8000
host: 0.0.0.0
database:
url: "sqlite:///app.db" # or postgresql://user:pass@localhost/db
ddl-auto: "create-if-not-exists" # Auto-creates tables from entities
3. Entities (entities.py)
Define your database models using standard Python classes. StarSpring maps them automatically.
from starspring import Entity, BaseEntity, Column
from datetime import datetime
@Entity(table_name="users")
class User(BaseEntity):
# BaseEntity automatically adds 'id', 'created_at', 'updated_at'
username: str = Column(unique=True, length=50, nullable=False)
email: str = Column(unique=True, nullable=False)
is_active: bool = Column(default=True)
role: str = Column(default="USER")
4. Repositories (repositories.py)
Create an interface for data access. Inherit from StarRepository.
Note: Identify the Entity type in the generic (e.g., [User]).
from starspring import Repository, StarRepository
from my_app.entities import User
@Repository
class UserRepository(StarRepository[User]):
# StarSpring automatically implements standard CRUD (save, find_by_id, delete, etc.)
# Define custom finders just by naming them!
async def find_by_username(self, username: str) -> User | None:
...
async def find_by_email_and_is_active(self, email: str, is_active: bool) -> User | None:
...
5. Services (services.py)
Encapsulate your business logic here. Use @Transactional to ensure data integrity.
from starspring import Service, Transactional
from my_app.repositories import UserRepository
from my_app.entities import User
@Service
class UserService:
# Dependency Injection: Just mention the type in the constructor!
def __init__(self, user_repo: UserRepository):
self.user_repo = user_repo
@Transactional
async def register_user(self, username: str, email: str) -> User:
# Check if exists
existing = await self.user_repo.find_by_email_and_is_active(email, True)
if existing:
raise ValueError("User already exists")
# Create new user
new_user = User(username=username, email=email)
return await self.user_repo.save(new_user)
6. Controllers (controllers.py)
Expose your logic as a REST API.
# Note: Use @Controller for REST endpoints too.
# StarSpring automatically serializes dict/list responses to JSON.
from starspring import Controller, GetMapping, PostMapping, ResponseEntity
from my_app.services import UserService
@Controller("/api/users")
class UserController:
def __init__(self, user_service: UserService):
self.user_service = user_service
@GetMapping("/{username}")
async def get_user(self, username: str) -> dict:
# You can return dicts, lists, or Entities directly
user = await self.user_service.user_repo.find_by_username(username)
# Assuming BaseEntity has .to_dict() or Pydantic serialization
return user.to_dict() if user else ResponseEntity.not_found()
@PostMapping("/register")
async def register(self, username: str, email: str) -> dict:
# Arguments are automatically extracted from JSON body or Query params
try:
user = await self.user_service.register_user(username, email)
return {"status": "success", "user_id": user.id}
except ValueError as e:
return ResponseEntity.bad_request(str(e))
7. Main Entry Point (main.py)
Bootstrap the application.
from starspring import StarSpringApplication
# Initialize App
app = StarSpringApplication(
title="My User API",
config_path="application.yaml"
)
# Scan for all your components (Controllers, Services, Repositories)
app.scan_components("my_app")
if __name__ == "__main__":
# Runs the server (default: localhost:8000)
app.run()
📚 Core Concepts
Dependency Injection (DI)
StarSpring manages the lifecycle of your objects. When you ask for a UserRepository in your UserService constructor, the framework:
- Finds the
UserRepositoryclass. - Creates an instance of it (Singleton by default).
- Passes it to your
UserService.
This makes testing easier (you can mock repositories) and code cleaner.
Database & ORM
We use a Code-First approach.
- Define Python classes (
@Entity). - StarSpring tells SQLAlchemy to map these classes to tables.
- If
database.ddl-autois set tocreate, the framework creates the tables for you on startup.
Transaction Management
Use the @Transactional decorator on any method (usually in Services).
- Success: The transaction commits automatically.
- Reference Counter: If you nest
@Transactionalmethods, the inner one joins the outer transaction. - Error: If an exception occurs, the entire transaction rolls back.
🛠 Advanced Configuration
You can tune every part of the framework via application.yaml.
server:
port: 8080
cors:
allowed-origins: ["*"]
allowed-methods: ["GET", "POST", "PUT", "DELETE"]
logging:
level: INFO
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
🤝 Contributing
We welcome contributions!
- Fork the repository.
- Create a feature branch.
- Submit a Pull Request.
Please ensure all tests pass before submitting.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file starspring-0.1.1.tar.gz.
File metadata
- Download URL: starspring-0.1.1.tar.gz
- Upload date:
- Size: 40.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff49ce8565e419920adbc1e2e0b2737e973a0a5492c5f5b98675b3b7f91f3fa8
|
|
| MD5 |
7cd3a0505f5cb9312e1b818e580ef207
|
|
| BLAKE2b-256 |
6cfa5d5d1170286d27b27d3656c5e3d1d1407ede47d40c927cb58554b1ba59d0
|
File details
Details for the file starspring-0.1.1-py3-none-any.whl.
File metadata
- Download URL: starspring-0.1.1-py3-none-any.whl
- Upload date:
- Size: 47.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e6712ad96e98e0fa5c6b5f2343f6cb798b4f96907235d646d6495ef860bcb8e
|
|
| MD5 |
03cf71ec2563f568aef914f13da6db91
|
|
| BLAKE2b-256 |
f381fd021fe96bda824d93eba903a44105b68a014539de0c0d8f2fbca8a7143f
|