Files
OpenBB/openbb_platform/extensions/tests/utils/router_testers.py
montezdesousa f328a45b95 [Feature] - refactor examples (#6154)
* remove auto examples and split python from api

* add missing exampels

* rebuild

* query params focstring

* black

* add scoped examples

* group model imports in the router

* unblock api

* fix

* classify examples

* fix package identation

* black sig

* fix indentation without linter

* fix python examples

* remove doc

* pylint

* again

* add model validators

* commodity, crypto, currency

* filter examples

* fix python examples

* fix filter and build

* undo toml change

* add comment

* oop

* comment

* typing

* lint

* Update router.py

* Update econometrics_router.py

* fix to_python

* to_python

* to_python

* black

* fix multiple line field descriptions

* remove circular import

* add missing import

* pass indent as object attr

* doc

* doc

* this looks better

* forgot this

* fix: new examples adapted

* fix prev commit

* avoid future problems

* Update ownership_router.py

* rebuild + remove todo

* make description mandatory for python examples

* simple indent

* append_examples func works for both website and docstring

* Add example unit tests

* Edit example unit tests

* fix validator

* this works

* fix to_python

* fix mandatory docstrings

* typing

* shorter error msgs

* economy router

* fix more examples

* more examples

* more examples

* more examples

* field desc

* minor fix

* fix etf examples

* handling types better

* lint

* rename method

* rename var

* docstring + move method

* typing

* prompt

* rebuild

* prompt fix in PythonEx

* fix examples without model

* example mock data

* add get_field_type func to get field data type

* panel data

* mock data

* fix

* fix

* docstring

* ohlcv

* pylint

* quantitaive router

* simplify mock data

* fix remaining quantitative routers

* a bit more flexibility for examples

* lint

* mock dat from sample

* docstring

* assertion

* bugfix

* minor fix

* technical

* fix integration tests

* fix docstring

* econometrics examples

* econometrics examples

* remove warning

* add technical examples

* fix bad examples

* fix more examples

* update test rules

* remoce old pydantic referenc

* fix bug in treasury prices

* fix quantitative examples

* discovery router

* equity shorts

* equity shorts

* fix currency pairs

* fix sec_router example

* fix panel data to support all funcs

* black

* more examples fixes

* simplify test

* rebuild

* test doc

* add provider to some ex

* ^

* last

* add provider

* rebuild

* working examples

* noqa

* pylint

* pylint

* clean

* minor fix

* fix test

* lint

* ruff

---------

Co-authored-by: Pratyush Shukla <ps4534@nyu.edu>
Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com>
2024-03-09 23:22:40 +00:00

142 lines
5.3 KiB
Python

"""Router testers."""
import ast
import os
from typing import Any, Dict, List, Optional
from openbb_core.app.provider_interface import ProviderInterface
from extensions.tests.utils.helpers import (
collect_router_functions,
collect_routers,
find_decorator,
find_missing_router_function_models,
get_decorator_details,
get_required_fields,
import_routers,
parse_example_string,
)
def check_router_function_models() -> List[str]:
"""Check if the models in the router functions exist in the provider interface map."""
pi = ProviderInterface()
pi_map = pi.map
routers = collect_routers("extensions")
loaded_routers = import_routers(routers)
router_functions = collect_router_functions(loaded_routers)
missing_models = find_missing_router_function_models(router_functions, pi_map)
return missing_models
def check_router_model_functions_signature() -> List[str]:
"""Check if the router model functions have the correct signature."""
expected_args = ["cc", "provider_choices", "standard_params", "extra_params"]
expected_return_type = "OBBject"
missing_args: List[str] = []
missing_return_type: List[str] = []
routers = collect_routers("extensions")
loaded_routers = import_routers(routers)
router_functions = collect_router_functions(loaded_routers)
for router_name, functions in router_functions.items():
for function in functions:
decorator = find_decorator(
os.path.join(*router_name.split(".")) + ".py",
function.__name__,
)
if decorator:
if "POST" in decorator or "GET" in decorator:
continue
args = list(function.__code__.co_varnames)
if args != expected_args and "model" in decorator:
missing_args.append(
f"{function.__name__} in {router_name} missing expected args: {expected_args}"
)
if expected_return_type not in str(function.__annotations__["return"]):
missing_return_type.append(
f"{function.__name__} in {router_name} "
f"doesn't have the expected return type: {expected_return_type}"
)
return missing_args + missing_return_type
def check_general(
keywords: Dict, examples: List, router_name: str, function: Any
) -> List[str]:
"""Check for general violations in the router command examples."""
general_violation: List[str] = []
# Check if the endpoint has examples
if "examples" not in keywords or not examples:
general_violation.append(
f"'{router_name}' > '{function.__name__}': missing examples"
)
return general_violation
return general_violation
def check_api(
examples: str, router_name: str, model: Optional[str], function: Any
) -> List[str]:
"""Check for API examples."""
# Check if the endpoint has at least 1 example with all required fields
api_example_violation: List[str] = []
parsed_examples = parse_example_string(examples)
if model and "APIEx" in parsed_examples:
required_fields = get_required_fields(model.strip("'"))
for api_example in parsed_examples["APIEx"]:
params = ast.literal_eval(api_example.get("params", "{}"))
if len(set(params.keys()) - set(required_fields) - {"provider"}) == 0:
break
else:
api_example_violation.append(
f"'{router_name}' > '{function.__name__}': missing example with required fields only > {required_fields}"
)
return api_example_violation
def check_router_command_examples() -> List[str]:
"""Check if the router command examples satisfy criteria."""
general_violation: List[str] = []
api_example_violation: List[str] = []
python_example_violation: List[str] = []
routers = collect_routers("extensions")
loaded_routers = import_routers(routers)
router_functions = collect_router_functions(loaded_routers)
for router_name, functions in router_functions.items():
for function in functions:
if (
"basemodel_to_df" in function.__name__
or "router" not in function.__module__
):
continue
decorator = find_decorator(
os.path.join(*router_name.split(".")) + ".py",
function.__name__,
)
if decorator:
decorator_details = get_decorator_details(function)
if decorator_details["decorator"] == "router.command":
keywords = decorator_details["keywords"]
examples = keywords.get("examples", [])
# General checks
general_violation += check_general(
keywords, examples, router_name, function
)
if examples:
# API example checks
model = keywords.get("model", None)
api_example_violation += check_api(
examples, router_name, model, function
)
return general_violation + api_example_violation + python_example_violation