c2cwsgiutils 6.1.7.dev4__py3-none-any.whl → 6.2.0.dev54__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 (48) hide show
  1. c2cwsgiutils/acceptance/__init__.py +1 -0
  2. c2cwsgiutils/acceptance/connection.py +3 -2
  3. c2cwsgiutils/acceptance/image.py +5 -3
  4. c2cwsgiutils/acceptance/package-lock.json +110 -248
  5. c2cwsgiutils/acceptance/package.json +2 -2
  6. c2cwsgiutils/acceptance/print.py +1 -0
  7. c2cwsgiutils/acceptance/utils.py +2 -1
  8. c2cwsgiutils/auth.py +9 -8
  9. c2cwsgiutils/broadcast/__init__.py +1 -1
  10. c2cwsgiutils/broadcast/local.py +4 -0
  11. c2cwsgiutils/broadcast/redis.py +8 -2
  12. c2cwsgiutils/client_info.py +2 -0
  13. c2cwsgiutils/coverage_setup.py +2 -2
  14. c2cwsgiutils/db.py +11 -2
  15. c2cwsgiutils/db_maintenance_view.py +1 -1
  16. c2cwsgiutils/debug/__init__.py +4 -2
  17. c2cwsgiutils/debug/_views.py +22 -4
  18. c2cwsgiutils/errors.py +7 -2
  19. c2cwsgiutils/health_check.py +39 -29
  20. c2cwsgiutils/index.py +1 -1
  21. c2cwsgiutils/loader.py +1 -1
  22. c2cwsgiutils/logging_view.py +1 -1
  23. c2cwsgiutils/models_graph.py +1 -1
  24. c2cwsgiutils/pretty_json.py +1 -1
  25. c2cwsgiutils/profiler.py +1 -0
  26. c2cwsgiutils/prometheus.py +58 -0
  27. c2cwsgiutils/pyramid.py +1 -0
  28. c2cwsgiutils/pyramid_logging.py +4 -0
  29. c2cwsgiutils/redis_stats.py +1 -1
  30. c2cwsgiutils/redis_utils.py +2 -0
  31. c2cwsgiutils/request_tracking/__init__.py +1 -1
  32. c2cwsgiutils/scripts/genversion.py +4 -2
  33. c2cwsgiutils/scripts/stats_db.py +1 -0
  34. c2cwsgiutils/scripts/test_print.py +4 -1
  35. c2cwsgiutils/sentry.py +1 -1
  36. c2cwsgiutils/setup_process.py +5 -1
  37. c2cwsgiutils/sql_profiler/__init__.py +1 -1
  38. c2cwsgiutils/sql_profiler/_impl.py +1 -1
  39. c2cwsgiutils/sqlalchemylogger/handlers.py +18 -12
  40. c2cwsgiutils/stats_pyramid/__init__.py +2 -1
  41. c2cwsgiutils/stats_pyramid/_pyramid_spy.py +1 -0
  42. c2cwsgiutils/version.py +1 -1
  43. {c2cwsgiutils-6.1.7.dev4.dist-info → c2cwsgiutils-6.2.0.dev54.dist-info}/METADATA +74 -12
  44. c2cwsgiutils-6.2.0.dev54.dist-info/RECORD +67 -0
  45. c2cwsgiutils-6.1.7.dev4.dist-info/RECORD +0 -67
  46. {c2cwsgiutils-6.1.7.dev4.dist-info → c2cwsgiutils-6.2.0.dev54.dist-info}/LICENSE +0 -0
  47. {c2cwsgiutils-6.1.7.dev4.dist-info → c2cwsgiutils-6.2.0.dev54.dist-info}/WHEEL +0 -0
  48. {c2cwsgiutils-6.1.7.dev4.dist-info → c2cwsgiutils-6.2.0.dev54.dist-info}/entry_points.txt +0 -0
@@ -87,10 +87,12 @@ class PyramidCeeSysLogHandler(cee_syslog_handler.CeeSysLogHandler): # type: ign
87
87
  """A CEE (JSON format) log handler with additional information about the current request."""
88
88
 
89
89
  def __init__(self, *args: Any, **kargv: Any) -> None:
90
+ """Initialize the handler."""
90
91
  super().__init__(*args, **kargv)
91
92
  self.addFilter(_PYRAMID_FILTER)
92
93
 
93
94
  def format(self, record: Any) -> str:
95
+ """Format the record into a CEE string."""
94
96
  message = _make_message_dict(
95
97
  record,
96
98
  self._fqdn,
@@ -112,11 +114,13 @@ class JsonLogHandler(Base):
112
114
  """Log to stdout in JSON."""
113
115
 
114
116
  def __init__(self, stream: Optional[TextIO] = None):
117
+ """Initialize the handler."""
115
118
  super().__init__(stream)
116
119
  self.addFilter(_PYRAMID_FILTER)
117
120
  self._fqdn = socket.getfqdn()
118
121
 
119
122
  def format(self, record: Any) -> str:
123
+ """Format the record into a JSON string."""
120
124
  message = _make_message_dict(
121
125
  record, self._fqdn, debugging_fields=True, extra_fields=True, facility=None, static_fields={}
122
126
  )
@@ -26,7 +26,7 @@ def _execute_command_patch(self: Any, command: str, *args: Any, **options: Any)
26
26
 
27
27
  def init(config: Optional[pyramid.config.Configurator] = None) -> None:
28
28
  """Initialize the Redis tracking, for backward compatibility."""
29
- warnings.warn("init function is deprecated; use includeme instead")
29
+ warnings.warn("init function is deprecated; use includeme instead", stacklevel=2)
30
30
  includeme(config)
31
31
 
32
32
 
@@ -100,11 +100,13 @@ class PubSubWorkerThread(threading.Thread):
100
100
  """A clone of redis.client.PubSubWorkerThread that doesn't die when the connections are broken."""
101
101
 
102
102
  def __init__(self, pubsub: redis.client.PubSub, name: Optional[str] = None) -> None:
103
+ """Initialize the PubSubWorkerThread."""
103
104
  super().__init__(name=name, daemon=True)
104
105
  self.pubsub = pubsub
105
106
  self._running = False
106
107
 
107
108
  def run(self) -> None:
109
+ """Run the worker."""
108
110
  if self._running:
109
111
  return
110
112
  self._running = True
@@ -83,7 +83,7 @@ def _patch_requests() -> None:
83
83
 
84
84
  def init(config: Optional[pyramid.config.Configurator] = None) -> None:
85
85
  """Initialize the request tracking, for backward compatibility."""
86
- warnings.warn("init function is deprecated; use includeme instead")
86
+ warnings.warn("init function is deprecated; use includeme instead", stacklevel=2)
87
87
  includeme(config)
88
88
 
89
89
 
@@ -24,7 +24,7 @@ def _get_package_version(comp: str) -> tuple[Optional[str], Optional[str]]:
24
24
  if matcher:
25
25
  return cast(tuple[str, str], matcher.groups())
26
26
  else:
27
- if len(comp) > 0 and not comp[:3] == "-e ":
27
+ if len(comp) > 0 and comp[:3] != "-e ":
28
28
  print("Cannot parse package version: " + comp)
29
29
  return None, None
30
30
 
@@ -46,7 +46,9 @@ def _get_packages_version() -> dict[str, str]:
46
46
 
47
47
  def deprecated() -> None:
48
48
  """Run the command and print a deprecated notice."""
49
- warnings.warn("c2cwsgiutils_genversion.py is deprecated; use c2cwsgiutils-genversion instead")
49
+ warnings.warn(
50
+ "c2cwsgiutils_genversion.py is deprecated; use c2cwsgiutils-genversion instead", stacklevel=2
51
+ )
50
52
  return main()
51
53
 
52
54
 
@@ -62,6 +62,7 @@ class Reporter:
62
62
  """The stats reporter."""
63
63
 
64
64
  def __init__(self, args: argparse.Namespace) -> None:
65
+ """Initialize the reporter."""
65
66
  self._error: Optional[Exception] = None
66
67
  self.registry = CollectorRegistry()
67
68
  self.prometheus_push = args.prometheus_url is not None
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  """Test a MapfishPrint server."""
3
+
3
4
  import argparse
4
5
  import logging
5
6
  import pprint
@@ -23,7 +24,9 @@ def _parse_args() -> argparse.Namespace:
23
24
 
24
25
  def deprecated() -> None:
25
26
  """Run the command and print a deprecated notice."""
26
- warnings.warn("c2cwsgiutils_test_print.py is deprecated; use c2cwsgiutils-test-print instead")
27
+ warnings.warn(
28
+ "c2cwsgiutils_test_print.py is deprecated; use c2cwsgiutils-test-print instead", stacklevel=2
29
+ )
27
30
  return main()
28
31
 
29
32
 
c2cwsgiutils/sentry.py CHANGED
@@ -33,7 +33,7 @@ def _create_before_send_filter(tags: MutableMapping[str, str]) -> Callable[[Any,
33
33
 
34
34
  def init(config: Optional[pyramid.config.Configurator] = None) -> None:
35
35
  """Initialize the Sentry integration, for backward compatibility."""
36
- warnings.warn("init function is deprecated; use includeme instead")
36
+ warnings.warn("init function is deprecated; use includeme instead", stacklevel=2)
37
37
  includeme(config)
38
38
 
39
39
 
@@ -5,6 +5,7 @@ Must be imported at the very beginning of the process's life, before any other m
5
5
  """
6
6
 
7
7
  import argparse
8
+ import logging
8
9
  import warnings
9
10
  from typing import Any, Callable, Optional, TypedDict, cast
10
11
 
@@ -55,7 +56,9 @@ def init(config_file: str = "c2c:///app/production.ini") -> None:
55
56
 
56
57
  def init_logging(config_file: str = "c2c:///app/production.ini") -> None:
57
58
  """Initialize the non-WSGI application."""
58
- warnings.warn("init_logging function is deprecated; use init instead so that all features are enabled")
59
+ warnings.warn(
60
+ "init_logging function is deprecated; use init instead so that all features are enabled", stacklevel=2
61
+ )
59
62
  loader = get_config_loader(config_file)
60
63
  loader.setup_logging(None)
61
64
 
@@ -95,4 +98,5 @@ def bootstrap_application(
95
98
  """
96
99
  loader = get_config_loader(config_uri)
97
100
  loader.setup_logging(options)
101
+ logging.getLogger(__name__).info("Loading the application from %s", config_uri)
98
102
  return cast(PyramidEnv, bootstrap(config_uri, options=options))
@@ -18,7 +18,7 @@ _LOG = logging.getLogger(__name__)
18
18
 
19
19
  def init(config: pyramid.config.Configurator) -> None:
20
20
  """Install a pyramid event handler that adds the request information, for backward compatibility."""
21
- warnings.warn("init function is deprecated; use includeme instead")
21
+ warnings.warn("init function is deprecated; use includeme instead", stacklevel=2)
22
22
  includeme(config)
23
23
 
24
24
 
@@ -56,7 +56,7 @@ class _Repository:
56
56
  ]
57
57
  )
58
58
  _LOG.info(output)
59
- except Exception: # nosec # pylint: disable=broad-except
59
+ except Exception: # pylint: disable=broad-except # noqa: S110
60
60
  pass
61
61
 
62
62
 
@@ -11,7 +11,10 @@ from sqlalchemy.exc import SQLAlchemyError
11
11
  from sqlalchemy.orm import sessionmaker
12
12
  from sqlalchemy_utils import create_database, database_exists
13
13
 
14
- from c2cwsgiutils.sqlalchemylogger._filters import ContainsExpression, DoesNotContainExpression
14
+ from c2cwsgiutils.sqlalchemylogger._filters import (
15
+ ContainsExpression,
16
+ DoesNotContainExpression,
17
+ )
15
18
  from c2cwsgiutils.sqlalchemylogger._models import Base, create_log_class
16
19
 
17
20
  _LOG = logging.getLogger(__name__)
@@ -29,12 +32,13 @@ class SQLAlchemyHandler(logging.Handler):
29
32
  does_not_contain_expression: str = "",
30
33
  contains_expression: str = "",
31
34
  ) -> None:
35
+ """Initialize the SQLAlchemyHandler."""
32
36
  super().__init__()
33
37
  # Initialize DB session
34
38
  self.engine = create_engine(sqlalchemy_url["url"])
35
39
  self.Log = create_log_class( # pylint: disable=invalid-name
36
40
  tablename=sqlalchemy_url.get("tablename", "logs"),
37
- tableargs=sqlalchemy_url.get("tableargs", None), # type: ignore
41
+ tableargs=sqlalchemy_url.get("tableargs"), # type: ignore
38
42
  )
39
43
  Base.metadata.bind = self.engine
40
44
  self.session = sessionmaker(bind=self.engine)() # noqa
@@ -61,15 +65,16 @@ class SQLAlchemyHandler(logging.Handler):
61
65
  if not self.log_queue.empty():
62
66
  logs.append(self.log_queue.get())
63
67
  self.log_queue.task_done()
64
- if logs:
65
- # try to reduce the number of INSERT requests to the DB
66
- # by writing chunks of self.MAX_NB_LOGS size,
67
- # but also do not wait forever before writing stuff (self.MAX_TIMOUT)
68
- if (len(logs) >= self.MAX_NB_LOGS) or (
69
- time.perf_counter() >= (time_since_last + self.MAX_TIMEOUT)
70
- ):
71
- self._write_logs(logs)
72
- break
68
+ # try to reduce the number of INSERT requests to the DB
69
+ # by writing chunks of self.MAX_NB_LOGS size,
70
+ # but also do not wait forever before writing stuff (self.MAX_TIMOUT)
71
+ if (
72
+ logs
73
+ and (len(logs) >= self.MAX_NB_LOGS)
74
+ or (time.perf_counter() >= (time_since_last + self.MAX_TIMEOUT))
75
+ ):
76
+ self._write_logs(logs)
77
+ break
73
78
  _LOG.debug("%s: stopping processor thread", __name__)
74
79
 
75
80
  def _write_logs(self, logs: list[Any]) -> None:
@@ -94,7 +99,7 @@ class SQLAlchemyHandler(logging.Handler):
94
99
  _LOG.info("%s: creating new database", __name__)
95
100
  if not database_exists(self.engine.url):
96
101
  create_database(self.engine.url)
97
- # FIXME: we should not access directly the private __table_args__
102
+ # FIXME: we should not access directly the private __table_args__ # pylint: disable=fixme
98
103
  # variable, but add an accessor method in models.Log class
