commodutil 5.4.0__tar.gz → 5.5.1__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 (93) hide show
  1. commodutil-5.5.1/.github/workflows/1_tests.yml +40 -0
  2. commodutil-5.5.1/.github/workflows/2_coverage.yml +51 -0
  3. commodutil-5.5.1/.github/workflows/3_linting.yml +49 -0
  4. commodutil-5.5.1/.github/workflows/4_release.yml +58 -0
  5. {commodutil-5.4.0 → commodutil-5.5.1}/CHANGELOG.md +10 -0
  6. {commodutil-5.4.0 → commodutil-5.5.1}/PKG-INFO +3 -2
  7. commodutil-5.5.1/README.md +21 -0
  8. {commodutil-5.4.0 → commodutil-5.5.1}/azure-build-pipelines.yml +9 -1
  9. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/__init__.py +1 -1
  10. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/dates.py +1 -1
  11. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/calendar.py +1 -1
  12. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/continuous.py +5 -3
  13. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/quarterly.py +1 -1
  14. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/spreads.py +1 -2
  15. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/util.py +1 -1
  16. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forwards.py +3 -3
  17. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/__init__.py +38 -11
  18. commodutil-5.5.1/commodutil/standards/geography.py +352 -0
  19. commodutil-5.4.0/commodutil/standards/regions.py → commodutil-5.5.1/commodutil/standards/trading_hubs.py +28 -36
  20. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/stats.py +3 -1
  21. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil.egg-info/PKG-INFO +3 -2
  22. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil.egg-info/SOURCES.txt +7 -7
  23. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil.egg-info/requires.txt +1 -0
  24. {commodutil-5.4.0 → commodutil-5.5.1}/pyproject.toml +27 -1
  25. {commodutil-5.4.0 → commodutil-5.5.1}/tests/conftest.py +1 -1
  26. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/conftest.py +2 -2
  27. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/test_calendar.py +6 -4
  28. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/test_quarterly.py +5 -3
  29. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/test_spreads.py +5 -2
  30. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_arb.py +1 -1
  31. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_pandasutils.py +3 -3
  32. commodutil-5.5.1/tests/test_regex_literals.py +21 -0
  33. commodutil-5.5.1/tests/test_standards_geography.py +172 -0
  34. commodutil-5.5.1/tests/test_standards_trading_hubs.py +267 -0
  35. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_stats.py +7 -3
  36. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_transforms.py +4 -5
  37. commodutil-5.5.1/uv.lock +1682 -0
  38. commodutil-5.4.0/.github/workflows/1_tests.yml +0 -40
  39. commodutil-5.4.0/.github/workflows/2_coverage.yml +0 -52
  40. commodutil-5.4.0/.github/workflows/3_linting.yml +0 -47
  41. commodutil-5.4.0/.github/workflows/4_release.yml +0 -64
  42. commodutil-5.4.0/commodutil.egg-info/scm_file_list.json +0 -78
  43. commodutil-5.4.0/commodutil.egg-info/scm_version.json +0 -8
  44. commodutil-5.4.0/requirements-test.txt +0 -10
  45. commodutil-5.4.0/requirements.txt +0 -3
  46. commodutil-5.4.0/requirements_dev.txt +0 -8
  47. commodutil-5.4.0/tests/test_standards_regions.py +0 -355
  48. {commodutil-5.4.0 → commodutil-5.5.1}/.coveragerc +0 -0
  49. {commodutil-5.4.0 → commodutil-5.5.1}/.gitignore +0 -0
  50. {commodutil-5.4.0 → commodutil-5.5.1}/.pypirc +0 -0
  51. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/arb.py +0 -0
  52. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/convfactors.py +0 -0
  53. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/__init__.py +0 -0
  54. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/fly.py +0 -0
  55. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/forward/structure.py +0 -0
  56. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/pandasutil.py +0 -0
  57. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/priceconv.py +0 -0
  58. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/analysis_types.py +0 -0
  59. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/commodities.py +0 -0
  60. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/commodity_groups.py +0 -0
  61. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/currency.py +0 -0
  62. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/price_unit.py +0 -0
  63. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/unit_registry.py +0 -0
  64. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/standards/units.py +0 -0
  65. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil/transforms.py +0 -0
  66. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil.egg-info/dependency_links.txt +0 -0
  67. {commodutil-5.4.0 → commodutil-5.5.1}/commodutil.egg-info/top_level.txt +0 -0
  68. {commodutil-5.4.0 → commodutil-5.5.1}/setup.cfg +0 -0
  69. {commodutil-5.4.0 → commodutil-5.5.1}/tests/__init__.py +0 -0
  70. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/__init__.py +0 -0
  71. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/test_continuous.py +0 -0
  72. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/test_fly.py +0 -0
  73. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/test_structure.py +0 -0
  74. {commodutil-5.4.0 → commodutil-5.5.1}/tests/forward/test_util.py +0 -0
  75. {commodutil-5.4.0 → commodutil-5.5.1}/tests/golden/golden_factors.json +0 -0
  76. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_aliases.py +0 -0
  77. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_align_fx_result.py +0 -0
  78. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_cl.csv +0 -0
  79. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_conv.py +0 -0
  80. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_dates.py +0 -0
  81. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_forwards.py +0 -0
  82. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_golden_factors.py +0 -0
  83. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_price_conv.py +0 -0
  84. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_price_unit.py +0 -0
  85. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_priceconv_reexports.py +0 -0
  86. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_rate_pint.py +0 -0
  87. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_standards_analysis_types.py +0 -0
  88. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_standards_commodities.py +0 -0
  89. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_standards_commodity_groups.py +0 -0
  90. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_standards_currency.py +0 -0
  91. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_standards_units.py +0 -0
  92. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_unit_registry.py +0 -0
  93. {commodutil-5.4.0 → commodutil-5.5.1}/tests/test_weekly.csv +0 -0
