Files
OpenBB/openbb_terminal/session/hub_model.py
James Maslek 707ae7e317 Release 2.5.0 (#4355)
* Rename SDK folder

* Fixing all the tests I hope

* Depreciate the sia menu

* Fix routine script

* Update SDK generation scripts

* This needed fixing anyways

* Regenerate SDK files

* Update paths in sdk helpers

* Regenerate the remains of the SDK

* Fix candle not working with symbol via the sdk

* Fix pydocstyle errors

* deps

* Add in Docstrings

* Push to website since I need to upload images

* typos

* Add in Fixed Income Guide

* Tests : fix cassette

* changes to layout and adding more content

* trailmap

* poetry

* updates to requirements files

* add `_try_to_login` to sdk generation, fix `_chart` in `about()` url

* sentiment analysis

* refactor

* changing to base model default

* rounding

* renewing poetry

* fixed poetry

* spacing

* black

* adds selectable models for realized volatility calculations

* fixes line too long

* Add intro guides to Fixed Income

* Fix some missing docstrings

* Fix website not working

* missed a few

* fix /economy/test_yfinance_view tests

* fix etf/test_stockanalysis_model.py

* fix etf/test_stockanalysis_view.py

* fix test_stocks_controller

* deprecating non used function

* update financedatabase to 2.0.4

* Delete SIA from OpenBB Docs and SDK

* Searching was not done properly for short name and index

* changes the default data source for crypto.load

* Fix tests I broke

* Little fixy fix to remove duplicates

* Fix tests

* typo

* adds check for empty dataframe

* Patch Equity Report

* Update so that image links to website

* linting v2

* silly imports

* adding tempfile

* add imap unordered

* reordering imports

* Adding databento as a source (#4293)

* First commit

* Baby steps

* Keys and sdk

* Fix import for api key

* Add SDK endpoints

* Test + api checks

* tests

* roque print of api key

* Changes

* minor

* custom timeout

* improve timeouts

---------

Co-authored-by: hjoaquim <h.joaquim@campus.fct.unl.pt>

* Tests

* Integration test

* frozendict remove

* update spec

* rename sdk faq to troubleshooting

* add hidden import

* add hidden imports

* imports again

* valid url check

* new lines and prompt

* split imports

* more spec

* adds cones to the crypto-ta menu

* Fix tests

* Update code to reflect new changes to FinanceDatabase

* Small bugfix for DCF if you have no ticker loaded

* remove yfinance from news

* add reverse fx choices

* black

* ruff

* Add options greeks to the SDK

* Linting

* Delete rogue file and update test and add fixedincome to en.yml

* fix for options screener

* ruff

* updates tests for options screener

* reqs

* updates more test files

* rewrite for test_github_model

* rewrite test for test_syncretism_view

* removes test_view_available_presets[]

* black

* coverage

* adds option screener preset

* Update directories.py

* len & set

* set all list

* adds unit testing for cones

* ruff

* pylint

* adds options screener endpoint to SDK

* test markers

* Testing draft PR mode

* Update package to v2.0.7

* Remove etf/screener and tests

* Updated

* Merge reqs

* Updated readme

* hook test for pyinstaller

* Little fixy fix

* Remove etf/scr from SDK

* Update tests

* Update hook-whisper.py

* oops lol

* Update sdk

* update

* Etf

* removed old trailmap csv's

* Update fixedincome text

* add greeks to trail

* rouge file

* merge killed it

* fix test

* fix build failure

* catch for error message

* fix for frozendict

* caching search and prompting on hub

* whisper model prompts

* Fix long/short issue and fix transform issue

* separates volatility models from cones function

* Introduce CPI functionality

* improves error handling for volatility models when window length is too small

* ur welcome <3

* additional sanity check for volatility_view

* updates volatility_model test

* black

* Fix linting

* Make cpi a little bit more robust

* Add in missing value

* sdk updates

* update dep files

* Update trail_map_forecasting.csv

* import ordering pylint?

* fix trailing comma

* sorted trailmaps

* remove one test artifact

* rewrite test

* Adds the missing pieces.

* adds clickable URL in keys + Databento

* adds databento images

* adds images for Databento

* update deps

* req files

* swap order in databento

* ruff

* mypy

* lint

* sdk

* makes requested changes

* ruff v2..

* replaces screenshot.

* Removed because it shouldn't have been in this PR.

* ruff v3

* Minor edit, move installation to position 2 instead of last

* util linting changes

* linting for controller

* fix test

* test

* Revert some tests

* Guess not

* see if this sticks

* fixes

* Fix linters.  Add --video if not provided

* Checkout develop tests for keys

* Release time

* Revert papermill and update gh pages action

* Fix shortname (#4356)

* uninstall brotli on conda test

* Fix issue 4316 (#4357)

* Fix issue 4316

* Updating polygon_model + options_controller

* Tests : FRED

* ruff

---------

Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com>
Co-authored-by: Jeroen Bouma <jer.bouma@gmail.com>
Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com>
Co-authored-by: hjoaquim <h.joaquim@campus.fct.unl.pt>
Co-authored-by: Chavithra PARANA <chavithra@gmail.com>
Co-authored-by: teh_coderer <me@tehcoderer.com>
Co-authored-by: martinb-bb <105685594+martinb-bb@users.noreply.github.com>
Co-authored-by: Diogo Sousa <montezdesousa@gmail.com>
Co-authored-by: northern-64bit <75195383+northern-64bit@users.noreply.github.com>
Co-authored-by: luqazino@gmail.com <luqazino@gmail.com>
Co-authored-by: colin99d <colin99delahunty@gmail.com>
Co-authored-by: montezdesousa <79287829+montezdesousa@users.noreply.github.com>
Co-authored-by: andrewkenreich <andrew.kenreich@gmail.com>
2023-03-01 08:47:12 -05:00

678 lines
18 KiB
Python

import json
from typing import Dict, Optional
import requests
from openbb_terminal.rich_config import console
REGISTER_URL = "https://my.openbb.dev/register"
BASE_URL = "https://payments.openbb.dev/"
# BASE_URL = "http://127.0.0.1:8000/"
TIMEOUT = 15
CONNECTION_ERROR_MSG = "[red]Connection error.[/red]"
CONNECTION_TIMEOUT_MSG = "[red]Connection timeout.[/red]"
def create_session(
email: str, password: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
) -> Optional[requests.Response]:
"""Create a session.
Parameters
----------
email : str
The email.
password : str
The password.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the login request.
"""
try:
data = {
"email": email,
"password": password,
"remember": True,
}
return requests.post(url=base_url + "login", json=data, timeout=timeout)
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("\n[red]Failed to request login info.[/red]")
return None
def create_session_from_token(
token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
):
"""Create a session from token.
Parameters
----------
token : str
The token.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
"""
try:
data = {
"token": token,
}
return requests.post(url=base_url + "sdk/login", json=data, timeout=timeout)
except requests.exceptions.ConnectionError:
console.print("\n[red]Connection error.[/red]")
return None
except requests.exceptions.Timeout:
console.print("\n[red]Connection timeout.[/red]")
return None
except Exception:
console.print("\n[red]Failed to request login info.[/red]")
return None
def delete_session(
auth_header: str, token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
) -> Optional[requests.Response]:
"""Delete the session.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
token : str
The token to delete.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the logout request.
"""
try:
response = requests.post(
url=base_url + "logout",
headers={"Authorization": auth_header},
json={"token": token},
timeout=timeout,
)
if response.status_code != 200:
console.print("[red]Failed to delete server session.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to delete server session.[/red]")
return None
def process_session_response(response: requests.Response) -> dict:
"""Process the response from the login request.
Parameters
----------
response : requests.Response
The response from the login request.
Returns
-------
dict
The login info.
"""
if response.status_code == 200:
login = response.json()
return login
if response.status_code == 401:
console.print("\n[red]Wrong credentials.[/red]")
return {}
if response.status_code == 403:
console.print("\n[red]Unverified email.[/red]")
return {}
console.print("\n[red]Failed to login.[/red]")
return {}
def get_session(email: str, password: str) -> dict:
"""Get the session info.
Parameters
----------
email : str
The email.
password : str
The password.
Returns
-------
dict
The session info.
"""
response = create_session(email, password)
if response is None:
return {}
return process_session_response(response)
def get_session_from_token(token: str) -> dict:
"""Get the session info from token.
Parameters
----------
token : str
The token.
Returns
-------
dict
The session info.
"""
response = create_session_from_token(token)
if response is None:
return {}
return process_session_response(response)
def fetch_user_configs(
session: dict, base_url: str = BASE_URL, timeout: int = TIMEOUT
) -> Optional[requests.Response]:
"""Fetch user configurations.
Parameters
----------
session : dict
The session info.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the get request.
"""
token_type = session.get("token_type", "")
token = session.get("access_token", "")
try:
response = requests.get(
url=base_url + "terminal/user",
headers={"Authorization": f"{token_type.title()} {token}"},
timeout=timeout,
)
if response.status_code not in [200, 401]: # 401: invalid token
console.print("[red]\nFailed to fetch configurations.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]\nFailed to fetch configurations.[/red]")
return None
def patch_user_configs(
key: str,
value: str,
type_: str,
auth_header: str,
base_url: str = BASE_URL,
timeout: int = TIMEOUT,
) -> Optional[requests.Response]:
"""Patch user configurations to the server.
Parameters
----------
key : str
The key to patch.
value : str
The value to patch.
type_ : str
The type of the patch, either "keys" or "settings".
auth_header : str
The authorization header, e.g. "Bearer <token>".
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the patch request.
"""
if type_ not in ["keys", "settings"]:
console.print("[red]\nInvalid patch type.[/red]")
return None
data = {"key": f"features_{type_}.{key}", "value": value}
try:
response = requests.patch(
url=base_url + "terminal/user",
headers={"Authorization": auth_header},
json=data,
timeout=timeout,
)
if response.status_code == 200:
console.print("[green]Saved remotely.[/green]")
else:
console.print("[red]Failed to save remotely.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to save remotely.[/red]")
return None
def clear_user_configs(
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
) -> Optional[requests.Response]:
"""Clear user configurations to the server.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the put request.
"""
data: Dict[str, dict] = {"features_keys": {}, "features_settings": {}}
try:
response = requests.put(
url=base_url + "terminal/user",
headers={"Authorization": auth_header},
json=data,
timeout=timeout,
)
if response.status_code == 200:
console.print("[green]Cleared configurations.[/green]")
else:
console.print("[red]Failed to clear configurations.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to clear configurations.[/red]")
return None
def upload_routine(
auth_header: str,
name: str = "",
description: str = "",
routine: str = "",
override: bool = False,
base_url=BASE_URL,
timeout: int = TIMEOUT,
) -> Optional[requests.Response]:
"""Send a routine to the server.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
name : str
The name of the routine.
routine : str
The routine.
override : bool
Whether to override the routine if it already exists.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the post request.
"""
data = {
"name": name,
"description": description,
"script": routine,
"override": override,
}
try:
response = requests.post(
headers={"Authorization": auth_header},
url=base_url + "terminal/script",
json=data,
timeout=timeout,
)
if response.status_code == 200:
console.print("[green]Successfully uploaded your routine.[/green]")
elif response.status_code != 409: # 409: routine already exists
console.print(
"[red]" + response.json().get("detail", "Unknown error.") + "[/red]"
)
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to upload your routine.[/red]")
return None
def download_routine(
auth_header: str,
name: str = "",
base_url=BASE_URL,
timeout: int = TIMEOUT,
) -> Optional[requests.Response]:
"""Download a routine from the server.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
name : str
The name of the routine.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the get request.
"""
try:
response = requests.get(
headers={"Authorization": auth_header},
url=base_url + "terminal/script/" + name,
timeout=timeout,
)
if response.status_code == 404:
console.print("[red]Routine not found.[/red]")
elif response.status_code != 200:
console.print("[red]Failed to download your routine.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to download your routine.[/red]")
return None
def delete_routine(
auth_header: str,
name: str = "",
base_url=BASE_URL,
timeout: int = TIMEOUT,
) -> Optional[requests.Response]:
"""Delete a routine from the server.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
name : str
The name of the routine.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the delete request.
"""
try:
response = requests.delete(
headers={"Authorization": auth_header},
url=base_url + "terminal/script/" + name,
timeout=timeout,
)
if response.status_code == 200:
console.print("[green]Successfully deleted your routine.[/green]")
elif response.status_code == 404:
console.print("[red]Routine not found.[/red]")
else:
console.print("[red]Failed to delete your routine.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to delete your routine.[/red]")
return None
def list_routines(
auth_header: str,
page: int = 1,
size: int = 10,
base_url=BASE_URL,
timeout: int = TIMEOUT,
) -> Optional[requests.Response]:
"""List all routines from the server.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
page : int
The page number.
size : int
The number of routines per page.
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
The response from the get request.
"""
fields = "name%2Cdescription"
try:
response = requests.get(
headers={"Authorization": auth_header},
url=f"{base_url}terminal/script?fields={fields}&page={page}&size={size}",
timeout=timeout,
)
if response.status_code != 200:
console.print("[red]Failed to list your routines.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to list your routines.[/red]")
return None
def generate_personal_access_token(
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT, days: int = 30
) -> Optional[requests.Response]:
"""
Generate an OpenBB Personal Access Token.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
days : int
The number of days the token should be valid for.
Returns
-------
Optional[requests.Response]
"""
url = f"{base_url}/sdk/token"
payload = json.dumps({"days": days})
headers = {
"Authorization": auth_header,
"Content-Type": "application/json",
}
try:
response = requests.put(url=url, headers=headers, data=payload, timeout=timeout)
if response.status_code != 200:
console.print("[red]Failed to generate personal access token.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to generate personal access token.[/red]")
return None
def get_personal_access_token(
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
) -> Optional[requests.Response]:
"""
Show the user's OpenBB Personal Access Token.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
"""
url = f"{base_url}/sdk/token"
headers = {"Authorization": auth_header}
try:
response = requests.get(url=url, headers=headers, timeout=timeout)
if response.status_code != 200:
console.print("[red]Failed to get personal access token.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to get personal access token.[/red]")
return None
def revoke_personal_access_token(
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
) -> Optional[requests.Response]:
"""
Delete the user's OpenBB Personal Access Token.
Parameters
----------
auth_header : str
The authorization header, e.g. "Bearer <token>".
base_url : str
The base url, by default BASE_URL
timeout : int
The timeout, by default TIMEOUT
Returns
-------
Optional[requests.Response]
"""
url = f"{base_url}/sdk/token"
headers = {"Authorization": auth_header}
try:
response = requests.delete(url=url, headers=headers, timeout=timeout)
if response.status_code not in [200, 202]:
console.print("[red]Failed to revoke personal access token.[/red]")
return response
except requests.exceptions.ConnectionError:
console.print(f"\n{CONNECTION_ERROR_MSG}")
return None
except requests.exceptions.Timeout:
console.print(f"\n{CONNECTION_TIMEOUT_MSG}")
return None
except Exception:
console.print("[red]Failed to revoke personal access token.[/red]")
return None