domains / app-frameworks / pallets/flask
Backward-compatible API design
When adding or changing public API surface, favor explicit, well-documented parameters over hidden `**kwargs` popping, and evolve signatures in a way that keeps existing behavior working.
When adding or changing public API surface, favor explicit, well-documented parameters over hidden **kwargs popping, and evolve signatures in a way that keeps existing behavior working.
- Add new options as named parameters in the function signature (not via
options.pop(...)) so they appear in the docstring and are discoverable, e.g.provide_automatic_optionsshould be a real parameter ofadd_url_rule, not something silently popped out of**options. - Avoid sentinel values that are ambiguous with “not provided”. If
Noneis a legitimate value (e.g.json=Nonemeaning “send JSON null”), don’t reuse it as “argument not passed”; instead detect presence via"json" in kwargsor a dedicated sentinel. - When generalizing an existing API (e.g. turning
from_json(filename)into a more flexiblefrom_file(filename, loads)), keep the old method as a thin wrapper delegating to the new one, and mark it with aDeprecationWarningrather than removing or silently changing its behavior. - Before adding new validation/assertions to existing public methods (e.g. asserting that a view function name contains no dots), verify they don’t reject previously valid, supported usage (such as partials or custom endpoint names) — gate the check so it only applies when relevant.
- When composing nested/hierarchical options (such as blueprint
subdomainandurl_prefix), define and document a single, predictable combination rule (e.g., child values nest with parent values) instead of silently overriding or raising errors that would break legitimate configurations.
Example of safe evolution with deprecation:
def from_file(self, filename, loads, silent=False):
"""Update config from a file loaded via `loads`."""
...
return self.from_mapping(obj)
def from_json(self, filename, silent=False):
"""Deprecated: use from_file(filename, json.loads) instead."""
warnings.warn(
"'from_json' is deprecated and will be removed in 2.0. Use 'from_file' instead.",
DeprecationWarning,
stacklevel=2,
)
return self.from_file(filename, json.loads, silent=silent)
This keeps the public API stable for existing users while enabling richer, more flexible functionality going forward.