
    mjS5                       d dl mZ d dlZd dlmc mZ d dlm	Z	 d dl
mZ d dlmZ d dlZd dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZmZ d dlmZmZm Z  d dl!m"Z"m#Z# d dl$m%Z% d dl&m'Z' dZ( eddd          Z)d1dZ*d2dZ+d3dZ,dd d4d&Z- G d' d(          Z.d5d)Z/d5d*Z0d5d+Z1d5d,Z2d5d-Z3d5d.Z4d5d/Z5d5d0Z6dS )6    )annotationsN)Iterator)date)Decimal)
Connection)
TestClient)get_db)
create_app)QuoteRefreshRequest)EquityPriceQuote)get_equity_summarylist_equity_positions)_quality_from_errorrefresh_equity_quoterefresh_equity_quotes_batch)confirmed_canonical_positionsrun_daily_market_valuation)get_portfolio_advisor_snapshot)apply_migrationsz2026-07-26T12:00:00Zi        valuedate | str | Nonereturnstrc                    t          | t                    r|                                 n't          | pt                                                    S N)
isinstancer   	isoformatr   TARGET)r   s    [/home/agent/.hermes/repos/FinanceManager/tests/unit/test_sprint11_portfolio_completeness.py
_date_textr"      s?     *5$ 7 7]5??SA\&JZJZJ\J\=]=]]    r   c                    t          j        dd          } t           j        | _        |                     d           t          |            |                     dt          f           |                     dt          f           | S )Nz:memory:F)check_same_threadzPRAGMA foreign_keys=ONzINSERT INTO platforms(platform_id,name,platform_type,country,default_currency,created_at) VALUES('postfinance','PostFinance','broker','CH','CHF',?)zINSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,created_at) VALUES('etrading','postfinance','Manual Portfolio','brokerage','CHF',?))sqlite3connectRowrow_factoryexecuter   NOWconns    r!   _connectr.      s    ?:???D{DLL)***TLL  g  jm  io  p  p  pLL  v  y|  x~      Kr#   r-   r   c                h     t                      }d fd}||j        t          <   t          |          S )Nr   Iterator[Connection]c               3     K    V  d S r    r,   s   r!   overridez_client.<locals>.override)   s      




r#   )r   r0   )r
   dependency_overridesr	   r   )r-   appr3   s   `  r!   _clientr6   '   sC    
,,C     '/CV$c??r#   Ftransactionscountintr8   boolNonec               v   t          |          D ]}d|d}d|d}d|d}|                     d|dd|d||| d	t          f           |                     d
d|d|||d| d	t          f           |r,|                     dd|d|d|dd|dt          f           |                                  d S )Nzinst-02dTCH010dzINSERT INTO instruments(instrument_id,asset_class,name,ticker,isin,exchange,currency,provider_symbol,data_provider_primary,created_at) VALUES(?,?,?,?,?,'SIX','CHF',?,'fmp',?)stockz	Position z.SWzINSERT INTO instrument_price_mappings(mapping_id,instrument_id,isin,ticker,exchange,currency,provider,provider_symbol,provider_market,trading_currency,mapping_status,confidence,created_at) VALUES(?,?,?,?,?,'CHF','fmp',?,'SIX','CHF','mapped','1',?)zmap-SIXa"  INSERT INTO transactions(transaction_id,transaction_type,account_id,instrument_id,trade_date,quantity,currency_original,source_type,source_id,row_hash,is_confirmed,quality_status,created_at) VALUES(?, 'initial_position_snapshot','etrading',?,'2026-07-01','1','CHF','confirmed',?,?,1,'ok',?)ztx-zsource-zhash-)ranger*   r+   commit)r-   r9   r8   indexinstrument_idtickerisins          r!   _seed_positionsrJ   /   s   u T T++++ U E     F  IV  X_  ax  mr  ax  ax  ax  z@  BF  KQ  HV  HV  HV  X[  H\  	]  	]  	]  O  Rd  Y^  Rd  Rd  Rd  fs  uy  {A  CH  MS  JX  JX  JX  Z]  Q^  	_  	_  	_ 	TLL  ~  AR  GL  AR  AR  AR  Ta  cx  mr  cx  cx  cx  zM  BG  zM  zM  zM  OR  @S  T  T  TKKMMMMMr#   c                  (    e Zd ZdZddZddddZdS )FreshProvidermockr   r<   c                    g | _         d S r   )calls)selfs    r!   __init__zFreshProvider.__init__=   s     "


r#   N
price_dateprovider_symbolr   rS   date | Noner   c          
         | j                             |           t          |dt          d          ddt	          |           dd          S )NCHF10fmprC   
T12:00:00ZfreshrT   currencycloseproviderprovider_marketprice_timestampquality_status)rO   appendr   r   r"   rP   rT   rS   s      r!   	get_pricezFreshProvider.get_price?   s    
/***%W^_cWdWdot  GL  ak  lv  aw  aw  ^C  ^C  ^C  T[  \  \  \  	\r#   r   r<   rT   r   rS   rU   r   r   )__name__
__module____qualname__namerQ   re   r2   r#   r!   rL   rL   ;   sV        D# # # #KO \ \ \ \ \ \ \ \r#   rL   c                :   t                      }t          |d           t                      |                     dfd           t	          |t          ddt                                          dd                    }|j        }|j	        }||k    }|j
        }||k    }|j        }||k    }	d}
||
k    }|r|r|	r|st          j        d|||	|fd	|||||
f          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |          t          j        |
          d	z  }dd|iz  }t%          t          j        |                    d x}x}x}x}	x}x}x}x}}
|j        }d}||u }|st          j        d|fd||f          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}j        }t-          |          }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        t,                    rt          j        t,                    nddt          j                    v st          j                  rt          j                  ndt          j        |          t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}x}}|                    d                                          d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}|                     dd             t	          |t          ddt                                          dd                    }|j        }d}||k    }|st          j        d|fd!||f          d"t          j                    v st          j        |          rt          j        |          nd"t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}|j	        }d}||k    }|st          j        d|fd#||f          d"t          j                    v st          j        |          rt          j        |          nd"t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}|j        }d}||u }|st          j        d|fd||f          d"t          j                    v st          j        |          rt          j        |          nd"t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}d S )$N   Djarvis_finance.services.market_service.equity_price_provider_by_namec                    S r   r2   _namer_   s    r!   <lambda>zJtest_batch_processes_all_22_and_resume_skips_fresh_cache.<locals>.<lambda>H       nv r#   autod   r   r_   limitrS   pacing_secondsmax_retries)==rz   rz   rz   )zJ%(py2)s
{%(py2)s = %(py0)s.total
} == %(py9)s
{%(py9)s = %(py7)s.updated
}zN%(py9)s
{%(py9)s = %(py7)s.updated
} == %(py12)s
{%(py12)s = %(py10)s.valued
}zX%(py12)s
{%(py12)s = %(py10)s.valued
} == %(py15)s
{%(py15)s = %(py13)s.coverage_total
}z:%(py15)s
{%(py15)s = %(py13)s.coverage_total
} == %(py17)sresult)	py0py2py7py9py10py12py13py15py17zassert %(py19)spy19Tis)z0%(py2)s
{%(py2)s = %(py0)s.complete
} is %(py5)sr|   r}   py5assert %(py7)sr~   rz   )zK%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.calls
})
} == %(py8)slenr_   r|   py1py3r   py8assert %(py10)sr   zVSELECT COUNT(*) FROM market_prices WHERE price_date='2026-07-24' AND close IS NOT NULLz%(py1)s == %(py4)sr   py4assert %(py6)spy6c                Z    d dD                                  t          d                    S )Nc              3     K   | ]}|V  d S r   r2   .0_s     r!   	<genexpr>z]test_batch_processes_all_22_and_resume_skips_fresh_cache.<locals>.<lambda>.<locals>.<genexpr>O   s$      n}n}uvopn}n}n}n}n}n}r#   r2   zfresh prices must be skippedthrowAssertionError)rq   s    r!   rr   zJtest_batch_processes_all_22_and_resume_skips_fresh_cache.<locals>.<lambda>O   sN    n}n}z|n}n}n}  oD  oD  ES  Tr  Es  Es  ot  ot r#   )z.%(py2)s
{%(py2)s = %(py0)s.cached
} == %(py5)sresumed)z/%(py2)s
{%(py2)s = %(py0)s.updated
} == %(py5)s)r.   rJ   rL   setattrr   r   r    r   totalupdatedvaluedcoverage_total
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprr   _format_explanationcompleterO   r   r*   fetchonecached)monkeypatchr-   r{   @py_assert1@py_assert8@py_assert3@py_assert11@py_assert4@py_assert14@py_assert5@py_assert16@py_assert6@py_format18@py_format20@py_format6@py_format8@py_assert2@py_assert7@py_format9@py_format11@py_assert0@py_format5@py_format7r   r_   s                           @r!   8test_batch_processes_all_22_and_resume_skips_fresh_cacher   D   s\	   ::DD"H^`v`v`v`vwww(/BFZ]jpjzjzj|j|  NO  ]^  0_  0_  0_  `  `F<Y6>Y<>YYV]Y>]YYf>SY]>SYYWYY>SWYYYYYYYYYYYYYYYYYYYY<>]>SWYYYYYYYYYYYYY6YYYYY6YYYYYY<YYYYYYYYYYY6YYYYY6YYYYYY>YYYYYYYYYYYVYYYYYVYYYYYY]YYYYYYYYYYYfYYYYYfYYYYYY>SYYYYWYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY?"d"?d""""""""""?d""""""""""""6"""""6""""""?""""d"""""""""""""""""""""""""""~$3~$"$"$$$$$$$$$$"$$$$$$$$$$$$3$$$$$3$$$$$$$$$$$$$x$$$$$x$$$$$$~$$$$$$$$"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$<<pqqzz||}~  F  DF  F  DF  F  F  F  F  F  F  F  F  F  F  DF  F  F  F  F  F  F  F  F  F  DF  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F^  at  at  u  u  u)$0CV[^kqk{k{k}k}  OP  ^_  1`  1`  1`  a  aG>R>R>R77>R?a?a?a77?a#t#t##########t############7#####7##########t#############################r#   c           
        t                      }t          |d           |                    dt                                          t
          f           |                                 t                      |                     dfd           t          |t          ddt                                          dd                    }g }|j        }d}||k    }|}|r%|j        }d}	||	k    }
