Created
February 18, 2018 06:29
-
-
Save s-c-p/d2475b282e04ef8b7c6951025c13b335 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
allows you to use switch case in python, like so | |
``` | |
... | |
x = 5 | |
... | |
... | |
with switch(x, locals()) as (case, default): | |
@case(4) | |
def _(): | |
return "not a match" | |
@case(5) | |
def _(): | |
return "yes, a match" | |
@default | |
def _(): | |
return None | |
``` | |
it is scope constrained (I hope it means what I think it means) and extensible | |
like you can include logging before function call and see my project teapy, for | |
which this was originally developed. | |
""" | |
import uuid | |
from contextlib import contextmanager | |
# import logging | |
# LOG_FORMAT = '%(asctime)-15s %(message)s' | |
# logging.basicConfig(filename='time-travel.log', format=LOG_FORMAT) | |
class SwitchError(RuntimeError): | |
pass | |
@contextmanager | |
def switch(switchable, returnNamespace): | |
# TODO: logging, ? use `logging.handler` to use sqlite | |
# DONE: duplicate-error | |
blocks = dict() | |
# there might be a scenario where case_val IS the string `default` | |
# to mitigate false positive in duplicate-default scan, we generate a | |
# random string as key for holding actual default's responder function | |
default_case = str(uuid.uuid4()) | |
blocks[default_case] = None | |
def case(case_val): | |
def decorator(func): | |
try: | |
blocks[case_val] | |
except KeyError: | |
blocks[case_val] = func # first assignment | |
else: # means key:value pair already existed | |
raise SwitchError("Repeated case: %s" % case_val) | |
return func | |
return decorator | |
def default(func): | |
if blocks[default_case] is None: | |
blocks[default_case] = func # first assignment | |
else: | |
raise SwitchError("Repeated default case") | |
return func | |
yield case, default | |
if blocks[default_case] is None: | |
raise SwitchError("you didn't handle the default clause of switch-case") | |
else: | |
defaultFn = blocks[default_case] | |
# execute the desired function | |
executeFn = blocks.get(switchable, defaultFn) | |
returnNamespace['switch_case_result'] = executeFn() | |
# logging.info("%s (%s) recieved with args-- %s", ???) | |
return | |
# tests ---------------------------------------------------------------------- | |
import pytest | |
def switch_example(x): | |
with switch(x, locals()) as (case, default): | |
@case(4) | |
def _(): | |
return "too less" | |
@case(5) | |
def _(): | |
return "yes" | |
@default | |
def _(): | |
return 'no match found' | |
return locals()['switch_case_result'] | |
def test_switch(): | |
assert switch_example(5) == "yes" | |
assert switch_example(4) == "too less" | |
assert switch_example('improbable case') == "no match found" | |
return | |
def test_switch__case_repeat(): | |
with pytest.raises(SwitchError) as exc: | |
x = str() | |
with switch(x, locals()) as (case, default): | |
@case('a') | |
def _(): | |
pass | |
@case('b') | |
def _(): | |
pass | |
@case('a') | |
def _(): | |
pass | |
@default | |
def _(): | |
pass | |
assert str(exc.value) == "Repeated case: a" | |
return | |
def test_switch__default_repeat(): | |
with pytest.raises(SwitchError) as exc: | |
x = str() | |
with switch(x, locals()) as (case, default): | |
@case('a') | |
def _(): | |
pass | |
@case('b') | |
def _(): | |
pass | |
@default | |
def _(): | |
print('nice day') | |
@default | |
def _(): | |
pass | |
assert str(exc.value) == "Repeated default case" | |
return | |
def test_switch__default_clause_missing(): | |
with pytest.raises(SwitchError) as exc: | |
x = str() | |
with switch(x, locals()) as (case, default): | |
@case('a') | |
def _(): | |
pass | |
@case('b') | |
def _(): | |
pass | |
assert str(exc.value) == "you didn't handle the default clause of switch-case" | |
return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment