Skip to content

Commit

Permalink
Fix replaced_by_pep8 calls when wrapping staticmethods (Issue #548)
Browse files Browse the repository at this point in the history
  • Loading branch information
ptmcg committed Mar 9, 2024
1 parent 4bcb251 commit f39d8b3
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 36 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Expand Up @@ -14,6 +14,9 @@ Version 3.2.0 will also discontinue support for Python versions 3.6 and 3.7.

Version 3.1.3 - in development
------------------------------
- Fixed issue where PEP8 compatibility names for `ParserElement` staticmethods were
not themselves defined as staticmethods. When called using a `ParserElement` instance,
this resulted in a `TypeError` exception. Reported by eylenburg (#548).


Version 3.1.2 - March, 2024
Expand Down
4 changes: 2 additions & 2 deletions pyparsing/__init__.py
Expand Up @@ -121,7 +121,7 @@ def __repr__(self):


__version_info__ = version_info(3, 1, 3, "final", 1)
__version_time__ = "07 Mar 2024 13:11 UTC"
__version_time__ = "09 Mar 2024 15:40 UTC"
__version__ = __version_info__.__version__
__versionTime__ = __version_time__
__author__ = "Paul McGuire <ptmcg.gm+pyparsing@gmail.com>"
Expand All @@ -143,7 +143,7 @@ def __repr__(self):
_builtin_exprs as common_builtin_exprs,
)

# define backward compat synonyms
# Compatibility synonyms
if "pyparsing_unicode" not in globals():
pyparsing_unicode = unicode # type: ignore[misc]
if "pyparsing_common" not in globals():
Expand Down
2 changes: 1 addition & 1 deletion pyparsing/actions.py
Expand Up @@ -196,7 +196,7 @@ def with_class(classname, namespace=""):
return with_attribute(**{classattr: classname})


# pre-PEP8 compatibility symbols
# Compatibility synonyms
# fmt: off
replaceWith = replaced_by_pep8("replaceWith", replace_with)
removeQuotes = replaced_by_pep8("removeQuotes", remove_quotes)
Expand Down
27 changes: 11 additions & 16 deletions pyparsing/common.py
Expand Up @@ -151,12 +151,12 @@ class pyparsing_common:
[UUID('12345678-1234-5678-1234-567812345678')]
"""

convert_to_integer = token_map(int)
convert_to_integer = staticmethod(token_map(int))
"""
Parse action for converting parsed integers to Python int
"""

convert_to_float = token_map(float)
convert_to_float = staticmethod(token_map(float))
"""
Parse action for converting parsed numbers to Python float
"""
Expand Down Expand Up @@ -418,20 +418,15 @@ def strip_html_tags(s: str, l: int, tokens: ParseResults):
# fmt: on

# pre-PEP8 compatibility names
convertToInteger = convert_to_integer
"""Deprecated - use :class:`convert_to_integer`"""
convertToFloat = convert_to_float
"""Deprecated - use :class:`convert_to_float`"""
convertToDate = convert_to_date
"""Deprecated - use :class:`convert_to_date`"""
convertToDatetime = convert_to_datetime
"""Deprecated - use :class:`convert_to_datetime`"""
stripHTMLTags = strip_html_tags
"""Deprecated - use :class:`strip_html_tags`"""
upcaseTokens = upcase_tokens
"""Deprecated - use :class:`upcase_tokens`"""
downcaseTokens = downcase_tokens
"""Deprecated - use :class:`downcase_tokens`"""
# fmt: off
convertToInteger = staticmethod(replaced_by_pep8("convertToInteger", convert_to_integer))
convertToFloat = staticmethod(replaced_by_pep8("convertToFloat", convert_to_float))
convertToDate = staticmethod(replaced_by_pep8("convertToDate", convert_to_date))
convertToDatetime = staticmethod(replaced_by_pep8("convertToDatetime", convert_to_datetime))
stripHTMLTags = staticmethod(replaced_by_pep8("stripHTMLTags", strip_html_tags))
upcaseTokens = staticmethod(replaced_by_pep8("upcaseTokens", upcase_tokens))
downcaseTokens = staticmethod(replaced_by_pep8("downcaseTokens", downcase_tokens))
# fmt: on


_builtin_exprs = [
Expand Down
23 changes: 14 additions & 9 deletions pyparsing/core.py
Expand Up @@ -2264,19 +2264,22 @@ def create_diagram(

# Compatibility synonyms
# fmt: off
inlineLiteralsUsing = replaced_by_pep8("inlineLiteralsUsing", inline_literals_using)
setDefaultWhitespaceChars = replaced_by_pep8(
inlineLiteralsUsing = staticmethod(replaced_by_pep8("inlineLiteralsUsing", inline_literals_using))
setDefaultWhitespaceChars = staticmethod(replaced_by_pep8(
"setDefaultWhitespaceChars", set_default_whitespace_chars
)
))
disableMemoization = staticmethod(replaced_by_pep8("disableMemoization", disable_memoization))
enableLeftRecursion = staticmethod(replaced_by_pep8("enableLeftRecursion", enable_left_recursion))
enablePackrat = staticmethod(replaced_by_pep8("enablePackrat", enable_packrat))
resetCache = staticmethod(replaced_by_pep8("resetCache", reset_cache))

setResultsName = replaced_by_pep8("setResultsName", set_results_name)
setBreak = replaced_by_pep8("setBreak", set_break)
setParseAction = replaced_by_pep8("setParseAction", set_parse_action)
addParseAction = replaced_by_pep8("addParseAction", add_parse_action)
addCondition = replaced_by_pep8("addCondition", add_condition)
setFailAction = replaced_by_pep8("setFailAction", set_fail_action)
tryParse = replaced_by_pep8("tryParse", try_parse)
enableLeftRecursion = replaced_by_pep8("enableLeftRecursion", enable_left_recursion)
enablePackrat = replaced_by_pep8("enablePackrat", enable_packrat)
parseString = replaced_by_pep8("parseString", parse_string)
scanString = replaced_by_pep8("scanString", scan_string)
transformString = replaced_by_pep8("transformString", transform_string)
Expand All @@ -2290,8 +2293,7 @@ def create_diagram(
setName = replaced_by_pep8("setName", set_name)
parseFile = replaced_by_pep8("parseFile", parse_file)
runTests = replaced_by_pep8("runTests", run_tests)
canParseNext = can_parse_next
resetCache = reset_cache
canParseNext = replaced_by_pep8("canParseNext", can_parse_next)
defaultName = default_name
# fmt: on

Expand Down Expand Up @@ -2556,7 +2558,10 @@ def set_default_keyword_chars(chars) -> None:
"""
Keyword.DEFAULT_KEYWORD_CHARS = chars

setDefaultKeywordChars = set_default_keyword_chars
# Compatibility synonyms
setDefaultKeywordChars = staticmethod(
replaced_by_pep8("setDefaultKeywordChars", set_default_keyword_chars)
)


class CaselessLiteral(Literal):
Expand Down Expand Up @@ -6070,7 +6075,7 @@ def autoname_elements() -> None:
v for v in vars().values() if isinstance(v, ParserElement)
]

