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.
- c2cwsgiutils/__init__.py +13 -13
- c2cwsgiutils/acceptance/connection.py +5 -2
- c2cwsgiutils/acceptance/image.py +98 -4
- c2cwsgiutils/acceptance/package-lock.json +1933 -0
- c2cwsgiutils/acceptance/package.json +7 -0
- c2cwsgiutils/acceptance/print.py +4 -4
- c2cwsgiutils/acceptance/screenshot.js +62 -0
- c2cwsgiutils/acceptance/utils.py +14 -22
- c2cwsgiutils/auth.py +4 -4
- c2cwsgiutils/broadcast/__init__.py +15 -7
- c2cwsgiutils/broadcast/interface.py +3 -2
- c2cwsgiutils/broadcast/local.py +3 -2
- c2cwsgiutils/broadcast/redis.py +8 -7
- c2cwsgiutils/client_info.py +5 -5
- c2cwsgiutils/config_utils.py +2 -1
- c2cwsgiutils/coverage_setup.py +2 -2
- c2cwsgiutils/db.py +58 -37
- c2cwsgiutils/db_maintenance_view.py +2 -1
- c2cwsgiutils/debug/_listeners.py +10 -9
- c2cwsgiutils/debug/_views.py +12 -11
- c2cwsgiutils/debug/utils.py +5 -5
- c2cwsgiutils/errors.py +7 -6
- c2cwsgiutils/health_check.py +96 -85
- c2cwsgiutils/index.py +90 -105
- c2cwsgiutils/loader.py +3 -3
- c2cwsgiutils/logging_view.py +3 -2
- c2cwsgiutils/models_graph.py +8 -6
- c2cwsgiutils/prometheus.py +175 -57
- c2cwsgiutils/pyramid.py +4 -2
- c2cwsgiutils/pyramid_logging.py +2 -1
- c2cwsgiutils/redis_stats.py +13 -11
- c2cwsgiutils/redis_utils.py +15 -14
- c2cwsgiutils/request_tracking/__init__.py +36 -30
- c2cwsgiutils/request_tracking/_sql.py +3 -1
- c2cwsgiutils/scripts/genversion.py +4 -4
- c2cwsgiutils/scripts/stats_db.py +130 -68
- c2cwsgiutils/scripts/test_print.py +1 -1
- c2cwsgiutils/sentry.py +2 -1
- c2cwsgiutils/setup_process.py +13 -17
- c2cwsgiutils/sql_profiler/_impl.py +12 -5
- c2cwsgiutils/sqlalchemylogger/README.md +48 -0
- c2cwsgiutils/sqlalchemylogger/_models.py +7 -4
- c2cwsgiutils/sqlalchemylogger/examples/example.py +15 -0
- c2cwsgiutils/sqlalchemylogger/handlers.py +11 -8
- c2cwsgiutils/static/favicon-16x16.png +0 -0
- c2cwsgiutils/static/favicon-32x32.png +0 -0
- c2cwsgiutils/stats_pyramid/__init__.py +7 -11
- c2cwsgiutils/stats_pyramid/_db_spy.py +14 -11
- c2cwsgiutils/stats_pyramid/_pyramid_spy.py +29 -20
- c2cwsgiutils/templates/index.html.mako +50 -0
- c2cwsgiutils/version.py +49 -16
- c2cwsgiutils-5.2.1.dev197.dist-info/LICENSE +22 -0
- {c2cwsgiutils-5.1.7.dev20230901073305.dist-info → c2cwsgiutils-5.2.1.dev197.dist-info}/METADATA +187 -135
- c2cwsgiutils-5.2.1.dev197.dist-info/RECORD +67 -0
- {c2cwsgiutils-5.1.7.dev20230901073305.dist-info → c2cwsgiutils-5.2.1.dev197.dist-info}/WHEEL +1 -2
- c2cwsgiutils-5.2.1.dev197.dist-info/entry_points.txt +21 -0
- c2cwsgiutils/acceptance/composition.py +0 -129
- c2cwsgiutils/metrics.py +0 -110
- c2cwsgiutils/scripts/check_es.py +0 -130
- c2cwsgiutils/scripts/coverage_report.py +0 -36
- c2cwsgiutils/stats.py +0 -355
- c2cwsgiutils/stats_pyramid/_views.py +0 -16
- c2cwsgiutils-5.1.7.dev20230901073305.data/scripts/c2cwsgiutils-run +0 -32
- c2cwsgiutils-5.1.7.dev20230901073305.dist-info/LICENSE.txt +0 -28
- c2cwsgiutils-5.1.7.dev20230901073305.dist-info/RECORD +0 -69
- c2cwsgiutils-5.1.7.dev20230901073305.dist-info/entry_points.txt +0 -25
- c2cwsgiutils-5.1.7.dev20230901073305.dist-info/top_level.txt +0 -2
- tests/acceptance/__init__.py +0 -0
- tests/acceptance/test_utils.py +0 -13
c2cwsgiutils/acceptance/print.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import functools
|
2
2
|
import json
|
3
3
|
import logging
|
4
|
-
from typing import Any,
|
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["
|
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) ->
|
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:
|
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
|
+
})();
|
c2cwsgiutils/acceptance/utils.py
CHANGED
@@ -1,33 +1,22 @@
|
|
1
1
|
import logging
|
2
|
-
import os
|
3
2
|
import time
|
4
|
-
from typing import Any, Callable
|
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
|
-
|
8
|
+
_LOG = logging.getLogger(__name__)
|
9
|
+
_DEFAULT_TIMEOUT = 60
|
12
10
|
|
13
11
|
|
14
|
-
def
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
60
|
-
if time.
|
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:
|
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,
|
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) ->
|
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) ->
|
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,
|
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
|
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[
|
77
|
-
) -> Optional[
|
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[
|
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[
|
110
|
+
def impl(func: Callable[..., _DECORATOR_RETURN]) -> Callable[..., Optional[list[_DECORATOR_RETURN]]]:
|
103
111
|
@functools.wraps(func)
|
104
|
-
def wrapper(**kwargs: Any) -> Optional[
|
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
|
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[
|
20
|
+
) -> Optional[list[Any]]:
|
20
21
|
pass # pragma: no cover
|
c2cwsgiutils/broadcast/local.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from
|
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[
|
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
|
c2cwsgiutils/broadcast/redis.py
CHANGED
@@ -4,9 +4,10 @@ import random
|
|
4
4
|
import string
|
5
5
|
import threading
|
6
6
|
import time
|
7
|
-
from
|
7
|
+
from collections.abc import Mapping
|
8
|
+
from typing import Any, Callable, Optional
|
8
9
|
|
9
|
-
import redis
|
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 =
|
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[
|
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
|
-
) ->
|
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.
|
97
|
+
timeout_time = time.perf_counter() + timeout
|
97
98
|
with cond:
|
98
99
|
while len(answers) < nb_received:
|
99
|
-
to_wait = timeout_time - time.
|
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",
|
c2cwsgiutils/client_info.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import re
|
2
|
-
from typing import Any, Callable
|
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[[
|
15
|
+
def __init__(self, application: Callable[[dict[str, str], Any], Any]):
|
16
16
|
self._application = application
|
17
17
|
|
18
|
-
def __call__(self, environ:
|
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:
|
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:
|
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",
|
c2cwsgiutils/config_utils.py
CHANGED
c2cwsgiutils/coverage_setup.py
CHANGED
@@ -9,13 +9,13 @@ LOG = logging.getLogger(__name__)
|
|
9
9
|
|
10
10
|
|
11
11
|
def init() -> None:
|
12
|
-
"""
|
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
|
-
"""
|
18
|
+
"""Initialize the code coverage."""
|
19
19
|
if os.environ.get("COVERAGE", "0") != "1":
|
20
20
|
return
|
21
21
|
import coverage
|