c2cwsgiutils 6.1.0.dev105__py3-none-any.whl → 6.1.7__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 +17 -11
  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 +2 -7
  20. c2cwsgiutils/debug/_views.py +20 -12
  21. c2cwsgiutils/debug/utils.py +9 -9
  22. c2cwsgiutils/errors.py +13 -15
  23. c2cwsgiutils/health_check.py +24 -30
  24. c2cwsgiutils/index.py +34 -13
  25. c2cwsgiutils/loader.py +21 -2
  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 +10 -10
  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 +12 -11
  46. c2cwsgiutils/stats_pyramid/__init__.py +1 -5
  47. c2cwsgiutils/stats_pyramid/_db_spy.py +2 -2
  48. c2cwsgiutils/stats_pyramid/_pyramid_spy.py +12 -1
  49. c2cwsgiutils/templates/index.html.mako +4 -1
  50. c2cwsgiutils/version.py +11 -5
  51. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dist-info}/LICENSE +1 -1
  52. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dist-info}/METADATA +18 -6
  53. c2cwsgiutils-6.1.7.dist-info/RECORD +67 -0
  54. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dist-info}/WHEEL +1 -1
  55. c2cwsgiutils-6.1.0.dev105.dist-info/RECORD +0 -67
  56. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dist-info}/entry_points.txt +0 -0
c2cwsgiutils/__init__.py CHANGED
@@ -1,12 +1,12 @@
1
+ import ast
1
2
  import configparser
2
3
  import logging
3
4
  import os
4
- import re
5
5
  import sys
6
6
  from configparser import SectionProxy
7
7
  from typing import Any
8
8
 
9
- LOG = logging.getLogger(__name__)
9
+ _LOG = logging.getLogger(__name__)
10
10
 
11
11
 
12
12
  def get_config_defaults() -> dict[str, str]:
@@ -16,13 +16,13 @@ def get_config_defaults() -> dict[str, str]:
16
16
  configparser does not support duplicated defaults with different cases, this function filter
17
17
  the second one to avoid the issue.
18
18
 
19
- configparser interpretate the % then we need to escape them
19
+ configparser interpret the % then we need to escape them
20
20
  """
21
21
  result: dict[str, str] = {}
22
22
  lowercase_keys: set[str] = set()
23
23
  for key, value in os.environ.items():
24
24
  if key.lower() in lowercase_keys:
25
- LOG.warning("The environment variable '%s' is duplicated with different case, ignoring", key)
25
+ _LOG.warning("The environment variable '%s' is duplicated with different case, ignoring", key)
26
26
  continue
27
27
  lowercase_keys.add(key.lower())
28
28
  result[key] = value.replace("%", "%%")
@@ -32,23 +32,26 @@ def get_config_defaults() -> dict[str, str]:
32
32
  def _create_handlers(config: configparser.ConfigParser) -> dict[str, Any]:
33
33
  handlers = [k.strip() for k in config["handlers"]["keys"].split(",")]
34
34
  d_handlers: dict[str, Any] = {}
35
- stream_re = re.compile(r"\((.*?),\)")
36
35
  for hh in handlers:
37
36
  block = config[f"handler_{hh}"]
38
- stream_match = stream_re.match(block["args"])
39
- if stream_match is None:
40
- raise Exception(f"Could not parse args of handler {hh}") # pylint: disable=broad-exception-raised
41
- args = stream_match.groups()[0]
37
+ if "args" in block:
38
+ raise ValueError(f"Can not parse args of handlers {hh}, use kwargs instead.")
42
39
  c = block["class"]
43
40
  if "." not in c:
44
41
  # classes like StreamHandler does not need the prefix in the ini so we add it here
45
42
  c = f"logging.{c}"
46
43
  conf = {
47
44
  "class": c,
48
- "stream": f"ext://{args}", # like ext://sys.stdout
49
45
  }
46
+ if "level" in block:
47
+ conf["level"] = block["level"]
50
48
  if "formatter" in block:
51
49
  conf["formatter"] = block["formatter"]
50
+ if "filters" in block:
51
+ conf["filters"] = block["filters"]
52
+ if "kwargs" in block:
53
+ kwargs = ast.literal_eval(block["kwargs"])
54
+ conf.update(kwargs)
52
55
  d_handlers[hh] = conf
53
56
  return d_handlers
54
57
 
@@ -57,7 +60,7 @@ def _filter_logger(block: SectionProxy) -> dict[str, Any]:
57
60
  out: dict[str, Any] = {"level": block["level"]}
58
61
  handlers = block.get("handlers", "")
59
62
  if handlers != "":
60
- out["handlers"] = [block["handlers"]]
63
+ out["handlers"] = [k.strip() for k in block["handlers"].split(",")]
61
64
  return out
62
65
 
63
66
 
@@ -3,7 +3,7 @@ import time
3
3
  import typing
4
4
  from functools import wraps
5
5
 
6
- LOG = logging.getLogger(__name__)
6
+ _LOG = logging.getLogger(__name__)
7
7
 
8
8
 
9
9
  def retry(
@@ -16,7 +16,6 @@ def retry(
16
16
  original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry
17
17
 
18
18
  Arguments:
19
-
20
19
  exception_to_check: the exception to check. may be a tuple of exceptions to check
21
20
  tries: number of times to try (not retry) before giving up
22
21
  delay: initial delay between retries in seconds
@@ -32,7 +31,7 @@ def retry(
32
31
  return f(*args, **kwargs)
33
32
  except exception_to_check as e:
34
33
  msg = f"{e:s}, Retrying in {mdelay:d} seconds..."
35
- LOG.warning(msg)
34
+ _LOG.warning(msg)
36
35
  time.sleep(mdelay)
37
36
  mtries -= 1
38
37
  mdelay *= backoff
@@ -82,8 +82,7 @@ class Connection:
82
82
  **kwargs: Any,
83
83
  ) -> Any:
84
84
  """Get the given URL (relative to the root of API)."""
85
-
86
- from lxml import etree # nosec
85
+ from lxml import etree # nosec # pylint: disable=import-outside-toplevel
87
86
 
88
87
  with self.session.get(
89
88
  self.base_url + url,
@@ -3,11 +3,11 @@ import os
3
3
  import subprocess # nosec
4
4
  from typing import TYPE_CHECKING, Any, Optional
5
5
 
6
- import numpy as np
7
- import skimage.color
8
- import skimage.io
9
- import skimage.metrics
10
- import skimage.transform
6
+ import numpy as np # pylint: disable=import-error
7
+ import skimage.color # pylint: disable=import-error
8
+ import skimage.io # pylint: disable=import-error
9
+ import skimage.metrics # pylint: disable=import-error
10
+ import skimage.transform # pylint: disable=import-error
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from typing import TypeAlias
@@ -58,7 +58,7 @@ def normalize_image(image: NpNdarrayInt) -> NpNdarrayInt:
58
58
  return image
59
59
 
60
60
 
61
- def check_image(
61
+ def check_image( # pylint: disable=too-many-locals,too-many-statements
62
62
  result_folder: str,
63
63
  image_to_check: NpNdarrayInt,
64
64
  expected_filename: str,
@@ -108,6 +108,13 @@ def check_image(
108
108
 
109
109
  mask = None
110
110
  if mask_filename is not None:
111
+ background_color = [255, 255, 255]
112
+ for color in range(3):
113
+ img_hist, _ = skimage.exposure.histogram(
114
+ image_to_check[..., color], nbins=256, source_range="dtype"
115
+ )
116
+ background_color[color] = np.argmax(img_hist)
117
+
111
118
  mask = skimage.io.imread(mask_filename)
112
119
 
113
120
  assert mask is not None, "Wrong mask: " + mask_filename
@@ -130,7 +137,7 @@ def check_image(
130
137
  assert (
131
138
  mask.shape[0] == image_to_check.shape[0] and mask.shape[1] == image_to_check.shape[1]
132
139
  ), f"Mask and image should have the same shape ({mask.shape} != {image_to_check.shape})"
133
- image_to_check[mask] = [255, 255, 255]
140
+ image_to_check[mask] = background_color
134
141
 
135
142
  if not os.path.exists(result_folder):
136
143
  os.makedirs(result_folder)
@@ -148,7 +155,7 @@ def check_image(
148
155
  assert (
149
156
  expected.shape[0] == mask.shape[0] and expected.shape[1] == mask.shape[1]
150
157
  ), f"Mask and expected image should have the same shape ({mask.shape} != {expected.shape})"
151
- expected[mask] = [255, 255, 255]
158
+ expected[mask] = background_color
152
159
 
153
160
  assert (
154
161
  expected.shape == image_to_check.shape
@@ -175,7 +182,7 @@ def check_screenshot(
175
182
  expected_filename: str,
176
183
  width: int = 800,
177
184
  height: int = 600,
178
- sleep: int = 0,
185
+ sleep: int = 100,
179
186
  headers: Optional[dict[str, str]] = None,
180
187
  media: Optional[list[dict[str, str]]] = None,
181
188
  level: float = 1.0,
@@ -189,7 +196,7 @@ def check_screenshot(
189
196
 
190
197
  See also `check_image` for the other parameters.
191
198
 
192
- Args:
199
+ Arguments:
193
200
  url: The URL to screenshot
194
201
  width: The width of the generated screenshot
195
202
  height: The height of the generated screenshot
@@ -202,7 +209,6 @@ def check_screenshot(
202
209
  generate_expected_image: See `check_image`
203
210
  use_mask: See `check_image`
204
211
  """
205
-
206
212
  if headers is None:
207
213
  headers = {}
208
214
  if media is None: