New Integration Tests (#3377)

This commit is contained in:
Colin Delahunty
2022-11-26 04:18:52 +01:00
committed by GitHub
parent 2e2e5e2fb6
commit 9f7635faee
47 changed files with 467 additions and 393 deletions

3
.gitignore vendored
View File

@@ -31,7 +31,8 @@ openbb_terminal/portfolio/portfolios/*
.coverage.*
!openbb_terminal/reports/templates/*.ipynb
*_tests.csv
integration_test_output/*
integration_test_output/
integration_test_summary/
openbb_terminal/reports/templates/*.html
website/functions
*_sdk_audit.csv

View File

@@ -0,0 +1,213 @@
#!/usr/bin/env python
"""Main Testing Module"""
__docformat__ = "numpy"
from datetime import datetime
from pathlib import Path
from typing import List, Dict
import traceback
import argparse
import logging
import csv
import sys
import os
from openbb_terminal.rich_config import console
from openbb_terminal.core.config.paths import (
MISCELLANEOUS_DIRECTORY,
REPOSITORY_DIRECTORY,
)
from openbb_terminal.terminal_controller import run_scripts
logger = logging.getLogger(__name__)
special_arguments_values = [
"ticker",
"currency",
"crypto",
"country",
"repo",
"crypto_vs",
"crypto_full",
"currency_vs",
]
def build_test_path_list(path_list: List[str]) -> List[Path]:
"""Build the paths to use in test mode."""
if path_list == "":
console.print("Please send a path when using test mode")
return []
test_files = []
for path in path_list:
script_path = MISCELLANEOUS_DIRECTORY / "scripts" / path
if script_path.exists():
chosen_path = script_path
else:
console.print(f"\n[red]Can't find the file: {script_path}[/red]\n")
continue
if chosen_path.is_file() and str(chosen_path).endswith(".openbb"):
test_files.append(str(chosen_path))
elif chosen_path.is_dir():
all_files = os.walk(script_path)
for root, _, files in all_files:
for name in files:
if name.endswith(".openbb"):
path_obj = f"{root}/{name}"
test_files.append(path_obj)
test_files_unique = set(test_files)
return [Path(x) for x in test_files_unique]
def format_failures(fails: dict, output: bool) -> None:
"""Generates the message and csv from the fails dictionary
Parameters
-----------
fails: dict
The dictionary with failure information
output: bool
Whether or not to save output into a CSV file
"""
if fails:
console.print("\n[red]Failures:[/red]\n")
for file, exception in fails.items():
logger.error("%s: %s failed", file, exception["exception"])
# Write results to CSV
if output:
timestamp = datetime.now().timestamp()
stamp_str = str(timestamp).replace(".", "")
whole_path = Path(REPOSITORY_DIRECTORY / "integration_test_summary")
whole_path.mkdir(parents=True, exist_ok=True)
output_path = f"{stamp_str}_tests.csv"
with open(whole_path / output_path, "w") as file: # type: ignore
header = ["Script File", "Type", "Error", "Stacktrace"]
writer = csv.DictWriter(file, fieldnames=header) # type: ignore
writer.writeheader()
for file, exception in fails.items():
clean_type = (
str(type(exception["exception"]))
.replace("<class '", "")
.replace("'>", "")
)
writer.writerow(
{
"Script File": file,
"Type": clean_type,
"Error": exception["exception"],
"Stacktrace": exception["traceback"],
}
)
console.print(f"CSV of errors saved to {whole_path / output_path}")
def run_test_list(
path_list: List[str], verbose: bool, special_arguments: Dict[str, str], output: bool
):
"""Run commands in test mode."""
os.environ["DEBUG_MODE"] = "true"
if not path_list:
path_list = [""]
test_files = build_test_path_list(path_list)
SUCCESSES = 0
FAILURES = 0
fails = {}
length = len(test_files)
i = 0
console.print("[green]OpenBB Terminal Integrated Tests:\n[/green]")
for file in test_files:
console.print(f"{((i/length)*100):.1f}% {file}")
try:
run_scripts(
file,
test_mode=True,
verbose=verbose,
special_arguments=special_arguments,
output=output,
)
SUCCESSES += 1
except Exception as e:
_, _, exc_traceback = sys.exc_info()
fails[file] = {
"exception": e,
"traceback": traceback.extract_tb(exc_traceback),
}
FAILURES += 1
i += 1
format_failures(fails, output)
console.print(
f"Summary: [green]Successes: {SUCCESSES}[/green] [red]Failures: {FAILURES}[/red]"
)
def parse_args_and_run():
"""Parse input arguments and run integration tests."""
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="testing",
description="Integration tests for the OpenBB Terminal.",
)
parser.add_argument(
"-f",
"--file",
help=(
"The path or .openbb file to run. Starts at "
"OpenBBTerminal/openbb_terminal/miscellaneous/scripts"
),
dest="path",
nargs="+",
default="",
type=str,
)
parser.add_argument(
"-t",
"--test",
action="store_true",
help=(
"Run the terminal in testing mode. Also run this option and '-h'"
" to see testing argument options."
),
)
parser.add_argument(
"--no-output",
action="store_true",
default=False,
dest="no_output",
help="Blocks creation of CSV files and logs",
)
parser.add_argument(
"-v",
"--verbose",
help="Enable verbose output for debugging",
dest="verbose",
action="store_true",
default=False,
)
# This is the list of special arguments a user can send
for arg in special_arguments_values:
parser.add_argument(
f"--{arg}",
help=f"Change the default values for {arg}",
dest=arg,
type=str,
default="",
)
ns_parser, _ = parser.parse_known_args()
special_args_dict = {x: getattr(ns_parser, x) for x in special_arguments_values}
run_test_list(
path_list=ns_parser.path,
verbose=ns_parser.verbose,
special_arguments=special_args_dict,
output=not ns_parser.no_output,
)
if __name__ == "__main__":
parse_args_and_run()

View File

@@ -8,7 +8,7 @@ It aims to provide necessary information in order to:
- Run `integration tests`
- Identify errors noted from `integration tests`
## 1.1. Why having integration tests ?
## 1.1. Why have integration tests ?
The purpose of integration tests is to provide standard usage examples that can be programmatically run
to make sure that a specific functionality of the terminal and the process to utilize that functionality
@@ -28,6 +28,10 @@ should be `test_<menu>_<command>.openbb` if you are testing a specific command o
if you are testing the entire menu. However, it is encouraged to create as specific of integration tests
as possible to identify errors more precisely. Additionally, all tests must end with the `exit` command.
These files can be given dynamic output with the following syntax `${key=default}`. Please note that
both key and default can only contain letters and numbers with NO special characters. Each dynamic
argument MUST contain a key and a default value.
### Examples
Testing a specific command and it's arguments:
@@ -89,18 +93,19 @@ exit
### Conda Terminal
After navigating to the location of the OpenBBTerminal repo, one can run integration tests in a
few different ways using the wildcard expression.
few different ways using the wildcard expression. Please include a `-t` with `terminal.py` to run
the tests.
- Run all integration tests:
```zsh
python terminal.py scripts/*.openbb -t
python terminal.py -t
```
- Run some integration tests:
```zsh
python terminal.py scripts/test_stocks_*.openbb -t
python terminal.py -f stocks cryptocurrency -t
```
*This specific example runs all of the stocks integration tests. One can use this same format for different tests.*
@@ -108,9 +113,25 @@ few different ways using the wildcard expression.
- Run one integration tests:
```zsh
python terminal.py scripts/test_alt_covid.openbb -t
python terminal.py -f alternative/test_alt_covid.openbb -t
```
*Note that the base path is `OpenBBTerminal/openbb_terminal/miscellaneous/scripts`.*
- Run integration tests with arguments by adding --key=value
```zsh
python terminal.py --ticker=aapl -t
```
- To see a lot of possible keys, run the following:
```zsh
python terminal.py -h -t
```
If there are any test failures a csv will be generated with detailed information on the failures.
### Installer Terminal
Integration tests can also be used on installers, which is a packaged version of the conda terminal.
@@ -160,3 +181,5 @@ If the `-t` argument is not given, then the reason why a specific failure occurs
test is printed inline while the test is being run.
If there is an error, one can identify the command and or series of steps that causes it fairly easily.
Output from the integration tests can also be viewed in the `integration_test_output` folder .

View File

@@ -1,14 +1,10 @@
alternative
covid
country Australia
country ${country=Australia}
reset
slopes
country US
ov
country Russia
deaths
country United Kingdom
cases
country Canada
rates
exit
exit

View File

@@ -1,8 +1,8 @@
alternative
oss
rs openbb-finance/openbbterminal
sh openbb-finance/openbbterminal
rs ${repo=openbb-finance/openbbterminal}
sh ${repo=openbb-finance/openbbterminal}
tr
rossidx
rossidx --sortby Raised [$M] --reverse
exit
exit

View File

@@ -1,37 +1,37 @@
crypto
load eth
load ${crypto=eth}
# # Find
# find eth
# find eth --key symbol
# find eth --key id
# find ethereum --key name
# find eth --limit 5
# find eth --skip 3 # Bug that only skips second similar coins but not first
# find eth --source CoinGecko
# find eth --source CoinPaprika
# find eth --source Binance
# find eth --source Coinbase
# find ${crypto=eth}
# find ${crypto=eth} --key symbol
# find ${crypto=eth} --key id
# find ${crypto_full=ethereum} --key name
# find ${crypto=eth} --limit 5
# find ${crypto=eth} --skip 3 # Bug that only skips second similar coins but not first
# find ${crypto=eth} --source CoinGecko
# find ${crypto=eth} --source CoinPaprika
# find ${crypto=eth} --source Binance
# find ${crypto=eth} --source Coinbase
# # Bug with this source
# # find eth --source Yahoofinance
# # find ${crypto=eth} --source Yahoofinance
# # Price
# # price eth
# price eth
# # price ${crypto=eth}
# price ${crypto=eth}
# # Headlines
# headlines
# headlines ETH
# headlines ${crypto=ETH}
# # Candle
# candle
# candle --log
# # PRT
# prt --vs btc
# # Bug where we need --vs when we don't actually need it
# # prt --top 3
# # Bug where --price doesn't seem to do anything
# # prt --vs btc --price 1000
# PRT
# prt --vs ${crypto_vs=btc}
# Bug where we need --vs when we don't actually need it
# prt --top 3
# Bug where --price doesn't seem to do anything
# prt --vs ${crypto_vs=btc} --price 1000
exit

View File

@@ -1,127 +1,70 @@
crypto
load eth
load ${crypto=eth}
dd
# info
info
# ath
ath --vs usd
ath --vs ${currency_vs=usd}
atl --vs ${currency_vs=usd}
# atl
atl --vs usd
# web
web
# bc
bc
# pi
pi
# gov
gov
# basic
basic
# stats
stats
stats --vs GBP
stats --vs ${currency_vs=GBP}
# desc
desc
# market
market
# mkt
mkt
mkt --urls
mkt --vs ETH --limit 3 --sort volume --urls
mkt --vs BTC -s volume -r
mkt --vs ${crypto_vs=ETH} --limit 3 --sort volume --urls
mkt --vs {crypto_vs=ETH} --limit 3 --sort volume --urls
mkt --vs {crypto_vs=BTC} -s volume -r
# ex
ex
ex --limit 3 --sort adjusted_volume_24h_share
# balance
balance
# oi
# fundrate
# liquidations
# eb
# trades
trades
trades -e aax
trades --vs GBP
trades --vs ${currency_vs=GBP}
# ob
ob
ob -e aax
ob --vs GBP
ob --vs ${currency_vs=GBP}
# ps
ps
ps --vs ETH
ps --vs ${currency_vs=ETH}
# mcapdom
mcapdom
# mt
mt
# funot
# team
team
# inv
inv
# tk
tk
# fr
fr
# rm
rm
# events
events
events --limit 3 --sort name --urls
events --sort date -r
# news
news
news --limit 3 -k media -r en --filter bullish
news --sort published_at --reverse
# links
links
# twitter
twitter
twitter --limit 3 --sort retweet_count
twitter --sort date -r
# social
social
# score
score
# dev
dev
# gh
gh
exit

View File

@@ -9,8 +9,8 @@ newsletter --limit 3
# vaults
vaults
vaults --chain ethereum --protocol aave --kind stable --top 3 --links
vaults --chain ethereum -s apy -r
vaults --chain ${crypto_full=ethereum} --protocol aave --kind stable --top 3 --links
vaults --chain ${crypto_full=ethereum} -s apy -r
# tokens
tokens

View File

@@ -18,9 +18,9 @@ losers
losers -s Price [$] -l 5 -i 14d
# cpsearch CURRENTLY BUGGY
search bitcoin
search -q bitcoin -s name
search -q bitcoin -c exchanges -l 2
search ${crypto=bitcoin}
search -q ${crypto=bitcoin} -s name
search -q ${crypto=bitcoin} -c exchanges -l 2
nft
games

View File

@@ -3,36 +3,28 @@ onchain
# hr
# btccp
btccp
btccp --since 2012-01-01 --until 2022-01-01
# btcct
btcct
btcct --since 2012-01-01 --until 2022-01-01
# gwei
gwei
# whales
whales
whales --address # this is bugged
whales --min 5000000 --limit 3 --sort amount
whales --sort amount_usd -r
# lt
lt
lt --kind time --vs ETH --limit 3 --days 7 --sort tradeAmount
lt --kind time --vs ${crypto=ETH} --limit 3 --days 7 --sort tradeAmount
# dvcp
dvcp --coin ETH
dvcp --coin ETH --limit 3 --vs BTC --days 20 --sort high # limit is bugged
dvcp --coin ${crypto=ETH}
dvcp --coin ${crypto=ETH} --limit 3 --vs ${crypto=BTC} --days 20 --sort high # limit is bugged
# dvcp
tv --coin ETH
tv --coin ETH --limit 3 --vs BTC --sort tradeAmount
tv --coin ${crypto=ETH}
tv --coin ${crypto=ETH} --limit 3 --vs ${crypto=BTC} --sort tradeAmount
# ueat
ueat
ueat --limit 3 --sort transactions --interval month

View File

@@ -18,7 +18,7 @@ exchanges
exchanges --source CoinGecko
exchanges --source CoinPaprika
exchanges --urls
exchanges --vs ETH
exchanges --vs ${crypto_vs=ETH}
exchanges --source CoinGecko --limit 3 --sortby Trust_Score -r
# exrates
@@ -49,11 +49,11 @@ hm --category stablecoins --limit 3
# info
info
info --vs ETH --sortby price --limit 3
info --vs ${crypto_vs=ETH} --sortby price --limit 3
# markets
markets
markets --vs ETH --sortby price --limit 3
markets --vs ${crypto_vs=ETH} --sortby price --limit 3
# exmarkets
exmarkets
@@ -84,7 +84,7 @@ ewf
# wfpe
wfpe
wfpe -c ethereum
wfpe -c ${crypto_full=ethereum}
# altindex
altindex

View File

@@ -1,5 +1,5 @@
crypto
load eth
load ${crypto=eth}
qa
# summary

View File

@@ -1,86 +1,65 @@
crypto
load eth
load ${crypto=eth}
# tv
tv
# ema
ema
ema -l 100 -o 10
# sma
sma
sma -l 100 -o 10
# wma
wma
wma -l 100 -o 10
# hma
hma
hma -l 100 -o 10
# zlma
zlma
zlma -l 100 -o 10
# vwap
# cci
cci
cci --length 10 --scalar 10
# macd
macd
macd --fast 10 --slow 10 --signal 5
# rsi
rsi
rsi -l 10 -s 10 -d 2
# stoch
stoch
stoch -k 10 -d 10 --slowkperiod 2
# fisher
fisher
fisher --length 10
# cg
cg
cg --length 10
# adx
adx
adx -l 10 -s 10 -d 10
# aroon
aroon
aroon -l 10 -s 10
# bbands
bbands
bbands -l 10 -s 0.5 -m ema
# donchian
donchian
donchian -u 10 -l 10
# kc
kc
kc -l 10 -s 10 -m sma -o 1
# ad
ad
# adosc
adosc
adosc --open --fast 10 --slow 10
# obv
obv
# fib
fib
fib --period 10 --start 2022-01-01 --end 2022-03-03

View File

@@ -1,11 +1,9 @@
crypto
tools
# aprtoapy
aprtoapy
aprtoapy --narrative --apr 50 --compounding 6
# il
il
il --narrative --priceChangeA 5 --priceChangeB 3 --proportion 2 --value 10

View File

@@ -1,14 +1,14 @@
forex
load -h
load -i
to EUR
to ${currency=EUR}
quote -h
quote -argument
quote
load
candle
from ILS
from ${currency_vs=ILS}
quote
load
candle
exit
exit

View File

@@ -1,7 +1,7 @@
forex
load EURUSD
load -t EURUSD -r d -i 1day -s 2000-01-01
load -t EURUSD -r i -i 30min
load ${currency=EUR}${currency_vs=USD}
load -t ${currency=EUR}${currency_vs=USD} -r d -i 1day -s 2000-01-01
load -t ${currency=EUR}${currency_vs=USD} -r i -i 30min
fwd
quote
quote --source YahooFinance

View File

@@ -1,5 +1,5 @@
forex
load EURUSD --source YahooFinance
load USDEUR --source Polygon
load EURUSD --source AlphaVantage
load ${currency=EUR}${currency_vs=USD} --source YahooFinance
load ${currency_vs=USD}${currency=EUR} --source Polygon
load ${currency=EUR}${currency_vs=USD} --source AlphaVantage
exit

View File

@@ -4,21 +4,21 @@ oanda -argument
oanda
from -h
from -argument
from usd
from ${currency=usd}
to -h
to -argument
to chf
to ${currency_vs=chf}
price -h
price -argument
price
from eur
from ${currency=eur}
price
from ils
from ${currency=ils}
price
summary -h
summary
from usd
to chf
to ${currency_vs=chf}
orderbook -h
orderbook
list -h
@@ -53,9 +53,9 @@ candles -a -b -c -e -v
calendar
calendar -h
calendar -argument
from eur
to jpy
from ${currency=eur}
to ${currency_vs=jpy}
calendar
to gbp
calendar
exit
exit

View File

@@ -1,5 +1,5 @@
forex
load EURUSD --source YahooFinance
load ${currency=EUR}${currency_vs=USD} --source YahooFinance
qa
summary
normality
@@ -33,7 +33,7 @@ decompose
decompose --multiplicative
cusum
cusum -t 0.01 -d 0.01
load EURUSD --source YahooFinance
load ${currency=EUR}${currency_vsUSD} --source YahooFinance
qa
summary
normality

View File

@@ -1,5 +1,5 @@
forex
load EURUSD --source YahooFinance
load ${currency=EUR}${currency_vs=USD} --source YahooFinance
load
ta
ema
@@ -29,7 +29,7 @@ bbands -l 1 -s 0.25 -m ema
donchian
donchian --length_upper 10 --length_lower 1
fib
load USDEUR --source Polygon
load ${currency=USD}${currency_vs=EUR} --source Polygon
ta
ema
sma

View File

@@ -3,13 +3,6 @@ reports
## defaults
crypto
## simple coin
crypto --symbol BTC
## small-cap coin
crypto --symbol STEPN
## shitcoins
crypto --symbol LUCKY
crypto --symbol ${crypto=BTC}
exit

View File

@@ -3,7 +3,7 @@ reports
# economy
# Test with random tickers, that should be ignored by the report.
# economy AAPL
# economy --symbol MSFT
# economy ${ticker=AAPL}
# economy --symbol ${ticker=MSFT}
exit

View File

@@ -4,12 +4,6 @@ reports
equity
## simple ticker
equity --symbol AAPL
## Non-US ticker
equity --symbol NXPI
## Non-US ticker with suffix
equity --symbol PETR3.SA
equity --symbol ${ticker=AAPL}
exit

View File

@@ -1,7 +1,7 @@
stocks
search -c United States -s Consumer Cyclical -i Specialty Retail -e USA -l 5
load aaple -i 5
load aapl -s 2022-10-01
load ${ticker=aapl} -i 5
load ${ticker=aapl} -s 2022-10-01
quote
tob
tob -e EDGX

View File

@@ -1,6 +1,6 @@
stocks
ba
load aapl
load ${ticker=aapl}
headlines
headlines --raw
wsb
@@ -23,6 +23,5 @@ interest -w yolo
queries
rise
jcdr
load tsla
jctr
exit

View File

@@ -1,5 +1,5 @@
stocks
load tsla
load ${ticker=tsla}
bt
whatif
whatif -n 2.34

View File

@@ -1,5 +1,5 @@
stocks
load aapl
load ${ticker=aapl}
ca
tsne
historical
@@ -8,7 +8,7 @@ hcorr
hcorr --raw
hcorr -t h --display-full-matrix
volume
ticker msft
ticker ${ticker=msft}
income
income -t 31-Mar-2022 -q
balance
@@ -25,7 +25,7 @@ financial
ownership
performance
technical
ticker -t tsla
ticker -t ${ticker=tsla}
get --source Polygon
get --source Finnhub
get

View File

@@ -1,5 +1,5 @@
stocks
load aapl
load ${ticker=aapl}
dd
analyst
rating
@@ -14,6 +14,6 @@ est -e quarterearnings
sec
supplier
customer
load tsla
load ${ticker=tsla}
arktrades
exit

View File

@@ -6,11 +6,11 @@ ctb -source stocksera
hsi
pos
sidtc
load -t gme
load -t ${ticker=gme}
spos
psi
ftd
load aapl -i 5
load ${ticker=aapl} -i 5
ftd -n 5 --raw
dpotc
exit

View File

@@ -1,5 +1,5 @@
stocks
load aapl
load ${ticker=aapl}
fa
income -l 2 --source YahooFinance
income -l 2 --source Polygon

View File

@@ -1,20 +1,7 @@
stocks
load aapl
load ${ticker=aapl}
fa
h
help
?
q
fa
..
..
stocks
load aa
fa
quit
fa
home
stocks
load aal
fa
exit

View File

@@ -19,7 +19,7 @@ qtrcontracts -l 2 --raw
qtrcontracts -l 2 -a downmom
toplobbying
toplobbying -l 4 --raw
load aapl
load ${ticker=aapl}
gtrades
gtrades senate
gtrades house

View File

@@ -5,7 +5,7 @@ view whales.ini
set Electronics.ini
filter -l 4
filter -l 2 -u
load aapl
load ${ticker=aapl}
stats
stats -u
act --raw

View File

@@ -9,7 +9,7 @@ options
# unu -l 2 -s Strike -a -c
# unu -l 2 -s Vol
# calc
# load aapl
# load ${ticker=aapl}
# exp 0
# pcr
# info
@@ -25,7 +25,7 @@ options
# binom -s 150
# load spy
# vsurf
# load NDX --source Nasdaq
# load ${ticker=NDX} --source Nasdaq
# exp 0 --source Nasdaq
# chains --source Nasdaq
# oi --source Nasdaq

View File

@@ -1,6 +1,6 @@
stocks
options
load aapl
load ${ticker=aapl}
exp 0
payoff
list
@@ -10,4 +10,4 @@ add 15
add 10 -p
sop
plot
exit
exit

View File

@@ -1,6 +1,6 @@
stocks
options
load aapl
load ${ticker=aapl}
exp 0
pricing
add 150 -c 3
@@ -10,4 +10,4 @@ add 170 -c 0.5
add 180 -c 0.2
show
rnval
exit
exit

View File

@@ -1,5 +1,5 @@
stocks
load aapl
load ${ticker=aapl}
qa
summary
normality
@@ -33,7 +33,7 @@ es
sh
so
om
load aapl -i 1
load ${ticker=aapl} -i 1
pick returns
summary
normality
@@ -57,7 +57,7 @@ es
sh
so
om
load aapl --source Polygon
load ${ticker=aapl} --source Polygon
pick returns
summary
normality

View File

@@ -10,7 +10,7 @@ help
h
?
clear
load tsla
load ${ticker=tsla}
clear industry
clear sector
clear sector
@@ -37,4 +37,4 @@ sama
metric roa
reset
r
exit
exit

View File

@@ -1,5 +1,5 @@
stocks
load aapl
load ${ticker=aapl}
ta
view
recom
@@ -29,7 +29,7 @@ ad
adosc
obv
fib
load ionq -i 1
load ${ticker=ionq} -i 1
ema -l 20,30,50
sma -l 3
wma -l 5
@@ -54,7 +54,7 @@ ad --open
adosc --open --fast 4 --slow 10
obv
fib
load aapl --source Polygon
load ${ticker=aapl} --source Polygon
ema
sma
wma

View File

@@ -0,0 +1,9 @@
stocks
load ${ticker=aapl}
th
open
closed
all
exchange
symbol ${ticker=MSFT}
exit

View File

@@ -1,9 +0,0 @@
stocks
load aapl
th
open
closed
all
exchange
symbol MSFT
exit

View File

@@ -84,7 +84,6 @@ class StocksController(StockBaseController):
super().__init__(queue)
if session and obbff.USE_PROMPT_TOOLKIT:
choices: dict = self.choices_default
self.completer = NestedCompleter.from_nested_dict(choices)

View File

@@ -2,16 +2,17 @@
"""Main Terminal Module."""
__docformat__ = "numpy"
from datetime import datetime
import argparse
import difflib
import logging
import os
import csv
import re
from pathlib import Path
from datetime import datetime
import sys
import webbrowser
from typing import List
from typing import List, Dict, Optional
import contextlib
import dotenv
import certifi
@@ -29,6 +30,7 @@ from openbb_terminal.core.config.paths import (
HOME_DIRECTORY,
MISCELLANEOUS_DIRECTORY,
REPOSITORY_ENV_FILE,
REPOSITORY_DIRECTORY,
USER_DATA_DIRECTORY,
USER_ENV_FILE,
USER_ROUTINES_DIRECTORY,
@@ -51,9 +53,9 @@ from openbb_terminal.terminal_helper import (
is_reset,
print_goodbye,
reset,
suppress_stdout,
update_terminal,
welcome_message,
suppress_stdout,
)
from openbb_terminal.helper_funcs import parse_and_split_input
from openbb_terminal.keys_model import first_time_user
@@ -959,6 +961,8 @@ def run_scripts(
test_mode: bool = False,
verbose: bool = False,
routines_args: List[str] = None,
special_arguments: Optional[Dict[str, str]] = None,
output: bool = True,
):
"""Run given .openbb scripts.
@@ -973,125 +977,101 @@ def run_scripts(
routines_args : List[str]
One or multiple inputs to be replaced in the routine and separated by commas.
E.g. GME,AMC,BTC-USD
special_arguments: Optional[Dict[str, str]]
Replace `${key=default}` with `value` for every key in the dictionary
output: bool
Whether to log tests to txt files
"""
if path.exists():
with path.open() as fp:
raw_lines = [x for x in fp if (not is_reset(x)) and ("#" not in x) and x]
raw_lines = [
raw_line.strip("\n") for raw_line in raw_lines if raw_line.strip("\n")
]
if routines_args:
lines = list()
for rawline in raw_lines:
templine = rawline
for i, arg in enumerate(routines_args):
templine = templine.replace(f"$ARGV[{i}]", arg)
lines.append(templine)
else:
lines = raw_lines
if test_mode and "exit" not in lines[-1]:
lines.append("exit")
export_folder = ""
if "export" in lines[0]:
export_folder = lines[0].split("export ")[1].rstrip()
lines = lines[1:]
simulate_argv = f"/{'/'.join([line.rstrip() for line in lines])}"
file_cmds = simulate_argv.replace("//", "/home/").split()
file_cmds = insert_start_slash(file_cmds) if file_cmds else file_cmds
if export_folder:
file_cmds = [f"export {export_folder}{' '.join(file_cmds)}"]
else:
file_cmds = [" ".join(file_cmds)]
if not test_mode:
terminal(file_cmds, test_mode=True)
else:
if verbose:
terminal(file_cmds, test_mode=True)
else:
with suppress_stdout():
terminal(file_cmds, test_mode=True)
else:
if not path.exists():
console.print(f"File '{path}' doesn't exist. Launching base terminal.\n")
if not test_mode:
terminal()
with path.open() as fp:
raw_lines = [x for x in fp if (not is_reset(x)) and ("#" not in x) and x]
raw_lines = [
raw_line.strip("\n") for raw_line in raw_lines if raw_line.strip("\n")
]
def build_test_path_list(path_list: List[str], filtert: str) -> List[Path]:
"""Build the paths to use in test mode."""
if path_list == "":
console.print("Please send a path when using test mode")
return []
if routines_args:
lines = []
for rawline in raw_lines:
templine = rawline
for i, arg in enumerate(routines_args):
templine = templine.replace(f"$ARGV[{i}]", arg)
lines.append(templine)
# Handle new testing arguments:
elif special_arguments:
lines = []
for line in raw_lines:
new_line = re.sub(
r"\${[^{]+=[^{]+}",
lambda x: replace_dynamic(x, special_arguments), # type: ignore
line,
)
lines.append(new_line)
test_files = []
for path in path_list:
user_script_path = USER_DATA_DIRECTORY / "scripts" / path
default_script_path = MISCELLANEOUS_DIRECTORY / path
if user_script_path.exists():
chosen_path = user_script_path
elif default_script_path.exists():
chosen_path = default_script_path
else:
console.print(f"\n[red]Can't find the file:{path}[/red]\n")
continue
lines = raw_lines
if chosen_path.is_file() and str(chosen_path).endswith(".openbb"):
test_files.append(chosen_path)
elif chosen_path.is_dir():
script_directory = chosen_path
script_list = script_directory.glob("**/*.openbb")
script_list = [script for script in script_list if script.is_file()]
script_list = [script for script in script_list if filtert in str(script)]
test_files.extend(script_list)
if test_mode and "exit" not in lines[-1]:
lines.append("exit")
return test_files
export_folder = ""
if "export" in lines[0]:
export_folder = lines[0].split("export ")[1].rstrip()
lines = lines[1:]
simulate_argv = f"/{'/'.join([line.rstrip() for line in lines])}"
file_cmds = simulate_argv.replace("//", "/home/").split()
file_cmds = insert_start_slash(file_cmds) if file_cmds else file_cmds
if export_folder:
file_cmds = [f"export {export_folder}{' '.join(file_cmds)}"]
else:
file_cmds = [" ".join(file_cmds)]
if not test_mode or verbose:
terminal(file_cmds, test_mode=True)
else:
with suppress_stdout():
print(f"To ensure: {output}")
if output:
timestamp = datetime.now().timestamp()
stamp_str = str(timestamp).replace(".", "")
whole_path = Path(REPOSITORY_DIRECTORY / "integration_test_output")
whole_path.mkdir(parents=True, exist_ok=True)
first_cmd = file_cmds[0].split("/")[1]
with open(
whole_path / f"{stamp_str}_{first_cmd}_output.txt", "w"
) as output_file:
with contextlib.redirect_stdout(output_file):
terminal(file_cmds, test_mode=True)
else:
terminal(file_cmds, test_mode=True)
def run_test_list(path_list: List[str], filtert: str, verbose: bool):
"""Run commands in test mode."""
os.environ["DEBUG_MODE"] = "true"
def replace_dynamic(match: re.Match, special_arguments: Dict[str, str]) -> str:
"""Replaces ${key=default} with value in special_arguments if it exists, else with default.
test_files = build_test_path_list(path_list=path_list, filtert=filtert)
SUCCESSES = 0
FAILURES = 0
fails = {}
length = len(test_files)
i = 0
console.print("[green]OpenBB Terminal Integrated Tests:\n[/green]")
for file in test_files:
console.print(f"{((i/length)*100):.1f}% {file}")
try:
run_scripts(file, test_mode=True, verbose=verbose)
SUCCESSES += 1
except Exception as e:
fails[file] = e
FAILURES += 1
i += 1
if fails:
console.print("\n[red]Failures:[/red]\n")
for file, exception in fails.items():
logger.error("%s: %s failed", file, exception)
# Write results to CSV
timestamp = datetime.now().timestamp()
output_path = f"{timestamp}_tests.csv"
with open(output_path, "w") as file: # type: ignore
header = ["File", "Error"]
writer = csv.DictWriter(file, fieldnames=header) # type: ignore
writer.writeheader()
for file, exception in fails.items():
writer.writerow({"File": file, "Error": exception})
Parameters
----------
match: re.Match[str]
The match object
special_arguments: Dict[str, str]
The key value pairs to replace in the scripts
console.print(f"CSV of errors saved to {output_path}")
Returns
----------
str
The new string
"""
console.print(
f"Summary: [green]Successes: {SUCCESSES}[/green] [red]Failures: {FAILURES}[/red]"
)
cleaned = match[0].replace("{", "").replace("}", "").replace("$", "")
key, default = cleaned.split("=")
dict_value = special_arguments.get(key, default)
if dict_value:
return dict_value
return default
def run_routine(file: str, routines_args=List[str]):
@@ -1111,10 +1091,7 @@ def run_routine(file: str, routines_args=List[str]):
def main(
debug: bool,
test: bool,
filtert: str,
path_list: List[str],
verbose: bool,
routines_args: List[str] = None,
**kwargs,
):
@@ -1139,10 +1116,6 @@ def main(
if kwargs["module"] == "ipykernel_launcher":
ipykernel_launcher(kwargs["module_file"], kwargs["module_hist_file"])
if test:
run_test_list(path_list=path_list, filtert=filtert, verbose=verbose)
return
if debug:
os.environ["DEBUG_MODE"] = "true"
@@ -1179,29 +1152,6 @@ def parse_args_and_run():
default="",
type=str,
)
parser.add_argument(
"-t",
"--test",
dest="test",
action="store_true",
default=False,
help="Whether to run in test mode.",
)
parser.add_argument(
"--filter",
help="Send a keyword to filter in file name",
dest="filtert",
default="",
type=str,
)
parser.add_argument(
"-v",
"--verbose",
help="Enable verbose output for debugging",
dest="verbose",
action="store_true",
default=False,
)
parser.add_argument(
"-i",
"--input",
@@ -1222,6 +1172,15 @@ def parse_args_and_run():
default="",
type=str,
)
parser.add_argument(
"-t",
"--test",
action="store_true",
help=(
"Run the terminal in testing mode. Also run this option and '-h'"
" to see testing argument options."
),
)
parser.add_argument(
"-f",
help=argparse.SUPPRESS,
@@ -1250,10 +1209,7 @@ def parse_args_and_run():
main(
ns_parser.debug,
ns_parser.test,
ns_parser.filtert,
ns_parser.path,
ns_parser.verbose,
ns_parser.routine_args,
module=ns_parser.module,
module_file=ns_parser.module_file,

View File

@@ -1,4 +1,10 @@
from openbb_terminal.terminal_controller import parse_args_and_run
import sys
from openbb_terminal import terminal_controller
from openbb_terminal import integration_testing
if __name__ == "__main__":
parse_args_and_run()
sent_args = sys.argv[1:]
if "-t" in sent_args or "--test" in sent_args:
integration_testing.parse_args_and_run()
else:
terminal_controller.parse_args_and_run()

View File

@@ -46,15 +46,10 @@ def no_suppress():
@pytest.mark.vcr(record_mode="none")
@pytest.mark.record_stdout
@pytest.mark.parametrize(
"debug, test, verbose, filtert, path",
[
(True, False, False, None, None),
(False, False, False, None, ["scripts/test_alt_covid.openbb"]),
# (False, True, False, "alt_covid", ["scripts/"]),
# (False, True, True, "alt_covid", ["scripts/"]),
],
"debug, path",
[(True, None), (False, ["scripts/test_alt_covid.openbb"])],
)
def test_menu(mocker, debug, test, filtert, path, verbose):
def test_menu(mocker, debug, path):
mocker.patch(target="terminal_controller.terminal")
mocker.patch(target="terminal_controller.suppress_stdout", side_effect=no_suppress)
terminal_controller.main(debug, test, filtert, path, verbose)
terminal_controller.main(debug, path)