Hi Conor, Many apologies for being pushy but since I'm pretty much in the processing of finishing up my code (due in two days), I wonder if you could just take a look at the last three posts of mine---these constitute the final hurdle and I'll be done :)
Cheers, Az On Jun 9, 9:46 pm, Conor <[email protected]> wrote: > On 06/09/2010 02:45 PM, Az wrote: > > > > >> Expected: students, supervisors, projects, dictionaries of said objects, > >> and other attribute values (strings, ints, lists, etc.). Unexpected: > >> anything else, especially sessions, InstanceState objects, or other ORM > >> support objects. > > > Actually got some stuff like the following (copy-pasting bits from my > > print output): > > > (<class 'sqlalchemy.orm.state.InstanceState'>,) > > {'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at > > 0x2d5beb0>, 'proj_id': 1100034, 'postsim_probs': [], 'proj_sup': 1291, > > 'presim_pop': 0, 'own_project': False, 'allocated': False, > > 'proj_name': 'MPC on a Chip', 'blocked': False} > > > Stuff like that :S > > I'm not sure what that printout indicates. Try this as your debug printout: > > def get_memo_type_count(memo): > retval = {} > for obj in memo.itervalues(): > type_ = obj.__class__ > retval[type_] = retval.get(type_, 0) + 1 > return retval > > [perform deep copies] > type_count = get_memo_type_count(memo) > import pprint > pprint.pprint(type_count) > > This will tell you, e.g. how may Student objects were copied, how many > InstanceState objects were copied, etc. Remember that you will have to > override __deepcopy__ on your mapped classes or use the > use-case-specific copy function to prevent ORM attributes (such as > _sa_instance_state) from being copied. > > > > > [...] > >> The most likely cause is if you call session.add(temp_alloc) after > >> calling session.merge(temp_alloc) for the same temp_alloc object. I > >> noticed your original monteCarloBasic had two calls to > >> session.add(temp_alloc); did both get changed to > >> session.merge(temp_alloc)? If that doesn't work, can you verify that > >> SQLAlchemy's primary key for SimAllocation matches the database's > >> primary key for sim_alloc? What column type are you using for uid? Which > >> call to session.merge is failing (line 163 according to your traceback), > >> the one inside your "for rank in ranks" loop or the one outside? > > > Oh yeah good point, they're separate calls. Basically for the one in > > "for rank in ranks" > > adds for a student getting a project, the other adds if a student > > doesn't get a project since we want > > to track all students (allocated or not, since the state of being > > unallocated is what gives > > us motivation to optimise the results). > > Your original monteCarloBasic definition had this: > > for rank in ranks: > proj = random.choice(list(student.preferences[rank])) > if not (proj.allocated or proj.blocked or proj.own_project): > [...] > session.add(temp_alloc) # #1 > break > > ident += 1 > session.add(temp_alloc) # #2 > > session.add #1 is redundant since #2 gets called regardless of whether > the student gets allocated a project or not (ignoring exceptions). Just > a minor nitpick. > > > Anyway, session.merge() is for overwriting previously existing values > > right? Now thanks to the UUID I can add multiple calls to > > monteCarloBasic() to my physical database :) > > session.merge gives you "find or create" behavior: look for an existing > object in the database, or create a new one if no existing object is > found. Note that session.merge requires you to completely fill in the > object's primary key whereas session.add does not. > > > I basically wrote a small function that, for everytime the > > monteCarloBasic() is called, will append the UUID, the number of > > trials ran and the date-time to a text file. My supervisor would have > > to copy paste that into a GUI text field or the command line but it's > > not that much of a hassle, given the usefulness of the database. > > Sounds pretty ugly. What if you add extra tables to represent runs > and/or trials? > > class Run(Base): > # Having a separate table here gives you nice auto-incrementing run ids > # and lets you attach additional information to a run, such as timestamp, > # human-supplied comment, etc. > __tablename__ = 'run' > id = Column(Integer, primary_key=True) > timestamp = Column(DateTime, nullable=False) > # comment = Column(UnicodeText(100), nullable=False) > > trials = relationship('Trial', > back_populates='run', > order_by=lambda: Trial.id.asc()) > > class Trial(Base): > # Having a separate table here is of dubious value, but hey it makes the > # relationships a bit nicer! > __tablename__ = 'trial' > __table_args__ = (PrimaryKeyConstraint('run_id', 'id'), {}) > run_id = Column(Integer, ForeignKey('run.id')) > id = Column(Integer) > > run = relationship('Run', back_populates='trials') > sim_allocs = relationship('SimAllocation', back_populates='trial') > > class SimAllocation(Base): > ... > __table_args__ = (PrimaryKeyConstraint('run_id', 'trial_id', 'stud_id'), > ForeignKeyConstraint(['run_id', 'trial_id'], > ['trial.run_id', 'trial.id']), > {}) > > run_id = Column(Integer) > trial_id = Column(Integer) > stud_id = Column(Integer) > > trial = relationship('Trial', back_populates='sim_allocs') > > -Conor -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to [email protected]. 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.
