refactor: rebrand decp.info to colibre #57
- Rename project from decp.info to colibre across all codebase - Update domain from https://decp.info to https://colibre.fr - Update GitHub repo references to ColinMaudry/colibre - Rename deployment files: decpinfo-backup.* → colibre-backup.* - Update project configuration and documentation - Rename project assets: decp.info.png → colibre.png - Update environment variables and constants (DOMAIN_NAME, TOKEN_PREFIX, GITHUB_REPO, etc.) - Update URLs in all pages, tests, and configuration files - Keep DECP acronym in text (unchanged per requirements) - Add rebrand note to README.md Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
+22
-22
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
"""Benchmark comparatif de l'endpoint /data : decp.info vs data.gouv.fr.
|
||||
"""Benchmark comparatif de l'endpoint /data : colibre vs data.gouv.fr.
|
||||
|
||||
Les deux APIs partagent le même schéma de requête (mêmes opérateurs), donc
|
||||
chaque scénario est envoyé à l'identique aux deux et les temps de réponse
|
||||
sont comparés côte à côte.
|
||||
|
||||
Usage :
|
||||
python tests/api/benchmark.py --token decpinfo_xxx
|
||||
python tests/api/benchmark.py --url http://localhost:8050/api/v1/data --token decpinfo_xxx
|
||||
python tests/api/benchmark.py --decp-only --token decpinfo_xxx --runs 20
|
||||
python tests/api/benchmark.py --token colibre_xxx
|
||||
python tests/api/benchmark.py --url http://localhost:8050/api/v1/data --token colibre_xxx
|
||||
python tests/api/benchmark.py --decp-only --token colibre_xxx --runs 20
|
||||
|
||||
Par défaut, --url pointe vers la production decp.info ; data.gouv.fr est
|
||||
Par défaut, --url pointe vers la production colibre.fr ; data.gouv.fr est
|
||||
interrogé sans authentification.
|
||||
|
||||
"""
|
||||
@@ -23,7 +23,7 @@ from urllib.parse import quote
|
||||
|
||||
import httpx
|
||||
|
||||
DECP_DEFAULT_URL = "https://decp.info/api/v1/data"
|
||||
DECP_DEFAULT_URL = "https://colibre.fr/api/v1/data"
|
||||
DATAGOUV_DEFAULT_URL = (
|
||||
"https://tabular-api.data.gouv.fr/api/resources/"
|
||||
"22847056-61df-452d-837d-8b8ceadbfc52/data/"
|
||||
@@ -169,7 +169,7 @@ def measure(target: Target, query: str, runs: int) -> dict | None:
|
||||
}
|
||||
|
||||
|
||||
def run_benchmark(targets: list[Target], decp_label: str, runs: int) -> None:
|
||||
def run_benchmark(targets: list[Target], colibre_label: str, runs: int) -> None:
|
||||
print("\nAVERTISSEMENT : volumes de données différents entre les deux APIs.")
|
||||
print(f"Scénarios : {len(SCENARIOS)} | Répétitions : {runs}\n")
|
||||
|
||||
@@ -177,7 +177,7 @@ def run_benchmark(targets: list[Target], decp_label: str, runs: int) -> None:
|
||||
for scenario in SCENARIOS:
|
||||
query = build_query(scenario["params"])
|
||||
decp_only = scenario.get("decp_only", False)
|
||||
active = [t for t in targets if not (decp_only and t.label != decp_label)]
|
||||
active = [t for t in targets if not (decp_only and t.label != colibre_label)]
|
||||
|
||||
measures = {t.label: measure(t, query, runs) for t in active}
|
||||
rows.append({"name": scenario["name"], "measures": measures})
|
||||
@@ -191,7 +191,7 @@ def run_benchmark(targets: list[Target], decp_label: str, runs: int) -> None:
|
||||
bits.append(f"{t.label}: méd {m['median']:.0f}ms [{m['status']}]")
|
||||
print(f" {scenario['name'][:COL_NAME]:<{COL_NAME}} " + " | ".join(bits))
|
||||
|
||||
_print_summary(rows, targets, decp_label)
|
||||
_print_summary(rows, targets, colibre_label)
|
||||
|
||||
|
||||
def _fmt(m: dict | None, key: str) -> str:
|
||||
@@ -202,8 +202,8 @@ def _fmt(m: dict | None, key: str) -> str:
|
||||
return f"{m[key]:.0f}"
|
||||
|
||||
|
||||
def _print_summary(rows: list[dict], targets: list[Target], decp_label: str) -> None:
|
||||
dg = next((t.label for t in targets if t.label != decp_label), None)
|
||||
def _print_summary(rows: list[dict], targets: list[Target], colibre_label: str) -> None:
|
||||
dg = next((t.label for t in targets if t.label != colibre_label), None)
|
||||
|
||||
header = (
|
||||
f"{'Scénario':<{COL_NAME}}"
|
||||
@@ -218,18 +218,18 @@ def _print_summary(rows: list[dict], targets: list[Target], decp_label: str) ->
|
||||
print(f"{'=' * len(header)}\n{header}\n{sep}")
|
||||
|
||||
for row in rows:
|
||||
m_decp = row["measures"].get(decp_label)
|
||||
m_colibre = row["measures"].get(colibre_label)
|
||||
m_dg = row["measures"].get(dg) if dg else None
|
||||
|
||||
ratio = "—"
|
||||
if m_decp and m_dg and "error" not in m_decp and "error" not in m_dg:
|
||||
if m_colibre and m_dg and "error" not in m_colibre and "error" not in m_dg:
|
||||
if m_dg["median"] > 0:
|
||||
ratio = f"{m_decp['median'] / m_dg['median']:.2f}"
|
||||
ratio = f"{m_colibre['median'] / m_dg['median']:.2f}"
|
||||
|
||||
print(
|
||||
f"{row['name'][:COL_NAME]:<{COL_NAME}}"
|
||||
f" {_fmt(m_dg, 'median'):>{COL_STAT}} {_fmt(m_dg, 'p95'):>{COL_STAT}}"
|
||||
f" {_fmt(m_decp, 'median'):>{COL_STAT}} {_fmt(m_decp, 'p95'):>{COL_STAT}}"
|
||||
f" {_fmt(m_colibre, 'median'):>{COL_STAT}} {_fmt(m_colibre, 'p95'):>{COL_STAT}}"
|
||||
f" {ratio:>7}"
|
||||
)
|
||||
print(sep)
|
||||
@@ -237,12 +237,12 @@ def _print_summary(rows: list[dict], targets: list[Target], decp_label: str) ->
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Benchmark comparatif decp.info vs data.gouv.fr (/data)"
|
||||
description="Benchmark comparatif colibre vs data.gouv.fr (/data)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--url",
|
||||
default=DECP_DEFAULT_URL,
|
||||
help=f"Endpoint /data de decp.info (défaut : {DECP_DEFAULT_URL})",
|
||||
help=f"Endpoint /data de colibre (défaut : {DECP_DEFAULT_URL})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--datagouv-url",
|
||||
@@ -252,7 +252,7 @@ def main() -> None:
|
||||
parser.add_argument(
|
||||
"--token",
|
||||
default=None,
|
||||
help="Token Bearer decp.info (format decpinfo_xxx)",
|
||||
help="Token Bearer colibre (format decpinfo_xxx)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--runs",
|
||||
@@ -263,7 +263,7 @@ def main() -> None:
|
||||
parser.add_argument(
|
||||
"--decp-only",
|
||||
action="store_true",
|
||||
help="Ne benchmarker que decp.info (saute data.gouv.fr)",
|
||||
help="Ne benchmarker que colibre (saute data.gouv.fr)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -271,16 +271,16 @@ def main() -> None:
|
||||
print("--runs doit être ≥ 1", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
decp_label = "decp.info"
|
||||
colibre_label = "colibre"
|
||||
decp_headers = {"Authorization": f"Bearer {args.token}"} if args.token else {}
|
||||
decp = Target(label=decp_label, base_url=args.url, headers=decp_headers)
|
||||
decp = Target(label=colibre_label, base_url=args.url, headers=decp_headers)
|
||||
|
||||
targets = [decp]
|
||||
if not args.decp_only:
|
||||
# data.gouv.fr d'abord pour l'affichage côte à côte
|
||||
targets.insert(0, Target(label="data.gouv.fr", base_url=args.datagouv_url))
|
||||
|
||||
run_benchmark(targets, decp_label, args.runs)
|
||||
run_benchmark(targets, colibre_label, args.runs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -23,8 +23,8 @@ def fake_client(monkeypatch):
|
||||
monkeypatch.setenv("APP_BASE_URL", "http://localhost:8050")
|
||||
monkeypatch.setenv("BREVO_TEMPLATE_VERIFY_ID", "11")
|
||||
monkeypatch.setenv("BREVO_TEMPLATE_RESET_ID", "22")
|
||||
monkeypatch.setenv("MAIL_FROM", "noreply@decp.info")
|
||||
monkeypatch.setenv("MAIL_FROM_NAME", "decp.info")
|
||||
monkeypatch.setenv("MAIL_FROM", "noreply@colibre")
|
||||
monkeypatch.setenv("MAIL_FROM_NAME", "colibre")
|
||||
return client
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ def test_send_verification_email(fake_client):
|
||||
call = calls[0]
|
||||
assert call["template_id"] == 11
|
||||
assert call["to"][0].email == "a@b.c"
|
||||
assert call["sender"].email == "noreply@decp.info"
|
||||
assert call["sender"].email == "noreply@colibre"
|
||||
assert "/auth/verify-email?token=TOKEN123" in call["params"]["link"]
|
||||
assert call["headers"] == {"X-Sib-Sandbox": "drop"} # DEVELOPMENT=true en tests
|
||||
|
||||
|
||||
@@ -17,5 +17,5 @@ def test_send_verification_email_sandbox(monkeypatch):
|
||||
mailer.init_mailer()
|
||||
# Ne doit pas lever : l'API Brevo accepte la requête en sandbox.
|
||||
mailer.send_verification_email(
|
||||
os.getenv("MAIL_FROM", "noreply@decp.info"), "INTEGRATION_TOKEN"
|
||||
os.getenv("MAIL_FROM", "noreply@colibre"), "INTEGRATION_TOKEN"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ from moto import mock_aws
|
||||
|
||||
from src.backup.storage import S3Storage
|
||||
|
||||
BUCKET = "decp-backups"
|
||||
BUCKET = "colibre-backups"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
+4
-4
@@ -43,10 +43,10 @@ _TEST_DATA = [
|
||||
_PARQUET_PATH = Path(os.path.abspath("tests/test.parquet"))
|
||||
|
||||
# Base DuckDB de test ISOLÉE : src.db lit le chemin via DUCKDB_PATH (défaut
|
||||
# ./decp.duckdb). On la place dans tests/ pour ne JAMAIS toucher au decp.duckdb
|
||||
# de dev/prod — plus besoin de sauvegarder/restaurer. Le nom decp.duckdb
|
||||
# correspond au motif **/decp.duckdb déjà présent dans .gitignore.
|
||||
_DB_PATH = Path(os.path.abspath("tests/decp.duckdb"))
|
||||
# ./colibre.duckdb). On la place dans tests/ pour ne JAMAIS toucher au colibre.duckdb
|
||||
# de dev/prod — plus besoin de sauvegarder/restaurer. Le nom colibre.duckdb
|
||||
# correspond au motif **/colibre.duckdb déjà présent dans .gitignore.
|
||||
_DB_PATH = Path(os.path.abspath("tests/colibre.duckdb"))
|
||||
os.environ["DUCKDB_PATH"] = str(_DB_PATH)
|
||||
|
||||
# Schéma déterministe et hors-ligne : on COPIE le fixture committé vers un cache
|
||||
|
||||
@@ -16,25 +16,25 @@ _ISSUES = [
|
||||
{
|
||||
"number": 10,
|
||||
"title": "Feature en cours",
|
||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/10",
|
||||
"html_url": "https://github.com/ColinMaudry/colibre/issues/10",
|
||||
"labels": [{"name": "en cours"}],
|
||||
},
|
||||
{
|
||||
"number": 20,
|
||||
"title": "Feature au vote",
|
||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/20",
|
||||
"html_url": "https://github.com/ColinMaudry/colibre/issues/20",
|
||||
"labels": [{"name": "mis au vote"}],
|
||||
},
|
||||
{
|
||||
"number": 30,
|
||||
"title": "Issue sans label pertinent",
|
||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/30",
|
||||
"html_url": "https://github.com/ColinMaudry/colibre/issues/30",
|
||||
"labels": [{"name": "bug"}],
|
||||
},
|
||||
{
|
||||
"number": 40,
|
||||
"title": "Une PR déguisée en issue",
|
||||
"html_url": "https://github.com/ColinMaudry/decp.info/pull/40",
|
||||
"html_url": "https://github.com/ColinMaudry/colibre/pull/40",
|
||||
"labels": [{"name": "mis au vote"}],
|
||||
"pull_request": {"url": "..."},
|
||||
},
|
||||
@@ -49,5 +49,5 @@ def test_fetch_roadmap_issues_filters_by_label(monkeypatch):
|
||||
assert result["en_cours"][0] == {
|
||||
"number": 10,
|
||||
"title": "Feature en cours",
|
||||
"html_url": "https://github.com/ColinMaudry/decp.info/issues/10",
|
||||
"html_url": "https://github.com/ColinMaudry/colibre/issues/10",
|
||||
}
|
||||
|
||||
+9
-9
@@ -33,8 +33,8 @@ def test_001_logo_and_search(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
assert dash_duo.find_element(".logo > h1").text == "decp.info"
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
assert dash_duo.find_element(".logo > h1").text == "colibre"
|
||||
|
||||
for org_type in ["acheteur", "titulaire"]:
|
||||
name = f"{org_type.upper()} 1"
|
||||
@@ -64,7 +64,7 @@ def test_002_filter_persistence(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
|
||||
def open_page_and_check_filter_input():
|
||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/{page}")
|
||||
@@ -172,7 +172,7 @@ def test_006_observatoire_url_to_input(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
|
||||
# Navigate to observatoire with acheteur_id query param
|
||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire?acheteur_id=123")
|
||||
@@ -192,7 +192,7 @@ def test_007_observatoire_share_url(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
|
||||
# Navigate to observatoire with acheteur_id query param
|
||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire?acheteur_id=123")
|
||||
@@ -214,7 +214,7 @@ def test_008_search_to_observatoire(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
|
||||
# Search for an acheteur
|
||||
search_bar = dash_duo.find_element("#search")
|
||||
@@ -251,7 +251,7 @@ def test_009_observatoire_filter_persistence(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
|
||||
# Clear localStorage to start from a clean state
|
||||
dash_duo.driver.execute_script("localStorage.clear()")
|
||||
@@ -298,7 +298,7 @@ def test_011_observatoire_multi_param_url(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
|
||||
# Navigate with multiple filter params
|
||||
dash_duo.wait_for_page(
|
||||
@@ -360,7 +360,7 @@ def test_015_tableau_filter_date(dash_duo: DashComposite):
|
||||
from src.app import app
|
||||
|
||||
dash_duo.start_server(app)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4)
|
||||
dash_duo.wait_for_text_to_equal(".logo > h1", "colibre", timeout=4)
|
||||
|
||||
for page in ["tableau", "acheteurs/123", "titulaires/345"]:
|
||||
dash_duo.wait_for_page(f"{dash_duo.server_url}/{page}")
|
||||
|
||||
Reference in New Issue
Block a user