Giter Site home page Giter Site logo

Comments (7)

hjwp avatar hjwp commented on May 23, 2024 13

i think i know what it is. i should probably add a footnote in the book. but you need to change the @dataclass(frozen=True) to @dataclass(unsafe_hash=True). because sqlalchemy reasons.

from code.

jmaralc avatar jmaralc commented on May 23, 2024 1

Sorry Harry, my bad. It was failing in a copy of the model file with the frozen=True that I generated before by following the chapter. Sorry again for the extra work and thanks, diving in the hashes topics of dataclasses gave me a nice insight of what is happening.

from code.

nikoladsp avatar nikoladsp commented on May 23, 2024 1

Hi,
I hit the very same issue.

More to that, even with InstrumentationManager, dataclass is changed by SA: after mapping is performed, SA has added some of its internal attributes (_sa_instance_state and _sa_class_manager) to dataclass, so we can not speak about decoupling and this beats the purpose of Registry in the first place since dataclass only looks like its decoupled.

I am not sure if there is a clean way to do this with SA, and posted question here. Additionaly, turns out that InstrumentationManager is very old, untested and almost never used.

If anyone have some ideas, please share.

Thank you kindly

from code.

hjwp avatar hjwp commented on May 23, 2024 1

as always it's a tradeoff. Yes, in order to work, SQLAlchemy has to get its claws pretty deep into your objects, so they are not "truly" decoupled. On the other hand, an ORM does a lot of the heavy lifting for getting objects in and out of database columns.

The alternative is not to use an ORM at all, which I've enjoyed doing on the last few projects. You have to write a lot of your own SQL tho! Check out the exercise for the reader here, so you can get a feel for the tradeoff http://www.cosmicpython.com/book/chapter_02_repository.html#api_endpoint_with_repo

from code.

jmaralc avatar jmaralc commented on May 23, 2024

Not sure about it. I'm taking the code from the repo and it is already defined as:

@dataclass(unsafe_hash=True)`
class OrderLine:
    orderid: str
    sku: str
    qty: int

from code.

hjwp avatar hjwp commented on May 23, 2024

it's weird that you'd get a dataclasses.FrozenInstanceError then?

do you have a repo you can share?

from code.

tomdottom avatar tomdottom commented on May 23, 2024

After fighting SqlAlchemy and solving this before finding this issue I'd just like to say that you can use frozen dataclasses.
However, you will have to provide a custom instrumentation manager.

Example:

For a frozen OrderLine dataclass

@dataclass(unsafe_hash=True)
class OrderLine:
    orderid: str
    sku: str
    qty: int

We can use a custom FrozenDataclassInstrumentationManager .

from sqlalchemy import Column, Integer, MetaData String, Table
from sqlalchemy.ext.instrumentation import InstrumentationManager
from sqlalchemy.orm import mapper

metadata = MetaData()


DEL_ATTR = object()


class FrozenDataclassInstrumentationManager(InstrumentationManager):
    def install_member(self, class_, key, implementation):
        self.originals.setdefault(key, class_.__dict__.get(key, DEL_ATTR))
        setattr(class_, key, implementation)

    def uninstall_member(self, class_, key):
        original = self.originals.pop(key, None)
        if original is not DEL_ATTR:
            setattr(class_, key, original)
        else:
            delattr(class_, key)

    def dispose(self, class_):
        del self.originals
        delattr(class_, "_sa_class_manager")
    
    def manager_getter(self, class_):
        def get(cls):
            return cls.__dict__["_sa_class_manager"]
        return get

    def manage(self, class_, manager):
        self.originals = {}
        setattr(class_, "_sa_class_manager", manager)

    def get_instance_dict(self, class_, instance):
        return instance.__dict__

    def install_state(self, class_, instance, state):
        instance.__dict__["state"] = state

    def remove_state(self, class_, instance, state):
        del instance.__dict__["state"]

    def state_getter(self, class_):
        def find(instance):
            return instance.__dict__["state"]
        return find


OrderLine.__sa_instrumentation_manager__ = FrozenDataclassInstrumentationManager


orderline_table = Table(
    "order_lines",
    metadata,
    Column("id", Integer, primary_key=True, autoincrement=True),
    Column("sku", String(128), nullable=False),
    Column("quantity", Integer, nullable=False),
)

mapper(
    OrderLine,
    orderline_table,
)

https://stackoverflow.com/a/66941711/2398354

from code.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.