Skip to content
Closed
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
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Re-run pre-commit to verify clean
run: uv run pre-commit run --all-files

- name: Run pyright
- name: Run pre-push checks (pyright, vulture)
run: SKIP=pytest uv run pre-commit run --all-files --hook-stage pre-push

# If PR is from a fork, fail on any diff
Expand All @@ -54,5 +54,5 @@ jobs:
- name: Run pre-commit checks
run: uv run pre-commit run --all-files --show-diff-on-failure

- name: Run pyright
- name: Run pre-push checks (pyright, vulture)
run: SKIP=pytest uv run pre-commit run --all-files --hook-stage pre-push
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ repos:
pass_filenames: false
stages: [pre-push]

- id: vulture
name: vulture
entry: uv run vulture
language: system
types: [python]
pass_filenames: false
stages: [pre-push]

- id: pytest
name: pytest
entry: uv run pytest tests/ -x -q
Expand Down
23 changes: 1 addition & 22 deletions gittensor/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from datetime import datetime, timezone
from enum import Enum
from math import prod
from typing import TYPE_CHECKING, DefaultDict, Dict, List, Optional, Set, Tuple
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple

import bittensor as bt

Expand Down Expand Up @@ -112,21 +112,6 @@ def is_test_file(self) -> bool:

return any(re.search(pattern, basename) for pattern in test_patterns)

@classmethod
def from_github_response(cls, pr_number: int, repository_full_name: str, file_diff: DefaultDict) -> 'FileChange':
"""Create FileChange from GitHub API response"""
return cls(
pr_number=pr_number,
repository_full_name=repository_full_name,
filename=file_diff['filename'],
changes=file_diff['changes'],
additions=file_diff['additions'],
deletions=file_diff['deletions'],
status=file_diff['status'],
patch=file_diff.get('patch'),
previous_filename=file_diff.get('previous_filename'),
)


@dataclass
class Issue:
Expand Down Expand Up @@ -193,8 +178,6 @@ class PullRequest:
review_quality_multiplier: float = 1.0 # Penalty for CHANGES_REQUESTED reviews from maintainers
label_multiplier: float = 1.0 # Multiplier resolved from repository label config
label: Optional[str] = None # Resolved scoring label, set during scoring
current_labels: frozenset[str] = field(default_factory=frozenset)
label_timeline_order: tuple[str, ...] = field(default_factory=tuple) # Newest current labels first
changes_requested_count: int = 0 # Number of maintainer CHANGES_REQUESTED reviews
earned_score: float = 0.0
collateral_score: float = 0.0 # For OPEN PRs: potential_score * collateral_percent
Expand All @@ -220,10 +203,6 @@ class PullRequest:
head_ref_oid: Optional[str] = None
base_ref_oid: Optional[str] = None

def set_file_changes(self, file_changes: List[FileChange]) -> None:
"""Set the file changes for this pull request"""
self.file_changes = file_changes

def is_pioneer_eligible(self) -> bool:
"""Check if this PR qualifies for pioneer consideration.

Expand Down
2 changes: 1 addition & 1 deletion gittensor/cli/issue_commands/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def validate_bounty_amount(bounty: str) -> int:
param_hint='--bounty',
)

sign, digits, exponent = d.as_tuple()
_sign, _digits, exponent = d.as_tuple()
decimal_places = max(0, -int(exponent))
if decimal_places > ALPHA_DECIMALS:
raise click.BadParameter(
Expand Down
2 changes: 0 additions & 2 deletions gittensor/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
GRAPHQL_VIEWER_QUERY = '{ viewer { login } }'
# 1MB max file size for github api file fetches. Files exceeding this get no score.
MAX_FILE_SIZE_BYTES = 1_000_000
# Too many object lookups in one GraphQL query can trigger 502 errors and lose all results.
MAX_FILES_PER_GRAPHQL_BATCH = 50

# =============================================================================
# das-github-mirror (https://mirror.gittensor.io)
Expand Down
6 changes: 0 additions & 6 deletions gittensor/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@
"""

import os
from typing import Dict


def backoff_seconds(attempt: int, base: int = 5, cap: int = 30) -> int:
return min(base * (2**attempt), cap)


def parse_repo_name(repo_data: Dict):
"""Normalizes and converts repository name from dict"""
return f'{repo_data["owner"]["login"]}/{repo_data["name"]}'.lower()


def get_contract_address() -> str:
"""Get contract address. Override via CONTRACT_ADDRESS env var for dev/testing.

Expand Down
12 changes: 0 additions & 12 deletions gittensor/validator/utils/datetime_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
from datetime import datetime, timezone
from typing import Optional

import pytz

from gittensor.constants import (
SECONDS_PER_HOUR,
TIME_DECAY_GRACE_PERIOD_HOURS,
Expand All @@ -12,8 +10,6 @@
TIME_DECAY_SIGMOID_STEEPNESS_SCALAR,
)

CHICAGO_TZ = pytz.timezone('America/Chicago')


def parse_github_iso_to_utc(timestamp_str: str) -> datetime:
"""Parse a GitHub-style ISO 8601 string to a timezone-aware UTC datetime.
Expand All @@ -39,14 +35,6 @@ def parse_optional_github_iso_to_utc(value: Optional[str]) -> Optional[datetime]
return parse_github_iso_to_utc(value) if value else None


def parse_github_timestamp_to_cst(timestamp_str: str) -> datetime:
"""
Parse GitHub's ISO format timestamp and convert to Chicago timezone.
GitHub returns timestamps like: 2024-01-15T10:30:00Z
"""
return parse_github_iso_to_utc(timestamp_str).astimezone(CHICAGO_TZ)


def calculate_time_decay(merged_at: datetime) -> float:
"""Calculate sigmoid-based time decay multiplier from a merge timestamp."""
now = datetime.now(timezone.utc)
Expand Down
1 change: 0 additions & 1 deletion neurons/base/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ def __init__(self, config=None):
self.should_exit: bool = False
self.is_running: bool = False
self.thread: Union[threading.Thread, None] = None
self.lock = asyncio.Lock()

def serve_axon(self):
"""Serve axon to enable external connections."""
Expand Down
63 changes: 63 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dev = [
"pyright",
"ruff==0.14.10",
"pre-commit>=4.0",
"vulture==2.16",
]
debug = [
"debugpy==1.8.11",
Expand Down Expand Up @@ -55,3 +56,65 @@ quote-style = "single"

[tool.pytest.ini_options]
testpaths = ["tests"]

[tool.vulture]
# Dead-code scanner. Run via pre-push hook (`uv run vulture`) or directly.
# False positives live in `vulture_whitelist.py`; framework-driven names are
# matched here so individual call sites don't need annotation.
paths = ["gittensor", "neurons", "scripts", "tests"]
exclude = [
".venv/",
"smart-contracts/",
"assets/",
# Issue-bounty contract client: enum members and dataclass fields mirror
# the on-chain shape, so unused-name reports here are not actionable
"gittensor/validator/issue_competitions/contract_client.py",
# das-github-mirror response schema: dataclass fields mirror the upstream
# wire format and are kept even when no validator code reads them today
"gittensor/utils/mirror/models.py",
]
min_confidence = 60
sort_by_size = true
ignore_decorators = [
# Click command/group registration - vulture cannot see the registry calls
"@click.command",
"@click.group",
"@*.command",
"@*.group",
# pytest fixtures (incl. autouse) are resolved by pytest, not by import
"@pytest.fixture",
]
ignore_names = [
# `__exit__(self, exc_type, exc_value, traceback)` - dunder signature
"exc_type",
"exc_value",
"exc",
"tb",
"traceback",
# pytest hook functions defined in conftest.py
"pytest_*",
# Click subclass overrides invoked by the framework
"get_help",
"command_class",
# `lru_cache`'s synthetic cache-buster argument used by ttl_cache()
"ttl_hash",
# MagicMock attribute consumed by the mock framework, not by us
"side_effect",
# psycopg Connection attributes (autocommit setter, prepared-statement
# threshold) - written for side effects, read inside the driver
"autocommit",
"prepare_threshold",
# Required-env-var capture; kept for parity with `.env.example` even when
# no code reads it directly (wandb consumes WANDB_API_KEY from the env)
"WANDB_API_KEY",
# Attribute set on IssueCompetitionContractClient test doubles - the
# client itself is excluded above, so reads of this attribute are invisible
"contract_address",
# PRInfo TypedDict fields populated and read via `dict.get(...)`; vulture
# cannot link a string-keyed dict access to a typed attribute name
"author_id",
"review_count",
# Consumed only by `gittensor/utils/mirror/models.py`, excluded above as
# wire-format schema; the helper itself is otherwise invisible to vulture
"parse_optional_github_iso_to_utc",
]
8 changes: 0 additions & 8 deletions tests/cli/test_cli_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,13 +576,6 @@ def test_register_aborts_on_github_503_before_contract_call(self, cli_root, runn
"""
import gittensor.cli.issue_commands.mutations as mut

exec_was_called = {'value': False}

class _Sentinel:
def exec(self, *_args, **_kwargs):
exec_was_called['value'] = True
raise AssertionError('register_issue must not be submitted on a GitHub skip')

with (
patch(
'gittensor.cli.issue_commands.mutations._resolve_contract_and_network',
Expand All @@ -605,7 +598,6 @@ def exec(self, *_args, **_kwargs):
)

assert result.exit_code != 0
assert exec_was_called['value'] is False
assert 'Could not verify' in result.output
assert '503' in result.output

Expand Down
Loading