openepd 6.3.1__py3-none-any.whl → 6.4.1__py3-none-any.whl

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.
openepd/__version__.py CHANGED
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- VERSION = "6.3.1"
16
+ VERSION = "6.4.1"
openepd/model/common.py CHANGED
@@ -24,7 +24,7 @@ from openepd.model.validation.numbers import RatioFloat
24
24
  class Amount(BaseOpenEpdSchema):
25
25
  """A value-and-unit pairing for amounts that do not have an uncertainty."""
26
26
 
27
- qty: float | None = pyd.Field(description="How much of this in the amount.", default=None)
27
+ qty: float | None = pyd.Field(description="How much of this in the amount.", ge=0, default=None)
28
28
  unit: str | None = pyd.Field(description="Which unit. SI units are preferred.", example="kg", default=None)
29
29
 
30
30
  @pyd.root_validator
@@ -117,6 +117,18 @@ class Ingredient(BaseOpenEpdSchema):
117
117
  )
118
118
  citation: str | None = pyd.Field(default=None, description="Text citation describing the data source ")
119
119
 
120
+ @pyd.root_validator(skip_on_failure=True)
121
+ def _validate_evidence(cls, values: dict[str, Any]) -> dict[str, Any]:
122
+ # gwp_fraction should be backed by some type of evidence (fraction coming from product EPD etc) to be accounted
123
+ # for in the calculation of uncertainty
124
+ if values.get("gwp_fraction"):
125
+ if not values.get("evidence_type"):
126
+ raise ValueError("evidence_type is required if gwp_fraction is provided")
127
+ if not (values.get("citation") or values.get("link")):
128
+ raise ValueError("link or citation is required if gwp_fraction is provided")
129
+
130
+ return values
131
+
120
132
 
121
133
  class LatLng(BaseOpenEpdSchema):
122
134
  """A latitude and longitude."""
openepd/model/epd.py CHANGED
@@ -38,6 +38,7 @@ MANUFACTURER_DESCRIPTION = (
38
38
  'JSON object for declaring Org. Sometimes called the "Declaration Holder" or "Declaration Owner".'
39
39
  )
40
40
 
41
+ PLANT_DESCRIPTION = "List of object(s) for one or more plant(s) that this declaration applies to."
41
42
 
42
43
  #
43
44
  # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
@@ -161,7 +162,7 @@ class EpdPreviewV0(
161
162
  manufacturer: Org | None = pyd.Field(description=MANUFACTURER_DESCRIPTION)
162
163
  plants: list[Plant] = pyd.Field(
163
164
  max_items=32,
164
- description="List of object(s) for one or more plant(s) that this declaration applies to.",
165
+ description=PLANT_DESCRIPTION,
165
166
  default_factory=list,
166
167
  )
167
168
 
openepd/model/lcia.py CHANGED
@@ -357,6 +357,30 @@ class ScopeSetDiseaseIncidence(ScopeSet):
357
357
  allowed_units = "AnnualPerCapita"
358
358
 
359
359
 
360
+ class ScopeSetMass(ScopeSet):
361
+ """ScopeSet measuring mass in kg."""
362
+
363
+ allowed_units = "kg"
364
+
365
+
366
+ class ScopeSetVolume(ScopeSet):
367
+ """ScopeSet measuring mass in kg."""
368
+
369
+ allowed_units = "m3"
370
+
371
+
372
+ class ScopeSetMassOrVolume(ScopeSet):
373
+ """ScopeSet measuring mass in kg OR volume in m3, example: radioactive waste."""
374
+
375
+ allowed_units = ("kg", "m3")
376
+
377
+
378
+ class ScopeSetEnergy(ScopeSet):
379
+ """ScopeSet measuring mass in kg."""
380
+
381
+ allowed_units = "MJ"
382
+
383
+
360
384
  class ImpactSet(ScopesetByNameBase):
361
385
  """A set of impacts, such as GWP, ODP, AP, EP, POCP, EP-marine, EP-terrestrial, EP-freshwater, etc."""
362
386
 
@@ -554,71 +578,71 @@ class Impacts(pyd.BaseModel):
554
578
  class ResourceUseSet(ScopesetByNameBase):
555
579
  """A set of resource use indicators, such as RPRec, RPRm, etc."""
556
580
 
557
- RPRec: ScopeSet | None = pyd.Field(
581
+ RPRec: ScopeSetEnergy | None = pyd.Field(
558
582
  description="Renewable primary resources used as energy carrier (fuel). "
559
583
  "First use bio-based materials used as an energy source. Hydropower, solar and wind power used "
560
584
  "in the technosphere are also included in this indicator",
561
585
  default=None,
562
586
  )
563
- RPRm: ScopeSet | None = pyd.Field(
587
+ RPRm: ScopeSetEnergy | None = pyd.Field(
564
588
  description="Renewable primary resources with energy content used as material. "
565
589
  "First use biobased materials used as materials (e.g. wood, hemp, etc.).",
566
590
  default=None,
567
591
  )
568
- rpre: ScopeSet | None = pyd.Field(
592
+ rpre: ScopeSetEnergy | None = pyd.Field(
569
593
  description="Renewable primary energy resources as energy",
570
594
  default=None,
571
595
  )
572
- nrpre: ScopeSet | None = pyd.Field(
596
+ nrpre: ScopeSetEnergy | None = pyd.Field(
573
597
  description="Non-renewable primary resources as energy (fuel)",
574
598
  default=None,
575
599
  )
576
- nrprm: ScopeSet | None = pyd.Field(
600
+ nrprm: ScopeSetEnergy | None = pyd.Field(
577
601
  description="Non-renewable primary resources as material",
578
602
  default=None,
579
603
  )
580
- fw: ScopeSet | None = pyd.Field(
604
+ fw: ScopeSetVolume | None = pyd.Field(
581
605
  description="Use of net fresh water",
582
606
  default=None,
583
607
  )
584
- sm: ScopeSet | None = pyd.Field(
608
+ sm: ScopeSetMass | None = pyd.Field(
585
609
  description="Use of secondary materials",
586
610
  default=None,
587
611
  )
588
- rsf: ScopeSet | None = pyd.Field(
612
+ rsf: ScopeSetEnergy | None = pyd.Field(
589
613
  description="Use of renewable secondary materials",
590
614
  default=None,
591
615
  )
592
- nrsf: ScopeSet | None = pyd.Field(
616
+ nrsf: ScopeSetEnergy | None = pyd.Field(
593
617
  description="Use of non-renewable secondary fuels",
594
618
  default=None,
595
619
  )
596
- re: ScopeSet | None = pyd.Field(
620
+ re: ScopeSetEnergy | None = pyd.Field(
597
621
  description="Renewable energy resources",
598
622
  default=None,
599
623
  )
600
- pere: ScopeSet | None = pyd.Field(
624
+ pere: ScopeSetEnergy | None = pyd.Field(
601
625
  description="Use of renewable primary energy excluding renewable primary energy resources used as raw materials",
602
626
  default=None,
603
627
  )
604
- perm: ScopeSet | None = pyd.Field(
628
+ perm: ScopeSetEnergy | None = pyd.Field(
605
629
  description="Use of renewable primary energy resources used as raw materials",
606
630
  default=None,
607
631
  )
608
- pert: ScopeSet | None = pyd.Field(
632
+ pert: ScopeSetEnergy | None = pyd.Field(
609
633
  description="Total use of renewable primary energy resources",
610
634
  default=None,
611
635
  )
612
- penre: ScopeSet | None = pyd.Field(
636
+ penre: ScopeSetEnergy | None = pyd.Field(
613
637
  description="Use of non-renewable primary energy excluding "
614
638
  "non-renewable primary energy resources used as raw materials",
615
639
  default=None,
616
640
  )
617
- penrm: ScopeSet | None = pyd.Field(
641
+ penrm: ScopeSetEnergy | None = pyd.Field(
618
642
  description="Use of non-renewable primary energy resources used as raw materials",
619
643
  default=None,
620
644
  )
621
- penrt: ScopeSet | None = pyd.Field(
645
+ penrt: ScopeSetEnergy | None = pyd.Field(
622
646
  description="Total use of non-renewable primary energy resources",
623
647
  default=None,
624
648
  )
@@ -627,51 +651,51 @@ class ResourceUseSet(ScopesetByNameBase):
627
651
  class OutputFlowSet(ScopesetByNameBase):
628
652
  """A set of output flows, such as waste, emissions, etc."""
629
653
 
630
- twd: ScopeSet | None = pyd.Field(
654
+ twd: ScopeSetMass | None = pyd.Field(
631
655
  description="Total waste disposed",
632
656
  default=None,
633
657
  )
634
- hwd: ScopeSet | None = pyd.Field(
658
+ hwd: ScopeSetMass | None = pyd.Field(
635
659
  description="Hazardous waste disposed",
636
660
  default=None,
637
661
  )
638
- nhwd: ScopeSet | None = pyd.Field(
662
+ nhwd: ScopeSetMass | None = pyd.Field(
639
663
  description="Non-hazardous waste disposed",
640
664
  default=None,
641
665
  )
642
- rwd: ScopeSet | None = pyd.Field(
666
+ rwd: ScopeSetMass | None = pyd.Field(
643
667
  description="Radioactive waste disposed",
644
668
  default=None,
645
669
  )
646
- hlrw: ScopeSet | None = pyd.Field(
670
+ hlrw: ScopeSetMassOrVolume | None = pyd.Field(
647
671
  description="High level radioactive waste disposed",
648
672
  default=None,
649
673
  )
650
- illrw: ScopeSet | None = pyd.Field(
674
+ illrw: ScopeSetMassOrVolume | None = pyd.Field(
651
675
  description="Intermediate level radioactive waste disposed",
652
676
  default=None,
653
677
  )
654
- cru: ScopeSet | None = pyd.Field(
678
+ cru: ScopeSetMass | None = pyd.Field(
655
679
  description="Components for re-use",
656
680
  default=None,
657
681
  )
658
- mr: ScopeSet | None = pyd.Field(
682
+ mr: ScopeSetMass | None = pyd.Field(
659
683
  description="Recycled materials",
660
684
  default=None,
661
685
  )
662
- mfr: ScopeSet | None = pyd.Field(
686
+ mfr: ScopeSetMass | None = pyd.Field(
663
687
  description="Materials for recycling",
664
688
  default=None,
665
689
  )
666
- mer: ScopeSet | None = pyd.Field(
690
+ mer: ScopeSetMass | None = pyd.Field(
667
691
  description="Materials for energy recovery",
668
692
  default=None,
669
693
  )
670
- ee: ScopeSet | None = pyd.Field(
694
+ ee: ScopeSetEnergy | None = pyd.Field(
671
695
  description="Exported energy",
672
696
  default=None,
673
697
  )
674
- eh: ScopeSet | None = pyd.Field(
698
+ eh: ScopeSetEnergy | None = pyd.Field(
675
699
  description="Exported heat",
676
700
  default=None,
677
701
  )
openepd/model/org.py CHANGED
@@ -66,7 +66,6 @@ class Org(WithAttachmentsMixin, WithAltIdsMixin, OrgRef):
66
66
  class Plant(WithAttachmentsMixin, WithAltIdsMixin, BaseOpenEpdSchema):
67
67
  """Represent a manufacturing plant."""
68
68
 
69
- # TODO: Add proper validator
70
69
  id: str | None = pyd.Field(
71
70
  description="Plus code (aka Open Location Code) of plant's location and "
72
71
  "owner's web domain joined with `.`(dot).",
@@ -79,6 +78,12 @@ class Plant(WithAttachmentsMixin, WithAltIdsMixin, BaseOpenEpdSchema):
79
78
  deprecated="Pluscode field is deprecated. If users need a pluscode they can obtain it from "
80
79
  "`id` like this: `id.spit('.', maxsplit=1)[0]`",
81
80
  )
81
+ latitude: float | None = pyd.Field(
82
+ default=None, description="(deprecated) Latitude of the plant location. Use 'location' fields instead."
83
+ )
84
+ longitude: float | None = pyd.Field(
85
+ default=None, description="(deprecated) Longitude of the plant location. Use 'location' fields instead."
86
+ )
82
87
  owner: Org | None = pyd.Field(description="Organization that owns the plant", default=None)
83
88
  name: str | None = pyd.Field(
84
89
  max_length=200,
@@ -89,12 +94,13 @@ class Plant(WithAttachmentsMixin, WithAltIdsMixin, BaseOpenEpdSchema):
89
94
  address: str | None = pyd.Field(
90
95
  max_length=200,
91
96
  default=None,
92
- description="Text address, preferably geocoded",
97
+ description="(deprecated) Text address, preferably geocoded. Use 'location' fields instead",
93
98
  example="1503 Orchard Hill Rd, LaGrange, GA 30240, United States",
94
99
  )
95
100
  contact_email: pyd.EmailStr | None = pyd.Field(
96
101
  description="Email contact", example="info@interface.com", default=None
97
102
  )
103
+ location: Location | None = pyd.Field(description="Location of the plant", default=None)
98
104
 
99
105
  @classmethod
100
106
  def get_asset_type(cls) -> str | None:
@@ -103,6 +109,8 @@ class Plant(WithAttachmentsMixin, WithAltIdsMixin, BaseOpenEpdSchema):
103
109
 
104
110
  @pyd.validator("id")
105
111
  def _validate_id(cls, v: str) -> str:
112
+ if not v:
113
+ return v
106
114
  try:
107
115
  pluscode, web_domain = v.split(".", maxsplit=1)
108
116
  except ValueError as e:
@@ -2215,7 +2215,7 @@ class AciExposureClass(EnumGroupingAware, StrEnum):
2215
2215
  S1 = "aci.S1"
2216
2216
  S2 = "aci.S2"
2217
2217
  S3 = "aci.S3"
2218
- C0 = "aci.C1"
2218
+ C0 = "aci.C0"
2219
2219
  C1 = "aci.C1"
2220
2220
  C2 = "aci.C2"
2221
2221
  W0 = "aci.W0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openepd
3
- Version: 6.3.1
3
+ Version: 6.4.1
4
4
  Summary: Python library to work with OpenEPD format
5
5
  Home-page: https://github.com/cchangelabs/openepd
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  openepd/__init__.py,sha256=Shkfh0Kun0YRhmRDw7LkUj2eQL3X-HnP55u2THOEALw,794
2
- openepd/__version__.py,sha256=9-O6i7qcYZLc-Ty16U1UcqrtWq9-iQfVCVLwVjya99s,638
2
+ openepd/__version__.py,sha256=ynbiHC7WrNYOSyzyrd2Hj7jVjQQIObp13PMqmGs_IDQ,638
3
3
  openepd/api/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
4
4
  openepd/api/average_dataset/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
5
5
  openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=mxWwDokEGMe87Px8C_aHvIdVKZVHrEAuVtaSA1zJchU,7953
@@ -35,22 +35,22 @@ openepd/compat/pydantic.py,sha256=DOjSixsylLqMtFAIARu50sGcT4VPXN_c473q_2JwZQ0,11
35
35
  openepd/model/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
36
36
  openepd/model/base.py,sha256=OEYNFUTL4BivBNAt_LGowTlDuUjvKMHgf5U5ZBncZwQ,9805
37
37
  openepd/model/category.py,sha256=IQXNGQFQmFZ_H9PRONloX_UOSf1sTMDq1rM1yz8JR0Y,1639
38
- openepd/model/common.py,sha256=yx3m9Tqb7WgqW3SaHB3WftQaShD80dxTys2r63rswy8,9700
38
+ openepd/model/common.py,sha256=4iZAdmQy5UvLKrtmO8OnXsH1HD8jl20c6cv8MUZKW-M,10356
39
39
  openepd/model/declaration.py,sha256=oBJ_v_ESoQhybQIH5S5tmYVkgkoX3gwe3nvFyPqb4uk,13832
40
- openepd/model/epd.py,sha256=AAksfqbpxBiipwsphPil5MvQouCBDMVcAzvIYkeq5OQ,12070
40
+ openepd/model/epd.py,sha256=6G-5cpwaXx5BC6gQns2qlbqmsiEuXrsNmIK4mk1aJaQ,12108
41
41
  openepd/model/factory.py,sha256=XP7eeQNW5tqwX_4hfuEb3lK6BFQDb4KB0fSN0r8-lCU,2656
42
42
  openepd/model/generic_estimate.py,sha256=bbU0cR4izSqjZcfxUHNbdO4pllqqd8OaUFikrEgCFoA,3992
43
43
  openepd/model/geography.py,sha256=G3Oz3QBw5n-RiSCAv-vAGxrOZBhwIT5rASnPlo9dkcs,42095
44
44
  openepd/model/industry_epd.py,sha256=rgXhCUDAgzZ9eGio7ExqE3ymP3zTXnrrwcIDvg5YP1A,3285
45
- openepd/model/lcia.py,sha256=EChQO_zcc9ZV0cYHCsjjO24pn5oi8d3WMeUxB1Cj3Ww,24390
46
- openepd/model/org.py,sha256=xEYeqcqtmyd9fr322iCYwjhUlpRLREfzDe7gdBL7f04,4588
45
+ openepd/model/lcia.py,sha256=NTUoPv8Yy-f_MCiezEKvB4gx18r0In5vl2e2SuLqQjY,25012
46
+ openepd/model/org.py,sha256=PtG4-EgjKvNSt7446lV60HhDC3YyRx2E-yJ8MMs5raE,5049
47
47
  openepd/model/pcr.py,sha256=QknLtTn6Y14JORWKQ1qBqGgKnZpbKgqNiYF3Axl4U4c,5494
48
48
  openepd/model/specs/README.md,sha256=UGhSiFJ9hOxT1mZl-5ZrhkOrPKf1W_gcu5CI9hzV7LU,2430
49
49
  openepd/model/specs/__init__.py,sha256=IAevXqqYrCWlTH4z4Fy9o77vaOLinX56G05iIJJfm0M,3094
50
50
  openepd/model/specs/asphalt.py,sha256=V-N7NbrxyNnjgNXQbJPj17ZFM3Q-qxTxxjqpx61wEfA,3350
51
51
  openepd/model/specs/base.py,sha256=JgXvfy8K1Jpcai1eCUDZ-ndsLYkL-dcDyH2hQls6Znw,2652
52
52
  openepd/model/specs/concrete.py,sha256=spMvijIv79c87PXT_YV7coG851AkJ1ILl9EHCxN2-6E,9593
53
- openepd/model/specs/enums.py,sha256=rh35d0CZUIp1GDYopldu-dUJ3YQtXlKzJuMpyFLKT2w,63602
53
+ openepd/model/specs/enums.py,sha256=r7Ik8tgL60McK_5ACQn0qhIUTmxjnCQlGvHtFE6m8xM,63602
54
54
  openepd/model/specs/range/__init__.py,sha256=LmBClxzTNpWzGwS1zvFoAxbKILrMRMz22mJXKYu2u8I,4502
55
55
  openepd/model/specs/range/accessories.py,sha256=T3z-5jLoIVIIGeQi2cc5fMP3a7uGgvoW2E_SVmr3c30,2498
56
56
  openepd/model/specs/range/aggregates.py,sha256=nxk6iZHzs0CIoUMWSw4IfB-D4tGd4prh9O2HXnC9u70,2549
@@ -133,7 +133,7 @@ openepd/model/validation/quantity.py,sha256=UP6x2nUj1nP7G8e2rpi-HigHx9rwKeCuIDh_
133
133
  openepd/model/versioning.py,sha256=R_zm6rCrgF3vlJQYbpyWhirdS_Oek16cv_mvZmpuE8I,4473
134
134
  openepd/patch_pydantic.py,sha256=xrkzblatmU9HBzukWkp1cPq9ZSuohoz1p0pQqVKSlKs,4122
135
135
  openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
- openepd-6.3.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
137
- openepd-6.3.1.dist-info/METADATA,sha256=e71TcIfypVycIAtmh7z2JSBoGJSbaP5-RCK_-xEFn2c,9038
138
- openepd-6.3.1.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
139
- openepd-6.3.1.dist-info/RECORD,,
136
+ openepd-6.4.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
137
+ openepd-6.4.1.dist-info/METADATA,sha256=YqnvdbcllbapVDL63YMJA-0UJozK9OH5TGhnicVv95I,9038
138
+ openepd-6.4.1.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
139
+ openepd-6.4.1.dist-info/RECORD,,