plexus-python-common 1.0.22__tar.gz → 1.0.24__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.
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/PKG-INFO +6 -3
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/pyproject.toml +11 -3
- plexus_python_common-1.0.24/src/plexus/common/utils/apiutils.py +31 -0
- plexus_python_common-1.0.24/src/plexus/common/utils/sqlutils.py +9 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/strutils.py +47 -21
- plexus_python_common-1.0.24/src/plexus/common/utils/testutils.py +42 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus_python_common.egg-info/PKG-INFO +6 -3
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus_python_common.egg-info/SOURCES.txt +5 -1
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus_python_common.egg-info/requires.txt +6 -2
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/utils/ormutils_test.py +3 -2
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/utils/strutils_test.py +38 -1
- plexus_python_common-1.0.24/test/plexus_tests/common/utils/testutils_test.py +50 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/.editorconfig +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/.github/workflows/pr.yml +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/.github/workflows/push.yml +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/.gitignore +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/MANIFEST.in +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/README.md +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/VERSION +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/0-dummy +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/1-dummy +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/2-dummy +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.0.0.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.0.0.vol-0.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.0.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.1.1.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.1.1.vol-1.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.1.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.2.2.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.2.2.vol-2.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.2.jsonl +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.csv.part0 +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.csv.part1 +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.csv.part2 +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.txt +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/setup.cfg +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/setup.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/__init__.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMFile.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMNode.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMTags.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMWay.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/__init__.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/config.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/pose.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/proj.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/__init__.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/bagutils.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/datautils.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/jsonutils.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/ormutils.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/s3utils.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/shutils.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus_python_common.egg-info/top_level.txt +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/__init__.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/pose_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/proj_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/utils/datautils_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/utils/jsonutils_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/utils/s3utils_test.py +0 -0
- {plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/utils/shutils_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plexus-python-common
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.24
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Python :: 3.12
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.13
|
|
@@ -16,12 +16,15 @@ Requires-Dist: pyparsing>=3.2
|
|
|
16
16
|
Requires-Dist: pyproj>=3.6
|
|
17
17
|
Requires-Dist: pyquaternion>=0.9
|
|
18
18
|
Requires-Dist: sqlalchemy>=2.0
|
|
19
|
-
Requires-Dist: sqlmodel
|
|
20
19
|
Requires-Dist: rich>=13.9
|
|
20
|
+
Requires-Dist: textcase>=0.4
|
|
21
21
|
Requires-Dist: ujson>=5.9
|
|
22
22
|
Requires-Dist: iker-python-common[all]>=1.0
|
|
23
23
|
Provides-Extra: all
|
|
24
|
-
Requires-Dist: plexus-python-common; extra == "all"
|
|
24
|
+
Requires-Dist: plexus-python-common[api]; extra == "all"
|
|
25
|
+
Provides-Extra: api
|
|
26
|
+
Requires-Dist: fastapi>=0.119.0; extra == "api"
|
|
27
|
+
Requires-Dist: sqlmodel>=0.0.25; extra == "api"
|
|
25
28
|
Provides-Extra: test
|
|
26
29
|
Requires-Dist: ddt>=1.7; extra == "test"
|
|
27
30
|
Requires-Dist: moto[all,ec2,s3]>=5.1; extra == "test"
|
|
@@ -18,11 +18,15 @@ dev = [
|
|
|
18
18
|
"pyproj>=3.6",
|
|
19
19
|
"pyquaternion>=0.9",
|
|
20
20
|
"sqlalchemy>=2.0",
|
|
21
|
-
"sqlmodel",
|
|
22
21
|
"rich>=13.9",
|
|
22
|
+
"textcase>=0.4",
|
|
23
23
|
"ujson>=5.9",
|
|
24
24
|
"iker-python-common[all]>=1.0",
|
|
25
25
|
]
|
|
26
|
+
api = [
|
|
27
|
+
"fastapi>=0.119.0",
|
|
28
|
+
"sqlmodel>=0.0.25",
|
|
29
|
+
]
|
|
26
30
|
test = [
|
|
27
31
|
"ddt>=1.7",
|
|
28
32
|
"moto[ec2,s3,all]>=5.1",
|
|
@@ -53,15 +57,19 @@ dependencies = [
|
|
|
53
57
|
"pyproj>=3.6",
|
|
54
58
|
"pyquaternion>=0.9",
|
|
55
59
|
"sqlalchemy>=2.0",
|
|
56
|
-
"sqlmodel",
|
|
57
60
|
"rich>=13.9",
|
|
61
|
+
"textcase>=0.4",
|
|
58
62
|
"ujson>=5.9",
|
|
59
63
|
"iker-python-common[all]>=1.0",
|
|
60
64
|
]
|
|
61
65
|
|
|
62
66
|
[project.optional-dependencies]
|
|
63
67
|
all = [
|
|
64
|
-
"plexus-python-common",
|
|
68
|
+
"plexus-python-common[api]",
|
|
69
|
+
]
|
|
70
|
+
api = [
|
|
71
|
+
"fastapi>=0.119.0",
|
|
72
|
+
"sqlmodel>=0.0.25",
|
|
65
73
|
]
|
|
66
74
|
test = [
|
|
67
75
|
"ddt>=1.7",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from contextlib import AbstractContextManager
|
|
2
|
+
|
|
3
|
+
import sqlalchemy.orm as sa_orm
|
|
4
|
+
from fastapi import HTTPException
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"managed_db_session",
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DBSessionExceptionManager(AbstractContextManager):
|
|
12
|
+
def __init__(self, db: sa_orm.Session, commit_on_exit: bool):
|
|
13
|
+
self.db = db
|
|
14
|
+
self.commit_on_exit = commit_on_exit
|
|
15
|
+
|
|
16
|
+
def __enter__(self):
|
|
17
|
+
return self
|
|
18
|
+
|
|
19
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
20
|
+
if isinstance(exc_type, HTTPException):
|
|
21
|
+
return False # Propagate HTTPException
|
|
22
|
+
if exc_type is not None:
|
|
23
|
+
self.db.rollback() # Raise a new HTTPException (or any other exception type)
|
|
24
|
+
raise HTTPException(status_code=500, detail=str(exc_value)) from exc_value
|
|
25
|
+
if self.commit_on_exit:
|
|
26
|
+
self.db.commit()
|
|
27
|
+
return True
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def managed_db_session(db: sa_orm.Session, commit_on_exit: bool = True) -> DBSessionExceptionManager:
|
|
31
|
+
return DBSessionExceptionManager(db, commit_on_exit)
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/strutils.py
RENAMED
|
@@ -22,6 +22,8 @@ __all__ = [
|
|
|
22
22
|
"strict_relpath_parser",
|
|
23
23
|
"strict_abspath_pattern",
|
|
24
24
|
"strict_abspath_parser",
|
|
25
|
+
"email_address_pattern",
|
|
26
|
+
"email_address_parser",
|
|
25
27
|
"semver_pattern",
|
|
26
28
|
"semver_parser",
|
|
27
29
|
"colon_tag_pattern",
|
|
@@ -74,16 +76,39 @@ def make_string_parser(element: pp.ParserElement) -> pp.ParserElement:
|
|
|
74
76
|
return pp.Combine(pp.StringStart() + element + pp.StringEnd())
|
|
75
77
|
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
underscore_token: pp.ParserElement = pp.Char("_")
|
|
80
|
+
hyphen_token: pp.ParserElement = pp.Char("-")
|
|
81
|
+
period_token: pp.ParserElement = pp.Char(".")
|
|
82
|
+
colon_token: pp.ParserElement = pp.Char(":")
|
|
83
|
+
slash_token: pp.ParserElement = pp.Char("/")
|
|
84
|
+
plus_token: pp.ParserElement = pp.Char("+")
|
|
85
|
+
|
|
86
|
+
lower_regexp: re.Pattern[str] = re.compile(r"[a-z]")
|
|
87
|
+
upper_regexp: re.Pattern[str] = re.compile(r"[A-Z]")
|
|
88
|
+
digit_regexp: re.Pattern[str] = re.compile(r"[0-9]")
|
|
89
|
+
lower_digit_regexp: re.Pattern[str] = re.compile(r"[a-z0-9]")
|
|
90
|
+
upper_digit_regexp: re.Pattern[str] = re.compile(r"[A-Z0-9]")
|
|
91
|
+
alpha_digit_regexp: re.Pattern[str] = re.compile(r"[a-zA-Z0-9]")
|
|
92
|
+
hex_digit_regexp: re.Pattern[str] = re.compile(r"[a-f0-9]")
|
|
93
|
+
|
|
94
|
+
lowers_regexp: re.Pattern[str] = re.compile(rf"{lower_regexp.pattern}+")
|
|
95
|
+
uppers_regexp: re.Pattern[str] = re.compile(rf"{upper_regexp.pattern}+")
|
|
96
|
+
digits_regexp: re.Pattern[str] = re.compile(rf"{digit_regexp.pattern}+")
|
|
97
|
+
lower_digits_regexp: re.Pattern[str] = re.compile(rf"{lower_digit_regexp.pattern}+")
|
|
98
|
+
upper_digits_regexp: re.Pattern[str] = re.compile(rf"{upper_digit_regexp.pattern}+")
|
|
99
|
+
alpha_digits_regexp: re.Pattern[str] = re.compile(rf"{alpha_digit_regexp.pattern}+")
|
|
100
|
+
hex_digits_regexp: re.Pattern[str] = re.compile(rf"{hex_digit_regexp.pattern}+")
|
|
101
|
+
lower_identifier_regexp: re.Pattern[str] = re.compile(rf"{lower_regexp.pattern}{lower_digit_regexp.pattern}*")
|
|
102
|
+
upper_identifier_regexp: re.Pattern[str] = re.compile(rf"{upper_regexp.pattern}{upper_digit_regexp.pattern}*")
|
|
103
|
+
strict_chars_regexp: re.Pattern[str] = re.compile(rf"({alpha_digit_regexp.pattern}|[._-])+")
|
|
104
|
+
|
|
105
|
+
lower_element: pp.ParserElement = pp.Regex(lower_regexp.pattern)
|
|
106
|
+
upper_element: pp.ParserElement = pp.Regex(upper_regexp.pattern)
|
|
107
|
+
digit_element: pp.ParserElement = pp.Regex(digit_regexp.pattern)
|
|
108
|
+
lower_digit_element: pp.ParserElement = pp.Regex(lower_digit_regexp.pattern)
|
|
109
|
+
upper_digit_element: pp.ParserElement = pp.Regex(upper_digit_regexp.pattern)
|
|
110
|
+
alpha_digit_element: pp.ParserElement = pp.Regex(alpha_digit_regexp.pattern)
|
|
111
|
+
hex_digit_element: pp.ParserElement = pp.Regex(hex_digit_regexp.pattern)
|
|
87
112
|
|
|
88
113
|
lowers_element: pp.ParserElement = pp.Regex(lowers_regexp.pattern)
|
|
89
114
|
uppers_element: pp.ParserElement = pp.Regex(uppers_regexp.pattern)
|
|
@@ -96,24 +121,17 @@ lower_identifier_element: pp.ParserElement = pp.Regex(lower_identifier_regexp.pa
|
|
|
96
121
|
upper_identifier_element: pp.ParserElement = pp.Regex(upper_identifier_regexp.pattern)
|
|
97
122
|
strict_chars_element: pp.ParserElement = pp.Regex(strict_chars_regexp.pattern)
|
|
98
123
|
|
|
99
|
-
underscore_token: pp.ParserElement = pp.Char("_")
|
|
100
|
-
hyphen_token: pp.ParserElement = pp.Char("-")
|
|
101
|
-
period_token: pp.ParserElement = pp.Char(".")
|
|
102
|
-
colon_token: pp.ParserElement = pp.Char(":")
|
|
103
|
-
slash_token: pp.ParserElement = pp.Char("/")
|
|
104
|
-
plus_token: pp.ParserElement = pp.Char("+")
|
|
105
|
-
|
|
106
124
|
basic_datetime_regexp: re.Pattern[str] = re.compile(r"\d{8}T\d{6}")
|
|
107
125
|
extended_datetime_regexp: re.Pattern[str] = re.compile(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}")
|
|
108
126
|
|
|
109
127
|
basic_datetime_element: pp.ParserElement = pp.Regex(basic_datetime_regexp.pattern)
|
|
110
128
|
extended_datetime_element: pp.ParserElement = pp.Regex(extended_datetime_regexp.pattern)
|
|
111
129
|
|
|
112
|
-
|
|
113
|
-
|
|
130
|
+
positive_number_regexp: re.Pattern[str] = re.compile(rf"[1-9]{digit_regexp.pattern}*")
|
|
131
|
+
number_regexp: re.Pattern[str] = re.compile(rf"0|({positive_number_regexp.pattern})")
|
|
114
132
|
|
|
115
|
-
number_element: pp.ParserElement = pp.Regex(number_regexp.pattern)
|
|
116
133
|
positive_number_element: pp.ParserElement = pp.Regex(positive_number_regexp.pattern)
|
|
134
|
+
number_element: pp.ParserElement = pp.Regex(number_regexp.pattern)
|
|
117
135
|
|
|
118
136
|
snake_case_regexp: re.Pattern[str] = re.compile(
|
|
119
137
|
rf"{lower_digits_regexp.pattern}(?:_{lower_digits_regexp.pattern})*")
|
|
@@ -129,7 +147,8 @@ kebab_case_element: pp.ParserElement = pp.Combine(
|
|
|
129
147
|
dot_case_element: pp.ParserElement = pp.Combine(
|
|
130
148
|
lower_digits_element + (period_token + lower_digits_element)[...])
|
|
131
149
|
|
|
132
|
-
uuid_regexp: re.Pattern[str] = re.compile(
|
|
150
|
+
uuid_regexp: re.Pattern[str] = re.compile(
|
|
151
|
+
rf"{hex_digit_regexp.pattern}{{8}}(-{hex_digit_regexp.pattern}{{4}}){{3}}-{hex_digit_regexp.pattern}{{12}}")
|
|
133
152
|
uuid_element: pp.ParserElement = pp.Regex(uuid_regexp.pattern)
|
|
134
153
|
|
|
135
154
|
strict_relpath_regexp: re.Pattern[str] = re.compile(
|
|
@@ -146,6 +165,10 @@ strict_relpath_element: pp.ParserElement = pp.Combine(
|
|
|
146
165
|
strict_abspath_element: pp.ParserElement = pp.Combine(
|
|
147
166
|
slash_token + (strict_path_chars_element + slash_token)[...] + strict_path_chars_element[0, 1])
|
|
148
167
|
|
|
168
|
+
email_address_regexp: re.Pattern[str] = re.compile(
|
|
169
|
+
rf"(({lower_digit_regexp.pattern}|[_-])+)(?:\.({lower_digit_regexp.pattern}|[_-])+)*@(?:{kebab_case_regexp.pattern}\.)+({lower_digit_regexp.pattern}{{2,63}})")
|
|
170
|
+
email_address_element: pp.ParserElement = pp.Regex(email_address_regexp.pattern)
|
|
171
|
+
|
|
149
172
|
semver_regexp: re.Pattern[str] = re.compile(
|
|
150
173
|
rf"({number_regexp.pattern})\.({number_regexp.pattern})\.({number_regexp.pattern})"
|
|
151
174
|
rf"(?:-{alpha_digits_regexp.pattern}(?:\.{alpha_digits_regexp.pattern})*)?"
|
|
@@ -184,6 +207,9 @@ strict_relpath_parser = make_string_parser(strict_relpath_element)
|
|
|
184
207
|
strict_abspath_pattern = make_string_pattern(strict_abspath_regexp)
|
|
185
208
|
strict_abspath_parser = make_string_parser(strict_abspath_element)
|
|
186
209
|
|
|
210
|
+
email_address_pattern = make_string_pattern(email_address_regexp)
|
|
211
|
+
email_address_parser = make_string_parser(email_address_element)
|
|
212
|
+
|
|
187
213
|
semver_pattern = make_string_pattern(semver_regexp)
|
|
188
214
|
semver_parser = make_string_parser(semver_element)
|
|
189
215
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import textcase
|
|
2
|
+
from iker.common.utils.jsonutils import JsonType
|
|
3
|
+
from iker.common.utils.jsonutils import json_difference, json_reformat
|
|
4
|
+
|
|
5
|
+
from plexus.common.utils.datautils import compute_vin_code_check_digit
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"generate_dummy_uuid_str",
|
|
9
|
+
"generate_dummy_vin_code",
|
|
10
|
+
"case_insensitive_json_compare",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def generate_dummy_uuid_str(*nums: int) -> str:
|
|
15
|
+
if len(nums) > 8:
|
|
16
|
+
raise ValueError("a maximum of 8 integers can be provided")
|
|
17
|
+
if not all(0 <= num <= 0xFFFF for num in nums):
|
|
18
|
+
raise ValueError("all integers must be in the range 0 to 65535 (0xFFFF)")
|
|
19
|
+
i0, i1, i2, i3, i4, i5, i6, i7 = list(nums) + [0] * (8 - len(nums))
|
|
20
|
+
return f"{i0:04x}{i1:04x}-{i2:04x}-{i3:04x}-{i4:04x}-{i5:04x}{i6:04x}{i7:04x}"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def generate_dummy_vin_code(*nums: int) -> str:
|
|
24
|
+
if len(nums) > 4:
|
|
25
|
+
raise ValueError("a maximum of 4 integers can be provided")
|
|
26
|
+
if not all(0 <= num <= 9999 for num in nums):
|
|
27
|
+
raise ValueError("all integers must be in the range 0 to 9999")
|
|
28
|
+
i0, i1, i2, i3 = list(nums) + [0] * (4 - len(nums))
|
|
29
|
+
unchecked_vin_code = f"{i0:04d}{i1:04d}0{i2:04d}{i3:04d}"
|
|
30
|
+
check_digit = compute_vin_code_check_digit(unchecked_vin_code)
|
|
31
|
+
return unchecked_vin_code[:8] + check_digit + unchecked_vin_code[-8:]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def case_insensitive_json_compare(a: JsonType, b: JsonType, *, print_diff_messages: bool = True) -> bool:
|
|
35
|
+
identical = True
|
|
36
|
+
for node_path, diff_message in json_difference(json_reformat(a, key_formatter=textcase.camel),
|
|
37
|
+
json_reformat(b, key_formatter=textcase.camel),
|
|
38
|
+
[]):
|
|
39
|
+
if print_diff_messages:
|
|
40
|
+
print(node_path, diff_message)
|
|
41
|
+
identical = False
|
|
42
|
+
return identical
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plexus-python-common
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.24
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Python :: 3.12
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.13
|
|
@@ -16,12 +16,15 @@ Requires-Dist: pyparsing>=3.2
|
|
|
16
16
|
Requires-Dist: pyproj>=3.6
|
|
17
17
|
Requires-Dist: pyquaternion>=0.9
|
|
18
18
|
Requires-Dist: sqlalchemy>=2.0
|
|
19
|
-
Requires-Dist: sqlmodel
|
|
20
19
|
Requires-Dist: rich>=13.9
|
|
20
|
+
Requires-Dist: textcase>=0.4
|
|
21
21
|
Requires-Dist: ujson>=5.9
|
|
22
22
|
Requires-Dist: iker-python-common[all]>=1.0
|
|
23
23
|
Provides-Extra: all
|
|
24
|
-
Requires-Dist: plexus-python-common; extra == "all"
|
|
24
|
+
Requires-Dist: plexus-python-common[api]; extra == "all"
|
|
25
|
+
Provides-Extra: api
|
|
26
|
+
Requires-Dist: fastapi>=0.119.0; extra == "api"
|
|
27
|
+
Requires-Dist: sqlmodel>=0.0.25; extra == "api"
|
|
25
28
|
Provides-Extra: test
|
|
26
29
|
Requires-Dist: ddt>=1.7; extra == "test"
|
|
27
30
|
Requires-Dist: moto[all,ec2,s3]>=5.1; extra == "test"
|
|
@@ -46,13 +46,16 @@ src/plexus/common/carto/OSMTags.py
|
|
|
46
46
|
src/plexus/common/carto/OSMWay.py
|
|
47
47
|
src/plexus/common/carto/__init__.py
|
|
48
48
|
src/plexus/common/utils/__init__.py
|
|
49
|
+
src/plexus/common/utils/apiutils.py
|
|
49
50
|
src/plexus/common/utils/bagutils.py
|
|
50
51
|
src/plexus/common/utils/datautils.py
|
|
51
52
|
src/plexus/common/utils/jsonutils.py
|
|
52
53
|
src/plexus/common/utils/ormutils.py
|
|
53
54
|
src/plexus/common/utils/s3utils.py
|
|
54
55
|
src/plexus/common/utils/shutils.py
|
|
56
|
+
src/plexus/common/utils/sqlutils.py
|
|
55
57
|
src/plexus/common/utils/strutils.py
|
|
58
|
+
src/plexus/common/utils/testutils.py
|
|
56
59
|
src/plexus_python_common.egg-info/PKG-INFO
|
|
57
60
|
src/plexus_python_common.egg-info/SOURCES.txt
|
|
58
61
|
src/plexus_python_common.egg-info/dependency_links.txt
|
|
@@ -71,4 +74,5 @@ test/plexus_tests/common/utils/jsonutils_test.py
|
|
|
71
74
|
test/plexus_tests/common/utils/ormutils_test.py
|
|
72
75
|
test/plexus_tests/common/utils/s3utils_test.py
|
|
73
76
|
test/plexus_tests/common/utils/shutils_test.py
|
|
74
|
-
test/plexus_tests/common/utils/strutils_test.py
|
|
77
|
+
test/plexus_tests/common/utils/strutils_test.py
|
|
78
|
+
test/plexus_tests/common/utils/testutils_test.py
|
|
@@ -8,13 +8,17 @@ pyparsing>=3.2
|
|
|
8
8
|
pyproj>=3.6
|
|
9
9
|
pyquaternion>=0.9
|
|
10
10
|
sqlalchemy>=2.0
|
|
11
|
-
sqlmodel
|
|
12
11
|
rich>=13.9
|
|
12
|
+
textcase>=0.4
|
|
13
13
|
ujson>=5.9
|
|
14
14
|
iker-python-common[all]>=1.0
|
|
15
15
|
|
|
16
16
|
[all]
|
|
17
|
-
plexus-python-common
|
|
17
|
+
plexus-python-common[api]
|
|
18
|
+
|
|
19
|
+
[api]
|
|
20
|
+
fastapi>=0.119.0
|
|
21
|
+
sqlmodel>=0.0.25
|
|
18
22
|
|
|
19
23
|
[test]
|
|
20
24
|
ddt>=1.7
|
|
@@ -12,6 +12,7 @@ from iker.common.utils.jsonutils import JsonType
|
|
|
12
12
|
from iker.common.utils.randutils import randomizer
|
|
13
13
|
from sqlmodel import Field, SQLModel
|
|
14
14
|
|
|
15
|
+
from plexus.common.utils.apiutils import managed_db_session
|
|
15
16
|
from plexus.common.utils.ormutils import (
|
|
16
17
|
db_activate_revision_model,
|
|
17
18
|
db_activate_snapshot_model,
|
|
@@ -954,7 +955,7 @@ def test_make_snapshot_model_trigger(fixture_postgresql_test_proc, fixture_postg
|
|
|
954
955
|
dummy_json=rng.random_json_object(5),
|
|
955
956
|
)
|
|
956
957
|
|
|
957
|
-
with maker.make_session() as session:
|
|
958
|
+
with maker.make_session() as session, managed_db_session(session):
|
|
958
959
|
session.execute(sa.sql.text("SET TIMEZONE TO 'UTC'"))
|
|
959
960
|
session.commit()
|
|
960
961
|
|
|
@@ -1040,7 +1041,7 @@ def test_make_revision_model_trigger(fixture_postgresql_test_proc, fixture_postg
|
|
|
1040
1041
|
dummy_json=rng.random_json_object(5),
|
|
1041
1042
|
)
|
|
1042
1043
|
|
|
1043
|
-
with maker.make_session() as session:
|
|
1044
|
+
with maker.make_session() as session, managed_db_session(session):
|
|
1044
1045
|
session.execute(sa.sql.text("SET TIMEZONE TO 'UTC'"))
|
|
1045
1046
|
session.commit()
|
|
1046
1047
|
|
|
@@ -7,10 +7,10 @@ from iker.common.utils.dtutils import dt_parse_iso
|
|
|
7
7
|
from plexus.common.utils.strutils import BagName, UserEmail, UserName, VehicleName
|
|
8
8
|
from plexus.common.utils.strutils import colon_tag_parser, colon_tag_pattern, slash_tag_parser, slash_tag_pattern
|
|
9
9
|
from plexus.common.utils.strutils import dot_case_parser, dot_case_pattern
|
|
10
|
+
from plexus.common.utils.strutils import email_address_parser, email_address_pattern, semver_parser, semver_pattern
|
|
10
11
|
from plexus.common.utils.strutils import hex_string_parser, hex_string_pattern
|
|
11
12
|
from plexus.common.utils.strutils import kebab_case_parser, kebab_case_pattern
|
|
12
13
|
from plexus.common.utils.strutils import parse_bag_name, parse_user_email, parse_user_name, parse_vehicle_name
|
|
13
|
-
from plexus.common.utils.strutils import semver_parser, semver_pattern
|
|
14
14
|
from plexus.common.utils.strutils import snake_case_parser, snake_case_pattern
|
|
15
15
|
from plexus.common.utils.strutils import strict_abspath_parser, strict_abspath_pattern
|
|
16
16
|
from plexus.common.utils.strutils import strict_relpath_parser, strict_relpath_pattern
|
|
@@ -377,6 +377,43 @@ class StrUtilsTest(unittest.TestCase):
|
|
|
377
377
|
with self.assertRaises(pp.ParseException):
|
|
378
378
|
strict_abspath_parser.parse_string(data, parse_all=True)
|
|
379
379
|
|
|
380
|
+
data_email_address_pattern = [
|
|
381
|
+
("someone@dummy.com",),
|
|
382
|
+
("some.one@dummy.com",),
|
|
383
|
+
("some.1@dummy.com",),
|
|
384
|
+
("some-one@dummy.com",),
|
|
385
|
+
("someone-@dummy.com",),
|
|
386
|
+
("someone@dummy.company.com",),
|
|
387
|
+
("some.one@dummy-company.com",),
|
|
388
|
+
("some.1@dummy.company-company.com",),
|
|
389
|
+
("some_one@dummy-1st-company.co-ltd.com",),
|
|
390
|
+
]
|
|
391
|
+
|
|
392
|
+
@ddt.idata(data_email_address_pattern)
|
|
393
|
+
@ddt.unpack
|
|
394
|
+
def test_email_address_pattern(self, data):
|
|
395
|
+
self.assertIsNotNone(email_address_pattern.match(data))
|
|
396
|
+
self.assertIsNotNone(email_address_parser.parse_string(data, parse_all=True))
|
|
397
|
+
|
|
398
|
+
data_email_address_pattern__bad_cases = [
|
|
399
|
+
("",),
|
|
400
|
+
("some.one",),
|
|
401
|
+
("@dummy.com",),
|
|
402
|
+
("someone@dummy",),
|
|
403
|
+
("someone@dummy.methionylthreonylthreonylglutaminylarginyltyrosylglutamylserylleucine",),
|
|
404
|
+
("someone+one@dummy.com",),
|
|
405
|
+
("someone.@dummy.com",),
|
|
406
|
+
("someone@.dummy.com",),
|
|
407
|
+
("someone@dummy-.com",),
|
|
408
|
+
]
|
|
409
|
+
|
|
410
|
+
@ddt.idata(data_email_address_pattern__bad_cases)
|
|
411
|
+
@ddt.unpack
|
|
412
|
+
def test_email_address_pattern__bad_cases(self, data):
|
|
413
|
+
self.assertIsNone(email_address_pattern.match(data))
|
|
414
|
+
with self.assertRaises(pp.ParseException):
|
|
415
|
+
email_address_parser.parse_string(data, parse_all=True)
|
|
416
|
+
|
|
380
417
|
data_semver_pattern = [
|
|
381
418
|
("0.0.0",),
|
|
382
419
|
("1.2.3",),
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
import ddt
|
|
4
|
+
|
|
5
|
+
from plexus.common.utils.testutils import generate_dummy_uuid_str, generate_dummy_vin_code
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@ddt.ddt
|
|
9
|
+
class TestUtilsTest(unittest.TestCase):
|
|
10
|
+
data_generate_dummy_uuid_str = [
|
|
11
|
+
((), "00000000-0000-0000-0000-000000000000"),
|
|
12
|
+
((0,), "00000000-0000-0000-0000-000000000000"),
|
|
13
|
+
((0, 0,), "00000000-0000-0000-0000-000000000000"),
|
|
14
|
+
((0, 0, 0, 0, 0, 0, 0, 0,), "00000000-0000-0000-0000-000000000000"),
|
|
15
|
+
((1,), "00010000-0000-0000-0000-000000000000"),
|
|
16
|
+
((1, 2, 3, 4, 5, 6, 7, 8,), "00010002-0003-0004-0005-000600070008"),
|
|
17
|
+
((0x1, 0x10, 0x100, 0x1000, 0xF, 0xFF, 0xFFF, 0xFFFF,), "00010010-0100-1000-000f-00ff0fffffff"),
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
@ddt.idata(data_generate_dummy_uuid_str)
|
|
21
|
+
@ddt.unpack
|
|
22
|
+
def test_generate_dummy_uuid_str(self, nums, expect):
|
|
23
|
+
self.assertEqual(generate_dummy_uuid_str(*nums), expect)
|
|
24
|
+
|
|
25
|
+
data_generate_dummy_uuid_str__bad_case = [
|
|
26
|
+
((0, 0, 0, 0, 0, 0, 0, 0, 0,),),
|
|
27
|
+
((-1,),),
|
|
28
|
+
((0x10000,),),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
@ddt.idata(data_generate_dummy_uuid_str__bad_case)
|
|
32
|
+
@ddt.unpack
|
|
33
|
+
def test_generate_dummy_uuid_str__bad_case(self, nums):
|
|
34
|
+
with self.assertRaises(ValueError):
|
|
35
|
+
generate_dummy_uuid_str(*nums)
|
|
36
|
+
|
|
37
|
+
data_generate_dummy_vin_code = [
|
|
38
|
+
((), "00000000000000000"),
|
|
39
|
+
((0,), "00000000000000000"),
|
|
40
|
+
((0, 0,), "00000000000000000"),
|
|
41
|
+
((0, 0, 0, 0,), "00000000000000000"),
|
|
42
|
+
((1,), "00010000500000000"),
|
|
43
|
+
((1, 2, 3, 4,), "00010002700030004"),
|
|
44
|
+
((1, 23, 456, 7890,), "00010023504567890"),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
@ddt.idata(data_generate_dummy_vin_code)
|
|
48
|
+
@ddt.unpack
|
|
49
|
+
def test_generate_dummy_vin_code(self, nums, expect):
|
|
50
|
+
self.assertEqual(generate_dummy_vin_code(*nums), expect)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/0-dummy
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/1-dummy
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/2-dummy
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.0.jsonl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.1.jsonl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.2.jsonl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/resources/unittest/shutils/dummy.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMFile.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMNode.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMTags.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/OSMWay.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/carto/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/__init__.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/bagutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/datautils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/jsonutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/ormutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/s3utils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/src/plexus/common/utils/shutils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/pose_test.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.22 → plexus_python_common-1.0.24}/test/plexus_tests/common/proj_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|