c2cwsgiutils 6.0.10.dev11__py3-none-any.whl → 6.1.0__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 (56) 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 +9 -17
  5. c2cwsgiutils/acceptance/package-lock.json +270 -1062
  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 +43 -37
  10. c2cwsgiutils/broadcast/__init__.py +16 -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 +13 -5
  15. c2cwsgiutils/config_utils.py +1 -0
  16. c2cwsgiutils/coverage_setup.py +4 -3
  17. c2cwsgiutils/db.py +36 -41
  18. c2cwsgiutils/db_maintenance_view.py +13 -13
  19. c2cwsgiutils/debug/__init__.py +2 -2
  20. c2cwsgiutils/debug/_listeners.py +1 -1
  21. c2cwsgiutils/debug/_views.py +7 -6
  22. c2cwsgiutils/debug/utils.py +9 -9
  23. c2cwsgiutils/errors.py +13 -14
  24. c2cwsgiutils/health_check.py +25 -30
  25. c2cwsgiutils/index.py +14 -16
  26. c2cwsgiutils/loader.py +1 -1
  27. c2cwsgiutils/logging_view.py +12 -12
  28. c2cwsgiutils/models_graph.py +0 -1
  29. c2cwsgiutils/pretty_json.py +0 -1
  30. c2cwsgiutils/prometheus.py +1 -7
  31. c2cwsgiutils/pyramid.py +0 -1
  32. c2cwsgiutils/pyramid_logging.py +2 -1
  33. c2cwsgiutils/redis_stats.py +9 -9
  34. c2cwsgiutils/redis_utils.py +19 -18
  35. c2cwsgiutils/request_tracking/__init__.py +14 -13
  36. c2cwsgiutils/request_tracking/_sql.py +0 -1
  37. c2cwsgiutils/scripts/genversion.py +5 -5
  38. c2cwsgiutils/scripts/stats_db.py +19 -17
  39. c2cwsgiutils/scripts/test_print.py +5 -5
  40. c2cwsgiutils/sentry.py +55 -20
  41. c2cwsgiutils/services.py +2 -2
  42. c2cwsgiutils/setup_process.py +0 -2
  43. c2cwsgiutils/sql_profiler/__init__.py +6 -6
  44. c2cwsgiutils/sql_profiler/_impl.py +19 -17
  45. c2cwsgiutils/sqlalchemylogger/README.md +30 -13
  46. c2cwsgiutils/sqlalchemylogger/handlers.py +12 -11
  47. c2cwsgiutils/stats_pyramid/__init__.py +1 -5
  48. c2cwsgiutils/stats_pyramid/_db_spy.py +2 -2
  49. c2cwsgiutils/stats_pyramid/_pyramid_spy.py +0 -1
  50. c2cwsgiutils/version.py +11 -5
  51. {c2cwsgiutils-6.0.10.dev11.dist-info → c2cwsgiutils-6.1.0.dist-info}/LICENSE +1 -1
  52. {c2cwsgiutils-6.0.10.dev11.dist-info → c2cwsgiutils-6.1.0.dist-info}/METADATA +12 -12
  53. c2cwsgiutils-6.1.0.dist-info/RECORD +67 -0
  54. {c2cwsgiutils-6.0.10.dev11.dist-info → c2cwsgiutils-6.1.0.dist-info}/WHEEL +1 -1
  55. c2cwsgiutils-6.0.10.dev11.dist-info/RECORD +0 -67
  56. {c2cwsgiutils-6.0.10.dev11.dist-info → c2cwsgiutils-6.1.0.dist-info}/entry_points.txt +0 -0
c2cwsgiutils/db.py CHANGED
@@ -1,10 +1,11 @@
1
1
  """SQLalchemy models."""
2
+
2
3
  import logging
3
4
  import re
4
5
  import warnings
5
6
  from collections.abc import Iterable
6
7
  from re import Pattern
7
- from typing import TYPE_CHECKING, Any, Callable, Optional, Union, cast
8
+ from typing import Any, Callable, Optional, Union, cast
8
9
 
9
10
  import pyramid.config
10
11
  import pyramid.config.settings
@@ -16,18 +17,14 @@ import zope.sqlalchemy
16
17
  from sqlalchemy import engine_from_config
17
18
  from zope.sqlalchemy import register
18
19
 
19
- if TYPE_CHECKING:
20
- scoped_session = sqlalchemy.orm.scoped_session[sqlalchemy.orm.Session]
21
- sessionmaker = sqlalchemy.orm.sessionmaker[sqlalchemy.orm.Session]
22
- else:
23
- scoped_session = sqlalchemy.orm.scoped_session
24
- sessionmaker = sqlalchemy.orm.sessionmaker
20
+ _scoped_session = sqlalchemy.orm.scoped_session[sqlalchemy.orm.Session]
21
+ _sessionmaker = sqlalchemy.orm.sessionmaker[sqlalchemy.orm.Session] # pylint: disable=unsubscriptable-object
25
22
 
26
23
 
27
- LOG = logging.getLogger(__name__)
28
- RE_COMPILE: Callable[[str], Pattern[str]] = re.compile
24
+ _LOG = logging.getLogger(__name__)
25
+ _RE_COMPILE: Callable[[str], Pattern[str]] = re.compile
29
26
 
30
- force_readonly = False
27
+ FORCE_READONLY = False
31
28
 
32
29
 
33
30
  class Tweens:
@@ -44,7 +41,7 @@ def setup_session(
44
41
  force_master: Optional[Iterable[str]] = None,
45
42
  force_slave: Optional[Iterable[str]] = None,
46
43
  ) -> tuple[
47
- Union[sqlalchemy.orm.Session, scoped_session],
44
+ Union[sqlalchemy.orm.Session, _scoped_session],
48
45
  sqlalchemy.engine.Engine,
49
46
  sqlalchemy.engine.Engine,
50
47
  ]:
@@ -59,8 +56,7 @@ def setup_session(
59
56
  Those parameters are lists of regex that are going to be matched against "{VERB} {PATH}". Warning, the
60
57
  path includes the route_prefix.
61
58
 
62
- Keyword Arguments:
63
-
59
+ Arguments:
64
60
  config: The pyramid Configuration object
65
61
  master_prefix: The prefix for the master connection configuration entries in the application \
66
62
  settings
@@ -83,7 +79,7 @@ def setup_session(
83
79
 
84
80
  # Setup a slave DB connection and add a tween to use it.
85
81
  if settings[master_prefix + ".url"] != settings.get(slave_prefix + ".url"):
86
- LOG.info("Using a slave DB for reading %s", master_prefix)
82
+ _LOG.info("Using a slave DB for reading %s", master_prefix)
87
83
  ro_engine = sqlalchemy.engine_from_config(config.get_settings(), slave_prefix + ".")
88
84
  ro_engine.c2c_name = slave_prefix # type: ignore
89
85
  tween_name = master_prefix.replace(".", "_")
@@ -104,7 +100,7 @@ def create_session(
104
100
  force_master: Optional[Iterable[str]] = None,
105
101
  force_slave: Optional[Iterable[str]] = None,
106
102
  **engine_config: Any,
107
- ) -> Union[sqlalchemy.orm.Session, scoped_session]:
103
+ ) -> Union[sqlalchemy.orm.Session, _scoped_session]:
108
104
  """
109
105
  Create a SQLAlchemy session.
110
106
 
@@ -116,8 +112,7 @@ def create_session(
116
112
  Those parameters are lists of regex that are going to be matched against "{VERB} {PATH}". Warning, the
117
113
  path includes the route_prefix.
118
114
 
119
- Keyword Arguments:
120
-
115
+ Arguments:
121
116
  config: The pyramid Configuration object. If None, only master is used
122
117
  name: The name of the check
123
118
  url: The URL for the master DB
@@ -139,7 +134,7 @@ def create_session(
139
134
 
140
135
  # Setup a slave DB connection and add a tween to use it.
141
136
  if url != slave_url and config is not None:
142
- LOG.info("Using a slave DB for reading %s", name)
137
+ _LOG.info("Using a slave DB for reading %s", name)
143
138
  ro_engine = sqlalchemy.create_engine(slave_url, **engine_config)
144
139
  _add_tween(config, name, db_session, force_master, force_slave)
145
140
  rw_engine.c2c_name = name + "_master" # type: ignore
@@ -156,15 +151,15 @@ def create_session(
156
151
  def _add_tween(
157
152
  config: pyramid.config.Configurator,
158
153
  name: str,
159
- db_session: scoped_session,
154
+ db_session: _scoped_session,
160
155
  force_master: Optional[Iterable[str]],
161
156
  force_slave: Optional[Iterable[str]],
162
157
  ) -> None:
163
158
  master_paths: Iterable[Pattern[str]] = (
164
- list(map(RE_COMPILE, force_master)) if force_master is not None else []
159
+ list(map(_RE_COMPILE, force_master)) if force_master is not None else []
165
160
  )
166
161
  slave_paths: Iterable[Pattern[str]] = (
167
- list(map(RE_COMPILE, force_slave)) if force_slave is not None else []
162
+ list(map(_RE_COMPILE, force_slave)) if force_slave is not None else []
168
163
  )
169
164
 
170
165
  def db_chooser_tween_factory(
@@ -181,18 +176,18 @@ def _add_tween(
181
176
  old = session.bind
182
177
  method_path: Any = f"{request.method} {request.path}"
183
178
  has_force_master = any(r.match(method_path) for r in master_paths)
184
- if force_readonly or (
179
+ if FORCE_READONLY or (
185
180
  not has_force_master
186
181
  and (request.method in ("GET", "OPTIONS") or any(r.match(method_path) for r in slave_paths))
187
182
  ):
188
- LOG.debug(
183
+ _LOG.debug(
189
184
  "Using %s database for: %s",
190
185
  db_session.c2c_ro_bind.c2c_name, # type: ignore
191
186
  method_path,
192
187
  )
193
188
  session.bind = db_session.c2c_ro_bind # type: ignore
194
189
  else:
195
- LOG.debug(
190
+ _LOG.debug(
196
191
  "Using %s database for: %s",
197
192
  db_session.c2c_rw_bind.c2c_name, # type: ignore
198
193
  method_path,
@@ -210,7 +205,7 @@ def _add_tween(
210
205
  config.add_tween("c2cwsgiutils.db.tweens." + name, over="pyramid_tm.tm_tween_factory")
211
206
 
212
207
 
213
- class SessionFactory(sessionmaker):
208
+ class SessionFactory(_sessionmaker):
214
209
  """The custom session factory that manage the read only and read write sessions."""
215
210
 
216
211
  def __init__(
@@ -222,42 +217,43 @@ class SessionFactory(sessionmaker):
222
217
  ):
223
218
  super().__init__()
224
219
  self.master_paths: Iterable[Pattern[str]] = (
225
- list(map(RE_COMPILE, force_master)) if force_master else []
220
+ list(map(_RE_COMPILE, force_master)) if force_master else []
226
221
  )
227
- self.slave_paths: Iterable[Pattern[str]] = list(map(RE_COMPILE, force_slave)) if force_slave else []
222
+ self.slave_paths: Iterable[Pattern[str]] = list(map(_RE_COMPILE, force_slave)) if force_slave else []
228
223
  self.ro_engine = ro_engine
229
224
  self.rw_engine = rw_engine
230
225
 
231
226
  def engine_name(self, readwrite: bool) -> str:
227
+ """Get the engine name."""
232
228
  if readwrite:
233
229
  return cast(str, self.rw_engine.c2c_name) # type: ignore
234
230
  return cast(str, self.ro_engine.c2c_name) # type: ignore
235
231
 
236
232
  def __call__( # type: ignore
237
233
  self, request: Optional[pyramid.request.Request], readwrite: Optional[bool] = None, **local_kw: Any
238
- ) -> scoped_session:
234
+ ) -> _scoped_session:
239
235
  if readwrite is not None:
240
- if readwrite and not force_readonly:
241
- LOG.debug("Using %s database", self.rw_engine.c2c_name) # type: ignore
236
+ if readwrite and not FORCE_READONLY:
237
+ _LOG.debug("Using %s database", self.rw_engine.c2c_name) # type: ignore
242
238
  self.configure(bind=self.rw_engine)
243
239
  else:
244
- LOG.debug("Using %s database", self.ro_engine.c2c_name) # type: ignore
240
+ _LOG.debug("Using %s database", self.ro_engine.c2c_name) # type: ignore
245
241
  self.configure(bind=self.ro_engine)
246
242
  else:
247
243
  assert request is not None
248
244
  method_path: str = f"{request.method} {request.path}" if request is not None else ""
249
245
  has_force_master = any(r.match(method_path) for r in self.master_paths)
250
- if force_readonly or (
246
+ if FORCE_READONLY or (
251
247
  not has_force_master
252
248
  and (
253
249
  request.method in ("GET", "OPTIONS")
254
250
  or any(r.match(method_path) for r in self.slave_paths)
255
251
  )
256
252
  ):
257
- LOG.debug("Using %s database for: %s", self.ro_engine.c2c_name, method_path) # type: ignore
253
+ _LOG.debug("Using %s database for: %s", self.ro_engine.c2c_name, method_path) # type: ignore
258
254
  self.configure(bind=self.ro_engine)
259
255
  else:
260
- LOG.debug("Using %s database for: %s", self.rw_engine.c2c_name, method_path) # type: ignore
256
+ _LOG.debug("Using %s database for: %s", self.rw_engine.c2c_name, method_path) # type: ignore
261
257
  self.configure(bind=self.rw_engine)
262
258
  return super().__call__(**local_kw) # type: ignore
263
259
 
@@ -271,15 +267,15 @@ def get_engine(
271
267
 
272
268
  def get_session_factory(
273
269
  engine: sqlalchemy.engine.Engine,
274
- ) -> sessionmaker:
270
+ ) -> _sessionmaker:
275
271
  """Get the session factory from the engine."""
276
- factory = sessionmaker()
272
+ factory = _sessionmaker()
277
273
  factory.configure(bind=engine)
278
274
  return factory
279
275
 
280
276
 
281
277
  def get_tm_session(
282
- session_factory: sessionmaker,
278
+ session_factory: _sessionmaker,
283
279
  transaction_manager: transaction.TransactionManager,
284
280
  ) -> sqlalchemy.orm.Session:
285
281
  """
@@ -347,7 +343,7 @@ def get_tm_session_pyramid(
347
343
  session_factory: SessionFactory,
348
344
  transaction_manager: transaction.TransactionManager,
349
345
  request: pyramid.request.Request,
350
- ) -> scoped_session:
346
+ ) -> _scoped_session:
351
347
  """
352
348
  Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
353
349
 
@@ -368,8 +364,7 @@ def init(
368
364
  """
369
365
  Initialize the database for a Pyramid app.
370
366
 
371
- Keyword Arguments:
372
-
367
+ Arguments:
373
368
  config: The pyramid Configuration object
374
369
  master_prefix: The prefix for the master connection configuration entries in the application \
375
370
  settings
@@ -391,7 +386,7 @@ def init(
391
386
 
392
387
  # Setup a slave DB connection and add a tween to use it.
393
388
  if slave_prefix and settings[master_prefix + ".url"] != settings.get(slave_prefix + ".url"):
394
- LOG.info("Using a slave DB for reading %s", master_prefix)
389
+ _LOG.info("Using a slave DB for reading %s", master_prefix)
395
390
  ro_engine = get_engine(config.get_settings(), slave_prefix + ".")
396
391
  ro_engine.c2c_name = slave_prefix # type: ignore
397
392
  else:
@@ -7,10 +7,10 @@ import pyramid.request
7
7
 
8
8
  from c2cwsgiutils import auth, broadcast, config_utils, db, redis_utils
9
9
 
10
- LOG = logging.getLogger(__name__)
11
- CONFIG_KEY = "c2c.db_maintenance_view_enabled"
12
- ENV_KEY = "C2C_DB_MAINTENANCE_VIEW_ENABLED"
13
- REDIS_PREFIX = "c2c_db_maintenance_"
10
+ _LOG = logging.getLogger(__name__)
11
+ _CONFIG_KEY = "c2c.db_maintenance_view_enabled"
12
+ _ENV_KEY = "C2C_DB_MAINTENANCE_VIEW_ENABLED"
13
+ _REDIS_PREFIX = "c2c_db_maintenance_"
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_db_maintenance",
27
27
  config_utils.get_base_path(config) + r"/db/maintenance",
@@ -29,7 +29,7 @@ def includeme(config: pyramid.config.Configurator) -> None:
29
29
  )
