python3-commons 0.4.0__tar.gz → 0.5.0__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.

Potentially problematic release.


This version of python3-commons might be problematic. Click here for more details.

Files changed (46) hide show
  1. {python3_commons-0.4.0/src/python3_commons.egg-info → python3_commons-0.5.0}/PKG-INFO +3 -1
  2. {python3_commons-0.4.0 → python3_commons-0.5.0}/requirements.txt +2 -0
  3. {python3_commons-0.4.0 → python3_commons-0.5.0}/setup.cfg +3 -1
  4. python3_commons-0.5.0/src/python3_commons/audit.py +102 -0
  5. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/object_storage.py +0 -14
  6. {python3_commons-0.4.0 → python3_commons-0.5.0/src/python3_commons.egg-info}/PKG-INFO +3 -1
  7. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons.egg-info/requires.txt +2 -0
  8. python3_commons-0.4.0/src/python3_commons/audit.py +0 -44
  9. {python3_commons-0.4.0 → python3_commons-0.5.0}/.coveragerc +0 -0
  10. {python3_commons-0.4.0 → python3_commons-0.5.0}/.github/workflows/python-publish.yaml +0 -0
  11. {python3_commons-0.4.0 → python3_commons-0.5.0}/.gitignore +0 -0
  12. {python3_commons-0.4.0 → python3_commons-0.5.0}/AUTHORS.rst +0 -0
  13. {python3_commons-0.4.0 → python3_commons-0.5.0}/CHANGELOG.rst +0 -0
  14. {python3_commons-0.4.0 → python3_commons-0.5.0}/LICENSE +0 -0
  15. {python3_commons-0.4.0 → python3_commons-0.5.0}/README.md +0 -0
  16. {python3_commons-0.4.0 → python3_commons-0.5.0}/README.rst +0 -0
  17. {python3_commons-0.4.0 → python3_commons-0.5.0}/docs/Makefile +0 -0
  18. {python3_commons-0.4.0 → python3_commons-0.5.0}/docs/_static/.gitignore +0 -0
  19. {python3_commons-0.4.0 → python3_commons-0.5.0}/docs/authors.rst +0 -0
  20. {python3_commons-0.4.0 → python3_commons-0.5.0}/docs/changelog.rst +0 -0
  21. {python3_commons-0.4.0 → python3_commons-0.5.0}/docs/conf.py +0 -0
  22. {python3_commons-0.4.0 → python3_commons-0.5.0}/docs/index.rst +0 -0
  23. {python3_commons-0.4.0 → python3_commons-0.5.0}/docs/license.rst +0 -0
  24. {python3_commons-0.4.0 → python3_commons-0.5.0}/pyproject.toml +0 -0
  25. {python3_commons-0.4.0 → python3_commons-0.5.0}/requirements_dev.txt +0 -0
  26. {python3_commons-0.4.0 → python3_commons-0.5.0}/requirements_test.txt +0 -0
  27. {python3_commons-0.4.0 → python3_commons-0.5.0}/setup.py +0 -0
  28. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/__init__.py +0 -0
  29. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/conf.py +0 -0
  30. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/db.py +0 -0
  31. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/fs.py +0 -0
  32. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/helpers.py +0 -0
  33. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/logging/__init__.py +0 -0
  34. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/logging/filters.py +0 -0
  35. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/logging/formatter.py +0 -0
  36. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/serializers/__init__.py +0 -0
  37. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/serializers/json.py +0 -0
  38. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/serializers/msgpack.py +0 -0
  39. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons/serializers/msgspec.py +0 -0
  40. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons.egg-info/SOURCES.txt +0 -0
  41. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons.egg-info/dependency_links.txt +0 -0
  42. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons.egg-info/not-zip-safe +0 -0
  43. {python3_commons-0.4.0 → python3_commons-0.5.0}/src/python3_commons.egg-info/top_level.txt +0 -0
  44. {python3_commons-0.4.0 → python3_commons-0.5.0}/tests/conftest.py +0 -0
  45. {python3_commons-0.4.0 → python3_commons-0.5.0}/tests/test_msgpack.py +0 -0
  46. {python3_commons-0.4.0 → python3_commons-0.5.0}/tests/test_msgspec.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python3-commons
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Re-usable Python3 code
5
5
  Home-page: https://github.com/kamikaze/python3-commons
6
6
  Author: Oleg Korsak
@@ -15,11 +15,13 @@ Description-Content-Type: text/x-rst; charset=UTF-8
15
15
  License-File: LICENSE
16
16
  License-File: AUTHORS.rst
17
17
  Requires-Dist: asyncpg==0.29.0
18
+ Requires-Dist: lxml==5.2.2
18
19
  Requires-Dist: minio==7.2.7
19
20
  Requires-Dist: msgpack==1.0.8
20
21
  Requires-Dist: msgspec==0.18.6
21
22
  Requires-Dist: pydantic[email]==2.7.2
