def __init__(self, local_node): VisitorRoute.__init__(self) self.__local_node = local_node self.__router = Router(local_node) self.__reflector = RouterReflect() self.debugging = 0
class RouterVisitor(VisitorRoute): def __init__(self, local_node): VisitorRoute.__init__(self) self.__local_node = local_node self.__router = Router(local_node) self.__reflector = RouterReflect() self.debugging = 0 # Every method in this class should return a list of pair (destination, message) # The destination is a class 'Node' and the message is a (sub)class of 'RouteMessage'. def visit_RouteDirect(self, message): if (self.debugging & 1): import pdb pdb.set_trace() return self.__router.route_directly(message) def visit_RouteByNameID(self, message): if (self.debugging & 2): import pdb pdb.set_trace() return self.__router.route_by_name(message) def visit_RouteByNumericID(self, message): if (self.debugging & 4): import pdb pdb.set_trace() return self.__router.route_by_numeric(message) def visit_RouteByPayload(self, message): if (self.debugging & 8): import pdb pdb.set_trace() return message.route(self.__local_node) def visit_RouteByCPE(self, message): # message ISA RouteByCPE # payload ISA ApplicationMessage assert (message.space_part.first_component().value != None), ( "message %s has invalid spacepart (no component value for %s)" % (repr(message), repr(message.space_part.first_component()))) if (self.debugging & 16): import pdb pdb.set_trace() if (not message.forking): return self.__reflector.by_cpe_get_next_hop_insertion( self.__local_node, message) else: return self.__reflector.by_cpe_get_next_hop_forking( self.__local_node, message) # MessageDispatcher.dispatch() will be happy with a list of <neighbour, message> def __repr__(self): return "<RouterVisitor:" + repr(self.__reflector.trace) + ">" @property def trace(self): return self.__reflector.trace
def test_route(begin, end): network = load_network() router = Router(network) path = router.enroute(network.node(begin), network.node(end)) if path is None: print 'Cannot find path between %s and %s' % (begin, end) else: print path
def get(self): origin = self.request.get('origin') destination = self.request.get('destination') if origin is None or destination is None: self.send_json({'status': 'fail'}) else: router = Router(test_routing.load_network()) path = Path.as_geojson(router.enroute(origin, destination)) self.send_json(path)
def getSafestRoutes(): tolat = float(request.args["tolat"]) tolon = float(request.args["tolon"]) fromlat = float(request.args["fromlat"]) fromlon = float(request.args["fromlon"]) fromLoc = {'lat': fromlat, 'lng': fromlon} toLoc = {'lat': tolat, 'lng': tolon} r = Router(fromLoc, toLoc) print(json.dumps(r.getRoutes())) return json.dumps(r.getRoutes())
class RouterVisitor(VisitorRoute): def __init__(self, local_node): VisitorRoute.__init__(self) self.__local_node = local_node self.__router = Router(local_node) self.__reflector = RouterReflect() self.debugging=0 # Every method in this class should return a list of pair (destination, message) # The destination is a class 'Node' and the message is a (sub)class of 'RouteMessage'. def visit_RouteDirect(self, message): if (self.debugging&1): import pdb; pdb.set_trace() return self.__router.route_directly(message) def visit_RouteByNameID(self, message): if (self.debugging&2): import pdb; pdb.set_trace() return self.__router.route_by_name(message) def visit_RouteByNumericID(self, message): if (self.debugging&4): import pdb; pdb.set_trace() return self.__router.route_by_numeric(message) def visit_RouteByPayload(self, message): if (self.debugging&8): import pdb; pdb.set_trace() return message.route(self.__local_node) def visit_RouteByCPE(self, message): # message ISA RouteByCPE # payload ISA ApplicationMessage assert (message.space_part.first_component().value != None),( "message %s has invalid spacepart (no component value for %s)"% (repr(message),repr(message.space_part.first_component()))) if (self.debugging&16): import pdb; pdb.set_trace() if (not message.forking): return self.__reflector.by_cpe_get_next_hop_insertion(self.__local_node, message) else: return self.__reflector.by_cpe_get_next_hop_forking(self.__local_node, message) # MessageDispatcher.dispatch() will be happy with a list of <neighbour, message> def __repr__(self): return "<RouterVisitor:"+repr(self.__reflector.trace)+">" @property def trace(self): return self.__reflector.trace
def decide_side_join(self, message): ln = self.__local_node nb = ln.neighbourhood lname = ln.name_id jname = message.joining_node.name_id side = Router.by_name_get_direction(lname, jname) nextn = nb.get_neighbour(side,0,jname) othern= nb.get_neighbour(not side,0,jname) wrapf = nb.can_wrap(side,jname) # wrap forwards wrapb = nb.can_wrap(not side,jname) # wrap backwards if (nextn.name_id == jname): hring = nb.get_ring(0).get_side(side) if hring.size<2: return side,ln # there isn't enough neighbours yet. nextn=hring.get_neighbours()[1] # skip new-comer if (not NodeID.lies_between_direction(side, lname, jname, nextn.name_id, wrapf)): ln.sign("need to reverse side %s-%s-%s %s!"%(lname, jname, nextn.name_id,repr(wrapf))) if (othern.name_id==jname): hring = nb.get_ring(0).get_side(not side) if hring.size<2: return not side, ln othern=hring.get_neighbours()[1] #skip new-comer if(not NodeID.lies_between_direction(not side, lname, jname, othern.name_id, wrapb)): LOGGER.debug("?_? node %s shouldn't have received %s (%s ; %s)?_?"%( ln,message.trace,othern.pname,repr(wrapb))) print(">_< debugging") import pdb; pdb.set_trace() print("<_> resuming") side = not side nextn= othern return side, nextn
def __init__(self, local_node): VisitorRoute.__init__(self) self.__local_node = local_node self.__router = Router(local_node) self.__reflector = RouterReflect() self.debugging=0
def __init__(self, **kwargs): #: A :class:`ConfigDict` for app specific configuration. self.config = self._global_config._make_overlay() self.config._add_change_listener( functools.partial(self.trigger_hook, 'config')) self.config.update({ "catchall": True }) if kwargs.get('catchall') is False: depr(0, 13, "Bottle(catchall) keyword argument.", "The 'catchall' setting is now part of the app " "configuration. Fix: `app.config['catchall'] = False`") self.config['catchall'] = False if kwargs.get('autojson') is False: depr(0, 13, "Bottle(autojson) keyword argument.", "The 'autojson' setting is now part of the app " "configuration. Fix: `app.config['json.enable'] = False`") self.config['json.disable'] = True self._mounts = [] #: A :class:`ResourceManager` for application files self.resources = ResourceManager() self.routes = [] # List of installed :class:`Route` instances. self.router = Router() # Maps requests to :class:`Route` instances. self.error_handler = {} # Core plugins self.plugins = [] # List of installed plugins. self.install(JSONPlugin()) self.install(TemplatePlugin())
def test_routing_cases(self): router = Router('tests/data/test_case_1.csv') cases = [('A', 'A', 0, 0), ('A', 'B', 0, 5), ('A', 'C', 1, 10), ('E', 'J', 2, 30), ('A', 'D', 0, 15), ('H', 'I', 0, 10), ('A', 'J', None), ('C', 'G', None)] for case in cases: self._test_routing_case(case, router, self)
def main(args) -> int: try: print("TrainRoutes CLI Started") print(f'Loading routes from {args.routes_file}') router = Router(args.routes_file) print('Routes loaded') # Support non-interactive origin/dest args origin = args.origin dest = args.dest start_cli_loop(router, origin, dest) except Exception as ex: print(ex, file=sys.stderr) return 1
def start_cli_loop(router: Router, origin: str = None, dest: str = None): interactive = not origin and not dest first_time = True while interactive or first_time: first_time = False # block until origin is valid while not router.has_station(origin): if origin: print(f'Station "{origin}" not found') origin = input('Enter Origin Station: ') # block until dest is valid while not router.has_station(dest): if dest: print(f'Station "{dest}" not found') dest = input('Enter Destination Station: ') print('Routing...') try: route = router.find_route(origin, dest) if route is None: print(f'Result: No routes from {origin} to {dest}') else: print( f'Result: {route.stop_count} stop(s), {route.total_time} minute(s)' ) print( f'Details: {", ".join([str(seg) for seg in route.path])}') except Exception as ex: print(ex, file=sys.stderr) origin = dest = None return 0
def decide_side_join(self, message): ln = self.__local_node nb = ln.neighbourhood lname = ln.name_id jname = message.joining_node.name_id side = Router.by_name_get_direction(lname, jname) nextn = nb.get_neighbour(side, 0, jname) othern = nb.get_neighbour(not side, 0, jname) wrapf = nb.can_wrap(side, jname) # wrap forwards wrapb = nb.can_wrap(not side, jname) # wrap backwards if (nextn.name_id == jname): hring = nb.get_ring(0).get_side(side) if hring.size < 2: return side, ln # there isn't enough neighbours yet. nextn = hring.get_neighbours()[1] # skip new-comer if (not NodeID.lies_between_direction(side, lname, jname, nextn.name_id, wrapf)): ln.sign("need to reverse side %s-%s-%s %s!" % (lname, jname, nextn.name_id, repr(wrapf))) if (othern.name_id == jname): hring = nb.get_ring(0).get_side(not side) if hring.size < 2: return not side, ln othern = hring.get_neighbours()[1] #skip new-comer if (not NodeID.lies_between_direction(not side, lname, jname, othern.name_id, wrapb)): LOGGER.debug( "?_? node %s shouldn't have received %s (%s ; %s)?_?" % (ln, message.trace, othern.pname, repr(wrapb))) print(">_< debugging") import pdb pdb.set_trace() print("<_> resuming") side = not side nextn = othern return side, nextn
def getRandomLocation(): return { 'lat': uniform(52.42252295423907, 54.00776876193478), 'lng': uniform(-9.041748046875002, -6.470947265625) } sumdecrease = 0 counter = 0 sumLength = 0 sumTime = 0 for index in range(50): location1 = getRandomLocation() location2 = getRandomLocation() router = Router(location1, location2) routes = [] response = router.routeApi() locationObjects = response['response']['route'][0]['leg'][0]['maneuver'] lengthFastest = response['response']['route'][0]['leg'][0]['length'] travelTimeFastest = response['response']['route'][0]['leg'][0][ 'travelTime'] router.names = getLocNames(locationObjects) locationJson = router.locationsToJsonRoute(locationObjects) routes.append(locationJson) average1 = router.getAverageCovid(locationObjects) bboxstr = router.getBboxString(locationObjects) response1 = router.routeApi(bboxstr=bboxstr) secondRoute = response1['response']['route'][0]['leg'][0]['maneuver']
def setUp(self): self._sink = TestSink() self._router = Router(default_sink=self._sink) self._faucet = TestFaucet() self._router.add_faucet(self._faucet, name="test")
class RouterTest(unittest.TestCase): _router = None _sink = None _faucet = None def setUp(self): self._sink = TestSink() self._router = Router(default_sink=self._sink) self._faucet = TestFaucet() self._router.add_faucet(self._faucet, name="test") def test_tick(self): self._router.tick() def test_default_sink(self): message = {"from": {"media": "test"}, "message": "test"} self._faucet.create_message(message) self._router.tick() self.assertEquals(self._sink.messages, [message]) def test_no_message(self): faucet = TestFaucet() self._router.add_faucet(faucet, name="empty") self._router.tick() # most important is that this doesn't raise any exceptions self.assertEquals(self._sink.messages, []) def test_add_sink(self): rule = Rule(target="sink", media="telegram", user="******") sink = TestSink() message1 = {"from": {"media": "test"}, "message": "test"} message2 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } message3 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } message4 = {"from": {"media": "test"}, "to": "sink", "message": "test"} self._router.add_sink(sink, name="sink") self._router.add_rule(rule, faucet_name="test") for message in (message1, message2, message3, message4): self._faucet.create_message(message) self._router.tick() self.assertEqual(self._sink.messages, [message1, message3]) self.assertEqual(sink.messages, [message2, message4]) def test_message_with_to_but_sink_not_present(self): message = { "from": { "media": "test" }, "to": "inexistent", "message": "test" } self._faucet.create_message(message) self._router.tick() self.assertEqual(self._sink.messages, [message]) def test_more_specific_rule_has_priority(self): rule1 = Rule(target="sink1", media="telegram", user="******") rule2 = Rule(target="sink2", media="telegram") rule3 = Rule(target="sink3", media="telegram", user="******") for rule in (rule1, rule2, rule3): self._router.add_rule(rule, faucet_name="test") sinks = [] for name in ("sink1", "sink2", "sink3"): sinks.append(TestSink()) self._router.add_sink(sinks[-1], name=name) message1 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } message2 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } message3 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } for message in (message1, message2, message3): self._faucet.create_message(message) self._router.tick() self.assertEqual(sinks[0].messages, [message1]) self.assertEqual(sinks[1].messages, [message2]) self.assertEqual(sinks[2].messages, [message3]) def test_remove_faucet(self): self._router.remove_faucet("test") self._faucet.create_message({ "from": { "media": "test" }, "message": "test" }) self._router.tick() self.assertEqual(self._sink.messages, []) def test_remove_faucet_object(self): self._router.remove_faucet(self._faucet) self._faucet.create_message({ "from": { "media": "test" }, "message": "test" }) self._router.tick() self.assertEqual(self._sink.messages, []) def test_remove_sink(self): self._router.add_sink(TestSink(), "sink") self._router.add_rule(Rule(target="sink", media="test"), faucet_name="test") self._router.remove_sink("sink") message = {"from": {"media": "test"}, "message": "test"} self._faucet.create_message(message) self._router.tick() self.assertEqual(self._sink.messages, [message]) def test_remove_sink_object(self): sink = TestSink() self._router.add_sink(sink, "sink") self._router.add_rule(Rule(target="sink", media="test"), faucet_name="test") self._router.remove_sink(sink) message = {"from": {"media": "test"}, "message": "test"} self._faucet.create_message(message) self._router.tick() self.assertEqual(self._sink.messages, [message]) def test_choice_rule(self): sink1 = TestSink() sink2 = TestSink() self._router.add_sink(sink1, "sink1") self._router.add_sink(sink2, "sink2") self._router.add_rule(TestChoiceRule("sink"), faucet_name="test") message1 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } message2 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } message3 = { "from": { "media": "telegram", "user": "******" }, "message": "test" } for message in (message1, message2, message3): self._faucet.create_message(message) self._router.tick() self.assertEqual(sink1.messages, [message1]) self.assertEqual(sink2.messages, [message2]) self.assertEqual(self._sink.messages, [message3]) def test_sink_factory(self): from unittest.mock import MagicMock self._router.add_rule(Rule(target="sink"), faucet_name="test") sink = TestSink() def callback(router, name): router.add_sink(sink, name) router.add_faucet(TestFaucet(), name) factory = MagicMock(side_effect=callback) self._router.add_sink_factory(factory) message = {"from": {"media": "test"}, "message": "test"} self._faucet.create_message(message) self._router.tick() self.assertEqual(self._sink.messages, []) self.assertEqual(sink.messages, [message]) factory.assert_called_once_with(self._router, "sink")
def __init__(self, request, client_address, server): self.router = Router() self.router.register_routes(routes) super().__init__(request, client_address, server)
class Handler(BaseHTTPRequestHandler): def __init__(self, request, client_address, server): self.router = Router() self.router.register_routes(routes) super().__init__(request, client_address, server) def do_GET(self): self.router.handle(request=self) return def do_POST(self): self.router.handle(request=self) return def do_PUT(self): self.router.handle(request=self) return def do_PATCH(self): self.router.handle(request=self) return def do_DELETE(self): self.router.handle(request=self) return def do_OPTIONS(self): self.router.handle(request=self) return def do_HEAD(self): self.router.handle(request=self) return
def test_error_handling(self): router = Router('tests/data/test_case_1.csv') self.assertRaises(InvalidStationError, lambda: router.find_route('A', 'Z')) self.assertRaises(InvalidStationError, lambda: router.find_route(None, ''))
def test_initialization(self): self.assertRaises(FileNotFoundError, lambda: Router('non_existent_file.csv')) self.assertRaises(IsADirectoryError, lambda: Router('tests/data')) self.assertRaises(InvalidRecordError, lambda: Router('tests/data/invalid_file.csv'))
def geojson_test(begin='Cuatro Caminos', end='Juanacatlan'): network = load_network() router = Router(network) path = router.enroute(network.node(begin), network.node(end)) print Path.as_geojson(path)
from routing import Router router = Router() router.fromPicture("./img4s.jpg") router.build() router.simulation()
class Bottle(object): """ Each Bottle object represents a single, distinct web application and consists of routes, callbacks, plugins, resources and configuration. Instances are callable WSGI applications. :param catchall: If true (default), handle all exceptions. Turn off to let debugging middleware handle exceptions. """ @lazy_attribute def _global_config(cls): cfg = ConfigDict() cfg.meta_set('catchall', 'validate', bool) return cfg def __init__(self, **kwargs): #: A :class:`ConfigDict` for app specific configuration. self.config = self._global_config._make_overlay() self.config._add_change_listener( functools.partial(self.trigger_hook, 'config')) self.config.update({ "catchall": True }) if kwargs.get('catchall') is False: depr(0, 13, "Bottle(catchall) keyword argument.", "The 'catchall' setting is now part of the app " "configuration. Fix: `app.config['catchall'] = False`") self.config['catchall'] = False if kwargs.get('autojson') is False: depr(0, 13, "Bottle(autojson) keyword argument.", "The 'autojson' setting is now part of the app " "configuration. Fix: `app.config['json.enable'] = False`") self.config['json.disable'] = True self._mounts = [] #: A :class:`ResourceManager` for application files self.resources = ResourceManager() self.routes = [] # List of installed :class:`Route` instances. self.router = Router() # Maps requests to :class:`Route` instances. self.error_handler = {} # Core plugins self.plugins = [] # List of installed plugins. self.install(JSONPlugin()) self.install(TemplatePlugin()) #: If true, most exceptions are caught and returned as :exc:`HTTPError` catchall = DictProperty('config', 'catchall') __hook_names = 'before_request', 'after_request', 'app_reset', 'config' __hook_reversed = {'after_request'} @cached_property def _hooks(self): return dict((name, []) for name in self.__hook_names) def add_hook(self, name, func): """ Attach a callback to a hook. Three hooks are currently implemented: before_request Executed once before each request. The request context is available, but no routing has happened yet. after_request Executed once after each request regardless of its outcome. app_reset Called whenever :meth:`Bottle.reset` is called. """ if name in self.__hook_reversed: self._hooks[name].insert(0, func) else: self._hooks[name].append(func) def remove_hook(self, name, func): """ Remove a callback from a hook. """ if name in self._hooks and func in self._hooks[name]: self._hooks[name].remove(func) return True def trigger_hook(self, __name, *args, **kwargs): """ Trigger a hook and return a list of results. """ return [hook(*args, **kwargs) for hook in self._hooks[__name][:]] def hook(self, name): """ Return a decorator that attaches a callback to a hook. See :meth:`add_hook` for details.""" def decorator(func): self.add_hook(name, func) return func return decorator def _mount_wsgi(self, prefix, app, **options): segments = [p for p in prefix.split('/') if p] if not segments: raise ValueError('WSGI applications cannot be mounted to "/".') path_depth = len(segments) def mountpoint_wrapper(): try: request.path_shift(path_depth) rs = HTTPResponse([]) def start_response(status, headerlist, exc_info=None): if exc_info: _raise(*exc_info) rs.status = status for name, value in headerlist: rs.add_header(name, value) return rs.body.append body = app(request.environ, start_response) rs.body = itertools.chain(rs.body, body) if rs.body else body return rs finally: request.path_shift(-path_depth) options.setdefault('skip', True) options.setdefault('method', 'PROXY') options.setdefault('mountpoint', {'prefix': prefix, 'target': app}) options['callback'] = mountpoint_wrapper self.route('/%s/<:re:.*>' % '/'.join(segments), **options) if not prefix.endswith('/'): self.route('/' + '/'.join(segments), **options) def _mount_app(self, prefix, app, **options): if app in self._mounts or '_mount.app' in app.config: depr(0, 13, "Application mounted multiple times. Falling back to WSGI mount.", "Clone application before mounting to a different location.") return self._mount_wsgi(prefix, app, **options) if options: depr(0, 13, "Unsupported mount options. Falling back to WSGI mount.", "Do not specify any route options when mounting bottle application.") return self._mount_wsgi(prefix, app, **options) if not prefix.endswith("/"): depr(0, 13, "Prefix must end in '/'. Falling back to WSGI mount.", "Consider adding an explicit redirect from '/prefix' to '/prefix/' in the parent application.") return self._mount_wsgi(prefix, app, **options) self._mounts.append(app) app.config['_mount.prefix'] = prefix app.config['_mount.app'] = self for route in app.routes: route.rule = prefix + route.rule.lstrip('/') self.add_route(route) def mount(self, prefix, app, **options): """ Mount an application (:class:`Bottle` or plain WSGI) to a specific URL prefix. Example:: parent_app.mount('/prefix/', child_app) :param prefix: path prefix or `mount-point`. :param app: an instance of :class:`Bottle` or a WSGI application. Plugins from the parent application are not applied to the routes of the mounted child application. If you need plugins in the child application, install them separately. While it is possible to use path wildcards within the prefix path (:class:`Bottle` childs only), it is highly discouraged. The prefix path must end with a slash. If you want to access the root of the child application via `/prefix` in addition to `/prefix/`, consider adding a route with a 307 redirect to the parent application. """ if not prefix.startswith('/'): raise ValueError("Prefix must start with '/'") if isinstance(app, Bottle): return self._mount_app(prefix, app, **options) else: return self._mount_wsgi(prefix, app, **options) def merge(self, routes): """ Merge the routes of another :class:`Bottle` application or a list of :class:`Route` objects into this application. The routes keep their 'owner', meaning that the :data:`Route.app` attribute is not changed. """ if isinstance(routes, Bottle): routes = routes.routes for route in routes: self.add_route(route) def install(self, plugin): """ Add a plugin to the list of plugins and prepare it for being applied to all routes of this application. A plugin may be a simple decorator or an object that implements the :class:`Plugin` API. """ if hasattr(plugin, 'setup'): plugin.setup(self) if not callable(plugin) and not hasattr(plugin, 'apply'): raise TypeError("Plugins must be callable or implement .apply()") self.plugins.append(plugin) self.reset() return plugin def uninstall(self, plugin): """ Uninstall plugins. Pass an instance to remove a specific plugin, a type object to remove all plugins that match that type, a string to remove all plugins with a matching ``name`` attribute or ``True`` to remove all plugins. Return the list of removed plugins. """ removed, remove = [], plugin for i, plugin in list(enumerate(self.plugins))[::-1]: if remove is True or remove is plugin or remove is type(plugin) \ or getattr(plugin, 'name', True) == remove: removed.append(plugin) del self.plugins[i] if hasattr(plugin, 'close'): plugin.close() if removed: self.reset() return removed def reset(self, route=None): """ Reset all routes (force plugins to be re-applied) and clear all caches. If an ID or route object is given, only that specific route is affected. """ if route is None: routes = self.routes elif isinstance(route, Route): routes = [route] else: routes = [self.routes[route]] for route in routes: route.reset() if DEBUG: for route in routes: route.prepare() self.trigger_hook('app_reset') def close(self): """ Close the application and all installed plugins. """ for plugin in self.plugins: if hasattr(plugin, 'close'): plugin.close() def run(self, **kwargs): """ Calls :func:`run` with the same parameters. """ run(self, **kwargs) def match(self, environ): """ Search for a matching route and return a (:class:`Route` , urlargs) tuple. The second value is a dictionary with parameters extracted from the URL. Raise :exc:`HTTPError` (404/405) on a non-match.""" return self.router.match(environ) def get_url(self, routename, **kargs): """ Return a string that matches a named route """ scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/' location = self.router.build(routename, **kargs).lstrip('/') return urljoin(urljoin('/', scriptname), location) def add_route(self, route): """ Add a route object, but do not change the :data:`Route.app` attribute.""" self.routes.append(route) self.router.add(route.rule, route.method, route, name=route.name) if DEBUG: route.prepare() def route(self, path=None, method='GET', callback=None, name=None, apply=None, skip=None, **config): """ A decorator to bind a function to a request URL. Example:: @app.route('/hello/<name>') def hello(name): return 'Hello %s' % name The ``<name>`` part is a wildcard. See :class:`Router` for syntax details. :param path: Request path or a list of paths to listen to. If no path is specified, it is automatically generated from the signature of the function. :param method: HTTP method (`GET`, `POST`, `PUT`, ...) or a list of methods to listen to. (default: `GET`) :param callback: An optional shortcut to avoid the decorator syntax. ``route(..., callback=func)`` equals ``route(...)(func)`` :param name: The name for this route. (default: None) :param apply: A decorator or plugin or a list of plugins. These are applied to the route callback in addition to installed plugins. :param skip: A list of plugins, plugin classes or names. Matching plugins are not installed to this route. ``True`` skips all. Any additional keyword arguments are stored as route-specific configuration and passed to plugins (see :meth:`Plugin.apply`). """ if callable(path): path, callback = None, path plugins = makelist(apply) skiplist = makelist(skip) def decorator(callback): if isinstance(callback, str): callback = load(callback) for rule in makelist(path) or yieldroutes(callback): for verb in makelist(method): verb = verb.upper() route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config) self.add_route(route) return callback return decorator(callback) if callback else decorator def get(self, path=None, method='GET', **options): """ Equals :meth:`route`. """ return self.route(path, method, **options) def post(self, path=None, method='POST', **options): """ Equals :meth:`route` with a ``POST`` method parameter. """ return self.route(path, method, **options) def put(self, path=None, method='PUT', **options): """ Equals :meth:`route` with a ``PUT`` method parameter. """ return self.route(path, method, **options) def delete(self, path=None, method='DELETE', **options): """ Equals :meth:`route` with a ``DELETE`` method parameter. """ return self.route(path, method, **options) def patch(self, path=None, method='PATCH', **options): """ Equals :meth:`route` with a ``PATCH`` method parameter. """ return self.route(path, method, **options) def error(self, code=500, callback=None): """ Register an output handler for a HTTP error code. Can be used as a decorator or called directly :: def error_handler_500(error): return 'error_handler_500' app.error(code=500, callback=error_handler_500) @app.error(404) def error_handler_404(error): return 'error_handler_404' """ def decorator(callback): if isinstance(callback, str): callback = load(callback) self.error_handler[int(code)] = callback return callback return decorator(callback) if callback else decorator def default_error_handler(self, res): return bytes(template(ERROR_PAGE_TEMPLATE, e=res, template_settings=dict(name='__ERROR_PAGE_TEMPLATE'))) def _handle(self, environ): path = environ['bottle.raw_path'] = environ['PATH_INFO'] environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore') environ['bottle.app'] = self request.bind(environ) response.bind() try: while True: # Remove in 0.14 together with RouteReset out = None try: self.trigger_hook('before_request') route, args = self.router.match(environ) environ['route.handle'] = route environ['bottle.route'] = route environ['route.url_args'] = args out = route.call(**args) break except HTTPResponse as E: out = E break except RouteReset: depr(0, 13, "RouteReset exception deprecated", "Call route.call() after route.reset() and " "return the result.") route.reset() continue finally: if isinstance(out, HTTPResponse): out.apply(response) try: self.trigger_hook('after_request') except HTTPResponse as E: out = E out.apply(response) except (KeyboardInterrupt, SystemExit, MemoryError): raise except Exception as E: if not self.catchall: raise stacktrace = format_exc() environ['wsgi.errors'].write(stacktrace) environ['wsgi.errors'].flush() out = HTTPError(500, "Internal Server Error", E, stacktrace) out.apply(response) return out def _cast(self, out, peek=None): """ Try to convert the parameter into something WSGI compatible and set correct HTTP headers when possible. Support: False, str, unicode, dict, HTTPResponse, HTTPError, file-like, iterable of strings and iterable of unicodes """ # Empty output is done here if not out: if 'Content-Length' not in response: response['Content-Length'] = 0 return [] # Join lists of byte or unicode strings. Mixed lists are NOT supported if isinstance(out, (tuple, list))\ and isinstance(out[0], (bytes, str)): out = out[0][0:0].join(out) # b'abc'[0:0] -> b'' # Encode unicode strings if isinstance(out, str): out = out.encode(response.charset) # Byte Strings are just returned if isinstance(out, bytes): if 'Content-Length' not in response: response['Content-Length'] = len(out) return [out] # HTTPError or HTTPException (recursive, because they may wrap anything) # TODO: Handle these explicitly in handle() or make them iterable. if isinstance(out, HTTPError): out.apply(response) out = self.error_handler.get(out.status_code, self.default_error_handler)(out) return self._cast(out) if isinstance(out, HTTPResponse): out.apply(response) return self._cast(out.body) # File-like objects. if hasattr(out, 'read'): if 'wsgi.file_wrapper' in request.environ: return request.environ['wsgi.file_wrapper'](out) elif hasattr(out, 'close') or not hasattr(out, '__iter__'): return WSGIFileWrapper(out) # Handle Iterables. We peek into them to detect their inner type. try: iout = iter(out) first = next(iout) while not first: first = next(iout) except StopIteration: return self._cast('') except HTTPResponse as E: first = E except (KeyboardInterrupt, SystemExit, MemoryError): raise except Exception as error: if not self.catchall: raise first = HTTPError(500, 'Unhandled exception', error, format_exc()) # These are the inner types allowed in iterator or generator objects. if isinstance(first, HTTPResponse): return self._cast(first) elif isinstance(first, bytes): new_iter = itertools.chain([first], iout) elif isinstance(first, str): encoder = lambda x: x.encode(response.charset) new_iter = map(encoder, itertools.chain([first], iout)) else: msg = 'Unsupported response type: %s' % type(first) return self._cast(HTTPError(500, msg)) if hasattr(out, 'close'): new_iter = _closeiter(new_iter, out.close) return new_iter def wsgi(self, environ, start_response): """ The bottle WSGI-interface. """ try: out = self._cast(self._handle(environ)) # rfc2616 section 4.3 if response._status_code in (100, 101, 204, 304)\ or environ['REQUEST_METHOD'] == 'HEAD': if hasattr(out, 'close'): out.close() out = [] start_response(response._status_line, response.headerlist) return out except (KeyboardInterrupt, SystemExit, MemoryError): raise except Exception as E: if not self.catchall: raise err = '<h1>Critical error while processing request: %s</h1>' \ % html_escape(environ.get('PATH_INFO', '/')) if DEBUG: err += '<h2>Error:</h2>\n<pre>\n%s\n</pre>\n' \ '<h2>Traceback:</h2>\n<pre>\n%s\n</pre>\n' \ % (html_escape(repr(E)), html_escape(format_exc())) environ['wsgi.errors'].write(err) environ['wsgi.errors'].flush() headers = [('Content-Type', 'text/html; charset=UTF-8')] start_response('500 INTERNAL SERVER ERROR', headers, sys.exc_info()) return [bytes(err)] def __call__(self, environ, start_response): """ Each instance of :class:'Bottle' is a WSGI application. """ return self.wsgi(environ, start_response) def __enter__(self): """ Use this application as default for all module-level shortcuts. """ default_app.push(self) return self def __exit__(self, exc_type, exc_value, traceback): default_app.pop() def __setattr__(self, name, value): if name in self.__dict__: raise AttributeError("Attribute %s already defined. Plugin conflict?" % name) self.__dict__[name] = value
import ujson from state import State import util from routing import Router, Route import network import sensor from state import State router = Router() @Route(endpoint='/setup', methods=['GET']) def get_setup_page(request): response = open('static\\setup.html', 'r').read() return response @Route(endpoint='/sensor', methods=['GET']) def get_sensor_page(request): response = open('static\\sensor.html', 'r').read() return response @Route(endpoint='/', methods=['GET']) def get_index(request): response = open('static\\index.html', 'r').read() return response @Route(endpoint='/api/accesspoints', methods=['GET'])
""" Lambda example with external dependency """ import sys sys.path.insert(0, "./lib") import logging from parsing import EventParser from routing import Router logger = logging.getLogger() logger.setLevel(logging.INFO) parser = EventParser() router = Router() def handle(event, context): file = parser.parse(event, 's3') logger.info(f'Routing {file.full_path}...') try: router.route(file) except Exception as e: return logger.error(f'Failed routing {file.full_path}. Exception: {e}') return logger.info(f'Successfully routed {file.full_path}')
from routing import Router all_benchmarks = [ 'example', 'impossible', 'impossible2', 'kuma', 'misty', 'oswald', 'rusty', 'stanley', 'stdcell', 'sydney', 'temp', 'wavy' ] if __name__ == '__main__': for benchmark in all_benchmarks: router = Router('benchmarks/'+benchmark+'.infile') router.routeAll() print('benchmark {}: {} / {} segments routed!'.format(benchmark, router.best_total_segments, router.total_possible_segments))