30
30
  config.add_view(_db_maintenance, route_name="c2c_db_maintenance", renderer="fast_json", http_cache=0)
31
31
  _restore(config)
32
- LOG.info("Enabled the /db/maintenance API")
32
+ _LOG.info("Enabled the /db/maintenance API")
33
33
 
34
34
 
35
35
  def _db_maintenance(request: pyramid.request.Request) -> Mapping[str, Any]:
@@ -38,7 +38,7 @@ def _db_maintenance(request: pyramid.request.Request) -> Mapping[str, Any]:
38
38
  if readonly_param is not None:
39
39
  readonly = readonly_param.lower() == "true"
40
40
 
41
- LOG.critical("Readonly DB status changed from %s to %s", db.force_readonly, readonly)
41
+ _LOG.critical("Readonly DB status changed from %s to %s", db.FORCE_READONLY, readonly)
42
42
  _set_readonly(value=readonly)
43
43
  _store(request.registry.settings, readonly)
44
44
  return {"status": 200, "readonly": readonly}
@@ -51,7 +51,7 @@ def _db_maintenance(request: pyramid.request.Request) -> Mapping[str, Any]:
51
51
 
52
52
  @broadcast.decorator(expect_answers=True)
53
53
  def _set_readonly(value: bool) -> bool:
54
- db.force_readonly = value
54
+ db.FORCE_READONLY = value
55
55
  return True
56
56
 
57
57
 
@@ -59,24 +59,24 @@ def _restore(config: pyramid.config.Configurator) -> None:
59
59
  try:
60
60
  readonly = _get_redis_value(config.get_settings())
61
61
  if readonly is not None:
62
- LOG.debug("Restoring readonly DB status to %s", readonly)
63
- db.force_readonly = readonly == "true"
62
+ _LOG.debug("Restoring readonly DB status to %s", readonly)
63
+ db.FORCE_READONLY = readonly == "true"
64
64
  except ImportError:
65
65
  pass # don't have redis
66
66
  except Exception: # pylint: disable=broad-except
67
67
  # survive an error since crashing now can have bad consequences for the service. :/
68
- LOG.error("Cannot restore readonly DB status.", exc_info=True)
68
+ _LOG.error("Cannot restore readonly DB status.", exc_info=True)
69
69
 
70
70
 
71
71
  def _store(settings: Mapping[str, Any], readonly: bool) -> None:
72
72
  master, _, _ = redis_utils.get(settings)
73
73
  if master is not None:
74
- master.set(REDIS_PREFIX + "force_readonly", "true" if readonly else "false")
74
+ master.set(_REDIS_PREFIX + "force_readonly", "true" if readonly else "false")
75
75
 
76
76
 
77
77
  def _get_redis_value(settings: Mapping[str, Any]) -> Optional[str]:
78
78
  _, slave, _ = redis_utils.get(settings)
79
79
  if slave is not None:
80
- value = slave.get(REDIS_PREFIX + "force_readonly")
80
+ value = slave.get(_REDIS_PREFIX + "force_readonly")
81
81
  return str(value) if value else None
