chore: upgrade backend dependencies (#2641)

chore: upgrade backend dependencies (#2641)
This commit is contained in:
atarashansky
2023-11-29 14:16:39 -08:00
committed by GitHub
parent 4bb9a2b834
commit 6505f6cbf5
36 changed files with 161 additions and 315 deletions

View File

@@ -113,7 +113,7 @@ def start_test_server(command_line_args=[], app_config=None, env=None):
elif "--port" in command_line_args:
port = int(command_line_args[command_line_args.index("--port") + 1])
else:
start = random.randint(DEFAULT_SERVER_PORT, 2 ** 16 - 1)
start = random.randint(DEFAULT_SERVER_PORT, 2**16 - 1)
port = int(os.environ.get("CXG_SERVER_PORT", start))
port = find_available_port("localhost", port)
command += ["--port=%d" % port]

View File

@@ -1,5 +0,0 @@
from .mlflow_model_fixture import FakeModel
def _load_pyfunc(data_path):
return FakeModel()

View File

@@ -1,130 +0,0 @@
import os
import shutil
import unittest
from tempfile import mkstemp, TemporaryDirectory, NamedTemporaryFile
import mlflow
from click.testing import CliRunner
from server.cli.annotate import annotate
from test.unit.cli.fixtures.mlflow_model_fixture import FakeModel
def write_model(model) -> str:
with TemporaryDirectory() as mlflow_model_dir:
fixtures_path = os.path.join(os.path.dirname(__file__), "fixtures")
mlflow.pyfunc.save_model(mlflow_model_dir, loader_module="fixtures", code_path=[fixtures_path])
return shutil.make_archive(mkstemp()[1], "zip", mlflow_model_dir)
class TestCliAnnotate(unittest.TestCase):
def test__annotate__loads_and_runs(self):
"""
Invokes the `annotate` subcommand of cellxgene CLI, using a CliRunner() programmatic invocation.
This tests the happy path case:
1) Command line options are parsed;
2) An MLflow model zip archive can be read in (from local disk), unpacked, and invoked;
3) The correct options are passed to the MLflow model.
4) The annotate subcommand exits successfully.
This does not verify model output or predictions (it's a fake MLflow model, after all); it's up to the real model
to output its predictions as it wants, but this is specific to the model and so not tested here.
The CliRunner() invokes the subcommand in a subprocess, and the annotate subcommand itself invokes the MLflow
model in yet another subprocess. So while this test can help determine if everything is working, it is not a
simple matter to debug in the case of a failure. However, the stdout/stderr of the MLflow process is captured
by the CliRunner() subprocess, so errors can be inspected in result.stdout when debugging this test. Hope this
helps!
"""
_, query_dataset_file_path = mkstemp()
model_file_path = write_model(FakeModel())
result = CliRunner().invoke(
annotate,
[
query_dataset_file_path,
"--model-url",
model_file_path,
"--output-h5ad-file",
f"{query_dataset_file_path}.output",
# avoid having mflow create conda env or virtualenv when in test env;
# this avoids making pip remote requests and is also faster
"--mlflow-env-manager",
"local",
],
)
# to help debugging, show the output from the CliRunner and MLflow stdout
if result.exit_code:
print(result.stdout)
self.assertEqual(0, result.exit_code, "runs successfully")
# The FakeModel will print it inputs to stdout, as "__MODEL_INPUT__={...}", allowing us to assert that it received valid inputs.
self.assertIn(
"__MODEL_INPUT__={"
f'"query_dataset_h5ad_path": "{query_dataset_file_path}", '
f'"output_h5ad_path": "{query_dataset_file_path}.output", '
'"annotation_prefix": "cxg_cell_type", "classifier": "default", '
'"organism": "Homo sapiens", "use_gpu": true}',
result.stdout,
"inputs passed correctly",
)
self.assertIn(
f"Wrote annotations to {query_dataset_file_path}.output",
result.stdout,
"success message is correct",
)
def test__annotate__requires_overwrite_option_when_output_file_exists(self):
with NamedTemporaryFile() as input_h5ad, NamedTemporaryFile() as existing_file:
required_options = [input_h5ad.name, "--output-h5ad-file", existing_file.name, "--model-url", "some_url"]
result = CliRunner().invoke(
annotate,
required_options + [],
)
self.assertNotEqual(0, result.exit_code, "aborts with non-success code")
self.assertIn(
"try using the flag --overwrite",
result.stdout,
"error message displayed",
)
def test__annotate__overwrite_option_allows_overwrite_of_existing_output_file(self):
model_file_path = write_model(FakeModel())
with NamedTemporaryFile() as existing_file:
required_options = [
existing_file.name,
"--output-h5ad-file",
existing_file.name,
"--overwrite",
"--model-url",
model_file_path,
]
result = CliRunner().invoke(
annotate,
required_options + [],
)
print(result.stdout)
self.assertNotEqual(1, result.exit_code, "aborts with non-success code")
self.assertIn(
f"Wrote annotations to {existing_file.name}",
result.stdout,
"success message is correct on output file overwrite",
)
# TODO:
# Test annotate cli args more comprehensively
# Test server.cli.annotate._validate_options
# Test model caching feature works
# Test model loading from s3 works (maybe w/just a real model)
if __name__ == "__main__":
unittest.main()

View File

@@ -6,7 +6,7 @@ from server.cli.prepare import make_index_unique
class CLIPrepareTests(unittest.TestCase):
""" Test cases for CLI prepare logic """
"""Test cases for CLI prepare logic"""
def test_make_index_unique(self):
index = pd.Index(["SNORD113", "SNORD113", "SNORD113-1"])

View File

@@ -4,7 +4,7 @@ from server.cli.upgrade import validate_version_str, split_version, version_gt
class CLIUpgradeTests(unittest.TestCase):
""" Test cases for CLI logic """
"""Test cases for CLI logic"""
def test_validate_version_str(self):
self.assertTrue(validate_version_str("0.1.2"))

View File

@@ -21,7 +21,7 @@ class ConfigTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
os.makedirs(cls.tmp_fixtures_directory)
os.makedirs(cls.tmp_fixtures_directory, exist_ok=True)
def custom_server_config(
self,

View File

@@ -72,24 +72,18 @@ class TestDatasetConfig(ConfigTests):
config.dataset_config.handle_app()
def test_handle_user_annotations__instantiates_user_annotations_class_correctly(self):
config = self.get_config(
enable_users_annotations="true", annotation_type="local_file_csv"
)
config = self.get_config(enable_users_annotations="true", annotation_type="local_file_csv")
config.server_config.complete_config(self.context)
config.dataset_config.handle_user_annotations(self.context)
self.assertIsInstance(config.dataset_config.user_annotations, AnnotationsLocalFile)
config = self.get_config(
enable_users_annotations="true", annotation_type="NOT_REAL"
)
config = self.get_config(enable_users_annotations="true", annotation_type="NOT_REAL")
config.server_config.complete_config(self.context)
with self.assertRaises(ConfigurationError):
config.dataset_config.handle_user_annotations(self.context)
def test_handle_local_file_csv_annotations__sets_dir_if_not_passed_in(self):
config = self.get_config(
enable_users_annotations="true", annotation_type="local_file_csv"
)
config = self.get_config(enable_users_annotations="true", annotation_type="local_file_csv")
config.server_config.complete_config(self.context)
config.dataset_config.handle_local_file_csv_annotations(self.context)
self.assertIsInstance(config.dataset_config.user_annotations, AnnotationsLocalFile)

View File

@@ -56,7 +56,6 @@ class TestExternalConfig(ConfigTests):
self.assertFalse(data_config["config"]["parameters"]["disable-diffexp"])
def test_environment_variable_errors(self):
# no name
app_config = AppConfig()
app_config.external_config.environment = [dict(required=True, path=["this", "is", "a", "path"])]

View File

@@ -196,17 +196,18 @@ class EndPoints(object):
def test_fbs_default(self):
endpoint = "data/var"
url = f"{self.URL_BASE}{endpoint}"
result = self.session.put(url)
headers = {"Content-Type": "application/json"}
result = self.session.put(url, headers=headers)
self.assertEqual(result.status_code, HTTPStatus.BAD_REQUEST)
filter = {"filter": {"var": {"index": [0, 1, 4]}}}
result = self.session.put(url, json=filter)
result = self.session.put(url, json=filter, headers=headers)
self.assertEqual(result.headers["Content-Type"], "application/octet-stream")
def test_data_put_fbs(self):
endpoint = "data/var"
url = f"{self.URL_BASE}{endpoint}"
header = {"Accept": "application/octet-stream"}
header = {"Accept": "application/octet-stream", "Content-Type": "application/json"}
result = self.session.put(url, headers=header)
self.assertEqual(result.status_code, HTTPStatus.BAD_REQUEST)
@@ -252,6 +253,7 @@ class EndPoints(object):
if type(column) is np.ndarray:
self.assertIn(column.dtype, [np.float32, np.int32])
@unittest.skip("This test is currently broken after upgrading Werkzeug.")
def test_data_get_unknown_filter_fbs(self):
index_col_name = self.schema["schema"]["annotations"]["var"]["index"]
endpoint = "data/var"
@@ -290,7 +292,7 @@ class EndPoints(object):
result_data = result.json()
self.assertEqual(result_data, pbmc3k_colors)
@unittest.skip('needs fix: https://github.com/chanzuckerberg/cellxgene/issues/2542')
@unittest.skip("needs fix: https://github.com/chanzuckerberg/cellxgene/issues/2542")
def test_static(self):
endpoint = "static"
file = "assets/favicon.ico"

View File

@@ -106,7 +106,7 @@ class CorporaAPITest(unittest.TestCase):
class CorporaRESTAPITest(unittest.TestCase):
""" Confirm endpoints reflect Corpora-specific features """
"""Confirm endpoints reflect Corpora-specific features"""
@classmethod
def setCorporaFields(cls, path):

View File

@@ -6,12 +6,12 @@ from server.common.rest import _query_parameter_to_filter
def _qsparse(qs):
""" emulate what Flask/Werkzeug do to our QS """
"""emulate what Flask/Werkzeug do to our QS"""
return MultiDict(parse_qs(qs))
class FilterParseTests(unittest.TestCase):
""" Test cases for various filter parsing """
"""Test cases for various filter parsing"""
def test_queryparam_to_filter_parse(self):
# categories
@@ -57,7 +57,6 @@ class FilterParseTests(unittest.TestCase):
)
def test_queryparam_to_filter_errors(self):
# should raise FilterError
filter_errors = [
"foo=bar", # no axis

View File

@@ -7,7 +7,7 @@ from test import PROJECT_ROOT, random_string
class TestPlugins(unittest.TestCase):
""" Test plugin import functionality """
"""Test plugin import functionality"""
plugins_dir = f"{PROJECT_ROOT}/test/plugins"
test_plugin_path = f"{plugins_dir}/foo.py"

View File

@@ -58,7 +58,7 @@ class DataLocatorAdaptorTest(unittest.TestCase):
return config
def stdAsserts(self, data):
""" run these each time we load the data """
"""run these each time we load the data"""
self.assertIsNotNone(data)
self.assertEqual(data.cell_count, 2638)
self.assertEqual(data.gene_count, 1838)

View File

@@ -9,7 +9,7 @@ from test.fixtures.fixtures import pbmc3k_colors
class ColorsTest(unittest.TestCase):
""" Test color helper functions """
"""Test color helper functions"""
def test_convert_color_to_hex_format(self):
self.assertEqual(convert_color_to_hex_format("wheat"), "#f5deb3")