mirror of
https://github.com/getredash/redash.git
synced 2025-12-19 17:37:19 -05:00
Fix bundle-extensions script to work on recent importlib-resources. (#5050)
Also adds a test case for running the script.
This commit is contained in:
@@ -6,8 +6,8 @@ from pathlib import Path
|
||||
from shutil import copy
|
||||
from collections import OrderedDict as odict
|
||||
|
||||
from importlib_metadata import entry_points
|
||||
from importlib_resources import contents, is_resource, path
|
||||
import importlib_metadata
|
||||
import importlib_resources
|
||||
|
||||
# Name of the subdirectory
|
||||
BUNDLE_DIRECTORY = "bundle"
|
||||
@@ -25,18 +25,6 @@ if not extensions_directory.exists():
|
||||
os.environ["EXTENSIONS_DIRECTORY"] = str(extensions_relative_path)
|
||||
|
||||
|
||||
def resource_isdir(module, resource):
|
||||
"""Whether a given resource is a directory in the given module
|
||||
|
||||
https://importlib-resources.readthedocs.io/en/latest/migration.html#pkg-resources-resource-isdir
|
||||
"""
|
||||
try:
|
||||
return resource in contents(module) and not is_resource(module, resource)
|
||||
except (ImportError, TypeError):
|
||||
# module isn't a package, so can't have a subdirectory/-package
|
||||
return False
|
||||
|
||||
|
||||
def entry_point_module(entry_point):
|
||||
"""Returns the dotted module path for the given entry point"""
|
||||
return entry_point.pattern.match(entry_point.value).group("module")
|
||||
@@ -77,18 +65,28 @@ def load_bundles():
|
||||
|
||||
"""
|
||||
bundles = odict()
|
||||
for entry_point in entry_points().get("redash.bundles", []):
|
||||
for entry_point in importlib_metadata.entry_points().get("redash.bundles", []):
|
||||
logger.info('Loading Redash bundle "%s".', entry_point.name)
|
||||
module = entry_point_module(entry_point)
|
||||
# Try to get a list of bundle files
|
||||
if not resource_isdir(module, BUNDLE_DIRECTORY):
|
||||
try:
|
||||
bundle_dir = importlib_resources.files(module).joinpath(BUNDLE_DIRECTORY)
|
||||
except (ImportError, TypeError):
|
||||
# Module isn't a package, so can't have a subdirectory/-package
|
||||
logger.error(
|
||||
'Redash bundle directory "%s" could not be found.', entry_point.name
|
||||
'Redash bundle module "%s" could not be imported: "%s"',
|
||||
entry_point.name,
|
||||
module,
|
||||
)
|
||||
continue
|
||||
with path(module, BUNDLE_DIRECTORY) as bundle_dir:
|
||||
bundles[entry_point.name] = list(bundle_dir.rglob("*"))
|
||||
|
||||
if not bundle_dir.is_dir():
|
||||
logger.error(
|
||||
'Redash bundle directory "%s" could not be found or is not a directory: "%s"',
|
||||
entry_point.name,
|
||||
bundle_dir,
|
||||
)
|
||||
continue
|
||||
bundles[entry_point.name] = list(bundle_dir.rglob("*"))
|
||||
return bundles
|
||||
|
||||
|
||||
|
||||
2
tests/extensions/redash-dummy/.gitignore
vendored
Normal file
2
tests/extensions/redash-dummy/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
dist
|
||||
build
|
||||
2
tests/extensions/redash-dummy/MANIFEST.in
Normal file
2
tests/extensions/redash-dummy/MANIFEST.in
Normal file
@@ -0,0 +1,2 @@
|
||||
include README.md
|
||||
recursive-include redash_dummy *.jsx
|
||||
@@ -1,6 +1,6 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: redash-dummy
|
||||
Version: 0.1
|
||||
Version: 0.2
|
||||
Summary: Redash extensions for testing
|
||||
Home-page: UNKNOWN
|
||||
Author: Redash authors
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
MANIFEST.in
|
||||
README.md
|
||||
redash_dummy.py
|
||||
setup.py
|
||||
redash_dummy/__init__.py
|
||||
redash_dummy/extension.py
|
||||
redash_dummy/jobs.py
|
||||
redash_dummy.egg-info/PKG-INFO
|
||||
redash_dummy.egg-info/SOURCES.txt
|
||||
redash_dummy.egg-info/dependency_links.txt
|
||||
redash_dummy.egg-info/entry_points.txt
|
||||
redash_dummy.egg-info/top_level.txt
|
||||
redash_dummy.egg-info/top_level.txt
|
||||
redash_dummy/bundle/WideFooter.jsx
|
||||
@@ -1,10 +1,13 @@
|
||||
[redash.bundles]
|
||||
wide_footer = redash_dummy
|
||||
|
||||
[redash.extensions]
|
||||
assertive_extension = redash_dummy:assertive_extension
|
||||
non_callable_extension = redash_dummy:module_attribute
|
||||
not_findable_extension = redash_dummy:missing_attribute
|
||||
assertive_extension = redash_dummy.extension:assertive_extension
|
||||
non_callable_extension = redash_dummy.extension:module_attribute
|
||||
not_findable_extension = redash_dummy.extension:missing_attribute
|
||||
not_importable_extension = missing_extension_module:extension
|
||||
working_extension = redash_dummy:extension
|
||||
working_extension = redash_dummy.extension:extension
|
||||
|
||||
[redash.periodic_jobs]
|
||||
dummy_periodic_job = redash_dummy:periodic_job
|
||||
dummy_periodic_job = redash_dummy.jobs:periodic_job
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
export default function WideFooter() {
|
||||
return (
|
||||
<div>
|
||||
This is a wide footer
|
||||
</div>
|
||||
);
|
||||
}
|
||||
11
tests/extensions/redash-dummy/redash_dummy/extension.py
Normal file
11
tests/extensions/redash-dummy/redash_dummy/extension.py
Normal file
@@ -0,0 +1,11 @@
|
||||
module_attribute = "hello!"
|
||||
|
||||
|
||||
def extension(app):
|
||||
"""This extension will work"""
|
||||
return "extension loaded"
|
||||
|
||||
|
||||
def assertive_extension(app):
|
||||
"""This extension won't work"""
|
||||
assert False
|
||||
@@ -1,17 +1,5 @@
|
||||
from datetime import timedelta
|
||||
|
||||
module_attribute = "hello!"
|
||||
|
||||
|
||||
def extension(app):
|
||||
"""This extension will work"""
|
||||
return "extension loaded"
|
||||
|
||||
|
||||
def assertive_extension(app):
|
||||
"""This extension won't work"""
|
||||
assert False
|
||||
|
||||
|
||||
def job_callback():
|
||||
return "result"
|
||||
@@ -1,21 +1,25 @@
|
||||
from setuptools import setup
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
|
||||
setup(
|
||||
name="redash-dummy",
|
||||
version="0.1",
|
||||
version="0.2",
|
||||
description="Redash extensions for testing",
|
||||
author="Redash authors",
|
||||
license="MIT",
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
"redash.extensions": [
|
||||
"working_extension = redash_dummy:extension",
|
||||
"non_callable_extension = redash_dummy:module_attribute",
|
||||
"not_findable_extension = redash_dummy:missing_attribute",
|
||||
"working_extension = redash_dummy.extension:extension",
|
||||
"non_callable_extension = redash_dummy.extension:module_attribute",
|
||||
"not_findable_extension = redash_dummy.extension:missing_attribute",
|
||||
"not_importable_extension = missing_extension_module:extension",
|
||||
"assertive_extension = redash_dummy:assertive_extension",
|
||||
"assertive_extension = redash_dummy.extension:assertive_extension",
|
||||
],
|
||||
"redash.periodic_jobs": ["dummy_periodic_job = redash_dummy.jobs:periodic_job"],
|
||||
"redash.bundles": [
|
||||
"wide_footer = redash_dummy",
|
||||
],
|
||||
"redash.periodic_jobs": ["dummy_periodic_job = redash_dummy:periodic_job"],
|
||||
},
|
||||
py_modules=["redash_dummy"],
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from redash import extensions
|
||||
from redash.tasks import periodic_job_definitions
|
||||
@@ -8,7 +10,13 @@ from tests import BaseTestCase
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
dummy_extension = "redash-dummy"
|
||||
dummy_path = os.path.join(os.path.dirname(__file__), dummy_extension)
|
||||
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
app_dir = this_dir.parent.parent
|
||||
dummy_path = str(this_dir / dummy_extension)
|
||||
test_bundle = (
|
||||
app_dir / "client" / "app" / "extensions" / "wide_footer" / "WideFooter.jsx"
|
||||
)
|
||||
|
||||
|
||||
class TestExtensions(BaseTestCase):
|
||||
@@ -47,5 +55,25 @@ class TestExtensions(BaseTestCase):
|
||||
|
||||
def test_dummy_periodic_task_definitions(self):
|
||||
jobs = periodic_job_definitions()
|
||||
from redash_dummy import job_callback
|
||||
from redash_dummy.jobs import job_callback
|
||||
|
||||
self.assertIn(job_callback, [job.get("func", None) for job in jobs])
|
||||
|
||||
|
||||
class TestBundles(BaseTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Install the redash-dummy package temporarily using pip
|
||||
# in the user's local site package directory under ~/.local/
|
||||
subprocess.call(["pip", "install", "--user", dummy_path])
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
subprocess.call(["pip", "uninstall", "-y", "redash-dummy"])
|
||||
|
||||
def test_bundle_extensions(self):
|
||||
# cleaning up after running bundle-extensions again
|
||||
self.addCleanup(lambda: shutil.rmtree(test_bundle.parent))
|
||||
assert not test_bundle.exists()
|
||||
subprocess.run(str(app_dir / "bin" / "bundle-extensions"), check=True)
|
||||
assert test_bundle.exists()
|
||||
|
||||
Reference in New Issue
Block a user