I had a similar idea ~8 years ago while working on a RAD (rapid application
development) framework [*] that had to manage business objects using a
variety of frameworks: an ORM (SQLAlchemy), a full-text engine (Whoosh), as
well as a specifically developed CRUD Web UI framework, permission system,
audit system, etc.

In this context, variable decorators, in addition to type annotations,
could bring a whole new level of internal DSL expressivity, including for
instance:

- Annotation to express data access and structural constraints (support for
DBC e.g. "@constraints" or alternative constructs for some Attrs /
Dataclass features)

- Annotations to express ORM features (à la Java's
JPA): @Id, @NotNull, @OneToOne, @ManyToMany, etc.

- Annotations to express serialization (think Marshmallow or Pydantic)

- Annotation to express UI hints (e.g.: @widget(type=RichText,
size="300px", max_length=500, color=GREEN, required=True, ...))

- Annotations to express full-text search indexability (e.g. @indexed)

- Annotation to express field-level permissions: @acl(...)
or @permission(...)

etc.

This could provide more elegant, and better decoupled, syntax for things
that are currently done using either metaclasses (e.g. Django ORM or
SQLAlchemy ORM) or the "class Meta" idiom used by frameworks such as Django
or Marshmallow.

  S.

[*]: since this was not available, we eventually went with an external DSL
in combination with the "info" argument to the Column declaration in
SQLAlchemy, used to pass metadata useful for our framework. This worked,
but the code could have been much more elegant with variable decorators (in
other words, it was quite ugly in some places and harder than necessary to
maintain).


On Tue, May 25, 2021 at 3:39 AM micro codery <ucod...@gmail.com> wrote:

> Variable decorators have been suggested here before, as have new statements
> that could also achieve the same level of access to the binding name.
> However
> I propose a much more restricted syntax that would make for less edge cases
> where what is actually passed to the decorator callable may be ambiguous.
>
> Basically this would add syntax to python that would transform
> @decorator("spam this") variable
> into
> variable = decorator("variable", "spam this")
>
> The decorator would be limited to being on the same line as the variable
> name.
> Additionally, the variable can not also be assigned to on the same line, so
> @decorator("spam this") variable = eggs
> would be a SyntaxError. Annotating these variable would be allowed
> @decoratopr("spam this") variable: Food
> The actual decorator would follow the same rules as current decorators in
> that
> the parentheses can be omitted if no other arguments are required to the
> function and any arbitrary expression can be used, however the same
> restraint
> should be cautioned as is for current decorators post PEP 614.
>
> The most straightforward use of this decorating would be that str() could
> be
> used without change to declare variables that are strings of the same name,
> generally cutting down on repeating yourself when declaring constants.
>
> #instead of GREEN = "GREEN"
> @str GREEN
>
> The classic example of a factory that needs its target name as a string
> value
> is namedtuple. I don't think this example is enough alone to sway this
> list but
> I bring it up as it has also been at the front of past ideas to allow
> variable
> decorating.
>
> #instead of Point = namedtuple("Point", "x y z")
> @namedtuple("x y z") Point
>
> I have sometimes heard that dataclasses make this no longer an issue,
> implying
> that dataclasses can be used in place of namedtuple in any new code.
> Putting
> aside that dataclasses are not a strict replacement for namedtuple, the
> dataclasses module continues this factory design with the make_dataclass
> function.
>
> #instead of Point = make_dataclass("Point", [("x", int), ("y", int), ("z",
> int)])
> @make_dataclass([("x", int), ("y", int), ("z", int)]) Point
>
> Enum is one more case where there is a factory equivalent to the class
> declaration.
>
> #instead of Colors = Enum("Colors", "RED GREEN BLUE")
> @Enum("RED GREEN BLUE") Colors
>
> If you want each enum member value to match its name there is even more
> repetition, however by using the original example for decorated variables,
> this
> can be reduced when using the more common class style.
>
> class Colors(Enum):
>     @str RED
>     @str GREEN
>     @str BLUE
>
> One final standard library module that I will mention because it seems to
> keep
> adding similar factory functions is typing. It already has the factory
> functions
> NewType, TypeVar, ParamSpec, TypedDict, NamedTuple. Their use with the new
> variable decorator would look much the same as earlier examples, but here
> would
> be one case where type hinting the variable in such a statement could aid
> the
> decorator function
>
> #instead of UUIDType = NewType("UUIDType", str)
> @NewType UUIDType: str
>
> If adopted, no change to these functions would be necessary to allow their
> use
> as a variable decorators as they all already take the name as a string in
> the
> first argument. Additionally, as variable decorators are actually
> callables just like
> the current decorators, no new restrictions are being forced on users of
> the language.
> If a user really wants to create a namedtuple with a typename of Foo but
> assign
> the result to a variable named ___trippleS33cret___name__here_ the language
> will not stop them.
>
>
> I would very much like to know if any module maintainers are interested in
> this
> syntax. Convincing arguments from the standard lib (whether you consider
> the
> above convincing or not) are probably not enough to get a syntax change
> into
> python. But if enough third party modules want to use this functionality I
> believe that would be the real push to get it done.
>
> Specifically this idea first started growing when I read on another ideas
> message that using the module sympy would often start with a line like
> x = symbol('x')
> which, with no change, could be used as a variable decorator
> @symbol x
> Now what may be even more typical (I really have never used the module
> myself)
> is defining all needed symbols on one line with
> x, y, z = symbol('x y z')
> which could conceivably be rewritten like
> @symbol x, y, z
> However I have not yet been able to decide if multi-assignment would be
> overall
> beneficial to this new syntax. Probably not, at least at this stage. It
> would
> not be hard for a decorator function to return multiple values, but how
> would
> the multiple names be passed in? A string with whitespace like this
> original,
> and namedtuple's field_names, is possible as no valid identifier can have a
> space in it. However, it forces any would-be variable decorator to know
> this
> and check if a space is in its first argument, even if it cannot produce
> multiple values. Another option is to pass in an iterable, but the same
> additional effort would be placed on decorators that otherwise don't want
> to
> deal with multi-assignment. Unpacking the names as the first n arguments
> would
> mean that decorators that just want one variable can get just that and
> those
> that may want more will also get them, but then practically no variable
> decorator
> could take additional non-keyword arguments.
>
> Regards
> ~ Jeremiah
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/2FOIN5UEQ3LG2QMHVJD54LBBJTA3JZZQ/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Stefane Fermigier - http://fermigier.com/ - http://twitter.com/sfermigier -
http://linkedin.com/in/sfermigier
Founder & CEO, Abilian - Enterprise Social Software -
http://www.abilian.com/
Chairman, National Council for Free & Open Source Software (CNLL) -
http://cnll.fr/
Founder & Organiser, PyParis & PyData Paris - http://pyparis.org/ &
http://pydata.fr/
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/7HD7BLNCP3IOKOZC4OD5F33Y56E77NPD/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to