falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.49k stars 933 forks source link

Cumbersome to pass curly brackets to field converters #2062

Open vytas7 opened 2 years ago

vytas7 commented 2 years ago

At the time of this writing, it is cumbersome to instantiate converters with any parameter containing curly brackets in its expression.

For instance, the following attempt to validate color to be one of "red", "green" or "blue"

import falcon
import falcon.routing

class In(falcon.routing.BaseConverter):
    def __init__(self, values):
        self._values = frozenset(values)

    def convert(self, value):
        if value not in self._values:
            return None
        return value

class ColorResource:
    def on_get(self, req, resp, color):
        resp.media = {'color': color, 'path': req.path}

app = falcon.App()
app.router_options.converters['in'] = In

app.add_route('/colors/{color:in({"red", "green", "blue"})}', ColorResource())

... fails with the following ValueError: Field names must be valid identifiers (""red", "green", "blue"" is not valid).

One could easily work around the problem in this contrived example by using a list or tuple instead of the set literal, but what if we need curly brackets in a regex, or need to pass a dict?

vytas7 commented 2 years ago

Perhaps we could support escaping curly brackets by doubling them ({{ & }}), just as the Python format string syntax does?

CaselIT commented 2 years ago

Perhaps we could support escaping curly brackets by doubling them ({{ & }}), just as the Python format string syntax does?

I like that idea, since it would be somewhat natural to python users to escape them that way. Especially since f-string has become a thing

vytas7 commented 2 years ago

(It's the same {{ & }} even in str.format(), which dates back to early 3.x versions and 2.7.)

chgad commented 1 month ago

Double Braces {{ feel like bloating the route string/parameter definition. Looking into where this parseing happens i think it would be best, keeping multiple parametercases in mind, to split parsing into two steps:

  1. Extract every parameter definition from the route segment → Every grouping of single { like {object_id:int} in the segment obj_{object_id:int}_img
  2. Extract the parameters specification.

This should cover at least all python native, non-recursive (not Object of Object of ...), structures.