Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions .github/scripts/increment_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,13 @@ def extract_version(pyproject_content: str):
return VersionLine(old_line=version_line, version_str=version_part)


def increment_version_at_pyproject(
pyproject_path: str, inc_type: str, with_beta: bool
) -> str:
def increment_version_at_pyproject(pyproject_path: str, inc_type: str, with_beta: bool) -> str:
with open(pyproject_path, "rt") as f:
setup_content = f.read()

version = extract_version(setup_content)
version.increment(inc_type, with_beta)
setup_content = setup_content.replace(
version.old_line, version.version_line_with_mark()
)
setup_content = setup_content.replace(version.old_line, version.version_line_with_mark())

with open(pyproject_path, "w") as f:
f.write(setup_content)
Expand Down Expand Up @@ -143,9 +139,7 @@ def main():
help="increment version type: patch or minor",
choices=["minor", "patch"],
)
parser.add_argument(
"--beta", choices=["true", "false"], help="is beta version"
)
parser.add_argument("--beta", choices=["true", "false"], help="is beta version")
parser.add_argument(
"--changelog-path",
default=DEFAULT_CHANGELOG_PATH,
Expand All @@ -158,13 +152,11 @@ def main():

is_beta = args.beta == "true"

new_version = increment_version_at_pyproject(
args.pyproject_path, args.inc_type, is_beta
)
new_version = increment_version_at_pyproject(args.pyproject_path, args.inc_type, is_beta)
add_changelog_version(args.changelog_path, new_version)
set_version_in_version_file(DEFAULT_YDB_VERSION_FILE, new_version)
print(new_version)


if __name__ == "__main__":
main()
main()
26 changes: 26 additions & 0 deletions .github/workflows/run-linters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Run Linters

on:
push:
branches:
- '**'
pull_request_target:
branches:
- '**'
workflow_dispatch:

jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.13'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- name: Run linters
run: make lint
1 change: 0 additions & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Run tests
run: make test
10 changes: 3 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,17 @@ run-server:

# Run lint checks
lint: dev
flake8 ydb_mcp tests
ruff check ydb_mcp tests
mypy ydb_mcp
black --check ydb_mcp tests
isort --check-only --profile black ydb_mcp tests

# Format code
format: dev
black ydb_mcp tests
isort --profile black ydb_mcp tests
ruff format ydb_mcp tests

# Install package
install:
pip install -e .

# Install development dependencies
dev:
pip install -e ".[dev]"
pip install -r requirements-dev.txt
pip install -e ".[dev]"
35 changes: 23 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,35 @@ dependencies = [

[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"black>=22.0.0",
"isort>=5.0.0",
"mypy>=0.9.0",
"pytest>=7.3.1",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
"pytest-assume>=2.4.3",
"mypy>=1.3.0",
"ruff>=0.11.0",
"docker>=7.0.0",
]

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

[tool.black]
line-length = 100
target-version = ["py38"]
[tool.ruff]
line-length = 121
target-version = "py310"

[tool.isort]
profile = "black"
line_length = 100
[tool.ruff.lint]
select = [
"E", # pycodestyle
"F", # pyflakes
"I", # isort
# TODO: extend with more rules
]

[tool.mypy]
python_version = "3.8"
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
warn_unused_configs = true

[[tool.mypy.overrides]]
module = "ydb.*"
ignore_missing_imports = true
5 changes: 1 addition & 4 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ pytest>=7.3.1
pytest-asyncio>=0.21.0
pytest-cov>=4.1.0
pytest-assume>=2.4.3
black>=23.3.0
isort>=5.12.0
mypy>=1.3.0
flake8>=6.0.0
httpx>=0.24.0
ruff>=0.11.0
docker>=7.0.0 # For YDB Docker container management in tests
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Pytest configuration for testing YDB MCP server."""

import os
from unittest.mock import AsyncMock, MagicMock, patch
from unittest.mock import AsyncMock, patch

import pytest

Expand Down
1 change: 0 additions & 1 deletion tests/docker_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import os
import platform
import socket
import time

Expand Down
3 changes: 1 addition & 2 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from urllib.parse import urlparse

import pytest
import ydb

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


@pytest.fixture(scope="function")
async def mcp_server(session_mcp_server):
async def mcp_server(session_mcp_server): # noqa: F811
"""Provide a clean MCP server connection for each test by restarting the connection."""
if session_mcp_server is None:
pytest.fail("Could not get a valid MCP server instance")
Expand Down
24 changes: 6 additions & 18 deletions tests/integration/test_authentication_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
from ydb_mcp.server import AUTH_MODE_ANONYMOUS, AUTH_MODE_LOGIN_PASSWORD

# Suppress the utcfromtimestamp deprecation warning from the YDB library
warnings.filterwarnings(
"ignore", message="datetime.datetime.utcfromtimestamp.*", category=DeprecationWarning
)
warnings.filterwarnings("ignore", message="datetime.datetime.utcfromtimestamp.*", category=DeprecationWarning)

# Table name used for tests - using timestamp to avoid conflicts
TEST_TABLE = f"mcp_integration_test_{int(time.time())}"
Expand Down Expand Up @@ -58,12 +56,7 @@ async def test_login_password_authentication(mcp_server):
# Verify we can execute a query
result = await call_mcp_tool(mcp_server, "ydb_query", sql="SELECT 1+1 as result")
# Parse the JSON from the 'text' field if present
if (
isinstance(result, list)
and len(result) > 0
and isinstance(result[0], dict)
and "text" in result[0]
):
if isinstance(result, list) and len(result) > 0 and isinstance(result[0], dict) and "text" in result[0]:
parsed = json.loads(result[0]["text"])
else:
parsed = result
Expand All @@ -80,12 +73,7 @@ async def test_login_password_authentication(mcp_server):
# Query should fail with auth error
result = await call_mcp_tool(mcp_server, "ydb_query", sql="SELECT 1+1 as result")
# Parse the JSON from the 'text' field if present
if (
isinstance(result, list)
and len(result) > 0
and isinstance(result[0], dict)
and "text" in result[0]
):
if isinstance(result, list) and len(result) > 0 and isinstance(result[0], dict) and "text" in result[0]:
parsed = json.loads(result[0]["text"])
else:
parsed = result
Expand All @@ -111,9 +99,9 @@ async def test_login_password_authentication(mcp_server):
# Allow empty error message as valid
pass
else:
assert any(
keyword in error_msg for keyword in all_keywords
), f"Unexpected error message: {parsed.get('error')}"
assert any(keyword in error_msg for keyword in all_keywords), (
f"Unexpected error message: {parsed.get('error')}"
)

finally:
# Switch back to anonymous auth to clean up (fixture will handle final state reset)
Expand Down
Loading