commodutil 5.5.1__tar.gz → 5.5.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 (83) hide show
  1. {commodutil-5.5.1 → commodutil-5.5.2}/CHANGELOG.md +4 -0
  2. {commodutil-5.5.1 → commodutil-5.5.2}/PKG-INFO +1 -1
  3. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/geography.py +8 -3
  4. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil.egg-info/PKG-INFO +1 -1
  5. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_standards_geography.py +13 -0
  6. {commodutil-5.5.1 → commodutil-5.5.2}/uv.lock +3 -3
  7. {commodutil-5.5.1 → commodutil-5.5.2}/.coveragerc +0 -0
  8. {commodutil-5.5.1 → commodutil-5.5.2}/.github/workflows/1_tests.yml +0 -0
  9. {commodutil-5.5.1 → commodutil-5.5.2}/.github/workflows/2_coverage.yml +0 -0
  10. {commodutil-5.5.1 → commodutil-5.5.2}/.github/workflows/3_linting.yml +0 -0
  11. {commodutil-5.5.1 → commodutil-5.5.2}/.github/workflows/4_release.yml +0 -0
  12. {commodutil-5.5.1 → commodutil-5.5.2}/.gitignore +0 -0
  13. {commodutil-5.5.1 → commodutil-5.5.2}/.pypirc +0 -0
  14. {commodutil-5.5.1 → commodutil-5.5.2}/README.md +0 -0
  15. {commodutil-5.5.1 → commodutil-5.5.2}/azure-build-pipelines.yml +0 -0
  16. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/__init__.py +0 -0
  17. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/arb.py +0 -0
  18. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/convfactors.py +0 -0
  19. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/dates.py +0 -0
  20. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/__init__.py +0 -0
  21. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/calendar.py +0 -0
  22. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/continuous.py +0 -0
  23. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/fly.py +0 -0
  24. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/quarterly.py +0 -0
  25. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/spreads.py +0 -0
  26. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/structure.py +0 -0
  27. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forward/util.py +0 -0
  28. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/forwards.py +0 -0
  29. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/pandasutil.py +0 -0
  30. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/priceconv.py +0 -0
  31. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/__init__.py +0 -0
  32. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/analysis_types.py +0 -0
  33. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/commodities.py +0 -0
  34. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/commodity_groups.py +0 -0
  35. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/currency.py +0 -0
  36. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/price_unit.py +0 -0
  37. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/trading_hubs.py +0 -0
  38. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/unit_registry.py +0 -0
  39. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/standards/units.py +0 -0
  40. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/stats.py +0 -0
  41. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil/transforms.py +0 -0
  42. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil.egg-info/SOURCES.txt +0 -0
  43. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil.egg-info/dependency_links.txt +0 -0
  44. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil.egg-info/requires.txt +0 -0
  45. {commodutil-5.5.1 → commodutil-5.5.2}/commodutil.egg-info/top_level.txt +0 -0
  46. {commodutil-5.5.1 → commodutil-5.5.2}/pyproject.toml +0 -0
  47. {commodutil-5.5.1 → commodutil-5.5.2}/setup.cfg +0 -0
  48. {commodutil-5.5.1 → commodutil-5.5.2}/tests/__init__.py +0 -0
  49. {commodutil-5.5.1 → commodutil-5.5.2}/tests/conftest.py +0 -0
  50. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/__init__.py +0 -0
  51. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/conftest.py +0 -0
  52. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/test_calendar.py +0 -0
  53. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/test_continuous.py +0 -0
  54. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/test_fly.py +0 -0
  55. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/test_quarterly.py +0 -0
  56. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/test_spreads.py +0 -0
  57. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/test_structure.py +0 -0
  58. {commodutil-5.5.1 → commodutil-5.5.2}/tests/forward/test_util.py +0 -0
  59. {commodutil-5.5.1 → commodutil-5.5.2}/tests/golden/golden_factors.json +0 -0
  60. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_aliases.py +0 -0
  61. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_align_fx_result.py +0 -0
  62. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_arb.py +0 -0
  63. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_cl.csv +0 -0
  64. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_conv.py +0 -0
  65. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_dates.py +0 -0
  66. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_forwards.py +0 -0
  67. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_golden_factors.py +0 -0
  68. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_pandasutils.py +0 -0
  69. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_price_conv.py +0 -0
  70. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_price_unit.py +0 -0
  71. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_priceconv_reexports.py +0 -0
  72. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_rate_pint.py +0 -0
  73. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_regex_literals.py +0 -0
  74. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_standards_analysis_types.py +0 -0
  75. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_standards_commodities.py +0 -0
  76. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_standards_commodity_groups.py +0 -0
  77. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_standards_currency.py +0 -0
  78. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_standards_trading_hubs.py +0 -0
  79. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_standards_units.py +0 -0
  80. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_stats.py +0 -0
  81. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_transforms.py +0 -0
  82. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_unit_registry.py +0 -0
  83. {commodutil-5.5.1 → commodutil-5.5.2}/tests/test_weekly.csv +0 -0
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.5.2 - 2026-07-28
4
+
5
+ - Fixed country-name resolution to normalize ampersands to `and`, matching ISO names such as Antigua and Barbuda.
6
+
3
7
  ## 5.5.0 - 2026-07-27
4
8
 
5
9
  - Added `commodutil.standards.geography` with pycountry-backed countries, desk aliases, and membership-defined country groups; added `pycountry` as a production dependency.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commodutil
3
- Version: 5.5.1
3
+ Version: 5.5.2
4
4
  Summary: common commodity/oil analytics utils
5
5
  Author-email: aeorxc <author@example.com>
6
6
  License-Expression: MIT
@@ -98,6 +98,11 @@ COUNTRY_ALIASES: dict[str, str] = {
98
98
  }
99
99
 
100
100
 
101
+ def _normalize_country_name(name: str) -> str:
102
+ """Return the case-folded lookup key for a country name."""
103
+ return " ".join(name.replace("&", " and ").split()).casefold()
104
+
105
+
101
106
  def _build_country_name_map(aliases: Dict[str, str]) -> Dict[str, str]:
102
107
  """Build the case-folded name map and reject conflicting aliases."""
103
108
  result: Dict[str, str] = {}
@@ -106,7 +111,7 @@ def _build_country_name_map(aliases: Dict[str, str]) -> Dict[str, str]:
106
111
  name = getattr(country, attribute, None)
107
112
  if name is None:
108
113
  continue
109
- key = name.casefold()
114
+ key = _normalize_country_name(name)
110
115
  existing = result.get(key)
111
116
  if existing is not None and existing != country.alpha_2:
112
117
  raise ValueError(
@@ -120,7 +125,7 @@ def _build_country_name_map(aliases: Dict[str, str]) -> Dict[str, str]:
120
125
  raise ValueError(
121
126
  f"country alias {alias!r} has unknown country code {code!r}"
122
127
  )
123
- key = alias.casefold()
128
+ key = _normalize_country_name(alias)
124
129
  existing = result.get(key)
125
130
  if existing is not None and existing != code:
126
131
  raise ValueError(
@@ -144,7 +149,7 @@ def canonical_country(text: object) -> Optional[str]:
144
149
  code = cleaned.upper()
145
150
  if code in VALID_COUNTRY_CODES:
146
151
  return code
147
- return COUNTRY_NAME_MAP.get(cleaned.casefold())
152
+ return COUNTRY_NAME_MAP.get(_normalize_country_name(cleaned))
148
153
 
149
154
 
150
155
  def is_canonical_country(code: object) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commodutil
3
- Version: 5.5.1
3
+ Version: 5.5.2
4
4
  Summary: common commodity/oil analytics utils
5
5
  Author-email: aeorxc <author@example.com>
6
6
  License-Expression: MIT
@@ -66,6 +66,19 @@ def test_country_name_map_contains_pycountry_names_and_aliases():
66
66
  assert COUNTRY_NAME_MAP["uk"] == "GB"
67
67
 
68
68
 
69
+ @pytest.mark.parametrize(
70
+ "value,expected",
71
+ [
72
+ ("Antigua & Barbuda", "AG"),
73
+ ("Trinidad & Tobago", "TT"),
74
+ ("Bosnia & Herzegovina", "BA"),
75
+ ("&", None),
76
+ ],
77
+ )
78
+ def test_canonical_country_normalizes_ampersands(value, expected):
79
+ assert canonical_country(value) == expected
80
+
81
+
69
82
  @pytest.mark.parametrize(
70
83
  "value,expected",
71
84
  [
@@ -1627,7 +1627,7 @@ wheels = [
1627
1627
 
1628
1628
  [[package]]
1629
1629
  name = "twine"
1630
- version = "6.2.0"
1630
+ version = "7.0.0"
1631
1631
  source = { registry = "https://pypi.org/simple" }
1632
1632
  dependencies = [
1633
1633
  { name = "id" },
@@ -1640,9 +1640,9 @@ dependencies = [
1640
1640
  { name = "rich" },
1641
1641
  { name = "urllib3" },
1642
1642
  ]
1643
- sdist = { url = "https://files.pythonhosted.org/packages/e0/a8/949edebe3a82774c1ec34f637f5dd82d1cf22c25e963b7d63771083bbee5/twine-6.2.0.tar.gz", hash = "sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf", size = 172262, upload-time = "2025-09-04T15:43:17.255Z" }
1643
+ sdist = { url = "https://files.pythonhosted.org/packages/92/3c/58f808a359700f39a967dffede33efeac809262c03303fa3eec6afff8f49/twine-7.0.0.tar.gz", hash = "sha256:85cdb29c518efef867360ae4acd4b0dfd61c8654a22fca08e6f8539f05022177", size = 215032, upload-time = "2026-07-27T15:59:00.825Z" }
1644
1644
  wheels = [
1645
- { url = "https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl", hash = "sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8", size = 42727, upload-time = "2025-09-04T15:43:15.994Z" },
1645
+ { url = "https://files.pythonhosted.org/packages/96/08/ddcdc06225eaad6de0e48e1002b06d919dbde20582d0662c7af51308e5d6/twine-7.0.0-py3-none-any.whl", hash = "sha256:b854164df26db268af05f49aa5c0344b10e27a494343ff05b1e0bad3b135f5a7", size = 43204, upload-time = "2026-07-27T15:58:59.26Z" },
1646
1646
  ]
1647
1647
 
1648
1648
  [[package]]
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