sqlspec 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

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.

Potentially problematic release.


This version of sqlspec might be problematic. Click here for more details.

@@ -5,8 +5,8 @@ from typing import TYPE_CHECKING, Generic, TypeVar
5
5
 
6
6
  from oracledb import ConnectionPool
7
7
 
8
- from sqlspec.config import GenericDatabaseConfig, GenericPoolConfig
9
- from sqlspec.utils.empty import Empty
8
+ from sqlspec.base import DatabaseConfigProtocol, GenericDatabaseConfig, GenericPoolConfig
9
+ from sqlspec.typing import Empty
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  import ssl
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
17
17
  from oracledb.connection import AsyncConnection, Connection
18
18
  from oracledb.pool import AsyncConnectionPool, ConnectionPool
19
19
 
20
- from sqlspec.utils.empty import EmptyType
20
+ from sqlspec.typing import EmptyType
21
21
 
22
22
  __all__ = (
23
23
  "OracleGenericDatabaseConfig",
@@ -32,7 +32,7 @@ PoolT = TypeVar("PoolT", bound="ConnectionPool | AsyncConnectionPool")
32
32
 
33
33
 
34
34
  @dataclass
35
- class OracleGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
35
+ class OracleGenericPoolConfig(Generic[ConnectionT, PoolT], GenericPoolConfig):
36
36
  """Configuration for Oracle database connection pools.
37
37
 
38
38
  This class provides configuration options for both synchronous and asynchronous Oracle
@@ -58,7 +58,7 @@ class OracleGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
58
58
  """New password for password change operations"""
59
59
  wallet_password: str | EmptyType = Empty
60
60
  """Password for accessing Oracle Wallet"""
61
- access_token: str | tuple | Callable | EmptyType = Empty
61
+ access_token: str | tuple[str, ...] | Callable[[], str] | EmptyType = Empty
62
62
  """Token for token-based authentication"""
63
63
  host: str | EmptyType = Empty
64
64
  """Database server hostname"""
@@ -112,11 +112,11 @@ class OracleGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
112
112
  """If True, allows connections with different tags"""
113
113
  config_dir: str | EmptyType = Empty
114
114
  """Directory containing Oracle configuration files"""
115
- appcontext: list | EmptyType = Empty
115
+ appcontext: list[str] | EmptyType = Empty
116
116
  """Application context list"""
117
- shardingkey: list | EmptyType = Empty
117
+ shardingkey: list[str] | EmptyType = Empty
118
118
  """Sharding key list"""
119
- supershardingkey: list | EmptyType = Empty
119
+ supershardingkey: list[str] | EmptyType = Empty
120
120
  """Super sharding key list"""
121
121
  debug_jdwp: str | EmptyType = Empty
122
122
  """JDWP debugging string"""
@@ -137,7 +137,7 @@ class OracleGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
137
137
 
138
138
 
139
139
  @dataclass
140
- class OracleGenericDatabaseConfig(Generic[PoolT, ConnectionT], GenericDatabaseConfig):
140
+ class OracleGenericDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT], GenericDatabaseConfig):
141
141
  """Oracle database Configuration.
142
142
 
143
143
  This class provides the base configuration for Oracle database connections, extending
@@ -13,7 +13,7 @@ from sqlspec.adapters.oracledb.config._common import (
13
13
  OracleGenericPoolConfig,
14
14
  )
15
15
  from sqlspec.exceptions import ImproperConfigurationError
16
- from sqlspec.utils.dataclass import simple_asdict
16
+ from sqlspec.typing import dataclass_to_dict
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from collections.abc import Generator
@@ -26,14 +26,17 @@ __all__ = (
26
26
 
27
27
 
28
28
  @dataclass
29
- class OracleSyncPoolConfig(OracleGenericPoolConfig[ConnectionPool, Connection]):
29
+ class OracleSyncPoolConfig(OracleGenericPoolConfig[Connection, ConnectionPool]):
30
30
  """Sync Oracle Pool Config"""
31
31
 
32
32
 
33
33
  @dataclass
34
- class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[ConnectionPool, Connection]):
34
+ class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[Connection, ConnectionPool]):
35
35
  """Oracle database Configuration."""
36
36
 
37
+ __is_async__ = False
38
+ __supports_connection_pooling__ = True
39
+
37
40
  pool_config: OracleSyncPoolConfig | None = None
38
41
  """Oracle Pool configuration"""
39
42
  pool_instance: ConnectionPool | None = None
@@ -51,7 +54,7 @@ class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[ConnectionPool, Conne
51
54
  function.
52
55
  """
53
56
  if self.pool_config:
54
- return simple_asdict(self.pool_config, exclude_empty=True, convert_nested=False)
57
+ return dataclass_to_dict(self.pool_config, exclude_empty=True, convert_nested=False)
55
58
  msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
56
59
  raise ImproperConfigurationError(msg)
57
60
 
@@ -70,18 +73,11 @@ class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[ConnectionPool, Conne
70
73
 
71
74
  pool_config = self.pool_config_dict
72
75
  self.pool_instance = oracledb_create_pool(**pool_config)
73
- if self.pool_instance is None:
76
+ if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
74
77
  msg = "Could not configure the 'pool_instance'. Please check your configuration."
75
78
  raise ImproperConfigurationError(msg)
76
79
  return self.pool_instance
77
80
 
78
- def lifespan(self, *args: Any, **kwargs: Any) -> Generator[None, None, None]:
79
- db_pool = self.create_pool()
80
- try:
81
- yield
82
- finally:
83
- db_pool.close()
84
-
85
81
  def provide_pool(self, *args: Any, **kwargs: Any) -> ConnectionPool:
86
82
  """Create a pool instance.
87
83
 
@@ -98,5 +94,5 @@ class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[ConnectionPool, Conne
98
94
  A connection instance.
99
95
  """
100
96
  db_pool = self.provide_pool(*args, **kwargs)
101
- with db_pool.acquire() as connection:
97
+ with db_pool.acquire() as connection: # pyright: ignore[reportUnknownMemberType]
102
98
  yield connection
@@ -1,5 +1,5 @@
1
- from ._async import PsycoPgAsyncDatabaseConfig, PsycoPgAsyncPoolConfig
2
- from ._sync import PsycoPgSyncDatabaseConfig, PsycoPgSyncPoolConfig
1
+ from sqlspec.adapters.psycopg.config._async import PsycoPgAsyncDatabaseConfig, PsycoPgAsyncPoolConfig
2
+ from sqlspec.adapters.psycopg.config._sync import PsycoPgSyncDatabaseConfig, PsycoPgSyncPoolConfig
3
3
 
4
4
  __all__ = (
5
5
  "PsycoPgAsyncDatabaseConfig",
@@ -12,7 +12,7 @@ from sqlspec.adapters.psycopg.config._common import (
12
12
  PsycoPgGenericPoolConfig,
13
13
  )
14
14
  from sqlspec.exceptions import ImproperConfigurationError
15
- from sqlspec.utils.dataclass import simple_asdict
15
+ from sqlspec.typing import dataclass_to_dict
16
16
 
17
17
  if TYPE_CHECKING:
18
18
  from collections.abc import AsyncGenerator, Awaitable
@@ -26,14 +26,17 @@ __all__ = (
26
26
 
27
27
 
28
28
  @dataclass
29
- class PsycoPgAsyncPoolConfig(PsycoPgGenericPoolConfig[AsyncConnectionPool, AsyncConnection]):
29
+ class PsycoPgAsyncPoolConfig(PsycoPgGenericPoolConfig[AsyncConnection, AsyncConnectionPool]):
30
30
  """Async Psycopg Pool Config"""
31
31
 
32
32
 
33
33
  @dataclass
34
- class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[AsyncConnectionPool, AsyncConnection]):
34
+ class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[AsyncConnection, AsyncConnectionPool]):
35
35
  """Async Psycopg database Configuration."""
36
36
 
37
+ __is_async__ = True
38
+ __supports_connection_pooling__ = True
39
+
37
40
  pool_config: PsycoPgAsyncPoolConfig | None = None
38
41
  """Psycopg Pool configuration"""
39
42
  pool_instance: AsyncConnectionPool | None = None
@@ -43,7 +46,7 @@ class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[AsyncConnectionPoo
43
46
  def pool_config_dict(self) -> dict[str, Any]:
44
47
  """Return the pool configuration as a dict."""
45
48
  if self.pool_config:
46
- return simple_asdict(self.pool_config, exclude_empty=True, convert_nested=False)
49
+ return dataclass_to_dict(self.pool_config, exclude_empty=True, convert_nested=False)
47
50
  msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
48
51
  raise ImproperConfigurationError(msg)
49
52
 
@@ -58,20 +61,11 @@ class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[AsyncConnectionPoo
58
61
 
59
62
  pool_config = self.pool_config_dict
60
63
  self.pool_instance = AsyncConnectionPool(**pool_config)
61
- if self.pool_instance is None:
64
+ if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
62
65
  msg = "Could not configure the 'pool_instance'. Please check your configuration." # type: ignore[unreachable]
63
66
  raise ImproperConfigurationError(msg)
64
67
  return self.pool_instance
65
68
 
66
- @asynccontextmanager
67
- async def lifespan(self, *args: Any, **kwargs: Any) -> AsyncGenerator[None, None]:
68
- """Manage the lifecycle of the connection pool."""
69
- pool = await self.create_pool()
70
- try:
71
- yield
72
- finally:
73
- await pool.close()
74
-
75
69
  def provide_pool(self, *args: Any, **kwargs: Any) -> Awaitable[AsyncConnectionPool]:
76
70
  """Create and return a connection pool."""
77
71
  return self.create_pool()
@@ -3,8 +3,8 @@ from __future__ import annotations
3
3
  from dataclasses import dataclass
4
4
  from typing import TYPE_CHECKING, Generic, TypeVar
5
5
 
6
- from sqlspec.config import GenericDatabaseConfig, GenericPoolConfig
7
- from sqlspec.utils.empty import Empty
6
+ from sqlspec.base import DatabaseConfigProtocol, GenericDatabaseConfig, GenericPoolConfig
7
+ from sqlspec.typing import Empty
8
8
 
9
9
  if TYPE_CHECKING:
10
10
  from collections.abc import Callable
@@ -13,7 +13,8 @@ if TYPE_CHECKING:
13
13
  from psycopg import AsyncConnection, Connection
14
14
  from psycopg_pool import AsyncConnectionPool, ConnectionPool
15
15
 
16
- from sqlspec.utils.empty import EmptyType
16
+ from sqlspec.typing import EmptyType
17
+
17
18
 
18
19
  __all__ = (
19
20
  "PsycoPgGenericDatabaseConfig",
@@ -26,7 +27,7 @@ PoolT = TypeVar("PoolT", bound="ConnectionPool | AsyncConnectionPool")
26
27
 
27
28
 
28
29
  @dataclass
29
- class PsycoPgGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
30
+ class PsycoPgGenericPoolConfig(Generic[ConnectionT, PoolT], GenericPoolConfig):
30
31
  """Configuration for Psycopg connection pools.
31
32
 
32
33
  This class provides configuration options for both synchronous and asynchronous Psycopg
@@ -61,7 +62,7 @@ class PsycoPgGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
61
62
 
62
63
 
63
64
  @dataclass
64
- class PsycoPgGenericDatabaseConfig(Generic[PoolT, ConnectionT], GenericDatabaseConfig):
65
+ class PsycoPgGenericDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT], GenericDatabaseConfig):
65
66
  """Psycopg database Configuration.
66
67
 
67
68
  This class provides the base configuration for Psycopg database connections, extending
@@ -12,7 +12,7 @@ from sqlspec.adapters.psycopg.config._common import (
12
12
  PsycoPgGenericPoolConfig,
13
13
  )
14
14
  from sqlspec.exceptions import ImproperConfigurationError
15
- from sqlspec.utils.dataclass import simple_asdict
15
+ from sqlspec.typing import dataclass_to_dict
16
16
 
17
17
  if TYPE_CHECKING:
18
18
  from collections.abc import Generator
@@ -26,14 +26,17 @@ __all__ = (
26
26
 
27
27
 
28
28
  @dataclass
29
- class PsycoPgSyncPoolConfig(PsycoPgGenericPoolConfig[ConnectionPool, Connection]):
29
+ class PsycoPgSyncPoolConfig(PsycoPgGenericPoolConfig[Connection, ConnectionPool]):
30
30
  """Sync Psycopg Pool Config"""
31
31
 
32
32
 
33
33
  @dataclass
34
- class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[ConnectionPool, Connection]):
34
+ class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[Connection, ConnectionPool]):
35
35
  """Sync Psycopg database Configuration."""
36
36
 
37
+ __is_async__ = False
38
+ __supports_connection_pooling__ = True
39
+
37
40
  pool_config: PsycoPgSyncPoolConfig | None = None
38
41
  """Psycopg Pool configuration"""
39
42
  pool_instance: ConnectionPool | None = None
@@ -43,7 +46,7 @@ class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[ConnectionPool, Con
43
46
  def pool_config_dict(self) -> dict[str, Any]:
44
47
  """Return the pool configuration as a dict."""
45
48
  if self.pool_config:
46
- return simple_asdict(self.pool_config, exclude_empty=True, convert_nested=False)
49
+ return dataclass_to_dict(self.pool_config, exclude_empty=True, convert_nested=False)
47
50
  msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
48
51
  raise ImproperConfigurationError(msg)
49
52
 
@@ -58,20 +61,11 @@ class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[ConnectionPool, Con
58
61
 
59
62
  pool_config = self.pool_config_dict
60
63
  self.pool_instance = ConnectionPool(**pool_config)
61
- if self.pool_instance is None:
64
+ if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
62
65
  msg = "Could not configure the 'pool_instance'. Please check your configuration." # type: ignore[unreachable]
63
66
  raise ImproperConfigurationError(msg)
64
67
  return self.pool_instance
65
68
 
66
- @contextmanager
67
- def lifespan(self, *args: Any, **kwargs: Any) -> Generator[None, None, None]:
68
- """Manage the lifecycle of the connection pool."""
69
- pool = self.create_pool()
70
- try:
71
- yield
72
- finally:
73
- pool.close()
74
-
75
69
  def provide_pool(self, *args: Any, **kwargs: Any) -> ConnectionPool:
76
70
  """Create and return a connection pool."""
77
71
  return self.create_pool()
@@ -4,10 +4,9 @@ from contextlib import contextmanager
4
4
  from dataclasses import dataclass
5
5
  from typing import TYPE_CHECKING, Any, Literal
6
6
 
7
- from sqlspec.config import GenericDatabaseConfig
7
+ from sqlspec.base import GenericDatabaseConfig, NoPoolConfig
8
8
  from sqlspec.exceptions import ImproperConfigurationError
9
- from sqlspec.utils.dataclass import simple_asdict
10
- from sqlspec.utils.empty import Empty, EmptyType
9
+ from sqlspec.typing import Empty, EmptyType, dataclass_to_dict
11
10
 
12
11
  if TYPE_CHECKING:
13
12
  from collections.abc import Generator
@@ -17,7 +16,7 @@ __all__ = ("SqliteConfig",)
17
16
 
18
17
 
19
18
  @dataclass
20
- class SqliteConfig(GenericDatabaseConfig):
19
+ class SqliteConfig(NoPoolConfig["Connection"], GenericDatabaseConfig):
21
20
  """Configuration for SQLite database connections.
