openepd 3.1.1__tar.gz → 3.1.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 (95) hide show
  1. {openepd-3.1.1 → openepd-3.1.2}/PKG-INFO +2 -1
  2. {openepd-3.1.1 → openepd-3.1.2}/pyproject.toml +3 -2
  3. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/__version__.py +1 -1
  4. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/concrete.py +62 -17
  5. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/enums.py +26 -20
  6. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/openings.py +209 -79
  7. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/steel.py +109 -42
  8. {openepd-3.1.1 → openepd-3.1.2}/LICENSE +0 -0
  9. {openepd-3.1.1 → openepd-3.1.2}/README.md +0 -0
  10. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/__init__.py +0 -0
  11. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/__init__.py +0 -0
  12. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/base_sync_client.py +0 -0
  13. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/category/__init__.py +0 -0
  14. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/category/dto.py +0 -0
  15. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/category/sync_api.py +0 -0
  16. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/common.py +0 -0
  17. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/dto/__init__.py +0 -0
  18. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/dto/base.py +0 -0
  19. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/dto/common.py +0 -0
  20. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/dto/meta.py +0 -0
  21. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/dto/mf.py +0 -0
  22. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/dto/params.py +0 -0
  23. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/epd/__init__.py +0 -0
  24. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/epd/dto.py +0 -0
  25. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/epd/sync_api.py +0 -0
  26. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/errors.py +0 -0
  27. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/pcr/__init__.py +0 -0
  28. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/pcr/dto.py +0 -0
  29. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/pcr/sync_api.py +0 -0
  30. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/sync_client.py +0 -0
  31. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/api/test/__init__.py +0 -0
  32. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/bundle/__init__.py +0 -0
  33. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/bundle/base.py +0 -0
  34. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/bundle/model.py +0 -0
  35. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/bundle/reader.py +0 -0
  36. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/bundle/writer.py +0 -0
  37. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/compat/__init__.py +0 -0
  38. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/compat/pydantic.py +0 -0
  39. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/__init__.py +0 -0
  40. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/base.py +0 -0
  41. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/category.py +0 -0
  42. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/common.py +0 -0
  43. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/epd.py +0 -0
  44. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/factory.py +0 -0
  45. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/lcia.py +0 -0
  46. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/org.py +0 -0
  47. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/pcr.py +0 -0
  48. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/README.md +0 -0
  49. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/__init__.py +0 -0
  50. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/aluminium.py +0 -0
  51. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/asphalt.py +0 -0
  52. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/base.py +0 -0
  53. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/concrete.py +0 -0
  54. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/accessories.py +0 -0
  55. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/aggregates.py +0 -0
  56. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/aluminium.py +0 -0
  57. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/asphalt.py +0 -0
  58. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/bulk_materials.py +0 -0
  59. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/cast_decks_and_underlayment.py +0 -0
  60. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/cladding.py +0 -0
  61. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/cmu.py +0 -0
  62. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/common.py +0 -0
  63. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/conveying_equipment.py +0 -0
  64. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/electrical.py +0 -0
  65. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/electrical_transmission_and_distribution_equipment.py +0 -0
  66. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/electricity.py +0 -0
  67. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/finishes.py +0 -0
  68. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/fire_and_smoke_protection.py +0 -0
  69. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/furnishings.py +0 -0
  70. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/grouting.py +0 -0
  71. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/manufacturing_inputs.py +0 -0
  72. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/masonry.py +0 -0
  73. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/material_handling.py +0 -0
  74. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/mechanical.py +0 -0
  75. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/mechanical_insulation.py +0 -0
  76. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/network_infrastructure.py +0 -0
  77. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/other_electrical_equipment.py +0 -0
  78. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/other_materials.py +0 -0
  79. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/plumbing.py +0 -0
  80. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/precast_concrete.py +0 -0
  81. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/sheathing.py +0 -0
  82. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/thermal_moisture_protection.py +0 -0
  83. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/utility_piping.py +0 -0
  84. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/wood.py +0 -0
  85. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/generated/wood_joists.py +0 -0
  86. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/glass.py +0 -0
  87. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/steel.py +0 -0
  88. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/specs/wood.py +0 -0
  89. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/standard.py +0 -0
  90. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/validation/__init__.py +0 -0
  91. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/validation/common.py +0 -0
  92. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/validation/numbers.py +0 -0
  93. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/validation/quantity.py +0 -0
  94. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/model/versioning.py +0 -0
  95. {openepd-3.1.1 → openepd-3.1.2}/src/openepd/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openepd
