Renamed LabThing plugins to extensions
This commit is contained in:
parent
d96e188d16
commit
2a245185a6
10 changed files with 89 additions and 89 deletions
|
|
@ -11,16 +11,16 @@ from datetime import datetime
|
||||||
|
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
|
||||||
from openflexure_microscope.api.utilities import list_routes, init_default_plugins
|
from openflexure_microscope.api.utilities import list_routes, init_default_extensions
|
||||||
|
|
||||||
from openflexure_microscope.config import (
|
from openflexure_microscope.config import (
|
||||||
settings_file_path,
|
settings_file_path,
|
||||||
JSONEncoder,
|
JSONEncoder,
|
||||||
USER_PLUGINS_PATH,
|
USER_EXTENSIONS_PATH,
|
||||||
)
|
)
|
||||||
|
|
||||||
from openflexure_microscope.common.flask_labthings.labthing import LabThing
|
from openflexure_microscope.common.flask_labthings.labthing import LabThing
|
||||||
from openflexure_microscope.common.flask_labthings.plugins import find_plugins
|
from openflexure_microscope.common.flask_labthings.extensions import find_extensions
|
||||||
|
|
||||||
from openflexure_microscope.api.microscope import default_microscope as api_microscope
|
from openflexure_microscope.api.microscope import default_microscope as api_microscope
|
||||||
|
|
||||||
|
|
@ -73,11 +73,11 @@ labthing.title = f"OpenFlexure Microscope {api_microscope.name}"
|
||||||
# Attach lab devices
|
# Attach lab devices
|
||||||
labthing.register_device(api_microscope, "openflexure_microscope")
|
labthing.register_device(api_microscope, "openflexure_microscope")
|
||||||
|
|
||||||
# Attach plugins
|
# Attach extensions
|
||||||
if not os.path.isfile(USER_PLUGINS_PATH):
|
if not os.path.isfile(USER_EXTENSIONS_PATH):
|
||||||
init_default_plugins(USER_PLUGINS_PATH)
|
init_default_extensions(USER_EXTENSIONS_PATH)
|
||||||
for plugin in find_plugins(USER_PLUGINS_PATH):
|
for extension in find_extensions(USER_EXTENSIONS_PATH):
|
||||||
labthing.register_plugin(plugin)
|
labthing.register_extension(extension)
|
||||||
|
|
||||||
# Attach captures resources
|
# Attach captures resources
|
||||||
labthing.add_resource(views.CaptureList, f"/captures")
|
labthing.add_resource(views.CaptureList, f"/captures")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from openflexure_microscope.common.flask_labthings.find import find_device
|
from openflexure_microscope.common.flask_labthings.find import find_device
|
||||||
from openflexure_microscope.common.flask_labthings.plugins import BasePlugin
|
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
||||||
from openflexure_microscope.common.flask_labthings.resource import Resource
|
from openflexure_microscope.common.flask_labthings.resource import Resource
|
||||||
|
|
||||||
from openflexure_microscope.devel import JsonResponse, request, jsonify, taskify, abort
|
from openflexure_microscope.devel import JsonResponse, request, jsonify, taskify, abort
|
||||||
|
|
@ -139,7 +139,7 @@ def sharpness_edge(image):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
### Autofocus plugin
|
### Autofocus extension
|
||||||
|
|
||||||
|
|
||||||
def measure_sharpness(microscope, metric_fn=sharpness_sum_lap2):
|
def measure_sharpness(microscope, metric_fn=sharpness_sum_lap2):
|
||||||
|
|
@ -353,15 +353,15 @@ class FastAutofocusAPI(Resource):
|
||||||
abort(503, "No stage connected. Unable to autofocus.")
|
abort(503, "No stage connected. Unable to autofocus.")
|
||||||
|
|
||||||
|
|
||||||
autofocus_plugin_v2 = BasePlugin("autofocus")
|
autofocus_extension_v2 = BaseExtension("autofocus")
|
||||||
|
|
||||||
autofocus_plugin_v2.add_method(fast_autofocus, "fast_autofocus")
|
autofocus_extension_v2.add_method(fast_autofocus, "fast_autofocus")
|
||||||
autofocus_plugin_v2.add_method(autofocus, "autofocus")
|
autofocus_extension_v2.add_method(autofocus, "autofocus")
|
||||||
|
|
||||||
autofocus_plugin_v2.add_view(MeasureSharpnessAPI, "/measure_sharpness")
|
autofocus_extension_v2.add_view(MeasureSharpnessAPI, "/measure_sharpness")
|
||||||
|
|
||||||
autofocus_plugin_v2.add_view(AutofocusAPI, "/autofocus")
|
autofocus_extension_v2.add_view(AutofocusAPI, "/autofocus")
|
||||||
autofocus_plugin_v2.register_action(AutofocusAPI)
|
autofocus_extension_v2.register_action(AutofocusAPI)
|
||||||
|
|
||||||
autofocus_plugin_v2.add_view(FastAutofocusAPI, "/fast_autofocus")
|
autofocus_extension_v2.add_view(FastAutofocusAPI, "/fast_autofocus")
|
||||||
autofocus_plugin_v2.register_action(FastAutofocusAPI)
|
autofocus_extension_v2.register_action(FastAutofocusAPI)
|
||||||
|
|
@ -6,8 +6,8 @@ from typing import Tuple
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from openflexure_microscope.camera.base import generate_basename
|
from openflexure_microscope.camera.base import generate_basename
|
||||||
from openflexure_microscope.common.flask_labthings.find import find_device, find_plugin
|
from openflexure_microscope.common.flask_labthings.find import find_device, find_extension
|
||||||
from openflexure_microscope.common.flask_labthings.plugins import BasePlugin
|
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
||||||
|
|
||||||
from openflexure_microscope.devel import (
|
from openflexure_microscope.devel import (
|
||||||
JsonResponse,
|
JsonResponse,
|
||||||
|
|
@ -169,10 +169,10 @@ def tile(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if autofocus is enabled
|
# Check if autofocus is enabled
|
||||||
autofocus_plugin = find_plugin("autofocus")
|
autofocus_extension = find_extension("autofocus")
|
||||||
if (
|
if (
|
||||||
autofocus_dz
|
autofocus_dz
|
||||||
and autofocus_plugin
|
and autofocus_extension
|
||||||
and microscope.has_real_stage()
|
and microscope.has_real_stage()
|
||||||
and microscope.has_real_camera()
|
and microscope.has_real_camera()
|
||||||
):
|
):
|
||||||
|
|
@ -211,7 +211,7 @@ def tile(
|
||||||
# Refocus
|
# Refocus
|
||||||
if autofocus_enabled:
|
if autofocus_enabled:
|
||||||
if fast_autofocus:
|
if fast_autofocus:
|
||||||
autofocus_plugin.fast_autofocus(
|
autofocus_extension.fast_autofocus(
|
||||||
dz=autofocus_dz,
|
dz=autofocus_dz,
|
||||||
target_z=-z_stack_dz / 2.0, # Finish below the focus
|
target_z=-z_stack_dz / 2.0, # Finish below the focus
|
||||||
initial_move_up=False, # We're already at the top of the scan
|
initial_move_up=False, # We're already at the top of the scan
|
||||||
|
|
@ -219,7 +219,7 @@ def tile(
|
||||||
# TODO: save the focus data for future reference? Use it for diagnostics?
|
# TODO: save the focus data for future reference? Use it for diagnostics?
|
||||||
else:
|
else:
|
||||||
logging.debug("Running autofocus")
|
logging.debug("Running autofocus")
|
||||||
autofocus_plugin.autofocus(
|
autofocus_extension.autofocus(
|
||||||
range(-3 * autofocus_dz, 4 * autofocus_dz, autofocus_dz)
|
range(-3 * autofocus_dz, 4 * autofocus_dz, autofocus_dz)
|
||||||
)
|
)
|
||||||
logging.debug("Finished autofocus")
|
logging.debug("Finished autofocus")
|
||||||
|
|
@ -398,7 +398,7 @@ class TileScanAPI(Resource):
|
||||||
return jsonify(task.state), 201
|
return jsonify(task.state), 201
|
||||||
|
|
||||||
|
|
||||||
scan_plugin_v2 = BasePlugin("scan")
|
scan_extension_v2 = BaseExtension("scan")
|
||||||
|
|
||||||
scan_plugin_v2.add_view(TileScanAPI, "/tile")
|
scan_extension_v2.add_view(TileScanAPI, "/tile")
|
||||||
scan_plugin_v2.register_action(TileScanAPI)
|
scan_extension_v2.register_action(TileScanAPI)
|
||||||
|
|
@ -108,22 +108,22 @@ def create_file(config_path):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def init_default_plugins(plugin_path):
|
def init_default_extensions(extension_path):
|
||||||
global _DEFAULT_PLUGIN_INIT
|
global _DEFAULT_extension_INIT
|
||||||
os.makedirs(os.path.dirname(plugin_path), exist_ok=True)
|
os.makedirs(os.path.dirname(extension_path), exist_ok=True)
|
||||||
|
|
||||||
if not os.path.exists(plugin_path): # If user plugins file doesn't exist
|
if not os.path.exists(extension_path): # If user extensions file doesn't exist
|
||||||
logging.warning("No plugin file found at {}. Creating...".format(plugin_path))
|
logging.warning("No extension file found at {}. Creating...".format(extension_path))
|
||||||
create_file(plugin_path)
|
create_file(extension_path)
|
||||||
|
|
||||||
logging.info("Populating {}...".format(plugin_path))
|
logging.info("Populating {}...".format(extension_path))
|
||||||
with open(plugin_path, "w") as outfile:
|
with open(extension_path, "w") as outfile:
|
||||||
outfile.write(_DEFAULT_PLUGIN_INIT)
|
outfile.write(_DEFAULT_extension_INIT)
|
||||||
|
|
||||||
|
|
||||||
_DEFAULT_PLUGIN_INIT = """
|
_DEFAULT_extension_INIT = """
|
||||||
from openflexure_microscope.api.default_plugins.autofocus import autofocus_plugin_v2
|
from openflexure_microscope.api.default_extensions.autofocus import autofocus_extension_v2
|
||||||
from openflexure_microscope.api.default_plugins.scan import scan_plugin_v2
|
from openflexure_microscope.api.default_extensions.scan import scan_extension_v2
|
||||||
|
|
||||||
__plugins__ = [autofocus_plugin_v2, scan_plugin_v2]
|
__extensions__ = [autofocus_extension_v2, scan_extension_v2]
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ from openflexure_microscope.common.labthings_core.utilities import get_docstring
|
||||||
from openflexure_microscope.utilities import camel_to_snake, snake_to_spine
|
from openflexure_microscope.utilities import camel_to_snake, snake_to_spine
|
||||||
|
|
||||||
|
|
||||||
class BasePlugin:
|
class BaseExtension:
|
||||||
"""
|
"""
|
||||||
Parent class for all plugins.
|
Parent class for all extensions.
|
||||||
|
|
||||||
Handles binding route views and forms.
|
Handles binding route views and forms.
|
||||||
"""
|
"""
|
||||||
|
|
@ -23,7 +23,7 @@ class BasePlugin:
|
||||||
self._rules = {} # Key: Original rule. Val: View class
|
self._rules = {} # Key: Original rule. Val: View class
|
||||||
self._gui = None
|
self._gui = None
|
||||||
|
|
||||||
self._cls = str(self) # String description of plugin instance
|
self._cls = str(self) # String description of extension instance
|
||||||
|
|
||||||
self.actions = []
|
self.actions = []
|
||||||
self.properties = []
|
self.properties = []
|
||||||
|
|
@ -43,7 +43,7 @@ class BasePlugin:
|
||||||
while cleaned_rule[0] == "/":
|
while cleaned_rule[0] == "/":
|
||||||
cleaned_rule = cleaned_rule[1:]
|
cleaned_rule = cleaned_rule[1:]
|
||||||
|
|
||||||
# Expand the rule to include plugin name
|
# Expand the rule to include extension name
|
||||||
full_rule = "/{}/{}".format(self._name_uri_safe, cleaned_rule)
|
full_rule = "/{}/{}".format(self._name_uri_safe, cleaned_rule)
|
||||||
|
|
||||||
view_id = cleaned_rule.replace("/", "_").replace("<", "").replace(">", "")
|
view_id = cleaned_rule.replace("/", "_").replace("<", "").replace(">", "")
|
||||||
|
|
@ -119,20 +119,20 @@ class BasePlugin:
|
||||||
setattr(self, method_name, method)
|
setattr(self, method_name, method)
|
||||||
else:
|
else:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"Unable to bind method to plugin. Method name already exists."
|
"Unable to bind method to extension. Method name already exists."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def find_plugins(plugin_path, module_name="plugins"):
|
def find_extensions(extension_path, module_name="extensions"):
|
||||||
logging.debug(f"Loading plugins from {plugin_path}")
|
logging.debug(f"Loading extensions from {extension_path}")
|
||||||
|
|
||||||
spec = util.spec_from_file_location(module_name, plugin_path)
|
spec = util.spec_from_file_location(module_name, extension_path)
|
||||||
mod = util.module_from_spec(spec)
|
mod = util.module_from_spec(spec)
|
||||||
sys.modules[spec.name] = mod
|
sys.modules[spec.name] = mod
|
||||||
|
|
||||||
spec.loader.exec_module(mod)
|
spec.loader.exec_module(mod)
|
||||||
|
|
||||||
if hasattr(mod, "__plugins__"):
|
if hasattr(mod, "__extensions__"):
|
||||||
return mod.__plugins__
|
return mod.__extensions__
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
@ -15,10 +15,10 @@ def current_labthing():
|
||||||
return app.extensions[EXTENSION_NAME]
|
return app.extensions[EXTENSION_NAME]
|
||||||
|
|
||||||
|
|
||||||
def registered_plugins(labthing_instance=None):
|
def registered_extensions(labthing_instance=None):
|
||||||
if not labthing_instance:
|
if not labthing_instance:
|
||||||
labthing_instance = current_labthing()
|
labthing_instance = current_labthing()
|
||||||
return labthing_instance.plugins
|
return labthing_instance.extensions
|
||||||
|
|
||||||
|
|
||||||
def registered_devices(labthing_instance=None):
|
def registered_devices(labthing_instance=None):
|
||||||
|
|
@ -37,14 +37,14 @@ def find_device(device_name, labthing_instance=None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def find_plugin(plugin_name, labthing_instance=None):
|
def find_extension(extension_name, labthing_instance=None):
|
||||||
if not labthing_instance:
|
if not labthing_instance:
|
||||||
labthing_instance = current_labthing()
|
labthing_instance = current_labthing()
|
||||||
|
|
||||||
logging.debug("Current labthing:")
|
logging.debug("Current labthing:")
|
||||||
logging.debug(current_labthing())
|
logging.debug(current_labthing())
|
||||||
|
|
||||||
if plugin_name in labthing_instance.plugins:
|
if extension_name in labthing_instance.extensions:
|
||||||
return labthing_instance.plugins[plugin_name]
|
return labthing_instance.extensions[extension_name]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ from flask import url_for, jsonify
|
||||||
from apispec import APISpec
|
from apispec import APISpec
|
||||||
from apispec.ext.marshmallow import MarshmallowPlugin
|
from apispec.ext.marshmallow import MarshmallowPlugin
|
||||||
|
|
||||||
from .plugins import BasePlugin
|
from .extensions import BaseExtension
|
||||||
from .views.plugins import PluginListResource
|
from .views.extensions import ExtensionListResource
|
||||||
from .views.tasks import TaskList, TaskResource
|
from .views.tasks import TaskList, TaskResource
|
||||||
|
|
||||||
from .spec import view2path
|
from .spec import view2path
|
||||||
|
|
@ -32,7 +32,7 @@ class LabThing(object):
|
||||||
|
|
||||||
self.devices = {}
|
self.devices = {}
|
||||||
|
|
||||||
self.plugins = {}
|
self.extensions = {}
|
||||||
|
|
||||||
self.resources = []
|
self.resources = []
|
||||||
self.properties = {}
|
self.properties = {}
|
||||||
|
|
@ -121,9 +121,9 @@ class LabThing(object):
|
||||||
self._complete_url("/swagger", ""), "swagger", self.swagger
|
self._complete_url("/swagger", ""), "swagger", self.swagger
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add plugin overview
|
# Add extension overview
|
||||||
self.add_resource(PluginListResource, "/plugins")
|
self.add_resource(ExtensionListResource, "/extensions")
|
||||||
self.register_property(PluginListResource)
|
self.register_property(ExtensionListResource)
|
||||||
# Add task routes
|
# Add task routes
|
||||||
self.add_resource(TaskList, "/tasks")
|
self.add_resource(TaskList, "/tasks")
|
||||||
self.register_property(TaskList)
|
self.register_property(TaskList)
|
||||||
|
|
@ -134,26 +134,26 @@ class LabThing(object):
|
||||||
def register_device(self, device_object, device_name: str):
|
def register_device(self, device_object, device_name: str):
|
||||||
self.devices[device_name] = device_object
|
self.devices[device_name] = device_object
|
||||||
|
|
||||||
### Plugin stuff
|
### Extension stuff
|
||||||
|
|
||||||
def register_plugin(self, plugin_object):
|
def register_extension(self, extension_object):
|
||||||
if isinstance(plugin_object, BasePlugin):
|
if isinstance(extension_object, BaseExtension):
|
||||||
self.plugins[plugin_object.name] = plugin_object
|
self.extensions[extension_object.name] = extension_object
|
||||||
else:
|
else:
|
||||||
raise TypeError("Plugin object must be an instance of BasePlugin")
|
raise TypeError("Extension object must be an instance of BaseExtension")
|
||||||
|
|
||||||
for plugin_view_id, plugin_view in plugin_object.views.items():
|
for extension_view_id, extension_view in extension_object.views.items():
|
||||||
# Add route to the plugins blueprint
|
# Add route to the extensions blueprint
|
||||||
self.add_resource(
|
self.add_resource(
|
||||||
plugin_view["view"],
|
extension_view["view"],
|
||||||
"/plugins" + plugin_view["rule"],
|
"/extensions" + extension_view["rule"],
|
||||||
**plugin_view["kwargs"],
|
**extension_view["kwargs"],
|
||||||
)
|
)
|
||||||
|
|
||||||
for prop in plugin_object.properties:
|
for prop in extension_object.properties:
|
||||||
self.register_property(prop)
|
self.register_property(prop)
|
||||||
|
|
||||||
for action in plugin_object.actions:
|
for action in extension_object.actions:
|
||||||
self.register_action(action)
|
self.register_action(action)
|
||||||
|
|
||||||
### Resource stuff
|
### Resource stuff
|
||||||
|
|
@ -327,9 +327,9 @@ class LabThing(object):
|
||||||
"description": get_docstring(self.swagger),
|
"description": get_docstring(self.swagger),
|
||||||
"methods": ["GET"],
|
"methods": ["GET"],
|
||||||
},
|
},
|
||||||
"plugins": {
|
"extensions": {
|
||||||
"href": self.url_for(PluginListResource, _external=True),
|
"href": self.url_for(ExtensionListResource, _external=True),
|
||||||
**description_from_view(PluginListResource),
|
**description_from_view(ExtensionListResource),
|
||||||
},
|
},
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"href": self.url_for(TaskList, _external=True),
|
"href": self.url_for(TaskList, _external=True),
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
"""
|
"""
|
||||||
Top-level representation of attached and enabled plugins
|
Top-level representation of attached and enabled Extensions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from openflexure_microscope.common.labthings_core.utilities import get_docstring
|
from openflexure_microscope.common.labthings_core.utilities import get_docstring
|
||||||
from ..utilities import description_from_view
|
from ..utilities import description_from_view
|
||||||
|
|
||||||
from openflexure_microscope.common.flask_labthings.resource import Resource
|
from openflexure_microscope.common.flask_labthings.resource import Resource
|
||||||
from openflexure_microscope.common.flask_labthings.find import registered_plugins
|
from openflexure_microscope.common.flask_labthings.find import registered_extensions
|
||||||
from openflexure_microscope.common.flask_labthings.schema import Schema
|
from openflexure_microscope.common.flask_labthings.schema import Schema
|
||||||
from openflexure_microscope.common.flask_labthings.decorators import marshal_with
|
from openflexure_microscope.common.flask_labthings.decorators import marshal_with
|
||||||
from openflexure_microscope.common.flask_labthings import fields
|
from openflexure_microscope.common.flask_labthings import fields
|
||||||
|
|
@ -17,7 +17,7 @@ from flask import jsonify, url_for
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class PluginSchema(Schema):
|
class ExtensionSchema(Schema):
|
||||||
name = fields.String(data_key="title")
|
name = fields.String(data_key="title")
|
||||||
_name_python_safe = fields.String(data_key="pythonName")
|
_name_python_safe = fields.String(data_key="pythonName")
|
||||||
_cls = fields.String(data_key="pythonObject")
|
_cls = fields.String(data_key="pythonObject")
|
||||||
|
|
@ -44,23 +44,23 @@ class PluginSchema(Schema):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class PluginListResource(Resource):
|
class ExtensionListResource(Resource):
|
||||||
"""
|
"""
|
||||||
List and basic documentation for all enabled plugins
|
List and basic documentation for all enabled Extensions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@marshal_with(PluginSchema(many=True))
|
@marshal_with(ExtensionSchema(many=True))
|
||||||
def get(self):
|
def get(self):
|
||||||
"""
|
"""
|
||||||
Return the current plugin forms
|
Return the current Extension forms
|
||||||
|
|
||||||
.. :quickref: Plugin; Get forms
|
.. :quickref: Extension; Get forms
|
||||||
|
|
||||||
Returns an array of present plugin forms (describing plugin user interfaces.)
|
Returns an array of present Extension forms (describing Extension user interfaces.)
|
||||||
Please note, this is *not* a list of all enabled plugins, only those with associated
|
Please note, this is *not* a list of all enabled Extensions, only those with associated
|
||||||
user interface forms.
|
user interface forms.
|
||||||
|
|
||||||
A complete list of enabled plugins can be found in the microscope state.
|
A complete list of enabled Extensions can be found in the microscope state.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return registered_plugins().values()
|
return registered_extensions().values()
|
||||||
|
|
@ -182,7 +182,7 @@ DEFAULT_CONFIG_FILE_PATH = os.path.join(HERE, "microscope_settings.default.json"
|
||||||
|
|
||||||
USER_CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".openflexure")
|
USER_CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".openflexure")
|
||||||
USER_CONFIG_FILE_PATH = os.path.join(USER_CONFIG_DIR, "microscope_settings.json")
|
USER_CONFIG_FILE_PATH = os.path.join(USER_CONFIG_DIR, "microscope_settings.json")
|
||||||
USER_PLUGINS_PATH = os.path.join(USER_CONFIG_DIR, "microscope_plugins", "__init__.py")
|
USER_EXTENSIONS_PATH = os.path.join(USER_CONFIG_DIR, "microscope_extensions", "__init__.py")
|
||||||
|
|
||||||
# Load the default config
|
# Load the default config
|
||||||
with open(DEFAULT_CONFIG_FILE_PATH, "r") as default_rc:
|
with open(DEFAULT_CONFIG_FILE_PATH, "r") as default_rc:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue