Skip to content

Commit

Permalink
Merge pull request #11 from uclahs-cds/aholmes-polish-web-and-db
Browse files Browse the repository at this point in the history
Add checks to determine whether "create" and "modify" can safely run
  • Loading branch information
aholmes authored Sep 29, 2023
2 parents 7b135ec + 04c69b2 commit a757cae
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 17 deletions.
79 changes: 79 additions & 0 deletions src/web/BL_Python/web/scaffolding/scaffolder.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import logging
import sys
import types
from dataclasses import asdict, dataclass, field
from importlib.machinery import SourceFileLoader
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
from typing import Any, cast
Expand Down Expand Up @@ -313,7 +316,83 @@ def _scaffold_endpoints(
overwrite_existing_files=overwrite_existing_files,
)

# it is safe for create if:
# - the current directory is not a scaffolded application
# it is safe for modify if:
# - the <application name> directory exists
# - the <application name> directory is a scaffolded application
# - the scaffolder is run from the scaffolded application's parent directory
def _check_scaffolded_application_exists(self, test_path: Path):
"""
Determine whether the application <config.application_name> is an importable
BL_Python.web application that has been previously scaffolded with
this tool.
:param test_path: The directory to test for the existence of a scaffolded application.
"""
application_import_path = Path(".", test_path)
self._log.debug(
f"Adding `{application_import_path}` to process module import path."
)
# modifying the import path to include a relative directory
# is less than ideal and potentionally dangerous. we should
# consider forking here or doing something else to prevent
# the global modification.
sys.path.insert(0, str(application_import_path))

try:
# if any of these steps fail, then the `test_path`
# does not already contain a scaffolded application
loader = SourceFileLoader(
self._config.application_name,
str(
Path(
test_path,
self._config.application_name,
"__init__.py",
)
),
)
mod = types.ModuleType(loader.name)
sys.modules[self._config.application_name] = mod
module = loader.load_module()
_ = module.__version__
_ = module._version.__bl_python_scaffold__
# if no errors occur, then the `test_path`
# contains a scaffolded application
return True
except Exception as e:
self._log.debug(str(e), exc_info=True)
return False
finally:
if self._config.application_name in sys.modules:
del sys.modules[self._config.application_name]
popped_import_path = sys.path.pop(0)
self._log.debug(
f"Popped `{popped_import_path}` from process module import path. Expected to pop `{application_import_path}`."
)

def scaffold(self):
in_parent_directory = self._check_scaffolded_application_exists(
Path(self._config.output_directory)
)
in_application_directory = self._check_scaffolded_application_exists(Path("."))

# "create" can run from any directory that is not an existing
# application's root directory.
if self._config.mode == "create" and in_application_directory:
self._log.critical(
"Attmpted to scaffold a new application in the same directory as an existing application. This is not supported. Change your working directory to the application's parent directory, or run this from a directory that does not contain an existing application."
)
return
# modify can only run from an existing application's
# parent directory.
elif self._config.mode == "modify" and not in_parent_directory:
self._log.critical(
f"Attempted to modify an existing application from a directory that is not the existing application's parent directory. This is not supported. Change your working directory to the application's parent directory."
)
return

# used for the primary set of templates that a
# scaffolded application is made up of.
base_env = Environment(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
application_configs = []
application_modules = []
from {{application_name}}._version import __version__

{% if 'database' in module %}
from BL_Python.database.config import DatabaseConfig
from BL_Python.database.dependency_injection import ScopedSessionModule
application_configs.append(DatabaseConfig)
application_modules.append(ScopedSessionModule())
{% endif %}
def create_app():
application_configs = []
application_modules = []

from BL_Python.web.application import create_app
# fmt: off
app = create_app(
application_configs=application_configs,
application_modules=application_modules
)
# fmt: on
{% if 'database' in module %}
from BL_Python.database.config import DatabaseConfig
from BL_Python.database.dependency_injection import ScopedSessionModule
application_configs.append(DatabaseConfig)
application_modules.append(ScopedSessionModule())
{% endif %}

from BL_Python.web.application import create_app as _create_app
# fmt: off
return _create_app(
application_configs=application_configs,
application_modules=application_modules
)
# fmt: on
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __init__ import app
from __init__ import create_app

app.run()
if __name__ == '__main__':
create_app().run()
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import importlib.metadata

__version__ = importlib.metadata.version(__package__ or __name__)
__bl_python_scaffold__ = True

0 comments on commit a757cae

Please sign in to comment.