Upload 4 files
Browse files
openbb_platform/tests/conftest.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Configuration for pytest."""
|
| 2 |
+
|
| 3 |
+
# TODO: See if we can dynamically import the test modules under the openbb_platform
|
| 4 |
+
|
| 5 |
+
# TODO: Add global fixture for headers here
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def pytest_configure():
|
| 11 |
+
"""Set environment variables for testing."""
|
| 12 |
+
os.environ["OPENBB_AUTO_BUILD"] = "false"
|
openbb_platform/tests/test_auto_build.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Test the auto_build feature."""
|
| 2 |
+
|
| 3 |
+
import importlib
|
| 4 |
+
import sys
|
| 5 |
+
from unittest.mock import patch
|
| 6 |
+
|
| 7 |
+
import pytest
|
| 8 |
+
|
| 9 |
+
# pylint: disable=redefined-outer-name, unused-import, import-outside-toplevel
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
@pytest.fixture(autouse=True)
|
| 13 |
+
def setup_mocks():
|
| 14 |
+
"""Set up mocks for the test."""
|
| 15 |
+
with patch("openbb._PackageBuilder.auto_build") as mock_auto_build:
|
| 16 |
+
mock_auto_build.return_value = None
|
| 17 |
+
yield mock_auto_build
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
@pytest.fixture
|
| 21 |
+
def openbb_module(setup_mocks):
|
| 22 |
+
"""Reload the openbb module."""
|
| 23 |
+
if "openbb" in sys.modules:
|
| 24 |
+
importlib.reload(sys.modules["openbb"])
|
| 25 |
+
else:
|
| 26 |
+
pass
|
| 27 |
+
return setup_mocks
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
@pytest.mark.integration
|
| 31 |
+
def test_autobuild_called(openbb_module):
|
| 32 |
+
"""Test that auto_build is called upon importing openbb."""
|
| 33 |
+
openbb_module.assert_called_once()
|
openbb_platform/tests/test_extension_map.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Test the extension map."""
|
| 2 |
+
|
| 3 |
+
import json
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from typing import Dict
|
| 6 |
+
|
| 7 |
+
from poetry.core.constraints.version import Version, VersionConstraint, parse_constraint
|
| 8 |
+
from poetry.core.pyproject.toml import PyProjectTOML
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def create_ext_map(extensions: dict) -> Dict[str, Version]:
|
| 12 |
+
"""Create the extension map from extension."""
|
| 13 |
+
ext_map = {}
|
| 14 |
+
for _, v in extensions.items():
|
| 15 |
+
for value in v:
|
| 16 |
+
name, version = value.split("@")
|
| 17 |
+
ext_map[name] = Version.parse(version)
|
| 18 |
+
return ext_map
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def load_req_ext(file: Path) -> Dict[str, VersionConstraint]:
|
| 22 |
+
"""Load the required extensions from pyproject.toml."""
|
| 23 |
+
pyproject = PyProjectTOML(file)
|
| 24 |
+
deps = pyproject.data["tool"]["poetry"]["dependencies"]
|
| 25 |
+
req_ext = {}
|
| 26 |
+
for k, v in deps.items():
|
| 27 |
+
if k.startswith("openbb-") and k not in ("openbb-core"):
|
| 28 |
+
name = k[7:].replace("-", "_")
|
| 29 |
+
if isinstance(v, str):
|
| 30 |
+
req_ext[name] = parse_constraint(v)
|
| 31 |
+
elif isinstance(v, dict) and not v.get("optional", False):
|
| 32 |
+
req_ext[name] = parse_constraint(v["version"])
|
| 33 |
+
return req_ext
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def test_extension_map():
|
| 37 |
+
"""Ensure only required extensions are built and versions respect pyproject.toml"""
|
| 38 |
+
this_dir = Path(__file__).parent
|
| 39 |
+
with open(Path(this_dir, "..", "openbb", "assets", "reference.json")) as f:
|
| 40 |
+
reference = json.load(f)
|
| 41 |
+
ext_map = create_ext_map(reference.get("info", {}).get("extensions", {}))
|
| 42 |
+
req_ext = load_req_ext(Path(this_dir, "..", "pyproject.toml"))
|
| 43 |
+
|
| 44 |
+
for ext in req_ext:
|
| 45 |
+
if ext != "platform_api":
|
| 46 |
+
assert ext in ext_map, (
|
| 47 |
+
f"Extension '{ext}' is required in pyproject.toml but is not built, install"
|
| 48 |
+
" it and rebuild or remove it from mandatory requirements in pyproject.toml"
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
for name, version in ext_map.items():
|
| 52 |
+
assert name in req_ext, (
|
| 53 |
+
f"'{name}' is not a required extension in pyproject.toml, uninstall it and"
|
| 54 |
+
" rebuild, or add it to pyproject.toml"
|
| 55 |
+
)
|
| 56 |
+
assert req_ext[name].allows(version), (
|
| 57 |
+
f"Version '{version}' of extension '{name}' is not compatible with the"
|
| 58 |
+
f" version '{req_ext[name]}' constraint in pyproject.toml"
|
| 59 |
+
)
|
openbb_platform/tests/test_pyproject_toml.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Test the pyproject.toml file for consistency and its dependencies."""
|
| 2 |
+
|
| 3 |
+
import glob
|
| 4 |
+
import os
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
from tomlkit import load
|
| 8 |
+
|
| 9 |
+
ROOT_DIR = Path(__file__).parent.parent
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_optional_packages():
|
| 13 |
+
"""Ensure only required extensions are built and versions respect pyproject.toml"""
|
| 14 |
+
with open(ROOT_DIR / "pyproject.toml") as f:
|
| 15 |
+
data = load(f)
|
| 16 |
+
dependencies = data["tool"]["poetry"]["dependencies"]
|
| 17 |
+
extras = data["tool"]["poetry"]["extras"]
|
| 18 |
+
all_packages = extras["all"]
|
| 19 |
+
|
| 20 |
+
default_packages = []
|
| 21 |
+
optional_packages = []
|
| 22 |
+
|
| 23 |
+
for package, details in dependencies.items():
|
| 24 |
+
if isinstance(details, dict) and details.get("optional") is True:
|
| 25 |
+
optional_packages.append(package)
|
| 26 |
+
else:
|
| 27 |
+
default_packages.append(package)
|
| 28 |
+
|
| 29 |
+
# check that optional packages have the same content as all_packages and extras
|
| 30 |
+
assert sorted(optional_packages) == sorted(all_packages)
|
| 31 |
+
assert sorted(optional_packages) == sorted(extras["all"])
|
| 32 |
+
|
| 33 |
+
# assert that there is no overlap between default and optional packages
|
| 34 |
+
assert set(default_packages).isdisjoint(set(optional_packages))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def test_default_package_files():
|
| 38 |
+
"""Ensure only required extensions are built and versions respect pyproject.toml"""
|
| 39 |
+
with open(ROOT_DIR / "pyproject.toml") as f:
|
| 40 |
+
data = load(f)
|
| 41 |
+
dependencies = data["tool"]["poetry"]["dependencies"]
|
| 42 |
+
package_files = glob.glob("openbb_platform/openbb/package/*.py")
|
| 43 |
+
|
| 44 |
+
invalid_packages = []
|
| 45 |
+
default_packages = []
|
| 46 |
+
|
| 47 |
+
for package, details in dependencies.items():
|
| 48 |
+
if isinstance(details, dict) is False:
|
| 49 |
+
default_packages.append(package)
|
| 50 |
+
|
| 51 |
+
for file_path in package_files:
|
| 52 |
+
package_name = os.path.basename(file_path).replace(".py", "")
|
| 53 |
+
if package_name.startswith("_"):
|
| 54 |
+
continue
|
| 55 |
+
if "_" in package_name:
|
| 56 |
+
base_package = package_name.split("_")[0]
|
| 57 |
+
if "openbb-" + base_package not in default_packages:
|
| 58 |
+
invalid_packages.append(package_name)
|
| 59 |
+
elif "openbb-" + package_name not in default_packages:
|
| 60 |
+
invalid_packages.append(package_name)
|
| 61 |
+
|
| 62 |
+
assert not invalid_packages, (
|
| 63 |
+
f"If not making a PR, ignore this error -> "
|
| 64 |
+
f"Found non-required extension static assets: {invalid_packages}. "
|
| 65 |
+
f"Only required packages should be committed."
|
| 66 |
+
f"Please create a new environment with only required extensions, "
|
| 67 |
+
f"rebuild the static assets, and commit the changes."
|
| 68 |
+
)
|