Skip to content

Prepare ThinkDSP for PyPI packaging#134

Open
hoppa1231 wants to merge 6 commits intoAllenDowney:masterfrom
hoppa1231:master
Open

Prepare ThinkDSP for PyPI packaging#134
hoppa1231 wants to merge 6 commits intoAllenDowney:masterfrom
hoppa1231:master

Conversation

@hoppa1231
Copy link

No description provided.

- Implement tests for spectrum generation with both even and odd lengths.
- Add tests for ComplexSinusoid, Chirp, ExpoChirp, and wave addition.
- Include tests for DCT and impulse signal generation.
- Ensure numerical accuracy with assertions for expected results.
@hoppa1231
Copy link
Author

Summary

  • Prepare ThinkDSP for PyPI packaging with a src/ layout.
  • Update metadata, dependencies, and classifiers to be PyPI‑valid.
  • Add packaging files and a GitHub Actions publish workflow.

Motivation

I wanted to make ThinkDSP installable as a standard Python package from PyPI.
While doing this, I also fixed invalid Trove classifiers and aligned metadata
with current packaging tooling. This allows automated builds and publishing.

Changes

  • Added src/thinkdsp/__init__.py (copied from code/thinkdsp.py) for a
    conventional src/ package layout.
  • Added tests/test_thinkdsp.py (copied from code/thinkdsp_test.py).
  • Updated pyproject.toml:
    • project metadata (readme, license, packages, include, exclude)
    • valid PyPI classifiers
    • optional extras for notebooks
    • updated dependencies to allow NumPy 2.x
    • switched build backend to poetry-core
  • Added LICENSE (MIT).
  • Updated .gitignore to ignore common Python/venv/build/test artifacts.
  • Updated README.md with an attribution block.
  • Added .github/workflows/publish.yml for PyPI publishing via OIDC.

Testing

  • Not run (packaging/metadata changes only).

Notes / Potential Concerns

  • Package name on PyPI had to be unique (I used thinkdsp-kim for publishing),
    but the import name remains thinkdsp.
  • Dependencies now require Python >=3.9 to support NumPy 2.x.
  • If you prefer to avoid a src/ layout or PyPI publishing workflow, I can
    split this into smaller PRs or drop those parts.

@hoppa1231 hoppa1231 changed the title Fix deprecated numpy methods in WavFileWriter and read_wave functions Prepare ThinkDSP for PyPI packaging Feb 11, 2026
@AllenDowney
Copy link
Owner

This looks really good, thank you!

I have held off on making thinkdsp an installable package because (1) it's not necessary for readers, and (2) many readers have problems installing packages. So I don't want to encourage readers to go down this road.

But it is nice to give people the option, so I am inclined to merge this PR and put the package on PyPI. In that case we can use the name thinkdsp without the suffix, and drop the language about the distribution being unofficial (also still crediting you as maintainer).

What do you think?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request prepares the ThinkDSP codebase for PyPI packaging by restructuring the project into a proper Python package with a src/ layout, adding packaging configuration, tests, CI/CD workflows, and license files.

Changes:

  • Reorganized code into a src/thinkdsp/ package structure with proper Python packaging setup
  • Added pyproject.toml with Poetry configuration for PyPI publishing as "thinkdsp-kim"
  • Created GitHub Actions workflow for automated PyPI publishing and added comprehensive .gitignore
  • Updated code to use modern NumPy methods (tobytes/frombuffer) and improved IPython Audio import handling
  • Added MIT License file, attribution section in README, and pytest-based test suite

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
pyproject.toml Configures Poetry packaging with metadata, dependencies, and build system for PyPI distribution
src/thinkdsp/init.py Main package module with DSP utilities, updated with modern NumPy methods
tests/test_thinkdsp.py Unit tests for core DSP functionality (Wave, Spectrum, Signal classes)
code/thinkdsp.py Updated original code file with deprecation fixes (tobytes, frombuffer, Audio import)
README.md Added attribution section explaining this is a packaging fork maintained by hoppa1231
LICENSE Added MIT License file with copyright information for Allen B. Downey
.gitignore Expanded to include Python, Poetry, and packaging-related ignore patterns
.github/workflows/publish.yml GitHub Actions workflow for building and publishing to PyPI on version tags

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

pandas = "^1.1.4"
scipy = "^1.5.4"
python = ">=3.9,<4.0"
numpy = ">=1.22.4,<3.0"
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The numpy version constraint ">=1.22.4,<3.0" is reasonable, but NumPy 1.22.4 was released in 2022 and requires Python 3.8+. Since the minimum Python version is set to 3.9, consider aligning the numpy minimum version with what's typically available for Python 3.9 environments. NumPy 1.22 dropped support for deprecated functions that might be used in older code. Verify that all numpy usage in the codebase is compatible with numpy 1.22+, particularly the np.fromstring usage (deprecated in favor of np.frombuffer).

Suggested change
numpy = ">=1.22.4,<3.0"
numpy = ">=1.20,<3.0"

