cledar-sdk 1.4.0__py3-none-any.whl → 2.0.1__py3-none-any.whl

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 (84) hide show
  1. {cledar_sdk-1.4.0.dist-info → cledar_sdk-2.0.1.dist-info}/METADATA +2 -2
  2. cledar_sdk-2.0.1.dist-info/RECORD +4 -0
  3. cledar_sdk-1.4.0.dist-info/RECORD +0 -83
  4. common_logging/README.md +0 -53
  5. common_logging/__init__.py +0 -0
  6. common_logging/tests/test_universal_plaintext_formatter.py +0 -249
  7. common_logging/universal_plaintext_formatter.py +0 -94
  8. kafka_service/README.md +0 -239
  9. kafka_service/__init__.py +0 -40
  10. kafka_service/clients/base.py +0 -98
  11. kafka_service/clients/consumer.py +0 -110
  12. kafka_service/clients/producer.py +0 -80
  13. kafka_service/config/schemas.py +0 -178
  14. kafka_service/exceptions.py +0 -22
  15. kafka_service/handlers/dead_letter.py +0 -82
  16. kafka_service/handlers/parser.py +0 -49
  17. kafka_service/logger.py +0 -3
  18. kafka_service/models/input.py +0 -13
  19. kafka_service/models/message.py +0 -10
  20. kafka_service/models/output.py +0 -8
  21. kafka_service/tests/.env.test.kafka +0 -3
  22. kafka_service/tests/README.md +0 -216
  23. kafka_service/tests/conftest.py +0 -104
  24. kafka_service/tests/integration/__init__.py +0 -1
  25. kafka_service/tests/integration/conftest.py +0 -78
  26. kafka_service/tests/integration/helpers.py +0 -47
  27. kafka_service/tests/integration/test_consumer_integration.py +0 -375
  28. kafka_service/tests/integration/test_integration.py +0 -391
  29. kafka_service/tests/integration/test_producer_consumer_interaction.py +0 -388
  30. kafka_service/tests/integration/test_producer_integration.py +0 -217
  31. kafka_service/tests/unit/__init__.py +0 -1
  32. kafka_service/tests/unit/test_base_kafka_client.py +0 -390
  33. kafka_service/tests/unit/test_config_validation.py +0 -609
  34. kafka_service/tests/unit/test_dead_letter_handler.py +0 -443
  35. kafka_service/tests/unit/test_error_handling.py +0 -674
  36. kafka_service/tests/unit/test_input_parser.py +0 -310
  37. kafka_service/tests/unit/test_input_parser_comprehensive.py +0 -489
  38. kafka_service/tests/unit/test_utils.py +0 -25
  39. kafka_service/tests/unit/test_utils_comprehensive.py +0 -408
  40. kafka_service/utils/callbacks.py +0 -19
  41. kafka_service/utils/messages.py +0 -28
  42. kafka_service/utils/topics.py +0 -2
  43. kserve_service/README.md +0 -352
  44. kserve_service/__init__.py +0 -3
  45. kserve_service/tests/__init__.py +0 -0
  46. kserve_service/tests/test_utils.py +0 -64
  47. kserve_service/utils.py +0 -27
  48. monitoring_service/README.md +0 -71
  49. monitoring_service/__init__.py +0 -0
  50. monitoring_service/monitoring_server.py +0 -112
  51. monitoring_service/tests/integration/test_monitoring_server_int.py +0 -166
  52. monitoring_service/tests/test_monitoring_server.py +0 -62
  53. nonce_service/README.md +0 -99
  54. nonce_service/__init__.py +0 -3
  55. nonce_service/nonce_service.py +0 -36
  56. nonce_service/tests/__init__.py +0 -0
  57. nonce_service/tests/test_nonce_service.py +0 -136
  58. redis_service/README.md +0 -536
  59. redis_service/__init__.py +0 -15
  60. redis_service/async_example.py +0 -111
  61. redis_service/example.py +0 -37
  62. redis_service/exceptions.py +0 -22
  63. redis_service/logger.py +0 -3
  64. redis_service/model.py +0 -10
  65. redis_service/redis.py +0 -525
  66. redis_service/redis_config_store.py +0 -252
  67. redis_service/tests/test_async_integration_redis.py +0 -162
  68. redis_service/tests/test_async_redis_service.py +0 -384
  69. redis_service/tests/test_integration_redis.py +0 -119
  70. redis_service/tests/test_redis_service.py +0 -319
  71. storage_service/README.md +0 -529
  72. storage_service/__init__.py +0 -0
  73. storage_service/constants.py +0 -3
  74. storage_service/exceptions.py +0 -50
  75. storage_service/models.py +0 -19
  76. storage_service/object_storage.py +0 -955
  77. storage_service/tests/conftest.py +0 -18
  78. storage_service/tests/test_abfs.py +0 -165
  79. storage_service/tests/test_integration_filesystem.py +0 -359
  80. storage_service/tests/test_integration_s3.py +0 -453
  81. storage_service/tests/test_local.py +0 -384
  82. storage_service/tests/test_s3.py +0 -521
  83. {cledar_sdk-1.4.0.dist-info → cledar_sdk-2.0.1.dist-info}/WHEEL +0 -0
  84. {cledar_sdk-1.4.0.dist-info → cledar_sdk-2.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cledar-sdk
3
- Version: 1.4.0
3
+ Version: 2.0.1
4
4
  Summary: Cledar Python SDK
5
5
  Author: Cledar
6
6
  License-File: LICENSE
@@ -160,7 +160,7 @@ storage.upload_file(
160
160
 
161
161
  ### Monitoring Server
162
162
  ```python
163
- from monitoring_service.monitoring_server import MonitoringServer, MonitoringServerConfig
163
+ from cledar.monitoring import MonitoringServer, MonitoringServerConfig
164
164
 
165
165
  config = MonitoringServerConfig(
166
166
  readiness_checks={"s3": storage.is_alive},
@@ -0,0 +1,4 @@
1
+ cledar_sdk-2.0.1.dist-info/METADATA,sha256=pa0zmgjruZ9hf02xRPvJ7iBcr_cPl2yofalRdyG3HUQ,6733
2
+ cledar_sdk-2.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
3
+ cledar_sdk-2.0.1.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
4
+ cledar_sdk-2.0.1.dist-info/RECORD,,
@@ -1,83 +0,0 @@
1
- common_logging/README.md,sha256=DIGwhCPugbeQ_tggXIVGi4NYkPZFtJcrO1RQksXxdPk,1798
2
- common_logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- common_logging/universal_plaintext_formatter.py,sha256=ExuXwfZmc_4tp3RIsoe_ByYpnTN0iQBOi101FB8hksc,3309
4
- common_logging/tests/test_universal_plaintext_formatter.py,sha256=bY6vvpra81_YXN2MLVjNuA8Iu7kOaZH0lmQMsohjRPI,8560
5
- kafka_service/README.md,sha256=3lKulsfEUs6qaKExlpPkxT_X1NYBAHraiqQRdvkQ48I,7021
6
- kafka_service/__init__.py,sha256=YejBYb9sS5d0VLuYg48vqKWTWSTwlEnsGF_2Z3guXAQ,1131
7
- kafka_service/exceptions.py,sha256=LJ-mUYCwoQsDM-bL4ms9ZCiWIOw5kt1KStbN04Mavl0,501
8
- kafka_service/logger.py,sha256=jdZSJnuPpUXEwG5eLKlQMLkVxaKwuma_o9udbOAjXo0,60
9
- kafka_service/clients/base.py,sha256=LhiCF9vNxn-kCWld4Xfzy1lYCUj7PbhJhNURE7wIx70,3692
10
- kafka_service/clients/consumer.py,sha256=m0u-Q2HXLk7pD4z2ucwaQxavW3VATbvVD1fDTSAi0tA,3590
11
- kafka_service/clients/producer.py,sha256=oJMZ9zg7n-DFWrySu-xveQ70ZXZEQkuXE0ewMeLLKoo,2605
12
- kafka_service/config/schemas.py,sha256=ToAv2d3F7mMpuePBWsC12jugdMWLPQMoNCXub0VIbgE,6550
13
- kafka_service/handlers/dead_letter.py,sha256=Y4krNONrMayaYsvFZrXh-pRK8kfyWibEYrUyDLy-XH8,2552
14
- kafka_service/handlers/parser.py,sha256=BsEUFI5bDBQzf9f9s7XClk_TfEXveOG5yCTT4sOibPI,1475
15
- kafka_service/models/input.py,sha256=VEf9DDbXew4tJSHP7cEbXWW3k6s_1gN8QGcqs5LmxuU,254
16
- kafka_service/models/message.py,sha256=NsnQi5ZMVWR8yOw2gtUAGxdQNDolaXycf9qlnkBi38o,182
17
- kafka_service/models/output.py,sha256=jLPatV6B5L-qudF0a7xT4OINuU9FcmsBUYQNSiL-TFc,179
18
- kafka_service/tests/.env.test.kafka,sha256=7EUptc8_8o9_NJwaMFaZGI31_rDzh3y2edVwe6RrX3I,86
19
- kafka_service/tests/README.md,sha256=bdfyf1O6SroC6L31FssXrO53DbD6DwJTy1Ym8rYlIJo,7259
20
- kafka_service/tests/conftest.py,sha256=VbW8VvWy1w0IMyTJJupAK9JXRfbnR9uDFq8qoz4WO8I,3476
21
- kafka_service/tests/integration/__init__.py,sha256=AydX6rUkcrtA5i3sbhBPuBN2WAPzUI06g3-mQpT7tVE,43
22
- kafka_service/tests/integration/conftest.py,sha256=Tf6-bOkeKLLDA_Ftx5mEEzEf62kdIQeXfJUV7WacViY,2536
23
- kafka_service/tests/integration/helpers.py,sha256=lv2YQVWUDZtQTP-u5udcxrtTyfgKNoIqVXzhzHy0fJU,1242
24
- kafka_service/tests/integration/test_consumer_integration.py,sha256=otAPiO3XgRMdyByiQZWntEVeaghZ9PYjUh8RecZigZw,10911
25
- kafka_service/tests/integration/test_integration.py,sha256=MQBbo6KXP5oNzfMXBut5XC3HcJx4stmHlp19vQ8cr5E,12007
26
- kafka_service/tests/integration/test_producer_consumer_interaction.py,sha256=7Z6no7zkADn8uDkiKbICO-bZDpW_H37Z1yaC50B0PLA,11920
27
- kafka_service/tests/integration/test_producer_integration.py,sha256=0NXNB5gN0hPSXj5j2oP9FlhAXrNVpNg5N_1DkGOHUy0,6438
28
- kafka_service/tests/unit/__init__.py,sha256=uiWL_3JORErRzHi12hW0-kFU36zdkl3MBg4_qtH6TM0,36
29
- kafka_service/tests/unit/test_base_kafka_client.py,sha256=6O31wIuoKkb-EEqD-a5PjB-zbM0h5vTFz1VGr9V3KVQ,13321
30
- kafka_service/tests/unit/test_config_validation.py,sha256=KpMAI_5s-XWOW_bNT9rTie61eoet4kkB7YTFd9W2hOE,19971
31
- kafka_service/tests/unit/test_dead_letter_handler.py,sha256=qsJZKXm_fBZUnaDwBAF7Bj9aS-y7Uxc-e7u6pPQLTgc,13905
32
- kafka_service/tests/unit/test_error_handling.py,sha256=h91hwG02DwGEZrziSv0mLshQFK98p-P38g4gWPHuyyY,22828
33
- kafka_service/tests/unit/test_input_parser.py,sha256=_MIWkvhYRZR_7lg9Jo_MD3ckCTGrMrSyeR_7F5wrHSw,11556
34
- kafka_service/tests/unit/test_input_parser_comprehensive.py,sha256=LVC2Xl2kqDfj3XK0cZ2s6kRpK2T0m5Xu2Wdlo3-5z2E,14099
35
- kafka_service/tests/unit/test_utils.py,sha256=5TPn16Jsxb3dALEfUhm6iPBZjvWuMT88nAL0-HIzqZI,812
36
- kafka_service/tests/unit/test_utils_comprehensive.py,sha256=VjyHgZDhilYtLEBFNedc72-x3vQ58dpM0IbtWtEvp3E,14140
37
- kafka_service/utils/callbacks.py,sha256=mqs94wLhnVQTYrN-taD57FRU4K3jXHnNaZLIbBbgFGc,588
38
- kafka_service/utils/messages.py,sha256=j3Lr1_Rwr2FqepfhM-Jw4kaU3PkvqgugDeYzQsH7L60,738
39
- kafka_service/utils/topics.py,sha256=ekh7nJwUOojgfil7Ntef_FbebA1ExUcgp1QWUTj0Ywc,118
40
- kserve_service/README.md,sha256=b15WY_y96UiLAlbbtioua2esswtp3m7pLrhoOCy9q_o,8722
41
- kserve_service/__init__.py,sha256=XROt6VPOY8_vzt6vkiNAB4ffbgOAHOBlNrWrqmJOmgQ,66
42
- kserve_service/utils.py,sha256=Q6V-sws5dkIGZKW7XCKIPQ1Qs6itu2eLZ2mfW0HM20w,897
43
- kserve_service/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
- kserve_service/tests/test_utils.py,sha256=5XoSkr6tbDCJ7mV-jqaT7AlrKFAyk3hnRQh-u67KJd0,1678
45
- monitoring_service/README.md,sha256=UdcfEXK3IhCeBhYdrrV45DXh7FTAK72bXBmUDnqZY8E,2148
46
- monitoring_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
- monitoring_service/monitoring_server.py,sha256=lBnImACViG6QE70RFTziDg8zh0FJsiza6knPI-rvsE8,3488
48
- monitoring_service/tests/test_monitoring_server.py,sha256=urL2seruM_peNIr7c4hblGfEDjqQUzhPCE2gXIJ_Vf8,1657
49
- monitoring_service/tests/integration/test_monitoring_server_int.py,sha256=5PP-nm-gZPMyShccYUU17TfRprWq2Ij6Y1YA6JnN9jE,5359
50
- nonce_service/README.md,sha256=sPxpA9UJfrqCWidNmzgdcXGT_-6SxPvysnhsSvC5FEo,3533
51
- nonce_service/__init__.py,sha256=Rh6JWML_ncfb_t_mVl7PIKOXpELRdfunMsFWAtbt5EE,68
52
- nonce_service/nonce_service.py,sha256=6RhA2eEztH_pNdjkBI5eqmRh14I96NjgVYy2v_z7vdM,1100
53
- nonce_service/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
- nonce_service/tests/test_nonce_service.py,sha256=sWzCBXghZNDOnSo8NQB6tyJJ95g2tZGRPlThFqD2P7g,4047
55
- redis_service/README.md,sha256=rsIieAu4TwjoeIbHG30x3t3TyR9P9Ulcy69gdfG_jRg,14632
56
- redis_service/__init__.py,sha256=SgTAyteZ3pPV8R608-EQ84RmytUfSQaPGl0UJxLnGL0,250
57
- redis_service/async_example.py,sha256=m8dkSspJK8yti9U_Q3_Sc9XW1aq3RYL4EzBdLx5_u84,2949
58
- redis_service/example.py,sha256=OApl0JU59viBUZORLxlYBhVMdCc5QvOBdOjscxbm_aQ,1091
59
- redis_service/exceptions.py,sha256=vvD7SO0xHutSLvUf0ttMo7C6OeaVi8f3bxMservsSVI,737
60
- redis_service/logger.py,sha256=OBOTx6zk_6wkpB2N_FRV7gXR3xy4dpy4iX2B0oFfZ90,60
61
- redis_service/model.py,sha256=ykW_KHygNHhfHPvP2RyJj0g_WENXxJEP2HvGy7Yb4uo,174
62
- redis_service/redis.py,sha256=DuWaXMU5RhAW2Rf9T-Hg_1FIrQqkPin1vTXQMJJ6Sno,19817
63
- redis_service/redis_config_store.py,sha256=EFhyvg_Eklrh2tc5dtFpe6nnjMDkTqYT_egclhf0KaI,8919
64
- redis_service/tests/test_async_integration_redis.py,sha256=I-rWvOm9Cnpl8AZcrPb58tTbkq_YKh3WR2bwXB-EJRM,5005
65
- redis_service/tests/test_async_redis_service.py,sha256=DgzBZscXu_FiV6QIZT2AHQ0rk_Zwzu2HmsifeDhArRU,12501
66
- redis_service/tests/test_integration_redis.py,sha256=O3z5EgkeB6Sd9C1S3rRMW916bybDCAHb-DgTFZGLTqI,3345
67
- redis_service/tests/test_redis_service.py,sha256=n3FIYBk9SGzpDkRWnPj-Mi3NKYtDEpbwgjpjb_JwjF4,10252
68
- storage_service/README.md,sha256=Rkew1joVijHVEfyXS9C7dDw55rQ4HYRbHkRYlZiREak,15655
69
- storage_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
- storage_service/constants.py,sha256=O6qHRQafs35_3TUShxtE2kq1lI4HQ-NRs2oWQFMt7Ko,85
71
- storage_service/exceptions.py,sha256=ItDsFU0Jzdg94yfXkLoC-Wp0Pz-XryNAypZDxpDNRnk,715
72
- storage_service/models.py,sha256=m1h1xx0YkdY6TIwrcBKKtZrzF1CltKzL-UQZgmP0MOQ,484
73
- storage_service/object_storage.py,sha256=wpZyEZvidLWgZli5BH_zCFWL42AwK9oN2pXBPVTmsHY,35830
74
- storage_service/tests/conftest.py,sha256=UfEjadRrCQuLbc9kNU8Y_8NWTyEp1DXmJ4nmb8hWU6k,467
75
- storage_service/tests/test_abfs.py,sha256=i7-yAlIjIDB8fkdOVz994bU62SMDK4VcRR9uu1OB7ic,5869
76
- storage_service/tests/test_integration_filesystem.py,sha256=-H3Skc_geYIjXW1si-8uHVxVImmPzr8h6aGYMolzORk,11174
77
- storage_service/tests/test_integration_s3.py,sha256=Ivg_52LXibqVGMS-53z4zda_Yh4u6FO8WplUUu5WWBc,13614
78
- storage_service/tests/test_local.py,sha256=3CgtxQ_lBBaPR4t9Ip0i7T98scrTOCdkmHYMVansNCc,11256
79
- storage_service/tests/test_s3.py,sha256=zAppsvVCeLx_NN1tQfqHo57mONEjeFDmiwyecrS3ZgQ,16355
80
- cledar_sdk-1.4.0.dist-info/METADATA,sha256=KY0mpTdaySyoD8xe8RDSEM0IZRFrF2rLCwNAy1SBcjg,6752
81
- cledar_sdk-1.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
82
- cledar_sdk-1.4.0.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
83
- cledar_sdk-1.4.0.dist-info/RECORD,,
common_logging/README.md DELETED
@@ -1,53 +0,0 @@
1
- # Universal Formatter
2
-
3
- The `UniversalPlaintextFormatter` is a custom logging formatter that extends the standard `logging.Formatter` class. It adds the ability to include extra attributes from log records while excluding standard attributes and configurable keys.
4
-
5
- ## Usage
6
-
7
- To use the `UniversalPlaintextFormatter` in your logging configuration, add the following to your `logging.conf` file:
8
-
9
- ```ini
10
- [formatter_plaintextFormatter]
11
- class=questions_generator.common_services.logging.universal_formatter.UniversalPlaintextFormatter
12
- format=%(asctime)s %(name)s [%(levelname)s]: %(message)s
13
- datefmt=%Y-%m-%d %H:%M:%S
14
- ```
15
-
16
- ## Features
17
-
18
- - Extends the standard logging.Formatter
19
- - Automatically includes extra attributes from log records
20
- - Excludes standard LogRecord attributes to keep logs clean
21
- - Configurable exclusion of additional keys
22
-
23
- ## Configuration Options
24
-
25
- In addition to the standard formatter options, you can configure which keys to exclude from the log output:
26
-
27
- ```ini
28
- [formatter_plaintextFormatter]
29
- class=questions_generator.common_services.logging.universal_formatter.UniversalPlaintextFormatter
30
- format=%(asctime)s %(name)s [%(levelname)s]: %(message)s
31
- datefmt=%Y-%m-%d %H:%M:%S
32
- exclude_keys=key1,key2,key3
33
- ```
34
-
35
- The `exclude_keys` option allows you to specify a comma-separated list of keys that should be excluded from the log output, in addition to the standard LogRecord attributes.
36
-
37
- ## Example
38
-
39
- When using this formatter, any extra attributes added to the log record will be automatically included in the log output:
40
-
41
- ```python
42
- import logging
43
-
44
- logger = logging.getLogger(__name__)
45
- logger.info("User logged in", extra={"user_id": 123, "ip_address": "192.168.1.1"})
46
- ```
47
-
48
- Output:
49
- ```
50
- 2023-08-04 12:34:56 my_module [INFO]: User logged in
51
- user_id: 123
52
- ip_address: 192.168.1.1
53
- ```
File without changes
@@ -1,249 +0,0 @@
1
- # pylint: disable=unused-argument, protected-access
2
- import logging
3
- import os
4
- import tempfile
5
- from pathlib import Path
6
-
7
- import pytest
8
-
9
- from common_logging.universal_plaintext_formatter import UniversalPlaintextFormatter
10
-
11
-
12
- @pytest.fixture(name="formatter")
13
- def fixture_formatter() -> UniversalPlaintextFormatter:
14
- """Create a basic formatter instance for testing."""
15
- return UniversalPlaintextFormatter(
16
- fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
17
- )
18
-
19
-
20
- @pytest.fixture(name="log_record")
21
- def fixture_log_record() -> logging.LogRecord:
22
- """Create a basic log record for testing."""
23
- return logging.LogRecord(
24
- name="test_logger",
25
- level=logging.INFO,
26
- pathname="/path/to/file.py",
27
- lineno=42,
28
- msg="Test message",
29
- args=(),
30
- exc_info=None,
31
- )
32
-
33
-
34
- def test_basic_formatting_without_extras(
35
- formatter: UniversalPlaintextFormatter, log_record: logging.LogRecord
36
- ) -> None:
37
- """Test that basic formatting works without extra attributes."""
38
- formatted = formatter.format(log_record)
39
- assert "Test message" in formatted
40
- assert "test_logger" in formatted
41
- assert "INFO" in formatted
42
-
43
-
44
- def test_standard_attributes_excluded(
45
- formatter: UniversalPlaintextFormatter, log_record: logging.LogRecord
46
- ) -> None:
47
- """Test that standard LogRecord attributes are excluded from extras."""
48
- formatted = formatter.format(log_record)
49
- # Standard attributes should not appear as extras
50
- assert "pathname:" not in formatted
51
- assert "lineno:" not in formatted
52
- assert "levelname:" not in formatted
53
-
54
-
55
- def test_extra_attributes_included(
56
- formatter: UniversalPlaintextFormatter, log_record: logging.LogRecord
57
- ) -> None:
58
- """Test that extra attributes are included in the formatted output."""
59
- log_record.user_id = "12345"
60
- log_record.request_id = "abc-def-ghi"
61
-
62
- formatted = formatter.format(log_record)
63
-
64
- assert "user_id: 12345" in formatted
65
- assert "request_id: abc-def-ghi" in formatted
66
-
67
-
68
- def test_default_exclude_keys(
69
- formatter: UniversalPlaintextFormatter, log_record: logging.LogRecord
70
- ) -> None:
71
- """Test that DEFAULT_EXCLUDE_KEYS (message, asctime) are excluded."""
72
- # Add 'message' and 'asctime' as extra attributes (shouldn't appear in extras)
73
- log_record.message = "This should be excluded"
74
- log_record.asctime = "2025-01-01 12:00:00"
75
-
76
- formatted = formatter.format(log_record)
77
-
78
- # These should not appear as extras
79
- lines = formatted.split("\n")
80
- extra_lines = [
81
- line for line in lines if line.strip().startswith(("message:", "asctime:"))
82
- ]
83
- assert len(extra_lines) == 0
84
-
85
-
86
- def test_multiple_extras_formatting(
87
- formatter: UniversalPlaintextFormatter, log_record: logging.LogRecord
88
- ) -> None:
89
- """Test formatting with multiple extra attributes."""
90
- log_record.user_id = "12345"
91
- log_record.session_id = "session-xyz"
92
- log_record.ip_address = "192.168.1.1"
93
-
94
- formatted = formatter.format(log_record)
95
-
96
- assert "user_id: 12345" in formatted
97
- assert "session_id: session-xyz" in formatted
98
- assert "ip_address: 192.168.1.1" in formatted
99
-
100
- # Check that extras are indented
101
- lines = formatted.split("\n")
102
- extra_lines = [
103
- line
104
- for line in lines
105
- if any(key in line for key in ("user_id:", "session_id:", "ip_address:"))
106
- ]
107
- for line in extra_lines:
108
- assert line.startswith(" ")
109
-
110
-
111
- def test_config_exclude_keys_from_file(log_record: logging.LogRecord) -> None:
112
- """Test that exclude_keys from configuration file are properly excluded."""
113
- with tempfile.TemporaryDirectory() as tmpdir:
114
- config_path = Path(tmpdir) / "logging.conf"
115
- config_content = """[formatter_plaintextFormatter]
116
- exclude_keys = custom_field, another_field
117
- """
118
- config_path.write_text(config_content)
119
-
120
- # Change to temp directory to read config
121
- original_dir = os.getcwd()
122
- try:
123
- os.chdir(tmpdir)
124
- formatter = UniversalPlaintextFormatter(fmt="%(message)s")
125
-
126
- # Add attributes that should be excluded
127
- log_record.custom_field = "should be excluded"
128
- log_record.another_field = "also excluded"
129
- log_record.included_field = "should be included"
130
-
131
- formatted = formatter.format(log_record)
132
-
133
- assert "custom_field:" not in formatted
134
- assert "another_field:" not in formatted
135
- assert "included_field: should be included" in formatted
136
- finally:
137
- os.chdir(original_dir)
138
-
139
-
140
- def test_config_exclude_keys_with_whitespace(
141
- log_record: logging.LogRecord,
142
- ) -> None:
143
- """Test that whitespace in exclude_keys configuration is handled correctly."""
144
- with tempfile.TemporaryDirectory() as tmpdir:
145
- config_path = Path(tmpdir) / "logging.conf"
146
- config_content = """[formatter_plaintextFormatter]
147
- exclude_keys = field1 , field2 , field3
148
- """
149
- config_path.write_text(config_content)
150
-
151
- original_dir = os.getcwd()
152
- try:
153
- os.chdir(tmpdir)
154
- formatter = UniversalPlaintextFormatter(fmt="%(message)s")
155
-
156
- log_record.field1 = "excluded"
157
- log_record.field2 = "excluded"
158
- log_record.field3 = "excluded"
159
-
160
- formatted = formatter.format(log_record)
161
-
162
- assert "field1:" not in formatted
163
- assert "field2:" not in formatted
164
- assert "field3:" not in formatted
165
- finally:
166
- os.chdir(original_dir)
167
-
168
-
169
- def test_no_config_file(
170
- formatter: UniversalPlaintextFormatter, log_record: logging.LogRecord
171
- ) -> None:
172
- """Test that formatter works correctly when config file doesn't exist."""
173
- log_record.some_extra = "value"
174
- formatted = formatter.format(log_record)
175
-
176
- # Should still format correctly
177
- assert "Test message" in formatted
178
- assert "some_extra: value" in formatted
179
-
180
-
181
- def test_empty_extras(
182
- formatter: UniversalPlaintextFormatter, log_record: logging.LogRecord
183
- ) -> None:
184
- """Test formatting when there are no extra attributes."""
185
- formatted = formatter.format(log_record)
186
-
187
- # Should only contain the base formatted message without extra newlines
188
- lines = formatted.split("\n")
189
- assert len([line for line in lines if line.strip()]) == 1
190
-
191
-
192
- def test_standard_attrs_caching(
193
- formatter: UniversalPlaintextFormatter,
194
- ) -> None:
195
- """Test that standard attributes are cached after first call."""
196
- assert formatter._standard_attrs is None
197
-
198
- # First call should set the cache
199
- standard_attrs = formatter._get_standard_attrs()
200
- assert formatter._standard_attrs is not None
201
- assert formatter._standard_attrs == standard_attrs
202
-
203
- # Second call should return cached value
204
- standard_attrs_2 = formatter._get_standard_attrs()
205
- assert standard_attrs_2 is standard_attrs # Same object
206
-
207
-
208
- def test_formatter_with_custom_format_string(
209
- log_record: logging.LogRecord,
210
- ) -> None:
211
- """Test formatter with a custom format string."""
212
- formatter = UniversalPlaintextFormatter(fmt="[%(levelname)s] %(message)s")
213
- log_record.extra_data = "test"
214
-
215
- formatted = formatter.format(log_record)
216
-
217
- assert "[INFO] Test message" in formatted
218
- assert "extra_data: test" in formatted
219
-
220
-
221
- def test_exclude_keys_combination(log_record: logging.LogRecord) -> None:
222
- """Test that all exclusion sources are combined correctly."""
223
- with tempfile.TemporaryDirectory() as tmpdir:
224
- config_path = Path(tmpdir) / "logging.conf"
225
- config_content = """[formatter_plaintextFormatter]
226
- exclude_keys = config_excluded
227
- """
228
- config_path.write_text(config_content)
229
-
230
- original_dir = os.getcwd()
231
- try:
232
- os.chdir(tmpdir)
233
- formatter = UniversalPlaintextFormatter(fmt="%(message)s")
234
-
235
- # Add various attributes
236
- log_record.pathname = "standard_attr" # Standard LogRecord attribute
237
- log_record.message = "default_excluded" # DEFAULT_EXCLUDE_KEYS
238
- log_record.config_excluded = "from_config" # From config file
239
- log_record.should_appear = "yes" # Should appear
240
-
241
- formatted = formatter.format(log_record)
242
-
243
- # Only should_appear should be in extras
244
- assert "pathname:" not in formatted # Standard attribute
245
- assert "message:" not in formatted # DEFAULT_EXCLUDE_KEYS
246
- assert "config_excluded:" not in formatted # Config exclude
247
- assert "should_appear: yes" in formatted # Should be included
248
- finally:
249
- os.chdir(original_dir)
@@ -1,94 +0,0 @@
1
- import configparser
2
- import logging
3
- from typing import Any
4
-
5
-
6
- class UniversalPlaintextFormatter(logging.Formatter):
7
- """
8
- A custom formatter for logging that extends the standard logging.Formatter.
9
-
10
- This formatter adds the ability to include extra attributes from log records while
11
- excluding standard attributes and configurable keys.
12
- """
13
-
14
- # Predefined exclusions - keys that should always be excluded
15
- DEFAULT_EXCLUDE_KEYS = {"message", "asctime"}
16
-
17
- def __init__(self, *args: Any, **kwargs: Any) -> None:
18
- """
19
- Initialize the formatter with standard formatter parameters.
20
-
21
- Args:
22
- *args: Variable length argument list for the parent class.
23
- **kwargs: Arbitrary keyword arguments for the parent class.
24
- """
25
- super().__init__(*args, **kwargs)
26
- self._standard_attrs: set[str] | None = None
27
- self._config_exclude_keys = self._load_exclude_keys_from_config()
28
-
29
- def _load_exclude_keys_from_config(self) -> set[str]:
30
- """
31
- Load additional keys to exclude from the configuration file.
32
-
33
- Returns:
34
- set: A set of keys to exclude from log records.
35
- """
36
- try:
37
- config = configparser.ConfigParser()
38
- config.read("logging.conf")
39
- if config.has_option("formatter_plaintextFormatter", "exclude_keys"):
40
- exclude_str = config.get("formatter_plaintextFormatter", "exclude_keys")
41
- return set(key.strip() for key in exclude_str.split(",") if key.strip())
42
- except (configparser.Error, FileNotFoundError, PermissionError, ValueError):
43
- pass
44
- return set()
45
-
46
- def _get_standard_attrs(self) -> set[str]:
47
- """
48
- Get the set of standard attributes to exclude from log records.
49
-
50
- This includes standard LogRecord attributes, predefined exclusions,
51
- and exclusions from configuration.
52
-
53
- Returns:
54
- set: A set of attribute names to exclude.
55
- """
56
- if self._standard_attrs is None:
57
- dummy_record = logging.LogRecord(
58
- name="dummy",
59
- level=logging.INFO,
60
- pathname="",
61
- lineno=0,
62
- msg="",
63
- args=(),
64
- exc_info=None,
65
- )
66
- # Combine standard attributes + predefined + from configuration
67
- all_excludes = (
68
- set(dummy_record.__dict__.keys())
69
- | self.DEFAULT_EXCLUDE_KEYS
70
- | self._config_exclude_keys
71
- )
72
- self._standard_attrs = all_excludes
73
- return self._standard_attrs
74
-
75
- def format(self, record: logging.LogRecord) -> str:
76
- """
77
- Format the log record, adding any extra attributes not in the standard set.
78
-
79
- Args:
80
- record: The log record to format.
81
-
82
- Returns:
83
- str: The formatted log message with extra attributes appended.
84
- """
85
- base = super().format(record)
86
- extras = {
87
- k: v
88
- for k, v in record.__dict__.items()
89
- if k not in self._get_standard_attrs()
90
- }
91
- if extras:
92
- extras_str = "\n".join(f" {k}: {v}" for k, v in extras.items())
93
- return f"{base}\n{extras_str}"
94
- return base