99
104
  if not isinstance(self.Log.__table_args__, type(None)) and self.Log.__table_args__.get(
100
105
  "schema", None
@@ -107,6 +112,7 @@ class SQLAlchemyHandler(logging.Handler):
107
112
  Base.metadata.create_all(self.engine)
108
113
 
109
114
  def emit(self, record: Any) -> None:
115
+ """Emit the log."""
110
116
  trace = None
111
117
  exc = record.__dict__["exc_info"]
112
118
  if exc:
@@ -10,7 +10,7 @@ from c2cwsgiutils.stats_pyramid import _pyramid_spy
10
10
 
11
11
  def init(config: pyramid.config.Configurator) -> None:
12
12
  """Initialize the whole stats module, for backward compatibility."""
13
- warnings.warn("init function is deprecated; use includeme instead")
13
+ warnings.warn("init function is deprecated; use includeme instead", stacklevel=2)
14
14
  includeme(config)
15
15
 
16
16
 
@@ -20,6 +20,7 @@ def includeme(config: pyramid.config.Configurator) -> None:
20
20
 
21
21
  Arguments:
22
22
  config: The Pyramid config
23
+
23
24
  """
24
25
  _pyramid_spy.init(config)
25
26
  init_db_spy()
@@ -99,6 +99,7 @@ def init(config: pyramid.config.Configurator) -> None: # pragma: nocover
99
99
 
100
100
  Arguments:
101
101
  config: The Pyramid config
102
+
102
103
  """
103
104
  config.add_subscriber(_request_callback, pyramid.events.NewRequest)
104
105
  config.add_subscriber(_before_rendered_callback, pyramid.events.BeforeRender)
c2cwsgiutils/version.py CHANGED
@@ -37,7 +37,7 @@ _PROMETHEUS_VERSIONS_INFO = prometheus_client.Gauge(
37
37
 
38
38
  def init(config: pyramid.config.Configurator) -> None:
39
39
  """Initialize the versions view, for backward compatibility."""
40
- warnings.warn("init function is deprecated; use includeme instead")
40
+ warnings.warn("init function is deprecated; use includeme instead", stacklevel=2)
41
41
  includeme(config)
42
42
 
43
43
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: c2cwsgiutils
3
- Version: 6.1.7.dev4
3
+ Version: 6.2.0.dev54
4
4
  Summary: Common utilities for Camptocamp WSGI applications
5
5
  Home-page: https://github.com/camptocamp/c2cwsgiutils
6
6
  License: BSD-2-Clause
@@ -33,22 +33,26 @@ Provides-Extra: sentry
33
33
  Provides-Extra: standard
34
34
  Provides-Extra: test-images
35
35
  Provides-Extra: tests
36
+ Provides-Extra: waitress
36
37
  Provides-Extra: webserver
37
- Requires-Dist: SQLAlchemy ; extra == "standard" or extra == "webserver" or extra == "all"
38
- Requires-Dist: SQLAlchemy-Utils ; extra == "standard" or extra == "webserver" or extra == "all"
38
+ Requires-Dist: Paste ; extra == "standard" or extra == "waitress" or extra == "all"
39
+ Requires-Dist: SQLAlchemy ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
40
+ Requires-Dist: SQLAlchemy-Utils ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
39
41
  Requires-Dist: alembic ; extra == "standard" or extra == "alembic" or extra == "all"
40
42
  Requires-Dist: boltons ; extra == "tests" or extra == "all"
41
43
  Requires-Dist: cee_syslog_handler
42
- Requires-Dist: cornice ; extra == "standard" or extra == "webserver" or extra == "all"
44
+ Requires-Dist: cornice ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
45
+ Requires-Dist: coverage ; extra == "debug" or extra == "all"
43
46
  Requires-Dist: gunicorn ; extra == "standard" or extra == "webserver" or extra == "all"
44
47
  Requires-Dist: lxml ; extra == "tests" or extra == "all"
45
48
  Requires-Dist: objgraph ; extra == "debug" or extra == "all"
46
- Requires-Dist: prometheus-client ; extra == "standard" or extra == "webserver" or extra == "all"
47
- Requires-Dist: psycopg2 ; extra == "standard" or extra == "webserver" or extra == "all"
49
+ Requires-Dist: prometheus-client ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
50
+ Requires-Dist: psutil ; extra == "debug" or extra == "all"
51
+ Requires-Dist: psycopg2 ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
48
52
  Requires-Dist: pyjwt ; extra == "standard" or extra == "oauth2" or extra == "all"
49
- Requires-Dist: pyramid ; extra == "standard" or extra == "webserver" or extra == "all"
50
- Requires-Dist: pyramid-tm ; extra == "standard" or extra == "webserver" or extra == "all"
51
- Requires-Dist: pyramid_mako ; extra == "standard" or extra == "webserver" or extra == "all"
53
+ Requires-Dist: pyramid ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
54
+ Requires-Dist: pyramid-tm ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
55
+ Requires-Dist: pyramid_mako ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
52
56
  Requires-Dist: pyyaml
53
57
  Requires-Dist: redis ; extra == "standard" or extra == "broadcast" or extra == "all"
54
58
  Requires-Dist: requests
@@ -56,9 +60,9 @@ Requires-Dist: requests-oauthlib ; extra == "standard" or extra == "oauth2" or e
56
60
  Requires-Dist: scikit-image ; extra == "test-images"
57
61
  Requires-Dist: sentry-sdk ; extra == "standard" or extra == "sentry" or extra == "all"
58
62
  Requires-Dist: ujson
59
- Requires-Dist: waitress ; extra == "dev" or extra == "all"
60
- Requires-Dist: zope.interface ; extra == "standard" or extra == "webserver" or extra == "all"
61
- Requires-Dist: zope.sqlalchemy ; extra == "standard" or extra == "webserver" or extra == "all"
63
+ Requires-Dist: waitress ; extra == "standard" or extra == "dev" or extra == "waitress" or extra == "all"
64
+ Requires-Dist: zope.interface ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
65
+ Requires-Dist: zope.sqlalchemy ; extra == "standard" or extra == "webserver" or extra == "waitress" or extra == "all"
62
66
  Project-URL: Repository, https://github.com/camptocamp/c2cwsgiutils
63
67
  Description-Content-Type: text/markdown
64
68
 
@@ -672,6 +676,64 @@ def hello_get(request):
672
676
  return {'hello': True}
673
677
  ```
674
678
 
679
+ ## Waitress
680
+
681
+ In production mode we usually use Gunicorn but we can also use Waitress.
682
+
683
+ The advantage to use Waitress is that it creates only one process, that makes it easier to manage especially on Kubernetes:
684
+
685
+ - The memory is more stable.
686
+ - The OOM killer will restart the container.
687
+ - Prometheus didn't request trick to aggregate the metrics.
688
+
689
+ Then to migrate from Gunicorn to Waitress you should do:
690
+
691
+ Add call to `c2cwsgiutils.prometheus.start_single_process()` on your application main function.
692
+
693
+ Changes to do in your docker file:
694
+
695
+ ```diff
696
+
697
+ ENV \
698
+ - GUNICORN_LOG_LEVEL=WARNING \
699
+ + WAITRESS_LOG_LEVEL=WARNING \
700
+ + WAITRESS_THREADS=10 \
701
+
702
+ -RUN mkdir -p /prometheus-metrics \
703
+ - && chmod a+rwx /prometheus-metrics
704
+ -ENV PROMETHEUS_MULTIPROC_DIR=/prometheus-metrics
705
+
706
+
707
+ -CMD ["/venv/bin/gunicorn", "--paste=/app/production.ini"]
708
+ +CMD ["/venv/bin/pserve", "c2c:///app/production.ini"]
709
+ ```
710
+
711
+ Remove the no more needed file `gunicorn.conf.py`.
712
+
713
+ Update the `production.ini` file:
714
+
715
+ ```diff
716
+
717
+ -# this file should be used by gunicorn.
718
+
719
+ [server:main]
720
+ +threads = %(WAITRESS_THREADS)s
721
+ +trusted_proxy = True
722
+ +clear_untrusted_proxy_headers = False
723
+
724
+ [loggers]
725
+ -keys = root, gunicorn, sqlalchemy, c2cwsgiutils, c2cwsgiutils_app
726
+ +keys = root, waitress, sqlalchemy, c2cwsgiutils, c2cwsgiutils_app
727
+
728
+ -[logger_gunicorn]
729
+ -level = %(GUNICORN_LOG_LEVEL)s
730
+ +[logger_waitress]
731
+ +level = %(WAITRESS_LOG_LEVEL)s
732
+ handlers =
733
+ -qualname = gunicorn.error
734
+ +qualname = waitress
735
+ ```
736
+
675
737
  # Exception handling
676
738
 
677
739
  c2cwsgiutils can install exception handling views that will catch any exception raised by the
@@ -0,0 +1,67 @@
1
+ c2cwsgiutils/__init__.py,sha256=HVSc-4O8i2aB0ozEI4AI8Xsb-4S6fAwhl8uRhv-DsFg,4057
2
+ c2cwsgiutils/acceptance/__init__.py,sha256=5PeqPHxAPMRbZpKk1XlC9RCyotegSsKVfPxADYAgG7w,1502
3
+ c2cwsgiutils/acceptance/connection.py,sha256=A83v335e4s-_cePe-bqRcEHHTOdgguetzdAtVp19-Zk,9834
4
+ c2cwsgiutils/acceptance/image.py,sha256=zKouNqU424rkWW43-NwIEVeXIXaqZxSwe04NSE-3174,9290
5
+ c2cwsgiutils/acceptance/package-lock.json,sha256=jLvCfPizXSwqLXC_02w3Vbq6qi5XIYpcCJmwy08iUdk,42580
6
+ c2cwsgiutils/acceptance/package.json,sha256=u0---w2SMjJ_ZsAQ3_4k2zopt4Wq-VfBOLN59rZPoRo,102
7
+ c2cwsgiutils/acceptance/print.py,sha256=DOPDHUP9wfM75qiPYhFI1P3awQKIBH-edO_TmhCjT8k,2568
8
+ c2cwsgiutils/acceptance/screenshot.js,sha256=FAJYIWOLJFMm0MNggKzo3mIybtN-VtKLdMzPhQ9pO1g,2041
9
+ c2cwsgiutils/acceptance/utils.py,sha256=beq_pGJCMBRMmzLERw7z79vc9KtX5gY-g37WiUHa4q8,1901
10
+ c2cwsgiutils/auth.py,sha256=gNJ8VKXPJu_lSlOwxhNSrjjaJ9TzasWIbEpkmYnoauQ,9582
11
+ c2cwsgiutils/broadcast/__init__.py,sha256=9vhFSNUwMqNp73D3LXnQJeLOYB49VUU4KwIoOvDaS3o,4484
12
+ c2cwsgiutils/broadcast/interface.py,sha256=AkDT_m0eXTQp3mmMLf9KRtpXnWoVhJpb_UNjCbHM-3I,665
13
+ c2cwsgiutils/broadcast/local.py,sha256=BZ0iDmU81W8C3Xzs9Dz9jRdTO-WXXvA_7Z5xV6RWoNA,1317
14
+ c2cwsgiutils/broadcast/redis.py,sha256=9FsKxsddf9khYe7aTKou2lmLgXEVcRqVyeFuhxM8-ZM,5378
15
+ c2cwsgiutils/broadcast/utils.py,sha256=0fQZXPu3p_5LEJpGenJwiiMxECQjJhjZBjIkBk8h-ng,272
16
+ c2cwsgiutils/client_info.py,sha256=MIlD88JJ-IL3GwhJsMB73IbsWcglMkdnCyOgDEQG8ns,4004
17
+ c2cwsgiutils/config_utils.py,sha256=vkBu-3GQsE94NOBOvT5FE-Ij29EUrKnDsmdUdtu_yzo,1524
18
+ c2cwsgiutils/coverage_setup.py,sha256=OGsz3bDX8Vcy9K8TBkRb4aQVAhK6618OVV9Az2p3hGA,928
19
+ c2cwsgiutils/db.py,sha256=YvJKo1cXhKcjYwRpUkQbx70YOnOgsYJ5wID5rkLhF6g,16262
20
+ c2cwsgiutils/db_maintenance_view.py,sha256=1y_sfjnHsvl98yzTM24rqmchqGIXDp61KTwraXJZM0s,3102
21
+ c2cwsgiutils/debug/__init__.py,sha256=a2RytL9_DgqiJzc5CCdKd1yF2sSk6SCIVh1gUrWVq1o,1364
22
+ c2cwsgiutils/debug/_listeners.py,sha256=-fk3KFeB_E4m_YFXJ5MfxuqfA1sWCje9p3FH_93WfXM,4248
23
+ c2cwsgiutils/debug/_views.py,sha256=bge_jnylY6oBtWTZjSoDByLbx3MjapY4JiZu97xQoWU,8518
24
+ c2cwsgiutils/debug/utils.py,sha256=sIKZHQ8empzxE2OI3h7Uce8cvv4O7AD1y_VYeZfLVCA,2320
25
+ c2cwsgiutils/errors.py,sha256=miNVnEX9qBtwaRnny_k9IcBbbw-8vC3unFumi2w5Q9w,6679
26
+ c2cwsgiutils/health_check.py,sha256=Wi3JQCKa7tqACuSgBi13oE69Xc-Vz1nheqBaxfOGXQU,20141
27
+ c2cwsgiutils/index.py,sha256=ag7A8HJ9MgU72etDBuFMaci-xKjOD9R8OOm3UMEoQJY,18002
28
+ c2cwsgiutils/loader.py,sha256=VbvENJZgl3Mmkysx-BODSl_Qh3LtQrz51pZ1F_A50Rk,1400
29
+ c2cwsgiutils/logging_view.py,sha256=wa2hCjGKkpRwrCA4K6Zk1Z3hPGUMB6SJAnki-_lLY00,3384
30
+ c2cwsgiutils/models_graph.py,sha256=AROTzCHJCjjOiOmQj_Hk40WQdIPaHFLgN4Jech1aUzc,2683
31
+ c2cwsgiutils/pretty_json.py,sha256=houw_oeU63CgzQTPlBrrYzinpE-UtqPeYLfTXdLHyu0,1711
32
+ c2cwsgiutils/profiler.py,sha256=3902yp1rHpSNpsYKmqs_IrEpFg9P2QqNtjyolk53ZgQ,778
33
+ c2cwsgiutils/prometheus.py,sha256=vTb0cDO30DQwjVdu0qCFEyTAOv7jeUFioDjTCbp1bYA,8712
34
+ c2cwsgiutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
+ c2cwsgiutils/pyramid.py,sha256=kSCsBG5IPd0-tsXwdiJ3cj_yj-AxQYFusvTxPE6AaeQ,1388
36
+ c2cwsgiutils/pyramid_logging.py,sha256=U1MD7xEAGH7QdX7FA6O12eHhzMx76i1WCXtf_EiJgVE,3911
37
+ c2cwsgiutils/redis_stats.py,sha256=yUVVNGR_rIecH4uRfRWMySERCTYMWtJhSXAs0iK4TAs,1646
38
+ c2cwsgiutils/redis_utils.py,sha256=kY1QbZWVnUI-bxCeJOxn5VBfna2hS1oUQxx9HEws_ww,4813
39
+ c2cwsgiutils/request_tracking/__init__.py,sha256=ZeCxPJNrUxKLDmV5bOs0zmD9vx0FFIPs7T3xDNG-5BU,4146
40
+ c2cwsgiutils/request_tracking/_sql.py,sha256=ZOQ3hD5z-WasfBzNig75fjrCvw4tGr1rhWOv97iLYws,572
41
+ c2cwsgiutils/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ c2cwsgiutils/scripts/genversion.py,sha256=SZswHR6qbeErcxn5d5yAa4QPnw9z4LCeP9GOweTj16g,2014
43
+ c2cwsgiutils/scripts/stats_db.py,sha256=EaI1WAHGKj-sUWpznIOs8yMlgx2pnzwAksA8hA-nF28,10452
44
+ c2cwsgiutils/scripts/test_print.py,sha256=pLqqVZ9cVvjdD3MdJQ7Ul8i5OIBFvo1Gnr78rdH0Dh4,2130
45
+ c2cwsgiutils/sentry.py,sha256=ZnWo0-8xgwWxDG_wo9gI8rDtZlKgcZXorG3b0tU5Hh0,6508
46
+ c2cwsgiutils/services.py,sha256=AxdiH2S8gfEQpOY36R4WqKtJ-3P4OXhx0srTm5G5070,1569
47
+ c2cwsgiutils/setup_process.py,sha256=K4o3feB98zKoPiI2k7MnTsItwf_i-NSL8ziUmGnYg_Q,3553
48
+ c2cwsgiutils/sql_profiler/__init__.py,sha256=YR8003lCNNGC2eZdyIt5gt76-1frG5szw8IYE_EsQB4,921
49
+ c2cwsgiutils/sql_profiler/_impl.py,sha256=OdhAn-5x84Bz5RCldhgjX50b6yxSLnLh5nydNgHvgGc,3801
50
+ c2cwsgiutils/sqlalchemylogger/README.md,sha256=qXfyhGC4Kbt-Ye_geTPm_1InpclhthmKZpc66rqB4as,2018
51
+ c2cwsgiutils/sqlalchemylogger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
+ c2cwsgiutils/sqlalchemylogger/_filters.py,sha256=OJQ9_WA-fd9fMZ7TUNFzHHTPI6msw2NVBl5RoeYFnGw,752
53
+ c2cwsgiutils/sqlalchemylogger/_models.py,sha256=A9SQ8AqUazCMemVjp5p_1x4bZG3LAYW9pOXT84FdNkE,1471
54
+ c2cwsgiutils/sqlalchemylogger/examples/example.py,sha256=n48dJdUi1FH1hfBMAbfHLGPSb1bOVD8pXMxXB57PnpQ,460
55
+ c2cwsgiutils/sqlalchemylogger/handlers.py,sha256=hDDWmiV6ksEcRCJlqIdQW3P9hq2BTC70wrLmY0vYkyA,4979
56
+ c2cwsgiutils/static/favicon-16x16.png,sha256=LKk6RFvb3NlPIZdDfAodE8H9IN8KM6CMGnMx4vOHlUQ,887
57
+ c2cwsgiutils/static/favicon-32x32.png,sha256=i4ucx08zAZARd8e7JTMGK-gb5WcOmyuDN6IN4brsEOo,1216
58
+ c2cwsgiutils/stats_pyramid/__init__.py,sha256=0NizIUbaPbNf6bPye7pGrF9AaFerIN30EhEMts1XgfY,801
59
+ c2cwsgiutils/stats_pyramid/_db_spy.py,sha256=A61t6VKIrRRIjbyZTldmAUl_Q3ZDVFYqyxjuntzmllc,2919
60
+ c2cwsgiutils/stats_pyramid/_pyramid_spy.py,sha256=GnJRlLSAPl4PwQH5jfmc2OX5Hz9MSRRVJT2VcqkniVE,3518
61
+ c2cwsgiutils/templates/index.html.mako,sha256=cK8qGBDeQG5SiJJCfvL0oKpgacr7dPKx634AAQivmjA,1416
62
+ c2cwsgiutils/version.py,sha256=7H3URblj26Ql0bL3eXtP0LSRBeW4HbEsQ8O_BfWNr90,3124
63
+ c2cwsgiutils-6.2.0.dev54.dist-info/LICENSE,sha256=6bEOU0n7ued3SA-DQCsHQaACONMMRzGHmH5XhDVeD-U,1304
64
+ c2cwsgiutils-6.2.0.dev54.dist-info/METADATA,sha256=03TOp4coKrTK6qINS1J4_AsYPpcYYyU_wUtRhy3wspM,36359
65
+ c2cwsgiutils-6.2.0.dev54.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
66
+ c2cwsgiutils-6.2.0.dev54.dist-info/entry_points.txt,sha256=ujgqMTL1awN9qDg8WXmrF7m0fgR-hslUM6zKH86pvy0,703
67
+ c2cwsgiutils-6.2.0.dev54.dist-info/RECORD,,
@@ -1,67 +0,0 @@
1
- c2cwsgiutils/__init__.py,sha256=HVSc-4O8i2aB0ozEI4AI8Xsb-4S6fAwhl8uRhv-DsFg,4057
2
- c2cwsgiutils/acceptance/__init__.py,sha256=TJA1yzmyPujkg80oj-LBj2ueOQVYL8HLW87pejWTIDY,1501
3
- c2cwsgiutils/acceptance/connection.py,sha256=yqChhHBpYhQL0Cb7K8FqeP16jg1UtmxGAi6Tw1TXEbI,9783
4
- c2cwsgiutils/acceptance/image.py,sha256=Wi4EXDTKZ-uyIIQFn8SpRpUTzbpj5LlCwSkLjcYRGTk,9269
5
- c2cwsgiutils/acceptance/package-lock.json,sha256=uiNM1L8_IsK7G8A8f2qKpUF0za-tO6_RvgNN3cEDKwg,47777
6
- c2cwsgiutils/acceptance/package.json,sha256=DiJUVhci1sP-qu71s3RzxcsF4GsZdo2ZOUeqX3148ss,101
7
- c2cwsgiutils/acceptance/print.py,sha256=qdh6pqlHgkIjUCJxS3rcgpOV4fDk9RxFlkfH5aAwDsQ,2567
8
- c2cwsgiutils/acceptance/screenshot.js,sha256=FAJYIWOLJFMm0MNggKzo3mIybtN-VtKLdMzPhQ9pO1g,2041
9
- c2cwsgiutils/acceptance/utils.py,sha256=zLvWqqPLBGCzGAtmIqidao66BKmER_Du1AfKCEhoc-I,1892
10
- c2cwsgiutils/auth.py,sha256=ljTUPYGpEkkDg6ifOegXS1Q1JlcRth0P5vbMCs7VK6k,9585
11
- c2cwsgiutils/broadcast/__init__.py,sha256=mYiTVL34QkJkEjxURlDIE7bmwZaEPT9Lw9zMwbiVtL0,4470
12
- c2cwsgiutils/broadcast/interface.py,sha256=AkDT_m0eXTQp3mmMLf9KRtpXnWoVhJpb_UNjCbHM-3I,665
13
- c2cwsgiutils/broadcast/local.py,sha256=kQp6OWcRU-nx7uEBAXwdMum_rOz3LSj6fyL_R12QrMY,1139
14
- c2cwsgiutils/broadcast/redis.py,sha256=xCcGSr7jr6QdFM-YZzFFaySQis1xKb0HqqbGR8qjSNM,5202
15
- c2cwsgiutils/broadcast/utils.py,sha256=0fQZXPu3p_5LEJpGenJwiiMxECQjJhjZBjIkBk8h-ng,272
16
- c2cwsgiutils/client_info.py,sha256=rvXQLyhma0kPoWQINwUzrxfG2gGIjQDNrxPUDRGJxpA,3916
17
- c2cwsgiutils/config_utils.py,sha256=vkBu-3GQsE94NOBOvT5FE-Ij29EUrKnDsmdUdtu_yzo,1524
18
- c2cwsgiutils/coverage_setup.py,sha256=BrdjYUmqYl1C-gHuKA7EI5gbQs8Dtdeb2eZKtzr-5L0,909
19
- c2cwsgiutils/db.py,sha256=JT5F9Dqm2r0Jsh3w3CX79ngAUtakMLpf1secfN1nQnk,16106
20
- c2cwsgiutils/db_maintenance_view.py,sha256=58F-p9drkhCI99GoLRPIqT5U-Pm8ckSSUEl-tNxMmjU,3088
21
- c2cwsgiutils/debug/__init__.py,sha256=GkYNt2fU5PFykw9HmqPEwZrF2mTJumjSu54pp38EhOM,1325
22
- c2cwsgiutils/debug/_listeners.py,sha256=-fk3KFeB_E4m_YFXJ5MfxuqfA1sWCje9p3FH_93WfXM,4248
23
- c2cwsgiutils/debug/_views.py,sha256=EY-reJAs68wZu3D1DosNBE_DnY3vbD55k-jkCNOZ9MU,7751
24
- c2cwsgiutils/debug/utils.py,sha256=sIKZHQ8empzxE2OI3h7Uce8cvv4O7AD1y_VYeZfLVCA,2320
25
- c2cwsgiutils/errors.py,sha256=-hWLQ1qDlh9kn06-33U2c39BbOxuCvJIkBkdxriE5mo,6644
26
- c2cwsgiutils/health_check.py,sha256=OhfPcApBht1qtBOX8e8pdeq3QwF4FbgGkofjqpl8GvQ,20068
27
- c2cwsgiutils/index.py,sha256=zQTp2dlb50DZy0TZOPYDxJv84kivcYirswz7rFMbSDA,17988
28
- c2cwsgiutils/loader.py,sha256=aDs_YOoiEc_vr94fnc3TjUklIGgIOBZdoYLAjQHgTpo,1393
29
- c2cwsgiutils/logging_view.py,sha256=d0UkvYRGkVUMY9_vbjEzXmm8-6CCec2B43a3mJAqWyw,3370
30
- c2cwsgiutils/models_graph.py,sha256=q5dW_gZ5iUZCzBya5Kpy57y9oqsG-rGi9AvrXCDgYqs,2679
31
- c2cwsgiutils/pretty_json.py,sha256=WQlgNVeWPD_QMEjkNq5rFVGdFwQ7xDyICf0uxj0Hu2U,1697
32
- c2cwsgiutils/profiler.py,sha256=3tIwoDSzOKQ06ug_U6j5VDR1BQ9auUOqdJRRLRhDoHw,739
33
- c2cwsgiutils/prometheus.py,sha256=XV_SSm0nT09MD8EEl2a4xtd2busO3r--JyboU9OvWaQ,6576
34
- c2cwsgiutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- c2cwsgiutils/pyramid.py,sha256=MnVMskHMlJ4KQDjDR7CQdYaH70YXOtJ-1ThTPBqa03c,1387
36
- c2cwsgiutils/pyramid_logging.py,sha256=M4XtWQZStreEoyC5qlwxcDDKCp4PZOr9SN05GnaYvvA,3732
37
- c2cwsgiutils/redis_stats.py,sha256=8OTVRcElESgM6qjN944MOjoYRb0FGcQgo3JmDglfpPw,1632
38
- c2cwsgiutils/redis_utils.py,sha256=02QoBGSjfBwKsWk-4DrXT8119HuUJuV_ezW7bc-Rv8s,4734
39
- c2cwsgiutils/request_tracking/__init__.py,sha256=9Fp505q5zKjqfm9MuM7BDiYsx_pdg4vViNAr43OWYuk,4132
40
- c2cwsgiutils/request_tracking/_sql.py,sha256=ZOQ3hD5z-WasfBzNig75fjrCvw4tGr1rhWOv97iLYws,572
41
- c2cwsgiutils/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
- c2cwsgiutils/scripts/genversion.py,sha256=lpGqU5wNSKdoOMDwVjFvWJVPEzdk0P8Tpfk7NLcrTok,1990
43
- c2cwsgiutils/scripts/stats_db.py,sha256=kGCWBpG6gp_yDH3eZwEOujrvlyM0g97po6-EyjV8SXU,10413
44
- c2cwsgiutils/scripts/test_print.py,sha256=NSXc0a2DZvKXjZYc2yr6oF72PCpeyL3GJthNFxGErEA,2101
45
- c2cwsgiutils/sentry.py,sha256=su_t2SHxx_zK-gQfotmDbgbSdwTQdFvkgJnqcrQU7ps,6494
46
- c2cwsgiutils/services.py,sha256=AxdiH2S8gfEQpOY36R4WqKtJ-3P4OXhx0srTm5G5070,1569
47
- c2cwsgiutils/setup_process.py,sha256=VSiyVaQ65btIEBql1sBCZpOjCr0QQjRbcVDY2I7GbLM,3426
48
- c2cwsgiutils/sql_profiler/__init__.py,sha256=2bh5s4xqPLUl7EPnm75R1RDKtc098PgZLHkwHGfS-94,907
49
- c2cwsgiutils/sql_profiler/_impl.py,sha256=6qkXMhDGcheCDwOH09gFJDrtXRsngkvm29icZWZMtMI,3797
50
- c2cwsgiutils/sqlalchemylogger/README.md,sha256=qXfyhGC4Kbt-Ye_geTPm_1InpclhthmKZpc66rqB4as,2018
51
- c2cwsgiutils/sqlalchemylogger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- c2cwsgiutils/sqlalchemylogger/_filters.py,sha256=OJQ9_WA-fd9fMZ7TUNFzHHTPI6msw2NVBl5RoeYFnGw,752
53
- c2cwsgiutils/sqlalchemylogger/_models.py,sha256=A9SQ8AqUazCMemVjp5p_1x4bZG3LAYW9pOXT84FdNkE,1471
54
- c2cwsgiutils/sqlalchemylogger/examples/example.py,sha256=n48dJdUi1FH1hfBMAbfHLGPSb1bOVD8pXMxXB57PnpQ,460
55
- c2cwsgiutils/sqlalchemylogger/handlers.py,sha256=nr9-eQsZ5d0DHbtc4Ym0_faa7qg1dF44CsdoZtuuRZM,4878
56
- c2cwsgiutils/static/favicon-16x16.png,sha256=LKk6RFvb3NlPIZdDfAodE8H9IN8KM6CMGnMx4vOHlUQ,887
57
- c2cwsgiutils/static/favicon-32x32.png,sha256=i4ucx08zAZARd8e7JTMGK-gb5WcOmyuDN6IN4brsEOo,1216
58
- c2cwsgiutils/stats_pyramid/__init__.py,sha256=alSRhpCa5Kh9JnMnR5XqcMqr5wyL8ogROprrfsIl_qU,786
59
- c2cwsgiutils/stats_pyramid/_db_spy.py,sha256=A61t6VKIrRRIjbyZTldmAUl_Q3ZDVFYqyxjuntzmllc,2919
60
- c2cwsgiutils/stats_pyramid/_pyramid_spy.py,sha256=mRiOmQXV9x8JjkGV4MsaC7sD3qO6dWUTog0bharLLD0,3517
61
- c2cwsgiutils/templates/index.html.mako,sha256=cK8qGBDeQG5SiJJCfvL0oKpgacr7dPKx634AAQivmjA,1416
62
- c2cwsgiutils/version.py,sha256=1ghPu-aKMJdfCSUrxgBENNqNQ-7JMKJr6tS14dDmW4Q,3110
63
- c2cwsgiutils-6.1.7.dev4.dist-info/LICENSE,sha256=6bEOU0n7ued3SA-DQCsHQaACONMMRzGHmH5XhDVeD-U,1304
64
- c2cwsgiutils-6.1.7.dev4.dist-info/METADATA,sha256=bNxv5REJhQ1RiSYrsuk-h7s28UfeJTZIIuoFWUXfHO0,34401
65
- c2cwsgiutils-6.1.7.dev4.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
66
- c2cwsgiutils-6.1.7.dev4.dist-info/entry_points.txt,sha256=ujgqMTL1awN9qDg8WXmrF7m0fgR-hslUM6zKH86pvy0,703
67
- c2cwsgiutils-6.1.7.dev4.dist-info/RECORD,,