Copilot uses AI. Check for mistakes.
scipy = ">=1.13.0,<2.0"
matplotlib = ">=3.8.0,<4.0"
jupyter = { version = "^1.0.0", optional = true }
pandas = { version = "^1.1.4", optional = true }
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pandas version constraint uses "^1.1.4" which means ">=1.1.4,<2.0.0". However, pandas 1.1.4 was released in 2020 and is quite old. This package may not be compatible with pandas 2.x which was released in April 2023. Consider testing compatibility with pandas 2.x and updating the constraint to ">=1.1.4,<3.0" if compatible, or explicitly documenting the pandas 2.x incompatibility.

Suggested change
pandas = { version = "^1.1.4", optional = true }
pandas = { version = ">=1.1.4,<3.0", optional = true }

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +6
"""This file contains code for use with "Think Stats",
by Allen B. Downey, available from greenteapress.com

Copyright 2014 Allen B. Downey
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
"""
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file header incorrectly references "Think Stats" instead of "Think DSP" and mentions GNU GPLv3 license while the LICENSE file and pyproject.toml specify MIT License. This is inconsistent with the actual source code which uses MIT License and references "Think DSP".

Copilot uses AI. Check for mistakes.
scipy = "^1.5.4"
python = ">=3.9,<4.0"
numpy = ">=1.22.4,<3.0"
scipy = ">=1.13.0,<2.0"
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scipy version constraint ">=1.13.0,<2.0" is very restrictive and may cause compatibility issues. SciPy 1.13.0 was released in May 2024, which means users with older Python environments (even Python 3.9-3.11 that are supported) may not be able to install this package if they have older scipy versions. Consider using a more permissive constraint like ">=1.5.4,<2.0" to match the minimum Python 3.9 requirement, or document why scipy 1.13.0 is specifically required.

Suggested change
scipy = ">=1.13.0,<2.0"
scipy = ">=1.5.4,<2.0"

Copilot uses AI. Check for mistakes.
raise ValueError("sampwidth %d unknown" % sampwidth)

if sampwidth == 3:
xs = np.fromstring(z_str, dtype=np.int8).astype(np.int32)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code uses np.fromstring which was deprecated in NumPy 1.14 and removed in NumPy 1.24. Since the pyproject.toml specifies numpy>=1.22.4, this will break with NumPy 1.24+. The code should be updated to use np.frombuffer instead, similar to line 113.

Suggested change
xs = np.fromstring(z_str, dtype=np.int8).astype(np.int32)
xs = np.frombuffer(z_str, dtype=np.int8).astype(np.int32)

Copilot uses AI. Check for mistakes.
Comment on lines 11 to 17
## Attribution

This repository packages the `thinkdsp` code from *Think DSP* by Allen B. Downey.
Original code and copyright remain with the author under the MIT License.
This packaging fork is maintained by `hoppa1231` and is not affiliated with the
original author or publisher.

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README does not include installation instructions for the PyPI package (thinkdsp-kim). Consider adding a section explaining how to install the package using pip, such as "pip install thinkdsp-kim" or "pip install thinkdsp-kim[notebooks]" for the optional dependencies. This would help users understand how to use the packaged version.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +9
from __future__ import print_function, division

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file includes "from future import print_function, division" which is only needed for Python 2 compatibility. Since pyproject.toml specifies python = ">=3.9,<4.0", this import is unnecessary and should be removed as it's redundant in Python 3.9+.

Suggested change
from __future__ import print_function, division

Copilot uses AI. Check for mistakes.
return ys


class PinkNoise(Noise):
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class does not call Noise.init during initialization. (PinkNoise.init may be missing a call to a base class init)

Copilot uses AI. Check for mistakes.
print(cos_cov, sin_cov, mag((cos_cov, sin_cov)))
return

wfile = WavFileWriter()
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement is unreachable.

Copilot uses AI. Check for mistakes.

__radd__ = __add__

def __or__(self, other):
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method raises ValueError - should raise an ArithmeticError or return NotImplemented instead.

Copilot uses AI. Check for mistakes.
@hoppa1231
Copy link
Author

Thanks, AllenDowney — I agree with your reasoning.

I’m happy to proceed with an official PyPI release. Publishing as thinkdsp (no suffix) makes sense, and we can keep the book workflow unchanged while offering pip install as an optional convenience for those who want it.

If you’re good with that, I’ll update this PR to:

  • rename the distribution from thinkdsp-kimthinkdsp (and adjust the publish workflow accordingly),
  • update the README attribution to remove the “unofficial/not affiliated” wording while keeping clear credit + maintainer info,
  • keep install instructions minimal and explicitly optional (so we don’t push readers into packaging issues).

I’ll also address the Copilot review items in the same update:

  • clean up pyproject.toml (remove duplicate constraints; loosen pins for numpy/scipy/matplotlib to be less restrictive; keep notebook deps optional, and broaden pandas if compatible),
  • fix the test header to “Think DSP” + MIT and remove the Python 2 __future__ import,
  • add the missing base __init__ call for PinkNoise (or remove the override if not needed),
  • remove the unreachable debug snippet,
  • and adjust __or__ to return NotImplemented / raise TypeError instead of ValueError.

Let me know if you’d prefer dropping the PyPI publish workflow from this PR and handling publishing separately.

@AllenDowney
Copy link
Owner

@hoppa1231 I'm working on getting the thinkdsp name back pypi/support#9359

If that gets resolved, we can pick it up from there. So hold off for now, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments