Skip to content
Open
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
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ jobs:
run: uv sync --all-groups --frozen

- name: Ruff lint
run: uv run ruff check .
run: uv run ruff check --output-format=github .

- name: Ty type check
run: uv run ty check src/

- name: Pytest
run: uv run pytest
run: uv run pytest --cov-report=xml

- name: Upload coverage
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
fail_ci_if_error: false
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.PHONY: dev lint format test build clean

dev:
uv sync --all-groups

lint:
uv run ruff format --check . && uv run ruff check . && uv run ty check src/

format:
uv run ruff format .

test:
uv run pytest

test-fast:
uv run pytest -x -q --no-cov

build:
uv build

clean:
rm -rf dist/ build/ *.egg-info/ .pytest_cache/ .coverage htmlcov/
80 changes: 77 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,99 @@ lint = [
]
test = [
"pytest>=9.0.2",
"pytest-cov>=6.0",
]
dev = [
{ include-group = "lint" },
{ include-group = "test" },
]

[tool.uv]
default-groups = ["dev"]

[tool.ruff]
line-length = 100
target-version = "py311"
src = ["src"]

[tool.ruff.lint]
select = ["E", "F", "W", "I", "B", "UP"]
select = ["ALL"]
ignore = [
"D", # pydocstyle (docstrings)
"COM812", # missing trailing comma (conflicts with formatter)
"ISC001", # single-line implicit string concat (conflicts with formatter)
"TC", # type-checking imports (too strict for this project)
"TD002", # missing TODO author
"TD003", # missing TODO link
"FIX002", # line contains TODO
"TRY003", # long exception messages (too strict for CLI apps)
"EM101", # exception string literal (too strict)
"EM102", # exception f-string (too strict)
"ANN401", # Any type disallowed (sometimes necessary)
"PLR0915", # too many statements (refactor later)
"PLR0911", # too many return statements (acceptable for parsing)
"PLR2004", # magic value comparison (too strict)
"PLC0415", # import not at top level (intentional for optional deps)
"PTH", # pathlib enforcement (would require full refactor)
"RUF001", # ambiguous unicode (en dash is intentional)
"PLW2901", # loop variable overwritten (common pattern)
"S310", # URL open audit (handled at call site)
"FBT", # boolean trap (acceptable for tool APIs)
]

[tool.ruff.lint.per-file-ignores]
"src/different_agent/agents.py" = ["E501"]
"src/different_agent/report.py" = ["E501"]
"tests/**/*.py" = [
"S101", # assert allowed in tests
"S603", # subprocess call (test helper)
"PLR2004", # magic values allowed in tests
"ANN", # type annotations optional in tests
"INP001", # implicit namespace package
]
"src/different_agent/agents.py" = [
"E501", # long lines in prompt strings
]
"src/different_agent/report.py" = [
"E501", # long lines in HTML template
"PERF401", # for loop more readable than comprehension for HTML generation
]
"src/different_agent/git_tools.py" = [
"S603", # subprocess.run with trusted git commands
]
"src/different_agent/github_tools.py" = [
"BLE001", # broad exceptions for robust API wrappers
]
"src/different_agent/config.py" = [
"TRY004", # ValueError is appropriate for config parsing
"FBT001", # boolean default args in config helpers
]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
docstring-code-format = true

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
addopts = [
"-ra",
"--strict-markers",
"--strict-config",
"--cov=different_agent",
"--cov-report=term-missing",
"--cov-fail-under=0",
]

[tool.coverage.run]
branch = true
source = ["src/different_agent"]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"if __name__ == .__main__.:",
]

[tool.ty.environment]
python-version = "3.11"
4 changes: 2 additions & 2 deletions src/different_agent/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class TargetAssessmentsResponse(BaseModel):
"""


def create_inspiration_agent(model: BaseChatModel, cache: BaseCache | None = None):
def create_inspiration_agent(model: BaseChatModel, cache: BaseCache | None = None) -> Any:
return create_deep_agent(
model=model,
tools=[
Expand All @@ -210,7 +210,7 @@ def create_inspiration_agent(model: BaseChatModel, cache: BaseCache | None = Non
)


def create_target_agent(model: BaseChatModel, cache: BaseCache | None = None):
def create_target_agent(model: BaseChatModel, cache: BaseCache | None = None) -> Any:
return create_deep_agent(
model=model,
tools=[git_grep, git_show_file],
Expand Down
6 changes: 3 additions & 3 deletions src/different_agent/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import logging
import os
from pathlib import Path
from typing import Any
from typing import Any, ClassVar

from dotenv import load_dotenv
from langchain_core.callbacks import get_usage_metadata_callback
Expand All @@ -20,14 +20,14 @@


class _ColorFormatter(logging.Formatter):
_COLORS = {
_COLORS: ClassVar[dict[int, str]] = {
logging.DEBUG: "\x1b[36m",
logging.INFO: "\x1b[32m",
logging.WARNING: "\x1b[33m",
logging.ERROR: "\x1b[31m",
logging.CRITICAL: "\x1b[35m",
}
_RESET = "\x1b[0m"
_RESET: ClassVar[str] = "\x1b[0m"

def format(self, record: logging.LogRecord) -> str:
original_level = record.levelname
Expand Down
4 changes: 2 additions & 2 deletions src/different_agent/github_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _github_request_json(url: str) -> Any:
headers["Authorization"] = f"Bearer {token}"

req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req, timeout=30) as resp: # noqa: S310
with urllib.request.urlopen(req, timeout=30) as resp:
payload = resp.read().decode("utf-8")
return json.loads(payload)

Expand Down Expand Up @@ -189,7 +189,7 @@ def github_recent_prs(
date_str = merged_at or updated_at
if isinstance(date_str, str):
try:
dt = datetime.fromisoformat(date_str.replace("Z", "+00:00"))
dt = datetime.fromisoformat(date_str)
except ValueError:
dt = None
if dt is not None and dt < threshold:
Expand Down
Loading
Loading