openepd 6.12.1__py3-none-any.whl → 6.13.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.
@@ -0,0 +1,178 @@
1
+ #
2
+ # Copyright 2025 by C Change Labs Inc. www.c-change-labs.com
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ from typing import Collection
17
+
18
+ from openepd.m49.const import (
19
+ COUNTRY_VERBOSE_NAME_TO_M49,
20
+ ISO3166_ALPHA2_TO_M49,
21
+ M49_TO_COUNTRY_VERBOSE_NAME,
22
+ M49_TO_ISO3166_ALPHA2,
23
+ M49_TO_REGION_VERBOSE_NAME,
24
+ OPENEPD_SPECIAL_REGIONS,
25
+ REGION_VERBOSE_NAME_TO_M49,
26
+ )
27
+
28
+
29
+ def iso_to_m49(regions: Collection[str]) -> set[str]:
30
+ """
31
+ Convert ISO3166 alpha2 country codes to M49 region codes.
32
+
33
+ :param regions: List of ISO3166 alpha2 country codes (e.g., ["US", "CA", "MX"])
34
+ :return: Set of M49 region codes (e.g., {"840", "124", "484"})
35
+ :raises ValueError: If a country code is not found in M49 region codes.
36
+ """
37
+
38
+ if not regions:
39
+ return set()
40
+
41
+ result = set()
42
+ for code in regions:
43
+ m49_code = ISO3166_ALPHA2_TO_M49.get(code.upper())
44
+ if m49_code:
45
+ result.add(m49_code)
46
+ else:
47
+ raise ValueError(f"Country code '{code}' not found in M49 region codes.")
48
+
49
+ return result
50
+
51
+
52
+ def m49_to_iso(regions: Collection[str]) -> set[str]:
53
+ """
54
+ Convert M49 region codes to ISO3166 alpha2 country codes.
55
+
56
+ :param regions: List of M49 region codes (e.g., ["840", "124", "484"])
57
+ :return: Set of ISO3166 alpha2 country codes (e.g., {"US", "CA", "MX"})
58
+ :raises ValueError: If a region code is not found in ISO3166.
59
+ """
60
+
61
+ if not regions:
62
+ return set()
63
+
64
+ result = set()
65
+ for code in regions:
66
+ iso_code = M49_TO_ISO3166_ALPHA2.get(code.upper())
67
+ if iso_code:
68
+ result.add(iso_code)
69
+ else:
70
+ raise ValueError(f"Region code '{code}' not found in ISO3166.")
71
+
72
+ return result
73
+
74
+
75
+ def region_and_country_names_to_m49(regions: Collection[str]) -> set[str]:
76
+ """
77
+ Convert user-friendly region and country names to M49 region codes.
78
+
79
+ :param regions: List of user-friendly region and country names (e.g., ["Europe",
80
+ "North America", "Austria", "Germany"])
81
+ :return: Set of M49 region codes (e.g., {"150", "003", "040", "276"})
82
+ :raises ValueError: If a region or country name is not found in M49 region codes.
83
+ """
84
+
85
+ if not regions:
86
+ return set()
87
+
88
+ result = set()
89
+ for name in regions:
90
+ m49_code = REGION_VERBOSE_NAME_TO_M49.get(name.title()) or COUNTRY_VERBOSE_NAME_TO_M49.get(name.title())
91
+ if not m49_code:
92
+ raise ValueError(f"Region or country name '{name}' not found in M49 region codes.")
93
+ result.add(m49_code)
94
+
95
+ return result
96
+
97
+
98
+ def m49_to_region_and_country_names(regions: Collection[str]) -> set[str]:
99
+ """
100
+ Convert M49 region codes to user-friendly region names and country names.
101
+
102
+ :param regions: List of M49 region codes (e.g., ["150", "003", "040", "276"])
103
+ :return: Set of user-friendly region and country names (e.g., {"Europe", "North America", "Austria", "Germany"})
104
+ :raises ValueError: If a region code is not found in M49 region codes.
105
+ """
106
+
107
+ if not regions:
108
+ return set()
109
+
110
+ result = set()
111
+ for code in regions:
112
+ if code not in M49_TO_REGION_VERBOSE_NAME and code not in M49_TO_COUNTRY_VERBOSE_NAME:
113
+ raise ValueError(f"Region code '{code}' not found in M49 region codes.")
114
+
115
+ name = M49_TO_REGION_VERBOSE_NAME.get(code) or M49_TO_COUNTRY_VERBOSE_NAME.get(code, code)
116
+ result.add(name)
117
+ return result
118
+
119
+
120
+ def openepd_to_m49(regions: Collection[str]) -> set[str]:
121
+ """
122
+ Convert OpenEPD geography definitions to pure M49 region codes.
123
+
124
+ :param regions: list of OpenEPD geography definitions including letter codes and aliases
125
+ like "EU27" or "NAFTA" (e.g., ["EU27", "NAFTA"], ["US", "CA, MX"])
126
+ :return: Set of M49 region codes (e.g., {"040", "056", "100", "191", "196", "203", "208", "233", "246", "250",
127
+ "276", "300", "348", "372", "380", "428", "440", "442", "470", "528", "616", "620", "642", "703", "705", "724",
128
+ "752", "840", "124", "484"}, {"840", "124", "484"})
129
+ :raises ValueError: If a region or country name is not found in ISO3166 or OpenEPD special regions.
130
+ """
131
+
132
+ if not regions:
133
+ return set()
134
+
135
+ result = set()
136
+ for region in regions:
137
+ if region in OPENEPD_SPECIAL_REGIONS:
138
+ result.update(OPENEPD_SPECIAL_REGIONS[region].m49_codes)
139
+ else:
140
+ m49_code = ISO3166_ALPHA2_TO_M49.get(region.upper())
141
+ if m49_code:
142
+ result.add(m49_code)
143
+ else:
144
+ raise ValueError(f"Region '{region}' not found in ISO3166 or OpenEPD special regions.")
145
+ return result
146
+
147
+
148
+ def m49_to_openepd(regions: list[str]) -> set[str]:
149
+ """
150
+ Convert M49 region codes to OpenEPD geography definitions.
151
+
152
+ :param regions: List of M49 region codes (e.g., ["040", "056", "100", "191", "196", "203", "208", "233", "246",
153
+ "250", "276", "300", "348", "372", "380", "428", "440", "442", "470", "528", "616", "620", "642", "703", "705",
154
+ "724", "752", "840", "124", "484"], ["840", "124", "484"], ["040", "056", "100"])
155
+ :return: Set of OpenEPD geography definitions including letter codes and aliases
156
+ like "EU27" or "NAFTA" (e.g., {"EU27", "NAFTA"}, {"NAFTA"}, {"AT", "BE", "BG"})
157
+ :raises ValueError: If a region code is not found in ISO3166 or OpenEPD special regions.
158
+ """
159
+
160
+ if not regions:
161
+ return set()
162
+
163
+ result = set()
164
+ remaining_codes = set(regions)
165
+ for special_region, special_region_data in OPENEPD_SPECIAL_REGIONS.items():
166
+ special_region_codes = set(special_region_data.m49_codes)
167
+ if special_region_codes.issubset(remaining_codes):
168
+ result.add(special_region)
169
+ remaining_codes -= special_region_codes
170
+
171
+ for code in remaining_codes:
172
+ iso_code = M49_TO_ISO3166_ALPHA2.get(code)
173
+ if iso_code:
174
+ result.add(iso_code)
175
+ else:
176
+ raise ValueError(f"Region code '{code}' not found in ISO3166 or OpenEPD special regions.")
177
+
178
+ return result
@@ -15,8 +15,6 @@
15
15
  #
16
16
  from typing import Literal
17
17
 
18
- from pydantic.v1 import NonNegativeInt
19
-
20
18
  from openepd.compat.pydantic import pyd
21
19
  from openepd.model.base import BaseDocumentFactory, BaseOpenEpdSchema, OpenEpdDoctypes
22
20
  from openepd.model.common import WithAltIdsMixin, WithAttachmentsMixin
@@ -36,15 +34,15 @@ from openepd.model.versioning import OpenEpdVersions, Version
36
34
  class SampleSize(BaseOpenEpdSchema):
37
35
  """Sample size."""
38
36
 
39
- products: NonNegativeInt | None = pyd.Field(
37
+ products: pyd.NonNegativeInt | None = pyd.Field(
40
38
  default=None,
41
39
  description="Count of separate products or results that were included in this industry EPD, "
42
40
  "and over which the standard deviation was calculated",
43
41
  )
44
- plants: NonNegativeInt | None = pyd.Field(
42
+ plants: pyd.NonNegativeInt | None = pyd.Field(
45
43
  default=None, description="Count of unique manufacturing plants that submitted data for this Industry EPD"
46
44
  )
47
- manufacturers: NonNegativeInt | None = pyd.Field(
45
+ manufacturers: pyd.NonNegativeInt | None = pyd.Field(
48
46
  default=None, description="Count of unique manufacturing companies that submitted data for this Industry EPD"
49
47
  )
50
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openepd
3
- Version: 6.12.1
3
+ Version: 6.13.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=fhxfEyEurLvSfvQci-vb3njzl_lvhcLXiZrecCOaMU8,794
2
- openepd/__version__.py,sha256=YzSSIKghgjH_RpO3Tffw6dYJf2wV2WNvVVEA1RJt70c,639
2
+ openepd/__version__.py,sha256=sgmt6cETSc5fqwbwM-ICVdVetdp89fDLgd8mFB7w4go,639
3
3
  openepd/api/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
4
4
  openepd/api/average_dataset/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
5
5
  openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=KHCmSKMOJTQct6vhdhAatAENoouStc_yVRza5AFNoIo,7953
@@ -32,6 +32,9 @@ openepd/bundle/writer.py,sha256=gHK1D-F-td2C18QFWerg666JUTLaGUkTUSQURJi9o74,8136
32
32
  openepd/compat/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
33
33
  openepd/compat/compat_functional_validators.py,sha256=aWg3a80fqT8zjN0S260N-Ad2WFKAaB8ByN7ArBW3NMA,834
34
34
  openepd/compat/pydantic.py,sha256=dNwPXK1X5xq9sdkd0kcbKQAUIter1GAfcxXOl6hmITQ,1146
35
+ openepd/m49/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
36
+ openepd/m49/const.py,sha256=O31VJ5_sR4GAOvJnFsi3An2YMaMa96H7XBqaQ0kNwnw,31734
37
+ openepd/m49/geo_converter.py,sha256=mRamQTVwd35kwn5-23N3E8cxqpYG7l9eW787SJYM7nw,6515
35
38
  openepd/model/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
36
39
  openepd/model/base.py,sha256=1GeaEDn-ppy94GaOaZI1y6Yew_0eBBho1COaxfzzLCw,9834
37
40
  openepd/model/category.py,sha256=reeOVRDuZPYU77EMwG0K5VjnK2H9yOGxT0PJXXqrjEk,1639
@@ -41,7 +44,7 @@ openepd/model/epd.py,sha256=qYYJQKbcFNOU_qS5Ag9CXn7Tx0TkIoUOZQEDGJI-xZw,12290
41
44
  openepd/model/factory.py,sha256=doexyqZXJVGd45T1JsbjuyGUjEykW-MerKUq4SQHhRY,2656
42
45
  openepd/model/generic_estimate.py,sha256=zLGTyf4Uzmp2C0m-J1ePWItSz2RGdZ0OiGPWC5nhKHk,3992
43
46
  openepd/model/geography.py,sha256=Jx7NIDdk_sIvwyh-7YxnIjAwIHW2HCQK7UtFGM2xKtw,42095
44
- openepd/model/industry_epd.py,sha256=pKt9rtW7iBPvp7zbMX5c6SRrjh3zb7iR6d3OayI_qHc,4039
47
+ openepd/model/industry_epd.py,sha256=QZr7OhgGkzqZ8H5p6dCIVk9zSHEYtK3y9Nk-DvkFMyk,4011
45
48
  openepd/model/lcia.py,sha256=gS4WFcw7v8PKKDCBUQXQP5I8Jh_TdyZyIklAjUc5HL4,25507
46
49
  openepd/model/org.py,sha256=MtaUrD8IdSbcMJEwL2lnXOIXNfE8wpzrepFSe2qh2uc,5342
47
50
  openepd/model/pcr.py,sha256=b8WmeII8MZ3rJFWxugqv_Z0ETan8NMWj9L6mSrhneJk,5494
@@ -136,7 +139,7 @@ openepd/model/validation/quantity.py,sha256=vfSe-3DGQf84bCp_sMIU0ZPAA1wIilodpTjL
136
139
  openepd/model/versioning.py,sha256=cm3LaAUODnbbu3W3pC6baJzxKusTQ1kZH-PwwScCj3c,4473
137
140
  openepd/patch_pydantic.py,sha256=LVqDMKn723VYYf_V-RgTLxIb1xiUtYOfPYCQP6-7RoM,4122
138
141
  openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
- openepd-6.12.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
140
- openepd-6.12.1.dist-info/METADATA,sha256=SX0KqNw2vVhumIUbF9N9ASCXIuTigkSG1foQMtayHwc,9039
141
- openepd-6.12.1.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
142
- openepd-6.12.1.dist-info/RECORD,,
142
+ openepd-6.13.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
143
+ openepd-6.13.1.dist-info/METADATA,sha256=T7QapSryr1s5pRrcSY-TBnm6HauXRFkEOD-_If1ZfpI,9039
144
+ openepd-6.13.1.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
145
+ openepd-6.13.1.dist-info/RECORD,,