Modernize to pyproject.toml and fix test assertion
- Remove requirements.txt and requirements-dev.txt (duplicates pyproject.toml) - Update Dockerfile to use 'pip install .' instead of requirements.txt - Update README.md and GitHub workflows to use 'pip install -e .[dev]' - Fix test_get_valuation_comparables: check for 'deal_date' instead of non-existent 'asset_room_num' (rooms field is optional and excluded when None due to exclude_none=True) - Fix fastmcp version constraint in pyproject.toml (>=2.13.0,<3.0.0) - Add vcrpy to dev dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -45,7 +45,7 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -r requirements-dev.txt
|
pip install -e .[dev]
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: pytest tests/ -m "not api_health" -q
|
run: pytest tests/ -m "not api_health" -q
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -r requirements-dev.txt
|
pip install -e .[dev]
|
||||||
|
|
||||||
- name: Run unit tests with coverage
|
- name: Run unit tests with coverage
|
||||||
run: |
|
run: |
|
||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -r requirements-dev.txt
|
pip install -e .[dev]
|
||||||
|
|
||||||
- name: Run black (check only)
|
- name: Run black (check only)
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+4
-4
@@ -18,16 +18,16 @@ RUN apt-get update && \
|
|||||||
gcc \
|
gcc \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy requirements first for better layer caching
|
# Copy package files for better layer caching
|
||||||
COPY requirements.txt .
|
COPY pyproject.toml .
|
||||||
|
COPY README.md .
|
||||||
|
|
||||||
# Install Python dependencies
|
# Install Python dependencies
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir .
|
||||||
|
|
||||||
# Copy application code
|
# Copy application code
|
||||||
COPY nadlan_mcp/ ./nadlan_mcp/
|
COPY nadlan_mcp/ ./nadlan_mcp/
|
||||||
COPY run_http_server.py .
|
COPY run_http_server.py .
|
||||||
COPY README.md .
|
|
||||||
|
|
||||||
# Create non-root user for security
|
# Create non-root user for security
|
||||||
RUN useradd -m -u 1000 appuser && \
|
RUN useradd -m -u 1000 appuser && \
|
||||||
|
|||||||
@@ -55,9 +55,14 @@ This project provides a comprehensive Python interface to the Israeli government
|
|||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Install required packages:**
|
4. **Install the package:**
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
|
Or for development with all dev dependencies:
|
||||||
|
```bash
|
||||||
|
pip install -e .[dev]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -298,7 +303,7 @@ python -c "import logging; logging.basicConfig(level=logging.DEBUG)" run_mcp_ser
|
|||||||
#### Troubleshooting
|
#### Troubleshooting
|
||||||
|
|
||||||
**Connection Issues:**
|
**Connection Issues:**
|
||||||
- Ensure all dependencies are installed: `pip install -r requirements.txt`
|
- Ensure all dependencies are installed: `pip install -e .`
|
||||||
- Check that Python path is correct in client configuration
|
- Check that Python path is correct in client configuration
|
||||||
- Verify the server starts without errors
|
- Verify the server starts without errors
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -26,7 +26,7 @@ dependencies = [
|
|||||||
"requests>=2.31.0",
|
"requests>=2.31.0",
|
||||||
"python-dotenv>=1.0.0",
|
"python-dotenv>=1.0.0",
|
||||||
"pydantic>=2.0.0",
|
"pydantic>=2.0.0",
|
||||||
"fastmcp>=0.1.0",
|
"fastmcp>=2.13.0,<3.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
@@ -39,6 +39,7 @@ dev = [
|
|||||||
"mypy>=1.5.0",
|
"mypy>=1.5.0",
|
||||||
"pre-commit>=3.4.0",
|
"pre-commit>=3.4.0",
|
||||||
"types-requests>=2.31.0",
|
"types-requests>=2.31.0",
|
||||||
|
"vcrpy>=4.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# Development dependencies for nadlan-mcp
|
|
||||||
# Install with: pip install -r requirements-dev.txt
|
|
||||||
-r requirements.txt
|
|
||||||
|
|
||||||
# Testing
|
|
||||||
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 - 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
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
requests>=2.31.0,<3.0.0
|
|
||||||
python-dotenv>=1.0.0,<2.0.0
|
|
||||||
mcp>=1.0.0,<2.0.0
|
|
||||||
fastmcp>=0.1.0,<1.0.0
|
|
||||||
pydantic>=2.0.0,<3.0.0
|
|
||||||
uvicorn>=0.27.0,<1.0.0
|
|
||||||
+10
-14
@@ -8,16 +8,17 @@ enabling deployment to cloud platforms like Render, Railway, or Docker container
|
|||||||
For local Claude Desktop integration, use run_fastmcp_server.py (stdio transport) instead.
|
For local Claude Desktop integration, use run_fastmcp_server.py (stdio transport) instead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from nadlan_mcp.fastmcp_server import mcp
|
from nadlan_mcp.fastmcp_server import mcp
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ def main():
|
|||||||
logger.info("=" * 60)
|
logger.info("=" * 60)
|
||||||
logger.info("Starting Nadlan-MCP HTTP Server")
|
logger.info("Starting Nadlan-MCP HTTP Server")
|
||||||
logger.info("=" * 60)
|
logger.info("=" * 60)
|
||||||
logger.info(f"Transport: HTTP (via uvicorn)")
|
logger.info("Transport: HTTP (via uvicorn)")
|
||||||
logger.info(f"Host: {host}")
|
logger.info(f"Host: {host}")
|
||||||
logger.info(f"Port: {port}")
|
logger.info(f"Port: {port}")
|
||||||
logger.info(f"MCP Endpoint: http://{host}:{port}/mcp")
|
logger.info(f"MCP Endpoint: http://{host}:{port}/mcp")
|
||||||
@@ -41,15 +42,15 @@ def main():
|
|||||||
try:
|
try:
|
||||||
# Get the HTTP ASGI app from FastMCP
|
# Get the HTTP ASGI app from FastMCP
|
||||||
# Try different possible method names based on FastMCP version
|
# Try different possible method names based on FastMCP version
|
||||||
if hasattr(mcp, 'streamable_http_app'):
|
if hasattr(mcp, "streamable_http_app"):
|
||||||
app = mcp.streamable_http_app()
|
app = mcp.streamable_http_app()
|
||||||
elif hasattr(mcp, 'http_app'):
|
elif hasattr(mcp, "http_app"):
|
||||||
app = mcp.http_app()
|
app = mcp.http_app()
|
||||||
elif hasattr(mcp, 'get_app'):
|
elif hasattr(mcp, "get_app"):
|
||||||
app = mcp.get_app()
|
app = mcp.get_app()
|
||||||
else:
|
else:
|
||||||
# Fallback: try to access the app directly
|
# Fallback: try to access the app directly
|
||||||
app = getattr(mcp, 'app', None)
|
app = getattr(mcp, "app", None)
|
||||||
if app is None:
|
if app is None:
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
"FastMCP instance has no HTTP app method. "
|
"FastMCP instance has no HTTP app method. "
|
||||||
@@ -59,12 +60,7 @@ def main():
|
|||||||
logger.info(f"Using app: {type(app).__name__}")
|
logger.info(f"Using app: {type(app).__name__}")
|
||||||
|
|
||||||
# Run with uvicorn
|
# Run with uvicorn
|
||||||
uvicorn.run(
|
uvicorn.run(app, host=host, port=port, log_level="info")
|
||||||
app,
|
|
||||||
host=host,
|
|
||||||
port=port,
|
|
||||||
log_level="info"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to start HTTP server: {e}", exc_info=True)
|
logger.error(f"Failed to start HTTP server: {e}", exc_info=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@@ -96,7 +96,9 @@ class TestMCPToolsE2E:
|
|||||||
assert "comparables" in data
|
assert "comparables" in data
|
||||||
comp = data["comparables"][0]
|
comp = data["comparables"][0]
|
||||||
assert "deal_amount" in comp
|
assert "deal_amount" in comp
|
||||||
assert "asset_room_num" in comp
|
# rooms field is optional and excluded when None
|
||||||
|
# Just verify the comparable has basic required fields
|
||||||
|
assert "deal_date" in comp
|
||||||
|
|
||||||
def test_get_deal_statistics(self):
|
def test_get_deal_statistics(self):
|
||||||
"""Test deal statistics calculation."""
|
"""Test deal statistics calculation."""
|
||||||
|
|||||||
Reference in New Issue
Block a user