c2cwsgiutils 6.1.8.dev86__py3-none-any.whl → 6.1.9.dev39__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.

Potentially problematic release.


This version of c2cwsgiutils might be problematic. Click here for more details.

@@ -735,9 +735,9 @@
735
735
  "license": "MIT"
736
736
  },
737
737
  "node_modules/js-yaml": {
738
- "version": "4.1.0",
739
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
740
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
738
+ "version": "4.1.1",
739
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
740
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
741
741
  "license": "MIT",
742
742
  "dependencies": {
743
743
  "argparse": "^2.0.1"
@@ -1107,9 +1107,9 @@
1107
1107
  }
1108
1108
  },
1109
1109
  "node_modules/tar-fs": {
1110
- "version": "3.0.9",
1111
- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.9.tgz",
1112
- "integrity": "sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==",
1110
+ "version": "3.1.1",
1111
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz",
1112
+ "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==",
1113
1113
  "license": "MIT",
1114
1114
  "dependencies": {
1115
1115
  "pump": "^3.0.0",
c2cwsgiutils/db.py CHANGED
@@ -51,7 +51,7 @@ def setup_session(
51
51
  With an accompanying tween that switches between the master and the slave DB
52
52
  connection. Uses prefixed entries in the application's settings.
53
53
 
54
- The slave DB will be used for anything that is GET and OPTIONS queries. The master DB will be used for
54
+ The slave DB will be used for anything that is GET, HEAD and OPTIONS queries. The master DB will be used for
55
55
  all the other queries. You can tweak this behavior with the force_master and force_slave parameters.
56
56
  Those parameters are lists of regex that are going to be matched against "{VERB} {PATH}". Warning, the
57
57
  path includes the route_prefix.
@@ -107,7 +107,7 @@ def create_session(
107
107
  With an accompanying tween that switches between the master and the slave DB
108
108
  connection.
109
109
 
110
- The slave DB will be used for anything that is GET and OPTIONS queries. The master DB will be used for
110
+ The slave DB will be used for anything that is GET, HEAD and OPTIONS queries. The master DB will be used for
111
111
  all the other queries. You can tweak this behavior with the force_master and force_slave parameters.
112
112
  Those parameters are lists of regex that are going to be matched against "{VERB} {PATH}". Warning, the
113
113
  path includes the route_prefix.
@@ -178,7 +178,10 @@ def _add_tween(
178
178
  has_force_master = any(r.match(method_path) for r in master_paths)
179
179
  if FORCE_READONLY or (
180
180
  not has_force_master
181
- and (request.method in ("GET", "OPTIONS") or any(r.match(method_path) for r in slave_paths))
181
+ and (
182
+ request.method in ("GET", "HEAD", "OPTIONS")
183
+ or any(r.match(method_path) for r in slave_paths)
184
+ )
182
185
  ):
183
186
  _LOG.debug(
184
187
  "Using %s database for: %s",
@@ -246,7 +249,7 @@ class SessionFactory(_sessionmaker):
246
249
  if FORCE_READONLY or (
247
250
  not has_force_master
248
251
  and (
249
- request.method in ("GET", "OPTIONS")
252
+ request.method in ("GET", "OPTIONS", "HEAD")
250
253
  or any(r.match(method_path) for r in self.slave_paths)
251
254
  )
252
255
  ):
@@ -132,6 +132,7 @@ class MultiProcessCustomCollector(prometheus_client.registry.Collector):
132
132
  def _deserialize_collected_data(
133
133
  results: list[list[SerializedMetric]],
134
134
  ) -> Generator[prometheus_client.core.Metric, None, None]:
135
+ imported = set()
135
136
  for serialized_collection in results:
136
137
  if serialized_collection is None:
137
138
  continue
@@ -149,6 +150,10 @@ def _deserialize_collected_data(
149
150
  else:
150
151
  raise NotImplementedError()
151
152
  for sample in serialized_metric["samples"]:
153
+ canonical = (sample["name"], frozenset(sample.get("labels", {}).items()))
154
+ if canonical in imported:
155
+ continue
156
+ imported.add(canonical)
152
157
  metric.samples.append(
153
158
  prometheus_client.metrics_core.Sample(**sample), # type: ignore[attr-defined]
154
159
  )
@@ -15,7 +15,7 @@ _LOG = logging.getLogger(__name__)
15
15
  _PROMETHEUS_DB_SUMMARY = prometheus_client.Summary(
16
16
  prometheus.build_metric_name("database"),
17
17
  "Database requests",
18
- ["what"],
18
+ ["what", "engine"],
19
19
  unit="seconds",
20
20
  )
21
21
 
@@ -66,12 +66,14 @@ def _simplify_sql(sql: str) -> str:
66
66
  return re.sub(r"%\(\w+\)\w", "?", sql)
67
67
 
68
68
 
69
- def _create_sqlalchemy_timer_cb(what: str) -> Callable[..., Any]:
69
+ def _create_sqlalchemy_timer_cb(what: str, engine_name: str | None = None) -> Callable[..., Any]:
70
70
  start = time.perf_counter()
71
71
 
72
72
  def after(*_args: Any, **_kwargs: Any) -> None:
73
- _PROMETHEUS_DB_SUMMARY.labels({"query": what}).observe(time.perf_counter() - start)
74
- _LOG.debug("Execute statement '%s' in %d.", what, time.perf_counter() - start)
73
+ elapsed_time = time.perf_counter() - start
74
+ _PROMETHEUS_DB_SUMMARY.labels(what=what, engine=engine_name).observe(elapsed_time)
75
+ engine_suffix = f", on {engine_name}" if engine_name else ""
76
+ _LOG.debug("Execute statement '%s' in %.3f%ss.", what, elapsed_time, engine_suffix)
75
77
 
76
78
  return after
77
79
 
@@ -79,8 +81,12 @@ def _create_sqlalchemy_timer_cb(what: str) -> Callable[..., Any]:
79
81
  def _before_cursor_execute(
80
82
  conn: Connection, _cursor: Any, statement: str, _parameters: Any, _context: Any, _executemany: Any
81
83
  ) -> None:
84
+ engine_name = getattr(conn.engine, "c2c_name", None)
82
85
  sqlalchemy.event.listen(
83
- conn, "after_cursor_execute", _create_sqlalchemy_timer_cb(_simplify_sql(statement)), once=True
86
+ conn,
87
+ "after_cursor_execute",
88
+ _create_sqlalchemy_timer_cb(_simplify_sql(statement), engine_name),
89
+ once=True,
84
90
  )
85
91
 
86
92
 
@@ -19,8 +19,8 @@
19
19
  />
20
20
  <link
21
21
  rel="stylesheet"
22
- href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css"
23
- integrity="sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg=="
22
+ href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.8/css/bootstrap.min.css"
23
+ integrity="sha512-2bBQCjcnw658Lho4nlXJcc6WkV/UxpE/sAokbXPxQNGqmNdQrWqtw26Ns9kFF/yG792pKR1Sx8/Y1Lf1XN4GKA=="
24
24
  crossorigin="anonymous"
25
25
  referrerpolicy="no-referrer"
26
26
  />
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015-2025, Camptocamp SA
1
+ Copyright (c) 2015-2026, Camptocamp SA
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: c2cwsgiutils
3
- Version: 6.1.8.dev86
3
+ Version: 6.1.9.dev39
4
4
  Summary: Common utilities for Camptocamp WSGI applications
5
5
  Home-page: https://github.com/camptocamp/c2cwsgiutils
6
6
  License: BSD-2-Clause
@@ -2,7 +2,7 @@ c2cwsgiutils/__init__.py,sha256=HVSc-4O8i2aB0ozEI4AI8Xsb-4S6fAwhl8uRhv-DsFg,4057
2
2
  c2cwsgiutils/acceptance/__init__.py,sha256=TJA1yzmyPujkg80oj-LBj2ueOQVYL8HLW87pejWTIDY,1501
3
3
  c2cwsgiutils/acceptance/connection.py,sha256=yqChhHBpYhQL0Cb7K8FqeP16jg1UtmxGAi6Tw1TXEbI,9783
4
4
  c2cwsgiutils/acceptance/image.py,sha256=Wi4EXDTKZ-uyIIQFn8SpRpUTzbpj5LlCwSkLjcYRGTk,9269
5
- c2cwsgiutils/acceptance/package-lock.json,sha256=AH-kvpzij3RePKw75pATymZsRtpE_nK_3zbRktfLrNY,47966
5
+ c2cwsgiutils/acceptance/package-lock.json,sha256=s9K_-AtzWSi5G6G6fokW80YKdmG39VZ8hu7WnqhAfVI,47966
6
6
  c2cwsgiutils/acceptance/package.json,sha256=DiJUVhci1sP-qu71s3RzxcsF4GsZdo2ZOUeqX3148ss,101
7
7
  c2cwsgiutils/acceptance/print.py,sha256=qdh6pqlHgkIjUCJxS3rcgpOV4fDk9RxFlkfH5aAwDsQ,2567
8
8
  c2cwsgiutils/acceptance/screenshot.js,sha256=FAJYIWOLJFMm0MNggKzo3mIybtN-VtKLdMzPhQ9pO1g,2041
@@ -16,7 +16,7 @@ c2cwsgiutils/broadcast/utils.py,sha256=0fQZXPu3p_5LEJpGenJwiiMxECQjJhjZBjIkBk8h-
16
16
  c2cwsgiutils/client_info.py,sha256=rvXQLyhma0kPoWQINwUzrxfG2gGIjQDNrxPUDRGJxpA,3916
17
17
  c2cwsgiutils/config_utils.py,sha256=vkBu-3GQsE94NOBOvT5FE-Ij29EUrKnDsmdUdtu_yzo,1524
18
18
  c2cwsgiutils/coverage_setup.py,sha256=BrdjYUmqYl1C-gHuKA7EI5gbQs8Dtdeb2eZKtzr-5L0,909
19
- c2cwsgiutils/db.py,sha256=JT5F9Dqm2r0Jsh3w3CX79ngAUtakMLpf1secfN1nQnk,16106
19
+ c2cwsgiutils/db.py,sha256=zdlZ81hHCuPCdO7WoX5dM46NjZnvebyl9-DHf6oV8t8,16192
20
20
  c2cwsgiutils/db_maintenance_view.py,sha256=58F-p9drkhCI99GoLRPIqT5U-Pm8ckSSUEl-tNxMmjU,3088
21
21
  c2cwsgiutils/debug/__init__.py,sha256=GkYNt2fU5PFykw9HmqPEwZrF2mTJumjSu54pp38EhOM,1325
22
22
  c2cwsgiutils/debug/_listeners.py,sha256=-fk3KFeB_E4m_YFXJ5MfxuqfA1sWCje9p3FH_93WfXM,4248
@@ -30,7 +30,7 @@ c2cwsgiutils/logging_view.py,sha256=d0UkvYRGkVUMY9_vbjEzXmm8-6CCec2B43a3mJAqWyw,
30
30
  c2cwsgiutils/models_graph.py,sha256=q5dW_gZ5iUZCzBya5Kpy57y9oqsG-rGi9AvrXCDgYqs,2679
31
31
  c2cwsgiutils/pretty_json.py,sha256=WQlgNVeWPD_QMEjkNq5rFVGdFwQ7xDyICf0uxj0Hu2U,1697
32
32
  c2cwsgiutils/profiler.py,sha256=3tIwoDSzOKQ06ug_U6j5VDR1BQ9auUOqdJRRLRhDoHw,739
33
- c2cwsgiutils/prometheus.py,sha256=5oNG9UzTxiyE_UdLV70PuPs-NqrvLWfvdYb82KC0JT8,6813
33
+ c2cwsgiutils/prometheus.py,sha256=Sc4Zysbm93aR9ejJxettzK-inKvywXtXSlOKJ2YMwuM,7035
34
34
  c2cwsgiutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  c2cwsgiutils/pyramid.py,sha256=MnVMskHMlJ4KQDjDR7CQdYaH70YXOtJ-1ThTPBqa03c,1387
36
36
  c2cwsgiutils/pyramid_logging.py,sha256=M4XtWQZStreEoyC5qlwxcDDKCp4PZOr9SN05GnaYvvA,3732
@@ -56,12 +56,12 @@ c2cwsgiutils/sqlalchemylogger/handlers.py,sha256=nr9-eQsZ5d0DHbtc4Ym0_faa7qg1dF4
56
56
  c2cwsgiutils/static/favicon-16x16.png,sha256=LKk6RFvb3NlPIZdDfAodE8H9IN8KM6CMGnMx4vOHlUQ,887
57
57
  c2cwsgiutils/static/favicon-32x32.png,sha256=i4ucx08zAZARd8e7JTMGK-gb5WcOmyuDN6IN4brsEOo,1216
58
58
  c2cwsgiutils/stats_pyramid/__init__.py,sha256=alSRhpCa5Kh9JnMnR5XqcMqr5wyL8ogROprrfsIl_qU,786
59
- c2cwsgiutils/stats_pyramid/_db_spy.py,sha256=A61t6VKIrRRIjbyZTldmAUl_Q3ZDVFYqyxjuntzmllc,2919
59
+ c2cwsgiutils/stats_pyramid/_db_spy.py,sha256=T6q26_6Q-ObjXPNUip5TsX-YkBl11v8vfFL1_9m_dHw,3180
60
60
  c2cwsgiutils/stats_pyramid/_pyramid_spy.py,sha256=mRiOmQXV9x8JjkGV4MsaC7sD3qO6dWUTog0bharLLD0,3517
61
- c2cwsgiutils/templates/index.html.mako,sha256=cK8qGBDeQG5SiJJCfvL0oKpgacr7dPKx634AAQivmjA,1416
61
+ c2cwsgiutils/templates/index.html.mako,sha256=e54pfSL0nGRsnJkahFRLevNyUhvlCNb_2uVaO8rDhbg,1416
62
62
  c2cwsgiutils/version.py,sha256=1ghPu-aKMJdfCSUrxgBENNqNQ-7JMKJr6tS14dDmW4Q,3110
63
- c2cwsgiutils-6.1.8.dev86.dist-info/LICENSE,sha256=6bEOU0n7ued3SA-DQCsHQaACONMMRzGHmH5XhDVeD-U,1304
64
- c2cwsgiutils-6.1.8.dev86.dist-info/METADATA,sha256=knyojZvprQXcTUnYgy5Og56Vx_9mZ3MH-LMLDuDAfGc,34425
65
- c2cwsgiutils-6.1.8.dev86.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
66
- c2cwsgiutils-6.1.8.dev86.dist-info/entry_points.txt,sha256=ujgqMTL1awN9qDg8WXmrF7m0fgR-hslUM6zKH86pvy0,703
67
- c2cwsgiutils-6.1.8.dev86.dist-info/RECORD,,
63
+ c2cwsgiutils-6.1.9.dev39.dist-info/LICENSE,sha256=hCNci_ppSy6SKe_nTdgzjCsTIaNQgAKqDSghWn_G-1I,1304
64
+ c2cwsgiutils-6.1.9.dev39.dist-info/METADATA,sha256=z01HptgN2oM7oZy6Mp1aechbqu2ufn1lRN9U1J0uSaw,34425
65
+ c2cwsgiutils-6.1.9.dev39.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
66
+ c2cwsgiutils-6.1.9.dev39.dist-info/entry_points.txt,sha256=ujgqMTL1awN9qDg8WXmrF7m0fgR-hslUM6zKH86pvy0,703
67
+ c2cwsgiutils-6.1.9.dev39.dist-info/RECORD,,