xloft 0.5.1__py3-none-any.whl → 0.9.6__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.
Potentially problematic release.
This version of xloft might be problematic. Click here for more details.
- xloft/__init__.py +35 -17
- xloft/converters/__init__.py +19 -0
- xloft/converters/human_size.py +39 -0
- xloft/converters/roman.py +116 -0
- xloft/errors.py +32 -26
- xloft/itis.py +60 -0
- xloft/namedtuple.py +206 -257
- {xloft-0.5.1.dist-info → xloft-0.9.6.dist-info}/METADATA +63 -35
- xloft-0.9.6.dist-info/RECORD +12 -0
- {xloft-0.5.1.dist-info → xloft-0.9.6.dist-info}/WHEEL +1 -1
- {xloft-0.5.1.dist-info → xloft-0.9.6.dist-info}/licenses/LICENSE +21 -21
- xloft/human.py +0 -64
- xloft-0.5.1.dist-info/RECORD +0 -9
xloft/__init__.py
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
# ____ ____ _____ ___ ________ _________
|
|
2
|
+
# |_ _||_ _||_ _| .' `.|_ __ || _ _ |
|
|
3
|
+
# \ \ / / | | / .-. \ | |_ \_||_/ | | \_|
|
|
4
|
+
# > `' < | | _ | | | | | _| | |
|
|
5
|
+
# _/ /'`\ \_ _| |__/ |\ `-' /_| |_ _| |_
|
|
6
|
+
# |____||____||________| `.___.'|_____| |_____|
|
|
7
|
+
#
|
|
8
|
+
#
|
|
9
|
+
# Copyright (c) 2025 Gennady Kostyunin
|
|
10
|
+
# XLOFT is free software under terms of the MIT License.
|
|
11
|
+
# Repository https://github.com/kebasyaty/xloft
|
|
12
|
+
#
|
|
13
|
+
"""(XLOFT) X-Library of tools.
|
|
14
|
+
|
|
15
|
+
Modules exported by this package:
|
|
16
|
+
|
|
17
|
+
- `namedtuple`- Class imitates the behavior of the _named tuple_.
|
|
18
|
+
- `converters` - Collection of tools for converting data.
|
|
19
|
+
- `itis` - Tools for determining something.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
__all__ = (
|
|
25
|
+
"int_to_roman",
|
|
26
|
+
"roman_to_int",
|
|
27
|
+
"to_human_size",
|
|
28
|
+
"is_number",
|
|
29
|
+
"is_palindrome",
|
|
30
|
+
"NamedTuple",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from xloft.converters import int_to_roman, roman_to_int, to_human_size
|
|
34
|
+
from xloft.itis import is_number, is_palindrome
|
|
35
|
+
from xloft.namedtuple import NamedTuple
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Collection of tools for converting data.
|
|
2
|
+
|
|
3
|
+
The module contains the following functions:
|
|
4
|
+
|
|
5
|
+
- `to_human_size(n_bytes)` - Returns a humanized string: 200 bytes | 1 KB | 1.5 MB etc.
|
|
6
|
+
- `int_to_roman` - Convert an integer to Roman.
|
|
7
|
+
- `roman_to_int` - Convert to integer from Roman.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
__all__ = (
|
|
13
|
+
"to_human_size",
|
|
14
|
+
"int_to_roman",
|
|
15
|
+
"roman_to_int",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from xloft.converters.human_size import to_human_size
|
|
19
|
+
from xloft.converters.roman import int_to_roman, roman_to_int
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Converts the number of bytes into a human-readable format.
|
|
2
|
+
|
|
3
|
+
The module contains the following functions:
|
|
4
|
+
|
|
5
|
+
- `to_human_size(n_bytes)` - Returns a humanized string: 200 bytes | 1 KB | 1.5 MB etc.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
__all__ = ("to_human_size",)
|
|
11
|
+
|
|
12
|
+
import math
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def to_human_size(n_bytes: int) -> str:
|
|
16
|
+
"""Converts the number of bytes into a human-readable format.
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
>>> from xloft import to_human_size
|
|
20
|
+
>>> to_human_size(200)
|
|
21
|
+
200 bytes
|
|
22
|
+
>>> to_human_size(1048576)
|
|
23
|
+
1 MB
|
|
24
|
+
>>> to_human_size(1048575)
|
|
25
|
+
1023.999 KB
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
n_bytes: The number of bytes.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Returns a humanized string: 200 bytes | 1 KB | 1.5 MB etc.
|
|
32
|
+
"""
|
|
33
|
+
idx: int = math.floor(math.log(n_bytes) / math.log(1024))
|
|
34
|
+
ndigits: int = [0, 3, 6, 9, 12][idx]
|
|
35
|
+
human_size: int | float = n_bytes if n_bytes < 1024 else abs(round(n_bytes / pow(1024, idx), ndigits))
|
|
36
|
+
order = ["bytes", "KB", "MB", "GB", "TB"][idx]
|
|
37
|
+
if math.modf(human_size)[0] == 0.0:
|
|
38
|
+
human_size = int(human_size)
|
|
39
|
+
return f"{human_size} {order}"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Convert an integer to Roman and vice versa.
|
|
2
|
+
|
|
3
|
+
The module contains the following functions:
|
|
4
|
+
|
|
5
|
+
- `int_to_roman` - Convert an integer to Roman.
|
|
6
|
+
- `roman_to_int` - Convert to integer from Roman.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
"int_to_roman",
|
|
13
|
+
"roman_to_int",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
ROMAN = [
|
|
17
|
+
(1000, "M"),
|
|
18
|
+
(900, "CM"),
|
|
19
|
+
(500, "D"),
|
|
20
|
+
(400, "CD"),
|
|
21
|
+
(100, "C"),
|
|
22
|
+
(90, "XC"),
|
|
23
|
+
(50, "L"),
|
|
24
|
+
(40, "XL"),
|
|
25
|
+
(10, "X"),
|
|
26
|
+
(9, "IX"),
|
|
27
|
+
(5, "V"),
|
|
28
|
+
(4, "IV"),
|
|
29
|
+
(1, "I"),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def int_to_roman(number: int) -> str:
|
|
34
|
+
"""Convert an integer to Roman.
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
>>> from xloft import int_to_roman
|
|
38
|
+
>>> int_to_roman(1994)
|
|
39
|
+
MCMXCIV
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
number (int): Integer.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Roman numeral string.
|
|
46
|
+
"""
|
|
47
|
+
result = ""
|
|
48
|
+
for arabic, roman in ROMAN:
|
|
49
|
+
(factor, number) = divmod(number, arabic)
|
|
50
|
+
result += roman * factor
|
|
51
|
+
return result
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def roman_to_int(roman: str) -> int:
|
|
55
|
+
"""Convert to integer from Roman.
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
>>> from xloft import roman_to_int
|
|
59
|
+
>>> roman_to_int("MCMXCIV")
|
|
60
|
+
1994
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
roman (str): Roman numeral string.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Integer.
|
|
67
|
+
"""
|
|
68
|
+
i_count = roman.count("I")
|
|
69
|
+
v_count = roman.count("V")
|
|
70
|
+
x_count = roman.count("X")
|
|
71
|
+
l_count = roman.count("L")
|
|
72
|
+
c_count = roman.count("C")
|
|
73
|
+
d_count = roman.count("D")
|
|
74
|
+
m_count = roman.count("M")
|
|
75
|
+
|
|
76
|
+
iv_count = roman.count("IV")
|
|
77
|
+
i_count -= iv_count
|
|
78
|
+
v_count -= iv_count
|
|
79
|
+
|
|
80
|
+
ix_count = roman.count("IX")
|
|
81
|
+
i_count -= ix_count
|
|
82
|
+
x_count -= ix_count
|
|
83
|
+
|
|
84
|
+
xl_count = roman.count("XL")
|
|
85
|
+
x_count -= xl_count
|
|
86
|
+
l_count -= xl_count
|
|
87
|
+
|
|
88
|
+
xc_count = roman.count("XC")
|
|
89
|
+
x_count -= xc_count
|
|
90
|
+
c_count -= xc_count
|
|
91
|
+
|
|
92
|
+
cd_count = roman.count("CD")
|
|
93
|
+
c_count -= cd_count
|
|
94
|
+
d_count -= cd_count
|
|
95
|
+
|
|
96
|
+
cm_count = roman.count("CM")
|
|
97
|
+
c_count -= cm_count
|
|
98
|
+
m_count -= cm_count
|
|
99
|
+
|
|
100
|
+
total = 0
|
|
101
|
+
total += 1 * i_count
|
|
102
|
+
total += 5 * v_count
|
|
103
|
+
total += 10 * x_count
|
|
104
|
+
total += 50 * l_count
|
|
105
|
+
total += 100 * c_count
|
|
106
|
+
total += 500 * d_count
|
|
107
|
+
total += 1000 * m_count
|
|
108
|
+
|
|
109
|
+
total += 4 * iv_count
|
|
110
|
+
total += 9 * ix_count
|
|
111
|
+
total += 40 * xl_count
|
|
112
|
+
total += 90 * xc_count
|
|
113
|
+
total += 400 * cd_count
|
|
114
|
+
total += 900 * cm_count
|
|
115
|
+
|
|
116
|
+
return total
|
xloft/errors.py
CHANGED
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
"""XLOT Exceptions."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
""
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
"""XLOT Exceptions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"XLOTException",
|
|
7
|
+
"AttributeDoesNotSetValueError",
|
|
8
|
+
"AttributeCannotBeDeleteError",
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class XLOTException(Exception):
|
|
13
|
+
"""Root Custom Exception."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def]# noqa: D107
|
|
16
|
+
super().__init__(*args, **kwargs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AttributeDoesNotSetValueError(XLOTException):
|
|
20
|
+
"""Exception is raised if the attribute does not setting value."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, attribute_name: str) -> None: # noqa: D107
|
|
23
|
+
self.message = f"The attribute `{attribute_name}` does not setting value!"
|
|
24
|
+
super().__init__(self.message)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AttributeCannotBeDeleteError(XLOTException):
|
|
28
|
+
"""Exception is raised if the attribute cannot be delete."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, attribute_name: str) -> None: # noqa: D107
|
|
31
|
+
self.message = f"The attribute `{attribute_name}` cannot be delete!"
|
|
32
|
+
super().__init__(self.message)
|
xloft/itis.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Tools for determining something.
|
|
2
|
+
|
|
3
|
+
The module contains the following functions:
|
|
4
|
+
|
|
5
|
+
- `is_number` - Check if a string is a number.
|
|
6
|
+
- `is_palindrome` - Check if a string is a palindrome.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
"is_number",
|
|
13
|
+
"is_palindrome",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def is_number(value: str) -> bool:
|
|
18
|
+
"""Check if a string is a number.
|
|
19
|
+
|
|
20
|
+
Only decimal numbers.
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
>>> from xloft import is_number
|
|
24
|
+
>>> is_number("123")
|
|
25
|
+
True
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
value (str): Some kind of string.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
True, if the string is a number.
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
float(value)
|
|
35
|
+
return True
|
|
36
|
+
except ValueError:
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def is_palindrome(value: str) -> bool:
|
|
41
|
+
"""Check if a string is a palindrome.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
>>> from xloft import is_palindrome
|
|
45
|
+
>>> is_palindrome("Go hang a salami, I'm a lasagna hog")
|
|
46
|
+
True
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
value (str): Alpha-numeric string.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Boolean value.
|
|
53
|
+
"""
|
|
54
|
+
if not isinstance(value, str):
|
|
55
|
+
raise TypeError("The value is not a string!")
|
|
56
|
+
if not len(value):
|
|
57
|
+
raise ValueError("The string must not be empty!")
|
|
58
|
+
string_list = [char.lower() for char in value if char.isalnum()]
|
|
59
|
+
reverse_list = string_list[::-1]
|
|
60
|
+
return reverse_list == string_list
|
xloft/namedtuple.py
CHANGED
|
@@ -1,257 +1,206 @@
|
|
|
1
|
-
"""This module contains the implementation of the `NamedTuple` class.
|
|
2
|
-
|
|
3
|
-
`NamedTuple` class imitates the behavior of the
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"""
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"""
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
>>>
|
|
95
|
-
10
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Returns:
|
|
101
|
-
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
def
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
"""
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
self.
|
|
157
|
-
|
|
158
|
-
def
|
|
159
|
-
"""
|
|
160
|
-
|
|
161
|
-
Examples:
|
|
162
|
-
>>> from xloft import NamedTuple
|
|
163
|
-
>>> nt = NamedTuple(x=10, y="Hello")
|
|
164
|
-
>>>
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
>>>
|
|
182
|
-
|
|
183
|
-
"
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
Returns:
|
|
187
|
-
|
|
188
|
-
"""
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
>>>
|
|
199
|
-
>>> nt
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def values(self) -> list[Any]:
|
|
208
|
-
"""Get a list of values.
|
|
209
|
-
|
|
210
|
-
Examples:
|
|
211
|
-
>>> from xloft import NamedTuple
|
|
212
|
-
>>> nt = NamedTuple(x=10, y="Hello")
|
|
213
|
-
>>> nt.values()
|
|
214
|
-
[10, "Hello"]
|
|
215
|
-
|
|
216
|
-
Returns:
|
|
217
|
-
List of values.
|
|
218
|
-
"""
|
|
219
|
-
attrs: dict[str, Any] = self.__dict__
|
|
220
|
-
keys: list[str] = self._jWjSaNy1RbtQinsN_keys
|
|
221
|
-
return [attrs[key] for key in keys]
|
|
222
|
-
|
|
223
|
-
def has_key(self, key: str) -> bool:
|
|
224
|
-
"""Returns True if the key exists, otherwise False.
|
|
225
|
-
|
|
226
|
-
Args:
|
|
227
|
-
key: Key name.
|
|
228
|
-
|
|
229
|
-
Examples:
|
|
230
|
-
>>> from xloft import NamedTuple
|
|
231
|
-
>>> nt = NamedTuple(x=10, y="Hello")
|
|
232
|
-
>>> nt.has_key("x")
|
|
233
|
-
True
|
|
234
|
-
|
|
235
|
-
Returns:
|
|
236
|
-
True if the key exists, otherwise False.
|
|
237
|
-
"""
|
|
238
|
-
keys: list[str] = self._jWjSaNy1RbtQinsN_keys
|
|
239
|
-
return key in keys
|
|
240
|
-
|
|
241
|
-
def has_value(self, value: Any) -> bool:
|
|
242
|
-
"""Returns True if the value exists, otherwise False.
|
|
243
|
-
|
|
244
|
-
Args:
|
|
245
|
-
value: Value of key.
|
|
246
|
-
|
|
247
|
-
Examples:
|
|
248
|
-
>>> from xloft import NamedTuple
|
|
249
|
-
>>> nt = NamedTuple(x=10, y="Hello")
|
|
250
|
-
>>> nt.has_value(10)
|
|
251
|
-
True
|
|
252
|
-
|
|
253
|
-
Returns:
|
|
254
|
-
True if the value exists, otherwise False.
|
|
255
|
-
"""
|
|
256
|
-
values = self.values()
|
|
257
|
-
return value in values
|
|
1
|
+
"""This module contains the implementation of the `NamedTuple` class.
|
|
2
|
+
|
|
3
|
+
`NamedTuple` class imitates the behavior of the *named tuple*.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from xloft.errors import (
|
|
11
|
+
AttributeCannotBeDeleteError,
|
|
12
|
+
AttributeDoesNotSetValueError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NamedTuple:
|
|
17
|
+
"""This class imitates the behavior of the `named tuple`."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, **kwargs: dict[str, Any]) -> None: # noqa: D107
|
|
20
|
+
self.__dict__["_0D5rSmH9Sy2XUWb5_keys"] = []
|
|
21
|
+
for name, value in kwargs.items():
|
|
22
|
+
self.__dict__[name] = value
|
|
23
|
+
self._0D5rSmH9Sy2XUWb5_keys.append(name)
|
|
24
|
+
|
|
25
|
+
def __len__(self) -> int:
|
|
26
|
+
"""Get the number of elements.
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
>>> from xloft import NamedTuple
|
|
30
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
31
|
+
>>> len(nt)
|
|
32
|
+
2
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
The number of elements in the tuple.
|
|
36
|
+
"""
|
|
37
|
+
return len(self._0D5rSmH9Sy2XUWb5_keys)
|
|
38
|
+
|
|
39
|
+
def __getattr__(self, name: str) -> Any:
|
|
40
|
+
"""Getter.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
>>> from xloft import NamedTuple
|
|
44
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
45
|
+
>>> nt.x
|
|
46
|
+
10
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
name: Key name.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Value of key.
|
|
53
|
+
"""
|
|
54
|
+
return self.__dict__[name]
|
|
55
|
+
|
|
56
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
57
|
+
"""Blocked Setter."""
|
|
58
|
+
raise AttributeDoesNotSetValueError(name)
|
|
59
|
+
|
|
60
|
+
def __delattr__(self, name: str) -> None:
|
|
61
|
+
"""Blocked Deleter."""
|
|
62
|
+
raise AttributeCannotBeDeleteError(name)
|
|
63
|
+
|
|
64
|
+
def get(self, key: str) -> Any:
|
|
65
|
+
"""Return the value for key if key is in the dictionary, else `None`.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
key: Key name.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
>>> from xloft import NamedTuple
|
|
72
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
73
|
+
>>> nt.get("x")
|
|
74
|
+
10
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Value of key.
|
|
78
|
+
"""
|
|
79
|
+
value = self.__dict__.get(key)
|
|
80
|
+
if value is not None:
|
|
81
|
+
return value
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
def update(self, key: str, value: Any) -> None:
|
|
85
|
+
"""Update a value of key.
|
|
86
|
+
|
|
87
|
+
Attention: This is an uncharacteristic action for the type `tuple`.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
key: Key name.
|
|
91
|
+
value: Value of key.
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
>>> from xloft import NamedTuple
|
|
95
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
96
|
+
>>> nt.update("x", 20)
|
|
97
|
+
>>> nt.x
|
|
98
|
+
20
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
None
|
|
102
|
+
"""
|
|
103
|
+
keys: list[str] = self._0D5rSmH9Sy2XUWb5_keys
|
|
104
|
+
if key not in keys:
|
|
105
|
+
err_msg = f"The key `{key}` is missing!"
|
|
106
|
+
raise KeyError(err_msg)
|
|
107
|
+
self.__dict__[key] = value
|
|
108
|
+
|
|
109
|
+
def to_dict(self) -> dict[str, Any]:
|
|
110
|
+
"""Convert to the dictionary.
|
|
111
|
+
|
|
112
|
+
Examples:
|
|
113
|
+
>>> from xloft import NamedTuple
|
|
114
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
115
|
+
>>> d = nt.to_dict()
|
|
116
|
+
>>> d["x"]
|
|
117
|
+
10
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Dictionary with keys and values of the tuple.
|
|
121
|
+
"""
|
|
122
|
+
attrs: dict[str, Any] = self.__dict__
|
|
123
|
+
keys: list[str] = self._0D5rSmH9Sy2XUWb5_keys
|
|
124
|
+
return {key: attrs[key] for key in keys}
|
|
125
|
+
|
|
126
|
+
def items(self) -> list[tuple[str, Any]]:
|
|
127
|
+
"""Return a set-like object providing a view on the NamedTuple's items.
|
|
128
|
+
|
|
129
|
+
Examples:
|
|
130
|
+
>>> from xloft import NamedTuple
|
|
131
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
132
|
+
>>> for key, val in nt.items():
|
|
133
|
+
... print(f"Key: {key}, Value: {val}")
|
|
134
|
+
"Key: x, Value: 10"
|
|
135
|
+
"Key: y, Value: Hello"
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
list[tuple[str, Any]]
|
|
139
|
+
"""
|
|
140
|
+
attrs: dict[str, Any] = self.__dict__
|
|
141
|
+
keys: list[str] = self._0D5rSmH9Sy2XUWb5_keys
|
|
142
|
+
return [(key, attrs[key]) for key in keys]
|
|
143
|
+
|
|
144
|
+
def keys(self) -> list[str]:
|
|
145
|
+
"""Get a list of keys.
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
>>> from xloft import NamedTuple
|
|
149
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
150
|
+
>>> nt.keys()
|
|
151
|
+
["x", "y"]
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
List of keys.
|
|
155
|
+
"""
|
|
156
|
+
return self._0D5rSmH9Sy2XUWb5_keys.copy()
|
|
157
|
+
|
|
158
|
+
def values(self) -> list[Any]:
|
|
159
|
+
"""Get a list of values.
|
|
160
|
+
|
|
161
|
+
Examples:
|
|
162
|
+
>>> from xloft import NamedTuple
|
|
163
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
164
|
+
>>> nt.values()
|
|
165
|
+
[10, "Hello"]
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
List of values.
|
|
169
|
+
"""
|
|
170
|
+
attrs: dict[str, Any] = self.__dict__
|
|
171
|
+
keys: list[str] = self._0D5rSmH9Sy2XUWb5_keys
|
|
172
|
+
return [attrs[key] for key in keys]
|
|
173
|
+
|
|
174
|
+
def has_key(self, key: str) -> bool:
|
|
175
|
+
"""Returns True if the key exists, otherwise False.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
key: Key name.
|
|
179
|
+
|
|
180
|
+
Examples:
|
|
181
|
+
>>> from xloft import NamedTuple
|
|
182
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
183
|
+
>>> nt.has_key("x")
|
|
184
|
+
True
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
True if the key exists, otherwise False.
|
|
188
|
+
"""
|
|
189
|
+
return key in self._0D5rSmH9Sy2XUWb5_keys
|
|
190
|
+
|
|
191
|
+
def has_value(self, value: Any) -> bool:
|
|
192
|
+
"""Returns True if the value exists, otherwise False.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
value: Value of key.
|
|
196
|
+
|
|
197
|
+
Examples:
|
|
198
|
+
>>> from xloft import NamedTuple
|
|
199
|
+
>>> nt = NamedTuple(x=10, y="Hello")
|
|
200
|
+
>>> nt.has_value(10)
|
|
201
|
+
True
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
True if the value exists, otherwise False.
|
|
205
|
+
"""
|
|
206
|
+
return value in self.values()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xloft
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.6
|
|
4
4
|
Summary: (XLOFT) X-Library of tools
|
|
5
|
-
Project-URL: Homepage, https://github.
|
|
5
|
+
Project-URL: Homepage, https://kebasyaty.github.io/xloft/
|
|
6
6
|
Project-URL: Repository, https://github.com/kebasyaty/xloft
|
|
7
7
|
Project-URL: Source, https://github.com/kebasyaty/xloft
|
|
8
8
|
Project-URL: Bug Tracker, https://github.com/kebasyaty/xloft/issues
|
|
@@ -17,10 +17,12 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
17
17
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
18
18
|
Classifier: Operating System :: Microsoft :: Windows
|
|
19
19
|
Classifier: Operating System :: POSIX
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
20
21
|
Classifier: Programming Language :: Python :: 3
|
|
21
22
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
26
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
27
|
Classifier: Topic :: Software Development :: Libraries
|
|
26
28
|
Classifier: Topic :: Utilities
|
|
@@ -47,21 +49,14 @@ Description-Content-Type: text/markdown
|
|
|
47
49
|
<a href="https://pypi.python.org/pypi/xloft/" alt="PyPI status"><img src="https://img.shields.io/pypi/status/xloft.svg" alt="PyPI status"></a>
|
|
48
50
|
<a href="https://pypi.python.org/pypi/xloft/" alt="PyPI version fury.io"><img src="https://badge.fury.io/py/xloft.svg" alt="PyPI version fury.io"></a>
|
|
49
51
|
<br>
|
|
50
|
-
<a href="https://
|
|
51
|
-
<a href="https://pepy.tech/projects/xloft"><img src="https://static.pepy.tech/badge/xloft" alt="PyPI Downloads"></a>
|
|
52
|
-
<a href="https://github.com/kebasyaty/xloft/blob/main/LICENSE" alt="GitHub license"><img src="https://img.shields.io/github/license/kebasyaty/xloft" alt="GitHub license"></a>
|
|
53
|
-
<a href="https://mypy-lang.org/" alt="Types: Mypy"><img src="https://img.shields.io/badge/types-Mypy-202235.svg?color=0c7ebf" alt="Types: Mypy"></a>
|
|
52
|
+
<a href="https://pyrefly.org/" alt="Types: Pyrefly"><img src="https://img.shields.io/badge/types-Pyrefly-FFB74D.svg" alt="Types: Pyrefly"></a>
|
|
54
53
|
<a href="https://docs.astral.sh/ruff/" alt="Code style: Ruff"><img src="https://img.shields.io/badge/code%20style-Ruff-FDD835.svg" alt="Code style: Ruff"></a>
|
|
55
|
-
<a href="https://github.com/kebasyaty/xloft" alt="PyPI implementation"><img src="https://img.shields.io/pypi/implementation/xloft" alt="PyPI implementation"></a>
|
|
56
|
-
<br>
|
|
57
54
|
<a href="https://pypi.org/project/xloft"><img src="https://img.shields.io/pypi/format/xloft" alt="Format"></a>
|
|
58
|
-
<a href="https://
|
|
59
|
-
<a href="https://github.com/kebasyaty/xloft"><img src="https://img.shields.io/github/
|
|
60
|
-
<a href="https://github.com/kebasyaty/xloft"><img src="https://img.shields.io/github/last-commit/kebasyaty/xloft/main" alt="Last commit"></a>
|
|
61
|
-
<a href="https://github.com/kebasyaty/xloft/releases/" alt="GitHub release"><img src="https://img.shields.io/github/release/kebasyaty/xloft" alt="GitHub release"></a>
|
|
55
|
+
<a href="https://pepy.tech/projects/xloft"><img src="https://static.pepy.tech/badge/xloft" alt="PyPI Downloads"></a>
|
|
56
|
+
<a href="https://github.com/kebasyaty/xloft/blob/main/LICENSE" alt="GitHub license"><img src="https://img.shields.io/github/license/kebasyaty/xloft" alt="GitHub license"></a>
|
|
62
57
|
</p>
|
|
63
58
|
<p align="center">
|
|
64
|
-
The collection is represented by three modules of `NamedTuple`, `
|
|
59
|
+
The collection is represented by three modules of `NamedTuple`, `Converters`, `ItIs`.
|
|
65
60
|
<br>
|
|
66
61
|
In the future, new tools can be added.
|
|
67
62
|
</p>
|
|
@@ -70,13 +65,6 @@ Description-Content-Type: text/markdown
|
|
|
70
65
|
|
|
71
66
|
##
|
|
72
67
|
|
|
73
|
-
<img src="https://raw.githubusercontent.com/kebasyaty/xloft/v0/assets/attention.svg" alt="Attention">
|
|
74
|
-
<p>
|
|
75
|
-
The `quantum` module was deleted.
|
|
76
|
-
<br>
|
|
77
|
-
<a href="https://pypi.python.org/pypi/quantum-loop/" alt="quantum-loop">He is now here</a>
|
|
78
|
-
</p>
|
|
79
|
-
|
|
80
68
|
<br>
|
|
81
69
|
|
|
82
70
|
## Documentation
|
|
@@ -98,6 +86,8 @@ uv add xloft
|
|
|
98
86
|
- **NamedTuple**
|
|
99
87
|
|
|
100
88
|
```python
|
|
89
|
+
"""This class imitates the behavior of the `named tuple`."""
|
|
90
|
+
|
|
101
91
|
from xloft import NamedTuple
|
|
102
92
|
|
|
103
93
|
|
|
@@ -155,30 +145,68 @@ nt["y"] = "Hi" # => TypeError
|
|
|
155
145
|
nt["_id"] = "new_id" # => TypeError
|
|
156
146
|
nt["z"] = [1, 2, 3] # => TypeError
|
|
157
147
|
|
|
158
|
-
nt.x = 20 # => raise:
|
|
159
|
-
nt.y = "Hi" # => raise:
|
|
160
|
-
nt._id = "new_id" # => raise:
|
|
161
|
-
nt.z = [1, 2, 3] # => raise:
|
|
148
|
+
nt.x = 20 # => raise: AttributeDoesNotSetValueError
|
|
149
|
+
nt.y = "Hi" # => raise: AttributeDoesNotSetValueError
|
|
150
|
+
nt._id = "new_id" # => raise: AttributeDoesNotSetValueError
|
|
151
|
+
nt.z = [1, 2, 3] # => raise: AttributeDoesNotSetValueError
|
|
162
152
|
|
|
163
|
-
del nt.x # => raise:
|
|
164
|
-
del nt.y # => raise:
|
|
165
|
-
del nt._id # => raise:
|
|
153
|
+
del nt.x # => raise: AttributeCannotBeDeleteError
|
|
154
|
+
del nt.y # => raise: AttributeCannotBeDeleteError
|
|
155
|
+
del nt._id # => raise: AttributeCannotBeDeleteError
|
|
166
156
|
```
|
|
167
157
|
|
|
168
|
-
- **
|
|
158
|
+
- **Converters**
|
|
169
159
|
|
|
170
160
|
```python
|
|
171
|
-
|
|
161
|
+
"""Convert the number of bytes into a human-readable format."""
|
|
172
162
|
|
|
163
|
+
from xloft import to_human_size, int_to_roman, roman_to_int
|
|
164
|
+
# from xloft.converters import to_human_size, int_to_roman, roman_to_int
|
|
173
165
|
|
|
174
|
-
s = to_human_size(200)
|
|
175
|
-
print(s) # => 200 bytes
|
|
176
166
|
|
|
177
|
-
|
|
178
|
-
|
|
167
|
+
to_human_size(200) # => 200 bytes
|
|
168
|
+
to_human_size(1048576) # => 1 MB
|
|
169
|
+
to_human_size(1048575) # => 1023.999 KB
|
|
170
|
+
#
|
|
171
|
+
int_to_roman(1994) # => MCMXCIV
|
|
172
|
+
roman_to_int("MCMXCIV") # => 1994
|
|
173
|
+
```
|
|
179
174
|
|
|
180
|
-
|
|
181
|
-
|
|
175
|
+
- **ItIs**
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
"""Check if a string is a number."""
|
|
179
|
+
|
|
180
|
+
from xloft import is_number, is_palindrome
|
|
181
|
+
# from xloft.itis import is_number, is_palindrome
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
is_number("") # => False
|
|
185
|
+
is_number(" ") # => False
|
|
186
|
+
is_number("1230.") # => False
|
|
187
|
+
is_number("0x5") # => False
|
|
188
|
+
is_number("0o5") # => False
|
|
189
|
+
is_number("-5.0") # => True
|
|
190
|
+
is_number("+5.0") # => True
|
|
191
|
+
is_number("5.0") # => True
|
|
192
|
+
is_number(".5") # => True
|
|
193
|
+
is_number("5.") # => True
|
|
194
|
+
is_number("3.4E+38") # => True
|
|
195
|
+
is_number("3.4E-38") # => True
|
|
196
|
+
is_number("1.7E+308") # => True
|
|
197
|
+
is_number("1.7E-308") # => True
|
|
198
|
+
is_number("-1.7976931348623157e+308") # => True
|
|
199
|
+
is_number("1.7976931348623157e+308") # => True
|
|
200
|
+
is_number("72028601076372765770200707816364342373431783018070841859646251155447849538676") # => True
|
|
201
|
+
is_number("-72028601076372765770200707816364342373431783018070841859646251155447849538676") # => True
|
|
202
|
+
#
|
|
203
|
+
is_palindrome("racecar") # True
|
|
204
|
+
is_palindrome("Go hang a salami, I'm a lasagna hog") # True
|
|
205
|
+
is_palindrome("22022022") # True
|
|
206
|
+
is_palindrome("Gene") # False
|
|
207
|
+
is_palindrome("123") # False
|
|
208
|
+
is_palindrome(123) # TypeError
|
|
209
|
+
is_palindrome("") # ValueError
|
|
182
210
|
```
|
|
183
211
|
|
|
184
212
|
## Changelog
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
xloft/__init__.py,sha256=hHQbBnIet5HUmjwp8R-6BCkGkFFSJYnXYz3INWFLwoc,1157
|
|
2
|
+
xloft/errors.py,sha256=FuI9IWgoD7J5Z34ijXhAGDBAEwBdbJOrHThEk1I33kI,988
|
|
3
|
+
xloft/itis.py,sha256=iQiPh4tvsHVqO5UIk3ZAcFQLS0KBPDogT6A0cNttjFk,1321
|
|
4
|
+
xloft/namedtuple.py,sha256=NFqgaArayECek36v7_rIfOhb8TgnXTY3XfSgwT_4yCY,5539
|
|
5
|
+
xloft/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
xloft/converters/__init__.py,sha256=YxWzIqa9TgDTc2aSJnxniKWdaQF_GGOu--5k1yOR8mA,510
|
|
7
|
+
xloft/converters/human_size.py,sha256=-nxGQIz5_KMTSbOigYWPbXk4u2IAugTHpUYC_o2AM6E,1110
|
|
8
|
+
xloft/converters/roman.py,sha256=pqoM3xwaafzJtI6Fih--2GykM9JuOJ7sXaJbqZYlwmE,2293
|
|
9
|
+
xloft-0.9.6.dist-info/METADATA,sha256=Y6km_9v-wuHeeDbcGcR0TTNz9mNY3rE2MRzCOVLyiXg,7445
|
|
10
|
+
xloft-0.9.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
11
|
+
xloft-0.9.6.dist-info/licenses/LICENSE,sha256=mS0Wz0yGNB63gEcWEnuIb_lldDYV0sjRaO-o_GL6CWE,1074
|
|
12
|
+
xloft-0.9.6.dist-info/RECORD,,
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Gennady Kostyunin
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Gennady Kostyunin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
xloft/human.py
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"""A collection of instruments for converting data to format is convenient for humans.
|
|
2
|
-
|
|
3
|
-
The module contains the following functions:
|
|
4
|
-
|
|
5
|
-
- `to_human_size(size)` - Returns a humanized string: 200 bytes | 1 KB | 1.5 MB etc.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
__all__ = (
|
|
11
|
-
"to_human_size",
|
|
12
|
-
"get_cache_human_size",
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
import math
|
|
16
|
-
|
|
17
|
-
# To caching the results from to_human_size method.
|
|
18
|
-
_cache_human_size: dict[int, str] = {}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def get_cache_human_size() -> dict[int, str]:
|
|
22
|
-
"""Get a copy of variable _cach_human_size.
|
|
23
|
-
|
|
24
|
-
Hint: To tests.
|
|
25
|
-
"""
|
|
26
|
-
return _cache_human_size.copy()
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def clean_cache_human_size() -> None:
|
|
30
|
-
"""Reset of variable _cach_human_size."""
|
|
31
|
-
global _cache_human_size # noqa: PLW0603
|
|
32
|
-
_cache_human_size = {}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def to_human_size(n_bytes: int) -> str:
|
|
36
|
-
"""Convert number of bytes to readable format.
|
|
37
|
-
|
|
38
|
-
Examples:
|
|
39
|
-
>>> from xloft import to_human_size
|
|
40
|
-
>>> to_human_size(200)
|
|
41
|
-
200 bytes
|
|
42
|
-
>>> to_human_size(1048576)
|
|
43
|
-
1 MB
|
|
44
|
-
>>> to_human_size(1048575)
|
|
45
|
-
1023.999 KB
|
|
46
|
-
|
|
47
|
-
Args:
|
|
48
|
-
n_bytes: The number of bytes.
|
|
49
|
-
|
|
50
|
-
Returns:
|
|
51
|
-
Returns a humanized string: 200 bytes | 1 KB | 1.5 MB etc.
|
|
52
|
-
"""
|
|
53
|
-
result: str | None = _cache_human_size.get(n_bytes)
|
|
54
|
-
if result is not None:
|
|
55
|
-
return result
|
|
56
|
-
idx: int = math.floor(math.log(n_bytes) / math.log(1024))
|
|
57
|
-
ndigits: int = [0, 3, 6, 9, 12][idx]
|
|
58
|
-
human_size: int | float = n_bytes if n_bytes < 1024 else abs(round(n_bytes / pow(1024, idx), ndigits))
|
|
59
|
-
order = ["bytes", "KB", "MB", "GB", "TB"][idx]
|
|
60
|
-
if math.modf(human_size)[0] == 0.0:
|
|
61
|
-
human_size = int(human_size)
|
|
62
|
-
result = f"{human_size} {order}"
|
|
63
|
-
_cache_human_size[n_bytes] = result
|
|
64
|
-
return result
|
xloft-0.5.1.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
xloft/__init__.py,sha256=mf6z2-Tnl-CdYMa8mrI5MlTl48G0GQoYNNj2PMp8SsQ,419
|
|
2
|
-
xloft/errors.py,sha256=hZcmF0QVVdvE5oM1jsXymRk_pPGgDSnUDM9wx9zJAYQ,895
|
|
3
|
-
xloft/human.py,sha256=WQbVOKpOvzGot-c7f3xitbS05JUIQmj3dreGtRV6GA0,1792
|
|
4
|
-
xloft/namedtuple.py,sha256=a_l3bZF-L2I7MGxuF2CXzAHgNai-Vyj6SY1ODwxs7TU,6856
|
|
5
|
-
xloft/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
xloft-0.5.1.dist-info/METADATA,sha256=o24kZAXLE4z4CaUnpSlqLbl-JihkCc0eXsP4mLsZQ-M,7079
|
|
7
|
-
xloft-0.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
8
|
-
xloft-0.5.1.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
|
|
9
|
-
xloft-0.5.1.dist-info/RECORD,,
|