Thursday, 9 September 2021

is it possible to find class name given class variable

class A:
    var = 'hello'


type(A.var)               # returns: <class 'str'>
A.var.__class__.__name__  # returns: 'str'
vars(A)                   # returns: mappingproxy({'__module__': '__main__', 'var': 'hello', '__dict__': <attribute ' __dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, '__getattribute__': <slot wrapper '__getattribute__' of 'object' objects>})

given A.var is it possible to find class A, or just var is related to class A, may be something similar to 'qualname' for methods.

Edited

reason I wanted to find the class name is I am implementing micro ORM, similar to SQLAlchemy using declarative mapping.

As you can see in this example.

import sqlalchemy as sa
import sqlalchemy.ext.declarative

meta = sa.MetaData()
DeclarativeBase = sa.ext.declarative.declarative_base(metadata=meta)


class User(DeclartiveBase):
    __tablename__ = 'user'

    id            = sa.Column(Integer, primary_key=True)
    name          = sa.Column(String)
    fullname      = sa.Column(String)

as you can see class is used as the abstraction for the real table, intresting thing is you can still access all the column using vars(Users) and filter column using isinstance(<var>, sa.Column).

while doing query some how query is able to know which table the row is from, which is similar to the question I asked above, may its something to do with sa.Column.

Session = sa.orm.sessionmaker(bind=engine)
session = Session()

rows = session.query(
    User.id,
    User.name,
).all()

Sample

This is sample of the implemenation, which is able to do basic table creating, insertion and update.

class Col(str):
    pass

class Base:
    @classmethod
    def childs(cls):
        subclasses = set()
        work = [cls]
        while work:
            parent = work.pop()
            for child in parent.__subclasses__():
                if child not in subclasses:
                    subclasses.add(child)
                    work.append(child)
        return subclasses


    @classmethod
    def create(cls, cursor):
        query = 'CREATE TABLE IF NOT EXISTS {} ({})'.format(
            cls.__tablename__,
            ', '.join(
                k + ' ' + v
                for k, v in vars(cls).items()
                if isinstance(v, Col)
            )
        )
        cursor.execute(query)


    @staticmethod
    def create_all_tables(cursor):
        for cls in __class__.childs():
            cls.create(cursor)


    @classmethod
    def drop(cls, cursor):
        query = 'DROP TABLE IF EXISTS {}'.format(
            cls.__tablename__,
        )
        cursor.execute(query)


    @classmethod
    def insert(cls, cursor, kvRow):
        query = 'INSERT INTO {} ({}) VALUES(:{})'.format(
            cls.__tablename__,
            ', '.join(kvRow.keys()),
            ', :'.join(kvRow.keys())
        )
        cursor.execute(query, kvRow)


    @classmethod
    def update(cls, cursor, kvRow):
        query = 'UPDATE {} SET ({})=(:{}) WHERE name=\'{}\''.format(
            cls.__tablename__,
            ', '.join(kvRow.keys()),
            ', :'.join(kvRow.keys()),
            kvRow['name']
        )
        cursor.execute(query, kvRow)

using it

class User(Base):
    __tablename__ = 'user'

    id            = Col('INTEGER PRIMARY KEY')
    name          = Col('VARCHAR')
    fullname      = Col('VARCHAR')

now creating table is similar to sqlalchemy meta.create_all(bind=engine, checkfirst=True)

import sqlite3

conn   = sqlite3.connect('./sqlite.db')
cursor = conn.cursor()
Base.create_all_tables(cursor)

Which I don't understand is how sqlchemy session.query is able to understand the table the row is from.



from is it possible to find class name given class variable

No comments:

Post a Comment