Jaymon / prom

A PostgreSQL or SQLite orm for Python
MIT License
22 stars 4 forks source link

fsetter failed #98

Closed Jaymon closed 1 year ago

Jaymon commented 4 years ago

This one was unexpected

class Foo(Orm):

    bar = Field(str, True)

    @bar.fsetter
    def bar(self, val):
        return val

    che_bar = Field(str, True)

    @che_bar.fsetter
    def bar(self, val):
        return val

Notice the che_bar.fsetter has the same name as the bar.fsetter, this caused the Foo.create(bar="1", che_bar="2") call to fail with:

UniqueError: NOT NULL constraint failed: foo.bar

The fix was just to change the name of the second method to:

@che_bar.fsetter
def che_bar(self, val):
    return val

But I'd like to understand why this failed

Jaymon commented 1 year ago

This works as expected:

class Foo(Orm):
    bar = Field(str, True)

    @bar.fsetter
    def che(self, val): return val

    che = Field(str, True)

    @che.fsetter
    def che(self, val): return val

This looks to be something strange with the Python parser. Any function names work except when the method names are the name of the first descriptor (in this case, the first descriptor is named bar).

Everything looks to be set correctly during execution but after the class is defined bar has che as the descriptor (ie, they are pointing to the same descriptor instance). I don't see anywhere in the code where they would be switched so I think it's some strange compiler switcheroo or something, it does not appear to be my code though because this fails in a similar manner:

class Foo(object):
    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, v1):
        pout.v("_bar")
        self._bar = v1

    @property
    def che(self):
        pout.v("_che")
        return self._che

    @che.setter
    def bar(self, v2):
        self._che = v2

pout.v(Foo.bar, Foo.che)

f = Foo()
f.bar = 1
pout.v(f.bar) # returns `che` value
f.che = 2 # AttributeError: can't set attribute 'che'
pout.v(f)

And bar returns the che value.

I think I've done everything I can to understand this without spending lots more time on it, so I'm going to go ahead and close this issue and I've marked it as wontfix since I can't actually fix it.

Jaymon commented 1 year ago

This was my test method in tests.model.OrmTest:

    def test_fields_setters(self):
        class Foo(Orm):

            interface = self.get_interface()
            bar = Field(int, True)

            @bar.fsetter
            def bar(self, v1):
                pout.v("1", v1)
                return 1

            che = Field(int, True)

            @che.fsetter
            def bar(self, v2):
                pout.v("2", v2)
                return 2

        pout.v(Foo.bar, Foo.che)

        f = Foo()
        f.bar = 1
        f.che = 2
        return
        #pout.i(Foo)
        f = Foo.create(bar="1", che_bar="2")