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 sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to