-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
2,344 additions
and
1,476 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Example parameterized Jupyter notebook." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from wvpy.assignment import (\n", | ||
" assign_values_from_map, \n", | ||
" dict_to_assignments_str,\n", | ||
" ensure_names_not_already_assigned,\n", | ||
" record_assignments,\n", | ||
")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 2, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# overrides (usually this comes from external driver)\n", | ||
"# In practice sheet_vars will be set by the system runner, this form informs Jupyter or the IDE \n", | ||
"# that sheet_vars is a defined variable.\n", | ||
"sheet_vars = globals().get(\"sheet_vars\", {}) # take previous value if there is one, else empty dictionary" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 3, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# check that none of the variables we want to override are already assigned\n", | ||
"# this check is to cut down confusion of having these assigned somewhere other than\n", | ||
"# the context manager that is the next block\n", | ||
"ensure_names_not_already_assigned(globals(), keys=sheet_vars.keys())" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 4, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# set some variables to default values we are willing to override\n", | ||
"# we do this with the with context manager so that our Jupyter or IDE thinks these variables are defined in our environment\n", | ||
"# this defines both the set of names we allow overriding of and default values so we can debug in and IDE\n", | ||
"assignments = {}\n", | ||
"with record_assignments(globals(), result=assignments):\n", | ||
" # default values to be overridden\n", | ||
" city = \"Los Angeles\"\n", | ||
" state = \"CA\"\n", | ||
" country = \"USA\"" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 5, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"default assignments are:\n", | ||
"{'city': 'Los Angeles', 'country': 'USA', 'state': 'CA'}\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(\"default assignments are:\")\n", | ||
"print(assignments)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 6, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# override explicit assignments with values from sheet_vars\n", | ||
"assign_values_from_map(\n", | ||
" globals(),\n", | ||
" values=sheet_vars,\n", | ||
" expected_keys=assignments.keys(),\n", | ||
")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 7, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"running with the following actual values\n", | ||
"\n", | ||
"city = 'Los Angeles'\n", | ||
"country = 'USA'\n", | ||
"state = 'CA'\n", | ||
"\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(\"running with the following actual values\")\n", | ||
"print(dict_to_assignments_str({k: globals()[k] for k in assignments.keys()}))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 8, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"Analysis and results for Los Angeles.\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"# small simulation of parameterized analysis process\n", | ||
"print(f\"Analysis and results for {city}.\")" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "wvpy_dev_env", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.11.2" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
"""Classes and functions for working with variable assignments""" | ||
|
||
from typing import Any, Dict, Iterable, Optional | ||
from contextlib import contextmanager | ||
|
||
|
||
def dict_to_assignments_str(values: Dict[str, Any]) -> str: | ||
""" | ||
Format a dictionary as a block of Python assignment statements. | ||
Example: | ||
```python | ||
from wvpy.assignment import dict_to_assignments_str | ||
print(dict_to_assignments_str({"a": 1, "b": 2})) | ||
``` | ||
:param values: dictionary | ||
:return: assignment statements | ||
""" | ||
assert isinstance(values, dict) | ||
return ( | ||
"\n" | ||
+ "\n".join([f"{k} = {repr(values[k])}" for k in sorted(values.keys())]) | ||
+ "\n" | ||
) | ||
|
||
|
||
@contextmanager | ||
def record_assignments( | ||
env, | ||
*, | ||
result: Dict[str, Any], | ||
) -> None: | ||
""" | ||
Context manager to record all assignments to new variables in a with-block. | ||
New variables being variables not set prior to entering the with block. | ||
Example: | ||
```python | ||
from wvpy.assignment import dict_to_assignments_str, record_assignments | ||
assignments = {} | ||
with record_assignments(globals(), result=assignments): | ||
a = 1 | ||
b = 2 | ||
print(assignments) | ||
print(dict_to_assignments_str(assignments)) | ||
``` | ||
:param env: working environment, setting to `globals()` is usually the correct choice. | ||
:param result: dictionary to store results in. function calls `.clear()` on result. | ||
:return None: | ||
""" | ||
assert isinstance(result, dict) | ||
pre_known_vars = set(env.keys()) | ||
result.clear() | ||
try: | ||
yield | ||
finally: | ||
post_known_vars = set(env.keys()) | ||
declared_vars = post_known_vars - pre_known_vars | ||
for k in sorted(declared_vars): | ||
result[k] = env[k] | ||
|
||
|
||
def ensure_names_not_already_assigned(env, *, keys: Iterable[str]) -> None: | ||
""" | ||
Check that no key in keys is already set in the environment env. | ||
Raises ValueError if keys are already assigned. | ||
:param env: working environment, setting to `globals()` is usually the correct choice. | ||
:param keys: keys to confirm not already set. | ||
:return None: | ||
""" | ||
already_assigned_vars = set(keys).intersection(set(env.keys())) | ||
if len(already_assigned_vars) > 0: | ||
raise ValueError(f"variables already set: {sorted(already_assigned_vars)}") | ||
|
||
|
||
def assign_values_from_map( | ||
env, *, values: Dict[str, Any], expected_keys: Optional[Iterable[str]] | ||
) -> None: | ||
""" | ||
Assign values from map into environment. | ||
:param env: working environment, setting to `globals()` is usually the correct choice. | ||
:param values: dictionary to copy into environment. | ||
:param expected_keys: if not null a set of keys we are restricting to | ||
:return None: | ||
""" | ||
assert isinstance(values, dict) | ||
for k in values.keys(): | ||
assert isinstance(k, str) | ||
if expected_keys is not None: | ||
unexpected_vars = set(values.keys()) - set(expected_keys) | ||
if len(unexpected_vars) > 0: | ||
raise ValueError( | ||
f"attempting to assign undeclared variables: {sorted(unexpected_vars)}" | ||
) | ||
# do the assignments | ||
for k, v in values.items(): | ||
env[k] = v |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Oops, something went wrong.