invalid variable name inline
This commit is contained in:
parent
ad8ba02de9
commit
2426a68685
4 changed files with 78 additions and 11 deletions
|
|
@ -26,8 +26,10 @@ from ytdl_sub.script.utils.exceptions import CycleDetected
|
||||||
from ytdl_sub.script.utils.exceptions import FunctionDoesNotExist
|
from ytdl_sub.script.utils.exceptions import FunctionDoesNotExist
|
||||||
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
|
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
|
||||||
from ytdl_sub.script.utils.exceptions import InvalidSyntaxException
|
from ytdl_sub.script.utils.exceptions import InvalidSyntaxException
|
||||||
|
from ytdl_sub.script.utils.exceptions import InvalidVariableName
|
||||||
from ytdl_sub.script.utils.exceptions import UserException
|
from ytdl_sub.script.utils.exceptions import UserException
|
||||||
from ytdl_sub.script.utils.exceptions import VariableDoesNotExist
|
from ytdl_sub.script.utils.exceptions import VariableDoesNotExist
|
||||||
|
from ytdl_sub.script.utils.name_validation import validate_variable_name
|
||||||
from ytdl_sub.utils.exceptions import StringFormattingException
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
||||||
from ytdl_sub.validators.string_formatter_validators import is_valid_source_variable_name
|
from ytdl_sub.validators.string_formatter_validators import is_valid_source_variable_name
|
||||||
|
|
||||||
|
|
@ -172,21 +174,17 @@ class _Parser:
|
||||||
if _is_breakable(ch):
|
if _is_breakable(ch):
|
||||||
break
|
break
|
||||||
|
|
||||||
is_lower = ch.isascii() and ch.islower()
|
if not var_name:
|
||||||
if not var_name and not is_lower:
|
variable_start_pos = self._pos
|
||||||
raise StringFormattingException("invalid var name")
|
|
||||||
|
|
||||||
if not (is_lower or ch.isnumeric() or ch == "_"):
|
|
||||||
raise StringFormattingException("invalid var name")
|
|
||||||
|
|
||||||
var_name += ch
|
var_name += ch
|
||||||
self._pos += 1
|
self._pos += 1
|
||||||
|
|
||||||
if not var_name:
|
try:
|
||||||
raise StringFormattingException("invalid var name")
|
validate_variable_name(var_name)
|
||||||
|
except InvalidVariableName:
|
||||||
if not is_valid_source_variable_name(var_name, raise_exception=False):
|
self._set_highlight_position(variable_start_pos)
|
||||||
raise UNREACHABLE
|
raise
|
||||||
|
|
||||||
if self._variable_names is not None and var_name not in self._variable_names:
|
if self._variable_names is not None and var_name not in self._variable_names:
|
||||||
self._set_highlight_position(variable_start_pos)
|
self._set_highlight_position(variable_start_pos)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,14 @@ class InvalidSyntaxException(UserException):
|
||||||
"""Syntax is incorrect"""
|
"""Syntax is incorrect"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidVariableName(UserException):
|
||||||
|
"""Variable name is invalid"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidFunctionName(UserException):
|
||||||
|
"""Custom function name is invalid"""
|
||||||
|
|
||||||
|
|
||||||
class IncompatibleFunctionArguments(UserException):
|
class IncompatibleFunctionArguments(UserException):
|
||||||
"""Function has invalid arguments"""
|
"""Function has invalid arguments"""
|
||||||
|
|
||||||
|
|
|
||||||
50
src/ytdl_sub/script/utils/name_validation.py
Normal file
50
src/ytdl_sub/script/utils/name_validation.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ytdl_sub.script.functions import Functions
|
||||||
|
from ytdl_sub.script.utils.exceptions import InvalidFunctionName
|
||||||
|
from ytdl_sub.script.utils.exceptions import InvalidVariableName
|
||||||
|
|
||||||
|
_NAME_REGEX_VALIDATOR = re.compile(r"^[a-z][a-z0-9_]*$")
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid_name(name: str) -> bool:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
True if the name adheres to the ``snake_case`` format. False otherwise.
|
||||||
|
"""
|
||||||
|
return re.match(_NAME_REGEX_VALIDATOR, name) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def validate_variable_name(variable_name: str) -> None:
|
||||||
|
"""
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
InvalidVariableName
|
||||||
|
if the variable name is invalid
|
||||||
|
"""
|
||||||
|
if not is_valid_name(variable_name):
|
||||||
|
raise InvalidVariableName(
|
||||||
|
f"Variable name '{variable_name}' is invalid. "
|
||||||
|
f"Names must be lower_snake_cased and begin with a letter."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_custom_function_name(custom_function_name: str) -> None:
|
||||||
|
"""
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
InvalidVariableName
|
||||||
|
if the variable name is invalid
|
||||||
|
"""
|
||||||
|
if not is_valid_name(custom_function_name):
|
||||||
|
raise InvalidFunctionName(
|
||||||
|
f"Custom function name '%{custom_function_name}' is invalid:"
|
||||||
|
" Names must be %lower_snake_cased and begin with a letter."
|
||||||
|
)
|
||||||
|
|
||||||
|
if Functions.is_built_in(custom_function_name):
|
||||||
|
raise InvalidFunctionName(
|
||||||
|
f"Custom function name '%{custom_function_name}' is invalid:"
|
||||||
|
" The name is used by a built-in function and cannot be overwritten."
|
||||||
|
)
|
||||||
|
|
@ -5,6 +5,7 @@ import pytest
|
||||||
from ytdl_sub.script.script import Script
|
from ytdl_sub.script.script import Script
|
||||||
from ytdl_sub.script.types.resolvable import String
|
from ytdl_sub.script.types.resolvable import String
|
||||||
from ytdl_sub.script.utils.exceptions import CycleDetected
|
from ytdl_sub.script.utils.exceptions import CycleDetected
|
||||||
|
from ytdl_sub.script.utils.exceptions import InvalidVariableName
|
||||||
from ytdl_sub.script.utils.exceptions import VariableDoesNotExist
|
from ytdl_sub.script.utils.exceptions import VariableDoesNotExist
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -50,3 +51,13 @@ class TestVariable:
|
||||||
match=re.escape("Variable c does not exist."),
|
match=re.escape("Variable c does not exist."),
|
||||||
):
|
):
|
||||||
Script({"a": "a", "b": "{c}"}).resolve()
|
Script({"a": "a", "b": "{c}"}).resolve()
|
||||||
|
|
||||||
|
def test_invalid_variable_name_inline(self):
|
||||||
|
with pytest.raises(
|
||||||
|
InvalidVariableName,
|
||||||
|
match=re.escape(
|
||||||
|
"Variable name 'vali_LOL_INVALID' is invalid. "
|
||||||
|
"Names must be lower_snake_cased and begin with a letter."
|
||||||
|
),
|
||||||
|
):
|
||||||
|
Script({"a": "{vali_LOL_INVALID}"}).resolve()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue