c2cwsgiutils 5.1.7.dev20230901073305__py3-none-any.whl → 5.2.1.dev197__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 (69) hide show
  1. c2cwsgiutils/__init__.py +13 -13
  2. c2cwsgiutils/acceptance/connection.py +5 -2
  3. c2cwsgiutils/acceptance/image.py +98 -4
  4. c2cwsgiutils/acceptance/package-lock.json +1933 -0
  5. c2cwsgiutils/acceptance/package.json +7 -0
  6. c2cwsgiutils/acceptance/print.py +4 -4
  7. c2cwsgiutils/acceptance/screenshot.js +62 -0
  8. c2cwsgiutils/acceptance/utils.py +14 -22
  9. c2cwsgiutils/auth.py +4 -4
  10. c2cwsgiutils/broadcast/__init__.py +15 -7
  11. c2cwsgiutils/broadcast/interface.py +3 -2
  12. c2cwsgiutils/broadcast/local.py +3 -2
  13. c2cwsgiutils/broadcast/redis.py +8 -7
  14. c2cwsgiutils/client_info.py +5 -5
  15. c2cwsgiutils/config_utils.py +2 -1
  16. c2cwsgiutils/coverage_setup.py +2 -2
  17. c2cwsgiutils/db.py +58 -37
  18. c2cwsgiutils/db_maintenance_view.py +2 -1
  19. c2cwsgiutils/debug/_listeners.py +10 -9
  20. c2cwsgiutils/debug/_views.py +12 -11
  21. c2cwsgiutils/debug/utils.py +5 -5
  22. c2cwsgiutils/errors.py +7 -6
  23. c2cwsgiutils/health_check.py +96 -85
  24. c2cwsgiutils/index.py +90 -105
  25. c2cwsgiutils/loader.py +3 -3
  26. c2cwsgiutils/logging_view.py +3 -2
  27. c2cwsgiutils/models_graph.py +8 -6
  28. c2cwsgiutils/prometheus.py +175 -57
  29. c2cwsgiutils/pyramid.py +4 -2
  30. c2cwsgiutils/pyramid_logging.py +2 -1
  31. c2cwsgiutils/redis_stats.py +13 -11
  32. c2cwsgiutils/redis_utils.py +15 -14
  33. c2cwsgiutils/request_tracking/__init__.py +36 -30
  34. c2cwsgiutils/request_tracking/_sql.py +3 -1
  35. c2cwsgiutils/scripts/genversion.py +4 -4
  36. c2cwsgiutils/scripts/stats_db.py +130 -68
  37. c2cwsgiutils/scripts/test_print.py +1 -1
  38. c2cwsgiutils/sentry.py +2 -1
  39. c2cwsgiutils/setup_process.py +13 -17
  40. c2cwsgiutils/sql_profiler/_impl.py +12 -5
  41. c2cwsgiutils/sqlalchemylogger/README.md +48 -0
  42. c2cwsgiutils/sqlalchemylogger/_models.py +7 -4
  43. c2cwsgiutils/sqlalchemylogger/examples/example.py +15 -0
  44. c2cwsgiutils/sqlalchemylogger/handlers.py +11 -8
  45. c2cwsgiutils/static/favicon-16x16.png +0 -0
  46. c2cwsgiutils/static/favicon-32x32.png +0 -0
  47. c2cwsgiutils/stats_pyramid/__init__.py +7 -11
  48. c2cwsgiutils/stats_pyramid/_db_spy.py +14 -11
  49. c2cwsgiutils/stats_pyramid/_pyramid_spy.py +29 -20
  50. c2cwsgiutils/templates/index.html.mako +50 -0
  51. c2cwsgiutils/version.py +49 -16
  52. c2cwsgiutils-5.2.1.dev197.dist-info/LICENSE +22 -0
  53. {c2cwsgiutils-5.1.7.dev20230901073305.dist-info → c2cwsgiutils-5.2.1.dev197.dist-info}/METADATA +187 -135
  54. c2cwsgiutils-5.2.1.dev197.dist-info/RECORD +67 -0
  55. {c2cwsgiutils-5.1.7.dev20230901073305.dist-info → c2cwsgiutils-5.2.1.dev197.dist-info}/WHEEL +1 -2
  56. c2cwsgiutils-5.2.1.dev197.dist-info/entry_points.txt +21 -0
  57. c2cwsgiutils/acceptance/composition.py +0 -129
  58. c2cwsgiutils/metrics.py +0 -110
  59. c2cwsgiutils/scripts/check_es.py +0 -130
  60. c2cwsgiutils/scripts/coverage_report.py +0 -36
  61. c2cwsgiutils/stats.py +0 -355
  62. c2cwsgiutils/stats_pyramid/_views.py +0 -16
  63. c2cwsgiutils-5.1.7.dev20230901073305.data/scripts/c2cwsgiutils-run +0 -32
  64. c2cwsgiutils-5.1.7.dev20230901073305.dist-info/LICENSE.txt +0 -28
  65. c2cwsgiutils-5.1.7.dev20230901073305.dist-info/RECORD +0 -69
  66. c2cwsgiutils-5.1.7.dev20230901073305.dist-info/entry_points.txt +0 -25
  67. c2cwsgiutils-5.1.7.dev20230901073305.dist-info/top_level.txt +0 -2
  68. tests/acceptance/__init__.py +0 -0
  69. tests/acceptance/test_utils.py +0 -13
@@ -0,0 +1,7 @@
1
+ {
2
+ "dependencies": {
3
+ "commander": "11.0.0",
4
+ "puppeteer": "21.3.5"
5
+ },
6
+ "type": "module"
7
+ }
@@ -1,7 +1,7 @@
1
1
  import functools
2
2
  import json
3
3
  import logging
4
- from typing import Any, Dict, Optional
4
+ from typing import Any, Optional
5
5
 
6
6
  import requests
7
7
 
@@ -23,7 +23,7 @@ class PrintConnection(connection.Connection):
23
23
  origin: The origin and referrer to include in the requests
24
24
  """
25
25
  super().__init__(base_url=base_url, origin=origin)
26
- self.session.headers["Referer"] = origin
26
+ self.session.headers["Referrer"] = origin
27
27
 
28
28
  def wait_ready(self, timeout: int = 60, app: str = "default") -> None:
29
29
  """Wait the print instance to be ready."""
@@ -32,14 +32,14 @@ class PrintConnection(connection.Connection):
32
32
  def get_capabilities(self, app: str) -> Any:
33
33
  return self.get_json(app + "/capabilities.json", cache_expected=connection.CacheExpected.YES)
34
34
 
35
- def get_example_requests(self, app: str) -> Dict[str, Any]:
35
+ def get_example_requests(self, app: str) -> dict[str, Any]:
36
36
  samples = self.get_json(app + "/exampleRequest.json", cache_expected=connection.CacheExpected.YES)
37
37
  out = {}
38
38
  for name, value in samples.items():
39
39
  out[name] = json.loads(value)
40
40
  return out
41
41
 
42
- def get_pdf(self, app: str, request: Dict[str, Any], timeout: int = 60) -> requests.Response:
42
+ def get_pdf(self, app: str, request: dict[str, Any], timeout: int = 60) -> requests.Response:
43
43
  create_report = self.post_json(app + "/report.pdf", json=request)
44
44
  LOG.debug("create_report=%s", create_report)
45
45
  ref = create_report["ref"]
@@ -0,0 +1,62 @@
1
+ import puppeteer from 'puppeteer';
2
+ import { program } from 'commander';
3
+
4
+ program
5
+ .option('--url <char>', 'The URL')
6
+ .option('--output <char>', 'The output filename')
7
+ .option('--width <int>', 'The page width', 800)
8
+ .option('--height <int>', 'The page height', 600)
9
+ .option('--headers <str>', 'The headers', '{}')
10
+ // see: https://pptr.dev/api/puppeteer.page.emulatemediafeatures
11
+ .option('--media <str>', 'The media feature, see Page.emulateMediaFeatures', '[]');
12
+
13
+ program.parse();
14
+
15
+ const options = program.opts();
16
+
17
+ (async () => {
18
+ const browser = await puppeteer.launch({
19
+ headless: 'new',
20
+ args: ['--no-sandbox', '--disable-web-security'],
21
+ });
22
+ const page = await browser.newPage();
23
+ page.setDefaultNavigationTimeout(60000);
24
+ await page.setExtraHTTPHeaders(JSON.parse(options.headers));
25
+ await page.emulateMediaFeatures(JSON.parse(options.media));
26
+
27
+ page.on('console', async (msg) => {
28
+ const msgArgs = msg.args();
29
+ for (let i = 0; i < msgArgs.length; ++i) {
30
+ console.log(await msgArgs[i].jsonValue());
31
+ }
32
+ });
33
+ page.on('error', (err) => {
34
+ console.log('error', err);
35
+ });
36
+ page.on('pageerror', (err) => {
37
+ console.log('pageerror', err);
38
+ });
39
+ page.on('requestfailed', (request) => {
40
+ console.log('requestfailed on URL:', request.url());
41
+ console.log(request.failure());
42
+ const response = request.response();
43
+ if (response !== null) {
44
+ console.log(response);
45
+ console.log(response.status());
46
+ console.log(response.statusText());
47
+ console.log(response.text());
48
+ }
49
+ });
50
+
51
+ await page.goto(options.url, { timeout: 60000 });
52
+
53
+ await page.setViewport({
54
+ width: parseInt(options.width),
55
+ height: parseInt(options.height),
56
+ });
57
+ await page.screenshot({
58
+ path: options.output,
59
+ clip: { x: 0, y: 0, width: parseInt(options.width), height: parseInt(options.height) },
60
+ });
61
+ await browser.close();
62
+ })();
@@ -1,33 +1,22 @@
1
1
  import logging
2
- import os
3
2
  import time
4
- from typing import Any, Callable, List, Tuple
3
+ from typing import Any, Callable
5
4
 
6
- import boltons.iterutils
7
- import netifaces
8
5
  import pytest
9
6
  import requests
10
7
 
11
- LOG = logging.getLogger(__name__)
8
+ _LOG = logging.getLogger(__name__)
9
+ _DEFAULT_TIMEOUT = 60
12
10
 
13
11
 
14
- def in_docker() -> bool:
15
- """Is in Docker mode."""
16
- return os.environ.get("DOCKER_RUN") != "0"
17
-
18
-
19
- DOCKER_GATEWAY = netifaces.gateways()[netifaces.AF_INET][0][0] if in_docker() else "localhost"
20
- DEFAULT_TIMEOUT = 60
21
-
22
-
23
- def wait_url(url: str, timeout: float = DEFAULT_TIMEOUT) -> None:
12
+ def wait_url(url: str, timeout: float = _DEFAULT_TIMEOUT) -> None:
24
13
  """Wait the the URL is available without any error."""
25
14
 
26
15
  def what() -> bool:
27
- LOG.info("Trying to connect to %s... ", url)
16
+ _LOG.info("Trying to connect to %s... ", url)
28
17
  r = requests.get(url, timeout=timeout)
29
18
  if r.status_code == 200:
30
- LOG.info("%s service started", url)
19
+ _LOG.info("%s service started", url)
31
20
  return True
32
21
  else:
33
22
  return False
@@ -35,7 +24,7 @@ def wait_url(url: str, timeout: float = DEFAULT_TIMEOUT) -> None:
35
24
  retry_timeout(what, timeout=timeout)
36
25
 
37
26
 
38
- def retry_timeout(what: Callable[[], Any], timeout: float = DEFAULT_TIMEOUT, interval: float = 0.5) -> Any:
27
+ def retry_timeout(what: Callable[[], Any], timeout: float = _DEFAULT_TIMEOUT, interval: float = 0.5) -> Any:
39
28
  """
40
29
  Retry the function until the timeout.
41
30
 
@@ -45,7 +34,8 @@ def retry_timeout(what: Callable[[], Any], timeout: float = DEFAULT_TIMEOUT, int
45
34
  timeout: the timeout to get a success
46
35
  interval: the interval between try
47
36
  """
48
- timeout = time.monotonic() + timeout
37
+
38
+ timeout = time.perf_counter() + timeout
49
39
  while True:
50
40
  error = ""
51
41
  try:
@@ -56,8 +46,8 @@ def retry_timeout(what: Callable[[], Any], timeout: float = DEFAULT_TIMEOUT, int
56
46
  raise
57
47
  except Exception as e: # pylint: disable=broad-except
58
48
  error = str(e)
59
- LOG.info(" Failed: %s", e)
60
- if time.monotonic() > timeout:
49
+ _LOG.info(" Failed: %s", e)
50
+ if time.perf_counter() > timeout:
61
51
  assert False, "Timeout: " + error
62
52
  time.sleep(interval)
63
53
 
@@ -68,10 +58,12 @@ def approx(struct: Any, **kwargs: Any) -> Any:
68
58
 
69
59
  See pytest.approx
70
60
  """
61
+ import boltons.iterutils
62
+
71
63
  if isinstance(struct, float):
72
64
  return pytest.approx(struct, **kwargs)
73
65
 
74
- def visit(_path: List[str], key: Any, value: Any) -> Tuple[Any, Any]:
66
+ def visit(_path: list[str], key: Any, value: Any) -> tuple[Any, Any]:
75
67
  if isinstance(value, float):
76
68
  value = pytest.approx(value, **kwargs)
77
69
  return key, value
c2cwsgiutils/auth.py CHANGED
@@ -1,7 +1,8 @@
1
1
  import hashlib
2
2
  import logging
3
+ from collections.abc import Mapping
3
4
  from enum import Enum
4
- from typing import Any, Mapping, Optional, Tuple, TypedDict, cast
5
+ from typing import Any, Optional, TypedDict, cast
5
6
 
6
7
  import jwt
7
8
  import pyramid.request
@@ -98,8 +99,7 @@ def _is_auth_secret(request: pyramid.request.Request) -> bool:
98
99
  return False
99
100
 
100
101
 
101
- def _is_auth_user_github(request: pyramid.request.Request) -> Tuple[bool, UserDetails]:
102
-
102
+ def _is_auth_user_github(request: pyramid.request.Request) -> tuple[bool, UserDetails]:
103
103
  settings = request.registry.settings
104
104
  cookie = request.cookies.get(
105
105
  env_or_settings(
@@ -129,7 +129,7 @@ def _is_auth_user_github(request: pyramid.request.Request) -> Tuple[bool, UserDe
129
129
  return False, {}
130
130
 
131
131
 
132
- def is_auth_user(request: pyramid.request.Request) -> Tuple[bool, UserDetails]:
132
+ def is_auth_user(request: pyramid.request.Request) -> tuple[bool, UserDetails]:
133
133
  """
134
134
  Check if the client is authenticated.
135
135
 
@@ -2,7 +2,7 @@
2
2
  import functools
3
3
  import logging
4
4
  import warnings
5
- from typing import Any, Callable, Dict, List, Optional, TypeVar
5
+ from typing import Any, Callable, Optional, TypeVar
6
6
 
7
7
  import pyramid.config
8
8
 
@@ -36,11 +36,12 @@ def includeme(config: Optional[pyramid.config.Configurator] = None) -> None:
36
36
  if _broadcaster is None:
37
37
  if master is not None and slave is not None:
38
38
  _broadcaster = redis.RedisBroadcaster(broadcast_prefix, master, slave)
39
+ LOG.info("Broadcast service setup using Redis implementation")
39
40
  else:
40
41
  _broadcaster = local.LocalBroadcaster()
41
42
  LOG.info("Broadcast service setup using local implementation")
42
43
  elif isinstance(_broadcaster, local.LocalBroadcaster) and master is not None and slave is not None:
43
- LOG.info("Switching from a local broadcaster to a redis broadcaster")
44
+ LOG.info("Switching from a local broadcaster to a Redis broadcaster")
44
45
  prev_broadcaster = _broadcaster
45
46
  _broadcaster = redis.RedisBroadcaster(broadcast_prefix, master, slave)
46
47
  _broadcaster.copy_local_subscriptions(prev_broadcaster)
@@ -55,6 +56,13 @@ def _get(need_init: bool = False) -> interface.BaseBroadcaster:
55
56
  return _broadcaster
56
57
 
57
58
 
59
+ def cleanup() -> None:
60
+ """Cleanup the broadcaster to force to reinitialize it."""
61
+
62
+ global _broadcaster
63
+ _broadcaster = None
64
+
65
+
58
66
  def subscribe(channel: str, callback: Callable[..., Any]) -> None:
59
67
  """
60
68
  Subscribe to a broadcast channel with the given callback.
@@ -73,8 +81,8 @@ def unsubscribe(channel: str) -> None:
73
81
 
74
82
 
75
83
  def broadcast(
76
- channel: str, params: Optional[Dict[str, Any]] = None, expect_answers: bool = False, timeout: float = 10
77
- ) -> Optional[List[Any]]:
84
+ channel: str, params: Optional[dict[str, Any]] = None, expect_answers: bool = False, timeout: float = 10
85
+ ) -> Optional[list[Any]]:
78
86
  """
79
87
  Broadcast a message to the given channel.
80
88
 
@@ -92,16 +100,16 @@ _DECORATOR_RETURN = TypeVar("_DECORATOR_RETURN")
92
100
 
93
101
  def decorator(
94
102
  channel: Optional[str] = None, expect_answers: bool = False, timeout: float = 10
95
- ) -> Callable[[Callable[..., _DECORATOR_RETURN]], Callable[..., Optional[List[_DECORATOR_RETURN]]]]:
103
+ ) -> Callable[[Callable[..., _DECORATOR_RETURN]], Callable[..., Optional[list[_DECORATOR_RETURN]]]]:
96
104
  """
97
105
  Decorate function will be called through the broadcast functionality.
98
106
 
99
107
  If expect_answers is set to True, the returned value will be a list of all the answers.
100
108
  """
101
109
 
102
- def impl(func: Callable[..., _DECORATOR_RETURN]) -> Callable[..., Optional[List[_DECORATOR_RETURN]]]:
110
+ def impl(func: Callable[..., _DECORATOR_RETURN]) -> Callable[..., Optional[list[_DECORATOR_RETURN]]]:
103
111
  @functools.wraps(func)
104
- def wrapper(**kwargs: Any) -> Optional[List[_DECORATOR_RETURN]]:
112
+ def wrapper(**kwargs: Any) -> Optional[list[_DECORATOR_RETURN]]:
105
113
  return broadcast(_channel, params=kwargs, expect_answers=expect_answers, timeout=timeout)
106
114
 
107
115
  if channel is None:
@@ -1,5 +1,6 @@
1
1
  from abc import abstractmethod
2
- from typing import Any, Callable, List, Mapping, Optional
2
+ from collections.abc import Mapping
3
+ from typing import Any, Callable, Optional
3
4
 
4
5
 
5
6
  class BaseBroadcaster:
@@ -16,5 +17,5 @@ class BaseBroadcaster:
16
17
  @abstractmethod
17
18
  def broadcast(
18
19
  self, channel: str, params: Mapping[str, Any], expect_answers: bool, timeout: float
19
- ) -> Optional[List[Any]]:
20
+ ) -> Optional[list[Any]]:
20
21
  pass # pragma: no cover
@@ -1,4 +1,5 @@
1
- from typing import Any, Callable, List, Mapping, MutableMapping, Optional
1
+ from collections.abc import Mapping, MutableMapping
2
+ from typing import Any, Callable, Optional
2
3
 
3
4
  # noinspection PyProtectedMember
4
5
  from c2cwsgiutils.broadcast import interface, utils
@@ -18,7 +19,7 @@ class LocalBroadcaster(interface.BaseBroadcaster):
18
19
 
19
20
  def broadcast(
20
21
  self, channel: str, params: Mapping[str, Any], expect_answers: bool, timeout: float
21
- ) -> Optional[List[Any]]:
22
+ ) -> Optional[list[Any]]:
22
23
  subscriber = self._subscribers.get(channel, None)
23
24
  answers = [utils.add_host_info(subscriber(**params))] if subscriber is not None else []
24
25
  return answers if expect_answers else None
@@ -4,9 +4,10 @@ import random
4
4
  import string
5
5
  import threading
6
6
  import time
7
- from typing import Any, Callable, List, Mapping, Optional
7
+ from collections.abc import Mapping
8
+ from typing import Any, Callable, Optional
8
9
 
9
- import redis # pylint: disable=unused-import
10
+ import redis
10
11
 
11
12
  from c2cwsgiutils.broadcast import interface, local, utils
12
13
 
@@ -46,7 +47,7 @@ class RedisBroadcaster(interface.BaseBroadcaster):
46
47
  response = callback(**data["params"])
47
48
  except Exception as e: # pragma: no cover # pylint: disable=broad-except
48
49
  LOG.error("Failed handling a broadcast message", exc_info=True)
49
- response = dict(status=500, message=str(e))
50
+ response = {"status": 500, "message": str(e)}
50
51
  answer_channel = data.get("answer_channel")
51
52
  if answer_channel is not None:
52
53
  LOG.debug("Sending broadcast answer on %s", answer_channel)
@@ -63,7 +64,7 @@ class RedisBroadcaster(interface.BaseBroadcaster):
63
64
 
64
65
  def broadcast(
65
66
  self, channel: str, params: Mapping[str, Any], expect_answers: bool, timeout: float
66
- ) -> Optional[List[Any]]:
67
+ ) -> Optional[list[Any]]:
67
68
  if expect_answers:
68
69
  return self._broadcast_with_answer(channel, params, timeout)
69
70
  else:
@@ -72,7 +73,7 @@ class RedisBroadcaster(interface.BaseBroadcaster):
72
73
 
73
74
  def _broadcast_with_answer(
74
75
  self, channel: str, params: Optional[Mapping[str, Any]], timeout: float
75
- ) -> List[Any]:
76
+ ) -> list[Any]:
76
77
  cond = threading.Condition()
77
78
  answers = []
78
79
  assert self._thread.is_alive()
@@ -93,10 +94,10 @@ class RedisBroadcaster(interface.BaseBroadcaster):
93
94
  try:
94
95
  nb_received = self._broadcast(channel, message)
95
96
 
96
- timeout_time = time.monotonic() + timeout
97
+ timeout_time = time.perf_counter() + timeout
97
98
  with cond:
98
99
  while len(answers) < nb_received:
99
- to_wait = timeout_time - time.monotonic()
100
+ to_wait = timeout_time - time.perf_counter()
100
101
  if to_wait <= 0.0: # pragma: no cover
101
102
  LOG.warning(
102
103
  "timeout waiting for %d/%d answers on %s",
@@ -1,5 +1,5 @@
1
1
  import re
2
- from typing import Any, Callable, Dict
2
+ from typing import Any, Callable
3
3
 
4
4
  SEP_RE = re.compile(r", *")
5
5
 
@@ -12,10 +12,10 @@ class Filter:
12
12
  Concerned headers: Forwarded and the X_Forwarded_* Headers.
13
13
  """
14
14
 
15
- def __init__(self, application: Callable[[Dict[str, str], Any], Any]):
15
+ def __init__(self, application: Callable[[dict[str, str], Any], Any]):
16
16
  self._application = application
17
17
 
18
- def __call__(self, environ: Dict[str, str], start_response: Any) -> Any:
18
+ def __call__(self, environ: dict[str, str], start_response: Any) -> Any:
19
19
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded
20
20
  if "HTTP_FORWARDED" in environ:
21
21
  _handle_forwarded(environ)
@@ -25,7 +25,7 @@ class Filter:
25
25
  return self._application(environ, start_response)
26
26
 
27
27
 
28
- def _handle_others(environ: Dict[str, str]) -> None:
28
+ def _handle_others(environ: dict[str, str]) -> None:
29
29
  # The rest is taken from paste.deploy.config.PrefixMiddleware
30
30
  if "HTTP_X_FORWARDED_SERVER" in environ:
31
31
  environ["HTTP_ORIGINAL_X_FORWARDED_SERVER"] = environ["HTTP_X_FORWARDED_SERVER"]
@@ -45,7 +45,7 @@ def _handle_others(environ: Dict[str, str]) -> None:
45
45
  environ["wsgi.url_scheme"] = environ.pop("HTTP_X_FORWARDED_PROTO")
46
46
 
47
47
 
48
- def _handle_forwarded(environ: Dict[str, str]) -> None:
48
+ def _handle_forwarded(environ: dict[str, str]) -> None:
49
49
  environ["HTTP_ORIGINAL_FORWARDED"] = environ["HTTP_FORWARDED"]
50
50
  for header in (
51
51
  "X_FORWARDED_SERVER",
@@ -1,6 +1,7 @@
1
1
  """Private utilities."""
2
2
  import os
3
- from typing import Any, Callable, Mapping, Optional, cast
3
+ from collections.abc import Mapping
4
+ from typing import Any, Callable, Optional, cast
4
5
 
5
6
  import pyramid.config
6
7
 
@@ -9,13 +9,13 @@ LOG = logging.getLogger(__name__)
9
9
 
10
10
 
11
11
  def init() -> None:
12
- """Initialise the code coverage, for backward compatibility."""
12
+ """Initialize the code coverage, for backward compatibility."""
13
13
  warnings.warn("init function is deprecated; use includeme instead")
14
14
  includeme()
15
15
 
16
16
 
17
17
  def includeme(config: Optional[pyramid.config.Configurator] = None) -> None:
18
- """Initialise the code coverage."""
18
+ """Initialize the code coverage."""
19
19
  if os.environ.get("COVERAGE", "0") != "1":
20
20
  return
21
21
  import coverage