3
- Version: 3.1.1
3
+ Version: 3.1.2
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
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Provides-Extra: api-client
20
20
  Requires-Dist: email-validator (>=1.3.1)
21
+ Requires-Dist: idna (>=3.7)
21
22
  Requires-Dist: pydantic (>=1.10,<3.0)
22
23
  Requires-Dist: requests (>=2.0) ; extra == "api-client"
23
24
  Project-URL: Repository, https://github.com/cchangelabs/openepd
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openepd"
3
- version = "3.1.1"
3
+ version = "3.1.2"
4
4
  license = "Apache-2.0"
5
5
  description = "Python library to work with OpenEPD format"
6
6
  authors = ["C-Change Labs <support@c-change-labs.com>"]
@@ -24,6 +24,7 @@ python = "^3.11"
24
24
  pydantic = ">=1.10,<3.0"
25
25
  email-validator = ">=1.3.1"
26
26
  requests = { version = ">=2.0", optional = true }
27
+ idna = ">=3.7"
27
28
 
28
29
  # Optional dependencies
29
30
  # lxml = { version = "~=4.9.2", optional = true }
@@ -38,7 +39,7 @@ teamcity-messages = ">=1.31"
38
39
  wheel = "~=0.40.0"
39
40
 
40
41
  # Dev tools
41
- black = "~=22.3"
42
+ black = "~=24.3"
42
43
  licenseheaders = "~=0.8"
43
44
  flake8 = "~=4.0"
44
45
  flake8-import-graph = "~=0.1.3"
@@ -17,4 +17,4 @@
17
17
  # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
18
  # Find out more at www.BuildingTransparency.org
19
19
  #