82
82
  return None
@@ -23,7 +23,7 @@ def init(config: pyramid.config.Configurator) -> None:
23
23
  def includeme(config: pyramid.config.Configurator) -> None:
24
24
  """Initialize the debug tools."""
25
25
  if auth.is_enabled(config, ENV_KEY, CONFIG_KEY):
26
- from c2cwsgiutils.debug import _views
26
+ from c2cwsgiutils.debug import _views # pylint: disable=import-outside-toplevel
27
27
 
28
28
  init_daemon(config)
29
29
  _views.init(config)
@@ -37,6 +37,6 @@ def init_daemon(config: Optional[pyramid.config.Configurator] = None) -> None:
37
37
  those requests.
38
38
  """
39
39
  if config_utils.env_or_config(config, ENV_KEY, CONFIG_KEY, type_=config_utils.config_bool):
40
- from c2cwsgiutils.debug import _listeners
40
+ from c2cwsgiutils.debug import _listeners # pylint: disable=import-outside-toplevel
41
41
 
42
42
  _listeners.init()
@@ -90,7 +90,7 @@ def _dump_memory_impl(
90
90
  for i in sorted(mod_counts.items(), key=lambda x: -x[1])[:limit]
91
91
  ]
92
92
  elif analyze_type == "linecache":
93
- import linecache
93
+ import linecache # pylint: disable=import-outside-toplevel
94
94
 
95
95
  cache = linecache.cache
96
96
  result[analyze_type]["biggest_objects"] = sorted(
@@ -16,8 +16,8 @@ from pyramid.httpexceptions import HTTPException, exception_response
16
16
  from c2cwsgiutils import auth, broadcast, config_utils
17
17
  from c2cwsgiutils.debug.utils import dump_memory_maps, get_size
18
18
 
19
- LOG = logging.getLogger(__name__)
20
- SPACE_RE = re.compile(r" +")
19
+ _LOG = logging.getLogger(__name__)
20
+ _SPACE_RE = re.compile(r" +")
21
21
 
22
22
 
23
23
  def _beautify_stacks(source: list[Mapping[str, Any]]) -> list[Mapping[str, Any]]:
@@ -80,7 +80,7 @@ def _dump_memory_diff(request: pyramid.request.Request) -> list[Any]:
80
80
  except Exception: # nosec # pylint: disable=broad-except
81
81
  pass
82
82
 
83
- LOG.debug("checking memory growth for %s", path)
83
+ _LOG.debug("checking memory growth for %s", path)
84
84
 
85
85
  peak_stats: dict[Any, Any] = {}
86
86
  for i in range(3):
@@ -91,10 +91,10 @@ def _dump_memory_diff(request: pyramid.request.Request) -> list[Any]:
91
91
  response = None
92
92
  try:
93
93
  response = request.invoke_subrequest(sub_request)
94
- LOG.debug("response was %d", response.status_code)
94
+ _LOG.debug("response was %d", response.status_code)
95
95
 
96
96
  except HTTPException as ex:
97
- LOG.debug("response was %s", str(ex))
97
+ _LOG.debug("response was %s", str(ex))
98
98
 
99
99
  del response
100
100
 
@@ -142,6 +142,7 @@ def _error(request: pyramid.request.Request) -> Any:
142
142
 
143
143
 
144
144
  def _time(request: pyramid.request.Request) -> Any:
145
+ del request # unused
145
146
  return {
146
147
  "local_time": str(datetime.now()),
147
148
  "gmt_time": str(datetime.utcnow()),
@@ -211,4 +212,4 @@ def init(config: pyramid.config.Configurator) -> None:
211
212
  _add_view(config, "error", "error", _error)
212
213
  _add_view(config, "time", "time", _time)
213
214
  _add_view(config, "show_refs", "show_refs.dot", _show_refs)
214
- LOG.info("Enabled the /debug/... API")
215
+ _LOG.info("Enabled the /debug/... API")
@@ -8,18 +8,18 @@ from types import FunctionType, ModuleType
8
8
  from typing import Any
9
9
 
10
10
  # 7ff7d33bd000-7ff7d33be000 r--p 00000000 00:65 49 /usr/lib/toto.so
11
- SMAPS_LOCATION_RE = re.compile(r"^[0-9a-f]+-[0-9a-f]+ +.... +[0-9a-f]+ +[^ ]+ +\d+ +(.*)$")
11
+ _SMAPS_LOCATION_RE = re.compile(r"^[0-9a-f]+-[0-9a-f]+ +.... +[0-9a-f]+ +[^ ]+ +\d+ +(.*)$")
12
12
 
13
13
  # Size: 4 kB
14
- SMAPS_ENTRY_RE = re.compile(r"^([\w]+): +(\d+) kB$")
14
+ _SMAPS_ENTRY_RE = re.compile(r"^([\w]+): +(\d+) kB$")
15
15
 
16
- BLACKLIST = type, ModuleType, FunctionType
17
- LOG = logging.getLogger(__name__)
16
+ _BLACKLIST = type, ModuleType, FunctionType
17
+ _LOG = logging.getLogger(__name__)
18
18
 
19
19
 
20
20
  def get_size(obj: Any) -> int:
21
21
  """Get the sum size of object & members."""
22
- if isinstance(obj, BLACKLIST):
22
+ if isinstance(obj, _BLACKLIST):
23
23
  return 0
24
24
  seen_ids: set[int] = set()
25
25
  size = 0
@@ -27,7 +27,7 @@ def get_size(obj: Any) -> int:
27
27
  while objects:
28
28
  need_referents = []
29
29
  for obj_ in objects:
30
- if not isinstance(obj_, BLACKLIST) and id(obj_) not in seen_ids:
30
+ if not isinstance(obj_, _BLACKLIST) and id(obj_) not in seen_ids:
31
31
  seen_ids.add(id(obj_))
32
32
  size += sys.getsizeof(obj_)
33
33
  need_referents.append(obj_)
@@ -45,11 +45,11 @@ def dump_memory_maps(pid: str = "self") -> list[dict[str, Any]]:
45
45
  sizes: dict[str, Any] = {}
46
46
  for line in input_:
47
47
  line = line.rstrip("\n")
48
- matcher = SMAPS_LOCATION_RE.match(line)
48
+ matcher = _SMAPS_LOCATION_RE.match(line)
49
49
  if matcher:
50
50
  cur_dict = sizes.setdefault(matcher.group(1), defaultdict(int))
51
51
  else:
52
- matcher = SMAPS_ENTRY_RE.match(line)
52
+ matcher = _SMAPS_ENTRY_RE.match(line)
53
53
  if matcher:
54
54
  name = matcher.group(1)
55
55
  if name in ("Size", "Rss", "Pss"):
@@ -59,5 +59,5 @@ def dump_memory_maps(pid: str = "self") -> list[dict[str, Any]]:
59
59
  and not line.startswith("ProtectionKey:")
60
60
  and not line.startswith("THPeligible:")
61
61
  ):
62
- LOG.debug("Don't know how to parse /proc/%s/smaps line: %s", pid, line)
62
+ _LOG.debug("Don't know how to parse /proc/%s/smaps line: %s", pid, line)
63
63
  return [{"name": name, **value} for name, value in sizes.items() if value.get("pss_kb", 0) > 0]
c2cwsgiutils/errors.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Install exception views to have nice JSON error pages."""
2
+
2
3
  import logging
3
4
  import os
4
5
  import traceback
@@ -13,14 +14,12 @@ from webob.request import DisconnectionError
13
14
 
14
15
  from c2cwsgiutils import auth, config_utils
15
16
 
16
- DEVELOPMENT = os.environ.get("DEVELOPMENT", "0") != "0"
17
- DEPRECATED_CONFIG_KEY = "c2c.error_details_secret"
18
- DEPRECATED_ENV_KEY = "ERROR_DETAILS_SECRET"
17
+ _DEVELOPMENT = os.environ.get("DEVELOPMENT", "0") != "0"
19
18
 
20
- LOG = logging.getLogger(__name__)
21
- STATUS_LOGGER = {
22
- 401: LOG.debug,
23
- 500: LOG.error
19
+ _LOG = logging.getLogger(__name__)
20
+ _STATUS_LOGGER = {
21
+ 401: _LOG.debug,
22
+ 500: _LOG.error,
24
23
  # The rest are warnings
25
24
  }
26
25
 
@@ -52,7 +51,7 @@ def _do_error(
52
51
  request: pyramid.request.Request,
53
52
  status: int,
54
53
  exception: Exception,
55
- logger: Callable[..., None] = LOG.error,
54
+ logger: Callable[..., None] = _LOG.error,
56
55
  reduce_info_sent: Callable[[Exception], None] = lambda e: None,
57
56
  ) -> pyramid.response.Response:
58
57
  logger(
@@ -81,7 +80,7 @@ def _do_error(
81
80
 
82
81
  def _http_error(exception: HTTPException, request: pyramid.request.Request) -> Any:
83
82
  if request.method != "OPTIONS":
84
- log = STATUS_LOGGER.get(exception.status_code, LOG.warning)
83
+ log = _STATUS_LOGGER.get(exception.status_code, _LOG.warning)
85
84
  log(
86
85
  "%s %s returned status code %s: %s",
87
86
  request.method,
@@ -101,7 +100,7 @@ def _http_error(exception: HTTPException, request: pyramid.request.Request) -> A
101
100
 
102
101
 
103
102
  def _include_dev_details(request: pyramid.request.Request) -> bool:
104
- return DEVELOPMENT or auth.is_auth(request)
103
+ return _DEVELOPMENT or auth.is_auth(request)
105
104
 
106
105
 
107
106
  def _integrity_error(
@@ -120,7 +119,7 @@ def _client_interrupted_error(
120
119
  exception: Exception, request: pyramid.request.Request
121
120
  ) -> pyramid.response.Response:
122
121
  # No need to cry wolf if it's just the client that interrupted the connection
123
- return _do_error(request, 500, exception, logger=LOG.info)
122
+ return _do_error(request, 500, exception, logger=_LOG.info)
124
123
 
125
124
 
126
125
  def _boto_client_error(exception: Any, request: pyramid.request.Request) -> pyramid.response.Response:
@@ -131,7 +130,7 @@ def _boto_client_error(exception: Any, request: pyramid.request.Request) -> pyra
131
130
  status_code = exception.response["ResponseMetadata"]["HTTPStatusCode"]
132
131
  else:
133
132
  status_code = int(exception.response["Error"]["Code"])
134
- log = STATUS_LOGGER.get(status_code, LOG.warning)
133
+ log = _STATUS_LOGGER.get(status_code, _LOG.warning)
135
134
  return _do_error(request, status_code, exception, logger=log)
136
135
 
137
136
 
@@ -142,7 +141,7 @@ def _other_error(exception: Exception, request: pyramid.request.Request) -> pyra
142
141
  status = 500
143
142
  if exception_class == "beaker.exceptions.BeakerException" and str(exception) == "Invalid signature":
144
143
  status = 401
145
- LOG.debug("Actual exception: %s.%s", exception.__class__.__module__, exception.__class__.__name__)
144
+ _LOG.debug("Actual exception: %s.%s", exception.__class__.__module__, exception.__class__.__name__)
146
145
  return _do_error(request, status, exception)
147
146
 
148
147
 
@@ -178,4 +177,4 @@ def includeme(config: pyramid.config.Configurator) -> None:
178
177
  config.add_view(view=_client_interrupted_error, context=exception, **common_options)
179
178
 
180
179
  config.add_view(view=_other_error, context=Exception, **common_options)
181
- LOG.info("Installed the error catching views")
180
+ _LOG.info("Installed the error catching views")