c2cwsgiutils 6.1.0.dev105__py3-none-any.whl → 6.1.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 (55) hide show
  1. c2cwsgiutils/__init__.py +14 -11
  2. c2cwsgiutils/acceptance/__init__.py +2 -3
  3. c2cwsgiutils/acceptance/connection.py +1 -2
  4. c2cwsgiutils/acceptance/image.py +7 -8
  5. c2cwsgiutils/acceptance/package-lock.json +306 -213
  6. c2cwsgiutils/acceptance/package.json +2 -2
  7. c2cwsgiutils/acceptance/print.py +7 -3
  8. c2cwsgiutils/acceptance/utils.py +1 -3
  9. c2cwsgiutils/auth.py +27 -25
  10. c2cwsgiutils/broadcast/__init__.py +15 -16
  11. c2cwsgiutils/broadcast/interface.py +3 -3
  12. c2cwsgiutils/broadcast/local.py +1 -0
  13. c2cwsgiutils/broadcast/redis.py +13 -12
  14. c2cwsgiutils/client_info.py +19 -1
  15. c2cwsgiutils/coverage_setup.py +4 -3
  16. c2cwsgiutils/db.py +35 -41
  17. c2cwsgiutils/db_maintenance_view.py +13 -13
  18. c2cwsgiutils/debug/__init__.py +2 -2
  19. c2cwsgiutils/debug/_listeners.py +1 -1
  20. c2cwsgiutils/debug/_views.py +7 -6
  21. c2cwsgiutils/debug/utils.py +9 -9
  22. c2cwsgiutils/errors.py +13 -15
  23. c2cwsgiutils/health_check.py +24 -30
  24. c2cwsgiutils/index.py +7 -9
  25. c2cwsgiutils/loader.py +1 -1
  26. c2cwsgiutils/logging_view.py +12 -12
  27. c2cwsgiutils/models_graph.py +0 -1
  28. c2cwsgiutils/pretty_json.py +0 -1
  29. c2cwsgiutils/prometheus.py +1 -7
  30. c2cwsgiutils/pyramid.py +0 -1
  31. c2cwsgiutils/pyramid_logging.py +1 -1
  32. c2cwsgiutils/redis_stats.py +9 -9
  33. c2cwsgiutils/redis_utils.py +19 -18
  34. c2cwsgiutils/request_tracking/__init__.py +13 -13
  35. c2cwsgiutils/request_tracking/_sql.py +0 -1
  36. c2cwsgiutils/scripts/genversion.py +5 -5
  37. c2cwsgiutils/scripts/stats_db.py +19 -17
  38. c2cwsgiutils/scripts/test_print.py +5 -5
  39. c2cwsgiutils/sentry.py +55 -20
  40. c2cwsgiutils/services.py +2 -2
  41. c2cwsgiutils/setup_process.py +0 -1
  42. c2cwsgiutils/sql_profiler/__init__.py +5 -6
  43. c2cwsgiutils/sql_profiler/_impl.py +18 -17
  44. c2cwsgiutils/sqlalchemylogger/README.md +30 -13
  45. c2cwsgiutils/sqlalchemylogger/handlers.py +11 -10
  46. c2cwsgiutils/stats_pyramid/__init__.py +1 -5
  47. c2cwsgiutils/stats_pyramid/_db_spy.py +2 -2
  48. c2cwsgiutils/stats_pyramid/_pyramid_spy.py +0 -1
  49. c2cwsgiutils/version.py +11 -5
  50. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.1.dist-info}/LICENSE +1 -1
  51. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.1.dist-info}/METADATA +17 -5
  52. c2cwsgiutils-6.1.1.dist-info/RECORD +67 -0
  53. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.1.dist-info}/WHEEL +1 -1
  54. c2cwsgiutils-6.1.0.dev105.dist-info/RECORD +0 -67
  55. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.1.dist-info}/entry_points.txt +0 -0
@@ -16,7 +16,7 @@ import traceback
16
16
  from collections.abc import Mapping
17
17
  from enum import Enum
18
18
  from types import TracebackType
19
- from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, cast
19
+ from typing import Any, Callable, Literal, Optional, Union, cast
20
20
 
21
21
  import prometheus_client
22
22
  import pyramid.config
@@ -30,13 +30,10 @@ from pyramid.httpexceptions import HTTPNotFound
30
30
  import c2cwsgiutils.db
31
31
  from c2cwsgiutils import auth, broadcast, config_utils, prometheus, redis_utils, version
32
32
 
33
- if TYPE_CHECKING:
34
- scoped_session = sqlalchemy.orm.scoped_session[sqlalchemy.orm.Session]
35
- else:
36
- scoped_session = sqlalchemy.orm.scoped_session
33
+ _scoped_session = sqlalchemy.orm.scoped_session[sqlalchemy.orm.Session]
37
34
 
38
- LOG = logging.getLogger(__name__)
39
- ALEMBIC_HEAD_RE = re.compile(r"^([a-f0-9]+) \(head\)\n$")
35
+ _LOG = logging.getLogger(__name__)
36
+ _ALEMBIC_HEAD_RE = re.compile(r"^([a-f0-9]+) \(head\)\n$")
40
37
 
41
38
  _PROMETHEUS_DB_SUMMARY = prometheus_client.Summary(
42
39
  prometheus.build_metric_name("health_check_db"),
@@ -78,14 +75,16 @@ class JsonCheckException(Exception):
78
75
  return self.message
79
76
 
80
77
  def json_data(self) -> Any:
78
+ """Return the JSON data to be returned in the response."""
81
79
  return self.json
82
80
 
83
81
 
84
82
  class _Binding:
85
83
  def name(self) -> str:
84
+ """Return the name of the binding."""
86
85
  raise NotImplementedError()
87
86
 
88
- def __enter__(self) -> scoped_session:
87
+ def __enter__(self) -> _scoped_session:
89
88
  raise NotImplementedError()
90
89
 
91
90
  def __exit__(
@@ -105,12 +104,12 @@ class _NewBinding(_Binding):
105
104
  def name(self) -> str:
106
105
  return self.session.engine_name(self.readwrite)
107
106
 
108
- def __enter__(self) -> scoped_session:
107
+ def __enter__(self) -> _scoped_session:
109
108
  return self.session(None, self.readwrite)
110
109
 
111
110
 
112
111
  class _OldBinding(_Binding):
113
- def __init__(self, session: scoped_session, engine: sqlalchemy.engine.Engine):
112
+ def __init__(self, session: _scoped_session, engine: sqlalchemy.engine.Engine):
114
113
  self.session = session
115
114
  self.engine = engine
116
115
  self.prev_bind = None
@@ -118,7 +117,7 @@ class _OldBinding(_Binding):
118
117
  def name(self) -> str:
119
118
  return cast(str, self.engine.c2c_name) # type: ignore
120
119
 
121
- def __enter__(self) -> scoped_session:
120
+ def __enter__(self) -> _scoped_session:
122
121
  self.prev_bind = self.session.bind # type: ignore
123
122
  self.session.bind = self.engine
124
123
  return self.session
@@ -134,7 +133,7 @@ class _OldBinding(_Binding):
134
133
 
135
134
 
136
135
  def _get_binding_class(
137
- session: Union[scoped_session, c2cwsgiutils.db.SessionFactory],
136
+ session: Union[_scoped_session, c2cwsgiutils.db.SessionFactory],
138
137
  ro_engin: sqlalchemy.engine.Engine,
139
138
  rw_engin: sqlalchemy.engine.Engine,
140
139
  readwrite: bool,
@@ -146,7 +145,7 @@ def _get_binding_class(
146
145
 
147
146
 
148
147
  def _get_bindings(
149
- session: Union[scoped_session, c2cwsgiutils.db.SessionFactory],
148
+ session: Union[_scoped_session, c2cwsgiutils.db.SessionFactory],
150
149
  engine_type: EngineType,
151
150
  ) -> list[_Binding]:
152
151
  if isinstance(session, c2cwsgiutils.db.SessionFactory):
@@ -184,7 +183,7 @@ def _get_alembic_version(alembic_ini_path: str, name: str) -> str:
184
183
  out = subprocess.check_output( # nosec
185
184
  ["alembic", "--config", alembic_ini_path, "--name", name, "heads"], cwd=dirname, env=env
186
185
  ).decode("utf-8")
187
- out_match = ALEMBIC_HEAD_RE.match(out)
186
+ out_match = _ALEMBIC_HEAD_RE.match(out)
188
187
  if not out_match:
189
188
  raise Exception( # pylint: disable=broad-exception-raised
190
189
  "Cannot get the alembic HEAD version from: " + out
@@ -219,8 +218,8 @@ class HealthCheck:
219
218
 
220
219
  def add_db_session_check(
221
220
  self,
222
- session: Union[scoped_session, c2cwsgiutils.db.SessionFactory],
223
- query_cb: Optional[Callable[[scoped_session], Any]] = None,
221
+ session: Union[_scoped_session, c2cwsgiutils.db.SessionFactory],
222
+ query_cb: Optional[Callable[[_scoped_session], Any]] = None,
224
223
  at_least_one_model: Optional[object] = None,
225
224
  level: int = 1,
226
225
  engine_type: EngineType = EngineType.READ_AND_WRITE,
@@ -229,7 +228,6 @@ class HealthCheck:
229
228
  Check a DB session is working. You can specify either query_cb or at_least_one_model.
230
229
 
231
230
  Arguments:
232
-
233
231
  session: a DB session created by c2cwsgiutils.db.init()
234
232
  query_cb: a callable that take a session as parameter and check it works
235
233
  at_least_one_model: a model that must have at least one entry in the DB
@@ -247,7 +245,7 @@ class HealthCheck:
247
245
 
248
246
  def add_alembic_check(
249
247
  self,
250
- session: scoped_session,
248
+ session: _scoped_session,
251
249
  alembic_ini_path: str,
252
250
  level: int = 2,
253
251
  name: str = "alembic",
@@ -258,7 +256,6 @@ class HealthCheck:
258
256
  Check the DB version against the HEAD version of Alembic.
259
257
 
260
258
  Arguments:
261
-
262
259
  session: A DB session created by c2cwsgiutils.db.init() giving access to the DB \
263
260
  managed by Alembic
264
261
  alembic_ini_path: Path to the Alembic INI file
@@ -283,7 +280,7 @@ class HealthCheck:
283
280
  assert version_table
284
281
 
285
282
  class _Check:
286
- def __init__(self, session: scoped_session) -> None:
283
+ def __init__(self, session: _scoped_session) -> None:
287
284
  self.session = session
288
285
 
289
286
  def __call__(self, request: pyramid.request.Request) -> str:
@@ -334,7 +331,6 @@ class HealthCheck:
334
331
  Check that a GET on an URL returns 2xx.
335
332
 
336
333
  Arguments:
337
-
338
334
  url: the URL to query or a function taking the request and returning it
339
335
  params: the parameters or a function taking the request and returning them
340
336
  headers: the headers or a function taking the request and returning them
@@ -367,7 +363,6 @@ class HealthCheck:
367
363
  One such check is automatically added if the broadcaster is configured with redis.
368
364
 
369
365
  Arguments:
370
-
371
366
  name: the name of the check (defaults to url)
372
367
  level: the level of the health check
373
368
  """
@@ -415,13 +410,13 @@ class HealthCheck:
415
410
  """
416
411
  Check that the version matches across all instances.
417
412
 
418
- Keyword Arguments:
419
-
413
+ Arguments:
420
414
  name: the name of the check (defaults to "version")
421
415
  level: the level of the health check
422
416
  """
423
417
 
424
418
  def check(request: pyramid.request.Request) -> dict[str, Any]:
419
+ del request # unused
425
420
  ref = version.get_version()
426
421
  all_versions = _get_all_versions()
427
422
  assert all_versions
@@ -443,7 +438,6 @@ class HealthCheck:
443
438
  in the response. In case of failure it must raise an exception.
444
439
 
445
440
  Arguments:
446
-
447
441
  name: the name of the check
448
442
  check_cb: the callback to call (takes the request as parameter)
449
443
  level: the level of the health check
@@ -489,7 +483,7 @@ class HealthCheck:
489
483
  _set_success(check_name=name)
490
484
  except Exception as e: # pylint: disable=broad-except
491
485
  _PROMETHEUS_HEALTH_CHECKS_FAILURE.labels(name=name).set(1)
492
- LOG.warning("Health check %s failed", name, exc_info=True)
486
+ _LOG.warning("Health check %s failed", name, exc_info=True)
493
487
  failure = {"message": str(e), "timing": time.perf_counter() - start, "level": level}
494
488
  if isinstance(e, JsonCheckException) and e.json_data() is not None:
495
489
  failure["result"] = e.json_data()
@@ -500,9 +494,10 @@ class HealthCheck:
500
494
  @staticmethod
501
495
  def _create_db_engine_check(
502
496
  binding: _Binding,
503
- query_cb: Callable[[scoped_session], None],
497
+ query_cb: Callable[[_scoped_session], None],
504
498
  ) -> tuple[str, Callable[[pyramid.request.Request], None]]:
505
499
  def check(request: pyramid.request.Request) -> None:
500
+ del request # unused
506
501
  with binding as session:
507
502
  with _PROMETHEUS_DB_SUMMARY.labels(
508
503
  connection=binding.name(), check="database", configuration="<default>"
@@ -512,8 +507,8 @@ class HealthCheck:
512
507
  return "db_engine_" + binding.name(), check
513
508
 
514
509
  @staticmethod
515
- def _at_least_one(model: Any) -> Callable[[scoped_session], Any]:
516
- def query(session: scoped_session) -> None:
510
+ def _at_least_one(model: Any) -> Callable[[_scoped_session], Any]:
511
+ def query(session: _scoped_session) -> None:
517
512
  result = session.query(model).first()
518
513
  if result is None:
519
514
  raise HTTPNotFound(model.__name__ + " record not found")
@@ -528,7 +523,6 @@ def _maybe_function(what: Any, request: pyramid.request.Request) -> Any:
528
523
  @broadcast.decorator(expect_answers=False)
529
524
  def _set_success(check_name: str) -> None:
530
525
  """Set check in success in all process."""
531
-
532
526
  _PROMETHEUS_HEALTH_CHECKS_FAILURE.labels(name=check_name).set(0)
533
527
 
534
528
 
c2cwsgiutils/index.py CHANGED
@@ -42,12 +42,12 @@ from c2cwsgiutils.auth import (
42
42
  )
43
43
  from c2cwsgiutils.config_utils import env_or_settings
44
44
 
45
- LOG = logging.getLogger(__name__)
45
+ _LOG = logging.getLogger(__name__)
46
46
 
47
47
  additional_title: Optional[str] = None
48
48
  additional_noauth: list[str] = []
49
49
  additional_auth: list[str] = []
50
- ELEM_ID = 0
50
+ _ELEM_ID = 0
51
51
 
52
52
 
53
53
  def _url(
@@ -113,9 +113,9 @@ def input_(
113
113
  name: str, label: Optional[str] = None, type_: Optional[str] = None, value: Union[str, int] = ""
114
114
  ) -> str:
115
115
  """Get an HTML input."""
116
- global ELEM_ID
117
- id_ = ELEM_ID
118
- ELEM_ID += 1
116
+ global _ELEM_ID # pylint: disable=global-statement
117
+ id_ = _ELEM_ID
118
+ _ELEM_ID += 1
119
119
 
120
120
  if label is None and type_ != "hidden":
121
121
  label = name.replace("_", " ").capitalize()
@@ -138,7 +138,6 @@ def input_(
138
138
 
139
139
  def button(label: str) -> str:
140
140
  """Get en HTML button."""
141
-
142
141
  return f'<button class="btn btn-primary" type="submit">{label}</button>'
143
142
 
144
143
 
@@ -153,8 +152,8 @@ def _index(request: pyramid.request.Request) -> dict[str, str]:
153
152
  body = ""
154
153
  body += _health_check(request)
155
154
  body += _stats(request)
156
- body += _versions(request)
157
155
  if has_access:
156
+ body += _versions(request)
158
157
  body += _debug(request)
159
158
  body += _db_maintenance(request)
160
159
  body += _logging(request)
@@ -346,7 +345,6 @@ def _health_check(request: pyramid.request.Request) -> str:
346
345
 
347
346
  def _github_login(request: pyramid.request.Request) -> dict[str, Any]:
348
347
  """Get the view that start the authentication on GitHub."""
349
-
350
348
  settings = request.registry.settings
351
349
  params = dict(request.params)
352
350
  callback_url = _url(
@@ -500,7 +498,7 @@ def includeme(config: pyramid.config.Configurator) -> None:
500
498
  settings = config.get_settings()
501
499
  auth_type_ = auth_type(settings)
502
500
  if auth_type_ == AuthenticationType.SECRET:
503
- LOG.warning(
501
+ _LOG.warning(
504
502
  "It is recommended to use OAuth2 with GitHub login instead of the `C2C_SECRET` because it "
505
503
  "protects from brute force attacks and the access grant is personal and can be revoked."
506
504
  )
c2cwsgiutils/loader.py CHANGED
@@ -5,7 +5,7 @@ from plaster_pastedeploy import Loader as BaseLoader
5
5
 
6
6
  from c2cwsgiutils import get_config_defaults
7
7
 
8
- LOG = logging.getLogger(__name__)
8
+ _LOG = logging.getLogger(__name__)
9
9
 
10
10
 
11
11
  class Loader(BaseLoader): # type: ignore
@@ -7,10 +7,10 @@ import pyramid.request
7
7
 
8
8
  from c2cwsgiutils import auth, broadcast, config_utils, redis_utils
9
9
 
10
- LOG = logging.getLogger(__name__)
11
- CONFIG_KEY = "c2c.log_view_enabled"
12
- ENV_KEY = "C2C_LOG_VIEW_ENABLED"
13
- REDIS_PREFIX = "c2c_logging_level_"
10
+ _LOG = logging.getLogger(__name__)
11
+ _CONFIG_KEY = "c2c.log_view_enabled"
12
+ _ENV_KEY = "C2C_LOG_VIEW_ENABLED"
13
+ _REDIS_PREFIX = "c2c_logging_level_"
14
14
 
15
15
 
16
16
  def install_subscriber(config: pyramid.config.Configurator) -> None:
@@ -21,7 +21,7 @@ def install_subscriber(config: pyramid.config.Configurator) -> None:
21
21
 
22
22
  def includeme(config: pyramid.config.Configurator) -> None:
23
23
  """Install the view to configure the loggers, if configured to do so."""
24
- if auth.is_enabled(config, ENV_KEY, CONFIG_KEY):
24
+ if auth.is_enabled(config, _ENV_KEY, _CONFIG_KEY):
25
25
  config.add_route(
26
26
  "c2c_logging_level", config_utils.get_base_path(config) + r"/logging/level", request_method="GET"
27
27
  )
@@ -29,7 +29,7 @@ def includeme(config: pyramid.config.Configurator) -> None:
29
29
  _logging_change_level, route_name="c2c_logging_level", renderer="fast_json", http_cache=0
30
30
  )
31
31
  _restore_overrides(config)
32
- LOG.info("Enabled the /logging/level API")
32
+ _LOG.info("Enabled the /logging/level API")
33
33
 
34
34
 
35
35
  def _logging_change_level(request: pyramid.request.Request) -> Mapping[str, Any]:
@@ -39,7 +39,7 @@ def _logging_change_level(request: pyramid.request.Request) -> Mapping[str, Any]
39
39
  level = request.params.get("level")
40
40
  logger = logging.getLogger(name)
41
41
  if level is not None:
42
- LOG.critical(
42
+ _LOG.critical(
43
43
  "Logging of %s changed from %s to %s", name, logging.getLevelName(logger.level), level
44
44
  )
45
45
  _set_level(name=name, level=level)
@@ -63,20 +63,20 @@ def _set_level(name: str, level: str) -> bool:
63
63
  def _restore_overrides(config: pyramid.config.Configurator) -> None:
64
64
  try:
65
65
  for name, level in _list_overrides(config.get_settings()):
66
- LOG.debug("Restoring logging level override for %s: %s", name, level)
66
+ _LOG.debug("Restoring logging level override for %s: %s", name, level)
67
67
  logging.getLogger(name).setLevel(level)
68
68
  except ImportError:
69
69
  pass # don't have redis
70
70
  except Exception: # pylint: disable=broad-except
71
71
  # survive an error there. Logging levels is not business critical...
72
- LOG.warning("Cannot restore logging levels", exc_info=True)
72
+ _LOG.warning("Cannot restore logging levels", exc_info=True)
73
73
 
74
74
 
75
75
  def _store_override(settings: Mapping[str, Any], name: str, level: str) -> None:
76
76
  try:
77
77
  master, _, _ = redis_utils.get(settings)
78
78
  if master:
79
- master.set(REDIS_PREFIX + name, level)
79
+ master.set(_REDIS_PREFIX + name, level)
80
80
  except ImportError:
81
81
  pass
82
82
 
@@ -84,8 +84,8 @@ def _store_override(settings: Mapping[str, Any], name: str, level: str) -> None:
84
84
  def _list_overrides(settings: Mapping[str, Any]) -> Generator[tuple[str, str], None, None]:
85
85
  _, slave, _ = redis_utils.get(settings)
86
86
  if slave is not None:
87
- for key in slave.scan_iter(REDIS_PREFIX + "*"):
87
+ for key in slave.scan_iter(_REDIS_PREFIX + "*"):
88
88
  level = slave.get(key)
89
- name = key[len(REDIS_PREFIX) :]
89
+ name = key[len(_REDIS_PREFIX) :]
90
90
  if level is not None:
91
91
  yield name, str(level)
@@ -7,7 +7,6 @@ import sqlalchemy as sa
7
7
 
8
8
  def generate_model_graph(module: Any) -> None:
9
9
  """Generate a graphical model of the database classes."""
10
-
11
10
  base_name = None
12
11
  if len(sys.argv) == 1:
13
12
  base_name = "Base"
@@ -34,7 +34,6 @@ def init(config: pyramid.config.Configurator) -> None:
34
34
 
35
35
  def includeme(config: pyramid.config.Configurator) -> None:
36
36
  """Initialize json and fast_json renderer."""
37
-
38
37
  pretty_print = config_bool(
39
38
  env_or_config(config, "C2C_JSON_PRETTY_PRINT", "c2c.json.pretty_print", "false")
40
39
  )
@@ -24,7 +24,6 @@ MULTI_PROCESS_COLLECTOR_BROADCAST_CHANNELS = [
24
24
 
25
25
  def start(registry: Optional[prometheus_client.CollectorRegistry] = None) -> None:
26
26
  """Start separate HTTP server to provide the Prometheus metrics."""
27
-
28
27
  if os.environ.get("C2C_PROMETHEUS_PORT") is not None:
29
28
  broadcast.includeme()
30
29
 
@@ -38,20 +37,18 @@ def start(registry: Optional[prometheus_client.CollectorRegistry] = None) -> Non
38
37
 
39
38
  def includeme(config: pyramid.config.Configurator) -> None:
40
39
  """Initialize prometheus_client in pyramid context."""
41
-
40
+ del config # unused
42
41
  broadcast.subscribe("c2cwsgiutils_prometheus_collector_gc", _broadcast_collector_gc)
43
42
  broadcast.subscribe("c2cwsgiutils_prometheus_collector_process", _broadcast_collector_process)
44
43
 
45
44
 
46
45
  def build_metric_name(postfix: str) -> str:
47
46
  """Build the metric name with the prefix from the environment variable."""
48
-
49
47
  return os.environ.get("C2C_PROMETHEUS_PREFIX", "c2cwsgiutils_") + postfix
50
48
 
51
49
 
52
50
  def cleanup() -> None:
53
51
  """Cleanup the prometheus_client registry."""
54
-
55
52
  redis_utils.cleanup()
56
53
  broadcast.cleanup()
57
54
 
@@ -74,7 +71,6 @@ class SerializedMetric(TypedDict):
74
71
 
75
72
  def _broadcast_collector_gc() -> list[SerializedMetric]:
76
73
  """Get the collected GC gauges."""
77
-
78
74
  return serialize_collected_data(prometheus_client.GC_COLLECTOR)
79
75
 
80
76
 
@@ -85,7 +81,6 @@ def _broadcast_collector_process() -> list[SerializedMetric]:
85
81
 
86
82
  def serialize_collected_data(collector: prometheus_client.registry.Collector) -> list[SerializedMetric]:
87
83
  """Serialize the data from the custom collector."""
88
-
89
84
  gauges: list[SerializedMetric] = []
90
85
  for process_gauge in collector.collect():
91
86
  gauge: SerializedMetric = {
@@ -162,7 +157,6 @@ class MemoryMapCollector(prometheus_client.registry.Collector):
162
157
  Initialize.
163
158
 
164
159
  Arguments:
165
-
166
160
  memory_type: can be rss, pss or size
167
161
  pids: the list of pids or none
168
162
  """
c2cwsgiutils/pyramid.py CHANGED
@@ -30,7 +30,6 @@ def includeme(config: pyramid.config.Configurator) -> None:
30
30
  Initialize all the pyramid services and event handlers provided by this library.
31
31
 
32
32
  Arguments:
33
-
34
33
  config: The pyramid Configuration
35
34
  """
36
35
  logging.captureWarnings(True)
@@ -21,7 +21,7 @@ from typing import TYPE_CHECKING, Any, Optional, TextIO
21
21
  import cee_syslog_handler
22
22
  from pyramid.threadlocal import get_current_request
23
23
 
24
- LOG = logging.getLogger(__name__)
24
+ _LOG = logging.getLogger(__name__)
25
25
 
26
26
 
27
27
  class _PyramidFilter(logging.Filter):
@@ -7,8 +7,8 @@ import pyramid.config
7
7
 
8
8
  from c2cwsgiutils import config_utils, prometheus
9
9
 
10
- LOG = logging.getLogger(__name__)
11
- ORIG: Optional[Callable[..., Any]] = None
10
+ _LOG = logging.getLogger(__name__)
11
+ _ORIG: Optional[Callable[..., Any]] = None
12
12
 
13
13
  _PROMETHEUS_REDIS_SUMMARY = prometheus_client.Summary(
14
14
  prometheus.build_metric_name("redis"),
@@ -19,9 +19,9 @@ _PROMETHEUS_REDIS_SUMMARY = prometheus_client.Summary(
19
19
 
20
20
 
21
21
  def _execute_command_patch(self: Any, command: str, *args: Any, **options: Any) -> Any:
22
- assert ORIG is not None
22
+ assert _ORIG is not None
23
23
  with _PROMETHEUS_REDIS_SUMMARY.labels(command=command).time():
24
- return ORIG(self, command, *args, **options)
24
+ return _ORIG(self, command, *args, **options)
25
25
 
26
26
 
27
27
  def init(config: Optional[pyramid.config.Configurator] = None) -> None:
@@ -32,15 +32,15 @@ def init(config: Optional[pyramid.config.Configurator] = None) -> None:
32
32
 
33
33
  def includeme(config: Optional[pyramid.config.Configurator] = None) -> None:
34
34
  """Initialize the Redis tracking."""
35
- global ORIG
35
+ global _ORIG # pylint: disable=global-statement
36
36
  if config_utils.env_or_config(
37
37
  config, "C2C_TRACK_REDIS", "c2c.track_redis", True, config_utils.config_bool
38
38
  ):
39
39
  try:
40
- import redis.client
40
+ import redis.client # pylint: disable=import-outside-toplevel
41
41
 
42
- ORIG = redis.client.Redis.execute_command
42
+ _ORIG = redis.client.Redis.execute_command
43
43
  redis.client.Redis.execute_command = _execute_command_patch # type: ignore
44
- LOG.info("Enabled the redis tracking")
44
+ _LOG.info("Enabled the redis tracking")
45
45
  except Exception: # pragma: nocover # pylint: disable=broad-except
46
- LOG.warning("Cannot enable redis tracking", exc_info=True)
46
+ _LOG.warning("Cannot enable redis tracking", exc_info=True)
@@ -11,19 +11,19 @@ import yaml
11
11
 
12
12
  import c2cwsgiutils.config_utils
13
13
 
14
- LOG = logging.getLogger(__name__)
14
+ _LOG = logging.getLogger(__name__)
15
15
 
16
16
  REDIS_URL_KEY = "C2C_REDIS_URL"
17
- REDIS_OPTIONS_KEY = "C2C_REDIS_OPTIONS"
17
+ _REDIS_OPTIONS_KEY = "C2C_REDIS_OPTIONS"
18
18
  REDIS_SENTINELS_KEY = "C2C_REDIS_SENTINELS"
19
19
  REDIS_SERVICENAME_KEY = "C2C_REDIS_SERVICENAME"
20
- REDIS_DB_KEY = "C2C_REDIS_DB"
20
+ _REDIS_DB_KEY = "C2C_REDIS_DB"
21
21
 
22
22
  REDIS_URL_KEY_PROP = "c2c.redis_url"
23
- REDIS_OPTIONS_KEY_PROP = "c2c.redis_options"
23
+ _REDIS_OPTIONS_KEY_PROP = "c2c.redis_options"
24
24
  REDIS_SENTINELS_KEY_PROP = "c2c.redis_sentinels"
25
25
  REDIS_SERVICENAME_KEY_PROP = "c2c.redis_servicename"
26
- REDIS_DB_KEY_PROP = "c2c.redis_db"
26
+ _REDIS_DB_KEY_PROP = "c2c.redis_db"
27
27
 
28
28
  _master: Optional["redis.client.Redis[str]"] = None
29
29
  _slave: Optional["redis.client.Redis[str]"] = None
@@ -32,7 +32,7 @@ _sentinel: Optional[redis.sentinel.Sentinel] = None
32
32
 
33
33
  def cleanup() -> None:
34
34
  """Cleanup the redis connections."""
35
- global _master, _slave, _sentinel
35
+ global _master, _slave, _sentinel # pylint: disable=global-statement
36
36
  _master = None
37
37
  _slave = None
38
38
  _sentinel = None
@@ -52,17 +52,17 @@ def get(
52
52
 
53
53
 
54
54
  def _init(settings: Optional[Mapping[str, Any]]) -> None:
55
- global _master, _slave, _sentinel
55
+ global _master, _slave, _sentinel # pylint: disable=global-statement
56
56
  sentinels = c2cwsgiutils.config_utils.env_or_settings(
57
57
  settings, REDIS_SENTINELS_KEY, REDIS_SENTINELS_KEY_PROP
58
58
  )
59
59
  service_name = c2cwsgiutils.config_utils.env_or_settings(
60
60
  settings, REDIS_SERVICENAME_KEY, REDIS_SERVICENAME_KEY_PROP
61
61
  )
62
- db = c2cwsgiutils.config_utils.env_or_settings(settings, REDIS_DB_KEY, REDIS_DB_KEY_PROP)
62
+ db = c2cwsgiutils.config_utils.env_or_settings(settings, _REDIS_DB_KEY, _REDIS_DB_KEY_PROP)
63
63
  url = c2cwsgiutils.config_utils.env_or_settings(settings, REDIS_URL_KEY, REDIS_URL_KEY_PROP)
64
64
  redis_options_ = c2cwsgiutils.config_utils.env_or_settings(
65
- settings, REDIS_OPTIONS_KEY, REDIS_OPTIONS_KEY_PROP
65
+ settings, _REDIS_OPTIONS_KEY, _REDIS_OPTIONS_KEY_PROP
66
66
  )
67
67
 
68
68
  redis_options = (
@@ -82,16 +82,16 @@ def _init(settings: Optional[Mapping[str, Any]]) -> None:
82
82
  db=db,
83
83
  **redis_options,
84
84
  )
85
- LOG.info("Redis setup using: %s, %s, %s", sentinels, service_name, redis_options_)
85
+ _LOG.info("Redis setup using: %s, %s, %s", sentinels, service_name, redis_options_)
86
86
  _master = _sentinel.master_for(service_name)
87
87
  _slave = _sentinel.slave_for(service_name)
88
88
  return
89
89
  if url:
90
- LOG.info("Redis setup using: %s, with options: %s", url, redis_options_)
90
+ _LOG.info("Redis setup using: %s, with options: %s", url, redis_options_)
91
91
  _master = redis.client.Redis.from_url(url, decode_responses=True, **redis_options)
92
92
  _slave = _master
93
93
  else:
94
- LOG.info(
94
+ _LOG.info(
95
95
  "No Redis configuration found, use %s or %s to configure it", REDIS_URL_KEY, REDIS_SENTINELS_KEY
96
96
  )
97
97
 
@@ -114,22 +114,23 @@ class PubSubWorkerThread(threading.Thread):
114
114
  try:
115
115
  pubsub.get_message(ignore_subscribe_messages=True, timeout=1)
116
116
  if not last_was_ok:
117
- LOG.info("Redis is back")
117
+ _LOG.info("Redis is back")
118
118
  last_was_ok = True
119
119
  except redis.exceptions.RedisError:
120
120
  if last_was_ok:
121
- LOG.warning("Redis connection problem")
121
+ _LOG.warning("Redis connection problem")
122
122
  last_was_ok = False
123
123
  time.sleep(0.5)
124
124
  except Exception: # pylint: disable=broad-except
125
- LOG.warning("Unexpected error", exc_info=True)
126
- LOG.info("Redis subscription worker stopped")
125
+ _LOG.warning("Unexpected error", exc_info=True)
126
+ _LOG.info("Redis subscription worker stopped")
127
127
  pubsub.close()
128
128
  self._running = False
129
129
 
130
130
  def stop(self) -> None:
131
- # stopping simply unsubscribes from all channels and patterns.
132
- # the unsubscribe responses that are generated will short circuit
131
+ """Stop the worker."""
132
+ # Stopping simply unsubscribes from all channels and patterns.
133
+ # The unsubscribe responses that are generated will short circuit
133
134
  # the loop in run(), calling pubsub.close() to clean up the connection
134
135
  self.pubsub.unsubscribe()
135
136
  self.pubsub.punsubscribe()
@@ -20,10 +20,10 @@ from pyramid.threadlocal import get_current_request
20
20
 
21
21
  from c2cwsgiutils import config_utils, prometheus
22
22
 
23
- ID_HEADERS: list[str] = []
23
+ _ID_HEADERS: list[str] = []
24
24
  _HTTPAdapter_send = requests.adapters.HTTPAdapter.send
25
- LOG = logging.getLogger(__name__)
26
- DEFAULT_TIMEOUT: Optional[float] = None
25
+ _LOG = logging.getLogger(__name__)
26
+ _DEFAULT_TIMEOUT: Optional[float] = None
27
27
  _PROMETHEUS_REQUESTS_SUMMARY = prometheus_client.Summary(
28
28
  prometheus.build_metric_name("requests"),
29
29
  "Requests requests",
@@ -33,7 +33,7 @@ _PROMETHEUS_REQUESTS_SUMMARY = prometheus_client.Summary(
33
33
 
34
34
 
35
35
  def _gen_request_id(request: pyramid.request.Request) -> str:
36
- for id_header in ID_HEADERS:
36
+ for id_header in _ID_HEADERS:
37
37
  if id_header in request.headers:
38
38
  return request.headers[id_header] # type: ignore
39
39
  return str(uuid.uuid4())
@@ -50,15 +50,15 @@ def _patch_requests() -> None:
50
50
  proxies: Optional[Mapping[str, str]] = None,
51
51
  ) -> requests.Response:
52
52
  pyramid_request = get_current_request()
53
- header = ID_HEADERS[0]
53
+ header = _ID_HEADERS[0]
54
54
  if pyramid_request is not None and header not in request.headers:
55
55
  request.headers[header] = pyramid_request.c2c_request_id
56
56
 
57
57
  if timeout is None:
58
- if DEFAULT_TIMEOUT is not None:
59
- timeout = DEFAULT_TIMEOUT
58
+ if _DEFAULT_TIMEOUT is not None:
59
+ timeout = _DEFAULT_TIMEOUT
60
60
  else:
61
- LOG.warning("Doing a %s request without timeout to %s", request.method, request.url)
61
+ _LOG.warning("Doing a %s request without timeout to %s", request.method, request.url)
62
62
 
63
63
  assert request.url
64
64
  parsed = urllib.parse.urlparse(request.url)
@@ -94,20 +94,20 @@ def includeme(config: Optional[pyramid.config.Configurator] = None) -> None:
94
94
  Use a X-Request-ID (or other) header to track all the logs related to a request
95
95
  including on the sub services.
96
96
  """
97
- global ID_HEADERS, DEFAULT_TIMEOUT
98
- ID_HEADERS = ["X-Request-ID", "X-Correlation-ID", "Request-ID", "X-Varnish", "X-Amzn-Trace-Id"]
97
+ global _ID_HEADERS, _DEFAULT_TIMEOUT # pylint: disable=global-statement
98
+ _ID_HEADERS = ["X-Request-ID", "X-Correlation-ID", "Request-ID", "X-Varnish", "X-Amzn-Trace-Id"]
99
99
  if config is not None:
100
100
  extra_header = config_utils.env_or_config(config, "C2C_REQUEST_ID_HEADER", "c2c.request_id_header")
101
101
  if extra_header:
102
- ID_HEADERS.insert(0, extra_header)
102
+ _ID_HEADERS.insert(0, extra_header)
103
103
  config.add_request_method(_gen_request_id, "c2c_request_id", reify=True)
104
104
 
105
- DEFAULT_TIMEOUT = config_utils.env_or_config(
105
+ _DEFAULT_TIMEOUT = config_utils.env_or_config(
106
106
  config, "C2C_REQUESTS_DEFAULT_TIMEOUT", "c2c.requests_default_timeout", type_=float
107
107
  )
108
108
  _patch_requests()
109
109
 
110
110
  if config_utils.env_or_config(config, "C2C_SQL_REQUEST_ID", "c2c.sql_request_id", False):
111
- from . import _sql
111
+ from . import _sql # pylint: disable=import-outside-toplevel
112
112
 
113
113
  _sql.init()