@@ -0,0 +1,40 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, windows-latest]
17
+ python-version: ['3.11', '3.12']
18
+ timeout-minutes: 15
19
+
20
+ steps:
21
+ - name: Check out code repository
22
+ uses: actions/checkout@v7.0.0
23
+
24
+ - name: Set up uv and Python ${{ matrix.python-version }}
25
+ uses: astral-sh/setup-uv@v8.3.2
26
+ with:
27
+ version: '0.11.28'
28
+ python-version: ${{ matrix.python-version }}
29
+ enable-cache: true
30
+ cache-dependency-glob: pyproject.toml
31
+
32
+ # Oil_Feed is private and GitHub has no OIL_FEED_PAT secret yet. Resolve
33
+ # from public PyPI without changing the committed Azure lock.
34
+ - name: Resolve project test dependencies from public PyPI
35
+ run: |
36
+ python -c "from pathlib import Path; Path('uv.lock').unlink()"
37
+ uv --no-config sync --default-index https://pypi.org/simple --no-default-groups --group test
38
+
39
+ - name: Run unit tests
40
+ run: uv run --no-sync pytest
@@ -0,0 +1,51 @@
1
+ name: Code coverage
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ run:
12
+ runs-on: ubuntu-latest
13
+ env:
14
+ OS: ubuntu-latest
15
+ PYTHON: '3.12'
16
+ timeout-minutes: 15
17
+
18
+ steps:
19
+ - name: Check out code repository
20
+ uses: actions/checkout@v7.0.0
21
+
22
+ - name: Set up uv and Python 3.12
23
+ uses: astral-sh/setup-uv@v8.3.2
24
+ with:
25
+ version: '0.11.28'
26
+ python-version: '3.12'
27
+ enable-cache: true
28
+ cache-dependency-glob: pyproject.toml
29
+
30
+ # Oil_Feed is private and GitHub has no OIL_FEED_PAT secret yet. Resolve
31
+ # from public PyPI without changing the committed Azure lock.
32
+ - name: Resolve project test dependencies from public PyPI
33
+ run: |
34
+ python -c "from pathlib import Path; Path('uv.lock').unlink()"
35
+ uv --no-config sync --default-index https://pypi.org/simple --no-default-groups --group test
36
+
37
+ - name: Generate coverage report
38
+ run: |
39
+ uv run --no-sync coverage run -m pytest
40
+ uv run --no-sync coverage xml
41
+
42
+ - name: Upload coverage to Codecov
43
+ uses: codecov/codecov-action@v7.0.0
44
+ with:
45
+ token: ${{ secrets.CODECOV_TOKEN }}
46
+ env_vars: OS,PYTHON
47
+ fail_ci_if_error: true
48
+ files: coverage.xml
49
+ flags: unittests
50
+ name: codecov-umbrella
51
+ verbose: true
@@ -0,0 +1,49 @@
1
+ name: Lint and format code
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ lint:
12
+ runs-on: ubuntu-latest
13
+ env:
14
+ OS: ubuntu-latest
15
+ PYTHON: '3.12'
16
+ timeout-minutes: 15
17
+
18
+ steps:
19
+ - name: Check out code repository
20
+ uses: actions/checkout@v7.0.0
21
+
22
+ - name: Set up uv and Python 3.12
23
+ uses: astral-sh/setup-uv@v8.3.2
24
+ with:
25
+ version: '0.11.28'
26
+ python-version: '3.12'
27
+ enable-cache: true
28
+ cache-dependency-glob: pyproject.toml
29
+
30
+ # Oil_Feed is private and GitHub has no OIL_FEED_PAT secret yet. Resolve
31
+ # from public PyPI without changing the committed Azure lock.
32
+ - name: Resolve project development dependencies from public PyPI
33
+ run: |
34
+ python -c "from pathlib import Path; Path('uv.lock').unlink()"
35
+ uv --no-config sync --default-index https://pypi.org/simple --no-default-groups --group dev
36
+
37
+ - name: Lint with pylint
38
+ continue-on-error: true
39
+ run: uv run --no-sync pylint commodutil
40
+
41
+ - name: Run Black check
42
+ continue-on-error: true
43
+ run: uv run --no-sync black --check .
44
+
45
+ - name: Check type hints with mypy
46
+ continue-on-error: true
47
+ run: |
48
+ uv run --no-sync mypy commodutil
49
+ uv run --no-sync mypy tests
@@ -0,0 +1,58 @@
1
+ name: Upload release to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - '*'
7
+ release:
8
+ types: [ created ]
9
+
10
+ jobs:
11
+ deploy:
12
+ runs-on: ubuntu-latest
13
+ env:
14
+ OS: ubuntu-latest
15
+ PYTHON: '3.12'
16
+ timeout-minutes: 15
17
+
18
+ steps:
19
+ - name: Check out code repository
20
+ uses: actions/checkout@v7.0.0
21
+ with:
22
+ fetch-depth: 0
23
+
24
+ - name: Set up uv and Python 3.12
25
+ uses: astral-sh/setup-uv@v8.3.2
26
+ with:
27
+ version: '0.11.28'
28
+ python-version: '3.12'
29
+ enable-cache: true
30
+ cache-dependency-glob: pyproject.toml
31
+
32
+ - name: Get version from tag
33
+ run: |
34
+ VERSION="${GITHUB_REF_NAME#v}"
35
+ echo "SETUPTOOLS_SCM_PRETEND_VERSION=$VERSION" >> "$GITHUB_ENV"
36
+ echo "Building version: $VERSION"
37
+
38
+ # Oil_Feed is private and GitHub has no OIL_FEED_PAT secret yet. Resolve
39
+ # from public PyPI without changing the committed Azure lock.
40
+ - name: Resolve release tooling from public PyPI
41
+ run: |
42
+ python -c "from pathlib import Path; Path('uv.lock').unlink()"
43
+ uv --no-config sync --default-index https://pypi.org/simple --no-default-groups --group release
44
+
45
+ - name: Build source and wheel distributions
46
+ run: uv --no-config build --no-sources
47
+
48
+ - name: Publish to TestPyPI
49
+ env:
50
+ TWINE_USERNAME: __token__
51
+ TWINE_PASSWORD: ${{ secrets.TESTPYPI_API_TOKEN }}
52
+ run: uv run --no-sync twine upload --repository-url https://test.pypi.org/legacy/ dist/*
53
+
54
+ - name: Publish to PyPI
55
+ env:
56
+ TWINE_USERNAME: __token__
57
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
58
+ run: uv run --no-sync twine upload dist/*
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.5.0 - 2026-07-27
4
+
5
+ - Added `commodutil.standards.geography` with pycountry-backed countries, desk aliases, and membership-defined country groups; added `pycountry` as a production dependency.
6
+ - Breaking: `standards.regions` renamed to `standards.trading_hubs`; region-named symbols renamed (`REGION_PATTERNS` -> `TRADING_HUB_PATTERNS`, `VALID_REGIONS` -> `VALID_TRADING_HUBS`, `normalize_region` -> `normalize_trading_hub`, `is_valid_region` -> `is_valid_trading_hub`); no compatibility shim. Migrate imports to `commodutil.standards.trading_hubs`. `CRUDE_GRADE_REGIONS` family unchanged (relocated).
7
+
8
+ ## 5.4.1 - 2026-07-16
9
+
10
+ - Added pandas 3 compatibility and removed project-owned deprecation and invalid-escape warnings.
11
+ - Migrated Azure Pipelines and GitHub Actions to reproducible, locked uv project-mode installs.
12
+
3
13
  ## 5.4.0 - 2026-07-12
4
14
 
5
15
  - Added `normalize_price_unit_strict` and `is_canonical_price_unit` to `commodutil.standards.units` (and the `commodutil` / `commodutil.standards` facades): the STRICT counterpart to the lenient `canonical_price_unit_token`. Where the lenient token preserves unrecognised currency/unit fragments so it can label any quote string, the strict variant returns a canonical `CCY/unit` token only when both legs resolve (recognised currency over a `canonical_quantity_unit` denominator) and `None` otherwise — for validating a curated price-unit qualifier that must round-trip through conversion (e.g. `usd_ton`/`USD/ton` refused, `USD/MT` -> `USD/mt`).
@@ -1,17 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commodutil
3
- Version: 5.4.0
3
+ Version: 5.5.1
4
4
  Summary: common commodity/oil analytics utils
5
5
  Author-email: aeorxc <author@example.com>
6
+ License-Expression: MIT
6
7
  Project-URL: Homepage, https://dev.azure.com/RWEST-MFI-TE/Oil/_git/commodutil
7
8
  Project-URL: Source, https://dev.azure.com/RWEST-MFI-TE/Oil/_git/commodutil
8
9
  Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.9
12
12
  Requires-Dist: pandas>=2.1
13
13
  Requires-Dist: dask[delayed]
14
14
  Requires-Dist: pint
15
+ Requires-Dist: pycountry
15
16
  Requires-Dist: python-dateutil
16
17
  Provides-Extra: test
17
18
  Requires-Dist: pytest; extra == "test"
@@ -0,0 +1,21 @@
1
+ # commodutil
2
+ Common commodity and oil analytics utilities.
3
+
4
+ ## Dependency modes
5
+ `pyproject.toml` is commodutil's only dependency declaration. Runtime dependencies live in
6
+ `project.dependencies`; PEP 735 groups provide `test`, `dev`, and `release` tooling.
7
+
8
+ Azure Pipelines uses locked project mode. `uv.lock` fixes the exact Oil_Feed solution, and
9
+ the pipeline installs the `test` group on Python 3.11 and 3.12 before testing the exact wheel
10
+ built once upstream. After changing dependencies, regenerate the lock with uv 0.11.28 against
11
+ Oil_Feed and run `uv lock --check`. The lock may contain the credential-free feed URL, but it
12
+ must never contain usernames, tokens, or other registries.
13
+
14
+ The shared pipeline template also supports a requirements mode for other legacy repositories.
15
+ commodutil does not use that mode and intentionally has no `requirements*.txt` manifests.
16
+
17
+ Oil_Feed is private and this GitHub repository currently has no feed credential. GitHub Actions
18
+ therefore removes the feed-specific lock only in its ephemeral checkout and resolves the same
19
+ pyproject groups from public PyPI. To make GitHub use the committed frozen solution, add an
20
+ `OIL_FEED_PAT` repository secret with Azure Artifacts Packaging Read permission, then replace
21
+ the public-resolution step with runtime-authenticated `uv sync --frozen`. Never commit the PAT.
@@ -9,14 +9,22 @@ extends:
9
9
  template: templates/python-packages-pipeline.yml@pipeline-templates
10
10
  parameters:
11
11
  packageName: 'commodutil'
12
+ pythonVersion: '3.12'
13
+ additionalPythonVersions:
14
+ - '3.11'
15
+ dependencyMode: project
16
+ dependencyGroups:
17
+ - test
18
+ installOdbc: false
12
19
  createRefinitivConfig: false
13
20
 
14
21
  pool: Self-Hosted-AWS
15
22
 
16
23
  trigger:
24
+ batch: true
17
25
  branches:
18
26
  include:
19
27
  - main
20
28
  tags:
21
29
  include:
22
- - "*"
30
+ - "*"
@@ -7,7 +7,7 @@ facade eagerly imported convfactors and its pint registry).
7
7
 
8
8
  Cheap paths:
9
9
  import commodutil # near-instant
10
- from commodutil.standards.regions import ... # stdlib only
10
+ from commodutil.standards.trading_hubs import ... # stdlib only
11
11
  from commodutil.standards.currency import ... # stdlib only
12
12
 
13
13
  Heavier paths (lazy-load their sub-module on first attribute access):
@@ -77,7 +77,7 @@ def find_year(df, use_delta=False):
77
77
  """
78
78
  res = {}
79
79
  for colname in df:
80
- colregex = re.findall("\d\d\d\d", str(colname))
80
+ colregex = re.findall(r"\d\d\d\d", str(colname))
81
81
  colyear = None
82
82
  if len(colregex) >= 1:
83
83
  colyear = int(colregex[0])
@@ -231,7 +231,7 @@ def half_year_contracts(contracts):
231
231
  s.name = "Summer {}".format(year)
232
232
  dfs.append(s)
233
233
 
234
- res = pd.concat(dfs, axis=1)
234
+ res = pd.concat(dfs, axis=1, sort=True)
235
235
  # sort columns by years
236
236
  cols = list(res.columns)
237
237
  cols.sort(key=lambda s: s.split()[1])
@@ -36,8 +36,8 @@ def generate_series(df, expiry_dates=None, roll_days=0, front_month=1, back_adju
36
36
  continuous_dfs = []
37
37
 
38
38
  for front_month_x in front_month:
39
- mask_switch = pd.DataFrame(index=df.index, columns=df.columns)
40
- mask_adjust = pd.DataFrame(index=df.index, columns=df.columns)
39
+ mask_switch = pd.DataFrame(index=df.index, columns=df.columns, dtype=float)
40
+ mask_adjust = pd.DataFrame(index=df.index, columns=df.columns, dtype=float)
41
41
 
42
42
  # Iterating over the columns (contracts)
43
43
  for contract in df.columns:
@@ -79,7 +79,9 @@ def generate_series(df, expiry_dates=None, roll_days=0, front_month=1, back_adju
79
79
 
80
80
  # Back-adjustment
81
81
  if back_adjust:
82
- mask_adjust_series = mask_adjust.fillna(method='bfill').sum(axis=1, skipna=True, min_count=1).fillna(0)
82
+ mask_adjust_series = mask_adjust.bfill().sum(
83
+ axis=1, skipna=True, min_count=1
84
+ ).fillna(0)
83
85
  continuous_df = continuous_df.add(mask_adjust_series, axis=0)
84
86
 
85
87
  continuous_dfs.append(continuous_df)
@@ -100,7 +100,7 @@ def quarterly_contracts(contracts, col_format=None):
100
100
  dfs.append(s)
101
101
 
102
102
  if len(dfs) > 0:
103
- res = pd.concat(dfs, axis=1)
103
+ res = pd.concat(dfs, axis=1, sort=True)
104
104
  # sort columns by years
105
105
  cols = list(res.columns)
106
106
  cols.sort(key=lambda s: s.split()[1])
@@ -1,4 +1,3 @@
1
- import datetime
2
1
  from calendar import month_abbr
3
2
 
4
3
  import pandas as pd
@@ -121,7 +120,7 @@ def all_monthly_spreads_extended(contracts, col_format=None):
121
120
  if not dfs:
122
121
  return None
123
122
 
124
- res = pd.concat(dfs, axis=1)
123
+ res = pd.concat(dfs, axis=1, sort=True)
125
124
  legmap = {}
126
125
  for df in dfs:
127
126
  legmap.update(df.attrs)
@@ -14,7 +14,7 @@ def convert_contract_to_date(contract):
14
14
  :param contract:
15
15
  :return:
16
16
  """
17
- c = re.findall("\d\d\d\d\w", contract)
17
+ c = re.findall(r"\d\d\d\d\w", contract)
18
18
  if len(c) > 0:
19
19
  c = c[0]
20
20
  d = "%s-%s-1" % (c[:4], futures_month_conv_inv.get(c[-1], 0))
@@ -88,7 +88,7 @@ def spread_combination_quarter(contracts, combination_type, verbose_columns=True
88
88
  contracts.attrs = {}
89
89
  if combination_type.startswith("q"):
90
90
  q_contracts = quarterly_contracts(contracts)
91
- m = re.search("q\dq\dq\d", combination_type)
91
+ m = re.search(r"q\dq\dq\d", combination_type)
92
92
  if m:
93
93
  q_spreads = fly_quarterly(
94
94
  q_contracts,
@@ -104,7 +104,7 @@ def spread_combination_quarter(contracts, combination_type, verbose_columns=True
104
104
  if exclude_price_month:
105
105
  contracts = q_spreads.apply(replace_last_month_with_nan, axis=0)
106
106
  return q_spreads
107
- m = re.search("q\dq\d", combination_type)
107
+ m = re.search(r"q\dq\d", combination_type)
108
108
  if m:
109
109
  q_spreads = time_spreads_quarterly(
110
110
  contracts, combination_type[0:2], combination_type[2:4]
@@ -121,7 +121,7 @@ def spread_combination_quarter(contracts, combination_type, verbose_columns=True
121
121
  contracts = q_spreads.apply(replace_last_month_with_nan, axis=0)
122
122
  return q_spreads
123
123
 
124
- m = re.search("q\d", combination_type)
124
+ m = re.search(r"q\d", combination_type)
125
125
  if m:
126
126
  q_contracts = q_contracts[
127
127
  [
@@ -1,7 +1,7 @@
1
1
  """commodutil.standards: canonical vocabularies for commodity trading.
2
2
 
3
3
  Re-exports the public surface of each submodule so callers can write
4
- `from commodutil.standards import normalize_region` instead of reaching
4
+ `from commodutil.standards import normalize_trading_hub` instead of reaching
5
5
  into the submodule directly.
6
6
  """
7
7
 
@@ -34,19 +34,33 @@ from commodutil.standards.currency import (
34
34
  split_currency_unit,
35
35
  to_symbol,
36
36
  )
37
+ from commodutil.standards.geography import (
38
+ COUNTRY_ALIASES,
39
+ COUNTRY_GROUP_MEMBERS,
40
+ COUNTRY_GROUP_ROWS,
41
+ COUNTRY_NAME_MAP,
42
+ VALID_COUNTRY_CODES,
43
+ VALID_COUNTRY_GROUP_KEYS,
44
+ CountryGroupRow,
45
+ canonical_country,
46
+ country_group_members,
47
+ country_in_group,
48
+ is_canonical_country,
49
+ is_canonical_country_group,
50
+ )
37
51
  from commodutil.standards.price_unit import (
38
52
  PriceUnit,
39
53
  resolve_price_unit,
40
54
  resolve_price_unit_from_attrs,
41
55
  )
42
- from commodutil.standards.regions import (
56
+ from commodutil.standards.trading_hubs import (
43
57
  CRUDE_GRADE_REGIONS,
44
- REGION_PATTERNS,
58
+ TRADING_HUB_PATTERNS,
45
59
  VALID_CRUDE_GRADE_REGIONS,
46
- VALID_REGIONS,
60
+ VALID_TRADING_HUBS,
47
61
  is_crude_grade_region,
48
- is_valid_region,
49
- normalize_region,
62
+ is_valid_trading_hub,
63
+ normalize_trading_hub,
50
64
  )
51
65
  from commodutil.standards.units import (
52
66
  UNIT_MAP,
@@ -85,18 +99,31 @@ __all__ = [
85
99
  "required_fx_pair",
86
100
  "split_currency_unit",
87
101
  "to_symbol",
102
+ # geography
103
+ "COUNTRY_ALIASES",
104
+ "VALID_COUNTRY_CODES",
105
+ "COUNTRY_NAME_MAP",
106
+ "canonical_country",
107
+ "is_canonical_country",
108
+ "CountryGroupRow",
109
+ "COUNTRY_GROUP_ROWS",
110
+ "VALID_COUNTRY_GROUP_KEYS",
111
+ "COUNTRY_GROUP_MEMBERS",
112
+ "is_canonical_country_group",
113
+ "country_group_members",
114
+ "country_in_group",
88
115
  # price_unit
89
116
  "PriceUnit",
90
117
  "resolve_price_unit",
91
118
  "resolve_price_unit_from_attrs",
92
- # regions
119
+ # trading_hubs
93
120
  "CRUDE_GRADE_REGIONS",
94
- "REGION_PATTERNS",
121
+ "TRADING_HUB_PATTERNS",
95
122
  "VALID_CRUDE_GRADE_REGIONS",
96
- "VALID_REGIONS",
123
+ "VALID_TRADING_HUBS",
97
124
  "is_crude_grade_region",
98
- "is_valid_region",
99
- "normalize_region",
125
+ "is_valid_trading_hub",
126
+ "normalize_trading_hub",
100
127
  # units
101
128
  "UNIT_MAP",
102
129
  "canonical_price_unit_token",