22
21
 
23
22
  This class provides configuration options for SQLite database connections, wrapping all parameters
@@ -26,7 +25,7 @@ class SqliteConfig(GenericDatabaseConfig):
26
25
  For details see: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
27
26
  """
28
27
 
29
- database: str
28
+ database: str = ":memory:"
30
29
  """The path to the database file to be opened. Pass ":memory:" to open a connection to a database that resides in RAM instead of on disk."""
31
30
 
32
31
  timeout: float | EmptyType = Empty
@@ -57,7 +56,7 @@ class SqliteConfig(GenericDatabaseConfig):
57
56
  Returns:
58
57
  A string keyed dict of config kwargs for the sqlite3.connect() function.
59
58
  """
60
- return simple_asdict(self, exclude_empty=True, convert_nested=False)
59
+ return dataclass_to_dict(self, exclude_empty=True, convert_nested=False)
61
60
 
62
61
  def create_connection(self) -> Connection:
63
62
  """Create and return a new database connection.
@@ -71,27 +70,11 @@ class SqliteConfig(GenericDatabaseConfig):
71
70
  import sqlite3
72
71
 
73
72
  try:
74
- return sqlite3.connect(**self.connection_config_dict)
73
+ return sqlite3.connect(**self.connection_config_dict) # type: ignore[no-any-return,unused-ignore]
75
74
  except Exception as e:
76
75
  msg = f"Could not configure the SQLite connection. Error: {e!s}"
77
76
  raise ImproperConfigurationError(msg) from e
78
77
 
79
- @contextmanager
80
- def lifespan(self, *args: Any, **kwargs: Any) -> Generator[None, None, None]:
81
- """Manage the lifecycle of a database connection.
82
-
83
- Yields:
84
- None
85
-
86
- Raises:
87
- ImproperConfigurationError: If the connection could not be established.
88
- """
89
- connection = self.create_connection()
90
- try:
91
- yield
92
- finally:
93
- connection.close()
94
-
95
78
  @contextmanager
96
79
  def provide_connection(self, *args: Any, **kwargs: Any) -> Generator[Connection, None, None]:
97
80
  """Create and provide a database connection.