22
23
  Requires-Dist: pydantic-settings==2.2.1
24
+ Requires-Dist: zeep==4.2.1
23
25
  Provides-Extra: testing
24
26
  Requires-Dist: pytest; extra == "testing"
25
27
  Requires-Dist: pytest-cov; extra == "testing"
@@ -1,6 +1,8 @@
1
1
  asyncpg==0.29.0
2
+ lxml==5.2.2
2
3
  minio==7.2.7
3
4
  msgpack==1.0.8
4
5
  msgspec==0.18.6
5
6
  pydantic[email]==2.7.2
6
7
  pydantic-settings==2.2.1
8
+ zeep==4.2.1
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = python3-commons
3
- version = 0.4.0
3
+ version = 0.5.0
4
4
  description = Re-usable Python3 code
5
5
  author = Oleg Korsak
6
6
  author_email = kamikaze.is.waiting.you@gmail.com
@@ -24,11 +24,13 @@ package_dir =
24
24
  setup_requires = pyscaffold>=3.2a0,<3.3a0
25
25
  install_requires =
26
26
  asyncpg==0.29.0
27
+ lxml==5.2.2
27
28
  minio==7.2.7
28
29
  msgpack==1.0.8
29
30
  msgspec==0.18.6
30
31
  pydantic[email]==2.7.2
31
32
  pydantic-settings==2.2.1
33
+ zeep==4.2.1
32
34
  python_requires = >=3.12
33
35
 
34
36
  [options.packages.find]
