antelope-interface 0.2.6.2__tar.gz → 0.2.7__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 (39) hide show
  1. {antelope_interface-0.2.6.2/src/antelope_interface.egg-info → antelope_interface-0.2.7}/PKG-INFO +1 -1
  2. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/pyproject.toml +1 -1
  3. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/setup.py +9 -0
  4. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/flows/flow.py +24 -57
  5. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/flows/flow_interface.py +3 -1
  6. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/iforeground.py +15 -6
  7. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/models/__init__.py +28 -8
  8. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/base.py +10 -1
  9. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/process_ref.py +5 -3
  10. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7/src/antelope_interface.egg-info}/PKG-INFO +1 -1
  11. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/LICENSE +0 -0
  12. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/MANIFEST.in +0 -0
  13. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/README.md +0 -0
  14. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/setup.cfg +0 -0
  15. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/__init__.py +0 -0
  16. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/exchanges_from_spreadsheet.py +0 -0
  17. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/flows/__init__.py +0 -0
  18. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/flows/openlca_locales.json +0 -0
  19. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/__init__.py +0 -0
  20. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/abstract_query.py +0 -0
  21. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/ibackground.py +0 -0
  22. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/ibasic.py +0 -0
  23. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/iconfigure.py +0 -0
  24. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/iexchange.py +0 -0
  25. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/iindex.py +0 -0
  26. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/interfaces/iquantity.py +1 -1
  27. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/models/auth.py +0 -0
  28. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/__init__.py +0 -0
  29. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/catalog_ref.py +0 -0
  30. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/exchange_ref.py +0 -0
  31. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/flow_ref.py +0 -0
  32. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/quantity_ref.py +0 -0
  33. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/tests/__init__.py +0 -0
  34. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/refs/tests/test_flows.py +0 -0
  35. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope/xdb_tokens.py +0 -0
  36. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope_interface.egg-info/SOURCES.txt +0 -0
  37. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope_interface.egg-info/dependency_links.txt +0 -0
  38. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/src/antelope_interface.egg-info/requires.txt +0 -0
  39. {antelope_interface-0.2.6.2 → antelope_interface-0.2.7}/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.2.7
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.2.7"
26
26
 
27
27
  [tool.setuptools.packages.find]
28
28
  where = ["src"]
@@ -5,6 +5,15 @@ setup()
5
5
 
6
6
  """
7
7
  Version History:
8
+ 0.2.7 2024/09/10 - synchronization release for background / LCI changes
9
+ add make_ref() machinery to a few interface routes
10
+ alter extend_process to use dependencies instead of inventory
11
+ make deep_lcia() biogenic-aware
12
+ (note: folding observations directly into lci() / abandoning sys_lcia() still to come)
13
+
14
+ 0.2.6.3 2024/08/15 - cutoff_flows and remote traversal compatibility
15
+ - modify FlowInterface and FlowEntity to not die on missing reference_entity
16
+
8
17
  0.2.6.2 2024/06/11 - get_context into basic interface
9
18
  0.2.6.1 2024/06/06 - ItemNotFound
10
19
 
@@ -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
@@ -486,9 +493,9 @@ class Characterization(ResponseModel):
486
493
  origin: str
487
494
  flowable: str
488
495
  ref_quantity: str
489
- ref_unit: str
496
+ ref_unit: Optional[str] = None
490
497
  query_quantity: str
491
- query_unit: str
498
+ query_unit: Optional[str] = None
492
499
  context: List[str]
493
500
  value: Dict
494
501
 
@@ -499,6 +506,19 @@ class Characterization(ResponseModel):
499
506
  ch.value[loc] = cf[loc]
500
507
  return ch
501
508
 
509
+ @classmethod
510
+ def from_cfs(cls, cfs):
511
+ rq = set(k.ref_quantity for k in cfs)
512
+ qq = set(k.quantity for k in cfs)
513
+ fb = set(k.flowable for k in cfs)
514
+ if len(rq) + len(qq) + len(fb) != 3:
515
+ raise ValueError('disagreeable CFs')
516
+ ch = cls.null(cfs[0])
517
+ for cf in cfs:
518
+ for loc in cf.locations:
519
+ ch.value[loc] = cf[loc]
520
+ return ch
521
+
502
522
  @classmethod
503
523
  def null(cls, cf):
504
524
  ch = cls(origin=cf.origin, flowable=cf.flowable,
@@ -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.2.7
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
@@ -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
  '''