starspring 0.1.0__tar.gz
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-0.1.0/PKG-INFO +284 -0
- starspring-0.1.0/README.md +247 -0
- starspring-0.1.0/pyproject.toml +67 -0
- starspring-0.1.0/setup.cfg +4 -0
- starspring-0.1.0/starspring/__init__.py +150 -0
- starspring-0.1.0/starspring/application.py +421 -0
- starspring-0.1.0/starspring/client/__init__.py +1 -0
- starspring-0.1.0/starspring/client/rest_client.py +220 -0
- starspring-0.1.0/starspring/config/__init__.py +1 -0
- starspring-0.1.0/starspring/config/environment.py +81 -0
- starspring-0.1.0/starspring/config/properties.py +146 -0
- starspring-0.1.0/starspring/core/__init__.py +1 -0
- starspring-0.1.0/starspring/core/context.py +180 -0
- starspring-0.1.0/starspring/core/controller.py +47 -0
- starspring-0.1.0/starspring/core/exceptions.py +82 -0
- starspring-0.1.0/starspring/core/response.py +147 -0
- starspring-0.1.0/starspring/data/__init__.py +47 -0
- starspring-0.1.0/starspring/data/database_config.py +113 -0
- starspring-0.1.0/starspring/data/entity.py +365 -0
- starspring-0.1.0/starspring/data/orm_gateway.py +256 -0
- starspring-0.1.0/starspring/data/query_builder.py +345 -0
- starspring-0.1.0/starspring/data/repository.py +324 -0
- starspring-0.1.0/starspring/data/schema_generator.py +151 -0
- starspring-0.1.0/starspring/data/transaction.py +58 -0
- starspring-0.1.0/starspring/decorators/__init__.py +1 -0
- starspring-0.1.0/starspring/decorators/components.py +179 -0
- starspring-0.1.0/starspring/decorators/configuration.py +102 -0
- starspring-0.1.0/starspring/decorators/routing.py +306 -0
- starspring-0.1.0/starspring/decorators/validation.py +30 -0
- starspring-0.1.0/starspring/middleware/__init__.py +1 -0
- starspring-0.1.0/starspring/middleware/cors.py +90 -0
- starspring-0.1.0/starspring/middleware/exception.py +83 -0
- starspring-0.1.0/starspring/middleware/logging.py +60 -0
- starspring-0.1.0/starspring/template/__init__.py +19 -0
- starspring-0.1.0/starspring/template/engine.py +168 -0
- starspring-0.1.0/starspring/template/model_and_view.py +69 -0
- starspring-0.1.0/starspring.egg-info/PKG-INFO +284 -0
- starspring-0.1.0/starspring.egg-info/SOURCES.txt +39 -0
- starspring-0.1.0/starspring.egg-info/dependency_links.txt +1 -0
- starspring-0.1.0/starspring.egg-info/requires.txt +17 -0
- starspring-0.1.0/starspring.egg-info/top_level.txt +1 -0
|
@@ -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,247 @@
|
|
|
1
|
+
# StarSpring Framework
|
|
2
|
+
|
|
3
|
+
[](https://www.python.org/downloads/)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://pypi.org/project/starspring/)
|
|
6
|
+
|
|
7
|
+
**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.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 🌟 Features
|
|
12
|
+
|
|
13
|
+
* **Dependency Injection (IoC)**: Fully typed, automatic constructor injection. No more global state or manual wiring.
|
|
14
|
+
* **Declarative Routing**: Use `@GetMapping`, `@PostMapping` decorators for clean, readable controllers.
|
|
15
|
+
* **Enterprise ORM**: Built on **SQLAlchemy** with **Imperative Mapping**. Define simple Python classes, and they become powerful database entities automatically.
|
|
16
|
+
* **Magic Repositories**: Define interfaces, and StarSpring implements the queries for you (e.g., `find_by_email_and_active(email, True)`).
|
|
17
|
+
* **Robust Transaction Management**: `@Transactional` decorators with support for robust nested transactions (`SAVEPOINT`s).
|
|
18
|
+
* **Production Ready**: Built-in support for CORS, Exception Handling, Logging, and Configuration Management (`application.yaml`).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 📦 Installation
|
|
23
|
+
|
|
24
|
+
StarSpring requires Python 3.10+.
|
|
25
|
+
|
|
26
|
+
### Using pip
|
|
27
|
+
```bash
|
|
28
|
+
pip install starspring
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Using uv (Recommended for speed)
|
|
32
|
+
```bash
|
|
33
|
+
uv pip install starspring
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Database Drivers
|
|
37
|
+
StarSpring uses SQLAlchemy. Install the driver for your database:
|
|
38
|
+
```bash
|
|
39
|
+
# SQLite (Standard)
|
|
40
|
+
pip install starspring
|
|
41
|
+
|
|
42
|
+
# PostgreSQL
|
|
43
|
+
pip install psycopg2-binary
|
|
44
|
+
# or
|
|
45
|
+
pip install asyncpg
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🚀 Building Your First Application
|
|
51
|
+
|
|
52
|
+
Here is a complete walkthrough of building a User Management API.
|
|
53
|
+
|
|
54
|
+
### 1. Project Structure
|
|
55
|
+
We recommend a standard layered architecture:
|
|
56
|
+
```text
|
|
57
|
+
my_app/
|
|
58
|
+
├── __init__.py
|
|
59
|
+
├── main.py # Entry point
|
|
60
|
+
├── application.yaml # Configuration
|
|
61
|
+
├── entities.py # Database Models
|
|
62
|
+
├── repositories.py # Data Access
|
|
63
|
+
├── services.py # Business Logic
|
|
64
|
+
└── controllers.py # REST Endpoints
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 2. Configuration (`application.yaml`)
|
|
68
|
+
Configure your server and database connection.
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
server:
|
|
72
|
+
port: 8000
|
|
73
|
+
host: 0.0.0.0
|
|
74
|
+
|
|
75
|
+
database:
|
|
76
|
+
url: "sqlite:///app.db" # or postgresql://user:pass@localhost/db
|
|
77
|
+
ddl-auto: "create-if-not-exists" # Auto-creates tables from entities
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3. Entities (`entities.py`)
|
|
81
|
+
Define your database models using standard Python classes. StarSpring maps them automatically.
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from starspring import Entity, BaseEntity, Column, Id, GeneratedValue
|
|
85
|
+
from datetime import datetime
|
|
86
|
+
|
|
87
|
+
@Entity(table_name="users")
|
|
88
|
+
class User(BaseEntity):
|
|
89
|
+
# BaseEntity automatically adds 'id', 'created_at', 'updated_at'
|
|
90
|
+
|
|
91
|
+
username: str = Column(unique=True, length=50, nullable=False)
|
|
92
|
+
email: str = Column(unique=True, nullable=False)
|
|
93
|
+
is_active: bool = Column(default=True)
|
|
94
|
+
role: str = Column(default="USER")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 4. Repositories (`repositories.py`)
|
|
98
|
+
Create an interface for data access. Inherit from `StarRepository`.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from starspring import Repository, StarRepository
|
|
102
|
+
from my_app.entities import User
|
|
103
|
+
|
|
104
|
+
@Repository
|
|
105
|
+
class UserRepository(StarRepository[User, int]):
|
|
106
|
+
# StarSpring automatically implements standard CRUD (save, find_by_id, delete, etc.)
|
|
107
|
+
|
|
108
|
+
# Define custom finders just by naming them!
|
|
109
|
+
async def find_by_username(self, username: str) -> User | None:
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
async def find_by_email_and_is_active(self, email: str, is_active: bool) -> User | None:
|
|
113
|
+
...
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 5. Services (`services.py`)
|
|
117
|
+
Encapsulate your business logic here. Use `@Transactional` to ensure data integrity.
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from starspring import Service, Transactional
|
|
121
|
+
from my_app.repositories import UserRepository
|
|
122
|
+
from my_app.entities import User
|
|
123
|
+
|
|
124
|
+
@Service
|
|
125
|
+
class UserService:
|
|
126
|
+
# Dependency Injection: Just mention the type in the constructor!
|
|
127
|
+
def __init__(self, user_repo: UserRepository):
|
|
128
|
+
self.user_repo = user_repo
|
|
129
|
+
|
|
130
|
+
@Transactional
|
|
131
|
+
async def register_user(self, username: str, email: str) -> User:
|
|
132
|
+
# Check if exists
|
|
133
|
+
existing = await self.user_repo.find_by_email_and_is_active(email, True)
|
|
134
|
+
if existing:
|
|
135
|
+
raise ValueError("User already exists")
|
|
136
|
+
|
|
137
|
+
# Create new user
|
|
138
|
+
new_user = User(username=username, email=email)
|
|
139
|
+
return await self.user_repo.save(new_user)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 6. Controllers (`controllers.py`)
|
|
143
|
+
Expose your logic as a REST API.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from starspring import RestController, GetMapping, PostMapping
|
|
147
|
+
from starspring.web.response import ResponseEntity
|
|
148
|
+
from my_app.services import UserService
|
|
149
|
+
|
|
150
|
+
@RestController("/api/users")
|
|
151
|
+
class UserController:
|
|
152
|
+
|
|
153
|
+
def __init__(self, user_service: UserService):
|
|
154
|
+
self.user_service = user_service
|
|
155
|
+
|
|
156
|
+
@GetMapping("/{username}")
|
|
157
|
+
async def get_user(self, username: str) -> dict:
|
|
158
|
+
# You can return dicts, lists, or Entities directly
|
|
159
|
+
user = await self.user_service.user_repo.find_by_username(username)
|
|
160
|
+
return user.to_dict() if user else ResponseEntity.not_found()
|
|
161
|
+
|
|
162
|
+
@PostMapping("/register")
|
|
163
|
+
async def register(self, username: str, email: str) -> dict:
|
|
164
|
+
# Arguments are automatically extracted from JSON body or Query params
|
|
165
|
+
try:
|
|
166
|
+
user = await self.user_service.register_user(username, email)
|
|
167
|
+
return {"status": "success", "user_id": user.id}
|
|
168
|
+
except ValueError as e:
|
|
169
|
+
return ResponseEntity.bad_request(str(e))
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 7. Main Entry Point (`main.py`)
|
|
173
|
+
Bootstrap the application.
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from starspring import StarSpringApplication
|
|
177
|
+
|
|
178
|
+
# Initialize App
|
|
179
|
+
app = StarSpringApplication(
|
|
180
|
+
title="My User API",
|
|
181
|
+
config_path="application.yaml"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Scan for all your components (Controllers, Services, Repositories)
|
|
185
|
+
app.scan_components("my_app")
|
|
186
|
+
|
|
187
|
+
if __name__ == "__main__":
|
|
188
|
+
# Runs the server (default: localhost:8000)
|
|
189
|
+
app.run()
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 📚 Core Concepts
|
|
195
|
+
|
|
196
|
+
### Dependency Injection (DI)
|
|
197
|
+
StarSpring manages the lifecycle of your objects. When you ask for a `UserRepository` in your `UserService` constructor, the framework:
|
|
198
|
+
1. Finds the `UserRepository` class.
|
|
199
|
+
2. Creates an instance of it (Singleton by default).
|
|
200
|
+
3. Passes it to your `UserService`.
|
|
201
|
+
|
|
202
|
+
This makes testing easier (you can mock repositories) and code cleaner.
|
|
203
|
+
|
|
204
|
+
### Database & ORM
|
|
205
|
+
We use a **Code-First** approach.
|
|
206
|
+
1. Define Python classes (`@Entity`).
|
|
207
|
+
2. StarSpring tells SQLAlchemy to map these classes to tables.
|
|
208
|
+
3. If `database.ddl-auto` is set to `create`, the framework creates the tables for you on startup.
|
|
209
|
+
|
|
210
|
+
### Transaction Management
|
|
211
|
+
Use the `@Transactional` decorator on any method (usually in Services).
|
|
212
|
+
* **Success**: The transaction commits automatically.
|
|
213
|
+
* **Reference Counter**: If you nest `@Transactional` methods, the inner one joins the outer transaction.
|
|
214
|
+
* **Error**: If an exception occurs, the entire transaction rolls back.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 🛠 Advanced Configuration
|
|
219
|
+
|
|
220
|
+
You can tune every part of the framework via `application.yaml`.
|
|
221
|
+
|
|
222
|
+
```yaml
|
|
223
|
+
server:
|
|
224
|
+
port: 8080
|
|
225
|
+
cors:
|
|
226
|
+
allowed-origins: ["*"]
|
|
227
|
+
allowed-methods: ["GET", "POST", "PUT", "DELETE"]
|
|
228
|
+
|
|
229
|
+
logging:
|
|
230
|
+
level: INFO
|
|
231
|
+
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 🤝 Contributing
|
|
237
|
+
|
|
238
|
+
We welcome contributions!
|
|
239
|
+
1. Fork the repository.
|
|
240
|
+
2. Create a feature branch.
|
|
241
|
+
3. Submit a Pull Request.
|
|
242
|
+
|
|
243
|
+
Please ensure all tests pass before submitting.
|
|
244
|
+
|
|
245
|
+
## 📄 License
|
|
246
|
+
|
|
247
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "starspring"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A Spring Boot-inspired Python web framework built on Starlette"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "StarSpring Contributors"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["web", "framework", "starlette", "spring-boot", "dependency-injection"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
|
|
25
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
dependencies = [
|
|
29
|
+
"starlette>=0.27.0",
|
|
30
|
+
"pydantic>=2.0.0",
|
|
31
|
+
"uvicorn[standard]>=0.23.0",
|
|
32
|
+
"python-multipart>=0.0.6",
|
|
33
|
+
"pyyaml>=6.0",
|
|
34
|
+
"httpx>=0.24.0",
|
|
35
|
+
"jinja2>=3.1.6",
|
|
36
|
+
"sqlalchemy>=2.0.46",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=7.4.0",
|
|
42
|
+
"pytest-asyncio>=0.21.0",
|
|
43
|
+
"black>=23.7.0",
|
|
44
|
+
"mypy>=1.5.0",
|
|
45
|
+
]
|
|
46
|
+
sqlalchemy = [
|
|
47
|
+
"sqlalchemy>=2.0.0",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[project.urls]
|
|
51
|
+
Homepage = "https://github.com/yourusername/starspring"
|
|
52
|
+
Documentation = "https://github.com/yourusername/starspring#readme"
|
|
53
|
+
Repository = "https://github.com/yourusername/starspring"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.packages.find]
|
|
56
|
+
where = ["."]
|
|
57
|
+
include = ["starspring*"]
|
|
58
|
+
|
|
59
|
+
[tool.black]
|
|
60
|
+
line-length = 100
|
|
61
|
+
target-version = ['py310']
|
|
62
|
+
|
|
63
|
+
[tool.mypy]
|
|
64
|
+
python_version = "3.10"
|
|
65
|
+
warn_return_any = true
|
|
66
|
+
warn_unused_configs = true
|
|
67
|
+
disallow_untyped_defs = false
|