Skip to content

Commit a975550

Browse files
authored
Merge pull request #4 from ydb-platform/enable_linters
Change linters to Ruff and add CI job
2 parents 8c66b94 + 2e4d2b0 commit a975550

23 files changed

+356
-578
lines changed

.github/scripts/increment_version.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,13 @@ def extract_version(pyproject_content: str):
9797
return VersionLine(old_line=version_line, version_str=version_part)
9898

9999

100-
def increment_version_at_pyproject(
101-
pyproject_path: str, inc_type: str, with_beta: bool
102-
) -> str:
100+
def increment_version_at_pyproject(pyproject_path: str, inc_type: str, with_beta: bool) -> str:
103101
with open(pyproject_path, "rt") as f:
104102
setup_content = f.read()
105103

106104
version = extract_version(setup_content)
107105
version.increment(inc_type, with_beta)
108-
setup_content = setup_content.replace(
109-
version.old_line, version.version_line_with_mark()
110-
)
106+
setup_content = setup_content.replace(version.old_line, version.version_line_with_mark())
111107

112108
with open(pyproject_path, "w") as f:
113109
f.write(setup_content)
@@ -143,9 +139,7 @@ def main():
143139
help="increment version type: patch or minor",
144140
choices=["minor", "patch"],
145141
)
146-
parser.add_argument(
147-
"--beta", choices=["true", "false"], help="is beta version"
148-
)
142+
parser.add_argument("--beta", choices=["true", "false"], help="is beta version")
149143
parser.add_argument(
150144
"--changelog-path",
151145
default=DEFAULT_CHANGELOG_PATH,
@@ -158,13 +152,11 @@ def main():
158152

159153
is_beta = args.beta == "true"
160154

161-
new_version = increment_version_at_pyproject(
162-
args.pyproject_path, args.inc_type, is_beta
163-
)
155+
new_version = increment_version_at_pyproject(args.pyproject_path, args.inc_type, is_beta)
164156
add_changelog_version(args.changelog_path, new_version)
165157
set_version_in_version_file(DEFAULT_YDB_VERSION_FILE, new_version)
166158
print(new_version)
167159

168160

169161
if __name__ == "__main__":
170-
main()
162+
main()

.github/workflows/run-linters.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Run Linters
2+
3+
on:
4+
push:
5+
branches:
6+
- '**'
7+
pull_request_target:
8+
branches:
9+
- '**'
10+
workflow_dispatch:
11+
12+
jobs:
13+
lint:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
- name: Set up Python
19+
uses: actions/setup-python@v4
20+
with:
21+
python-version: '3.13'
22+
- name: Install dependencies
23+
run: |
24+
python -m pip install --upgrade pip
25+
- name: Run linters
26+
run: make lint

.github/workflows/run-tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,5 @@ jobs:
2222
- name: Install dependencies
2323
run: |
2424
python -m pip install --upgrade pip
25-
pip install -r requirements-dev.txt
2625
- name: Run tests
2726
run: make test

Makefile

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,17 @@ run-server:
4343

4444
# Run lint checks
4545
lint: dev
46-
flake8 ydb_mcp tests
46+
ruff check ydb_mcp tests
4747
mypy ydb_mcp
48-
black --check ydb_mcp tests
49-
isort --check-only --profile black ydb_mcp tests
5048

5149
# Format code
5250
format: dev
53-
black ydb_mcp tests
54-
isort --profile black ydb_mcp tests
51+
ruff format ydb_mcp tests
5552

5653
# Install package
5754
install:
5855
pip install -e .
5956

6057
# Install development dependencies
6158
dev:
62-
pip install -e ".[dev]"
63-
pip install -r requirements-dev.txt
59+
pip install -e ".[dev]"

pyproject.toml

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,35 @@ dependencies = [
2727

2828
[project.optional-dependencies]
2929
dev = [
30-
"pytest>=7.0.0",
31-
"black>=22.0.0",
32-
"isort>=5.0.0",
33-
"mypy>=0.9.0",
30+
"pytest>=7.3.1",
31+
"pytest-asyncio>=0.21.0",
32+
"pytest-cov>=4.1.0",
33+
"pytest-assume>=2.4.3",
34+
"mypy>=1.3.0",
35+
"ruff>=0.11.0",
36+
"docker>=7.0.0",
3437
]
3538

3639
[project.scripts]
3740
ydb-mcp = "ydb_mcp.__main__:main"
3841

39-
[tool.black]
40-
line-length = 100
41-
target-version = ["py38"]
42+
[tool.ruff]
43+
line-length = 121
44+
target-version = "py310"
4245

43-
[tool.isort]
44-
profile = "black"
45-
line_length = 100
46+
[tool.ruff.lint]
47+
select = [
48+
"E", # pycodestyle
49+
"F", # pyflakes
50+
"I", # isort
51+
# TODO: extend with more rules
52+
]
4653

4754
[tool.mypy]
48-
python_version = "3.8"
55+
python_version = "3.10"
4956
warn_return_any = true
50-
warn_unused_configs = true
57+
warn_unused_configs = true
58+
59+
[[tool.mypy.overrides]]
60+
module = "ydb.*"
61+
ignore_missing_imports = true

requirements-dev.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ pytest>=7.3.1
33
pytest-asyncio>=0.21.0
44
pytest-cov>=4.1.0
55
pytest-assume>=2.4.3
6-
black>=23.3.0
7-
isort>=5.12.0
86
mypy>=1.3.0
9-
flake8>=6.0.0
10-
httpx>=0.24.0
7+
ruff>=0.11.0
118
docker>=7.0.0 # For YDB Docker container management in tests

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Pytest configuration for testing YDB MCP server."""
22

33
import os
4-
from unittest.mock import AsyncMock, MagicMock, patch
4+
from unittest.mock import AsyncMock, patch
55

66
import pytest
77

tests/docker_utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import logging
22
import os
3-
import platform
43
import socket
54
import time
65

tests/integration/conftest.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from urllib.parse import urlparse
1616

1717
import pytest
18-
import ydb
1918

2019
from tests.docker_utils import start_ydb_container, stop_container, wait_for_port
2120
from ydb_mcp.server import AUTH_MODE_ANONYMOUS, YDBMCPServer
@@ -279,7 +278,7 @@ async def session_mcp_server(ydb_server):
279278

280279

281280
@pytest.fixture(scope="function")
282-
async def mcp_server(session_mcp_server):
281+
async def mcp_server(session_mcp_server): # noqa: F811
283282
"""Provide a clean MCP server connection for each test by restarting the connection."""
284283
if session_mcp_server is None:
285284
pytest.fail("Could not get a valid MCP server instance")

tests/integration/test_authentication_integration.py

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
from ydb_mcp.server import AUTH_MODE_ANONYMOUS, AUTH_MODE_LOGIN_PASSWORD
1515

1616
# Suppress the utcfromtimestamp deprecation warning from the YDB library
17-
warnings.filterwarnings(
18-
"ignore", message="datetime.datetime.utcfromtimestamp.*", category=DeprecationWarning
19-
)
17+
warnings.filterwarnings("ignore", message="datetime.datetime.utcfromtimestamp.*", category=DeprecationWarning)
2018

2119
# Table name used for tests - using timestamp to avoid conflicts
2220
TEST_TABLE = f"mcp_integration_test_{int(time.time())}"
@@ -58,12 +56,7 @@ async def test_login_password_authentication(mcp_server):
5856
# Verify we can execute a query
5957
result = await call_mcp_tool(mcp_server, "ydb_query", sql="SELECT 1+1 as result")
6058
# Parse the JSON from the 'text' field if present
61-
if (
62-
isinstance(result, list)
63-
and len(result) > 0
64-
and isinstance(result[0], dict)
65-
and "text" in result[0]
66-
):
59+
if isinstance(result, list) and len(result) > 0 and isinstance(result[0], dict) and "text" in result[0]:
6760
parsed = json.loads(result[0]["text"])
6861
else:
6962
parsed = result
@@ -80,12 +73,7 @@ async def test_login_password_authentication(mcp_server):
8073
# Query should fail with auth error
8174
result = await call_mcp_tool(mcp_server, "ydb_query", sql="SELECT 1+1 as result")
8275
# Parse the JSON from the 'text' field if present
83-
if (
84-
isinstance(result, list)
85-
and len(result) > 0
86-
and isinstance(result[0], dict)
87-
and "text" in result[0]
88-
):
76+
if isinstance(result, list) and len(result) > 0 and isinstance(result[0], dict) and "text" in result[0]:
8977
parsed = json.loads(result[0]["text"])
9078
else:
9179
parsed = result
@@ -111,9 +99,9 @@ async def test_login_password_authentication(mcp_server):
11199
# Allow empty error message as valid
112100
pass
113101
else:
114-
assert any(
115-
keyword in error_msg for keyword in all_keywords
116-
), f"Unexpected error message: {parsed.get('error')}"
102+
assert any(keyword in error_msg for keyword in all_keywords), (
103+
f"Unexpected error message: {parsed.get('error')}"
104+
)
117105

118106
finally:
119107
# Switch back to anonymous auth to clean up (fixture will handle final state reset)

0 commit comments

Comments
 (0)