# backward compatibility names
# Compatibility synonyms
# fmt: off
sglQuotedString = sgl_quoted_string
dblQuotedString = dbl_quoted_string
Expand Down
1 change: 1 addition & 0 deletions pyparsing/exceptions.py
Expand Up @@ -245,6 +245,7 @@ def explain(self, depth=16) -> str:
"""
return self.explain_exception(self, depth)

# Compatibility synonyms
# fmt: off
markInputline = replaced_by_pep8("markInputline", mark_input_line)
# fmt: on
Expand Down
2 changes: 1 addition & 1 deletion pyparsing/helpers.py
Expand Up @@ -1049,7 +1049,7 @@ def delimited_list(
)


# pre-PEP8 compatible names
# Compatibility synonyms
# fmt: off
opAssoc = OpAssoc
anyOpenTag = any_open_tag
Expand Down
13 changes: 7 additions & 6 deletions pyparsing/results.py
Expand Up @@ -10,6 +10,9 @@
import pprint
from typing import Tuple, Any, Dict, Set, List

from .util import replaced_by_pep8


str_type: Tuple[type, ...] = (str, bytes)
_generator_type = type((_ for _ in ()))

Expand Down Expand Up @@ -785,12 +788,10 @@ def is_iterable(obj):
ret = cls([ret], name=name)
return ret

asList = as_list
"""Deprecated - use :class:`as_list`"""
asDict = as_dict
"""Deprecated - use :class:`as_dict`"""
getName = get_name
"""Deprecated - use :class:`get_name`"""
# Compatibility synonyms
asList = replaced_by_pep8("asList", as_list)
asDict = replaced_by_pep8("asDict", as_dict)
getName = replaced_by_pep8("getName", get_name)


MutableMapping.register(ParseResults)
Expand Down
2 changes: 1 addition & 1 deletion pyparsing/util.py
Expand Up @@ -246,7 +246,7 @@ def replaced_by_pep8(compat_name: str, fn: C) -> C:

# (Presence of 'self' arg in signature is used by explain_exception() methods, so we take
# some extra steps to add it if present in decorated function.)
if "self" == list(inspect.signature(fn).parameters)[0]:
if "self" == next(iter(inspect.signature(fn).parameters), ""):

@wraps(fn)
def _inner(self, *args, **kwargs):
Expand Down
30 changes: 30 additions & 0 deletions tests/test_unit.py
Expand Up @@ -10206,6 +10206,36 @@ def test_exception_messages(self, tests=test_exception_messages_tests):
with self.assertRaisesParseException(expected_msg=expected_msg):
expr.parse_string(input_str)

def test_pep8_synonyms(self):
"""
Test that staticmethods wrapped by replaced_by_pep8 wrapper are properly
callable as staticmethods.
"""

def run_subtest(fn_name, expr=None, args=""):
bool_expr = pp.one_of("true false", as_keyword=True)
if expr is None:
expr = "bool_expr"

# try calling a ParserElement staticmethod via a ParserElement instance
with self.subTest(fn_name=fn_name):
exec(f"{expr}.{fn_name}({args})", globals(), locals())

# access staticmethod synonyms using a ParserElement
parser_element_staticmethod_names = """
enablePackrat disableMemoization enableLeftRecursion resetCache
""".split()

if not (pp.ParserElement._packratEnabled or pp.ParserElement._left_recursion_enabled):
for name in parser_element_staticmethod_names:
run_subtest(name)
pp.ParserElement.disable_memoization()

run_subtest("setDefaultWhitespaceChars", args="' '")
run_subtest("inlineLiteralsUsing", args="pp.Suppress")

run_subtest("setDefaultKeywordChars", expr="pp.Keyword('START')", args="'abcde'")


class Test03_EnablePackratParsing(TestCase):
def runTest(self):
Expand Down

0 comments on commit f39d8b3

Please sign in to comment.