velocity-python 0.1.1__tar.gz → 0.1.2__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.
- {velocity_python-0.1.1 → velocity_python-0.1.2}/PKG-INFO +12 -6
- {velocity_python-0.1.1 → velocity_python-0.1.2}/pyproject.toml +17 -6
- velocity_python-0.1.2/src/velocity/__init__.py +17 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/__init__.py +21 -11
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/row.py +43 -5
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/table.py +4 -4
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/export.py +11 -4
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/PKG-INFO +12 -6
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/SOURCES.txt +1 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/requires.txt +15 -4
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_row_batch_update.py +3 -0
- velocity_python-0.1.2/tests/test_row_cache_staleness.py +296 -0
- velocity_python-0.1.1/src/velocity/__init__.py +0 -8
- {velocity_python-0.1.1 → velocity_python-0.1.2}/LICENSE +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/README.md +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/setup.cfg +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/formbuilder/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/formbuilder/reshaper.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/invoices.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/orders.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/payments.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/purchase_orders.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/validators/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/validators/formbuilder_template.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/demo_profiles.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/profiles.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/router.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_formbuilder_reshaper.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_formbuilder_template_validator.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_demo_profiles.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_profiles.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_router.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_where_clause_validation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: velocity-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
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
|
|
@@ -19,12 +19,16 @@ Classifier: Operating System :: OS Independent
|
|
|
19
19
|
Requires-Python: >=3.9
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: boto3>=1.35.0
|
|
23
|
-
Requires-Dist: requests>=2.32.0
|
|
24
|
-
Requires-Dist: jinja2>=3.1.0
|
|
25
|
-
Requires-Dist: xlrd>=2.0.1
|
|
26
|
-
Requires-Dist: openpyxl>=3.1.0
|
|
27
22
|
Requires-Dist: sqlparse>=0.5.0
|
|
23
|
+
Provides-Extra: aws
|
|
24
|
+
Requires-Dist: boto3>=1.35.0; extra == "aws"
|
|
25
|
+
Requires-Dist: requests>=2.32.0; extra == "aws"
|
|
26
|
+
Provides-Extra: excel
|
|
27
|
+
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
28
|
+
Provides-Extra: templates
|
|
29
|
+
Requires-Dist: jinja2>=3.1.0; extra == "templates"
|
|
30
|
+
Provides-Extra: http
|
|
31
|
+
Requires-Dist: requests>=2.32.0; extra == "http"
|
|
28
32
|
Provides-Extra: mysql
|
|
29
33
|
Requires-Dist: mysql-connector-python>=9.0.0; extra == "mysql"
|
|
30
34
|
Provides-Extra: sqlserver
|
|
@@ -34,6 +38,8 @@ Requires-Dist: psycopg[binary]>=3.2.0; extra == "postgres"
|
|
|
34
38
|
Provides-Extra: payment
|
|
35
39
|
Requires-Dist: stripe>=12.0.0; extra == "payment"
|
|
36
40
|
Requires-Dist: braintree>=4.30.0; extra == "payment"
|
|
41
|
+
Provides-Extra: all
|
|
42
|
+
Requires-Dist: velocity-python[aws,excel,http,payment,postgres,templates]; extra == "all"
|
|
37
43
|
Provides-Extra: dev
|
|
38
44
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
39
45
|
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "velocity-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Velocity Team", email="info@codeclubs.org" },
|
|
10
10
|
]
|
|
@@ -26,11 +26,6 @@ classifiers = [
|
|
|
26
26
|
"Operating System :: OS Independent",
|
|
27
27
|
]
|
|
28
28
|
dependencies = [
|
|
29
|
-
"boto3>=1.35.0",
|
|
30
|
-
"requests>=2.32.0",
|
|
31
|
-
"jinja2>=3.1.0",
|
|
32
|
-
"xlrd>=2.0.1",
|
|
33
|
-
"openpyxl>=3.1.0",
|
|
34
29
|
"sqlparse>=0.5.0"
|
|
35
30
|
]
|
|
36
31
|
|
|
@@ -38,6 +33,19 @@ dependencies = [
|
|
|
38
33
|
Homepage = "https://codeclubs.org/projects/velocity"
|
|
39
34
|
|
|
40
35
|
[project.optional-dependencies]
|
|
36
|
+
aws = [
|
|
37
|
+
"boto3>=1.35.0",
|
|
38
|
+
"requests>=2.32.0",
|
|
39
|
+
]
|
|
40
|
+
excel = [
|
|
41
|
+
"openpyxl>=3.1.0",
|
|
42
|
+
]
|
|
43
|
+
templates = [
|
|
44
|
+
"jinja2>=3.1.0",
|
|
45
|
+
]
|
|
46
|
+
http = [
|
|
47
|
+
"requests>=2.32.0",
|
|
48
|
+
]
|
|
41
49
|
mysql = [
|
|
42
50
|
"mysql-connector-python>=9.0.0",
|
|
43
51
|
]
|
|
@@ -51,6 +59,9 @@ payment = [
|
|
|
51
59
|
"stripe>=12.0.0",
|
|
52
60
|
"braintree>=4.30.0",
|
|
53
61
|
]
|
|
62
|
+
all = [
|
|
63
|
+
"velocity-python[postgres,aws,excel,templates,http,payment]",
|
|
64
|
+
]
|
|
54
65
|
dev = [
|
|
55
66
|
"pytest>=8.0.0",
|
|
56
67
|
"pytest-cov>=6.0.0",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
__version__ = version = "0.1.2"
|
|
2
|
+
|
|
3
|
+
import importlib as _importlib
|
|
4
|
+
|
|
5
|
+
from . import db
|
|
6
|
+
from . import misc
|
|
7
|
+
from . import app
|
|
8
|
+
|
|
9
|
+
__all__ = ["aws", "db", "misc", "app"]
|
|
10
|
+
|
|
11
|
+
_LAZY_SUBMODULES = {"aws"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def __getattr__(name: str):
|
|
15
|
+
if name in _LAZY_SUBMODULES:
|
|
16
|
+
return _importlib.import_module(f".{name}", __name__)
|
|
17
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -1,15 +1,5 @@
|
|
|
1
|
+
import importlib as _importlib
|
|
1
2
|
import os
|
|
2
|
-
import requests
|
|
3
|
-
|
|
4
|
-
from velocity.aws.amplify import AmplifyProject
|
|
5
|
-
from velocity.aws.amplify_build import (
|
|
6
|
-
BackendDeploymentConfig,
|
|
7
|
-
build_environment_variables,
|
|
8
|
-
get_amplify_app_id_and_branch,
|
|
9
|
-
initialize_build_environment,
|
|
10
|
-
run_backend_deployment,
|
|
11
|
-
update_lambda_layers_to_latest,
|
|
12
|
-
)
|
|
13
3
|
|
|
14
4
|
DEBUG = (os.environ.get("ENV") != "production") or (os.environ.get("DEBUG") == "Y")
|
|
15
5
|
|
|
@@ -23,11 +13,31 @@ class AWS(object):
|
|
|
23
13
|
# Get AWS EC2 Instance ID. Must run this from the EC2 instance itself to get the ID
|
|
24
14
|
@staticmethod
|
|
25
15
|
def instance_id(cls):
|
|
16
|
+
import requests
|
|
26
17
|
response = requests.get("http://169.254.169.254/latest/meta-data/instance-id")
|
|
27
18
|
instance_id = response.text
|
|
28
19
|
return instance_id
|
|
29
20
|
|
|
30
21
|
|
|
22
|
+
# Lazy-load heavy modules (boto3-dependent) on first access
|
|
23
|
+
_LAZY_ATTRS = {
|
|
24
|
+
"AmplifyProject": "velocity.aws.amplify",
|
|
25
|
+
"BackendDeploymentConfig": "velocity.aws.amplify_build",
|
|
26
|
+
"build_environment_variables": "velocity.aws.amplify_build",
|
|
27
|
+
"get_amplify_app_id_and_branch": "velocity.aws.amplify_build",
|
|
28
|
+
"initialize_build_environment": "velocity.aws.amplify_build",
|
|
29
|
+
"run_backend_deployment": "velocity.aws.amplify_build",
|
|
30
|
+
"update_lambda_layers_to_latest": "velocity.aws.amplify_build",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def __getattr__(name: str):
|
|
35
|
+
if name in _LAZY_ATTRS:
|
|
36
|
+
module = _importlib.import_module(_LAZY_ATTRS[name])
|
|
37
|
+
return getattr(module, name)
|
|
38
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
39
|
+
|
|
40
|
+
|
|
31
41
|
__all__ = [
|
|
32
42
|
"AmplifyProject",
|
|
33
43
|
"AWS",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pprint
|
|
2
|
+
import time as _time
|
|
2
3
|
import warnings
|
|
3
4
|
from collections.abc import MutableMapping
|
|
4
5
|
from velocity.db.exceptions import DbColumnMissingError
|
|
@@ -8,6 +9,7 @@ from velocity.db.exceptions import DbColumnMissingError
|
|
|
8
9
|
# intercepted by __getattr__ / __setattr__.
|
|
9
10
|
_INTERNAL_ATTRS = frozenset({
|
|
10
11
|
"table", "pk", "_cache", "_column_set", "_batching", "_pending",
|
|
12
|
+
"_cache_ttl", "_cache_time", "_no_cache",
|
|
11
13
|
})
|
|
12
14
|
|
|
13
15
|
|
|
@@ -23,7 +25,7 @@ class Row(MutableMapping):
|
|
|
23
25
|
write-through (immediate UPDATE) and also update the local cache.
|
|
24
26
|
"""
|
|
25
27
|
|
|
26
|
-
def __init__(self, table, key, lock=None):
|
|
28
|
+
def __init__(self, table, key, lock=None, cache_ttl=None, no_cache=False):
|
|
27
29
|
if isinstance(table, str):
|
|
28
30
|
raise Exception("Table parameter must be a `table` instance.")
|
|
29
31
|
object.__setattr__(self, "table", table)
|
|
@@ -43,6 +45,9 @@ class Row(MutableMapping):
|
|
|
43
45
|
object.__setattr__(self, "_column_set", None)
|
|
44
46
|
object.__setattr__(self, "_batching", False)
|
|
45
47
|
object.__setattr__(self, "_pending", {})
|
|
48
|
+
object.__setattr__(self, "_cache_ttl", cache_ttl)
|
|
49
|
+
object.__setattr__(self, "_cache_time", None)
|
|
50
|
+
object.__setattr__(self, "_no_cache", no_cache)
|
|
46
51
|
if lock:
|
|
47
52
|
self.lock()
|
|
48
53
|
|
|
@@ -51,10 +56,20 @@ class Row(MutableMapping):
|
|
|
51
56
|
# ------------------------------------------------------------------
|
|
52
57
|
|
|
53
58
|
def _ensure_cache(self):
|
|
54
|
-
"""Populate the local cache from the database if not yet loaded."""
|
|
59
|
+
"""Populate the local cache from the database if not yet loaded or expired."""
|
|
60
|
+
if self._no_cache:
|
|
61
|
+
# Always fetch fresh — never store in cache
|
|
62
|
+
data = self.table.select(where=self.pk).as_dict().one()
|
|
63
|
+
return data or {}
|
|
64
|
+
if self._cache is not None and self._cache_ttl is not None:
|
|
65
|
+
elapsed = _time.monotonic() - (self._cache_time or 0)
|
|
66
|
+
if elapsed > self._cache_ttl:
|
|
67
|
+
object.__setattr__(self, "_cache", None)
|
|
68
|
+
object.__setattr__(self, "_column_set", None)
|
|
55
69
|
if self._cache is None:
|
|
56
70
|
data = self.table.select(where=self.pk).as_dict().one()
|
|
57
71
|
object.__setattr__(self, "_cache", data or {})
|
|
72
|
+
object.__setattr__(self, "_cache_time", _time.monotonic())
|
|
58
73
|
return self._cache
|
|
59
74
|
|
|
60
75
|
def _column_names_lower(self):
|
|
@@ -232,9 +247,9 @@ class Row(MutableMapping):
|
|
|
232
247
|
data.update(kwds)
|
|
233
248
|
if data:
|
|
234
249
|
self.table.update_or_insert(data, pk=self.pk)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
250
|
+
# Invalidate cache so trigger-computed columns are re-fetched
|
|
251
|
+
object.__setattr__(self, "_cache", None)
|
|
252
|
+
object.__setattr__(self, "_column_set", None)
|
|
238
253
|
return self
|
|
239
254
|
|
|
240
255
|
def copy(self, lock=None):
|
|
@@ -366,6 +381,29 @@ class Row(MutableMapping):
|
|
|
366
381
|
self.table.select(where=self.pk, lock=True)
|
|
367
382
|
return self
|
|
368
383
|
|
|
384
|
+
def with_lock(self):
|
|
385
|
+
"""SELECT ... FOR UPDATE and clear the cache so the next read is fresh.
|
|
386
|
+
|
|
387
|
+
Returns self for chaining::
|
|
388
|
+
|
|
389
|
+
row = row.with_lock()
|
|
390
|
+
balance = row["balance"] # guaranteed fresh, locked
|
|
391
|
+
"""
|
|
392
|
+
self.table.select(where=self.pk, lock=True)
|
|
393
|
+
object.__setattr__(self, "_cache", None)
|
|
394
|
+
object.__setattr__(self, "_column_set", None)
|
|
395
|
+
return self
|
|
396
|
+
|
|
397
|
+
def no_cache(self):
|
|
398
|
+
"""Return a new Row that never caches — every read hits the database.
|
|
399
|
+
|
|
400
|
+
Useful for critical-path reads where staleness is unacceptable::
|
|
401
|
+
|
|
402
|
+
fresh_row = row.no_cache()
|
|
403
|
+
balance = fresh_row["balance"] # always from DB
|
|
404
|
+
"""
|
|
405
|
+
return Row(self.table, self.pk, no_cache=True)
|
|
406
|
+
|
|
369
407
|
def notBlank(self, key, failobj=None):
|
|
370
408
|
"""
|
|
371
409
|
Returns the value if it is not blank, else failobj.
|
|
@@ -400,13 +400,13 @@ class Table:
|
|
|
400
400
|
"""
|
|
401
401
|
return Column(self, name)
|
|
402
402
|
|
|
403
|
-
def row(self, key=None, lock=None):
|
|
403
|
+
def row(self, key=None, lock=None, cache_ttl=None, no_cache=False):
|
|
404
404
|
"""
|
|
405
405
|
Retrieves a Row instance for the given primary key or conditions dict. If `key` is None, returns a new row.
|
|
406
406
|
"""
|
|
407
407
|
if key is None:
|
|
408
408
|
return self.new(lock=lock)
|
|
409
|
-
return Row(self, key, lock=lock)
|
|
409
|
+
return Row(self, key, lock=lock, cache_ttl=cache_ttl, no_cache=no_cache)
|
|
410
410
|
|
|
411
411
|
def dict(self, key):
|
|
412
412
|
"""
|
|
@@ -415,14 +415,14 @@ class Table:
|
|
|
415
415
|
r = self.find(key)
|
|
416
416
|
return r.to_dict() if r else {}
|
|
417
417
|
|
|
418
|
-
def rows(self, where=None, orderby=None, qty=None, lock=None, skip_locked=None):
|
|
418
|
+
def rows(self, where=None, orderby=None, qty=None, lock=None, skip_locked=None, cache_ttl=None, no_cache=False):
|
|
419
419
|
"""
|
|
420
420
|
Generator that yields Row objects matching `where`, up to `qty`.
|
|
421
421
|
"""
|
|
422
422
|
for key in self.ids(
|
|
423
423
|
where=where, orderby=orderby, qty=qty, lock=lock, skip_locked=skip_locked
|
|
424
424
|
):
|
|
425
|
-
yield Row(self, key, lock=lock)
|
|
425
|
+
yield Row(self, key, lock=lock, cache_ttl=cache_ttl, no_cache=no_cache)
|
|
426
426
|
|
|
427
427
|
def ids(
|
|
428
428
|
self,
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from datetime import date, datetime, time, timedelta
|
|
2
4
|
from decimal import Decimal
|
|
3
5
|
from io import BytesIO
|
|
4
|
-
from typing import Dict, List
|
|
6
|
+
from typing import TYPE_CHECKING, Dict, List
|
|
5
7
|
import base64
|
|
6
8
|
import re
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from openpyxl.
|
|
10
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
11
|
+
import openpyxl
|
|
12
|
+
from openpyxl.styles import NamedStyle
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
NUMBER_FORMAT_RE = re.compile(r"[#0?][#0?,]*(?:\.[#0?]+)?")
|
|
@@ -107,6 +109,8 @@ def _display_value(cell) -> str:
|
|
|
107
109
|
|
|
108
110
|
def autosize_columns(ws, fixed: Dict[str, float] | None = None):
|
|
109
111
|
"""Autosize columns in the worksheet based on content length."""
|
|
112
|
+
from openpyxl.utils import get_column_letter
|
|
113
|
+
|
|
110
114
|
fixed = fixed or {}
|
|
111
115
|
for col in ws.columns:
|
|
112
116
|
max_length = 0
|
|
@@ -135,6 +139,9 @@ def create_spreadsheet(
|
|
|
135
139
|
auto_size: bool = True,
|
|
136
140
|
):
|
|
137
141
|
"""Create an Excel spreadsheet with specified headers, rows, and styles."""
|
|
142
|
+
import openpyxl
|
|
143
|
+
from openpyxl.styles import Alignment, Border, Font, NamedStyle, Side
|
|
144
|
+
|
|
138
145
|
styles = styles or {}
|
|
139
146
|
merge = merge or []
|
|
140
147
|
formats = formats or {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: velocity-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
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
|
|
@@ -19,12 +19,16 @@ Classifier: Operating System :: OS Independent
|
|
|
19
19
|
Requires-Python: >=3.9
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: boto3>=1.35.0
|
|
23
|
-
Requires-Dist: requests>=2.32.0
|
|
24
|
-
Requires-Dist: jinja2>=3.1.0
|
|
25
|
-
Requires-Dist: xlrd>=2.0.1
|
|
26
|
-
Requires-Dist: openpyxl>=3.1.0
|
|
27
22
|
Requires-Dist: sqlparse>=0.5.0
|
|
23
|
+
Provides-Extra: aws
|
|
24
|
+
Requires-Dist: boto3>=1.35.0; extra == "aws"
|
|
25
|
+
Requires-Dist: requests>=2.32.0; extra == "aws"
|
|
26
|
+
Provides-Extra: excel
|
|
27
|
+
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
28
|
+
Provides-Extra: templates
|
|
29
|
+
Requires-Dist: jinja2>=3.1.0; extra == "templates"
|
|
30
|
+
Provides-Extra: http
|
|
31
|
+
Requires-Dist: requests>=2.32.0; extra == "http"
|
|
28
32
|
Provides-Extra: mysql
|
|
29
33
|
Requires-Dist: mysql-connector-python>=9.0.0; extra == "mysql"
|
|
30
34
|
Provides-Extra: sqlserver
|
|
@@ -34,6 +38,8 @@ Requires-Dist: psycopg[binary]>=3.2.0; extra == "postgres"
|
|
|
34
38
|
Provides-Extra: payment
|
|
35
39
|
Requires-Dist: stripe>=12.0.0; extra == "payment"
|
|
36
40
|
Requires-Dist: braintree>=4.30.0; extra == "payment"
|
|
41
|
+
Provides-Extra: all
|
|
42
|
+
Requires-Dist: velocity-python[aws,excel,http,payment,postgres,templates]; extra == "all"
|
|
37
43
|
Provides-Extra: dev
|
|
38
44
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
39
45
|
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
|
|
@@ -168,6 +168,7 @@ tests/test_prepared_statements.py
|
|
|
168
168
|
tests/test_psycopg3_upgrade.py
|
|
169
169
|
tests/test_query_cache.py
|
|
170
170
|
tests/test_row_batch_update.py
|
|
171
|
+
tests/test_row_cache_staleness.py
|
|
171
172
|
tests/test_sqs_per_record_transactions.py
|
|
172
173
|
tests/test_sys_modified_count_postgres_demo.py
|
|
173
174
|
tests/test_table_alter.py
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
sqlparse>=0.5.0
|
|
2
|
+
|
|
3
|
+
[all]
|
|
4
|
+
velocity-python[aws,excel,http,payment,postgres,templates]
|
|
5
|
+
|
|
6
|
+
[aws]
|
|
1
7
|
boto3>=1.35.0
|
|
2
8
|
requests>=2.32.0
|
|
3
|
-
jinja2>=3.1.0
|
|
4
|
-
xlrd>=2.0.1
|
|
5
|
-
openpyxl>=3.1.0
|
|
6
|
-
sqlparse>=0.5.0
|
|
7
9
|
|
|
8
10
|
[dev]
|
|
9
11
|
pytest>=8.0.0
|
|
@@ -17,6 +19,12 @@ pre-commit>=4.0.0
|
|
|
17
19
|
sphinx>=8.0.0
|
|
18
20
|
sphinx-rtd-theme>=3.0.0
|
|
19
21
|
|
|
22
|
+
[excel]
|
|
23
|
+
openpyxl>=3.1.0
|
|
24
|
+
|
|
25
|
+
[http]
|
|
26
|
+
requests>=2.32.0
|
|
27
|
+
|
|
20
28
|
[mysql]
|
|
21
29
|
mysql-connector-python>=9.0.0
|
|
22
30
|
|
|
@@ -30,6 +38,9 @@ psycopg[binary]>=3.2.0
|
|
|
30
38
|
[sqlserver]
|
|
31
39
|
python-tds>=1.15.0
|
|
32
40
|
|
|
41
|
+
[templates]
|
|
42
|
+
jinja2>=3.1.0
|
|
43
|
+
|
|
33
44
|
[test]
|
|
34
45
|
pytest>=8.0.0
|
|
35
46
|
pytest-cov>=6.0.0
|
|
@@ -26,6 +26,9 @@ def _make_row(cache=None, pk=None):
|
|
|
26
26
|
object.__setattr__(row, "_column_set", None)
|
|
27
27
|
object.__setattr__(row, "_batching", False)
|
|
28
28
|
object.__setattr__(row, "_pending", {})
|
|
29
|
+
object.__setattr__(row, "_cache_ttl", None)
|
|
30
|
+
object.__setattr__(row, "_cache_time", None)
|
|
31
|
+
object.__setattr__(row, "_no_cache", False)
|
|
29
32
|
return row
|
|
30
33
|
|
|
31
34
|
|