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