On Tue, May 25, 2021 at 12:14 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Tue, May 25, 2021 at 10:55:07AM +0200, Stéfane Fermigier wrote:

> 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:

Could you explain exactly how this proposed feature would allow us to do
all the things you say it would allow us to do? It's not clear to me how
knowing the binding name on the left would allow us to "express data
access constraints" etc.

I was thinking at the framework level, e.g. the decorator would be use to register some metadata somewhere (either class-level or in a global registry, say), and the framework would be to check permission against the current user when accessing the object's field (e.g. at serialisation / deserialisation time, and/or when rendering templates).

For all the things I have suggested, what I have in mind is just:

1) Register some metadata at decorator execution time
2) The framework uses these metadata when it needs them


E.g. you say:

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

I don't even know how to begin interpreting how you get there from the
proposed syntax:

    @function(args) name
    # -> `name = function('name', args)`

For the use cases I have in mind, some kind of context information would need to be passed too, like:

class Customer:

    @permissions({"read": USER, "write": MANAGER})
    first_name: str

the function primary_key should be called with the class being constructed for it to make sense.

Here are some alternatives:

1) Set metadata directly on some magical attribute:

class Customer:
    __permissions__ = {
        'first_name': { READ: ..., WRITE: ... }
    }

    first_name: str

cons: risk of mispelling or forgetting some attributes; lack of locality; how do we deal with inheritance ?

1bis):

class Customer:
    class Meta:
        permissions__ = {
            'first_name': { READ: ..., WRITE: ... }
        }

    first_name: str

This is similar to the previous one, so same issues.

2) Dexterity syntax (I'm not a user of Dexterity, so I might be wrong, this is from: https://www.stevemcmahon.com/classes/dexterity/dexterity%20class%202013.pdf ):

class Customer:
    dexterity.read_permission(
        first_name='cmf.ReviewPortalContent'
    )
    dexterity.write_permission(
        first_name='cmf.ReviewPortalContent'
    )
    first_name: str


con: easy to misspell the field name (hopefully the rest of the issues is taken care by the framework)

3) One possible idiom to use decorators as I think would be fit, without changing the language, but at the price of an extra line and some additional mental burden:

class Customer:
    first_name: str


    @acl({"read": USER, "write": MANAGER})
    def meta_first_name(self): pass

I.e. use a method decorator on a dummy function named similarly to the variable (e.g. by prepending some magical prefix).

The obvious con is that we still haven't prevented the risk of typo in the function name.

[...] As I see it, objects should almost never know or care what names (note
plural) they are known by, or even if they are bound to any names at
all. There are a few exceptions, mostly classes and sympy symbols, but
I expect that this functionality should be rather niche.

For the kind of applications I have been doing over the last 20 years (enterprise content and information management applications), this is not  niche, this is where 50% of the work goes (i.e. defining object models, permissions, workflows, forms, validation, etc.).

  S.

--
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/