slab-cli 0.19.0__tar.gz → 0.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {slab_cli-0.19.0 → slab_cli-0.20.0}/PKG-INFO +2 -2
  2. {slab_cli-0.19.0 → slab_cli-0.20.0}/pyproject.toml +3 -2
  3. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/display.py +38 -4
  4. {slab_cli-0.19.0 → slab_cli-0.20.0}/README.md +0 -0
  5. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/__init__.py +0 -0
  6. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/banner.py +0 -0
  7. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/browse.py +0 -0
  8. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/client.py +0 -0
  9. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/__init__.py +0 -0
  10. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/breaks.py +0 -0
  11. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/catalog.py +0 -0
  12. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/collection.py +0 -0
  13. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/custom_sets.py +0 -0
  14. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/export.py +0 -0
  15. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/lots.py +0 -0
  16. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/pricing.py +0 -0
  17. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/registry.py +0 -0
  18. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/setup.py +0 -0
  19. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/commands/update.py +0 -0
  20. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/config.py +0 -0
  21. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/context.py +0 -0
  22. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/flags.py +0 -0
  23. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/help.py +0 -0
  24. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/main.py +0 -0
  25. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/paging.py +0 -0
  26. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/picker.py +0 -0
  27. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/platforms/__init__.py +0 -0
  28. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/platforms/base.py +0 -0
  29. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/platforms/posix.py +0 -0
  30. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/platforms/windows.py +0 -0
  31. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/prompts.py +0 -0
  32. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/sources.py +0 -0
  33. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/theme.py +0 -0
  34. {slab_cli-0.19.0 → slab_cli-0.20.0}/src/slab_cli/updates.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: slab-cli
3
- Version: 0.19.0
3
+ Version: 0.20.0
4
4
  Summary: CLI for the slab trading-card API — catalog, collect, and track your cards from the terminal.
5
5
  Author: dev_jeb
6
- Requires-Dist: slab-schemas>=0.34.0
6
+ Requires-Dist: slab-schemas>=0.35.0
7
7
  Requires-Dist: httpx>=0.27
8
8
  Requires-Dist: rich>=13.0
9
9
  Requires-Dist: inquirerpy>=0.3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "slab-cli"
3
- version = "0.19.0"
3
+ version = "0.20.0"
4
4
  description = "CLI for the slab trading-card API — catalog, collect, and track your cards from the terminal."
5
5
  readme = "README.md"
6
6
  authors = [{name = "dev_jeb"}]
