Skip to content

Commit 4ae32e3

Browse files
authored
Merge pull request #4 from IdoKendo/infra-update
Update linter and add type checker
2 parents 8b22928 + d808a56 commit 4ae32e3

File tree

11 files changed

+281
-47
lines changed

11 files changed

+281
-47
lines changed

.github/workflows/build.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ jobs:
1616
matrix:
1717
os: [ubuntu-latest, windows-latest]
1818
python-version: ["3.8", "3.9", "3.10", "3.11"]
19+
experimental: [false]
20+
include:
21+
- python-version: "3.12-dev"
22+
os: ubuntu-latest
23+
experimental: true
1924

2025
steps:
2126
- name: Checkout sources
@@ -33,6 +38,7 @@ jobs:
3338
3439
- name: Run tox
3540
run: tox
41+
continue-on-error: ${{ matrix.experimental }}
3642

3743
- name: upload coverage to Codecov
3844
if: "matrix.python-version == '3.11'"

.pre-commit-config.yaml

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
repos:
22
- repo: https://github.com/psf/black
3-
rev: 22.12.0
3+
rev: 23.3.0
44
hooks:
55
- id: black
6-
args: [--safe, --line-length=120]
6+
args: [--safe]
77
- repo: https://github.com/pre-commit/pre-commit-hooks
88
rev: v4.4.0
99
hooks:
@@ -13,19 +13,13 @@ repos:
1313
- id: check-added-large-files
1414
- id: debug-statements
1515
language_version: python3
16-
- repo: https://github.com/PyCQA/flake8
17-
rev: 6.0.0
16+
- repo: https://github.com/charliermarsh/ruff-pre-commit
17+
rev: v0.0.269
1818
hooks:
19-
- id: flake8
20-
args: [--max-line-length=120]
21-
language_version: python3
22-
- repo: https://github.com/asottile/reorder_python_imports
23-
rev: v3.9.0
24-
hooks:
25-
- id: reorder-python-imports
26-
args: [--application-directories=.src/, --py310-plus]
27-
- repo: https://github.com/asottile/pyupgrade
28-
rev: v3.3.1
19+
- id: ruff
20+
args: [--fix]
21+
- repo: https://github.com/pre-commit/mirrors-mypy
22+
rev: v1.3.0
2923
hooks:
30-
- id: pyupgrade
31-
args: [--py311-plus]
24+
- id: mypy
25+
args: [--no-strict-optional, --ignore-missing-imports]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.. A new scriv changelog fragment.
2+
..
3+
.. Uncomment the header that is right (remove the leading dots).
4+
..
5+
.. Removed
6+
.. -------
7+
..
8+
.. - A bullet item for the Removed category.
9+
..
10+
Added
11+
-----
12+
13+
- Added mypy type checker
14+
15+
Changed
16+
-------
17+
18+
- Changed linting to ruff
19+
20+
.. Deprecated
21+
.. ----------
22+
..
23+
.. - A bullet item for the Deprecated category.
24+
..
25+
.. Fixed
26+
.. -----
27+
..
28+
.. - A bullet item for the Fixed category.
29+
..
30+
.. Security
31+
.. --------
32+
..
33+
.. - A bullet item for the Security category.
34+
..
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.. A new scriv changelog fragment.
2+
..
3+
.. Uncomment the header that is right (remove the leading dots).
4+
..
5+
.. Removed
6+
.. -------
7+
..
8+
.. - A bullet item for the Removed category.
9+
..
10+
Added
11+
-----
12+
13+
- Added support for python 3.12-dev
14+
..
15+
.. Changed
16+
.. -------
17+
..
18+
.. - A bullet item for the Changed category.
19+
..
20+
.. Deprecated
21+
.. ----------
22+
..
23+
.. - A bullet item for the Deprecated category.
24+
..
25+
.. Fixed
26+
.. -----
27+
..
28+
.. - A bullet item for the Fixed category.
29+
..
30+
.. Security
31+
.. --------
32+
..
33+
.. - A bullet item for the Security category.
34+
..
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.. A new scriv changelog fragment.
2+
..
3+
.. Uncomment the header that is right (remove the leading dots).
4+
..
5+
.. Removed
6+
.. -------
7+
..
8+
.. - A bullet item for the Removed category.
9+
..
10+
.. Added
11+
.. -----
12+
..
13+
.. - A bullet item for the Added category.
14+
..
15+
Changed
16+
-------
17+
18+
- query() and execute() will raise ConnectionError in case they are run without active connection.
19+
..
20+
.. Deprecated
21+
.. ----------
22+
..
23+
.. - A bullet item for the Deprecated category.
24+
..
25+
.. Fixed
26+
.. -----
27+
..
28+
.. - A bullet item for the Fixed category.
29+
..
30+
.. Security
31+
.. --------
32+
..
33+
.. - A bullet item for the Security category.
34+
..

poetry.lock

Lines changed: 72 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "mysql-context-manager"
3-
version = "0.1.6"
3+
version = "0.1.5"
44
description = "Work with MySQL databases asynchronously, and in context."
55
license = "MIT"
66
authors = ["IdoKendo <[email protected]>"]
@@ -25,11 +25,37 @@ tox = "^4.5"
2525
pytest-asyncio = "^0.21"
2626
pytest-mock = "^3.10"
2727
pytest-cov = "^4.0"
28+
mypy = "^1.3"
2829

2930
[tool.pytest.ini_options]
3031
addopts = "--cov=mysql_context_manager --cov-report xml"
3132
testpaths = ["tests"]
3233

34+
[tool.ruff]
35+
exclude = [".tox"]
36+
target-version = "py38"
37+
select = [
38+
"A", # builtins
39+
"ARG", # unsued arguments
40+
"B", # bugbear
41+
"C4", # comprehensions
42+
"C90", # mccabe
43+
"COM", # commas
44+
"E", # pycodestyle
45+
"F", # pyflakes
46+
"I", # isort
47+
"N", # pep8-naming
48+
"PT", # pytest style
49+
"RUF", # ruff
50+
"SIM", # simplify
51+
"TID", # tidy imports
52+
"UP", # pyupgrade
53+
"W", # warnings
54+
]
55+
56+
[tool.ruff.isort]
57+
force-single-line = true
58+
3359
[build-system]
3460
requires = ["poetry-core>=1.0.0"]
3561
build-backend = "poetry.core.masonry.api"

src/mysql_context_manager/__init__.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
__version__ = "0.1.6"
55

6+
import contextlib
67
import json
78
from json import JSONDecodeError
89
from typing import Any
@@ -32,7 +33,7 @@ def __init__(
3233
if schema is None:
3334
schema = ""
3435
self.connection_string = f"mysql://{credentials}@{hostname}:{port}/{schema}"
35-
self.connection = None
36+
self.connection: databases.Database | None = None
3637
self.engine = None
3738

3839
async def __aenter__(self):
@@ -53,8 +54,8 @@ async def disconnect(self) -> None:
5354
async def connect(self) -> None:
5455
"""Establishes the connection to the database"""
5556
self.connection = databases.Database(self.connection_string)
56-
57-
await self.connection.connect()
57+
if self.connection is not None:
58+
await self.connection.connect()
5859

5960
async def query(self, sql_query: str, **kwargs) -> list[dict[str, Any]]:
6061
"""Queries the database
@@ -65,21 +66,24 @@ async def query(self, sql_query: str, **kwargs) -> list[dict[str, Any]]:
6566
Returns:
6667
list[dict[str, Any]]: List of rows represented in dictioary format
6768
69+
Raises:
70+
ConnectionError: in case of method call before running connect()
71+
6872
Examples:
69-
>>> query = "select username, element from users where team_name = :team_name limit 2;"
73+
>>> query = "select name, elem from users where team = :team limit 2;"
7074
>>> async with MysqlConnector(hostname="localhost") as conn:
71-
>>> print(await conn.query(query, team_name="Team Avatar"))
72-
[{"username": "Katara", "element": "water"}, {"username": "Toph", "element": "earth"}]
75+
>>> print(await conn.query(query, team="Team Avatar"))
76+
[{"name": "Katara", "elem": "water"}, {"name": "Toph", "elem": "earth"}]
7377
7478
"""
75-
result = await self.connection.fetch_all(query=sql_query, values=kwargs)
76-
result = [dict(i) for i in result]
79+
if self.connection is None:
80+
raise ConnectionError("No active connection")
81+
records = await self.connection.fetch_all(query=sql_query, values=kwargs)
82+
result = [dict(i) for i in records]
7783
for res in result:
7884
for key, val in res.items():
79-
try:
85+
with contextlib.suppress(JSONDecodeError, TypeError):
8086
res[key] = json.loads(val)
81-
except (JSONDecodeError, TypeError):
82-
pass
8387
return result
8488

8589
async def execute(self, sql_query: str, **kwargs) -> None:
@@ -88,9 +92,14 @@ async def execute(self, sql_query: str, **kwargs) -> None:
8892
Args:
8993
sql_query (str): SQL query, with placeholders as :placeholder
9094
95+
Raises:
96+
ConnectionError: in case of method call before running connect()
97+
9198
Examples:
92-
>>> query = "update users set username = :username where user_id = :user_id;"
99+
>>> query = "update users set name = :name where user_id = :user_id;"
93100
>>> async with MysqlConnector(hostname="localhost") as conn:
94-
>>> await conn.query(query, username="Truth", user_id=42)
101+
>>> await conn.query(query, name="Truth", user_id=42)
95102
"""
103+
if self.connection is None:
104+
raise ConnectionError("No active connection")
96105
await self.connection.execute(query=sql_query, values=kwargs)

tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33

44
@pytest.fixture()
5-
def mock_db(mocker):
5+
def _mock_db(mocker):
66
mocker.patch("databases.Database.connect", return_value=None)
77
mocker.patch("databases.Database.disconnect", return_value=None)
88
mocker.patch(
99
"databases.Database.fetch_all",
1010
return_value=[
11-
[("username", "Aang")],
11+
[("name", "Aang")],
1212
],
1313
)
1414
mocker.patch("databases.Database.execute", return_value=None)

0 commit comments

Comments
 (0)