Skip to content

Commit 9a8f41a

Browse files
committed
Merge remote-tracking branch 'upstream/main' into fix/waveletpacketnd-reconstruct-indexing
2 parents 9c4980e + 8a1539a commit 9a8f41a

8 files changed

Lines changed: 74 additions & 45 deletions

File tree

‎.github/workflows/emscripten.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ jobs:
3434
if: github.repository == 'PyWavelets/pywt'
3535
steps:
3636
- name: Check out repository
37-
uses: actions/checkout@v6.0.2
37+
uses: actions/checkout@v7.0.1
3838

3939
- name: Build and test PyWavelets
40-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
40+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
4141
env:
4242
CIBW_PLATFORM: pyodide
4343
CIBW_TEST_REQUIRES: pytest matplotlib

‎.github/workflows/lint.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ jobs:
2121
python-version: ["3.13"]
2222

2323
steps:
24-
- uses: actions/checkout@v6.0.2
24+
- uses: actions/checkout@v7.0.1
2525

2626
- name: Set up Python ${{ matrix.python-version }}
27-
uses: actions/setup-python@v6
27+
uses: actions/setup-python@v7
2828
with:
2929
python-version: ${{ matrix.python-version }}
3030

‎.github/workflows/tests.yml‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ jobs:
6262
python-version: "3.14"
6363
OPTIONS_NAME: "editable-install"
6464
steps:
65-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
66-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
65+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
66+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
6767
with:
6868
python-version: ${{ matrix.python-version}}
6969
allow-prereleases: true
@@ -142,10 +142,10 @@ jobs:
142142
strategy:
143143
fail-fast: false
144144
matrix:
145-
python-version: ["3.13t", "3.14t"]
145+
python-version: ["3.14t"]
146146
steps:
147-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
148-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
147+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
148+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
149149
with:
150150
python-version: ${{ matrix.python-version}}
151151

@@ -183,8 +183,8 @@ jobs:
183183
OPTIONS_NAME: "pre-releases"
184184

185185
steps:
186-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
187-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
186+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
187+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
188188
with:
189189
python-version: ${{ matrix.python-version}}
190190
allow-prereleases: true
@@ -248,7 +248,7 @@ jobs:
248248
name: Test under ASan and UBSan
249249
runs-on: macos-latest
250250
steps:
251-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.2.2
251+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2
252252
with:
253253
submodules: recursive
254254
fetch-tags: true

‎.github/workflows/wheel_tests_and_release.yml‎

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,24 @@ jobs:
3434
fail-fast: false
3535
matrix:
3636
os: [ubuntu-latest]
37-
cibw_python: ["cp312", "cp313", "cp313t", "cp314", "cp314t"]
37+
cibw_python: ["cp312", "cp313", "cp314", "cp314t"]
3838
cibw_arch: ["x86_64"]
3939
steps:
40-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
40+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
4141
with:
4242
fetch-depth: 0
43-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
43+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
4444
name: Install Python
4545
with:
4646
python-version: "3.12"
4747

4848
- name: Build the wheel
49-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
49+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
5050
with:
5151
output-dir: dist
5252
env:
5353
CIBW_BUILD: ${{ matrix.cibw_python }}-*
5454
CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }}
55-
CIBW_ENABLE: cpython-freethreading
5655
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
5756
with:
5857
name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }}
@@ -66,25 +65,24 @@ jobs:
6665
fail-fast: false
6766
matrix:
6867
os: [ubuntu-22.04-arm]
69-
cibw_python: ["cp312", "cp313", "cp313t", "cp314", "cp314t"]
68+
cibw_python: ["cp312", "cp313", "cp314", "cp314t"]
7069
cibw_arch: ["aarch64"]
7170
steps:
72-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
71+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
7372
with:
7473
fetch-depth: 0
75-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
74+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
7675
name: Install Python
7776
with:
7877
python-version: "3.12"
7978

8079
- name: Build the wheel
81-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
80+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
8281
with:
8382
output-dir: dist
8483
env:
8584
CIBW_BUILD: ${{ matrix.cibw_python }}-*
8685
CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }}
87-
CIBW_ENABLE: cpython-freethreading
8886
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
8987
with:
9088
name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }}
@@ -97,42 +95,40 @@ jobs:
9795
fail-fast: false
9896
matrix:
9997
os: [macos-15-intel, macos-14]
100-
cibw_python: ["cp312", "cp313", "cp313t", "cp314", "cp314t"]
98+
cibw_python: ["cp312", "cp313", "cp314", "cp314t"]
10199
cibw_arch: ["x86_64", "arm64"]
102100
exclude:
103101
- os: macos-14
104102
cibw_arch: "x86_64"
105103
- os: macos-15-intel
106104
cibw_arch: "arm64"
107105
steps:
108-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
106+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
109107
with:
110108
fetch-depth: 0
111109

112-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
110+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
113111
name: Install Python
114112
with:
115113
python-version: "3.12"
116114

117115
- name: Build wheels for CPython (macOS) (x86_64)
118116
if: matrix.cibw_arch == 'x86_64'
119-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
117+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
120118
with:
121119
output-dir: dist
122120
env:
123121
CIBW_BUILD: ${{ matrix.cibw_python }}-*
124122
CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }}
125-
CIBW_ENABLE: cpython-freethreading
126123

127124
- name: Build wheels for CPython (macOS) (arm64)
128125
if: matrix.cibw_arch == 'arm64'
129-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
126+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
130127
with:
131128
output-dir: dist
132129
env:
133130
CIBW_BUILD: ${{ matrix.cibw_python }}-*
134131
CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }}
135-
CIBW_ENABLE: cpython-freethreading
136132

137133
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
138134
with:
@@ -148,7 +144,7 @@ jobs:
148144
matrix:
149145
os: [windows-latest, windows-11-arm]
150146
cibw_arch: ["AMD64", "x86", "ARM64"]
151-
cibw_python: ["cp312", "cp313", "cp313t", "cp314", "cp314t"]
147+
cibw_python: ["cp312", "cp313", "cp314", "cp314t"]
152148
exclude:
153149
- os: windows-latest
154150
cibw_arch: ARM64
@@ -157,11 +153,11 @@ jobs:
157153
- os: windows-11-arm
158154
cibw_arch: AMD64
159155
steps:
160-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
156+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
161157
with:
162158
fetch-depth: 0
163159

164-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
160+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
165161
name: Install Python
166162
with:
167163
python-version: "3.12"
@@ -185,13 +181,12 @@ jobs:
185181
architecture: arm64
186182

187183
- name: Build Windows wheels for CPython
188-
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
184+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
189185
with:
190186
output-dir: dist
191187
env:
192188
CIBW_BUILD: ${{ matrix.cibw_python }}-*
193189
CIBW_ARCHS_WINDOWS: ${{ matrix.cibw_arch }}
194-
CIBW_ENABLE: cpython-freethreading
195190

196191
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
197192
with:
@@ -212,11 +207,11 @@ jobs:
212207
if: github.repository == 'PyWavelets/pywt' && startsWith(github.ref, 'refs/tags/v')
213208
runs-on: ubuntu-latest
214209
steps:
215-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
210+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
216211
with:
217212
fetch-depth: 0
218213

219-
- uses: actions/setup-python@2e3e4b15a884dc73a63f962bff250a855150a234 # v5.5.0
214+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
220215
name: Install Python
221216
with:
222217
python-version: "3.12"
@@ -248,7 +243,7 @@ jobs:
248243
TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }}
249244

250245
- name: Github release
251-
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
246+
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
252247
env:
253248
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
254249
GITHUB_REPOSITORY: ${{ github.repository }}
@@ -270,7 +265,7 @@ jobs:
270265
(github.event_name == 'schedule')
271266
runs-on: ubuntu-latest
272267
steps:
273-
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.2
268+
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.1.2
274269
with:
275270
fetch-depth: 0
276271

‎pywt/_dwt.py‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ def pad(x, pad_widths, mode):
442442
pad_widths = np.array(pad_widths)
443443
pad_widths = np.round(pad_widths).astype(np.intp, copy=False)
444444
if pad_widths.min() < 0:
445-
raise ValueError("pad_widths must be > 0")
445+
raise ValueError("pad_widths must be >= 0")
446446
pad_widths = np.broadcast_to(pad_widths, (x.ndim, 2)).tolist()
447447

448448
if mode in ['symmetric', 'reflect']:
@@ -468,9 +468,12 @@ def pad_smooth(vector, pad_width, iaxis, kwargs):
468468
left + np.arange(pad_width[0], 0, -1) * slope_left
469469

470470
# smooth extension to right
471-
right = vector[-pad_width[1] - 1]
472-
slope_right = (right - vector[-pad_width[1] - 2])
473-
vector[-pad_width[1]:] = \
471+
# Note: indices are measured from the start of the vector so that
472+
# a pad width of 0 gives an empty slice rather than the full one.
473+
iright = vector.size - pad_width[1] - 1
474+
right = vector[iright]
475+
slope_right = (right - vector[iright - 1])
476+
vector[iright + 1:] = \
474477
right + np.arange(1, pad_width[1] + 1) * slope_right
475478
return vector
476479
xp = np.pad(x, pad_widths, pad_smooth)
@@ -481,7 +484,7 @@ def pad_antisymmetric(vector, pad_width, iaxis, kwargs):
481484
npad_l, npad_r = pad_width
482485
vsize_nonpad = vector.size - npad_l - npad_r
483486
# Note: must modify vector in-place
484-
vector[:] = np.pad(vector[pad_width[0]:-pad_width[-1]],
487+
vector[:] = np.pad(vector[npad_l:vector.size - npad_r],
485488
pad_width, mode='symmetric')
486489
vp = vector
487490
r_edge = npad_l + vsize_nonpad - 1

‎pywt/_swt.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def swt(data, wavelet, level=None, start_level=0, axis=-1,
100100
2. variance is partitioned across scales
101101
102102
When used with ``norm=True``, this transform is closely related to the
103-
multiple-overlap DWT (MODWT) as popularized for time-series analysis,
103+
maximal-overlap DWT (MODWT) as popularized for time-series analysis,
104104
although the underlying implementation is slightly different from the one
105105
published in [1]_. Specifically, the implementation used here requires a
106106
signal that is a multiple of ``2**level`` in length.

‎pywt/tests/test_cwt_wavelets.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ def test_cwt_complex(dtype, tol, method):
396396
assert_equal(cfs_complex.dtype, sst_complex.dtype)
397397

398398

399-
@pytest.mark.parametrize('axis, method', product([0, 1], ['conv', 'fft']))
399+
@pytest.mark.parametrize('axis, method', list(product([0, 1], ['conv', 'fft'])))
400400
def test_cwt_batch(axis, method):
401401
dtype = np.float64
402402
time, sst = pywt.data.nino()

‎pywt/tests/test_dwt_idwt.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,37 @@ def test_pad_1d():
279279
pywt.pad(x, (4, 4), 'periodic'))
280280

281281

282+
def test_pad_zero_width():
283+
# zero pad width is a no-op for all modes except 'periodization', which
284+
# also promotes odd-length axes to even length (gh-589)
285+
for ndim in [1, 2, 3]:
286+
x = np.arange(3.0**ndim).reshape((3, ) * ndim)
287+
for mode in pywt.Modes.modes:
288+
if mode == 'periodization':
289+
continue
290+
assert_array_equal(pywt.pad(x, 0, mode), x,
291+
err_msg=f"mode={mode}, ndim={ndim}")
292+
293+
294+
def test_pad_one_sided():
295+
# a zero pad width on only one side of the axis (gh-589)
296+
x = [1, 2, 3]
297+
assert_array_equal(pywt.pad(x, (2, 0), 'smooth'), [-1, 0, 1, 2, 3])
298+
assert_array_equal(pywt.pad(x, (0, 2), 'smooth'), [1, 2, 3, 4, 5])
299+
assert_array_equal(pywt.pad(x, (2, 0), 'antisymmetric'), [-2, -1, 1, 2, 3])
300+
assert_array_equal(pywt.pad(x, (0, 2), 'antisymmetric'), [1, 2, 3, -3, -2])
301+
302+
# one-sided padding matches the corresponding slice of two-sided padding
303+
for mode in pywt.Modes.modes:
304+
if mode == 'periodization':
305+
continue
306+
two_sided = pywt.pad(x, (4, 6), mode)
307+
assert_array_equal(pywt.pad(x, (4, 0), mode), two_sided[:-6],
308+
err_msg=f"mode={mode}")
309+
assert_array_equal(pywt.pad(x, (0, 6), mode), two_sided[4:],
310+
err_msg=f"mode={mode}")
311+
312+
282313
def test_pad_errors():
283314
# negative pad width
284315
x = [1, 2, 3]

0 commit comments

Comments
 (0)