feat: add Meet Kevin pydantic schemas (analysis + API shapes)
This commit is contained in:
parent
8f616e6487
commit
75534de71b
2 changed files with 512 additions and 0 deletions
|
|
@ -584,3 +584,197 @@ class TestTokenResponse:
|
|||
)
|
||||
restored = TokenResponse.model_validate_json(t.model_dump_json())
|
||||
assert restored == t
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# --- Meet Kevin schemas ---
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestMeetKevinTickerMention:
|
||||
def test_valid_ticker_mention(self) -> None:
|
||||
from shared.schemas.meet_kevin import MeetKevinTickerMention
|
||||
|
||||
mention = MeetKevinTickerMention(
|
||||
symbol="AAPL",
|
||||
action="buy",
|
||||
conviction=0.85,
|
||||
time_horizon="months",
|
||||
rationale_quote="Strong earnings growth expected",
|
||||
video_timestamp_seconds=120,
|
||||
)
|
||||
assert mention.symbol == "AAPL"
|
||||
assert mention.conviction == 0.85
|
||||
|
||||
def test_symbol_auto_uppercases(self) -> None:
|
||||
from shared.schemas.meet_kevin import MeetKevinTickerMention
|
||||
|
||||
mention = MeetKevinTickerMention(
|
||||
symbol="tsla",
|
||||
action="hold",
|
||||
conviction=0.5,
|
||||
time_horizon="weeks",
|
||||
rationale_quote="Neutral outlook",
|
||||
)
|
||||
assert mention.symbol == "TSLA"
|
||||
|
||||
def test_conviction_out_of_range_high(self) -> None:
|
||||
from shared.schemas.meet_kevin import MeetKevinTickerMention
|
||||
|
||||
with pytest.raises(ValidationError):
|
||||
MeetKevinTickerMention(
|
||||
symbol="AAPL",
|
||||
action="buy",
|
||||
conviction=1.5,
|
||||
time_horizon="months",
|
||||
rationale_quote="Too confident",
|
||||
)
|
||||
|
||||
def test_conviction_out_of_range_low(self) -> None:
|
||||
from shared.schemas.meet_kevin import MeetKevinTickerMention
|
||||
|
||||
with pytest.raises(ValidationError):
|
||||
MeetKevinTickerMention(
|
||||
symbol="AAPL",
|
||||
action="sell",
|
||||
conviction=-0.1,
|
||||
time_horizon="days",
|
||||
rationale_quote="Negative conviction",
|
||||
)
|
||||
|
||||
def test_conviction_edge_cases(self) -> None:
|
||||
from shared.schemas.meet_kevin import MeetKevinTickerMention
|
||||
|
||||
# Test 0.0
|
||||
m1 = MeetKevinTickerMention(
|
||||
symbol="GOOG",
|
||||
action="avoid",
|
||||
conviction=0.0,
|
||||
time_horizon="unspecified",
|
||||
rationale_quote="No confidence",
|
||||
)
|
||||
assert m1.conviction == 0.0
|
||||
|
||||
# Test 1.0
|
||||
m2 = MeetKevinTickerMention(
|
||||
symbol="MSFT",
|
||||
action="buy",
|
||||
conviction=1.0,
|
||||
time_horizon="long_term",
|
||||
rationale_quote="Maximum confidence",
|
||||
)
|
||||
assert m2.conviction == 1.0
|
||||
|
||||
def test_timestamp_optional(self) -> None:
|
||||
from shared.schemas.meet_kevin import MeetKevinTickerMention
|
||||
|
||||
mention = MeetKevinTickerMention(
|
||||
symbol="NVDA",
|
||||
action="watch",
|
||||
conviction=0.6,
|
||||
time_horizon="intraday",
|
||||
rationale_quote="Monitoring closely",
|
||||
)
|
||||
assert mention.video_timestamp_seconds is None
|
||||
|
||||
|
||||
class TestMeetKevinAnalysis:
|
||||
def test_valid_analysis(self) -> None:
|
||||
from shared.schemas.meet_kevin import (
|
||||
MeetKevinAnalysis,
|
||||
MeetKevinTickerMention,
|
||||
)
|
||||
|
||||
analysis = MeetKevinAnalysis(
|
||||
market_outlook_direction="bullish",
|
||||
market_outlook_reasoning="Strong macro tailwinds",
|
||||
macro_themes=["inflation_easing", "ai_acceleration"],
|
||||
key_risks=["geopolitical_uncertainty", "rate_volatility"],
|
||||
summary="Overall positive outlook for tech sector",
|
||||
tickers=[
|
||||
MeetKevinTickerMention(
|
||||
symbol="AAPL",
|
||||
action="buy",
|
||||
conviction=0.85,
|
||||
time_horizon="months",
|
||||
rationale_quote="Strong earnings expected",
|
||||
)
|
||||
],
|
||||
)
|
||||
assert analysis.market_outlook_direction == "bullish"
|
||||
assert len(analysis.tickers) == 1
|
||||
assert analysis.tickers[0].symbol == "AAPL"
|
||||
|
||||
def test_multiple_tickers(self) -> None:
|
||||
from shared.schemas.meet_kevin import (
|
||||
MeetKevinAnalysis,
|
||||
MeetKevinTickerMention,
|
||||
)
|
||||
|
||||
analysis = MeetKevinAnalysis(
|
||||
market_outlook_direction="neutral",
|
||||
market_outlook_reasoning="Mixed signals",
|
||||
macro_themes=["earnings_season"],
|
||||
key_risks=["fed_decisions"],
|
||||
summary="Cautious outlook",
|
||||
tickers=[
|
||||
MeetKevinTickerMention(
|
||||
symbol="TSLA",
|
||||
action="buy",
|
||||
conviction=0.7,
|
||||
time_horizon="weeks",
|
||||
rationale_quote="Breakout expected",
|
||||
),
|
||||
MeetKevinTickerMention(
|
||||
symbol="GOOG",
|
||||
action="hold",
|
||||
conviction=0.5,
|
||||
time_horizon="months",
|
||||
rationale_quote="Wait for clarity",
|
||||
),
|
||||
],
|
||||
)
|
||||
assert len(analysis.tickers) == 2
|
||||
assert analysis.tickers[0].symbol == "TSLA"
|
||||
assert analysis.tickers[1].symbol == "GOOG"
|
||||
|
||||
def test_empty_tickers_list(self) -> None:
|
||||
from shared.schemas.meet_kevin import MeetKevinAnalysis
|
||||
|
||||
analysis = MeetKevinAnalysis(
|
||||
market_outlook_direction="bearish",
|
||||
market_outlook_reasoning="Recession risk",
|
||||
macro_themes=["inflation"],
|
||||
key_risks=["unemployment"],
|
||||
summary="Negative outlook",
|
||||
tickers=[],
|
||||
)
|
||||
assert len(analysis.tickers) == 0
|
||||
|
||||
def test_json_round_trip(self) -> None:
|
||||
from shared.schemas.meet_kevin import (
|
||||
MeetKevinAnalysis,
|
||||
MeetKevinTickerMention,
|
||||
)
|
||||
|
||||
analysis = MeetKevinAnalysis(
|
||||
market_outlook_direction="mixed",
|
||||
market_outlook_reasoning="Divergent sector performance",
|
||||
macro_themes=["rate_peak", "ai_growth"],
|
||||
key_risks=["credit_stress"],
|
||||
summary="Selective opportunities",
|
||||
tickers=[
|
||||
MeetKevinTickerMention(
|
||||
symbol="NVIDIA",
|
||||
action="buy",
|
||||
conviction=0.95,
|
||||
time_horizon="long_term",
|
||||
rationale_quote="AI leader",
|
||||
video_timestamp_seconds=300,
|
||||
)
|
||||
],
|
||||
)
|
||||
json_str = analysis.model_dump_json()
|
||||
restored = MeetKevinAnalysis.model_validate_json(json_str)
|
||||
assert restored == analysis
|
||||
assert restored.tickers[0].symbol == "NVIDIA"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue