rerouter

RegEx based router


Keywords
router, setuptools, development
License
MIT
Install
pip install rerouter==0.0.2

Documentation

A RegEx based router

rerouter routes string commands to annotated functions.

How to define the 'grammar':

"Grammar" is the pattern that tells rerouter which handler a string command should be routed to.

For example, github slack client supports slash commands like:

subscribe user/repo +label:"teams/designers" +label:"urgent"
subscribe user/repo commits:myBranch author:"hotfix"
close [issue link]
open [pull request link]

Suppose we want to build a router that routes various command to different handlers, we can do:

router = RegExRouter()


@router.route("subscribe <user_repo> [<option(+label|commits|author)>:<value>]+")
def handle_subscribe(rns, *args, **kwargs):
    """Handle commands like:

    subscribe user/repo +label:"teams/designers" +label:"urgent"
    subscribe user/repo commits:myBranch author:"hotfix"    
    """
    pass


@router.route("(close|open) [link:<link_url>]+")
def handle_open_close(rns, *args, **kwargs):
    """Handle commands like:
    
    close [issue link]
    open [pull request link]    
    """
    pass

More examples:

@router.route("settings (set|get|delete) project:<jira_project>")
def f_settings(rns, *args, **kwargs):
   """Matches:
   
   settings set project:TEST-PROJ
   settings get project:TEST-PROJ
   settings delete project:TEST-PROJ
   """
   pass


@router.routex(
    ("(subscribe)", ""),
    ("(?P<feature>reviews|pushes|checks)", ""),
    (
        "(?P<filter_name>[+-]path|[+-]fork|[+-]branch|[+-]reviewer):(?P<filter_value>[^:]+)",  # noqa
        "+",
    ),
)
def f_subscribe(rns):
   """Matches:
   
   subscribe reviews +path:foo/bar/* -fork:main/release +path:infra/tools/*
   subscribe pushes path:foo/bar/* fork:main/release path:infra/tools/*  
   """
   pass


@router.route("a+ b")
@router.route("a* c* b")
def f_abc(rns, *args, **kwargs):
   """Matches:
   
   aa
   ab
   aab
   aaab
   acb
   aacb
   cb
   ccb
   """
   pass

How to start routing:

This is done by calling the RegExRouter::route_to method, example:

router = RegExRouter()


@router.route("hello <user>")
def handle_subscribe(rns, *args, **kwargs):
    return rns.named("user")

res = router.route_to("hello world") # res == 'world'

Behind the scene, rerouter translates the routing syntax into a list of regex patterns, aka:

grammar: (close|open) [link:<link_url>]+
re patterns: 1. (close|open);
2. (link):(^(?P<{link_url}>[^:]+)$)

In the callback function, the rns is a RegExRouteMatch object which has the following properties:

  1. conclusion: bool: whether the grammar match the command. (for annotation use cases, this is always true)
  2. matches: a list of RegEx match objects, for example, command: close https://example.com will be routed to handle_open_close(...)and the matches will be
    1. <re.Match object, match='close'>
    2. <re.Match object, match='http://example.com''>
  3. grammar: the grammar which the command matches, in our example, its value is (close|open) [link:<link_url>]+