alchemyjsonschema icon indicating copy to clipboard operation
alchemyjsonschema copied to clipboard

Use with Automap?

Open jpw1991 opened this issue 9 years ago • 10 comments

Hello,

Sorry if this is the wrong place to ask this question. I'm pretty new to github.

I want to use alchemyjsonschema with automap. My setup is similar to the example code shown here. When I try using

factory = SchemaFactory(SingleModelWalker)
result = factory(someTable)

I get an <class 'AttributeError'>. someTable is of type <class 'sqlalchemy.ext.automap.someTable'>

Any advice? Thanks

jpw1991 avatar May 10 '16 13:05 jpw1991

Was able to solve my own issue somewhat. I need to predefine the class and then reflect it again, then it works:

        class someTable(Base):
            __tablename__ = "someTable"

        # reflect in to override the predefined classes
        Base.prepare(engine=engine, reflect=True)

Was hoping to avoid having to do that.

jpw1991 avatar May 10 '16 13:05 jpw1991

oh, i see.

podhmo avatar May 12 '16 22:05 podhmo

these tests are passed in my local's environment. (but, i found another bug for required field of related table, of course, this is out of context of this issue)

https://gist.github.com/podhmo/cf12f3e6874ba3628b3f867b9ea65d04

when generated classes don't have __tablename__ property, above error is occured. maybe.

podhmo avatar May 14 '16 10:05 podhmo

I could not reproduce same error (using automap then AttributeError is raised). if you can, please, give me a simple set enable to reproduce it.

podhmo avatar May 14 '16 10:05 podhmo

Thanks for looking into that. I realised my problem only comes when I try to use it on a query. Maybe this is false usage, if so, I'm sorry about that.

I wrote this up to illustrate my problem. The first test works, second one will not:

import sqlalchemy, unittest
from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine
from collections import OrderedDict

from alchemyjsonschema import SchemaFactory
from alchemyjsonschema import SingleModelWalker


class Test(unittest.TestCase):

    def setUp(self):
        self.Base = automap_base()
        self.engine = create_engine("postgresql://postgres:testpw@localhost:5432/testdb")
        self.Base.prepare(self.engine, reflect=True)

        self.session = sqlalchemy.orm.Session(self.engine)

    def test_will_work(self):
        TestTable = self.Base.classes.test_table

        factory = SchemaFactory(SingleModelWalker)
        result = factory(TestTable)

        expected_result = {
            'type': 'object',
            'title': 'test_table',
            'properties': OrderedDict([('firstnumber', {
                'type': 'integer'
            }), ('secondnumber', {
                'type': 'integer'
            }), ('bez', {
                'type': 'string',
                'maxLength': 50
            })]),
            'required': ['firstnumber', 'secondnumber']
        }
        self.assertEqual(result, expected_result)

    def test_wont_work(self):
        TestTable = self.Base.classes.test_table

        row = self.session.query(TestTable).first()

        factory = SchemaFactory(SingleModelWalker)
        result = factory(row)

        expected_result = {
            'type': 'object',
            'title': 'test_table',
            'properties': OrderedDict([('firstnumber', {
                'type': 'integer',
                'value': 1
            }), ('secondnumber', {
                'type': 'integer',
                'value': 1
            }), ('bez', {
                'type': 'string',
                'maxLength': 50,
                'value': 'test'
            })]),
            'required': ['firstnumber', 'secondnumber']
        }
        self.assertEqual(result, expected_result)

    def tearDown(self):
        self.session.rollback()

if __name__ == "__main__":
    unittest.main()

DB table looks like:

                                  Table "public.test_table"
   Column    |         Type          | Modifiers | Storage  | Stats target | Description 
-------------+-----------------------+-----------+----------+--------------+-------------
 firstnumber  | integer               | not null  | plain    |              | 
 secondnumber | integer               | not null  | plain    |              | 
 bez          | character varying(50) |           | extended |              | 
Indexes:
    "test_table_pkey" PRIMARY KEY, btree (firstnumber, secondnumber)

jpw1991 avatar May 17 '16 07:05 jpw1991

Thanks!

podhmo avatar May 18 '16 00:05 podhmo

No problem. I hope it helps.

jpw1991 avatar May 18 '16 19:05 jpw1991

ah, I haven't expected passing a instance of defined model class. but, if will be able to passing a instance, it is also convenience, maybe.

podhmo avatar May 18 '16 21:05 podhmo

two phase action is good for this.

  1. build schema from model class
  2. add value from model instance
from alchemyjsonschema import emit_value
schema = factory(row.__class__)
schema = emit_value(schema, row)

podhmo avatar May 18 '16 21:05 podhmo

Ok, sounds good. Thanks for your help

jpw1991 avatar May 20 '16 15:05 jpw1991