commodutil 4.2.0__tar.gz → 4.3.0__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.
- {commodutil-4.2.0 → commodutil-4.3.0}/PKG-INFO +1 -1
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/__init__.py +3 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/convfactors.py +1 -2
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/__init__.py +4 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/units.py +47 -1
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/PKG-INFO +1 -1
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_units.py +24 -1
- {commodutil-4.2.0 → commodutil-4.3.0}/.coveragerc +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/1_tests.yml +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/2_coverage.yml +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/3_linting.yml +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/4_release.yml +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/.gitignore +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/.pypirc +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/azure-build-pipelines.yml +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/arb.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/dates.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/__init__.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/calendar.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/continuous.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/fly.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/quarterly.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/spreads.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/structure.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/util.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forwards.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/pandasutil.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/analysis_types.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/commodities.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/commodity_groups.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/currency.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/regions.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/stats.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/transforms.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/SOURCES.txt +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/dependency_links.txt +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/requires.txt +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/top_level.txt +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/pyproject.toml +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/requirements-test.txt +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/requirements.txt +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/requirements_dev.txt +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/setup.cfg +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/__init__.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/conftest.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/__init__.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/conftest.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_calendar.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_continuous.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_fly.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_quarterly.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_spreads.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_structure.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_util.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_arb.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_cl.csv +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_conv.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_dates.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_forwards.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_pandasutils.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_price_conv.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_analysis_types.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_commodities.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_commodity_groups.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_currency.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_regions.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_stats.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_transforms.py +0 -0
- {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_weekly.csv +0 -0
|
@@ -36,6 +36,9 @@ _LAZY_EXPORTS = {
|
|
|
36
36
|
"fractional_to_major": "commodutil.standards.currency",
|
|
37
37
|
"is_fractional_currency": "commodutil.standards.currency",
|
|
38
38
|
"split_currency_unit": "commodutil.standards.currency",
|
|
39
|
+
# standards.units (stdlib-only -- cheap, no pint)
|
|
40
|
+
"canonical_quantity_unit": "commodutil.standards.units",
|
|
41
|
+
"quantity_unit_from_price_unit": "commodutil.standards.units",
|
|
39
42
|
# dates
|
|
40
43
|
"curmon": "commodutil.dates",
|
|
41
44
|
"curmonyear": "commodutil.dates",
|
|
@@ -11,6 +11,7 @@ from dataclasses import dataclass
|
|
|
11
11
|
import pandas as pd
|
|
12
12
|
from functools import lru_cache
|
|
13
13
|
|
|
14
|
+
from commodutil.standards import currency as _currency
|
|
14
15
|
from commodutil.standards.units import to_pint_token as _to_pint_token
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
@@ -542,8 +543,6 @@ def convfactor(from_unit: str, to_unit: str, commodity: Optional[str] = None) ->
|
|
|
542
543
|
# above) and reads currency vocabulary directly from _currency. Callers
|
|
543
544
|
# wanting currency vocabulary should import from commodutil.standards.currency.
|
|
544
545
|
|
|
545
|
-
from commodutil.standards import currency as _currency
|
|
546
|
-
|
|
547
546
|
|
|
548
547
|
def convert_price(
|
|
549
548
|
value: Union[float, pd.Series],
|
|
@@ -43,7 +43,9 @@ from commodutil.standards.regions import (
|
|
|
43
43
|
)
|
|
44
44
|
from commodutil.standards.units import (
|
|
45
45
|
UNIT_MAP,
|
|
46
|
+
canonical_quantity_unit,
|
|
46
47
|
default_unit_for_commodity,
|
|
48
|
+
quantity_unit_from_price_unit,
|
|
47
49
|
to_pint_token,
|
|
48
50
|
)
|
|
49
51
|
|
|
@@ -81,6 +83,8 @@ __all__ = [
|
|
|
81
83
|
"normalize_region",
|
|
82
84
|
# units
|
|
83
85
|
"UNIT_MAP",
|
|
86
|
+
"canonical_quantity_unit",
|
|
84
87
|
"default_unit_for_commodity",
|
|
88
|
+
"quantity_unit_from_price_unit",
|
|
85
89
|
"to_pint_token",
|
|
86
90
|
]
|
|
@@ -26,6 +26,8 @@ from __future__ import annotations
|
|
|
26
26
|
|
|
27
27
|
from typing import Optional
|
|
28
28
|
|
|
29
|
+
from commodutil.standards.currency import split_currency_unit
|
|
30
|
+
|
|
29
31
|
|
|
30
32
|
# ---- Alias -> canonical normalisation ----
|
|
31
33
|
|
|
@@ -45,6 +47,7 @@ UNIT_MAP = {
|
|
|
45
47
|
"metric tons": "mt",
|
|
46
48
|
"metric tonne": "mt",
|
|
47
49
|
"metric tonnes": "mt",
|
|
50
|
+
"mt": "mt",
|
|
48
51
|
"tonne": "mt",
|
|
49
52
|
"tonnes": "mt",
|
|
50
53
|
}
|
|
@@ -72,6 +75,43 @@ def default_unit_for_commodity(commodity: Optional[str]) -> str:
|
|
|
72
75
|
return _DEFAULT_UNIT.get(str(commodity).lower(), "bbl")
|
|
73
76
|
|
|
74
77
|
|
|
78
|
+
def canonical_quantity_unit(unit: object) -> str | None:
|
|
79
|
+
"""Return the canonical quantity unit token for free-form unit text.
|
|
80
|
+
|
|
81
|
+
This intentionally covers quoted physical units only: ``bbl``, ``gal``,
|
|
82
|
+
and ``mt``. Rate periods and currencies are outside this vocabulary.
|
|
83
|
+
"""
|
|
84
|
+
if unit is None:
|
|
85
|
+
return None
|
|
86
|
+
text = str(unit).strip().lower()
|
|
87
|
+
if not text:
|
|
88
|
+
return None
|
|
89
|
+
return UNIT_MAP.get(text)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def quantity_unit_from_price_unit(price_unit: object) -> str | None:
|
|
93
|
+
"""Return the denominator quantity unit from a price-unit string.
|
|
94
|
+
|
|
95
|
+
Examples:
|
|
96
|
+
``USD/MT`` -> ``mt``
|
|
97
|
+
``USc/GAL`` -> ``gal``
|
|
98
|
+
``$/BBL`` -> ``bbl``
|
|
99
|
+
|
|
100
|
+
Bare quantity units are also accepted. Bare rate units such as
|
|
101
|
+
``bbl/day`` return ``None`` because the denominator is a time period, not
|
|
102
|
+
a physical quantity.
|
|
103
|
+
"""
|
|
104
|
+
if price_unit is None:
|
|
105
|
+
return None
|
|
106
|
+
text = str(price_unit).strip()
|
|
107
|
+
if not text:
|
|
108
|
+
return None
|
|
109
|
+
_, unit_text = split_currency_unit(text)
|
|
110
|
+
if "/" in unit_text:
|
|
111
|
+
_, _, unit_text = text.partition("/")
|
|
112
|
+
return canonical_quantity_unit(unit_text)
|
|
113
|
+
|
|
114
|
+
|
|
75
115
|
# ---- Pint-token normalisation ----
|
|
76
116
|
|
|
77
117
|
|
|
@@ -122,4 +162,10 @@ def to_pint_token(unit: Optional[str]) -> Optional[str]:
|
|
|
122
162
|
return u
|
|
123
163
|
|
|
124
164
|
|
|
125
|
-
__all__ = [
|
|
165
|
+
__all__ = [
|
|
166
|
+
"UNIT_MAP",
|
|
167
|
+
"canonical_quantity_unit",
|
|
168
|
+
"default_unit_for_commodity",
|
|
169
|
+
"quantity_unit_from_price_unit",
|
|
170
|
+
"to_pint_token",
|
|
171
|
+
]
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"""Tests for commodutil.standards.units."""
|
|
2
2
|
|
|
3
|
-
from commodutil.standards.units import
|
|
3
|
+
from commodutil.standards.units import (
|
|
4
|
+
canonical_quantity_unit,
|
|
5
|
+
default_unit_for_commodity,
|
|
6
|
+
quantity_unit_from_price_unit,
|
|
7
|
+
)
|
|
4
8
|
|
|
5
9
|
|
|
6
10
|
def test_natgas_defaults_to_mmbtu():
|
|
@@ -69,6 +73,25 @@ def test_unit_map_canonical_set_only_three():
|
|
|
69
73
|
assert set(UNIT_MAP.values()) == {"bbl", "gal", "mt"}
|
|
70
74
|
|
|
71
75
|
|
|
76
|
+
def test_canonical_quantity_unit_normalizes_common_labels():
|
|
77
|
+
assert canonical_quantity_unit("BBL") == "bbl"
|
|
78
|
+
assert canonical_quantity_unit("barrels") == "bbl"
|
|
79
|
+
assert canonical_quantity_unit("GAL") == "gal"
|
|
80
|
+
assert canonical_quantity_unit("Metric Tonnes") == "mt"
|
|
81
|
+
assert canonical_quantity_unit("mmbtu") is None
|
|
82
|
+
assert canonical_quantity_unit(None) is None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_quantity_unit_from_price_unit_uses_quote_denominator():
|
|
86
|
+
assert quantity_unit_from_price_unit("USD/MT") == "mt"
|
|
87
|
+
assert quantity_unit_from_price_unit("usd/mt") == "mt"
|
|
88
|
+
assert quantity_unit_from_price_unit("USc/GAL") == "gal"
|
|
89
|
+
assert quantity_unit_from_price_unit("USC/GAL") == "gal"
|
|
90
|
+
assert quantity_unit_from_price_unit("$/BBL") == "bbl"
|
|
91
|
+
assert quantity_unit_from_price_unit("BBL") == "bbl"
|
|
92
|
+
assert quantity_unit_from_price_unit("bbl/day") is None
|
|
93
|
+
|
|
94
|
+
|
|
72
95
|
# ---- to_pint_token tests ----
|
|
73
96
|
|
|
74
97
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|