| 603 | |
| 604 | @setupmethod |
| 605 | def add_url_rule( |
| 606 | self, |
| 607 | rule: str, |
| 608 | endpoint: str | None = None, |
| 609 | view_func: ft.RouteCallable | None = None, |
| 610 | provide_automatic_options: bool | None = None, |
| 611 | **options: t.Any, |
| 612 | ) -> None: |
| 613 | if endpoint is None: |
| 614 | endpoint = _endpoint_from_view_func(view_func) class="cm"># type: ignore |
| 615 | options[class="st">"endpoint"] = endpoint |
| 616 | methods = options.pop(class="st">"methods", None) |
| 617 | |
| 618 | class="cm"># if the methods are not given and the view_func object knows its |
| 619 | class="cm"># methods we can use that instead. If neither exists, we go with |
| 620 | class="cm"># a tuple of only ``GET`` as default. |
| 621 | if methods is None: |
| 622 | methods = getattr(view_func, class="st">"methods", None) or (class="st">"GET",) |
| 623 | if isinstance(methods, str): |
| 624 | raise TypeError( |
| 625 | class="st">"Allowed methods must be a list of strings, for" |
| 626 | &class="cm">#x27; example: @app.route(..., methods=[class="st">"POST"])' |
| 627 | ) |
| 628 | methods = {item.upper() for item in methods} |
| 629 | |
| 630 | class="cm"># Methods that should always be added |
| 631 | required_methods: set[str] = set(getattr(view_func, class="st">"required_methods", ())) |
| 632 | |
| 633 | class="cm"># starting with Flask 0.8 the view_func object can disable and |
| 634 | class="cm"># force-enable the automatic options handling. |
| 635 | if provide_automatic_options is None: |
| 636 | provide_automatic_options = getattr( |
| 637 | view_func, class="st">"provide_automatic_options", None |
| 638 | ) |
| 639 | |
| 640 | if provide_automatic_options is None: |
| 641 | if class="st">"OPTIONS" not in methods and self.config[class="st">"PROVIDE_AUTOMATIC_OPTIONS"]: |
| 642 | provide_automatic_options = True |
| 643 | required_methods.add(class="st">"OPTIONS") |
| 644 | else: |
| 645 | provide_automatic_options = False |
| 646 | |
| 647 | class="cm"># Add the required methods now. |
| 648 | methods |= required_methods |
| 649 | |
| 650 | rule_obj = self.url_rule_class(rule, methods=methods, **options) |
| 651 | rule_obj.provide_automatic_options = provide_automatic_options class="cm"># type: ignore[attr-defined] |
| 652 | |
| 653 | self.url_map.add(rule_obj) |
| 654 | if view_func is not None: |
| 655 | old_func = self.view_functions.get(endpoint) |
| 656 | if old_func is not None and old_func != view_func: |
| 657 | raise AssertionError( |
| 658 | class="st">"View function mapping is overwriting an existing" |
| 659 | fclass="st">" endpoint function: {endpoint}" |
| 660 | ) |
| 661 | self.view_functions[endpoint] = view_func |
| 662 | |