From 6a40a966ad423ae917e36fede7c35deb94120b6e Mon Sep 17 00:00:00 2001 From: Jonas Scholl Date: Sat, 8 Apr 2023 15:15:32 +0200 Subject: [PATCH 1/6] enable SSL for test postgres instance --- tests/docker-compose.yaml | 4 +++ tests/postgres.crt | 67 +++++++++++++++++++++++++++++++++++++++ tests/postgres.key | 27 ++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 tests/postgres.crt create mode 100644 tests/postgres.key diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml index 7fb8a11..ef8c4fe 100644 --- a/tests/docker-compose.yaml +++ b/tests/docker-compose.yaml @@ -4,9 +4,13 @@ services: postgresql-database: image: postgres:15 container_name: "database-setup-tools-test-postgres-database" + command: -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key ports: - "5432:5432" environment: POSTGRES_USER: "postgres" POSTGRES_PASSWORD: "postgres" POSTGRES_DB: "postgres" + volumes: + - ./postgres.crt:/var/lib/postgresql/server.crt + - ./postgres.key:/var/lib/postgresql/server.key diff --git a/tests/postgres.crt b/tests/postgres.crt new file mode 100644 index 0000000..ef4faf6 --- /dev/null +++ b/tests/postgres.crt @@ -0,0 +1,67 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: + c5:e4:99:1e:19:94:7b:5e + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=localhost + Validity + Not Before: Apr 8 13:12:14 2023 GMT + Not After : May 8 13:12:14 2023 GMT + Subject: CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:ad:02:9c:51:96:7f:2e:8b:f4:d3:52:32:ae:38: + 33:dc:e8:e6:75:18:a0:75:cc:03:dd:51:d9:75:20: + 2f:39:c7:04:1c:f6:68:bd:93:05:53:83:66:2c:0e: + 3f:2b:76:4d:0d:7c:e1:83:72:4d:4b:df:d8:d1:31: + a5:f5:2a:29:3c:b4:21:27:f4:81:aa:a3:e4:46:50: + 23:1a:fa:de:f3:da:a0:72:5b:7b:9e:ea:e5:5f:fd: + 22:9d:ce:dc:9d:3d:e6:59:b2:30:19:bd:f7:27:5c: + dd:95:4c:1a:06:21:e2:75:f2:bc:32:f0:82:61:12: + cc:26:34:14:25:42:71:96:f5:75:8f:b5:10:70:b5: + 14:6a:79:c6:c8:6a:fd:b1:86:66:d2:17:eb:44:50: + 90:07:7a:14:ef:7a:58:79:f0:23:2b:f5:f3:61:ee: + d1:f6:9c:af:be:a2:77:0e:dd:0b:8a:9b:95:9d:73: + 11:08:7e:a5:40:62:3d:69:8d:de:5a:a3:fd:a1:7a: + a1:d1:0e:32:0d:dd:f8:6c:a3:29:1b:ae:47:fc:be: + 1a:a8:89:dc:d6:a8:a0:78:18:f1:e3:d6:f9:8a:52: + 7a:10:a5:13:c4:13:d4:a9:22:aa:82:6e:28:bb:4f: + 99:99:99:80:7e:b6:ce:ac:79:d7:76:ad:86:b6:6b: + 79:f9 + Exponent: 65537 (0x10001) + Signature Algorithm: sha256WithRSAEncryption + aa:68:b1:9f:47:d8:34:a4:24:d2:dc:1a:9f:ef:2a:e9:6f:db: + 4d:3e:f5:49:96:bd:d9:8b:06:90:d3:5c:df:72:d7:75:c7:7c: + d0:3d:e7:80:f4:83:0e:2c:62:6a:c2:cb:fb:ec:59:c2:63:08: + 10:4f:81:6c:66:64:1e:ae:db:69:58:e5:b0:7b:11:65:da:59: + 56:13:95:59:28:e1:3d:ca:9f:95:50:d2:2a:a8:69:dd:a8:6d: + ad:04:9e:88:04:fb:8e:29:90:d8:1c:1c:6b:a5:48:b6:72:df: + e6:fe:ed:a1:62:ff:fa:a3:36:22:88:fd:46:b4:eb:4a:ad:14: + 15:83:82:a9:23:c6:e2:80:74:f8:ad:ac:16:fc:14:0b:49:ea: + 01:3f:0e:19:e9:94:1f:c0:69:91:a8:4e:45:60:b4:f2:7d:0f: + d0:93:e6:43:45:4a:38:23:06:d9:de:f6:88:78:76:c5:da:c8: + c3:04:4a:77:5a:df:8e:88:9f:ea:6e:a5:3c:c3:3b:26:75:e1: + 58:14:05:45:25:26:b2:6e:e3:1b:ff:37:1d:29:f1:4b:23:c5: + c2:19:8c:db:ee:66:fc:64:a3:62:42:67:15:8d:15:d3:f1:83: + 98:8c:8e:99:8d:dc:c5:b3:e2:6f:f1:d8:1e:5f:8a:5d:f4:5a: + 9d:12:fb:7f +-----BEGIN CERTIFICATE----- +MIICpDCCAYwCCQDF5JkeGZR7XjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwHhcNMjMwNDA4MTMxMjE0WhcNMjMwNTA4MTMxMjE0WjAUMRIwEAYD +VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt +ApxRln8ui/TTUjKuODPc6OZ1GKB1zAPdUdl1IC85xwQc9mi9kwVTg2YsDj8rdk0N +fOGDck1L39jRMaX1Kik8tCEn9IGqo+RGUCMa+t7z2qByW3ue6uVf/SKdztydPeZZ +sjAZvfcnXN2VTBoGIeJ18rwy8IJhEswmNBQlQnGW9XWPtRBwtRRqecbIav2xhmbS +F+tEUJAHehTvelh58CMr9fNh7tH2nK++oncO3QuKm5WdcxEIfqVAYj1pjd5ao/2h +eqHRDjIN3fhsoykbrkf8vhqoidzWqKB4GPHj1vmKUnoQpRPEE9SpIqqCbii7T5mZ +mYB+ts6sedd2rYa2a3n5AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKposZ9H2DSk +JNLcGp/vKulv200+9UmWvdmLBpDTXN9y13XHfNA954D0gw4sYmrCy/vsWcJjCBBP +gWxmZB6u22lY5bB7EWXaWVYTlVko4T3Kn5VQ0iqoad2oba0EnogE+44pkNgcHGul +SLZy3+b+7aFi//qjNiKI/Ua060qtFBWDgqkjxuKAdPitrBb8FAtJ6gE/DhnplB/A +aZGoTkVgtPJ9D9CT5kNFSjgjBtne9oh4dsXayMMESnda346In+pupTzDOyZ14VgU +BUUlJrJu4xv/Nx0p8UsjxcIZjNvuZvxko2JCZxWNFdPxg5iMjpmN3MWz4m/x2B5f +il30Wp0S+38= +-----END CERTIFICATE----- diff --git a/tests/postgres.key b/tests/postgres.key new file mode 100644 index 0000000..1cd03b0 --- /dev/null +++ b/tests/postgres.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEArQKcUZZ/Lov001Iyrjgz3OjmdRigdcwD3VHZdSAvOccEHPZo +vZMFU4NmLA4/K3ZNDXzhg3JNS9/Y0TGl9SopPLQhJ/SBqqPkRlAjGvre89qgclt7 +nurlX/0inc7cnT3mWbIwGb33J1zdlUwaBiHidfK8MvCCYRLMJjQUJUJxlvV1j7UQ +cLUUannGyGr9sYZm0hfrRFCQB3oU73pYefAjK/XzYe7R9pyvvqJ3Dt0LipuVnXMR +CH6lQGI9aY3eWqP9oXqh0Q4yDd34bKMpG65H/L4aqInc1qigeBjx49b5ilJ6EKUT +xBPUqSKqgm4ou0+ZmZmAfrbOrHnXdq2Gtmt5+QIDAQABAoIBAEXNHNZJ+swDyWYM +7sedg0coa/poUizUf+amJC7+Ki+MXNt2ivGZRHfaNrmlkdTuKM49SRroXckz6d0U +w9kzBmooXowpOLto3iuEH3W+K3+FAGDDChAmwx5EGdhDYnzKQYqEuqVYIEQwUnHu +vz0kJKLjqQyAPon9tIHhVxNlSEDX44qilDy4mUmhBFHnk8FtpWkXdAIvVstA14Il +ia5/tFFfblr7h6p8opVedRISaON/IWRwgdcuzNIpTO8rbm+XofZEFu2rVpJ/77ea +ADXcxQupy4k1dnlCp306Sbj3tyPhl3erAXUmsqttdwP22M4IgNn6TcbWpB5ytFnu +jyY9koECgYEA2Xk23MYIZUB9hN75jT8MklDCkzsAbscT9hlH3VKCL4IPtB/0UF47 +kiEXhF55jKj30CKpMqYoYpLnAdweEYU/m5u4UFbkhoL28Kkb7GS2PHCEak2Ubx2m +y7mOmvCoWMyxGfm6Eby2NGXzbZW12cPIO7jroXrril17E8B14l1xyxECgYEAy6jp +ZElVf5M5nMSVwmyObNVnJeMxHm2qXGxw5HlG3hxmfyKXQB28Qr7eGhRl+/kPZZgM +XwVztAPGeFJJR4+/0sn4/YIUe9Johip4JRUbR09lMpPIMCD/4yvo3+EIsWq8ezwy +08lNkzq2JsStQ3w8bf5QZ3X/gFN10z7AuknsMGkCgYAHdaj0GbbgAj5L+HoG5krA +GhUSh8uUATAmGOfmJ5Zfms5/FzmCKDlS4d+0oqj4sjMN6KJ1Ik3wU6mo3qwJXdC4 +vbasys477vIZfzN+AFZf7FweaVrWFOZLxqmlluuvYBYTFgXT5e06DuUytRfvyE9t +/QHYICdEL8CxBMEGar4kgQKBgF5GHWu36qT4gMXJ1k0+tRs6GdpW9cjRGPhZllSc +sypj2Spm177tRNVcxzEpWiAupWrw3GEsA+hDix7tcFB5AWHQ7rpi+Zprxsi8Zgs8 +Xvk+jmjAMf3deLYvAEiKQdzmvMMLFbglygwqNGFzz4SawNply9BotdIwUC1uMgbJ +61RpAoGAafVs+giGECP23QQniZA/GAFIKNDik3fiadL0dSeHXJZ94j344XDbsBTk +eVa/5IRs5tC8Q7aLdrSuwV87KD2yMrAYmDR9nQKWd70zYoYexaoJ3YPDu5ISilgU +zm1rwgN9u8+rb6ByuJavt79cWZaVncPe+Bvg0gNMr+Im3RCLiN8= +-----END RSA PRIVATE KEY----- From 4ef8c72b52dbb853b1ce82e0ce7ed9b687773501 Mon Sep 17 00:00:00 2001 From: Jonas Scholl Date: Sat, 8 Apr 2023 15:48:57 +0200 Subject: [PATCH 2/6] test SSL support --- database_setup_tools/session_manager.py | 8 +- database_setup_tools/setup.py | 9 +- tests/integration/database_config.py | 5 +- .../integration/test_database_integration.py | 117 ++++++++++-------- 4 files changed, 74 insertions(+), 65 deletions(-) diff --git a/database_setup_tools/session_manager.py b/database_setup_tools/session_manager.py index 903bfa7..c642863 100644 --- a/database_setup_tools/session_manager.py +++ b/database_setup_tools/session_manager.py @@ -1,6 +1,6 @@ import threading from functools import cached_property -from typing import Generator, Optional +from typing import Any, Generator, Optional from sqlalchemy import create_engine from sqlalchemy.engine import Engine @@ -21,14 +21,14 @@ def __new__(cls, *args, **kwargs): cls._instances.append((super(cls, cls).__new__(cls), (args, kwargs))) return cls._get_cached_instance(args, kwargs) - def __init__(self, database_uri: str, **kwargs): + def __init__(self, database_uri: str, **engine_options: dict[str, Any]): """Session Manager constructor Args: database_uri (str): The URI of the database to manage sessions for Keyword Args: - **kwargs: Keyword arguments to pass to the engine + **engine_options: Keyword arguments to pass to the engine postgresql: pool_size (int): The maximum number of connections to the database @@ -39,7 +39,7 @@ def __init__(self, database_uri: str, **kwargs): raise TypeError("database_uri must be a string") self._database_uri = database_uri - self._engine = self._get_engine(**kwargs) + self._engine = self._get_engine(**engine_options) self._session_factory = sessionmaker(self.engine) self._Session = scoped_session(self._session_factory) diff --git a/database_setup_tools/setup.py b/database_setup_tools/setup.py index e4ba194..12202d9 100644 --- a/database_setup_tools/setup.py +++ b/database_setup_tools/setup.py @@ -1,5 +1,5 @@ import threading -from typing import List, Optional +from typing import Any, List, Optional import sqlalchemy_utils from sqlalchemy import MetaData, Table @@ -21,13 +21,15 @@ def __new__(cls, *args, **kwargs): cls._instances.append((super(cls, cls).__new__(cls), (args, kwargs))) return cls._get_cached_instance(args, kwargs) - def __init__(self, model_metadata: MetaData, database_uri: str): + def __init__(self, model_metadata: MetaData, database_uri: str, **engine_options: dict[str, Any]): """Set up a database based on its URI and metadata. Will not overwrite existing data. Args: model_metadata (Metadata): The metadata of the models to create the tables for database_uri (str): The URI of the database to create the tables for + Keyword Args: + **engine_options: Keyword arguments to pass to the engine """ if not isinstance(model_metadata, MetaData): raise TypeError("model_metadata must be a MetaData") @@ -37,6 +39,7 @@ def __init__(self, model_metadata: MetaData, database_uri: str): self._model_metadata = model_metadata self._database_uri = database_uri + self._engine_options = engine_options self.create_database() @property @@ -55,7 +58,7 @@ def session_manager(self) -> SessionManager: Returns: SessionManager: The session manager """ - return SessionManager(database_uri=self.database_uri) + return SessionManager(database_uri=self.database_uri, **self._engine_options) @property def database_uri(self) -> str: diff --git a/tests/integration/database_config.py b/tests/integration/database_config.py index 32b624a..6a2dbfe 100644 --- a/tests/integration/database_config.py +++ b/tests/integration/database_config.py @@ -1,5 +1,4 @@ -POSTGRESQL_DATABASE_URI = "postgresql+psycopg2://postgres:postgres@localhost:5432/test" - DATABASE_URIS = [ - POSTGRESQL_DATABASE_URI, + "postgresql+psycopg2://postgres:postgres@localhost:5432/test", # PostgreSQL + "postgresql+psycopg2://postgres:postgres@localhost:5432/test?sslmode=require", # PostgreSQL with SSL ] diff --git a/tests/integration/test_database_integration.py b/tests/integration/test_database_integration.py index 6637dc4..728e8fe 100644 --- a/tests/integration/test_database_integration.py +++ b/tests/integration/test_database_integration.py @@ -2,10 +2,8 @@ import pytest from sqlalchemy.exc import OperationalError -from sqlalchemy.orm.scoping import ScopedSession -from sqlmodel import Field, SQLModel +from sqlalchemy.orm import Session -from database_setup_tools.session_manager import SessionManager from database_setup_tools.setup import DatabaseSetup from tests.integration.database_config import DATABASE_URIS from tests.sample_model import Customer, model_metadata @@ -13,6 +11,10 @@ @pytest.mark.parametrize("database_uri", DATABASE_URIS) class TestDatabaseIntegration: + # + # Fixtures + # + @pytest.fixture def database_setup(self, database_uri: str) -> DatabaseSetup: setup = DatabaseSetup(model_metadata=model_metadata, database_uri=database_uri) @@ -22,31 +24,12 @@ def database_setup(self, database_uri: str) -> DatabaseSetup: setup.drop_database() @pytest.fixture - def database_session(self, database_setup: DatabaseSetup) -> Iterator[ScopedSession]: + def session(self, database_setup: DatabaseSetup) -> Iterator[Session]: """Get a database session""" return next(database_setup.session_manager.get_session()) - def test_create_database_and_tables(self, database_setup: DatabaseSetup, database_session: ScopedSession): - """Test that the tables are created correctly""" - database_session.execute(f"SELECT * FROM {Customer.__tablename__}") - - def test_create_database_multiple_times(self, database_setup: DatabaseSetup, database_session: ScopedSession): - """Test that creating the database multiple times does not cause problems""" - database_setup.create_database() - database_session.execute(f"SELECT * FROM {Customer.__tablename__}") - - def test_drop_database(self, database_setup: DatabaseSetup, database_session: ScopedSession): - """Test that the database is dropped correctly""" - assert database_setup.drop_database() is True - - with pytest.raises(OperationalError): - database_session.execute(f"SELECT * FROM {Customer.__tablename__}") - - assert database_setup.drop_database() is False - - def test_truncate_all_tables(self, database_setup: DatabaseSetup, database_session: ScopedSession): - """Test that all tables are truncated correctly""" - + @pytest.fixture + def delivery_table(self, session: Session) -> str: setup_statements = [ f"""CREATE TABLE delivery ( id INTEGER, @@ -63,44 +46,68 @@ def test_truncate_all_tables(self, database_setup: DatabaseSetup, database_sessi f"INSERT INTO \"{Customer.__tablename__}\" VALUES (1, 'John Doe')", "INSERT INTO \"delivery\" VALUES (1, 'Delivery 1', 1)", ] + for statement in setup_statements: - database_session.execute(statement) + session.execute(statement) - assert database_session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 1 - assert database_session.execute(f'SELECT * FROM "delivery"').rowcount == 1 - database_session.commit() + return "delivery" - database_setup.truncate() + @pytest.fixture + def standalone_table(self, session: Session) -> str: + setup_statements = [ + "CREATE TABLE standalone (id INTEGER, PRIMARY KEY(id))", + 'SELECT * FROM "standalone"', + 'INSERT INTO "standalone" VALUES (1)', + ] - assert database_session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 0 - assert database_session.execute(f'SELECT * FROM "delivery"').rowcount == 0 + for statement in setup_statements: + session.execute(statement) - def test_truncate_custom_tables(self, database_uri: str): - """Test that only specified tables are truncated correctly""" + return "standalone" - class TableToTruncate(SQLModel, table=True): - id: int = Field(index=True, primary_key=True) - name: str + # + # Tests + # - setup = DatabaseSetup(model_metadata=model_metadata, database_uri=database_uri) - setup.drop_database() - setup.create_database() - database_session = next(setup.session_manager.get_session()) + def test_create_database_and_tables(self, database_setup: DatabaseSetup, session: Session): + """Test that the tables are created correctly""" + session.execute(f"SELECT * FROM {Customer.__tablename__}") - setup_statements = [ - f'SELECT * FROM "{Customer.__tablename__}"', - f'SELECT * FROM "{TableToTruncate.__tablename__}"', - f"INSERT INTO \"{Customer.__tablename__}\" VALUES (1, 'John Doe')", - f"INSERT INTO \"{TableToTruncate.__tablename__}\" VALUES (1, 'Test')", - ] - for statement in setup_statements: - database_session.execute(statement) + def test_create_database_multiple_times(self, database_setup: DatabaseSetup, session: Session): + """Test that creating the database multiple times does not cause problems""" + database_setup.create_database() + session.execute(f"SELECT * FROM {Customer.__tablename__}") + + def test_drop_database(self, database_setup: DatabaseSetup, session: Session): + """Test that the database is dropped correctly""" + assert database_setup.drop_database() is True + + with pytest.raises(OperationalError): + session.execute(f"SELECT * FROM {Customer.__tablename__}") + + assert database_setup.drop_database() is False + + def test_truncate_all_tables(self, database_setup: DatabaseSetup, session: Session, delivery_table: str): + """Test that all tables are truncated correctly""" + + assert session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 1 + assert session.execute(f'SELECT * FROM "{delivery_table}"').rowcount == 1 + session.commit() + + database_setup.truncate() + + assert session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 0 + assert session.execute(f'SELECT * FROM "{delivery_table}"').rowcount == 0 + + def test_truncate_custom_tables(self, database_setup: DatabaseSetup, session: Session, delivery_table: str, standalone_table: str): + """Test that only specified tables are truncated correctly""" - assert database_session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 1 - assert database_session.execute(f'SELECT * FROM "{TableToTruncate.__tablename__}"').rowcount == 1 - database_session.commit() + assert session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 1 + assert session.execute(f'SELECT * FROM "{delivery_table}"').rowcount == 1 + session.commit() - setup.truncate(tables=[TableToTruncate]) + database_setup.truncate(tables=[Customer]) - assert database_session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 1 - assert database_session.execute(f'SELECT * FROM "{TableToTruncate.__tablename__}"').rowcount == 0 + assert session.execute(f"SELECT * FROM {Customer.__tablename__}").rowcount == 0 + assert session.execute(f'SELECT * FROM "{delivery_table}"').rowcount == 0 + assert session.execute(f'SELECT * FROM "{standalone_table}"').rowcount == 1 From ab16e43860b7dcfcdadb88f91d66bcb131aa464e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannic=20Schr=C3=B6er?= Date: Sat, 8 Apr 2023 18:20:39 +0200 Subject: [PATCH 3/6] Update docker-compose.yaml --- tests/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml index ef8c4fe..36d8e2e 100644 --- a/tests/docker-compose.yaml +++ b/tests/docker-compose.yaml @@ -2,7 +2,7 @@ version: "3.9" services: postgresql-database: - image: postgres:15 + image: postgres:14 container_name: "database-setup-tools-test-postgres-database" command: -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key ports: From fe93b0ff2c00b13ed87bf8073a2f2ff6cb0552f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannic=20Schr=C3=B6er?= Date: Sat, 8 Apr 2023 18:27:21 +0200 Subject: [PATCH 4/6] certificates from image --- .vscode/PythonImportHelper-v2-Completion.json | 397 ++++++++++++++++++ tests/docker-compose.yaml | 10 +- tests/postgres.crt | 67 --- tests/postgres.key | 27 -- 4 files changed, 402 insertions(+), 99 deletions(-) create mode 100644 .vscode/PythonImportHelper-v2-Completion.json delete mode 100644 tests/postgres.crt delete mode 100644 tests/postgres.key diff --git a/.vscode/PythonImportHelper-v2-Completion.json b/.vscode/PythonImportHelper-v2-Completion.json new file mode 100644 index 0000000..85c746f --- /dev/null +++ b/.vscode/PythonImportHelper-v2-Completion.json @@ -0,0 +1,397 @@ +[ + { + "label": "threading", + "kind": 6, + "isExtraImport": true, + "importPath": "threading", + "description": "threading", + "detail": "threading", + "documentation": {} + }, + { + "label": "cached_property", + "importPath": "functools", + "description": "functools", + "isExtraImport": true, + "detail": "functools", + "documentation": {} + }, + { + "label": "Any", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Generator", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Optional", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Any", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "List", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Optional", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Iterator", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Callable", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Any", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Any", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "Callable", + "importPath": "typing", + "description": "typing", + "isExtraImport": true, + "detail": "typing", + "documentation": {} + }, + { + "label": "create_engine", + "importPath": "sqlalchemy", + "description": "sqlalchemy", + "isExtraImport": true, + "detail": "sqlalchemy", + "documentation": {} + }, + { + "label": "MetaData", + "importPath": "sqlalchemy", + "description": "sqlalchemy", + "isExtraImport": true, + "detail": "sqlalchemy", + "documentation": {} + }, + { + "label": "Table", + "importPath": "sqlalchemy", + "description": "sqlalchemy", + "isExtraImport": true, + "detail": "sqlalchemy", + "documentation": {} + }, + { + "label": "Engine", + "importPath": "sqlalchemy.engine", + "description": "sqlalchemy.engine", + "isExtraImport": true, + "detail": "sqlalchemy.engine", + "documentation": {} + }, + { + "label": "Engine", + "importPath": "sqlalchemy.engine", + "description": "sqlalchemy.engine", + "isExtraImport": true, + "detail": "sqlalchemy.engine", + "documentation": {} + }, + { + "label": "Session", + "importPath": "sqlalchemy.orm", + "description": "sqlalchemy.orm", + "isExtraImport": true, + "detail": "sqlalchemy.orm", + "documentation": {} + }, + { + "label": "sessionmaker", + "importPath": "sqlalchemy.orm", + "description": "sqlalchemy.orm", + "isExtraImport": true, + "detail": "sqlalchemy.orm", + "documentation": {} + }, + { + "label": "Session", + "importPath": "sqlalchemy.orm", + "description": "sqlalchemy.orm", + "isExtraImport": true, + "detail": "sqlalchemy.orm", + "documentation": {} + }, + { + "label": "scoped_session", + "importPath": "sqlalchemy.orm.scoping", + "description": "sqlalchemy.orm.scoping", + "isExtraImport": true, + "detail": "sqlalchemy.orm.scoping", + "documentation": {} + }, + { + "label": "sqlalchemy_utils", + "kind": 6, + "isExtraImport": true, + "importPath": "sqlalchemy_utils", + "description": "sqlalchemy_utils", + "detail": "sqlalchemy_utils", + "documentation": {} + }, + { + "label": "SQLModel", + "importPath": "sqlmodel.main", + "description": "sqlmodel.main", + "isExtraImport": true, + "detail": "sqlmodel.main", + "documentation": {} + }, + { + "label": "SQLModelMetaclass", + "importPath": "sqlmodel.main", + "description": "sqlmodel.main", + "isExtraImport": true, + "detail": "sqlmodel.main", + "documentation": {} + }, + { + "label": "SessionManager", + "importPath": "database_setup_tools.session_manager", + "description": "database_setup_tools.session_manager", + "isExtraImport": true, + "detail": "database_setup_tools.session_manager", + "documentation": {} + }, + { + "label": "SessionManager", + "importPath": "database_setup_tools.session_manager", + "description": "database_setup_tools.session_manager", + "isExtraImport": true, + "detail": "database_setup_tools.session_manager", + "documentation": {} + }, + { + "label": "SessionManager", + "importPath": "database_setup_tools.session_manager", + "description": "database_setup_tools.session_manager", + "isExtraImport": true, + "detail": "database_setup_tools.session_manager", + "documentation": {} + }, + { + "label": "pytest", + "kind": 6, + "isExtraImport": true, + "importPath": "pytest", + "description": "pytest", + "detail": "pytest", + "documentation": {} + }, + { + "label": "OperationalError", + "importPath": "sqlalchemy.exc", + "description": "sqlalchemy.exc", + "isExtraImport": true, + "detail": "sqlalchemy.exc", + "documentation": {} + }, + { + "label": "DatabaseSetup", + "importPath": "database_setup_tools.setup", + "description": "database_setup_tools.setup", + "isExtraImport": true, + "detail": "database_setup_tools.setup", + "documentation": {} + }, + { + "label": "DatabaseSetup", + "importPath": "database_setup_tools.setup", + "description": "database_setup_tools.setup", + "isExtraImport": true, + "detail": "database_setup_tools.setup", + "documentation": {} + }, + { + "label": "DATABASE_URIS", + "importPath": "tests.integration.database_config", + "description": "tests.integration.database_config", + "isExtraImport": true, + "detail": "tests.integration.database_config", + "documentation": {} + }, + { + "label": "Customer", + "importPath": "tests.sample_model", + "description": "tests.sample_model", + "isExtraImport": true, + "detail": "tests.sample_model", + "documentation": {} + }, + { + "label": "model_metadata", + "importPath": "tests.sample_model", + "description": "tests.sample_model", + "isExtraImport": true, + "detail": "tests.sample_model", + "documentation": {} + }, + { + "label": "model_metadata", + "importPath": "tests.sample_model", + "description": "tests.sample_model", + "isExtraImport": true, + "detail": "tests.sample_model", + "documentation": {} + }, + { + "label": "contextmanager", + "importPath": "contextlib", + "description": "contextlib", + "isExtraImport": true, + "detail": "contextlib", + "documentation": {} + }, + { + "label": "unstub", + "importPath": "mockito", + "description": "mockito", + "isExtraImport": true, + "detail": "mockito", + "documentation": {} + }, + { + "label": "Field", + "importPath": "sqlmodel", + "description": "sqlmodel", + "isExtraImport": true, + "detail": "sqlmodel", + "documentation": {} + }, + { + "label": "SQLModel", + "importPath": "sqlmodel", + "description": "sqlmodel", + "isExtraImport": true, + "detail": "sqlmodel", + "documentation": {} + }, + { + "label": "SessionManager", + "kind": 6, + "importPath": "database_setup_tools.session_manager", + "description": "database_setup_tools.session_manager", + "peekOfCode": "class SessionManager:\n \"\"\"Manages engines, sessions and connection pools. Thread-safe singleton\"\"\"\n _instances = []\n _lock = threading.Lock()\n def __new__(cls, *args, **kwargs):\n if not cls._get_cached_instance(args, kwargs):\n with cls._lock:\n if not cls._get_cached_instance(args, kwargs):\n cls._instances.append((super(cls, cls).__new__(cls), (args, kwargs)))\n return cls._get_cached_instance(args, kwargs)", + "detail": "database_setup_tools.session_manager", + "documentation": {} + }, + { + "label": "DatabaseSetup", + "kind": 6, + "importPath": "database_setup_tools.setup", + "description": "database_setup_tools.setup", + "peekOfCode": "class DatabaseSetup:\n \"\"\"Create the database and the tables if not done yet\"\"\"\n _instances = []\n _lock = threading.Lock()\n def __new__(cls, *args, **kwargs):\n if not cls._get_cached_instance(args, kwargs):\n with cls._lock:\n if not cls._get_cached_instance(args, kwargs):\n cls._instances.append((super(cls, cls).__new__(cls), (args, kwargs)))\n return cls._get_cached_instance(args, kwargs)", + "detail": "database_setup_tools.setup", + "documentation": {} + }, + { + "label": "DATABASE_URIS", + "kind": 5, + "importPath": "tests.integration.database_config", + "description": "tests.integration.database_config", + "peekOfCode": "DATABASE_URIS = [\n \"postgresql+psycopg2://postgres:postgres@localhost:5432/test\", # PostgreSQL\n \"postgresql+psycopg2://postgres:postgres@localhost:5432/test?sslmode=require\", # PostgreSQL with SSL\n]", + "detail": "tests.integration.database_config", + "documentation": {} + }, + { + "label": "TestDatabaseIntegration", + "kind": 6, + "importPath": "tests.integration.test_database_integration", + "description": "tests.integration.test_database_integration", + "peekOfCode": "class TestDatabaseIntegration:\n #\n # Fixtures\n #\n @pytest.fixture\n def database_setup(self, database_uri: str) -> DatabaseSetup:\n setup = DatabaseSetup(model_metadata=model_metadata, database_uri=database_uri)\n setup.drop_database()\n setup.create_database()\n yield setup", + "detail": "tests.integration.test_database_integration", + "documentation": {} + }, + { + "label": "TestSessionManager", + "kind": 6, + "importPath": "tests.unit.test_session_manager", + "description": "tests.unit.test_session_manager", + "peekOfCode": "class TestSessionManager:\n @pytest.fixture\n def database_uri(self) -> str:\n return \"sqlite://\"\n @pytest.fixture\n def session_manager(self, database_uri: str) -> SessionManager:\n yield SessionManager(database_uri=database_uri)\n @pytest.mark.parametrize(\"invalid_database_uri\", [None, (), 42, False])\n def test_create_session_manager_fail_invalid_database_uri_type(self, invalid_database_uri: Any):\n with pytest.raises(TypeError):", + "detail": "tests.unit.test_session_manager", + "documentation": {} + }, + { + "label": "TestSetup", + "kind": 6, + "importPath": "tests.unit.test_setup", + "description": "tests.unit.test_setup", + "peekOfCode": "class TestSetup:\n @pytest.fixture\n def database_uri(self) -> str:\n return \"sqlite://\"\n @pytest.fixture\n def database_setup(self, when: Callable, database_uri: str) -> DatabaseSetup:\n when(DatabaseSetup).create_database().thenReturn(None)\n yield DatabaseSetup(model_metadata=model_metadata, database_uri=database_uri)\n @pytest.mark.parametrize(\"database_uri\", [\"sqlite://\", \"postgresql://\"])\n def test_database_setup_is_singleton_with_same_arguments(self, database_setup: DatabaseSetup, database_uri: str):", + "detail": "tests.unit.test_setup", + "documentation": {} + }, + { + "label": "Customer", + "kind": 6, + "importPath": "tests.sample_model", + "description": "tests.sample_model", + "peekOfCode": "class Customer(SQLModel, table=True):\n \"\"\"Customer model\"\"\"\n id: int = Field(index=True, primary_key=True)\n name: str\nmodel_metadata = SQLModel.metadata", + "detail": "tests.sample_model", + "documentation": {} + }, + { + "label": "model_metadata", + "kind": 5, + "importPath": "tests.sample_model", + "description": "tests.sample_model", + "peekOfCode": "model_metadata = SQLModel.metadata", + "detail": "tests.sample_model", + "documentation": {} + } +] \ No newline at end of file diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml index 36d8e2e..11fa818 100644 --- a/tests/docker-compose.yaml +++ b/tests/docker-compose.yaml @@ -2,15 +2,15 @@ version: "3.9" services: postgresql-database: - image: postgres:14 + image: postgres:15 container_name: "database-setup-tools-test-postgres-database" - command: -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key + command: > + -c ssl=on + -c ssl_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem + -c ssl_key_file=/etc/ssl/private/ssl-cert-snakeoil.key ports: - "5432:5432" environment: POSTGRES_USER: "postgres" POSTGRES_PASSWORD: "postgres" POSTGRES_DB: "postgres" - volumes: - - ./postgres.crt:/var/lib/postgresql/server.crt - - ./postgres.key:/var/lib/postgresql/server.key diff --git a/tests/postgres.crt b/tests/postgres.crt deleted file mode 100644 index ef4faf6..0000000 --- a/tests/postgres.crt +++ /dev/null @@ -1,67 +0,0 @@ -Certificate: - Data: - Version: 1 (0x0) - Serial Number: - c5:e4:99:1e:19:94:7b:5e - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=localhost - Validity - Not Before: Apr 8 13:12:14 2023 GMT - Not After : May 8 13:12:14 2023 GMT - Subject: CN=localhost - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:ad:02:9c:51:96:7f:2e:8b:f4:d3:52:32:ae:38: - 33:dc:e8:e6:75:18:a0:75:cc:03:dd:51:d9:75:20: - 2f:39:c7:04:1c:f6:68:bd:93:05:53:83:66:2c:0e: - 3f:2b:76:4d:0d:7c:e1:83:72:4d:4b:df:d8:d1:31: - a5:f5:2a:29:3c:b4:21:27:f4:81:aa:a3:e4:46:50: - 23:1a:fa:de:f3:da:a0:72:5b:7b:9e:ea:e5:5f:fd: - 22:9d:ce:dc:9d:3d:e6:59:b2:30:19:bd:f7:27:5c: - dd:95:4c:1a:06:21:e2:75:f2:bc:32:f0:82:61:12: - cc:26:34:14:25:42:71:96:f5:75:8f:b5:10:70:b5: - 14:6a:79:c6:c8:6a:fd:b1:86:66:d2:17:eb:44:50: - 90:07:7a:14:ef:7a:58:79:f0:23:2b:f5:f3:61:ee: - d1:f6:9c:af:be:a2:77:0e:dd:0b:8a:9b:95:9d:73: - 11:08:7e:a5:40:62:3d:69:8d:de:5a:a3:fd:a1:7a: - a1:d1:0e:32:0d:dd:f8:6c:a3:29:1b:ae:47:fc:be: - 1a:a8:89:dc:d6:a8:a0:78:18:f1:e3:d6:f9:8a:52: - 7a:10:a5:13:c4:13:d4:a9:22:aa:82:6e:28:bb:4f: - 99:99:99:80:7e:b6:ce:ac:79:d7:76:ad:86:b6:6b: - 79:f9 - Exponent: 65537 (0x10001) - Signature Algorithm: sha256WithRSAEncryption - aa:68:b1:9f:47:d8:34:a4:24:d2:dc:1a:9f:ef:2a:e9:6f:db: - 4d:3e:f5:49:96:bd:d9:8b:06:90:d3:5c:df:72:d7:75:c7:7c: - d0:3d:e7:80:f4:83:0e:2c:62:6a:c2:cb:fb:ec:59:c2:63:08: - 10:4f:81:6c:66:64:1e:ae:db:69:58:e5:b0:7b:11:65:da:59: - 56:13:95:59:28:e1:3d:ca:9f:95:50:d2:2a:a8:69:dd:a8:6d: - ad:04:9e:88:04:fb:8e:29:90:d8:1c:1c:6b:a5:48:b6:72:df: - e6:fe:ed:a1:62:ff:fa:a3:36:22:88:fd:46:b4:eb:4a:ad:14: - 15:83:82:a9:23:c6:e2:80:74:f8:ad:ac:16:fc:14:0b:49:ea: - 01:3f:0e:19:e9:94:1f:c0:69:91:a8:4e:45:60:b4:f2:7d:0f: - d0:93:e6:43:45:4a:38:23:06:d9:de:f6:88:78:76:c5:da:c8: - c3:04:4a:77:5a:df:8e:88:9f:ea:6e:a5:3c:c3:3b:26:75:e1: - 58:14:05:45:25:26:b2:6e:e3:1b:ff:37:1d:29:f1:4b:23:c5: - c2:19:8c:db:ee:66:fc:64:a3:62:42:67:15:8d:15:d3:f1:83: - 98:8c:8e:99:8d:dc:c5:b3:e2:6f:f1:d8:1e:5f:8a:5d:f4:5a: - 9d:12:fb:7f ------BEGIN CERTIFICATE----- -MIICpDCCAYwCCQDF5JkeGZR7XjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls -b2NhbGhvc3QwHhcNMjMwNDA4MTMxMjE0WhcNMjMwNTA4MTMxMjE0WjAUMRIwEAYD -VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt -ApxRln8ui/TTUjKuODPc6OZ1GKB1zAPdUdl1IC85xwQc9mi9kwVTg2YsDj8rdk0N -fOGDck1L39jRMaX1Kik8tCEn9IGqo+RGUCMa+t7z2qByW3ue6uVf/SKdztydPeZZ -sjAZvfcnXN2VTBoGIeJ18rwy8IJhEswmNBQlQnGW9XWPtRBwtRRqecbIav2xhmbS -F+tEUJAHehTvelh58CMr9fNh7tH2nK++oncO3QuKm5WdcxEIfqVAYj1pjd5ao/2h -eqHRDjIN3fhsoykbrkf8vhqoidzWqKB4GPHj1vmKUnoQpRPEE9SpIqqCbii7T5mZ -mYB+ts6sedd2rYa2a3n5AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKposZ9H2DSk -JNLcGp/vKulv200+9UmWvdmLBpDTXN9y13XHfNA954D0gw4sYmrCy/vsWcJjCBBP -gWxmZB6u22lY5bB7EWXaWVYTlVko4T3Kn5VQ0iqoad2oba0EnogE+44pkNgcHGul -SLZy3+b+7aFi//qjNiKI/Ua060qtFBWDgqkjxuKAdPitrBb8FAtJ6gE/DhnplB/A -aZGoTkVgtPJ9D9CT5kNFSjgjBtne9oh4dsXayMMESnda346In+pupTzDOyZ14VgU -BUUlJrJu4xv/Nx0p8UsjxcIZjNvuZvxko2JCZxWNFdPxg5iMjpmN3MWz4m/x2B5f -il30Wp0S+38= ------END CERTIFICATE----- diff --git a/tests/postgres.key b/tests/postgres.key deleted file mode 100644 index 1cd03b0..0000000 --- a/tests/postgres.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEArQKcUZZ/Lov001Iyrjgz3OjmdRigdcwD3VHZdSAvOccEHPZo -vZMFU4NmLA4/K3ZNDXzhg3JNS9/Y0TGl9SopPLQhJ/SBqqPkRlAjGvre89qgclt7 -nurlX/0inc7cnT3mWbIwGb33J1zdlUwaBiHidfK8MvCCYRLMJjQUJUJxlvV1j7UQ -cLUUannGyGr9sYZm0hfrRFCQB3oU73pYefAjK/XzYe7R9pyvvqJ3Dt0LipuVnXMR -CH6lQGI9aY3eWqP9oXqh0Q4yDd34bKMpG65H/L4aqInc1qigeBjx49b5ilJ6EKUT -xBPUqSKqgm4ou0+ZmZmAfrbOrHnXdq2Gtmt5+QIDAQABAoIBAEXNHNZJ+swDyWYM -7sedg0coa/poUizUf+amJC7+Ki+MXNt2ivGZRHfaNrmlkdTuKM49SRroXckz6d0U -w9kzBmooXowpOLto3iuEH3W+K3+FAGDDChAmwx5EGdhDYnzKQYqEuqVYIEQwUnHu -vz0kJKLjqQyAPon9tIHhVxNlSEDX44qilDy4mUmhBFHnk8FtpWkXdAIvVstA14Il -ia5/tFFfblr7h6p8opVedRISaON/IWRwgdcuzNIpTO8rbm+XofZEFu2rVpJ/77ea -ADXcxQupy4k1dnlCp306Sbj3tyPhl3erAXUmsqttdwP22M4IgNn6TcbWpB5ytFnu -jyY9koECgYEA2Xk23MYIZUB9hN75jT8MklDCkzsAbscT9hlH3VKCL4IPtB/0UF47 -kiEXhF55jKj30CKpMqYoYpLnAdweEYU/m5u4UFbkhoL28Kkb7GS2PHCEak2Ubx2m -y7mOmvCoWMyxGfm6Eby2NGXzbZW12cPIO7jroXrril17E8B14l1xyxECgYEAy6jp -ZElVf5M5nMSVwmyObNVnJeMxHm2qXGxw5HlG3hxmfyKXQB28Qr7eGhRl+/kPZZgM -XwVztAPGeFJJR4+/0sn4/YIUe9Johip4JRUbR09lMpPIMCD/4yvo3+EIsWq8ezwy -08lNkzq2JsStQ3w8bf5QZ3X/gFN10z7AuknsMGkCgYAHdaj0GbbgAj5L+HoG5krA -GhUSh8uUATAmGOfmJ5Zfms5/FzmCKDlS4d+0oqj4sjMN6KJ1Ik3wU6mo3qwJXdC4 -vbasys477vIZfzN+AFZf7FweaVrWFOZLxqmlluuvYBYTFgXT5e06DuUytRfvyE9t -/QHYICdEL8CxBMEGar4kgQKBgF5GHWu36qT4gMXJ1k0+tRs6GdpW9cjRGPhZllSc -sypj2Spm177tRNVcxzEpWiAupWrw3GEsA+hDix7tcFB5AWHQ7rpi+Zprxsi8Zgs8 -Xvk+jmjAMf3deLYvAEiKQdzmvMMLFbglygwqNGFzz4SawNply9BotdIwUC1uMgbJ -61RpAoGAafVs+giGECP23QQniZA/GAFIKNDik3fiadL0dSeHXJZ94j344XDbsBTk -eVa/5IRs5tC8Q7aLdrSuwV87KD2yMrAYmDR9nQKWd70zYoYexaoJ3YPDu5ISilgU -zm1rwgN9u8+rb6ByuJavt79cWZaVncPe+Bvg0gNMr+Im3RCLiN8= ------END RSA PRIVATE KEY----- From a6bdfb1d78df1147dbc78d8171d78e5ad01e9f22 Mon Sep 17 00:00:00 2001 From: Jonas Scholl Date: Sun, 9 Apr 2023 09:43:52 +0200 Subject: [PATCH 5/6] some fixes --- .gitignore | 1 + .vscode/PythonImportHelper-v2-Completion.json | 397 ------------------ database_setup_tools/setup.py | 3 +- 3 files changed, 3 insertions(+), 398 deletions(-) delete mode 100644 .vscode/PythonImportHelper-v2-Completion.json diff --git a/.gitignore b/.gitignore index 7afe6c5..4d4aa8a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__/ # IDE/OS .idea .DS_Store +.vscode/PythonImportHelper-v2-Completion.json test.db test.db-journal diff --git a/.vscode/PythonImportHelper-v2-Completion.json b/.vscode/PythonImportHelper-v2-Completion.json deleted file mode 100644 index 85c746f..0000000 --- a/.vscode/PythonImportHelper-v2-Completion.json +++ /dev/null @@ -1,397 +0,0 @@ -[ - { - "label": "threading", - "kind": 6, - "isExtraImport": true, - "importPath": "threading", - "description": "threading", - "detail": "threading", - "documentation": {} - }, - { - "label": "cached_property", - "importPath": "functools", - "description": "functools", - "isExtraImport": true, - "detail": "functools", - "documentation": {} - }, - { - "label": "Any", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Generator", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Optional", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Any", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "List", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Optional", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Iterator", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Callable", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Any", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Any", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "Callable", - "importPath": "typing", - "description": "typing", - "isExtraImport": true, - "detail": "typing", - "documentation": {} - }, - { - "label": "create_engine", - "importPath": "sqlalchemy", - "description": "sqlalchemy", - "isExtraImport": true, - "detail": "sqlalchemy", - "documentation": {} - }, - { - "label": "MetaData", - "importPath": "sqlalchemy", - "description": "sqlalchemy", - "isExtraImport": true, - "detail": "sqlalchemy", - "documentation": {} - }, - { - "label": "Table", - "importPath": "sqlalchemy", - "description": "sqlalchemy", - "isExtraImport": true, - "detail": "sqlalchemy", - "documentation": {} - }, - { - "label": "Engine", - "importPath": "sqlalchemy.engine", - "description": "sqlalchemy.engine", - "isExtraImport": true, - "detail": "sqlalchemy.engine", - "documentation": {} - }, - { - "label": "Engine", - "importPath": "sqlalchemy.engine", - "description": "sqlalchemy.engine", - "isExtraImport": true, - "detail": "sqlalchemy.engine", - "documentation": {} - }, - { - "label": "Session", - "importPath": "sqlalchemy.orm", - "description": "sqlalchemy.orm", - "isExtraImport": true, - "detail": "sqlalchemy.orm", - "documentation": {} - }, - { - "label": "sessionmaker", - "importPath": "sqlalchemy.orm", - "description": "sqlalchemy.orm", - "isExtraImport": true, - "detail": "sqlalchemy.orm", - "documentation": {} - }, - { - "label": "Session", - "importPath": "sqlalchemy.orm", - "description": "sqlalchemy.orm", - "isExtraImport": true, - "detail": "sqlalchemy.orm", - "documentation": {} - }, - { - "label": "scoped_session", - "importPath": "sqlalchemy.orm.scoping", - "description": "sqlalchemy.orm.scoping", - "isExtraImport": true, - "detail": "sqlalchemy.orm.scoping", - "documentation": {} - }, - { - "label": "sqlalchemy_utils", - "kind": 6, - "isExtraImport": true, - "importPath": "sqlalchemy_utils", - "description": "sqlalchemy_utils", - "detail": "sqlalchemy_utils", - "documentation": {} - }, - { - "label": "SQLModel", - "importPath": "sqlmodel.main", - "description": "sqlmodel.main", - "isExtraImport": true, - "detail": "sqlmodel.main", - "documentation": {} - }, - { - "label": "SQLModelMetaclass", - "importPath": "sqlmodel.main", - "description": "sqlmodel.main", - "isExtraImport": true, - "detail": "sqlmodel.main", - "documentation": {} - }, - { - "label": "SessionManager", - "importPath": "database_setup_tools.session_manager", - "description": "database_setup_tools.session_manager", - "isExtraImport": true, - "detail": "database_setup_tools.session_manager", - "documentation": {} - }, - { - "label": "SessionManager", - "importPath": "database_setup_tools.session_manager", - "description": "database_setup_tools.session_manager", - "isExtraImport": true, - "detail": "database_setup_tools.session_manager", - "documentation": {} - }, - { - "label": "SessionManager", - "importPath": "database_setup_tools.session_manager", - "description": "database_setup_tools.session_manager", - "isExtraImport": true, - "detail": "database_setup_tools.session_manager", - "documentation": {} - }, - { - "label": "pytest", - "kind": 6, - "isExtraImport": true, - "importPath": "pytest", - "description": "pytest", - "detail": "pytest", - "documentation": {} - }, - { - "label": "OperationalError", - "importPath": "sqlalchemy.exc", - "description": "sqlalchemy.exc", - "isExtraImport": true, - "detail": "sqlalchemy.exc", - "documentation": {} - }, - { - "label": "DatabaseSetup", - "importPath": "database_setup_tools.setup", - "description": "database_setup_tools.setup", - "isExtraImport": true, - "detail": "database_setup_tools.setup", - "documentation": {} - }, - { - "label": "DatabaseSetup", - "importPath": "database_setup_tools.setup", - "description": "database_setup_tools.setup", - "isExtraImport": true, - "detail": "database_setup_tools.setup", - "documentation": {} - }, - { - "label": "DATABASE_URIS", - "importPath": "tests.integration.database_config", - "description": "tests.integration.database_config", - "isExtraImport": true, - "detail": "tests.integration.database_config", - "documentation": {} - }, - { - "label": "Customer", - "importPath": "tests.sample_model", - "description": "tests.sample_model", - "isExtraImport": true, - "detail": "tests.sample_model", - "documentation": {} - }, - { - "label": "model_metadata", - "importPath": "tests.sample_model", - "description": "tests.sample_model", - "isExtraImport": true, - "detail": "tests.sample_model", - "documentation": {} - }, - { - "label": "model_metadata", - "importPath": "tests.sample_model", - "description": "tests.sample_model", - "isExtraImport": true, - "detail": "tests.sample_model", - "documentation": {} - }, - { - "label": "contextmanager", - "importPath": "contextlib", - "description": "contextlib", - "isExtraImport": true, - "detail": "contextlib", - "documentation": {} - }, - { - "label": "unstub", - "importPath": "mockito", - "description": "mockito", - "isExtraImport": true, - "detail": "mockito", - "documentation": {} - }, - { - "label": "Field", - "importPath": "sqlmodel", - "description": "sqlmodel", - "isExtraImport": true, - "detail": "sqlmodel", - "documentation": {} - }, - { - "label": "SQLModel", - "importPath": "sqlmodel", - "description": "sqlmodel", - "isExtraImport": true, - "detail": "sqlmodel", - "documentation": {} - }, - { - "label": "SessionManager", - "kind": 6, - "importPath": "database_setup_tools.session_manager", - "description": "database_setup_tools.session_manager", - "peekOfCode": "class SessionManager:\n \"\"\"Manages engines, sessions and connection pools. Thread-safe singleton\"\"\"\n _instances = []\n _lock = threading.Lock()\n def __new__(cls, *args, **kwargs):\n if not cls._get_cached_instance(args, kwargs):\n with cls._lock:\n if not cls._get_cached_instance(args, kwargs):\n cls._instances.append((super(cls, cls).__new__(cls), (args, kwargs)))\n return cls._get_cached_instance(args, kwargs)", - "detail": "database_setup_tools.session_manager", - "documentation": {} - }, - { - "label": "DatabaseSetup", - "kind": 6, - "importPath": "database_setup_tools.setup", - "description": "database_setup_tools.setup", - "peekOfCode": "class DatabaseSetup:\n \"\"\"Create the database and the tables if not done yet\"\"\"\n _instances = []\n _lock = threading.Lock()\n def __new__(cls, *args, **kwargs):\n if not cls._get_cached_instance(args, kwargs):\n with cls._lock:\n if not cls._get_cached_instance(args, kwargs):\n cls._instances.append((super(cls, cls).__new__(cls), (args, kwargs)))\n return cls._get_cached_instance(args, kwargs)", - "detail": "database_setup_tools.setup", - "documentation": {} - }, - { - "label": "DATABASE_URIS", - "kind": 5, - "importPath": "tests.integration.database_config", - "description": "tests.integration.database_config", - "peekOfCode": "DATABASE_URIS = [\n \"postgresql+psycopg2://postgres:postgres@localhost:5432/test\", # PostgreSQL\n \"postgresql+psycopg2://postgres:postgres@localhost:5432/test?sslmode=require\", # PostgreSQL with SSL\n]", - "detail": "tests.integration.database_config", - "documentation": {} - }, - { - "label": "TestDatabaseIntegration", - "kind": 6, - "importPath": "tests.integration.test_database_integration", - "description": "tests.integration.test_database_integration", - "peekOfCode": "class TestDatabaseIntegration:\n #\n # Fixtures\n #\n @pytest.fixture\n def database_setup(self, database_uri: str) -> DatabaseSetup:\n setup = DatabaseSetup(model_metadata=model_metadata, database_uri=database_uri)\n setup.drop_database()\n setup.create_database()\n yield setup", - "detail": "tests.integration.test_database_integration", - "documentation": {} - }, - { - "label": "TestSessionManager", - "kind": 6, - "importPath": "tests.unit.test_session_manager", - "description": "tests.unit.test_session_manager", - "peekOfCode": "class TestSessionManager:\n @pytest.fixture\n def database_uri(self) -> str:\n return \"sqlite://\"\n @pytest.fixture\n def session_manager(self, database_uri: str) -> SessionManager:\n yield SessionManager(database_uri=database_uri)\n @pytest.mark.parametrize(\"invalid_database_uri\", [None, (), 42, False])\n def test_create_session_manager_fail_invalid_database_uri_type(self, invalid_database_uri: Any):\n with pytest.raises(TypeError):", - "detail": "tests.unit.test_session_manager", - "documentation": {} - }, - { - "label": "TestSetup", - "kind": 6, - "importPath": "tests.unit.test_setup", - "description": "tests.unit.test_setup", - "peekOfCode": "class TestSetup:\n @pytest.fixture\n def database_uri(self) -> str:\n return \"sqlite://\"\n @pytest.fixture\n def database_setup(self, when: Callable, database_uri: str) -> DatabaseSetup:\n when(DatabaseSetup).create_database().thenReturn(None)\n yield DatabaseSetup(model_metadata=model_metadata, database_uri=database_uri)\n @pytest.mark.parametrize(\"database_uri\", [\"sqlite://\", \"postgresql://\"])\n def test_database_setup_is_singleton_with_same_arguments(self, database_setup: DatabaseSetup, database_uri: str):", - "detail": "tests.unit.test_setup", - "documentation": {} - }, - { - "label": "Customer", - "kind": 6, - "importPath": "tests.sample_model", - "description": "tests.sample_model", - "peekOfCode": "class Customer(SQLModel, table=True):\n \"\"\"Customer model\"\"\"\n id: int = Field(index=True, primary_key=True)\n name: str\nmodel_metadata = SQLModel.metadata", - "detail": "tests.sample_model", - "documentation": {} - }, - { - "label": "model_metadata", - "kind": 5, - "importPath": "tests.sample_model", - "description": "tests.sample_model", - "peekOfCode": "model_metadata = SQLModel.metadata", - "detail": "tests.sample_model", - "documentation": {} - } -] \ No newline at end of file diff --git a/database_setup_tools/setup.py b/database_setup_tools/setup.py index 12202d9..1254baa 100644 --- a/database_setup_tools/setup.py +++ b/database_setup_tools/setup.py @@ -1,4 +1,5 @@ import threading +from ctypes import Union from typing import Any, List, Optional import sqlalchemy_utils @@ -88,7 +89,7 @@ def create_database(self) -> bool: return True return False - def truncate(self, tables: Optional[List[SQLModel | SQLModelMetaclass]] = None): + def truncate(self, tables: Optional[List[Union[SQLModel, SQLModelMetaclass]]] = None): """Truncate all tables in the database""" tables_to_truncate: List[Table] = self.model_metadata.sorted_tables if tables is not None: From 1c1cd03bc24b0df770c172b24dd191cd94fc69fa Mon Sep 17 00:00:00 2001 From: Jonas Scholl Date: Sun, 9 Apr 2023 09:47:40 +0200 Subject: [PATCH 6/6] fix wrong type import --- database_setup_tools/setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/database_setup_tools/setup.py b/database_setup_tools/setup.py index 1254baa..d255d67 100644 --- a/database_setup_tools/setup.py +++ b/database_setup_tools/setup.py @@ -1,6 +1,5 @@ import threading -from ctypes import Union -from typing import Any, List, Optional +from typing import Any, List, Optional, Union import sqlalchemy_utils from sqlalchemy import MetaData, Table