antelope-interface 0.2.6.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {antelope_interface-0.2.6.2/src/antelope_interface.egg-info → antelope_interface-0.3.0}/PKG-INFO +1 -1
  2. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/pyproject.toml +1 -1
  3. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/setup.py +13 -0
  4. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/flows/flow.py +24 -57
  5. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/flows/flow_interface.py +3 -1
  6. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/iforeground.py +15 -6
  7. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/models/__init__.py +30 -8
  8. antelope_interface-0.3.0/src/antelope/models/comparators.py +79 -0
  9. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/base.py +18 -9
  10. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/process_ref.py +5 -3
  11. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0/src/antelope_interface.egg-info}/PKG-INFO +1 -1
  12. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope_interface.egg-info/SOURCES.txt +1 -0
  13. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/LICENSE +0 -0
  14. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/MANIFEST.in +0 -0
  15. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/README.md +0 -0
  16. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/setup.cfg +0 -0
  17. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/__init__.py +0 -0
  18. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/exchanges_from_spreadsheet.py +0 -0
  19. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/flows/__init__.py +0 -0
  20. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/flows/openlca_locales.json +0 -0
  21. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/__init__.py +0 -0
  22. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/abstract_query.py +0 -0
  23. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/ibackground.py +0 -0
  24. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/ibasic.py +0 -0
  25. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/iconfigure.py +0 -0
  26. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/iexchange.py +0 -0
  27. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/iindex.py +0 -0
  28. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/interfaces/iquantity.py +1 -1
  29. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/models/auth.py +0 -0
  30. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/__init__.py +0 -0
  31. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/catalog_ref.py +0 -0
  32. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/exchange_ref.py +0 -0
  33. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/flow_ref.py +0 -0
  34. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/quantity_ref.py +0 -0
  35. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/tests/__init__.py +0 -0
  36. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/refs/tests/test_flows.py +0 -0
  37. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope/xdb_tokens.py +0 -0
  38. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope_interface.egg-info/dependency_links.txt +0 -0
  39. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope_interface.egg-info/requires.txt +0 -0
  40. {antelope_interface-0.2.6.2 → antelope_interface-0.3.0}/src/antelope_interface.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: antelope_interface
3
- Version: 0.2.6.2
3
+ Version: 0.3.0
4
4
  Summary: A common interface for accessing LCA data
5
5
  Author-email: Brandon Kuczenski <bkuczenski@ucsb.edu>
6
6
  License: BSD-3-Clause
@@ -22,7 +22,7 @@ classifiers = [
22
22
  "Topic :: Scientific/Engineering"
23
23
  ]
24
24
  dependencies = ["synonym_dict >= 0.2.4", "pydantic >= 2.5.0"]
25
- version = "0.2.6.2"
25
+ version = "0.3.0"
26
26
 
27
27
  [tool.setuptools.packages.find]
28
28
  where = ["src"]
@@ -5,6 +5,19 @@ setup()
5
5
 
6
6
  """
7
7
  Version History:
8
+ 0.3.0 2024/10/24 - 0.3.0 release. add comparators.
9
+
10
+ 0.3.0-pre 2024/09/22 - pre-release for workshop (minor bugfix on UnallocatedExchange model)
11
+
12
+ 0.2.7 2024/09/10 - synchronization release for background / LCI changes
13
+ add make_ref() machinery to a few interface routes
14
+ alter extend_process to use dependencies instead of inventory
15
+ make deep_lcia() biogenic-aware
16
+ (note: folding observations directly into lci() / abandoning sys_lcia() still to come)
17
+
18
+ 0.2.6.3 2024/08/15 - cutoff_flows and remote traversal compatibility
19
+ - modify FlowInterface and FlowEntity to not die on missing reference_entity
20
+
8
21
  0.2.6.2 2024/06/11 - get_context into basic interface
9
22
  0.2.6.1 2024/06/06 - ItemNotFound
10
23
 
@@ -6,6 +6,7 @@ import re
6
6
  import json
7
7
 
8
8
  from abc import ABC
9
+ from collections import defaultdict
9
10
 
10
11
  from synonym_dict import SynonymSet
11
12
  from synonym_dict.flowables.cas_number import CasNumber, InvalidCasNumber
@@ -20,16 +21,6 @@ def flowname_is_biogenic(flowname):
20
21
  return bool(biogenic.search(flowname))
21
22
 
22
23
 
23
- class QuelledCO2(object):
24
- def __init__(self, flowable, context):
25
- self.flowable = flowable
26
- self.context = context
27
-
28
- @property
29
- def value(self):
30
- return 0.0
31
-
32
-
33
24
  """
