[sqlalchemy] Inconsistent results in session.flush()
Hi, I'm having a problem where the results of session.flush() vary from one run to another of my test suite. The unit of work transaction dump is significantly different from one run to the next, similar to the issue in ticket 461. I haven't managed to make a test case small enough to post to the list yet, and I think I need to delve a little further into the code to find out why it's failing. (This is with both 0.3.5 and rev2416) The logs from the UOWTransaction on a failing run and a passing run are below. As well as the ordering being different, there is at least one class (ReleaseLine) that doesn't appear in the bad run. Unfortunately I don't know how to go about debugging this. I think I need to see exactly what is going on in the dependency sort. Do you have any suggestions for suitable places to add some extra logging? This is a failing run: INFO:sqlalchemy.orm.unitofwork.UOWTransaction.0x..30:Task dump: UOWTask(0x184b2b0, Component/component/None) (save/update phase) | |- UOWTask(0x184bb50, User/user/None) (save/update phase) | |- Save User(0x1851870) | | |- Process User(0x1851870).branches | | |- Process User(0x1851870).reviews | | |- Process User(0x1851870).labels | | |- Process Branch(0x17ee310).user | | |- Process Branch(0x184b190).user | | | |- UOWTask(0x184bb70, ChangeOrigin/change_origin/None) (save/update phase) | | | |- Process Branch(0x17ee310).change_origin | | | |- Process Branch(0x184b190).change_origin | | | | | |- UOWTask(0x184b590, Label/label/None) (save/update phase) | | | | | | | |- UOWTask(0x184b1b0, Branch/branch/None) (save/update phase) | | | | |- Save Branch(0x17ee310) | | | | |- Save Branch(0x184b190) | | | | | |- Process Branch(0x17ee310).review | | | | | |- Process Branch(0x184b190).review | | | | | | | | | |- UOWTask(0x183f470, Review/review/None) (save/update phase) | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bb30, sqlalchemy.orm.dependency.MapperStub object at 0x0183FDF0) (save/update phase) | | | | | | |- Process Branch(0x17ee310).label | | | | | | |- Process Branch(0x184b190).label | | | | | | | | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bfb0, Counter/counter/None) (save/update phase) | | | | |- Save Counter(0x184b0f0) | | | | | | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bb50, User/user/None) (delete phase) | | | |- UOWTask(0x184bb70, ChangeOrigin/change_origin/None) (delete phase) | | | | | |- UOWTask(0x184b590, Label/label/None) (delete phase) | | | | | | | |- UOWTask(0x184b1b0, Branch/branch/None) (delete phase) | | | | | | | | | |- UOWTask(0x183f470, Review/review/None) (delete phase) | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bb30, sqlalchemy.orm.dependency.MapperStub object at 0x0183FDF0) (delete phase) | | | | | | | | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bfb0, Counter/counter/None) (delete phase) | | | | | | | | | | | | | | | | | | | | | | | | | And on a good run looks like this: INFO:sqlalchemy.orm.unitofwork.UOWTransaction.0x..f0:Task dump: UOWTask(0x17f2610, User/user/None) (save/update phase) |- Save User(0x17fe9f0) | |- Process User(0x17fe9f0).labels | |- Process Branch(0x17caa10).user | |- Process Branch(0x17f2470).user | |- Process User(0x17fe9f0).reviews | |- Process User(0x17fe9f0).branches | |- UOWTask(0x17f2a50, ChangeOrigin/change_origin/None) (save/update phase) | | |- Process Branch(0x17caa10).change_origin | | |- Process Branch(0x17f2470).change_origin | | | |- UOWTask(0x17f29f0, Component/component/None) (save/update phase) | | | | | |- UOWTask(0x17f2ad0, ReleaseLine/release_line/None) (save/update phase) | | | | |- Process Branch(0x17caa10).release_line | | | | |- Process Branch(0x17f2470).release_line | | | | |- Process Counter(0x17fed10).release_line | | | | | | | |- UOWTask(0x17f2430, Counter/counter/None) (save/update phase) | | | | |- Save Counter(0x17fed10) | | | | | | | | | | | | | | | | |- UOWTask(0x17f2450, Branch/branch/None) (save/update phase) | | | | |- Save Branch(0x17caa10) | | | | |- Save Branch(0x17f2470) | | | | | |- Process Branch(0x17caa10).review | | | | |
[sqlalchemy] Re: Inconsistent results in session.flush()
I've just run the attached script about thirty times, and it succeeded 5 times and failed the rest. I've cut out a lot of unnecessary stuff, but it's still a bit long I'm afraid. I'll cut it down some more, but since you seemed so eager to see it ;-) I thought I'd send it along as is. On a bad run, the dependency tuples look like this: DEBUG:sqlalchemy.orm.unitofwork.UOWTransaction.0x..50:Dependency sort: Mapper|User|user Mapper|Component|component Mapper|ChangeOrigin|change_origin Mapper|Label|label (cycles: [Mapper|Label|label, Mapper|ReleaseLine|release_line]) Mapper|Counter|counter Mapper|Branch|branch sqlalchemy.orm.dependency.MapperStub object at 0x00D59590 And on a good run they look like this: DEBUG:sqlalchemy.orm.unitofwork.UOWTransaction.0x..10:Dependency sort: Mapper|User|user Mapper|Component|component Mapper|ChangeOrigin|change_origin Mapper|ReleaseLine|release_line (cycles: [Mapper|ReleaseLine|release_line, Mapper|Label|label]) Mapper|Counter|counter Mapper|Branch|branch sqlalchemy.orm.dependency.MapperStub object at 0x00D59670 Thanks a lot for looking at this, Simon Michael Bayer wrote: I can actually read a fair degree from these dumps, i need mostly to know what the actual dependencies are (i.e. which classes are dependent on what, whats the error). also when you do the full debug echoing the UOW should illustrate a series of dependency tuples which will show what pairs of classes the UOW perceives as dependent on each other. On Mar 16, 2007, at 6:59 AM, King Simon-NFHD78 wrote: Hi, I'm having a problem where the results of session.flush() vary from one run to another of my test suite. The unit of work transaction dump is significantly different from one run to the next, similar to the issue in ticket 461. I haven't managed to make a test case small enough to post to the list yet, and I think I need to delve a little further into the code to find out why it's failing. (This is with both 0.3.5 and rev2416) The logs from the UOWTransaction on a failing run and a passing run are below. As well as the ordering being different, there is at least one class (ReleaseLine) that doesn't appear in the bad run. Unfortunately I don't know how to go about debugging this. I think I need to see exactly what is going on in the dependency sort. Do you have any suggestions for suitable places to add some extra logging? This is a failing run: INFO:sqlalchemy.orm.unitofwork.UOWTransaction.0x..30:Task dump: UOWTask(0x184b2b0, Component/component/None) (save/update phase) | |- UOWTask(0x184bb50, User/user/None) (save/update phase) | |- Save User(0x1851870) | | |- Process User(0x1851870).branches | | |- Process User(0x1851870).reviews | | |- Process User(0x1851870).labels | | |- Process Branch(0x17ee310).user | | |- Process Branch(0x184b190).user | | | |- UOWTask(0x184bb70, ChangeOrigin/change_origin/None) (save/update phase) | | | |- Process Branch(0x17ee310).change_origin | | | |- Process Branch(0x184b190).change_origin | | | | | |- UOWTask(0x184b590, Label/label/None) (save/update phase) | | | | | | | |- UOWTask(0x184b1b0, Branch/branch/None) (save/update phase) | | | | |- Save Branch(0x17ee310) | | | | |- Save Branch(0x184b190) | | | | | |- Process Branch(0x17ee310).review | | | | | |- Process Branch(0x184b190).review | | | | | | | | | |- UOWTask(0x183f470, Review/review/None) (save/update phase) | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bb30, sqlalchemy.orm.dependency.MapperStub object at 0x0183FDF0) (save/update phase) | | | | | | |- Process Branch(0x17ee310).label | | | | | | |- Process Branch(0x184b190).label | | | | | | | | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bfb0, Counter/counter/None) (save/ update phase) | | | | |- Save Counter(0x184b0f0) | | | | | | | | | | | | | | | | | | | | | | | | | |- UOWTask(0x184bb50, User/user/None) (delete phase) | | | |- UOWTask(0x184bb70, ChangeOrigin/change_origin/None) (delete phase) | | | | | |- UOWTask(0x184b590, Label/label/None) (delete phase) | | | | | | | |- UOWTask(0x184b1b0, Branch/branch/None) (delete phase) | | | | | | | | | |- UOWTask(0x183f470, Review/review/None) (delete phase
[sqlalchemy] Re: table name bind param
tml wrote: also to clarify, the text actually has :table_name used in many other places: t = metadata.engine.text(LOCK TABLE :table_name WRITE; UPDATE :table_name SET rgt=rgt + 2 WHERE rgt :insert_node_val and parent_id = :parent_id; UPDATE :table_name SET lft=lft + 2 WHERE lft :insert_node_val and parent_id = :parent_id; .. so if i had it as %s, i would have to repeat the same name multiple times in % (name, name, name). I'm ok with this, just curious if there is a better way. I don't think bind parameters can be used for table names, so you are stuck with python format strings, but you can use a dictionary instead of a tuple when formatting strings. Instead of using %s, you use %(name)s, and instead of the tuple (name, name, name) you pass a single dictionary {'name': your_table_name} http://docs.python.org/lib/typesseq-strings.html Hope that helps, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Polymorphic collections / ticket #500
I wanted to do something like this in the past, and in the end, rather than using polymorphic mappers it made more sense to create a MapperExtension which overrides create_instance. In create_instance you can examine your 'typ' column to decide what class to create, selecting one of your Manager/Demigod classes if necessary, or falling back to the Person class otherwise. Hope that helps, Simon From: sqlalchemy@googlegroups.com [mailto:[EMAIL PROTECTED] On Behalf Of Rick Morrison Sent: 06 March 2007 01:12 To: sqlalchemy Subject: [sqlalchemy] Polymorphic collections / ticket #500 The fix for ticket #500 breaks a pattern I've been using. It's most likely an anti-pattern, but I don't see a way to get what I want in SA otherwise. I've got a series of entities class Person(): pass class Manager(Person): def __init__(self): # do manager stuff class Demigod(Person): def __init__(self): # do demigod stuff etc. there are mappers for each of these entities that inherit from Person(), so all of the normal Person() properties exist, but Person() itself is not polymorphic. That's on purpose, and because the class hierarchy of Manager(), etc, is not exhaustive, and I occasionally want to save instances of Person() directly. If I make the Person() class polymorphic on a column of say typ, then SA clears whatever typ I may have tried to set directly, and seems to make me specify an exhaustive list of sub-types. And so I leave Person() as non-polymorphic. I also have a collection of Person() objects on a different mapper, which can load entity objects of any type. Before rev #2382, I could put a Manager() in a Person() collection, and it would flush OK. Now it bitches that it wants a real polymorphic mapper. I don't want to use a polymorphic mapper, because I don't want to specify an exhaustive list of every class that I'm ever going to use. What to do? Thanks, Rick --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Table being removed from nested query
Hi, I have a problem in which a table is being removed from the FROM clause of a nested query. The attached file should show the problem, which I've tested on 0.3.5 and rev 2383. In the example, there are two tables, department and employee, such that one department has many employees. The inner query joins the two tables and returns department IDs: inner = select([departments.c.department_id], employees.c.department_id == departments.c.department_id) inner = inner.alias('filtered_departments') The SQL looks like: SELECT departments.department_id FROM departments, employees WHERE employees.department_id = departments.department_id I then join this query back to the department table: join = inner.join(departments, onclause=inner.c.department_id==departments.c.department_id) SQL for the join condition looks like: (SELECT departments.department_id FROM departments, employees WHERE employees.department_id = departments.department_id) AS filtered_departments JOIN departments ON filtered_departments.department_id = departments.department_id This still looks correct to me. However, I then base a query on this join: outer = select([departments.c.name], from_obj=[join], use_labels=True) At this point, the 'departments' table is no longer part of the inner query. The SQL looks like: SELECT departments.name FROM (SELECT departments.department_id AS department_id FROM employees WHERE employees.department_id = departments.department_id) AS filtered_departments JOIN departments ON filtered_departments.department_id = departments.department_id ...and the query doesn't run. I think I can work around it by putting the join condition in the whereclause of the select, instead of from_obj, but is there a reason why the join version doesn't work? Thanks, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~--- inner_query_test.py Description: inner_query_test.py
[sqlalchemy] Re: Associations in a cleaner way
Knut Aksel Røysland wrote: [snip] However, an instance of D also needs a reference to an instance of C. If the appropriate instance of C exists in the database (or is pending to go into it), I want to pick this one, or otherwise create a new instance of C. What I am looking for is the most clean way to achieve this. I have run into trouble trying to use session.get(C, c_id) to lookup instances of C that have not been flushed yet. (I guess this might have something to do with primary keys not working before instances have become persistent?) Furthermore, I want the constructor of D to be where I lookup or create the appropriate instance of P, which seems to require that I pass the session object to the constructor so it can use session.get to look for an existing instance of P. I feel this passing of the session object around, is going to clutter the code, so I am looking for a cleaner way. [snip] You may find the UniqueObject recipe useful: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject It should help with the 'use-existing-or-create-new' part of your problem. I had a few difficulties when I tried to use it, but on reflection I think that was because I held references to objects after I had cleared the session. It also makes it difficult when you really do want to check whether an object exists in the DB without creating it, but it shouldn't be too difficult to adapt. Instead of passing the session object around, you might be able to use the object_session function, which returns the session which the object is associated with, so in your constructor you could try 'session = object_session(self)' Hope that helps, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: SQA failing on table creation
percious wrote: Here is the dump: ...snip... sqlalchemy.exceptions.SQLError: (OperationalError) (1071, 'Specified key was too long; max key length is 999 bytes') '\nCREATE TABLE `Album` (\n\tid INTEGER NOT NULL AUTO_INCREMENT, \n\tname VARCHAR(128), \n\tdirectory VARCHAR(512), \n\t`imageOrder` VARCHAR(512), \n\t`coverImage` INTEGER, \n\tPRIMARY KEY (id), \n\t UNIQUE (directory), \n\t FOREIGN KEY(`coverImage`) REFERENCES `Image` (id)\n)\n\n' () Here is the table code: AlbumTable = Table('Album', metadata, Column('id', Integer, primary_key=True), Column('name', Unicode(128)), Column('directory', Unicode(512), unique=True), Column('imageOrder', Unicode(512)), Column('coverImage', Integer, ForeignKey('Image.id')), ) Mysql version 5.0.27 TIA -chris I think this is because of your 'unique=True' on your Unicode directory column. MySQL is building a unique index on that column, and the number of bytes that it uses per character varies depending on the encoding. If it is UTF-16, for example, it will use 2 bytes per character, so your VARCHAR(512) column would be 1024 bytes, and as the error message says, the max key length is 999 bytes. This is a MySQL problem, not SQLAlchemy. I don't know what the solution is - you may need to play with MySQL's character encoding. See for example things like: http://www.xaprb.com/blog/2006/04/17/max-key-length-in-mysql/ Hope that helps, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: How do I tell if an object has been INSERTed or UPDATEd?
Marco Mariani wrote: Simon Willison wrote: I've got a bit of code that looks like this: session = get_session() session.save(obj) session.flush() You can see what's going to be inserted/updated/deleted by accessing session.new, session.dirty, session.deleted http://www.sqlalchemy.org/docs/unitofwork.myt What's the best way of telling if obj has been newly created (INSERT) or merely updated (UPDATE)? I tried just checking for obj.id is None but I can't garauntee that my primary key is called 'id'. I would hope so! :-)) If you are wanting to know _after_ the session.flush(), I don't think session.new/dirty/deleted will help you. Also, your primary key will be read back from the database immediately after INSERT, so it won't be None. Between, the save and the flush, obj in session.new should do the job. Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Lazy loading advantages and disadvantages
Adam M Peacock wrote: Is there a difference in the SQL executed when using lazy vs eager loading? Specifically, if I use eager loading will everything be queried at once with a more efficient join, or will it still use the lazy style (as far as I understand it) of generating a ton extra queries as it loads each relation separately? If it is the former, more efficient case (an eager relation uses a join) is it possible to override the loader type at query time, such as being lazy by default but being nice to the database when I know I'm going to need all the data from the relation (especially if I'm calling a couple thousand rows for a report)? Eager loads are performed using a join, so only a single query is issued. You can change the eager/lazy behaviour at query time by using the 'options' method on the query object. See http://www.sqlalchemy.org/docs/datamapping.myt#datamapping_selectrelati ons_eagerload and http://www.sqlalchemy.org/docs/datamapping.myt#datamapping_selectrelati ons_options for more. Hope that helps, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: new setuptools vs local SA copy
Rick Morrison wrote: I keep two versions of SA installed here, one is a stable version installed in the Python site-packages folder, and one is current trunk with some local patches for testing. I used to be able to run tests and programs using the local version by just inserting the local directory into the Python path, and imports would then use that. I've recently upgraded to setuptools 0.6c5 and that doesn't seem to work anymore -- I now always get the version from the site-packages folder. Anyone running this kind of configuration out there run into something like this? The way I've done this is to run 'python setup.py develop' in the SVN checkout. This puts the path to the checkout in easy-install.pth, and it also creates an SQLAlchemy.egg-link file with the same path - I don't know what this is used for. To go back to the stable version I run 'easy_install -U SQLAlchemy'. This seems to work on both Windows and Linux, but I am only on setuptools 0.6c3. This is probably more complicated than it needs to be - I would have thought you can switch just by editing the easy-install.pth file. The correct way is probably to use setuptools' --multi-version switch, and put pkg_resources.require() somewhere in your application, but I've not used that yet. Another thing that I've found very useful (on Linux) is this: http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-p ython Particularly with fast-moving projects like SQLAlchemy and TurboGears, trying to share a single copy of a library between multiple applications without breaking them every time I upgraded the library was getting tricky. There's also working-env: http://blog.ianbicking.org/workingenv-update.html which I haven't tried yet, but has the advantage of working on Windows (apparently). Hope that helps, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: SelectResults, counts and one-to-many relationships
Michael Bayer wrote: I added distinct() to selectresults as a method and made the unit test a little clearer (since i dont like relying on the selectresults mod)... q = sess.query(Department) d = SelectResults(q) d = d.join_to('employees').filter(Employee.c.name.startswith('J')) d = d.distinct() d = d.order_by([desc(Department.c.name)]) ...and... for the order by getting removed during the select, that seemed to be an optimization that got stuck in there and since this is a really fringe use case its never come up, so i removed it and added your test case (only with distinct=True) in rev 2301. I think you're slipping - I had to wait a whole three and a half hours for this fix ;-) Seriously, thanks again, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: iteration over mapper
Jose Soares wrote: Hi all, Probably this is a stupid question, :-[ but I don't understand how to iterate an object mapper to get fields value. --- user = session.query(User).select(id=1) for j in user.c: print j.name logname id password for j in user.c: print j.value 'Column' object has no attribute 'value' The fields are attributes of the 'user' object itself, so the values are at user.logname, user.id and user.password. To get an attribute whose name is stored in a variable, you can use 'getattr': for col in user.c: value = getattr(user, col.name) print col.name, value Hope that helps, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Using .label() on boolean expressions
Hi, I don't know if this is valid SQL, but MySQL seems to accept it... I'd like to write a query that looks like: SELECT s.result LIKE 'Pass%' AS pass ... Which would return 1 or 0 for each row depending on whether the result column begins with Pass. In SQLAlchemy this would become: sa.select([s.c.result.startswith('Pass').label('pass')] ...) Without the .label(), this works, but I can't label it because BooleanExpressions don't have a label method. Is there another way to do this? Thanks, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Using .label() on boolean expressions
Simon King wrote: I don't know if this is valid SQL, but MySQL seems to accept it... I'd like to write a query that looks like: SELECT s.result LIKE 'Pass%' AS pass ... Which would return 1 or 0 for each row depending on whether the result column begins with Pass. Another way I tried to do this was to use the SQL: SELECT IF(s.result LIKE 'Pass%', 'Pass', 'Fail') AS pass ... because that would be a function rather than a boolean expression, and functions can be labelled. I knew I couldn't call 'sa.func.if', but I thought it would be nice if you could use sa.func.if_ - the _FunctionGateway object could strip the trailing underscore from the name. It took me a while to realise I could use sa.func.IF, but the capital letters look ugly :-). Alternatively, _FunctionGateway could be given a __call__ method which would take the name as a parameter, so you could use 'sa.func(if)'. Just an idea. Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Questions about polymorphic mappers
Michael Bayer wrote: Simon King wrote: [requirements for instances returned from MapperExtension.create_instance] at this point the entity_name should get set after your custom create_instance is called (at least thats in the trunk). init_attr is not required, it pre-sets attributes on the object that are otherwise auto-created later (but the autocreation step throws a single AttributeError per attribute, which hits performance a little bit). Thanks a lot for explaining that. It looks to me like I would be better off simply using this method to load my class hierarchy, rather than trying to twist polymorphic_identity into something that it was never meant to do. Also, adding get_polymorphic_identity as a MapperExtension method would add an overhead for every single object load for what is probably a very infrequently used feature - I'd hate to be responsible for that! Yet again, SQLAlchemy is already able to do exactly what I want - sorry it's taken a while for me to realise it. Cheers, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Questions about polymorphic mappers
Micheal Bayer wrote: id rather just add another plugin point on MapperExtension for this, which takes place before the polymorphic decision stage at the top of the _instance method, like get_polymorphic_identity(). that way you could do all of this stuff cleanly in an extension (and id do that instead of making polymorphic_identity into a list). hows that sound? That would be ideal for me, and would seem to be the most flexible solution as well - it leaves the decision for which class to use up to the application. What would it actually return, though? An instance ready to be populated? Thanks a lot, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Questions about polymorphic mappers
Michael Bayer wrote: i think using the polymorphic_map is OK. i downplayed its existence since I felt it was confusing to people, which is also the reason i made the _polymorphic_map argument to mapper private; it was originally public. but it seemed like it was producing two ways of doing the same thing so i made it private. OK - I'll carry on using that then. using class_mapper() function instead of class.mapper Ah - that's what I was missing. I hadn't seen the class_mapper function. Thanks for that. as far as having multiple polymorphic_identity values map to the same class, i would think we could just have polymorphic_identity be a list instead of a scalar. right now, if you just inserted multiple values for the same class in polymorphic_map, it would *almost* work except that the save() process is hardwiring the polymorphic_on column to the single polymorphic_identity value no matter what its set to. so attached is an untested patch which accepts either a scalar or a list value for polymorphic_identity, and if its a list then instances need their polymorphic_on attribute set to a valid entry before flushing. try this out and see if it does what you need, and i can easily enough add this to the trunk to be available in the next release (though id need to write some tests also). I think this would definitely be a useful feature, and in fact I was originally going to attempt (or at least suggest!) something like that myself. I'll try the patch and let you know how well it works. However, I still have a situation where I would like to be able to use a default class for unknown types. I don't want to hard-code all the possible options up-front - only the ones that I actually want to treat specially. I've been playing around with some different options, and this is what I've ended up with: class EmployeeMeta(type): def __call__(cls, kind, _fix_class=True, **kwargs): if not _fix_class: return type.__call__(cls, kind=kind, **kwargs) cls = get_employee_class(kind) return cls(kind=kind, _fix_class=False, **kwargs) def get_employee_class(kind): if kind == 'manager': return Manager else: return Employee class Employee(object): __metaclass__ = EmployeeMeta class Manager(Employee): pass class EmployeeMapperExtension(sa.MapperExtension): def create_instance(self, mapper, selectcontext, row, class_): cls = get_employee_class(row[employee_table.c.kind]) if class_ != cls: return sa.class_mapper(cls)._instance(selectcontext, row) return sa.EXT_PASS assign_mapper(ctx, Employee, employee_table, extension=EmployeeMapperExtension()) assign_mapper(ctx, Manager, inherits=Employee.mapper) This seems to do the right thing - Manager instances get created for managers, but any other row becomes an Employee. To add a subclass for another row type, I just need to adapt the get_employee_class function and add another call to assign_mapper. With a bit more work in the metaclass, it could all be done with a special attribute in the subclass. The only thing I'm not sure about is the mapper extension - is it OK to call the mapper._instance method, or is there a better way to do this? Thanks again, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~--- inheritance_test.py Description: inheritance_test.py