antelope-interface 0.2.2__tar.gz → 0.2.3.2__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 (42) hide show
  1. antelope_interface-0.2.3.2/MANIFEST.in +1 -0
  2. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2}/PKG-INFO +7 -3
  3. antelope_interface-0.2.3.2/pyproject.toml +28 -0
  4. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2}/setup.py +9 -2
  5. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/__init__.py +1 -1
  6. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/flows/flow.py +2 -0
  7. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/abstract_query.py +21 -0
  8. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/iindex.py +13 -4
  9. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/iquantity.py +0 -22
  10. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/models/__init__.py +65 -14
  11. antelope_interface-0.2.3.2/src/antelope/refs/__init__.py +5 -0
  12. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/base.py +25 -10
  13. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/catalog_ref.py +4 -3
  14. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/exchange_ref.py +6 -0
  15. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/flow_ref.py +17 -6
  16. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/process_ref.py +8 -4
  17. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/quantity_ref.py +27 -11
  18. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope_interface.egg-info/PKG-INFO +8 -4
  19. antelope_interface-0.2.3.2/src/antelope_interface.egg-info/SOURCES.txt +36 -0
  20. antelope_interface-0.2.3.2/src/antelope_interface.egg-info/requires.txt +2 -0
  21. antelope_interface-0.2.2/MANIFEST.in +0 -1
  22. antelope_interface-0.2.2/antelope/refs/__init__.py +0 -2
  23. antelope_interface-0.2.2/antelope_interface.egg-info/SOURCES.txt +0 -35
  24. antelope_interface-0.2.2/antelope_interface.egg-info/requires.txt +0 -2
  25. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2}/LICENSE +0 -0
  26. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2}/README.md +0 -0
  27. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2}/setup.cfg +0 -0
  28. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/exchanges_from_spreadsheet.py +0 -0
  29. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/flows/__init__.py +0 -0
  30. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/flows/flow_interface.py +0 -0
  31. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/flows/openlca_locales.json +0 -0
  32. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/__init__.py +0 -0
  33. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/ibackground.py +0 -0
  34. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/iconfigure.py +0 -0
  35. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/iexchange.py +0 -0
  36. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/interfaces/iforeground.py +0 -0
  37. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/models/auth.py +0 -0
  38. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/tests/__init__.py +0 -0
  39. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/refs/tests/test_flows.py +0 -0
  40. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope/xdb_tokens.py +0 -0
  41. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope_interface.egg-info/dependency_links.txt +0 -0
  42. {antelope_interface-0.2.2 → antelope_interface-0.2.3.2/src}/antelope_interface.egg-info/top_level.txt +0 -0
@@ -0,0 +1 @@
1
+ include src/antelope/flows/openlca_locales.json
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: antelope_interface
3
- Version: 0.2.2
3
+ Version: 0.2.3.2
4
+ Summary: A common interface for accessing LCA data
4
5
  Home-page: https://github.com/AntelopeLCA/antelope
5
6
  Author: Brandon Kuczenski
6
- Author-email: bkuczenski@ucsb.edu
7
- License: BSD 3-Clause
7
+ Author-email: Brandon Kuczenski <bkuczenski@ucsb.edu>
8
+ License: BSD-3-Clause
9
+ Keywords: one,two
8
10
  Classifier: Development Status :: 4 - Beta
9
11
  Classifier: Intended Audience :: Science/Research
10
12
  Classifier: License :: OSI Approved :: BSD License
@@ -15,6 +17,8 @@ Classifier: Topic :: Scientific/Engineering
15
17
  Requires-Python: >=3.6
16
18
  Description-Content-Type: text/markdown
17
19
  License-File: LICENSE
20
+ Requires-Dist: synonym_dict
21
+ Requires-Dist: pydantic
18
22
 
19
23
  # antelope
20
24
  Standard Interface and reference framework for LCA
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "antelope_interface"
7
+ authors =[
8
+ {name = "Brandon Kuczenski", email="bkuczenski@ucsb.edu"}
9
+ ]
10
+ description = "A common interface for accessing LCA data"
11
+ readme ={ file = "README.md", content-type = "text/markdown"}
12
+ requires-python = ">=3.6"
13
+ keywords = ["one", "two"]
14
+ license = {text = "BSD-3-Clause"}
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Science/Research",
18
+ "License :: OSI Approved :: BSD License",
19
+ "Natural Language :: English",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Scientific/Engineering"
23
+ ]
24
+ dependencies = ["synonym_dict", "pydantic"]
25
+ version = "0.2.3.2"
26
+
27
+ [tool.setuptools.packages.find]
28
+ where = ["src"]
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- ANTELOPE_VERSION = '0.2.2'
3
+ ANTELOPE_VERSION = '0.2.3.2'
4
4
 
5
5
  requires = [
6
6
  "synonym_dict>=0.2.4",
@@ -9,6 +9,13 @@ requires = [
9
9
 
10
10
  """
11
11
  Version History:
12
+ 0.2.3.2 2024/03/26 move to src layout
13
+
14
+ 0.2.3.1 2024/03/22 LciaDetail objects now return DirectedFlow instead of FlowSpec (as exchange proxy)
15
+
16
+ 0.2.3 2024/01/05 - 'lcia' index route; exclude LCIA metadata from quantity manager synonyms
17
+ Versions >= 0.2.3 to support 0.3-branch development code (but this package is not branched)
18
+
12
19
  0.2.2 2023/11/30 - oryx debug release
13
20
 
14
21
  0.2.1-virtualize - 2023/04/10 xdb passes benchmarks.
@@ -71,5 +78,5 @@ setup(
71
78
  "Topic :: Scientific/Engineering"
72
79
  ],
73
80
  python_requires='>=3.6',
74
- packages=find_packages()
81
+ packages=find_packages('src')
75
82
  )
@@ -18,7 +18,7 @@ from .flows import BaseEntity, NullEntity, FlowInterface, Flow
18
18
 
19
19
  from .refs.process_ref import MultipleReferences, NoReference
20
20
  from .refs.catalog_ref import CatalogRef, QuantityRef, UnknownOrigin
21
- from .refs.quantity_ref import convert, NoUnitConversionTable, RefQuantityRequired
21
+ from .refs.quantity_ref import convert, ConversionError, RefQuantityRequired
22
22
 
23
23
  from .refs.base import NoCatalog, EntityRefMergeError, InvalidQuery, PropertyExists
24
24
  from .refs.exchange_ref import ExchangeRef, RxRef, EXCHANGE_TYPES
@@ -132,6 +132,8 @@ class Flow(FlowInterface):
132
132
  :return:
133
133
  """
134
134
  if key == 'name':
135
+ if value.lower().startswith('carbon dioxide'):
136
+ self._is_co2 = True
135
137
  self._add_synonym(value, set_name=True)
136
138
  return True
137
139
  elif key == 'casnumber':
@@ -146,4 +146,25 @@ class AbstractQuery(object):
146
146
  return self._perform_query('basic', 'synonyms', KeyError, item,
147
147
  **kwargs)
148
148
 
149
+ def is_lcia_engine(self, **kwargs):
150
+ """
151
+ A key question in the quantity interface is the way terms are managed. There are two main footings:
152
+ - the terms specified by the source are authentic / canonical and should be reproduced
153
+ - terms from different data sources refer to the same concept.
154
+ An archive's Term Manager determines how input terms are interpreted and how characterizations are looked up.
155
+
156
+ if the term manager is an LciaEngine, it uses a standard set of contexts and flowables, and provides routes
157
+ to add new synonyms for flowables/contexts and to report new flowables or contexts. Ultimately the objective
158
+ is to manage characterization + knowledge of intermediate flows.
159
+
160
+ This routine reports whether an origin implements the LciaEngine [protocol?] for dealing with flows.
161
+
162
+ :param kwargs:
163
+ :return: True/False - could also provide more structured information as needed.
164
+ """
165
+
166
+ try:
167
+ return self._perform_query('basic', 'is_lcia_engine', TypeError, **kwargs)
168
+ except TypeError:
169
+ return False
149
170
 
@@ -167,14 +167,23 @@ class IndexInterface(AbstractQuery):
167
167
  for i in self._perform_query(_interface, 'quantities', IndexRequired, **kwargs):
168
168
  yield self.make_ref(i)
169
169
 
170
+ def lcia(self, **kwargs):
171
+ """
172
+ Generate LCIA methodologies or collections of LCIA indicators. type not yet specified
173
+ :param kwargs: keyword search
174
+ :return:
175
+ """
176
+ for i in self._perform_query(_interface, 'lcia', IndexRequired, **kwargs):
177
+ yield self.make_ref(i)
178
+
170
179
  def lcia_methods(self, **kwargs):
171
180
  """
172
- Generate LCIA Methods-- which are quantities that have defined indicators
173
- :param kwargs:
181
+ Generate LCIA methods (nominally, quantities with an 'Indicator' property)
182
+ :param kwargs: keyword search
174
183
  :return:
175
184
  """
176
- indicator = kwargs.pop('Indicator', '')
177
- return self.quantities(Indicator=indicator, **kwargs)
185
+ for i in self._perform_query(_interface, 'lcia_methods', IndexRequired, **kwargs):
186
+ yield self.make_ref(i)
178
187
 
179
188
  """
180
189
  API functions- entity-specific -- get accessed by catalog ref
@@ -248,28 +248,6 @@ class QuantityInterface(AbstractQuery):
248
248
  qdb-only queries
249
249
  '''
250
250
 
251
- def is_lcia_engine(self, **kwargs):
252
- """
253
- A key question in the quantity interface is the way terms are managed. There are two main footings:
254
- - the terms specified by the source are authentic / canonical and should be reproduced
255
- - terms from different data sources refer to the same concept.
256
- An archive's Term Manager determines how input terms are interpreted and how characterizations are looked up.
257
-
258
- if the term manager is an LciaEngine, it uses a standard set of contexts and flowables, and provides routes
259
- to add new synonyms for flowables/contexts and to report new flowables or contexts. Ultimately the objective
260
- is to manage characterization + knowledge of intermediate flows.
261
-
262
- This routine reports whether an interface implements the LciaEngine [protocol?] for dealing with flows.
263
-
264
- :param kwargs:
265
- :return: True/False - could also provide more structured information as needed.
266
- """
267
-
268
- try:
269
- return self._perform_query(_interface, 'is_lcia_engine', QuantityRequired, **kwargs)
270
- except QuantityRequired:
271
- return False
272
-
273
251
  def get_canonical(self, quantity, **kwargs):
274
252
  """
275
253
  This is not really qdb-specific as trivial for non-qdbs.
@@ -62,18 +62,53 @@ class Entity(EntityRef):
62
62
  entity_type: str
63
63
  properties: Dict
64
64
 
65
+ def signature_fields(self):
66
+ # refs just return everything they know
67
+ for k in self.properties.keys():
68
+ yield k
69
+
70
+ @property
71
+ def external_ref(self): # what, was there some taboo against this?
72
+ return self.entity_id
73
+
65
74
  @classmethod
66
75
  def from_entity(cls, entity, **kwargs):
67
- e_s = entity.serialize() # this ensures that we get the reference field
68
- e_s.update(kwargs)
76
+ ent = cls(origin=entity.origin, entity_id=entity.external_ref, entity_type=entity.entity_type,
77
+ properties=dict())
78
+ # ent.properties.update(kwargs) # I don't know why this was here but I don't think I want it
79
+ for k in entity.signature_fields():
80
+ ent.properties[k] = entity[k]
81
+
69
82
  if entity.uuid is not None and entity.uuid != entity.external_ref:
70
- e_s['uuid'] = entity.uuid
83
+ ent.properties['uuid'] = entity.uuid
71
84
  # a bit of bleed from foreground here- but we need fragments to work-- bonus this also supports (RX) exchanges
72
85
  if hasattr(entity, 'flow'):
73
- e_s['flow'] = EntityRef.from_entity(entity.flow)
86
+ ent.properties['flow'] = FlowEntity.from_flow(entity.flow)
74
87
  if hasattr(entity, 'direction'):
75
- e_s['direction'] = entity.direction
76
- return cls.from_json(e_s)
88
+ ent.properties['direction'] = entity.direction
89
+
90
+ if entity.entity_type == 'quantity':
91
+ ent.properties['unit'] = str(ent.properties.pop('referenceUnit', entity.unit))
92
+ ent.properties['Synonyms'] = []
93
+ for k in ('Method', 'Category', 'Indicator', 'Synonyms'):
94
+ if entity.has_property(k):
95
+ ent.properties[k] = entity[k]
96
+ elif entity.entity_type == 'flow':
97
+ ent.properties['referenceQuantity'] = entity.reference_entity.external_ref
98
+ ent.properties['locale'] = entity.locale
99
+ ent.properties['context'] = list(entity.context)
100
+ ent.properties['Synonyms'] = [t for t in entity.synonyms if t != entity['name']] # FlowInterface.synonyms
101
+ elif entity.entity_type == 'process':
102
+ ent.properties['referenceExchange'] = [ReferenceExchange.from_exchange(x) for x in entity.reference_entity]
103
+
104
+ return ent
105
+
106
+ @classmethod
107
+ def from_flow(cls, flow):
108
+ ent = cls.from_entity(flow)
109
+ ent.properties['locale'] = flow.locale
110
+ ent.properties['context'] = list(flow.context)
111
+ return ent
77
112
 
78
113
  @classmethod
79
114
  def from_json(cls, j):
@@ -127,6 +162,7 @@ class FlowEntity(Entity):
127
162
 
128
163
  obj.properties['name'] = entity.name
129
164
  obj.properties[entity.reference_field] = entity.reference_entity.external_ref
165
+ obj.properties['Synonyms'] = []
130
166
 
131
167
  for key, val in kwargs.items():
132
168
  obj.properties[key] = entity[key]
@@ -146,13 +182,12 @@ class FlowEntity(Entity):
146
182
  @classmethod
147
183
  def from_exchange_model(cls, ex):
148
184
  """
149
- ExchangeModel includes a FlowSpec instead of a flow
185
+ ExchangeModel formerly included a FlowSpec instead of a flow-- but now it includes a FlowEntity
150
186
  :param ex:
151
187
  :return:
152
188
  """
153
189
  return cls(origin=ex.origin, entity_id=ex.flow.external_ref, entity_type='flow', context=ex.flow.context,
154
- locale=ex.flow.locale, properties={'name': ex.flow.flowable,
155
- 'referenceQuantity': ex.flow.quantity_ref})
190
+ locale=ex.flow.locale, properties=ex.flow.properties)
156
191
 
157
192
 
158
193
  class Context(ResponseModel):
@@ -228,9 +263,25 @@ class DirectedFlow(ResponseModel):
228
263
  flow: FlowSpec
229
264
  direction: str
230
265
 
266
+ @property
267
+ def origin(self):
268
+ return self.flow.origin
269
+
270
+ @property
271
+ def external_ref(self):
272
+ return self.flow.external_ref
273
+
274
+ @property
275
+ def quantity_ref(self):
276
+ return self.flow.quantity_ref
277
+
278
+ @property
279
+ def name(self):
280
+ return self.flow.flowable
281
+
231
282
  @classmethod
232
283
  def from_exchange(cls, obj):
233
- return cls(flow=FlowSpec.from_flow(obj.flow), direction=obj.direction)
284
+ return cls(flow=FlowSpec.from_exchange(obj), direction=obj.direction)
234
285
 
235
286
 
236
287
  class Exchange(ResponseModel):
@@ -239,7 +290,7 @@ class Exchange(ResponseModel):
239
290
  """
240
291
  origin: str
241
292
  process: str
242
- flow: FlowSpec
293
+ flow: FlowEntity
243
294
  direction: str
244
295
  termination: Optional[str]
245
296
  context: Optional[List[str]]
@@ -254,7 +305,7 @@ class Exchange(ResponseModel):
254
305
  else:
255
306
  term = x.termination
256
307
  cx = None
257
- return cls(origin=x.process.origin, process=x.process.external_ref, flow=FlowSpec.from_flow(x.flow),
308
+ return cls(origin=x.process.origin, process=x.process.external_ref, flow=FlowEntity.from_flow(x.flow),
258
309
  direction=x.direction, termination=term, context=cx, type=x.type, comment=x.comment, str=str(x), **kwargs)
259
310
 
260
311
 
@@ -517,13 +568,13 @@ class SummaryLciaScore(AggregatedLciaScore):
517
568
 
518
569
 
519
570
  class LciaDetail(ResponseModel):
520
- exchange: Optional[FlowSpec]
571
+ exchange: Optional[DirectedFlow]
521
572
  factor: QuantityConversion
522
573
  result: float
523
574
 
524
575
  @classmethod
525
576
  def from_detailed_lcia_result(cls, d):
526
- return cls(exchange=FlowSpec.from_exchange(d.exchange),
577
+ return cls(exchange=DirectedFlow.from_exchange(d.exchange),
527
578
  factor=QuantityConversion.from_qrresult(d.factor),
528
579
  result=d.result)
529
580
 
@@ -0,0 +1,5 @@
1
+ from .catalog_ref import CatalogRef
2
+ from .exchange_ref import ExchangeRef, RxRef
3
+ from .process_ref import ProcessRef
4
+ from .flow_ref import FlowRef
5
+ from .quantity_ref import QuantityRef
@@ -222,6 +222,11 @@ class BaseRef(BaseEntity):
222
222
  if _notprint:
223
223
  print('==Local Fields==')
224
224
  _notprint = False
225
+ try:
226
+ if (isinstance(v, list) or isinstance(v, dict) or isinstance(v, set)) and len(v) > 10:
227
+ v = '[%s with %d entries]' % (type(v), len(v))
228
+ except TypeError:
229
+ pass
225
230
  print('%*s: %s' % (ml, k, v))
226
231
 
227
232
  def serialize(self, **kwargs):
@@ -331,8 +336,9 @@ class EntityRef(BaseRef):
331
336
  def signature_fields(self):
332
337
  # this seems problematic
333
338
  # just let a ref yield everything it knows
334
- for k in self._d.keys():
335
- yield k
339
+ for k, v in self._d.items():
340
+ if v is not _MissingItem:
341
+ yield k
336
342
 
337
343
  def _show_ref(self):
338
344
  print('%s: %s' % (self.reference_field, self.reference_entity))
@@ -361,15 +367,20 @@ class EntityRef(BaseRef):
361
367
  return False
362
368
  return True
363
369
 
364
- def properties(self):
365
- try:
366
- for k in self._query.properties(self):
367
- yield k
368
- except NoAccessToEntity:
370
+ def properties(self, force_query=False):
371
+ if force_query:
372
+ try:
373
+ for k in self._query.properties(self): # this forces a query refresh
374
+ if self.get(k) is not _MissingItem:
375
+ yield k
376
+ except NoAccessToEntity:
377
+ force_query = False
378
+ if not force_query: # this could probably be done better with more clever exception catching
369
379
  for k in self._d.keys():
370
- yield k
380
+ if self.get(k) is not _MissingItem:
381
+ yield k
371
382
 
372
- def get_item(self, item, force_query=True):
383
+ def get_item(self, item):
373
384
  """
374
385
 
375
386
  This keeps generating recursion errors. Let's think it through.
@@ -403,7 +414,11 @@ class EntityRef(BaseRef):
403
414
  raise KeyError(item)
404
415
  if lit is self:
405
416
  raise
406
- val = lit.get_item(item)
417
+ try:
418
+ val = lit.get_item(item)
419
+ except KeyError:
420
+ self._d[item] = _MissingItem
421
+ raise
407
422
  except KeyError:
408
423
  self._d[item] = _MissingItem
409
424
  raise
@@ -97,9 +97,10 @@ class CatalogRef(BaseRef):
97
97
  Code repetition! for subclass purity
98
98
  :return:
99
99
  """
100
- yield self.name
101
- yield str(self) # this is the same as above for entities, but includes origin for refs
102
- yield self.external_ref # do we definitely want this? will squash versions together
100
+ if not self.is_lcia_method:
101
+ yield self.name
102
+ yield str(self) # this is the same as above for entities, but includes origin for refs
103
+ yield self.external_ref # do we definitely want this? will squash versions together
103
104
  if self.uuid is not None:
104
105
  yield self.uuid
105
106
  if self.origin is not None:
@@ -127,6 +127,12 @@ class ExchangeRef(object):
127
127
  else:
128
128
  raise ValueError('Unintelligible termination %s' % term)
129
129
 
130
+ @property
131
+ def is_elementary(self):
132
+ if hasattr(self.termination, 'elementary'):
133
+ return bool(self.termination.elementary)
134
+ return False
135
+
130
136
  @property
131
137
  def term_ref(self):
132
138
  """
@@ -89,8 +89,11 @@ class FlowRef(EntityRef, Flow):
89
89
  :param value:
90
90
  :return:
91
91
  """
92
- self._catch_context(key, value)
93
- self._catch_flowable(key.lower(), value)
92
+ if key == 'locale':
93
+ self._locale = value
94
+ else:
95
+ self._catch_context(key, value)
96
+ self._catch_flowable(key.lower(), value)
94
97
  super(FlowRef, self).__setitem__(key, value)
95
98
 
96
99
  def serialize(self, characterizations=False, domesticate=False, **kwargs):
@@ -125,16 +128,24 @@ class FlowRef(EntityRef, Flow):
125
128
  def profile(self, **kwargs):
126
129
  return self._query.profile(self.external_ref, **kwargs)
127
130
 
128
- def characterize(self, quantity, value, context=None, location='GLO', **kwargs):
131
+ def characterize(self, quantity, value, context=None, location='GLO', origin=None, **kwargs):
129
132
  if context is None:
130
133
  context = self.context
131
134
  flowable = self.name
135
+ if origin is None:
136
+ origin = self.origin
132
137
  self.pop_char(quantity, context, location)
133
138
  return self._query.characterize(flowable, self.reference_entity, quantity, value, context=context,
134
- origin=self.origin, location=location, **kwargs)
139
+ origin=origin, location=location, **kwargs)
140
+
141
+ def cf(self, quantity, context=None, locale=None, **kwargs):
142
+ if context is None:
143
+ context = self.context
144
+ if locale is None:
145
+ locale = self.locale
135
146
 
136
- def cf(self, quantity, **kwargs):
137
- return quantity.cf(self, **kwargs)
147
+ return self._query.cf(self.external_ref, quantity, ref_quantity=self.reference_entity, context=context,
148
+ locale=locale, **kwargs)
138
149
 
139
150
  '''
140
151
  Characterization caching
@@ -8,6 +8,9 @@ class MultipleReferences(Exception):
8
8
 
9
9
 
10
10
  class NoReference(Exception):
11
+ """
12
+ Indicates that a process has no reference flow matching a given specification
13
+ """
11
14
  pass
12
15
 
13
16
 
@@ -30,7 +33,7 @@ class ProcessRef(EntityRef):
30
33
  @property
31
34
  def reference_entity(self):
32
35
  if self._reference_entity is None:
33
- self._reference_entity = self._query.get_reference(self.external_ref)
36
+ self._reference_entity = self._query.get_reference(self)
34
37
  if len(self._reference_entity) == 1:
35
38
  self._default_rx = self._reference_entity[0].flow.external_ref
36
39
  return self._reference_entity
@@ -88,9 +91,10 @@ class ProcessRef(EntityRef):
88
91
  try:
89
92
  return next(x for x in self.reference_entity if x.flow.match(flow))
90
93
  except StopIteration:
91
- print('%s: references:' % self.link)
92
- self._show_ref()
93
- raise KeyError(flow)
94
+ pass
95
+ print(self.link)
96
+ # self._show_ref()
97
+ raise NoReference(flow)
94
98
 
95
99
  def references(self):
96
100
  for x in self.reference_entity:
@@ -15,6 +15,7 @@ but it depends on the LciaResult implementation, which is irretrievably part of
15
15
 
16
16
  """
17
17
 
18
+ from ..flows import FlowInterface
18
19
  from .base import EntityRef
19
20
  from synonym_dict import LowerDict
20
21
 
@@ -23,7 +24,7 @@ class RefQuantityRequired(Exception):
23
24
  pass
24
25
 
25
26
 
26
- class NoUnitConversionTable(Exception):
27
+ class ConversionError(Exception):
27
28
  pass
28
29
 
29
30
 
@@ -68,7 +69,7 @@ def convert(quantity, from_unit=None, to=None):
68
69
  if quantity.unit not in uc_table:
69
70
  uc_table[quantity.unit] = 1.0
70
71
  except KeyError:
71
- raise NoUnitConversionTable
72
+ raise ConversionError('%s: No Unit Conversion Table' % quantity)
72
73
 
73
74
  if from_unit is None:
74
75
  if quantity.unit in uc_table:
@@ -79,7 +80,7 @@ def convert(quantity, from_unit=None, to=None):
79
80
  try:
80
81
  inbound = uc_table[from_unit]
81
82
  except KeyError:
82
- raise KeyError('Unknown unit %s for quantity %s' % (from_unit, quantity))
83
+ raise ConversionError('%s: Unknown from_unit %s' % (quantity, from_unit))
83
84
 
84
85
  if to is None:
85
86
  if quantity.unit in uc_table:
@@ -91,7 +92,7 @@ def convert(quantity, from_unit=None, to=None):
91
92
  try:
92
93
  outbound = uc_table[to]
93
94
  except KeyError:
94
- raise KeyError('Unknown unit %s for quantity %s' % (to, quantity))
95
+ raise ConversionError('%s: Unknown to_unit %s' % (quantity, to))
95
96
 
96
97
  return round(outbound / inbound, 12) # round off to curtail numerical / serialization issues
97
98
 
@@ -116,7 +117,8 @@ class QuantityRef(EntityRef):
116
117
  def _addl(self):
117
118
  u = self.unit or ''
118
119
  if self.is_lcia_method:
119
- return '%s] [LCIA' % u
120
+ m = self.get('Method', 'LCIA')
121
+ return '%s] [%s' % (u, m)
120
122
  return u
121
123
 
122
124
  @property
@@ -132,7 +134,10 @@ class QuantityRef(EntityRef):
132
134
 
133
135
  @property
134
136
  def is_lcia_method(self):
135
- return 'Indicator' in self._d
137
+ is_ind = self._d.get('Indicator', '')
138
+ if isinstance(is_ind, str) and len(is_ind) > 0:
139
+ return True
140
+ return False
136
141
 
137
142
  def convert(self, from_unit=None, to=None):
138
143
  if not self.has_property('UnitConversion'):
@@ -146,10 +151,11 @@ class QuantityRef(EntityRef):
146
151
  This is a little kludgey-- but requires agreement on what terms are considered synonymous.
147
152
  :return:
148
153
  """
149
- yield self['Name']
150
- yield self.name
151
- yield str(self) # this is the same as above for entities, but includes origin for refs
152
- yield self.external_ref # do we definitely want this? will squash versions together
154
+ if not self.is_lcia_method:
155
+ yield self['Name']
156
+ yield self.name
157
+ yield str(self) # this is the same as above for entities, but includes origin for refs
158
+ yield self.external_ref # do we definitely want this? version-less name will return earliest version
153
159
  if self.uuid is not None:
154
160
  yield self.uuid
155
161
  if self.origin is not None:
@@ -168,6 +174,10 @@ class QuantityRef(EntityRef):
168
174
  def has_lcia_engine(self):
169
175
  return self._query.is_lcia_engine()
170
176
 
177
+ @property
178
+ def is_local(self):
179
+ return self._query.origin == 'local.qdb'
180
+
171
181
  def is_canonical(self, other):
172
182
  return self._query.get_canonical(other) is self
173
183
 
@@ -229,7 +239,13 @@ class QuantityRef(EntityRef):
229
239
  def do_lcia(self, inventory, **kwargs):
230
240
  return self._query.do_lcia(self, inventory, **kwargs)
231
241
 
232
- def quantity_relation(self, flowable, ref_quantity, context, locale='GLO', **kwargs):
242
+ def quantity_relation(self, flowable, ref_quantity=None, context=None, locale='GLO', **kwargs):
243
+ if isinstance(flowable, FlowInterface):
244
+ if ref_quantity is None:
245
+ ref_quantity = flowable.reference_entity
246
+ if context is None:
247
+ context = flowable.context
248
+ flowable = flowable.name
233
249
  return self._query.quantity_relation(flowable, ref_quantity, self, context, locale=locale, **kwargs)
234
250
 
235
251
  def norm(self, **kwargs):
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.1
2
- Name: antelope-interface
3
- Version: 0.2.2
2
+ Name: antelope_interface
3
+ Version: 0.2.3.2
4
+ Summary: A common interface for accessing LCA data
4
5
  Home-page: https://github.com/AntelopeLCA/antelope
5
6
  Author: Brandon Kuczenski
6
- Author-email: bkuczenski@ucsb.edu
7
- License: BSD 3-Clause
7
+ Author-email: Brandon Kuczenski <bkuczenski@ucsb.edu>
8
+ License: BSD-3-Clause
9
+ Keywords: one,two
8
10
  Classifier: Development Status :: 4 - Beta
9
11
  Classifier: Intended Audience :: Science/Research
10
12
  Classifier: License :: OSI Approved :: BSD License
@@ -15,6 +17,8 @@ Classifier: Topic :: Scientific/Engineering
15
17
  Requires-Python: >=3.6
16
18
  Description-Content-Type: text/markdown
17
19
  License-File: LICENSE
20
+ Requires-Dist: synonym_dict
21
+ Requires-Dist: pydantic
18
22
 
19
23
  # antelope
20
24
  Standard Interface and reference framework for LCA
@@ -0,0 +1,36 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ setup.py
6
+ src/antelope/__init__.py
7
+ src/antelope/exchanges_from_spreadsheet.py
8
+ src/antelope/xdb_tokens.py
9
+ src/antelope/flows/__init__.py
10
+ src/antelope/flows/flow.py
11
+ src/antelope/flows/flow_interface.py
12
+ src/antelope/flows/openlca_locales.json
13
+ src/antelope/interfaces/__init__.py
14
+ src/antelope/interfaces/abstract_query.py
15
+ src/antelope/interfaces/ibackground.py
16
+ src/antelope/interfaces/iconfigure.py
17
+ src/antelope/interfaces/iexchange.py
18
+ src/antelope/interfaces/iforeground.py
19
+ src/antelope/interfaces/iindex.py
20
+ src/antelope/interfaces/iquantity.py
21
+ src/antelope/models/__init__.py
22
+ src/antelope/models/auth.py
23
+ src/antelope/refs/__init__.py
24
+ src/antelope/refs/base.py
25
+ src/antelope/refs/catalog_ref.py
26
+ src/antelope/refs/exchange_ref.py
27
+ src/antelope/refs/flow_ref.py
28
+ src/antelope/refs/process_ref.py
29
+ src/antelope/refs/quantity_ref.py
30
+ src/antelope/refs/tests/__init__.py
31
+ src/antelope/refs/tests/test_flows.py
32
+ src/antelope_interface.egg-info/PKG-INFO
33
+ src/antelope_interface.egg-info/SOURCES.txt
34
+ src/antelope_interface.egg-info/dependency_links.txt
35
+ src/antelope_interface.egg-info/requires.txt
36
+ src/antelope_interface.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ synonym_dict
2
+ pydantic
@@ -1 +0,0 @@
1
- include antelope/flows/openlca_locales.json
@@ -1,2 +0,0 @@
1
- from .catalog_ref import CatalogRef
2
- from .exchange_ref import ExchangeRef, RxRef
@@ -1,35 +0,0 @@
1
- LICENSE
2
- MANIFEST.in
3
- README.md
4
- setup.py
5
- antelope/__init__.py
6
- antelope/exchanges_from_spreadsheet.py
7
- antelope/xdb_tokens.py
8
- antelope/flows/__init__.py
9
- antelope/flows/flow.py
10
- antelope/flows/flow_interface.py
11
- antelope/flows/openlca_locales.json
12
- antelope/interfaces/__init__.py
13
- antelope/interfaces/abstract_query.py
14
- antelope/interfaces/ibackground.py
15
- antelope/interfaces/iconfigure.py
16
- antelope/interfaces/iexchange.py
17
- antelope/interfaces/iforeground.py
18
- antelope/interfaces/iindex.py
19
- antelope/interfaces/iquantity.py
20
- antelope/models/__init__.py
21
- antelope/models/auth.py
22
- antelope/refs/__init__.py
23
- antelope/refs/base.py
24
- antelope/refs/catalog_ref.py
25
- antelope/refs/exchange_ref.py
26
- antelope/refs/flow_ref.py
27
- antelope/refs/process_ref.py
28
- antelope/refs/quantity_ref.py
29
- antelope/refs/tests/__init__.py
30
- antelope/refs/tests/test_flows.py
31
- antelope_interface.egg-info/PKG-INFO
32
- antelope_interface.egg-info/SOURCES.txt
33
- antelope_interface.egg-info/dependency_links.txt
34
- antelope_interface.egg-info/requires.txt
35
- antelope_interface.egg-info/top_level.txt
@@ -1,2 +0,0 @@
1
- synonym_dict>=0.2.4
2
- pydantic>=2.5.0