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.

@@ -1,2 +1,2 @@
1
1
  from . import iconv
2
- from . import oconv
2
+ from . import oconv
@@ -1,32 +1,33 @@
1
+ # iconv.py
1
2
  import re
2
3
  import codecs
3
- import decimal as _decimal
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
- def none(data):
9
- if data == "":
10
- return None
11
- if data == "null":
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
- if data == "None":
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
- if not data:
22
- return data
23
- return re.search(r"\d{10}$", re.sub("[^0-9]", "", data)).group()
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 data
29
- return {
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
- }[data.lower()]
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
- def _(param):
51
- if isinstance(param, str):
52
- return datetime.strptime(param, kwds["fmt"]).date()
53
- else:
54
- return param
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(*args, **kwds):
62
- kwds.setdefault("fmt", "%X")
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
- if args and args[0]:
71
- return _(args[0])
72
- return _
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 timestamp(*args, **kwds):
76
- kwds.setdefault("fmt", "%c")
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
- if args and args[0]:
85
- return _(args[0])
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 email(data):
90
- if not data:
91
- return None
92
- if data == "None":
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
- if data == "@new":
124
- return data
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
- if data == "None":
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
- if not data:
138
- return data
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 round(precision, data=None):
143
- def function(data):
144
- if data == "None":
120
+ def function(value):
121
+ if value in ("None", None):
145
122
  return None
146
- if not data:
147
- return data
148
- if isinstance(data, str):
149
- data = re.sub("[^0-9\.-]", "", data)
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 == None:
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
- if data == "None":
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
- if not data:
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
- if data == "None":
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
- if not data:
171
- return data
172
- return re.search(r"^\d{9}$", re.sub("[^0-9]", "", data)).group()
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 list(data):
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
- if data[0] == "[":
180
- return data
181
- if not isinstance(data, list):
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 padding(length, char):
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
- if data == "":
221
- return None
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)
@@ -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
- new = []
30
- for day in data:
31
- new.append(day_of_week(day, abbrev=abbrev))
32
- return ','.join(new)
33
- if data == None:
34
- return ''
35
- if data == 'None':
36
- return ''
37
- if not data:
38
- return data
39
- if abbrev:
40
- return {
41
- 1: 'Mon',
42
- 2: 'Tue',
43
- 3: 'Wed',
44
- 4: 'Thu',
45
- 5: 'Fri',
46
- 6: 'Sat',
47
- 7: 'Sun'
48
- }[int(data)]
49
- return {
50
- 1: 'Monday',
51
- 2: 'Tuesday',
52
- 3: 'Wednesday',
53
- 4: 'Thursday',
54
- 5: 'Friday',
55
- 6: 'Saturday',
56
- 7: 'Sunday'
57
- }[int(data)]
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
- return codecs.decode(data,'rot13')
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
- if isinstance(data,str):
117
- if data.lower() in ['false','','f','off','no']:
118
- return False
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
- if data in [None,'']:
124
- return ''
125
- data = re.sub("[^0-9\.-]", "", str(data))
126
- return '${:,.2f}'.format(decimal.Decimal(data))
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 round(precision, data=None):
130
- def function(data):
131
- data = re.sub("[^0-9\.]", "", str(data))
132
- if data == '':
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
- def ein(data):
141
- if data == None:
142
- return ''
143
- if data == 'None':
144
- return ''
145
- if not data:
146
- return data
147
- data = re.search(r'\d{9}$', re.sub("[^0-9]", "", data)).group()
148
- return "{}-{}".format(data[:2],data[2:])
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 list(data):
152
- if data in (None,'None'):
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
- if data[0] == '[':
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
- if data == None:
164
- return ''
165
- if data == 'None':
166
- return ''
167
- return str(data).title()
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 lower(data):
171
- if data == None:
172
- return ''
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 upper(data):
179
- if data == None:
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
- if data == None:
203
- return ''
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)