Skip to content

Created Directories #1

Merged
merged 4 commits into from
Sep 12, 2025
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
Binary file added .coverage
Binary file not shown.
1 change: 0 additions & 1 deletion README.md

This file was deleted.

11 changes: 11 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "acmecli"
version = "0.0.1"
requires-python = ">=3.10"

[tool.setuptools.packages.find]
where = ["src"]
Empty file added python
Empty file.
49 changes: 49 additions & 0 deletions run
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
import sys, subprocess, re, os

def do_install():
subprocess.check_call([sys.executable, "-m", "pip", "install", "-e", "."])
return 0

def do_test():
import re, subprocess, sys, os, pathlib

# Always run from repo root
os.chdir(pathlib.Path(__file__).parent.resolve())

cmd = [sys.executable, "-m", "pytest", "tests",
"--maxfail=1", "--disable-warnings",
"--cov=acmecli", "--cov-report=term-missing"]
r = subprocess.run(cmd, text=True, capture_output=True)
out = (r.stdout or "") + (r.stderr or "")

# Extract counts
collected = re.search(r"collected\s+(\d+)", out)
passed = re.search(r"(\d+)\s+passed", out)
cov = re.search(r"TOTAL\s+.*?(\d+)%", out)

x = int(passed.group(1)) if passed else 0
y = int(collected.group(1)) if collected else 0
z = int(cov.group(1)) if cov else 0

print(f"{x}/{y} test cases passed. {z}% line coverage achieved.")
return 0 if r.returncode == 0 else 1


def main():
if len(sys.argv) < 2:
print("Usage: run install|test|score <URL_FILE>")
sys.exit(1)
cmd = sys.argv[1]
if cmd == "install": sys.exit(do_install())
if cmd == "test": sys.exit(do_test())
if cmd == "score":
if len(sys.argv) < 3:
print("Usage: run score <URL_FILE>")
sys.exit(1)
sys.exit(do_score(sys.argv[2]))
print("Unknown command.")
sys.exit(1)

if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import run
4 changes: 4 additions & 0 deletions src/acmecli.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Metadata-Version: 2.4
Name: acmecli
Version: 0.0.1
Requires-Python: >=3.10
15 changes: 15 additions & 0 deletions src/acmecli.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pyproject.toml
src/acmecli/__init__.py
src/acmecli/cli.py
src/acmecli/reporter.py
src/acmecli/scoring.py
src/acmecli/types.py
src/acmecli.egg-info/PKG-INFO
src/acmecli.egg-info/SOURCES.txt
src/acmecli.egg-info/dependency_links.txt
src/acmecli.egg-info/top_level.txt
src/acmecli/metrics/__init__.py
src/acmecli/metrics/base.py
src/acmecli/metrics/license_metric.py
tests/test_metrics_contract.py
tests/test_reporter_schema.py
1 change: 1 addition & 0 deletions src/acmecli.egg-info/dependency_links.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions src/acmecli.egg-info/top_level.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
acmecli
Empty file added src/acmecli/__init__.py
Empty file.
Binary file added src/acmecli/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file added src/acmecli/__pycache__/types.cpython-313.pyc
Binary file not shown.
42 changes: 42 additions & 0 deletions src/acmecli/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import sys
from pathlib import Path
from .types import ReportRow
from .reporter import write_ndjson

def _classify(url: str) -> str:
u = url.strip().lower()
if "huggingface.co/datasets/" in u:
return "DATASET"
if "github.com/" in u:
return "CODE"
if "huggingface.co/" in u:
return "MODEL"
return "CODE"

def _stub_row(name: str) -> ReportRow:
zero = 0.0
return ReportRow(
name=name, category="MODEL",
net_score=zero, net_score_latency=0,
ramp_up_time=zero, ramp_up_time_latency=0,
bus_factor=zero, bus_factor_latency=0,
performance_claims=zero, performance_claims_latency=0,
license=zero, license_latency=0,
size_score={"raspberry_pi":0.0, "jetson_nano":0.0, "desktop_pc":0.0, "aws_server":0.0},
size_score_latency=0,
dataset_and_code_score=zero, dataset_and_code_score_latency=0,
dataset_quality=zero, dataset_quality_latency=0,
code_quality=zero, code_quality_latency=0
)

def main(argv: list[str]) -> int:
# argv pattern: ["score", "/abs/path/URL_FILE"]
_, url_file = argv
lines = Path(url_file).read_text(encoding="utf-8").splitlines()
for raw in lines:
url = raw.strip()
if not url:
continue
if _classify(url) == "MODEL":
write_ndjson(_stub_row(url))
return 0
Empty file added src/acmecli/metrics/__init__.py
Empty file.
Binary file not shown.
Binary file added src/acmecli/metrics/__pycache__/base.cpython-313.pyc
Binary file not shown.
Binary file not shown.
7 changes: 7 additions & 0 deletions src/acmecli/metrics/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from typing import List
from ..types import Metric, MetricValue, TargetSpec, SourceHandler, Cache

REGISTRY: List[Metric] = []

def register(metric: Metric) -> None:
REGISTRY.append(metric)
18 changes: 18 additions & 0 deletions src/acmecli/metrics/license_metric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import time
from ..types import Metric, Signals, TargetSpec, SourceHandler, Cache, MetricValue
from .base import register

class LicenseMetric:
name = "license"

def collect(self, spec: TargetSpec, handler: SourceHandler, cache: Cache) -> Signals:
# Week 1 stub: no network; just return empty signals
return {}

def score(self, signals: Signals) -> MetricValue:
t0 = time.perf_counter()
value = 0.0 # TODO: map license presence/compatibility → [0,1]
latency_ms = int((time.perf_counter() - t0) * 1000)
return MetricValue(self.name, value, latency_ms)

register(LicenseMetric())
6 changes: 6 additions & 0 deletions src/acmecli/reporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import json
from dataclasses import asdict
from .types import ReportRow

def write_ndjson(row: ReportRow) -> None:
print(json.dumps(asdict(row), ensure_ascii=False))
26 changes: 26 additions & 0 deletions src/acmecli/scoring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import Dict, List
from .types import MetricValue

# Initial weights (sum ≈ 1.0). Tweak later.
WEIGHTS: Dict[str, float] = {
"ramp_up_time": 0.15,
"bus_factor": 0.15,
"performance_claims": 0.10,
"license": 0.20,
"size": 0.10, # average of size_score dict
"dataset_and_code_score": 0.10,
"dataset_quality": 0.10,
"code_quality": 0.10,
}

class ScoringEngine:
def compute(self, values: List[MetricValue], size_avg: float = 0.0) -> tuple[float, int]:
lookup = {mv.name: mv for mv in values}
total_latency = sum(mv.latency_ms for mv in values)
net = 0.0
for k, w in WEIGHTS.items():
if k == "size":
net += w * float(size_avg)
elif k in lookup:
net += w * float(lookup[k].value)
return (max(0.0, min(1.0, net)), total_latency)
64 changes: 64 additions & 0 deletions src/acmecli/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from dataclasses import dataclass, asdict
from typing import Protocol, Iterable, TypedDict, Literal, Optional, Dict

Category = Literal["MODEL", "DATASET", "CODE"]
Source = Literal["GITHUB", "HUGGINGFACE", "LOCAL"]

@dataclass(frozen=True)
class TargetSpec:
url: str
source: Source
name: str
category: Category
revision: Optional[str] = None # commit/tag if known

class Signals(TypedDict, total=False):
readme_text: str
license_name: str
contributors: Dict[str, int]
stars: int
downloads: int

@dataclass(frozen=True)
class MetricValue:
name: str # e.g. "ramp_up_time"
value: float # [0,1]
latency_ms: int

@dataclass(frozen=True)
class ReportRow:
# Required NDJSON fields + per-metric latencies (values are stubs for now)
name: str
category: Category
net_score: float
net_score_latency: int
ramp_up_time: float
ramp_up_time_latency: int
bus_factor: float
bus_factor_latency: int
performance_claims: float
performance_claims_latency: int
license: float
license_latency: int
size_score: Dict[str, float] # {raspberry_pi, jetson_nano, desktop_pc, aws_server}
size_score_latency: int
dataset_and_code_score: float
dataset_and_code_score_latency: int
dataset_quality: float
dataset_quality_latency: int
code_quality: float
code_quality_latency: int

class SourceHandler(Protocol):
def resolve_revision(self, url: str) -> str: ...
def fetch_meta(self, spec: TargetSpec) -> dict: ...
def stream_files(self, spec: TargetSpec, patterns: list[str]) -> Iterable[tuple[str, bytes]]: ...

class Cache(Protocol):
def get(self, key: str) -> bytes | None: ...
def set(self, key: str, data: bytes, etag: str | None = None) -> None: ...

class Metric(Protocol):
name: str
def collect(self, spec: TargetSpec, handler: SourceHandler, cache: Cache) -> Signals: ...
def score(self, signals: Signals) -> MetricValue: ...
Binary file not shown.
Binary file not shown.
11 changes: 11 additions & 0 deletions tests/test_metrics_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from acmecli.metrics.base import REGISTRY
from acmecli.metrics.license_metric import LicenseMetric

def test_registry_has_license_metric():
assert any(m.name == "license" for m in REGISTRY)

def test_metric_value_range():
m = LicenseMetric()
mv = m.score({})
assert 0.0 <= mv.value <= 1.0
assert mv.latency_ms >= 0
16 changes: 16 additions & 0 deletions tests/test_reporter_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from acmecli.types import ReportRow

def test_reportrow_has_required_fields():
row = ReportRow(
name="demo", category="MODEL",
net_score=0.0, net_score_latency=0,
ramp_up_time=0.0, ramp_up_time_latency=0,
bus_factor=0.0, bus_factor_latency=0,
performance_claims=0.0, performance_claims_latency=0,
license=0.0, license_latency=0,
size_score={}, size_score_latency=0,
dataset_and_code_score=0.0, dataset_and_code_score_latency=0,
dataset_quality=0.0, dataset_quality_latency=0,
code_quality=0.0, code_quality_latency=0
)
assert row.category == "MODEL"