o
    %#«j0
  ã                   @   s¾   d Z ddlZddlZddlmZ ddlmZ eeƒ ¡ j	Z
e
d Ze
d Zdefdd	„Zeeƒ ed
d�defdd„ƒZdefdd„ZG dd„ dƒZed
d�defdd„ƒZddœdd„ZdS )a…  
config_loader.py

Single source of truth for reading THIS project's own config.json and
.env credentials (screener/trade -- separate files, separate process,
no relationship to screener/premarket's config_loader.py of the same
name, despite the identical pattern). Every other module here imports
get_config() / get_env() from here instead of touching os.environ or
config.json directly.
é    N)ÚPath)Ú	lru_cachezconfig.jsonz.envÚpathc                 C   s    |   ¡ sdS t| dƒ�;}|D ]/}| ¡ }|r| d¡sd|vr q| d¡\}}}| ¡ }| ¡  d¡ d¡}tj ||¡ qW d  ƒ dS 1 sIw   Y  dS )z6Minimal .env loader (no external dependency required).NÚrú#ú=ú"ú')ÚexistsÚopenÚstripÚ
startswithÚ	partitionÚosÚenvironÚ
setdefault)r   ÚfÚlineÚkeyÚ_Úvalue© r   úconfig_loader.pyÚ_load_dotenv   s   ù"ÿr   é   )ÚmaxsizeÚreturnc                  C   s8   t tdƒ�} t | ¡W  d   ƒ S 1 sw   Y  d S )Nr   )r   ÚCONFIG_PATHÚjsonÚload)r   r   r   r   Ú
get_config(   s   $ÿr    c                   C   s   t  ¡  t ƒ S )zEForce re-read of config.json (useful if tuning live without restart).)r    Úcache_clearr   r   r   r   Úreload_config.   s   r"   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )Ú	EnvConfigz@Wraps required Alpaca credentials with clear failure if missing.c                 C   s@   t j d¡| _t j d¡| _t j dd¡| _t j dd¡| _d S )NÚALPACA_API_KEYÚALPACA_SECRET_KEYÚAPCA_API_BASE_URLz https://paper-api.alpaca.marketsÚALPACA_DATA_URLzhttps://data.alpaca.markets)r   r   ÚgetÚapi_keyÚ
secret_keyÚbase_urlÚdata_url)Úselfr   r   r   Ú__init__7   s   zEnvConfig.__init__c                 C   sB   g }| j s
| d¡ | js| d¡ |rtdd |¡› d�ƒ‚d S )Nr$   r%   z(Missing required environment variables: z, z@. Copy .env.example to .env and fill in your Alpaca credentials.)r)   Úappendr*   ÚEnvironmentErrorÚjoin)r-   Úmissingr   r   r   Úvalidate=   s   

ÿÿzEnvConfig.validateN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r.   r3   r   r   r   r   r#   4   s    r#   c                   C   s   t ƒ S )N)r#   r   r   r   r   Úget_envJ   s   r8   )Údefaultc                 G   s6   t ƒ }|D ]}t|tƒr||vr|   S || }q|S )zOConvenience getter for nested config values, e.g. cfg("universe", "price_min").)r    Ú
isinstanceÚdict)r9   ÚkeysÚnodeÚkr   r   r   ÚcfgO   s   
r?   )r7   r   r   Úpathlibr   Ú	functoolsr   Ú__file__ÚresolveÚparentÚBASE_DIRr   ÚENV_PATHr   r;   r    r"   r#   r8   r?   r   r   r   r   Ú<module>   s"    