tigrbl_tests 0.3.6.dev1__tar.gz → 0.3.7__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.
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/PKG-INFO +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/pyproject.toml +1 -1
- tigrbl_tests-0.3.7/tests/request/test_request_dot_notation.py +29 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/request/test_request_response_conveniences.py +2 -2
- tigrbl_tests-0.3.7/tests/request/test_request_transport_convenience_dot_notation.py +61 -0
- tigrbl_tests-0.3.7/tests/requests/test_request_json_modes.py +37 -0
- tigrbl_tests-0.3.7/tests/response/test_response_dot_notation.py +21 -0
- tigrbl_tests-0.3.7/tests/response/test_response_transport_convenience_dot_notation.py +27 -0
- tigrbl_tests-0.3.7/tests/security/test_dot_notation_schemes.py +35 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/decorators/test_response_ctx_bindings.py +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/response_utils.py +3 -3
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_file_response.py +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_alias_table_rpc.py +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_ctx_precedence.py +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_diagnostics_kernelz.py +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_html_jinja_behavior.py +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_template.py +1 -1
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_uuid.py +2 -2
- tigrbl_tests-0.3.7/tests/unit/test_stdapi_transport_asgi_wsgi.py +269 -0
- tigrbl_tests-0.3.6.dev1/tests/unit/test_stdapi_transport_asgi_wsgi.py +0 -121
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/LICENSE +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/README.md +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/__init__.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/conftest.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/hooks/test_hook_ctx_phase_validation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/__init__.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_acronym_route_name.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_allow_anon.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_apikey_generation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_authn_provider_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_bindings_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_bindings_modules.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_bulk_docs_client.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_core_access.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_engine_install_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_engine_resolver_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_error_mappings.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_field_spec_effects.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_header_io_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_healthz_methodz_hookz.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_hook_ctx_v3_i9n.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_hook_lifecycle.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_iospec_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_iospec_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_jsonrpc_batch_behavior.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_key_digest_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_list_filters_optional.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_mixins.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_mountable_favicon_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_mountable_lens_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_mountable_openapi_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_mountable_openrpc_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_mountable_swagger_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_nested_path_schema_and_rpc.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_nested_routing_depth.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_op_ctx_alias_examples.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_op_ctx_behavior.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_op_ctx_core_crud_order.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_openapi_clear_response_schema.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_openapi_schema_examples_presence.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_opspec_effects_i9n_test.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_owner_tenant_policy.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_request_extras.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_request_extras_provider.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_response_extras_provider.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_rest_fallback_serialization.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_rest_row_serialization.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_rest_rpc_parity_v3.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_row_result_serialization.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_schema.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_schema_ctx_attributes_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_schema_ctx_op_ctx_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_schema_ctx_spec_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_sqlite_attachments.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_storage_spec_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_symmetry_parity.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_tigrbl_api_app_usage_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_tigrbl_api_usage_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_tigrbl_api_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_tigrbl_app_include_api_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_tigrbl_app_multi_api_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_tigrbl_app_usage_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_tigrbl_app_uvicorn.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_v3_bulk_rest_endpoints.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_v3_default_rest_ops.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_v3_default_rpc_ops.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_v3_opspec_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/test_verb_alias_policy.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/i9n/uvicorn_utils.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/mount/__init__.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/mount/test_mount_favico.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/parity/__init__.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/parity/test_stdapi_openapi_docs.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/parity/test_stdapi_primitives.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/parity/test_stdapi_routing.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/perf/__init__.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/perf/test_collect_caching.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/perf/test_hookz_performance.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/perf/test_methodz_performance.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/security/test_schemes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/__init__.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/decorators/test_alias_ctx_bindings.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/decorators/test_engine_ctx_bindings.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/decorators/test_hook_ctx_bindings.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/decorators/test_op_alias_bindings.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/decorators/test_op_ctx_bindings.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/decorators/test_schema_ctx_bindings.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_emit_paired_post.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_emit_paired_pre.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_emit_readtime_alias.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_out_masking.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_refresh_demand.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_resolve_assemble.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_resolve_paired_gen.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_schema_collect_in.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_schema_collect_out.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_storage_to_stored.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_wire_build_in.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_wire_build_out.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_wire_dump.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/atoms/test_wire_validate_in.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/runtime/test_events_phases.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_acol_vcol_knobs.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_alias_ctx_op_alias_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_alias_ctx_op_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_api_level_set_auth.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_app_model_defaults.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_app_reexport.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_base_columnspec_inheritance.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_base_facade_initialize.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_build_list_params_spec_model.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_bulk_body_annotation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_bulk_response_schema.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_colspec_map_isolation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_column_collect_mixins.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_column_rest_rpc_results.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_column_table_orm_binding.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_config_dataclass_none.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_core_crud_bulk_ops.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_core_crud_default_ops.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_core_crud_methods.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_core_wrap_memoization.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_db_dependency.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_decorator_and_collect.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_default_tags.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_engine_install_api.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_engine_install_app.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_engine_install_op.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_engine_install_table.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_engine_spec_and_shortcuts.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_engine_usage_levels.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_field_spec_attrs.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_get_schema.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_handler_step_qualname.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_hook_ctx_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_hook_ctx_binding.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_hookz_empty_phase.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_hybrid_session_run_sync.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_in_tx.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_include_model_columns_namespace.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_include_models_base_prefix.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_initialize_async_task.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_initialize_cross_ddl.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_initialize_mixed_engines.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_initialize_task_schedule.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_io_spec_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_iospec_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_iospec_effects.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_jsonrpc_id_example.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_jsonrpc_openrpc.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_jsonrpc_router_default_tag.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_kernel_invoke_ctx.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_kernel_opview_on_demand.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_kernel_plan_labels.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_kernelz_endpoint.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_make_column_shortcuts.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_mixins_sqlalchemy.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_op_alias.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_op_class_engine_binding.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_op_ctx_arity_paths.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_op_ctx_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_op_ctx_core_crud_integration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_op_ctx_dynamic_attach.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_op_ctx_persist_options.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_opspec_effects.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_postgres_engine_errors.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_postgres_env_vars.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_relationship_alias_cols.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_request_body_schema.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_request_response_examples.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_resolver_interning_warmup.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_resolver_precedence.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_parity.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_rest.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_rpc.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rest_all_default_op_verbs.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rest_bulk_delete_suppresses_clear.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rest_no_schema_jsonable.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rest_operation_id_uniqueness.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rest_rpc_parity_default_ops.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rest_rpc_prefixes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rest_rpc_symmetry.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_router_compatibility_shims.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rpc_all_default_op_verbs.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_rpc_default_ops.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_schema_ctx_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_schema_ctx_plain_class.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_schema_spec_presence.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_schemas_binding.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_security_per_route.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_should_wire_canonical.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_api.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_app.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_column.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_engine.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_field.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_hook.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_io.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_op.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_storage.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_spec_table.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_sqlite_attachments.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_sqlite_uuid_type.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_stdapi_request_injection.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_storage_spec_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_sys_handler_crud.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_sys_run_rollback.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_sys_tx_async_begin.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_sys_tx_begin.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_sys_tx_commit.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_table_base_exports.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_table_collect_spec.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_table_columns_namespace.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_table_namespace_init.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_table_namespace_isolation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_api_app_configuration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_api_app_instantiation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_api_app_subclass_definition.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_api_configuration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_api_instantiation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_api_subclass_definition.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_app_configuration.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_app_event_handlers.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_app_instantiation.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_tigrbl_app_subclass_definition.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_v3_favicon_endpoint.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_v3_healthz_endpoint.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_v3_op_alias.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_v3_op_ctx_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_v3_schemas_and_decorators.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_v3_storage_spec_attributes.py +0 -0
- {tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_verbosity.py +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tigrbl.headers import Headers
|
|
4
|
+
from tigrbl.requests import Request
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_request_headers_support_dot_notation_access_and_assignment() -> None:
|
|
8
|
+
headers = Headers({"X-Trace-Id": "abc123"})
|
|
9
|
+
|
|
10
|
+
assert headers.x_trace_id == "abc123"
|
|
11
|
+
|
|
12
|
+
headers.authorization = "Bearer token"
|
|
13
|
+
assert headers["authorization"] == "Bearer token"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_request_exposes_dot_notation_attributes_without_getattr_helpers() -> None:
|
|
17
|
+
request = Request(
|
|
18
|
+
method="GET",
|
|
19
|
+
path="/health",
|
|
20
|
+
headers={"Cookie": "session=abc123"},
|
|
21
|
+
query={"page": ["1"]},
|
|
22
|
+
path_params={},
|
|
23
|
+
body=b"",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
assert request.path == "/health"
|
|
27
|
+
assert request.url.path == "/health"
|
|
28
|
+
assert request.query_params["page"] == "1"
|
|
29
|
+
assert request.cookies["session"] == "abc123"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from tigrbl.requests import Request
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _make_request(*, headers: dict[str, str], body: bytes = b"") -> Request:
|
|
11
|
+
return Request(
|
|
12
|
+
method="POST",
|
|
13
|
+
path="/session",
|
|
14
|
+
headers=headers,
|
|
15
|
+
query={},
|
|
16
|
+
path_params={},
|
|
17
|
+
body=body,
|
|
18
|
+
scope={"client": ("203.0.113.10", 443)},
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_request_headers_and_cookies_support_nested_dot_notation_access() -> None:
|
|
23
|
+
request = _make_request(
|
|
24
|
+
headers={
|
|
25
|
+
"Authorization": "Bearer access-token",
|
|
26
|
+
"Cookie": "sid=session-token; tenant=acme",
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
assert request.headers.authorization == "Bearer access-token"
|
|
31
|
+
assert request.headers.cookie.sid == "session-token"
|
|
32
|
+
assert request.headers.cookie.tenant == "acme"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.mark.asyncio()
|
|
36
|
+
async def test_request_exposes_json_and_dot_notation_bearer_conveniences() -> None:
|
|
37
|
+
request = _make_request(
|
|
38
|
+
headers={"Authorization": "Bearer access-token"},
|
|
39
|
+
body=json.dumps({"ok": True}).encode("utf-8"),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
assert request.json() == {"ok": True}
|
|
43
|
+
assert await request.json() == {"ok": True}
|
|
44
|
+
assert request.bearer_token == "access-token"
|
|
45
|
+
assert request.session_token == "access-token"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_request_session_token_falls_back_to_cookie_and_client_ip_attribute() -> None:
|
|
49
|
+
request = _make_request(headers={"Cookie": "sid=session-token"})
|
|
50
|
+
|
|
51
|
+
assert request.session_token == "session-token"
|
|
52
|
+
assert request.client.ip == "203.0.113.10"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_request_exposes_b64url_helpers_via_dot_notation() -> None:
|
|
56
|
+
request = _make_request(headers={})
|
|
57
|
+
|
|
58
|
+
token = request.b64url_encode(b'{"alg":"HS256"}')
|
|
59
|
+
|
|
60
|
+
assert token == "eyJhbGciOiJIUzI1NiJ9"
|
|
61
|
+
assert request.b64url_decode(token) == b'{"alg":"HS256"}'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from tigrbl.requests import Request
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _make_request(path: str, body: bytes | None = None) -> Request:
|
|
11
|
+
return Request(
|
|
12
|
+
method="POST",
|
|
13
|
+
path=path,
|
|
14
|
+
headers={"content-type": "application/json"},
|
|
15
|
+
query={},
|
|
16
|
+
path_params={},
|
|
17
|
+
body=body or b"",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.asyncio()
|
|
22
|
+
async def test_request_supports_request_url_path_and_body_and_async_json() -> None:
|
|
23
|
+
req = _make_request("/users/42", json.dumps({"id": 42}).encode("utf-8"))
|
|
24
|
+
|
|
25
|
+
assert req.url.path == "/users/42"
|
|
26
|
+
assert req.body == b'{"id": 42}'
|
|
27
|
+
assert await req.json() == {"id": 42}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_request_json_is_usable_without_await_for_blocking_style() -> None:
|
|
31
|
+
req = _make_request("/users", json.dumps({"ok": True, "id": 1}).encode("utf-8"))
|
|
32
|
+
|
|
33
|
+
payload = req.json()
|
|
34
|
+
|
|
35
|
+
assert payload["ok"] is True
|
|
36
|
+
assert payload.get("id") == 1
|
|
37
|
+
assert dict(payload) == {"ok": True, "id": 1}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tigrbl.headers import Headers
|
|
4
|
+
from tigrbl.responses import Response
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_response_headers_support_dot_notation_access_and_assignment() -> None:
|
|
8
|
+
headers = Headers({"Content-Type": "application/json"})
|
|
9
|
+
|
|
10
|
+
assert headers.content_type == "application/json"
|
|
11
|
+
|
|
12
|
+
headers.x_trace_id = "trace-123"
|
|
13
|
+
assert headers["x-trace-id"] == "trace-123"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_response_exposes_dot_notation_attributes_without_getattr_helpers() -> None:
|
|
17
|
+
response = Response.text("ok", headers={"X-Request-Id": "req-1"})
|
|
18
|
+
|
|
19
|
+
assert response.status_code == 200
|
|
20
|
+
assert response.body_text == "ok"
|
|
21
|
+
assert response.headers_map.x_request_id == "req-1"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tigrbl.responses import Response
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_response_supports_instance_json_method_for_body_payload() -> None:
|
|
7
|
+
response = Response(
|
|
8
|
+
status_code=200,
|
|
9
|
+
headers=[("content-type", "application/json; charset=utf-8")],
|
|
10
|
+
body=b'{"ok":true,"count":1}',
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
assert response.json() == {"ok": True, "count": 1}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_response_headers_and_cookies_support_dot_notation() -> None:
|
|
17
|
+
response = Response(
|
|
18
|
+
status_code=200,
|
|
19
|
+
headers=[
|
|
20
|
+
("x-request-id", "req-123"),
|
|
21
|
+
("set-cookie", "sid=session-token; Path=/"),
|
|
22
|
+
],
|
|
23
|
+
body=b"",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
assert response.headers_map.x_request_id == "req-123"
|
|
27
|
+
assert response.cookies.sid == "session-token"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tigrbl.security import APIKey, HTTPBearer
|
|
4
|
+
from tigrbl.requests import Request
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_http_bearer_reads_authorization_from_request_headers_attribute() -> None:
|
|
8
|
+
request = Request(
|
|
9
|
+
method="GET",
|
|
10
|
+
path="/secure",
|
|
11
|
+
headers={"Authorization": "bearer token-123"},
|
|
12
|
+
query={},
|
|
13
|
+
path_params={},
|
|
14
|
+
body=b"",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
creds = HTTPBearer()(request)
|
|
18
|
+
|
|
19
|
+
assert creds is not None
|
|
20
|
+
assert creds.credentials == "token-123"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_api_key_reads_query_value_from_request_query_params_attribute() -> None:
|
|
24
|
+
request = Request(
|
|
25
|
+
method="GET",
|
|
26
|
+
path="/secure",
|
|
27
|
+
headers={},
|
|
28
|
+
query={"api_key": ["secret-value"]},
|
|
29
|
+
path_params={},
|
|
30
|
+
body=b"",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
value = APIKey(name="api_key", in_="query")(request)
|
|
34
|
+
|
|
35
|
+
assert value == "secret-value"
|
|
@@ -8,8 +8,8 @@ from tigrbl.bindings import (
|
|
|
8
8
|
register_rpc,
|
|
9
9
|
)
|
|
10
10
|
from tigrbl.op.mro_collect import mro_collect_decorated_ops
|
|
11
|
-
from tigrbl.
|
|
12
|
-
from tigrbl.
|
|
11
|
+
from tigrbl.responses import response_ctx, render_template
|
|
12
|
+
from tigrbl.responses.shortcuts import (
|
|
13
13
|
as_file,
|
|
14
14
|
as_html,
|
|
15
15
|
as_json,
|
|
@@ -19,7 +19,7 @@ from tigrbl.response.shortcuts import (
|
|
|
19
19
|
)
|
|
20
20
|
from pydantic import BaseModel
|
|
21
21
|
from typing import get_args
|
|
22
|
-
from tigrbl.
|
|
22
|
+
from tigrbl.responses.types import ResponseKind
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
RESPONSE_KINDS = get_args(ResponseKind)
|
|
@@ -5,7 +5,7 @@ from httpx import ASGITransport, Client
|
|
|
5
5
|
|
|
6
6
|
from tigrbl.op.mro_collect import mro_collect_decorated_ops
|
|
7
7
|
from tigrbl.op import op_ctx
|
|
8
|
-
from tigrbl.
|
|
8
|
+
from tigrbl.responses.shortcuts import as_file
|
|
9
9
|
from tigrbl.bindings import (
|
|
10
10
|
build_hooks,
|
|
11
11
|
build_handlers,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import pytest
|
|
3
3
|
from tigrbl import alias_ctx
|
|
4
|
-
from tigrbl.
|
|
4
|
+
from tigrbl.responses import response_ctx
|
|
5
5
|
from tigrbl.engine.shortcuts import engine as build_engine, mem
|
|
6
6
|
from tigrbl.orm.mixins import GUIDPk
|
|
7
7
|
from tigrbl.orm.tables import Base
|
{tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_diagnostics_kernelz.py
RENAMED
|
@@ -3,7 +3,7 @@ from types import SimpleNamespace
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
5
|
from tigrbl.op.types import OpSpec
|
|
6
|
-
from tigrbl.
|
|
6
|
+
from tigrbl.responses.types import ResponseSpec, TemplateSpec
|
|
7
7
|
from tigrbl.system.diagnostics import _build_kernelz_endpoint
|
|
8
8
|
|
|
9
9
|
from .response_utils import RESPONSE_KINDS
|
{tigrbl_tests-0.3.6.dev1 → tigrbl_tests-0.3.7}/tests/unit/test_response_html_jinja_behavior.py
RENAMED
|
@@ -9,7 +9,7 @@ from tigrbl import TigrblApp
|
|
|
9
9
|
from tigrbl.bindings import rpc_call
|
|
10
10
|
from tigrbl.system.diagnostics import _build_kernelz_endpoint
|
|
11
11
|
from tigrbl.runtime.kernel import _default_kernel as K
|
|
12
|
-
from tigrbl.
|
|
12
|
+
from tigrbl.responses import render_template
|
|
13
13
|
|
|
14
14
|
from .response_utils import build_model_for_response, build_model_for_jinja_response
|
|
15
15
|
|
|
@@ -8,7 +8,7 @@ import types
|
|
|
8
8
|
from uuid import uuid4
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
from tigrbl.
|
|
11
|
+
from tigrbl.responses.shortcuts import as_json
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def test_as_json_serializes_uuid() -> None:
|
|
@@ -27,7 +27,7 @@ def test_as_json_serializes_bytes() -> None:
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def test_as_json_fallbacks_when_orjson_unsupported(monkeypatch) -> None:
|
|
30
|
-
import tigrbl.
|
|
30
|
+
import tigrbl.responses.shortcuts as shortcuts
|
|
31
31
|
|
|
32
32
|
original_orjson = sys.modules.get("orjson")
|
|
33
33
|
fake_orjson = types.SimpleNamespace(
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from tigrbl.types import APIRouter, Request, Response
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.asyncio()
|
|
11
|
+
async def test_asgi_http_scope_dispatches_with_query_and_body() -> None:
|
|
12
|
+
app = APIRouter()
|
|
13
|
+
|
|
14
|
+
@app.post("/echo")
|
|
15
|
+
async def echo(request: Request) -> dict[str, object]:
|
|
16
|
+
return {
|
|
17
|
+
"method": request.method,
|
|
18
|
+
"query": request.query,
|
|
19
|
+
"body": request.body.decode("utf-8"),
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
messages: list[dict[str, object]] = []
|
|
23
|
+
|
|
24
|
+
request_messages = iter(
|
|
25
|
+
[
|
|
26
|
+
{
|
|
27
|
+
"type": "http.request",
|
|
28
|
+
"body": b'{"hello":"world"}',
|
|
29
|
+
"more_body": False,
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
async def receive() -> dict[str, object]:
|
|
35
|
+
return next(request_messages)
|
|
36
|
+
|
|
37
|
+
async def send(message: dict[str, object]) -> None:
|
|
38
|
+
messages.append(message)
|
|
39
|
+
|
|
40
|
+
await app._asgi_app(
|
|
41
|
+
{
|
|
42
|
+
"type": "http",
|
|
43
|
+
"method": "POST",
|
|
44
|
+
"path": "/echo",
|
|
45
|
+
"query_string": b"x=1&x=2",
|
|
46
|
+
"headers": [(b"content-type", b"application/json")],
|
|
47
|
+
},
|
|
48
|
+
receive,
|
|
49
|
+
send,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
assert messages[0]["type"] == "http.response.start"
|
|
53
|
+
assert messages[0]["status"] == 200
|
|
54
|
+
assert messages[1]["type"] == "http.response.body"
|
|
55
|
+
assert (
|
|
56
|
+
messages[1]["body"]
|
|
57
|
+
== b'{"method":"POST","query":{"x":["1","2"]},"body":"{\\"hello\\":\\"world\\"}"}'
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@pytest.mark.asyncio()
|
|
62
|
+
async def test_asgi_non_http_scope_returns_500() -> None:
|
|
63
|
+
app = APIRouter()
|
|
64
|
+
messages: list[dict[str, object]] = []
|
|
65
|
+
|
|
66
|
+
async def receive() -> dict[str, object]:
|
|
67
|
+
return {"type": "websocket.receive", "text": "ignored"}
|
|
68
|
+
|
|
69
|
+
async def send(message: dict[str, object]) -> None:
|
|
70
|
+
messages.append(message)
|
|
71
|
+
|
|
72
|
+
await app._asgi_app({"type": "websocket"}, receive, send)
|
|
73
|
+
|
|
74
|
+
assert messages == [
|
|
75
|
+
{"type": "http.response.start", "status": 500, "headers": []},
|
|
76
|
+
{"type": "http.response.body", "body": b""},
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@pytest.mark.asyncio()
|
|
81
|
+
async def test_asgi_204_response_omits_body_and_content_length() -> None:
|
|
82
|
+
app = APIRouter()
|
|
83
|
+
|
|
84
|
+
@app.delete("/items/{item_id}", status_code=204)
|
|
85
|
+
def delete_item(item_id: str) -> None:
|
|
86
|
+
assert item_id == "1"
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
messages: list[dict[str, object]] = []
|
|
90
|
+
|
|
91
|
+
request_messages = iter([{"type": "http.request", "body": b"", "more_body": False}])
|
|
92
|
+
|
|
93
|
+
async def receive() -> dict[str, object]:
|
|
94
|
+
return next(request_messages)
|
|
95
|
+
|
|
96
|
+
async def send(message: dict[str, object]) -> None:
|
|
97
|
+
messages.append(message)
|
|
98
|
+
|
|
99
|
+
await app._asgi_app(
|
|
100
|
+
{
|
|
101
|
+
"type": "http",
|
|
102
|
+
"method": "DELETE",
|
|
103
|
+
"path": "/items/1",
|
|
104
|
+
"query_string": b"",
|
|
105
|
+
"headers": [],
|
|
106
|
+
},
|
|
107
|
+
receive,
|
|
108
|
+
send,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
assert messages[0]["type"] == "http.response.start"
|
|
112
|
+
assert messages[0]["status"] == 204
|
|
113
|
+
assert (b"content-length", b"0") not in messages[0]["headers"]
|
|
114
|
+
assert messages[1] == {
|
|
115
|
+
"type": "http.response.body",
|
|
116
|
+
"body": b"",
|
|
117
|
+
"more_body": False,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@pytest.mark.asyncio()
|
|
122
|
+
async def test_asgi_head_response_strips_body_and_entity_headers() -> None:
|
|
123
|
+
app = APIRouter()
|
|
124
|
+
|
|
125
|
+
@app.get("/items")
|
|
126
|
+
def list_items() -> dict[str, str]:
|
|
127
|
+
return {"ok": "yes"}
|
|
128
|
+
|
|
129
|
+
messages: list[dict[str, object]] = []
|
|
130
|
+
|
|
131
|
+
request_messages = iter([{"type": "http.request", "body": b"", "more_body": False}])
|
|
132
|
+
|
|
133
|
+
async def receive() -> dict[str, object]:
|
|
134
|
+
return next(request_messages)
|
|
135
|
+
|
|
136
|
+
async def send(message: dict[str, object]) -> None:
|
|
137
|
+
messages.append(message)
|
|
138
|
+
|
|
139
|
+
await app._asgi_app(
|
|
140
|
+
{
|
|
141
|
+
"type": "http",
|
|
142
|
+
"method": "HEAD",
|
|
143
|
+
"path": "/items",
|
|
144
|
+
"query_string": b"",
|
|
145
|
+
"headers": [],
|
|
146
|
+
},
|
|
147
|
+
receive,
|
|
148
|
+
send,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
assert messages[0]["type"] == "http.response.start"
|
|
152
|
+
start_headers = dict(messages[0]["headers"])
|
|
153
|
+
assert b"content-length" not in start_headers
|
|
154
|
+
assert b"content-type" not in start_headers
|
|
155
|
+
assert b"transfer-encoding" not in start_headers
|
|
156
|
+
assert messages[1] == {
|
|
157
|
+
"type": "http.response.body",
|
|
158
|
+
"body": b"",
|
|
159
|
+
"more_body": False,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_wsgi_205_response_strips_body_and_entity_headers() -> None:
|
|
164
|
+
app = APIRouter()
|
|
165
|
+
|
|
166
|
+
@app.get("/reset", status_code=205)
|
|
167
|
+
def reset() -> dict[str, str]:
|
|
168
|
+
return {"reset": "ok"}
|
|
169
|
+
|
|
170
|
+
called: dict[str, object] = {}
|
|
171
|
+
|
|
172
|
+
def start_response(status: str, headers: list[tuple[str, str]]) -> None:
|
|
173
|
+
called["status"] = status
|
|
174
|
+
called["headers"] = headers
|
|
175
|
+
|
|
176
|
+
response_chunks = app._wsgi_app(
|
|
177
|
+
{
|
|
178
|
+
"REQUEST_METHOD": "GET",
|
|
179
|
+
"PATH_INFO": "/reset",
|
|
180
|
+
"QUERY_STRING": "",
|
|
181
|
+
"CONTENT_LENGTH": "0",
|
|
182
|
+
"wsgi.input": io.BytesIO(b""),
|
|
183
|
+
},
|
|
184
|
+
start_response,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
headers = dict(called["headers"])
|
|
188
|
+
assert called["status"] == "205 Reset Content"
|
|
189
|
+
assert "content-length" not in headers
|
|
190
|
+
assert "content-type" not in headers
|
|
191
|
+
assert "transfer-encoding" not in headers
|
|
192
|
+
assert response_chunks == [b""]
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def test_wsgi_recomputes_stale_content_length() -> None:
|
|
196
|
+
app = APIRouter()
|
|
197
|
+
|
|
198
|
+
@app.get("/raw")
|
|
199
|
+
def raw() -> object:
|
|
200
|
+
return Response(
|
|
201
|
+
body=b"hello",
|
|
202
|
+
headers=[("content-type", "text/plain"), ("content-length", "999")],
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
called: dict[str, object] = {}
|
|
206
|
+
|
|
207
|
+
def start_response(status: str, headers: list[tuple[str, str]]) -> None:
|
|
208
|
+
called["status"] = status
|
|
209
|
+
called["headers"] = headers
|
|
210
|
+
|
|
211
|
+
response_chunks = app._wsgi_app(
|
|
212
|
+
{
|
|
213
|
+
"REQUEST_METHOD": "GET",
|
|
214
|
+
"PATH_INFO": "/raw",
|
|
215
|
+
"QUERY_STRING": "",
|
|
216
|
+
"CONTENT_LENGTH": "0",
|
|
217
|
+
"wsgi.input": io.BytesIO(b""),
|
|
218
|
+
},
|
|
219
|
+
start_response,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
headers = dict(called["headers"])
|
|
223
|
+
assert called["status"] == "200 OK"
|
|
224
|
+
assert headers["content-length"] == "5"
|
|
225
|
+
assert response_chunks == [b"hello"]
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def test_wsgi_dispatch_reads_body_and_query() -> None:
|
|
229
|
+
app = APIRouter()
|
|
230
|
+
|
|
231
|
+
@app.post("/echo")
|
|
232
|
+
def echo(request: Request) -> dict[str, object]:
|
|
233
|
+
return {
|
|
234
|
+
"path": request.path,
|
|
235
|
+
"query": request.query,
|
|
236
|
+
"body": request.body.decode("utf-8"),
|
|
237
|
+
"script_name": request.script_name,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
called: dict[str, object] = {}
|
|
241
|
+
|
|
242
|
+
def start_response(status: str, headers: list[tuple[str, str]]) -> None:
|
|
243
|
+
called["status"] = status
|
|
244
|
+
called["headers"] = headers
|
|
245
|
+
|
|
246
|
+
response_chunks = app._wsgi_app(
|
|
247
|
+
{
|
|
248
|
+
"REQUEST_METHOD": "POST",
|
|
249
|
+
"PATH_INFO": "/echo",
|
|
250
|
+
"SCRIPT_NAME": "/v1",
|
|
251
|
+
"QUERY_STRING": "a=1&a=2",
|
|
252
|
+
"CONTENT_TYPE": "application/json",
|
|
253
|
+
"CONTENT_LENGTH": "7",
|
|
254
|
+
"wsgi.input": io.BytesIO(b'{"a":1}'),
|
|
255
|
+
},
|
|
256
|
+
start_response,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
assert called["status"] == "200 OK"
|
|
260
|
+
assert response_chunks == [
|
|
261
|
+
b'{"path":"/echo","query":{"a":["1","2"]},"body":"{\\"a\\":1}","script_name":"/v1"}'
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def test_invalid_asgi_wsgi_invocation_raises_type_error() -> None:
|
|
266
|
+
app = APIRouter()
|
|
267
|
+
|
|
268
|
+
with pytest.raises(TypeError, match="Invalid ASGI/WSGI invocation"):
|
|
269
|
+
app("not-a-scope")
|