velocity-python 0.0.34__py3-none-any.whl → 0.0.64__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/db/core/column.py +25 -105
- velocity/db/core/database.py +79 -23
- velocity/db/core/decorators.py +84 -47
- velocity/db/core/engine.py +179 -184
- velocity/db/core/result.py +94 -49
- velocity/db/core/row.py +81 -46
- velocity/db/core/sequence.py +112 -22
- velocity/db/core/table.py +660 -243
- velocity/db/core/transaction.py +75 -77
- velocity/db/servers/mysql.py +5 -237
- velocity/db/servers/mysql_reserved.py +237 -0
- velocity/db/servers/postgres/__init__.py +19 -0
- velocity/db/servers/postgres/operators.py +23 -0
- velocity/db/servers/postgres/reserved.py +254 -0
- velocity/db/servers/postgres/sql.py +1041 -0
- velocity/db/servers/postgres/types.py +109 -0
- velocity/db/servers/sqlite.py +1 -210
- velocity/db/servers/sqlite_reserved.py +208 -0
- velocity/db/servers/sqlserver.py +1 -316
- velocity/db/servers/sqlserver_reserved.py +314 -0
- velocity/db/servers/tablehelper.py +277 -0
- velocity/misc/conv/iconv.py +277 -91
- velocity/misc/conv/oconv.py +5 -4
- velocity/misc/db.py +2 -2
- velocity/misc/format.py +2 -2
- {velocity_python-0.0.34.dist-info → velocity_python-0.0.64.dist-info}/METADATA +6 -6
- velocity_python-0.0.64.dist-info/RECORD +47 -0
- {velocity_python-0.0.34.dist-info → velocity_python-0.0.64.dist-info}/WHEEL +1 -1
- velocity/db/servers/postgres.py +0 -1396
- velocity_python-0.0.34.dist-info/RECORD +0 -39
- {velocity_python-0.0.34.dist-info → velocity_python-0.0.64.dist-info}/LICENSE +0 -0
- {velocity_python-0.0.34.dist-info → velocity_python-0.0.64.dist-info}/top_level.txt +0 -0
velocity/misc/conv/iconv.py
CHANGED
|
@@ -1,189 +1,375 @@
|
|
|
1
|
-
# iconv.py
|
|
2
1
|
import re
|
|
2
|
+
import ast
|
|
3
3
|
import codecs
|
|
4
4
|
from decimal import Decimal, ROUND_HALF_UP
|
|
5
5
|
from email.utils import parseaddr
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
from typing import Optional, Union, Callable
|
|
8
8
|
|
|
9
|
-
# Convert data to SQL format for storage
|
|
9
|
+
# Convert JS data to SQL format for storage
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def none(data: str) -> Optional[str]:
|
|
13
|
-
"""
|
|
14
|
-
|
|
13
|
+
"""
|
|
14
|
+
Converts various 'null' representations to None.
|
|
15
|
+
|
|
16
|
+
- Now handles 'null', 'None', '@NULL', or empty string as None.
|
|
17
|
+
- Returns the original string otherwise.
|
|
18
|
+
"""
|
|
19
|
+
if data.strip().lower() in ("null", "none", "@null", ""):
|
|
20
|
+
return None
|
|
21
|
+
return data
|
|
15
22
|
|
|
16
23
|
|
|
17
24
|
def phone(data: str) -> Optional[str]:
|
|
18
|
-
"""
|
|
19
|
-
|
|
25
|
+
"""
|
|
26
|
+
Attempts to normalize a phone number.
|
|
27
|
+
|
|
28
|
+
- Strips all non-digit characters.
|
|
29
|
+
- Accepts 10-digit or 11-digit phone numbers.
|
|
30
|
+
(If 11 digits and starts with '1', we accept the trailing 10 digits).
|
|
31
|
+
- Returns None if the result is not 10 digits after normalization.
|
|
32
|
+
"""
|
|
33
|
+
if not data or data.strip().lower() in ("none", "@null"):
|
|
20
34
|
return None
|
|
21
35
|
cleaned_data = re.sub(r"[^0-9]", "", data)
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
if len(cleaned_data) == 11 and cleaned_data.startswith("1"):
|
|
37
|
+
cleaned_data = cleaned_data[1:] # drop leading '1'
|
|
38
|
+
return cleaned_data if len(cleaned_data) == 10 else None
|
|
24
39
|
|
|
25
40
|
|
|
26
41
|
def day_of_week(data: str) -> Optional[int]:
|
|
27
|
-
"""
|
|
42
|
+
"""
|
|
43
|
+
Converts day of the week to an integer representation (1=Mon,...,7=Sun).
|
|
44
|
+
|
|
45
|
+
- Handles both long and short forms: "monday"/"mon", "tuesday"/"tue", etc.
|
|
46
|
+
- Returns None for unrecognized input.
|
|
47
|
+
"""
|
|
28
48
|
if not data:
|
|
29
49
|
return None
|
|
30
50
|
days = {
|
|
31
51
|
"monday": 1,
|
|
32
|
-
"tuesday": 2,
|
|
33
|
-
"wednesday": 3,
|
|
34
|
-
"thursday": 4,
|
|
35
|
-
"friday": 5,
|
|
36
|
-
"saturday": 6,
|
|
37
|
-
"sunday": 7,
|
|
38
52
|
"mon": 1,
|
|
53
|
+
"tuesday": 2,
|
|
39
54
|
"tue": 2,
|
|
55
|
+
"wednesday": 3,
|
|
40
56
|
"wed": 3,
|
|
57
|
+
"thursday": 4,
|
|
41
58
|
"thu": 4,
|
|
59
|
+
"friday": 5,
|
|
42
60
|
"fri": 5,
|
|
61
|
+
"saturday": 6,
|
|
43
62
|
"sat": 6,
|
|
63
|
+
"sunday": 7,
|
|
44
64
|
"sun": 7,
|
|
45
65
|
}
|
|
46
|
-
return days.get(data.lower())
|
|
66
|
+
return days.get(data.strip().lower())
|
|
47
67
|
|
|
48
68
|
|
|
49
|
-
def
|
|
50
|
-
"""
|
|
69
|
+
def date_conv(data: str, fmt: str = "%Y-%m-%d") -> Optional[datetime.date]:
|
|
70
|
+
"""
|
|
71
|
+
Parses a date string into a date object using the specified format.
|
|
72
|
+
|
|
73
|
+
- Returns None if parsing fails or if 'None' or '@null'.
|
|
74
|
+
"""
|
|
75
|
+
data_clean = none(data) # re-use the none() converter
|
|
76
|
+
if data_clean is None:
|
|
77
|
+
return None
|
|
51
78
|
try:
|
|
52
|
-
return datetime.strptime(
|
|
53
|
-
except
|
|
79
|
+
return datetime.strptime(data_clean, fmt).date()
|
|
80
|
+
except ValueError:
|
|
54
81
|
return None
|
|
55
82
|
|
|
56
83
|
|
|
57
|
-
def
|
|
58
|
-
"""
|
|
84
|
+
def time_conv(data: str, fmt: str = "%H:%M:%S") -> Optional[datetime.time]:
|
|
85
|
+
"""
|
|
86
|
+
Parses a time string into a time object using the specified format.
|
|
87
|
+
|
|
88
|
+
- Defaults to HH:MM:SS if no format is provided.
|
|
89
|
+
- Returns None if parsing fails or if 'None' or '@null'.
|
|
90
|
+
"""
|
|
91
|
+
data_clean = none(data)
|
|
92
|
+
if data_clean is None:
|
|
93
|
+
return None
|
|
59
94
|
try:
|
|
60
|
-
return datetime.strptime(
|
|
61
|
-
except
|
|
95
|
+
return datetime.strptime(data_clean, fmt).time()
|
|
96
|
+
except ValueError:
|
|
62
97
|
return None
|
|
63
98
|
|
|
64
99
|
|
|
65
|
-
def timestamp(data: str, fmt: str = "%
|
|
66
|
-
"""
|
|
100
|
+
def timestamp(data: str, fmt: str = "%Y-%m-%d %H:%M:%S") -> Optional[datetime]:
|
|
101
|
+
"""
|
|
102
|
+
Parses a timestamp string into a datetime object using the specified format.
|
|
103
|
+
|
|
104
|
+
- Returns None if parsing fails or if 'None' or '@null'.
|
|
105
|
+
- Defaults to "%Y-%m-%d %H:%M:%S".
|
|
106
|
+
"""
|
|
107
|
+
data_clean = none(data)
|
|
108
|
+
if data_clean is None:
|
|
109
|
+
return None
|
|
67
110
|
try:
|
|
68
|
-
return datetime.strptime(
|
|
69
|
-
except
|
|
111
|
+
return datetime.strptime(data_clean, fmt)
|
|
112
|
+
except ValueError:
|
|
70
113
|
return None
|
|
71
114
|
|
|
72
115
|
|
|
73
116
|
def email(data: str) -> Optional[str]:
|
|
74
|
-
"""
|
|
75
|
-
|
|
117
|
+
"""
|
|
118
|
+
Validates and returns a cleaned email address if properly formatted.
|
|
119
|
+
|
|
120
|
+
- Uses parseaddr and requires an '@' and at least one '.' after '@'.
|
|
121
|
+
- Returns None if invalid or if 'None'/'@null'.
|
|
122
|
+
- This is still quite basic compared to more advanced email validation needs.
|
|
123
|
+
"""
|
|
124
|
+
data_clean = none(data)
|
|
125
|
+
if data_clean is None:
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
data_clean = data_clean.strip().lower()
|
|
129
|
+
# parseaddr only reliably splits out the email part
|
|
130
|
+
addr = parseaddr(data_clean)[1]
|
|
131
|
+
if "@" not in addr:
|
|
132
|
+
return None
|
|
133
|
+
# At least one '.' after the '@'
|
|
134
|
+
domain_part = addr.split("@", 1)[-1]
|
|
135
|
+
if "." not in domain_part:
|
|
76
136
|
return None
|
|
77
|
-
|
|
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")
|
|
137
|
+
return addr
|
|
82
138
|
|
|
83
139
|
|
|
84
|
-
def integer(data: str) -> int:
|
|
85
|
-
"""
|
|
86
|
-
|
|
140
|
+
def integer(data: str) -> Optional[int]:
|
|
141
|
+
"""
|
|
142
|
+
Converts a string to an integer, removing non-numeric (and '.') characters.
|
|
143
|
+
|
|
144
|
+
- Returns None if conversion fails or if 'None'/'@null'.
|
|
145
|
+
- Accepts optional leading sign and decimal point, but truncates toward int.
|
|
146
|
+
"""
|
|
147
|
+
data_clean = none(data)
|
|
148
|
+
if data_clean is None:
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
# Keep digits, sign, and decimal
|
|
152
|
+
cleaned = re.sub(r"[^0-9\.\-+]", "", data_clean)
|
|
153
|
+
if cleaned.count(".") > 1:
|
|
154
|
+
# Too many decimal points => treat as invalid
|
|
155
|
+
return None
|
|
87
156
|
try:
|
|
88
|
-
return int(float(
|
|
157
|
+
return int(float(cleaned))
|
|
89
158
|
except ValueError:
|
|
90
|
-
|
|
159
|
+
return None
|
|
91
160
|
|
|
92
161
|
|
|
93
162
|
def boolean(data: Union[str, bool]) -> bool:
|
|
94
|
-
"""
|
|
95
|
-
|
|
163
|
+
"""
|
|
164
|
+
Converts various string representations to a boolean.
|
|
165
|
+
|
|
166
|
+
- 'false', '', 'f', 'off', '0', and 'no' => False
|
|
167
|
+
- Everything else => True
|
|
168
|
+
- If data is already bool, it is returned as is.
|
|
169
|
+
"""
|
|
170
|
+
if isinstance(data, bool):
|
|
171
|
+
return data
|
|
172
|
+
data_str = str(data).strip().lower()
|
|
173
|
+
if data_str in ["false", "", "f", "off", "0", "no", "@null", "none"]:
|
|
96
174
|
return False
|
|
97
|
-
return
|
|
175
|
+
return True
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def rot13(data: str) -> Optional[str]:
|
|
179
|
+
"""
|
|
180
|
+
Encodes a string using ROT13.
|
|
98
181
|
|
|
182
|
+
- Returns None if input is None or 'None' or '@null'.
|
|
183
|
+
"""
|
|
184
|
+
data_clean = none(data)
|
|
185
|
+
if data_clean is None:
|
|
186
|
+
return None
|
|
187
|
+
return codecs.encode(data_clean, "rot13")
|
|
99
188
|
|
|
100
|
-
def rot13(data: str) -> str:
|
|
101
|
-
"""Encodes a string using ROT13."""
|
|
102
|
-
return codecs.encode(data, "rot13")
|
|
103
189
|
|
|
190
|
+
def pointer(data: str) -> Optional[int]:
|
|
191
|
+
"""
|
|
192
|
+
Converts a pointer-like string to an integer, or returns None for special tokens.
|
|
104
193
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
194
|
+
- If data is '@new', '@null', 'None', or empty => returns None.
|
|
195
|
+
- Otherwise tries to parse as int; returns None if it fails.
|
|
196
|
+
"""
|
|
197
|
+
data_clean = none(data)
|
|
198
|
+
if data_clean is None or data_clean.lower() == "@new":
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
# Attempt to parse as integer
|
|
202
|
+
cleaned = re.sub(r"[^0-9\+\-]", "", data_clean)
|
|
203
|
+
if not cleaned:
|
|
204
|
+
return None
|
|
205
|
+
try:
|
|
206
|
+
return int(cleaned)
|
|
207
|
+
except ValueError:
|
|
108
208
|
return None
|
|
109
|
-
return int(data)
|
|
110
209
|
|
|
111
210
|
|
|
112
211
|
def money(data: str) -> Optional[Decimal]:
|
|
113
|
-
"""
|
|
114
|
-
|
|
212
|
+
"""
|
|
213
|
+
Converts a monetary string to a Decimal, removing non-numeric characters.
|
|
214
|
+
|
|
215
|
+
- Returns None if 'None' or '@null' or if parse fails.
|
|
216
|
+
- Example input: "$12,345.67" => Decimal("12345.67")
|
|
217
|
+
"""
|
|
218
|
+
data_clean = none(data)
|
|
219
|
+
if data_clean is None:
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
cleaned = re.sub(r"[^0-9\.\-]", "", data_clean)
|
|
223
|
+
if cleaned.count(".") > 1:
|
|
224
|
+
return None
|
|
225
|
+
try:
|
|
226
|
+
return Decimal(cleaned)
|
|
227
|
+
except:
|
|
115
228
|
return None
|
|
116
|
-
return Decimal(re.sub(r"[^0-9\.-]", "", data))
|
|
117
229
|
|
|
118
230
|
|
|
119
231
|
def round_to(
|
|
120
232
|
precision: int, data: Optional[Union[str, float, Decimal]] = None
|
|
121
|
-
) -> Union[Decimal, Callable[[Union[str, float, Decimal]], Decimal]]:
|
|
122
|
-
"""
|
|
233
|
+
) -> Union[Decimal, Callable[[Union[str, float, Decimal]], Optional[Decimal]]]:
|
|
234
|
+
"""
|
|
235
|
+
Rounds a number to a specified precision.
|
|
236
|
+
|
|
237
|
+
- If called with data, returns a single rounded Decimal or None.
|
|
238
|
+
- If called without data, returns a function that can be used as a converter.
|
|
239
|
+
"""
|
|
123
240
|
|
|
124
|
-
def
|
|
125
|
-
if
|
|
241
|
+
def _round_inner(val: Union[str, float, Decimal, None]) -> Optional[Decimal]:
|
|
242
|
+
val_str = none(str(val)) if val is not None else None
|
|
243
|
+
if val_str is None:
|
|
126
244
|
return None
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
Decimal(
|
|
131
|
-
|
|
245
|
+
# Remove non-numeric (except decimal, sign)
|
|
246
|
+
cleaned = re.sub(r"[^0-9\.\-+]", "", val_str)
|
|
247
|
+
try:
|
|
248
|
+
as_dec = Decimal(cleaned)
|
|
249
|
+
except:
|
|
250
|
+
return None
|
|
251
|
+
return as_dec.quantize(Decimal(10) ** -precision, rounding=ROUND_HALF_UP)
|
|
252
|
+
|
|
253
|
+
return _round_inner(data) if data is not None else _round_inner
|
|
132
254
|
|
|
133
|
-
return function(data) if data is not None else function
|
|
134
255
|
|
|
256
|
+
def decimal_val(data: str) -> Optional[Decimal]:
|
|
257
|
+
"""
|
|
258
|
+
Converts a numeric string to a Decimal, removing non-numeric characters.
|
|
135
259
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
260
|
+
- Returns None if 'None'/'@null' or parse fails.
|
|
261
|
+
- Accepts a single decimal point; returns None if multiple decimals.
|
|
262
|
+
"""
|
|
263
|
+
data_clean = none(data)
|
|
264
|
+
if data_clean is None:
|
|
265
|
+
return None
|
|
266
|
+
cleaned = re.sub(r"[^0-9\.\-]", "", data_clean)
|
|
267
|
+
# if multiple decimal points => invalid
|
|
268
|
+
if cleaned.count(".") > 1:
|
|
269
|
+
return None
|
|
270
|
+
try:
|
|
271
|
+
return Decimal(cleaned)
|
|
272
|
+
except:
|
|
139
273
|
return None
|
|
140
|
-
return Decimal(re.sub(r"[^0-9\.-]", "", data))
|
|
141
274
|
|
|
142
275
|
|
|
143
276
|
def ein(data: str) -> Optional[str]:
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
return None
|
|
147
|
-
cleaned_data = re.sub(r"[^0-9]", "", data)
|
|
148
|
-
match = re.fullmatch(r"\d{9}", cleaned_data)
|
|
149
|
-
return match.group() if match else None
|
|
277
|
+
"""
|
|
278
|
+
Validates and returns a 9-digit EIN, or None if invalid.
|
|
150
279
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if
|
|
280
|
+
- Strips non-digit chars; must be exactly 9 digits.
|
|
281
|
+
"""
|
|
282
|
+
data_clean = none(data)
|
|
283
|
+
if data_clean is None:
|
|
284
|
+
return None
|
|
285
|
+
cleaned_data = re.sub(r"[^0-9]", "", data_clean)
|
|
286
|
+
if len(cleaned_data) == 9:
|
|
287
|
+
return cleaned_data
|
|
288
|
+
return None
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def to_list(data: Union[str, list, None]) -> Optional[list]:
|
|
292
|
+
"""
|
|
293
|
+
Converts a string or single element into a list representation.
|
|
294
|
+
|
|
295
|
+
- Returns None for 'None'/'@null' or empty string.
|
|
296
|
+
- If data is already a list, returns it.
|
|
297
|
+
- If data looks like a Python list string, attempts to eval it safely.
|
|
298
|
+
- Otherwise returns a 1-element list with that data.
|
|
299
|
+
"""
|
|
300
|
+
if not data or str(data).lower().strip() in ("none", "@null", ""):
|
|
155
301
|
return None
|
|
156
|
-
if isinstance(data,
|
|
157
|
-
return
|
|
158
|
-
|
|
302
|
+
if isinstance(data, list):
|
|
303
|
+
return data
|
|
304
|
+
data_str = str(data).strip()
|
|
305
|
+
if data_str.startswith("[") and data_str.endswith("]"):
|
|
306
|
+
try:
|
|
307
|
+
return ast.literal_eval(data_str)
|
|
308
|
+
except:
|
|
309
|
+
return [data_str] # fallback: treat as a single string
|
|
310
|
+
return [data_str]
|
|
159
311
|
|
|
160
312
|
|
|
161
313
|
def title(data: str) -> str:
|
|
162
|
-
"""
|
|
163
|
-
|
|
314
|
+
"""
|
|
315
|
+
Converts a string to title case.
|
|
316
|
+
|
|
317
|
+
- Returns empty string if 'None'/'@null' or empty input.
|
|
318
|
+
"""
|
|
319
|
+
data_clean = none(data)
|
|
320
|
+
if data_clean is None:
|
|
321
|
+
return ""
|
|
322
|
+
return data_clean.title()
|
|
164
323
|
|
|
165
324
|
|
|
166
325
|
def lower(data: str) -> str:
|
|
167
|
-
"""
|
|
168
|
-
|
|
326
|
+
"""
|
|
327
|
+
Converts a string to lowercase.
|
|
328
|
+
|
|
329
|
+
- Returns empty string if 'None'/'@null' or empty input.
|
|
330
|
+
"""
|
|
331
|
+
data_clean = none(data)
|
|
332
|
+
if data_clean is None:
|
|
333
|
+
return ""
|
|
334
|
+
return data_clean.lower()
|
|
169
335
|
|
|
170
336
|
|
|
171
337
|
def upper(data: str) -> str:
|
|
172
|
-
"""
|
|
173
|
-
|
|
338
|
+
"""
|
|
339
|
+
Converts a string to uppercase.
|
|
340
|
+
|
|
341
|
+
- Returns empty string if 'None'/'@null' or empty input.
|
|
342
|
+
"""
|
|
343
|
+
data_clean = none(data)
|
|
344
|
+
if data_clean is None:
|
|
345
|
+
return ""
|
|
346
|
+
return data_clean.upper()
|
|
174
347
|
|
|
175
348
|
|
|
176
349
|
def padding(length: int, char: str = " ") -> Callable[[str], Optional[str]]:
|
|
177
|
-
"""
|
|
350
|
+
"""
|
|
351
|
+
Pads a string to the specified length with a given character on the left.
|
|
352
|
+
|
|
353
|
+
- If data is None/'None'/'@null' or empty, returns None.
|
|
354
|
+
"""
|
|
178
355
|
|
|
179
356
|
def inner(data: str) -> Optional[str]:
|
|
180
|
-
|
|
357
|
+
data_clean = none(data)
|
|
358
|
+
if data_clean is None:
|
|
181
359
|
return None
|
|
182
|
-
return
|
|
360
|
+
return data_clean.rjust(length, char)
|
|
183
361
|
|
|
184
362
|
return inner
|
|
185
363
|
|
|
186
364
|
|
|
187
365
|
def string(data: str) -> Optional[str]:
|
|
188
|
-
"""
|
|
189
|
-
|
|
366
|
+
"""
|
|
367
|
+
Converts an empty string to None, otherwise returns the string.
|
|
368
|
+
|
|
369
|
+
- Also treats 'None', '@null' as None.
|
|
370
|
+
"""
|
|
371
|
+
data_clean = none(data)
|
|
372
|
+
# If none() returned None, it’s None. Else, check if empty.
|
|
373
|
+
if data_clean is None:
|
|
374
|
+
return None
|
|
375
|
+
return data_clean if data_clean else None
|
velocity/misc/conv/oconv.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# oconv.py
|
|
2
1
|
import re
|
|
3
2
|
import codecs
|
|
4
3
|
import decimal
|
|
@@ -12,7 +11,7 @@ import ast
|
|
|
12
11
|
|
|
13
12
|
def none(data: Optional[str]) -> str:
|
|
14
13
|
"""Converts various 'null' representations to an empty string."""
|
|
15
|
-
return "" if data in (None, "None", "null", "@NULL") else data
|
|
14
|
+
return "" if data in (None, "None", "null", "@NULL", "@null") else data
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
def phone(data: Optional[str]) -> str:
|
|
@@ -58,7 +57,7 @@ def day_of_week(data: Union[int, str, List], abbrev: bool = False) -> str:
|
|
|
58
57
|
return ""
|
|
59
58
|
|
|
60
59
|
|
|
61
|
-
def
|
|
60
|
+
def date_conv(
|
|
62
61
|
data: Union[datetime.datetime, datetime.date, str], fmt: str = "%Y-%m-%d"
|
|
63
62
|
) -> str:
|
|
64
63
|
"""Formats a date object as a string according to the specified format."""
|
|
@@ -69,7 +68,9 @@ def date(
|
|
|
69
68
|
)
|
|
70
69
|
|
|
71
70
|
|
|
72
|
-
def
|
|
71
|
+
def time_conv(
|
|
72
|
+
data: Union[datetime.datetime, datetime.time, str], fmt: str = "%X"
|
|
73
|
+
) -> str:
|
|
73
74
|
"""Formats a time object as a string according to the specified format."""
|
|
74
75
|
return (
|
|
75
76
|
data.strftime(fmt)
|
velocity/misc/db.py
CHANGED
|
@@ -36,9 +36,9 @@ class join(object):
|
|
|
36
36
|
vals.extend(args)
|
|
37
37
|
for key, val in kwargs.items():
|
|
38
38
|
if isinstance(val, numbers.Number):
|
|
39
|
-
vals.append("{}={}"
|
|
39
|
+
vals.append(f"{key}={val}")
|
|
40
40
|
else:
|
|
41
|
-
vals.append("{}='{}'"
|
|
41
|
+
vals.append(f"{key}='{val}'")
|
|
42
42
|
return vals
|
|
43
43
|
|
|
44
44
|
|
velocity/misc/format.py
CHANGED
|
@@ -66,10 +66,10 @@ def to_json(o, datefmt: str = "%Y-%m-%d", timefmt: str = "%H:%M:%S") -> str:
|
|
|
66
66
|
return None
|
|
67
67
|
elif isinstance(obj, decimal.Decimal):
|
|
68
68
|
return float(obj)
|
|
69
|
-
elif isinstance(obj, date):
|
|
70
|
-
return obj.strftime(datefmt)
|
|
71
69
|
elif isinstance(obj, datetime):
|
|
72
70
|
return obj.strftime(f"{datefmt} {timefmt}")
|
|
71
|
+
elif isinstance(obj, date):
|
|
72
|
+
return obj.strftime(datefmt)
|
|
73
73
|
elif isinstance(obj, time):
|
|
74
74
|
return obj.strftime(timefmt)
|
|
75
75
|
elif isinstance(obj, timedelta):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: velocity-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.64
|
|
4
4
|
Summary: A rapid application development library for interfacing with data storage
|
|
5
5
|
Author-email: Paul Perez <pperez@codeclubs.org>
|
|
6
6
|
Project-URL: Homepage, https://codeclubs.org/projects/velocity
|
|
@@ -15,11 +15,11 @@ Requires-Dist: jinja2
|
|
|
15
15
|
Requires-Dist: xlrd
|
|
16
16
|
Requires-Dist: openpyxl
|
|
17
17
|
Provides-Extra: mysql
|
|
18
|
-
Requires-Dist: mysql-connector-python
|
|
19
|
-
Provides-Extra: postgres
|
|
20
|
-
Requires-Dist: psycopg2-binary ; extra == 'postgres'
|
|
18
|
+
Requires-Dist: mysql-connector-python; extra == "mysql"
|
|
21
19
|
Provides-Extra: sqlserver
|
|
22
|
-
Requires-Dist: python-tds
|
|
20
|
+
Requires-Dist: python-tds; extra == "sqlserver"
|
|
21
|
+
Provides-Extra: postgres
|
|
22
|
+
Requires-Dist: psycopg2-binary; extra == "postgres"
|
|
23
23
|
|
|
24
24
|
# Velocity.DB
|
|
25
25
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
velocity/__init__.py,sha256=BV64vuHaj6lbPZ96w6YkJ_mgqq506ohvETaJVjBy-_s,88
|
|
2
|
+
velocity/aws/__init__.py,sha256=GBTEr02whnCH3TG-BWCpUC3KfHY3uNxD21g0OvsVJnc,598
|
|
3
|
+
velocity/aws/handlers/__init__.py,sha256=xnpFZJVlC2uoeeFW4zuPST8wA8ajaQDky5Y6iXZzi3A,172
|
|
4
|
+
velocity/aws/handlers/context.py,sha256=UIjNR83y2NSIyK8HMPX8t5tpJHFNabiZvNgmmdQL3HA,1822
|
|
5
|
+
velocity/aws/handlers/lambda_handler.py,sha256=RfEFIIn6a2k0W25AMEOMWCqbpUkXF13kV6vXFVKz0b0,6309
|
|
6
|
+
velocity/aws/handlers/response.py,sha256=LXhtizLKnVBWjtHyE0h0bk-NYDrRpj7CHa7tRz9KkC4,9324
|
|
7
|
+
velocity/aws/handlers/sqs_handler.py,sha256=YBqrEkA6EfkQUVk_kwsSI-HjFJO8-JqYco-p0UYDNXE,3368
|
|
8
|
+
velocity/db/__init__.py,sha256=vrn2AFNAKaqTdnPwLFS0OcREcCtzUCOodlmH54U7ADg,200
|
|
9
|
+
velocity/db/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
velocity/db/core/column.py,sha256=tAr8tL3a2nyaYpNHhGl508FrY_pGZTzyYgjAV5CEBv4,4092
|
|
11
|
+
velocity/db/core/database.py,sha256=3zNGItklu9tZCKsbx2T2vCcU1so8AL9PPL0DLjvaz6s,3554
|
|
12
|
+
velocity/db/core/decorators.py,sha256=ZwwNc6wGx7Qe7xPZGgeHuqqtXEeNqyDXB0M5ROY-40I,4612
|
|
13
|
+
velocity/db/core/engine.py,sha256=Ykw_G78UeS59JZLRHqOrprfOv-uxm7HshA6V0cST6QE,13074
|
|
14
|
+
velocity/db/core/exceptions.py,sha256=MOWyA1mlMe8eWbFkEHK0Lp9czdplpRyqbAn2JfGmMrM,707
|
|
15
|
+
velocity/db/core/result.py,sha256=OVqoMwlx3CHNNwr-JGWRx5I8u_YX6hlUpecx99UT5nE,6164
|
|
16
|
+
velocity/db/core/row.py,sha256=aliLYTTFirgJsOvmUsANwJMyxaATuhpGpFJhcu_twwY,6709
|
|
17
|
+
velocity/db/core/sequence.py,sha256=VMBc0ZjGnOaWTwKW6xMNTdP8rZ2umQ8ml4fHTTwuGq4,3904
|
|
18
|
+
velocity/db/core/table.py,sha256=1zI_GgkUCCjRmM30OGiLOgJnnAeJNkriK_mYeV34lC0,35058
|
|
19
|
+
velocity/db/core/transaction.py,sha256=SMkgu39IbgjOIeTzhXo_k7XEEc9MDvztphEYp-fUdQ0,6506
|
|
20
|
+
velocity/db/servers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
velocity/db/servers/mysql.py,sha256=qHwlB_Mg02R7QFjD5QvJCorYYiP50CqEiQyZVl3uYns,20914
|
|
22
|
+
velocity/db/servers/mysql_reserved.py,sha256=CYdZJBOpS-ptImaRZcmVLumdUdbFuf9Tfdzu_mUT5wY,3507
|
|
23
|
+
velocity/db/servers/sqlite.py,sha256=X210a5pENT9PiVK7f16fxXzFwEsq8fSe58Vouv2xqlk,33234
|
|
24
|
+
velocity/db/servers/sqlite_reserved.py,sha256=-xmjl-Hgu6lKqkCAXq_6U8_aJX6gvaMgLMLdCt-Ej7o,3006
|
|
25
|
+
velocity/db/servers/sqlserver.py,sha256=0uGLEWRXiUhrOVTpEA1zvaKq1mcfiaCDp9r7gX-N71g,29914
|
|
26
|
+
velocity/db/servers/sqlserver_reserved.py,sha256=3LGQYU0qfvk6AbKety96gbzzfLbZ0dNHDPLxKGvvi4Q,4596
|
|
27
|
+
velocity/db/servers/tablehelper.py,sha256=0QsQc73q2En3p0778DKAEiEo3ZtZowgFpAKZXwORjfw,9816
|
|
28
|
+
velocity/db/servers/postgres/__init__.py,sha256=n6Ti5USqXME8Df18iklC-D0eI1Hr0szZAeSS3xz5ycQ,464
|
|
29
|
+
velocity/db/servers/postgres/operators.py,sha256=A2T1qFwhzPl0fdXVhLZJhh5Qfx-qF8oZsDnxnq2n_V8,389
|
|
30
|
+
velocity/db/servers/postgres/reserved.py,sha256=5tKLaqFV-HrWRj-nsrxl5KGbmeM3ukn_bPZK36XEu8M,3648
|
|
31
|
+
velocity/db/servers/postgres/sql.py,sha256=-hJ6Ly9iZY3SoAJFjrSjLUAAYPMwG-28RyFRh-Owbpo,35453
|
|
32
|
+
velocity/db/servers/postgres/types.py,sha256=Wa45ppVf_pdWul-jYWFRGMl6IdSq8dAp10SKnhL7osQ,3757
|
|
33
|
+
velocity/misc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
+
velocity/misc/db.py,sha256=MPgt-kkukKR_Wh_S_5W-MyDgaeoZ4YLoDJ54wU2ppm4,2830
|
|
35
|
+
velocity/misc/export.py,sha256=lATvwTe-Of6X7ZtzvJZiFghh9QlyMYZfDfQ_GJyt5yg,5197
|
|
36
|
+
velocity/misc/format.py,sha256=fA5ai3kp-bLhPCCg7Yq9XPhUCE3In-jVZobjBGvmHDg,2649
|
|
37
|
+
velocity/misc/mail.py,sha256=BrxDqeVsOd0epyJKwrHA-owzs6di2oLA_qJskoTux-c,2553
|
|
38
|
+
velocity/misc/merge.py,sha256=EYtqwnckBllPO60tRALxFRuzmUQ7Wl0qZC6sCgyiZDA,1885
|
|
39
|
+
velocity/misc/timer.py,sha256=cN3aS0t6HLlhYfF2Ir6ihJehxNrWf9ebaLzXUaWRKEA,1637
|
|
40
|
+
velocity/misc/conv/__init__.py,sha256=MLYF58QHjzfDSxb1rdnmLnuEQCa3gnhzzZ30CwZVvQo,40
|
|
41
|
+
velocity/misc/conv/iconv.py,sha256=d4_BucW8HTIkGNurJ7GWrtuptqUf-9t79ObzjJ5N76U,10603
|
|
42
|
+
velocity/misc/conv/oconv.py,sha256=h5Lo05DqOQnxoD3y6Px_MQP_V-pBbWf8Hkgkb9Xp1jk,6032
|
|
43
|
+
velocity_python-0.0.64.dist-info/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
|
|
44
|
+
velocity_python-0.0.64.dist-info/METADATA,sha256=vAWChPbSU4kqhj3uwJP8mdpgT2SvwyHY84Dv_l8FQ6E,8519
|
|
45
|
+
velocity_python-0.0.64.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
46
|
+
velocity_python-0.0.64.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
|
|
47
|
+
velocity_python-0.0.64.dist-info/RECORD,,
|