velocity-python 0.0.30__py3-none-any.whl → 0.0.32__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 velocity-python might be problematic. Click here for more details.
- velocity/__init__.py +1 -1
- velocity/aws/__init__.py +4 -8
- velocity/aws/handlers/response.py +203 -52
- velocity/db/core/column.py +31 -20
- velocity/db/core/database.py +9 -9
- velocity/db/core/engine.py +101 -99
- velocity/db/core/exceptions.py +23 -0
- velocity/db/core/sequence.py +11 -3
- velocity/db/servers/mysql.py +580 -282
- velocity/db/servers/sqlite.py +649 -371
- velocity/db/servers/sqlserver.py +746 -331
- velocity/misc/conv/__init__.py +1 -1
- velocity/misc/conv/iconv.py +106 -143
- velocity/misc/conv/oconv.py +128 -162
- velocity/misc/db.py +25 -19
- velocity/misc/export.py +125 -115
- velocity/misc/format.py +57 -59
- velocity/misc/mail.py +51 -40
- velocity/misc/merge.py +34 -17
- velocity/misc/timer.py +35 -12
- {velocity_python-0.0.30.dist-info → velocity_python-0.0.32.dist-info}/METADATA +1 -1
- velocity_python-0.0.32.dist-info/RECORD +39 -0
- {velocity_python-0.0.30.dist-info → velocity_python-0.0.32.dist-info}/WHEEL +1 -1
- velocity_python-0.0.30.dist-info/RECORD +0 -39
- {velocity_python-0.0.30.dist-info → velocity_python-0.0.32.dist-info}/LICENSE +0 -0
- {velocity_python-0.0.30.dist-info → velocity_python-0.0.32.dist-info}/top_level.txt +0 -0
velocity/misc/conv/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
from . import iconv
|
|
2
|
-
from . import oconv
|
|
2
|
+
from . import oconv
|
velocity/misc/conv/iconv.py
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
|
+
# iconv.py
|
|
1
2
|
import re
|
|
2
3
|
import codecs
|
|
3
|
-
|
|
4
|
+
from decimal import Decimal, ROUND_HALF_UP
|
|
4
5
|
from email.utils import parseaddr
|
|
5
6
|
from datetime import datetime
|
|
7
|
+
from typing import Optional, Union, Callable
|
|
6
8
|
|
|
9
|
+
# Convert data to SQL format for storage
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if data
|
|
12
|
-
return None
|
|
13
|
-
if data == "@NULL":
|
|
14
|
-
return None
|
|
15
|
-
return data
|
|
11
|
+
|
|
12
|
+
def none(data: str) -> Optional[str]:
|
|
13
|
+
"""Converts various 'null' representations to None."""
|
|
14
|
+
return None if data in ("", "null", "None", "@NULL") else data
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
def phone(data):
|
|
19
|
-
|
|
17
|
+
def phone(data: str) -> Optional[str]:
|
|
18
|
+
"""Extracts a 10-digit phone number or returns None if invalid."""
|
|
19
|
+
if data in ("None", None):
|
|
20
20
|
return None
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return
|
|
21
|
+
cleaned_data = re.sub(r"[^0-9]", "", data)
|
|
22
|
+
match = re.search(r"\d{10}$", cleaned_data)
|
|
23
|
+
return match.group() if match else None
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def day_of_week(data):
|
|
26
|
+
def day_of_week(data: str) -> Optional[int]:
|
|
27
|
+
"""Converts day of the week to an integer representation."""
|
|
27
28
|
if not data:
|
|
28
|
-
return
|
|
29
|
-
|
|
29
|
+
return None
|
|
30
|
+
days = {
|
|
30
31
|
"monday": 1,
|
|
31
32
|
"tuesday": 2,
|
|
32
33
|
"wednesday": 3,
|
|
@@ -41,174 +42,137 @@ def day_of_week(data):
|
|
|
41
42
|
"fri": 5,
|
|
42
43
|
"sat": 6,
|
|
43
44
|
"sun": 7,
|
|
44
|
-
}
|
|
45
|
-
|
|
45
|
+
}
|
|
46
|
+
return days.get(data.lower())
|
|
46
47
|
|
|
47
|
-
def date(*args, **kwds):
|
|
48
|
-
kwds.setdefault("fmt", "%Y-%m-%d")
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if args and args[0]:
|
|
57
|
-
return _(args[0])
|
|
58
|
-
return _
|
|
49
|
+
def date(data: str, fmt: str = "%Y-%m-%d") -> Optional[datetime.date]:
|
|
50
|
+
"""Parses a date string into a date object using the specified format."""
|
|
51
|
+
try:
|
|
52
|
+
return datetime.strptime(data, fmt).date()
|
|
53
|
+
except (ValueError, TypeError):
|
|
54
|
+
return None
|
|
59
55
|
|
|
60
56
|
|
|
61
|
-
def time(
|
|
62
|
-
|
|
57
|
+
def time(data: str, fmt: str = "%X") -> Optional[datetime.time]:
|
|
58
|
+
"""Parses a time string into a time object using the specified format."""
|
|
59
|
+
try:
|
|
60
|
+
return datetime.strptime(data, fmt).time()
|
|
61
|
+
except (ValueError, TypeError):
|
|
62
|
+
return None
|
|
63
63
|
|
|
64
|
-
def _(param):
|
|
65
|
-
if isinstance(param, str):
|
|
66
|
-
return datetime.strptime(param, kwds["fmt"]).time()
|
|
67
|
-
else:
|
|
68
|
-
return param
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
def timestamp(data: str, fmt: str = "%c") -> Optional[datetime]:
|
|
66
|
+
"""Parses a timestamp string into a datetime object using the specified format."""
|
|
67
|
+
try:
|
|
68
|
+
return datetime.strptime(data, fmt)
|
|
69
|
+
except (ValueError, TypeError):
|
|
70
|
+
return None
|
|
73
71
|
|
|
74
72
|
|
|
75
|
-
def
|
|
76
|
-
|
|
73
|
+
def email(data: str) -> Optional[str]:
|
|
74
|
+
"""Validates and returns an email address if properly formatted."""
|
|
75
|
+
if not data or data.lower() == "none":
|
|
76
|
+
return None
|
|
77
|
+
data = data.strip().lower()
|
|
78
|
+
email_address = parseaddr(data)[1]
|
|
79
|
+
if "@" in email_address and "." in email_address.split("@")[1]:
|
|
80
|
+
return email_address
|
|
81
|
+
raise ValueError("Invalid email format")
|
|
77
82
|
|
|
78
|
-
def _(param):
|
|
79
|
-
if isinstance(param, str):
|
|
80
|
-
return datetime.strptime(param, kwds["fmt"])
|
|
81
|
-
else:
|
|
82
|
-
return param
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return
|
|
84
|
+
def integer(data: str) -> int:
|
|
85
|
+
"""Converts a string to an integer, removing non-numeric characters."""
|
|
86
|
+
return int(re.sub(r"[^0-9\.-]", "", data))
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
def
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return None
|
|
94
|
-
data = data.strip().lower()
|
|
95
|
-
if "@" not in data:
|
|
96
|
-
raise Exception()
|
|
97
|
-
email = parseaddr(data)[1]
|
|
98
|
-
mailbox, domain = email.split("@")
|
|
99
|
-
if "." in domain:
|
|
100
|
-
if len(domain.split(".")[1]) < 1:
|
|
101
|
-
raise Exception()
|
|
102
|
-
else:
|
|
103
|
-
raise Exception()
|
|
104
|
-
return data
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def integer(data):
|
|
108
|
-
return int(re.sub("[^0-9\.-]", "", str(data)))
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def boolean(data):
|
|
112
|
-
if isinstance(data, str):
|
|
113
|
-
if data.lower() in ["false", "", "f", "off", "no"]:
|
|
114
|
-
return False
|
|
89
|
+
def boolean(data: Union[str, bool]) -> bool:
|
|
90
|
+
"""Converts various string representations to a boolean."""
|
|
91
|
+
if isinstance(data, str) and data.lower() in ["false", "", "f", "off", "no"]:
|
|
92
|
+
return False
|
|
115
93
|
return bool(data)
|
|
116
94
|
|
|
117
95
|
|
|
118
|
-
def rot13(data):
|
|
96
|
+
def rot13(data: str) -> str:
|
|
97
|
+
"""Encodes a string using ROT13."""
|
|
119
98
|
return codecs.encode(data, "rot13")
|
|
120
99
|
|
|
121
100
|
|
|
122
|
-
def pointer(data):
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if data == "":
|
|
126
|
-
return None
|
|
127
|
-
if data == None:
|
|
128
|
-
return None
|
|
129
|
-
if data == "@NULL":
|
|
101
|
+
def pointer(data: Union[str, None]) -> Optional[int]:
|
|
102
|
+
"""Converts a pointer to an integer, or returns None for null values."""
|
|
103
|
+
if data in ("@new", "", "@NULL", None):
|
|
130
104
|
return None
|
|
131
105
|
return int(data)
|
|
132
106
|
|
|
133
107
|
|
|
134
|
-
def money(data):
|
|
135
|
-
|
|
108
|
+
def money(data: str) -> Optional[Decimal]:
|
|
109
|
+
"""Converts a monetary string to a Decimal, removing non-numeric characters."""
|
|
110
|
+
if data in ("None", None):
|
|
136
111
|
return None
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return _decimal.Decimal(re.sub("[^0-9\.-]", "", str(data)))
|
|
112
|
+
return Decimal(re.sub(r"[^0-9\.-]", "", data))
|
|
113
|
+
|
|
140
114
|
|
|
115
|
+
def round_to(
|
|
116
|
+
precision: int, data: Optional[Union[str, float, Decimal]] = None
|
|
117
|
+
) -> Union[Decimal, Callable[[Union[str, float, Decimal]], Decimal]]:
|
|
118
|
+
"""Rounds a number to a specified precision."""
|
|
141
119
|
|
|
142
|
-
def
|
|
143
|
-
|
|
144
|
-
if data == "None":
|
|
120
|
+
def function(value):
|
|
121
|
+
if value in ("None", None):
|
|
145
122
|
return None
|
|
146
|
-
if
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return _decimal.Decimal(data).quantize(
|
|
151
|
-
_decimal.Decimal(10) ** -precision, rounding=_decimal.ROUND_HALF_UP
|
|
123
|
+
if isinstance(value, str):
|
|
124
|
+
value = re.sub(r"[^0-9\.-]", "", value)
|
|
125
|
+
return Decimal(value).quantize(
|
|
126
|
+
Decimal(10) ** -precision, rounding=ROUND_HALF_UP
|
|
152
127
|
)
|
|
153
128
|
|
|
154
|
-
if data
|
|
155
|
-
return function
|
|
156
|
-
return function(data)
|
|
129
|
+
return function(data) if data is not None else function
|
|
157
130
|
|
|
158
131
|
|
|
159
|
-
def decimal(data):
|
|
160
|
-
|
|
132
|
+
def decimal(data: str) -> Optional[Decimal]:
|
|
133
|
+
"""Converts a numeric string to a Decimal, removing non-numeric characters."""
|
|
134
|
+
if data in ("None", None):
|
|
161
135
|
return None
|
|
162
|
-
|
|
163
|
-
return data
|
|
164
|
-
return _decimal.Decimal(re.sub("[^0-9\.-]", "", str(data)))
|
|
136
|
+
return Decimal(re.sub(r"[^0-9\.-]", "", data))
|
|
165
137
|
|
|
166
138
|
|
|
167
|
-
def ein(data):
|
|
168
|
-
|
|
139
|
+
def ein(data: str) -> Optional[str]:
|
|
140
|
+
"""Validates and returns a 9-digit EIN, or None if invalid."""
|
|
141
|
+
if data in ("None", None):
|
|
169
142
|
return None
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return
|
|
143
|
+
cleaned_data = re.sub(r"[^0-9]", "", data)
|
|
144
|
+
match = re.fullmatch(r"\d{9}", cleaned_data)
|
|
145
|
+
return match.group() if match else None
|
|
173
146
|
|
|
174
147
|
|
|
175
|
-
def
|
|
148
|
+
def to_list(data: Union[str, list]) -> Optional[list]:
|
|
149
|
+
"""Converts a string or single element into a list representation."""
|
|
176
150
|
if data in (None, "None"):
|
|
177
151
|
return None
|
|
178
|
-
if isinstance(data, str):
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
data = [data]
|
|
183
|
-
return repr(data)
|
|
152
|
+
if isinstance(data, str) and data.startswith("["):
|
|
153
|
+
return eval(data) # Assuming the input string is a list string
|
|
154
|
+
return [data] if not isinstance(data, list) else data
|
|
155
|
+
|
|
184
156
|
|
|
157
|
+
def title(data: str) -> str:
|
|
158
|
+
"""Converts a string to title case."""
|
|
159
|
+
return "" if data in (None, "None") else str(data).title()
|
|
185
160
|
|
|
186
|
-
def title(data):
|
|
187
|
-
if data == None:
|
|
188
|
-
return ""
|
|
189
|
-
if data == "None":
|
|
190
|
-
return ""
|
|
191
|
-
return str(data).title()
|
|
192
161
|
|
|
162
|
+
def lower(data: str) -> str:
|
|
163
|
+
"""Converts a string to lowercase."""
|
|
164
|
+
return "" if data in (None, "None") else str(data).lower()
|
|
193
165
|
|
|
194
|
-
def lower(data):
|
|
195
|
-
if data == None:
|
|
196
|
-
return ""
|
|
197
|
-
if data == "None":
|
|
198
|
-
return ""
|
|
199
|
-
return str(data).lower()
|
|
200
166
|
|
|
167
|
+
def upper(data: str) -> str:
|
|
168
|
+
"""Converts a string to uppercase."""
|
|
169
|
+
return "" if data in (None, "None") else str(data).upper()
|
|
201
170
|
|
|
202
|
-
def upper(data):
|
|
203
|
-
if data == None:
|
|
204
|
-
return ""
|
|
205
|
-
if data == "None":
|
|
206
|
-
return ""
|
|
207
|
-
return str(data).upper()
|
|
208
171
|
|
|
172
|
+
def padding(length: int, char: str = " ") -> Callable[[str], Optional[str]]:
|
|
173
|
+
"""Pads a string to the specified length with a given character."""
|
|
209
174
|
|
|
210
|
-
def
|
|
211
|
-
def inner(data):
|
|
175
|
+
def inner(data: str) -> Optional[str]:
|
|
212
176
|
if data in [None, "None", ""]:
|
|
213
177
|
return None
|
|
214
178
|
return str(data).rjust(length, char)
|
|
@@ -216,7 +180,6 @@ def padding(length, char):
|
|
|
216
180
|
return inner
|
|
217
181
|
|
|
218
182
|
|
|
219
|
-
def string(data):
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return str(data)
|
|
183
|
+
def string(data: str) -> Optional[str]:
|
|
184
|
+
"""Converts an empty string to None, otherwise returns the string itself."""
|
|
185
|
+
return None if data == "" else str(data)
|
velocity/misc/conv/oconv.py
CHANGED
|
@@ -3,202 +3,168 @@ import codecs
|
|
|
3
3
|
import decimal
|
|
4
4
|
from datetime import datetime, date, time
|
|
5
5
|
from pprint import pformat
|
|
6
|
+
from typing import Optional, Union, List, Callable
|
|
7
|
+
|
|
8
|
+
# Convert SQL data to JS format for display
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def none(data: Optional[str]) -> str:
|
|
12
|
+
"""Converts various 'null' representations to an empty string."""
|
|
13
|
+
return "" if data in (None, "None", "null", "@NULL") else data
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def phone(data: Optional[str]) -> str:
|
|
17
|
+
"""Formats a 10-digit phone number as (XXX) XXX-XXXX or returns an empty string if invalid."""
|
|
18
|
+
if data in (None, "None", ""):
|
|
19
|
+
return ""
|
|
20
|
+
digits = re.sub(r"[^0-9]", "", data)
|
|
21
|
+
match = re.search(r"\d{10}$", digits)
|
|
22
|
+
if match:
|
|
23
|
+
num = match.group()
|
|
24
|
+
return f"({num[:3]}) {num[3:6]}-{num[6:]}"
|
|
25
|
+
return ""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def day_of_week(data: Union[int, str, List], abbrev: bool = False) -> str:
|
|
29
|
+
"""Converts a day number (1-7) to a day name, abbreviated if specified. Supports lists."""
|
|
30
|
+
days_full = {
|
|
31
|
+
1: "Monday",
|
|
32
|
+
2: "Tuesday",
|
|
33
|
+
3: "Wednesday",
|
|
34
|
+
4: "Thursday",
|
|
35
|
+
5: "Friday",
|
|
36
|
+
6: "Saturday",
|
|
37
|
+
7: "Sunday",
|
|
38
|
+
}
|
|
39
|
+
days_abbrev = {1: "Mon", 2: "Tue", 3: "Wed", 4: "Thu", 5: "Fri", 6: "Sat", 7: "Sun"}
|
|
40
|
+
days = days_abbrev if abbrev else days_full
|
|
6
41
|
|
|
7
|
-
def none(data):
|
|
8
|
-
if data == None:
|
|
9
|
-
return ''
|
|
10
|
-
if data == 'None':
|
|
11
|
-
return ''
|
|
12
|
-
if data == 'null':
|
|
13
|
-
return ''
|
|
14
|
-
return data
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def phone(data):
|
|
18
|
-
if data == None:
|
|
19
|
-
return ''
|
|
20
|
-
if data == 'None':
|
|
21
|
-
return ''
|
|
22
|
-
if not data:
|
|
23
|
-
return data
|
|
24
|
-
data = re.search(r'\d{10}$', re.sub("[^0-9]", "", data)).group()
|
|
25
|
-
return "({}) {}-{}".format(data[:3],data[3:6],data[6:])
|
|
26
|
-
|
|
27
|
-
def day_of_week(data, abbrev=False):
|
|
28
42
|
if isinstance(data, list):
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def date(*args, **kwds):
|
|
61
|
-
kwds.setdefault('fmt','%Y-%m-%d')
|
|
62
|
-
def _(param):
|
|
63
|
-
if isinstance(param,(datetime, date)):
|
|
64
|
-
return param.strftime( kwds['fmt'] )
|
|
65
|
-
else:
|
|
66
|
-
return param
|
|
67
|
-
if args and args[0]:
|
|
68
|
-
return _(args[0])
|
|
69
|
-
return _
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def time(*args, **kwds):
|
|
73
|
-
kwds.setdefault('fmt','%X')
|
|
74
|
-
def _(param):
|
|
75
|
-
if isinstance(param,(datetime, time)):
|
|
76
|
-
return param.strftime( kwds['fmt'] )
|
|
77
|
-
else:
|
|
78
|
-
return param
|
|
79
|
-
if args and args[0]:
|
|
80
|
-
return _(args[0])
|
|
81
|
-
return _
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def timestamp(*args, **kwds):
|
|
85
|
-
kwds.setdefault('fmt','%c')
|
|
86
|
-
def _(param):
|
|
87
|
-
if isinstance(param,(datetime)):
|
|
88
|
-
return param.strftime( kwds['fmt'] )
|
|
89
|
-
else:
|
|
90
|
-
return param
|
|
91
|
-
if args:
|
|
92
|
-
return _(args[0])
|
|
93
|
-
return _
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def email(data):
|
|
97
|
-
if data == None:
|
|
98
|
-
return ''
|
|
99
|
-
if data == 'None':
|
|
100
|
-
return ''
|
|
101
|
-
return data.lower()
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def pointer(data):
|
|
43
|
+
return ",".join(day_of_week(day, abbrev) for day in data if day in days)
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
return days[int(data)]
|
|
47
|
+
except (ValueError, KeyError, TypeError):
|
|
48
|
+
return ""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def date(data: Union[datetime, date, str], fmt: str = "%Y-%m-%d") -> str:
|
|
52
|
+
"""Formats a date object as a string according to the specified format."""
|
|
53
|
+
return data.strftime(fmt) if isinstance(data, (datetime, date)) else str(data)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def time(data: Union[datetime, time, str], fmt: str = "%X") -> str:
|
|
57
|
+
"""Formats a time object as a string according to the specified format."""
|
|
58
|
+
return data.strftime(fmt) if isinstance(data, (datetime, time)) else str(data)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def timestamp(data: Union[datetime, str], fmt: str = "%c") -> str:
|
|
62
|
+
"""Formats a datetime object as a string according to the specified format."""
|
|
63
|
+
return data.strftime(fmt) if isinstance(data, datetime) else str(data)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def email(data: Optional[str]) -> str:
|
|
67
|
+
"""Returns a lowercase email address or an empty string if invalid."""
|
|
68
|
+
return "" if data in (None, "None") else data.lower()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def pointer(data: Union[str, int]) -> Union[int, str]:
|
|
72
|
+
"""Converts a string to an integer, or returns an empty string if conversion fails."""
|
|
105
73
|
try:
|
|
106
74
|
return int(data)
|
|
107
|
-
except:
|
|
108
|
-
return
|
|
75
|
+
except (ValueError, TypeError):
|
|
76
|
+
return ""
|
|
109
77
|
|
|
110
78
|
|
|
111
|
-
def rot13(data):
|
|
112
|
-
|
|
79
|
+
def rot13(data: str) -> str:
|
|
80
|
+
"""Encodes a string using ROT13."""
|
|
81
|
+
return codecs.decode(data, "rot13")
|
|
113
82
|
|
|
114
83
|
|
|
115
|
-
def boolean(data):
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
84
|
+
def boolean(data: Union[str, bool]) -> bool:
|
|
85
|
+
"""Converts various representations to a boolean."""
|
|
86
|
+
if isinstance(data, str) and data.lower() in ["false", "", "f", "off", "no"]:
|
|
87
|
+
return False
|
|
119
88
|
return bool(data)
|
|
120
89
|
|
|
121
90
|
|
|
122
|
-
def money(data):
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
91
|
+
def money(data: str) -> str:
|
|
92
|
+
"""Formats a numeric string as currency."""
|
|
93
|
+
if data in [None, ""]:
|
|
94
|
+
return ""
|
|
95
|
+
cleaned_data = re.sub(r"[^0-9\.-]", "", str(data))
|
|
96
|
+
return f"${decimal.Decimal(cleaned_data):,.2f}"
|
|
127
97
|
|
|
128
98
|
|
|
129
|
-
def
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return '0'
|
|
134
|
-
return '{:.{prec}f}'.format(decimal.Decimal(data), prec=precision)
|
|
135
|
-
if data == None:
|
|
136
|
-
return function
|
|
137
|
-
return function(data)
|
|
99
|
+
def round_to(
|
|
100
|
+
precision: int, data: Optional[Union[str, float, decimal.Decimal]] = None
|
|
101
|
+
) -> Union[Callable, str]:
|
|
102
|
+
"""Rounds a number to the specified precision."""
|
|
138
103
|
|
|
104
|
+
def function(value):
|
|
105
|
+
cleaned_value = re.sub(r"[^0-9\.-]", "", str(value))
|
|
106
|
+
return (
|
|
107
|
+
f"{decimal.Decimal(cleaned_value):.{precision}f}" if cleaned_value else "0"
|
|
108
|
+
)
|
|
139
109
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if
|
|
146
|
-
return
|
|
147
|
-
|
|
148
|
-
|
|
110
|
+
return function if data is None else function(data)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def ein(data: str) -> str:
|
|
114
|
+
"""Formats a 9-digit EIN as XX-XXXXXXX or returns an empty string if invalid."""
|
|
115
|
+
if data in (None, "None", ""):
|
|
116
|
+
return ""
|
|
117
|
+
cleaned_data = re.sub(r"[^0-9]", "", data)
|
|
118
|
+
match = re.fullmatch(r"\d{9}", cleaned_data)
|
|
119
|
+
return f"{cleaned_data[:2]}-{cleaned_data[2:]}" if match else ""
|
|
149
120
|
|
|
150
121
|
|
|
151
|
-
def
|
|
152
|
-
|
|
122
|
+
def to_list(data: Union[str, List]) -> Optional[List]:
|
|
123
|
+
"""Converts a single element or JSON-like list string to a list."""
|
|
124
|
+
if data in (None, "None"):
|
|
153
125
|
return None
|
|
154
126
|
if isinstance(data, list):
|
|
155
127
|
return data
|
|
156
|
-
if isinstance(data, str):
|
|
157
|
-
|
|
158
|
-
return eval(data)
|
|
128
|
+
if isinstance(data, str) and data.startswith("["):
|
|
129
|
+
try:
|
|
130
|
+
return eval(data) # Be cautious with eval; only use if data is trusted
|
|
131
|
+
except (SyntaxError, NameError):
|
|
132
|
+
return None
|
|
159
133
|
return [data]
|
|
160
134
|
|
|
161
135
|
|
|
162
|
-
def title(data):
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
136
|
+
def title(data: Optional[str]) -> str:
|
|
137
|
+
"""Converts a string to title case."""
|
|
138
|
+
return "" if data in (None, "None") else str(data).title()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def lower(data: Optional[str]) -> str:
|
|
142
|
+
"""Converts a string to lowercase."""
|
|
143
|
+
return "" if data in (None, "None") else str(data).lower()
|
|
168
144
|
|
|
169
145
|
|
|
170
|
-
def
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if data == 'None':
|
|
174
|
-
return ''
|
|
175
|
-
return str(data).lower()
|
|
146
|
+
def upper(data: Optional[str]) -> str:
|
|
147
|
+
"""Converts a string to uppercase."""
|
|
148
|
+
return "" if data in (None, "None") else str(data).upper()
|
|
176
149
|
|
|
177
150
|
|
|
178
|
-
def
|
|
179
|
-
|
|
180
|
-
return ''
|
|
181
|
-
if data == 'None':
|
|
182
|
-
return ''
|
|
183
|
-
return str(data).upper()
|
|
151
|
+
def padding(length: int, char: str) -> Callable[[str], str]:
|
|
152
|
+
"""Returns a function that pads a string to the specified length with the given character."""
|
|
184
153
|
|
|
154
|
+
def inner(data: str) -> str:
|
|
155
|
+
return str(data).rjust(length, char) if data not in (None, "None", "") else ""
|
|
185
156
|
|
|
186
|
-
def padding(length, char):
|
|
187
|
-
def inner(data):
|
|
188
|
-
if data is None:
|
|
189
|
-
return ''
|
|
190
|
-
return str(data).rjust(length, char)
|
|
191
157
|
return inner
|
|
192
158
|
|
|
193
159
|
|
|
194
|
-
def pprint(data):
|
|
160
|
+
def pprint(data: str) -> str:
|
|
161
|
+
"""Pretty-prints a JSON-like string representation of data."""
|
|
195
162
|
try:
|
|
196
163
|
return pformat(eval(data))
|
|
197
|
-
except:
|
|
164
|
+
except (SyntaxError, NameError):
|
|
198
165
|
return data
|
|
199
166
|
|
|
200
167
|
|
|
201
|
-
def string(data):
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return str(data)
|
|
168
|
+
def string(data: Optional[str]) -> str:
|
|
169
|
+
"""Converts a None value to an empty string; otherwise returns the string itself."""
|
|
170
|
+
return "" if data is None else str(data)
|