New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AssertionError when saving changes of multiple objects #171

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

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

This comment has been minimized.

Show comment
Hide comment
@kozlovsky

kozlovsky Mar 22, 2016

Member

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.

Member

kozlovsky commented Mar 22, 2016

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

This comment has been minimized.

Show comment
Hide comment
@mpurdon

mpurdon Mar 24, 2016

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

Thanks!

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 added a commit that referenced this issue Apr 4, 2016

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/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment