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.
- lcore-0.0.1.dist-info/METADATA +340 -0
- lcore-0.0.1.dist-info/RECORD +7 -0
- lcore-0.0.1.dist-info/WHEEL +5 -0
- lcore-0.0.1.dist-info/entry_points.txt +2 -0
- lcore-0.0.1.dist-info/licenses/LICENSE +21 -0
- lcore-0.0.1.dist-info/top_level.txt +1 -0
- lcore.py +5512 -0
|
@@ -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> •
|
|
65
|
+
<a href="https://play.lcore.lusansapkota.com.np">Live Playground</a> •
|
|
66
|
+
<a href="https://lcore.lusansapkota.com.np/getting-started.html">Getting Started</a> •
|
|
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> • 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,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
|