sqlspec/base.py ADDED
@@ -0,0 +1,87 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import AsyncGenerator, Awaitable, Generator
3
+ from contextlib import AbstractAsyncContextManager, AbstractContextManager
4
+ from dataclasses import dataclass
5
+ from typing import Any, ClassVar, Generic, TypeVar, Union
6
+
7
+ __all__ = (
8
+ "DatabaseConfigProtocol",
9
+ "GenericPoolConfig",
10
+ "NoPoolConfig",
11
+ )
12
+
13
+ ConnectionT = TypeVar("ConnectionT")
14
+ PoolT = TypeVar("PoolT")
15
+
16
+
17
+ @dataclass
18
+ class DatabaseConfigProtocol(Generic[ConnectionT, PoolT], ABC):
19
+ """Protocol defining the interface for database configurations."""
20
+
21
+ __is_async__: ClassVar[bool] = False
22
+ __supports_connection_pooling__: ClassVar[bool] = False
23
+
24
+ @abstractmethod
25
+ def create_connection(self) -> Union[ConnectionT, Awaitable[ConnectionT]]:
26
+ """Create and return a new database connection."""
27
+ raise NotImplementedError
28
+
29
+ @abstractmethod
30
+ def provide_connection(
31
+ self, *args: Any, **kwargs: Any
32
+ ) -> Union[
33
+ Generator[ConnectionT, None, None],
34
+ AsyncGenerator[ConnectionT, None],
35
+ AbstractContextManager[ConnectionT],
36
+ AbstractAsyncContextManager[ConnectionT],
37
+ ]:
38
+ """Provide a database connection context manager."""
39
+ raise NotImplementedError
40
+
41
+ @property
42
+ @abstractmethod
43
+ def connection_config_dict(self) -> dict[str, Any]:
44
+ """Return the connection configuration as a dict."""
45
+ raise NotImplementedError
46
+
47
+ @abstractmethod
48
+ def create_pool(self) -> Union[PoolT, Awaitable[PoolT]]:
49
+ """Create and return connection pool."""
50
+ raise NotImplementedError
51
+
52
+ @abstractmethod
53
+ def provide_pool(
54
+ self, *args: Any, **kwargs: Any
55
+ ) -> Union[PoolT, Awaitable[PoolT], AbstractContextManager[PoolT], AbstractAsyncContextManager[PoolT]]:
56
+ """Provide pool instance."""
57
+ raise NotImplementedError
58
+
59
+ @property
60
+ def is_async(self) -> bool:
61
+ """Return whether the configuration is for an async database."""
62
+ return self.__is_async__
63
+
64
+ @property
65
+ def support_connection_pooling(self) -> bool:
66
+ """Return whether the configuration supports connection pooling."""
67
+ return self.__supports_connection_pooling__
68
+
69
+
70
+ class NoPoolConfig(DatabaseConfigProtocol[ConnectionT, None]):
71
+ """Base class for database configurations that do not implement a pool."""
72
+
73
+ def create_pool(self) -> None:
74
+ """This database backend has not implemented the pooling configurations."""
75
+
76
+ def provide_pool(self, *args: Any, **kwargs: Any) -> None:
77
+ """This database backend has not implemented the pooling configurations."""
78
+
79
+
80
+ @dataclass
81
+ class GenericPoolConfig:
82
+ """Generic Database Pool Configuration."""
83
+
84
+
85
+ @dataclass
86
+ class GenericDatabaseConfig:
87
+ """Generic Database Configuration."""
sqlspec/filters.py CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from abc import ABC, abstractmethod
5
+ from abc import ABC
6
6
  from collections import abc # noqa: TC003
7
7
  from dataclasses import dataclass
8
8
  from datetime import datetime # noqa: TC003
9
- from typing import Generic, Literal
9
+ from typing import Generic, Literal, Protocol
10
10
 
11
11
  from typing_extensions import TypeVar
12
12
 
@@ -25,11 +25,14 @@ __all__ = (
25
25
  )
26
26
 
27
27
  T = TypeVar("T")
28
+ StatementT = TypeVar("StatementT", bound="str")
28
29
 
29
30
 
30
- class StatementFilter(ABC):
31
- @abstractmethod
32
- def append_to_statement(self, statement: str) -> str:
31
+ class StatementFilter(Protocol):
32
+ """Protocol for filters that can be appended to a statement."""
33
+
34
+ def append_to_statement(self, statement: StatementT) -> StatementT:
35
+ """Append the filter to the statement."""
33
36
  return statement
34
37
 
35
38