mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-03 13:58:12 +08:00
Add server plugin system (#1447)
* Add server plugin system Plugins are optional modules loaded at runtime. Specification: * Plugins are loaded from the server.plugins module (directory server/plugins) * The import_plugins method is run as part of the initialization of the server module in __init__.py * Add plugins to the EB build process * Remove bit of dead code * Respond to feedback from @bmccandless
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import random
|
||||
import shutil
|
||||
import string
|
||||
import tempfile
|
||||
from os import path, popen
|
||||
|
||||
@@ -74,3 +76,7 @@ def app_config(data_locator, backed=False):
|
||||
config.update(**args)
|
||||
config.complete_config()
|
||||
return config
|
||||
|
||||
|
||||
def random_string(n):
|
||||
return "".join(random.choice(string.ascii_letters) for _ in range(n))
|
||||
|
||||
@@ -7,7 +7,6 @@ from server.test.test_datasets.fixtures import pbmc3k_colors
|
||||
|
||||
|
||||
class TestCxgAdaptor(unittest.TestCase):
|
||||
|
||||
def test_get_colors(self):
|
||||
data = self.get_data("pbmc3k.cxg")
|
||||
self.assertDictEqual(data.get_colors(), pbmc3k_colors)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import random
|
||||
import shutil
|
||||
import string
|
||||
import unittest
|
||||
|
||||
import anndata
|
||||
@@ -8,7 +6,7 @@ import anndata
|
||||
from server.common.data_locator import DataLocator
|
||||
from server.converters.cxgtool import write_cxg
|
||||
from server.data_cxg.cxg_adaptor import CxgAdaptor
|
||||
from server.test import PROJECT_ROOT, app_config
|
||||
from server.test import PROJECT_ROOT, app_config, random_string
|
||||
from server.test.test_datasets.fixtures import pbmc3k_colors
|
||||
|
||||
|
||||
@@ -31,8 +29,8 @@ class TestCxgAdaptor(unittest.TestCase):
|
||||
self.assertEqual(data.get_colors(), {})
|
||||
|
||||
def convert_pbmc3k(self, **kwargs):
|
||||
random_string = "".join(random.choice(string.ascii_letters) for _ in range(8))
|
||||
data_locator = f"/tmp/test_{random_string}.cxg"
|
||||
rand_str = random_string(8)
|
||||
data_locator = f"/tmp/test_{rand_str}.cxg"
|
||||
self.fixtures.append(data_locator)
|
||||
source_h5ad = anndata.read_h5ad(f"{PROJECT_ROOT}/example-dataset/pbmc3k.h5ad")
|
||||
write_cxg(adata=source_h5ad, container=data_locator, title="pbmc3k", **kwargs)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import os
|
||||
import shutil
|
||||
import unittest
|
||||
|
||||
from server.common.utils import import_plugins
|
||||
from server.test import PROJECT_ROOT, random_string
|
||||
|
||||
|
||||
class TestPlugins(unittest.TestCase):
|
||||
""" Test plugin import functionality """
|
||||
|
||||
plugins_dir = f"{PROJECT_ROOT}/server/test/plugins"
|
||||
test_plugin_path = f"{plugins_dir}/foo.py"
|
||||
secret = random_string(8)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
if not os.path.isdir(cls.plugins_dir):
|
||||
os.mkdir(cls.plugins_dir)
|
||||
with open(cls.test_plugin_path, "w") as fh:
|
||||
fh.write(f'SECRET = "{cls.secret}"\n')
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls) -> None:
|
||||
if os.path.isdir(cls.plugins_dir):
|
||||
shutil.rmtree(cls.plugins_dir)
|
||||
|
||||
def test_import_plugins(self):
|
||||
self.assertTrue(os.path.isfile(self.test_plugin_path))
|
||||
loaded_modules = import_plugins("server.test.plugins")
|
||||
# test that import plugins found the file
|
||||
self.assertEqual(["server.test.plugins.foo"], [ele.__name__ for ele in loaded_modules])
|
||||
# test that the module was properly executed
|
||||
self.assertEqual(self.secret, loaded_modules[0].SECRET)
|
||||
Reference in New Issue
Block a user