@@ -0,0 +1,102 @@
1
+ import asyncio
2
+ import logging
3
+ import tarfile
4
+ from datetime import date, datetime, timedelta, UTC
5
+ from io import BytesIO
6
+ from uuid import uuid4
7
+ from zoneinfo import ZoneInfo
8
+
9
+ from lxml import etree
10
+ from zeep.plugins import Plugin
11
+ from zeep.wsdl.definitions import AbstractOperation
12
+
13
+ from python3_commons import object_storage
14
+ from python3_commons.conf import s3_settings
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class ZeepAuditPlugin(Plugin):
20
+ def __init__(self, audit_name: str = 'zeep'):
21
+ super().__init__()
22
+ self.audit_name = audit_name
23
+
24
+ @staticmethod
25
+ def store_audit_in_s3(envelope, operation: AbstractOperation, direction: str):
26
+ xml = etree.tostring(envelope, encoding='UTF-8', pretty_print=True)
27
+ now = datetime.now(tz=UTC)
28
+ date_path = now.strftime('%Y/%m/%d')
29
+ timestamp = now.strftime('%H%M%S')
30
+ coro = object_storage.store_bytes_in_s3(
31
+ settings, xml,
32
+ f'audit/{date_path}/{self.audit_name}/{operation.name}/{timestamp}_{str(uuid4())[-12:]}_{direction}.xml'
33
+ )
34
+
35
+ try:
36
+ loop = asyncio.get_running_loop()
37
+ except RuntimeError:
38
+ loop = None
39
+
40
+ if loop and loop.is_running():
41
+ loop.create_task(coro)
42
+ else:
43
+ asyncio.run(coro)
44
+
45
+ def ingress(self, envelope, http_headers, operation: AbstractOperation):
46
+ self.store_audit_in_s3(envelope, operation, 'ingress')
47
+
48
+ return envelope, http_headers
49
+
50
+ def egress(self, envelope, http_headers, operation: AbstractOperation, binding_options):
51
+ self.store_audit_in_s3(envelope, operation, 'egress')
52
+
53
+ return envelope, http_headers
54
+
55
+
56
+ async def write_audit_data(settings: S3Settings, key: str, data: bytes):
57
+ if settings.s3_secret_access_key:
58
+ try:
59
+ client = get_s3_client(settings)
60
+
61
+ client.put_object(settings.s3_bucket, key, io.BytesIO(data), len(data))
62
+ except S3Error as e:
63
+ logger.error(f'Failed storing object in storage: {e}')
64
+ else:
65
+ logger.debug(f'Stored object in storage: {key}')
66
+ else:
67
+ logger.debug(f'S3 is not configured, not storing object in storage: {key}')
68
+
69
+
70
+ async def archive_audit_data(root_path: str = 'audit'):
71
+ now = datetime.now(tz=UTC) - timedelta(days=1)
72
+ year = now.year
73
+ month = now.month
74
+ day = now.day
75
+ bucket_name = s3_settings.s3_bucket
76
+ fo = BytesIO()
77
+ object_names = []
78
+ date_path = object_storage.get_absolute_path(f'{root_path}/{year}/{month:02}/{day:02}')
79
+
80
+ with tarfile.open(fileobj=fo, mode='w|bz2') as archive:
81
+ if objects := object_storage.get_objects(bucket_name, date_path, recursive=True):
82
+ logger.info(f'Compacting files in: {date_path}')
83
+
84
+ for name, last_modified, content in objects:
85
+ info = tarfile.TarInfo(name)
86
+ info.size = len(content)
87
+ info.mtime = last_modified.timestamp()
88
+ archive.addfile(info, BytesIO(content))
89
+ object_names.append(name)
90
+
91
+ fo.seek(0)
92
+
93
+ if object_names:
94
+ archive_path = object_storage.get_absolute_path(
95
+ f'.archive/{year}_{month:02}/{year}_{month:02}_{day:02}.tar.bz2')
96
+ object_storage.put_object(bucket_name, archive_path, fo, fo.getbuffer().nbytes)
97
+
98
+ if errors := object_storage.remove_objects(bucket_name, object_names=object_names):
99
+ for error in errors:
100
+ logger.error(f'Failed to delete object in {bucket_name=}: {error}')
101
+ else:
102
+ logger.info('No objects to archive found.')
@@ -125,17 +125,3 @@ def remove_objects(bucket_name: str, prefix: str = None,
125
125
  errors = s3_client.remove_objects(bucket_name, delete_object_list)
126
126
 
127
127
  return errors
128
-
129
-
130
- async def store_bytes_in_s3(settings: S3Settings, data: bytes, key: str):
131
- if settings.s3_secret_access_key:
132
- try:
133
- client = get_s3_client(settings)
134
-
135
- client.put_object(settings.s3_bucket, key, io.BytesIO(data), len(data))
136
- except S3Error as e:
137
- logger.error(f'Failed storing object in storage: {e}')
138
- else:
139
- logger.debug(f'Stored object in storage: {key}')
140
- else:
141
- logger.debug(f'S3 is not configured, not storing object in storage: {key}')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python3-commons
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Re-usable Python3 code
5
5
  Home-page: https://github.com/kamikaze/python3-commons
6
6
  Author: Oleg Korsak
@@ -15,11 +15,13 @@ Description-Content-Type: text/x-rst; charset=UTF-8
15
15
  License-File: LICENSE
16
16
  License-File: AUTHORS.rst
17
17
  Requires-Dist: asyncpg==0.29.0
18
+ Requires-Dist: lxml==5.2.2
18
19
  Requires-Dist: minio==7.2.7
19
20
  Requires-Dist: msgpack==1.0.8
20
21
  Requires-Dist: msgspec==0.18.6
21
22
  Requires-Dist: pydantic[email]==2.7.2
22
23
  Requires-Dist: pydantic-settings==2.2.1
24
+ Requires-Dist: zeep==4.2.1
23
25
  Provides-Extra: testing
24
26
  Requires-Dist: pytest; extra == "testing"
25
27
  Requires-Dist: pytest-cov; extra == "testing"
@@ -1,9 +1,11 @@
1
1
  asyncpg==0.29.0
2
+ lxml==5.2.2
2
3
  minio==7.2.7
3
4
  msgpack==1.0.8
4
5
  msgspec==0.18.6
5
6
  pydantic[email]==2.7.2
6
7
  pydantic-settings==2.2.1
8
+ zeep==4.2.1
7
9
 
8
10
  [testing]
9
11
  pytest
@@ -1,44 +0,0 @@
1
- import logging
2
- import tarfile
3
- from datetime import date, timedelta
4
- from io import BytesIO
5
-
6
- from python3_commons import object_storage
7
- from python3_commons.conf import s3_settings
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
-
12
- async def archive_audit_data(root_path: str = 'audit'):
13
- today = date.today() - timedelta(days=1)
14
- year = today.year
15
- month = today.month
16
- day = today.day
17
- bucket_name = s3_settings.s3_bucket
18
- fo = BytesIO()
19
- object_names = []
20
- date_path = object_storage.get_absolute_path(f'{root_path}/{year}/{month:02}/{day:02}')
21
-
22
- with tarfile.open(fileobj=fo, mode='w|bz2') as archive:
23
- if objects := object_storage.get_objects(bucket_name, date_path, recursive=True):
24
- logger.info(f'Compacting files in: {date_path}')
25
-
26
- for name, last_modified, content in objects:
27
- info = tarfile.TarInfo(name)
28
- info.size = len(content)
29
- info.mtime = last_modified.timestamp()
30
- archive.addfile(info, BytesIO(content))
31
- object_names.append(name)
32
-
33
- fo.seek(0)
34
-
35
- if object_names:
36
- archive_path = object_storage.get_absolute_path(
37
- f'.archive/{year}_{month:02}/{year}_{month:02}_{day:02}.tar.bz2')
38
- object_storage.put_object(bucket_name, archive_path, fo, fo.getbuffer().nbytes)
39
-
40
- if errors := object_storage.remove_objects(bucket_name, object_names=object_names):
41
- for error in errors:
42
- logger.error(f'Failed to delete object in {bucket_name=}: {error}')
43
- else:
44
- logger.info('No objects to archive found.')
File without changes