1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
import json
import sys
from rich.console import Console
from rich.table import Table
from rich import box
console = Console()
STATUS_COLORS = {
"registered": "green",
"filed": "yellow",
"pending": "yellow",
"expired": "red",
"refused": "red",
"withdrawn": "dim",
}
TYPE_ABBREV = {
"WORD": "Word",
"FIGURATIVE": "Fig.",
"COMBINED": "Combined",
"3D": "3D",
"COLOUR": "Colour",
"SOUND": "Sound",
"OTHER": "Other",
}
def _status_markup(status):
key = (status or "").lower()
color = STATUS_COLORS.get(key, "white")
return f"[{color}]{status or '—'}[/{color}]"
def _truncate(text, width):
text = text or "—"
if len(text) > width:
return text[: width - 1] + "…"
return text
def _format_fetched(iso: str) -> str:
if not iso:
return "—"
# Compact: "2026-02-24 10:30 UTC"
try:
ts = iso.replace("T", " ").replace("Z", "")
return f"[dim]{ts} UTC[/dim]"
except Exception:
return f"[dim]{iso}[/dim]"
def print_table(result, query, verbose=False, image_path=None):
trademarks = result["trademarks"]
total = result["total"]
page = result["page"]
fetched_at = result.get("fetched_at", "")
if image_path:
from pathlib import Path
header = f'Similar logos to "{Path(image_path).name}" — {total:,} result{"s" if total != 1 else ""} (page {page})'
else:
header = f'Trademark Search: "{query}" — {total:,} result{"s" if total != 1 else ""} (page {page})'
console.print(f"\n[bold]{header}[/bold]\n")
if not trademarks:
console.print(f'[yellow]No trademarks found for "{query}"[/yellow]')
return
table = Table(box=box.ROUNDED, show_lines=False, highlight=False)
table.add_column("Origin", width=12, no_wrap=True)
table.add_column("Name", width=30)
table.add_column("Status", width=14, no_wrap=True)
table.add_column("Type", width=10, no_wrap=True)
table.add_column("Owner", width=28)
table.add_column("Classes", width=12, no_wrap=True)
table.add_column("Applied", width=12, no_wrap=True)
table.add_column("App #", width=14, no_wrap=True)
if verbose:
table.add_column("Fetched", width=20, no_wrap=True)
fetched_cell = _format_fetched(fetched_at)
for tm in trademarks:
code = tm.get("office", "")
name_label = tm.get("office_name", code) or code
origin = f"[bold]{code}[/bold] {name_label}" if code else "—"
tm_name = f"[cyan]{_truncate(tm.get('name'), 29)}[/cyan]"
status = _status_markup(tm.get("status"))
tm_type = TYPE_ABBREV.get((tm.get("type") or "").upper(), tm.get("type") or "—")
owner = _truncate(tm.get("owner"), 27)
classes_raw = tm.get("classes") or []
classes = ", ".join(str(c) for c in classes_raw) if classes_raw else "—"
applied = tm.get("application_date") or "—"
app_num = tm.get("application_number") or "—"
row = [origin, tm_name, status, tm_type, owner, classes, applied, app_num]
if verbose:
row.append(fetched_cell)
table.add_row(*row)
console.print(table)
def print_json(result):
json.dump(result["trademarks"], sys.stdout, indent=2, default=str)
sys.stdout.write("\n")
|