archipy-mysql 5.11.0__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.
@@ -0,0 +1,245 @@
1
+ ### JetBrains template
2
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
3
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
4
+ .idea
5
+ # User-specific stuff
6
+ .idea/**/workspace.xml
7
+ .idea/**/tasks.xml
8
+ .idea/**/usage.statistics.xml
9
+ .idea/**/dictionaries
10
+ .idea/**/shelf
11
+ dist
12
+ # AWS User-specific
13
+ .idea/**/aws.xml
14
+
15
+ # Generated files
16
+ .idea/**/contentModel.xml
17
+
18
+ # Sensitive or high-churn files
19
+ .idea/**/dataSources/
20
+ .idea/**/dataSources.ids
21
+ .idea/**/dataSources.local.xml
22
+ .idea/**/sqlDataSources.xml
23
+ .idea/**/dynamic.xml
24
+ .idea/**/uiDesigner.xml
25
+ .idea/**/dbnavigator.xml
26
+
27
+ # Gradle
28
+ .idea/**/gradle.xml
29
+ .idea/**/libraries
30
+
31
+ # Gradle and Maven with auto-import
32
+ # When using Gradle or Maven with auto-import, you should exclude module files,
33
+ # since they will be recreated, and may cause churn. Uncomment if using
34
+ # auto-import.
35
+ # .idea/artifacts
36
+ # .idea/compiler.xml
37
+ # .idea/jarRepositories.xml
38
+ # .idea/modules.xml
39
+ # .idea/*.iml
40
+ # .idea/modules
41
+ # *.iml
42
+ # *.ipr
43
+
44
+ # CMake
45
+ cmake-build-*/
46
+
47
+ # Mongo Explorer plugin
48
+ .idea/**/mongoSettings.xml
49
+
50
+ # File-based project format
51
+ *.iws
52
+
53
+ # IntelliJ
54
+ out/
55
+
56
+ # mpeltonen/sbt-idea plugin
57
+ .idea_modules/
58
+
59
+ # JIRA plugin
60
+ atlassian-ide-plugin.xml
61
+
62
+ # Cursive Clojure plugin
63
+ .idea/replstate.xml
64
+
65
+ # SonarLint plugin
66
+ .idea/sonarlint/
67
+
68
+ # Crashlytics plugin (for Android Studio and IntelliJ)
69
+ com_crashlytics_export_strings.xml
70
+ crashlytics.properties
71
+ crashlytics-build.properties
72
+ fabric.properties
73
+
74
+ # Editor-based Rest Client
75
+ .idea/httpRequests
76
+
77
+ # Android studio 3.1+ serialized cache file
78
+ .idea/caches/build_file_checksums.ser
79
+
80
+ ### Python template
81
+ # Byte-compiled / optimized / DLL files
82
+ __pycache__/
83
+ *.py[cod]
84
+ *$py.class
85
+
86
+ # C extensions
87
+ *.so
88
+
89
+ # Distribution / packaging
90
+ .Python
91
+ build/
92
+ develop-eggs/
93
+ dist/
94
+ downloads/
95
+ eggs/
96
+ .eggs/
97
+ lib/
98
+ lib64/
99
+ parts/
100
+ sdist/
101
+ var/
102
+ wheels/
103
+ share/python-wheels/
104
+ *.egg-info/
105
+ .installed.cfg
106
+ *.egg
107
+ MANIFEST
108
+
109
+ # PyInstaller
110
+ # Usually these files are written by a python script from a template
111
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
112
+ *.manifest
113
+ *.spec
114
+
115
+ # Installer logs
116
+ pip-log.txt
117
+ pip-delete-this-directory.txt
118
+
119
+ # Unit test / coverage reports
120
+ htmlcov/
121
+ .tox/
122
+ .nox/
123
+ .coverage
124
+ .coverage.*
125
+ .cache
126
+ nosetests.xml
127
+ coverage.xml
128
+ *.cover
129
+ *.py,cover
130
+ .hypothesis/
131
+ .pytest_cache/
132
+ cover/
133
+
134
+ # Translations
135
+ *.mo
136
+ *.pot
137
+
138
+ # Django stuff:
139
+ *.log
140
+ local_settings.py
141
+ db.sqlite3
142
+ db.sqlite3-journal
143
+
144
+ # Flask stuff:
145
+ instance/
146
+ .webassets-cache
147
+
148
+ # Scrapy stuff:
149
+ .scrapy
150
+
151
+ # Sphinx documentation
152
+ docs/_build/
153
+
154
+ # PyBuilder
155
+ .pybuilder/
156
+ target/
157
+
158
+ # Jupyter Notebook
159
+ .ipynb_checkpoints
160
+
161
+ # IPython
162
+ profile_default/
163
+ ipython_config.py
164
+
165
+ # pyenv
166
+ # For a library or package, you might want to ignore these files since the code is
167
+ # intended to run in multiple environments; otherwise, check them in:
168
+ # .python-version
169
+
170
+ # pipenv
171
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
172
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
173
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
174
+ # install all needed dependencies.
175
+ #Pipfile.lock
176
+
177
+ # poetry
178
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
179
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
180
+ # commonly ignored for libraries.
181
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
182
+ #poetry.lock
183
+
184
+ # pdm
185
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
186
+ #pdm.lock
187
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
188
+ # in version control.
189
+ # https://pdm.fming.dev/#use-with-ide
190
+ .pdm.toml
191
+
192
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
193
+ __pypackages__/
194
+
195
+ # Celery stuff
196
+ celerybeat-schedule
197
+ celerybeat.pid
198
+
199
+ # SageMath parsed files
200
+ *.sage.py
201
+
202
+ # Environments
203
+ .env
204
+ .venv
205
+ env/
206
+ venv/
207
+ ENV/
208
+ env.bak/
209
+ venv.bak/
210
+
211
+ # Spyder project settings
212
+ .spyderproject
213
+ .spyproject
214
+
215
+ # Rope project settings
216
+ .ropeproject
217
+
218
+ # mkdocs documentation
219
+ /site
220
+
221
+ # mypy
222
+ .mypy_cache/
223
+ .dmypy.json
224
+ dmypy.json
225
+
226
+ # Pyre type checker
227
+ .pyre/
228
+
229
+ # pytype static type analyzer
230
+ .pytype/
231
+
232
+ # Cython debug symbols
233
+ cython_debug/
234
+
235
+ # PyCharm
236
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
237
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
238
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
239
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
240
+ #.idea/
241
+
242
+ .ruff_cache
243
+ bandit-report.json
244
+
245
+ .gitattributes
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.5
2
+ Name: archipy-mysql
3
+ Version: 5.11.0
4
+ Summary: ArchiPy mysql adapter.
5
+ Author-email: Hossein Nejati <hosseinnejati14@gmail.com>
6
+ License-Expression: Apache-2.0
7
+ Requires-Python: <4,>=3.14
8
+ Requires-Dist: archipy==5.11.0
9
+ Provides-Extra: async
10
+ Requires-Dist: asyncmy2>=0.2.21; extra == 'async'
11
+ Provides-Extra: sync
12
+ Requires-Dist: pymysql>=1.2.3; extra == 'sync'
13
+ Description-Content-Type: text/markdown
14
+
15
+ # archipy-mysql
16
+
17
+ mysql adapter for [ArchiPy](https://syntaxarc.github.io/ArchiPy/). Install via the core extra:
18
+
19
+ ```bash
20
+ uv add "archipy[mysql]"
21
+ ```
@@ -0,0 +1,7 @@
1
+ # archipy-mysql
2
+
3
+ mysql adapter for [ArchiPy](https://syntaxarc.github.io/ArchiPy/). Install via the core extra:
4
+
5
+ ```bash
6
+ uv add "archipy[mysql]"
7
+ ```
@@ -0,0 +1 @@
1
+ """MySQL adapter package."""
@@ -0,0 +1 @@
1
+ """MySQL SQLAlchemy adapters for ArchiPy."""
@@ -0,0 +1,78 @@
1
+ """MySQL SQLAlchemy adapter implementations."""
2
+
3
+ from typing import override
4
+
5
+ from archipy.adapters.base.sqlalchemy.adapters import (
6
+ AsyncBaseSQLAlchemyAdapter,
7
+ BaseSQLAlchemyAdapter,
8
+ )
9
+ from archipy.adapters.mysql.sqlalchemy.session_managers import (
10
+ AsyncMySQLSQlAlchemySessionManager,
11
+ MySQLSQlAlchemySessionManager,
12
+ )
13
+ from archipy.configs.base_config import BaseConfig
14
+ from archipy.configs.config_template import MySQLSQLAlchemyConfig
15
+
16
+
17
+ class MySQLSQLAlchemyAdapter(BaseSQLAlchemyAdapter[MySQLSQLAlchemyConfig]):
18
+ """Synchronous SQLAlchemy adapter for MySQL.
19
+
20
+ Inherits from BaseSQLAlchemyAdapter to provide MySQL-specific session management
21
+ and database operations.
22
+
23
+ Args:
24
+ orm_config: MySQL-specific configuration. If None, uses global config.
25
+ """
26
+
27
+ def __init__(self, orm_config: MySQLSQLAlchemyConfig | None = None) -> None:
28
+ """Initialize the MySQL adapter with a session manager.
29
+
30
+ Args:
31
+ orm_config: MySQL-specific configuration. If None, uses global config.
32
+ """
33
+ configs = BaseConfig.global_config().MYSQL_SQLALCHEMY if orm_config is None else orm_config
34
+ super().__init__(configs)
35
+
36
+ @override
37
+ def _create_session_manager(self, configs: MySQLSQLAlchemyConfig) -> MySQLSQlAlchemySessionManager:
38
+ """Create a MySQL-specific session manager.
39
+
40
+ Args:
41
+ configs: MySQL configuration.
42
+
43
+ Returns:
44
+ A MySQL session manager instance.
45
+ """
46
+ return MySQLSQlAlchemySessionManager(configs)
47
+
48
+
49
+ class AsyncMySQLSQLAlchemyAdapter(AsyncBaseSQLAlchemyAdapter[MySQLSQLAlchemyConfig]):
50
+ """Asynchronous SQLAlchemy adapter for MySQL.
51
+
52
+ Inherits from AsyncBaseSQLAlchemyAdapter to provide async MySQL-specific session
53
+ management and database operations.
54
+
55
+ Args:
56
+ orm_config: MySQL-specific configuration. If None, uses global config.
57
+ """
58
+
59
+ def __init__(self, orm_config: MySQLSQLAlchemyConfig | None = None) -> None:
60
+ """Initialize the async MySQL adapter with a session manager.
61
+
62
+ Args:
63
+ orm_config: MySQL-specific configuration. If None, uses global config.
64
+ """
65
+ configs = BaseConfig.global_config().MYSQL_SQLALCHEMY if orm_config is None else orm_config
66
+ super().__init__(configs)
67
+
68
+ @override
69
+ def _create_async_session_manager(self, configs: MySQLSQLAlchemyConfig) -> AsyncMySQLSQlAlchemySessionManager:
70
+ """Create an async MySQL-specific session manager.
71
+
72
+ Args:
73
+ configs: MySQL configuration.
74
+
75
+ Returns:
76
+ An async MySQL session manager instance.
77
+ """
78
+ return AsyncMySQLSQlAlchemySessionManager(configs)
@@ -0,0 +1,125 @@
1
+ """Registry for MySQL SQLAlchemy session managers."""
2
+
3
+ from archipy.adapters.base.sqlalchemy.session_manager_ports import (
4
+ AsyncSessionManagerPort,
5
+ SessionManagerPort,
6
+ )
7
+ from archipy.adapters.base.sqlalchemy.session_manager_registry import (
8
+ SessionManagerRegistry,
9
+ )
10
+ from archipy.adapters.mysql.sqlalchemy.session_managers import (
11
+ AsyncMySQLSQlAlchemySessionManager,
12
+ MySQLSQlAlchemySessionManager,
13
+ )
14
+ from archipy.helpers.metaclasses.singleton import Singleton
15
+ from archipy.models.errors import (
16
+ DatabaseConnectionError,
17
+ InvalidArgumentError,
18
+ InvalidEntityTypeError,
19
+ )
20
+
21
+
22
+ class MySQLSessionManagerRegistry(SessionManagerRegistry, metaclass=Singleton):
23
+ """Registry for MySQL SQLAlchemy session managers.
24
+
25
+ This registry provides a centralized access point for both synchronous and
26
+ asynchronous MySQL session managers, implementing the Service Locator pattern.
27
+ It lazily initializes the appropriate session manager when first requested.
28
+
29
+ The registry maintains singleton instances of:
30
+ - A synchronous session manager (MySQLSQlAlchemySessionManager)
31
+ - An asynchronous session manager (AsyncMySQLSQlAlchemySessionManager)
32
+ """
33
+
34
+ @classmethod
35
+ def get_sync_manager(cls) -> SessionManagerPort:
36
+ """Get the synchronous MySQL session manager instance.
37
+
38
+ Lazily initializes a default MySQLSQlAlchemySessionManager if none has been set.
39
+
40
+ Returns:
41
+ SessionManagerPort: The registered synchronous session manager
42
+
43
+ Raises:
44
+ DatabaseConnectionError: If there's an error initializing the session manager
45
+ """
46
+ if cls._sync_instance is None:
47
+ try:
48
+ cls._sync_instance = MySQLSQlAlchemySessionManager()
49
+ except Exception as e:
50
+ raise DatabaseConnectionError(
51
+ database="mysql",
52
+ ) from e
53
+ return cls._sync_instance
54
+
55
+ @classmethod
56
+ def set_sync_manager(cls, manager: SessionManagerPort) -> None:
57
+ """Set a custom synchronous session manager.
58
+
59
+ Args:
60
+ manager: An instance implementing SessionManagerPort
61
+
62
+ Raises:
63
+ InvalidArgumentError: If the manager is None
64
+ InvalidEntityTypeError: If the manager doesn't implement SessionManagerPort
65
+ """
66
+ if manager is None:
67
+ raise InvalidArgumentError(argument_name="mysql_session_manager")
68
+
69
+ if not isinstance(manager, SessionManagerPort):
70
+ raise InvalidEntityTypeError(
71
+ expected_type="SessionManagerPort",
72
+ actual_type=type(manager).__name__,
73
+ )
74
+ cls._sync_instance = manager
75
+
76
+ @classmethod
77
+ def get_async_manager(cls) -> AsyncSessionManagerPort:
78
+ """Get the asynchronous MySQL session manager instance.
79
+
80
+ Lazily initializes a default AsyncMySQLSQlAlchemySessionManager if none has been set.
81
+
82
+ Returns:
83
+ AsyncSessionManagerPort: The registered asynchronous session manager
84
+
85
+ Raises:
86
+ DatabaseConnectionError: If there's an error initializing the session manager
87
+ """
88
+ if cls._async_instance is None:
89
+ try:
90
+ cls._async_instance = AsyncMySQLSQlAlchemySessionManager()
91
+ except Exception as e:
92
+ raise DatabaseConnectionError(
93
+ database="mysql",
94
+ ) from e
95
+ return cls._async_instance
96
+
97
+ @classmethod
98
+ def set_async_manager(cls, manager: AsyncSessionManagerPort) -> None:
99
+ """Set a custom asynchronous session manager.
100
+
101
+ Args:
102
+ manager: An instance implementing AsyncSessionManagerPort
103
+
104
+ Raises:
105
+ InvalidArgumentError: If the manager is None
106
+ InvalidEntityTypeError: If the manager doesn't implement AsyncSessionManagerPort
107
+ """
108
+ if manager is None:
109
+ raise InvalidArgumentError(argument_name="mysql_async_session_manager")
110
+
111
+ if not isinstance(manager, AsyncSessionManagerPort):
112
+ raise InvalidEntityTypeError(
113
+ expected_type="AsyncSessionManagerPort",
114
+ actual_type=type(manager).__name__,
115
+ )
116
+ cls._async_instance = manager
117
+
118
+ @classmethod
119
+ def reset(cls) -> None:
120
+ """Reset the registry to its initial state.
121
+
122
+ This method clears both registered managers, useful for testing.
123
+ """
124
+ cls._sync_instance = None
125
+ cls._async_instance = None
@@ -0,0 +1,176 @@
1
+ """MySQL SQLAlchemy session manager implementations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, override
6
+
7
+ from sqlalchemy import URL
8
+ from sqlalchemy.dialects.mysql.base import MySQLTypeCompiler
9
+ from sqlalchemy.exc import SQLAlchemyError
10
+
11
+ from archipy.adapters.base.sqlalchemy.session_managers import (
12
+ AsyncBaseSQLAlchemySessionManager,
13
+ BaseSQLAlchemySessionManager,
14
+ )
15
+ from archipy.configs.base_config import BaseConfig
16
+ from archipy.configs.config_template import MySQLSQLAlchemyConfig
17
+ from archipy.helpers.metaclasses.singleton import Singleton
18
+ from archipy.models.errors import DatabaseConnectionError
19
+
20
+ if TYPE_CHECKING:
21
+ from sqlalchemy.dialects.postgresql import UUID as PostgresUUID
22
+
23
+
24
+ def _patch_mysql_uuid_mapping() -> None:
25
+ """Patch the MySQL type compiler to map UUID to VARCHAR.
26
+
27
+ MySQL does not support a native UUID column type, so PostgreSQL UUID
28
+ columns used in shared entity models must be mapped to VARCHAR(36).
29
+ This is patched at module level to ensure it is applied before engine creation.
30
+ """
31
+
32
+ def visit_UUID(self: MySQLTypeCompiler, type_: PostgresUUID, **kw: object) -> str: # noqa: ARG001
33
+ """Map PostgreSQL UUID to VARCHAR(36) for MySQL."""
34
+ return "VARCHAR(36)"
35
+
36
+ MySQLTypeCompiler.visit_UUID = visit_UUID
37
+
38
+
39
+ # Apply the patch when the module is imported
40
+ _patch_mysql_uuid_mapping()
41
+
42
+
43
+ class MySQLSQlAlchemySessionManager(BaseSQLAlchemySessionManager[MySQLSQLAlchemyConfig], metaclass=Singleton):
44
+ """Synchronous SQLAlchemy session manager for MySQL.
45
+
46
+ Inherits from BaseSQLAlchemySessionManager to provide MySQL-specific session
47
+ management, including connection URL creation and engine configuration.
48
+
49
+ Args:
50
+ orm_config: MySQL-specific configuration. If None, uses global config.
51
+ """
52
+
53
+ def __init__(self, orm_config: MySQLSQLAlchemyConfig | None = None) -> None:
54
+ """Initialize the MySQL session manager.
55
+
56
+ Args:
57
+ orm_config: MySQL-specific configuration. If None, uses global config.
58
+ """
59
+ configs = BaseConfig.global_config().MYSQL_SQLALCHEMY if orm_config is None else orm_config
60
+ super().__init__(configs)
61
+
62
+ @override
63
+ def _expected_config_type(self) -> type[MySQLSQLAlchemyConfig]:
64
+ """Return the expected configuration type for MySQL.
65
+
66
+ Returns:
67
+ The MySQLSQLAlchemyConfig class.
68
+ """
69
+ return MySQLSQLAlchemyConfig
70
+
71
+ @override
72
+ def _get_database_name(self) -> str:
73
+ """Return the name of the database being used.
74
+
75
+ Returns:
76
+ str: The name of the database ('mysql').
77
+ """
78
+ return "mysql"
79
+
80
+ @override
81
+ def _create_url(self, configs: MySQLSQLAlchemyConfig) -> URL:
82
+ """Create a MySQL connection URL.
83
+
84
+ Args:
85
+ configs: MySQL configuration.
86
+
87
+ Returns:
88
+ A SQLAlchemy URL object for MySQL.
89
+
90
+ Raises:
91
+ DatabaseConnectionError: If there's an error creating the URL.
92
+ """
93
+ try:
94
+ return URL.create(
95
+ drivername=configs.DRIVER_NAME,
96
+ username=configs.USERNAME,
97
+ password=configs.PASSWORD,
98
+ host=configs.HOST,
99
+ port=configs.PORT,
100
+ database=configs.DATABASE,
101
+ )
102
+ except SQLAlchemyError as e:
103
+ raise DatabaseConnectionError(
104
+ database=self._get_database_name(),
105
+ ) from e
106
+
107
+
108
+ class AsyncMySQLSQlAlchemySessionManager(
109
+ AsyncBaseSQLAlchemySessionManager[MySQLSQLAlchemyConfig],
110
+ metaclass=Singleton,
111
+ ):
112
+ """Asynchronous SQLAlchemy session manager for MySQL.
113
+
114
+ Inherits from AsyncBaseSQLAlchemySessionManager to provide async MySQL-specific
115
+ session management, including connection URL creation and async engine configuration.
116
+
117
+ Args:
118
+ orm_config: MySQL-specific configuration. If None, uses global config.
119
+ """
120
+
121
+ def __init__(self, orm_config: MySQLSQLAlchemyConfig | None = None) -> None:
122
+ """Initialize the async MySQL session manager.
123
+
124
+ Args:
125
+ orm_config: MySQL-specific configuration. If None, uses global config.
126
+ """
127
+ configs = BaseConfig.global_config().MYSQL_SQLALCHEMY if orm_config is None else orm_config
128
+ super().__init__(configs)
129
+
130
+ @override
131
+ def _expected_config_type(self) -> type[MySQLSQLAlchemyConfig]:
132
+ """Return the expected configuration type for MySQL.
133
+
134
+ Returns:
135
+ The MySQLSQLAlchemyConfig class.
136
+ """
137
+ return MySQLSQLAlchemyConfig
138
+
139
+ @override
140
+ def _get_database_name(self) -> str:
141
+ """Return the name of the database being used.
142
+
143
+ Returns:
144
+ str: The name of the database ('mysql').
145
+ """
146
+ return "mysql"
147
+
148
+ @override
149
+ def _create_url(self, configs: MySQLSQLAlchemyConfig) -> URL:
150
+ """Create an async MySQL connection URL.
151
+
152
+ For async operations, MySQL uses the mysql+asyncmy driver which is provided
153
+ by the asyncmy2 package.
154
+
155
+ Args:
156
+ configs: MySQL configuration.
157
+
158
+ Returns:
159
+ A SQLAlchemy URL object for MySQL with async driver.
160
+
161
+ Raises:
162
+ DatabaseConnectionError: If there's an error creating the URL.
163
+ """
164
+ try:
165
+ return URL.create(
166
+ drivername="mysql+asyncmy",
167
+ username=configs.USERNAME,
168
+ password=configs.PASSWORD,
169
+ host=configs.HOST,
170
+ port=configs.PORT,
171
+ database=configs.DATABASE,
172
+ )
173
+ except SQLAlchemyError as e:
174
+ raise DatabaseConnectionError(
175
+ database=self._get_database_name(),
176
+ ) from e
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "archipy-mysql"
3
+ description = "ArchiPy mysql adapter."
4
+ authors = [
5
+ { name = "Hossein Nejati", email = "hosseinnejati14@gmail.com" },
6
+ ]
7
+ readme = "README.md"
8
+ license = "Apache-2.0"
9
+ version = "5.11.0" # This version is set on publish flow!
10
+ requires-python = ">=3.14,<4"
11
+ dependencies = [
12
+ "archipy==5.11.0", # Pinned to core version on publish flow!
13
+ ]
14
+
15
+ [project.optional-dependencies]
16
+ sync = ["pymysql>=1.2.3"]
17
+ async = ["asyncmy2>=0.2.21"]
18
+
19
+ [build-system]
20
+ requires = ["hatchling"]
21
+ build-backend = "hatchling.build"
22
+
23
+ [tool.hatch.build.targets.wheel]
24
+ packages = ["archipy"]
25
+
26
+ [tool.uv.sources]
27
+ archipy = { workspace = true }