|
}|
rj        }d	g}||k    }|}|st          j        d
|fd||f          dt!          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |r>t          j        d
|
fd||	f          dt!          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |	          dz  }dd|iz  }|                    |           |
rt          j        d
|fd||f          dt!          j                    v st          j                  rt          j                  ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t-          t          j        |                    d x}x}x}x}x}x}x}
x}	x}x}}t                      }t          |d           |                    dt                                          t
          f           |                                 t                      |                     dfd           t          |t          ddt                                          dd                    }g }|j        }d}||k    }|}|r%|j        }d}	||	k    }
|
}|
rj        }d	g}||k    }|}|st          j        d
|fd||f          dt!          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |r>t          j        d
|
fd||	f          dt!          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |	          dz  }dd|iz  }|                    |           |
rt          j        d
|fd||f          dt!          j                    v st          j                  rt          j                  ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t-          t          j        |                    d x}x}x}x}x}x}x}
x}	x}x}}d S )N   zINSERT INTO market_prices(market_price_id,instrument_id,price_date,close,currency,provider,provider_symbol,provider_market,quality_status,created_at)
                    VALUES('wrong-cache','inst-00',?,'99','USD','fmp','T00.SW','SIX','fresh',?)rn   c                    S r   r2   rp   s    r!   rr   zLtest_batch_does_not_treat_wrong_currency_cache_as_coverage.<locals>.<lambda>]   rs   r#   rt   ru   r   rv   T00.SWr   )z.%(py4)s
{%(py4)s = %(py2)s.cached
} == %(py7)sr{   r}   r   r~   %(py9)sr   )z3%(py13)s
{%(py13)s = %(py11)s.updated
} == %(py16)spy11r   py16%(py18)spy18)z1%(py22)s
{%(py22)s = %(py20)s.calls
} == %(py25)sr_   py20py22py25%(py27)spy27assert %(py30)spy30a  INSERT INTO market_prices(market_price_id,instrument_id,price_date,close,currency,provider,provider_symbol,provider_market,quality_status,created_at)
                    VALUES('wrong-exchange-cache','inst-00',?,'99','CHF','fmp','T00.SW','NASDAQ','fresh',?)c                    S r   r2   )rq   exchange_providers    r!   rr   zLtest_batch_does_not_treat_wrong_currency_cache_as_coverage.<locals>.<lambda>g   s    n r#   exchange_resultr   )r.   rJ   r*   r    r   r+   rE   rL   r   r   r   r   r   rO   r   r   r   r   r   r   rc   _format_boolopr   r   )r   r-   r{   r   r   r   r   r   @py_assert12@py_assert15r   @py_assert21@py_assert24@py_assert23r   @py_format10@py_format17@py_format19@py_format26@py_format28@py_format29@py_format31wrong_exchange_connr   r   r_   s                           @@r!   :test_batch_does_not_treat_wrong_currency_cache_as_coverager   V   s   ::DD!LL cekeueuewewy|d}  KKMMMH^`v`v`v`vwww(/BFZ]jpjzjzj|j|  NO  ]^  0_  0_  0_  `  `FVV6=VAV=AVVVVV&.VAV.A"5VVVVV(.VXJV.J:VVVVVVVVVVVV=AVVVVVVVVVVVV6VVVVV6VVVVVV=VVVVAVVVVVVVVVVVVVVVVVVVVVVVVVVV.AVVVVVVVVVVVV&VVVVV&VVVVVV.VVVVAVVVVVVVVVVVVVVVVVVVVVVVVVVV.JVVVVVVVVVVVV(VVVVV(VVVVVV.VVVVJVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV"**'+++ !oqw  rB  rB  rD  rD  FI  qJK K K   %^````  A  A  A12EGZdjru  CI  CS  CS  CU  CU  fg  uv  Hw  Hw  Hw  x  xOqq?!qQq!Q&qqqqq?+Bqaq+Ba+GqqqqqL]LcqhpgqqLcgqLqqqqqqqqqqqq!Qqqqqqqqqqqqq?qqqqq?qqqqqq!qqqqQqqqqqqqqqqqqqqqqqqqqqqqqqqq+Baqqqqqqqqqqqq?qqqqq?qqqqqq+BqqqqaqqqqqqqqqqqqqqqqqqqqqqqqqqqLcgqqqqqqqqqqqqqL]qqqqqL]qqqqqqLcqqqqgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr#   c           
     ~   t                      }t          |d            G d dt                    } |            |                     dfd           t	          |t          ddt                                          dd	                    }g }|j        }d}||k    }|}|r|j	        d         d
         }	d}
|	|
k    }|}|s@t          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |r`t          j        d|fd|	|
f          t          j        |	          t          j        |
          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t%          t          j        |                    d x}x}x}x}x}x}	x}}
|                    d                                          d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t%          t          j        |                    d x}x}}d S )Nr   c                      e Zd Zddd
d	ZdS )Rtest_rate_limit_retries_without_marking_instrument_inactive.<locals>.RetryProviderNrR   rT   r   rS   rU   r   r   c          
        | j                             |           t          | j                   dk    r't          |dd ddt	          |           ddd          S t          |dt          d	          ddt	          |           dd
          S )Nr   rW   rY   rC   rZ   rate_limitedfmp_rate_limitedrT   r]   r^   r_   r`   ra   rb   error_messagerX   r[   r\   )rO   rc   r   r   r"   r   rd   s      r!   re   z\test_rate_limit_retries_without_marking_instrument_inactive.<locals>.RetryProvider.get_pricep   s   Jo...4:!##'RW_cns  FK  `j  ku  `v  `v  ]B  ]B  ]B  Sa  qC  D  D  D  D#Oe[bcg[h[hsx  KP  eo  pz  e{  e{  bG  bG  bG  X_  `  `  `  `r#   rg   )rh   ri   rj   re   r2   r#   r!   RetryProviderr   o   s=        OS 	` 	` 	` 	` 	` 	` 	` 	`r#   r   rn   c                    S r   r2   rp   s    r!   rr   zMtest_rate_limit_retries_without_marking_instrument_inactive.<locals>.<lambda>v   rs   r#   rt   ru   r   rv   attempts   r   )z/%(py4)s
{%(py4)s = %(py2)s.updated
} == %(py7)sr{   r   r   r   )z%(py12)s == %(py15)s)r   r   z%(py17)sr   zassert %(py20)sr   zGSELECT instrument_status FROM instruments WHERE instrument_id='inst-00'suspected_inactive)!=)z%(py1)s != %(py4)sr   r   r   )r.   rJ   rL   r   r   r   r    r   r   resultsr   r   r   r   r   r   rc   r   r   r   r*   r   )r   r-   r   r{   r   r   r   r   r   r   r   @py_assert13r   r   @py_format16r   r   @py_format21r   r   r   r_   s                        @r!   ;test_rate_limit_retries_without_marking_instrument_inactiver   l   s$   ::DD!` ` ` ` ` ` ` ` }H^`v`v`v`vwww(/BFZ]jpjzjzj|j|  NO  ]^  0_  0_  0_  `  `FEE6>EQE>QEEEEE6>!#4Z#@EAE#@A#EEEEEEEEEEEE>QEEEEEEEEEEEE6EEEEE6EEEEEE>EEEEQEEEEEEEEEEEEEEEEEEEEEEEEEEE#@AEEEEE#@EEEEAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE<<abbkkmmnop  I  uI  Ip  uI  I  I  I  I  I  I  I  I  I  Ip  uI  I  I  I  I  Ip  I  I  I  I  uI  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  I  Ir#   c           
     2
   t                      }t          |dd           |                    d           |                                 |                     dd            t          |dt          dt                                          	                    }t          |t          dd
