dycw-utilities 0.174.8__tar.gz → 0.174.9__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.
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/PKG-INFO +1 -1
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/pyproject.toml +2 -2
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/hypothesis.py +34 -0
- dycw_utilities-0.174.9/src/utilities/permissions.py +297 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/README.md +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/aeventkit.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/asyncio.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/click.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/docker.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/git.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/grp.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/gzip.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/http.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/jinja2.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/json.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/math.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/os.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/postgres.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pottery.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pwd.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pydantic_settings.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pydantic_settings_sops.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pytest_plugins/__init__.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/random.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/re.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/shutil.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/string.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/subprocess.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/testbook.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/text.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/types.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/version.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/zoneinfo.py +0 -0
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
name = "dycw-utilities"
|
|
102
102
|
readme = "README.md"
|
|
103
103
|
requires-python = ">= 3.12"
|
|
104
|
-
version = "0.174.
|
|
104
|
+
version = "0.174.9"
|
|
105
105
|
|
|
106
106
|
[project.entry-points.pytest11]
|
|
107
107
|
pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
# bump-my-version
|
|
136
136
|
[tool.bumpversion]
|
|
137
137
|
allow_dirty = true
|
|
138
|
-
current_version = "0.174.
|
|
138
|
+
current_version = "0.174.9"
|
|
139
139
|
|
|
140
140
|
[[tool.bumpversion.files]]
|
|
141
141
|
filename = "src/utilities/__init__.py"
|
|
@@ -77,6 +77,7 @@ from utilities.math import (
|
|
|
77
77
|
)
|
|
78
78
|
from utilities.os import get_env_var
|
|
79
79
|
from utilities.pathlib import module_path, temp_cwd
|
|
80
|
+
from utilities.permissions import Permissions
|
|
80
81
|
from utilities.platform import IS_LINUX
|
|
81
82
|
from utilities.sentinel import Sentinel, is_sentinel, sentinel
|
|
82
83
|
from utilities.tempfile import TEMP_DIR, TemporaryDirectory
|
|
@@ -864,6 +865,38 @@ def _path_parts(draw: DrawFn, /) -> str:
|
|
|
864
865
|
##
|
|
865
866
|
|
|
866
867
|
|
|
868
|
+
@composite
|
|
869
|
+
def permissions(
|
|
870
|
+
draw: DrawFn,
|
|
871
|
+
/,
|
|
872
|
+
*,
|
|
873
|
+
user_read: MaybeSearchStrategy[bool | None] = None,
|
|
874
|
+
user_write: MaybeSearchStrategy[bool | None] = None,
|
|
875
|
+
user_execute: MaybeSearchStrategy[bool | None] = None,
|
|
876
|
+
group_read: MaybeSearchStrategy[bool | None] = None,
|
|
877
|
+
group_write: MaybeSearchStrategy[bool | None] = None,
|
|
878
|
+
group_execute: MaybeSearchStrategy[bool | None] = None,
|
|
879
|
+
others_read: MaybeSearchStrategy[bool | None] = None,
|
|
880
|
+
others_write: MaybeSearchStrategy[bool | None] = None,
|
|
881
|
+
others_execute: MaybeSearchStrategy[bool | None] = None,
|
|
882
|
+
) -> Permissions:
|
|
883
|
+
"""Strategy for generating `Permissions`."""
|
|
884
|
+
return Permissions(
|
|
885
|
+
user_read=draw2(draw, user_read, booleans()),
|
|
886
|
+
user_write=draw2(draw, user_write, booleans()),
|
|
887
|
+
user_execute=draw2(draw, user_execute, booleans()),
|
|
888
|
+
group_read=draw2(draw, group_read, booleans()),
|
|
889
|
+
group_write=draw2(draw, group_write, booleans()),
|
|
890
|
+
group_execute=draw2(draw, group_execute, booleans()),
|
|
891
|
+
others_read=draw2(draw, others_read, booleans()),
|
|
892
|
+
others_write=draw2(draw, others_write, booleans()),
|
|
893
|
+
others_execute=draw2(draw, others_execute, booleans()),
|
|
894
|
+
)
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
##
|
|
898
|
+
|
|
899
|
+
|
|
867
900
|
@composite
|
|
868
901
|
def plain_date_times(
|
|
869
902
|
draw: DrawFn,
|
|
@@ -1611,6 +1644,7 @@ __all__ = [
|
|
|
1611
1644
|
"numbers",
|
|
1612
1645
|
"pairs",
|
|
1613
1646
|
"paths",
|
|
1647
|
+
"permissions",
|
|
1614
1648
|
"plain_date_times",
|
|
1615
1649
|
"py_datetimes",
|
|
1616
1650
|
"quadruples",
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from functools import reduce
|
|
6
|
+
from operator import or_
|
|
7
|
+
from stat import (
|
|
8
|
+
S_IRGRP,
|
|
9
|
+
S_IROTH,
|
|
10
|
+
S_IRUSR,
|
|
11
|
+
S_IWGRP,
|
|
12
|
+
S_IWOTH,
|
|
13
|
+
S_IWUSR,
|
|
14
|
+
S_IXGRP,
|
|
15
|
+
S_IXOTH,
|
|
16
|
+
S_IXUSR,
|
|
17
|
+
)
|
|
18
|
+
from typing import Literal, Self, override
|
|
19
|
+
|
|
20
|
+
from utilities.dataclasses import replace_non_sentinel
|
|
21
|
+
from utilities.functions import ensure_member
|
|
22
|
+
from utilities.re import (
|
|
23
|
+
ExtractGroupError,
|
|
24
|
+
ExtractGroupsError,
|
|
25
|
+
extract_group,
|
|
26
|
+
extract_groups,
|
|
27
|
+
)
|
|
28
|
+
from utilities.sentinel import Sentinel, sentinel
|
|
29
|
+
from utilities.typing import get_args
|
|
30
|
+
|
|
31
|
+
_MIN_INT = 0o0
|
|
32
|
+
_MAX_INT = 0o777
|
|
33
|
+
type _ZeroToSeven = Literal[0, 1, 2, 3, 4, 5, 6, 7]
|
|
34
|
+
_ZERO_TO_SEVEN: list[_ZeroToSeven] = list(get_args(_ZeroToSeven.__value__))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(order=True, unsafe_hash=True, kw_only=True, slots=True)
|
|
38
|
+
class Permissions:
|
|
39
|
+
user_read: bool = False
|
|
40
|
+
user_write: bool = False
|
|
41
|
+
user_execute: bool = False
|
|
42
|
+
group_read: bool = False
|
|
43
|
+
group_write: bool = False
|
|
44
|
+
group_execute: bool = False
|
|
45
|
+
others_read: bool = False
|
|
46
|
+
others_write: bool = False
|
|
47
|
+
others_execute: bool = False
|
|
48
|
+
|
|
49
|
+
def __int__(self) -> int:
|
|
50
|
+
return (
|
|
51
|
+
100
|
|
52
|
+
* self._int(
|
|
53
|
+
read=self.user_read, write=self.user_write, execute=self.user_execute
|
|
54
|
+
)
|
|
55
|
+
+ 10
|
|
56
|
+
* self._int(
|
|
57
|
+
read=self.group_read, write=self.group_write, execute=self.group_execute
|
|
58
|
+
)
|
|
59
|
+
+ self._int(
|
|
60
|
+
read=self.others_read,
|
|
61
|
+
write=self.others_write,
|
|
62
|
+
execute=self.others_execute,
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def _int(
|
|
67
|
+
self, *, read: bool = False, write: bool = False, execute: bool = False
|
|
68
|
+
) -> _ZeroToSeven:
|
|
69
|
+
return (4 if read else 0) + (2 if write else 0) + (1 if execute else 0)
|
|
70
|
+
|
|
71
|
+
@override
|
|
72
|
+
def __repr__(self) -> str:
|
|
73
|
+
return ",".join([
|
|
74
|
+
self._repr_parts(
|
|
75
|
+
"u",
|
|
76
|
+
read=self.user_read,
|
|
77
|
+
write=self.user_write,
|
|
78
|
+
execute=self.user_execute,
|
|
79
|
+
),
|
|
80
|
+
self._repr_parts(
|
|
81
|
+
"g",
|
|
82
|
+
read=self.group_read,
|
|
83
|
+
write=self.group_write,
|
|
84
|
+
execute=self.group_execute,
|
|
85
|
+
),
|
|
86
|
+
self._repr_parts(
|
|
87
|
+
"o",
|
|
88
|
+
read=self.others_read,
|
|
89
|
+
write=self.others_write,
|
|
90
|
+
execute=self.others_execute,
|
|
91
|
+
),
|
|
92
|
+
])
|
|
93
|
+
|
|
94
|
+
def _repr_parts(
|
|
95
|
+
self,
|
|
96
|
+
prefix: Literal["u", "g", "o"],
|
|
97
|
+
/,
|
|
98
|
+
*,
|
|
99
|
+
read: bool = False,
|
|
100
|
+
write: bool = False,
|
|
101
|
+
execute: bool = False,
|
|
102
|
+
) -> str:
|
|
103
|
+
parts: list[str] = []
|
|
104
|
+
if read:
|
|
105
|
+
parts.append("r")
|
|
106
|
+
if write:
|
|
107
|
+
parts.append("w")
|
|
108
|
+
if execute:
|
|
109
|
+
parts.append("x")
|
|
110
|
+
return f"{prefix}={''.join(parts)}"
|
|
111
|
+
|
|
112
|
+
@override
|
|
113
|
+
def __str__(self) -> str:
|
|
114
|
+
return repr(self)
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def from_int(cls, n: int, /) -> Self:
|
|
118
|
+
with suppress(ExtractGroupsError):
|
|
119
|
+
user, group, others = extract_groups(r"^([0-7])([0-7])([0-7])$", str(n))
|
|
120
|
+
user_read, user_write, user_execute = cls._from_int(
|
|
121
|
+
ensure_member(int(user), _ZERO_TO_SEVEN)
|
|
122
|
+
)
|
|
123
|
+
group_read, group_write, group_execute = cls._from_int(
|
|
124
|
+
ensure_member(int(group), _ZERO_TO_SEVEN)
|
|
125
|
+
)
|
|
126
|
+
others_read, others_write, others_execute = cls._from_int(
|
|
127
|
+
ensure_member(int(others), _ZERO_TO_SEVEN)
|
|
128
|
+
)
|
|
129
|
+
return cls(
|
|
130
|
+
user_read=user_read,
|
|
131
|
+
user_write=user_write,
|
|
132
|
+
user_execute=user_execute,
|
|
133
|
+
group_read=group_read,
|
|
134
|
+
group_write=group_write,
|
|
135
|
+
group_execute=group_execute,
|
|
136
|
+
others_read=others_read,
|
|
137
|
+
others_write=others_write,
|
|
138
|
+
others_execute=others_execute,
|
|
139
|
+
)
|
|
140
|
+
with suppress(ExtractGroupsError):
|
|
141
|
+
group, others = extract_groups(r"^([0-7])([0-7])$", str(n))
|
|
142
|
+
group_read, group_write, group_execute = cls._from_int(
|
|
143
|
+
ensure_member(int(group), _ZERO_TO_SEVEN)
|
|
144
|
+
)
|
|
145
|
+
others_read, others_write, others_execute = cls._from_int(
|
|
146
|
+
ensure_member(int(others), _ZERO_TO_SEVEN)
|
|
147
|
+
)
|
|
148
|
+
return cls(
|
|
149
|
+
group_read=group_read,
|
|
150
|
+
group_write=group_write,
|
|
151
|
+
group_execute=group_execute,
|
|
152
|
+
others_read=others_read,
|
|
153
|
+
others_write=others_write,
|
|
154
|
+
others_execute=others_execute,
|
|
155
|
+
)
|
|
156
|
+
with suppress(ExtractGroupError):
|
|
157
|
+
others = extract_group(r"^([0-7])$", str(n))
|
|
158
|
+
others_read, others_write, others_execute = cls._from_int(
|
|
159
|
+
ensure_member(int(others), _ZERO_TO_SEVEN)
|
|
160
|
+
)
|
|
161
|
+
return cls(
|
|
162
|
+
others_read=others_read,
|
|
163
|
+
others_write=others_write,
|
|
164
|
+
others_execute=others_execute,
|
|
165
|
+
)
|
|
166
|
+
if n == 0:
|
|
167
|
+
return cls()
|
|
168
|
+
raise PermissionsFromIntError(n=n)
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def _from_int(cls, n: _ZeroToSeven, /) -> tuple[bool, bool, bool]:
|
|
172
|
+
return bool(4 & n), bool(2 & n), bool(1 & n)
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def from_octal(cls, n: int, /) -> Self:
|
|
176
|
+
if _MIN_INT <= n <= _MAX_INT:
|
|
177
|
+
return cls(
|
|
178
|
+
user_read=bool(n & S_IRUSR),
|
|
179
|
+
user_write=bool(n & S_IWUSR),
|
|
180
|
+
user_execute=bool(n & S_IXUSR),
|
|
181
|
+
group_read=bool(n & S_IRGRP),
|
|
182
|
+
group_write=bool(n & S_IWGRP),
|
|
183
|
+
group_execute=bool(n & S_IXGRP),
|
|
184
|
+
others_read=bool(n & S_IROTH),
|
|
185
|
+
others_write=bool(n & S_IWOTH),
|
|
186
|
+
others_execute=bool(n & S_IXOTH),
|
|
187
|
+
)
|
|
188
|
+
raise PermissionsFromOctalError(n=n)
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def from_text(cls, text: str, /) -> Self:
|
|
192
|
+
try:
|
|
193
|
+
user, group, others = extract_groups(
|
|
194
|
+
r"^u=(r?w?x?),g=(r?w?x?),o=(r?w?x?)$", text
|
|
195
|
+
)
|
|
196
|
+
except ExtractGroupsError:
|
|
197
|
+
raise PermissionsFromTextError(text=text) from None
|
|
198
|
+
user_read, user_write, user_execute = cls._from_text_part(user)
|
|
199
|
+
group_read, group_write, group_execute = cls._from_text_part(group)
|
|
200
|
+
others_read, others_write, others_execute = cls._from_text_part(others)
|
|
201
|
+
return cls(
|
|
202
|
+
user_read=user_read,
|
|
203
|
+
user_write=user_write,
|
|
204
|
+
user_execute=user_execute,
|
|
205
|
+
group_read=group_read,
|
|
206
|
+
group_write=group_write,
|
|
207
|
+
group_execute=group_execute,
|
|
208
|
+
others_read=others_read,
|
|
209
|
+
others_write=others_write,
|
|
210
|
+
others_execute=others_execute,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
def _from_text_part(cls, text: str, /) -> tuple[bool, bool, bool]:
|
|
215
|
+
read, write, execute = extract_groups("^(r?)(w?)(x?)$", text)
|
|
216
|
+
return read != "", write != "", execute != ""
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def octal(self) -> int:
|
|
220
|
+
flags: list[int] = [
|
|
221
|
+
S_IRUSR if self.user_read else 0,
|
|
222
|
+
S_IWUSR if self.user_write else 0,
|
|
223
|
+
S_IXUSR if self.user_execute else 0,
|
|
224
|
+
S_IRGRP if self.group_read else 0,
|
|
225
|
+
S_IWGRP if self.group_write else 0,
|
|
226
|
+
S_IXGRP if self.group_execute else 0,
|
|
227
|
+
S_IROTH if self.others_read else 0,
|
|
228
|
+
S_IWOTH if self.others_write else 0,
|
|
229
|
+
S_IXOTH if self.others_execute else 0,
|
|
230
|
+
]
|
|
231
|
+
return reduce(or_, flags)
|
|
232
|
+
|
|
233
|
+
def replace(
|
|
234
|
+
self,
|
|
235
|
+
*,
|
|
236
|
+
user_read: bool | Sentinel = sentinel,
|
|
237
|
+
user_write: bool | Sentinel = sentinel,
|
|
238
|
+
user_execute: bool | Sentinel = sentinel,
|
|
239
|
+
group_read: bool | Sentinel = sentinel,
|
|
240
|
+
group_write: bool | Sentinel = sentinel,
|
|
241
|
+
group_execute: bool | Sentinel = sentinel,
|
|
242
|
+
others_read: bool | Sentinel = sentinel,
|
|
243
|
+
others_write: bool | Sentinel = sentinel,
|
|
244
|
+
others_execute: bool | Sentinel = sentinel,
|
|
245
|
+
) -> Self:
|
|
246
|
+
return replace_non_sentinel(
|
|
247
|
+
self,
|
|
248
|
+
user_read=user_read,
|
|
249
|
+
user_write=user_write,
|
|
250
|
+
user_execute=user_execute,
|
|
251
|
+
group_read=group_read,
|
|
252
|
+
group_write=group_write,
|
|
253
|
+
group_execute=group_execute,
|
|
254
|
+
others_read=others_read,
|
|
255
|
+
others_write=others_write,
|
|
256
|
+
others_execute=others_execute,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
@dataclass(kw_only=True, slots=True)
|
|
261
|
+
class PermissionsError(Exception): ...
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@dataclass(kw_only=True, slots=True)
|
|
265
|
+
class PermissionsFromIntError(PermissionsError):
|
|
266
|
+
n: int
|
|
267
|
+
|
|
268
|
+
@override
|
|
269
|
+
def __str__(self) -> str:
|
|
270
|
+
return f"Invalid integer for permissions; got {self.n}"
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@dataclass(kw_only=True, slots=True)
|
|
274
|
+
class PermissionsFromOctalError(PermissionsError):
|
|
275
|
+
n: int
|
|
276
|
+
|
|
277
|
+
@override
|
|
278
|
+
def __str__(self) -> str:
|
|
279
|
+
return f"Invalid octal for permissions; got {oct(self.n)}"
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@dataclass(kw_only=True, slots=True)
|
|
283
|
+
class PermissionsFromTextError(PermissionsError):
|
|
284
|
+
text: str
|
|
285
|
+
|
|
286
|
+
@override
|
|
287
|
+
def __str__(self) -> str:
|
|
288
|
+
return f"Invalid string for permissions; got {self.text!r}"
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
__all__ = [
|
|
292
|
+
"Permissions",
|
|
293
|
+
"PermissionsError",
|
|
294
|
+
"PermissionsFromIntError",
|
|
295
|
+
"PermissionsFromOctalError",
|
|
296
|
+
"PermissionsFromTextError",
|
|
297
|
+
]
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pytest_plugins/pytest_randomly.py
RENAMED
|
File without changes
|
{dycw_utilities-0.174.8 → dycw_utilities-0.174.9}/src/utilities/pytest_plugins/pytest_regressions.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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|