Skip to content

Commit

Permalink
Moves creating temporary module to ad_hoc_utils
Browse files Browse the repository at this point in the history
This is a better place to live.

Makes note that one function is deprecated.
  • Loading branch information
skrawcz committed Apr 26, 2024
1 parent 6c3408b commit f51cc4c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 41 deletions.
42 changes: 41 additions & 1 deletion hamilton/ad_hoc_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
"""A suite of tools for ad-hoc use"""

import atexit
import importlib.util
import linecache
import os
import sys
import tempfile
import types
import uuid
from types import ModuleType
Expand Down Expand Up @@ -61,7 +65,9 @@ def create_temporary_module(*functions: Callable, module_name: str = None) -> Mo


def module_from_source(source: str) -> ModuleType:
"""Create a temporary module from source code"""
"""Create a temporary module from source code.
Deprecated in favor of `create_module()` below.
"""
module_name = _generate_unique_temp_module_name()
module_object = ModuleType(module_name)
code_object = compile(source, module_name, "exec")
Expand All @@ -75,3 +81,37 @@ def module_from_source(source: str) -> ModuleType:
module_name,
)
return module_object


def create_module(source: str, module_name: str = None, verbosity: int = 0) -> ModuleType:
"""Create a temporary module from source code and load it as a proper Python module.
Registers the module in sys.modules and cleans up the temporary file on interpreter shutdown.
But if the python interpreter errors out, or the server is shutdown, the temporary file will not be cleaned up.
"""
# Create a temporary file to hold the code
with tempfile.NamedTemporaryFile(delete=False, suffix=".py", mode="w") as tmp_file:
tmp_file.write(source)
module_path = tmp_file.name
if verbosity > 1:
print(f"Temporary file created at {module_path}")

# Determine a module name if not provided
if module_name is None:
module_name = os.path.basename(module_path).split(".")[0]

# Load the module from the temporary file
spec = importlib.util.spec_from_file_location(module_name, module_path)
module_object = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module_object)

# Register the module in sys.modules
sys.modules[module_name] = module_object

# Clean up the temporary file on interpreter shutdown
def cleanup(module_path=module_path):
os.remove(module_path)

atexit.register(lambda: cleanup())

return module_object
42 changes: 2 additions & 40 deletions hamilton/plugins/jupyter_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,16 @@
"""

import atexit
import importlib.util
import json
import os
import sys
import tempfile
from pathlib import Path
from types import ModuleType

from IPython.core.magic import Magics, cell_magic, line_magic, magics_class
from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring
from IPython.display import HTML, display

from hamilton import driver, lifecycle


def create_module(source: str, module_name: str = None, verbosity: int = 0) -> ModuleType:
"""Create a temporary module from source code and load it as a proper Python module.
Registers the module in sys.modules and cleans up the temporary file on interpreter shutdown.
But if the python interpreter errors out, or the server is shutdown, the temporary file will not be cleaned up.
"""
# Create a temporary file to hold the code
with tempfile.NamedTemporaryFile(delete=False, suffix=".py", mode="w") as tmp_file:
tmp_file.write(source)
module_path = tmp_file.name
if verbosity > 1:
print(f"Temporary file created at {module_path}")

# Determine a module name if not provided
if module_name is None:
module_name = os.path.basename(module_path).split(".")[0]

# Load the module from the temporary file
spec = importlib.util.spec_from_file_location(module_name, module_path)
module_object = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module_object)

# Register the module in sys.modules
sys.modules[module_name] = module_object

# Clean up the temporary file on interpreter shutdown
def cleanup(module_path=module_path):
os.remove(module_path)

atexit.register(lambda: cleanup())

return module_object
from hamilton import ad_hoc_utils, driver, lifecycle


def insert_cell_with_content():
Expand Down Expand Up @@ -249,7 +211,7 @@ def cell_to_module(self, line, cell):
print("Failed to parse config as JSON. Please ensure it's a valid JSON string:")
print(args.config)

module_object = create_module(cell, module_name, verbosity=args.verbosity)
module_object = ad_hoc_utils.create_module(cell, module_name, verbosity=args.verbosity)

# shell.push() assign a variable in the notebook. The dictionary keys are variable name
self.shell.push({module_name: module_object})
Expand Down

0 comments on commit f51cc4c

Please sign in to comment.