@@ -11,7 +11,8 @@ dependencies = [
11
11
  # grading-desk models `slab card grade` / `slab collection grade` parse responses into.
12
12
  # 0.34 reframes the grading desk from verdicts to break-even readings (BreakEvenRegion,
13
13
  # GradingDesk.break_even) — the desk shows data, never tells the user to grade.
14
- "slab-schemas>=0.34.0",
14
+ # 0.35 adds Liquidity/LiquidityLabel, which the market view's Sells column renders.
15
+ "slab-schemas>=0.35.0",
15
16
  "httpx>=0.27",
16
17
  "rich>=13.0",
17
18
  "InquirerPy>=0.3",
@@ -20,7 +20,8 @@ from slab_schemas.community import (
20
20
  from slab_schemas.custom_sets import CustomSetDetail, CustomSetOut, CustomSetSearchResult
21
21
  from slab_schemas.dashboard import CatalogStats, DashboardStats, HighlightCard, LabeledCount
22
22
  from slab_schemas.grading_desk import CollectionGradingDesk, GradingDesk
23
- from slab_schemas.enums import BreakEvenRegion, Grade, SealedFormat
23
+ from slab_schemas.enums import BreakEvenRegion, Grade, LiquidityLabel, SealedFormat
24
+ from slab_schemas.liquidity import Liquidity
24
25
  from slab_schemas.pricing import CardComps, CardMarket, PortfolioSummary, SetTopCards
25
26
  from slab_schemas.sealed import SealedPriceHistory, SealedProductOut
26
27
  from slab_schemas.timeseries import CardPriceHistory
@@ -971,7 +972,8 @@ def render_card_market(m: CardMarket) -> None:
971
972
 
972
973
  # The Δ columns are FMV (appraisal) drift, not the window's sales — FMV smooths 90 days of
973
974
  # comps, so these lag the live market (two-lane rule, CLAUDE.md). Headers say FMV so a
974
- # "+$5" cell reads as the appraisal moving, not as last week's market.
975
+ # "+$5" cell reads as the appraisal moving, not as last week's market. "Sells" is the other
976
+ # lane: real sale cadence from comps (liquidity), so the price and its pace sit side by side.
975
977
  table = slab_table([
976
978
  ("Grade", {"style": "slab.value"}),
977
979
  ("FMV", {"justify": "right"}),
@@ -979,6 +981,7 @@ def render_card_market(m: CardMarket) -> None:
979
981
  ("FMV Δ7d", {"justify": "right"}),
980
982
  ("FMV Δ30d", {"justify": "right"}),
981
983
  ("Comps", {"justify": "right", "style": "slab.dim"}),
984
+ ("Sells", {"style": "slab.dim"}),
982
985
  ])
983
986
 
984
987
  for pp in sorted(m.price_points, key=lambda p: (p.finish or "", p.grade_key)):
@@ -990,14 +993,39 @@ def render_card_market(m: CardMarket) -> None:
990
993
  if pp.price_low is not None and pp.price_high is not None:
991
994
  rng = f"${pp.price_low:,.0f} – ${pp.price_high:,.0f}"
992
995
  table.add_row(label, fmv, rng, signed_money(pp.price_change_7d),
993
- signed_money(pp.price_change_30d), str(pp.sample_size))
996
+ signed_money(pp.price_change_30d), str(pp.sample_size),
997
+ _liquidity_text(pp.liquidity))
994
998
 
995
999
  window = m.price_points[0].window_days
996
1000
  console.print(heading("Market Price", f"{window}-day window, as of {m.as_of_date}"))
997
1001
  console.print(table)
1002
+ if any(pp.liquidity for pp in m.price_points):
1003
+ console.print(
1004
+ " [slab.dim]Sells = how often this exact printing and grade actually sells — the "
1005
+ "typical gap between real sales in the last 90 days, or the past year's count for "
1006
+ "slow movers. A rare seller isn't bad; it means the price is an estimate you may "
1007
+ "wait to realize.[/]"
1008
+ )
998
1009
  console.print()
999
1010
 
1000
1011
 
1012
+ def _liquidity_text(liq: Liquidity | None) -> str:
1013
+ """A liquidity reading as one short table cell — the pace, then the datum behind it.
1014
+ Data statements only, mirroring the `liquidity.*` glossary."""
1015
+ if liq is None:
1016
+ return "—"
1017
+ L = LiquidityLabel
1018
+ if liq.median_days_between_sales is not None:
1019
+ gap = liq.median_days_between_sales
1020
+ word = {L.sells_daily: "~daily", L.sells_weekly: "~weekly"}.get(liq.label, "~monthly")
1021
+ return f"{word} (every {gap}d)" if gap > 0 else f"{word} (several/day)"
1022
+ if liq.label == L.too_new_to_say:
1023
+ return f"too new to say ({liq.observed_days}d watched)"
1024
+ if liq.label == L.no_recent_sales:
1025
+ return "none this year"
1026
+ return f"{liq.sales_365d}×/year"
1027
+
1028
+
1001
1029
  def _format_label(fmt: str) -> str:
1002
1030
  """SealedFormat value -> display label: hobby_box -> Hobby Box."""
1003
1031
  return fmt.replace("_", " ").title()
@@ -1201,15 +1229,21 @@ def render_grading_desk(d: GradingDesk) -> None:
1201
1229
  ("Sells for", {"justify": "right", "style": "slab.foil"}),
1202
1230
  ("You clear", {"justify": "right"}),
1203
1231
  ("Sales", {"justify": "right", "style": "slab.dim"}),
1232
+ ("Sells", {"style": "slab.dim"}),
1204
1233
  ])
1205
1234
  for l in d.lanes:
1206
1235
  n = f"{l.sample_size}!" if l.low_confidence else str(l.sample_size)
1207
- table.add_row(l.grade_key, money(l.fair_market_value), signed_money(l.payoff), n)
1236
+ table.add_row(l.grade_key, money(l.fair_market_value), signed_money(l.payoff), n,
1237
+ _liquidity_text(l.liquidity))
1208
1238
  console.print(heading("Payoff per Grade", "after the fee, vs staying raw"))
1209
1239
  console.print(table)
1210
1240
  if any(l.low_confidence for l in d.lanes):
1211
1241
  console.print(" [slab.dim]! = priced off very few sales — an anecdote, "
1212
1242
  "not a market.[/]")
1243
+ if any(l.liquidity for l in d.lanes):
1244
+ console.print(" [slab.dim]Sells = how often that grade actually trades — a payoff "
1245
+ "at a grade that sells twice a year is a longer wait than one that "
1246
+ "sells weekly.[/]")
1213
1247
 
1214
1248
  console.print()
1215
1249
  console.print(f" {_desk_reading_line(d)}")
File without changes