34
25
  openlca_locales.json file created from: antelope_olca package, gen_locales('openlca_locales.json')
35
26
  """
@@ -232,7 +223,7 @@ class Flow(FlowInterface, ABC):
232
223
  @property
233
224
  def _chars_seen(self):
234
225
  if self.__chars_seen is None:
235
- self.__chars_seen = dict()
226
+ self.__chars_seen = defaultdict(dict)
236
227
  return self.__chars_seen
237
228
 
238
229
  @property
@@ -242,7 +233,7 @@ class Flow(FlowInterface, ABC):
242
233
  return True
243
234
  return False
244
235
 
245
- def lookup_cf(self, quantity, context, locale, refresh=False, quell_biogenic_co2=None, **kwargs):
236
+ def lookup_cf(self, quantity, context, locale, refresh=False, **kwargs):
246
237
  """
247
238
  Cache characterization factors obtained from quantity relation queries. It is decided to leave this in
248
239
  the interface, since it does not depend on anything from outside the interface.
@@ -251,64 +242,32 @@ class Flow(FlowInterface, ABC):
251
242
  locale to retrieve a cached result. Wildcard results, such as with 'None' specified for any of the three,
252
243
  are not supported.
253
244
 
254
- Two, it requires implementations to properly handle the Quell-Biogenic-CO2 feature (see below). This is
255
- enabled EITHER by passing quell_biogenic_co2 as a parameter OR by assigning it as a property to the quantity.
256
- The valid values for this parameter are True (suppress biogenic CO2), False (treat all flows the same), or
257
- 'only' (inverse of True: quell all flows except biogenic CO2).
245
+ Two, it requires implementations to properly handle the Quell-Biogenic-CO2 feature.
258
246
 
259
247
  BIOGENIC CO2: This function includes a mechanism to suppress ALL impact scores for biogenic CO2. Any flow
260
- can have the is_co2 flag set-- this happens automatically if the flow is given a CAS number that matches
261
- CO2 (124-38-9). It can also be set in client code. If this flag is true, AND the flow's name matches a
248
+ can have the is_co2 flag set-- this happens automatically if the flow is given a name that matches
249
+ 'carbon dioxide' or a CAS number that matches CO2 (124-38-9). It can also be set in client code.
250
+
251
+ If this flag is true, AND the flow's name matches a
262
252
  regexp that describes non-fossil, biogenic, "in air", then the flow is considered to be biogenic CO2 (its
263
253
  quell_co2 property is True).
264
254
 
265
- WHEN performing a lookup, the function determines whether to quell biogenic CO2 in the following two ways:
266
- either the quantity has a property 'quell_biogenic_co2' or the lookup_cf receives a kwarg 'quell_biogenic_co2'
267
- The kwarg overrides the quantity property. IF the boolean value of the specification is 'True', AND the flow's
268
- quell_co2 property is True, THEN the flow will return a "QuelledCO2" characterization that always equals 0.
269
- Otherwise, it will perform the lookup.
270
-
271
- ** Special feature ** setting the quantity's 'quell_biogenic_co2' property to the string "only" will cause it
272
- to return the INVERSE of quell=True - will return quelled CF for all NON-quelled flows and ONLY measure
273
- biogenic CO2.
255
+ It is up to implementation code to handle these properties.
274
256
 
275
257
  :param quantity:
276
258
  :param context:
277
259
  :param locale:
278
260
  :param refresh: drop cached result and re-query.
279
- :param quell_biogenic_co2: [None] override quantity specification for this property.
280
261
  :param kwargs:
281
262
  :return: whatever the implementation's quantity_relation() returns
282
263
  """
283
264
  locale = locale or self.locale
284
265
  key = (quantity, context, locale)
285
266
 
286
- _invert_bio = False
287
-
288
- if quell_biogenic_co2 is not None:
289
- if quell_biogenic_co2 == 'only':
290
- qbc = False
291
- _invert_bio = True
292
- else:
293
- qbc = bool(quell_biogenic_co2)
294
- else:
295
- qbc = quantity.get('quell_biogenic_co2')
296
- if qbc == 'only':
297
- qbc = False
298
- _invert_bio = True
299
-
300
- if _invert_bio:
301
- if not self.quell_co2:
302
- return QuelledCO2(self._flowable, context)
303
- else:
304
- if qbc:
305
- if self.quell_co2:
306
- return QuelledCO2(self._flowable, context)
307
-
308
267
  if refresh:
309
- self._chars_seen.pop(key, None)
268
+ self.pop_char(*key)
310
269
  try:
311
- return self._chars_seen.__getitem__(key)
270
+ return self._check_char(*key)
312
271
  except KeyError:
313
272
  try:
314
273
  qr = quantity.quantity_relation(self.name, self.reference_entity, context, locale=locale, **kwargs)
@@ -316,11 +275,20 @@ class Flow(FlowInterface, ABC):
316
275
  qr = e.args[0]
317
276
  except NoFactorsFound:
318
277
  qr = None
319
- self._chars_seen[key] = qr
278
+ self._chars_seen[quantity][context, locale] = qr
320
279
  return qr
321
280
 
281
+ def _check_char(self, qq, cx, loc):
282
+ return self._chars_seen[qq][cx, loc]
283
+
322
284
  def pop_char(self, qq, cx, loc):
323
- return self._chars_seen.pop((qq, cx, loc), None)
285
+ return self._chars_seen[qq].pop((cx, loc), None)
286
+
287
+ def clear_chars(self, quantity=None):
288
+ if quantity:
289
+ self._chars_seen.pop(quantity, None)
290
+ else:
291
+ self.__chars_seen = None
324
292
 
325
293
  def see_chars(self, qq, cx, cfs):
326
294
  """
@@ -331,12 +299,11 @@ class Flow(FlowInterface, ABC):
331
299
  :return:
332
300
  """
333
301
  for cf in cfs:
334
- key = qq, cx, cf.locale
335
- self._chars_seen[key] = cf
302
+ self._chars_seen[qq][cx, cf.locale] = cf
336
303
 
337
304
  def is_seen(self, qq, context=None, locale=None):
338
305
  if context is None:
339
306
  context = self.context
340
307
  if locale is None:
341
308
  locale = self.locale
342
- return (qq, context, locale) in self._chars_seen
309
+ return (context, locale) in self._chars_seen[qq]
@@ -98,7 +98,9 @@ class FlowInterface(BaseEntity, ABC):
98
98
  """
99
99
  @property
100
100
  def unit(self):
101
- return self.reference_entity.unit
101
+ if hasattr(self.reference_entity, 'unit'):
102
+ return self.reference_entity.unit
103
+ return ''
102
104
 
103
105
  @property
104
106
  def name(self):
@@ -25,7 +25,7 @@ class ForegroundInterface(AbstractQuery):
25
25
  return self._perform_query(_interface, 'save', ForegroundRequired, **kwargs)
26
26
 
27
27
  def find_term(self, term_ref, origin=None, **kwargs):
28
- """
28
+ """ # DEPRECATED
29
29
  Find a termination for the given reference. Essentially do type and validity checking and return something
30
30
  that can be used as a valid termination.
31
31
  :param term_ref: either an entity, entity ref, or string
@@ -48,8 +48,8 @@ class ForegroundInterface(AbstractQuery):
48
48
  :param kwargs:
49
49
  :return:
50
50
  """
51
- return self._perform_query(_interface, 'new_quantity', ForegroundRequired,
52
- name, ref_unit=ref_unit, **kwargs)
51
+ return self.make_ref(self._perform_query(_interface, 'new_quantity', ForegroundRequired,
52
+ name, ref_unit=ref_unit, **kwargs))
53
53
 
54
54
  def new_flow(self, name, ref_quantity=None, context=None, **kwargs):
55
55
  """
@@ -170,7 +170,7 @@ class ForegroundInterface(AbstractQuery):
170
170
 
171
171
  :param fragment:
172
172
  :param exchange_value: [this must be the second positional argument for legacy reasons, but can still be None]
173
- :param anchor: [renamed from 'termination' - the latter is still accepted in core+]
173
+ :param anchor: type-agnostic; left to implementation
174
174
  :param name:
175
175
  :param scenario:
176
176
  :param kwargs:
@@ -204,6 +204,17 @@ class ForegroundInterface(AbstractQuery):
204
204
  return self._perform_query(_interface, 'traverse', ForegroundRequired,
205
205
  fragment, scenario, **kwargs)
206
206
 
207
+ def cutoff_flows(self, fragment, scenario=None, **kwargs):
208
+ """
209
+ Report cut-off flows (inputs and outputs to the fragment) grouped as exchanges
210
+ :param fragment:
211
+ :param scenario:
212
+ :param kwargs:
213
+ :return:
214
+ """
215
+ return self._perform_query(_interface, 'cutoff_flows', ForegroundRequired,
216
+ fragment, scenario, **kwargs)
217
+
207
218
  def activity(self, fragment, scenario=None, **kwargs):
208
219
  """
209
220
  Traverse the fragment, returning direct-descendent nodes only. This must be run on an authentic entity and
@@ -229,5 +240,3 @@ class ForegroundInterface(AbstractQuery):
229
240
  """
230
241
  return self._perform_query(_interface, 'fragment_lcia', ForegroundRequired,
231
242
  fragment, quantity_ref, scenario, **kwargs)
232
-
233
-
@@ -46,6 +46,10 @@ class EntityRef(ResponseModel):
46
46
  entity_id: str
47
47
  entity_type: Optional[str]
48
48
 
49
+ @property
50
+ def external_ref(self): # what, was there some taboo against this?
51
+ return self.entity_id
52
+
49
53
  @classmethod
50
54
  def from_entity(cls, entity):
51
55
  return cls(origin=entity.origin, entity_id=entity.external_ref, entity_type=entity.entity_type)
@@ -67,10 +71,6 @@ class Entity(EntityRef):
67
71
  for k in self.properties.keys():
68
72
  yield k
69
73
 
70
- @property
71
- def external_ref(self): # what, was there some taboo against this?
72
- return self.entity_id
73
-
74
74
  @classmethod
75
75
  def from_search(cls, entity):
76
76
  ent = cls(origin=entity.origin, entity_id=entity.external_ref, entity_type=entity.entity_type,
@@ -169,7 +169,8 @@ class FlowEntity(Entity):
169
169
  properties=dict())
170
170
 
171
171
  obj.properties['name'] = entity.name
172
- obj.properties[entity.reference_field] = entity.reference_entity.external_ref
172
+ if entity.reference_entity:
173
+ obj.properties[entity.reference_field] = entity.reference_entity.external_ref
173
174
  obj.properties['unit'] = entity.unit
174
175
  obj.properties['Synonyms'] = []
175
176
 
@@ -198,6 +199,12 @@ class FlowEntity(Entity):
198
199
  return cls(origin=ex.origin, entity_id=ex.flow.external_ref, entity_type='flow', context=ex.flow.context,
199
200
  locale=ex.flow.locale, properties=ex.flow.properties)
200
201
 
202
+ def serialize(self):
203
+ j = super(FlowEntity, self).serialize()
204
+ j['context'] = self.context
205
+ j['locale'] = self.locale
206
+ return j
207
+
201
208
 
202
209
  class Context(ResponseModel):
203
210
  name: str
@@ -245,7 +252,7 @@ class FlowSpec(ResponseModel):
245
252
  if x.type == 'context':
246
253
  cx = list(x.termination)
247
254
  elif x.type in ('reference', 'cutoff'):
248
- cx = None
255
+ cx = []
249
256
  else:
250
257
  raise TypeError('%s\nUnknown exchange type %s' % (x, x.type))
251
258
  loc = locale or x.flow.locale
@@ -333,6 +340,8 @@ class Exchange(ResponseModel):
333
340
  if x.type == 'context':
334
341
  cx = list(x.termination)
335
342
  term = None
343
+ elif x.type == 'reference':
344
+ term = cx = None
336
345
  else:
337
346
  term = x.termination
338
347
  cx = None
@@ -486,9 +495,9 @@ class Characterization(ResponseModel):
486
495
  origin: str
487
496
  flowable: str
488
497
  ref_quantity: str
489
- ref_unit: str
498
+ ref_unit: Optional[str] = None
490
499
  query_quantity: str
491
- query_unit: str
500
+ query_unit: Optional[str] = None
492
501
  context: List[str]
493
502
  value: Dict
494
503
 
@@ -499,6 +508,19 @@ class Characterization(ResponseModel):
499
508
  ch.value[loc] = cf[loc]
500
509
  return ch
501
510
 
511
+ @classmethod
512
+ def from_cfs(cls, cfs):
513
+ rq = set(k.ref_quantity for k in cfs)
514
+ qq = set(k.quantity for k in cfs)
515
+ fb = set(k.flowable for k in cfs)
516
+ if len(rq) + len(qq) + len(fb) != 3:
517
+ raise ValueError('disagreeable CFs')
518
+ ch = cls.null(cfs[0])
519
+ for cf in cfs:
520
+ for loc in cf.locations:
521
+ ch.value[loc] = cf[loc]
522
+ return ch
523
+
502
524
  @classmethod
503
525
  def null(cls, cf):
504
526
  ch = cls(origin=cf.origin, flowable=cf.flowable,
@@ -0,0 +1,79 @@
1
+ """
2
+ Comparators
3
+
4
+ These tools enable quick comparison of sets of exchanges to see if they match
5
+ """
6
+ from math import isclose
7
+
8
+
9
+ def _rx_key(rx):
10
+ return rx.process.external_ref, rx.flow.external_ref, rx.direction
11
+
12
+
13
+ def _exch_key(exch):
14
+ return exch.flow.external_ref, exch.direction, tuple(exch.termination)
15
+
16
+
17
+ def compare_ref_exchanges(s1, s2):
18
+ """
19
+ Tests qualitative equivalence of two sets of *reference* exchanges (process, flow, direction).
20
+ :param s1:
21
+ :param s2:
22
+ :return:
23
+ """
24
+ set1 = {_rx_key(s) for s in s1}
25
+ set2 = {_rx_key(s) for s in s2}
26
+ d1 = set1.difference(set2)
27
+ d2 = set2.difference(set1)
28
+ if len(d1) + len(d2) == 0:
29
+ print('PASS (%d)' % len(set1))
30
+ else:
31
+ print('DIFFERENT (%d,%d / %d)' % (len(d1), len(d2), len(set1)))
32
+ return d1, d2
33
+
34
+
35
+ def compare_exchanges(s1, s2):
36
+ """
37
+ Tests qualitative equivalence of two sets of *depenedent* exchanges (flow, direction, termination).
38
+ Returns two sets: those present only in s1, those present only in s2
39
+ :param s1:
40
+ :param s2:
41
+ :return:
42
+ """
43
+ set1 = {_exch_key(s) for s in s1}
44
+ set2 = {_exch_key(s) for s in s2}
45
+ d1 = set1.difference(set2)
46
+ d2 = set2.difference(set1)
47
+ if len(d1) + len(d2) == 0:
48
+ print('PASS (%d)' % len(set1))
49
+ else:
50
+ print('DIFFERENT (%d,%d / %d)' % (len(d1), len(d2), len(set1)))
51
+ return d1, d2
52
+
53
+
54
+ def compare_exchange_values(s1, s2, rel_tol=1e-6):
55
+ """
56
+ The exchanges are unordered, so it's nontrivial to test two sets of results against one another.
57
+ We use the approach of mapping (flow.external_ref, direction, termination) to exchange value.
58
+ This is a summary test that compares the two sets and returns the entries in s2 that do NOT match
59
+ the entry in s1 (key error qualifies as nonmatch)
60
+ Thus a return value of length 0 indicates a passed test.
61
+ :param s1:
62
+ :param s2:
63
+ :param rel_tol: default 1e-6
64
+ :return: a list of failed exchanges, expressed as 2-tuples: (bad_exch, good_val) or (bad_exch, None)
65
+ """
66
+ c = {_exch_key(x): x.value for x in s1}
67
+ fail = []
68
+ for s in s2:
69
+ try:
70
+ v = c[_exch_key(s)]
71
+ if not isclose(v, s.value, rel_tol=rel_tol):
72
+ fail.append((s, v))
73
+ except KeyError:
74
+ fail.append((s, None))
75
+ if len(fail) == 0:
76
+ print('PASS (%d)' % len(c))
77
+ else:
78
+ print('DIFFERENT (%d / %d)' % (len(fail), len(c)))
79
+ return fail
@@ -17,15 +17,15 @@ without access to a query object that can implement the various methods.
17
17
  3. Grounded references should behave equivalently to the entities themselves. (except the remote catalogs can act
18
18
  as gatekeepers to decide what information can be disclosed)
19
19
 
20
- The inheritance pattern is:
20
+ The inheritance pattern is: ::
21
21
 
22
- BaseRef
23
- | |
24
- | EntityRef (grounded by a catalog query)
25
- | | \ \
26
- | ProcessRef, FlowRef, QuantityRef [...]
27
- |
28
- CatalogRef (un-grounded)
22
+ BaseRef
23
+ | |
24
+ | EntityRef (grounded by a catalog query)
25
+ | | | |
26
+ | ProcessRef, FlowRef, QuantityRef [...]
27
+ |
28
+ CatalogRef (un-grounded)
29
29
 
30
30
  The CatalogRef can instantiate a grounded reference if supplied with a query object that implements the interface.
31
31
 
@@ -56,6 +56,10 @@ class PropertyExists(Exception):
56
56
  pass
57
57
 
58
58
 
59
+ class NoUuid(Exception):
60
+ pass
61
+
62
+
59
63
  class BaseRef(BaseEntity):
60
64
  """
61
65
  A base class for defining entity references. The base class can also store information, such as properties
@@ -298,12 +302,14 @@ class EntityRef(BaseRef):
298
302
  self._uuid = _uuid
299
303
  except InvalidQuery:
300
304
  pass # a None uuid is fine, but next time we ask, it will check again
305
+ if self._uuid is NoUuid:
306
+ return None
301
307
  return self._uuid
302
308
 
303
309
  @uuid.setter
304
310
  def uuid(self, value):
305
311
  # need to repeat this because uuid is overridden
306
- if self._uuid is not None:
312
+ if self._uuid is not None and self._uuid is not NoUuid:
307
313
  raise PropertyExists(self.link, self._uuid)
308
314
  if uuid_regex.match(str(value)):
309
315
  self._uuid = str(value)
@@ -367,6 +373,9 @@ class EntityRef(BaseRef):
367
373
  return False
368
374
  return True
369
375
 
376
+ def check_bg(self):
377
+ return self._query.check_bg()
378
+
370
379
  def properties(self, force_query=False):
371
380
  if force_query:
372
381
  try:
@@ -1,5 +1,6 @@
1
1
  from .base import EntityRef, _MissingItem
2
2
  from .exchange_ref import ExchangeRef
3
+ from ..interfaces.iindex import comp_dir
3
4
  from itertools import chain
4
5
 
5
6
 
@@ -97,9 +98,9 @@ class ProcessRef(EntityRef):
97
98
  return next(x for x in self.reference_entity if x.flow.match(flow))
98
99
  except StopIteration:
99
100
  pass
100
- print(self.link)
101
+ # print(self.link)
101
102
  # self._show_ref()
102
- raise NoReference(flow)
103
+ raise NoReference(self.link, flow)
103
104
 
104
105
  def references(self):
105
106
  for x in self.reference_entity:
@@ -227,7 +228,8 @@ class ProcessRef(EntityRef):
227
228
 
228
229
  def consumers(self, ref_flow=None, **kwargs):
229
230
  ref_flow = self._use_ref_exch(ref_flow)
230
- return self._query.consumers(self.external_ref, ref_flow=ref_flow, **kwargs)
231
+ return [self._to_exch_ref(x, value=None) for x in
232
+ self._query.consumers(self.external_ref, ref_flow=ref_flow, **kwargs)]
231
233
 
232
234
  def dependencies(self, ref_flow=None, **kwargs):
233
235
  ref_flow = self._use_ref_exch(ref_flow)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: antelope_interface
3
- Version: 0.2.6.2
3
+ Version: 0.3.0
4
4
  Summary: A common interface for accessing LCA data
5
5
  Author-email: Brandon Kuczenski <bkuczenski@ucsb.edu>
6
6
  License: BSD-3-Clause
@@ -21,6 +21,7 @@ src/antelope/interfaces/iindex.py
21
21
  src/antelope/interfaces/iquantity.py
22
22
  src/antelope/models/__init__.py
23
23
  src/antelope/models/auth.py
24
+ src/antelope/models/comparators.py
24
25
  src/antelope/refs/__init__.py
25
26
  src/antelope/refs/base.py
26
27
  src/antelope/refs/catalog_ref.py
@@ -220,7 +220,6 @@ class QuantityInterface(AbstractQuery):
220
220
  '''
221
221
  core required functionality
222
222
  NOTE: a foreground interface must have access to a qdb to run get_canonical
223
- '''
224
223
  def new_quantity(self, name, ref_unit=None, **kwargs):
225
224
  """
226
225
  Creates a new quantity entity and adds it to the foreground
@@ -245,6 +244,7 @@ class QuantityInterface(AbstractQuery):
245
244
  name, ref_quantity=ref_quantity, context=context,
246
245
  **kwargs)
247
246
 
247
+ '''
248
248
  '''
249
249
  qdb-only queries
250
250
  '''