velocity-python 0.0.113__tar.gz → 0.0.116__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of velocity-python might be problematic. Click here for more details.

Files changed (83) hide show
  1. {velocity_python-0.0.113 → velocity_python-0.0.116}/PKG-INFO +1 -1
  2. {velocity_python-0.0.113 → velocity_python-0.0.116}/pyproject.toml +1 -1
  3. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/__init__.py +1 -1
  4. velocity_python-0.0.116/src/velocity/aws/handlers/context.py +216 -0
  5. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/aws/handlers/lambda_handler.py +1 -4
  6. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity_python.egg-info/PKG-INFO +1 -1
  7. velocity_python-0.0.113/src/velocity/aws/handlers/context.py +0 -70
  8. {velocity_python-0.0.113 → velocity_python-0.0.116}/LICENSE +0 -0
  9. {velocity_python-0.0.113 → velocity_python-0.0.116}/README.md +0 -0
  10. {velocity_python-0.0.113 → velocity_python-0.0.116}/setup.cfg +0 -0
  11. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/app/__init__.py +0 -0
  12. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/app/invoices.py +0 -0
  13. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/app/orders.py +0 -0
  14. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/app/payments.py +0 -0
  15. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/app/purchase_orders.py +0 -0
  16. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/aws/__init__.py +0 -0
  17. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/aws/amplify.py +0 -0
  18. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/aws/handlers/__init__.py +0 -0
  19. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/aws/handlers/response.py +0 -0
  20. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  21. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/__init__.py +0 -0
  22. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/__init__.py +0 -0
  23. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/column.py +0 -0
  24. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/database.py +0 -0
  25. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/decorators.py +0 -0
  26. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/engine.py +0 -0
  27. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/exceptions.py +0 -0
  28. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/result.py +0 -0
  29. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/row.py +0 -0
  30. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/sequence.py +0 -0
  31. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/table.py +0 -0
  32. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/core/transaction.py +0 -0
  33. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/exceptions.py +0 -0
  34. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/__init__.py +0 -0
  35. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/mysql.py +0 -0
  36. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/mysql_reserved.py +0 -0
  37. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/postgres/__init__.py +0 -0
  38. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/postgres/operators.py +0 -0
  39. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/postgres/reserved.py +0 -0
  40. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/postgres/sql.py +0 -0
  41. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/postgres/types.py +0 -0
  42. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/sqlite.py +0 -0
  43. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/sqlite_reserved.py +0 -0
  44. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/sqlserver.py +0 -0
  45. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/sqlserver_reserved.py +0 -0
  46. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/servers/tablehelper.py +0 -0
  47. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/db/utils.py +0 -0
  48. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/__init__.py +0 -0
  49. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/conv/__init__.py +0 -0
  50. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/conv/iconv.py +0 -0
  51. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/conv/oconv.py +0 -0
  52. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/db.py +0 -0
  53. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/export.py +0 -0
  54. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/format.py +0 -0
  55. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/mail.py +0 -0
  56. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/merge.py +0 -0
  57. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/timer.py +0 -0
  58. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity/misc/tools.py +0 -0
  59. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity_python.egg-info/SOURCES.txt +0 -0
  60. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  61. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity_python.egg-info/requires.txt +0 -0
  62. {velocity_python-0.0.113 → velocity_python-0.0.116}/src/velocity_python.egg-info/top_level.txt +0 -0
  63. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_cursor_rowcount_fix.py +0 -0
  64. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_db.py +0 -0
  65. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_db_utils.py +0 -0
  66. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_email_processing.py +0 -0
  67. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_fix.py +0 -0
  68. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_format.py +0 -0
  69. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_iconv.py +0 -0
  70. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_merge.py +0 -0
  71. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_oconv.py +0 -0
  72. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_original_error.py +0 -0
  73. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_payment_profile_sorting.py +0 -0
  74. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_postgres.py +0 -0
  75. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_process_error_robustness.py +0 -0
  76. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_response.py +0 -0
  77. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_result_caching.py +0 -0
  78. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_result_sql_aware.py +0 -0
  79. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_row_get_missing_column.py +0 -0
  80. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_spreadsheet_functions.py +0 -0
  81. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_sql_builder.py +0 -0
  82. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_tablehelper.py +0 -0
  83. {velocity_python-0.0.113 → velocity_python-0.0.116}/tests/test_timer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.113
3
+ Version: 0.0.116
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Velocity Team <info@codeclubs.org>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.0.113"
7
+ version = "0.0.116"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.0.113"
1
+ __version__ = version = "0.0.116"
2
2
 
3
3
  from . import aws
4
4
  from . import db
@@ -0,0 +1,216 @@
1
+ import os
2
+ import boto3
3
+ import uuid
4
+ import support.app
5
+ from velocity.misc.format import to_json
6
+ from velocity.misc.merge import deep_merge
7
+ from datetime import datetime
8
+
9
+ engine = support.app.postgres()
10
+
11
+
12
+ @engine.transaction
13
+ class Context:
14
+
15
+ def __init__(
16
+ self, aws_event, aws_context, args, postdata, response, session, log=None
17
+ ):
18
+ self.__args = args
19
+ self.__postdata = postdata
20
+ self.__response = response
21
+ self.__session = session
22
+ self.__aws_event = aws_event
23
+ self.__aws_context = aws_context
24
+ self.__log = log
25
+
26
+ def postdata(self, keys=-1, default=None):
27
+ if keys == -1:
28
+ return self.__postdata
29
+ if not isinstance(keys, list):
30
+ keys = [keys]
31
+ data = self.__postdata
32
+ for key in keys:
33
+ if key in data:
34
+ data = data[key]
35
+ else:
36
+ return default
37
+ return data
38
+
39
+ def payload(self, keys=-1, default={}):
40
+ if "payload" not in self.__postdata:
41
+ return default
42
+ if keys == -1:
43
+ return self.__postdata["payload"]
44
+ if not isinstance(keys, list):
45
+ keys = [keys]
46
+ data = self.__postdata["payload"]
47
+ for key in keys:
48
+ if key in data:
49
+ data = data[key]
50
+ else:
51
+ return default
52
+ return data
53
+
54
+ def action(self):
55
+ return self.__postdata.get("action", self.__args.get("action", ""))
56
+
57
+ def args(self):
58
+ return self.__args
59
+
60
+ def response(self):
61
+ return self.__response
62
+
63
+ def session(self):
64
+ return self.__session
65
+
66
+ def dataset(self):
67
+ return self.payload().get("dataset", {})
68
+
69
+ def log(self, message, function=None):
70
+ if self.__log:
71
+ return self.__log(message, function)
72
+ else:
73
+ if function:
74
+ print(f"{function}: {message}")
75
+ else:
76
+ print(f"{message}")
77
+
78
+ def update_job(self, tx, data=None):
79
+ """Update job status and message in aws_job_activity table.
80
+
81
+ This method only UPDATES existing jobs. For creating new jobs, use create_job.
82
+ """
83
+ if not data:
84
+ return
85
+ if self.postdata("job_id"):
86
+ # Sanitize data before storing in database
87
+ sanitized_data = self._sanitize_job_data(data)
88
+ tx.table("aws_job_activity").update(sanitized_data, {"job_id": self.postdata("job_id")})
89
+ tx.commit()
90
+
91
+ def create_job(self, job_data):
92
+ """Create a new job record in aws_job_activity table using independent transaction."""
93
+ sanitized_data = self._sanitize_job_data(job_data)
94
+ tx.table("aws_job_activity").insert(sanitized_data)
95
+ tx.commit()
96
+
97
+ def _sanitize_job_data(self, data):
98
+ """Sanitize sensitive data before storing in aws_job_activity table."""
99
+ if not isinstance(data, dict):
100
+ return data
101
+
102
+ sanitized = {}
103
+
104
+ # List of sensitive field patterns to sanitize
105
+ sensitive_patterns = [
106
+ 'password', 'token', 'secret', 'key', 'credential', 'auth',
107
+ 'cognito_user', 'session', 'cookie', 'authorization'
108
+ ]
109
+
110
+ for key, value in data.items():
111
+ # Check if key contains sensitive patterns
112
+ if any(pattern in key.lower() for pattern in sensitive_patterns):
113
+ sanitized[key] = "[REDACTED]" if value else value
114
+ elif key == 'error' and value:
115
+ # Sanitize error messages - keep first 500 chars and remove potential sensitive info
116
+ error_str = str(value)[:500]
117
+ for pattern in sensitive_patterns:
118
+ if pattern in error_str.lower():
119
+ # Replace potential sensitive values with placeholder
120
+ import re
121
+ # Remove patterns like password=value, token=value, etc.
122
+ error_str = re.sub(
123
+ rf'{pattern}[=:]\s*[^\s,\]}}]+',
124
+ f'{pattern}=[REDACTED]',
125
+ error_str,
126
+ flags=re.IGNORECASE
127
+ )
128
+ sanitized[key] = error_str
129
+ elif key == 'traceback' and value:
130
+ # Sanitize traceback - keep structure but remove sensitive values
131
+ tb_str = str(value)
132
+ for pattern in sensitive_patterns:
133
+ if pattern in tb_str.lower():
134
+ import re
135
+ # Remove patterns like password=value, token=value, etc.
136
+ tb_str = re.sub(
137
+ rf'{pattern}[=:]\s*[^\s,\]}}]+',
138
+ f'{pattern}=[REDACTED]',
139
+ tb_str,
140
+ flags=re.IGNORECASE
141
+ )
142
+ # Limit traceback size to prevent DB bloat
143
+ sanitized[key] = tb_str[:2000]
144
+ elif key == 'message' and value:
145
+ # Sanitize message field
146
+ message_str = str(value)
147
+ for pattern in sensitive_patterns:
148
+ if pattern in message_str.lower():
149
+ import re
150
+ message_str = re.sub(
151
+ rf'{pattern}[=:]\s*[^\s,\]}}]+',
152
+ f'{pattern}=[REDACTED]',
153
+ message_str,
154
+ flags=re.IGNORECASE
155
+ )
156
+ sanitized[key] = message_str[:1000] # Limit message size
157
+ else:
158
+ # For other fields, copy as-is but check for nested dicts
159
+ if isinstance(value, dict):
160
+ sanitized[key] = self._sanitize_job_data(value)
161
+ elif isinstance(value, str) and len(value) > 5000:
162
+ # Limit very large string fields
163
+ sanitized[key] = value[:5000] + "...[TRUNCATED]"
164
+ else:
165
+ sanitized[key] = value
166
+
167
+ return sanitized
168
+
169
+ def enqueue(self, action, payload={}, user=None, suppress_job_activity=False):
170
+ """
171
+ Enqueue jobs to SQS with independent job activity tracking.
172
+
173
+ This method uses its own transaction for aws_job_activity updates to ensure
174
+ job tracking is never rolled back with other operations.
175
+ """
176
+ batch_id = str(uuid.uuid4())
177
+ results = {"batch_id": batch_id}
178
+ queue = boto3.resource("sqs").get_queue_by_name(
179
+ QueueName=os.environ["SqsWorkQueue"]
180
+ )
181
+ if isinstance(payload, dict):
182
+ payload = [payload]
183
+ messages = []
184
+ if user==None:
185
+ user = self.session.get("email_address") or "EnqueueTasks"
186
+ for item in payload:
187
+ message = {"action": action, "payload": item}
188
+ id = str(uuid.uuid4()).split("-")[0]
189
+ if suppress_job_activity:
190
+ messages.append({"Id": id, "MessageBody": to_json(message)})
191
+ else:
192
+ message["job_id"] = id
193
+ # Use separate transaction for job activity - this should never be rolled back
194
+ self.create_job({
195
+ "action": action,
196
+ "initial_timestamp": datetime.now(),
197
+ "created_by": user,
198
+ "sys_modified_by": user,
199
+ "payload": to_json(message),
200
+ "batch_id": str(batch_id),
201
+ "job_id": id,
202
+ "status": "Initialized",
203
+ "message": f"Job Initialized"
204
+ })
205
+ messages.append({"Id": id, "MessageBody": to_json(message)})
206
+
207
+ if len(messages) == 10:
208
+ result = queue.send_messages(Entries=messages)
209
+ results = deep_merge(results, result)
210
+ messages.clear()
211
+
212
+ if messages:
213
+ result = queue.send_messages(Entries=messages)
214
+ results = deep_merge(results, result)
215
+
216
+ return results
@@ -4,7 +4,7 @@ import sys
4
4
  import os
