Skip to content

Commit

Permalink
Add type hints.
Browse files Browse the repository at this point in the history
  • Loading branch information
riga committed Jun 23, 2022
1 parent ed62f6d commit 646b5a3
Showing 1 changed file with 33 additions and 32 deletions.
65 changes: 33 additions & 32 deletions pymitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import collections
import fnmatch
import asyncio
from typing import Optional, Callable, List, Awaitable, Union


LE_PY36 = sys.version_info[:2] <= (3, 6)
Expand All @@ -42,10 +43,10 @@ class EventEmitter(object):
def __init__(
self,
*,
delimiter=".",
wildcard=False,
new_listener=False,
max_listeners=-1,
delimiter: str = ".",
wildcard: bool = False,
new_listener: bool = False,
max_listeners: int = -1,
):
super().__init__()

Expand All @@ -63,7 +64,7 @@ def __init__(
def num_listeners(self):
return self._event_tree.num_listeners() + len(self._any_listeners)

def on(self, event, func=None, ttl=-1):
def on(self, event: str, func: Optional[Callable] = None, ttl: int = -1) -> Callable:
"""
Registers a function to an event. *ttl* defines the times to listen with negative values
meaning infinity. When *func* is *None*, decorator usage is assumed. Returns the wrapped
Expand All @@ -83,14 +84,14 @@ def on(func):

return on(func) if func else on

def once(self, event, func=None):
def once(self, event: str, func: Optional[Callable] = None) -> Callable:
"""
Registers a function to an event that is called once. When *func* is *None*, decorator usage
is assumed. Returns the wrapped function.
"""
return self.on(event, func=func, ttl=1)

def on_any(self, func=None, ttl=-1):
def on_any(self, func: Optional[Callable] = None, ttl: int = -1) -> Callable:
"""
Registers a function that is called every time an event is emitted. *ttl* defines the times
to listen with negative values meaning infinity. When *func* is *None*, decorator usage is
Expand All @@ -110,7 +111,7 @@ def on_any(func):

return on_any(func) if func else on_any

def off(self, event, func=None):
def off(self, event: str, func: Optional[Callable] = None) -> Callable:
"""
Removes a function that is registered to an event. When *func* is *None*, decorator usage is
assumed. Returns the wrapped function.
Expand All @@ -122,7 +123,7 @@ def off(func):

return off(func) if func else off

def off_any(self, func=None):
def off_any(self, func: Optional[Callable] = None) -> Callable:
"""
Removes a function that was registered via :py:meth:`on_any`. When *func* is *None*,
decorator usage is assumed. Returns the wrapped function.
Expand All @@ -138,26 +139,26 @@ def off_any(func):

return off_any(func) if func else off_any

def off_all(self):
def off_all(self) -> None:
"""
Removes all registered functions.
"""
self._event_tree.clear()
del self._any_listeners[:]

def listeners(self, event):
def listeners(self, event: str) -> List[Callable]:
"""
Returns all functions that are registered to an event.
"""
return [listener.func for listener in self._event_tree.find_listeners(event)]

def listeners_any(self):
def listeners_any(self) -> List[Callable]:
"""
Returns all functions that were registered using :py:meth:`on_any`.
"""
return [listener.func for listener in self._any_listeners]

def listeners_all(self):
def listeners_all(self) -> List[Callable]:
"""
Returns all registered functions, ordered by their registration time.
"""
Expand All @@ -173,7 +174,7 @@ def listeners_all(self):

return [listener.func for listener in listeners]

def _emit(self, event, *args, **kwargs):
def _emit(self, event: str, *args, **kwargs) -> List[Awaitable]:
# call listeners in order, keep track of awaitables from coroutines functions
awaitables = []
for listener in self._event_tree.find_listeners(event):
Expand All @@ -188,7 +189,7 @@ def _emit(self, event, *args, **kwargs):

return awaitables

def emit(self, event, *args, **kwargs):
def emit(self, event: str, *args, **kwargs) -> None:
"""
Emits an *event*. All functions of events that match *event* are invoked with *args* and
*kwargs* in the exact order of their registration, with the exception of async functions
Expand All @@ -207,7 +208,7 @@ async def start():
await asyncio.gather(*awaitables)
asyncio.run(start())

async def emit_async(self, event, *args, **kwargs):
async def emit_async(self, event: str, *args, **kwargs) -> Awaitable:
"""
Awaitable version of :py:meth:`emit`. However, this method does not start a new event loop
but uses the existing one.
Expand All @@ -222,7 +223,7 @@ async def emit_async(self, event, *args, **kwargs):

class BaseNode(object):

def __init__(self, wildcard, delimiter):
def __init__(self, wildcard: bool, delimiter: str):
super().__init__()

self.wildcard = wildcard
Expand All @@ -233,7 +234,7 @@ def __init__(self, wildcard, delimiter):
def clear(self):
self.nodes.clear()

def add_node(self, node):
def add_node(self, node: "Node"):
# when there is a node with the exact same name (pattern), merge listeners
if node.name in self.nodes:
_node = self.nodes[node.name]
Expand All @@ -253,30 +254,30 @@ class Node(BaseNode):
"""

@classmethod
def str_is_pattern(cls, s):
def str_is_pattern(cls, s: str):
return "*" in s or "?" in s

def __init__(self, name, *args):
def __init__(self, name: str, *args):
super().__init__(*args)

self.name = name
self.listeners = []

def num_listeners(self, recursive=True):
def num_listeners(self, recursive: bool = True) -> int:
n = len(self.listeners)

if recursive:
n += sum(node.num_listeners(recursive=recursive) for node in self.nodes.values())

return n

def remove_listeners_by_func(self, func):
def remove_listeners_by_func(self, func: Callable) -> None:
self.listeners[:] = [listener for listener in self.listeners if listener.func != func]

def add_listener(self, listener):
def add_listener(self, listener: "Listener") -> None:
self.listeners.append(listener)

def check_name(self, pattern):
def check_name(self, pattern: str) -> bool:
if self.wildcard:
if self.str_is_pattern(pattern):
return fnmatch.fnmatch(self.name, pattern)
Expand All @@ -285,7 +286,7 @@ def check_name(self, pattern):

return self.name == pattern

def find_nodes(self, event):
def find_nodes(self, event: Union[str, list, tuple]) -> List["Node"]:
# trivial case
if not event:
return []
Expand Down Expand Up @@ -313,13 +314,13 @@ class Tree(BaseNode):
Top-level node without a name or listeners, but providing higher-level node access.
"""

def num_listeners(self):
def num_listeners(self) -> int:
return sum(node.num_listeners(recursive=True) for node in self.nodes.values())

def find_nodes(self, *args, **kwargs):
def find_nodes(self, *args, **kwargs) -> List[Node]:
return sum((node.find_nodes(*args, **kwargs) for node in self.nodes.values()), [])

def add_listener(self, event, listener):
def add_listener(self, event: str, listener: "Listener") -> None:
# add nodes without evaluating wildcards, this is done during node lookup only
names = event.split(self.delimiter)

Expand All @@ -337,11 +338,11 @@ def add_listener(self, event, listener):
# add the listeners
node.listeners.extend([listener])

def remove_listeners_by_func(self, event, func):
def remove_listeners_by_func(self, event: str, func: Callable) -> None:
for node in self.find_nodes(event):
node.remove_listeners_by_func(func)

def find_listeners(self, event, sort=True):
def find_listeners(self, event: str, sort: bool = True) -> List["Listener"]:
listeners = sum((node.listeners for node in self.find_nodes(event)), [])

# sort by registration time
Expand All @@ -357,7 +358,7 @@ class Listener(object):
track of the times to listen left.
"""

def __init__(self, func, event, ttl):
def __init__(self, func: Callable, event: str, ttl: int):
super().__init__()

self.func = func
Expand All @@ -368,7 +369,7 @@ def __init__(self, func, event, ttl):
self.time = time.monotonic()

@property
def is_coroutine(self):
def is_coroutine(self) -> bool:
return asyncio.iscoroutinefunction(self.func)

def __call__(self, *args, **kwargs):
Expand Down

0 comments on commit 646b5a3

Please sign in to comment.