flet_navigator
A minimalist module for navigation in Flet that combines speed and simplicity.
- 3.11.12: Generic + safety update.
The version of the Flet Navigator.
A constant string representing the 404 route type.
Used to specify a custom route for handling 404 errors (Page Not Found) in applications. This can be customized for routing or error handling purposes.
An alias for a page-transferring arguments.
An alias for a page definition.
An alias for a template definition.
An alias for a route change callback.
An alias for a routes map.
An alias for a route parameters map.
An alias for a route properties map.
88class RouteContext: 89 """Route context class used for transferring data between routes and providing Navigator shortcuts.""" 90 91 page: Page = None 92 """The current page instance.""" 93 94 navigator: Union['PublicFletNavigator', 'VirtualFletNavigator'] = None 95 """The navigator that created this RouteContext instance.""" 96 97 arguments: Arguments = None 98 """Arguments passed from the previous page for context.""" 99 100 parameters: 'RouteParameters' = None 101 """URL parameters associated with the current route.""" 102 103 route_id: tuple[int, str] = None 104 """The unique identifier for this page.""" 105 106 def __init__(self, page: Page, navigator: Union['PublicFletNavigator', 'VirtualFletNavigator'], arguments: Arguments, parameters: 'RouteParameters', route_id: tuple[int, str]) -> None: 107 """Initialize a RouteContext instance.""" 108 self.page = page 109 110 self.navigator = navigator 111 112 self.arguments = arguments 113 114 self.parameters = parameters 115 116 self.route_id = route_id 117 118 def add(self, *controls: Control) -> None: 119 """Add one or more controls to the current page.""" 120 self.page.add(*controls) 121 122 def navigate(self, route: str, args: Arguments=(), **parameters: RouteParameters) -> None: 123 """Navigate to a specific route. If the navigator is virtual, parameters are not used.""" 124 if self.navigator.is_virtual(): 125 self.navigator.navigate(route, self.page, args) 126 127 else: 128 self.navigator.navigate(route, self.page, args, parameters) 129 130 def navigate_homepage(self, args: Arguments=(), **parameters: RouteParameters) -> None: 131 """Navigate to the homepage. If the navigator is virtual, parameters are not used.""" 132 if self.navigator.is_virtual(): 133 self.navigator.navigate_homepage(self.page, args) 134 135 else: 136 self.navigator.navigate_homepage(self.page, args, parameters) 137 138 def navigate_back(self, args: Arguments=(), **parameters: RouteParameters) -> None: 139 """Navigate back to the previous route. If the navigator is virtual, parameters are not used.""" 140 if self.navigator.is_virtual(): 141 self.navigator.navigate_back(self.page, args) 142 143 else: 144 self.navigator.navigate_back(self.page, args, parameters) 145 146 def set_homepage(self, homepage: str) -> None: 147 """Update navigator's homepage address.""" 148 self.navigator.set_homepage(homepage) 149 150 def spec_cpage_props(self, **props: dict[str, Any]) -> None: 151 """Specify current page properties.""" 152 self.navigator.props_map[self.route_id] = props 153 154 AbstractFletNavigator.proc_page_props(self.page, props, ()) 155 156 self.page.update() 157 158 def current_route(self) -> str: 159 """Get the navigator's current route state.""" 160 return self.navigator.route 161 162 def __repr__(self) -> str: 163 """Represent the RouteContext instance as a string for debugging purposes.""" 164 return f'{self.previous_page} -> {self.navigator.route} [{"NO-ARGUMENTS" if not self.arguments else self.arguments}, {"NO-PARAMETERS" if len(self.parameters) <= 0 else self.parameters}] ({self.route_id}) (NAVIGATOR-OBJECT {self.navigator})'
Route context class used for transferring data between routes and providing Navigator shortcuts.
106 def __init__(self, page: Page, navigator: Union['PublicFletNavigator', 'VirtualFletNavigator'], arguments: Arguments, parameters: 'RouteParameters', route_id: tuple[int, str]) -> None: 107 """Initialize a RouteContext instance.""" 108 self.page = page 109 110 self.navigator = navigator 111 112 self.arguments = arguments 113 114 self.parameters = parameters 115 116 self.route_id = route_id
Initialize a RouteContext instance.
URL parameters associated with the current route.
118 def add(self, *controls: Control) -> None: 119 """Add one or more controls to the current page.""" 120 self.page.add(*controls)
Add one or more controls to the current page.
146 def set_homepage(self, homepage: str) -> None: 147 """Update navigator's homepage address.""" 148 self.navigator.set_homepage(homepage)
Update navigator's homepage address.
150 def spec_cpage_props(self, **props: dict[str, Any]) -> None: 151 """Specify current page properties.""" 152 self.navigator.props_map[self.route_id] = props 153 154 AbstractFletNavigator.proc_page_props(self.page, props, ()) 155 156 self.page.update()
Specify current page properties.
477def route(route: Union[str, PageDefinition]) -> Any: 478 """Link a route to the last initialized navigator. 479 480 This function registers the route and associates it with a given page definition. 481 The only difference is the name. You can specify the name in the first argument. 482 or this function will fetch the given function name automatically.""" 483 if isinstance(route, Callable): 484 _pre_def_routes[route.__name__] = route 485 486 else: 487 def _route_decorator(page_definition: PageDefinition) -> None: 488 _pre_def_routes[route] = page_definition 489 490 return _route_decorator
Link a route to the last initialized navigator.
This function registers the route and associates it with a given page definition. The only difference is the name. You can specify the name in the first argument. or this function will fetch the given function name automatically.
493def load_page(path: str, name: Optional[str]=None) -> PageDefinition: 494 """Load a page definition from a specified module. 495 496 Let me explain this technically: it replaces all the system path separators with a dot. 497 After loading the module by its path, it loads the page definition function. 498 The function name is determined by the path. If a name is specified, then it loads the specified name. 499 Otherwise, it uses the last name in the path. 500 501 Can throw `ModuleNotFoundError` and `AttributeError`.""" 502 path = path.replace('\\', '.').replace('/', '.') 503 504 page = None 505 506 try: 507 page = getattr(import_module(path), _pd := path.split('.')[-1] if not name else name) 508 except ModuleNotFoundError: 509 raise TypeError(f'Failed to load page definition module: "{path}".') 510 except AttributeError: 511 raise ImportError(f'Failed to load page definition: "{_pd}".') 512 513 return page
Load a page definition from a specified module.
Let me explain this technically: it replaces all the system path separators with a dot. After loading the module by its path, it loads the page definition function. The function name is determined by the path. If a name is specified, then it loads the specified name. Otherwise, it uses the last name in the path.
Can throw ModuleNotFoundError
and AttributeError
.
516def template(template_definition: Union[str, TemplateDefinition], route_data: RouteContext, arguments: Arguments=()) -> Optional[Any]: 517 """Render a template for the given page data and arguments. 518 519 If `template_definition` is a string, then it's a global template. 520 The function will try to find the template you defined earlier via `@global_template` in the list of global templates. 521 If `template_definition` is a callable, then it's a local template. 522 The template will be rendered by calling the template function.""" 523 if isinstance(template_definition, str): 524 if template_definition in _global_templates: 525 return _global_templates[template_definition](route_data, arguments) 526 527 else: 528 route_data.navigator._logger.error(f'No global template found with the name: "{template_definition}". Ensure the template is registered and its name is correct.') 529 530 else: 531 return template_definition(route_data, arguments)
Render a template for the given page data and arguments.
If template_definition
is a string, then it's a global template.
The function will try to find the template you defined earlier via @global_template
in the list of global templates.
If template_definition
is a callable, then it's a local template.
The template will be rendered by calling the template function.
534def global_template(template_name: Optional[str]=None) -> Any: 535 """Register a global template to the last initialized navigator. 536 537 This function registers the template and associates it with a given template definition. 538 The only difference is the name. You can specify the name in the first argument. 539 or this function will fetch the given template function name automatically.""" 540 if isinstance(template_name, Callable): 541 _global_templates[template_name.__name__] = template_name 542 543 else: 544 def _global_template(template: TemplateDefinition) -> None: 545 _global_templates[template.__name__ if not template_name or not isinstance(template_name, str) else template_name] = template 546 547 return _global_template
Register a global template to the last initialized navigator.
This function registers the template and associates it with a given template definition. The only difference is the name. You can specify the name in the first argument. or this function will fetch the given template function name automatically.
550def fn_process(start: str='/', virtual: bool=False, routes: Routes={}, route_change_callback: RouteChangeCallback=None, startup_args: Arguments=(), public_startup_parameters: RouteParameters={}) -> Callable[[Page], None]: 551 """Shortcut to skip main function implementation and just calling `fn_process` in Flet's `app` function. 552 553 The best way to explain this function is to show an example: 554 ``` 555 @route('/') 556 def main(rd: RouteContext) -> None: 557 ... 558 559 app(fn_process()) # Instead of: app(lambda page: PublicFletNavigator(page).process(page)) 560 ```""" 561 return lambda page: ( 562 fn := PublicFletNavigator(page, routes, route_change_callback), 563 564 setattr(fn, 'route', start), 565 566 fn.process(page, startup_args, public_startup_parameters)) \ 567 if not virtual else ( 568 fn := VirtualFletNavigator(routes, route_change_callback), 569 570 setattr(fn, 'route', start), 571 572 fn.process(page, startup_args) 573 )
Shortcut to skip main function implementation and just calling fn_process
in Flet's app
function.
The best way to explain this function is to show an example:
@route('/')
def main(rd: RouteContext) -> None:
...
app(fn_process()) # Instead of: app(lambda page: PublicFletNavigator(page).process(page))