Name | thinking-runtime JSON |
Version |
0.0.3
JSON |
| download |
home_page | None |
Summary | Runtime configuration |
upload_time | 2024-09-01 22:00:52 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.12 |
license | MIT License Copyright (c) 2024 Filip Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
keywords |
thinking
runtime
configuration
|
VCS |
 |
bugtrack_url |
|
requirements |
thinking-modules
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# thinking-runtime
[](https://github.com/FilipMalczak/thinking-runtime/actions/workflows/ci.yml)
[](https://badge.fury.io/py/thinking-runtime)
> Part of [thinking](https://github.com/search?q=owner%3AFilipMalczak+thinking&type=repositories) family.
This will configure the very basics of the runtime before you run more code.
The point is to run some configurations before you proceed with anything else - logging anything, running any meaningul
code, etc. It is based on dunder config files like `__project__` or `__log__`, where you can configure meta-aspects
of your app. This lib will load them and configure the runtime for you.
Those dunder files should not be packaged and should reside in the root of your repo. If you're writing an app, you
can provide custom config files in your working directory. In case of libraries, you can have defaults for CI and local
development, without impacting consumers configs.
> Requires python 3.12. Is properly typed.
## Usage
> Admittedly, docs need enhancements.
Base abstraction is the `BootstrapAction`. It represents an action that needs to run when bootstrapping the runtime.
It must provide `perform(self) -> None` method that encapsulates the action itself. It can also have
`prepare(self) -> None` method and expose requirements for dunder config files by implementing
`requirements(self) -> list[ConfigurationRequirement]`. Each requirement is constructed from list of dunder name and
`required` flag (`False` by default, actions should usually provide default configs and dunder config files should
be used for customization).
> todo describe disabling actions
> todo talk about how you can do anything from any config, but there is only guarantee that config will be loaded before
> an action that requires it
Entrypoint to the framework is [`bootstrap()`](./thinking_runtime/bootstrap.py) method. It will register initial actions
and execute them. It should be called before anything else - notably before any call to `logging.getLogger` (so that
the framework can configure logging first).
> This is a subject to change in the future. It's pretty early in the lifecycle of this project. We will retrieve
> all existing loggers and reconfigure them, at some point, but not at MVP.
For each action the framework will retrieve requirements and iterate over them.
For each requirement it will iterate over dunder names and try to import them until import succeeds or it runs out of
names. If no import succeeded and `required` is `True`, there will be a failure.
First action that runs is [`SetupBootstrapping`](./thinking_runtime/setup.py). It will try to read any of `__bootstrap__`,
`__setup__`, `__project__`, `__structure__`. That file should use
[`register_action(action: ActionType, *, name: ActionName=None, enabled: bool=True)`](./thinking_runtime/setup.py)
to register any custom actions. Before the setup action is executed, following actions are already registered.
>...but can be disabled; document it.
First non-setup action is [`RecogniseRuntime`](./thinking_runtime/defaults/recognise_runtime.py). It will
analyse what is going on in the runtime to figure out if you're running the app or tests and if there are
any facets (think "Spring profiles") enabled. You can configure custom facets with `register_facet(facet: RuntimeFacetDefinition)`
or customize what is the package structure of your code and its tests with `project_structure() -> PackagesStructure`.
Config files used by that actions are the same as for `SetupBootstrapping` or `__runtime__`.
Another default step is [`ConfigureLogging`](./thinking_runtime/defaults/configure_logging.py). Use `__log__`, `__logs__`, `__logging__`
to make calls to [`thinking_runtime.default.logging_config.logging_config: LoggingConfig`](./thinking_runtime/defaults/logging_config.py)
and configure logging aspects like log format, handlers, etc. There is already a default config that will log to stderr
with a sane format, and in case of non-test environment, will als dump logs to a file (with name based on session timestamp).
Sweet part of this setup is that when `ConfigureLogging` is running (so, loading the dunder configs), there is a guarantee
that `RecogniseRuntime` has already executed, so you can safely make statements like
```python
if current_runtime().mode == RuntimeMode.APP:
logging_config.handlers.streams["STDOUT"].enabled = False
#or
if current_runtime().mode == RuntimeMode.TEST:
logging_config.format = "..."
```
### [`fluent_container`](./fluent_container) and logging configuration
This package allows for creation of `list`s on steroids, meant to simplify creation of configuration DSLs.
It exposes [`Container`](./fluent_container/container.py) base class that can hold
['Identifiable's](./fluent_container/traits.py) (anything that exposes `identifier` property).
It won't allow duplicates (considering only the `identifier`s) and will only accept the type that you specify (raising,
when you try to append something that doesn't match). Besides that it is ordered like a `list`.
It can also expose views (["closures"](./fluent_container/closure.py)) that filter out anything that doesn't match
view criteria (these usually being "of given type").
Both `Container` and `...Closure`s overload `append(...)` so that you can either pass a concrete instance of
`Identifiable` or simply constructor arguments.
See [`Handlers`](./thinking_runtime/defaults/logging_config.py) for example usage. Its a container of logging handler
definition. As the framework supports 3 main types of handlers: `StreamHandler` (routing logs to any stream, usually
stdout or stderr), `FileHandler` (dumping logs to file or rotating file) or `RawHandler` (wrapper over a raw `logging.Handler`
and its `identifier`), `Handlers` expose 3 properties: `streams`, `files` and `raw`, being `closures` that match
those specific types. Thanks to that you can use:
```python
handlers.streams.append(NamedTextIO("name", some_stream), "DEBUG")
handlers.files.all #or simply handlers.files, since it supports __iter__
handlers.raw["specific_id"]
```
instead of
```python
handlers.append(StreamHandler(NamedTextIO("name", some_stream), "DEBUG"))
[ x for x in handlers if isinstance(FileHandler) ]
{ x.identifier: x for x in handlers if isinstance(RawHandler) }["specific_id"]
```
Raw data
{
"_id": null,
"home_page": null,
"name": "thinking-runtime",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "thinking, runtime, configuration",
"author": null,
"author_email": "Filip Malczak <filip.malczak@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/d0/3b/bb97cca8aece913fa6b77d8872629ba4fc1f77cbda7b90010833703d86a1/thinking_runtime-0.0.3.tar.gz",
"platform": null,
"description": "# thinking-runtime\n\n[](https://github.com/FilipMalczak/thinking-runtime/actions/workflows/ci.yml)\n[](https://badge.fury.io/py/thinking-runtime)\n\n> Part of [thinking](https://github.com/search?q=owner%3AFilipMalczak+thinking&type=repositories) family.\n\nThis will configure the very basics of the runtime before you run more code.\n\nThe point is to run some configurations before you proceed with anything else - logging anything, running any meaningul\ncode, etc. It is based on dunder config files like `__project__` or `__log__`, where you can configure meta-aspects\nof your app. This lib will load them and configure the runtime for you.\n\nThose dunder files should not be packaged and should reside in the root of your repo. If you're writing an app, you \ncan provide custom config files in your working directory. In case of libraries, you can have defaults for CI and local\ndevelopment, without impacting consumers configs.\n\n> Requires python 3.12. Is properly typed.\n\n## Usage\n\n> Admittedly, docs need enhancements.\n\nBase abstraction is the `BootstrapAction`. It represents an action that needs to run when bootstrapping the runtime.\nIt must provide `perform(self) -> None` method that encapsulates the action itself. It can also have \n`prepare(self) -> None` method and expose requirements for dunder config files by implementing \n`requirements(self) -> list[ConfigurationRequirement]`. Each requirement is constructed from list of dunder name and\n`required` flag (`False` by default, actions should usually provide default configs and dunder config files should\nbe used for customization).\n\n> todo describe disabling actions\n\n> todo talk about how you can do anything from any config, but there is only guarantee that config will be loaded before\n> an action that requires it\n\nEntrypoint to the framework is [`bootstrap()`](./thinking_runtime/bootstrap.py) method. It will register initial actions\nand execute them. It should be called before anything else - notably before any call to `logging.getLogger` (so that\nthe framework can configure logging first).\n\n> This is a subject to change in the future. It's pretty early in the lifecycle of this project. We will retrieve\n> all existing loggers and reconfigure them, at some point, but not at MVP.\n\nFor each action the framework will retrieve requirements and iterate over them. \nFor each requirement it will iterate over dunder names and try to import them until import succeeds or it runs out of\nnames. If no import succeeded and `required` is `True`, there will be a failure.\n\nFirst action that runs is [`SetupBootstrapping`](./thinking_runtime/setup.py). It will try to read any of `__bootstrap__`, \n`__setup__`, `__project__`, `__structure__`. That file should use \n[`register_action(action: ActionType, *, name: ActionName=None, enabled: bool=True)`](./thinking_runtime/setup.py)\nto register any custom actions. Before the setup action is executed, following actions are already registered.\n\n>...but can be disabled; document it.\n\nFirst non-setup action is [`RecogniseRuntime`](./thinking_runtime/defaults/recognise_runtime.py). It will\nanalyse what is going on in the runtime to figure out if you're running the app or tests and if there are\nany facets (think \"Spring profiles\") enabled. You can configure custom facets with `register_facet(facet: RuntimeFacetDefinition)`\nor customize what is the package structure of your code and its tests with `project_structure() -> PackagesStructure`.\nConfig files used by that actions are the same as for `SetupBootstrapping` or `__runtime__`.\n\nAnother default step is [`ConfigureLogging`](./thinking_runtime/defaults/configure_logging.py). Use `__log__`, `__logs__`, `__logging__`\nto make calls to [`thinking_runtime.default.logging_config.logging_config: LoggingConfig`](./thinking_runtime/defaults/logging_config.py)\nand configure logging aspects like log format, handlers, etc. There is already a default config that will log to stderr\nwith a sane format, and in case of non-test environment, will als dump logs to a file (with name based on session timestamp).\n\nSweet part of this setup is that when `ConfigureLogging` is running (so, loading the dunder configs), there is a guarantee\nthat `RecogniseRuntime` has already executed, so you can safely make statements like\n\n```python\nif current_runtime().mode == RuntimeMode.APP:\n logging_config.handlers.streams[\"STDOUT\"].enabled = False\n\n#or\nif current_runtime().mode == RuntimeMode.TEST:\n logging_config.format = \"...\"\n```\n\n### [`fluent_container`](./fluent_container) and logging configuration\n\nThis package allows for creation of `list`s on steroids, meant to simplify creation of configuration DSLs. \n\nIt exposes [`Container`](./fluent_container/container.py) base class that can hold \n['Identifiable's](./fluent_container/traits.py) (anything that exposes `identifier` property).\nIt won't allow duplicates (considering only the `identifier`s) and will only accept the type that you specify (raising, \nwhen you try to append something that doesn't match). Besides that it is ordered like a `list`.\n\nIt can also expose views ([\"closures\"](./fluent_container/closure.py)) that filter out anything that doesn't match\nview criteria (these usually being \"of given type\").\n\nBoth `Container` and `...Closure`s overload `append(...)` so that you can either pass a concrete instance of \n`Identifiable` or simply constructor arguments.\n\nSee [`Handlers`](./thinking_runtime/defaults/logging_config.py) for example usage. Its a container of logging handler\ndefinition. As the framework supports 3 main types of handlers: `StreamHandler` (routing logs to any stream, usually\nstdout or stderr), `FileHandler` (dumping logs to file or rotating file) or `RawHandler` (wrapper over a raw `logging.Handler`\nand its `identifier`), `Handlers` expose 3 properties: `streams`, `files` and `raw`, being `closures` that match\nthose specific types. Thanks to that you can use:\n\n```python\nhandlers.streams.append(NamedTextIO(\"name\", some_stream), \"DEBUG\")\nhandlers.files.all #or simply handlers.files, since it supports __iter__ \nhandlers.raw[\"specific_id\"]\n```\n\ninstead of\n\n```python\nhandlers.append(StreamHandler(NamedTextIO(\"name\", some_stream), \"DEBUG\"))\n[ x for x in handlers if isinstance(FileHandler) ]\n{ x.identifier: x for x in handlers if isinstance(RawHandler) }[\"specific_id\"]\n```\n",
"bugtrack_url": null,
"license": "MIT License Copyright (c) 2024 Filip Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
"summary": "Runtime configuration",
"version": "0.0.3",
"project_urls": {
"Homepage": "https://github.com/FilipMalczak/thinking-runtime"
},
"split_keywords": [
"thinking",
" runtime",
" configuration"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "92fae25d226f66accafcdf5f3b8d9a2cfce1fbe40501cb56da005d53096085f4",
"md5": "046c2b1171cf54ff6a47e606a37f55ef",
"sha256": "b156333fda5d70306274077d8cf918dd2eb24e089a66619ac243e7d61be19aaf"
},
"downloads": -1,
"filename": "thinking_runtime-0.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "046c2b1171cf54ff6a47e606a37f55ef",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 14633,
"upload_time": "2024-09-01T22:00:50",
"upload_time_iso_8601": "2024-09-01T22:00:50.841130Z",
"url": "https://files.pythonhosted.org/packages/92/fa/e25d226f66accafcdf5f3b8d9a2cfce1fbe40501cb56da005d53096085f4/thinking_runtime-0.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d03bbb97cca8aece913fa6b77d8872629ba4fc1f77cbda7b90010833703d86a1",
"md5": "aefa3e769d6c18cbd7068845716c7782",
"sha256": "8a7252b905089262b5844ecf87728596a8893b0cb0b4efc4ddc889d04a31f76d"
},
"downloads": -1,
"filename": "thinking_runtime-0.0.3.tar.gz",
"has_sig": false,
"md5_digest": "aefa3e769d6c18cbd7068845716c7782",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 13907,
"upload_time": "2024-09-01T22:00:52",
"upload_time_iso_8601": "2024-09-01T22:00:52.243591Z",
"url": "https://files.pythonhosted.org/packages/d0/3b/bb97cca8aece913fa6b77d8872629ba4fc1f77cbda7b90010833703d86a1/thinking_runtime-0.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-01 22:00:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "FilipMalczak",
"github_project": "thinking-runtime",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "thinking-modules",
"specs": [
[
">=",
"0.0.4"
]
]
}
],
"lcname": "thinking-runtime"
}