remove pytest-depends, rerouting functions (#250)
parent
aa37109707
commit
19848f362d
|
@ -1 +1 @@
|
|||
Subproject commit c7daa64eb72e7d4598de2c748727627898ae81e0
|
||||
Subproject commit e2d7b3b8d2cd34c2ac628debbf026b994a04346d
|
|
@ -14,7 +14,6 @@ from agbenchmark.reports.reports import (
|
|||
generate_combined_suite_report,
|
||||
generate_single_call_report,
|
||||
session_finish,
|
||||
setup_dummy_dependencies,
|
||||
)
|
||||
from agbenchmark.start_benchmark import CONFIG_PATH, get_regression_data
|
||||
from agbenchmark.utils.data_types import SuiteConfig
|
||||
|
@ -23,6 +22,8 @@ GLOBAL_TIMEOUT = (
|
|||
1500 # The tests will stop after 25 minutes so we can send the reports.
|
||||
)
|
||||
|
||||
pytest_plugins = ["agbenchmark.utils.dependencies"]
|
||||
|
||||
|
||||
def resolve_workspace(workspace: str) -> str:
|
||||
if workspace.startswith("${") and workspace.endswith("}"):
|
||||
|
@ -159,15 +160,12 @@ def pytest_runtest_makereport(item: Any, call: Any) -> None:
|
|||
flags = "--test" in sys.argv or "--maintain" in sys.argv or "--improve" in sys.argv
|
||||
|
||||
if call.when == "call":
|
||||
test_name = ""
|
||||
# if it's a same task suite, we combine the report.
|
||||
# but not if it's a single --test
|
||||
if is_suite and is_suite.same_task and not flags:
|
||||
test_name = is_suite.prefix
|
||||
generate_combined_suite_report(item, challenge_data, challenge_location)
|
||||
else:
|
||||
# single non suite test
|
||||
test_name = challenge_data["name"]
|
||||
generate_single_call_report(item, call, challenge_data)
|
||||
# else: it's a same_task=false suite (tests aren't combined)
|
||||
if call.when == "teardown":
|
||||
|
@ -204,16 +202,6 @@ def scores(request: Any) -> None:
|
|||
return request.node.cls.scores.get(test_class_name)
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc: Any) -> None:
|
||||
"""This is to generate the dummy dependencies each test class"""
|
||||
test_class_instance = metafunc.cls()
|
||||
|
||||
if test_class_instance.setup_dependencies:
|
||||
test_class = metafunc.cls
|
||||
setup_dummy_dependencies(test_class_instance, test_class)
|
||||
setattr(test_class, "setup_dependencies", [])
|
||||
|
||||
|
||||
# this is adding the dependency marker and category markers automatically from the json
|
||||
def pytest_collection_modifyitems(items: Any, config: Any) -> None:
|
||||
data = get_regression_data()
|
||||
|
@ -222,7 +210,6 @@ def pytest_collection_modifyitems(items: Any, config: Any) -> None:
|
|||
# Assuming item.cls is your test class
|
||||
test_class_instance = item.cls()
|
||||
|
||||
# if it's a dummy dependency setup test, we also skip
|
||||
if "test_method" not in item.name:
|
||||
continue
|
||||
|
||||
|
@ -231,28 +218,22 @@ def pytest_collection_modifyitems(items: Any, config: Any) -> None:
|
|||
dependencies = test_class_instance.data.dependencies
|
||||
|
||||
# Filter dependencies if they exist in regression data if its an improvement test
|
||||
if (
|
||||
config.getoption("--improve")
|
||||
or config.getoption("--category")
|
||||
or test_class_instance.setup_dependencies # same_task suite
|
||||
):
|
||||
if config.getoption("--improve") or config.getoption(
|
||||
"--category"
|
||||
): # TODO: same task suite
|
||||
dependencies = [dep for dep in dependencies if not data.get(dep, None)]
|
||||
if (
|
||||
if ( # TODO: separate task suite
|
||||
config.getoption("--test")
|
||||
or ( # separate task suite
|
||||
not test_class_instance.setup_dependencies
|
||||
and config.getoption("--suite")
|
||||
)
|
||||
or config.getoption("--no_dep")
|
||||
or config.getoption("--maintain")
|
||||
):
|
||||
dependencies = []
|
||||
|
||||
categories = test_class_instance.data.category
|
||||
|
||||
# Add depends marker dynamically
|
||||
item.add_marker(pytest.mark.depends(on=dependencies, name=name))
|
||||
|
||||
categories = test_class_instance.data.category
|
||||
|
||||
# Add category marker dynamically
|
||||
for category in categories:
|
||||
item.add_marker(getattr(pytest.mark, category))
|
||||
|
|
|
@ -5,7 +5,7 @@ import sys
|
|||
import types
|
||||
from collections import deque
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any, Callable, Dict, Optional
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -14,11 +14,52 @@ from agbenchmark.utils.challenge import Challenge
|
|||
from agbenchmark.utils.data_types import ChallengeData, SuiteConfig
|
||||
from agbenchmark.utils.utils import get_test_path
|
||||
|
||||
DATA_CATEGORY = {}
|
||||
|
||||
|
||||
def setup_dummy_dependencies(
|
||||
file_datum: list[dict[str, Any]],
|
||||
challenge_class: Any,
|
||||
challenge_data: ChallengeData,
|
||||
) -> None:
|
||||
"""Sets up the dependencies if it's a suite. Creates tests that pass
|
||||
based on the main test run."""
|
||||
|
||||
def create_test_func(test_name: str) -> Callable[[Any, dict[str, Any]], None]:
|
||||
# This function will return another function
|
||||
|
||||
# Define a dummy test function that does nothing
|
||||
def setup_dependency_test(self: Any, scores: dict[str, Any]) -> None:
|
||||
scores = self.get_dummy_scores(test_name, scores)
|
||||
assert scores == 1
|
||||
|
||||
return setup_dependency_test
|
||||
|
||||
for datum in file_datum:
|
||||
DATA_CATEGORY[datum["name"]] = challenge_data.category[0]
|
||||
test_func = create_test_func(datum["name"])
|
||||
# TODO: replace this once I figure out actual dependencies
|
||||
test_func = pytest.mark.depends(on=[challenge_data.name], name=datum["name"])(
|
||||
test_func
|
||||
)
|
||||
test_func = pytest.mark.parametrize(
|
||||
"challenge_data",
|
||||
[None],
|
||||
indirect=True,
|
||||
)(test_func)
|
||||
|
||||
# Add category markers
|
||||
for category in challenge_data.category:
|
||||
test_func = getattr(pytest.mark, category)(test_func)
|
||||
|
||||
test_func = pytest.mark.usefixtures("scores")(test_func)
|
||||
setattr(challenge_class, f"test_{datum['name']}", test_func)
|
||||
|
||||
|
||||
def create_single_test(
|
||||
data: Dict[str, Any] | ChallengeData,
|
||||
challenge_location: str,
|
||||
suite_config: Optional[SuiteConfig] = None,
|
||||
file_datum: Optional[list[dict[str, Any]]] = None,
|
||||
) -> None:
|
||||
challenge_data = None
|
||||
artifacts_location = None
|
||||
|
@ -26,23 +67,22 @@ def create_single_test(
|
|||
challenge_data = data
|
||||
data = data.get_data()
|
||||
|
||||
DATA_CATEGORY[data["name"]] = data["category"][0]
|
||||
|
||||
# Define test class dynamically
|
||||
challenge_class = types.new_class(data["name"], (Challenge,))
|
||||
|
||||
clean_challenge_location = get_test_path(challenge_location)
|
||||
setattr(challenge_class, "CHALLENGE_LOCATION", clean_challenge_location)
|
||||
|
||||
# if its a parallel run suite we just give it the data
|
||||
if suite_config and suite_config.same_task:
|
||||
# in the case of a suite
|
||||
if isinstance(challenge_data, ChallengeData):
|
||||
if file_datum: # same task suite
|
||||
setup_dummy_dependencies(file_datum, challenge_class, challenge_data)
|
||||
|
||||
artifacts_location = str(Path(challenge_location).resolve())
|
||||
if "--test" in sys.argv or "--maintain" in sys.argv or "--improve" in sys.argv:
|
||||
artifacts_location = str(Path(challenge_location).resolve().parent.parent)
|
||||
else:
|
||||
setattr(
|
||||
challenge_class,
|
||||
"setup_dependencies",
|
||||
[test_name for test_name in data["info"].keys()],
|
||||
)
|
||||
setattr(
|
||||
challenge_class,
|
||||
"_data_cache",
|
||||
|
@ -83,15 +123,8 @@ def create_single_test(
|
|||
setattr(module, data["name"], challenge_class)
|
||||
|
||||
|
||||
def create_single_suite_challenge(
|
||||
suite_config: SuiteConfig, data: Dict[str, Any], path: Path
|
||||
) -> None:
|
||||
test_data = suite_config.challenge_from_test_data(data)
|
||||
create_single_test(
|
||||
test_data,
|
||||
str(path),
|
||||
suite_config=suite_config,
|
||||
)
|
||||
def create_single_suite_challenge(challenge_data: ChallengeData, path: Path) -> None:
|
||||
create_single_test(challenge_data, str(path))
|
||||
|
||||
|
||||
def create_challenge(
|
||||
|
@ -106,7 +139,8 @@ def create_challenge(
|
|||
|
||||
# if its a single test running we dont care about the suite
|
||||
if "--test" in sys.argv or "--maintain" in sys.argv or "--improve" in sys.argv:
|
||||
create_single_suite_challenge(suite_config, data, path)
|
||||
challenge_data = suite_config.challenge_from_test_data(data)
|
||||
create_single_suite_challenge(challenge_data, path)
|
||||
return json_files
|
||||
|
||||
# Get all data.json files within the grandparent directory
|
||||
|
@ -132,7 +166,7 @@ def create_challenge(
|
|||
challenge_data = suite_config.challenge_from_datum(file_datum)
|
||||
|
||||
create_single_test(
|
||||
challenge_data, str(grandparent_dir), suite_config=suite_config
|
||||
challenge_data, str(grandparent_dir), file_datum=file_datum
|
||||
)
|
||||
else:
|
||||
reverse = suite_config.reverse_order
|
||||
|
|
|
@ -2,9 +2,7 @@ import json
|
|||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
|
||||
import pytest
|
||||
from typing import Any
|
||||
|
||||
from agbenchmark.agent_interface import MOCK_FLAG
|
||||
from agbenchmark.reports.ReportManager import ReportManager
|
||||
|
@ -194,41 +192,6 @@ def generate_single_call_report(
|
|||
item.info_details = info_details
|
||||
|
||||
|
||||
def setup_dummy_dependencies(test_class_instance: Any, test_class: Any) -> None:
|
||||
"""Sets up the dependencies if it's a suite. Creates tests that pass
|
||||
based on the main test run."""
|
||||
|
||||
def create_test_func(test_name: str) -> Callable[[Any, dict[str, Any]], None]:
|
||||
# This function will return another function
|
||||
|
||||
# Define a dummy test function that does nothing
|
||||
def setup_dependency_test(self: Any, scores: dict[str, Any]) -> None:
|
||||
scores = self.get_dummy_scores(test_name, scores)
|
||||
assert scores == 1
|
||||
|
||||
return setup_dependency_test
|
||||
|
||||
for test_name in test_class_instance.setup_dependencies:
|
||||
setup_dependency_test = create_test_func(test_name)
|
||||
# Add the dummy test function to the class that the current test is part of
|
||||
# TODO: remove on=[test_class.__name__] and fix the actual dependencies problem
|
||||
test_func = pytest.mark.depends(on=[test_class.__name__], name=test_name)(
|
||||
setup_dependency_test
|
||||
)
|
||||
# Parametrize to tell makereport to skip it
|
||||
test_func = pytest.mark.parametrize(
|
||||
"challenge_data",
|
||||
[None],
|
||||
indirect=True,
|
||||
)(test_func)
|
||||
# Add category markers
|
||||
for category in test_class_instance.data.category:
|
||||
test_func = getattr(pytest.mark, category)(test_func)
|
||||
|
||||
test_func = pytest.mark.usefixtures("scores")(test_func)
|
||||
setattr(test_class, f"test_{test_name}", test_func)
|
||||
|
||||
|
||||
def finalize_reports(item: Any, challenge_data: dict[str, Any]) -> None:
|
||||
run_time = dict(item.user_properties).get("run_time")
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ if os.environ.get("HELICONE_API_KEY"):
|
|||
"benchmark_start_time", BENCHMARK_START_TIME
|
||||
)
|
||||
|
||||
|
||||
(
|
||||
HOME_DIRECTORY,
|
||||
CONFIG_PATH,
|
||||
|
|
|
@ -25,7 +25,6 @@ class Challenge(ABC):
|
|||
_data_cache: Dict[str, ChallengeData] = {}
|
||||
CHALLENGE_LOCATION: str = ""
|
||||
ARTIFACTS_LOCATION: str = "" # this is for suites
|
||||
setup_dependencies: List[str] = [] # this is for suites
|
||||
scores: dict[str, Any] = {} # this is for suites
|
||||
|
||||
@property
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
"""
|
||||
A module that provides the pytest hooks for this plugin.
|
||||
|
||||
The logic itself is in main.py.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
import pytest
|
||||
from _pytest.config.argparsing import OptionGroup
|
||||
from _pytest.nodes import Item
|
||||
|
||||
from .main import DependencyManager
|
||||
|
||||
# Each test suite run should have a single manager object. For regular runs, a simple singleton would suffice, but for
|
||||
# our own tests this causes problems, as the nested pytest runs get the same instance. This can be worked around by
|
||||
# running them all in subprocesses, but this slows the tests down massively. Instead, keep a stack of managers, so each
|
||||
# test suite will have its own manager, even nested ones.
|
||||
managers: list[DependencyManager] = []
|
||||
|
||||
|
||||
DEPENDENCY_PROBLEM_ACTIONS: dict[str, Callable[[str], None] | None] = {
|
||||
"run": None,
|
||||
"skip": lambda m: pytest.skip(m),
|
||||
"fail": lambda m: pytest.fail(m, False),
|
||||
"warning": lambda m: warnings.warn(m),
|
||||
}
|
||||
|
||||
|
||||
def _add_ini_and_option(
|
||||
parser: Any,
|
||||
group: OptionGroup,
|
||||
name: str,
|
||||
help: str,
|
||||
default: str | bool | int,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Add an option to both the ini file as well as the command line flags, with the latter overriding the former."""
|
||||
parser.addini(
|
||||
name,
|
||||
help + " This overrides the similarly named option from the config.",
|
||||
default=default,
|
||||
)
|
||||
group.addoption(f'--{name.replace("_", "-")}', help=help, default=None, **kwargs)
|
||||
|
||||
|
||||
def _get_ini_or_option(
|
||||
config: Any, name: str, choices: Optional[list[str]]
|
||||
) -> str | None:
|
||||
"""Get an option from either the ini file or the command line flags, the latter taking precedence."""
|
||||
value = config.getini(name)
|
||||
if value is not None and choices is not None and value not in choices:
|
||||
raise ValueError(
|
||||
f'Invalid ini value for {name}, choose from {", ".join(choices)}'
|
||||
)
|
||||
return config.getoption(name) or value
|
||||
|
||||
|
||||
def pytest_addoption(parser: Any) -> None:
|
||||
group = parser.getgroup("depends")
|
||||
|
||||
# Add a flag to list all names + the tests they resolve to
|
||||
group.addoption(
|
||||
"--list-dependency-names",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=(
|
||||
"List all non-nodeid dependency names + the tests they resolve to. "
|
||||
"Will also list all nodeid dependency names when verbosity is high enough."
|
||||
),
|
||||
)
|
||||
|
||||
# Add a flag to list all (resolved) dependencies for all tests + unresolvable names
|
||||
group.addoption(
|
||||
"--list-processed-dependencies",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="List all dependencies of all tests as a list of nodeids + the names that could not be resolved.",
|
||||
)
|
||||
|
||||
# Add an ini option + flag to choose the action to take for failed dependencies
|
||||
_add_ini_and_option(
|
||||
parser,
|
||||
group,
|
||||
name="failed_dependency_action",
|
||||
help=(
|
||||
"The action to take when a test has dependencies that failed. "
|
||||
'Use "run" to run the test anyway, "skip" to skip the test, and "fail" to fail the test.'
|
||||
),
|
||||
default="skip",
|
||||
choices=DEPENDENCY_PROBLEM_ACTIONS.keys(),
|
||||
)
|
||||
|
||||
# Add an ini option + flag to choose the action to take for unresolved dependencies
|
||||
_add_ini_and_option(
|
||||
parser,
|
||||
group,
|
||||
name="missing_dependency_action",
|
||||
help=(
|
||||
"The action to take when a test has dependencies that cannot be found within the current scope. "
|
||||
'Use "run" to run the test anyway, "skip" to skip the test, and "fail" to fail the test.'
|
||||
),
|
||||
default="warning",
|
||||
choices=DEPENDENCY_PROBLEM_ACTIONS.keys(),
|
||||
)
|
||||
|
||||
|
||||
def pytest_configure(config: Any) -> None:
|
||||
manager = DependencyManager()
|
||||
managers.append(manager)
|
||||
|
||||
# Setup the handling of problems with dependencies
|
||||
manager.options["failed_dependency_action"] = _get_ini_or_option(
|
||||
config,
|
||||
"failed_dependency_action",
|
||||
list(DEPENDENCY_PROBLEM_ACTIONS.keys()),
|
||||
)
|
||||
manager.options["missing_dependency_action"] = _get_ini_or_option(
|
||||
config,
|
||||
"missing_dependency_action",
|
||||
list(DEPENDENCY_PROBLEM_ACTIONS.keys()),
|
||||
)
|
||||
|
||||
# Register marker
|
||||
config.addinivalue_line(
|
||||
"markers",
|
||||
"depends(name='name', on=['other_name']): marks depencies between tests.",
|
||||
)
|
||||
|
||||
|
||||
@pytest.hookimpl(trylast=True)
|
||||
def pytest_collection_modifyitems(config: Any, items: list[Item]) -> None:
|
||||
manager = managers[-1]
|
||||
|
||||
# Register the founds tests on the manager
|
||||
manager.items = items
|
||||
|
||||
# Show the extra information if requested
|
||||
if config.getoption("list_dependency_names"):
|
||||
verbose = config.getoption("verbose") > 1
|
||||
manager.print_name_map(verbose)
|
||||
if config.getoption("list_processed_dependencies"):
|
||||
color = config.getoption("color")
|
||||
manager.print_processed_dependencies(color)
|
||||
|
||||
# Reorder the items so that tests run after their dependencies
|
||||
items[:] = manager.sorted_items
|
||||
|
||||
|
||||
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
||||
def pytest_runtest_makereport(item: Item) -> Any:
|
||||
manager = managers[-1]
|
||||
|
||||
# Run the step
|
||||
outcome = yield
|
||||
|
||||
# Store the result on the manager
|
||||
manager.register_result(item, outcome.get_result())
|
||||
|
||||
|
||||
def pytest_runtest_call(item: Item) -> None:
|
||||
manager = managers[-1]
|
||||
|
||||
# Handle missing dependencies
|
||||
missing_dependency_action = DEPENDENCY_PROBLEM_ACTIONS[
|
||||
manager.options["missing_dependency_action"]
|
||||
]
|
||||
missing = manager.get_missing(item)
|
||||
if missing_dependency_action and missing:
|
||||
missing_dependency_action(
|
||||
f'{item.nodeid} depends on {", ".join(missing)}, which was not found'
|
||||
)
|
||||
|
||||
# Check whether all dependencies succeeded
|
||||
failed_dependency_action = DEPENDENCY_PROBLEM_ACTIONS[
|
||||
manager.options["failed_dependency_action"]
|
||||
]
|
||||
failed = manager.get_failed(item)
|
||||
if failed_dependency_action and failed:
|
||||
failed_dependency_action(f'{item.nodeid} depends on {", ".join(failed)}')
|
||||
|
||||
|
||||
def pytest_unconfigure() -> None:
|
||||
managers.pop()
|
|
@ -0,0 +1,10 @@
|
|||
""" Constants for this module. """
|
||||
|
||||
# The name of the marker used
|
||||
MARKER_NAME = "depends"
|
||||
|
||||
# The name of the keyword argument for the marker that contains custom name(s) for the tests
|
||||
MARKER_KWARG_ID = "name"
|
||||
|
||||
# The name of the keyword argument for the marker that specifies the tests to depend on
|
||||
MARKER_KWARG_DEPENDENCIES = "on"
|
|
@ -0,0 +1,265 @@
|
|||
import math
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
import matplotlib.patches as patches
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
import numpy as np
|
||||
from pyvis.network import Network
|
||||
|
||||
from agbenchmark.generate_test import DATA_CATEGORY
|
||||
|
||||
|
||||
def bezier_curve(
|
||||
src: np.ndarray, ctrl: List[float], dst: np.ndarray
|
||||
) -> List[np.ndarray]:
|
||||
"""
|
||||
Generate Bézier curve points.
|
||||
|
||||
Args:
|
||||
- src (np.ndarray): The source point.
|
||||
- ctrl (List[float]): The control point.
|
||||
- dst (np.ndarray): The destination point.
|
||||
|
||||
Returns:
|
||||
- List[np.ndarray]: The Bézier curve points.
|
||||
"""
|
||||
curve = []
|
||||
for t in np.linspace(0, 1, num=100):
|
||||
curve_point = (
|
||||
np.outer((1 - t) ** 2, src)
|
||||
+ 2 * np.outer((1 - t) * t, ctrl)
|
||||
+ np.outer(t**2, dst)
|
||||
)
|
||||
curve.append(curve_point[0])
|
||||
return curve
|
||||
|
||||
|
||||
def curved_edges(
|
||||
G: nx.Graph, pos: Dict[Any, Tuple[float, float]], dist: float = 0.2
|
||||
) -> None:
|
||||
"""
|
||||
Draw curved edges for nodes on the same level.
|
||||
|
||||
Args:
|
||||
- G (Any): The graph object.
|
||||
- pos (Dict[Any, Tuple[float, float]]): Dictionary with node positions.
|
||||
- dist (float, optional): Distance for curvature. Defaults to 0.2.
|
||||
|
||||
Returns:
|
||||
- None
|
||||
"""
|
||||
ax = plt.gca()
|
||||
for u, v, data in G.edges(data=True):
|
||||
src = np.array(pos[u])
|
||||
dst = np.array(pos[v])
|
||||
|
||||
same_level = abs(src[1] - dst[1]) < 0.01
|
||||
|
||||
if same_level:
|
||||
control = [(src[0] + dst[0]) / 2, src[1] + dist]
|
||||
curve = bezier_curve(src, control, dst)
|
||||
arrow = patches.FancyArrowPatch(
|
||||
posA=curve[0], # type: ignore
|
||||
posB=curve[-1], # type: ignore
|
||||
connectionstyle=f"arc3,rad=0.2",
|
||||
color="gray",
|
||||
arrowstyle="-|>",
|
||||
mutation_scale=15.0,
|
||||
lw=1,
|
||||
shrinkA=10,
|
||||
shrinkB=10,
|
||||
)
|
||||
ax.add_patch(arrow)
|
||||
else:
|
||||
ax.annotate(
|
||||
"",
|
||||
xy=dst,
|
||||
xytext=src,
|
||||
arrowprops=dict(
|
||||
arrowstyle="-|>", color="gray", lw=1, shrinkA=10, shrinkB=10
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def tree_layout(graph: nx.DiGraph, root_node: Any) -> Dict[Any, Tuple[float, float]]:
|
||||
"""Compute positions as a tree layout centered on the root with alternating vertical shifts."""
|
||||
bfs_tree = nx.bfs_tree(graph, source=root_node)
|
||||
levels = {
|
||||
node: depth
|
||||
for node, depth in nx.single_source_shortest_path_length(
|
||||
bfs_tree, root_node
|
||||
).items()
|
||||
}
|
||||
|
||||
pos = {}
|
||||
max_depth = max(levels.values())
|
||||
level_positions = {i: 0 for i in range(max_depth + 1)} # type: ignore
|
||||
|
||||
# Count the number of nodes per level to compute the width
|
||||
level_count: Any = {}
|
||||
for node, level in levels.items():
|
||||
level_count[level] = level_count.get(level, 0) + 1
|
||||
|
||||
vertical_offset = (
|
||||
0.07 # The amount of vertical shift per node within the same level
|
||||
)
|
||||
|
||||
# Assign positions
|
||||
for node, level in sorted(levels.items(), key=lambda x: x[1]):
|
||||
total_nodes_in_level = level_count[level]
|
||||
horizontal_spacing = 1.0 / (total_nodes_in_level + 1)
|
||||
pos_x = (
|
||||
0.5
|
||||
- (total_nodes_in_level - 1) * horizontal_spacing / 2
|
||||
+ level_positions[level] * horizontal_spacing
|
||||
)
|
||||
|
||||
# Alternately shift nodes up and down within the same level
|
||||
pos_y = (
|
||||
-level
|
||||
+ (level_positions[level] % 2) * vertical_offset
|
||||
- ((level_positions[level] + 1) % 2) * vertical_offset
|
||||
)
|
||||
pos[node] = (pos_x, pos_y)
|
||||
|
||||
level_positions[level] += 1
|
||||
|
||||
return pos
|
||||
|
||||
|
||||
def graph_spring_layout(
|
||||
dag: nx.DiGraph, labels: Dict[Any, str], tree: bool = True
|
||||
) -> None:
|
||||
num_nodes = len(dag.nodes())
|
||||
# Setting up the figure and axis
|
||||
fig, ax = plt.subplots()
|
||||
ax.axis("off") # Turn off the axis
|
||||
|
||||
base = 3.0
|
||||
|
||||
if num_nodes > 10:
|
||||
base /= 1 + math.log(num_nodes)
|
||||
font_size = base * 10
|
||||
|
||||
font_size = max(10, base * 10)
|
||||
node_size = max(300, base * 1000)
|
||||
|
||||
if tree:
|
||||
root_node = [node for node, degree in dag.in_degree() if degree == 0][0]
|
||||
pos = tree_layout(dag, root_node)
|
||||
else:
|
||||
# Adjust k for the spring layout based on node count
|
||||
k_value = 3 / math.sqrt(num_nodes)
|
||||
|
||||
pos = nx.spring_layout(dag, k=k_value, iterations=50)
|
||||
|
||||
# Draw nodes and labels
|
||||
nx.draw_networkx_nodes(dag, pos, node_color="skyblue", node_size=int(node_size))
|
||||
nx.draw_networkx_labels(dag, pos, labels=labels, font_size=int(font_size))
|
||||
|
||||
# Draw curved edges
|
||||
curved_edges(dag, pos) # type: ignore
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
|
||||
def rgb_to_hex(rgb: Tuple[float, float, float]) -> str:
|
||||
return "#{:02x}{:02x}{:02x}".format(
|
||||
int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255)
|
||||
)
|
||||
|
||||
|
||||
def get_category_colors(categories: Dict[Any, str]) -> Dict[str, str]:
|
||||
unique_categories = set(categories.values())
|
||||
colormap = plt.cm.get_cmap("tab10", len(unique_categories)) # type: ignore
|
||||
return {
|
||||
category: rgb_to_hex(colormap(i)[:3])
|
||||
for i, category in enumerate(unique_categories)
|
||||
}
|
||||
|
||||
|
||||
def graph_interactive_network(
|
||||
dag: nx.DiGraph, labels: Dict[Any, str], show: bool = False
|
||||
) -> None:
|
||||
nt = Network(notebook=True, width="100%", height="800px", directed=True)
|
||||
|
||||
category_colors = get_category_colors(DATA_CATEGORY)
|
||||
|
||||
# Add nodes and edges to the pyvis network
|
||||
for node, label in labels.items():
|
||||
node_id_str = node.nodeid
|
||||
|
||||
# Get the category for this label
|
||||
category = DATA_CATEGORY.get(
|
||||
label, "unknown"
|
||||
) # Default to 'unknown' if label not found
|
||||
|
||||
# Get the color for this category
|
||||
color = category_colors.get(category, "grey")
|
||||
|
||||
nt.add_node(node_id_str, label=label, color=color)
|
||||
|
||||
# Add edges to the pyvis network
|
||||
for edge in dag.edges():
|
||||
source_id_str = edge[0].nodeid
|
||||
target_id_str = edge[1].nodeid
|
||||
if not (source_id_str in nt.get_nodes() and target_id_str in nt.get_nodes()):
|
||||
print(
|
||||
f"Skipping edge {source_id_str} -> {target_id_str} due to missing nodes."
|
||||
)
|
||||
continue
|
||||
nt.add_edge(source_id_str, target_id_str)
|
||||
|
||||
# Configure physics for hierarchical layout
|
||||
hierarchical_options = {
|
||||
"enabled": True,
|
||||
"levelSeparation": 200, # Increased vertical spacing between levels
|
||||
"nodeSpacing": 250, # Increased spacing between nodes on the same level
|
||||
"treeSpacing": 250, # Increased spacing between different trees (for forest)
|
||||
"blockShifting": True,
|
||||
"edgeMinimization": True,
|
||||
"parentCentralization": True,
|
||||
"direction": "UD",
|
||||
"sortMethod": "directed",
|
||||
}
|
||||
|
||||
physics_options = {
|
||||
"stabilization": {
|
||||
"enabled": True,
|
||||
"iterations": 1000, # Default is often around 100
|
||||
},
|
||||
"hierarchicalRepulsion": {
|
||||
"centralGravity": 0.0,
|
||||
"springLength": 200, # Increased edge length
|
||||
"springConstant": 0.01,
|
||||
"nodeDistance": 250, # Increased minimum distance between nodes
|
||||
"damping": 0.09,
|
||||
},
|
||||
"solver": "hierarchicalRepulsion",
|
||||
"timestep": 0.5,
|
||||
}
|
||||
|
||||
nt.options = {
|
||||
"nodes": {
|
||||
"font": {
|
||||
"size": 20, # Increased font size for labels
|
||||
"color": "black", # Set a readable font color
|
||||
},
|
||||
"shapeProperties": {"useBorderWithImage": True},
|
||||
},
|
||||
"edges": {
|
||||
"length": 250, # Increased edge length
|
||||
},
|
||||
"physics": physics_options,
|
||||
"layout": {"hierarchical": hierarchical_options},
|
||||
}
|
||||
|
||||
relative_path = "agbenchmark/challenges/dependencies.html"
|
||||
file_path = str(Path(relative_path).resolve())
|
||||
|
||||
if show:
|
||||
nt.show(file_path, notebook=False)
|
||||
nt.write_html(file_path)
|
|
@ -0,0 +1,239 @@
|
|||
"""
|
||||
A module to manage dependencies between pytest tests.
|
||||
|
||||
This module provides the methods implementing the main logic. These are used in the pytest hooks that are in
|
||||
__init__.py.
|
||||
"""
|
||||
|
||||
import collections
|
||||
from typing import Any, Generator
|
||||
|
||||
import colorama
|
||||
import networkx
|
||||
from _pytest.nodes import Item
|
||||
|
||||
from .constants import MARKER_KWARG_DEPENDENCIES, MARKER_NAME
|
||||
from .graphs import graph_interactive_network
|
||||
from .util import clean_nodeid, get_absolute_nodeid, get_markers, get_name
|
||||
|
||||
|
||||
class TestResult(object):
|
||||
"""Keeps track of the results of a single test."""
|
||||
|
||||
STEPS = ["setup", "call", "teardown"]
|
||||
GOOD_OUTCOMES = ["passed"]
|
||||
|
||||
def __init__(self, nodeid: str) -> None:
|
||||
"""Create a new instance for a test with a given node id."""
|
||||
self.nodeid = nodeid
|
||||
self.results: dict[str, Any] = {}
|
||||
|
||||
def register_result(self, result: Any) -> None:
|
||||
"""Register a result of this test."""
|
||||
if result.when not in self.STEPS:
|
||||
raise ValueError(
|
||||
f"Received result for unknown step {result.when} of test {self.nodeid}"
|
||||
)
|
||||
if result.when in self.results:
|
||||
raise AttributeError(
|
||||
f"Received multiple results for step {result.when} of test {self.nodeid}"
|
||||
)
|
||||
self.results[result.when] = result.outcome
|
||||
|
||||
@property
|
||||
def success(self) -> bool:
|
||||
"""Whether the entire test was successful."""
|
||||
return all(
|
||||
self.results.get(step, None) in self.GOOD_OUTCOMES for step in self.STEPS
|
||||
)
|
||||
|
||||
|
||||
class TestDependencies(object):
|
||||
"""Information about the resolved dependencies of a single test."""
|
||||
|
||||
def __init__(self, item: Item, manager: "DependencyManager") -> None:
|
||||
"""Create a new instance for a given test."""
|
||||
self.nodeid = clean_nodeid(item.nodeid)
|
||||
self.dependencies = set()
|
||||
self.unresolved = set()
|
||||
|
||||
markers = get_markers(item, MARKER_NAME)
|
||||
dependencies = [
|
||||
dep
|
||||
for marker in markers
|
||||
for dep in marker.kwargs.get(MARKER_KWARG_DEPENDENCIES, [])
|
||||
]
|
||||
for dependency in dependencies:
|
||||
# If the name is not known, try to make it absolute (ie file::[class::]method)
|
||||
if dependency not in manager.name_to_nodeids:
|
||||
absolute_dependency = get_absolute_nodeid(dependency, self.nodeid)
|
||||
if absolute_dependency in manager.name_to_nodeids:
|
||||
dependency = absolute_dependency
|
||||
|
||||
# Add all items matching the name
|
||||
if dependency in manager.name_to_nodeids:
|
||||
for nodeid in manager.name_to_nodeids[dependency]:
|
||||
self.dependencies.add(nodeid)
|
||||
else:
|
||||
self.unresolved.add(dependency)
|
||||
|
||||
|
||||
class DependencyManager(object):
|
||||
"""Keep track of tests, their names and their dependencies."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Create a new DependencyManager."""
|
||||
self.options: dict[str, Any] = {}
|
||||
self._items: list[Item] | None = None
|
||||
self._name_to_nodeids: Any = None
|
||||
self._nodeid_to_item: Any = None
|
||||
self._results: Any = None
|
||||
|
||||
@property
|
||||
def items(self) -> list[Item]:
|
||||
"""The collected tests that are managed by this instance."""
|
||||
if self._items is None:
|
||||
raise AttributeError("The items attribute has not been set yet")
|
||||
return self._items
|
||||
|
||||
@items.setter
|
||||
def items(self, items: list[Item]) -> None:
|
||||
if self._items is not None:
|
||||
raise AttributeError("The items attribute has already been set")
|
||||
self._items = items
|
||||
|
||||
self._name_to_nodeids = collections.defaultdict(list)
|
||||
self._nodeid_to_item = {}
|
||||
self._results = {}
|
||||
self._dependencies = {}
|
||||
|
||||
for item in items:
|
||||
nodeid = clean_nodeid(item.nodeid)
|
||||
# Add the mapping from nodeid to the test item
|
||||
self._nodeid_to_item[nodeid] = item
|
||||
# Add the mappings from all names to the node id
|
||||
name = get_name(item)
|
||||
self._name_to_nodeids[name].append(nodeid)
|
||||
# Create the object that will contain the results of this test
|
||||
self._results[nodeid] = TestResult(clean_nodeid(item.nodeid))
|
||||
|
||||
# Don't allow using unknown keys on the name_to_nodeids mapping
|
||||
self._name_to_nodeids.default_factory = None
|
||||
|
||||
for item in items:
|
||||
nodeid = clean_nodeid(item.nodeid)
|
||||
# Process the dependencies of this test
|
||||
# This uses the mappings created in the previous loop, and can thus not be merged into that loop
|
||||
self._dependencies[nodeid] = TestDependencies(item, self)
|
||||
|
||||
@property
|
||||
def name_to_nodeids(self) -> dict[str, list[str]]:
|
||||
"""A mapping from names to matching node id(s)."""
|
||||
assert self.items is not None
|
||||
return self._name_to_nodeids
|
||||
|
||||
@property
|
||||
def nodeid_to_item(self) -> dict[str, Item]:
|
||||
"""A mapping from node ids to test items."""
|
||||
assert self.items is not None
|
||||
return self._nodeid_to_item
|
||||
|
||||
@property
|
||||
def results(self) -> dict[str, TestResult]:
|
||||
"""The results of the tests."""
|
||||
assert self.items is not None
|
||||
return self._results
|
||||
|
||||
@property
|
||||
def dependencies(self) -> dict[str, TestDependencies]:
|
||||
"""The dependencies of the tests."""
|
||||
assert self.items is not None
|
||||
return self._dependencies
|
||||
|
||||
def print_name_map(self, verbose: bool = False) -> None:
|
||||
"""Print a human-readable version of the name -> test mapping."""
|
||||
print("Available dependency names:")
|
||||
for name, nodeids in sorted(self.name_to_nodeids.items(), key=lambda x: x[0]):
|
||||
if len(nodeids) == 1:
|
||||
if name == nodeids[0]:
|
||||
# This is just the base name, only print this when verbose
|
||||
if verbose:
|
||||
print(f" {name}")
|
||||
else:
|
||||
# Name refers to a single node id, so use the short format
|
||||
print(f" {name} -> {nodeids[0]}")
|
||||
else:
|
||||
# Name refers to multiple node ids, so use the long format
|
||||
print(f" {name} ->")
|
||||
for nodeid in sorted(nodeids):
|
||||
print(f" {nodeid}")
|
||||
|
||||
def print_processed_dependencies(self, colors: bool = False) -> None:
|
||||
"""Print a human-readable list of the processed dependencies."""
|
||||
missing = "MISSING"
|
||||
if colors:
|
||||
missing = f"{colorama.Fore.RED}{missing}{colorama.Fore.RESET}"
|
||||
colorama.init()
|
||||
try:
|
||||
print("Dependencies:")
|
||||
for nodeid, info in sorted(self.dependencies.items(), key=lambda x: x[0]):
|
||||
descriptions = []
|
||||
for dependency in info.dependencies:
|
||||
descriptions.append(dependency)
|
||||
for dependency in info.unresolved:
|
||||
descriptions.append(f"{dependency} ({missing})")
|
||||
if descriptions:
|
||||
print(f" {nodeid} depends on")
|
||||
for description in sorted(descriptions):
|
||||
print(f" {description}")
|
||||
finally:
|
||||
if colors:
|
||||
colorama.deinit()
|
||||
|
||||
@property
|
||||
def sorted_items(self, show_graph: bool = False) -> Generator:
|
||||
"""Get a sorted list of tests where all tests are sorted after their dependencies."""
|
||||
# Build a directed graph for sorting
|
||||
dag = networkx.DiGraph()
|
||||
|
||||
# Insert all items as nodes, to prevent items that have no dependencies and are not dependencies themselves from
|
||||
# being lost
|
||||
dag.add_nodes_from(self.items)
|
||||
|
||||
# Insert edges for all the dependencies
|
||||
for item in self.items:
|
||||
nodeid = clean_nodeid(item.nodeid)
|
||||
for dependency in self.dependencies[nodeid].dependencies:
|
||||
dag.add_edge(self.nodeid_to_item[dependency], item)
|
||||
|
||||
labels = {}
|
||||
for item in self.items:
|
||||
node_name = get_name(item)
|
||||
labels[item] = node_name
|
||||
|
||||
if show_graph:
|
||||
# graph_spring_layout(dag, labels)
|
||||
graph_interactive_network(dag, labels, show=False)
|
||||
|
||||
# Sort based on the dependencies
|
||||
return networkx.topological_sort(dag)
|
||||
|
||||
def register_result(self, item: Item, result: Any) -> None:
|
||||
"""Register a result of a test."""
|
||||
nodeid = clean_nodeid(item.nodeid)
|
||||
self.results[nodeid].register_result(result)
|
||||
|
||||
def get_failed(self, item: Item) -> Any:
|
||||
"""Get a list of unfulfilled dependencies for a test."""
|
||||
nodeid = clean_nodeid(item.nodeid)
|
||||
failed = []
|
||||
for dependency in self.dependencies[nodeid].dependencies:
|
||||
result = self.results[dependency]
|
||||
if not result.success:
|
||||
failed.append(dependency)
|
||||
return failed
|
||||
|
||||
def get_missing(self, item: Item) -> Any:
|
||||
"""Get a list of missing dependencies for a test."""
|
||||
nodeid = clean_nodeid(item.nodeid)
|
||||
return self.dependencies[nodeid].unresolved
|
|
@ -0,0 +1,85 @@
|
|||
""" Utility functions to process the identifiers of tests. """
|
||||
import re
|
||||
from typing import Iterator
|
||||
|
||||
from _pytest.mark.structures import Mark
|
||||
from _pytest.nodes import Item
|
||||
|
||||
from .constants import MARKER_KWARG_ID, MARKER_NAME
|
||||
|
||||
REGEX_PARAMETERS = re.compile(r"\[.+\]$")
|
||||
|
||||
|
||||
def clean_nodeid(nodeid: str) -> str:
|
||||
"""
|
||||
Remove any superfluous ::() from a node id.
|
||||
|
||||
>>> clean_nodeid('test_file.py::TestClass::()::test')
|
||||
'test_file.py::TestClass::test'
|
||||
>>> clean_nodeid('test_file.py::TestClass::test')
|
||||
'test_file.py::TestClass::test'
|
||||
>>> clean_nodeid('test_file.py::test')
|
||||
'test_file.py::test'
|
||||
"""
|
||||
return nodeid.replace("::()::", "::")
|
||||
|
||||
|
||||
def strip_nodeid_parameters(nodeid: str) -> str:
|
||||
"""
|
||||
Strip parameters from a node id.
|
||||
|
||||
>>> strip_nodeid_parameters('test_file.py::TestClass::test[foo]')
|
||||
'test_file.py::TestClass::test'
|
||||
>>> strip_nodeid_parameters('test_file.py::TestClass::test')
|
||||
'test_file.py::TestClass::test'
|
||||
"""
|
||||
return REGEX_PARAMETERS.sub("", nodeid)
|
||||
|
||||
|
||||
def get_absolute_nodeid(nodeid: str, scope: str) -> str:
|
||||
"""
|
||||
Transform a possibly relative node id to an absolute one using the scope in which it is used.
|
||||
|
||||
>>> scope = 'test_file.py::TestClass::test'
|
||||
>>> get_absolute_nodeid('test2', scope)
|
||||
'test_file.py::TestClass::test2'
|
||||
>>> get_absolute_nodeid('TestClass2::test2', scope)
|
||||
'test_file.py::TestClass2::test2'
|
||||
>>> get_absolute_nodeid('test_file2.py::TestClass2::test2', scope)
|
||||
'test_file2.py::TestClass2::test2'
|
||||
"""
|
||||
parts = nodeid.split("::")
|
||||
# Completely relative (test_name), so add the full current scope (either file::class or file)
|
||||
if len(parts) == 1:
|
||||
base_nodeid = scope.rsplit("::", 1)[0]
|
||||
nodeid = f"{base_nodeid}::{nodeid}"
|
||||
# Contains some scope already (Class::test_name), so only add the current file scope
|
||||
elif "." not in parts[0]:
|
||||
base_nodeid = scope.split("::", 1)[0]
|
||||
nodeid = f"{base_nodeid}::{nodeid}"
|
||||
return clean_nodeid(nodeid)
|
||||
|
||||
|
||||
def get_name(item: Item) -> str:
|
||||
"""
|
||||
Get all names for a test.
|
||||
|
||||
This will use the following methods to determine the name of the test:
|
||||
- If given, the custom name(s) passed to the keyword argument name on the marker
|
||||
"""
|
||||
name = ""
|
||||
|
||||
# Custom name
|
||||
markers = get_markers(item, MARKER_NAME)
|
||||
for marker in markers:
|
||||
if MARKER_KWARG_ID in marker.kwargs:
|
||||
name = marker.kwargs[MARKER_KWARG_ID]
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def get_markers(item: Item, name: str) -> Iterator[Mark]:
|
||||
"""Get all markers with the given name for a given item."""
|
||||
for marker in item.iter_markers():
|
||||
if marker.name == name:
|
||||
yield marker
|
|
@ -162,6 +162,34 @@ doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-
|
|||
test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
|
||||
trio = ["trio (<0.22)"]
|
||||
|
||||
[[package]]
|
||||
name = "appnope"
|
||||
version = "0.1.3"
|
||||
description = "Disable App Nap on macOS >= 10.9"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"},
|
||||
{file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asttokens"
|
||||
version = "2.2.1"
|
||||
description = "Annotate AST trees with source code positions"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"},
|
||||
{file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
six = "*"
|
||||
|
||||
[package.extras]
|
||||
test = ["astroid", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "4.0.2"
|
||||
|
@ -206,6 +234,17 @@ files = [
|
|||
pyflakes = ">=1.1.0,<3"
|
||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "backcall"
|
||||
version = "0.2.0"
|
||||
description = "Specifications for callback functions passed in to an API"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
|
||||
{file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "22.3.0"
|
||||
|
@ -451,6 +490,17 @@ files = [
|
|||
{file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "decorator"
|
||||
version = "5.1.1"
|
||||
description = "Decorators for Humans"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
|
||||
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.2"
|
||||
|
@ -465,6 +515,20 @@ files = [
|
|||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "executing"
|
||||
version = "1.2.0"
|
||||
description = "Get the currently executing AST node of a frame, and other information"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"},
|
||||
{file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["asttokens", "littleutils", "pytest", "rich"]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.100.1"
|
||||
|
@ -502,45 +566,45 @@ pyflakes = ">=2.3.0,<2.4.0"
|
|||
|
||||
[[package]]
|
||||
name = "fonttools"
|
||||
version = "4.41.1"
|
||||
version = "4.42.0"
|
||||
description = "Tools to manipulate font files"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fonttools-4.41.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a7bbb290d13c6dd718ec2c3db46fe6c5f6811e7ea1e07f145fd8468176398224"},
|
||||
{file = "fonttools-4.41.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec453a45778524f925a8f20fd26a3326f398bfc55d534e37bab470c5e415caa1"},
|
||||
{file = "fonttools-4.41.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2071267deaa6d93cb16288613419679c77220543551cbe61da02c93d92df72f"},
|
||||
{file = "fonttools-4.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e3334d51f0e37e2c6056e67141b2adabc92613a968797e2571ca8a03bd64773"},
|
||||
{file = "fonttools-4.41.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cac73bbef7734e78c60949da11c4903ee5837168e58772371bd42a75872f4f82"},
|
||||
{file = "fonttools-4.41.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:edee0900cf0eedb29d17c7876102d6e5a91ee333882b1f5abc83e85b934cadb5"},
|
||||
{file = "fonttools-4.41.1-cp310-cp310-win32.whl", hash = "sha256:2a22b2c425c698dcd5d6b0ff0b566e8e9663172118db6fd5f1941f9b8063da9b"},
|
||||
{file = "fonttools-4.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:547ab36a799dded58a46fa647266c24d0ed43a66028cd1cd4370b246ad426cac"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:849ec722bbf7d3501a0e879e57dec1fc54919d31bff3f690af30bb87970f9784"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38cdecd8f1fd4bf4daae7fed1b3170dfc1b523388d6664b2204b351820aa78a7"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ae64303ba670f8959fdaaa30ba0c2dabe75364fdec1caeee596c45d51ca3425"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14f3ccea4cc7dd1b277385adf3c3bf18f9860f87eab9c2fb650b0af16800f55"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:33191f062549e6bb1a4782c22a04ebd37009c09360e2d6686ac5083774d06d95"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:704bccd69b0abb6fab9f5e4d2b75896afa48b427caa2c7988792a2ffce35b441"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-win32.whl", hash = "sha256:4edc795533421e98f60acee7d28fc8d941ff5ac10f44668c9c3635ad72ae9045"},
|
||||
{file = "fonttools-4.41.1-cp311-cp311-win_amd64.whl", hash = "sha256:aaaef294d8e411f0ecb778a0aefd11bb5884c9b8333cc1011bdaf3b58ca4bd75"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3d1f9471134affc1e3b1b806db6e3e2ad3fa99439e332f1881a474c825101096"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:59eba8b2e749a1de85760da22333f3d17c42b66e03758855a12a2a542723c6e7"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9b3cc10dc9e0834b6665fd63ae0c6964c6bc3d7166e9bc84772e0edd09f9fa2"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2c2964bdc827ba6b8a91dc6de792620be4da3922c4cf0599f36a488c07e2b2"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7763316111df7b5165529f4183a334aa24c13cdb5375ffa1dc8ce309c8bf4e5c"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b2d1ee95be42b80d1f002d1ee0a51d7a435ea90d36f1a5ae331be9962ee5a3f1"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-win32.whl", hash = "sha256:f48602c0b3fd79cd83a34c40af565fe6db7ac9085c8823b552e6e751e3a5b8be"},
|
||||
{file = "fonttools-4.41.1-cp38-cp38-win_amd64.whl", hash = "sha256:b0938ebbeccf7c80bb9a15e31645cf831572c3a33d5cc69abe436e7000c61b14"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e5c2b0a95a221838991e2f0e455dec1ca3a8cc9cd54febd68cc64d40fdb83669"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:891cfc5a83b0307688f78b9bb446f03a7a1ad981690ac8362f50518bc6153975"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73ef0bb5d60eb02ba4d3a7d23ada32184bd86007cb2de3657cfcb1175325fc83"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f240d9adf0583ac8fc1646afe7f4ac039022b6f8fa4f1575a2cfa53675360b69"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bdd729744ae7ecd7f7311ad25d99da4999003dcfe43b436cf3c333d4e68de73d"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b927e5f466d99c03e6e20961946314b81d6e3490d95865ef88061144d9f62e38"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-win32.whl", hash = "sha256:afce2aeb80be72b4da7dd114f10f04873ff512793d13ce0b19d12b2a4c44c0f0"},
|
||||
{file = "fonttools-4.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:1df1b6f4c7c4bc8201eb47f3b268adbf2539943aa43c400f84556557e3e109c0"},
|
||||
{file = "fonttools-4.41.1-py3-none-any.whl", hash = "sha256:952cb405f78734cf6466252fec42e206450d1a6715746013f64df9cbd4f896fa"},
|
||||
{file = "fonttools-4.41.1.tar.gz", hash = "sha256:e16a9449f21a93909c5be2f5ed5246420f2316e94195dbfccb5238aaa38f9751"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9c456d1f23deff64ffc8b5b098718e149279abdea4d8692dba69172fb6a0d597"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:150122ed93127a26bc3670ebab7e2add1e0983d30927733aec327ebf4255b072"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48e82d776d2e93f88ca56567509d102266e7ab2fb707a0326f032fe657335238"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58c1165f9b2662645de9b19a8c8bdd636b36294ccc07e1b0163856b74f10bafc"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d6dc3fa91414ff4daa195c05f946e6a575bd214821e26d17ca50f74b35b0fe4"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fae4e801b774cc62cecf4a57b1eae4097903fced00c608d9e2bc8f84cd87b54a"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-win32.whl", hash = "sha256:b8600ae7dce6ec3ddfb201abb98c9d53abbf8064d7ac0c8a0d8925e722ccf2a0"},
|
||||
{file = "fonttools-4.42.0-cp310-cp310-win_amd64.whl", hash = "sha256:57b68eab183fafac7cd7d464a7bfa0fcd4edf6c67837d14fb09c1c20516cf20b"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0a1466713e54bdbf5521f2f73eebfe727a528905ff5ec63cda40961b4b1eea95"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3fb2a69870bfe143ec20b039a1c8009e149dd7780dd89554cc8a11f79e5de86b"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae881e484702efdb6cf756462622de81d4414c454edfd950b137e9a7352b3cb9"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27ec3246a088555629f9f0902f7412220c67340553ca91eb540cf247aacb1983"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ece1886d12bb36c48c00b2031518877f41abae317e3a55620d38e307d799b7e"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10dac980f2b975ef74532e2a94bb00e97a95b4595fb7f98db493c474d5f54d0e"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-win32.whl", hash = "sha256:83b98be5d291e08501bd4fc0c4e0f8e6e05b99f3924068b17c5c9972af6fff84"},
|
||||
{file = "fonttools-4.42.0-cp311-cp311-win_amd64.whl", hash = "sha256:e35bed436726194c5e6e094fdfb423fb7afaa0211199f9d245e59e11118c576c"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c36c904ce0322df01e590ba814d5d69e084e985d7e4c2869378671d79662a7d4"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d54e600a2bcfa5cdaa860237765c01804a03b08404d6affcd92942fa7315ffba"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01cfe02416b6d416c5c8d15e30315cbcd3e97d1b50d3b34b0ce59f742ef55258"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f81ed9065b4bd3f4f3ce8e4873cd6a6b3f4e92b1eddefde35d332c6f414acc3"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:685a4dd6cf31593b50d6d441feb7781a4a7ef61e19551463e14ed7c527b86f9f"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:329341ba3d86a36e482610db56b30705384cb23bd595eac8cbb045f627778e9d"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-win32.whl", hash = "sha256:4655c480a1a4d706152ff54f20e20cf7609084016f1df3851cce67cef768f40a"},
|
||||
{file = "fonttools-4.42.0-cp38-cp38-win_amd64.whl", hash = "sha256:6bd7e4777bff1dcb7c4eff4786998422770f3bfbef8be401c5332895517ba3fa"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9b55d2a3b360e0c7fc5bd8badf1503ca1c11dd3a1cd20f2c26787ffa145a9c7"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0df8ef75ba5791e873c9eac2262196497525e3f07699a2576d3ab9ddf41cb619"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd2363ea7728496827658682d049ffb2e98525e2247ca64554864a8cc945568"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d40673b2e927f7cd0819c6f04489dfbeb337b4a7b10fc633c89bf4f34ecb9620"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c8bf88f9e3ce347c716921804ef3a8330cb128284eb6c0b6c4b3574f3c580023"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:703101eb0490fae32baf385385d47787b73d9ea55253df43b487c89ec767e0d7"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-win32.whl", hash = "sha256:f0290ea7f9945174bd4dfd66e96149037441eb2008f3649094f056201d99e293"},
|
||||
{file = "fonttools-4.42.0-cp39-cp39-win_amd64.whl", hash = "sha256:ae7df0ae9ee2f3f7676b0ff6f4ebe48ad0acaeeeaa0b6839d15dbf0709f2c5ef"},
|
||||
{file = "fonttools-4.42.0-py3-none-any.whl", hash = "sha256:dfe7fa7e607f7e8b58d0c32501a3a7cac148538300626d1b930082c90ae7f6bd"},
|
||||
{file = "fonttools-4.42.0.tar.gz", hash = "sha256:614b1283dca88effd20ee48160518e6de275ce9b5456a3134d5f235523fc5065"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -627,20 +691,6 @@ files = [
|
|||
{file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "future-fstrings"
|
||||
version = "1.2.0"
|
||||
description = "A backport of fstrings to python<3.6"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "future_fstrings-1.2.0-py2.py3-none-any.whl", hash = "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63"},
|
||||
{file = "future_fstrings-1.2.0.tar.gz", hash = "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
rewrite = ["tokenize-rt (>=3)"]
|
||||
|
||||
[[package]]
|
||||
name = "gitdb"
|
||||
version = "4.0.10"
|
||||
|
@ -850,6 +900,44 @@ files = [
|
|||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
version = "8.14.0"
|
||||
description = "IPython: Productive Interactive Computing"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "ipython-8.14.0-py3-none-any.whl", hash = "sha256:248aca623f5c99a6635bc3857677b7320b9b8039f99f070ee0d20a5ca5a8e6bf"},
|
||||
{file = "ipython-8.14.0.tar.gz", hash = "sha256:1d197b907b6ba441b692c48cf2a3a2de280dc0ac91a3405b39349a50272ca0a1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
appnope = {version = "*", markers = "sys_platform == \"darwin\""}
|
||||
backcall = "*"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
decorator = "*"
|
||||
jedi = ">=0.16"
|
||||
matplotlib-inline = "*"
|
||||
pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
|
||||
pickleshare = "*"
|
||||
prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0"
|
||||
pygments = ">=2.4.0"
|
||||
stack-data = "*"
|
||||
traitlets = ">=5"
|
||||
|
||||
[package.extras]
|
||||
all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"]
|
||||
black = ["black"]
|
||||
doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"]
|
||||
kernel = ["ipykernel"]
|
||||
nbconvert = ["nbconvert"]
|
||||
nbformat = ["nbformat"]
|
||||
notebook = ["ipywidgets", "notebook"]
|
||||
parallel = ["ipyparallel"]
|
||||
qtconsole = ["qtconsole"]
|
||||
test = ["pytest (<7.1)", "pytest-asyncio", "testpath"]
|
||||
test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"]
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.12.0"
|
||||
|
@ -867,6 +955,58 @@ pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"
|
|||
plugins = ["setuptools"]
|
||||
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
||||
|
||||
[[package]]
|
||||
name = "jedi"
|
||||
version = "0.19.0"
|
||||
description = "An autocompletion tool for Python that can be used for text editors."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "jedi-0.19.0-py2.py3-none-any.whl", hash = "sha256:cb8ce23fbccff0025e9386b5cf85e892f94c9b822378f8da49970471335ac64e"},
|
||||
{file = "jedi-0.19.0.tar.gz", hash = "sha256:bcf9894f1753969cbac8022a8c2eaee06bfa3724e4192470aaffe7eb6272b0c4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
parso = ">=0.8.3,<0.9.0"
|
||||
|
||||
[package.extras]
|
||||
docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
|
||||
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
|
||||
testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.2"
|
||||
description = "A very fast and expressive template engine."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
|
||||
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
MarkupSafe = ">=2.0"
|
||||
|
||||
[package.extras]
|
||||
i18n = ["Babel (>=2.7)"]
|
||||
|
||||
[[package]]
|
||||
name = "jsonpickle"
|
||||
version = "3.0.1"
|
||||
description = "Python library for serializing any arbitrary object graph into JSON"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "jsonpickle-3.0.1-py2.py3-none-any.whl", hash = "sha256:130d8b293ea0add3845de311aaba55e6d706d0bb17bc123bd2c8baf8a39ac77c"},
|
||||
{file = "jsonpickle-3.0.1.tar.gz", hash = "sha256:032538804795e73b94ead410800ac387fdb6de98f8882ac957fcd247e3a85200"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"]
|
||||
testing = ["ecdsa", "feedparser", "gmpy2", "numpy", "pandas", "pymongo", "pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-flake8 (>=1.1.1)", "scikit-learn", "sqlalchemy"]
|
||||
testing-libs = ["simplejson", "ujson"]
|
||||
|
||||
[[package]]
|
||||
name = "kiwisolver"
|
||||
version = "1.4.4"
|
||||
|
@ -955,6 +1095,65 @@ files = [
|
|||
{file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markupsafe"
|
||||
version = "2.1.3"
|
||||
description = "Safely add untrusted strings to HTML/XML markup."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
|
||||
{file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
|
||||
{file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
|
||||
{file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
|
||||
{file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib"
|
||||
version = "3.7.2"
|
||||
|
@ -1016,6 +1215,20 @@ pillow = ">=6.2.0"
|
|||
pyparsing = ">=2.3.1,<3.1"
|
||||
python-dateutil = ">=2.7"
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib-inline"
|
||||
version = "0.1.6"
|
||||
description = "Inline Matplotlib backend for Jupyter"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"},
|
||||
{file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
traitlets = "*"
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.6.1"
|
||||
|
@ -1187,36 +1400,36 @@ test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "1.25.1"
|
||||
version = "1.25.2"
|
||||
description = "Fundamental package for array computing in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "numpy-1.25.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:77d339465dff3eb33c701430bcb9c325b60354698340229e1dff97745e6b3efa"},
|
||||
{file = "numpy-1.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d736b75c3f2cb96843a5c7f8d8ccc414768d34b0a75f466c05f3a739b406f10b"},
|
||||
{file = "numpy-1.25.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a90725800caeaa160732d6b31f3f843ebd45d6b5f3eec9e8cc287e30f2805bf"},
|
||||
{file = "numpy-1.25.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c6c9261d21e617c6dc5eacba35cb68ec36bb72adcff0dee63f8fbc899362588"},
|
||||
{file = "numpy-1.25.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0def91f8af6ec4bb94c370e38c575855bf1d0be8a8fbfba42ef9c073faf2cf19"},
|
||||
{file = "numpy-1.25.1-cp310-cp310-win32.whl", hash = "sha256:fd67b306320dcadea700a8f79b9e671e607f8696e98ec255915c0c6d6b818503"},
|
||||
{file = "numpy-1.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:c1516db588987450b85595586605742879e50dcce923e8973f79529651545b57"},
|
||||
{file = "numpy-1.25.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6b82655dd8efeea69dbf85d00fca40013d7f503212bc5259056244961268b66e"},
|
||||
{file = "numpy-1.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e8f6049c4878cb16960fbbfb22105e49d13d752d4d8371b55110941fb3b17800"},
|
||||
{file = "numpy-1.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41a56b70e8139884eccb2f733c2f7378af06c82304959e174f8e7370af112e09"},
|
||||
{file = "numpy-1.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5154b1a25ec796b1aee12ac1b22f414f94752c5f94832f14d8d6c9ac40bcca6"},
|
||||
{file = "numpy-1.25.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38eb6548bb91c421261b4805dc44def9ca1a6eef6444ce35ad1669c0f1a3fc5d"},
|
||||
{file = "numpy-1.25.1-cp311-cp311-win32.whl", hash = "sha256:791f409064d0a69dd20579345d852c59822c6aa087f23b07b1b4e28ff5880fcb"},
|
||||
{file = "numpy-1.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:c40571fe966393b212689aa17e32ed905924120737194b5d5c1b20b9ed0fb171"},
|
||||
{file = "numpy-1.25.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3d7abcdd85aea3e6cdddb59af2350c7ab1ed764397f8eec97a038ad244d2d105"},
|
||||
{file = "numpy-1.25.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a180429394f81c7933634ae49b37b472d343cccb5bb0c4a575ac8bbc433722f"},
|
||||
{file = "numpy-1.25.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d412c1697c3853c6fc3cb9751b4915859c7afe6a277c2bf00acf287d56c4e625"},
|
||||
{file = "numpy-1.25.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20e1266411120a4f16fad8efa8e0454d21d00b8c7cee5b5ccad7565d95eb42dd"},
|
||||
{file = "numpy-1.25.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f76aebc3358ade9eacf9bc2bb8ae589863a4f911611694103af05346637df1b7"},
|
||||
{file = "numpy-1.25.1-cp39-cp39-win32.whl", hash = "sha256:247d3ffdd7775bdf191f848be8d49100495114c82c2bd134e8d5d075fb386a1c"},
|
||||
{file = "numpy-1.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:1d5d3c68e443c90b38fdf8ef40e60e2538a27548b39b12b73132456847f4b631"},
|
||||
{file = "numpy-1.25.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:35a9527c977b924042170a0887de727cd84ff179e478481404c5dc66b4170009"},
|
||||
{file = "numpy-1.25.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d3fe3dd0506a28493d82dc3cf254be8cd0d26f4008a417385cbf1ae95b54004"},
|
||||
{file = "numpy-1.25.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:012097b5b0d00a11070e8f2e261128c44157a8689f7dedcf35576e525893f4fe"},
|
||||
{file = "numpy-1.25.1.tar.gz", hash = "sha256:9a3a9f3a61480cc086117b426a8bd86869c213fc4072e606f01c4e4b66eb92bf"},
|
||||
{file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"},
|
||||
{file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"},
|
||||
{file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"},
|
||||
{file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"},
|
||||
{file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"},
|
||||
{file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"},
|
||||
{file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"},
|
||||
{file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"},
|
||||
{file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"},
|
||||
{file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"},
|
||||
{file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"},
|
||||
{file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"},
|
||||
{file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"},
|
||||
{file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"},
|
||||
{file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"},
|
||||
{file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"},
|
||||
{file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"},
|
||||
{file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"},
|
||||
{file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"},
|
||||
{file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"},
|
||||
{file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"},
|
||||
{file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"},
|
||||
{file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"},
|
||||
{file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"},
|
||||
{file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1352,6 +1565,21 @@ sql-other = ["SQLAlchemy (>=1.4.16)"]
|
|||
test = ["hypothesis (>=6.34.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"]
|
||||
xml = ["lxml (>=4.6.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "parso"
|
||||
version = "0.8.3"
|
||||
description = "A Python Parser"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
|
||||
{file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
|
||||
testing = ["docopt", "pytest (<6.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.11.2"
|
||||
|
@ -1377,6 +1605,17 @@ files = [
|
|||
[package.dependencies]
|
||||
ptyprocess = ">=0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pickleshare"
|
||||
version = "0.7.5"
|
||||
description = "Tiny 'shelve'-like database with concurrency support"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
|
||||
{file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "10.0.0"
|
||||
|
@ -1487,6 +1726,20 @@ files = [
|
|||
{file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prompt-toolkit"
|
||||
version = "3.0.39"
|
||||
description = "Library for building powerful interactive command lines in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"},
|
||||
{file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
wcwidth = "*"
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
version = "5.9.5"
|
||||
|
@ -1524,6 +1777,20 @@ files = [
|
|||
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pure-eval"
|
||||
version = "0.2.2"
|
||||
description = "Safely evaluate AST nodes without side effects"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"},
|
||||
{file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
version = "0.5.0"
|
||||
|
@ -1623,6 +1890,20 @@ files = [
|
|||
{file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.16.1"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"},
|
||||
{file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
plugins = ["importlib-metadata"]
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.9"
|
||||
|
@ -1659,23 +1940,6 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
|||
[package.extras]
|
||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-depends"
|
||||
version = "1.0.1"
|
||||
description = "Tests that depend on other tests"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pytest-depends-1.0.1.tar.gz", hash = "sha256:90a28e2b87b75b18abd128c94015248544acac20e4392e9921e5a86f93319dfe"},
|
||||
{file = "pytest_depends-1.0.1-py3-none-any.whl", hash = "sha256:a1df072bcc93d77aca3f0946903f5fed8af2d9b0056db1dfc9ed5ac164ab0642"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = "*"
|
||||
future-fstrings = "*"
|
||||
networkx = "*"
|
||||
pytest = ">=3"
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
|
@ -1715,6 +1979,22 @@ files = [
|
|||
{file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyvis"
|
||||
version = "0.3.2"
|
||||
description = "A Python network graph visualization library"
|
||||
optional = false
|
||||
python-versions = ">3.6"
|
||||
files = [
|
||||
{file = "pyvis-0.3.2-py3-none-any.whl", hash = "sha256:5720c4ca8161dc5d9ab352015723abb7a8bb8fb443edeb07f7a322db34a97555"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
ipython = ">=5.3.0"
|
||||
jinja2 = ">=2.9.6"
|
||||
jsonpickle = ">=1.4.1"
|
||||
networkx = ">=1.11"
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
|
@ -1801,6 +2081,25 @@ files = [
|
|||
{file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stack-data"
|
||||
version = "0.6.2"
|
||||
description = "Extract data from python stack frames and tracebacks for informative displays"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"},
|
||||
{file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
asttokens = ">=2.1.0"
|
||||
executing = ">=1.2.0"
|
||||
pure-eval = "*"
|
||||
|
||||
[package.extras]
|
||||
tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.27.0"
|
||||
|
@ -1849,6 +2148,21 @@ notebook = ["ipywidgets (>=6)"]
|
|||
slack = ["slack-sdk"]
|
||||
telegram = ["requests"]
|
||||
|
||||
[[package]]
|
||||
name = "traitlets"
|
||||
version = "5.9.0"
|
||||
description = "Traitlets Python configuration system"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"},
|
||||
{file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
|
||||
test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"]
|
||||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.31.0.2"
|
||||
|
@ -1912,6 +2226,17 @@ brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
|||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.6"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
|
||||
{file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wsproto"
|
||||
version = "1.2.0"
|
||||
|
@ -2016,4 +2341,4 @@ multidict = ">=4.0"
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "c49ef31fd15da62773661a27bbd829e5d5bd0d0f45294f721a72eded670762e8"
|
||||
content-hash = "793a224969f4cdc094de21061917863e1d0fb3a960d57bd2c3947c3d5d5040eb"
|
||||
|
|
|
@ -13,7 +13,6 @@ pytest = "^7.3.2"
|
|||
requests = "^2.31.0"
|
||||
openai = "^0.27.8"
|
||||
pydantic = "^1.10.9"
|
||||
pytest-depends = "^1.0.1"
|
||||
python-dotenv = "^1.0.0"
|
||||
click = "^8.1.3"
|
||||
types-requests = "^2.31.0.1"
|
||||
|
@ -23,7 +22,10 @@ helicone = "^1.0.6"
|
|||
matplotlib = "^3.7.2"
|
||||
pandas = "^2.0.3"
|
||||
gitpython = "^3.1.32"
|
||||
networkx = "^3.1"
|
||||
colorama = "^0.4.6"
|
||||
agent-protocol = "^0.1.2"
|
||||
pyvis = "^0.3.2"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
flake8 = "^3.9.2"
|
||||
|
@ -55,6 +57,10 @@ markers = [
|
|||
"safety",
|
||||
"content_gen"
|
||||
]
|
||||
filterwarnings = [
|
||||
"ignore::pytest.PytestAssertRewriteWarning",
|
||||
"ignore::matplotlib.MatplotlibDeprecationWarning"
|
||||
]
|
||||
|
||||
[tool.poetry.scripts]
|
||||
agbenchmark = "agbenchmark.start_benchmark:cli"
|
||||
|
|
Loading…
Reference in New Issue