lcore 0.0.1__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.
@@ -0,0 +1,340 @@
1
+ Metadata-Version: 2.4
2
+ Name: lcore
3
+ Version: 0.0.1
4
+ Summary: A fast, lightweight, single-file Python WSGI framework with zero dependencies.
5
+ Author-email: Lusan Sapkota <sapkotalusan@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://lcore.lusansapkota.com.np
8
+ Project-URL: Documentation, https://lcore.lusansapkota.com.np
9
+ Project-URL: Repository, https://github.com/LusanSapkota/Lcore
10
+ Project-URL: Issues, https://github.com/LusanSapkota/Lcore/issues
11
+ Project-URL: Changelog, https://github.com/LusanSapkota/Lcore/releases
12
+ Keywords: web,framework,wsgi,microframework,api,rest,http,server,middleware,routing
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
24
+ Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
26
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
27
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Provides-Extra: ujson
32
+ Requires-Dist: ujson; extra == "ujson"
33
+ Provides-Extra: jinja2
34
+ Requires-Dist: jinja2; extra == "jinja2"
35
+ Provides-Extra: mako
36
+ Requires-Dist: mako; extra == "mako"
37
+ Provides-Extra: gunicorn
38
+ Requires-Dist: gunicorn; extra == "gunicorn"
39
+ Provides-Extra: waitress
40
+ Requires-Dist: waitress; extra == "waitress"
41
+ Provides-Extra: gevent
42
+ Requires-Dist: gevent; extra == "gevent"
43
+ Provides-Extra: eventlet
44
+ Requires-Dist: eventlet; extra == "eventlet"
45
+ Provides-Extra: watchdog
46
+ Requires-Dist: watchdog; extra == "watchdog"
47
+ Provides-Extra: dev
48
+ Requires-Dist: pytest; extra == "dev"
49
+ Requires-Dist: ujson; extra == "dev"
50
+ Dynamic: license-file
51
+
52
+ <p align="center">
53
+ <img src="docs/lcore.png" alt="Lcore" width="80">
54
+ </p>
55
+
56
+ <h1 align="center">Lcore</h1>
57
+
58
+ <p align="center">
59
+ A fast, lightweight, single-file Python WSGI framework with zero dependencies.<br>
60
+ Inspired by the simplicity of <a href="https://bottlepy.org">Bottle</a>.
61
+ </p>
62
+
63
+ <p align="center">
64
+ <a href="https://lcore.lusansapkota.com.np">Documentation</a> &bull;
65
+ <a href="https://play.lcore.lusansapkota.com.np">Live Playground</a> &bull;
66
+ <a href="https://lcore.lusansapkota.com.np/getting-started.html">Getting Started</a> &bull;
67
+ <a href="https://lcore.lusansapkota.com.np/api-reference.html">API Reference</a>
68
+ </p>
69
+
70
+ <p align="center">
71
+ <img src="https://img.shields.io/badge/python-3.8%2B-blue" alt="Python 3.8+">
72
+ <img src="https://img.shields.io/badge/version-0.0.1-informational" alt="v0.0.1">
73
+ <img src="https://img.shields.io/badge/status-early%20release-orange" alt="Early Release">
74
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="MIT">
75
+ <img src="https://img.shields.io/badge/dependencies-none-brightgreen" alt="Zero Dependencies">
76
+ </p>
77
+
78
+ ---
79
+
80
+ ## Installation
81
+
82
+ ```bash
83
+ pip install lcore
84
+ ```
85
+
86
+ > **Note:** `pip install lcore` pulls the latest **stable, tagged release** and is the recommended way to install.
87
+ >
88
+ > Copying `lcore.py` directly from the `main` branch may include unreleased or experimental changes. If you prefer copying the file, always use a **tagged release** (e.g. `v0.0.1`) from the [Releases](https://github.com/Lusan-sapkota/lcore/releases) page to ensure stability.
89
+
90
+ ## Quick Start
91
+
92
+ ```python
93
+ from lcore import Lcore
94
+
95
+ app = Lcore()
96
+
97
+ @app.route('/hello')
98
+ def hello():
99
+ return {'message': 'Hello, World!'}
100
+
101
+ app.run(host='0.0.0.0', port=8080)
102
+ ```
103
+
104
+ > **Async note:** `async def` route handlers are accepted but the worker thread is blocked for the duration -- there is no concurrency benefit. See the [async caveat](https://lcore.lusansapkota.com.np/routing.html#async-routes) before using them.
105
+
106
+ **Performance:** In internal benchmarks, Lcore processes roughly 90,000 -- 120,000 requests/sec on simple JSON and plaintext routes (single process, no I/O), which is approximately 3 -- 4x higher throughput than Flask under the same conditions. Results vary by hardware and workload.
107
+
108
+ ## Features
109
+
110
+ - **Single file, zero dependencies** -- drop `lcore.py` into any project
111
+ - **Full WSGI compliance** -- works with Gunicorn, uWSGI, Waitress, Gevent, and 17 more server adapters
112
+ - **Async/await** -- `async def` route handlers are accepted; note that the worker thread is blocked for the duration (WSGI constraint). See [async caveat](https://lcore.lusansapkota.com.np/routing.html#async-routes).
113
+ - **7 built-in middleware** -- CORS, CSRF, security headers, gzip compression, body limits, request ID, structured logging
114
+ - **Security** -- PBKDF2 password hashing, HMAC-SHA256 signed cookies, rate limiting, timing-safe comparison
115
+ - **Dependency injection** -- singleton, scoped, and transient lifetimes
116
+ - **Plugin system** -- JSON serialization, template rendering, and custom plugins with setup/apply lifecycle
117
+ - **Request validation** -- JSON body and query parameter validation with type checking
118
+ - **Built-in test client** -- `TestClient` for unit testing routes without starting a server
119
+ - **Background tasks** -- `BackgroundTaskPool` for fire-and-forget work (emails, cleanup, analytics)
120
+ - **4 template engines** -- built-in SimpleTemplate, plus Jinja2, Mako, and Cheetah adapters
121
+ - **12 lifecycle hooks** -- request start, auth, handler enter/exit, response build/send, and more
122
+ - **Module mounting** -- compose sub-applications with isolated routes and middleware
123
+ - **21 server adapters** -- use `server='auto'` to auto-select the best available
124
+
125
+ ## Why Lcore Exists
126
+
127
+ Most Python web frameworks make one of two trade-offs:
128
+
129
+ - **Simple and fast** (Bottle) -- single file, zero deps, but no middleware stack, no DI, no security primitives, no lifecycle hooks.
130
+ - **Full-featured** (Flask, Django) -- lots of extensions, but each extension is a dependency, and the base framework is slow.
131
+
132
+ Lcore was built to close that gap. The goal is a framework that you can drop into any environment as a single file with no `pip install`, that includes a production-ready middleware stack, security primitives, dependency injection, and lifecycle hooks out of the box -- without reaching for extensions.
133
+
134
+ It is inspired by the minimalism of [Bottle](https://bottlepy.org) and uses the same single-file approach, but ships with the features that Bottle leaves to you.
135
+
136
+ ## Design Philosophy
137
+
138
+ - **One file only.** The entire framework is `lcore.py`. No package structure, no sub-modules, no build step. Drop it in, import it, done.
139
+ - **Zero external dependencies.** Every import is from Python's standard library (`hashlib`, `threading`, `json`, `gzip`, `logging`, `asyncio`, `http`). Works in air-gapped environments, containers, and serverless functions where `pip` may not be available.
140
+ - **Production features built-in, not bolted on.** CORS, CSRF, security headers, rate limiting, signed cookies, and password hashing are part of the framework. You should not need to install five extensions to secure a production API.
141
+ - **Honest about limitations.** Lcore is WSGI. It documents and warns loudly when a feature has constraints (async handlers, per-process rate limiting, thread-blocking timeouts). No surprises.
142
+ - **Standard Python throughout.** No metaclass magic, no descriptor abuse, no import-time side effects beyond what is declared. The source is meant to be read.
143
+ - **449 tests, zero external test dependencies.** The test suite uses only `unittest` from the standard library.
144
+
145
+ ## When NOT to use Lcore
146
+
147
+ Lcore is the right choice for many synchronous WSGI workloads, but it is the wrong choice in these situations:
148
+
149
+ | Situation | Better choice |
150
+ |-----------|---------------|
151
+ | You need WebSockets or real-time async I/O | FastAPI, Starlette, Quart |
152
+ | You need true async concurrency (hundreds of simultaneous outbound HTTP calls, async DB drivers) | FastAPI, Starlette |
153
+ | Your team is already on Flask and the migration cost outweighs any benefit | Stay on Flask |
154
+ | You need automatic OpenAPI / Swagger generation | FastAPI |
155
+ | You need ASGI and Uvicorn / Daphne | FastAPI, Starlette |
156
+ | Your workload is I/O-bound and you want event-loop concurrency | FastAPI, Starlette |
157
+ | You need a full MVC framework with ORM, admin panel, and migrations | Django |
158
+
159
+ If your workload is primarily synchronous -- REST APIs, internal services, background job APIs, microservices that talk to SQL databases via sync drivers -- Lcore is a strong fit.
160
+
161
+ ## Ideal Use Cases
162
+
163
+ - **Internal REST APIs** -- admin panels, dashboards, data pipelines that talk to a SQL database via psycopg2, sqlite3, or mysqlclient
164
+ - **Microservices with no async I/O** -- services that call other services synchronously, process files, hash passwords, or do CPU-bound work
165
+ - **Rapid prototyping** -- drop in a single file, no virtual environment ceremony, start handling requests in minutes
166
+ - **Air-gapped or restricted environments** -- zero external dependencies means no supply-chain risk and no `pip` access required
167
+ - **Embedded or constrained deployments** -- containers, serverless functions, or edge nodes where you want the smallest possible footprint
168
+ - **Teams moving off Bottle** -- familiar single-file philosophy with middleware, DI, and security built in
169
+ - **Scripts that occasionally serve HTTP** -- background workers, CLI tools, or data jobs that also expose a health check or webhook endpoint
170
+
171
+ ## Live Demo & Documentation
172
+
173
+ | Link | Description |
174
+ |------|-------------|
175
+ | [play.lcore.lusansapkota.com.np](https://play.lcore.lusansapkota.com.np) | Interactive playground -- test routes, middleware, auth flows, and API endpoints live |
176
+ | [lcore.lusansapkota.com.np](https://lcore.lusansapkota.com.np) | Full documentation with guides, API reference, and real-world example |
177
+
178
+ The playground runs the TaskFlow demo backend -- a complete project management API (like Trello/Jira) that demonstrates every Lcore feature: token auth, RBAC, CRUD, file uploads, SMTP email, async handlers, middleware stack, dependency injection, plugins, and a full SPA frontend.
179
+
180
+ **Demo credentials:**
181
+
182
+ | Username | Password | Role |
183
+ |----------|----------|------|
184
+ | admin | admin123 | admin |
185
+ | alice | alice123 | member |
186
+ | bob | bob123 | member |
187
+
188
+ ## Production Example
189
+
190
+ ```python
191
+ from lcore import (
192
+ Lcore, request, response, ctx, on_shutdown,
193
+ CORSMiddleware, SecurityHeadersMiddleware,
194
+ BodyLimitMiddleware, CompressionMiddleware,
195
+ hash_password, verify_password,
196
+ BackgroundTaskPool, TestClient,
197
+ rate_limit, validate_request,
198
+ )
199
+
200
+ app = Lcore()
201
+
202
+ # Middleware stack
203
+ app.use(BodyLimitMiddleware(max_size=10 * 1024 * 1024))
204
+ app.use(SecurityHeadersMiddleware(hsts=True))
205
+ app.use(CORSMiddleware(allow_origins=['https://myapp.com']))
206
+ app.use(CompressionMiddleware())
207
+
208
+ # Background tasks
209
+ tasks = BackgroundTaskPool(max_workers=4)
210
+
211
+ # Secure password hashing (PBKDF2-SHA256)
212
+ @app.post('/register')
213
+ @validate_request(body={'username': str, 'password': str})
214
+ def register():
215
+ data = request.json
216
+ hashed = hash_password(data['password'])
217
+ # store hashed in database...
218
+ return {'created': True}
219
+
220
+ @app.post('/login')
221
+ @rate_limit(5, per=300) # NOTE: per-process — see "Multi-worker" note below
222
+ def login():
223
+ data = request.json
224
+ user = db.find_user(data['username'])
225
+ if user and verify_password(data['password'], user['password_hash']):
226
+ return {'token': generate_token(user)}
227
+ return {'error': 'Invalid credentials'}
228
+
229
+ # Graceful shutdown
230
+ @on_shutdown
231
+ def cleanup():
232
+ tasks.shutdown(wait=True)
233
+
234
+ app.run(server='gunicorn', host='0.0.0.0', port=8080, workers=4)
235
+ ```
236
+
237
+ ## Production Notes
238
+
239
+ ### Rate limiter is per-process
240
+ `@rate_limit` uses an in-process token bucket with 64-stripe locking. Under a
241
+ multi-worker server (e.g. `gunicorn -w 4`) each worker has its own independent
242
+ bucket store, so the effective per-client rate limit is `N × limit`.
243
+ **Lcore ships a built-in `RedisRateLimitBackend` — no extra code required:**
244
+
245
+ ```bash
246
+ pip install redis
247
+ ```
248
+
249
+ ```python
250
+ from lcore import RedisRateLimitBackend, rate_limit
251
+
252
+ _rl = RedisRateLimitBackend('redis://localhost:6379/0')
253
+
254
+ @app.post('/api/login')
255
+ @rate_limit(5, per=300, backend=_rl) # enforced across all workers
256
+ def login(): ...
257
+ ```
258
+
259
+ If Redis is unavailable the backend **fails open** (allows the request) and logs
260
+ a warning so a Redis outage does not take down your application.
261
+
262
+ Temporary workaround (no Redis): `@rate_limit(5 // num_workers, per=300)`.
263
+
264
+ ### Reverse proxies — always use ProxyFixMiddleware
265
+ Without it, `request.remote_addr` returns the proxy's IP, not the real client, and
266
+ `request.url` may use the wrong scheme (`http` instead of `https`). Add it first:
267
+
268
+ ```python
269
+ app.use(ProxyFixMiddleware(trusted_proxies=['10.0.0.1'])) # your proxy's IP(s)
270
+ ```
271
+
272
+ ### Request timeouts
273
+ `TimeoutMiddleware` uses a **persistent thread pool** (not per-request), so it is safe to use
274
+ under load. It returns 503 to the client when the deadline is exceeded, but the handler thread
275
+ continues running in the background — Python has no safe way to kill a thread. Avoid handlers
276
+ that block indefinitely.
277
+
278
+ ```python
279
+ app.use(TimeoutMiddleware(timeout=30))
280
+ ```
281
+
282
+ ## Testing
283
+
284
+ ```python
285
+ from lcore import Lcore, TestClient
286
+
287
+ app = Lcore()
288
+
289
+ @app.route('/api/users/<id:int>')
290
+ def get_user(id):
291
+ return {'id': id, 'name': 'Alice'}
292
+
293
+ client = TestClient(app)
294
+
295
+ resp = client.get('/api/users/1')
296
+ assert resp.status_code == 200
297
+ assert resp.json['name'] == 'Alice'
298
+
299
+ resp = client.post('/api/items', json={'name': 'Widget'})
300
+ assert resp.status_code == 200
301
+ ```
302
+
303
+ ## Project Structure
304
+
305
+ ```
306
+ Lcore/
307
+ lcore.py # The framework (single file)
308
+ backend/ # TaskFlow demo -- real-world example using every feature
309
+ app.py # Main entry point
310
+ config.py # Multi-source config + validation
311
+ models.py # SQLite database layer
312
+ modules/ # Auth, users, projects, notifications, plugins
313
+ templates/ # Welcome page, frontend SPA, error page
314
+ tests/ # 449 tests (unittest)
315
+ docs/ # Documentation site (hosted at lcore.lusansapkota.com.np)
316
+ benchmarks/ # Performance benchmarks
317
+ ```
318
+
319
+ ## Documentation
320
+
321
+ Full documentation at **[lcore.lusansapkota.com.np](https://lcore.lusansapkota.com.np)**
322
+
323
+ - [Getting Started](https://lcore.lusansapkota.com.np/getting-started.html) -- installation, first app, core concepts
324
+ - [Routing](https://lcore.lusansapkota.com.np/routing.html) -- typed parameters, groups, async handlers
325
+ - [Request/Response](https://lcore.lusansapkota.com.np/request-response.html) -- JSON, files, cookies, headers
326
+ - [Middleware](https://lcore.lusansapkota.com.np/middleware.html) -- built-in and custom middleware
327
+ - [Plugins](https://lcore.lusansapkota.com.np/plugins.html) -- plugin system and lifecycle
328
+ - [Advanced](https://lcore.lusansapkota.com.np/advanced.html) -- DI, security, testing, background tasks, production deployment
329
+ - [API Reference](https://lcore.lusansapkota.com.np/api-reference.html) -- complete class and function reference
330
+ - [Real-World Example](https://lcore.lusansapkota.com.np/real-world-example.html) -- TaskFlow backend walkthrough
331
+
332
+ ## License
333
+
334
+ MIT -- see [LICENSE](LICENSE) for details.
335
+
336
+ ---
337
+
338
+ <p align="center">
339
+ Built by <a href="https://lusansapkota.com.np">Lusan Sapkota</a> &bull; Inspired by <a href="https://bottlepy.org">Bottle</a>
340
+ </p>
@@ -0,0 +1,7 @@
1
+ lcore.py,sha256=RH-DXWLBQRv4b-OJiyWGpCcv66rfLZnzH5TMf3cSuR8,202157
2
+ lcore-0.0.1.dist-info/licenses/LICENSE,sha256=-ipijD0wtyNdgskw8rzmIadDfEcoLqe9rcUd_YNj_3U,1070
3
+ lcore-0.0.1.dist-info/METADATA,sha256=R1u8cQibXFFZOfX4WLb84P3II8bKRRaK1g91kgryVCA,15678
4
+ lcore-0.0.1.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
5
+ lcore-0.0.1.dist-info/entry_points.txt,sha256=WyIEOhsL2g6iSHpWAioTf2Dn5hECnIt4TTdxmNvwheI,37
6
+ lcore-0.0.1.dist-info/top_level.txt,sha256=fg7dnJr59wIeyIukxgoCm1xrLCzUXCHv-1FwUsdsxqE,6
7
+ lcore-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ lcore = lcore:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lusan Sapkota
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ lcore