| Name | bbwebservice JSON |
| Version |
2.2.0
JSON |
| download |
| home_page | None |
| Summary | A bare bone webserver |
| upload_time | 2025-10-16 10:49:31 |
| maintainer | None |
| docs_url | None |
| author | Lukas |
| requires_python | >=3.10 |
| license | None |
| keywords |
|
| VCS |
|
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
# bbwebservice
`bbwebservice` is a lightweight Python library for building small webservers. It keeps the original simplicity but now ships with multi-endpoint support, chunked request handling, scoped routing and a bounded worker pool.
## Installation
```bash
pip install bbwebservice
```
## Usage
- import helpers:
```python
from bbwebservice.webserver import *
from bbwebservice import core
```
### 1. Register pages for HTTP `GET`
- `@register(route=..., type=...)` registers a handler for a GET route.
- `route` accepts either a plain string or the selector syntax `ip:port::domain:/path`. Examples:
* `'::/status'` – matches every endpoint
* `'127.0.0.1::/debug'` – IPv4 127.0.0.1 on any port and any domain
* `':::example.com:/info'` – any IP/port, only domain `example.com`
* `UrlTemplate('[::1]:8000::/v1/{slug:str}')` – IPv6 with typed placeholders
- `type` specifies the MIME type of the response.
```python
@register(route='::/hello', type=MIME_TYPE.TEXT)
def hello():
return 'Hello World'
```
### 2. Register pages for HTTP `POST`
- `@post_handler` works like `@register` but the decorated function must accept an `args` parameter.
```python
@post_handler(route='::/login', type=MIME_TYPE.JSON)
def login(args):
payload = args[STORE_VARS.POST].decode('utf-8')
return {'status': 'ok', 'raw': payload}
```
### 3. Register handlers for other HTTP verbs
- Additional decorators mirror `@post_handler`:
* `@put_handler(...)`
* `@patch_handler(...)`
* `@delete_handler(...)`
* `@options_handler(...)`
- They share the same selector syntax and MIME type handling. `OPTIONS` handlers may omit the `args` parameter if you only need static responses; `HEAD` automatically reuses the corresponding `GET` handler and suppresses the body.
```python
@put_handler(route='::/items/{slug:str}', type=MIME_TYPE.JSON)
def update_item(args):
data = json.loads(args[STORE_VARS.POST].decode('utf-8'))
return {'slug': args[STORE_VARS.TEMPLATE_VARS]['slug'], 'data': data}
@options_handler(route='::/items/*', type=MIME_TYPE.TEXT)
def describe_items():
return 'Allowed: GET, POST, PUT, DELETE, PATCH'
```
### 4. Redirects
- Return a `Redirect` object to send 303/307 style responses.
```python
@register(route='::/old', type=MIME_TYPE.HTML)
def legacy():
return Redirect('/new')
```
### 5. Partial content / streaming
- Use `PartialContent` for ranged responses (video, downloads, etc.).
```python
@register(route='::/video', type=MIME_TYPE.MP4)
def video(_):
return PartialContent('/content/movie.mp4', default_size=80_000)
```
### 6. Error handler
- `@error_handler(error_code=..., type=...)` provides fallback pages.
```python
@error_handler(error_code=404, type=MIME_TYPE.HTML)
def not_found():
return load_file('/content/404.html')
```
### 7. Handler arguments
- Handlers that accept args can read or modify cookies, headers, query strings, etc.
```python
@register(route='::/inspect', type=MIME_TYPE.JSON)
def inspect(args):
args['response'].header.add_header_line(
Header_Line(Response_Header_Tag.SERVER, 'bbwebservice')
)
return args
```
### 8. Start the server
- Use `core.start()` to launch all configured listeners.
```python
@register(route='::/index', type=MIME_TYPE.HTML)
def index():
return load_file('/content/index.html')
core.start()
```
### 9. URL templates
- Dynamic routes use `UrlTemplate` with typed placeholders.
| Supported Types | Example |
|-----------------|--------------------|
| `str` | `{name:str}` |
| `int` | `{id:int}` |
| `float` | `{value:float}` |
| `bool` | `{flag:bool}` |
| `path` | `{path:path}` |
```python
@register(route=UrlTemplate('::/user/{name:str}/{age:int}'), type=MIME_TYPE.JSON)
def user(args):
return args[STORE_VARS.TEMPLATE_VARS]
```
### 10. Selector hierarchy
- The most specific selector wins automatically (IP > port > domain > global). Register routes knowing that concrete bindings take precedence over generic ones.
### 11. Response helpers
- In addition to returning bytes/strings, you can respond with:
* `Dynamic(content, mime_type)` – content with a custom MIME type
* `PartialContent` / `Redirect`
* `Response(...)` – convenience for setting status, headers, body in one object
### 12. Background tasks
- `server_task(func, interval)` schedules functions (receives global state if `data` parameter present). Tasks shut down gracefully with the server.
### 13. CORS
- Enable or disable at runtime:
```python
webserver.enable_cors(
allow_origin="*",
allow_methods=["GET", "POST"],
allow_headers=["Content-Type"],
expose_headers=["X-Total-Count"],
allow_credentials=False,
max_age=600,
)
```
`disable_cors()` and `get_cors_settings()` are provided as well. OPTIONS requests are answered automatically when CORS is active.
### 14. Worker pool and backpressure
- All listeners share a bounded worker pool. If the queue is full, new connections get `503 Service Unavailable`. Per-listener `max_threads` throttle accept loops, while the global `max_threads` (see config) bounds total concurrency.
### 15. Request parsing
- Headers are read incrementally up to `max_header_size`, bodies honour `Content-Length` or `Transfer-Encoding: chunked` (trailers are skipped). Chunked data is decoded into the `args[STORE_VARS.POST]` buffer. Oversized requests trigger 413/431 responses.
### 16. Logging
- Logging honours scopes (`ip:port::domain`) and only formats messages when a sink is active.
```python
set_logging(LOGGING_OPTIONS.INFO, True)
log_to_file('/logs/server.log', [LOGGING_OPTIONS.ERROR, LOGGING_OPTIONS.INFO])
set_logging_callback(lambda msg, ts, lvl: print('[callback]', lvl, msg))
```
There is also `webserver.response()` for building structured responses and `log()` for manual logging with scopes.
## Server Configuration
`config/config.json` controls listeners and limits:
```json
{
"max_threads": 100,
"max_header_size": 16384,
"max_body_size": 10485760,
"server": [
{
"ip": "default",
"port": 5000,
"queue_size": 50,
"max_threads": 25,
"SSL": false,
"host": "",
"cert_path": "",
"key_path": "",
"https-redirect": false,
"https-redirect-escape-paths": [],
"update-cert-state": false
}
]
}
```
* `ip`: `default` resolves at runtime, otherwise explicit IPv4/IPv6 (use `[::1]` style).
* Multiple entries in `server` bind additional sockets.
* `SSL` with `host` as list enables SNI (each entry supplies `host`, `cert_path`, `key_path`). Failed certificates are logged with full paths.
* `https-redirect` forces 301 to HTTPS except for paths listed in `https-redirect-escape-paths` (supports wildcard suffix `*`).
* `update-cert-state` watches certificate files and reloads them automatically.
Recommended ports: 5000 (local), 80 (HTTP), 443/8443 (HTTPS).
## Logging recap
```python
set_logging(LOGGING_OPTIONS.DEBUG, True)
set_logging(LOGGING_OPTIONS.TIME, True)
log_to_file()
```
Use `set_logging(scope='127.0.0.1:5000::example.com', ...)` to target specific endpoints.
## Testing
Run the integration script:
```bash
python testing/test_bbwebservice_example.py
```
It covers chunked uploads, CORS preflights, domain/IP selectors and redirects.
## License
MIT License © Lukas Walker (see `LICENSE` for details).
Raw data
{
"_id": null,
"home_page": null,
"name": "bbwebservice",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": null,
"author": "Lukas",
"author_email": "lukasogwalker@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/63/a7/a21f2f7727383113af25bcbe011b6efa31b0d03cf775f9450ad980714ee2/bbwebservice-2.2.0.tar.gz",
"platform": null,
"description": "# bbwebservice\n\n`bbwebservice` is a lightweight Python library for building small webservers. It keeps the original simplicity but now ships with multi-endpoint support, chunked request handling, scoped routing and a bounded worker pool.\n\n## Installation\n\n```bash\npip install bbwebservice\n```\n\n## Usage\n\n- import helpers:\n\n```python\nfrom bbwebservice.webserver import *\nfrom bbwebservice import core\n```\n\n### 1. Register pages for HTTP `GET`\n - `@register(route=..., type=...)` registers a handler for a GET route.\n - `route` accepts either a plain string or the selector syntax `ip:port::domain:/path`. Examples:\n * `'::/status'` \u2013 matches every endpoint\n * `'127.0.0.1::/debug'` \u2013 IPv4 127.0.0.1 on any port and any domain\n * `':::example.com:/info'` \u2013 any IP/port, only domain `example.com`\n * `UrlTemplate('[::1]:8000::/v1/{slug:str}')` \u2013 IPv6 with typed placeholders\n - `type` specifies the MIME type of the response.\n\n```python\n@register(route='::/hello', type=MIME_TYPE.TEXT)\ndef hello():\n return 'Hello World'\n```\n\n### 2. Register pages for HTTP `POST`\n - `@post_handler` works like `@register` but the decorated function must accept an `args` parameter.\n\n```python\n@post_handler(route='::/login', type=MIME_TYPE.JSON)\ndef login(args):\n payload = args[STORE_VARS.POST].decode('utf-8')\n return {'status': 'ok', 'raw': payload}\n```\n\n### 3. Register handlers for other HTTP verbs\n - Additional decorators mirror `@post_handler`:\n * `@put_handler(...)`\n * `@patch_handler(...)`\n * `@delete_handler(...)`\n * `@options_handler(...)`\n - They share the same selector syntax and MIME type handling. `OPTIONS` handlers may omit the `args` parameter if you only need static responses; `HEAD` automatically reuses the corresponding `GET` handler and suppresses the body.\n\n```python\n@put_handler(route='::/items/{slug:str}', type=MIME_TYPE.JSON)\ndef update_item(args):\n data = json.loads(args[STORE_VARS.POST].decode('utf-8'))\n return {'slug': args[STORE_VARS.TEMPLATE_VARS]['slug'], 'data': data}\n\n@options_handler(route='::/items/*', type=MIME_TYPE.TEXT)\ndef describe_items():\n return 'Allowed: GET, POST, PUT, DELETE, PATCH'\n```\n\n### 4. Redirects\n - Return a `Redirect` object to send 303/307 style responses.\n\n```python\n@register(route='::/old', type=MIME_TYPE.HTML)\ndef legacy():\n return Redirect('/new')\n```\n\n### 5. Partial content / streaming\n - Use `PartialContent` for ranged responses (video, downloads, etc.).\n\n```python\n@register(route='::/video', type=MIME_TYPE.MP4)\ndef video(_):\n return PartialContent('/content/movie.mp4', default_size=80_000)\n```\n\n### 6. Error handler\n - `@error_handler(error_code=..., type=...)` provides fallback pages.\n\n```python\n@error_handler(error_code=404, type=MIME_TYPE.HTML)\ndef not_found():\n return load_file('/content/404.html')\n```\n\n### 7. Handler arguments\n - Handlers that accept args can read or modify cookies, headers, query strings, etc.\n\n```python\n@register(route='::/inspect', type=MIME_TYPE.JSON)\ndef inspect(args):\n args['response'].header.add_header_line(\n Header_Line(Response_Header_Tag.SERVER, 'bbwebservice')\n )\n return args\n```\n\n### 8. Start the server\n - Use `core.start()` to launch all configured listeners.\n\n```python\n@register(route='::/index', type=MIME_TYPE.HTML)\ndef index():\n return load_file('/content/index.html')\n\ncore.start()\n```\n\n### 9. URL templates\n - Dynamic routes use `UrlTemplate` with typed placeholders.\n\n| Supported Types | Example |\n|-----------------|--------------------|\n| `str` | `{name:str}` |\n| `int` | `{id:int}` |\n| `float` | `{value:float}` |\n| `bool` | `{flag:bool}` |\n| `path` | `{path:path}` |\n\n```python\n@register(route=UrlTemplate('::/user/{name:str}/{age:int}'), type=MIME_TYPE.JSON)\ndef user(args):\n return args[STORE_VARS.TEMPLATE_VARS]\n```\n\n### 10. Selector hierarchy\n - The most specific selector wins automatically (IP > port > domain > global). Register routes knowing that concrete bindings take precedence over generic ones.\n\n### 11. Response helpers\n - In addition to returning bytes/strings, you can respond with:\n * `Dynamic(content, mime_type)` \u2013 content with a custom MIME type\n * `PartialContent` / `Redirect`\n * `Response(...)` \u2013 convenience for setting status, headers, body in one object\n\n### 12. Background tasks\n - `server_task(func, interval)` schedules functions (receives global state if `data` parameter present). Tasks shut down gracefully with the server.\n\n### 13. CORS\n - Enable or disable at runtime:\n\n```python\nwebserver.enable_cors(\n allow_origin=\"*\",\n allow_methods=[\"GET\", \"POST\"],\n allow_headers=[\"Content-Type\"],\n expose_headers=[\"X-Total-Count\"],\n allow_credentials=False,\n max_age=600,\n)\n```\n\n`disable_cors()` and `get_cors_settings()` are provided as well. OPTIONS requests are answered automatically when CORS is active.\n\n### 14. Worker pool and backpressure\n - All listeners share a bounded worker pool. If the queue is full, new connections get `503 Service Unavailable`. Per-listener `max_threads` throttle accept loops, while the global `max_threads` (see config) bounds total concurrency.\n\n### 15. Request parsing\n - Headers are read incrementally up to `max_header_size`, bodies honour `Content-Length` or `Transfer-Encoding: chunked` (trailers are skipped). Chunked data is decoded into the `args[STORE_VARS.POST]` buffer. Oversized requests trigger 413/431 responses.\n\n### 16. Logging\n - Logging honours scopes (`ip:port::domain`) and only formats messages when a sink is active.\n\n```python\nset_logging(LOGGING_OPTIONS.INFO, True)\nlog_to_file('/logs/server.log', [LOGGING_OPTIONS.ERROR, LOGGING_OPTIONS.INFO])\nset_logging_callback(lambda msg, ts, lvl: print('[callback]', lvl, msg))\n```\n\nThere is also `webserver.response()` for building structured responses and `log()` for manual logging with scopes.\n\n## Server Configuration\n\n`config/config.json` controls listeners and limits:\n\n```json\n{\n \"max_threads\": 100,\n \"max_header_size\": 16384,\n \"max_body_size\": 10485760,\n \"server\": [\n {\n \"ip\": \"default\",\n \"port\": 5000,\n \"queue_size\": 50,\n \"max_threads\": 25,\n \"SSL\": false,\n \"host\": \"\",\n \"cert_path\": \"\",\n \"key_path\": \"\",\n \"https-redirect\": false,\n \"https-redirect-escape-paths\": [],\n \"update-cert-state\": false\n }\n ]\n}\n```\n\n* `ip`: `default` resolves at runtime, otherwise explicit IPv4/IPv6 (use `[::1]` style).\n* Multiple entries in `server` bind additional sockets.\n* `SSL` with `host` as list enables SNI (each entry supplies `host`, `cert_path`, `key_path`). Failed certificates are logged with full paths.\n* `https-redirect` forces 301 to HTTPS except for paths listed in `https-redirect-escape-paths` (supports wildcard suffix `*`).\n* `update-cert-state` watches certificate files and reloads them automatically.\n\nRecommended ports: 5000 (local), 80 (HTTP), 443/8443 (HTTPS).\n\n## Logging recap\n\n```python\nset_logging(LOGGING_OPTIONS.DEBUG, True)\nset_logging(LOGGING_OPTIONS.TIME, True)\nlog_to_file()\n```\n\nUse `set_logging(scope='127.0.0.1:5000::example.com', ...)` to target specific endpoints.\n\n## Testing\n\nRun the integration script:\n\n```bash\npython testing/test_bbwebservice_example.py\n```\n\nIt covers chunked uploads, CORS preflights, domain/IP selectors and redirects.\n\n## License\n\nMIT License \u00a9 Lukas Walker (see `LICENSE` for details).\n\n\n",
"bugtrack_url": null,
"license": null,
"summary": "A bare bone webserver",
"version": "2.2.0",
"project_urls": null,
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "0e02ba5a745bce05edf19541dce009b84db82967d02ad711ae829c897be17640",
"md5": "dddc76dc5d87cf97379237230dfb8cc1",
"sha256": "083ab3c9e13c69c5bf02e5bcad12a56d60d422536da1cf09752f751429fe1b3c"
},
"downloads": -1,
"filename": "bbwebservice-2.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "dddc76dc5d87cf97379237230dfb8cc1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 38950,
"upload_time": "2025-10-16T10:49:30",
"upload_time_iso_8601": "2025-10-16T10:49:30.319731Z",
"url": "https://files.pythonhosted.org/packages/0e/02/ba5a745bce05edf19541dce009b84db82967d02ad711ae829c897be17640/bbwebservice-2.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "63a7a21f2f7727383113af25bcbe011b6efa31b0d03cf775f9450ad980714ee2",
"md5": "072603eb63d0cf1ec43b11ffade22bf9",
"sha256": "7b4b050ffce76b8a9e1a83182c757e24eff610f31385f5b2ab384570a0973da8"
},
"downloads": -1,
"filename": "bbwebservice-2.2.0.tar.gz",
"has_sig": false,
"md5_digest": "072603eb63d0cf1ec43b11ffade22bf9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 39179,
"upload_time": "2025-10-16T10:49:31",
"upload_time_iso_8601": "2025-10-16T10:49:31.762014Z",
"url": "https://files.pythonhosted.org/packages/63/a7/a21f2f7727383113af25bcbe011b6efa31b0d03cf775f9450ad980714ee2/bbwebservice-2.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-16 10:49:31",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "bbwebservice"
}