fixturify 0.1.11__tar.gz → 0.1.12__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.
- {fixturify-0.1.11 → fixturify-0.1.12}/PKG-INFO +1 -1
- {fixturify-0.1.11 → fixturify-0.1.12}/docker-compose.yml +3 -3
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/__init__.py +1 -1
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_recorder.py +51 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_stubs/_httpcore.py +35 -24
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_connection_cache.py +24 -9
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_aiomysql.py +1 -1
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_aiosqlite.py +1 -1
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_asyncpg.py +11 -5
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_base.py +9 -3
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_psycopg.py +1 -1
- {fixturify-0.1.11 → fixturify-0.1.12}/pyproject.toml +3 -1
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/nested/deep/test_grandparent_path.py +0 -2
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_connection_cache.py +9 -10
- {fixturify-0.1.11 → fixturify-0.1.12}/uv.lock +1 -1
- {fixturify-0.1.11 → fixturify-0.1.12}/.github/workflows/publish.yml +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/.gitignore +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/README.md +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/docs/http.md +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/docs/json_assert.md +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/docs/object_mapper.md +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/docs/read.md +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/docs/sql.md +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/_utils/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/_utils/_constants.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/_utils/_fixture_discovery.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/_utils/_path_resolver.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_config.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_decorator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_exceptions.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_fixture_discovery.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_matcher.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_mock_context.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_models.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_patcher.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_player.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_stubs/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_stubs/_aiohttp.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_stubs/_connection.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_stubs/_tornado.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/http_d/_utils.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/json_assert/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/json_assert/_actual_saver.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/json_assert/_assert.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/json_assert/_comparator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/json_assert/_diff_formatter.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/json_assert/_normalizer.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_base.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_dataclass.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_plain.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_pydantic_v1.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_pydantic_v2.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_sqlalchemy.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_sqlmodel.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_detectors/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_detectors/_type_detector.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/_base.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/_dataclass.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/_plain.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/_pydantic_v1.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/_pydantic_v2.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/_sqlalchemy.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_serializers/_sqlmodel.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/mapper.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/read_d/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/read_d/_decorator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/read_d/_fixture_loader.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_config.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_decorator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_driver_registry.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_executor.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_fixture_discovery.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_phase.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_mysql.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_psycopg2.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_registry.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/fixturify/sql_d/_strategies/_sqlite.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/__files/response_1_4678e16e.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/aiohttp_get_all_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/aiohttp_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/aiohttp_multiple_requests.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/aiohttp_post_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/aiohttp_read_text.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/aiohttp_with_config.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/boto3_localstack_s3.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/boto3_localstack_s3_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/boto3_localstack_sts.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/boto3_s3_list_buckets.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/boto3_sts_get_caller_identity.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/fixture_config_test.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/http_client_get_all_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/http_client_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/http_client_http_connection.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/http_client_post_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/http_client_sequential.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpcore_async_get_single.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpcore_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpcore_post_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpcore_via_httpx.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpcore_via_httpx_async.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpcore_with_config.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httplib2_get_all_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httplib2_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httplib2_post_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httplib2_sequential.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httplib2_with_config.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpx_async_get_all.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpx_async_get_single.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpx_async_multiple.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpx_sync_get_all.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpx_sync_get_single.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/httpx_sync_post.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/mixed_clients.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/multi_client_async.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/multi_client_playback_order.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/multi_client_post_requests.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/multi_client_sequential.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/multi_client_sync.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/multi_client_with_config.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/multi_client_with_urllib3.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/requests_get_all_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/requests_get_multiple_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/requests_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/requests_post_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/requests_sequential_calls.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/requests_with_config.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/tornado_async_get_all_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/tornado_async_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/tornado_async_multiple.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/tornado_sync_get_all_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/tornado_sync_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/tornado_sync_post_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/tornado_with_config.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/urllib3_get_all_objects.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/urllib3_get_single_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/urllib3_poolmanager.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/urllib3_post_object.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/fixtures/urllib3_via_requests.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_aiohttp_client.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_boto3_client.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_config.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_decorator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_fixture_discovery.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_http_client.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_httpcore_client.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_httplib2_client.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_integration.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_matcher.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_matching.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_models.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_multi_client_integration.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_player.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_recorder.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_tornado_client.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_http/test_urllib3_client.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_integration/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_integration/fixtures/api_request.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_integration/fixtures/cleanup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_integration/fixtures/expected_result.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_integration/fixtures/external_api.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_integration/fixtures/setup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_integration/test_full_integration.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/fixtures/ACTUAL/nested.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/fixtures/ACTUAL/user.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/fixtures/float_values.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/fixtures/nested.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/fixtures/unordered_list.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/fixtures/user.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/fixtures/users.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/nested/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/nested/deep/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/nested/test_parent_path.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/test_comparator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/test_json_assert.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/test_normalizer.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_circular.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_dataclass.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_dict.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_plain.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_pydantic.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_special_types.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_sqlalchemy.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_mapper_sqlmodel.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_object_mapper/test_type_detector.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/company.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/config.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/pydantic_company.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/pydantic_user.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/pydantic_users.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/sqlalchemy_user.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/sqlalchemy_users.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/sqlmodel_nested_company.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/sqlmodel_user_table.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/sqlmodel_users_table.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/user.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/fixtures/users.json +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/nested/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/nested/deep/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/nested/deep/test_grandparent_path.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/nested/test_parent_path.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/test_decorator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/test_decorator_models.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_read/test_fixture_loader.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/conftest.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/cleanup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/mysql_cleanup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/mysql_multistatement_cleanup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/mysql_multistatement_setup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/mysql_order_tracker_setup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/mysql_setup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/mysql_utf8_test.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/nested/deep.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/order_cleanup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/order_step1.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/order_step2.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/order_step3.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/order_step4.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/order_tracker_setup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/postgres_cleanup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/postgres_setup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/setup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/utf8_cleanup.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/fixtures/utf8_test.sql +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/mysql/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/mysql/conftest.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/mysql/test_integration.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/mysql_async/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/mysql_async/conftest.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/mysql_async/test_integration.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/postgres/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/postgres/conftest.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/postgres/test_integration.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/postgres_async/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/postgres_async/conftest.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/postgres_async/test_integration.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/submodule/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/submodule/deep/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/submodule/deep/test_grandparent_path.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/submodule/test_nested_path.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_config.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_decorator.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_driver_registry.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_executor.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_fixture_discovery.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_path_resolution.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_sql/test_phase.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_utils/__init__.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_utils/test_constants.py +0 -0
- {fixturify-0.1.11 → fixturify-0.1.12}/tests/test_utils/test_path_resolver.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fixturify
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.12
|
|
4
4
|
Summary: A collection of convenient testing utilities for Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/eleven-sea/pytools
|
|
6
6
|
Project-URL: Repository, https://github.com/eleven-sea/pytools
|
|
@@ -18,11 +18,11 @@ services:
|
|
|
18
18
|
environment:
|
|
19
19
|
- POSTGRES_USER=postgres
|
|
20
20
|
- POSTGRES_PASSWORD=postgres
|
|
21
|
-
- POSTGRES_DB=
|
|
21
|
+
- POSTGRES_DB=fixturify
|
|
22
22
|
volumes:
|
|
23
23
|
- postgres_data:/var/lib/postgresql/data
|
|
24
24
|
healthcheck:
|
|
25
|
-
test: ["CMD-SHELL", "pg_isready -U postgres -d
|
|
25
|
+
test: ["CMD-SHELL", "pg_isready -U postgres -d fixturify"]
|
|
26
26
|
interval: 5s
|
|
27
27
|
timeout: 5s
|
|
28
28
|
retries: 5
|
|
@@ -33,7 +33,7 @@ services:
|
|
|
33
33
|
- "3306:3306"
|
|
34
34
|
environment:
|
|
35
35
|
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
|
36
|
-
- MYSQL_DATABASE=
|
|
36
|
+
- MYSQL_DATABASE=fixturify
|
|
37
37
|
volumes:
|
|
38
38
|
- mysql_data:/var/lib/mysql
|
|
39
39
|
healthcheck:
|
|
@@ -811,10 +811,36 @@ def create_response_from_http_client(
|
|
|
811
811
|
Returns:
|
|
812
812
|
HttpResponse model
|
|
813
813
|
"""
|
|
814
|
+
import gzip
|
|
815
|
+
import zlib
|
|
816
|
+
|
|
814
817
|
headers = dict(response.getheaders()) if hasattr(response, "getheaders") else {}
|
|
815
818
|
content_type = headers.get("content-type", headers.get("Content-Type", ""))
|
|
819
|
+
content_encoding = headers.get(
|
|
820
|
+
"content-encoding", headers.get("Content-Encoding", "")
|
|
821
|
+
).lower()
|
|
816
822
|
|
|
817
823
|
body_bytes = response.read()
|
|
824
|
+
|
|
825
|
+
# Decompress if needed (http.client doesn't auto-decompress)
|
|
826
|
+
if body_bytes and content_encoding in ("gzip", "deflate"):
|
|
827
|
+
try:
|
|
828
|
+
if content_encoding == "gzip":
|
|
829
|
+
body_bytes = gzip.decompress(body_bytes)
|
|
830
|
+
elif content_encoding == "deflate":
|
|
831
|
+
# deflate can be raw or zlib-wrapped
|
|
832
|
+
try:
|
|
833
|
+
body_bytes = zlib.decompress(body_bytes)
|
|
834
|
+
except zlib.error:
|
|
835
|
+
body_bytes = zlib.decompress(body_bytes, -zlib.MAX_WBITS)
|
|
836
|
+
# Remove content-encoding header since we decompressed
|
|
837
|
+
headers = {
|
|
838
|
+
k: v for k, v in headers.items()
|
|
839
|
+
if k.lower() != "content-encoding"
|
|
840
|
+
}
|
|
841
|
+
except (gzip.BadGzipFile, OSError, zlib.error):
|
|
842
|
+
pass # Not actually compressed, use as-is
|
|
843
|
+
|
|
818
844
|
body, body_encoding, is_binary = _serialize_body(body_bytes, content_type)
|
|
819
845
|
|
|
820
846
|
if is_binary:
|
|
@@ -1312,18 +1338,43 @@ def create_response_from_httpcore(
|
|
|
1312
1338
|
Returns:
|
|
1313
1339
|
HttpResponse model
|
|
1314
1340
|
"""
|
|
1341
|
+
import gzip
|
|
1342
|
+
import zlib
|
|
1343
|
+
|
|
1315
1344
|
# Convert headers from list of tuples to dict
|
|
1316
1345
|
headers_dict: Dict[str, str] = {}
|
|
1346
|
+
content_encoding = ""
|
|
1317
1347
|
if response.headers:
|
|
1318
1348
|
for k, v in response.headers:
|
|
1319
1349
|
key = k.decode() if isinstance(k, bytes) else k
|
|
1320
1350
|
val = v.decode() if isinstance(v, bytes) else v
|
|
1321
1351
|
headers_dict[key] = val
|
|
1352
|
+
if key.lower() == "content-encoding":
|
|
1353
|
+
content_encoding = val.lower()
|
|
1322
1354
|
|
|
1323
1355
|
content_type = headers_dict.get("content-type", headers_dict.get("Content-Type", ""))
|
|
1324
1356
|
|
|
1325
1357
|
# Get body content
|
|
1326
1358
|
body_bytes = response.content
|
|
1359
|
+
|
|
1360
|
+
# Decompress if needed (httpcore doesn't auto-decompress)
|
|
1361
|
+
if body_bytes and content_encoding in ("gzip", "deflate"):
|
|
1362
|
+
try:
|
|
1363
|
+
if content_encoding == "gzip":
|
|
1364
|
+
body_bytes = gzip.decompress(body_bytes)
|
|
1365
|
+
elif content_encoding == "deflate":
|
|
1366
|
+
try:
|
|
1367
|
+
body_bytes = zlib.decompress(body_bytes)
|
|
1368
|
+
except zlib.error:
|
|
1369
|
+
body_bytes = zlib.decompress(body_bytes, -zlib.MAX_WBITS)
|
|
1370
|
+
# Remove content-encoding header since we decompressed
|
|
1371
|
+
headers_dict = {
|
|
1372
|
+
k: v for k, v in headers_dict.items()
|
|
1373
|
+
if k.lower() != "content-encoding"
|
|
1374
|
+
}
|
|
1375
|
+
except (gzip.BadGzipFile, OSError, zlib.error):
|
|
1376
|
+
pass # Not actually compressed, use as-is
|
|
1377
|
+
|
|
1327
1378
|
body, body_encoding, is_binary = _serialize_body(body_bytes, content_type)
|
|
1328
1379
|
|
|
1329
1380
|
if is_binary:
|
|
@@ -9,7 +9,7 @@ import functools
|
|
|
9
9
|
from typing import TYPE_CHECKING, Any
|
|
10
10
|
|
|
11
11
|
from .._models import HttpRequest, HttpResponse
|
|
12
|
-
from .._recorder import create_request_from_httpcore
|
|
12
|
+
from .._recorder import create_request_from_httpcore
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from .._mock_context import HttpMockContext
|
|
@@ -72,13 +72,14 @@ def _build_response(response_model: HttpResponse) -> Any:
|
|
|
72
72
|
"""Build httpcore Response from HttpResponse model."""
|
|
73
73
|
from httpcore import Response
|
|
74
74
|
import gzip
|
|
75
|
-
|
|
75
|
+
import zlib
|
|
76
|
+
|
|
76
77
|
# Get content encoding before filtering headers
|
|
77
78
|
content_encoding = response_model.headers.get(
|
|
78
|
-
"content-encoding",
|
|
79
|
+
"content-encoding",
|
|
79
80
|
response_model.headers.get("Content-Encoding", "")
|
|
80
81
|
).lower()
|
|
81
|
-
|
|
82
|
+
|
|
82
83
|
# Build headers as list of tuples
|
|
83
84
|
headers = [
|
|
84
85
|
(k.encode("ascii"), v.encode("ascii"))
|
|
@@ -86,15 +87,21 @@ def _build_response(response_model: HttpResponse) -> Any:
|
|
|
86
87
|
# Skip headers that cause issues
|
|
87
88
|
if k.lower() not in ("transfer-encoding", "content-encoding")
|
|
88
89
|
]
|
|
89
|
-
|
|
90
|
+
|
|
90
91
|
body = response_model.get_body_bytes()
|
|
91
|
-
|
|
92
|
-
# Decompress
|
|
93
|
-
if content_encoding
|
|
92
|
+
|
|
93
|
+
# Decompress body if needed (since we removed content-encoding header)
|
|
94
|
+
if body and content_encoding in ("gzip", "deflate"):
|
|
94
95
|
try:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
if content_encoding == "gzip":
|
|
97
|
+
body = gzip.decompress(body)
|
|
98
|
+
elif content_encoding == "deflate":
|
|
99
|
+
try:
|
|
100
|
+
body = zlib.decompress(body)
|
|
101
|
+
except zlib.error:
|
|
102
|
+
body = zlib.decompress(body, -zlib.MAX_WBITS)
|
|
103
|
+
except (gzip.BadGzipFile, OSError, zlib.error):
|
|
104
|
+
pass # Not actually compressed, use as-is
|
|
98
105
|
|
|
99
106
|
return Response(
|
|
100
107
|
status=response_model.status,
|
|
@@ -105,16 +112,17 @@ def _build_response(response_model: HttpResponse) -> Any:
|
|
|
105
112
|
|
|
106
113
|
def _serialize_response(httpcore_response: Any) -> HttpResponse:
|
|
107
114
|
"""Create HttpResponse from httpcore Response object.
|
|
108
|
-
|
|
109
|
-
Handles gzip decompression before serialization to ensure
|
|
115
|
+
|
|
116
|
+
Handles gzip/deflate decompression before serialization to ensure
|
|
110
117
|
body is stored as readable text, not binary.
|
|
111
118
|
"""
|
|
112
119
|
import gzip
|
|
120
|
+
import zlib
|
|
113
121
|
from .._models import HttpResponse
|
|
114
|
-
|
|
122
|
+
|
|
115
123
|
# Get body - should be available after read()/aread()
|
|
116
124
|
body_bytes = httpcore_response.content
|
|
117
|
-
|
|
125
|
+
|
|
118
126
|
# Convert headers
|
|
119
127
|
headers_dict = {}
|
|
120
128
|
content_encoding = ""
|
|
@@ -124,21 +132,24 @@ def _serialize_response(httpcore_response: Any) -> HttpResponse:
|
|
|
124
132
|
headers_dict[key] = val
|
|
125
133
|
if key.lower() == "content-encoding":
|
|
126
134
|
content_encoding = val.lower()
|
|
127
|
-
|
|
128
|
-
#
|
|
129
|
-
if content_encoding
|
|
135
|
+
|
|
136
|
+
# Decompress body before serialization if needed
|
|
137
|
+
if body_bytes and content_encoding in ("gzip", "deflate"):
|
|
130
138
|
try:
|
|
131
|
-
|
|
139
|
+
if content_encoding == "gzip":
|
|
140
|
+
body_bytes = gzip.decompress(body_bytes)
|
|
141
|
+
elif content_encoding == "deflate":
|
|
142
|
+
try:
|
|
143
|
+
body_bytes = zlib.decompress(body_bytes)
|
|
144
|
+
except zlib.error:
|
|
145
|
+
body_bytes = zlib.decompress(body_bytes, -zlib.MAX_WBITS)
|
|
132
146
|
# Remove content-encoding header since we decompressed
|
|
133
147
|
headers_dict = {
|
|
134
148
|
k: v for k, v in headers_dict.items()
|
|
135
149
|
if k.lower() != "content-encoding"
|
|
136
150
|
}
|
|
137
|
-
except (gzip.BadGzipFile, OSError):
|
|
138
|
-
pass # Not actually
|
|
139
|
-
|
|
140
|
-
# Determine content type
|
|
141
|
-
content_type = headers_dict.get("content-type", headers_dict.get("Content-Type", ""))
|
|
151
|
+
except (gzip.BadGzipFile, OSError, zlib.error):
|
|
152
|
+
pass # Not actually compressed, use as-is
|
|
142
153
|
|
|
143
154
|
# Try to decode as text/JSON
|
|
144
155
|
body_str = None
|
|
@@ -43,6 +43,9 @@ class ConnectionCache:
|
|
|
43
43
|
Maintains separate caches for sync and async connections.
|
|
44
44
|
Connections are created on first access and reused for subsequent calls.
|
|
45
45
|
All connections are closed when the process exits via atexit handler.
|
|
46
|
+
|
|
47
|
+
Async connections are tracked with their event loop - if the loop changes
|
|
48
|
+
or closes, the cached connection is invalidated automatically.
|
|
46
49
|
"""
|
|
47
50
|
|
|
48
51
|
_instance: Optional["ConnectionCache"] = None
|
|
@@ -58,7 +61,8 @@ class ConnectionCache:
|
|
|
58
61
|
return
|
|
59
62
|
self._initialized = True
|
|
60
63
|
self._sync_connections: Dict[CacheKey, Any] = {}
|
|
61
|
-
|
|
64
|
+
# Store (connection, event_loop) tuple for async connections
|
|
65
|
+
self._async_connections: Dict[CacheKey, Tuple[Any, Any]] = {}
|
|
62
66
|
self._sync_close_funcs: Dict[CacheKey, Any] = {}
|
|
63
67
|
self._async_close_funcs: Dict[CacheKey, Any] = {}
|
|
64
68
|
|
|
@@ -90,25 +94,36 @@ class ConnectionCache:
|
|
|
90
94
|
async def get_async(
|
|
91
95
|
self,
|
|
92
96
|
config: "SqlTestConfig",
|
|
93
|
-
|
|
97
|
+
connect_factory: Any,
|
|
94
98
|
) -> Any:
|
|
95
99
|
"""
|
|
96
100
|
Get or create an async connection.
|
|
97
101
|
|
|
102
|
+
Tracks the event loop - if the cached connection was created in a
|
|
103
|
+
different or closed loop, it's invalidated and a new one is created.
|
|
104
|
+
|
|
98
105
|
Args:
|
|
99
106
|
config: Database configuration
|
|
100
|
-
|
|
107
|
+
connect_factory: Callable that returns a coroutine when called
|
|
101
108
|
|
|
102
109
|
Returns:
|
|
103
110
|
Database connection object
|
|
104
111
|
"""
|
|
105
112
|
key = CacheKey.from_config(config)
|
|
113
|
+
current_loop = asyncio.get_running_loop()
|
|
106
114
|
|
|
107
|
-
if key
|
|
108
|
-
connection =
|
|
109
|
-
|
|
115
|
+
if key in self._async_connections:
|
|
116
|
+
connection, cached_loop = self._async_connections[key]
|
|
117
|
+
# Check if loop is the same and still running
|
|
118
|
+
if cached_loop is current_loop and not cached_loop.is_closed():
|
|
119
|
+
return connection
|
|
120
|
+
# Loop changed or closed - remove stale connection
|
|
121
|
+
del self._async_connections[key]
|
|
110
122
|
|
|
111
|
-
|
|
123
|
+
# Create new connection and track with current loop
|
|
124
|
+
connection = await connect_factory()
|
|
125
|
+
self._async_connections[key] = (connection, current_loop)
|
|
126
|
+
return connection
|
|
112
127
|
|
|
113
128
|
def register_sync_closer(
|
|
114
129
|
self,
|
|
@@ -150,7 +165,7 @@ class ConnectionCache:
|
|
|
150
165
|
This is called by atexit handler which runs in sync context.
|
|
151
166
|
We need to handle async cleanup carefully.
|
|
152
167
|
"""
|
|
153
|
-
for key, connection in list(self._async_connections.items()):
|
|
168
|
+
for key, (connection, _loop) in list(self._async_connections.items()):
|
|
154
169
|
try:
|
|
155
170
|
if hasattr(connection, "close"):
|
|
156
171
|
# Some async connections have sync close()
|
|
@@ -174,7 +189,7 @@ class ConnectionCache:
|
|
|
174
189
|
|
|
175
190
|
async def close_all_async(self) -> None:
|
|
176
191
|
"""Close all cached async connections from async context."""
|
|
177
|
-
for key, connection in list(self._async_connections.items()):
|
|
192
|
+
for key, (connection, _loop) in list(self._async_connections.items()):
|
|
178
193
|
try:
|
|
179
194
|
if key in self._async_close_funcs:
|
|
180
195
|
await self._async_close_funcs[key](connection)
|
|
@@ -28,7 +28,7 @@ class AiomysqlStrategy(AsyncSqlExecutionStrategy):
|
|
|
28
28
|
params = self.build_connection_params(config)
|
|
29
29
|
|
|
30
30
|
connection = await self.get_cached_connection_async(
|
|
31
|
-
config, driver.connect(**params)
|
|
31
|
+
config, lambda: driver.connect(**params)
|
|
32
32
|
)
|
|
33
33
|
async with connection.cursor() as cursor:
|
|
34
34
|
# aiomysql doesn't support multi-statement by default
|
|
@@ -26,7 +26,7 @@ class AiosqliteStrategy(AsyncSqlExecutionStrategy):
|
|
|
26
26
|
database_path = params.get("database", ":memory:")
|
|
27
27
|
|
|
28
28
|
connection = await self.get_cached_connection_async(
|
|
29
|
-
config, driver.connect(database_path)
|
|
29
|
+
config, lambda: driver.connect(database_path)
|
|
30
30
|
)
|
|
31
31
|
await connection.executescript(sql_content)
|
|
32
32
|
await connection.commit()
|
|
@@ -9,7 +9,11 @@ if TYPE_CHECKING:
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class AsyncpgStrategy(AsyncSqlExecutionStrategy):
|
|
12
|
-
"""Execution strategy for asyncpg (PostgreSQL async).
|
|
12
|
+
"""Execution strategy for asyncpg (PostgreSQL async).
|
|
13
|
+
|
|
14
|
+
Uses connection pools instead of single connections to support
|
|
15
|
+
concurrent operations across multiple tests.
|
|
16
|
+
"""
|
|
13
17
|
|
|
14
18
|
driver_name = "asyncpg"
|
|
15
19
|
is_async = True
|
|
@@ -23,11 +27,13 @@ class AsyncpgStrategy(AsyncSqlExecutionStrategy):
|
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
async def execute_async(self, sql_content: str, config: "SqlTestConfig") -> None:
|
|
26
|
-
"""Execute SQL using asyncpg."""
|
|
30
|
+
"""Execute SQL using asyncpg with connection pool."""
|
|
27
31
|
driver = self.get_driver_module()
|
|
28
32
|
params = self.build_connection_params(config)
|
|
29
33
|
|
|
30
|
-
connection
|
|
31
|
-
|
|
34
|
+
# Use pool instead of single connection for concurrency support
|
|
35
|
+
pool = await self.get_cached_connection_async(
|
|
36
|
+
config, lambda: driver.create_pool(**params, min_size=1, max_size=5)
|
|
32
37
|
)
|
|
33
|
-
|
|
38
|
+
async with pool.acquire() as connection:
|
|
39
|
+
await connection.execute(sql_content)
|
|
@@ -142,14 +142,20 @@ class AsyncSqlExecutionStrategy(SqlExecutionStrategy):
|
|
|
142
142
|
async def get_cached_connection_async(
|
|
143
143
|
self,
|
|
144
144
|
config: "SqlTestConfig",
|
|
145
|
-
|
|
145
|
+
connect_factory: Any,
|
|
146
146
|
) -> Any:
|
|
147
147
|
"""
|
|
148
148
|
Get a cached async connection or create a new one.
|
|
149
149
|
|
|
150
|
+
Note: Async connections are tied to the event loop. For caching to work,
|
|
151
|
+
pytest must use session-scoped event loop:
|
|
152
|
+
|
|
153
|
+
[tool.pytest.ini_options]
|
|
154
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
155
|
+
|
|
150
156
|
Args:
|
|
151
157
|
config: Database configuration
|
|
152
|
-
|
|
158
|
+
connect_factory: Callable that returns a coroutine when called
|
|
153
159
|
|
|
154
160
|
Returns:
|
|
155
161
|
Database connection (cached or newly created)
|
|
@@ -157,4 +163,4 @@ class AsyncSqlExecutionStrategy(SqlExecutionStrategy):
|
|
|
157
163
|
from .._connection_cache import get_connection_cache
|
|
158
164
|
|
|
159
165
|
cache = get_connection_cache()
|
|
160
|
-
return await cache.get_async(config,
|
|
166
|
+
return await cache.get_async(config, connect_factory)
|
|
@@ -28,7 +28,7 @@ class PsycopgStrategy(AsyncSqlExecutionStrategy):
|
|
|
28
28
|
params = self.build_connection_params(config)
|
|
29
29
|
|
|
30
30
|
connection = await self.get_cached_connection_async(
|
|
31
|
-
config, driver.AsyncConnection.connect(**params)
|
|
31
|
+
config, lambda: driver.AsyncConnection.connect(**params)
|
|
32
32
|
)
|
|
33
33
|
await connection.execute(sql_content)
|
|
34
34
|
await connection.commit()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fixturify"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.12"
|
|
4
4
|
description = "A collection of convenient testing utilities for Python"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
license = "MIT"
|
|
@@ -64,3 +64,5 @@ dev-dependencies = [
|
|
|
64
64
|
[tool.pytest.ini_options]
|
|
65
65
|
testpaths = ["tests"]
|
|
66
66
|
asyncio_mode = "auto"
|
|
67
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
68
|
+
asyncio_default_test_loop_scope = "function"
|
{fixturify-0.1.11 → fixturify-0.1.12}/tests/test_json_assert/nested/deep/test_grandparent_path.py
RENAMED
|
@@ -130,11 +130,9 @@ class TestJsonAssertGrandparentPathMismatch:
|
|
|
130
130
|
|
|
131
131
|
def test_nonexistent_file_creates_snapshot_grandparent(self, tmp_path):
|
|
132
132
|
"""Test that nonexistent file creates snapshot with ../../ path."""
|
|
133
|
-
import os
|
|
134
133
|
|
|
135
134
|
# This test verifies the snapshot creation behavior
|
|
136
135
|
# JsonAssert creates the file if it doesn't exist (snapshot testing)
|
|
137
|
-
data = {"name": "John"}
|
|
138
136
|
|
|
139
137
|
# Use a temp file path that doesn't exist
|
|
140
138
|
temp_file = tmp_path / "snapshot.json"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Tests for the connection cache module."""
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
|
-
from unittest.mock import Mock,
|
|
4
|
+
from unittest.mock import Mock, AsyncMock
|
|
5
5
|
|
|
6
6
|
from fixturify.sql_d._connection_cache import (
|
|
7
7
|
CacheKey,
|
|
@@ -193,10 +193,10 @@ class TestConnectionCache:
|
|
|
193
193
|
|
|
194
194
|
mock_conn = AsyncMock()
|
|
195
195
|
|
|
196
|
-
async def
|
|
196
|
+
async def connect_factory():
|
|
197
197
|
return mock_conn
|
|
198
198
|
|
|
199
|
-
result = await cache.get_async(config,
|
|
199
|
+
result = await cache.get_async(config, connect_factory)
|
|
200
200
|
|
|
201
201
|
assert result is mock_conn
|
|
202
202
|
|
|
@@ -215,19 +215,18 @@ class TestConnectionCache:
|
|
|
215
215
|
mock_conn = AsyncMock()
|
|
216
216
|
call_count = 0
|
|
217
217
|
|
|
218
|
-
async def
|
|
218
|
+
async def connect_factory():
|
|
219
219
|
nonlocal call_count
|
|
220
220
|
call_count += 1
|
|
221
221
|
return mock_conn
|
|
222
222
|
|
|
223
|
-
# First call
|
|
224
|
-
result1 = await cache.get_async(config,
|
|
225
|
-
# Second call -
|
|
226
|
-
result2 = await cache.get_async(config,
|
|
223
|
+
# First call - creates connection
|
|
224
|
+
result1 = await cache.get_async(config, connect_factory)
|
|
225
|
+
# Second call - reuses connection
|
|
226
|
+
result2 = await cache.get_async(config, connect_factory)
|
|
227
227
|
|
|
228
228
|
assert result1 is result2
|
|
229
|
-
#
|
|
230
|
-
# (second coro is not awaited because cache hit)
|
|
229
|
+
# Factory should only be called once (cache hit on second call)
|
|
231
230
|
assert call_count == 1
|
|
232
231
|
|
|
233
232
|
def test_close_all_sync(self) -> None:
|
|
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
|
|
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
|
{fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_pydantic_v1.py
RENAMED
|
File without changes
|
{fixturify-0.1.11 → fixturify-0.1.12}/fixturify/object_mapper/_deserializers/_pydantic_v2.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
|