starspring 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.
- starspring/__init__.py +150 -0
- starspring/application.py +421 -0
- starspring/client/__init__.py +1 -0
- starspring/client/rest_client.py +220 -0
- starspring/config/__init__.py +1 -0
- starspring/config/environment.py +81 -0
- starspring/config/properties.py +146 -0
- starspring/core/__init__.py +1 -0
- starspring/core/context.py +180 -0
- starspring/core/controller.py +47 -0
- starspring/core/exceptions.py +82 -0
- starspring/core/response.py +147 -0
- starspring/data/__init__.py +47 -0
- starspring/data/database_config.py +113 -0
- starspring/data/entity.py +365 -0
- starspring/data/orm_gateway.py +256 -0
- starspring/data/query_builder.py +345 -0
- starspring/data/repository.py +324 -0
- starspring/data/schema_generator.py +151 -0
- starspring/data/transaction.py +58 -0
- starspring/decorators/__init__.py +1 -0
- starspring/decorators/components.py +179 -0
- starspring/decorators/configuration.py +102 -0
- starspring/decorators/routing.py +306 -0
- starspring/decorators/validation.py +30 -0
- starspring/middleware/__init__.py +1 -0
- starspring/middleware/cors.py +90 -0
- starspring/middleware/exception.py +83 -0
- starspring/middleware/logging.py +60 -0
- starspring/template/__init__.py +19 -0
- starspring/template/engine.py +168 -0
- starspring/template/model_and_view.py +69 -0
- starspring-0.1.0.dist-info/METADATA +284 -0
- starspring-0.1.0.dist-info/RECORD +36 -0
- starspring-0.1.0.dist-info/WHEEL +5 -0
- starspring-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Template engine for rendering HTML templates
|
|
3
|
+
|
|
4
|
+
Integrates Jinja2 with Spring Boot-style patterns.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Any, Optional
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from jinja2 import Environment, FileSystemLoader, select_autoescape, Template
|
|
14
|
+
JINJA2_AVAILABLE = True
|
|
15
|
+
except ImportError:
|
|
16
|
+
JINJA2_AVAILABLE = False
|
|
17
|
+
Environment = None
|
|
18
|
+
FileSystemLoader = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TemplateEngine:
|
|
22
|
+
"""
|
|
23
|
+
Template rendering engine
|
|
24
|
+
|
|
25
|
+
Wraps Jinja2 with Spring Boot-style configuration.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
template_dir: str = "templates",
|
|
31
|
+
auto_reload: bool = True,
|
|
32
|
+
cache_size: int = 400
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Initialize template engine
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
template_dir: Directory containing templates
|
|
39
|
+
auto_reload: Whether to reload templates on change
|
|
40
|
+
cache_size: Template cache size
|
|
41
|
+
"""
|
|
42
|
+
if not JINJA2_AVAILABLE:
|
|
43
|
+
raise ImportError(
|
|
44
|
+
"Jinja2 is required for template rendering. "
|
|
45
|
+
"Install it with: pip install jinja2"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
self.template_dir = template_dir
|
|
49
|
+
|
|
50
|
+
# Create template directory if it doesn't exist
|
|
51
|
+
Path(template_dir).mkdir(parents=True, exist_ok=True)
|
|
52
|
+
|
|
53
|
+
# Initialize Jinja2 environment
|
|
54
|
+
self.env = Environment(
|
|
55
|
+
loader=FileSystemLoader(template_dir),
|
|
56
|
+
autoescape=select_autoescape(['html', 'xml']),
|
|
57
|
+
auto_reload=auto_reload,
|
|
58
|
+
cache_size=cache_size
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Add custom filters and functions
|
|
62
|
+
self._setup_filters()
|
|
63
|
+
|
|
64
|
+
def _setup_filters(self):
|
|
65
|
+
"""Setup custom Jinja2 filters"""
|
|
66
|
+
# Add custom filters here
|
|
67
|
+
self.env.filters['format_date'] = self._format_date
|
|
68
|
+
self.env.filters['format_currency'] = self._format_currency
|
|
69
|
+
|
|
70
|
+
def _format_date(self, value, format='%Y-%m-%d'):
|
|
71
|
+
"""Format datetime objects"""
|
|
72
|
+
if value is None:
|
|
73
|
+
return ''
|
|
74
|
+
try:
|
|
75
|
+
return value.strftime(format)
|
|
76
|
+
except:
|
|
77
|
+
return str(value)
|
|
78
|
+
|
|
79
|
+
def _format_currency(self, value, currency='$'):
|
|
80
|
+
"""Format currency values"""
|
|
81
|
+
if value is None:
|
|
82
|
+
return ''
|
|
83
|
+
try:
|
|
84
|
+
return f"{currency}{value:,.2f}"
|
|
85
|
+
except:
|
|
86
|
+
return str(value)
|
|
87
|
+
|
|
88
|
+
def render(self, template_name: str, context: Dict[str, Any] = None) -> str:
|
|
89
|
+
"""
|
|
90
|
+
Render a template
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
template_name: Template file name
|
|
94
|
+
context: Template context variables
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Rendered HTML string
|
|
98
|
+
"""
|
|
99
|
+
context = context or {}
|
|
100
|
+
template = self.env.get_template(template_name)
|
|
101
|
+
return template.render(**context)
|
|
102
|
+
|
|
103
|
+
def render_string(self, template_string: str, context: Dict[str, Any] = None) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Render a template from string
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
template_string: Template content as string
|
|
109
|
+
context: Template context variables
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Rendered HTML string
|
|
113
|
+
"""
|
|
114
|
+
context = context or {}
|
|
115
|
+
template = self.env.from_string(template_string)
|
|
116
|
+
return template.render(**context)
|
|
117
|
+
|
|
118
|
+
def add_global(self, name: str, value: Any):
|
|
119
|
+
"""
|
|
120
|
+
Add a global variable to all templates
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
name: Variable name
|
|
124
|
+
value: Variable value
|
|
125
|
+
"""
|
|
126
|
+
self.env.globals[name] = value
|
|
127
|
+
|
|
128
|
+
def add_filter(self, name: str, func: callable):
|
|
129
|
+
"""
|
|
130
|
+
Add a custom filter
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
name: Filter name
|
|
134
|
+
func: Filter function
|
|
135
|
+
"""
|
|
136
|
+
self.env.filters[name] = func
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# Global template engine instance
|
|
140
|
+
_template_engine: Optional[TemplateEngine] = None
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def get_template_engine() -> TemplateEngine:
|
|
144
|
+
"""Get the global template engine instance"""
|
|
145
|
+
global _template_engine
|
|
146
|
+
if _template_engine is None:
|
|
147
|
+
_template_engine = TemplateEngine()
|
|
148
|
+
return _template_engine
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def set_template_engine(engine: TemplateEngine):
|
|
152
|
+
"""Set the global template engine instance"""
|
|
153
|
+
global _template_engine
|
|
154
|
+
_template_engine = engine
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def render_template(template_name: str, context: Dict[str, Any] = None) -> str:
|
|
158
|
+
"""
|
|
159
|
+
Convenience function to render a template
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
template_name: Template file name
|
|
163
|
+
context: Template context variables
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Rendered HTML string
|
|
167
|
+
"""
|
|
168
|
+
return get_template_engine().render(template_name, context)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Template engine integration
|
|
3
|
+
|
|
4
|
+
Provides Jinja2 template rendering with Spring Boot-style patterns.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Any, Optional
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ModelAndView:
|
|
13
|
+
"""
|
|
14
|
+
Container for model and view name
|
|
15
|
+
|
|
16
|
+
Similar to Spring MVC's ModelAndView.
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
@GetMapping("/users")
|
|
20
|
+
def list_users(self) -> ModelAndView:
|
|
21
|
+
users = self.user_service.find_all()
|
|
22
|
+
return ModelAndView("users/list.html", {"users": users})
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, view_name: str, model: Optional[Dict[str, Any]] = None):
|
|
26
|
+
"""
|
|
27
|
+
Initialize ModelAndView
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
view_name: Template file name
|
|
31
|
+
model: Dictionary of model attributes
|
|
32
|
+
"""
|
|
33
|
+
self.view_name = view_name
|
|
34
|
+
self.model = model or {}
|
|
35
|
+
|
|
36
|
+
def add_object(self, key: str, value: Any) -> 'ModelAndView':
|
|
37
|
+
"""
|
|
38
|
+
Add an object to the model
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
key: Attribute name
|
|
42
|
+
value: Attribute value
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Self for method chaining
|
|
46
|
+
"""
|
|
47
|
+
self.model[key] = value
|
|
48
|
+
return self
|
|
49
|
+
|
|
50
|
+
def add_all_objects(self, objects: Dict[str, Any]) -> 'ModelAndView':
|
|
51
|
+
"""
|
|
52
|
+
Add multiple objects to the model
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
objects: Dictionary of attributes
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Self for method chaining
|
|
59
|
+
"""
|
|
60
|
+
self.model.update(objects)
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
def get_model(self) -> Dict[str, Any]:
|
|
64
|
+
"""Get the model dictionary"""
|
|
65
|
+
return self.model
|
|
66
|
+
|
|
67
|
+
def get_view_name(self) -> str:
|
|
68
|
+
"""Get the view name"""
|
|
69
|
+
return self.view_name
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: starspring
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Spring Boot-inspired Python web framework built on Starlette
|
|
5
|
+
Author: StarSpring Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yourusername/starspring
|
|
8
|
+
Project-URL: Documentation, https://github.com/yourusername/starspring#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/yourusername/starspring
|
|
10
|
+
Keywords: web,framework,starlette,spring-boot,dependency-injection
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: starlette>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Requires-Dist: uvicorn[standard]>=0.23.0
|
|
25
|
+
Requires-Dist: python-multipart>=0.0.6
|
|
26
|
+
Requires-Dist: pyyaml>=6.0
|
|
27
|
+
Requires-Dist: httpx>=0.24.0
|
|
28
|
+
Requires-Dist: jinja2>=3.1.6
|
|
29
|
+
Requires-Dist: sqlalchemy>=2.0.46
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
33
|
+
Requires-Dist: black>=23.7.0; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.5.0; extra == "dev"
|
|
35
|
+
Provides-Extra: sqlalchemy
|
|
36
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == "sqlalchemy"
|
|
37
|
+
|
|
38
|
+
# StarSpring Framework
|
|
39
|
+
|
|
40
|
+
[](https://www.python.org/downloads/)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
[](https://pypi.org/project/starspring/)
|
|
43
|
+
|
|
44
|
+
**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.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🌟 Features
|
|
49
|
+
|
|
50
|
+
* **Dependency Injection (IoC)**: Fully typed, automatic constructor injection. No more global state or manual wiring.
|
|
51
|
+
* **Declarative Routing**: Use `@GetMapping`, `@PostMapping` decorators for clean, readable controllers.
|
|
52
|
+
* **Enterprise ORM**: Built on **SQLAlchemy** with **Imperative Mapping**. Define simple Python classes, and they become powerful database entities automatically.
|
|
53
|
+
* **Magic Repositories**: Define interfaces, and StarSpring implements the queries for you (e.g., `find_by_email_and_active(email, True)`).
|
|
54
|
+
* **Robust Transaction Management**: `@Transactional` decorators with support for robust nested transactions (`SAVEPOINT`s).
|
|
55
|
+
* **Production Ready**: Built-in support for CORS, Exception Handling, Logging, and Configuration Management (`application.yaml`).
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 📦 Installation
|
|
60
|
+
|
|
61
|
+
StarSpring requires Python 3.10+.
|
|
62
|
+
|
|
63
|
+
### Using pip
|
|
64
|
+
```bash
|
|
65
|
+
pip install starspring
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Using uv (Recommended for speed)
|
|
69
|
+
```bash
|
|
70
|
+
uv pip install starspring
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Database Drivers
|
|
74
|
+
StarSpring uses SQLAlchemy. Install the driver for your database:
|
|
75
|
+
```bash
|
|
76
|
+
# SQLite (Standard)
|
|
77
|
+
pip install starspring
|
|
78
|
+
|
|
79
|
+
# PostgreSQL
|
|
80
|
+
pip install psycopg2-binary
|
|
81
|
+
# or
|
|
82
|
+
pip install asyncpg
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 🚀 Building Your First Application
|
|
88
|
+
|
|
89
|
+
Here is a complete walkthrough of building a User Management API.
|
|
90
|
+
|
|
91
|
+
### 1. Project Structure
|
|
92
|
+
We recommend a standard layered architecture:
|
|
93
|
+
```text
|
|
94
|
+
my_app/
|
|
95
|
+
├── __init__.py
|
|
96
|
+
├── main.py # Entry point
|
|
97
|
+
├── application.yaml # Configuration
|
|
98
|
+
├── entities.py # Database Models
|
|
99
|
+
├── repositories.py # Data Access
|
|
100
|
+
├── services.py # Business Logic
|
|
101
|
+
└── controllers.py # REST Endpoints
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2. Configuration (`application.yaml`)
|
|
105
|
+
Configure your server and database connection.
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
server:
|
|
109
|
+
port: 8000
|
|
110
|
+
host: 0.0.0.0
|
|
111
|
+
|
|
112
|
+
database:
|
|
113
|
+
url: "sqlite:///app.db" # or postgresql://user:pass@localhost/db
|
|
114
|
+
ddl-auto: "create-if-not-exists" # Auto-creates tables from entities
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3. Entities (`entities.py`)
|
|
118
|
+
Define your database models using standard Python classes. StarSpring maps them automatically.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from starspring import Entity, BaseEntity, Column, Id, GeneratedValue
|
|
122
|
+
from datetime import datetime
|
|
123
|
+
|
|
124
|
+
@Entity(table_name="users")
|
|
125
|
+
class User(BaseEntity):
|
|
126
|
+
# BaseEntity automatically adds 'id', 'created_at', 'updated_at'
|
|
127
|
+
|
|
128
|
+
username: str = Column(unique=True, length=50, nullable=False)
|
|
129
|
+
email: str = Column(unique=True, nullable=False)
|
|
130
|
+
is_active: bool = Column(default=True)
|
|
131
|
+
role: str = Column(default="USER")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 4. Repositories (`repositories.py`)
|
|
135
|
+
Create an interface for data access. Inherit from `StarRepository`.
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from starspring import Repository, StarRepository
|
|
139
|
+
from my_app.entities import User
|
|
140
|
+
|
|
141
|
+
@Repository
|
|
142
|
+
class UserRepository(StarRepository[User, int]):
|
|
143
|
+
# StarSpring automatically implements standard CRUD (save, find_by_id, delete, etc.)
|
|
144
|
+
|
|
145
|
+
# Define custom finders just by naming them!
|
|
146
|
+
async def find_by_username(self, username: str) -> User | None:
|
|
147
|
+
...
|
|
148
|
+
|
|
149
|
+
async def find_by_email_and_is_active(self, email: str, is_active: bool) -> User | None:
|
|
150
|
+
...
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 5. Services (`services.py`)
|
|
154
|
+
Encapsulate your business logic here. Use `@Transactional` to ensure data integrity.
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from starspring import Service, Transactional
|
|
158
|
+
from my_app.repositories import UserRepository
|
|
159
|
+
from my_app.entities import User
|
|
160
|
+
|
|
161
|
+
@Service
|
|
162
|
+
class UserService:
|
|
163
|
+
# Dependency Injection: Just mention the type in the constructor!
|
|
164
|
+
def __init__(self, user_repo: UserRepository):
|
|
165
|
+
self.user_repo = user_repo
|
|
166
|
+
|
|
167
|
+
@Transactional
|
|
168
|
+
async def register_user(self, username: str, email: str) -> User:
|
|
169
|
+
# Check if exists
|
|
170
|
+
existing = await self.user_repo.find_by_email_and_is_active(email, True)
|
|
171
|
+
if existing:
|
|
172
|
+
raise ValueError("User already exists")
|
|
173
|
+
|
|
174
|
+
# Create new user
|
|
175
|
+
new_user = User(username=username, email=email)
|
|
176
|
+
return await self.user_repo.save(new_user)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 6. Controllers (`controllers.py`)
|
|
180
|
+
Expose your logic as a REST API.
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from starspring import RestController, GetMapping, PostMapping
|
|
184
|
+
from starspring.web.response import ResponseEntity
|
|
185
|
+
from my_app.services import UserService
|
|
186
|
+
|
|
187
|
+
@RestController("/api/users")
|
|
188
|
+
class UserController:
|
|
189
|
+
|
|
190
|
+
def __init__(self, user_service: UserService):
|
|
191
|
+
self.user_service = user_service
|
|
192
|
+
|
|
193
|
+
@GetMapping("/{username}")
|
|
194
|
+
async def get_user(self, username: str) -> dict:
|
|
195
|
+
# You can return dicts, lists, or Entities directly
|
|
196
|
+
user = await self.user_service.user_repo.find_by_username(username)
|
|
197
|
+
return user.to_dict() if user else ResponseEntity.not_found()
|
|
198
|
+
|
|
199
|
+
@PostMapping("/register")
|
|
200
|
+
async def register(self, username: str, email: str) -> dict:
|
|
201
|
+
# Arguments are automatically extracted from JSON body or Query params
|
|
202
|
+
try:
|
|
203
|
+
user = await self.user_service.register_user(username, email)
|
|
204
|
+
return {"status": "success", "user_id": user.id}
|
|
205
|
+
except ValueError as e:
|
|
206
|
+
return ResponseEntity.bad_request(str(e))
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 7. Main Entry Point (`main.py`)
|
|
210
|
+
Bootstrap the application.
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from starspring import StarSpringApplication
|
|
214
|
+
|
|
215
|
+
# Initialize App
|
|
216
|
+
app = StarSpringApplication(
|
|
217
|
+
title="My User API",
|
|
218
|
+
config_path="application.yaml"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Scan for all your components (Controllers, Services, Repositories)
|
|
222
|
+
app.scan_components("my_app")
|
|
223
|
+
|
|
224
|
+
if __name__ == "__main__":
|
|
225
|
+
# Runs the server (default: localhost:8000)
|
|
226
|
+
app.run()
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 📚 Core Concepts
|
|
232
|
+
|
|
233
|
+
### Dependency Injection (DI)
|
|
234
|
+
StarSpring manages the lifecycle of your objects. When you ask for a `UserRepository` in your `UserService` constructor, the framework:
|
|
235
|
+
1. Finds the `UserRepository` class.
|
|
236
|
+
2. Creates an instance of it (Singleton by default).
|
|
237
|
+
3. Passes it to your `UserService`.
|
|
238
|
+
|
|
239
|
+
This makes testing easier (you can mock repositories) and code cleaner.
|
|
240
|
+
|
|
241
|
+
### Database & ORM
|
|
242
|
+
We use a **Code-First** approach.
|
|
243
|
+
1. Define Python classes (`@Entity`).
|
|
244
|
+
2. StarSpring tells SQLAlchemy to map these classes to tables.
|
|
245
|
+
3. If `database.ddl-auto` is set to `create`, the framework creates the tables for you on startup.
|
|
246
|
+
|
|
247
|
+
### Transaction Management
|
|
248
|
+
Use the `@Transactional` decorator on any method (usually in Services).
|
|
249
|
+
* **Success**: The transaction commits automatically.
|
|
250
|
+
* **Reference Counter**: If you nest `@Transactional` methods, the inner one joins the outer transaction.
|
|
251
|
+
* **Error**: If an exception occurs, the entire transaction rolls back.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## 🛠 Advanced Configuration
|
|
256
|
+
|
|
257
|
+
You can tune every part of the framework via `application.yaml`.
|
|
258
|
+
|
|
259
|
+
```yaml
|
|
260
|
+
server:
|
|
261
|
+
port: 8080
|
|
262
|
+
cors:
|
|
263
|
+
allowed-origins: ["*"]
|
|
264
|
+
allowed-methods: ["GET", "POST", "PUT", "DELETE"]
|
|
265
|
+
|
|
266
|
+
logging:
|
|
267
|
+
level: INFO
|
|
268
|
+
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 🤝 Contributing
|
|
274
|
+
|
|
275
|
+
We welcome contributions!
|
|
276
|
+
1. Fork the repository.
|
|
277
|
+
2. Create a feature branch.
|
|
278
|
+
3. Submit a Pull Request.
|
|
279
|
+
|
|
280
|
+
Please ensure all tests pass before submitting.
|
|
281
|
+
|
|
282
|
+
## 📄 License
|
|
283
|
+
|
|
284
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
starspring/__init__.py,sha256=erdKp-lAqhw9iFeIcVamGQAFLVhITCibPvHQFtgha5Q,3411
|
|
2
|
+
starspring/application.py,sha256=J_xMTqwtEBhccTznJA2Be4j-qjh-tJhsOMLMHcE7bf4,14113
|
|
3
|
+
starspring/client/__init__.py,sha256=Bomyz-O3w14OMozOLMa337TvRyEevj5m9bzkiswHnzk,29
|
|
4
|
+
starspring/client/rest_client.py,sha256=ZoecH1eEor3aN9udxqWzjBsfPJcTuRPTTMBG22PzUSI,7298
|
|
5
|
+
starspring/config/__init__.py,sha256=_OSjmqPwe35219tdibkRE7fdbWirb2G-Cz-CWPNC9rY,43
|
|
6
|
+
starspring/config/environment.py,sha256=wSKMYvukbKccB_DVz6fk-BjtQsbnK1EtS9CAUbjLOco,2316
|
|
7
|
+
starspring/config/properties.py,sha256=NEZcmGCSAJL9r69HybsoFeE75h00--M_uWPdGsOw7zI,4878
|
|
8
|
+
starspring/core/__init__.py,sha256=u81P23ha-vTNh50kLwWZMSLinbE-DxSBluYaYIsn2Gk,33
|
|
9
|
+
starspring/core/context.py,sha256=Ho6cLAhDlgCi5l3_mfvNsBUTQn6Z_3xd8C3UiXxvgsg,5914
|
|
10
|
+
starspring/core/controller.py,sha256=IqRCTvKbebeRt5_HzIufK5jEO0qaRJ1ybvtvSytadD0,1459
|
|
11
|
+
starspring/core/exceptions.py,sha256=9cu21pohqA1blzGN5dD5MBmggFc3em4M4vm36Hi1mx4,2879
|
|
12
|
+
starspring/core/response.py,sha256=BMQxL6AcdTevHNQeszqVW0yHN1YNctUKa14AnA_NydA,4717
|
|
13
|
+
starspring/data/__init__.py,sha256=0lBfm1wIj1caWDRF4bZGFtSDYJovMv6VwdmWhP6paBY,1102
|
|
14
|
+
starspring/data/database_config.py,sha256=pQ5ChPap-0m8Kq1sissTjd9vw56yJ80BwuSI6waGzNQ,3656
|
|
15
|
+
starspring/data/entity.py,sha256=gn6rH4VCPzn_oNK_TLxTiKMRKm-gI7vB3JrhYY0hBPU,12404
|
|
16
|
+
starspring/data/orm_gateway.py,sha256=LZfASLvnpdFYguK7_LtV1OnuhqkMwkAmlelLREqqvEI,8558
|
|
17
|
+
starspring/data/query_builder.py,sha256=1ef2S8oNa8tPpZ8qazsbVRglro2oJ7_7u2QhNCKeHCo,11690
|
|
18
|
+
starspring/data/repository.py,sha256=8gjoZ4iImz3J4b_ADs8qQottbkTjNyd9mZ1iZ91j3ko,10075
|
|
19
|
+
starspring/data/schema_generator.py,sha256=r6OqYjsW-HeDVAdlfKb2wAPC6XbedH-0E11pNmynKms,4834
|
|
20
|
+
starspring/data/transaction.py,sha256=kFVrv3xA2EhOXnDcN88QPhLq6rYX9UXC_2EUG_sQGzg,1613
|
|
21
|
+
starspring/decorators/__init__.py,sha256=WSJHi2c_4I1ZX6TzhGCvEgBkFWnCk9NbXKIyjH9ErqY,63
|
|
22
|
+
starspring/decorators/components.py,sha256=wB2CMNnqoJ2VPhQ1Er9_heFQyPLjna7KYKpdmmym1Yw,5288
|
|
23
|
+
starspring/decorators/configuration.py,sha256=XUkzZCusmaoGdQpm17d3x3zVTViXeC231RCfkfr35Ok,2901
|
|
24
|
+
starspring/decorators/routing.py,sha256=rENfRuRkBlpFLn6KSZGIoqnDpMqR0IwriPB5rX9iIC8,10560
|
|
25
|
+
starspring/decorators/validation.py,sha256=wsqvVA_IuGZprwLqbkoZ7Xg3qCK-om_Rxc4RqDU0Nhw,817
|
|
26
|
+
starspring/middleware/__init__.py,sha256=jzho4eY5jLPyUH-kUm6K--RFIF_X1z2oA-I_8EZZ43o,29
|
|
27
|
+
starspring/middleware/cors.py,sha256=74mmat0jYkvLi9x5iytxj4S-QupdH16r2r7k_Cw0iQk,2609
|
|
28
|
+
starspring/middleware/exception.py,sha256=Fk5X5vS-BKNBn0wPzXKStH30Mi8wq1qXGhVjY56-JMI,2685
|
|
29
|
+
starspring/middleware/logging.py,sha256=GXwAujaHcgMWigeS9Vv-cvEIw2E3G5hv15pebepfjmM,1667
|
|
30
|
+
starspring/template/__init__.py,sha256=aNwQaFo8sG-p-Q4bNOHPi4s67jOUIcH845_xggki3MU,387
|
|
31
|
+
starspring/template/engine.py,sha256=9xBcZDRnMdQN1I-ZWf_5tHkpuJhvYlsv-bo2f5boqEk,4794
|
|
32
|
+
starspring/template/model_and_view.py,sha256=qEQblzl3WotfnFVWCF3IcB6AOpCJHS6Hh998m-YFkLU,1799
|
|
33
|
+
starspring-0.1.0.dist-info/METADATA,sha256=R8MiBfqNbAcTL_AVlVzC0InqwD77EvLE1LmN65PCdEM,9572
|
|
34
|
+
starspring-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
35
|
+
starspring-0.1.0.dist-info/top_level.txt,sha256=FWPAl1oRZXxoFa3ePRyY7lmXpde2KMYRX7CBTNDuZtI,11
|
|
36
|
+
starspring-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
starspring
|