maybe better?

This commit is contained in:
Jesse Bannon 2023-12-08 00:03:43 -08:00
parent a7dcf49e00
commit fb58941ff5
5 changed files with 80 additions and 22 deletions

View file

@ -118,17 +118,13 @@ class Overrides(DictFormatterValidator, Scriptable):
The format_string after .format has been called
"""
if entry:
script = copy.deepcopy(entry.script)
script = entry.script
unresolvable = entry.unresolvable
else:
script = copy.deepcopy(self.script)
script = self.script
unresolvable = self.unresolvable
if function_overrides:
script.add(function_overrides)
script = copy.deepcopy(script).add(function_overrides)
return (
script.add({"tmp_var": formatter.format_string})
.resolve(unresolvable=unresolvable)
.get_str("tmp_var")
)
return str(script.is_resolvable(formatter.format_string, unresolvable=unresolvable))

View file

@ -190,6 +190,8 @@ class Preset(_PresetShell):
{source_var: "dummy_string" for source_var in self._source_variables}
)
)
# updates any resolved variables
_ = script.partial_build()
return script
@property
@ -209,7 +211,7 @@ class Preset(_PresetShell):
"""
Contains actualized script which should hold all Override variables
"""
return self._script_builder_with_added_variables.partial_build(update=True)
return self._script_builder_with_added_variables.partial_build()
@property
def _script(self) -> Script:
@ -252,19 +254,27 @@ class Preset(_PresetShell):
)
)
def __validate_override_string_formatter_validator(
@functools.cache
def _get_unresolvable_variables(
self,
formatter_validator: Union[StringFormatterValidator, OverridesStringFormatterValidator],
) -> None:
) -> Optional[Set[str]]:
unresolvable = (
set([VARIABLES.entry_metadata.variable_name] + list(self._added_variables.keys()))
if isinstance(formatter_validator, OverridesStringFormatterValidator)
else None
)
return unresolvable
def __validate_override_string_formatter_validator(
self,
formatter_validator: Union[StringFormatterValidator, OverridesStringFormatterValidator],
) -> None:
try:
self._script.add({"tmp_var": formatter_validator.format_string}).resolve(
unresolvable=unresolvable
).get("tmp_var")
self._script.is_resolvable(
formatter_validator.format_string,
unresolvable=self._get_unresolvable_variables(formatter_validator),
)
except VariableDoesNotExist as exc:
raise StringFormattingVariableNotFoundException(exc) from exc

View file

@ -261,7 +261,7 @@ class MultiUrlValidator(OptionsValidator):
for collection_url in self.urls.list:
script.add(collection_url.variables.dict_with_format_strings)
resolved_script = script.partial_build(update=True)
resolved_script = script.partial_build()
# Ensure at least URL is non-empty
has_non_empty_url = False

View file

@ -246,11 +246,12 @@ class Script:
for variable_name, resolved in resolved_variables.items():
self._variables[variable_name] = SyntaxTree(ast=[resolved])
def resolve(
def _resolve(
self,
resolved: Optional[Dict[str, Resolvable]] = None,
unresolvable: Optional[Set[str]] = None,
update: bool = False,
output_filter: Optional[Set[str]] = None,
) -> ScriptOutput:
"""
Parameters
@ -268,9 +269,17 @@ class Script:
-------
Dict of resolved values
"""
resolved: Dict[Variable, Resolvable] = {
Variable(name): value for name, value in (resolved or {}).items()
}
resolved: Dict[Variable, Resolvable] = dict(
# include all current variables that are resolvable
{
Variable(name): ast.resolvable
for name, ast in self._variables.items()
if ast.resolvable is not None
},
# add explicit defined resolved variables
**{Variable(name): value for name, value in (resolved or {}).items()},
)
unresolvable: Set[Variable] = {Variable(name) for name in (unresolvable or {})}
unresolved: Dict[Variable, SyntaxTree] = {
Variable(name): ast
@ -278,6 +287,8 @@ class Script:
if Variable(name) not in set(resolved.keys()).union(unresolvable)
}
tmp = 0
while unresolved:
unresolved_count: int = len(unresolved)
@ -308,8 +319,27 @@ class Script:
if update:
self._update_internally(resolved_variables=resolved_variables)
if output_filter:
return ScriptOutput(
{
name: resolvable
for name, resolvable in resolved_variables.items()
if name in output_filter
}
)
return ScriptOutput(resolved_variables)
def resolve(
self,
resolved: Optional[Dict[str, Resolvable]] = None,
unresolvable: Optional[Set[str]] = None,
update: bool = False,
) -> ScriptOutput:
return self._resolve(
resolved=resolved, unresolvable=unresolvable, update=update, output_filter=None
)
def add(self, variables: Dict[str, str]) -> "Script":
for variable_name, variable_definition in variables.items():
self._variables[variable_name] = parse(
@ -321,6 +351,21 @@ class Script:
self._validate()
return self
def is_resolvable(
self,
variable_definition: str,
resolved: Optional[Dict[str, Resolvable]] = None,
unresolvable: Optional[Set[str]] = None,
) -> Resolvable:
try:
self.add({"tmp_var": variable_definition})
return self._resolve(
resolved=resolved, unresolvable=unresolvable, output_filter={"tmp_var"}
).get("tmp_var")
finally:
if "tmp_var" in self._variables:
del self._variables["tmp_var"]
def get(self, variable_name: str) -> Resolvable:
if variable_name not in self._variables:
raise RuntimeException(
@ -419,7 +464,7 @@ class ScriptBuilder:
script._validate()
return script
def partial_build(self, update: bool = False) -> Script:
def partial_build(self) -> Script:
missing_variables, missing_functions = self._missing_metadata
maybe_resolvable_variables: Dict[str, SyntaxTree] = {
name: variable
@ -435,8 +480,9 @@ class ScriptBuilder:
script = self._build(
variables=maybe_resolvable_variables, functions=maybe_resolvable_functions
)
if update:
script.resolve(update=True)
# Update internal variables with anything that is resolved
for variable_name, variable_output in script.resolve(update=True).output.items():
self._variables[variable_name] = SyntaxTree([variable_output])
return script
def build(self) -> Script:

View file

@ -5,6 +5,7 @@ from typing import Optional
from typing import Tuple
import pytest
import yappi
from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
@ -149,6 +150,9 @@ class TestPrebuiltTVShowPresets:
is_youtube_channel: bool,
is_many_urls: bool,
):
# yappi.set_clock_type("wall") # Use set_clock_type("wall") for wall time
# yappi.start()
expected_summary_name = "unit/{}/{}/is_yt_{}{}".format(
media_player_preset,
tv_show_structure_preset,
@ -218,6 +222,8 @@ class TestPrebuiltTVShowPresets:
)
reformatted_transaction_log = reformatted_subscription.update_with_info_json(dry_run=False)
# yappi.get_func_stats().print_all()
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=reformatted_transaction_log,