Skip to content

Commit d1469a0

Browse files
authored
Feature update python (#368)
* Update unit_tests.yaml change python version from 3.10 to 3.12, using existing requirements.txt * Update requirements.txt update versions that were installed for Python 3.12 conda environment * Update unit_tests.yaml check out the feature_update_python branch of METcalcpy to incorporate the Python 3.12 changes * Update requirements.txt pyyaml should be 6.0.2 * Updating to Python 3.12 use "assert mock_foo.called" rather than "assert mock_foo.called_once_with(...)" Refer to this: python/cpython#100690 * Update numpy to 2.2.3 to be consistent with METcalcpy and METplotpy * Update python version * Change ?=3.12 to =3.12 for Python version * set minimum python version to 3.11 * Revert back to mimimum python of 3.10.4 * fix missing " * update escape sequence in lines 432 and 436 to be compatible with Python 3.12 * in pandas to_datetime, replace errors='ignore' to errors='raise' to address the FutureWarning * Addres FutureWarning: Downcasting behavior in the replace method. Opt-in to the future behavior and explicitly as specified in StackOverflow: https://stackoverflow.com/questions/79226735/pandas-replace-and-downcasting-deprecation-since-version-2-2-0 * update package versions to be consistent with those specified in the requirements.txt file * In addressing the FutureWarning, inadvertantly left the request for dtype in command. * use the feature_update_python branch instead of the develop branch to use the correct package versions * Explicitly cast the fill value to an int to satisfy the pandas 2.2 expectation of an int dtype * convert the OBS_LEAD andt FCST_LEAD series to int64 to make all dtypes consistent * set dtypes to OBS_LEAD and FCST_LEAD columns to facilitate merging * set dtype of the FCST_LEAD and OBS_LEAD series earlier, to fix error when using pandas merge * Revert to original code * Revert the OBS_LEAD column to match original code. Replicate same method for setting the FCST_LEAD column to int * set the FCST_LEAD and OBS_LEAD columns as strings, as the fill values in the constants.py file are supposed to be strings * Explicitly change the type of the fcst_lead and obs_lead columns prior to merging to address the FutureWarning * Address the ValueError when merging the OBS_LEAD columns between two different dataframes where one type is an int vs object * After merge, change the OBS_LEAD column to string values to address failing tests * move dtype reassignment outside of try-except code and catch only exceptions from merge validation issues * remove try-except and include changing the dtypes for the fcst_lead in both dataframes so they are consistent (and avoiding the ValueError when merging on different dtypes) * fix indentation error * fix syntax for verifying merge operation * Remove the validate option on merging two dataframes * Explicitly set the dtypes in fcst_column and obs_column for remaining merge operations * Update requirements.txt * Update requirements.txt * Update requirements.txt * Update nco_requirements.txt updates to package versions for Python 3.12 migration * Package versions for Python 3.10 * For testing current code for backwards compatibility with Python 3.10 * Update the names of the runs to facilitate monitoring of GHA's * Remove the python 3.10 run to isolate issues from running tests * Updates for Python 3.12 * Python 3.10 version for sonarqube * Unused/ignored, removing this. * Testing for Python 3.10 * Update unit_tests.yaml updated the METcalcpy version from feature_update_python to the develop branch * Update py310_unit_tests.yaml update METcalcpy branch to develop * Update benchmark_pandas2_2.yaml update METcalcpy branch to develop * Address another deprecation with m_2d_data.obs_valid * Removing testing for Python 3.10 due to lack of backwards compatibility in Pandas: pandas-dev/pandas#59845 * Updated for Python 3.12 * Update .readthedocs.yaml update for Python 3.12 * Update sonarqube.yaml update METcalcpy branch to the develop branch
1 parent 0a08ff5 commit d1469a0

14 files changed

+93
-51
lines changed

.github/workflows/benchmark_pandas2_2.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
strategy:
3333
fail-fast: false
3434
matrix:
35-
python-version: [ "3.10" ]
35+
python-version: [ "3.12" ]
3636

3737
steps:
3838
- uses: actions/checkout@v4
@@ -52,11 +52,11 @@ jobs:
5252
- name: Install dependencies
5353
run: |
5454
python -m pip install --upgrade pip
55-
python -m pip install pytest>=7.1.1
55+
python -m pip install pytest>=8.3.4
5656
python -m pip install pytest_benchmark
57-
python -m pip install netcdf4==1.6.2
57+
python -m pip install netcdf4==1.7.2
5858
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
59-
python -m pip install pandas==2.2
59+
python -m pip install pandas==2.2.3
6060
6161

6262
# Checking the branch name, not necessary but useful when setting things up.

.github/workflows/sonarqube.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ jobs:
6161
# Disable shallow clones for better analysis
6262
fetch-depth: 0
6363

64-
- name: Set up Python 3.10
64+
- name: Set up Python 3.12
6565
uses: actions/setup-python@v5
6666
with:
67-
python-version: "3.10"
67+
python-version: "3.12"
6868

6969
- name: Retrieve METcalcpy repository develop branch
7070
run: |
@@ -77,8 +77,8 @@ jobs:
7777
- name: Install dependencies
7878
run: |
7979
python -m pip install --upgrade pip
80-
python -m pip install pytest>=7.1.1
81-
python -m pip install netcdf4==1.6.2
80+
python -m pip install pytest>=8.3.4
81+
python -m pip install netcdf4==1.7.2
8282
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
8383
python -m pip install pytest-cov
8484

.github/workflows/unit_tests.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
strategy:
4242
fail-fast: false
4343
matrix:
44-
python-version: [ "3.10" ]
44+
python-version: [ "3.12" ]
4545

4646
steps:
4747
- uses: actions/checkout@v4
@@ -50,7 +50,7 @@ jobs:
5050
with:
5151
python-version: ${{ matrix.python-version }}
5252

53-
- name: Retrieve METcalcpy repository develop branch
53+
- name: Retrieve METcalcpy repository active feature branch
5454
run: |
5555
python -m pip install --upgrade pip
5656
metcalcpy_dir="${RUNNER_WORKSPACE}/METcalcpy"
@@ -62,8 +62,8 @@ jobs:
6262
- name: Install dependencies
6363
run: |
6464
python -m pip install --upgrade pip
65-
python -m pip install pytest>=7.1.1
66-
python -m pip install netcdf4==1.6.2
65+
# python -m pip install pytest>=7.1.1
66+
# python -m pip install netcdf4==1.6.2
6767
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
6868
python -m pip install pytest-cov
6969

.readthedocs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ formats: []
1212
build:
1313
os: ubuntu-22.04
1414
tools:
15-
python: "3.10"
15+
python: "3.12"
1616

1717
# Optionally set the version of Python and requirements required to build your
1818
# docs

METdbLoad/test/test_met_db_load.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ def test_empty_files(tmp_path):
455455
def test_print_version():
456456
mock_logger = MagicMock()
457457
print_version(mock_logger)
458-
assert mock_logger.info.called_once
458+
assert mock_logger.info.called
459459
assert mock_logger.info.call_args[0][0].startswith("METdbload Version:")
460460

461461
with pytest.raises(SystemExit):

METdbLoad/test/test_tables.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,11 @@ def test_something():
267267
# *** Count mode table rows
268268
q_line2 = "SELECT table_name, table_rows FROM information_schema.tables " + \
269269
"WHERE table_schema = '" + DB2 + "' AND " + \
270-
"table_name LIKE 'mode\_%';"
270+
"table_name LIKE 'mode\\_%';"
271271

272272
q_line3 = "SELECT table_name, table_rows FROM information_schema.tables " + \
273273
"WHERE table_schema = '" + DB3 + "' AND " + \
274-
"table_name LIKE 'mode\_%';"
274+
"table_name LIKE 'mode\\_%';"
275275

276276
same = count_rows(q_line2, q_line3)
277277

@@ -429,11 +429,11 @@ def test_something():
429429
# *** Count mtd table rows
430430
q_line2 = "SELECT table_name, table_rows FROM information_schema.tables " + \
431431
"WHERE table_schema = '" + DB2 + "' AND " + \
432-
"table_name LIKE 'mtd\_%';"
432+
"table_name LIKE 'mtd\\_%';"
433433

434434
q_line3 = "SELECT table_name, table_rows FROM information_schema.tables " + \
435435
"WHERE table_schema = '" + DB3 + "' AND " + \
436-
"table_name LIKE 'mtd\_%';"
436+
"table_name LIKE 'mtd\\_%';"
437437

438438
same = count_rows(q_line2, q_line3)
439439

METdbLoad/ush/read_data_files.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -549,17 +549,20 @@ def read_data(self, load_flags, load_files, line_types):
549549
mtd_file[CN.FCST_LEAD_HR], unit='sec')
550550