20
- VERSION = "3.1.1"
20
+ VERSION = "3.1.2"
@@ -34,19 +34,26 @@ from openepd.model.validation.quantity import (
34
34
 
35
35
 
36
36
  class CementGroutV1(BaseOpenEpdHierarchicalSpec):
37
- """Cement grout performance specification."""
37
+ """
38
+ Cement grout performance specification.
39
+
40
+ Cement grouting is a slurry that is placed as a flowable liquid. It is an effective material
41
+ for filling and strengthening granular soils, voids in rocks, foundation underpinnings, and
42
+ other underground voids. Also called structural grout, these materials typically impart
43
+ significant compressive strength to the system.
44
+ """
38
45
 
39
46
  _EXT_VERSION = "1.0"
40
47
 
41
48
 
42
49
  class ConcretePavingV1(BaseOpenEpdHierarchicalSpec):
43
- """Concrete paving performance specification."""
50
+ """Concrete paving."""
44
51
 
45
52
  _EXT_VERSION = "1.0"
46
53
 
47
54
  # Own fields:
48
55
  flexion_strength: PressureMPaStr | None = pyd.Field(
49
- default=None, description="Paving flexion strength", example="30 MPa"
56
+ default=None, description="Concrete flexural strength.", example="30 MPa"
50
57
  )
51
58
 
52
59
  _concrete_flexion_strength_is_quantity_validator = pyd.validator("flexion_strength", allow_reuse=True)(
@@ -55,36 +62,58 @@ class ConcretePavingV1(BaseOpenEpdHierarchicalSpec):
55
62
 
56
63
 
57
64
  class FlowableFillV1(BaseOpenEpdHierarchicalSpec):
58
- """Flowable fill performance specification."""
65
+ """
66
+ Flowable fill performance specification.
67
+
68
+ Flowable fill is a slurry that is placed as a flowable liquid (high slump) and sets with no
69
+ compaction. It is often used in tight or restricted access areas where placing and compacting
70
+ fill is difficult. Applications include filling large voids such as abandoned underground storage
71
+ tanks, basements, tunnels, mines, and sewers. It can also be used as paving sub-base, bridge
72
+ abutment, and retaining wall backfill.
73
+
74
+ Also called Controlled Density Fill (CDF) or Controlled Low Strength Materials (CLSMs). These materials typically
75
+ have compressive strengths under 1200 psi.
76
+ """
59
77
 
60
78
  _EXT_VERSION = "1.0"
61
79
 
62
80
 
63
81
  class OilPatchV1(BaseOpenEpdHierarchicalSpec):
64
- """Oil patch performance specification."""
82
+ """
83
+ Petroleum Industry Cement Slurry.
84
+
85
+ Concretes for use in creation, maintenance, and decommissioning of petroleum extraction wells and similar
86
+ applications. Includes foamed cement; often called cement in the drilling industry. Differs from
87
+ flowable fill and grout in that it contains no sand or other aggregates.
88
+ """
65
89
 
66
90
  _EXT_VERSION = "1.0"
67
91
 
68
92
 
69
93
  class ReadyMixV1(BaseOpenEpdHierarchicalSpec):
70
- """Concretes that are mixed just before use, and then poured on-site into forms."""
94
+ """Concretes to be mixed and then poured on-site."""
71
95
 
72
96
  _EXT_VERSION = "1.0"
73
97
 
74
98
 
75
99
  class ShotcreteV1(BaseOpenEpdHierarchicalSpec):
76
- """Shotcrete performance specification."""
100
+ """Concretes sprayed on a target."""
77
101
 
78
102
  _EXT_VERSION = "1.0"
79
103
 
80
104
 
81
105
  class ConcreteV1(BaseOpenEpdHierarchicalSpec):
82
- """Concrete performance specification."""
106
+ """
107
+ Concrete.
108
+
109
+ A composite material composed of fine and coarse aggregate bonded together with a fluid cement (cement paste) that
110
+ hardens over time.
111
+ """
83
112
 
84
113
  _EXT_VERSION = "1.0"
85
114
 
86
115
  # Own fields:
87
- lightweight: bool | None = pyd.Field(default=None, description="Lightweight", example=True)
116
+ lightweight: bool | None = pyd.Field(default=None, description="Product is lightweight", example=True)
88
117
 
89
118
  strength_28d: PressureMPaStr | None = pyd.Field(
90
119
  default=None, description="Concrete strength after 28 days", example="1 MPa"
@@ -95,14 +124,16 @@ class ConcreteV1(BaseOpenEpdHierarchicalSpec):
95
124
  example="30 MPa",
96
125
  )
97
126
  strength_other_d: Literal[3, 7, 14, 42, 56, 72, 96, 120] | None = pyd.Field(
98
- default=None, description="Test Day for the Late Strength", example=42
127
+ default=None, description="Test Day for strength_other", example=42
99
128
  )
100
129
 
101
130
  slump: LengthInchStr | None = pyd.Field(default=None, description="", example="2 in")
102
131
  min_slump: LengthInchStr | None = pyd.Field(default=None, description="Minimum test slump", example="2 in")
103
132
  max_slump: LengthInchStr | None = pyd.Field(default=None, description="", example="2 in")
104
133
 
105
- min_pipeline_size: LengthMmStr | None = pyd.Field(default=None, description="", example="200 mm")
134
+ min_pipeline_size: LengthMmStr | None = pyd.Field(
135
+ default=None, description="Minimum pipeline size", example="200 mm"
136
+ )
106
137
  w_c_ratio: RatioFloat | None = pyd.Field(
107
138
  default=None, description="Ratio of water to cement", example=0.5, ge=0, le=1
108
139
  )
@@ -114,13 +145,27 @@ class ConcreteV1(BaseOpenEpdHierarchicalSpec):
114
145
  finishable: bool | None = pyd.Field(default=None, description="Finishable", example=True)
115
146
  fiber_reinforced: bool | None = pyd.Field(default=None, description="fiber_reinforced", example=True)
116
147
 
117
- cementitious: Cementitious | None = pyd.Field(default=None, description="")
148
+ cementitious: Cementitious | None = pyd.Field(
149
+ default=None, description="List of cementitious materials, and proportion by mass"
150
+ )
118
151
 
119
- aggregate_size_max: LengthMmStr | None = pyd.Field(default=None, description="", example="0.0254 m")
120
- cement_content: MassKgStr | None = pyd.Field(default=None, description="", example="1 kg")
121
- aci_exposure_classes: list[AciExposureClass] | None = pyd.Field(default=None, description="", example=["aci.F0"])
122
- csa_exposure_classes: list[CsaExposureClass] | None = pyd.Field(default=None, description="", example=["csa.C-2"])
123
- en_exposure_classes: list[EnExposureClass] | None = pyd.Field(default=None, description="", example=["en206.X0"])
152
+ aggregate_size_max: LengthMmStr | None = pyd.Field(
153
+ default=None,
154
+ description="The smallest sieve size for which the entire amount of aggregate is able to pass. "
155
+ "Parameter describes diameter of aggregate",
156
+ example="8 mm",
157
+ )
158
+ cement_content: MassKgStr | None = pyd.Field(default=None, example="1 kg")
159
+
160
+ aci_exposure_classes: list[AciExposureClass] | None = pyd.Field(
161
+ default=None, description="List of ACI exposure classes", example=["aci.F0"]
162
+ )
163
+ csa_exposure_classes: list[CsaExposureClass] | None = pyd.Field(
164
+ default=None, description="List of CSA exposure classes", example=["csa.C-2"]
165
+ )
166
+ en_exposure_classes: list[EnExposureClass] | None = pyd.Field(
167
+ default=None, description="List of EN exposure classes", example=["en206.X0"]
168
+ )
124
169
  typical_application: ConcreteTypicalApplication | None = pyd.Field(default=None, description="Typical Application")
125
170
 
126
171
  _concrete_compressive_strength_28d_is_quantity_validator = pyd.validator("strength_28d", allow_reuse=True)(
@@ -372,14 +372,14 @@ class FrameMaterial(StrEnum):
372
372
  """
373
373
  Frame material.
374
374
 
375
- - Vinyl: Vinyl
376
- - Aluminium: Aluminium
377
- - Steel: Steel
378
- - Wood: Wood
379
- - Fiberglass: Fiberglass
380
- - Composite: Composite
381
- - None: None
382
- - Other: Other
375
+ - Vinyl: PVC and similar polymer frames
376
+ - Aluminium: Aluminium, with optional thermal improvement. Does not include aluminium clad.
377
+ - Steel: Steel, with optional thermal improvement
378
+ - Wood: Wood with optional cladding
379
+ - Fiberglass: Fiber reinforced plastic
380
+ - Composite: Plastic and Wood Fiber composite.
381
+ - None: This EPD does not cover the frame.
382
+ - Other: Other framing material not listed
383
383
 
384
384
  """
385
385
 
@@ -1793,12 +1793,12 @@ class HardwareFunction(StrEnum):
1793
1793
  """
1794
1794
  Hardware function.
1795
1795
 
1796
- - Lock: Lock
1797
- - Hinge: Hinge
1798
- - Handle: Handle
1799
- - Operator: Operator
1800
- - Balance: Balance
1801
- - Other: Other
1796
+ - Lock: Locks, Keepers, and similar items that resist opening.
1797
+ - Hinge: Hinges, Pivots, and similar items that secure glazing to the frame while it moves.
1798
+ - Handle: Handles, knobs, and similar items for directly manipulating a window.
1799
+ - Operator: Arms, Cranks, and other hardware that moves a window.
1800
+ - Balance: Springs, Sash Balances, and other items that counter the weight of an operable sash.
1801
+ - Other: Other hardware not described above.
1802
1802
 
1803
1803
  """
1804
1804
 
@@ -1975,11 +1975,17 @@ class ThermalSeparation(StrEnum):
1975
1975
  """
1976
1976
  Thermal separation.
1977
1977
 
1978
- - Aluminium: Aluminium
1979
- - Steel: Steel
1980
- - Thermally Improved Metal: Thermally Improved Metal
1981
- - Thermally Broken Metal: Thermally Broken Metal
1982
- - Nonmetal: Nonmetal
1978
+ - Aluminium: Aluminium System members with less than 1.6 mm (0.062 in) or no separation between metal or system
1979
+ members to provide a resistance heat transfer path from exterior to interior.
1980
+ - Steel: Steel System members with less than 1.6 mm (0.062 in) or no separation between metal or system members to
1981
+ provide a resistance heat transfer path from exterior to interior.
1982
+ - Thermally Improved Metal: Metal System members with a separation ≥ 1.60 mm (0.062 in) provided by either a
1983
+ thermal break or open air space that may be interrupted by short thermal bridges between the interior and
1984
+ exterior surfaces.
1985
+ - Thermally Broken Metal: Aluminium System members with a minimum of 5.30 mm (0.210 in) separation provided by
1986
+ a thermal break.
1987
+ - Nonmetal: Nonmetal material where the path from inside to outside inherently has low thermal conductivity,
1988
+ such as wood, vinyl, and fiberglass. Aluminium-clad or split windows fall in this category.
1983
1989
 
1984
1990
  """
1985
1991
 
@@ -2376,7 +2382,7 @@ class FlatGlassPanesThickness(StrEnum):
2376
2382
 
2377
2383
 
2378
2384
  class NAFSPerformanceGrade(StrEnum):
2379
- """NAFS Performance Grade enum."""
2385
+ """NAFS Performance Grade."""
2380
2386
 
2381
2387
  GRADE_15_PSF = "15 psf"
2382
2388
  GRADE_20_PSF = "20 psf"