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.
Files changed (63) hide show
  1. neuroglia_python-0.1.4/PKG-INFO +84 -0
  2. neuroglia_python-0.1.4/README.md +53 -0
  3. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/pyproject.toml +16 -15
  4. neuroglia_python-0.1.4/src/neuroglia/eventing/cloud_events/cloud_event.py +83 -0
  5. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_middleware.py +6 -6
  6. neuroglia_python-0.1.4/src/neuroglia/logging/logger.py +82 -0
  7. neuroglia_python-0.1.4/src/neuroglia/serialization/__init__.py +0 -0
  8. neuroglia_python-0.1.2/PKG-INFO +0 -51
  9. neuroglia_python-0.1.2/README.md +0 -21
  10. neuroglia_python-0.1.2/src/neuroglia/eventing/cloud_events/cloud_event.py +0 -74
  11. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/LICENSE +0 -0
  12. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/__init__.py +0 -0
  13. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/__init__.py +0 -0
  14. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/module_loader.py +0 -0
  15. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/operation_result.py +0 -0
  16. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/problem_details.py +0 -0
  17. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/type_extensions.py +0 -0
  18. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/core/type_finder.py +0 -0
  19. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/__init__.py +0 -0
  20. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/abstractions.py +0 -0
  21. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/__init__.py +0 -0
  22. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/abstractions.py +0 -0
  23. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/__init__.py +0 -0
  24. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/abstractions.py +0 -0
  25. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/event_sourcing_repository.py +0 -0
  26. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/event_store/__init__.py +0 -0
  27. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/event_store/event_store.py +0 -0
  28. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/event_sourcing/read_model_reconciliator.py +0 -0
  29. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/memory/__init__.py +0 -0
  30. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/memory/memory_repository.py +0 -0
  31. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/mongo/__init__.py +0 -0
  32. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/infrastructure/mongo/mongo_repository.py +0 -0
  33. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/__init__.py +0 -0
  34. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/get_by_id_query.py +0 -0
  35. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queries/generic/list_query.py +0 -0
  36. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/data/queryable.py +0 -0
  37. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/dependency_injection/__init__.py +0 -0
  38. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/dependency_injection/service_provider.py +0 -0
  39. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/__init__.py +0 -0
  40. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/decorators.py +0 -0
  41. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/__init__.py +0 -0
  42. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_bus.py +0 -0
  43. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_ingestor.py +0 -0
  44. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_publisher.py +0 -0
  45. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/expressions/__init__.py +0 -0
  46. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/expressions/javascript_expression_translator.py +0 -0
  47. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/__init__.py +0 -0
  48. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/abstractions.py +0 -0
  49. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/configuration/data_access_layer.py +0 -0
  50. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/hosting/web.py +0 -0
  51. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/integration/__init__.py +0 -0
  52. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/integration/models.py +0 -0
  53. {neuroglia_python-0.1.2/src/neuroglia/mvc → neuroglia_python-0.1.4/src/neuroglia/logging}/__init__.py +0 -0
  54. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mapping/__init__.py +0 -0
  55. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mapping/mapper.py +0 -0
  56. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mediation/__init__.py +0 -0
  57. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mediation/mediator.py +0 -0
  58. {neuroglia_python-0.1.2/src/neuroglia/serialization → neuroglia_python-0.1.4/src/neuroglia/mvc}/__init__.py +0 -0
  59. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/mvc/controller_base.py +0 -0
  60. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/reactive/__init__.py +0 -0
  61. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/reactive/rx_async.py +0 -0
  62. {neuroglia_python-0.1.2 → neuroglia_python-0.1.4}/src/neuroglia/serialization/abstractions.py +0 -0
  63. {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.2"
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 = "^0.6.0"
15
+ annotated-types = ">0.6.0"
15
16
  classy-fastapi = "^0.6.1"
16
- esdbclient = "^1.0.17"
17
- fastapi = "^0.109.2"
18
- grpcio = "^1.60.1"
19
- httpx = "^0.26.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 = "^2.2.0"
22
- pymongo = "^4.6.1"
22
+ pydantic-settings = ">=2"
23
+ pymongo = ">=4.6.3"
23
24
  python-dotenv = "^1.0.1"
24
- rx = "^3.2.0"
25
- uvicorn = "^0.27.1"
26
- typing-extensions = "^4.9.0"
27
- pytest = "^8.1.1"
28
- mkdocs = "^1.6.1"
29
- mkdocs-material = "^9.5.46"
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.23.5"
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
- ''' Represents the HTTP middleware used to handle incoming cloud events '''
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
- ''' Gets the current service provider '''
20
+ """ Gets the current service provider """
21
21
 
22
22
  cloud_event_bus: CloudEventBus
23
- ''' Gets the service used to stream the application's incoming and outgoing cloud events '''
23
+ """ Gets the service used to stream the application's incoming and outgoing cloud events """
24
24
 
25
25
  serializer: JsonSerializer
26
- ''' Gets the service used to serialize/deserialize values to/from JSON '''
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('content-type', None)
30
- if content_type is None or not content_type.startswith('application/cloudevents+json'):
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
@@ -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
-
@@ -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