551551
# Where fcst_lead was set to zero for math, set it to -9999
552+
552553
if mtd_file[CN.FCST_LEAD].eq(0).any():
554+
mtd_file[CN.FCST_LEAD] = mtd_file[CN.FCST_LEAD].astype(
555+
str)
553556
mtd_file.loc[mtd_file.fcst_lead ==
554-
0, CN.FCST_LEAD] = CN.MV_NOTAV
557+
0, CN.FCST_LEAD] = str(CN.MV_NOTAV)
555558

556559
# if OBS_LEAD is NA, set it to -9999
557560
if not mtd_file.obs_lead.dtypes == 'int':
561+
mtd_file[CN.OBS_LEAD] = mtd_file[CN.FCST_LEAD].astype(
562+
str)
558563
mtd_file.loc[mtd_file.obs_lead ==
559-
CN.NOTAV, CN.OBS_LEAD] = CN.MV_NOTAV
560-
mtd_file[CN.OBS_LEAD] = mtd_file[CN.OBS_LEAD].astype(
561-
int)
562-
564+
CN.NOTAV, CN.OBS_LEAD] = str(CN.MV_NOTAV)
565+
563566
# initially, match line data to the index of the file names
564567
mtd_file[CN.FILE_ROW] = row_num
565568

@@ -1534,16 +1537,16 @@ def read_stat(self, filename, hdr_names):
15341537
# convert MET dates to correct date format
15351538
stat_file[CN.FCST_VALID_BEG] = \
15361539
pd.to_datetime(stat_file[CN.FCST_VALID_BEG],
1537-
format='%Y%m%d_%H%M%S', errors='ignore')
1540+
format='%Y%m%d_%H%M%S', errors='raise')
15381541
stat_file[CN.FCST_VALID_END] = \
15391542
pd.to_datetime(stat_file[CN.FCST_VALID_END],
1540-
format='%Y%m%d_%H%M%S', errors='ignore')
1543+
format='%Y%m%d_%H%M%S', errors='raise')
15411544
stat_file[CN.OBS_VALID_BEG] = \
15421545
pd.to_datetime(stat_file[CN.OBS_VALID_BEG],
1543-
format='%Y%m%d_%H%M%S', errors='ignore')
1546+
format='%Y%m%d_%H%M%S', errors='raise')
15441547
stat_file[CN.OBS_VALID_END] = \
15451548
pd.to_datetime(stat_file[CN.OBS_VALID_END],
1546-
format='%Y%m%d_%H%M%S', errors='ignore')
1549+
format='%Y%m%d_%H%M%S', errors='raise')
15471550
return stat_file
15481551

15491552
def read_tcst(self, filename, hdr_names):
@@ -1581,10 +1584,10 @@ def read_tcst(self, filename, hdr_names):
15811584
# convert MET dates to correct date format
15821585
stat_file[CN.INIT] = \
15831586
pd.to_datetime(stat_file[CN.INIT],
1584-
format='%Y%m%d_%H%M%S', errors='ignore')
1587+
format='%Y%m%d_%H%M%S', errors='raise')
15851588
stat_file[CN.VALID] = \
15861589
pd.to_datetime(stat_file[CN.VALID],
1587-
format='%Y%m%d_%H%M%S', errors='ignore')
1590+
format='%Y%m%d_%H%M%S', errors='raise')
15881591

15891592
return stat_file
15901593

@@ -1621,13 +1624,14 @@ def read_mode(self, filename, hdr_names):
16211624
stat_file.columns = hdr_names
16221625

16231626
# convert MET dates to correct date format
1627+
16241628
stat_file[CN.FCST_VALID] = \
16251629
pd.to_datetime(stat_file[CN.FCST_VALID],
1626-
format='%Y%m%d_%H%M%S', errors='ignore')
1630+
format='%Y%m%d_%H%M%S', errors='raise')
16271631
stat_file.loc[stat_file.obs_valid ==
16281632
CN.NOTAV, CN.OBS_VALID] = CN.MV_NULL
16291633
stat_file[CN.OBS_VALID] = \
16301634
pd.to_datetime(stat_file[CN.OBS_VALID],
1631-
format='%Y%m%d_%H%M%S', errors='ignore')
1635+
format='%Y%m%d_%H%M%S', errors='raise')
16321636

16331637
return stat_file

METdbLoad/ush/write_mtd_sql.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,17 @@ def write_mtd_data(load_flags, m_2d_data, m_3d_single_data, m_3d_pair_data,
170170
m_2d_data.obs_valid = pd.to_datetime(m_2d_data.obs_valid,
171171
errors='coerce')
172172
# put the header ids back into the dataframe
173-
m_2d_data = pd.merge(
174-
left=mtd_headers, right=m_2d_data, on=CN.MTD_2D_HEADER_KEYS)
175-
m_2d_data.loc[m_2d_data.obs_valid.isnull(),
176-
CN.OBS_VALID] = CN.MV_NULL
173+
174+
# to address changes in pandas 2.2, explicitly convert the dtypes
175+
# for the obs_lead and fcst_lead columns in the dataframes that are being merged
176+
headers_to_convert = [CN.OBS_LEAD, CN.FCST_LEAD]
177+
for cur_header in headers_to_convert:
178+
mtd_headers[cur_header] = mtd_headers[cur_header].astype(str)
179+
m_2d_data[cur_header] = m_2d_data[cur_header].astype(str)
180+
181+
m_2d_data = pd.merge(left=mtd_headers, right=m_2d_data, on=CN.MTD_2D_HEADER_KEYS)
182+
obs_valid = m_2d_data.obs_valid.astype(str)
183+
m_2d_data.loc[obs_valid.isnull(), CN.OBS_VALID] = CN.MV_NULL
177184

178185
# create defaults for flags
179186
m_2d_data[CN.SIMPLE_FLAG] = 1
@@ -212,6 +219,14 @@ def write_mtd_data(load_flags, m_2d_data, m_3d_single_data, m_3d_pair_data,
212219
errors='coerce')
213220

214221
# put the header ids back into the dataframe
222+
223+
# to address changes in pandas 2.2, explicitly convert the dtypes
224+
# for the obs_lead and fcst_lead columns in the dataframes that are being merged
225+
headers_to_convert = [CN.OBS_LEAD, CN.FCST_LEAD]
226+
for cur_header in headers_to_convert:
227+
mtd_headers[cur_header] = mtd_headers[cur_header].astype(str)
228+
m_3d_single_data[cur_header] = m_3d_single_data[cur_header].astype(str)
229+
215230
m_3d_single_data = pd.merge(left=mtd_headers, right=m_3d_single_data,
216231
on=CN.MTD_HEADER_KEYS)
217232
m_3d_single_data.loc[m_3d_single_data.obs_valid.isnull(
@@ -254,6 +269,13 @@ def write_mtd_data(load_flags, m_2d_data, m_3d_single_data, m_3d_pair_data,
254269
errors='coerce')
255270

256271
# put the header ids back into the dataframe
272+
# to address changes in pandas 2.2, explicitly convert the dtypes
273+
# for the obs_lead and fcst_lead columns in the dataframes that are being merged
274+
headers_to_convert = [CN.OBS_LEAD, CN.FCST_LEAD]
275+
for cur_header in headers_to_convert:
276+
mtd_headers[cur_header] = mtd_headers[cur_header].astype(str)
277+
m_3d_pair_data[cur_header] = m_3d_pair_data[cur_header].astype(str)
278+
257279
m_3d_pair_data = pd.merge(left=mtd_headers, right=m_3d_pair_data,
258280
on=CN.MTD_HEADER_KEYS)
259281
m_3d_pair_data.loc[m_3d_pair_data.obs_valid.isnull(

METdbLoad/ush/write_stat_sql.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ def write_stat_data(load_flags, stat_data, tmp_dir, sql_cur, local_infile, logge
143143
str(len(line_data.index)))
144144

145145
# change all Not Available values to METviewer not available (-9999)
146+
pd.set_option('future.no_silent_downcasting', True)
146147
line_data = line_data.replace(CN.NOTAV, CN.MV_NOTAV)
147148

148149
# Only variable length lines have a line_data_id

docs/Users_Guide/installation.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ typing the command in the CLI and/or make the corresponding edit to
3232
Python Requirements
3333
-------------------
3434

35-
**Python 3.10.4+** - Python 3.10.4 or higher must be installed.
35+
**Python 3.12+** - Python 3.12 or higher must be installed.
36+
37+
**NOTE** Due to the lack of backwards compatibility in pandas 2.x, this code no longer works with Python 3.10
3638

3739
The requirements below come directly from the **requirements.txt** file
3840
at the top level of the repository.
3941

4042
.. literalinclude:: ../../requirements.txt
4143

44+
4245
Installation
4346
============
4447

nco_requirements.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
lxml>=4.9.1
2-
pandas>=1.5.2
3-
pyyaml>=6.0
4-
pytest>=7.2.1
5-
numpy>=1.24.2
1+
lxml>=5.3.0
2+
pandas>=2.2.3
3+
pyyaml>=6.0.2
4+
pytest>=8.3.4
5+
numpy>=2.2.2

py310_requirements.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
lxml==4.9.1
2+
numpy==1.24.2
3+
pandas==1.5.2
4+
pip==23.3
5+
PyMySQL==1.1.1
6+
pytest==7.2.1
7+
python-dateutil==2.8.2
8+
PyYAML==6.0
9+
xarray>=2023.1.0
10+
11+
12+

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
88
[project]
99
name = "metdataio"
1010
#dynamic = ["dependencies"]
11-
version = "3.0.0-rc1-dev"
11+
version = "3.1.0-beta2-dev"
1212
description = "METplus component that loads data into a database"
1313
authors = [
1414
{name = "METplus"},
@@ -53,4 +53,4 @@ source = [
5353
]
5454
omit = [
5555
"METreformat/test/*"
56-
]
56+
]

requirements.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
lxml==4.9.1
2-
numpy==1.24.2
3-
pandas==1.5.2
4-
pip==23.3
1+
lxml==5.3.0
2+
numpy==2.2.2
3+
pandas==2.2.3
4+
pip==25.0
55
PyMySQL==1.1.1
6-
pytest==7.2.1
7-
python-dateutil==2.8.2
8-
PyYAML==6.0
9-
xarray>=2023.1.0
6+
pytest==8.3.4
7+
python-dateutil==2.9.0.post0
8+
PyYAML==6.0.2
9+
xarray>=2025.1.2
1010

1111

1212

0 commit comments

Comments
 (0)