Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python upgrade to use memory views #9

Merged
merged 8 commits into from
Dec 14, 2024
Merged

python upgrade to use memory views #9

merged 8 commits into from
Dec 14, 2024

Conversation

cleemesser
Copy link
Owner

@cleemesser cleemesser commented Dec 14, 2024

This switches to using more modern memory views interface to numpy in Cython. upgrades to use Cython 3.0+ fixed setup.py to work with pyproject.toml by removing conflicting info

Summary by Sourcery

Upgrade the project to use memory views with numpy in Cython, enhancing performance and compatibility. Update the build configuration by removing conflicting setup.py information to align with pyproject.toml. Upgrade to Cython 3.0+ to leverage new features and improvements.

New Features:

  • Introduce memory views interface to numpy in Cython for improved performance.

Enhancements:

  • Upgrade to Cython 3.0+ for compatibility and performance improvements.

Build:

  • Remove conflicting information from setup.py to ensure compatibility with pyproject.toml.

Copy link
Contributor

sourcery-ai bot commented Dec 14, 2024

Reviewer's Guide by Sourcery

This pull request modernizes the codebase by upgrading to use memory views in Cython and making setup.py compatible with pyproject.toml. The changes include code formatting improvements, memory view syntax updates in Cython code, and build system modernization.

Class diagram for updated Cython memory view usage

classDiagram
    class CyEdfReader {
        - size_t nsamples_per_record
        + size_t nsamples_per_record
        + read_digital_signal(int signalnum, int start, int n, np.int32_t[:] sigbuf)
        + read_phys_signal(int signalnum, int start, int n, np.float64_t[:] sigbuf)
        + load_phys_datarecord(np.float64_t[:] db, int n=0)
    }

    class EdfWriter {
        + blockWriteDigitalSamples(np.int32_t[:] data)
        + blockWriteDigitalShortSamples(np.int16_t[:] data)
    }

    class EdfReader {
        + __init__(str file_name, str annotations_mode="all")
    }

    class Edfinfo {
        + __init__(str file_name, str text_encoding=DEFAULT_TEXT_ENCODING)
    }
Loading

File-Level Changes

Change Details Files
Updated Cython code to use modern memory view syntax
  • Replaced numpy array syntax with memory view syntax (e.g., np.ndarray[np.float64_t, ndim=1] to np.float64_t[:])
  • Updated array pointer access to use memory view indexing (e.g., &buf[0] instead of <type*>buf.data)
  • Added memory view type declarations for function parameters
edflib/_edflib.pyx
Modernized build system configuration
  • Added pyproject.toml with modern build system requirements
  • Removed redundant setup requirements from setup.py
  • Added project metadata to pyproject.toml
  • Added NPY_NO_DEPRECATED_API macro to prevent numpy API warnings
setup.py
pyproject.toml
Applied code formatting improvements across the codebase
  • Standardized string quotes to use double quotes
  • Fixed line spacing and indentation
  • Removed trailing whitespace
  • Reformatted long lines to improve readability
tests/test_edfreader.py
tests/test_edfwriter.py
examples/readekg.py
examples/readekg2.py
examples/readekg3.py
examples/filterplots.py
examples/stacklineplot.py
edflib/edfreader.py
edflib/edfwriter.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @cleemesser - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider keeping the version constraints from setup.py in pyproject.toml to ensure compatibility - particularly the numpy<2 constraint which was removed
Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

README.rst Outdated Show resolved Hide resolved

It still more needs tests, more refractoring to make a
real pythonic api before heading to towards a polished package.
real pythonic api before heading to towards a polished package.
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (typo): Remove duplicate word 'to'

The phrase 'to towards' contains a duplicate word - it should be either 'heading to' or 'heading towards'

Suggested change
real pythonic api before heading to towards a polished package.
real pythonic api before heading towards a polished package.

To upload to pypi::
python -m build

twine upload -r legacypypi dist/* <- fix this>
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Clean up the command line instruction

The '<- fix this>' comment should either be removed or replaced with a proper explanation of what needs to be fixed

Suggested change
twine upload -r legacypypi dist/* <- fix this>
twine upload -r legacypypi dist/*

from pylab import * # get rid of this in future


def mfreqz(b, a=1):
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider separating the frequency response calculations and plotting into separate functions.

The functions mix signal processing calculations with visualization code. This coupling makes the code less reusable and harder to test. Consider splitting into separate calculation and plotting functions:

def calc_freq_response(b, a=1):
    w, h = signal.freqz(b, a)
    h_dB = 20 * log10(abs(h))
    h_Phase = unwrap(arctan2(imag(h), real(h)))
    return w, h_dB, h_Phase

def plot_freq_response(w, h_dB, h_Phase):
    subplot(211)
    plot(w/max(w), h_dB)
    ylim(-150, 5)
    ylabel('Magnitude (db)')
    xlabel(r'Normalized Frequency (x$\pi$rad/sample)')
    title(r'Frequency response')
    subplot(212)
    plot(w/max(w), h_Phase)
    ylabel('Phase (radians)')
    xlabel(r'Normalized Frequency (x$\pi$rad/sample)')
    title(r'Phase response')
    subplots_adjust(hspace=0.5)
    show()

# Convenience wrapper maintaining original functionality
def mfreqz(b, a=1):
    w, h_dB, h_Phase = calc_freq_response(b, a)
    plot_freq_response(w, h_dB, h_Phase)

This approach:

  • Separates concerns between calculation and visualization
  • Enables reuse of calculations without plotting
  • Makes the code more testable
  • Maintains the original convenient interface

if len(kwargs) > 0:
raise Exception('Unhandled argument(s) given: %r' % list(kwargs.keys()))
raise Exception("Unhandled argument(s) given: %r" % list(kwargs.keys()))
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Raise a specific error instead of the general Exception or BaseException (raise-specific-error)

ExplanationIf a piece of code raises a specific exception type rather than the generic [`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException) or [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception), the calling code can:
  • get more information about what type of error it is
  • define specific exception handling for it

This way, callers of the code can handle the error appropriately.

How can you solve this?

So instead of having code raising Exception or BaseException like

if incorrect_input(value):
    raise Exception("The input is incorrect")

you can have code raising a specific error like

if incorrect_input(value):
    raise ValueError("The input is incorrect")

or

class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")

Comment on lines +17 to +25
ylabel("Magnitude (db)")
xlabel(r"Normalized Frequency (x$\pi$rad/sample)")
title(r"Frequency response")
subplot(212)
h_Phase = unwrap(arctan2(imag(h), real(h)))
plot(w / max(w), h_Phase)
ylabel("Phase (radians)")
xlabel(r"Normalized Frequency (x$\pi$rad/sample)")
title(r"Phase response")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Extract duplicate code into function (extract-duplicate-method)

Comment on lines +36 to +45
stem(x, response)
ylabel("Amplitude")
xlabel(r"n (samples)")
title(r"Impulse response")
subplot(212)
step = cumsum(response)
stem(x, step)
ylabel("Amplitude")
xlabel(r"n (samples)")
title(r"Step response")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Extract duplicate code into function (extract-duplicate-method)

cekgtr = cekg[:len(ekgtr)]
fekgtr = ekgtr[0:len(cekgtr)]-cekgtr[:]
cekgtr = cekg[: len(ekgtr)]
fekgtr = ekgtr[0 : len(cekgtr)] - cekgtr[:]
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Replace a[0:x] with a[:x] and a[x:len(a)] with a[x:] (remove-redundant-slice-index)

Suggested change
fekgtr = ekgtr[0 : len(cekgtr)] - cekgtr[:]
fekgtr = ekgtr[:len(cekgtr)] - cekgtr[:]


# findx2 = [ (ii, signal_labels[ii]) for ii in range(len(signal_labels))]
# findx2 = [ (ii, signal_labels[ii]) for ii in range(len(signal_labels))]
# X2 is signal 27
# A2 is signal 23

ekg = sigbufs[27][0:l] - sigbufs[23][0:l]
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Replace a[0:x] with a[:x] and a[x:len(a)] with a[x:] [×3] (remove-redundant-slice-index)

Comment on lines 55 to +58
if False:
# try pickout signal 5
_edflib.rewind(ef.handle, 5)
_edflib.read_int_samples(ef.handle, 5, Nibuf,ibuf)
_edflib.read_int_samples(ef.handle, 5, Nibuf, ibuf)
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Remove redundant conditional (remove-redundant-if)

Suggested change
if False:
# try pickout signal 5
_edflib.rewind(ef.handle, 5)
_edflib.read_int_samples(ef.handle, 5, Nibuf,ibuf)
_edflib.read_int_samples(ef.handle, 5, Nibuf, ibuf)

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@cleemesser cleemesser self-assigned this Dec 14, 2024
@cleemesser cleemesser merged commit 26f30fd into master Dec 14, 2024
@cleemesser cleemesser deleted the memviews branch December 14, 2024 06:46
This was referenced Dec 14, 2024
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.

1 participant