Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ListenerParser to be a plain old Python class #1490

Merged
merged 3 commits into from
Aug 9, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 25 additions & 39 deletions traits/traits_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .has_traits import HasPrivateTraits
from .trait_base import Undefined, Uninitialized
from .traits import Property
from .trait_types import Str, Int, Bool, Instance, List, Enum, Any
from .trait_types import Str, Bool, Instance, List, Enum, Any
from .trait_errors import TraitError
from .trait_notifiers import TraitChangeNotifyWrapper
from .util.weakiddict import WeakIDKeyDict
Expand Down Expand Up @@ -953,52 +953,36 @@ def unregister(self, old):
item.unregister(old)


class ListenerParser(HasPrivateTraits):

#: The string being parsed
text = Str

#: The length of the string being parsed.
len_text = Int

#: The current parse index within the string
index = Int

#: The next character from the string being parsed
next = Property

#: The next Python attribute name within the string:
name = Property

#: The next non-whitespace character
skip_ws = Property

#: Backspaces to the last character processed
backspace = Property

#: The ListenerBase object resulting from parsing **text**
listener = Instance(ListenerBase)
class ListenerParser:

# -- Property Implementations ---------------------------------------------

def _get_next(self):
@property
def next(self):
"""The next character from the string being parsed."""
index = self.index
self.index += 1
if index >= self.len_text:
return EOS

return self.text[index]

def _get_backspace(self):
@property
def backspace(self):
"""Backspaces to the last character processed."""
self.index = max(0, self.index - 1)

def _get_skip_ws(self):
@property
def skip_ws(self):
"""The next non-whitespace character."""
while True:
c = self.next
if c not in whitespace:
return c

def _get_name(self):
@property
def name(self):
"""The next Python attribute name within the string."""
match = name_pat.match(self.text, self.index - 1)
if match is None:
return ""
Expand All @@ -1009,9 +993,18 @@ def _get_name(self):

# -- object Method Overrides ----------------------------------------------

def __init__(self, text="", **traits):
def __init__(self, text):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not a 100% sure why we're changing the text default here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just for safety.

Previously, the text in the ListenerParser could be updated after initialization, triggering the _text_changed listener. With the refactored code, the only way the ListenerParser can be used correctly is to provide the text directly at initialization time. I made it non-optional so that we catch any code that tries to create a ListenerParser without providing the text to parse.

#: The text being parsed.
self.text = text
super().__init__(**traits)

#: The length of the string being parsed.
self.len_text = len(self.text)

#: The current parse index within the string.
self.index = 0

#: The parsed listener.
self.listener = self.parse()

# -- Private Methods ------------------------------------------------------

Expand Down Expand Up @@ -1151,13 +1144,6 @@ def error(self, msg):
"%s at column %d of '%s'" % (msg, self.index, self.text)
)

# -- Event Handlers -------------------------------------------------------

def _text_changed(self):
self.index = 0
self.len_text = len(self.text)
self.listener = self.parse()


class ListenerNotifyWrapper(TraitChangeNotifyWrapper):

Expand Down