def test_procurement_boundary(self): vocab.add_linked_art_boundary_check() a = model.Activity() p = vocab.ProvenanceEntry() a.caused = p js = factory.toJSON(a) self.assertTrue(not 'classified_as' in js['caused'][0])
def related_procurement(self, hmo, tx_label_args, current_tx=None, current_ts=None, buyer=None, seller=None, previous=False, ident=None, make_label=None): ''' Returns a new `vocab.ProvenanceEntry` object (and related acquisition) that is temporally related to the supplied procurement and associated data. The new procurement is for the given object, and has the given buyer and seller (both optional). If the `previous` flag is `True`, the new procurement is occurs before `current_tx`, and if the timespan `current_ts` is given, has temporal data to that effect. If `previous` is `False`, this relationship is reversed. The `make_label` argument, if supplied, is used as a function to generate the label for the provenance entry. Its arguments (generated in `handle_prev_post_owner`) are: * helper: the helper object for the current pipeline * sale_type: the sale type passed to `handle_prev_post_owner` (e.g. "Auction") * transaction: the transaction type being handled (e.g. "Sold") * rel: a string describing the relationship between this provenance entry and the object (e.g. "leading to the previous ownership of") * N trailing arguments used that are the contents of the `lot_object_key` tuple passed to `handle_prev_post_owner` ''' def _make_label_default(helper, sale_type, transaction, rel, *args): strs = [str(x) for x in args] return ', '.join(strs) if make_label is None: make_label = _make_label_default tx = vocab.ProvenanceEntry(ident=ident) tx_label = make_label(*tx_label_args) tx._label = tx_label tx.identified_by = model.Name(ident='', content=tx_label) if current_tx: if previous: tx.ends_before_the_start_of = current_tx else: tx.starts_after_the_end_of = current_tx modifier_label = 'Previous' if previous else 'Subsequent' try: pacq = model.Acquisition( ident='', label=f'{modifier_label} Acquisition of: “{hmo._label}”') pxfer = model.TransferOfCustody( ident='', label=f'{modifier_label} Transfer of Custody of: “{hmo._label}”' ) except AttributeError: pacq = model.Acquisition(ident='', label=f'{modifier_label} Acquisition') pxfer = model.TransferOfCustody( ident='', label=f'{modifier_label} Transfer of Custody') pacq.transferred_title_of = hmo pxfer.transferred_custody_of = hmo if buyer: pacq.transferred_title_to = buyer pxfer.transferred_custody_to = buyer if seller: pacq.transferred_title_from = seller pxfer.transferred_custody_from = seller tx.part = pacq tx.part = pxfer if current_ts: if previous: pacq.timespan = timespan_before(current_ts) else: pacq.timespan = timespan_after(current_ts) return tx, pacq
def __call__(self, data, non_auctions, event_properties, problematic_records, transaction_types): '''Add modeling data for the auction of a lot of objects.''' self.helper.copy_source_information(data['_object'], data) auction_houses_data = event_properties['auction_houses'] auction_locations = event_properties['auction_locations'] auction_data = data['auction_of_lot'] try: lot_object_key = object_key(auction_data) except Exception as e: warnings.warn( f'Failed to compute lot object key from data {auction_data} ({e})' ) pprint.pprint({k: v for k, v in data.items() if v != ''}, stream=sys.stderr) raise cno, lno, date = lot_object_key sale_type = non_auctions.get(cno, 'Auction') ask_price = data.get('ask_price', {}).get('ask_price') if ask_price: # if there is an asking price/currency, it's a direct sale, not an auction; # filter these out from subsequent modeling of auction lots. warnings.warn( f'Skipping {cno} {lno} because it asserts an asking price') return if sale_type != 'Auction': # the records in this sales catalog do not represent auction sales, so the # price data should not be asserted as a sale price, but instead as an # asking price. with suppress(KeyError): prices = data['price'] del data['price'] if prices: price_data = prices[0] price = get_crom_object(price_data) if price: ma = vocab.add_classification(price, vocab.AskingPrice) data['ask_price'] = add_crom_data(price_data, ma) shared_lot_number = self.helper.shared_lot_number_from_lno(lno) uid, uri = self.helper.shared_lot_number_ids(cno, lno, date) sale_data = {'uid': uid, 'uri': uri} lot = self.helper.sale_for_sale_type(sale_type, lot_object_key) data['lot_object_id'] = f'{cno} {lno} ({date})' if 'link_to_pdf' in auction_data: url = auction_data['link_to_pdf'] page = vocab.WebPage(ident=url, label=url) lot.referred_to_by = page for problem_key, problem in problematic_records.get('lots', []): # TODO: this is inefficient, but will probably be OK so long as the number # of problematic records is small. We do it this way because we can't # represent a tuple directly as a JSON dict key, and we don't want to # have to do post-processing on the services JSON files after loading. if tuple(problem_key) == lot_object_key: note = model.LinguisticObject(ident='', content=problem) problem_classification = model.Type( ident=self.helper.problematic_record_uri, label='Problematic Record') problem_classification.classified_as = vocab.instances[ "brief text"] note.classified_as = problem_classification lot.referred_to_by = note cite_content = [] if data.get('transaction_so'): cite_content.append(data['transaction_so']) if data.get('transaction_cite'): cite_content.append(data['transaction_cite']) if cite_content: content = ', '.join(cite_content) cite = vocab.BibliographyStatement( ident='', content=content, label='Source of transaction type') cite.identified_by = model.Name( ident='', content='Source of transaction type') lot.referred_to_by = cite transaction = data.get('transaction') SOLD = transaction_types['sold'] WITHDRAWN = transaction_types['withdrawn'] self.set_lot_objects(lot, cno, lno, sale_data['uri'], data, sale_type) auction, _, _ = self.helper.sale_event_for_catalog_number( cno, sale_type) if transaction not in WITHDRAWN: lot.part_of = auction event_dates = event_properties['auction_dates'].get(cno) auction_houses = [ get_crom_object(self.helper.add_auction_house_data(h.copy())) for h in auction_houses_data.get(cno, []) ] self.set_lot_auction_houses(lot, cno, auction_houses) self.set_lot_location(lot, cno, auction_locations) self.set_lot_date(lot, auction_data, event_dates) self.set_lot_notes(lot, auction_data, sale_type) tx_uri = self.helper.transaction_uri_for_lot(auction_data, data) lots = self.helper.lots_in_transaction(auction_data, data) tx = vocab.ProvenanceEntry(ident=tx_uri) tx_label = prov_entry_label(self.helper, sale_type, transaction, 'of', cno, lots, date) tx._label = tx_label tx.identified_by = model.Name(ident='', content=tx_label) tx.caused_by = lot tx_data = {'uri': tx_uri} if transaction in SOLD: if sale_type == 'Auction': # the records in this sales catalog represent auction sales, so the # price data for a sale should be asserted as a hammer price. with suppress(KeyError): prices = data['price'] if prices: price_data = prices[0] price = get_crom_object(price_data) if price: vocab.add_classification( price, vocab.HammerPrice) multi = self.helper.transaction_contains_multiple_lots( auction_data, data) if multi: tx_data['multi_lot_tx'] = lots with suppress(AttributeError): tx_data['_date'] = lot.timespan data['_prov_entry_data'] = add_crom_data(data=tx_data, what=tx) data['_event_causing_prov_entry'] = add_crom_data(data=sale_data, what=lot) yield data