velocity-python 0.1.12__tar.gz → 0.1.13__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.12/src/velocity_python.egg-info → velocity_python-0.1.13}/PKG-INFO +4 -2
- {velocity_python-0.1.12 → velocity_python-0.1.13}/pyproject.toml +5 -2
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/__init__.py +1 -1
- velocity_python-0.1.13/src/velocity/misc/pdf.py +199 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13/src/velocity_python.egg-info}/PKG-INFO +4 -2
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity_python.egg-info/SOURCES.txt +2 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity_python.egg-info/requires.txt +4 -1
- velocity_python-0.1.13/tests/test_pdf.py +188 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/LICENSE +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/README.md +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/setup.cfg +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/formbuilder/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/formbuilder/reshaper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/invoices.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/orders.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/payments.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/purchase_orders.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/validators/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/validators/formbuilder_template.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/demo_profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/router.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_formbuilder_reshaper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_formbuilder_template_validator.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_observability.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_payment_demo_profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_payment_profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_payment_router.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_row_dirty_tracking.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.13}/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.13
|
|
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
|
|
@@ -29,6 +29,8 @@ Provides-Extra: excel
|
|
|
29
29
|
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
30
30
|
Provides-Extra: templates
|
|
31
31
|
Requires-Dist: jinja2>=3.1.0; extra == "templates"
|
|
32
|
+
Provides-Extra: pdf
|
|
33
|
+
Requires-Dist: weasyprint>=62.0; extra == "pdf"
|
|
32
34
|
Provides-Extra: http
|
|
33
35
|
Requires-Dist: requests>=2.32.0; extra == "http"
|
|
34
36
|
Provides-Extra: mysql
|
|
@@ -41,7 +43,7 @@ Provides-Extra: payment
|
|
|
41
43
|
Requires-Dist: stripe>=12.0.0; extra == "payment"
|
|
42
44
|
Requires-Dist: braintree>=4.30.0; extra == "payment"
|
|
43
45
|
Provides-Extra: all
|
|
44
|
-
Requires-Dist: velocity-python[aws,excel,http,payment,postgres,templates]; extra == "all"
|
|
46
|
+
Requires-Dist: velocity-python[aws,excel,http,payment,pdf,postgres,templates]; extra == "all"
|
|
45
47
|
Provides-Extra: dev
|
|
46
48
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
47
49
|
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.13"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Velocity Team", email="info@codeclubs.org" },
|
|
10
10
|
]
|
|
@@ -48,6 +48,9 @@ excel = [
|
|
|
48
48
|
templates = [
|
|
49
49
|
"jinja2>=3.1.0",
|
|
50
50
|
]
|
|
51
|
+
pdf = [
|
|
52
|
+
"weasyprint>=62.0",
|
|
53
|
+
]
|
|
51
54
|
http = [
|
|
52
55
|
"requests>=2.32.0",
|
|
53
56
|
]
|
|
@@ -65,7 +68,7 @@ payment = [
|
|
|
65
68
|
"braintree>=4.30.0",
|
|
66
69
|
]
|
|
67
70
|
all = [
|
|
68
|
-
"velocity-python[postgres,aws,excel,templates,http,payment]",
|
|
71
|
+
"velocity-python[postgres,aws,excel,templates,http,payment,pdf]",
|
|
69
72
|
]
|
|
70
73
|
dev = [
|
|
71
74
|
"pytest>=8.0.0",
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HTML-to-PDF generation using WeasyPrint.
|
|
3
|
+
|
|
4
|
+
Provides a simple API for converting HTML strings to PDF bytes,
|
|
5
|
+
with support for page size, orientation, margins, and page footers.
|
|
6
|
+
|
|
7
|
+
Usage::
|
|
8
|
+
|
|
9
|
+
from velocity.misc.pdf import html_to_pdf
|
|
10
|
+
|
|
11
|
+
# Simple conversion
|
|
12
|
+
pdf_bytes = html_to_pdf("<h1>Hello</h1><p>World</p>")
|
|
13
|
+
|
|
14
|
+
# With options
|
|
15
|
+
pdf_bytes = html_to_pdf(
|
|
16
|
+
html,
|
|
17
|
+
page_size="Letter",
|
|
18
|
+
orientation="landscape",
|
|
19
|
+
margin="0.5in",
|
|
20
|
+
footer_right="Page {page} of {pages}",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# Wrap a body fragment with a full HTML document + default styles
|
|
24
|
+
from velocity.misc.pdf import wrap_html, html_to_pdf
|
|
25
|
+
|
|
26
|
+
html = wrap_html("My Report", "<p>Content here</p>")
|
|
27
|
+
pdf_bytes = html_to_pdf(html)
|
|
28
|
+
|
|
29
|
+
Requires the ``pdf`` extra::
|
|
30
|
+
|
|
31
|
+
pip install velocity-python[pdf]
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import logging
|
|
37
|
+
import os
|
|
38
|
+
from typing import Optional
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger("velocity.misc.pdf")
|
|
41
|
+
|
|
42
|
+
# On AWS Lambda, fontconfig needs to know where fonts.conf lives.
|
|
43
|
+
# The py-lib-support layer ships fonts/ at /opt/fonts/.
|
|
44
|
+
if "AWS_LAMBDA_FUNCTION_NAME" in os.environ:
|
|
45
|
+
os.environ.setdefault("FONTCONFIG_PATH", "/opt/fonts")
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
import weasyprint
|
|
49
|
+
except ImportError:
|
|
50
|
+
weasyprint = None # type: ignore[assignment]
|
|
51
|
+
|
|
52
|
+
_DEFAULT_BODY_CSS = """\
|
|
53
|
+
body {
|
|
54
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
55
|
+
font-size: 11pt;
|
|
56
|
+
line-height: 1.6;
|
|
57
|
+
color: #222;
|
|
58
|
+
margin: 0;
|
|
59
|
+
padding: 24px;
|
|
60
|
+
}
|
|
61
|
+
h1 { font-size: 20px; margin-bottom: 16px; }
|
|
62
|
+
p { margin: 0 0 12px; line-height: 1.6; }
|
|
63
|
+
ol, ul { padding-left: 24px; }
|
|
64
|
+
li { margin-bottom: 8px; }
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _require_weasyprint():
|
|
69
|
+
if weasyprint is None:
|
|
70
|
+
raise ImportError(
|
|
71
|
+
"weasyprint is required for PDF generation. "
|
|
72
|
+
"Install it with: pip install velocity-python[pdf]"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _build_page_css(
|
|
77
|
+
page_size: str = "Letter",
|
|
78
|
+
orientation: str = "portrait",
|
|
79
|
+
margin: Optional[str] = None,
|
|
80
|
+
margin_top: Optional[str] = None,
|
|
81
|
+
margin_right: Optional[str] = None,
|
|
82
|
+
margin_bottom: Optional[str] = None,
|
|
83
|
+
margin_left: Optional[str] = None,
|
|
84
|
+
footer_right: Optional[str] = None,
|
|
85
|
+
footer_center: Optional[str] = None,
|
|
86
|
+
footer_font_size: str = "8pt",
|
|
87
|
+
) -> str:
|
|
88
|
+
"""Build a ``@page`` CSS rule from the given options."""
|
|
89
|
+
parts = [f"size: {page_size} {orientation};"]
|
|
90
|
+
|
|
91
|
+
if margin:
|
|
92
|
+
parts.append(f"margin: {margin};")
|
|
93
|
+
else:
|
|
94
|
+
mt = margin_top or "0.5in"
|
|
95
|
+
mr = margin_right or "0.5in"
|
|
96
|
+
mb = margin_bottom or "0.75in"
|
|
97
|
+
ml = margin_left or "0.5in"
|
|
98
|
+
parts.append(f"margin: {mt} {mr} {mb} {ml};")
|
|
99
|
+
|
|
100
|
+
footer_blocks = []
|
|
101
|
+
if footer_right:
|
|
102
|
+
content = footer_right.replace("{page}", '" counter(page) "').replace("{pages}", '" counter(pages) "')
|
|
103
|
+
content = f'" {content} "'
|
|
104
|
+
footer_blocks.append(
|
|
105
|
+
f"@bottom-right {{ content: {content}; font-size: {footer_font_size}; color: #666; }}"
|
|
106
|
+
)
|
|
107
|
+
if footer_center:
|
|
108
|
+
content = footer_center.replace("{page}", '" counter(page) "').replace("{pages}", '" counter(pages) "')
|
|
109
|
+
content = f'" {content} "'
|
|
110
|
+
footer_blocks.append(
|
|
111
|
+
f"@bottom-center {{ content: {content}; font-size: {footer_font_size}; color: #666; }}"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
rule_body = "\n ".join(parts)
|
|
115
|
+
footer_body = "\n ".join(footer_blocks)
|
|
116
|
+
return f"@page {{\n {rule_body}\n {footer_body}\n}}"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def html_to_pdf(
|
|
120
|
+
html: str,
|
|
121
|
+
*,
|
|
122
|
+
page_size: str = "Letter",
|
|
123
|
+
orientation: str = "portrait",
|
|
124
|
+
margin: Optional[str] = None,
|
|
125
|
+
margin_top: Optional[str] = None,
|
|
126
|
+
margin_right: Optional[str] = None,
|
|
127
|
+
margin_bottom: Optional[str] = None,
|
|
128
|
+
margin_left: Optional[str] = None,
|
|
129
|
+
footer_right: Optional[str] = None,
|
|
130
|
+
footer_center: Optional[str] = None,
|
|
131
|
+
footer_font_size: str = "8pt",
|
|
132
|
+
) -> bytes:
|
|
133
|
+
"""
|
|
134
|
+
Convert an HTML string to PDF bytes.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
html: Complete HTML document string.
|
|
138
|
+
page_size: CSS page size (e.g. "Letter", "A4"). Default "Letter".
|
|
139
|
+
orientation: "portrait" or "landscape". Default "portrait".
|
|
140
|
+
margin: Shorthand margin for all sides (e.g. "0.5in").
|
|
141
|
+
margin_top/right/bottom/left: Individual margins (override ``margin``).
|
|
142
|
+
footer_right: Right-aligned footer text. Use ``{page}`` and ``{pages}``
|
|
143
|
+
for page numbering (e.g. ``"Page {page} of {pages}"``).
|
|
144
|
+
footer_center: Center-aligned footer text. Same placeholders.
|
|
145
|
+
footer_font_size: CSS font size for footer. Default "8pt".
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
PDF file contents as bytes.
|
|
149
|
+
|
|
150
|
+
Raises:
|
|
151
|
+
ImportError: If weasyprint is not installed.
|
|
152
|
+
"""
|
|
153
|
+
_require_weasyprint()
|
|
154
|
+
|
|
155
|
+
page_css = _build_page_css(
|
|
156
|
+
page_size=page_size,
|
|
157
|
+
orientation=orientation,
|
|
158
|
+
margin=margin,
|
|
159
|
+
margin_top=margin_top,
|
|
160
|
+
margin_right=margin_right,
|
|
161
|
+
margin_bottom=margin_bottom,
|
|
162
|
+
margin_left=margin_left,
|
|
163
|
+
footer_right=footer_right,
|
|
164
|
+
footer_center=footer_center,
|
|
165
|
+
footer_font_size=footer_font_size,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
css = weasyprint.CSS(string=page_css)
|
|
169
|
+
doc = weasyprint.HTML(string=html)
|
|
170
|
+
return doc.write_pdf(stylesheets=[css])
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def wrap_html(title: str, body: str, css: str = "") -> str:
|
|
174
|
+
"""
|
|
175
|
+
Wrap an HTML body fragment in a full HTML document with default styles.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
title: Document ``<title>`` and ``<h1>`` heading.
|
|
179
|
+
body: HTML body content (fragment, not full document).
|
|
180
|
+
css: Additional CSS to include after the default body styles.
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Complete HTML document string ready for :func:`html_to_pdf`.
|
|
184
|
+
"""
|
|
185
|
+
all_css = _DEFAULT_BODY_CSS + "\n" + css
|
|
186
|
+
return f"""<!DOCTYPE html>
|
|
187
|
+
<html>
|
|
188
|
+
<head>
|
|
189
|
+
<meta charset="utf-8">
|
|
190
|
+
<title>{title}</title>
|
|
191
|
+
<style>
|
|
192
|
+
{all_css}
|
|
193
|
+
</style>
|
|
194
|
+
</head>
|
|
195
|
+
<body>
|
|
196
|
+
<h1>{title}</h1>
|
|
197
|
+
{body}
|
|
198
|
+
</body>
|
|
199
|
+
</html>"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: velocity-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.13
|
|
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
|
|
@@ -29,6 +29,8 @@ Provides-Extra: excel
|
|
|
29
29
|
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
30
30
|
Provides-Extra: templates
|
|
31
31
|
Requires-Dist: jinja2>=3.1.0; extra == "templates"
|
|
32
|
+
Provides-Extra: pdf
|
|
33
|
+
Requires-Dist: weasyprint>=62.0; extra == "pdf"
|
|
32
34
|
Provides-Extra: http
|
|
33
35
|
Requires-Dist: requests>=2.32.0; extra == "http"
|
|
34
36
|
Provides-Extra: mysql
|
|
@@ -41,7 +43,7 @@ Provides-Extra: payment
|
|
|
41
43
|
Requires-Dist: stripe>=12.0.0; extra == "payment"
|
|
42
44
|
Requires-Dist: braintree>=4.30.0; extra == "payment"
|
|
43
45
|
Provides-Extra: all
|
|
44
|
-
Requires-Dist: velocity-python[aws,excel,http,payment,postgres,templates]; extra == "all"
|
|
46
|
+
Requires-Dist: velocity-python[aws,excel,http,payment,pdf,postgres,templates]; extra == "all"
|
|
45
47
|
Provides-Extra: dev
|
|
46
48
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
47
49
|
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
|
|
@@ -121,6 +121,7 @@ src/velocity/misc/export.py
|
|
|
121
121
|
src/velocity/misc/format.py
|
|
122
122
|
src/velocity/misc/mail.py
|
|
123
123
|
src/velocity/misc/merge.py
|
|
124
|
+
src/velocity/misc/pdf.py
|
|
124
125
|
src/velocity/misc/timer.py
|
|
125
126
|
src/velocity/misc/tools.py
|
|
126
127
|
src/velocity/misc/conv/__init__.py
|
|
@@ -170,6 +171,7 @@ tests/test_payment_demo_profiles.py
|
|
|
170
171
|
tests/test_payment_profiles.py
|
|
171
172
|
tests/test_payment_router.py
|
|
172
173
|
tests/test_payment_stripe_adapter.py
|
|
174
|
+
tests/test_pdf.py
|
|
173
175
|
tests/test_prepared_statements.py
|
|
174
176
|
tests/test_psycopg3_upgrade.py
|
|
175
177
|
tests/test_query_cache.py
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
sqlparse>=0.5.0
|
|
2
2
|
|
|
3
3
|
[all]
|
|
4
|
-
velocity-python[aws,excel,http,payment,postgres,templates]
|
|
4
|
+
velocity-python[aws,excel,http,payment,pdf,postgres,templates]
|
|
5
5
|
|
|
6
6
|
[aws]
|
|
7
7
|
boto3>=1.35.0
|
|
@@ -33,6 +33,9 @@ mysql-connector-python>=9.0.0
|
|
|
33
33
|
stripe>=12.0.0
|
|
34
34
|
braintree>=4.30.0
|
|
35
35
|
|
|
36
|
+
[pdf]
|
|
37
|
+
weasyprint>=62.0
|
|
38
|
+
|
|
36
39
|
[postgres]
|
|
37
40
|
psycopg[binary]>=3.2.0
|
|
38
41
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Tests for velocity.misc.pdf — HTML-to-PDF generation."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from unittest.mock import patch, MagicMock
|
|
5
|
+
|
|
6
|
+
from velocity.misc.pdf import (
|
|
7
|
+
html_to_pdf,
|
|
8
|
+
wrap_html,
|
|
9
|
+
_build_page_css,
|
|
10
|
+
_DEFAULT_BODY_CSS,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ── wrap_html ───────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestWrapHtml:
|
|
18
|
+
|
|
19
|
+
def test_produces_full_document(self):
|
|
20
|
+
result = wrap_html("My Title", "<p>Hello</p>")
|
|
21
|
+
assert "<!DOCTYPE html>" in result
|
|
22
|
+
assert "<title>My Title</title>" in result
|
|
23
|
+
assert "<h1>My Title</h1>" in result
|
|
24
|
+
assert "<p>Hello</p>" in result
|
|
25
|
+
|
|
26
|
+
def test_includes_default_css(self):
|
|
27
|
+
result = wrap_html("T", "<p>body</p>")
|
|
28
|
+
assert "font-family:" in result
|
|
29
|
+
assert _DEFAULT_BODY_CSS.strip()[:30] in result
|
|
30
|
+
|
|
31
|
+
def test_includes_custom_css(self):
|
|
32
|
+
result = wrap_html("T", "<p>body</p>", css=".custom { color: red; }")
|
|
33
|
+
assert ".custom { color: red; }" in result
|
|
34
|
+
|
|
35
|
+
def test_empty_body(self):
|
|
36
|
+
result = wrap_html("T", "")
|
|
37
|
+
assert "<h1>T</h1>" in result
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# ── _build_page_css ─────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TestBuildPageCss:
|
|
44
|
+
|
|
45
|
+
def test_defaults(self):
|
|
46
|
+
css = _build_page_css()
|
|
47
|
+
assert "size: Letter portrait;" in css
|
|
48
|
+
assert "margin:" in css
|
|
49
|
+
|
|
50
|
+
def test_landscape(self):
|
|
51
|
+
css = _build_page_css(orientation="landscape")
|
|
52
|
+
assert "size: Letter landscape;" in css
|
|
53
|
+
|
|
54
|
+
def test_a4(self):
|
|
55
|
+
css = _build_page_css(page_size="A4")
|
|
56
|
+
assert "size: A4 portrait;" in css
|
|
57
|
+
|
|
58
|
+
def test_shorthand_margin(self):
|
|
59
|
+
css = _build_page_css(margin="1in")
|
|
60
|
+
assert "margin: 1in;" in css
|
|
61
|
+
|
|
62
|
+
def test_individual_margins(self):
|
|
63
|
+
css = _build_page_css(
|
|
64
|
+
margin_top="0.5in",
|
|
65
|
+
margin_right="0.45in",
|
|
66
|
+
margin_bottom="0.55in",
|
|
67
|
+
margin_left="0.45in",
|
|
68
|
+
)
|
|
69
|
+
assert "margin: 0.5in 0.45in 0.55in 0.45in;" in css
|
|
70
|
+
|
|
71
|
+
def test_footer_right(self):
|
|
72
|
+
css = _build_page_css(footer_right="Page {page} of {pages}")
|
|
73
|
+
assert "@bottom-right" in css
|
|
74
|
+
assert 'counter(page)' in css
|
|
75
|
+
assert 'counter(pages)' in css
|
|
76
|
+
|
|
77
|
+
def test_footer_center(self):
|
|
78
|
+
css = _build_page_css(footer_center="CaringCent, LLC")
|
|
79
|
+
assert "@bottom-center" in css
|
|
80
|
+
assert "CaringCent, LLC" in css
|
|
81
|
+
|
|
82
|
+
def test_footer_font_size(self):
|
|
83
|
+
css = _build_page_css(footer_right="pg", footer_font_size="10pt")
|
|
84
|
+
assert "font-size: 10pt;" in css
|
|
85
|
+
|
|
86
|
+
def test_no_footers(self):
|
|
87
|
+
css = _build_page_css()
|
|
88
|
+
assert "@bottom-right" not in css
|
|
89
|
+
assert "@bottom-center" not in css
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# ── html_to_pdf ─────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class TestHtmlToPdf:
|
|
96
|
+
|
|
97
|
+
def test_raises_without_weasyprint(self):
|
|
98
|
+
with patch("velocity.misc.pdf.weasyprint", None):
|
|
99
|
+
with pytest.raises(ImportError, match="weasyprint is required"):
|
|
100
|
+
html_to_pdf("<h1>test</h1>")
|
|
101
|
+
|
|
102
|
+
def test_calls_weasyprint(self):
|
|
103
|
+
mock_wp = MagicMock()
|
|
104
|
+
mock_doc = MagicMock()
|
|
105
|
+
mock_doc.write_pdf.return_value = b"%PDF-fake"
|
|
106
|
+
mock_wp.HTML.return_value = mock_doc
|
|
107
|
+
mock_wp.CSS.return_value = MagicMock()
|
|
108
|
+
|
|
109
|
+
with patch("velocity.misc.pdf.weasyprint", mock_wp):
|
|
110
|
+
result = html_to_pdf("<h1>Hello</h1>")
|
|
111
|
+
|
|
112
|
+
assert result == b"%PDF-fake"
|
|
113
|
+
mock_wp.HTML.assert_called_once()
|
|
114
|
+
call_kwargs = mock_wp.HTML.call_args
|
|
115
|
+
assert "<h1>Hello</h1>" in call_kwargs[1]["string"]
|
|
116
|
+
mock_doc.write_pdf.assert_called_once()
|
|
117
|
+
|
|
118
|
+
def test_passes_page_css_as_stylesheet(self):
|
|
119
|
+
mock_wp = MagicMock()
|
|
120
|
+
mock_doc = MagicMock()
|
|
121
|
+
mock_doc.write_pdf.return_value = b"%PDF"
|
|
122
|
+
mock_wp.HTML.return_value = mock_doc
|
|
123
|
+
mock_css_obj = MagicMock()
|
|
124
|
+
mock_wp.CSS.return_value = mock_css_obj
|
|
125
|
+
|
|
126
|
+
with patch("velocity.misc.pdf.weasyprint", mock_wp):
|
|
127
|
+
html_to_pdf(
|
|
128
|
+
"<h1>test</h1>",
|
|
129
|
+
page_size="A4",
|
|
130
|
+
orientation="landscape",
|
|
131
|
+
footer_right="Page {page}",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# CSS should contain @page with landscape A4
|
|
135
|
+
css_string = mock_wp.CSS.call_args[1]["string"]
|
|
136
|
+
assert "A4 landscape" in css_string
|
|
137
|
+
assert "@bottom-right" in css_string
|
|
138
|
+
|
|
139
|
+
# write_pdf should receive the CSS object
|
|
140
|
+
mock_doc.write_pdf.assert_called_once_with(stylesheets=[mock_css_obj])
|
|
141
|
+
|
|
142
|
+
def test_landscape_with_margins(self):
|
|
143
|
+
mock_wp = MagicMock()
|
|
144
|
+
mock_doc = MagicMock()
|
|
145
|
+
mock_doc.write_pdf.return_value = b"%PDF"
|
|
146
|
+
mock_wp.HTML.return_value = mock_doc
|
|
147
|
+
mock_wp.CSS.return_value = MagicMock()
|
|
148
|
+
|
|
149
|
+
with patch("velocity.misc.pdf.weasyprint", mock_wp):
|
|
150
|
+
html_to_pdf(
|
|
151
|
+
"<h1>report</h1>",
|
|
152
|
+
orientation="landscape",
|
|
153
|
+
margin_top="0.5in",
|
|
154
|
+
margin_right="0.45in",
|
|
155
|
+
margin_bottom="0.55in",
|
|
156
|
+
margin_left="0.45in",
|
|
157
|
+
footer_right="Page {page} of {pages}",
|
|
158
|
+
footer_font_size="8pt",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
css_string = mock_wp.CSS.call_args[1]["string"]
|
|
162
|
+
assert "landscape" in css_string
|
|
163
|
+
assert "0.5in 0.45in 0.55in 0.45in" in css_string
|
|
164
|
+
assert "counter(page)" in css_string
|
|
165
|
+
assert "counter(pages)" in css_string
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ── Integration with wrap_html + html_to_pdf ────────────────────────
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class TestIntegration:
|
|
172
|
+
|
|
173
|
+
def test_wrap_then_convert(self):
|
|
174
|
+
mock_wp = MagicMock()
|
|
175
|
+
mock_doc = MagicMock()
|
|
176
|
+
mock_doc.write_pdf.return_value = b"%PDF-wrapped"
|
|
177
|
+
mock_wp.HTML.return_value = mock_doc
|
|
178
|
+
mock_wp.CSS.return_value = MagicMock()
|
|
179
|
+
|
|
180
|
+
html = wrap_html("Report", "<p>Content</p>")
|
|
181
|
+
|
|
182
|
+
with patch("velocity.misc.pdf.weasyprint", mock_wp):
|
|
183
|
+
result = html_to_pdf(html)
|
|
184
|
+
|
|
185
|
+
assert result == b"%PDF-wrapped"
|
|
186
|
+
passed_html = mock_wp.HTML.call_args[1]["string"]
|
|
187
|
+
assert "<title>Report</title>" in passed_html
|
|
188
|
+
assert "<p>Content</p>" in passed_html
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/app/tests/test_email_processing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/context_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/mixins/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/aws/handlers/mixins/web_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/base/initializer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.12 → velocity_python-0.1.13}/src/velocity/db/servers/mysql/operators.py
RENAMED
|
File without changes
|
|
File without changes
|