5
5
  import traceback
6
6
  from support.app import DEBUG
7
- from support.app import helpers, AlertError, enqueue
7
+ from support.app import helpers, AlertError
8
8
 
9
9
  from velocity.aws.handlers import Response
10
10
 
@@ -164,6 +164,3 @@ class LambdaHandler:
164
164
 
165
165
  def OnActionTracking(self, tx, context):
166
166
  self.track(tx, context.payload().get("data", {}))
167
-
168
- def enqueue(self, tx, action, payload={}):
169
- return enqueue(tx, action, payload, self.session["email_address"])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.113
3
+ Version: 0.0.116
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Velocity Team <info@codeclubs.org>
6
6
  License-Expression: MIT
@@ -1,70 +0,0 @@
1
- import support.app
2
-
3
- engine = support.app.postgres()
4
-
5
-
6
- @engine.transaction
7
- class Context:
8
-
9
- def __init__(
10
- self, aws_event, aws_context, args, postdata, response, session, log=None
11
- ):
12
- self.__args = args
13
- self.__postdata = postdata
14
- self.__response = response
15
- self.__session = session
16
- self.__aws_event = aws_event
17
- self.__aws_context = aws_context
18
- self.__log = log
19
-
20
- def postdata(self, keys=-1, default=None):
21
- if keys == -1:
22
- return self.__postdata
23
- if not isinstance(keys, list):
24
- keys = [keys]
25
- data = self.__postdata
26
- for key in keys:
27
- if key in data:
28
- data = data[key]
29
- else:
30
- return default
31
- return data
32
-
33
- def payload(self, keys=-1, default={}):
34
- if "payload" not in self.__postdata:
35
- return default
36
- if keys == -1:
37
- return self.__postdata["payload"]
38
- if not isinstance(keys, list):
39
- keys = [keys]
40
- data = self.__postdata["payload"]
41
- for key in keys:
42
- if key in data:
43
- data = data[key]
44
- else:
45
- return default
46
- return data
47
-
48
- def action(self):
49
- return self.__postdata.get("action", self.__args.get("action", ""))
50
-
51
- def args(self):
52
- return self.__args
53
-
54
- def response(self):
55
- return self.__response
56
-
57
- def session(self):
58
- return self.__session
59
-
60
- def dataset(self):
61
- return self.payload().get("dataset", {})
62
-
63
- def log(self, message, function=None):
64
- if self.__log:
65
- return self.__log(message, function)
66
- else:
67
- if function:
68
- print(f"{function}: {message}")
69
- else:
70
- print(f"{message}")