t                                          d                    }g }|j
        }d }||u }|}|r|j        }	d}
|	|
k    }|}|s~t          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |rt          j        d|fd|	|
f          dt          j                    v st          j        |          rt          j        |          ndt          j        |	          t          j        |
          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t)          t          j        |                    d x}x}x}x}x}x}	x}}
g }|j        }d}||k    }|}|r1t          j        } |            }t/          ||          }g }||k    }|}|s5t          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |rTt          j        d|fd||f          dt          j                    v st          j        t.                    rt          j        t.                    ndd t          j                    v st          j        |          rt          j        |          nd d!t          j                    v st          j        t                    rt          j        t                    nd!t          j        |          t          j        |          t          j        |          t          j        |          d"z  }d#d$|iz  }|                    |           t          j        |d          i z  }d%d&|iz  }t)          t          j        |                    d x}x}x}x}x}x}x}x}x}}d S )'Nr   Tr7   zfUPDATE instruments SET valuation_policy='exclude_from_auto_price_update' WHERE instrument_id='inst-00'rn   c                 Z    d dD                                  t          d                    S )Nc              3     K   | ]}|V  d S r   r2   r   s     r!   r   zVtest_excluded_instrument_is_not_fetched_or_valued.<locals>.<lambda>.<locals>.<genexpr>   s$      o~o~vwpqo~o~o~o~o~o~r#   r2   z&excluded instrument contacted providerr   )_argss    r!   rr   zCtest_excluded_instrument_is_not_fetched_or_valued.<locals>.<lambda>   sN    o~o~{}o~o~o~  pE  pE  FT  U}  F~  F~  p  p r#   inst-00rt   r_   rS   ru   r   )r_   rw   rS   rx   missingr   )z-%(py4)s
{%(py4)s = %(py2)s.close
} is %(py7)sdirectr   r   r   r   )z:%(py13)s
{%(py13)s = %(py11)s.quality_status
} == %(py16)sr   r   r   assert %(py21)spy21)as_of)z-%(py4)s
{%(py4)s = %(py2)s.total
} == %(py7)sbatch)z%(py19)s
{%(py19)s = %(py11)s(%(py12)s, as_of=%(py17)s
{%(py17)s = %(py15)s
{%(py15)s = %(py13)s.isoformat
}()
})
} == %(py22)sr   r-   r    )r   r   r   r   r   r   r   z%(py24)spy24zassert %(py27)sr   )r.   rJ   r*   rE   r   r   r   r    r   r   r^   rb   r   r   r   r   r   r   rc   r   r   r   r   r   )r   r-   r  r	  r   r   r   r   r   r   r   r   r   r   r   r   r   @py_format22r   @py_assert18r   @py_assert20@py_format23@py_format25r   r   s                             r!   1test_excluded_instrument_is_not_fetched_or_valuedr  |   s   ::DD!$////LLyzzzKKMMM^  a  a  @  @  @!$	3FPVcicscscucu3v3v3vwwF'.A6Y\ioiyiyi{i{  MN  /O  /O  /O  P  PEFF6<F4F<4FFFFFF$9FYF$9Y$FFFFFFFFFFFF<4FFFFFFFFFFFF6FFFFF6FFFFFF<FFFF4FFFFFFFFFFFFFFFFFFFFFFFFFFF$9YFFFFFFFFFFFFFFFFFFFFFFFFF$9FFFFYFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFcc5;c!c;!ccccc&JZcJZJZJ\J\c =dJ\ ] ] ]cacc ]ac cccccccccccc;!cccccccccccc5ccccc5cccccc;cccc!ccccccccccccccccccccccccccc ]accccccccccccc =ccccc =cccccccccccccdcccccdccccccccccccc&ccccc&ccccccJZccccJ\cccc ]ccccaccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccr#   c           	     6   d}t          |          }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        t                     rt          j        t                     ndt          j        |          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}x}}d	}t          |          }d
}||k    }|st          j        d|fd||f          dt          j                    v st          j        t                     rt          j        t                     ndt          j        |          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}x}}d}t          |          }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        t                     rt          j        t                     ndt          j        |          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}x}}t                      }t          |d           t          ddt          d          dddd          |                     dfd           t          |dt          dt                                                               }|j        }d}	||	k    }|st          j        d|fd||	f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |	          dz  }
dd |
iz  }t          t          j        |                    d x}x}}	|                    d!                                          d"         }d"}||k    }|slt          j        d|fd#||f          t          j        |          t          j        |          d$z  }d%d&|iz  }t          t          j        |                    d x}x}}t          dd't          d          ddd(d          |                     dfd)           t          |dt          dt                                                               }|j        }d*}	||	k    }|st          j        d|fd||	f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |	          dz  }
dd |
iz  }t          t          j        |                    d x}x}}	|                    d!                                          d"         }d"}||k    }|slt          j        d|fd#||f          t          j        |          t          j        |          d$z  }d%d&|iz  }t          t          j        |                    d x}x}}d S )+Nfmp_endpoint_restrictedplan_restrictedr   z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr   r|   r}   r   r~   assert %(py9)sr   fmp_auth_error
auth_errorr   r   r   r   rW   11yfinanceXSWXz2026-07-25T12:00:00Zr[   r\   rn   c                @     t          dddfdi                      S )NPr2   re   c                    S r   r2   )rP   r  _kwargsfutures      r!   rr   zZtest_provider_error_classes_future_and_currency_guards.<locals>.<lambda>.<locals>.<lambda>   s      kq r#   type)rq   r   s    r!   rr   zHtest_provider_error_classes_future_and_currency_guards.<locals>.<lambda>   s[      osnrsvxz  ~I  Kq  Kq  Kq  Kq  }r  os  os  ou  ou r#   r  rt   r  future_price_rejected)z6%(py2)s
{%(py2)s = %(py0)s.quality_status
} == %(py5)srejectedr   r   r~   z"SELECT COUNT(*) FROM market_pricesr   r   r   r   r   USDz2026-07-24T12:00:00Zc                @     t          dddfdi                      S )Nr  r2   re   c                    S r   r2   )rP   r  r  mismatchs      r!   rr   zZtest_provider_error_classes_future_and_currency_guards.<locals>.<lambda>.<locals>.<lambda>   s      ks r#   r!  )rq   r(  s    r!   rr   zHtest_provider_error_classes_future_and_currency_guards.<locals>.<lambda>   s[      ounrsvxz  ~I  Ks  Ks  Ks  Ks  }t  ou  ou  ow  ow r#   currency_mismatch)r   r   r   r   r   r   r   r   r   r.   rJ   r   r   r   r   r   r    r   rb   r*   r   )r   r   r   r   r   r   r   r-   r$  r   r   r   r   r   r   r   r(  s                  @@r!   6test_provider_error_classes_future_and_currency_guardsr*     s   8N899N=NN9=NNNNNNNNNNN9=NNNNNNNNNNNNNNNNNNNNNNNN8NNNN9NNNN=NNNNNNNNNNNNNNNNNNNNNNNNNNNNNN/@/00@L@0L@@@@@@@@@@0L@@@@@@@@@@@@@@@@@@@@@@@/@@@@0@@@@L@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1D122DnD2nDDDDDDDDDD2nDDDDDDDDDDDDDDDDDDDDDDD1DDDD2DDDDnDDDDDDDDDDDDDDDDDDDDDDDDDDDDD::DD!hgVZmmfp  CI  [q  BI  J  J  JF^  au  au  au  au  v  v  v#D)5HRXekeueuewew5x5x5xyyH"=&=="&==========="&=============8=====8======"====&============================<<<==FFHHKPqPKqPPPPPPPPPPKqPPPPPKPPPPqPPPPPPPPPPPPPPPPPPPPPPPPPPP5PWX\P]P]hr  EK  ]s  DK  L  L  LH^  aw  aw  aw  aw  x  x  x#D)5HRXekeueuewew5x5x5xyyH"9&99"&99999999999"&99999999999998999998999999"9999&9999999999999999999999999999<<<==FFHHKPqPKqPPPPPPPPPPKqPPPPPKPPPPqPPPPPPPPPPPPPPPPPPPPPPPPPPPPPr#   c                 x   t                      } t          |           }g }|j        }d}||k    }|}|r |j        }d}||u }	|	}|	r|j        }
d }|
|u }|}|st          j        d|fd||f          dt          j                    v st          j	        |          rt          j
        |          ndt          j
        |          t          j
        |          dz  }dd|iz  }|                    |           |r>t          j        d	|	fd
||f          dt          j                    v st          j	        |          rt          j
        |          ndt          j
        |          t          j
        |          dz  }dd|iz  }|                    |           |	rt          j        d	|fd|
|f          dt          j                    v st          j	        |          rt          j
        |          ndt          j
        |
          t          j
        |          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t          t          j        |                    d x}x}x}x}x}x}x}	x}x}
x}}t          | dd            G d d          }t!          | t"                                          d |            i          }|j        }d}||k    }|st          j        d|fd||f          dt          j                    v st          j	        |          rt          j
        |          ndt          j
        |          t          j
        |          dz  }d d!|iz  }t          t          j        |                    d x}x}}t'          |           }t)          |          }d}||k    }|st          j        d|fd"||f          d#t          j                    v st          j	        t(                    rt          j
        t(                    nd#d$t          j                    v st          j	        |          rt          j
        |          nd$t          j
        |          t          j
        |          d%z  }d&d'|iz  }t          t          j        |                    d x}x}}d( |D             }t+          |          }d)}||k    }|st          j        d|fd*||f          d+t          j                    v st          j	        t*                    rt          j
        t*                    nd+t          j
        |          t          j
        |          t          j
        |          d,z  }d-d|iz  }t          t          j        |                    d x}x}x}}t          |           }|j        }d}||u }|st          j        d	|fd.||f          d/t          j                    v st          j	        |          rt          j
        |          nd/t          j
        |          t          j
        |          dz  }d d!|iz  }t          t          j        |                    d x}x}}|j        }d }||u }|st          j        d	|fd0||f          d/t          j                    v st          j	        |          rt          j
        |          nd/t          j
        |          t          j
        |          dz  }d d!|iz  }t          t          j        |                    d x}x}}|j        }d1}||k    }|st          j        d|fd2||f          d/t          j                    v st          j	        |          rt          j
        |          nd/t          j
        |          t          j
        |          dz  }d d!|iz  }t          t          j        |                    d x}x}}|j        }d)}||k    }|st          j        d|fd3||f          d/t          j                    v st          j	        |          rt          j
        |          nd/t          j
        |          t          j
        |          dz  }d d!|iz  }t          t          j        |                    d x}x}}|j        }d4d5g}||k    }|st          j        d|fd6||f          d/t          j                    v st          j	        |          rt          j
        |          nd/t          j
        |          t          j
        |          dz  }d d!|iz  }t          t          j        |                    d x}x}}d7 |D             }t3          |          }|sd8d9t          j                    v st          j	        t2                    rt          j
        t2                    nd9t          j
        |          t          j
        |          d:z  }t          t          j        |                    d x}}d S );NunavailableFr   z.%(py4)s
{%(py4)s = %(py2)s.status
} == %(py7)semptyr   r   r   r   )z=%(py13)s
{%(py13)s = %(py11)s.coverage_complete
} is %(py16)sr   r   r   )z<%(py22)s
{%(py22)s = %(py20)s.equity_value_chf
} is %(py25)sr   r   r   r   r   r      Tr7   c                       e Zd ZdZdddd
ZdS )^test_unknown_values_remain_null_and_partial_summary_lists_all_missing.<locals>.PartialProviderrY   NrR   rT   r   rS   rU   r   r   c          
         |dk    rt          d          nd }t          |d|ddt          |           d|rdnd|rd nd	
          S )Nr   rX   rW   rY   rC   rZ   r[   endpoint_restrictedr  r   )r   r   r"   )rP   rT   rS   r^   s       r!   re   zhtest_unknown_values_remain_null_and_partial_summary_lists_all_missing.<locals>.PartialProvider.get_price   s    %4%@%@GDMMMdE#Oe[`kp  CH  ]g  hr  ]s  ]s  Z  Z  Z  [`  P{  PW  PW  f{  SX  Kw  KO  KO  ^w  x  x  x  xr#   rg   rh   ri   rj   rk   re   r2   r#   r!   PartialProviderr1     sB        OS 	x 	x 	x 	x 	x 	x 	x 	xr#   r5  rY   r  price_providerspartial)z.%(py2)s
{%(py2)s = %(py0)s.status
} == %(py5)sr{   r   r   r~   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   rows)r|   r   r   r   zassert %(py8)sr   c              3  (   K   | ]}|j         d u V  d S r   )market_value_chfr   rows     r!   r   zXtest_unknown_values_remain_null_and_partial_summary_lists_all_missing.<locals>.<genexpr>   s*      <<s#t+<<<<<<r#   r   r  sumr  r  )z9%(py2)s
{%(py2)s = %(py0)s.coverage_complete
} is %(py5)ssummary)z8%(py2)s
{%(py2)s = %(py0)s.equity_value_chf
} is %(py5)sz10.00)z:%(py2)s
{%(py2)s = %(py0)s.valued_partial_chf
} == %(py5)s)z:%(py2)s
{%(py2)s = %(py0)s.unvalued_positions
} == %(py5)sT01T02)z8%(py2)s
{%(py2)s = %(py0)s.unvalued_tickers
} == %(py5)sc              3  (   K   | ]}|j         d u V  d S r   )portfolio_share_pctr<  s     r!   r   zXtest_unknown_values_remain_null_and_partial_summary_lists_all_missing.<locals>.<genexpr>   s*      ??3s&$.??????r#   z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}all)r|   r}   r   )r.   r   statuscoverage_completeequity_value_chfr   r   r   r   r   r   rc   r   r   r   rJ   r   r    r   r   r   r>  valued_partial_chfunvalued_positionsunvalued_tickersrD  )r-   r.  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r5  r{   r   r   r9  r   r   r   r?  r   s                                  r!   Etest_unknown_values_remain_null_and_partial_summary_lists_all_missingrK     s   ::Dt$$Epp5<p=p<=(pppppU-Dpp-D-MpppppRWRhplppRhlpRpppppppppppp<=pppppppppppp5ppppp5pppppp<pppp=ppppppppppppppppppppppppppp-DppppppppppppUpppppUpppppp-DpppppppppppppppppppppppppppppppRhlpppppppppppppRWpppppRWppppppRhpppplppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppD!$////x x x x x x x x
 (F4D4D4F4FY^`o`o`q`qXrsssF=%I%=I%%%%%%%%%%=I%%%%%%%%%%%%6%%%%%6%%%%%%=%%%%I%%%%%%%%%%%%%%%%%%%%%%%%%%% &&Dt999>933tt9<<t<<<A3<<<AA<AAAAAAAAAA<AAAAAAAAAAAA3AAAAA3AAAAAA<AAAA<AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA &&G$--$----------$------------7-----7------$-------------------------------#+t+#t++++++++++#t++++++++++++7+++++7++++++#++++t+++++++++++++++++++++++++++%00%0000000000%0000000000007000007000000%0000000000000000000000000000000%**%**********%************7*****7******%*******************************#5u~5#~5555555555#~5555555555557555557555555#5555~555555555555555555555555555??$????3????????????????3?????3?????????????????????????????????r#   c                    t                      } t          | dd            G d d          }t          | t                                          d |            i          }g }|j        }d}||k    }|}|rd	}|j        }	||	v }
|
}|s~t          j        d
|fd||f          dt          j
                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |rt          j        d|
fd||	f          t          j        |          dt          j
                    v st          j        |          rt          j        |          ndt          j        |	          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t          t          j        |                    d x}x}x}x}x}x}x}
}	t#          |           d         }t%          |           }g }|j        }d }||u }|}|r|j        }d	}	||	k    }|}|s~t          j        d|fd||f          dt          j
                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |rt          j        d
|fd||	f          dt          j
                    v st          j        |          rt          j        |          ndt          j        |          t          j        |	          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t          t          j        |                    d x}x}x}x}x}x}x}}	g }|j        }d}||u }|}|r|j        }d }	||	u }|}|s~t          j        d|fd||f          dt          j
                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |rt          j        d|fd ||	f          dt          j
                    v st          j        |          rt          j        |          ndt          j        |          t          j        |	          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t          t          j        |                    d x}x}x}x}x}x}x}}	t/          |           }|j        }g }||k    }|st          j        d
|fd!||f          d"t          j
                    v st          j        t.                    rt          j        t.                    nd"d#t          j
                    v st          j        |           rt          j        |           nd#t          j        |          t          j        |          t          j        |          d$z  }d%d&|iz  }t          t          j        |                    d x}x}x}}d S )'Nr   Tr7   c                       e Zd ZdZdddd
ZdS )btest_stale_snapshot_values_remain_unknown_and_global_signals_are_suppressed.<locals>.StaleProviderrY   NrR   rT   r   rS   rU   r   r   c          	     H    t          |dt          d          dddd          S )NrW   rX   rY   rC   z2026-07-20T12:00:00Zr[   r\   )r   r   rd   s      r!   re   zltest_stale_snapshot_values_remain_unknown_and_global_signals_are_suppressed.<locals>.StaleProvider.get_price   sE    #Oe[bcg[h[hsx  KP  bx  IP  Q  Q  Q  Qr#   rg   r4  r2   r#   r!   StaleProviderrN     sB        OS 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Qr#   rP  rY   r6  r8  stale_pricer   r-  r{   r   r   r   )in)z8%(py12)s in %(py16)s
{%(py16)s = %(py14)s.reason_codes
})r   py14r   r   r   r   r  r  r   )z8%(py4)s
{%(py4)s = %(py2)s.market_value_chf
} is %(py7)sposition)z7%(py13)s
{%(py13)s = %(py11)s.status_code
} == %(py16)sr   F)z9%(py4)s
{%(py4)s = %(py2)s.coverage_complete
} is %(py7)sr?  )z<%(py13)s
{%(py13)s = %(py11)s.equity_value_chf
} is %(py16)s)zX%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}.investment_signals
} == %(py8)sr   r-   r   r   r   )r.   rJ   r   r    r   rE  reason_codesr   r   r   r   r   r   rc   r   r   r   r   r   r;  status_coderF  rG  r   investment_signals)r-   rP  r{   r   r   r   r   r   r   r   r   r   r   r   r   r   r  rT  r?  r   r   r   r   r   r   r   s                             r!   Ktest_stale_snapshot_values_remain_unknown_and_global_signals_are_suppressedrX     sC   ::DD!$////Q Q Q Q Q Q Q Q (F4D4D4F4FY^`m`m`o`oXpqqqFNN6=NIN=I%NNNNN-N6;NN-;N*NNNNNNNNNNNN=INNNNNNNNNNNN6NNNNN6NNNNNN=NNNNINNNNNNNNNNNNNNNNNNNNNNNNNNN-;NNNNNN-NNNNNNNNNNN6NNNNN6NNNNNN;NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN$T**1-H &&GVV8$VV$,VVVVV1EVV1E1VVVVVVVVVVVV$VVVVVVVVVVVV8VVVVV8VVVVVV$VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV1EVVVVVVVVVVVVVVVVVVVVVVV1EVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVRR7$RR$-RRRRR'2JRdR2Jd2RRRRRRRRRRRR$RRRRRRRRRRRR7RRRRR7RRRRRR$RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR2JdRRRRRRRRRRRR'RRRRR'RRRRRR2JRRRRdRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR)$//H/BHbHBbHHHHHHHHHHBbHHHHHHHHHHHH)HHHHH)HHHHHHHHHHHHH$HHHHH$HHHHHH/HHHHBHHHHbHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHr#   c           	        t                      }t          |dd           |                     dd            t          |          }|j        }d} ||          }|j        }d}||k    }|st          j        d|fd	||f          d
t          j	                    v st          j
        |          rt          j        |          nd
t          j        |          t          j        |          t          j        |          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}x}x}}|j        }d} ||          }|j        }d}||k    }|st          j        d|fd	||f          d
t          j	                    v st          j
        |          rt          j        |          nd
