neuroglia-python 0.1.2__tar.gz → 0.1.4__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.
- neuroglia_python-0.1.4/PKG-INFO +84 -0
- neuroglia_python-0.1.4/README.md +53 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/pyproject.toml +16 -15
- neuroglia_python-0.1.4/src/neuroglia/eventing/cloud_events/cloud_event.py +83 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_middleware.py +6 -6
- neuroglia_python-0.1.4/src/neuroglia/logging/logger.py +82 -0
- neuroglia_python-0.1.4/src/neuroglia/serialization/__init__.py +0 -0
- neuroglia_python-0.1.2/PKG-INFO +0 -51
- neuroglia_python-0.1.2/README.md +0 -21
- neuroglia_python-0.1.2/src/neuroglia/eventing/cloud_events/cloud_event.py +0 -74
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/LICENSE +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/module_loader.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/operation_result.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/problem_details.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/type_extensions.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/type_finder.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/abstractions.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/abstractions.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/abstractions.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/event_sourcing_repository.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/event_store/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/event_store/event_store.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/read_model_reconciliator.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/memory/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/memory/memory_repository.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/mongo/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/mongo/mongo_repository.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/get_by_id_query.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/list_query.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queryable.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/dependency_injection/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/dependency_injection/service_provider.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/decorators.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_bus.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_ingestor.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_publisher.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/expressions/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/expressions/javascript_expression_translator.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/abstractions.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/configuration/data_access_layer.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/web.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/integration/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/integration/models.py +0 -0
- {neuroglia_python-0.1.2/src/neuroglia/mvc → neuroglia_python-0.1.4/src/neuroglia/logging}/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mapping/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mapping/mapper.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mediation/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mediation/mediator.py +0 -0
- {neuroglia_python-0.1.2/src/neuroglia/serialization → neuroglia_python-0.1.4/src/neuroglia/mvc}/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mvc/controller_base.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/reactive/__init__.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/reactive/rx_async.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/serialization/abstractions.py +0 -0
- {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/serialization/json.py +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: neuroglia-python
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Port from .NET to Python of the Neuroglia Framework
|
|
5
|
+
License: Apache
|
|
6
|
+
Author: Charles d'Avernas
|
|
7
|
+
Author-email: charles.davernas@neuroglia.io
|
|
8
|
+
Requires-Python: >=3.12,<4.0
|
|
9
|
+
Classifier: License :: Other/Proprietary License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Requires-Dist: annotated-types (>0.6.0)
|
|
14
|
+
Requires-Dist: classy-fastapi (>=0.6.1,<0.7.0)
|
|
15
|
+
Requires-Dist: esdbclient (>1)
|
|
16
|
+
Requires-Dist: fastapi (>=0)
|
|
17
|
+
Requires-Dist: grpcio (>=1.71)
|
|
18
|
+
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
19
|
+
Requires-Dist: mkdocs (>=1.6.1)
|
|
20
|
+
Requires-Dist: mkdocs-material (>=9.5.46)
|
|
21
|
+
Requires-Dist: multipledispatch (>=1.0.0,<2.0.0)
|
|
22
|
+
Requires-Dist: pydantic-settings (>=2)
|
|
23
|
+
Requires-Dist: pymongo (>=4.6.3)
|
|
24
|
+
Requires-Dist: pytest (>=8.1.1)
|
|
25
|
+
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
26
|
+
Requires-Dist: rx (>=3.2.0)
|
|
27
|
+
Requires-Dist: typing-extensions (>=4.9.0)
|
|
28
|
+
Requires-Dist: uvicorn (>=0.34.0)
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# Neuroglia Python Framework
|
|
32
|
+
|
|
33
|
+
The framework is a very thin software layer built on top of [FastAPI](https://fastapi.tiangolo.com/) that provides developers with a set of coding features and tools that may be useful for any microservice (regardless of its role and domain/bounded context), such as:
|
|
34
|
+
|
|
35
|
+
- Implements all guidelines from https://12factor.net
|
|
36
|
+
- MVC Web App builder with fundamental abstractions
|
|
37
|
+
- Simple Dependency Injection mechanism, including automatic class discovery and instantiation
|
|
38
|
+
- Class-based API controller with automatic module discovery
|
|
39
|
+
- Modular Command/Query responsibility segregation
|
|
40
|
+
- Optional Event-sourcing for event-driven Domain modeling
|
|
41
|
+
- Clean layered Code https://levelup.gitconnected.com/clean-architecture-86c4f03e4771
|
|
42
|
+
- Pure Domain models, independent of persistence
|
|
43
|
+
- Application handlers (Command, Queries, Events, Tasks)
|
|
44
|
+
- Repository pattern
|
|
45
|
+
- Independent API controllers, endpoints and models (DTO's) vs Domain models and logic
|
|
46
|
+
- Native async Events ingestion, handling, emission (JSON [CloudEvent](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/json-format.md)) using [ReactiveX programming](https://medium.com/@willAmaral/asynchronous-programming-and-rx-anything-479d9cb8daee) with [RxPy](https://rxpy.readthedocs.io/en/latest/)
|
|
47
|
+
- Data models mapping between Domain and Integration
|
|
48
|
+
- Easy extension for background task scheduling with [apscheduler](https://apscheduler.readthedocs.io/en/3.x/)
|
|
49
|
+
- etc...
|
|
50
|
+
|
|
51
|
+
The code typically includes comments that help understand it.
|
|
52
|
+
|
|
53
|
+
The `src/main.py` file is the entry point that defines all dependencies, including the sub-folders where to dynamically load the API, Application, Persistence and Domain layers.
|
|
54
|
+
|
|
55
|
+
In turn, when booting, the web app dynamically discovers, identifies and instantiate dependencies then loads:
|
|
56
|
+
|
|
57
|
+
- API controllers and define the mapping between each endpoint and its corresponding Application handler
|
|
58
|
+
- Application handlers (incl. Commands, Queries, Events, Tasks) and services (any business logic)
|
|
59
|
+
- Integration dependencies (any API client service, persistence-layer clients, ) and models (API' DTO for requests and responses)
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
Temporarily hosted at https://bvandewe.github.io/pyneuro/
|
|
64
|
+
|
|
65
|
+
## Disclaimer
|
|
66
|
+
|
|
67
|
+
This project was the opportunity for me (cdavernas) to learn Python while porting some of the concepts and services of the .NET version of the Neuroglia Framework
|
|
68
|
+
|
|
69
|
+
## Packaging
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
# Set `package-mode = true` in pyproject.toml
|
|
73
|
+
# Set the version tag in pyproject.toml
|
|
74
|
+
# Commit changes
|
|
75
|
+
# Create API Token in pypi.org...
|
|
76
|
+
# Configure credentials for pypi registry:
|
|
77
|
+
poetry config pypi-token.pypi {pypi-....mytoken}
|
|
78
|
+
# Build package locally
|
|
79
|
+
poetry build
|
|
80
|
+
# Publish package to pypi.org:
|
|
81
|
+
poetry publish
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Neuroglia Python Framework
|
|
2
|
+
|
|
3
|
+
The framework is a very thin software layer built on top of [FastAPI](https://fastapi.tiangolo.com/) that provides developers with a set of coding features and tools that may be useful for any microservice (regardless of its role and domain/bounded context), such as:
|
|
4
|
+
|
|
5
|
+
- Implements all guidelines from https://12factor.net
|
|
6
|
+
- MVC Web App builder with fundamental abstractions
|
|
7
|
+
- Simple Dependency Injection mechanism, including automatic class discovery and instantiation
|
|
8
|
+
- Class-based API controller with automatic module discovery
|
|
9
|
+
- Modular Command/Query responsibility segregation
|
|
10
|
+
- Optional Event-sourcing for event-driven Domain modeling
|
|
11
|
+
- Clean layered Code https://levelup.gitconnected.com/clean-architecture-86c4f03e4771
|
|
12
|
+
- Pure Domain models, independent of persistence
|
|
13
|
+
- Application handlers (Command, Queries, Events, Tasks)
|
|
14
|
+
- Repository pattern
|
|
15
|
+
- Independent API controllers, endpoints and models (DTO's) vs Domain models and logic
|
|
16
|
+
- Native async Events ingestion, handling, emission (JSON [CloudEvent](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/json-format.md)) using [ReactiveX programming](https://medium.com/@willAmaral/asynchronous-programming-and-rx-anything-479d9cb8daee) with [RxPy](https://rxpy.readthedocs.io/en/latest/)
|
|
17
|
+
- Data models mapping between Domain and Integration
|
|
18
|
+
- Easy extension for background task scheduling with [apscheduler](https://apscheduler.readthedocs.io/en/3.x/)
|
|
19
|
+
- etc...
|
|
20
|
+
|
|
21
|
+
The code typically includes comments that help understand it.
|
|
22
|
+
|
|
23
|
+
The `src/main.py` file is the entry point that defines all dependencies, including the sub-folders where to dynamically load the API, Application, Persistence and Domain layers.
|
|
24
|
+
|
|
25
|
+
In turn, when booting, the web app dynamically discovers, identifies and instantiate dependencies then loads:
|
|
26
|
+
|
|
27
|
+
- API controllers and define the mapping between each endpoint and its corresponding Application handler
|
|
28
|
+
- Application handlers (incl. Commands, Queries, Events, Tasks) and services (any business logic)
|
|
29
|
+
- Integration dependencies (any API client service, persistence-layer clients, ) and models (API' DTO for requests and responses)
|
|
30
|
+
|
|
31
|
+
## Documentation
|
|
32
|
+
|
|
33
|
+
Temporarily hosted at https://bvandewe.github.io/pyneuro/
|
|
34
|
+
|
|
35
|
+
## Disclaimer
|
|
36
|
+
|
|
37
|
+
This project was the opportunity for me (cdavernas) to learn Python while porting some of the concepts and services of the .NET version of the Neuroglia Framework
|
|
38
|
+
|
|
39
|
+
## Packaging
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
# Set `package-mode = true` in pyproject.toml
|
|
43
|
+
# Set the version tag in pyproject.toml
|
|
44
|
+
# Commit changes
|
|
45
|
+
# Create API Token in pypi.org...
|
|
46
|
+
# Configure credentials for pypi registry:
|
|
47
|
+
poetry config pypi-token.pypi {pypi-....mytoken}
|
|
48
|
+
# Build package locally
|
|
49
|
+
poetry build
|
|
50
|
+
# Publish package to pypi.org:
|
|
51
|
+
poetry publish
|
|
52
|
+
|
|
53
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "neuroglia-python"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.4"
|
|
4
4
|
description = "Port from .NET to Python of the Neuroglia Framework"
|
|
5
5
|
authors = ["Charles d'Avernas <charles.davernas@neuroglia.io>"]
|
|
6
6
|
license = "Apache"
|
|
@@ -8,29 +8,30 @@ readme = "README.md"
|
|
|
8
8
|
packages = [
|
|
9
9
|
{ include = "neuroglia", from = "src" },
|
|
10
10
|
]
|
|
11
|
+
package-mode = true
|
|
11
12
|
|
|
12
13
|
[tool.poetry.dependencies]
|
|
13
14
|
python = "^3.12"
|
|
14
|
-
annotated-types = "
|
|
15
|
+
annotated-types = ">0.6.0"
|
|
15
16
|
classy-fastapi = "^0.6.1"
|
|
16
|
-
esdbclient = "
|
|
17
|
-
fastapi = "
|
|
18
|
-
grpcio = "
|
|
19
|
-
httpx = "^0.
|
|
17
|
+
esdbclient = ">1"
|
|
18
|
+
fastapi = ">=0"
|
|
19
|
+
grpcio = ">=1.71"
|
|
20
|
+
httpx = "^0.28.1"
|
|
20
21
|
multipledispatch = "^1.0.0"
|
|
21
|
-
pydantic-settings = "
|
|
22
|
-
pymongo = "
|
|
22
|
+
pydantic-settings = ">=2"
|
|
23
|
+
pymongo = ">=4.6.3"
|
|
23
24
|
python-dotenv = "^1.0.1"
|
|
24
|
-
rx = "
|
|
25
|
-
uvicorn = "
|
|
26
|
-
typing-extensions = "
|
|
27
|
-
pytest = "
|
|
28
|
-
mkdocs = "
|
|
29
|
-
mkdocs-material = "
|
|
25
|
+
rx = ">=3.2.0"
|
|
26
|
+
uvicorn = ">=0.34.0"
|
|
27
|
+
typing-extensions = ">=4.9.0"
|
|
28
|
+
pytest = ">=8.1.1"
|
|
29
|
+
mkdocs = ">=1.6.1"
|
|
30
|
+
mkdocs-material = ">=9.5.46"
|
|
30
31
|
|
|
31
32
|
[tool.poetry.group.dev.dependencies]
|
|
32
33
|
pytest = "^8.0.1"
|
|
33
|
-
pytest-asyncio = "^0.
|
|
34
|
+
pytest-asyncio = "^0.26.0"
|
|
34
35
|
mypy = "^1.8.0"
|
|
35
36
|
autopep8 = "^2.0.4"
|
|
36
37
|
coverage = "^7.4.1"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Any, Optional, Union, Dict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CloudEventSpecVersion:
|
|
7
|
+
"""Exposes all supported versions of the Cloud Event Specification"""
|
|
8
|
+
|
|
9
|
+
v1_0: str = "1.0"
|
|
10
|
+
""" Gets the version '1.0' of the Cloud Event Specification """
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class CloudEvent:
|
|
15
|
+
"""
|
|
16
|
+
Represents a Cloud Event.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
id (str): A string that uniquely identifies the cloud event in the scope of its source.
|
|
20
|
+
specversion (str): The version of the CloudEvents specification which the event uses. Defaults to '1.0'.
|
|
21
|
+
time (Optional[datetime]): The date and time at which the event has been produced.
|
|
22
|
+
source (str): The cloud event's source.
|
|
23
|
+
type (str): The cloud event's type.
|
|
24
|
+
subject (Optional[str]): A value that describes the subject of the event in the context of the event producer.
|
|
25
|
+
datacontenttype (Optional[str]): The cloud event's data content type. Defaults to 'application/json'.
|
|
26
|
+
dataschema (Optional[str]): An URI that references the versioned schema of the event's data.
|
|
27
|
+
data (Optional[Any]): The event's data, if any. Only used if the event has been formatted using the structured mode.
|
|
28
|
+
data_base64 (Optional[str]): The event's binary data, encoded in base 64. Used if the event has been formatted using the binary mode.
|
|
29
|
+
extensionAttributes (Optional[Dict[str, Any]]): A mapping containing the event's extension attributes.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
id: str
|
|
33
|
+
""" Gets/sets string that uniquely identifies the cloud event in the scope of its source. """
|
|
34
|
+
|
|
35
|
+
source: str
|
|
36
|
+
""" Gets/sets the cloud event's source. Must be an absolute URI. """
|
|
37
|
+
|
|
38
|
+
type: str
|
|
39
|
+
""" Gets/sets the cloud event's source. Should be a reverse DNS domain name, which must only contain lowercase alphanumeric, '-' and '.' characters. """
|
|
40
|
+
|
|
41
|
+
specversion: str = "1.0" # Default value for specversion
|
|
42
|
+
""" Gets/sets the version of the CloudEvents specification which the event uses. Defaults to '1.0'. """
|
|
43
|
+
|
|
44
|
+
sequencetype: Optional[str] = None
|
|
45
|
+
""" Gets/sets the type of the sequence. """
|
|
46
|
+
|
|
47
|
+
sequence: Optional[int] = None
|
|
48
|
+
""" Gets/sets the sequence of the event. """
|
|
49
|
+
|
|
50
|
+
time: Optional[datetime] = None
|
|
51
|
+
""" Gets/sets the date and time at which the event has been produced. """
|
|
52
|
+
|
|
53
|
+
subject: Optional[str] = None
|
|
54
|
+
""" Gets/sets value that describes the subject of the event in the context of the event producer. """
|
|
55
|
+
|
|
56
|
+
datacontenttype: Optional[str] = "application/json" # Default value for datacontenttype
|
|
57
|
+
""" Gets/sets the cloud event's data content type. Defaults to 'application/json'. """
|
|
58
|
+
|
|
59
|
+
dataschema: Optional[str] = None
|
|
60
|
+
""" Gets/sets an URI, if any, that references the versioned schema of the event's data. """
|
|
61
|
+
|
|
62
|
+
data: Optional[Any] = None
|
|
63
|
+
""" Gets/sets the event's data, if any. Only used if the event has been formatted using the structured mode. """
|
|
64
|
+
|
|
65
|
+
data_base64: Optional[str] = None
|
|
66
|
+
""" Gets/sets the event's binary data, encoded in base 64. Used if the event has been formatted using the binary mode. """
|
|
67
|
+
|
|
68
|
+
_extra_attributes: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
69
|
+
|
|
70
|
+
def __init__(self, **kwargs):
|
|
71
|
+
self._extra_attributes = {}
|
|
72
|
+
for key, value in kwargs.items():
|
|
73
|
+
if key in CloudEvent.__dataclass_fields__:
|
|
74
|
+
setattr(self, key, value)
|
|
75
|
+
else:
|
|
76
|
+
self._extra_attributes[key] = value
|
|
77
|
+
super().__init__()
|
|
78
|
+
|
|
79
|
+
def get_attribute(self, name: str) -> Optional[Any]:
|
|
80
|
+
"""Gets the value of the attribute with the specified name, if any"""
|
|
81
|
+
if not name:
|
|
82
|
+
raise ValueError("Attribute name cannot be empty or None.")
|
|
83
|
+
return self.__dict__[name] if name in self.__dict__.keys() else None
|
|
@@ -8,7 +8,7 @@ from starlette.middleware.base import BaseHTTPMiddleware
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class CloudEventMiddleware(BaseHTTPMiddleware):
|
|
11
|
-
|
|
11
|
+
"""Represents the HTTP middleware used to handle incoming cloud events"""
|
|
12
12
|
|
|
13
13
|
def __init__(self, app, service_provider: ServiceProviderBase):
|
|
14
14
|
super().__init__(app)
|
|
@@ -17,17 +17,17 @@ class CloudEventMiddleware(BaseHTTPMiddleware):
|
|
|
17
17
|
self.cloud_event_bus = self.service_provider.get_required_service(CloudEventBus)
|
|
18
18
|
|
|
19
19
|
service_provider: ServiceProviderBase
|
|
20
|
-
|
|
20
|
+
""" Gets the current service provider """
|
|
21
21
|
|
|
22
22
|
cloud_event_bus: CloudEventBus
|
|
23
|
-
|
|
23
|
+
""" Gets the service used to stream the application's incoming and outgoing cloud events """
|
|
24
24
|
|
|
25
25
|
serializer: JsonSerializer
|
|
26
|
-
|
|
26
|
+
""" Gets the service used to serialize/deserialize values to/from JSON """
|
|
27
27
|
|
|
28
28
|
async def dispatch(self, request: Request, call_next):
|
|
29
|
-
content_type = request.headers.get(
|
|
30
|
-
if content_type is None or not content_type.startswith(
|
|
29
|
+
content_type = request.headers.get("content-type", None)
|
|
30
|
+
if content_type is None or not content_type.startswith("application/cloudevents+json"):
|
|
31
31
|
return await call_next(request)
|
|
32
32
|
try:
|
|
33
33
|
attributes = self.serializer.deserialize(await request.body(), dict)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
# def configure_simplest_logging():
|
|
6
|
+
# logging.basicConfig(filename='logs/openbank.log', format='%(asctime)s %(levelname)-8s %(message)s', encoding='utf-8', level=logging.DEBUG)
|
|
7
|
+
# console_handler = logging.StreamHandler(sys.stdout)
|
|
8
|
+
# console_handler.setLevel(logging.DEBUG)
|
|
9
|
+
# log = logging.getLogger(__name__)
|
|
10
|
+
# log.addHandler(console_handler)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# def configure_logging_from_config(config_path: str):
|
|
14
|
+
# # config_path = "logging.conf"
|
|
15
|
+
# logging.config.fileConfig(config_path, disable_existing_loggers=True)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname) - 8s %(name)s:%(lineno)d %(message)s"
|
|
19
|
+
DEFAULT_LOG_FILENAME = "logs/debug.log"
|
|
20
|
+
DEFAULT_LOG_LEVEL = "DEBUG"
|
|
21
|
+
DEFAULT_LOG_LIBRARIES_LIST = ["asyncio", "httpx", "httpcore"]
|
|
22
|
+
DEFAULT_LOG_LIBRARIES_LEVEL = "WARN"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def configure_logging(
|
|
26
|
+
log_level: str = DEFAULT_LOG_LEVEL,
|
|
27
|
+
log_format: str = DEFAULT_LOG_FORMAT,
|
|
28
|
+
console: bool = True,
|
|
29
|
+
file: bool = True,
|
|
30
|
+
filename: str = DEFAULT_LOG_FILENAME,
|
|
31
|
+
lib_list: typing.List = DEFAULT_LOG_LIBRARIES_LIST,
|
|
32
|
+
lib_level: str = DEFAULT_LOG_LIBRARIES_LEVEL,
|
|
33
|
+
):
|
|
34
|
+
"""Configures the root logger with the given format and handler(s).
|
|
35
|
+
Optionally, the log level for some libraries may be customized separately
|
|
36
|
+
(which is interesting when setting a log level DEBUG on root but not wishing to see debugs for all libs).
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
log_level (str, optional): The log_level for the root logger. Defaults to DEFAULT_LOG_LEVEL.
|
|
40
|
+
log_format (str, optional): The format of the log records. Defaults to DEFAULT_LOG_FORMAT.
|
|
41
|
+
console (bool, optional): Whether to enable the console handler. Defaults to True.
|
|
42
|
+
file (bool, optional): Whether to enable the file-based handler. Defaults to True.
|
|
43
|
+
filename (str, optional): If file-based handler is enabled, this will set the filename of the log file. Defaults to DEFAULT_LOG_FILENAME.
|
|
44
|
+
lib_list (typing.List, optional): List of libraries/packages name. Defaults to DEFAULT_LOG_LIBRARIES_LIST.
|
|
45
|
+
lib_level (str, optional): The separate log level for the libraries included in the lib_list. Defaults to DEFAULT_LOG_LIBRARIES_LEVEL.
|
|
46
|
+
"""
|
|
47
|
+
root_logger = logging.getLogger()
|
|
48
|
+
root_logger.setLevel(log_level)
|
|
49
|
+
formatter = logging.Formatter(log_format)
|
|
50
|
+
if console:
|
|
51
|
+
_configure_console_based_logging(root_logger, log_level, formatter)
|
|
52
|
+
if file:
|
|
53
|
+
_configure_file_based_logging(root_logger, log_level, formatter, filename)
|
|
54
|
+
|
|
55
|
+
for lib_name in lib_list:
|
|
56
|
+
logging.getLogger(lib_name).setLevel(lib_level)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _configure_console_based_logging(root_logger, log_level, formatter):
|
|
60
|
+
console_handler = logging.StreamHandler()
|
|
61
|
+
handler = _configure_handler(console_handler, log_level, formatter)
|
|
62
|
+
root_logger.addHandler(handler)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _configure_file_based_logging(root_logger, log_level, formatter, filename):
|
|
66
|
+
# Ensure the directory exists
|
|
67
|
+
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
68
|
+
|
|
69
|
+
# Check if the file exists, if not, create it
|
|
70
|
+
if not os.path.isfile(filename):
|
|
71
|
+
with open(filename, "w"): # This will create the file if it does not exist
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
file_handler = logging.FileHandler(filename)
|
|
75
|
+
handler = _configure_handler(file_handler, log_level, formatter)
|
|
76
|
+
root_logger.addHandler(handler)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _configure_handler(handler: logging.StreamHandler, log_level, formatter) -> logging.StreamHandler:
|
|
80
|
+
handler.setLevel(log_level)
|
|
81
|
+
handler.setFormatter(formatter)
|
|
82
|
+
return handler
|
|
File without changes
|
neuroglia_python-0.1.2/PKG-INFO
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: neuroglia-python
|
|
3
|
-
Version: 0.1.2
|
|
4
|
-
Summary: Port from .NET to Python of the Neuroglia Framework
|
|
5
|
-
License: Apache
|
|
6
|
-
Author: Charles d'Avernas
|
|
7
|
-
Author-email: charles.davernas@neuroglia.io
|
|
8
|
-
Requires-Python: >=3.12,<4.0
|
|
9
|
-
Classifier: License :: Other/Proprietary License
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
-
Requires-Dist: annotated-types (>=0.6.0,<0.7.0)
|
|
13
|
-
Requires-Dist: classy-fastapi (>=0.6.1,<0.7.0)
|
|
14
|
-
Requires-Dist: esdbclient (>=1.0.17,<2.0.0)
|
|
15
|
-
Requires-Dist: fastapi (>=0.109.2,<0.110.0)
|
|
16
|
-
Requires-Dist: grpcio (>=1.60.1,<2.0.0)
|
|
17
|
-
Requires-Dist: httpx (>=0.26.0,<0.27.0)
|
|
18
|
-
Requires-Dist: mkdocs (>=1.6.1,<2.0.0)
|
|
19
|
-
Requires-Dist: mkdocs-material (>=9.5.46,<10.0.0)
|
|
20
|
-
Requires-Dist: multipledispatch (>=1.0.0,<2.0.0)
|
|
21
|
-
Requires-Dist: pydantic-settings (>=2.2.0,<3.0.0)
|
|
22
|
-
Requires-Dist: pymongo (>=4.6.1,<5.0.0)
|
|
23
|
-
Requires-Dist: pytest (>=8.1.1,<9.0.0)
|
|
24
|
-
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
25
|
-
Requires-Dist: rx (>=3.2.0,<4.0.0)
|
|
26
|
-
Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
|
|
27
|
-
Requires-Dist: uvicorn (>=0.27.1,<0.28.0)
|
|
28
|
-
Description-Content-Type: text/markdown
|
|
29
|
-
|
|
30
|
-
# Neuroglia Python Framework
|
|
31
|
-
|
|
32
|
-
A framework of libraries used to build modern Python V3 applications
|
|
33
|
-
|
|
34
|
-
## Disclaimer
|
|
35
|
-
|
|
36
|
-
This project was the opportunity for me (cdavernas) to learn Python while porting some of the concepts and services of the .NET version of the Neuroglia Framework
|
|
37
|
-
|
|
38
|
-
## Packaging
|
|
39
|
-
|
|
40
|
-
```sh
|
|
41
|
-
# Set the version tag in pyproject.toml
|
|
42
|
-
# Commit changes
|
|
43
|
-
|
|
44
|
-
poetry build
|
|
45
|
-
|
|
46
|
-
poetry config pypi-token.pypi pypi-AgEIcHl..... # Get API Token from pypi
|
|
47
|
-
|
|
48
|
-
poetry publish
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
neuroglia_python-0.1.2/README.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Neuroglia Python Framework
|
|
2
|
-
|
|
3
|
-
A framework of libraries used to build modern Python V3 applications
|
|
4
|
-
|
|
5
|
-
## Disclaimer
|
|
6
|
-
|
|
7
|
-
This project was the opportunity for me (cdavernas) to learn Python while porting some of the concepts and services of the .NET version of the Neuroglia Framework
|
|
8
|
-
|
|
9
|
-
## Packaging
|
|
10
|
-
|
|
11
|
-
```sh
|
|
12
|
-
# Set the version tag in pyproject.toml
|
|
13
|
-
# Commit changes
|
|
14
|
-
|
|
15
|
-
poetry build
|
|
16
|
-
|
|
17
|
-
poetry config pypi-token.pypi pypi-AgEIcHl..... # Get API Token from pypi
|
|
18
|
-
|
|
19
|
-
poetry publish
|
|
20
|
-
|
|
21
|
-
```
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass, field
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from typing import Any, Dict, Optional
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class CloudEventSpecVersion:
|
|
7
|
-
''' Exposes all supported versions of the Cloud Event Specification '''
|
|
8
|
-
|
|
9
|
-
v1_0: str = "1.0"
|
|
10
|
-
''' Gets the version '1.0' of the Cloud Event Specification '''
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@dataclass
|
|
14
|
-
class CloudEvent:
|
|
15
|
-
'''
|
|
16
|
-
Represents a Cloud Event.
|
|
17
|
-
|
|
18
|
-
Attributes:
|
|
19
|
-
id (str): A string that uniquely identifies the cloud event in the scope of its source.
|
|
20
|
-
specversion (str): The version of the CloudEvents specification which the event uses. Defaults to '1.0'.
|
|
21
|
-
time (Optional[datetime]): The date and time at which the event has been produced.
|
|
22
|
-
source (str): The cloud event's source.
|
|
23
|
-
type (str): The cloud event's type.
|
|
24
|
-
subject (Optional[str]): A value that describes the subject of the event in the context of the event producer.
|
|
25
|
-
datacontenttype (Optional[str]): The cloud event's data content type. Defaults to 'application/json'.
|
|
26
|
-
dataschema (Optional[str]): An URI that references the versioned schema of the event's data.
|
|
27
|
-
data (Optional[Any]): The event's data, if any. Only used if the event has been formatted using the structured mode.
|
|
28
|
-
data_base64 (Optional[str]): The event's binary data, encoded in base 64. Used if the event has been formatted using the binary mode.
|
|
29
|
-
**extensions: Keyword arguments representing extension attributes.
|
|
30
|
-
'''
|
|
31
|
-
|
|
32
|
-
id: str
|
|
33
|
-
''' Gets/sets string that uniquely identifies the cloud event in the scope of its source. '''
|
|
34
|
-
|
|
35
|
-
source: str
|
|
36
|
-
''' Gets/sets the cloud event's source. Must be an absolute URI. '''
|
|
37
|
-
|
|
38
|
-
type: str
|
|
39
|
-
''' Gets/sets the cloud event's source. Should be a reverse DNS domain name, which must only contain lowercase alphanumeric, '-' and '.' characters. '''
|
|
40
|
-
|
|
41
|
-
specversion: str = '1.0' # Default value for specversion
|
|
42
|
-
''' Gets/sets the version of the CloudEvents specification which the event uses. Defaults to '1.0'. '''
|
|
43
|
-
|
|
44
|
-
sequencetype: Optional[str] = None
|
|
45
|
-
''' Gets/sets the type of the sequence. '''
|
|
46
|
-
|
|
47
|
-
sequence: Optional[int] = None
|
|
48
|
-
''' Gets/sets the sequence of the event. '''
|
|
49
|
-
|
|
50
|
-
time: Optional[datetime] = None
|
|
51
|
-
''' Gets/sets the date and time at which the event has been produced. '''
|
|
52
|
-
|
|
53
|
-
subject: Optional[str] = None
|
|
54
|
-
''' Gets/sets value that describes the subject of the event in the context of the event producer. '''
|
|
55
|
-
|
|
56
|
-
datacontenttype: Optional[str] = 'application/json' # Default value for datacontenttype
|
|
57
|
-
''' Gets/sets the cloud event's data content type. Defaults to 'application/json'. '''
|
|
58
|
-
|
|
59
|
-
dataschema: Optional[str] = None
|
|
60
|
-
''' Gets/sets an URI, if any, that references the versioned schema of the event's data. '''
|
|
61
|
-
|
|
62
|
-
data: Optional[Any] = None
|
|
63
|
-
''' Gets/sets the event's data, if any. Only used if the event has been formatted using the structured mode. '''
|
|
64
|
-
|
|
65
|
-
data_base64: Optional[str] = None
|
|
66
|
-
''' Gets/sets the event's binary data, encoded in base 64. Used if the event has been formatted using the binary mode. '''
|
|
67
|
-
|
|
68
|
-
origin: Optional[str] = None
|
|
69
|
-
|
|
70
|
-
def get_attribute(self, name: str) -> Optional[Any]:
|
|
71
|
-
''' Gets the value of the attribute with the specified name, if any '''
|
|
72
|
-
if not name:
|
|
73
|
-
raise ValueError("Attribute name cannot be empty or None.")
|
|
74
|
-
return self.__dict__[name] if name in self.__dict__.keys() else None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/__init__.py
RENAMED
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/abstractions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/list_query.py
RENAMED
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/dependency_injection/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/__init__.py
RENAMED
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/serialization/abstractions.py
RENAMED
|
File without changes
|
|
File without changes
|