Rebrand Pinscope to Periscope across product and codebase.
Rename the core package to periscopex, update UI/docs/Docker/deploy defaults to periscope.michelebigi.it, and keep legacy version/storage key aliases so existing projects keep working. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,7 +15,7 @@ from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
from backend.config import settings
|
||||
from backend.pinscopex.utils import safe_mpn
|
||||
from backend.periscopex.utils import safe_mpn
|
||||
from backend.routers.deps import get_storage
|
||||
from backend.services import admin_settings as settings_svc
|
||||
from backend.services.billing_hook import get_billing
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Local Pinscope auth endpoints (register / login / me)."""
|
||||
"""Local Periscope auth endpoints (register / login / me)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -41,10 +41,10 @@ class ContactResponse(BaseModel):
|
||||
def _build_contact_message(data: ContactRequest) -> MIMEMultipart:
|
||||
"""Build the contact form email."""
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["From"] = f"Pinscope <{settings.email_sender}>"
|
||||
msg["From"] = f"Periscope <{settings.email_sender}>"
|
||||
msg["To"] = settings.contact_recipient
|
||||
msg["Reply-To"] = data.email
|
||||
msg["Subject"] = f"[Pinscope Contact] {data.subject or 'New message'} from {data.name}"
|
||||
msg["Subject"] = f"[Periscope Contact] {data.subject or 'New message'} from {data.name}"
|
||||
|
||||
# Plain text
|
||||
lines = [
|
||||
@@ -55,7 +55,7 @@ def _build_contact_message(data: ContactRequest) -> MIMEMultipart:
|
||||
lines.append(f"Company: {data.company}")
|
||||
if data.subject:
|
||||
lines.append(f"Subject: {data.subject}")
|
||||
lines += ["", data.message, "", "— Sent from the Pinscope contact form"]
|
||||
lines += ["", data.message, "", "— Sent from the Periscope contact form"]
|
||||
msg.attach(MIMEText("\n".join(lines), "plain"))
|
||||
|
||||
# HTML
|
||||
@@ -94,7 +94,7 @@ def _build_contact_message(data: ContactRequest) -> MIMEMultipart:
|
||||
{rows}
|
||||
</table>
|
||||
<div style="margin-top: 16px; padding: 16px; background: #f9fafb; border-radius: 8px; font-size: 14px; line-height: 1.6; white-space: pre-wrap;">{message}</div>
|
||||
<p style="margin-top: 24px; font-size: 12px; color: #888;">Sent from the Pinscope contact form</p>
|
||||
<p style="margin-top: 24px; font-size: 12px; color: #888;">Sent from the Periscope contact form</p>
|
||||
</div>"""
|
||||
msg.attach(MIMEText(html_body, "html"))
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from typing import Literal
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from pydantic import BaseModel
|
||||
|
||||
from backend.pinscopex.impedance import (
|
||||
from backend.periscopex.impedance import (
|
||||
GeometryError,
|
||||
TraceGeometry,
|
||||
coupled_diff_z,
|
||||
@@ -21,13 +21,13 @@ from backend.pinscopex.impedance import (
|
||||
stackup_targets,
|
||||
stripline_z0,
|
||||
)
|
||||
from backend.pinscopex.impedance_traces import (
|
||||
from backend.periscopex.impedance_traces import (
|
||||
NET_WALK_PITCH_MM,
|
||||
analyze_specified_nets,
|
||||
)
|
||||
from backend.pinscopex.antenna_rf import build_antenna_report, build_design_recipe
|
||||
from backend.pinscopex.models import DesignGraph, LayoutGraph
|
||||
from backend.pinscopex.parsers_kicad_pcb import parse_kicad_pcb
|
||||
from backend.periscopex.antenna_rf import build_antenna_report, build_design_recipe
|
||||
from backend.periscopex.models import DesignGraph, LayoutGraph
|
||||
from backend.periscopex.parsers_kicad_pcb import parse_kicad_pcb
|
||||
from backend.routers.deps import get_storage, resolve_or_404
|
||||
from backend.services import projects as proj_svc
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ async def start(project_id: str, request: Request):
|
||||
|
||||
# Idempotent enqueue: only one ``draft|complete|error|cancelled`` ->
|
||||
# ``queued`` transition can win. Concurrent /start clicks => 409.
|
||||
from backend._version import PINSCOPE_VERSION
|
||||
from backend._version import PERISCOPE_VERSION
|
||||
try:
|
||||
proj_svc.transition_status(
|
||||
storage, owner_user_id, project_id,
|
||||
@@ -92,7 +92,7 @@ async def start(project_id: str, request: Request):
|
||||
to_status=proj_svc.STATUS_QUEUED,
|
||||
cancel_requested=False,
|
||||
execution_name=None,
|
||||
pinscope_version=PINSCOPE_VERSION,
|
||||
periscope_version=PERISCOPE_VERSION,
|
||||
)
|
||||
except proj_svc.StatusConflict:
|
||||
raise HTTPException(409, "Pipeline already running or queued")
|
||||
@@ -199,7 +199,7 @@ async def reprocess(project_id: str, request: Request, req: ReprocessRequest | N
|
||||
(default) skips ICs that already produced a review; ``all`` re-reviews
|
||||
every IC.
|
||||
"""
|
||||
from backend._version import PINSCOPE_VERSION
|
||||
from backend._version import PERISCOPE_VERSION
|
||||
|
||||
storage = get_storage(request)
|
||||
owner_user_id, meta = await resolve_or_404(request, project_id)
|
||||
@@ -241,7 +241,7 @@ async def reprocess(project_id: str, request: Request, req: ReprocessRequest | N
|
||||
pause_checkpoint=None,
|
||||
pause_reason=None,
|
||||
completed_review_refs=keep_refs,
|
||||
pinscope_version=PINSCOPE_VERSION,
|
||||
periscope_version=PERISCOPE_VERSION,
|
||||
)
|
||||
except proj_svc.StatusConflict:
|
||||
raise HTTPException(409, "Pipeline already running or queued")
|
||||
|
||||
+11
-11
@@ -11,7 +11,7 @@ from pydantic import BaseModel
|
||||
MAX_UPLOAD_BYTES = 30 * 1024 * 1024 # 30 MB
|
||||
|
||||
from backend.config import settings
|
||||
from backend.pinscopex.utils import safe_mpn
|
||||
from backend.periscopex.utils import safe_mpn
|
||||
from backend.routers.deps import get_storage, get_user_id, resolve_or_404
|
||||
from backend.services import projects as proj_svc
|
||||
|
||||
@@ -63,7 +63,7 @@ async def check_library(req: LibraryCheckRequest, request: Request):
|
||||
|
||||
passive_resolved: list[str] = []
|
||||
if req.passive_mpns:
|
||||
from backend.pinscopex.resolve_passives import resolve_mpn
|
||||
from backend.periscopex.resolve_passives import resolve_mpn
|
||||
|
||||
passive_resolved = [
|
||||
mpn for mpn in req.passive_mpns
|
||||
@@ -256,7 +256,7 @@ async def get_netlist_subdesigns(project_id: str, request: Request):
|
||||
``selected`` list (None = "include everything") so the wizard can render
|
||||
the picker pre-populated.
|
||||
"""
|
||||
from backend.pinscopex.parsers_edif import list_edif_subdesigns
|
||||
from backend.periscopex.parsers_edif import list_edif_subdesigns
|
||||
import tempfile, os
|
||||
|
||||
storage = get_storage(request)
|
||||
@@ -360,7 +360,7 @@ async def upload_bom(
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from backend.pinscopex.parsers import parse_bom
|
||||
from backend.periscopex.parsers import parse_bom
|
||||
|
||||
try:
|
||||
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".csv")
|
||||
@@ -420,7 +420,7 @@ async def upload_bom(
|
||||
# simple → datasheet upload). Mirrors the bucket logic in
|
||||
# services/pipeline.py:_stage_bom_parse so the field is correct after
|
||||
# either path runs.
|
||||
from backend.pinscopex.taxonomy import SIMPLE_TYPES, type_for_ref
|
||||
from backend.periscopex.taxonomy import SIMPLE_TYPES, type_for_ref
|
||||
|
||||
ic_mpns: list[str] = []
|
||||
passive_mpns: list[str] = []
|
||||
@@ -511,9 +511,9 @@ async def upload_netlist(
|
||||
raise HTTPException(404, "Project not found")
|
||||
user_id = result[0] # owner_user_id for storage paths
|
||||
|
||||
from backend.pinscopex.netlist_bundle import materialize_netlist_upload
|
||||
from backend.pinscopex.parsers import parse_netlist_any, validate_netlist
|
||||
from backend.pinscopex.parsers_edif import list_edif_subdesigns
|
||||
from backend.periscopex.netlist_bundle import materialize_netlist_upload
|
||||
from backend.periscopex.parsers import parse_netlist_any, validate_netlist
|
||||
from backend.periscopex.parsers_edif import list_edif_subdesigns
|
||||
import tempfile
|
||||
|
||||
blobs: list[tuple[str, bytes]] = []
|
||||
@@ -616,7 +616,7 @@ async def upload_pcb(project_id: str, file: UploadFile, request: Request):
|
||||
if len(data) > MAX_UPLOAD_BYTES:
|
||||
raise HTTPException(413, f"File too large (max {MAX_UPLOAD_BYTES // 1024 // 1024} MB)")
|
||||
import tempfile, os
|
||||
from backend.pinscopex.parsers_kicad_pcb import parse_kicad_pcb
|
||||
from backend.periscopex.parsers_kicad_pcb import parse_kicad_pcb
|
||||
|
||||
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".kicad_pcb")
|
||||
try:
|
||||
@@ -647,7 +647,7 @@ def _build_designator_pins(
|
||||
(natural sort on refs and on pin numbers) so the wizard's dropdowns
|
||||
look identical regardless of netlist format.
|
||||
"""
|
||||
from backend.pinscopex.utils import natural_sort_key
|
||||
from backend.periscopex.utils import natural_sort_key
|
||||
|
||||
by_ref: dict[str, dict[str, str]] = {ref: {} for ref in parts}
|
||||
for net_name, pins in nets.items():
|
||||
@@ -1079,7 +1079,7 @@ async def lcsc_resolve_passive(
|
||||
# Catalog miss (ferrite, odd text): LLM path, charged if the logger has tokens.
|
||||
|
||||
# Download taxonomy to a temp dir so auto_resolve_specs can read/write it.
|
||||
# Mirrors the PipelineWorkspace pattern: pinscopex operates on local paths.
|
||||
# Mirrors the PipelineWorkspace pattern: periscopex operates on local paths.
|
||||
api_logger = ApiLogger()
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
tax_dir = Path(tmpdir) / "taxonomy"
|
||||
|
||||
@@ -11,15 +11,15 @@ from fastapi import APIRouter, HTTPException, Request
|
||||
from fastapi.responses import JSONResponse, Response
|
||||
from pydantic import BaseModel
|
||||
|
||||
from backend.pinscopex.models import Finding
|
||||
from backend.pinscopex.review_workflow import (
|
||||
from backend.periscopex.models import Finding
|
||||
from backend.periscopex.review_workflow import (
|
||||
ReviewError,
|
||||
apply_review_state,
|
||||
build_eco,
|
||||
eco_csv,
|
||||
sign_report,
|
||||
)
|
||||
from backend.pinscopex.utils import safe_mpn
|
||||
from backend.periscopex.utils import safe_mpn
|
||||
from backend.routers.deps import get_storage, get_user_id, resolve_or_404
|
||||
from backend.services import projects as proj_svc
|
||||
|
||||
@@ -51,7 +51,7 @@ async def get_cad_bridge(project_id: str, request: Request):
|
||||
storage = get_storage(request)
|
||||
owner_user_id, _ = await resolve_or_404(request, project_id)
|
||||
prefix = proj_svc.project_prefix(owner_user_id, project_id)
|
||||
key = f"{prefix}/pinscope-findings.json"
|
||||
key = f"{prefix}/periscope-findings.json"
|
||||
if not storage.exists(key):
|
||||
raise HTTPException(404, "CAD bridge not found — run the pipeline first")
|
||||
return JSONResponse(storage.read_json(key))
|
||||
|
||||
Reference in New Issue
Block a user