c2cwsgiutils 6.1.0.dev105__tar.gz → 6.1.7.dev4__tar.gz
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-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/LICENSE +1 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/PKG-INFO +18 -6
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/README.md +15 -3
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/__init__.py +14 -11
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/acceptance/__init__.py +2 -3
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/acceptance/connection.py +1 -2
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/acceptance/image.py +17 -11
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/acceptance/package-lock.json +306 -213
- c2cwsgiutils-6.1.7.dev4/c2cwsgiutils/acceptance/package.json +7 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/acceptance/print.py +7 -3
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/acceptance/utils.py +1 -3
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/auth.py +27 -25
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/broadcast/__init__.py +15 -16
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/broadcast/interface.py +3 -3
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/broadcast/local.py +1 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/broadcast/redis.py +13 -12
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/client_info.py +19 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/coverage_setup.py +4 -3
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/db.py +35 -41
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/db_maintenance_view.py +13 -13
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/debug/__init__.py +2 -2
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/debug/_listeners.py +2 -7
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/debug/_views.py +20 -12
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/debug/utils.py +9 -9
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/errors.py +13 -15
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/health_check.py +24 -30
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/index.py +34 -13
- c2cwsgiutils-6.1.7.dev4/c2cwsgiutils/loader.py +40 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/logging_view.py +12 -12
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/models_graph.py +0 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/pretty_json.py +0 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/prometheus.py +1 -7
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/pyramid.py +0 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/pyramid_logging.py +1 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/redis_stats.py +9 -9
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/redis_utils.py +19 -18
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/request_tracking/__init__.py +13 -13
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/request_tracking/_sql.py +0 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/scripts/genversion.py +5 -5
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/scripts/stats_db.py +19 -17
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/scripts/test_print.py +5 -5
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sentry.py +55 -20
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/services.py +2 -2
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/setup_process.py +0 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sql_profiler/__init__.py +5 -6
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sql_profiler/_impl.py +18 -17
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sqlalchemylogger/README.md +30 -13
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sqlalchemylogger/handlers.py +12 -11
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/stats_pyramid/__init__.py +1 -5
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/stats_pyramid/_db_spy.py +2 -2
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/stats_pyramid/_pyramid_spy.py +12 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/templates/index.html.mako +4 -1
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/version.py +11 -5
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/pyproject.toml +36 -37
- c2cwsgiutils-6.1.0.dev105/c2cwsgiutils/acceptance/package.json +0 -7
- c2cwsgiutils-6.1.0.dev105/c2cwsgiutils/loader.py +0 -21
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/acceptance/screenshot.js +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/broadcast/utils.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/config_utils.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/profiler.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/py.typed +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/scripts/__init__.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sqlalchemylogger/__init__.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sqlalchemylogger/_filters.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sqlalchemylogger/_models.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/sqlalchemylogger/examples/example.py +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/static/favicon-16x16.png +0 -0
- {c2cwsgiutils-6.1.0.dev105 → c2cwsgiutils-6.1.7.dev4}/c2cwsgiutils/static/favicon-32x32.png +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: c2cwsgiutils
|
3
|
-
Version: 6.1.
|
3
|
+
Version: 6.1.7.dev4
|
4
4
|
Summary: Common utilities for Camptocamp WSGI applications
|
5
5
|
Home-page: https://github.com/camptocamp/c2cwsgiutils
|
6
6
|
License: BSD-2-Clause
|
7
7
|
Keywords: geo,gis,sqlalchemy,orm,wsgi
|
8
8
|
Author: Camptocamp
|
9
9
|
Author-email: info@camptocamp.com
|
10
|
-
Requires-Python: >=3.
|
10
|
+
Requires-Python: >=3.10
|
11
11
|
Classifier: Development Status :: 5 - Production/Stable
|
12
12
|
Classifier: Environment :: Plugins
|
13
13
|
Classifier: Framework :: Pyramid
|
@@ -17,10 +17,10 @@ Classifier: License :: OSI Approved :: BSD License
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
18
18
|
Classifier: Programming Language :: Python
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
20
|
-
Classifier: Programming Language :: Python :: 3.9
|
21
20
|
Classifier: Programming Language :: Python :: 3.10
|
22
21
|
Classifier: Programming Language :: Python :: 3.11
|
23
22
|
Classifier: Programming Language :: Python :: 3.12
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
24
24
|
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
25
25
|
Classifier: Typing :: Typed
|
26
26
|
Provides-Extra: alembic
|
@@ -64,7 +64,7 @@ Description-Content-Type: text/markdown
|
|
64
64
|
|
65
65
|
# Camptocamp WSGI utilities
|
66
66
|
|
67
|
-
This is a Python 3 library
|
67
|
+
This is a Python 3 library providing common tools for Camptocamp WSGI
|
68
68
|
applications:
|
69
69
|
|
70
70
|
- Provide prometheus metrics
|
@@ -725,11 +725,16 @@ A few other environment variables can be used to tune the info sent with each re
|
|
725
725
|
- `SENTRY_CLIENT_IGNORE_EXCEPTIONS`: list (coma separated) of exceptions to ignore (defaults to SystemExit)
|
726
726
|
- `SENTRY_TAG_...`: to add other custom tags
|
727
727
|
- `SENTRY_LEVEL`: starting from what logging level to send events to Sentry (defaults to ERROR)
|
728
|
-
- `SENTRY_TRACES_SAMPLE_RATE`: The percentage of events to send to sentry in order to compute the performance. Value between 0 and 1
|
728
|
+
- `SENTRY_TRACES_SAMPLE_RATE`: The percentage of events to send to sentry in order to compute the performance. Value between 0 and 1 (default is 0)
|
729
|
+
- `SENTRY_INTEGRATION_LOGGING`: If set to 0, the Sentry integration will not log anything (default is 1)
|
730
|
+
- `SENTRY_INTEGRATION_PYRAMID`: If set to 0, the Sentry integration with Pyramid will not be enabled (default is 1)
|
731
|
+
- `SENTRY_INTEGRATION_SQLALCHEMY`: If set to 0, the Sentry integration with SQLAlchemy will not be enabled (default is 1)
|
732
|
+
- `SENTRY_INTEGRATION_REDIS`: If set to 0, the Sentry integration with Redis will not be enabled (default is 1)
|
733
|
+
- `SENTRY_INTEGRATION_ASYNCIO`: If set to 0, the Sentry integration with asyncio will not be enabled (default is 1)
|
729
734
|
|
730
735
|
# Developer info
|
731
736
|
|
732
|
-
You will need `docker` (>=1.12.0), `docker
|
737
|
+
You will need `docker` (>=1.12.0), `docker compose` and
|
733
738
|
`make` installed on the machine to play with this project.
|
734
739
|
Check available versions of `docker-engine` with
|
735
740
|
`apt-get policy docker-engine` and eventually force install the
|
@@ -758,6 +763,13 @@ To make a release:
|
|
758
763
|
- Add the new branch name in the `.github/workflows/rebuild.yaml` and
|
759
764
|
`.github/workflows/audit.yaml` files.
|
760
765
|
|
766
|
+
## Pserve
|
767
|
+
|
768
|
+
Pserve will not set the headers in the environment then if you are behind a reverse proxy, you will have
|
769
|
+
wrong values in client information, you can force them by using the environment variables:
|
770
|
+
`C2CWSGIUTILS_FORCE_PROTO`, `C2CWSGIUTILS_FORCE_HOST` `C2CWSGIUTILS_FORCE_SERVER_NAME` and
|
771
|
+
`C2CWSGIUTILS_FORCE_REMOTE_ADDR`.
|
772
|
+
|
761
773
|
## Testing
|
762
774
|
|
763
775
|
### Screenshots
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Camptocamp WSGI utilities
|
2
2
|
|
3
|
-
This is a Python 3 library
|
3
|
+
This is a Python 3 library providing common tools for Camptocamp WSGI
|
4
4
|
applications:
|
5
5
|
|
6
6
|
- Provide prometheus metrics
|
@@ -661,11 +661,16 @@ A few other environment variables can be used to tune the info sent with each re
|
|
661
661
|
- `SENTRY_CLIENT_IGNORE_EXCEPTIONS`: list (coma separated) of exceptions to ignore (defaults to SystemExit)
|
662
662
|
- `SENTRY_TAG_...`: to add other custom tags
|
663
663
|
- `SENTRY_LEVEL`: starting from what logging level to send events to Sentry (defaults to ERROR)
|
664
|
-
- `SENTRY_TRACES_SAMPLE_RATE`: The percentage of events to send to sentry in order to compute the performance. Value between 0 and 1
|
664
|
+
- `SENTRY_TRACES_SAMPLE_RATE`: The percentage of events to send to sentry in order to compute the performance. Value between 0 and 1 (default is 0)
|
665
|
+
- `SENTRY_INTEGRATION_LOGGING`: If set to 0, the Sentry integration will not log anything (default is 1)
|
666
|
+
- `SENTRY_INTEGRATION_PYRAMID`: If set to 0, the Sentry integration with Pyramid will not be enabled (default is 1)
|
667
|
+
- `SENTRY_INTEGRATION_SQLALCHEMY`: If set to 0, the Sentry integration with SQLAlchemy will not be enabled (default is 1)
|
668
|
+
- `SENTRY_INTEGRATION_REDIS`: If set to 0, the Sentry integration with Redis will not be enabled (default is 1)
|
669
|
+
- `SENTRY_INTEGRATION_ASYNCIO`: If set to 0, the Sentry integration with asyncio will not be enabled (default is 1)
|
665
670
|
|
666
671
|
# Developer info
|
667
672
|
|
668
|
-
You will need `docker` (>=1.12.0), `docker
|
673
|
+
You will need `docker` (>=1.12.0), `docker compose` and
|
669
674
|
`make` installed on the machine to play with this project.
|
670
675
|
Check available versions of `docker-engine` with
|
671
676
|
`apt-get policy docker-engine` and eventually force install the
|
@@ -694,6 +699,13 @@ To make a release:
|
|
694
699
|
- Add the new branch name in the `.github/workflows/rebuild.yaml` and
|
695
700
|
`.github/workflows/audit.yaml` files.
|
696
701
|
|
702
|
+
## Pserve
|
703
|
+
|
704
|
+
Pserve will not set the headers in the environment then if you are behind a reverse proxy, you will have
|
705
|
+
wrong values in client information, you can force them by using the environment variables:
|
706
|
+
`C2CWSGIUTILS_FORCE_PROTO`, `C2CWSGIUTILS_FORCE_HOST` `C2CWSGIUTILS_FORCE_SERVER_NAME` and
|
707
|
+
`C2CWSGIUTILS_FORCE_REMOTE_ADDR`.
|
708
|
+
|
697
709
|
## Testing
|
698
710
|
|
699
711
|
### Screenshots
|
@@ -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
|
-
|
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
|
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
|
-
|
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
|
-
|
39
|
-
|
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
|
-
|
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
|
-
|
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] =
|
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] =
|
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 =
|
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
|
-
|
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:
|