AssertionError when saving changes of multiple objects #171

Closed
mpurdon opened this Issue Mar 22, 2016 · 2 comments

Projects

None yet

2 participants

@mpurdon
mpurdon commented Mar 22, 2016

Given the following models:

class Booking(db.Entity):
    """
    Represents a charter booking

    """
    _table_ = "booking"

    id = PrimaryKey(int, auto=True)
    confirmation_number = Optional(unicode, unique=True)
    created_on = Required(datetime.datetime, default=datetime.datetime.now)
    travelling_on = Required(datetime.date)
    contact_name = Required(unicode, 255)
    contact_email = Required(unicode, 255)
    contact_phone = Required(unicode, 20)
    notes = Optional(unicode, 1024)
    passengers = Set('Passenger', cascade_delete=True)
    agent = Required('Agent')
    fare = Required('Fare')
    subtotal = Required(Decimal, default='0.00')
    total = Required(Decimal, default='0.00')
    grand_total = Required(Decimal, default='0.00')
    owing = Required(Decimal, default='0.00')
    currency = Required('Currency')
    flight = Optional('Flight')
    fare_adjustments = Set("BookingFareAdjustment", cascade_delete=True)
    payments = Set("Payment", cascade_delete=True)
    status = Required(BookingStatus)
    status_history = Set("BookingStatusHistory", cascade_delete=True)

class Flight(db.Entity):
    """
    Represents a flight

    """
    _table_ = "flight"

    id = PrimaryKey(int, auto=True)
    flight_number = Optional(unicode, 10)
    category = Required(FlightCategory)
    sectors = Set("Sector", cascade_delete=True)
    aircraft = Required('Aircraft')
    travel_date = Required(date)
    pilot = Optional(unicode, 255)
    notes = Optional(LongUnicode)
    booking = Optional('Booking')
    status = Required(FlightStatus)

The Postgresql database generates a valid table schema:

CREATE TABLE flight
(
  id serial NOT NULL,
  category text NOT NULL,
  aircraft integer NOT NULL,
  travel_date date NOT NULL,
  pilot character varying(255) NOT NULL,
  notes text NOT NULL,
  status text NOT NULL,
  CONSTRAINT flight_pkey PRIMARY KEY (id),
  CONSTRAINT fk_flight__aircraft FOREIGN KEY (aircraft)
      REFERENCES aircraft (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);
ALTER TABLE flight
  OWNER TO maw;

-- Index: idx_flight__aircraft

-- DROP INDEX idx_flight__aircraft;

CREATE INDEX idx_flight__aircraft
  ON flight
  USING btree
  (aircraft);

When I insert a booking and a flight like this:

            confirmed_booking = Booking(created_on=feb_26_2016.astimezone(pytz.UTC),
                                        agent=marnie,
                                        fare=fare,
                                        currency=fare.currency,
                                        travelling_on=mar_10_2016.astimezone(pytz.UTC),
                                        status=BookingStatus.created,
                                        contact_name='Matthew Purdon',
                                        contact_email='foo@@example.com',
                                        contact_phone='123.456.4897',
                                        notes='pax travelling on Virgin flight VA-234')

            flight = Flight(
                booking=confirmed_booking,
                aircraft=ac_j8_mqs,
                category=FlightCategory['charter'],
                travel_date=mar_10_2016.astimezone(pytz.UTC),
                pilot="Crash McEwen",
                notes="Make sure you bring life jackets.",
                status=FlightStatus['created']
            )

I get the following error

  File "<auto generated wrapper of commit() function>", line 2, in commit
  File "venv\lib\site-packages\pony\utils.py", line 65, in cut_traceback
    return func(*args, **kwargs)
  File "venv\lib\site-packages\pony\orm\core.py", line 596, in commit
    if cache is not None: cache.commit()
  File "venv\lib\site-packages\pony\orm\core.py", line 1518, in commit
    if cache.modified: cache.flush()
  File "venv\lib\site-packages\pony\orm\core.py", line 1583, in flush
    if obj is not None: obj._save_()
  File "venv\lib\site-packages\pony\orm\core.py", line 4734, in _save_
    else: assert False, "_save_() called for object %r with incorrect status %s" % (obj, status)  # pragma: no cover
AssertionError: _save_() called for object Flight[1] with incorrect status inserted

If I remove the assignment of booking to flight everything works ok. I inspected the variable stack using PyCharm's debugger and indeed the status is "inserted" for the Flight object:

__exception__ = {tuple} <type 'tuple'>: (<type 'exceptions.AssertionError'>, AssertionError('_save_() called for object Flight[1] with incorrect status inserted',), None)
cache = {SessionCache} <pony.orm.core.SessionCache object at 0x000000000495A0B8>
 collection_statistics = {dict} {}
 connection = {NoneType} None
 database = {Database} <pony.orm.core.Database object at 0x0000000003E833C8>
 db_session = {DBSessionContextManager} <pony.orm.core.DBSessionContextManager object at 0x0000000003D9A258>
 for_update = {set} set([Airport[8], BookingStatusHistory[new:78], Agency[1], ExchangeRate[1], Location[4], PaymentMethod[1], Fare[1], Fare[2], Booking[1], BookingStatusHistory[new:81], Passenger[1], BookingStatusHistory[new:84], Location[7], FareAdjustment[6], Airport[2], Bo
 immediate = {bool} True
 in_transaction = {bool} False
 indexes = {defaultdict} defaultdict(<type 'dict'>, {(BookingFareAdjustment.id,): {1: BookingFareAdjustment[1]}, (Location.id,): {1: Location[1], 2: Location[2], 3: Location[3], 4: Location[4], 5: Location[5], 6: Location[6], 7: Location[7], 8: Location[8], 9: Location[9], 10: Loc
 is_alive = {bool} False
 max_id_cache = {dict} {}
 modified = {bool} True
 modified_collections = {defaultdict} defaultdict(<type 'set'>, {})
 noflush_counter = {int} 0
 num = {int} 3
 obj_labels_cache = {dict} {}
 objects_to_save = {list} <type 'list'>: [Airframe[1], Airframe[2], Airframe[3], Aircraft[1], Aircraft[2], Aircraft[3], Aircraft[4], Aircraft[5], Location[1], Location[2], Location[3], Location[4], Location[5], Location[6], Location[7], Location[8], Location[9], Location[10], Locat
  __len__ = {int} 90
  00 = {Airframe} de Havilland Canada Twin Otter
  01 = {Airframe} Britton-Norman Islander
  02 = {Airframe} Merlyn Commander
  03 = {Aircraft} J8-MQS
  04 = {Aircraft} J8-KIM
  05 = {Aircraft} J8-PUG
  06 = {Aircraft} J8-PIE
  07 = {Aircraft} J8-CIW
  08 = {Location} Location[1]
  09 = {Location} Location[2]
  10 = {Location} Location[3]
  11 = {Location} Location[4]
  12 = {Location} Location[5]
  13 = {Location} Location[6]
  14 = {Location} Location[7]
  15 = {Location} Location[8]
  16 = {Location} Location[9]
  17 = {Location} Location[10]
  18 = {Location} Location[11]
  19 = {Location} Location[12]
  20 = {Location} Location[13]
  21 = {Location} Location[14]
  22 = {Location} Location[15]
  23 = {Airport} Airport[1]
  24 = {Airport} Airport[2]
  25 = {Airport} Airport[3]
  26 = {Airport} Airport[4]
  27 = {Airport} Airport[5]
  28 = {Airport} Airport[6]
  29 = {Airport} Airport[7]
  30 = {Airport} Airport[8]
  31 = {Airport} Airport[9]
  32 = {Agency} Agency[1]
  33 = {Agent} Agent[1]
  34 = {Currency} Currency[1]
  35 = {Currency} Currency[2]
  36 = {ExchangeRate} ExchangeRate[1]
  37 = {ExchangeRate} ExchangeRate[2]
  38 = {PaymentMethod} PaymentMethod[1]
  39 = {PaymentMethod} PaymentMethod[2]
  40 = {PaymentMethod} PaymentMethod[3]
  41 = {PaymentMethod} PaymentMethod[4]
  42 = {PaymentMethod} PaymentMethod[5]
  43 = {FareAdjustmentType} FareAdjustmentType[1]
  44 = {FareAdjustmentType} FareAdjustmentType[2]
  45 = {FareAdjustmentType} FareAdjustmentType[3]
  46 = {FareAdjustmentType} FareAdjustmentType[4]
  47 = {FareAdjustmentType} FareAdjustmentType[5]
  48 = {FareAdjustmentType} FareAdjustmentType[6]
  49 = {FareAdjustmentType} FareAdjustmentType[7]
  50 = {FareAdjustmentType} FareAdjustmentType[8]
  51 = {FareAdjustment} FareAdjustment[1]
  52 = {FareAdjustment} FareAdjustment[2]
  53 = {FareAdjustment} FareAdjustment[3]
  54 = {FareAdjustment} FareAdjustment[4]
  55 = {FareAdjustment} FareAdjustment[5]
  56 = {FareAdjustment} FareAdjustment[6]
  57 = {FareAdjustment} FareAdjustment[7]
  58 = {FareAdjustment} FareAdjustment[8]
  59 = {FareAdjustment} FareAdjustment[9]
  60 = {FareAdjustment} FareAdjustment[10]
  61 = {FareAdjustment} FareAdjustment[11]
  62 = {FareAdjustment} FareAdjustment[12]
  63 = {FareAdjustment} FareAdjustment[13]
  64 = {FareAdjustment} FareAdjustment[14]
  65 = {FareAdjustment} FareAdjustment[15]
  66 = {FareAdjustment} FareAdjustment[16]
  67 = {FareAdjustment} FareAdjustment[17]
  68 = {Fare} Fare[1]
  69 = {Fare} Fare[2]
  70 = {Booking} Matthew Purdon travelling from A to B on 2016-03-10
  71 = {Passenger} Passenger[1]
  72 = {BookingFareAdjustment} FareAdjustment[16] adjustment to booking Matthew Purdon travelling from A to B on 2016-03-10
  73 = {Payment} Payment[1]
  74 = {BookingStatusHistory} BookingStatusHistory[1]
  75 = {Flight} Flight[1]
   _access_rules_ = {defaultdict} defaultdict(<type 'set'>, {})
   _adict_ = {dict} {'category': Flight.category, 'status': Flight.status, 'travel_date': Flight.travel_date, 'sectors': Flight.sectors, 'notes': Flight.notes, 'aircraft': Flight.aircraft, 'flight_number': Flight.flight_number, 'id': Flight.id, 'booking': Flight.booking, 'pil
   _all_bases_ = {set} set([])
   _all_bits_ = {int} 127
   _all_bits_except_volatile_ = {int} 127
   _attrnames_cache_ = {dict} {}
   _attrs_ = {list} <type 'list'>: [Flight.id, Flight.flight_number, Flight.category, Flight.sectors, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.booking, Flight.status]
   _attrs_with_columns_ = {list} <type 'list'>: [Flight.id, Flight.flight_number, Flight.category, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.status]
   _base_attrs_ = {list} <type 'list'>: []
   _batchload_sql_cache_ = {dict} {}
   _bits_ = {dict} {Flight.flight_number: 1, Flight.travel_date: 8, Flight.booking: 0, Flight.id: 0, Flight.aircraft: 4, Flight.notes: 32, Flight.sectors: 0, Flight.category: 2, Flight.pilot: 16, Flight.status: 64}
   _bits_except_volatile_ = {dict} {Flight.flight_number: 1, Flight.travel_date: 8, Flight.booking: 0, Flight.id: 0, Flight.aircraft: 4, Flight.notes: 32, Flight.sectors: 0, Flight.category: 2, Flight.pilot: 16, Flight.status: 64}
   _cached_max_id_sql_ = {NoneType} None
   _columns_ = {list} <type 'list'>: ['id', 'flight_number', 'category', 'aircraft', 'travel_date', 'pilot', 'notes', 'status']
   _columns_without_pk_ = {list} <type 'list'>: ['flight_number', 'category', 'aircraft', 'travel_date', 'pilot', 'notes', 'status']
   _composite_keys_ = {list} <type 'list'>: []
   _converters_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGIntConverter object at 0x0000000004952D68>, <pony.orm.dbproviders.postgres.PGStrConverter object at 0x00000000049479B0>, <maw.orm.converters.EnumConverter object at 0x0000000004947A20>, <pony.orm.dbproviders
   _converters_without_pk_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGStrConverter object at 0x00000000049479B0>, <maw.orm.converters.EnumConverter object at 0x0000000004947A20>, <pony.orm.dbproviders.postgres.PGIntConverter object at 0x000000000494DDA0>, <pony.orm.dbapiprovid
   _database_ = {Database} <pony.orm.core.Database object at 0x0000000003E833C8>
   _dbvals_ = {dict} {Flight.flight_number: u'', Flight.travel_date: datetime.date(2016, 3, 10), Flight.aircraft: Aircraft[1], Flight.notes: u'Make sure you bring life jackets.', Flight.category: <FlightCategory.charter: 0>, Flight.pilot: u'Crash McEwen', Flight.status: <Fligh
    __len__ = {int} 7
    Flight.aircraft (71611624) = {Aircraft} J8-MQS
    Flight.category (71611272) = {FlightCategory} FlightCategory.charter
    Flight.flight_number (71610920) = {unicode} u''
    Flight.notes (71612680) = {unicode} u'Make sure you bring life jackets.'
    Flight.pilot (71612328) = {unicode} u'Crash McEwen'
    Flight.status (71613384) = {FlightStatus} FlightStatus.created
    Flight.travel_date (71611976) = {date} 2016-03-10
   _default_genexpr_ = {instance} GenExprInner: GenExprInner(Name('f'), [GenExprFor(AssName('f', 'OP_ASSIGN'), Name('.0'), [])])
   _default_iter_name_ = {str} 'f'
   _delete_sql_cache_ = {dict} {}
   _direct_bases_ = {list} <type 'list'>: []
   _discriminator_ = {NoneType} None
   _discriminator_attr_ = {NoneType} None
   _find_sql_cache_ = {dict} {}
   _id_ = {int} 18
   _indexes_ = {list} <type 'list'>: [<pony.orm.core.Index object at 0x000000000446C9D8>]
   _insert_sql_cache_ = {dict} {(Flight.flight_number, Flight.category, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.status): (u'INSERT INTO "flight" ("flight_number", "category", "aircraft", "travel_date", "pilot", "notes", "status") VALUES (%(p1)s, %(p2)s, %
   _keys_ = {list} <type 'list'>: []
   _load_sql_cache_ = {dict} {}
   _multiset_subclass_ = {NoneType} None
   _new_attrs_ = {list} <type 'list'>: [Flight.id, Flight.flight_number, Flight.category, Flight.sectors, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.booking, Flight.status]
   _newid_ = {NoneType} None
   _pk_ = {int} 1
   _pk_attrs_ = {tuple} <type 'tuple'>: (Flight.id,)
   _pk_columns_ = {list} <type 'list'>: ['id']
   _pk_converters_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGIntConverter object at 0x0000000004952D68>]
   _pk_is_composite_ = {bool} False
   _pk_nones_ = {tuple} <type 'tuple'>: (None,)
   _pk_paths_ = {list} <type 'list'>: ['id']
   _pkval_ = {int} 1
   _propagation_mixin_ = {type} <class 'pony.orm.core.FlightSetMixin'>
   _rbits_ = {int} 127
   _root_ = {EntityMeta} <class 'api.v1.models.flight.Flight'>
   _save_pos_ = {NoneType} None
   _session_cache_ = {SessionCache} <pony.orm.core.SessionCache object at 0x000000000495A0B8>
   _set_wrapper_subclass_ = {type} <class 'pony.orm.core.FlightSet'>
   _simple_keys_ = {list} <type 'list'>: []
   _status_ = {str} 'inserted'
   _subclass_adict_ = {dict} {}
   _subclass_attrs_ = {list} <type 'list'>: []
   _subclasses_ = {set} set([])
   _table_ = {str} 'flight'
   _update_sql_cache_ = {dict} {}
   _vals_ = {dict} {Flight.flight_number: u'', Flight.travel_date: datetime.date(2016, 3, 10), Flight.booking: Booking[1], Flight.id: 1, Flight.aircraft: Aircraft[1], Flight.notes: u'Make sure you bring life jackets.', Flight.sectors: SetData([Sector[new:77]]), Flight.catego
   _wbits_ = {int} 0
   aircraft = {Aircraft} J8-MQS
   booking = {Booking} Matthew Purdon travelling from BGI to MQS on 2016-03-10
    _access_rules_ = {defaultdict} defaultdict(<type 'set'>, {})
    _adict_ = {dict} {'fare': Booking.fare, 'passengers': Booking.passengers, 'confirmation_number': Booking.confirmation_number, 'flight': Booking.flight, 'travelling_on': Booking.travelling_on, 'subtotal': Booking.subtotal, 'notes': Booking.notes, 'status': Booking.status, '
    _all_bases_ = {set} set([])
    _all_bits_ = {int} 65535
    _all_bits_except_volatile_ = {int} 65535
    _attrnames_cache_ = {dict} {}
    _attrs_ = {list} <type 'list'>: [Booking.id, Booking.confirmation_number, Booking.created_on, Booking.travelling_on, Booking.contact_name, Booking.contact_email, Booking.contact_phone, Booking.notes, Booking.passengers, Booking.agent, Booking.fare, Booking.subtotal, Bookin
    _attrs_with_columns_ = {list} <type 'list'>: [Booking.id, Booking.confirmation_number, Booking.created_on, Booking.travelling_on, Booking.contact_name, Booking.contact_email, Booking.contact_phone, Booking.notes, Booking.agent, Booking.fare, Booking.subtotal, Booking.total, Booking.gra
    _base_attrs_ = {list} <type 'list'>: []
    _batchload_sql_cache_ = {dict} {}
    _bits_ = {dict} {Booking.payments: 0, Booking.agent: 128, Booking.passengers: 0, Booking.total: 1024, Booking.fare_adjustments: 0, Booking.currency: 8192, Booking.confirmation_number: 1, Booking.contact_name: 8, Booking.status: 32768, Booking.notes: 64, Booking.subtotal: 
    _bits_except_volatile_ = {dict} {Booking.payments: 0, Booking.agent: 128, Booking.passengers: 0, Booking.total: 1024, Booking.fare_adjustments: 0, Booking.currency: 8192, Booking.confirmation_number: 1, Booking.contact_name: 8, Booking.status: 32768, Booking.notes: 64, Booking.subtotal: 
    _cached_max_id_sql_ = {NoneType} None
    _columns_ = {list} <type 'list'>: ['id', 'confirmation_number', 'created_on', 'travelling_on', 'contact_name', 'contact_email', 'contact_phone', 'notes', 'agent', 'fare', 'subtotal', 'total', 'grand_total', 'owing', 'currency', 'flight', 'status']
    _columns_without_pk_ = {list} <type 'list'>: ['confirmation_number', 'created_on', 'travelling_on', 'contact_name', 'contact_email', 'contact_phone', 'notes', 'agent', 'fare', 'subtotal', 'total', 'grand_total', 'owing', 'currency', 'flight', 'status']
    _composite_keys_ = {list} <type 'list'>: []
    _converters_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGIntConverter object at 0x00000000049527B8>, <pony.orm.dbproviders.postgres.PGStrConverter object at 0x0000000004952898>, <pony.orm.dbproviders.postgres.PGDatetimeConverter object at 0x0000000004952908>, <pon
    _converters_without_pk_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGStrConverter object at 0x0000000004952898>, <pony.orm.dbproviders.postgres.PGDatetimeConverter object at 0x0000000004952908>, <pony.orm.dbapiprovider.DateConverter object at 0x0000000004952978>, <pony.orm.db
    _database_ = {Database} <pony.orm.core.Database object at 0x0000000003E833C8>
    _dbvals_ = {dict} {Booking.agent: Agent[1], Booking.total: Decimal('0.00'), Booking.currency: Currency[1], Booking.confirmation_number: u'bZDL61aX', Booking.contact_name: u'Matthew Purdon', Booking.status: <BookingStatus.confirmed: 3>, Booking.notes: u'pax travelling on Vir
    _default_genexpr_ = {instance} GenExprInner: GenExprInner(Name('b'), [GenExprFor(AssName('b', 'OP_ASSIGN'), Name('.0'), [])])
    _default_iter_name_ = {str} 'b'
    _delete_sql_cache_ = {dict} {}
    _direct_bases_ = {list} <type 'list'>: []
    _discriminator_ = {NoneType} None
    _discriminator_attr_ = {NoneType} None
    _find_sql_cache_ = {dict} {}
    _id_ = {int} 10
    _indexes_ = {list} <type 'list'>: [<pony.orm.core.Index object at 0x000000000446C2D0>, <pony.orm.core.Index object at 0x000000000446C318>]
    _insert_sql_cache_ = {dict} {(Booking.confirmation_number, Booking.created_on, Booking.travelling_on, Booking.contact_name, Booking.contact_email, Booking.contact_phone, Booking.notes, Booking.agent, Booking.fare, Booking.subtotal, Booking.total, Booking.grand_total, Booking.owing, B
    _keys_ = {list} <type 'list'>: [(Booking.confirmation_number,)]
    _load_sql_cache_ = {dict} {}
    _multiset_subclass_ = {NoneType} None
    _new_attrs_ = {list} <type 'list'>: [Booking.id, Booking.confirmation_number, Booking.created_on, Booking.travelling_on, Booking.contact_name, Booking.contact_email, Booking.contact_phone, Booking.notes, Booking.passengers, Booking.agent, Booking.fare, Booking.subtotal, Bookin
    _newid_ = {NoneType} None
    _pk_ = {int} 1
    _pk_attrs_ = {tuple} <type 'tuple'>: (Booking.id,)
    _pk_columns_ = {list} <type 'list'>: ['id']
    _pk_converters_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGIntConverter object at 0x00000000049527B8>]
    _pk_is_composite_ = {bool} False
    _pk_nones_ = {tuple} <type 'tuple'>: (None,)
    _pk_paths_ = {list} <type 'list'>: ['id']
    _pkval_ = {int} 1
    _propagation_mixin_ = {NoneType} None
    _rbits_ = {int} 65535
    _root_ = {EntityMeta} <class 'api.v1.models.booking.Booking'>
    _save_pos_ = {NoneType} None
    _session_cache_ = {SessionCache} <pony.orm.core.SessionCache object at 0x000000000495A0B8>
    _set_wrapper_subclass_ = {NoneType} None
    _simple_keys_ = {list} <type 'list'>: [Booking.confirmation_number]
    _status_ = {str} 'inserted'
    _subclass_adict_ = {dict} {}
    _subclass_attrs_ = {list} <type 'list'>: []
    _subclasses_ = {set} set([])
    _table_ = {str} 'booking'
    _update_sql_cache_ = {dict} {}
    _vals_ = {dict} {Booking.payments: SetData([Payment[1]]), Booking.agent: Agent[1], Booking.total: Decimal('0.00'), Booking.fare_adjustments: SetData([BookingFareAdjustment[1]]), Booking.passengers: SetData([Passenger[1]]), Booking.contact_name: u'Matthew Purdon', Booking.
    _wbits_ = {int} 0
    agent = {Agent} Agent[1]
    confirmation_number = {unicode} u'bZDL61aX'
    contact_email = {unicode} u'foo@example.com'
    contact_name = {unicode} u'Matthew Purdon'
    contact_phone = {unicode} u'125.265.1578'
    created_on = {datetime} 2016-02-26 04:56:00+00:00
    currency = {Currency} Currency[1]
    fare = {Fare} Fare[1]
    fare_adjustments = {BookingFareAdjustmentSet} BookingFareAdjustmentSet([...])
    flight = {Flight} Flight[1]
    grand_total = {Decimal} 0.00
    id = {int} 1
    notes = {unicode} u'pax travelling on Virgin flight VA-234'
    owing = {Decimal} 0.00
    passengers = {PassengerSet} PassengerSet([...])
    payments = {PaymentSet} PaymentSet([...])
    status = {BookingStatus} BookingStatus.confirmed
    status_history = {BookingStatusHistorySet} BookingStatusHistorySet([...])
    subtotal = {Decimal} 0.00
    total = {Decimal} 0.00
    travelling_on = {date} 2016-03-10
   category = {FlightCategory} FlightCategory.charter
   flight_number = {unicode} u''
   id = {int} 1
   notes = {unicode} u'Make sure you bring life jackets.'
   pilot = {unicode} u'Crash McEwen'
   sectors = {SectorSet} SectorSet([...])
   status = {FlightStatus} FlightStatus.created
   travel_date = {date} 2016-03-10
  76 = {Sector} Sector[new:77]
  77 = {BookingStatusHistory} BookingStatusHistory[new:78]
  78 = {Booking} Prince William travelling from BGI to MQS on 2016-03-14
  79 = {Passenger} Passenger[new:80]
  80 = {BookingStatusHistory} BookingStatusHistory[new:81]
  81 = {BookingStatusHistory} BookingStatusHistory[new:82]
  82 = {Booking} Liar McLiarpants travelling from BGI to MQS on 2016-03-13
  83 = {BookingStatusHistory} BookingStatusHistory[new:84]
  84 = {BookingStatusHistory} BookingStatusHistory[new:85]
  85 = {Booking} Bob Larkin travelling from BGI to MQS on 2016-03-12
  86 = {Passenger} Passenger[new:87]
  87 = {Passenger} Passenger[new:88]
  88 = {BookingFareAdjustment} FareAdjustment[16] adjustment to booking Bob Larkin travelling from BGI to MQS on 2016-03-12
  89 = {BookingStatusHistory} BookingStatusHistory[new:90]
 perm_cache = {defaultdict} defaultdict(<function <lambda> at 0x000000000479AC88>, {})
 query_results = {dict} {}
 saved_fk_state = {NoneType} None
 seeds = {defaultdict} defaultdict(<type 'set'>, {})
 user_roles_cache = {defaultdict} defaultdict(<type 'dict'>, {})
dependent_objects = {NoneType} None
obj = {Flight} Flight[1]
 _access_rules_ = {defaultdict} defaultdict(<type 'set'>, {})
 _adict_ = {dict} {'category': Flight.category, 'status': Flight.status, 'travel_date': Flight.travel_date, 'sectors': Flight.sectors, 'notes': Flight.notes, 'aircraft': Flight.aircraft, 'flight_number': Flight.flight_number, 'id': Flight.id, 'booking': Flight.booking, 'pil
 _all_bases_ = {set} set([])
 _all_bits_ = {int} 127
 _all_bits_except_volatile_ = {int} 127
 _attrnames_cache_ = {dict} {}
 _attrs_ = {list} <type 'list'>: [Flight.id, Flight.flight_number, Flight.category, Flight.sectors, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.booking, Flight.status]
 _attrs_with_columns_ = {list} <type 'list'>: [Flight.id, Flight.flight_number, Flight.category, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.status]
 _base_attrs_ = {list} <type 'list'>: []
 _batchload_sql_cache_ = {dict} {}
 _bits_ = {dict} {Flight.flight_number: 1, Flight.travel_date: 8, Flight.booking: 0, Flight.id: 0, Flight.aircraft: 4, Flight.notes: 32, Flight.sectors: 0, Flight.category: 2, Flight.pilot: 16, Flight.status: 64}
 _bits_except_volatile_ = {dict} {Flight.flight_number: 1, Flight.travel_date: 8, Flight.booking: 0, Flight.id: 0, Flight.aircraft: 4, Flight.notes: 32, Flight.sectors: 0, Flight.category: 2, Flight.pilot: 16, Flight.status: 64}
 _cached_max_id_sql_ = {NoneType} None
 _columns_ = {list} <type 'list'>: ['id', 'flight_number', 'category', 'aircraft', 'travel_date', 'pilot', 'notes', 'status']
 _columns_without_pk_ = {list} <type 'list'>: ['flight_number', 'category', 'aircraft', 'travel_date', 'pilot', 'notes', 'status']
 _composite_keys_ = {list} <type 'list'>: []
 _converters_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGIntConverter object at 0x0000000004952D68>, <pony.orm.dbproviders.postgres.PGStrConverter object at 0x00000000049479B0>, <maw.orm.converters.EnumConverter object at 0x0000000004947A20>, <pony.orm.dbproviders
 _converters_without_pk_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGStrConverter object at 0x00000000049479B0>, <maw.orm.converters.EnumConverter object at 0x0000000004947A20>, <pony.orm.dbproviders.postgres.PGIntConverter object at 0x000000000494DDA0>, <pony.orm.dbapiprovid
 _database_ = {Database} <pony.orm.core.Database object at 0x0000000003E833C8>
 _dbvals_ = {dict} {Flight.flight_number: u'', Flight.travel_date: datetime.date(2016, 3, 10), Flight.aircraft: Aircraft[1], Flight.notes: u'Make sure you bring life jackets.', Flight.category: <FlightCategory.charter: 0>, Flight.pilot: u'Crash McEwen', Flight.status: <Fligh
 _default_genexpr_ = {instance} GenExprInner: GenExprInner(Name('f'), [GenExprFor(AssName('f', 'OP_ASSIGN'), Name('.0'), [])])
 _default_iter_name_ = {str} 'f'
 _delete_sql_cache_ = {dict} {}
 _direct_bases_ = {list} <type 'list'>: []
 _discriminator_ = {NoneType} None
 _discriminator_attr_ = {NoneType} None
 _find_sql_cache_ = {dict} {}
 _id_ = {int} 18
 _indexes_ = {list} <type 'list'>: [<pony.orm.core.Index object at 0x000000000446C9D8>]
 _insert_sql_cache_ = {dict} {(Flight.flight_number, Flight.category, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.status): (u'INSERT INTO "flight" ("flight_number", "category", "aircraft", "travel_date", "pilot", "notes", "status") VALUES (%(p1)s, %(p2)s, %
 _keys_ = {list} <type 'list'>: []
 _load_sql_cache_ = {dict} {}
 _multiset_subclass_ = {NoneType} None
 _new_attrs_ = {list} <type 'list'>: [Flight.id, Flight.flight_number, Flight.category, Flight.sectors, Flight.aircraft, Flight.travel_date, Flight.pilot, Flight.notes, Flight.booking, Flight.status]
 _newid_ = {NoneType} None
 _pk_ = {int} 1
 _pk_attrs_ = {tuple} <type 'tuple'>: (Flight.id,)
 _pk_columns_ = {list} <type 'list'>: ['id']
 _pk_converters_ = {list} <type 'list'>: [<pony.orm.dbproviders.postgres.PGIntConverter object at 0x0000000004952D68>]
 _pk_is_composite_ = {bool} False
 _pk_nones_ = {tuple} <type 'tuple'>: (None,)
 _pk_paths_ = {list} <type 'list'>: ['id']
 _pkval_ = {int} 1
 _propagation_mixin_ = {type} <class 'pony.orm.core.FlightSetMixin'>
 _rbits_ = {int} 127
 _root_ = {EntityMeta} <class 'api.v1.models.flight.Flight'>
 _save_pos_ = {NoneType} None
 _session_cache_ = {SessionCache} <pony.orm.core.SessionCache object at 0x000000000495A0B8>
 _set_wrapper_subclass_ = {type} <class 'pony.orm.core.FlightSet'>
 _simple_keys_ = {list} <type 'list'>: []
 _status_ = {str} 'inserted'
 _subclass_adict_ = {dict} {}
 _subclass_attrs_ = {list} <type 'list'>: []
 _subclasses_ = {set} set([])
 _table_ = {str} 'flight'
 _update_sql_cache_ = {dict} {}
 _vals_ = {dict} {Flight.flight_number: u'', Flight.travel_date: datetime.date(2016, 3, 10), Flight.booking: Booking[1], Flight.id: 1, Flight.aircraft: Aircraft[1], Flight.notes: u'Make sure you bring life jackets.', Flight.sectors: SetData([Sector[new:77]]), Flight.catego
 _wbits_ = {int} 0
 aircraft = {Aircraft} J8-MQS
 booking = {Booking} Matthew Purdon travelling from A to B on 2016-03-10
 category = {FlightCategory} FlightCategory.charter
 flight_number = {unicode} u''
 id = {int} 1
 notes = {unicode} u'Make sure you bring life jackets.'
 pilot = {unicode} u'Crash McEwen'
 sectors = {SectorSet} SectorSet([...])
 status = {FlightStatus} FlightStatus.created
 travel_date = {date} 2016-03-10
status = {str} 'inserted'
@kozlovsky kozlovsky added the bug label Mar 22, 2016
@kozlovsky kozlovsky self-assigned this Mar 22, 2016
@kozlovsky kozlovsky added this to the 0.6.5 milestone Mar 22, 2016
@kozlovsky
Contributor

The bug is appeared when there is a one-to-one relationship consisted of two Optional attributes. It may be reproduced in the following way:

from pony.orm import *

db = Database('sqlite', ':memory:')

class B(db.Entity):
    name = Required(str)
    f = Optional("F")

class F(db.Entity):
    name = Required(str)
    b = Optional("B")

db.generate_mapping(create_tables=True)

sql_debug(True)

with db_session:
    b1 = B(name='B1')
    f1 = F(name='F1', b=b1)

We'll fix it today. The fix will be part of PonyORM 0.6.5 release.

@kozlovsky kozlovsky closed this in f3262e3 Mar 22, 2016
@mpurdon
mpurdon commented Mar 24, 2016

I can confirm that the problem is fixed for me when patching core with this commit.

Thanks!

@kozlovsky kozlovsky changed the title from AssertionError: _save_() called for object with incorrect status inserted to AssertionError when saving changes of multiple objects Apr 4, 2016
@kozlovsky kozlovsky added a commit that referenced this issue Apr 4, 2016
@kozlovsky kozlovsky Pony ORM Release 0.6.5 (2016-04-04)
# Improvements

* Fixes #172: Query prefetch() method should load specified lazy attributes right in the main query if possible

# Bugfixes

* Fixes #168: Incorrect caching when slicing the same query multiple times
* Fixes #169: When py_check() returns False, Pony should truncate too large values in resulting ValueError message
* Fixes #171: AssertionError when saving changes of multiple objects
* Fixes #176: Autostripped strings are not validated correctly for Required attributes

See blog post for more detailed information: https://blog.ponyorm.com/2016/04/04/pony-orm-release-0-6-5/
e96fccb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment