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.
Files changed (69) hide show
  1. {commodutil-4.2.0 → commodutil-4.3.0}/PKG-INFO +1 -1
  2. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/__init__.py +3 -0
  3. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/convfactors.py +1 -2
  4. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/__init__.py +4 -0
  5. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/units.py +47 -1
  6. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/PKG-INFO +1 -1
  7. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_units.py +24 -1
  8. {commodutil-4.2.0 → commodutil-4.3.0}/.coveragerc +0 -0
  9. {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/1_tests.yml +0 -0
  10. {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/2_coverage.yml +0 -0
  11. {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/3_linting.yml +0 -0
  12. {commodutil-4.2.0 → commodutil-4.3.0}/.github/workflows/4_release.yml +0 -0
  13. {commodutil-4.2.0 → commodutil-4.3.0}/.gitignore +0 -0
  14. {commodutil-4.2.0 → commodutil-4.3.0}/.pypirc +0 -0
  15. {commodutil-4.2.0 → commodutil-4.3.0}/azure-build-pipelines.yml +0 -0
  16. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/arb.py +0 -0
  17. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/dates.py +0 -0
  18. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/__init__.py +0 -0
  19. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/calendar.py +0 -0
  20. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/continuous.py +0 -0
  21. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/fly.py +0 -0
  22. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/quarterly.py +0 -0
  23. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/spreads.py +0 -0
  24. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/structure.py +0 -0
  25. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forward/util.py +0 -0
  26. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/forwards.py +0 -0
  27. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/pandasutil.py +0 -0
  28. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/analysis_types.py +0 -0
  29. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/commodities.py +0 -0
  30. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/commodity_groups.py +0 -0
  31. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/currency.py +0 -0
  32. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/standards/regions.py +0 -0
  33. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/stats.py +0 -0
  34. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil/transforms.py +0 -0
  35. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/SOURCES.txt +0 -0
  36. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/dependency_links.txt +0 -0
  37. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/requires.txt +0 -0
  38. {commodutil-4.2.0 → commodutil-4.3.0}/commodutil.egg-info/top_level.txt +0 -0
  39. {commodutil-4.2.0 → commodutil-4.3.0}/pyproject.toml +0 -0
  40. {commodutil-4.2.0 → commodutil-4.3.0}/requirements-test.txt +0 -0
  41. {commodutil-4.2.0 → commodutil-4.3.0}/requirements.txt +0 -0
  42. {commodutil-4.2.0 → commodutil-4.3.0}/requirements_dev.txt +0 -0
  43. {commodutil-4.2.0 → commodutil-4.3.0}/setup.cfg +0 -0
  44. {commodutil-4.2.0 → commodutil-4.3.0}/tests/__init__.py +0 -0
  45. {commodutil-4.2.0 → commodutil-4.3.0}/tests/conftest.py +0 -0
  46. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/__init__.py +0 -0
  47. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/conftest.py +0 -0
  48. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_calendar.py +0 -0
  49. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_continuous.py +0 -0
  50. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_fly.py +0 -0
  51. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_quarterly.py +0 -0
  52. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_spreads.py +0 -0
  53. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_structure.py +0 -0
  54. {commodutil-4.2.0 → commodutil-4.3.0}/tests/forward/test_util.py +0 -0
  55. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_arb.py +0 -0
  56. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_cl.csv +0 -0
  57. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_conv.py +0 -0
  58. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_dates.py +0 -0
  59. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_forwards.py +0 -0
  60. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_pandasutils.py +0 -0
  61. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_price_conv.py +0 -0
  62. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_analysis_types.py +0 -0
  63. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_commodities.py +0 -0
  64. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_commodity_groups.py +0 -0
  65. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_currency.py +0 -0
  66. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_standards_regions.py +0 -0
  67. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_stats.py +0 -0
  68. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_transforms.py +0 -0
  69. {commodutil-4.2.0 → commodutil-4.3.0}/tests/test_weekly.csv +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commodutil
3
- Version: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: common commodity/oil analytics utils
5
5
  Author-email: aeorxc <author@example.com>
6
6
  Project-URL: Homepage, https://dev.azure.com/RWEST-MFI-TE/Oil/_git/commodutil
@@ -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__ = ["UNIT_MAP", "default_unit_for_commodity", "to_pint_token"]
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,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commodutil
3
- Version: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: common commodity/oil analytics utils
5
5
  Author-email: aeorxc <author@example.com>
6
6
  Project-URL: Homepage, https://dev.azure.com/RWEST-MFI-TE/Oil/_git/commodutil
@@ -1,6 +1,10 @@
1
1
  """Tests for commodutil.standards.units."""
2
2
 
3
- from commodutil.standards.units import default_unit_for_commodity
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