Skip to content

Commit bdb379d

Browse files
register extensions in an extension registry
1 parent cad1ad5 commit bdb379d

13 files changed

Lines changed: 56 additions & 99 deletions

File tree

sifter/commands/require.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class CommandRequire(Command):
2121
def evaluate(self, message: Message, state: EvaluationState) -> Optional[Actions]:
2222
ext_name_list = self.positional_args[0]
2323
for ext_name in ext_name_list: # type: ignore
24-
if not sifter.handler.get('extension', ext_name):
24+
if not sifter.handler.ExtensionRegistry.get('extension', ext_name):
2525
raise RuntimeError(
2626
"Required extension '%s' not supported"
2727
% ext_name

sifter/comparator.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,16 @@
44
Text,
55
Optional,
66
Tuple,
7-
Type,
87
Union
98
)
109

1110
import sifter.handler
1211

1312
if TYPE_CHECKING:
14-
from sifter.grammar.comparator import Comparator
1513
from sifter.grammar.tag import Tag
1614
from sifter.grammar.state import EvaluationState
1715

1816

19-
def register(comparator_name: Optional[Text], comparator_cls: Type['Comparator']) -> None:
20-
sifter.handler.register('comparator', comparator_name, comparator_cls)
21-
22-
2317
def get_match_fn(
2418
comparator: Optional[Union[Text, 'Tag']],
2519
match_type: Optional[Union[Text, 'Tag']]
@@ -37,7 +31,7 @@ def get_match_fn(
3731
match_type = 'IS'
3832

3933
# TODO: support wildcard matching in comparator names (RFC 4790)
40-
cmp_handler = sifter.handler.get('comparator', comparator)
34+
cmp_handler = sifter.handler.ExtensionRegistry.get('comparator', comparator)
4135
if not cmp_handler:
4236
raise RuntimeError("Comparator not supported: %s" % comparator)
4337

sifter/extension.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55

66
def register(extension_name: Text) -> None:
7-
sifter.handler.register('extension', extension_name, True)
7+
sifter.handler.ExtensionRegistry.register('extension', extension_name, True)

sifter/extensions/builtin.py

Lines changed: 0 additions & 30 deletions
This file was deleted.

sifter/extensions/regex.py

Lines changed: 0 additions & 2 deletions
This file was deleted.

sifter/grammar/comparator.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
)
77

88
import re
9-
import sifter.comparator
109
from sifter.grammar.state import EvaluationState
1110

1211

@@ -16,22 +15,13 @@ class Comparator(object):
1615
COMPARATOR_ID: Optional[Text] = None
1716

1817
@classmethod
19-
def get_mapkey(cls):
18+
def handler_type(cls):
2019
return 'comparator'
2120

2221
@classmethod
23-
def get_identifier(cls):
22+
def handler_id(cls):
2423
return cls.COMPARATOR_ID
2524

26-
@classmethod
27-
def register(cls) -> None:
28-
try:
29-
sifter.comparator.register(cls.COMPARATOR_ID, cls)
30-
except AttributeError:
31-
# this method should only be called on sub-classes that define an
32-
# identifier
33-
raise NotImplementedError
34-
3525
@classmethod
3626
def sort_key(cls, s: Text) -> Text:
3727
return s

sifter/grammar/grammar.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from sifter.grammar.string import String
2020
import sifter.handler
2121
from sifter.grammar.lexer import SieveLexer
22+
from sifter.handler import ExtensionRegistry
2223

2324
if TYPE_CHECKING:
2425
from py.yacc import LRParser, YaccProduction # type: ignore
@@ -31,6 +32,7 @@ class SieveParser():
3132
def __init__(self) -> None:
3233
self.lexer = SieveLexer()
3334
self.parser = self.make_parser(self)
35+
self.extensions = ExtensionRegistry()
3436

3537
@staticmethod
3638
def make_parser(mod: Any) -> 'LRParser':
@@ -77,7 +79,7 @@ def p_command(self, p: 'YaccProduction') -> None:
7779
block = None
7880
if p[3] != ';':
7981
block = p[3]
80-
handler = sifter.handler.get('command', p[1])
82+
handler = sifter.handler.ExtensionRegistry.get('command', p[1])
8183
if handler is None:
8284
print("No handler registered for command '%s' on line %d" % (p[1], p.lineno(1)))
8385
raise SyntaxError
@@ -134,7 +136,7 @@ def p_test(self, p: 'YaccProduction') -> None:
134136
"""test : IDENTIFIER arguments"""
135137
# print("TEST:", p[1], p[2])
136138
tests = p[2].get('tests')
137-
handler = sifter.handler.get('test', p[1])
139+
handler = sifter.handler.ExtensionRegistry.get('test', p[1])
138140
if handler is None:
139141
print("No handler registered for test '%s' on line %d" % (p[1], p.lineno(1)))
140142
raise SyntaxError

sifter/grammar/rule.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,13 @@ class Rule(object):
3737
TESTS_MAX: Optional[int] = None
3838

3939
@classmethod
40-
def get_mapkey(cls):
40+
def handler_type(cls):
4141
return cls.RULE_TYPE
4242

4343
@classmethod
44-
def get_identifier(cls):
44+
def handler_id(cls):
4545
return cls.RULE_IDENTIFIER
4646

47-
@classmethod
48-
def register(cls) -> None:
49-
try:
50-
sifter.handler.register(cls.RULE_TYPE, cls.RULE_IDENTIFIER, cls)
51-
except AttributeError:
52-
# this method shouldn't be called on the Rule class directly,
53-
# only on subclasses that implement specific rules
54-
raise NotImplementedError
55-
5647
def __init__(
5748
self,
5849
arguments: Optional[List[Union['Tag', SupportsInt, List[Union[Text, 'String']]]]] = None,

sifter/handler.py

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,44 @@
1313
from sifter.grammar.comparator import Comparator
1414

1515

16-
_HANDLERS_MAP: Dict[Text, Dict[Text, Union[bool, Type['Comparator'], Type['Rule']]]] = {}
16+
class ExtensionRegistry():
1717

18+
_HANDLERS_MAP: Dict[Text, Dict[Text, Union[bool, Type['Comparator'], Type['Rule']]]] = {}
19+
DEFAULT_EXTENSION = [
20+
'regex',
21+
'comparator-i;ascii-casemap',
22+
'comparator-i;octet',
23+
'fileinto',
24+
]
1825

19-
def register(
20-
handler_type: Optional[Text],
21-
handler_id: Optional[Text],
22-
value: Union[bool, Type['Comparator'], Type['Rule']]
23-
) -> None:
24-
from sifter.grammar.rule import Rule
25-
from sifter.grammar.comparator import Comparator
26-
if not handler_type or not handler_id:
27-
raise ValueError("handler_type and handler_id must not be None!")
28-
if not isinstance(value, Rule) and not (isinstance(value, type) and issubclass(value, (Rule, Comparator))):
29-
print(type(value))
30-
_HANDLERS_MAP.setdefault(handler_type, {})[handler_id] = value
31-
else:
32-
for entry_point in pkg_resources.iter_entry_points('sifter_extensions'):
33-
if entry_point.name not in _HANDLERS_MAP:
34-
ext_cls = entry_point.load()
35-
_HANDLERS_MAP.setdefault(ext_cls.get_mapkey(), {})[ext_cls.get_identifier()] = ext_cls
36-
_HANDLERS_MAP[entry_point.name] = entry_point.load()
37-
26+
def __init__(self) -> None:
27+
for extension_name in self.DEFAULT_EXTENSION:
28+
self.register_extension(extension_name)
3829

39-
def unregister(handler_type: Text, handler_id: Text) -> Optional[Union[bool, Type['Comparator'], Type['Rule']]]:
40-
return _HANDLERS_MAP.get(handler_type, {}).pop(handler_id, None)
41-
42-
43-
def get(handler_type: Text, handler_id: Text) -> Optional[Union[bool, Type['Comparator'], Type['Rule']]]:
44-
return _HANDLERS_MAP.get(handler_type, {}).get(handler_id, None)
30+
for entry_point in pkg_resources.iter_entry_points('sifter_extensions'):
31+
self.register_handler(entry_point.load())
32+
33+
@classmethod
34+
def register_extension(cls, extension_name):
35+
cls.register('extension', extension_name, True)
36+
37+
@classmethod
38+
def register_handler(cls, ext_cls):
39+
cls.register(ext_cls.handler_type(), ext_cls.handler_id(), ext_cls)
40+
41+
@classmethod
42+
def register(
43+
cls,
44+
handler_type: Optional[Text],
45+
handler_id: Optional[Text],
46+
value: Union[bool, Type['Comparator'], Type['Rule']]
47+
) -> None:
48+
cls._HANDLERS_MAP.setdefault(handler_type, {})[handler_id] = value
49+
50+
@classmethod
51+
def unregister(cls, handler_type: Text, handler_id: Text) -> Optional[Union[bool, Type['Comparator'], Type['Rule']]]:
52+
return cls._HANDLERS_MAP.get(handler_type, {}).pop(handler_id, None)
53+
54+
@classmethod
55+
def get(cls, handler_type: Text, handler_id: Text) -> Optional[Union[bool, Type['Comparator'], Type['Rule']]]:
56+
return cls._HANDLERS_MAP.get(handler_type, {}).get(handler_id, None)

sifter/parser.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
TextIO
44
)
55

6-
import sifter.extensions.builtin # needed by the lexer
7-
import sifter.extensions.regex # needed by the lexer
6+
87
from sifter.grammar.grammar import SieveParser
98
from sifter.grammar.command_list import CommandList
109

0 commit comments

Comments
 (0)