dsw-config 4.13.0__py2.py3-none-any.whl → 4.15.0__py2.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.
dsw/config/build_info.py CHANGED
@@ -9,9 +9,9 @@ BuildInfo = namedtuple(
9
9
  )
10
10
 
11
11
  BUILD_INFO = BuildInfo(
12
- version='v4.13.0~c8e1cb3',
13
- built_at='2024-12-05 08:07:29Z',
14
- sha='c8e1cb3b7e0cc93bdf509eef715cd0a926d907c3',
12
+ version='v4.15.0~0624f1a',
13
+ built_at='2025-02-04 15:03:57Z',
14
+ sha='0624f1af3f4ccd0fa38ec76a640b17ef405ab153',
15
15
  branch='HEAD',
16
- tag='v4.13.0',
16
+ tag='v4.15.0',
17
17
  )
dsw/config/keys.py CHANGED
@@ -1,60 +1,61 @@
1
+ # pylint: disable=too-few-public-methods
1
2
  import collections
3
+ import typing
2
4
 
3
- from typing import Any, Optional, Generic, TypeVar, Callable
4
5
 
6
+ T = typing.TypeVar('T')
5
7
 
6
- T = TypeVar('T')
7
8
 
8
-
9
- def cast_bool(value: Any) -> bool:
9
+ def cast_bool(value: typing.Any) -> bool:
10
10
  return bool(value)
11
11
 
12
12
 
13
- def cast_optional_bool(value: Any) -> Optional[bool]:
13
+ def cast_optional_bool(value: typing.Any) -> bool | None:
14
14
  if value is None:
15
15
  return None
16
16
  return bool(value)
17
17
 
18
18
 
19
- def cast_int(value: Any) -> int:
19
+ def cast_int(value: typing.Any) -> int:
20
20
  return int(value)
21
21
 
22
22
 
23
- def cast_optional_int(value: Any) -> Optional[int]:
23
+ def cast_optional_int(value: typing.Any) -> int | None:
24
24
  if value is None:
25
25
  return None
26
26
  return int(value)
27
27
 
28
28
 
29
- def cast_float(value: Any) -> float:
29
+ def cast_float(value: typing.Any) -> float:
30
30
  return float(value)
31
31
 
32
32
 
33
- def cast_optional_float(value: Any) -> Optional[float]:
33
+ def cast_optional_float(value: typing.Any) -> float | None:
34
34
  if value is None:
35
35
  return None
36
36
  return float(value)
37
37
 
38
38
 
39
- def cast_str(value: Any) -> str:
39
+ def cast_str(value: typing.Any) -> str:
40
40
  return str(value)
41
41
 
42
42
 
43
- def cast_optional_str(value: Any) -> Optional[str]:
43
+ def cast_optional_str(value: typing.Any) -> str | None:
44
44
  if value is None:
45
45
  return None
46
46
  return str(value)
47
47
 
48
48
 
49
- def cast_optional_dict(value: Any) -> Optional[dict]:
49
+ def cast_optional_dict(value: typing.Any) -> dict | None:
50
50
  if not isinstance(value, dict):
51
51
  return None
52
52
  return value
53
53
 
54
54
 
55
- class ConfigKey(Generic[T]):
55
+ class ConfigKey(typing.Generic[T]):
56
56
 
57
- def __init__(self, yaml_path: list[str], cast: Callable[[Any], T],
57
+ def __init__(self, *, yaml_path: list[str],
58
+ cast: typing.Callable[[typing.Any], T],
58
59
  var_names=None, default=None, required=False):
59
60
  self.yaml_path = yaml_path
60
61
  self.var_names = var_names or [] # type: list[str]
@@ -63,12 +64,13 @@ class ConfigKey(Generic[T]):
63
64
  self.cast = cast
64
65
 
65
66
  def __str__(self):
66
- return 'ConfigKey: ' + '.'.join(self.yaml_path)
67
+ return f'ConfigKey: {".".join(self.yaml_path)}'
67
68
 
68
69
 
69
70
  class ConfigKeysMeta(type):
70
71
 
71
72
  @classmethod
73
+ # pylint: disable-next=unused-argument
72
74
  def __prepare__(mcs, name, bases, **kwargs):
73
75
  return collections.OrderedDict()
74
76
 
@@ -176,6 +178,12 @@ class _SentryKeys(ConfigKeysContainer):
176
178
  default='',
177
179
  cast=cast_str,
178
180
  )
181
+ environment = ConfigKey(
182
+ yaml_path=['sentry', 'environment'],
183
+ var_names=['SENTRY_ENVIRONMENT'],
184
+ default='production',
185
+ cast=cast_str,
186
+ )
179
187
 
180
188
 
181
189
  class _DatabaseKeys(ConfigKeysContainer):
dsw/config/logging.py CHANGED
@@ -28,6 +28,8 @@ class DSWLogger(logging.Logger):
28
28
 
29
29
 
30
30
  def prepare_logging(logging_cfg):
31
+ # pylint: disable-next=no-member
32
+ logger_dict = logging.root.manager.loggerDict
31
33
  if logging_cfg.dict_config is not None:
32
34
  logging.config.dictConfig(logging_cfg.dict_config)
33
35
  else:
@@ -36,15 +38,13 @@ def prepare_logging(logging_cfg):
36
38
  level=logging_cfg.global_level,
37
39
  format=logging_cfg.message_format
38
40
  )
39
- dsw_loggers = (logging.getLogger(name)
40
- for name in logging.root.manager.loggerDict.keys()
41
+ dsw_loggers = (logging.getLogger(name) for name in logger_dict
41
42
  if name.lower().startswith('dsw'))
42
43
  for logger in dsw_loggers:
43
44
  logger.setLevel(logging_cfg.level)
44
45
  # Set for all existing loggers
45
46
  logging.getLogger().addFilter(filter=LOG_FILTER)
46
- loggers = (logging.getLogger(name)
47
- for name in logging.root.manager.loggerDict.keys())
47
+ loggers = (logging.getLogger(name) for name in logger_dict)
48
48
  for logger in loggers:
49
49
  logger.addFilter(filter=LOG_FILTER)
50
50
  # Set for any future loggers
dsw/config/model.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ import dataclasses
2
2
 
3
3
  from .logging import prepare_logging, LOG_FILTER
4
4
 
@@ -19,52 +19,44 @@ class ConfigModel:
19
19
  return _config_to_string(self)
20
20
 
21
21
 
22
+ @dataclasses.dataclass
22
23
  class GeneralConfig(ConfigModel):
23
-
24
- def __init__(self, environment: str, client_url: str, secret: str):
25
- self.environment = environment
26
- self.client_url = client_url
27
- self.secret = secret
24
+ environment: str
25
+ client_url: str
26
+ secret: str
28
27
 
29
28
 
29
+ @dataclasses.dataclass
30
30
  class SentryConfig(ConfigModel):
31
-
32
- def __init__(self, enabled: bool, workers_dsn: Optional[str],
33
- traces_sample_rate: Optional[float], max_breadcrumbs: Optional[int]):
34
- self.enabled = enabled
35
- self.workers_dsn = workers_dsn
36
- self.traces_sample_rate = traces_sample_rate
37
- self.max_breadcrumbs = max_breadcrumbs
31
+ enabled: bool
32
+ workers_dsn: str | None
33
+ traces_sample_rate: float | None
34
+ max_breadcrumbs: int | None
35
+ environment: str
38
36
 
39
37
 
38
+ @dataclasses.dataclass
40
39
  class DatabaseConfig(ConfigModel):
41
-
42
- def __init__(self, connection_string: str, connection_timeout: int,
43
- queue_timeout: int):
44
- self.connection_string = connection_string
45
- self.connection_timeout = connection_timeout
46
- self.queue_timeout = queue_timeout
40
+ connection_string: str
41
+ connection_timeout: int
42
+ queue_timeout: int
47
43
 
48
44
 
45
+ @dataclasses.dataclass
49
46
  class S3Config(ConfigModel):
50
-
51
- def __init__(self, url: str, username: str, password: str,
52
- bucket: str, region: str):
53
- self.url = url
54
- self.username = username
55
- self.password = password
56
- self.bucket = bucket
57
- self.region = region
47
+ url: str
48
+ username: str
49
+ password: str
50
+ bucket: str
51
+ region: str
58
52
 
59
53
 
54
+ @dataclasses.dataclass
60
55
  class LoggingConfig(ConfigModel):
61
-
62
- def __init__(self, level: str, global_level: str, message_format: str,
63
- dict_config: Optional[dict] = None):
64
- self.level = level
65
- self.global_level = global_level
66
- self.message_format = message_format
67
- self.dict_config = dict_config
56
+ level: str
57
+ global_level: str
58
+ message_format: str
59
+ dict_config: dict | None = None
68
60
 
69
61
  def apply(self):
70
62
  prepare_logging(self)
@@ -74,20 +66,17 @@ class LoggingConfig(ConfigModel):
74
66
  LOG_FILTER.set_extra(key, value)
75
67
 
76
68
 
69
+ @dataclasses.dataclass
77
70
  class AWSConfig(ConfigModel):
78
-
79
- def __init__(self, access_key_id: Optional[str], secret_access_key: Optional[str],
80
- region: Optional[str]):
81
- self.access_key_id = access_key_id
82
- self.secret_access_key = secret_access_key
83
- self.region = region
71
+ access_key_id: str | None
72
+ secret_access_key: str | None
73
+ region: str | None
84
74
 
85
75
  @property
86
76
  def has_credentials(self) -> bool:
87
77
  return self.access_key_id is not None and self.secret_access_key is not None
88
78
 
89
79
 
80
+ @dataclasses.dataclass
90
81
  class CloudConfig(ConfigModel):
91
-
92
- def __init__(self, multi_tenant: bool):
93
- self.multi_tenant = multi_tenant
82
+ multi_tenant: bool
dsw/config/parser.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import os
2
- import yaml
2
+ import typing
3
3
 
4
- from typing import List, Any, IO
4
+ import yaml
5
5
 
6
6
  from .keys import ConfigKey, ConfigKeys
7
7
  from .model import GeneralConfig, SentryConfig, S3Config, \
@@ -10,14 +10,14 @@ from .model import GeneralConfig, SentryConfig, S3Config, \
10
10
 
11
11
  class MissingConfigurationError(Exception):
12
12
 
13
- def __init__(self, missing: List[str]):
13
+ def __init__(self, missing: list[str]):
14
14
  self.missing = missing
15
15
 
16
16
 
17
17
  class DSWConfigParser:
18
18
 
19
19
  def __init__(self, keys=ConfigKeys):
20
- self.cfg = dict()
20
+ self.cfg = {}
21
21
  self.keys = keys
22
22
 
23
23
  @staticmethod
@@ -28,7 +28,7 @@ class DSWConfigParser:
28
28
  except Exception:
29
29
  return False
30
30
 
31
- def read_file(self, fp: IO):
31
+ def read_file(self, fp: typing.IO):
32
32
  self.cfg = yaml.load(fp, Loader=yaml.FullLoader) or self.cfg
33
33
 
34
34
  def read_string(self, content: str):
@@ -50,12 +50,12 @@ class DSWConfigParser:
50
50
  if self.has_value_for_path(key.yaml_path):
51
51
  return True
52
52
  for var_name in key.var_names:
53
- if var_name in os.environ.keys() or \
54
- self._prefix_var(var_name) in os.environ.keys():
53
+ if var_name in os.environ or self._prefix_var(var_name) in os.environ:
55
54
  return True
55
+ return False
56
56
 
57
57
  def get_or_default(self, key: ConfigKey):
58
- x = self.cfg # type: Any
58
+ x: typing.Any = self.cfg
59
59
  for p in key.yaml_path:
60
60
  if not hasattr(x, 'keys') or p not in x.keys():
61
61
  return key.default
@@ -64,9 +64,9 @@ class DSWConfigParser:
64
64
 
65
65
  def get(self, key: ConfigKey):
66
66
  for var_name in key.var_names:
67
- if var_name in os.environ.keys():
67
+ if var_name in os.environ:
68
68
  return key.cast(os.environ[var_name])
69
- if self._prefix_var(var_name) in os.environ.keys():
69
+ if self._prefix_var(var_name) in os.environ:
70
70
  return key.cast(os.environ[self._prefix_var(var_name)])
71
71
  return key.cast(self.get_or_default(key))
72
72
 
@@ -118,6 +118,7 @@ class DSWConfigParser:
118
118
  workers_dsn=self.get(self.keys.sentry.worker_dsn),
119
119
  traces_sample_rate=self.get(self.keys.sentry.traces_sample_rate),
120
120
  max_breadcrumbs=self.get(self.keys.sentry.max_breadcrumbs),
121
+ environment=self.get(self.keys.sentry.environment),
121
122
  )
122
123
 
123
124
  @property
dsw/config/sentry.py CHANGED
@@ -1,23 +1,46 @@
1
+ import logging
2
+ import typing
3
+
1
4
  import sentry_sdk
5
+ from sentry_sdk.types import Event, Hint
6
+ from sentry_sdk.integrations.logging import LoggingIntegration
2
7
 
3
8
  from .model import SentryConfig
4
9
 
5
10
 
11
+ EventProcessor = typing.Callable[[Event, Hint], typing.Optional[Event]]
12
+
13
+
6
14
  class SentryReporter:
7
15
  report = False
16
+ filters = [] # type: list[EventProcessor]
8
17
 
9
18
  @classmethod
10
- def initialize(cls, dsn: str, server_name: str, environment: str,
11
- prog_name: str, release: str, config: SentryConfig):
19
+ def initialize(cls, *, config: SentryConfig, prog_name: str, release: str,
20
+ breadcrumb_level: int | None = logging.INFO,
21
+ event_level: int | None = logging.ERROR):
12
22
  cls.report = config.enabled and config.workers_dsn is not None
13
23
  if cls.report:
24
+ def before_send(event, hint):
25
+ for f in cls.filters:
26
+ if not f(event, hint):
27
+ return None
28
+ return event
29
+
14
30
  sentry_sdk.init(
15
- dsn=dsn,
31
+ dsn=config.workers_dsn,
16
32
  traces_sample_rate=config.traces_sample_rate or 1.0,
17
33
  max_breadcrumbs=config.max_breadcrumbs or sentry_sdk.consts.DEFAULT_MAX_BREADCRUMBS,
18
34
  release=release,
19
- server_name=server_name,
20
- environment=environment,
35
+ environment=config.environment,
36
+ before_send=before_send,
37
+ default_integrations=False,
38
+ integrations=[
39
+ LoggingIntegration(
40
+ level=breadcrumb_level,
41
+ event_level=event_level,
42
+ ),
43
+ ],
21
44
  )
22
45
  sentry_sdk.set_tag('component', prog_name)
23
46
 
@@ -32,6 +55,6 @@ class SentryReporter:
32
55
  sentry_sdk.capture_message(*args, **kwargs)
33
56
 
34
57
  @classmethod
35
- def set_context(cls, name: str, value):
58
+ def set_tags(cls, **tags):
36
59
  if cls.report:
37
- sentry_sdk.set_context(name, value)
60
+ sentry_sdk.set_tags(tags)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dsw-config
3
- Version: 4.13.0
3
+ Version: 4.15.0
4
4
  Summary: Library for DSW config manipulation
5
5
  Author-email: Marek Suchánek <marek.suchanek@ds-wizard.org>
6
6
  License: Apache License 2.0
@@ -11,11 +11,11 @@ Keywords: dsw,config,yaml,parser
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Topic :: Text Processing
17
17
  Classifier: Topic :: Utilities
18
- Requires-Python: <4,>=3.10
18
+ Requires-Python: <4,>=3.11
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
21
  Requires-Dist: PyYAML
@@ -0,0 +1,12 @@
1
+ dsw/config/__init__.py,sha256=2tf8kQHwcEpoGwUoXyczIFzkAUi112973KTccusrDmM,123
2
+ dsw/config/build_info.py,sha256=ZIViLHUrdxeLBrJ_kh0jWVyGkXhOHtA8ACFsTN6Jmhc,381
3
+ dsw/config/keys.py,sha256=uKMBHJI8gCrSqyjdpFnwzj1zRRoJnyB0jlXR4p0zDD0,6998
4
+ dsw/config/logging.py,sha256=I4-WjLNRIlmRS3TRXIF66IzI4c0DLzYsbJ0A9jGiPW4,1479
5
+ dsw/config/model.py,sha256=4IIy25TkS0VfDOxWdOW4AxVHVdUiRfBCmEqin9JcYf0,1760
6
+ dsw/config/parser.py,sha256=SOznsTdEMZ31aTKenvYpICA4y4_z-8MWFeTn3xUrlRY,4469
7
+ dsw/config/sentry.py,sha256=anpGZATeJYTLq7n8BF9m_8fcoNrP2hAS53fAZ6JsyOA,1940
8
+ dsw_config-4.15.0.dist-info/LICENSE,sha256=rDtJ4LdsXvf_euOpGD0Q86P78K4JyM5m4yfYz9wZ750,11346
9
+ dsw_config-4.15.0.dist-info/METADATA,sha256=HG1zgNiH3igY2bBBgpAIKF3CJPMvow7cFkBqfl5xRnI,1796
10
+ dsw_config-4.15.0.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
11
+ dsw_config-4.15.0.dist-info/top_level.txt,sha256=7SfbsHFoJ_vlAgG6C-xzETETwYO71dBrGnod8uMFnjw,4
12
+ dsw_config-4.15.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
@@ -1,12 +0,0 @@
1
- dsw/config/__init__.py,sha256=2tf8kQHwcEpoGwUoXyczIFzkAUi112973KTccusrDmM,123
2
- dsw/config/build_info.py,sha256=ldrmlx-ppzLSG3lD4GXZxHk1Xe1y2LPjAaNR2GQccu4,381
3
- dsw/config/keys.py,sha256=6X62tAr4ysFpI-ZCHsH9-0Eg0oh9szyjHqJihEQrQTQ,6691
4
- dsw/config/logging.py,sha256=vCpt349vmvO08SNbp0K6aU9BPt_78op0QxKflDYmg7Q,1484
5
- dsw/config/model.py,sha256=zJieb9FDDzCGwxX1ijaRVHpcyyx65Q-grqJBaRd6P2s,2684
6
- dsw/config/parser.py,sha256=klrTnzpe7dL6mxsewb8QExqqKfC-CZcIfZSINoeqVHk,4451
7
- dsw/config/sentry.py,sha256=Em1d72DGhLmrM5nUIuOwkG_98cjX4NeiYbQluTjRisg,1181
8
- dsw_config-4.13.0.dist-info/LICENSE,sha256=rDtJ4LdsXvf_euOpGD0Q86P78K4JyM5m4yfYz9wZ750,11346
9
- dsw_config-4.13.0.dist-info/METADATA,sha256=xSwbsKw0cNZoqXxANgMT1Nz58jAt6QXdfL_6xmHyXf0,1796
10
- dsw_config-4.13.0.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109
11
- dsw_config-4.13.0.dist-info/top_level.txt,sha256=7SfbsHFoJ_vlAgG6C-xzETETwYO71dBrGnod8uMFnjw,4
12
- dsw_config-4.13.0.dist-info/RECORD,,