t          j        |          t          j        |          t          j        |          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}x}x}}d S )Nr   Tr7   rn   c                 Z    d dD                                  t          d                    S )Nc              3     K   | ]}|V  d S r   r2   r   s     r!   r   zUtest_equity_get_endpoints_do_not_invoke_provider.<locals>.<lambda>.<locals>.<genexpr>   sH        {J  {J  BC{|  {J  {J  {J  {J  {J  {Jr#   r2   zGET render called providerr   )r  r  s     r!   rr   zBtest_equity_get_endpoints_do_not_invoke_provider.<locals>.<lambda>   sf      {J  {J  GI  {J  {J  {J  {P  {P  Q_  `|  Q}  Q}  {~  {~ r#   z/api/equity/positions   r   )zk%(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
}.status_code
} == %(py11)sclient)r|   r}   r   r   r   r   zassert %(py13)sr   z/api/equity/summary)r.   rJ   r   r6   getrV  r   r   r   r   r   r   r   r   )r   r-   r]  r   r   r   r   @py_assert10@py_assert9@py_format12@py_format14s              r!   0test_equity_get_endpoints_do_not_invoke_providerrc     s   ::DD!$////^  a~  a~      T]]F:A-A::-..A.:AcA:cAAAAAAAAAA:cAAAAAAAAAAAA6AAAAA6AAAAAA:AAAA-AAAA.AAAA:AAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:?+?::+,,?,8?C?8C??????????8C????????????6?????6??????:????+????,????8????C???????????????????????????????????r#   )r   r   r   r   )r   r   )r-   r   r   r   )r-   r   r9   r:   r8   r;   r   r<   rf   )7
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   collections.abcr   datetimer   decimalr   r&   r   fastapi.testclientr   jarvis_finance.api.dependenciesr	   jarvis_finance.api.mainr
   !jarvis_finance.api.schemas.marketr   !jarvis_finance.market_data.pricesr   &jarvis_finance.services.equity_servicer   r   &jarvis_finance.services.market_servicer   r   r   +jarvis_finance.services.portfolio_analyticsr   r   )jarvis_finance.services.portfolio_advisorr   !jarvis_finance.storage.migrationsr   r+   r    r"   r.   r6   rJ   rL   r   r   r   r  r*  rK  rX  rc  r2   r#   r!   <module>rv     s   " " " " " "               $ $ $ $ $ $                    ) ) ) ) ) ) 2 2 2 2 2 2 . . . . . . A A A A A A > > > > > > \ \ \ \ \ \ \ \ y y y y y y y y y y q q q q q q q q T T T T T T > > > > > >	dAr		^ ^ ^ ^       KP 	 	 	 	 	 	\ \ \ \ \ \ \ \$ $ $ $$r r r r,I I I I 	d 	d 	d 	dQ Q Q Q(@ @ @ @0I I I I&@ @ @ @ @ @r#   