diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..8af8ef3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,68 @@ +# Pre-commit hooks for code quality +# Install: pre-commit install +# Run manually: pre-commit run --all-files +# Update hooks: pre-commit autoupdate + +repos: + # Ruff - Fast Python linter and formatter (replaces black, isort, flake8) + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.0 # Use latest version + hooks: + # Run the linter + - id: ruff + args: [--fix] + types_or: [python, pyi] + + # Run the formatter + - id: ruff-format + types_or: [python, pyi] + + # Mypy - Static type checker (disabled for now - needs type annotation fixes) + # - repo: https://github.com/pre-commit/mirrors-mypy + # rev: v1.11.0 # Use latest version + # hooks: + # - id: mypy + # additional_dependencies: + # - types-requests + # - pydantic>=2.0.0 + # args: [--config-file=pyproject.toml] + # exclude: ^tests/ + + # Pre-commit hooks for general file quality + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + # File formatting + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-json + - id: check-toml + - id: check-added-large-files + args: [--maxkb=500] + + # Code quality + - id: check-ast # Validate Python syntax + - id: check-merge-conflict + - id: debug-statements # Check for debugger imports + + # Security + - id: detect-private-key + + # Check for common security issues (disabled for now - needs baseline configuration) + # - repo: https://github.com/PyCQA/bandit + # rev: 1.7.9 + # hooks: + # - id: bandit + # args: [-c, pyproject.toml] + # exclude: ^tests/ + +# CI skip: Set to false to run hooks in CI +ci: + autofix_commit_msg: | + [pre-commit.ci] auto fixes from pre-commit hooks + autofix_prs: true + autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate' + autoupdate_schedule: weekly + skip: [] + submodules: false diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7c15f02 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,169 @@ +[project] +name = "nadlan-mcp" +version = "2.0.0" +description = "Israeli Real Estate MCP Server" +readme = "README.md" +requires-python = ">=3.7" +license = {text = "MIT"} +authors = [ + {name = "Nadlan MCP Contributors"} +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] + +dependencies = [ + "requests>=2.31.0", + "python-dotenv>=1.0.0", + "pydantic>=2.0.0", + "fastmcp>=0.1.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.4.0", + "pytest-cov>=4.1.0", + "pytest-mock>=3.11.1", + "pytest-anyio>=0.0.0", + "ruff>=0.1.0", + "mypy>=1.5.0", + "pre-commit>=3.4.0", + "types-requests>=2.31.0", +] + +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +# Ruff configuration +[tool.ruff] +line-length = 100 +target-version = "py37" + +# Exclude directories +exclude = [ + ".git", + ".mypy_cache", + ".pytest_cache", + ".ruff_cache", + ".venv", + "venv", + "__pycache__", + "build", + "dist", + "*.egg-info", +] + +[tool.ruff.lint] +# Enable specific rule sets +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort (import sorting) + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "UP", # pyupgrade + "SIM", # flake8-simplify +] + +# Ignore specific rules +ignore = [ + "E501", # line too long (handled by formatter) + "B008", # do not perform function calls in argument defaults + "B904", # raise from exceptions + "SIM108", # use ternary operator (sometimes less readable) +] + +# Allow autofix for all enabled rules +fixable = ["ALL"] +unfixable = [] + +# Per-file ignores +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] # Allow unused imports in __init__.py +"tests/**/*.py" = ["S101"] # Allow assert in tests + +[tool.ruff.lint.isort] +known-first-party = ["nadlan_mcp"] +force-sort-within-sections = true + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" + +# Mypy configuration +[tool.mypy] +python_version = "3.10" +warn_return_any = true +warn_unused_configs = true +disallow_untyped_defs = false # Gradual typing - start permissive +check_untyped_defs = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +warn_no_return = true +warn_unreachable = true +strict_equality = true +pretty = true + +# Per-module options +[[tool.mypy.overrides]] +module = "tests.*" +disallow_untyped_defs = false + +[[tool.mypy.overrides]] +module = "fastmcp.*" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "mcp.*" +ignore_missing_imports = true + +# Pytest configuration +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = ["test_*.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] +addopts = "-ra -q --strict-markers" +markers = [ + "unit: fast unit tests (default)", + "integration: slow integration tests requiring real API calls", + "api_health: weekly API health check tests (run separately)", +] + +# Coverage configuration +[tool.coverage.run] +source = ["nadlan_mcp"] +omit = [ + "tests/*", + "nadlan_mcp/__pycache__/*", + "*/site-packages/*", +] + +[tool.coverage.report] +precision = 2 +show_missing = true +skip_covered = false +exclude_lines = [ + "pragma: no cover", + "def __repr__", + "if TYPE_CHECKING:", + "raise AssertionError", + "raise NotImplementedError", + "if __name__ == .__main__.:", + "@abstractmethod", +] diff --git a/requirements-dev.txt b/requirements-dev.txt index 7edc20b..2fc9f64 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,19 +1,19 @@ -# Development dependencies +# Development dependencies for nadlan-mcp +# Install with: pip install -r requirements-dev.txt -r requirements.txt # Testing -pytest>=7.0.0,<8.0.0 -pytest-cov>=4.0.0,<5.0.0 -pytest-mock>=3.10.0,<4.0.0 -vcrpy>=4.2.0,<5.0.0 +pytest>=7.4.0,<9.0.0 +pytest-cov>=4.1.0,<6.0.0 +pytest-mock>=3.11.1,<4.0.0 +pytest-anyio>=0.0.0,<1.0.0 +vcrpy>=5.1.0,<7.0.0 -# Code quality -black>=23.0.0,<24.0.0 -isort>=5.12.0,<6.0.0 -flake8>=6.0.0,<7.0.0 -mypy>=1.0.0,<2.0.0 -pre-commit>=3.0.0,<4.0.0 +# Code Quality - Using Ruff (replaces black, isort, flake8) +ruff>=0.6.0,<1.0.0 +mypy>=1.11.0,<2.0.0 +pre-commit>=3.8.0,<4.0.0 +bandit>=1.7.9,<2.0.0 # Type stubs types-requests>=2.31.0,<3.0.0 -