From dac438f370534d82b536e51ba5bc2d725510cf66 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Thu, 17 Mar 2022 14:12:21 -0400 Subject: [PATCH 001/287] Add example annotation files for a multi-frequency record. The annotation files given here may be useful as examples and for testing. They were generated by the following commands (WFDB 10.6.2): gqrs -r 03700181 -o gqrsl (an annotation file with no explicit time resolution - meaning the resolution is assumed to be one tick per WFDB frame, i.e. 1/125 s.) gqrs -H -r 03700181 -o gqrsh (an annotation file with a time resolution of 1/500 s, which, in this case, matches the sampling interval of the signal in question.) sqrs -r 03700181 && mv 03700181.qrs 03700181.sqrs (an annotation file with a time resolution of 1/250 s, which doesn't match either the frame interval or the sampling interval.) --- sample-data/03700181.gqrsh | Bin 0 -> 4242 bytes sample-data/03700181.gqrsl | Bin 0 -> 4062 bytes sample-data/03700181.sqrs | Bin 0 -> 2434 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 sample-data/03700181.gqrsh create mode 100644 sample-data/03700181.gqrsl create mode 100644 sample-data/03700181.sqrs diff --git a/sample-data/03700181.gqrsh b/sample-data/03700181.gqrsh new file mode 100644 index 0000000000000000000000000000000000000000..6390b1930f17bc5fa4b8f4643164b744725b128c GIT binary patch literal 4242 zcmZ{mTW=dx6otp-Oae}PO`1qZfJFswky0T9;ur7}`Ufhg1Vp6ezwwB~MM1m}D)EHi zt))qYM)7!@gm78kS>73&hDNo|?8{nf?{m%`7x#9r?%bI?dhqG}$>IHn2cLZL=)u8f zA57le-!F>i|L9+*DDJ&>_0i{t4<~ycPWBEb`|rHBzkm1ryOX_x3FeOrMHa=|sYu54+T(Lx2$=5t;33;Jd&`ewO5)XE>Zpc~Cq+GBgGWhRCAi6$?U zv;KWW;YKyfy^J1{W1Pr|E}|tE>V(eFvaHe-E_;km##1rlw*>^0E%)aCJ*XiAR_|() z`9YZJ&--mOb6CF>uj+9>%sOD}63mB7ya1VgAI+G?!{yLCC9 zE>QW&VmF8<0~?-Y9QQXofzsq&kbxe1LG>Tc&#wEuiruPj6dlSzx|y|+C;DJk_=2^` zyV$MxhNn}Xl+iDqu}1B55zerA6;^r?7NWd%W#MVAcfvKhuk65v6nK}q>M9I@yS$%P zi6ZIIMoxO~Q|1|e+*-s9!=%*`lMS}$@Ozu4hUHSdQ`edEX)AUt25|a2;pXX{%Rw6xd&kcL`=S!dmm!}C$vQ3a#wmXvTp#`@$O4)i_J|DkkoCR;Vw&Cfo~mNa4Y`=M8T ztMhZI?xeD>Gfu{~P`I zB_*-P?NqQT^4%eB6;&}QsfTC2vC=O%$nhI2EWDkpo}RJyyjz&&?k^Tk3i3dt9`_ao z?y#pf_`HpL*FA^qafN2_t@n(9+4GRS^*kficb@05&|r0KVQ)0;*>}8nxWQ;-rsA7x z1p_f7eG*M9Gua+btg#}A-d^~*tFVSG^4lr4rMrDQXTSmLxuUrzVBmpkm~n`hFQU)& z?nA>o`(T_aXJ_Fj2c(gn@!0-DdZX%>TRM$9y2G0~nPBiMU^io3EVwSk5q9z~RP{g^ zuFfo5dM1nCM?*1PEVN!`uCc7tOcwlb+|HHxd6?1KtUq&BV39@ixWZ09E;4st&-4o{ M@Xa->x@A%P3wovcRR910 literal 0 HcmV?d00001 diff --git a/sample-data/03700181.gqrsl b/sample-data/03700181.gqrsl new file mode 100644 index 0000000000000000000000000000000000000000..edac09d7e0c9faceed0007260113b56abad76e3e GIT binary patch literal 4062 zcmZvdO>PrG5QSr@k%ArPj{p(^DTp;v5+p#%#17&T+<*<@cZCCI;5dX^&0?}+L4E!D zrN#-etm&zr_g+=?bZ@+S^!NRjuip-ze?2^U@#^U4`1SGO^G}D^K5YCd)Bdc?;?M7U znGAPhjcu#hyZVNgD6Cpd`>sV#hD0FOb|WhX&-XPH$8H9uc#{F&szrD4|G971yQmcsy$BB1N)KEw+i|DXAjxx9$KgLL{ z_*KJX$Y{lmHDHluWo$-w6Ggtn!Q)xy98_0Et!pF4v2@0ajyJzOtLxgjY_f?tX54cx?t3NFV-e98St*6 zdqgNJ*QvqY$#B`aMf7FEWre=0cwdwun5O+z#T;U_D8IuZ1Vv1HVy>$70cD62TXRSR{?Mtxu;@5ks9 znddRH?dEZXj>OJyD|CoKmU(|%_9J`Vzp4J+ntv9ERtht3^N8Axr@A+b3DJ>xu<})t z=NxI>2@4#%ts>Qd6&um2K?)U{UNY0u)o3!oww-A9$)fCqdaQ8l$Df^rcQ5{~$Z9~r zE`H@Cuk7H^nS+04vD(1c3& zT%F?`Ue|1uWR_{3w?j?&iyFLrZ`bF|h@ z)0$Y_8@?;YEMSRQdy=&?s7z;-`jOq!63WJhTw?C79oo2l3zOe>8P)quuAakaS+jGZ|pQZ#C594B6->Hgy$0 zHzPhQ#Nu;o`t{w+`ad;d9$92+uj{TOha1da*k#4_`z(B@hru^0^McPfFUzAi@Aw+0 z{b_kppYU+U5UW})uh-bMzc}G_%L-E-Wr;z%xr_7cv^?v7UhDK;MA^7%lyxJEwG(A6 zQZHn6!WA(`?f$M-$68;UJEkYo@HxcO$l7=MiuwA4g+^9Pif`DnBx{V~cqt{4Gu+us zn+$NVa-y5Vyx7Uxix}}pKe5>EH9rc#;wdbAT4Mu)`|qq;#Ur)Ygv4$mmv~~a!gJ7` z^bLK9gNG=06%VYO+hWI;?8Lt)kNdZQab9mUZgXxnG9SbrG!!f&AH~ax#Z$V>FHJB> s6WWBbY&WIe=p#zNSB{WjP~X?>yJ1JMtb3JT*;KNu`qneHqneG4e+&n*Q~&?~ literal 0 HcmV?d00001 diff --git a/sample-data/03700181.sqrs b/sample-data/03700181.sqrs new file mode 100644 index 0000000000000000000000000000000000000000..9d52879fee86ff7f5a7e17eac93d5ba102f473fc GIT binary patch literal 2434 zcmZXUL2eU45Jd;6*KFBZ$^{S-8?F$s=K>J~1%gOokH?N3!!6*7903XH_4C)*;L%K1 zbyfZPRn_g`-HYEB7mNGrPgjetS9iBJ5BJx%pWiHAy?!|izy8$kS*^ox_k3vUHXYwc z=*UwW+p0Zwd93f)Huc?f3m(es#UEKTqJ2b~dfd6J7R=zq6DzsI2kTUeY&JD~616?b za=;E-UgUGXXzR8u>)7pNJI7E<%_7dMtehyG(>k|DjfiuM;A07|RC#Jc&a>(BNR?=^ zH*U@)51ELMN7z%R{f^&U$(&inV9s&&(Wp5_JzlY*=Lusor{4eL>>OVI){-d^J9FHY z%-NJHUo(MhPh^?NZrZNZaE3Eoz{^qlXLFs+^O{Cl$&+JF^|~M zTxUDd+xDa9MJ7+!z|qW!ie`Lz&+1H!$NQ$E(2G@R-0+~w8fDEI?b4=QmHlvJOXRlmTozXl;LJMK3-7V?WzP@FuA`8R?p&7- z2=sYhUl__9PY}pS2Hx24@?S&$eB*Ol#2UGMeQa`qR-$Byf-Ki=eN-Vhr+0KOvXdkQFhdzZ}MR~62 zu@PYdCNF0o*pD@joT?z=V<%umG)PD}E8;pUI+lJar`}Wo-`V#|Rcy|5+xuj<@pP`P z=FFt=loJxHV8UK96R&2M+_#Icr#DU`obXG8*{n1fhJ9>sZ9C>NI?>XR3GAPsLNo>~lhp_tgdN dGIyO@ijM72^3&1p+YwhA_Sjgbleno3!(RoBT*v?b literal 0 HcmV?d00001 From 0cd04862165d94128c32b3839002d5c54534bab7 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Thu, 17 Mar 2022 16:01:57 -0400 Subject: [PATCH 002/287] plot_items: add sampling_freq and ann_freq parameters. An annotation file (represented by a wfdb.Annotation object) may have a "sampling frequency" that differs from the sampling frequency or frequencies of the signals themselves. This will be the case, for example, for annotations generated by programs like sqrs that operate on an upsampled or downsampled copy of the input signals. In any event, when plotting annotations, we need to translate the annotation time into a sample number in order to display it in the correct location. Furthermore, in the future, we want to permit plotting multiple synchronized signals that are sampled at different frequencies. Therefore, to disambiguate between the many possible "sampling frequencies" invvolved, add parameters 'sampling_freq' and 'ann_freq'. Both parameters are optional and default to the value of 'fs'. Either may be a list (one entry per channel), allowing the API to accomodate multi-frequency data. Currently, if 'sampling_freq' is a list, all of its elements must be equal. --- wfdb/plot/plot.py | 175 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 155 insertions(+), 20 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index 99279b53..ac9aa719 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -8,12 +8,79 @@ from wfdb.io.annotation import Annotation +def _get_sampling_freq(sampling_freq, n_sig, frame_freq): + """ + Convert application-specified sampling frequency to a list. + + Parameters + ---------- + sampling_freq : number or sequence or None + The sampling frequency or frequencies of the signals. If this is a + list, its length must equal `n_sig`. If unset, defaults to + `frame_freq`. + n_sig : int + Number of channels. + frame_freq : number or None + Default sampling frequency (record frame frequency). + + Returns + ------- + sampling_freq : list + The sampling frequency for each channel (a list of length `n_sig`.) + + """ + if sampling_freq is None: + return [frame_freq] * n_sig + elif hasattr(sampling_freq, '__len__'): + if len(sampling_freq) != n_sig: + raise ValueError('length mismatch: n_sig = {}, ' + 'len(sampling_freq) = {}'.format( + n_sig, len(sampling_freq))) + return list(sampling_freq) + else: + return [sampling_freq] * n_sig + + +def _get_ann_freq(ann_freq, n_annot, frame_freq): + """ + Convert application-specified annotation frequency to a list. + + Parameters + ---------- + ann_freq : number or sequence or None + The sampling frequency or frequencies of the annotations. If this + is a list, its length must equal `n_annot`. If unset, defaults to + `frame_freq`. + n_annot : int + Number of channels. + frame_freq : number or None + Default sampling frequency (record frame frequency). + + Returns + ------- + ann_freq : list + The sampling frequency for each channel (a list of length `n_annot`). + + """ + if ann_freq is None: + return [frame_freq] * n_annot + elif hasattr(ann_freq, '__len__'): + if len(ann_freq) != n_annot: + raise ValueError('length mismatch: n_annot = {}, ' + 'len(ann_freq) = {}'.format( + n_annot, len(ann_freq))) + return list(ann_freq) + else: + return [ann_freq] * n_annot + + def plot_items(signal=None, ann_samp=None, ann_sym=None, fs=None, time_units='samples', sig_name=None, sig_units=None, xlabel=None, ylabel=None, title=None, sig_style=[''], ann_style=['r*'], ecg_grids=[], figsize=None, sharex=False, sharey=False, return_fig=False, - return_fig_axes=False): + return_fig_axes=False, sampling_freq=None, + ann_freq=None): """ Subplot individual channels of signals and/or annotations. @@ -87,6 +154,14 @@ def plot_items(signal=None, ann_samp=None, ann_sym=None, fs=None, 'figsize' argument passed into matplotlib.pyplot's `figure` function. return_fig : bool, optional Whether the figure is to be returned as an output argument. + sampling_freq : number or sequence, optional + The sampling frequency or frequencies of the signals. If this is a + list, it must have the same length as the number of channels. If + unspecified, defaults to `fs`. + ann_freq : number or sequence, optional + The sampling frequency or frequencies of the annotations. If this + is a list, it must have the same length as `ann_samp`. If + unspecified, defaults to `fs`. Returns ------- @@ -113,18 +188,25 @@ def plot_items(signal=None, ann_samp=None, ann_sym=None, fs=None, # Figure out number of subplots required sig_len, n_sig, n_annot, n_subplots = get_plot_dims(signal, ann_samp) + # Convert sampling_freq and ann_freq to lists if needed + sampling_freq = _get_sampling_freq(sampling_freq, n_sig, fs) + ann_freq = _get_ann_freq(ann_freq, n_annot, fs) + # Create figure fig, axes = create_figure(n_subplots, sharex, sharey, figsize) if signal is not None: - plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes) + plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes, + sampling_freq=sampling_freq) if ann_samp is not None: plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, - time_units, ann_style, axes) + time_units, ann_style, axes, + sampling_freq=sampling_freq, ann_freq=ann_freq) if ecg_grids: - plot_ecg_grids(ecg_grids, fs, sig_units, time_units, axes) + plot_ecg_grids(ecg_grids, fs, sig_units, time_units, axes, + sampling_freq=sampling_freq) # Add title and axis labels. # First, make sure that xlabel and ylabel inputs are valid @@ -238,7 +320,8 @@ def create_figure(n_subplots, sharex, sharey, figsize): return fig, axes -def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes): +def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes, + sampling_freq=None): """ Plot signal channels. @@ -262,22 +345,39 @@ def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes): will be used for all channels. axes : list The information needed for each subplot. + sampling_freq : number or sequence, optional + The sampling frequency or frequencies of the signals. If this is a + list, it must have the same length as the number of channels. If + unspecified, defaults to `fs`. Returns ------- N/A """ + if n_sig == 0: + return + # Extend signal style if necessary if len(sig_style) == 1: sig_style = n_sig * sig_style + # Convert sampling_freq to a list if needed + sampling_freq = _get_sampling_freq(sampling_freq, n_sig, fs) + + if any(f != sampling_freq[0] for f in sampling_freq): + raise NotImplementedError( + 'multiple sampling frequencies are not supported') + # Figure out time indices if time_units == 'samples': t = np.linspace(0, sig_len-1, sig_len) else: - downsample_factor = {'seconds':fs, 'minutes':fs * 60, - 'hours':fs * 3600} + downsample_factor = { + 'seconds': sampling_freq[0], + 'minutes': sampling_freq[0] * 60, + 'hours': sampling_freq[0] * 3600 + } t = np.linspace(0, sig_len-1, sig_len) / downsample_factor[time_units] # Plot the signals @@ -289,7 +389,7 @@ def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes): def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, - ann_style, axes): + ann_style, axes, sampling_freq=None, ann_freq=None): """ Plot annotations, possibly overlaid on signals. ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, ann_style, axes @@ -320,6 +420,14 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, will be used for all channels. axes : list The information needed for each subplot. + sampling_freq : number or sequence, optional + The sampling frequency or frequencies of the signals. If this is a + list, it must have the same length as the number of channels. If + unspecified, defaults to `fs`. + ann_freq : number or sequence, optional + The sampling frequency or frequencies of the annotations. If this + is a list, it must have the same length as `ann_samp`. If + unspecified, defaults to `fs`. Returns ------- @@ -330,25 +438,45 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, if len(ann_style) == 1: ann_style = n_annot * ann_style - # Figure out downsample factor for time indices - if time_units == 'samples': - downsample_factor = 1 - else: - downsample_factor = {'seconds':float(fs), 'minutes':float(fs)*60, - 'hours':float(fs)*3600}[time_units] + # Convert sampling_freq and ann_freq to lists if needed + sampling_freq = _get_sampling_freq(sampling_freq, n_sig, fs) + ann_freq = _get_ann_freq(ann_freq, n_annot, fs) # Plot the annotations for ch in range(n_annot): + afreq = ann_freq[ch] + if ch < n_sig: + sfreq = sampling_freq[ch] + else: + sfreq = afreq + + # Figure out downsample factor for time indices + if time_units == 'samples': + if afreq is None and sfreq is None: + downsample_factor = 1 + else: + downsample_factor = afreq / sfreq + else: + downsample_factor = { + 'seconds': float(afreq), + 'minutes': float(afreq) * 60, + 'hours': float(afreq) * 3600 + }[time_units] + if ann_samp[ch] is not None and len(ann_samp[ch]): # Figure out the y values to plot on a channel basis # 1 dimensional signals try: if n_sig > ch: + if sfreq == afreq: + index = ann_samp[ch] + else: + index = (sfreq / afreq * ann_samp[ch]).astype('int') if signal.ndim == 1: - y = signal[ann_samp[ch]] + y = signal[index] else: - y = signal[ann_samp[ch], ch] + y = signal[index, ch] else: y = np.zeros(len(ann_samp[ch])) except IndexError: @@ -364,7 +492,7 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, y[i])) -def plot_ecg_grids(ecg_grids, fs, units, time_units, axes): +def plot_ecg_grids(ecg_grids, fs, units, time_units, axes, sampling_freq=None): """ Add ECG grids to the axes. @@ -381,6 +509,10 @@ def plot_ecg_grids(ecg_grids, fs, units, time_units, axes): and 'hours'. axes : list The information needed for each subplot. + sampling_freq : number or sequence, optional + The sampling frequency or frequencies of the signals. If this is a + list, it must have the same length as the number of channels. If + unspecified, defaults to `fs`. Returns ------- @@ -390,6 +522,9 @@ def plot_ecg_grids(ecg_grids, fs, units, time_units, axes): if ecg_grids == 'all': ecg_grids = range(0, len(axes)) + # Convert sampling_freq to a list if needed + sampling_freq = _get_sampling_freq(sampling_freq, len(axes), fs) + for ch in ecg_grids: # Get the initial plot limits auto_xlims = axes[ch].get_xlim() @@ -397,8 +532,8 @@ def plot_ecg_grids(ecg_grids, fs, units, time_units, axes): (major_ticks_x, minor_ticks_x, major_ticks_y, minor_ticks_y) = calc_ecg_grids(auto_ylims[0], auto_ylims[1], - units[ch], fs, auto_xlims[1], - time_units) + units[ch], sampling_freq[ch], + auto_xlims[1], time_units) min_x, max_x = np.min(minor_ticks_x), np.max(minor_ticks_x) min_y, max_y = np.min(minor_ticks_y), np.max(minor_ticks_y) @@ -439,7 +574,7 @@ def calc_ecg_grids(minsig, maxsig, sig_units, fs, maxt, time_units): sig_units : list The units used for plotting each signal. fs : float - The sampling frequency of the record. + The sampling frequency of the signal. maxt : float The max time of the signal. time_units : str From e3813f7bfd6add2c18ea821a2eb86ee46976f4e8 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Thu, 17 Mar 2022 16:02:54 -0400 Subject: [PATCH 003/287] plot_wfdb: handle differing frame/annotation frequencies. An annotation file (represented by a wfdb.Annotation object) may have a "sampling frequency" that differs from the sampling frequency or frequencies of the signals themselves. This will be the case, for example, for annotations generated by programs like sqrs that operate on an upsampled or downsampled copy of the input signals. To handle this case, since record.fs does not equal annotation.fs, we must explicitly specify both sampling_freq and ann_freq when calling plot_items. --- wfdb/plot/plot.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index ac9aa719..67b0c3c3 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -779,12 +779,25 @@ def plot_wfdb(record=None, annotation=None, plot_sym=False, annotation=annotation, plot_sym=plot_sym) + if record: + sampling_freq = record.fs + else: + sampling_freq = None + + if annotation and annotation.fs is not None: + ann_freq = annotation.fs + elif record: + ann_freq = record.fs + else: + ann_freq = None + return plot_items(signal=signal, ann_samp=ann_samp, ann_sym=ann_sym, fs=fs, time_units=time_units, ylabel=ylabel, title=(title or record_name), sig_style=sig_style, sig_units=sig_units, ann_style=ann_style, ecg_grids=ecg_grids, - figsize=figsize, return_fig=return_fig) + figsize=figsize, return_fig=return_fig, + sampling_freq=sampling_freq, ann_freq=ann_freq) def get_wfdb_plot_items(record, annotation, plot_sym): From 6a7b47b8b8ffa1c22a4d63f7302c85b5f1a26c5b Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 14:50:28 -0400 Subject: [PATCH 004/287] plot_annotation: remove documentation of non-existent parameter. There is no sig_len parameter to plot_annotation. --- wfdb/plot/plot.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index 67b0c3c3..a4fcabbc 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -404,8 +404,6 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, The values of the annotation symbol locations. signal : ndarray Tranformed expanded signal into uniform signal. - sig_len : int - The signal length (per channel) of the dat file. n_sig : int The number of signals contained in the dat file. fs : float From 5fb38c142f72cce40f03e360b346fb9c412d5109 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 14:52:26 -0400 Subject: [PATCH 005/287] plot_wfdb: if plotting digital values, show units as "adu". If we are plotting digital (d_signal) values, then the values on the Y axis are ADC units, not physical units. Don't label the axes as physical units, and don't try to calculate grid lines as if ADC units were physical units. --- wfdb/plot/plot.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index a4fcabbc..565ae69c 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -857,14 +857,19 @@ def get_wfdb_plot_items(record, annotation, plot_sym): if record: if record.p_signal is not None: signal = record.p_signal + physical = True elif record.d_signal is not None: signal = record.d_signal + physical = False else: raise ValueError('The record has no signal to plot') fs = record.fs sig_name = [str(s) for s in record.sig_name] - sig_units = [str(s) for s in record.units] + if physical: + sig_units = [str(s) for s in record.units] + else: + sig_units = ['adu'] * n_sig record_name = 'Record: %s' % record.record_name ylabel = ['/'.join(pair) for pair in zip(sig_name, sig_units)] else: From da3bce5488802b5b477c2a8a25ab724e04eb17c2 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 15:21:28 -0400 Subject: [PATCH 006/287] New internal function _expand_signal. This function accepts either None, a one-dimensional array, a two-dimensional array, or a list (or other non-numpy sequence) of one-dimensional arrays, and converts the result to list of one-dimensional arrays (where each element represents one channel.) This will be used by various plotting functions to accept "non-smooth" signal data as the 'signal' argument while keeping backward compatibility. --- wfdb/plot/plot.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index 565ae69c..a0ecd66d 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -8,6 +8,43 @@ from wfdb.io.annotation import Annotation +def _expand_channels(signal): + """ + Convert application-specified signal data to a list. + + Parameters + ---------- + signal : 1d or 2d numpy array or list or None + The uniformly sampled signal or signals to be plotted. If signal + is a one-dimensional array, it is assumed to represent a single + channel. If it is a two-dimensional array, axes 0 and 1 must + represent time and channel number respectively. Otherwise it must + be a list of one-dimensional arrays (one for each channel.) + + Returns + ------- + signal : list + A list of one-dimensional arrays (one for each channel.) + + """ + if signal is None: + return [] + elif hasattr(signal, 'ndim'): + if signal.ndim == 1: + return [signal] + elif signal.ndim == 2: + return list(signal.transpose()) + else: + raise ValueError('invalid shape for signal array: {}'.format( + signal.shape)) + else: + signal = list(signal) + if any(s.ndim != 1 for s in signal): + raise ValueError('invalid shape for signal array(s): {}'.format( + [s.shape for s in signal])) + return signal + + def _get_sampling_freq(sampling_freq, n_sig, frame_freq): """ Convert application-specified sampling frequency to a list. From 317c427536443980fb93de8fa62f69a834e21988 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 15:28:10 -0400 Subject: [PATCH 007/287] plot_annotation: accept non-smooth signal data as input. When plotting signals, in addition to allowing the signal argument to be a one-dimensional or two-dimensional array, allow it to be a list of one-dimensional arrays (so that each channel can have a different length.) If signal is a 1D or 2D array, convert it to a list of arrays using _expand_channels. This allows the later logic to be simplified. --- wfdb/plot/plot.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index a0ecd66d..13bb2b38 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -439,8 +439,12 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, The number of annotations contained in the dat file. ann_sym : list The values of the annotation symbol locations. - signal : ndarray - Tranformed expanded signal into uniform signal. + signal : 1d or 2d numpy array or list + The uniformly sampled signal or signals to be plotted. If signal + is a one-dimensional array, it is assumed to represent a single + channel. If it is a two-dimensional array, axes 0 and 1 must + represent time and channel number respectively. Otherwise it must + be a list of one-dimensional arrays (one for each channel). n_sig : int The number of signals contained in the dat file. fs : float @@ -469,6 +473,9 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, N/A """ + # Convert signal to a list if needed + signal = _expand_channels(signal) + # Extend annotation style if necessary if len(ann_style) == 1: ann_style = n_annot * ann_style @@ -508,10 +515,7 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, index = ann_samp[ch] else: index = (sfreq / afreq * ann_samp[ch]).astype('int') - if signal.ndim == 1: - y = signal[index] - else: - y = signal[index, ch] + y = signal[ch][index] else: y = np.zeros(len(ann_samp[ch])) except IndexError: From 69c93a3ecf02e781c34c4dc315176508671e6659 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 15:40:11 -0400 Subject: [PATCH 008/287] plot_signal: accept non-smooth signal data as input. When plotting signals, in addition to allowing the signal argument to be a one-dimensional or two-dimensional array, allow it to be a list of one-dimensional arrays (so that each channel can have a different length.) This means that the array of X values (t) must be calculated separately for each channel, as both the sampling frequency and the number of samples may vary. (Here, we don't require that the lengths of the signals, in seconds, must all be the same, although they always will be when plotting a WFDB record.) The sig_len parameter makes no sense if the channels have different lengths; this parameter is now unused, and marked as deprecated. --- wfdb/plot/plot.py | 49 +++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index 13bb2b38..9f3df988 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -364,10 +364,14 @@ def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes, Parameters ---------- - signal : ndarray - Tranformed expanded signal into uniform signal. + signal : 1d or 2d numpy array or list + The uniformly sampled signal or signals to be plotted. If signal + is a one-dimensional array, it is assumed to represent a single + channel. If it is a two-dimensional array, axes 0 and 1 must + represent time and channel number respectively. Otherwise it must + be a list of one-dimensional arrays (one for each channel). sig_len : int - The signal length (per channel) of the dat file. + The signal length (per channel) of the dat file. Deprecated. n_sig : int The number of signals contained in the dat file. fs : float @@ -392,6 +396,8 @@ def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes, N/A """ + # Convert signal to a list if needed + signal = _expand_channels(signal) if n_sig == 0: return @@ -402,27 +408,24 @@ def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes, # Convert sampling_freq to a list if needed sampling_freq = _get_sampling_freq(sampling_freq, n_sig, fs) - if any(f != sampling_freq[0] for f in sampling_freq): - raise NotImplementedError( - 'multiple sampling frequencies are not supported') - - # Figure out time indices - if time_units == 'samples': - t = np.linspace(0, sig_len-1, sig_len) - else: - downsample_factor = { - 'seconds': sampling_freq[0], - 'minutes': sampling_freq[0] * 60, - 'hours': sampling_freq[0] * 3600 - } - t = np.linspace(0, sig_len-1, sig_len) / downsample_factor[time_units] - # Plot the signals - if signal.ndim == 1: - axes[0].plot(t, signal, sig_style[0], zorder=3) - else: - for ch in range(n_sig): - axes[ch].plot(t, signal[:,ch], sig_style[ch], zorder=3) + for ch in range(n_sig): + ch_len = len(signal[ch]) + ch_freq = sampling_freq[ch] + + # Figure out time indices + if time_units == 'samples': + t = np.linspace(0, ch_len-1, ch_len) + else: + downsample_factor = { + 'seconds': ch_freq, + 'minutes': ch_freq * 60, + 'hours': ch_freq * 3600 + } + t = np.linspace(0, ch_len-1, ch_len) + t /= downsample_factor[time_units] + + axes[ch].plot(t, signal[ch], sig_style[ch], zorder=3) def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, From 1dc98edfa9986090185972600027eeae878cde2a Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 15:44:13 -0400 Subject: [PATCH 009/287] plot_signal: avoid making redundant X-coordinate arrays. In most cases, the same X-coordinate array will be used for more than one channel; the contents of this array only depend on ch_len and ch_freq (and time_units), so we can cache these arrays in a dictionary, saving some (likely small) amount of time and memory when plotting a huge record. --- wfdb/plot/plot.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index 9f3df988..bc2c8e63 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -408,22 +408,28 @@ def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes, # Convert sampling_freq to a list if needed sampling_freq = _get_sampling_freq(sampling_freq, n_sig, fs) + tarrays = {} + # Plot the signals for ch in range(n_sig): ch_len = len(signal[ch]) ch_freq = sampling_freq[ch] # Figure out time indices - if time_units == 'samples': - t = np.linspace(0, ch_len-1, ch_len) - else: - downsample_factor = { - 'seconds': ch_freq, - 'minutes': ch_freq * 60, - 'hours': ch_freq * 3600 - } - t = np.linspace(0, ch_len-1, ch_len) - t /= downsample_factor[time_units] + try: + t = tarrays[ch_len, ch_freq] + except KeyError: + if time_units == 'samples': + t = np.linspace(0, ch_len-1, ch_len) + else: + downsample_factor = { + 'seconds': ch_freq, + 'minutes': ch_freq * 60, + 'hours': ch_freq * 3600 + } + t = np.linspace(0, ch_len-1, ch_len) + t /= downsample_factor[time_units] + tarrays[ch_len, ch_freq] = t axes[ch].plot(t, signal[ch], sig_style[ch], zorder=3) From be23d6ae8dd8a6532d770e2379a56b459bd27029 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 15:48:30 -0400 Subject: [PATCH 010/287] get_plot_dims: accept non-smooth signal data as input. When plotting signals, in addition to allowing the signal argument to be a one-dimensional or two-dimensional array, allow it to be a list of one-dimensional arrays (so that each channel can have a different length.) Using _expand_channels here, as in plot_annotation, allows the logic to be simplified. The sig_len return value makes no sense if the channels have different lengths; this return value is now marked as deprecated, and will be set to None if the channel lengths differ. --- wfdb/plot/plot.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index bc2c8e63..a81dc688 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -275,10 +275,12 @@ def get_plot_dims(signal, ann_samp): Parameters ---------- - signal : 1d or 2d numpy array, optional - The uniformly sampled signal to be plotted. If signal.ndim is 1, it is - assumed to be a one channel signal. If it is 2, axes 0 and 1, must - represent time and channel number respectively. + signal : 1d or 2d numpy array or list, optional + The uniformly sampled signal or signals to be plotted. If signal + is a one-dimensional array, it is assumed to represent a single + channel. If it is a two-dimensional array, axes 0 and 1 must + represent time and channel number respectively. Otherwise it must + be a list of one-dimensional arrays (one for each channel). ann_samp: list, optional A list of annotation locations to plot, with each list item corresponding to a different channel. List items may be: @@ -297,7 +299,7 @@ def get_plot_dims(signal, ann_samp): Returns ------- sig_len : int - The signal length (per channel) of the dat file. + The signal length (per channel) of the dat file. Deprecated. n_sig : int The number of signals contained in the dat file. n_annot : int @@ -306,13 +308,14 @@ def get_plot_dims(signal, ann_samp): The max between number of signals and annotations. """ - if signal is not None: - if signal.ndim == 1: - sig_len = len(signal) - n_sig = 1 - else: - sig_len = signal.shape[0] - n_sig = signal.shape[1] + # Convert signal to a list if needed + signal = _expand_channels(signal) + + if signal: + n_sig = len(signal) + sig_len = len(signal[0]) + if any(len(s) != sig_len for s in signal): + sig_len = None else: sig_len = 0 n_sig = 0 From 0de1a9df7ca970e839ff407be13584a483410aec Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 16:10:32 -0400 Subject: [PATCH 011/287] plot_items: accept non-smooth signal data as input. When plotting signals, in addition to allowing the signal argument to be a one-dimensional or two-dimensional array, allow it to be a list of one-dimensional arrays (so that each channel can have a different length.) --- wfdb/plot/plot.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index a81dc688..412f0944 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -123,10 +123,12 @@ def plot_items(signal=None, ann_samp=None, ann_sym=None, fs=None, Parameters ---------- - signal : 1d or 2d numpy array, optional - The uniformly sampled signal to be plotted. If signal.ndim is 1, it is - assumed to be a one channel signal. If it is 2, axes 0 and 1, must - represent time and channel number respectively. + signal : 1d or 2d numpy array or list, optional + The uniformly sampled signal or signals to be plotted. If signal + is a one-dimensional array, it is assumed to represent a single + channel. If it is a two-dimensional array, axes 0 and 1 must + represent time and channel number respectively. Otherwise it must + be a list of one-dimensional arrays (one for each channel). ann_samp: list, optional A list of annotation locations to plot, with each list item corresponding to a different channel. List items may be: @@ -222,6 +224,9 @@ def plot_items(signal=None, ann_samp=None, ann_sym=None, fs=None, """ import matplotlib.pyplot as plt + # Convert signal to a list if needed + signal = _expand_channels(signal) + # Figure out number of subplots required sig_len, n_sig, n_annot, n_subplots = get_plot_dims(signal, ann_samp) From 576412486a97e3f61a32c211cfbb4dcfb783f788 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Fri, 18 Mar 2022 16:14:39 -0400 Subject: [PATCH 012/287] plot_wfdb: plot non-smooth records. If a record is loaded in "non-smooth" ("expanded") mode, it can contain signals of different lengths sampled at different frequencies. In such a case, we want to plot each signal at its original frequency in order to see the effect of the sampling and the temporal relationships between the signals. plot_items now allows the signal argument to be either a numpy array (as in p_signal or d_signal, loaded when 'smooth_frames=True') or a list of arrays (as in e_p_signal or e_d_signal, loaded when 'smooth_frames=False'); in the latter case, plot_wfdb has to calculate and provide the correct per-channel sampling frequencies. (The annotation file, if any, may have its own sampling frequency, which may differ from the signal sampling frequencies. The *default*, if the annotation file doesn't specify a frequency, is always the record frame frequency (fs), not the sampling frequency of any particular signal.) --- wfdb/plot/plot.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index 412f0944..a1f09334 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -768,8 +768,9 @@ def plot_wfdb(record=None, annotation=None, plot_sym=False, function, while allowing direct input of WFDB objects. If the record object is input, the function will extract from it: - - signal values, from the `p_signal` (priority) or `d_signal` attribute - - sampling frequency, from the `fs` attribute + - signal values, from the `e_p_signal`, `e_d_signal`, `p_signal`, or + `d_signal` attribute (in that order of priority.) + - frame frequency, from the `fs` attribute - signal names, from the `sig_name` attribute - signal units, from the `units` attribute @@ -836,7 +837,10 @@ def plot_wfdb(record=None, annotation=None, plot_sym=False, plot_sym=plot_sym) if record: - sampling_freq = record.fs + if record.e_p_signal is not None or record.e_d_signal is not None: + sampling_freq = [spf * record.fs for spf in record.samps_per_frame] + else: + sampling_freq = record.fs else: sampling_freq = None @@ -913,11 +917,21 @@ def get_wfdb_plot_items(record, annotation, plot_sym): """ # Get record attributes if record: - if record.p_signal is not None: + if record.e_p_signal is not None: + signal = record.e_p_signal + n_sig = len(signal) + physical = True + elif record.e_d_signal is not None: + signal = record.e_d_signal + n_sig = len(signal) + physical = False + elif record.p_signal is not None: signal = record.p_signal + n_sig = signal.shape[1] physical = True elif record.d_signal is not None: signal = record.d_signal + n_sig = signal.shape[1] physical = False else: raise ValueError('The record has no signal to plot') @@ -972,7 +986,7 @@ def get_wfdb_plot_items(record, annotation, plot_sym): # In this case, omit empty middle channels. This function should # already process labels and arrangements before passing into # `plot_items` - sig_chans = set(range(signal.shape[1])) + sig_chans = set(range(n_sig)) all_chans = sorted(sig_chans.union(ann_chans)) # Need to update ylabels and annotation values From f5961688f430c1a4a5418809b2ee48e84c57156c Mon Sep 17 00:00:00 2001 From: Chen Xie Date: Mon, 11 Apr 2022 16:38:50 -0700 Subject: [PATCH 013/287] Convert the README file to markdown. Add badges and citing section --- README.md | 50 +++++++++++++++++++++++++++++++++++++++++++ README.rst | 63 ------------------------------------------------------ 2 files changed, 50 insertions(+), 63 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 00000000..1c6e45cf --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# The WFDB Python Package + +![signals](https://raw.githubusercontent.com/MIT-LCP/wfdb-python/master/demo-img.png) + +[![tests workflow](https://github.com/MIT-LCP/wfdb-python/actions/workflows/run-tests.yml/badge.svg)](https://github.com/MIT-LCP/wfdb-python/actions?query=workflow%3Arun-tests+event%3Apush+branch%3Amaster) +[![PyPI Downloads](https://img.shields.io/pypi/dm/wfdb.svg?label=PyPI%20downloads)](https://pypi.org/project/wfdb/) +[![PhysioNet Project](https://img.shields.io/badge/DOI-10.13026%2Fegpf--2788-blue)](https://doi.org/10.13026/egpf-2788) +[![Supported Python Versions](https://img.shields.io/pypi/pyversions/wfdb.svg)](https://pypi.org/project/wfdb) + +## Introduction + +A Python-native package for reading, writing, processing, and plotting physiologic signal and annotation data. The core I/O functionality is based on the Waveform Database (WFDB) [specifications](https://github.com/wfdb/wfdb-spec/). + +This package is heavily inspired by the original [WFDB Software Package](https://www.physionet.org/content/wfdb/), and initially aimed to replicate many of its command-line APIs. However, the projects are independent, and there is no promise of consistency between the two, beyond each package adhering to the core specifications. + +## Documentation and Usage + +See the [documentation site](http://wfdb.readthedocs.io) for the public APIs. + +See the [demo.ipynb](https://github.com/MIT-LCP/wfdb-python/blob/master/demo.ipynb) notebook file for example use cases. + +## Installation + +The distribution is hosted on pypi at: . To directly install the package from pypi, run from your terminal:: + +```sh +pip install wfdb +``` + +The development version is hosted at: . This repository also contains demo scripts and example data. To install the development version, clone or download the repository, navigate to the base directory, and run: + +```sh +pip install . +``` + +## Development + +The package is to be expanded with physiological signal-processing tools, and general improvements. Development is made for Python 3.6+ only. + +## Contributing + +We welcome community contributions in the form of pull requests. When contributing code, please ensure: + +- [PEP8](https://www.python.org/dev/peps/pep-0008/) style guidelines are followed. +- Documentation is provided. New functions and classes should have numpy/scipy style [docstrings](https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt). +- Unit tests are written for new features that are not covered by [existing tests](https://github.com/MIT-LCP/wfdb-python/tree/master/tests). + +## Citing + +When using this resource, please cite the software [publication](https://physionet.org/content/wfdb-python/) oh PhysioNet. diff --git a/README.rst b/README.rst deleted file mode 100644 index ba834cf1..00000000 --- a/README.rst +++ /dev/null @@ -1,63 +0,0 @@ -wfdb-python -=========== - -.. figure:: https://raw.githubusercontent.com/MIT-LCP/wfdb-python/master/demo-img.png - :alt: wfdb signals - - -Introduction ------------- - -The native Python waveform-database (WFDB) package. A library of tools for reading, writing, and processing WFDB signals and annotations. - -Core components of this package are based on the original WFDB specifications. This package does not contain the exact same functionality as the original WFDB package. It aims to implement as many of its core features as possible, with user-friendly APIs. Additional useful physiological signal-processing tools are added over time. - - -Documentation and Usage ------------------------ - -See the `documentation site`_ for the public APIs. - -See the `demo.ipynb`_ notebook file for more example use cases. - - -Installation ------------- - -The distribution is hosted on pypi at: https://pypi.python.org/pypi/wfdb/. To directly install the package from pypi without needing to explicitly download content, run from your terminal:: - - $ pip install wfdb - -The development version is hosted at: https://github.com/MIT-LCP/wfdb-python. This repository also contains demo scripts and example data. To install the development version, clone or download the repository, navigate to the base directory, and run:: - - $ pip install . - - -Development ------------ - -The development repository is hosted at: https://github.com/MIT-LCP/wfdb-python - -The package is to be expanded with physiological signal-processing tools, and general improvements. Development is made for Python 3.6+ only. - - -Contributing ------------- - -We welcome community contributions in the form of pull requests. When contributing code, please ensure: - -* PEP8_ style guidelines are followed. -* Documentation is provided. New functions and classes should have numpy/scipy style docstrings_. -* Unit tests are written for new features that are not covered by `existing tests`_. - - -.. |Build Status| image:: https://travis-ci.org/MIT-LCP/wfdb-python.svg?branch=master - :target: https://travis-ci.org/MIT-LCP/wfdb-python - -.. _documentation site: http://wfdb.readthedocs.io - -.. _PEP8: https://www.python.org/dev/peps/pep-0008/ -.. _docstrings: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt -.. _existing tests: https://github.com/MIT-LCP/wfdb-python/tree/master/tests - -.. _demo.ipynb: https://github.com/MIT-LCP/wfdb-python/blob/master/demo.ipynb From 0b1aa8f68b7879fff81f7fa16631e8c1a17b300a Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Wed, 13 Apr 2022 13:19:41 -0400 Subject: [PATCH 014/287] plot.plot: simplify wording in documentation. --- wfdb/plot/plot.py | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/wfdb/plot/plot.py b/wfdb/plot/plot.py index a1f09334..2010c2f2 100644 --- a/wfdb/plot/plot.py +++ b/wfdb/plot/plot.py @@ -15,11 +15,11 @@ def _expand_channels(signal): Parameters ---------- signal : 1d or 2d numpy array or list or None - The uniformly sampled signal or signals to be plotted. If signal - is a one-dimensional array, it is assumed to represent a single - channel. If it is a two-dimensional array, axes 0 and 1 must - represent time and channel number respectively. Otherwise it must - be a list of one-dimensional arrays (one for each channel.) + The signal or signals to be plotted. If signal is a + one-dimensional array, it is assumed to represent a single channel. + If it is a two-dimensional array, axes 0 and 1 must represent time + and channel number respectively. Otherwise it must be a list of + one-dimensional arrays (one for each channel.) Returns ------- @@ -124,11 +124,11 @@ def plot_items(signal=None, ann_samp=None, ann_sym=None, fs=None, Parameters ---------- signal : 1d or 2d numpy array or list, optional - The uniformly sampled signal or signals to be plotted. If signal - is a one-dimensional array, it is assumed to represent a single - channel. If it is a two-dimensional array, axes 0 and 1 must - represent time and channel number respectively. Otherwise it must - be a list of one-dimensional arrays (one for each channel). + The signal or signals to be plotted. If signal is a + one-dimensional array, it is assumed to represent a single channel. + If it is a two-dimensional array, axes 0 and 1 must represent time + and channel number respectively. Otherwise it must be a list of + one-dimensional arrays (one for each channel). ann_samp: list, optional A list of annotation locations to plot, with each list item corresponding to a different channel. List items may be: @@ -281,11 +281,11 @@ def get_plot_dims(signal, ann_samp): Parameters ---------- signal : 1d or 2d numpy array or list, optional - The uniformly sampled signal or signals to be plotted. If signal - is a one-dimensional array, it is assumed to represent a single - channel. If it is a two-dimensional array, axes 0 and 1 must - represent time and channel number respectively. Otherwise it must - be a list of one-dimensional arrays (one for each channel). + The signal or signals to be plotted. If signal is a + one-dimensional array, it is assumed to represent a single channel. + If it is a two-dimensional array, axes 0 and 1 must represent time + and channel number respectively. Otherwise it must be a list of + one-dimensional arrays (one for each channel). ann_samp: list, optional A list of annotation locations to plot, with each list item corresponding to a different channel. List items may be: @@ -373,11 +373,11 @@ def plot_signal(signal, sig_len, n_sig, fs, time_units, sig_style, axes, Parameters ---------- signal : 1d or 2d numpy array or list - The uniformly sampled signal or signals to be plotted. If signal - is a one-dimensional array, it is assumed to represent a single - channel. If it is a two-dimensional array, axes 0 and 1 must - represent time and channel number respectively. Otherwise it must - be a list of one-dimensional arrays (one for each channel). + The signal or signals to be plotted. If signal is a + one-dimensional array, it is assumed to represent a single channel. + If it is a two-dimensional array, axes 0 and 1 must represent time + and channel number respectively. Otherwise it must be a list of + one-dimensional arrays (one for each channel). sig_len : int The signal length (per channel) of the dat file. Deprecated. n_sig : int @@ -457,11 +457,11 @@ def plot_annotation(ann_samp, n_annot, ann_sym, signal, n_sig, fs, time_units, ann_sym : list The values of the annotation symbol locations. signal : 1d or 2d numpy array or list - The uniformly sampled signal or signals to be plotted. If signal - is a one-dimensional array, it is assumed to represent a single - channel. If it is a two-dimensional array, axes 0 and 1 must - represent time and channel number respectively. Otherwise it must - be a list of one-dimensional arrays (one for each channel). + The signal or signals to be plotted. If signal is a + one-dimensional array, it is assumed to represent a single channel. + If it is a two-dimensional array, axes 0 and 1 must represent time + and channel number respectively. Otherwise it must be a list of + one-dimensional arrays (one for each channel). n_sig : int The number of signals contained in the dat file. fs : float From b84a7656e1d5bb36e5e843b1331efeec0d1a722a Mon Sep 17 00:00:00 2001 From: Chen Date: Wed, 13 Apr 2022 11:00:33 -0700 Subject: [PATCH 015/287] Replace references to README.rst with README.md (#359) * Replace references to README.rst with README.md * Update desc content type --- MANIFEST.in | 4 ++-- setup.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 0ff3f716..2f5dfb98 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,11 +2,11 @@ include LICENSE # Include readme file -include README.rst +include README.md # Include the data files # recursive-include data * # If using Python 2.6 or less, then have to include package data, even though # it's already declared in setup.py -# include sample/*.dat \ No newline at end of file +# include sample/*.dat diff --git a/setup.py b/setup.py index e30da086..2549bc8f 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ here = path.abspath(path.dirname(__file__)) # Get the long description from the README file -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: +with open(path.join(here, 'README.md'), encoding='utf-8') as f: long_description = f.read() # Get the version number from the version.py file @@ -28,6 +28,7 @@ description='The WFDB Python Toolbox', long_description=long_description, + long_description_content_type="text/markdown", # The project's main homepage. url='https://github.com/MIT-LCP/wfdb-python', From 994b794a6f994fc3132e106ca23f41bf6758d1d1 Mon Sep 17 00:00:00 2001 From: Chen Date: Tue, 19 Apr 2022 20:53:39 -0700 Subject: [PATCH 016/287] Switch to Poetry for dependency management and package description (#356) * Add poetry configuration file and update project dependencies * Update package description and patch version. * Remove requirements.txt, setup.py, and MANIFEST.in. * Update GH workflows. Set test Python version matrix to 3.7, 3.8, 3.9. * Add instructions for developing with Poetry and downloading dependencies --- .github/workflows/run-tests.yml | 15 +- .gitignore | 3 + MANIFEST.in | 12 - README.md | 36 ++- poetry.lock | 526 ++++++++++++++++++++++++++++++++ pyproject.toml | 24 ++ requirements.txt | 6 - setup.py | 106 ------- wfdb/version.py | 2 +- 9 files changed, 593 insertions(+), 137 deletions(-) delete mode 100644 MANIFEST.in create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 0409c388..e77a93dc 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: os: [windows-latest, ubuntu-latest, macos-latest] - python-version: [3.6, 3.7, 3.8] + python-version: ["3.7", "3.8", "3.9"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -27,11 +27,12 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Run nosetests - run: | - nosetests + python -m pip install --upgrade pip poetry + pip install ".[dev]" + - name: Run tests + run: nosetests + - name: Validate poetry file + run: poetry check test-deb10-i386: runs-on: ubuntu-latest @@ -55,6 +56,6 @@ jobs: # https://github.com/actions/checkout/issues/334 - uses: actions/checkout@v1 - - name: Run nosetests + - name: Run tests run: | nosetests3 diff --git a/.gitignore b/.gitignore index 84200fc5..ebdd3e46 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,6 @@ target/ # OSX .DS_Store .DS_Store + +# pyenv +.python-version diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 2f5dfb98..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,12 +0,0 @@ -# Include the license file -include LICENSE - -# Include readme file -include README.md - -# Include the data files -# recursive-include data * - -# If using Python 2.6 or less, then have to include package data, even though -# it's already declared in setup.py -# include sample/*.dat diff --git a/README.md b/README.md index 1c6e45cf..42d83e03 100644 --- a/README.md +++ b/README.md @@ -21,23 +21,28 @@ See the [demo.ipynb](https://github.com/MIT-LCP/wfdb-python/blob/master/demo.ipy ## Installation -The distribution is hosted on pypi at: . To directly install the package from pypi, run from your terminal:: +The distribution is hosted on PyPI at: . The package can be directly installed from PyPI using either pip or poetry: ```sh pip install wfdb +poetry add wfdb ``` The development version is hosted at: . This repository also contains demo scripts and example data. To install the development version, clone or download the repository, navigate to the base directory, and run: ```sh +# Without dev dependencies pip install . -``` +poetry install -## Development +# With dev dependencies +pip install ".[dev]" +poetry install -E dev +``` -The package is to be expanded with physiological signal-processing tools, and general improvements. Development is made for Python 3.6+ only. +See the [note](#package-management) below about dev dependencies. -## Contributing +## Developing We welcome community contributions in the form of pull requests. When contributing code, please ensure: @@ -45,6 +50,27 @@ We welcome community contributions in the form of pull requests. When contributi - Documentation is provided. New functions and classes should have numpy/scipy style [docstrings](https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt). - Unit tests are written for new features that are not covered by [existing tests](https://github.com/MIT-LCP/wfdb-python/tree/master/tests). +### Package Management + +This project uses [poetry](https://python-poetry.org/docs/) for package management and distribution. + +Development dependencies are specified as optional dependencies, and then added to the "dev" extra group in the [pyproject.toml](./pyproject.toml) file. + +```sh +# Do NOT use: poetry add --dev +poetry add --optional +``` + +The `[tool.poetry.dev-dependencies]` attribute is NOT used because of a [limitation](https://github.com/python-poetry/poetry/issues/3514) that prevents these dependencies from being pip installable. Therefore, dev dependencies are not installed when purely running `poetry install`, and the `--no-dev` flag has no meaning in this project. + +Make sure the versions in [version.py](./wfdb/version.py) and [pyproject.toml](./pyproject.toml) are kept in sync. + +To upload a new distribution to PyPI: + +```sh +poetry publish +``` + ## Citing When using this resource, please cite the software [publication](https://physionet.org/content/wfdb-python/) oh PhysioNet. diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..706379ee --- /dev/null +++ b/poetry.lock @@ -0,0 +1,526 @@ +[[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.12" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "fonttools" +version = "4.32.0" +description = "Tools to manipulate font files" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["scipy", "munkres"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=14.0.0)"] +woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] + +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "kiwisolver" +version = "1.4.2" +description = "A fast implementation of the Cassowary constraint solver" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} + +[[package]] +name = "matplotlib" +version = "3.5.1" +description = "Python plotting package" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.0.1" +numpy = ">=1.17" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.2.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=4" + +[[package]] +name = "nose" +version = "1.3.7" +description = "nose extends unittest to make testing easier" +category = "main" +optional = true +python-versions = "*" + +[[package]] +name = "numpy" +version = "1.21.1" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + +[[package]] +name = "pandas" +version = "1.1.5" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +numpy = ">=1.15.4" +python-dateutil = ">=2.7.3" +pytz = ">=2017.2" + +[package.extras] +test = ["pytest (>=4.0.2)", "pytest-xdist", "hypothesis (>=3.58)"] + +[[package]] +name = "pillow" +version = "9.1.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinx-rtd-theme (>=1.0)", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "pyparsing" +version = "3.0.8" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" +optional = false +python-versions = ">=3.6.8" + +[package.extras] +diagrams = ["railroad-diagrams", "jinja2"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2022.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "requests" +version = "2.27.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "scipy" +version = "1.6.1" +description = "SciPy: Scientific Library for Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = ">=1.16.5" + +[[package]] +name = "setuptools-scm" +version = "6.4.2" +description = "the blessed package to manage your versions by scm tags" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +packaging = ">=20.0" +tomli = ">=1.0.0" + +[package.extras] +test = ["pytest (>=6.2)", "virtualenv (>20)"] +toml = ["setuptools (>=42)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "typing-extensions" +version = "4.2.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.9" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[extras] +dev = ["nose"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.7" +content-hash = "1cfc9fad8f7f149573d271b2f21a0c5ef5d84bfbb7400e5dcdde083310fd33f0" + +[metadata.files] +certifi = [ + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, +] +cycler = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] +fonttools = [ + {file = "fonttools-4.32.0-py3-none-any.whl", hash = "sha256:b038d1a0dee0079de7ade57071e2e2aced6e35bd697de244ac62938b2b1628c1"}, + {file = "fonttools-4.32.0.zip", hash = "sha256:59a90de72149893167e3d552ae2402c6874e006b9adc3feaf5f6d706fe20d392"}, +] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +kiwisolver = [ + {file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e395ece147f0692ca7cdb05a028d31b83b72c369f7b4a2c1798f4b96af1e3d8"}, + {file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b7f50a1a25361da3440f07c58cd1d79957c2244209e4f166990e770256b6b0b"}, + {file = "kiwisolver-1.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c032c41ae4c3a321b43a3650e6ecc7406b99ff3e5279f24c9b310f41bc98479"}, + {file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1dcade8f6fe12a2bb4efe2cbe22116556e3b6899728d3b2a0d3b367db323eacc"}, + {file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e45e780a74416ef2f173189ef4387e44b5494f45e290bcb1f03735faa6779bf"}, + {file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d2bb56309fb75a811d81ed55fbe2208aa77a3a09ff5f546ca95e7bb5fac6eff"}, + {file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b2d6c12f2ad5f55104a36a356192cfb680c049fe5e7c1f6620fc37f119cdc2"}, + {file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:262c248c60f22c2b547683ad521e8a3db5909c71f679b93876921549107a0c24"}, + {file = "kiwisolver-1.4.2-cp310-cp310-win32.whl", hash = "sha256:1008346a7741620ab9cc6c96e8ad9b46f7a74ce839dbb8805ddf6b119d5fc6c2"}, + {file = "kiwisolver-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:6ece2e12e4b57bc5646b354f436416cd2a6f090c1dadcd92b0ca4542190d7190"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b978afdb913ca953cf128d57181da2e8798e8b6153be866ae2a9c446c6162f40"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f88c4b8e449908eeddb3bbd4242bd4dc2c7a15a7aa44bb33df893203f02dc2d"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e348f1904a4fab4153407f7ccc27e43b2a139752e8acf12e6640ba683093dd96"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c839bf28e45d7ddad4ae8f986928dbf5a6d42ff79760d54ec8ada8fb263e097c"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8ae5a071185f1a93777c79a9a1e67ac46544d4607f18d07131eece08d415083a"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c222f91a45da9e01a9bc4f760727ae49050f8e8345c4ff6525495f7a164c8973"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:a4e8f072db1d6fb7a7cc05a6dbef8442c93001f4bb604f1081d8c2db3ca97159"}, + {file = "kiwisolver-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:be9a650890fb60393e60aacb65878c4a38bb334720aa5ecb1c13d0dac54dd73b"}, + {file = "kiwisolver-1.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ec2e55bf31b43aabe32089125dca3b46fdfe9f50afbf0756ae11e14c97b80ca"}, + {file = "kiwisolver-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d1078ba770d6165abed3d9a1be1f9e79b61515de1dd00d942fa53bba79f01ae"}, + {file = "kiwisolver-1.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbb5eb4a2ea1ffec26268d49766cafa8f957fe5c1b41ad00733763fae77f9436"}, + {file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e6cda72db409eefad6b021e8a4f964965a629f577812afc7860c69df7bdb84a"}, + {file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b1605c7c38cc6a85212dfd6a641f3905a33412e49f7c003f35f9ac6d71f67720"}, + {file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81237957b15469ea9151ec8ca08ce05656090ffabc476a752ef5ad7e2644c526"}, + {file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:240009fdf4fa87844f805e23f48995537a8cb8f8c361e35fda6b5ac97fcb906f"}, + {file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:240c2d51d098395c012ddbcb9bd7b3ba5de412a1d11840698859f51d0e643c4f"}, + {file = "kiwisolver-1.4.2-cp38-cp38-win32.whl", hash = "sha256:8b6086aa6936865962b2cee0e7aaecf01ab6778ce099288354a7229b4d9f1408"}, + {file = "kiwisolver-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:0d98dca86f77b851350c250f0149aa5852b36572514d20feeadd3c6b1efe38d0"}, + {file = "kiwisolver-1.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:91eb4916271655dfe3a952249cb37a5c00b6ba68b4417ee15af9ba549b5ba61d"}, + {file = "kiwisolver-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa4d97d7d2b2c082e67907c0b8d9f31b85aa5d3ba0d33096b7116f03f8061261"}, + {file = "kiwisolver-1.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:71469b5845b9876b8d3d252e201bef6f47bf7456804d2fbe9a1d6e19e78a1e65"}, + {file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8ff3033e43e7ca1389ee59fb7ecb8303abb8713c008a1da49b00869e92e3dd7c"}, + {file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89b57c2984f4464840e4b768affeff6b6809c6150d1166938ade3e22fbe22db8"}, + {file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffbdb9a96c536f0405895b5e21ee39ec579cb0ed97bdbd169ae2b55f41d73219"}, + {file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a830a03970c462d1a2311c90e05679da56d3bd8e78a4ba9985cb78ef7836c9f"}, + {file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f74f2a13af201559e3d32b9ddfc303c94ae63d63d7f4326d06ce6fe67e7a8255"}, + {file = "kiwisolver-1.4.2-cp39-cp39-win32.whl", hash = "sha256:e677cc3626287f343de751e11b1e8a5b915a6ac897e8aecdbc996cd34de753a0"}, + {file = "kiwisolver-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b3e251e5c38ac623c5d786adb21477f018712f8c6fa54781bd38aa1c60b60fc2"}, + {file = "kiwisolver-1.4.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0c380bb5ae20d829c1a5473cfcae64267b73aaa4060adc091f6df1743784aae0"}, + {file = "kiwisolver-1.4.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:484f2a5f0307bc944bc79db235f41048bae4106ffa764168a068d88b644b305d"}, + {file = "kiwisolver-1.4.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8afdf533b613122e4bbaf3c1e42c2a5e9e2d1dd3a0a017749a7658757cb377"}, + {file = "kiwisolver-1.4.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42f6ef9b640deb6f7d438e0a371aedd8bef6ddfde30683491b2e6f568b4e884e"}, + {file = "kiwisolver-1.4.2.tar.gz", hash = "sha256:7f606d91b8a8816be476513a77fd30abe66227039bd6f8b406c348cb0247dcc9"}, +] +matplotlib = [ + {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:456cc8334f6d1124e8ff856b42d2cc1c84335375a16448189999496549f7182b"}, + {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8a77906dc2ef9b67407cec0bdbf08e3971141e535db888974a915be5e1e3efc6"}, + {file = "matplotlib-3.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e70ae6475cfd0fad3816dcbf6cac536dc6f100f7474be58d59fa306e6e768a4"}, + {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53273c5487d1c19c3bc03b9eb82adaf8456f243b97ed79d09dded747abaf1235"}, + {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3b6f3fd0d8ca37861c31e9a7cab71a0ef14c639b4c95654ea1dd153158bf0df"}, + {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c87cdaf06fd7b2477f68909838ff4176f105064a72ca9d24d3f2a29f73d393"}, + {file = "matplotlib-3.5.1-cp310-cp310-win32.whl", hash = "sha256:e2f28a07b4f82abb40267864ad7b3a4ed76f1b1663e81c7efc84a9b9248f672f"}, + {file = "matplotlib-3.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:d70a32ee1f8b55eed3fd4e892f0286df8cccc7e0475c11d33b5d0a148f5c7599"}, + {file = "matplotlib-3.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:68fa30cec89b6139dc559ed6ef226c53fd80396da1919a1b5ef672c911aaa767"}, + {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e3484d8455af3fdb0424eae1789af61f6a79da0c80079125112fd5c1b604218"}, + {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e293b16cf303fe82995e41700d172a58a15efc5331125d08246b520843ef21ee"}, + {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e3520a274a0e054e919f5b3279ee5dbccf5311833819ccf3399dab7c83e90a25"}, + {file = "matplotlib-3.5.1-cp37-cp37m-win32.whl", hash = "sha256:2252bfac85cec7af4a67e494bfccf9080bcba8a0299701eab075f48847cca907"}, + {file = "matplotlib-3.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:abf67e05a1b7f86583f6ebd01f69b693b9c535276f4e943292e444855870a1b8"}, + {file = "matplotlib-3.5.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6c094e4bfecd2fa7f9adffd03d8abceed7157c928c2976899de282f3600f0a3d"}, + {file = "matplotlib-3.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:506b210cc6e66a0d1c2bb765d055f4f6bc2745070fb1129203b67e85bbfa5c18"}, + {file = "matplotlib-3.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b04fc29bcef04d4e2d626af28d9d892be6aba94856cb46ed52bcb219ceac8943"}, + {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577ed20ec9a18d6bdedb4616f5e9e957b4c08563a9f985563a31fd5b10564d2a"}, + {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e486f60db0cd1c8d68464d9484fd2a94011c1ac8593d765d0211f9daba2bd535"}, + {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b71f3a7ca935fc759f2aed7cec06cfe10bc3100fadb5dbd9c435b04e557971e1"}, + {file = "matplotlib-3.5.1-cp38-cp38-win32.whl", hash = "sha256:d24e5bb8028541ce25e59390122f5e48c8506b7e35587e5135efcb6471b4ac6c"}, + {file = "matplotlib-3.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:778d398c4866d8e36ee3bf833779c940b5f57192fa0a549b3ad67bc4c822771b"}, + {file = "matplotlib-3.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bb1c613908f11bac270bc7494d68b1ef6e7c224b7a4204d5dacf3522a41e2bc3"}, + {file = "matplotlib-3.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:edf5e4e1d5fb22c18820e8586fb867455de3b109c309cb4fce3aaed85d9468d1"}, + {file = "matplotlib-3.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40e0d7df05e8efe60397c69b467fc8f87a2affeb4d562fe92b72ff8937a2b511"}, + {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a350ca685d9f594123f652ba796ee37219bf72c8e0fc4b471473d87121d6d34"}, + {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3e66497cd990b1a130e21919b004da2f1dc112132c01ac78011a90a0f9229778"}, + {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:87900c67c0f1728e6db17c6809ec05c025c6624dcf96a8020326ea15378fe8e7"}, + {file = "matplotlib-3.5.1-cp39-cp39-win32.whl", hash = "sha256:b8a4fb2a0c5afbe9604f8a91d7d0f27b1832c3e0b5e365f95a13015822b4cd65"}, + {file = "matplotlib-3.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:fe8d40c434a8e2c68d64c6d6a04e77f21791a93ff6afe0dce169597c110d3079"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34a1fc29f8f96e78ec57a5eff5e8d8b53d3298c3be6df61e7aa9efba26929522"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b19a761b948e939a9e20173aaae76070025f0024fc8f7ba08bef22a5c8573afc"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6803299cbf4665eca14428d9e886de62e24f4223ac31ab9c5d6d5339a39782c7"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14334b9902ec776461c4b8c6516e26b450f7ebe0b3ef8703bf5cdfbbaecf774a"}, + {file = "matplotlib-3.5.1.tar.gz", hash = "sha256:b2e9810e09c3a47b73ce9cab5a72243a1258f61e7900969097a817232246ce1c"}, +] +nose = [ + {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, + {file = "nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac"}, + {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, +] +numpy = [ + {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, + {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, + {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, + {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, + {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, + {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, + {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, + {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, + {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, +] +packaging = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] +pandas = [ + {file = "pandas-1.1.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:bf23a3b54d128b50f4f9d4675b3c1857a688cc6731a32f931837d72effb2698d"}, + {file = "pandas-1.1.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5a780260afc88268a9d3ac3511d8f494fdcf637eece62fb9eb656a63d53eb7ca"}, + {file = "pandas-1.1.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b61080750d19a0122469ab59b087380721d6b72a4e7d962e4d7e63e0c4504814"}, + {file = "pandas-1.1.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:0de3ddb414d30798cbf56e642d82cac30a80223ad6fe484d66c0ce01a84d6f2f"}, + {file = "pandas-1.1.5-cp36-cp36m-win32.whl", hash = "sha256:70865f96bb38fec46f7ebd66d4b5cfd0aa6b842073f298d621385ae3898d28b5"}, + {file = "pandas-1.1.5-cp36-cp36m-win_amd64.whl", hash = "sha256:19a2148a1d02791352e9fa637899a78e371a3516ac6da5c4edc718f60cbae648"}, + {file = "pandas-1.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26fa92d3ac743a149a31b21d6f4337b0594b6302ea5575b37af9ca9611e8981a"}, + {file = "pandas-1.1.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c16d59c15d946111d2716856dd5479221c9e4f2f5c7bc2d617f39d870031e086"}, + {file = "pandas-1.1.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3be7a7a0ca71a2640e81d9276f526bca63505850add10206d0da2e8a0a325dae"}, + {file = "pandas-1.1.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:573fba5b05bf2c69271a32e52399c8de599e4a15ab7cec47d3b9c904125ab788"}, + {file = "pandas-1.1.5-cp37-cp37m-win32.whl", hash = "sha256:21b5a2b033380adbdd36b3116faaf9a4663e375325831dac1b519a44f9e439bb"}, + {file = "pandas-1.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:24c7f8d4aee71bfa6401faeba367dd654f696a77151a8a28bc2013f7ced4af98"}, + {file = "pandas-1.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2860a97cbb25444ffc0088b457da0a79dc79f9c601238a3e0644312fcc14bf11"}, + {file = "pandas-1.1.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5008374ebb990dad9ed48b0f5d0038124c73748f5384cc8c46904dace27082d9"}, + {file = "pandas-1.1.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2c2f7c670ea4e60318e4b7e474d56447cf0c7d83b3c2a5405a0dbb2600b9c48e"}, + {file = "pandas-1.1.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0a643bae4283a37732ddfcecab3f62dd082996021b980f580903f4e8e01b3c5b"}, + {file = "pandas-1.1.5-cp38-cp38-win32.whl", hash = "sha256:5447ea7af4005b0daf695a316a423b96374c9c73ffbd4533209c5ddc369e644b"}, + {file = "pandas-1.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:4c62e94d5d49db116bef1bd5c2486723a292d79409fc9abd51adf9e05329101d"}, + {file = "pandas-1.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:731568be71fba1e13cae212c362f3d2ca8932e83cb1b85e3f1b4dd77d019254a"}, + {file = "pandas-1.1.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c61c043aafb69329d0f961b19faa30b1dab709dd34c9388143fc55680059e55a"}, + {file = "pandas-1.1.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2b1c6cd28a0dfda75c7b5957363333f01d370936e4c6276b7b8e696dd500582a"}, + {file = "pandas-1.1.5-cp39-cp39-win32.whl", hash = "sha256:c94ff2780a1fd89f190390130d6d36173ca59fcfb3fe0ff596f9a56518191ccb"}, + {file = "pandas-1.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:edda9bacc3843dfbeebaf7a701763e68e741b08fccb889c003b0a52f0ee95782"}, + {file = "pandas-1.1.5.tar.gz", hash = "sha256:f10fc41ee3c75a474d3bdf68d396f10782d013d7f67db99c0efbfd0acb99701b"}, +] +pillow = [ + {file = "Pillow-9.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea"}, + {file = "Pillow-9.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652"}, + {file = "Pillow-9.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a"}, + {file = "Pillow-9.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7"}, + {file = "Pillow-9.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e"}, + {file = "Pillow-9.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3"}, + {file = "Pillow-9.1.0-cp310-cp310-win32.whl", hash = "sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160"}, + {file = "Pillow-9.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033"}, + {file = "Pillow-9.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c"}, + {file = "Pillow-9.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165"}, + {file = "Pillow-9.1.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a"}, + {file = "Pillow-9.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2"}, + {file = "Pillow-9.1.0-cp37-cp37m-win32.whl", hash = "sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244"}, + {file = "Pillow-9.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef"}, + {file = "Pillow-9.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512"}, + {file = "Pillow-9.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477"}, + {file = "Pillow-9.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b"}, + {file = "Pillow-9.1.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378"}, + {file = "Pillow-9.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e"}, + {file = "Pillow-9.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5"}, + {file = "Pillow-9.1.0-cp38-cp38-win32.whl", hash = "sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a"}, + {file = "Pillow-9.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34"}, + {file = "Pillow-9.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717"}, + {file = "Pillow-9.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581"}, + {file = "Pillow-9.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6"}, + {file = "Pillow-9.1.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4"}, + {file = "Pillow-9.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331"}, + {file = "Pillow-9.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8"}, + {file = "Pillow-9.1.0-cp39-cp39-win32.whl", hash = "sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58"}, + {file = "Pillow-9.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595"}, + {file = "Pillow-9.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481"}, + {file = "Pillow-9.1.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0"}, + {file = "Pillow-9.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a"}, + {file = "Pillow-9.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7"}, + {file = "Pillow-9.1.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3"}, + {file = "Pillow-9.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8"}, + {file = "Pillow-9.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458"}, + {file = "Pillow-9.1.0.tar.gz", hash = "sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97"}, +] +pyparsing = [ + {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, + {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pytz = [ + {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, + {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, +] +requests = [ + {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, + {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, +] +scipy = [ + {file = "scipy-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a15a1f3fc0abff33e792d6049161b7795909b40b97c6cc2934ed54384017ab76"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e79570979ccdc3d165456dd62041d9556fb9733b86b4b6d818af7a0afc15f092"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a423533c55fec61456dedee7b6ee7dce0bb6bfa395424ea374d25afa262be261"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:33d6b7df40d197bdd3049d64e8e680227151673465e5d85723b3b8f6b15a6ced"}, + {file = "scipy-1.6.1-cp37-cp37m-win32.whl", hash = "sha256:6725e3fbb47da428794f243864f2297462e9ee448297c93ed1dcbc44335feb78"}, + {file = "scipy-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5fa9c6530b1661f1370bcd332a1e62ca7881785cc0f80c0d559b636567fab63c"}, + {file = "scipy-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd50daf727f7c195e26f27467c85ce653d41df4358a25b32434a50d8870fc519"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f46dd15335e8a320b0fb4685f58b7471702234cba8bb3442b69a3e1dc329c345"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0e5b0ccf63155d90da576edd2768b66fb276446c371b73841e3503be1d63fb5d"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2481efbb3740977e3c831edfd0bd9867be26387cacf24eb5e366a6a374d3d00d"}, + {file = "scipy-1.6.1-cp38-cp38-win32.whl", hash = "sha256:68cb4c424112cd4be886b4d979c5497fba190714085f46b8ae67a5e4416c32b4"}, + {file = "scipy-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:5f331eeed0297232d2e6eea51b54e8278ed8bb10b099f69c44e2558c090d06bf"}, + {file = "scipy-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8a51d33556bf70367452d4d601d1742c0e806cd0194785914daf19775f0e67"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:83bf7c16245c15bc58ee76c5418e46ea1811edcc2e2b03041b804e46084ab627"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:794e768cc5f779736593046c9714e0f3a5940bc6dcc1dba885ad64cbfb28e9f0"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5da5471aed911fe7e52b86bf9ea32fb55ae93e2f0fac66c32e58897cfb02fa07"}, + {file = "scipy-1.6.1-cp39-cp39-win32.whl", hash = "sha256:8e403a337749ed40af60e537cc4d4c03febddcc56cd26e774c9b1b600a70d3e4"}, + {file = "scipy-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a5193a098ae9f29af283dcf0041f762601faf2e595c0db1da929875b7570353f"}, + {file = "scipy-1.6.1.tar.gz", hash = "sha256:c4fceb864890b6168e79b0e714c585dbe2fd4222768ee90bc1aa0f8218691b11"}, +] +setuptools-scm = [ + {file = "setuptools_scm-6.4.2-py3-none-any.whl", hash = "sha256:acea13255093849de7ccb11af9e1fb8bde7067783450cee9ef7a93139bddf6d4"}, + {file = "setuptools_scm-6.4.2.tar.gz", hash = "sha256:6833ac65c6ed9711a4d5d2266f8024cfa07c533a0e55f4c12f6eff280a5a9e30"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] +typing-extensions = [ + {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, + {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, +] +urllib3 = [ + {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, + {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..db065e97 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[tool.poetry] +name = "wfdb" +version = "4.0.0a0" +description = "The WFDB Python package: tools for reading, writing, and processing physiologic signals and annotations." +authors = ["The Laboratory for Computational Physiology "] +license = "MIT" + +[tool.poetry.dependencies] +python = "^3.7" +numpy = "^1.10.1" +scipy = "^1.0.0" +pandas = "^1.0.0" +matplotlib = "^3.3.4" +requests = "^2.8.1" +nose = {version = "^1.3.7", optional = true} + +[tool.poetry.extras] +dev = ["nose"] + +# Do NOT use [tool.poetry.dev-dependencies]. See: https://github.com/python-poetry/poetry/issues/3514 + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f9bb9b08..00000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -matplotlib==3.3.4 -nose==1.3.7 -numpy==1.18.5 -pandas==1.0.3 -requests==2.23.0 -scipy==1.4.1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 2549bc8f..00000000 --- a/setup.py +++ /dev/null @@ -1,106 +0,0 @@ -"""The WFDB Python Toolbox. -See: https://www.physionet.org/physiotools/wfdb.shtml -""" - -# Always prefer setuptools over distutils -from setuptools import setup, find_packages -# To use a consistent encoding -from codecs import open -from os import path - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, 'README.md'), encoding='utf-8') as f: - long_description = f.read() - -# Get the version number from the version.py file -with open('wfdb/version.py') as f: - __version__ = f.read().split()[-1].strip("'") - -setup( - name='wfdb', - - # Versions should comply with PEP440. For a discussion on single-sourcing - # the version across setup.py and the project code, see - # https://packaging.python.org/en/latest/single_source_version.html - version=__version__, - - description='The WFDB Python Toolbox', - long_description=long_description, - long_description_content_type="text/markdown", - - # The project's main homepage. - url='https://github.com/MIT-LCP/wfdb-python', - - # Author details - author='The Laboratory for Computational Physiology', - author_email='support@physionet.org', - - # Choose your license - license='MIT', - - # What does your project relate to? - keywords='WFDB clinical waveform', - - # You can just specify the packages manually here if your project is - # simple. Or you can use find_packages(). - # packages=find_packages(exclude=['contrib', 'docs', 'tests']), - packages=find_packages(), - - # Alternatively, if you want to distribute just a my_module.py, uncomment - # this: - # py_modules=["my_module"], - - # List run-time dependencies here. These will be installed by pip when - # your project is installed. For an analysis of "install_requires" vs pip's - # requirements files see: - # https://packaging.python.org/en/latest/discussions/install-requires-vs-requirements/?highlight=requirements - install_requires=[ - 'matplotlib>=3.3.4', - 'numpy>=1.10.1', - 'pandas>=0.17.0', - 'requests>=2.8.1', - 'scipy>=0.17.0', - ], - - # List additional groups of dependencies here (e.g. development - # dependencies). You can install these using the following syntax, - # for example: - # $ pip install -e .[dev,test] - extras_require={ - 'test': ['nose>=1.3.7'] - }, - - # If there are data files included in your packages that need to be - # installed, specify them here. If using Python 2.6 or less, then these - # have to be included in MANIFEST.in as well. - # package_data={'wfdb': ['wfdb.config'], - # }, - - # Although 'package_data' is the preferred approach, in some case you may - # need to place data files outside of your packages. See: - # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa - # In this case, 'data_file' will be installed into '/my_data' - # data_files=[('my_data', ['data/data_file'])], - # data_files=[('config', ['wfdb.config'])], - - # To provide executable scripts, use entry points in preference to the - # "scripts" keyword. Entry points provide cross-platform support and allow - # pip to create the appropriate form of executable for the target platform. - # entry_points={ - # 'console_scripts': [ - # 'sample=sample:main', - # ], - # }, - - # Add ways to quickly filter project - classifiers=[ - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "License :: OSI Approved :: MIT License" - ], -) diff --git a/wfdb/version.py b/wfdb/version.py index da4564dd..79fb7745 100644 --- a/wfdb/version.py +++ b/wfdb/version.py @@ -1 +1 @@ -__version__ = '3.4.1' +__version__ = '4.0.0a0' From 34059488f7fd3be3e04390df17b796dc073ba086 Mon Sep 17 00:00:00 2001 From: Chen Date: Wed, 20 Apr 2022 07:51:01 -0700 Subject: [PATCH 017/287] Replace nose with pytest and add Python 3.10 to testing matrix (#363) * Replace nose with pytest * Update workflow to use pytest and include Python 3.10 * Add test notes --- .github/workflows/run-tests.yml | 8 +- README.md | 11 ++ poetry.lock | 218 +++++++++++++++++++++++++++++--- pyproject.toml | 5 +- 4 files changed, 221 insertions(+), 21 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index e77a93dc..18a39019 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: os: [windows-latest, ubuntu-latest, macos-latest] - python-version: ["3.7", "3.8", "3.9"] + python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -30,7 +30,7 @@ jobs: python -m pip install --upgrade pip poetry pip install ".[dev]" - name: Run tests - run: nosetests + run: pytest - name: Validate poetry file run: poetry check @@ -47,7 +47,7 @@ jobs: python3-pandas \ python3-requests \ python3-scipy \ - python3-nose \ + python3-pytest \ git # Note: "actions/checkout@v2" requires libstdc++6:amd64 to be @@ -58,4 +58,4 @@ jobs: - name: Run tests run: | - nosetests3 + pytest-3 diff --git a/README.md b/README.md index 42d83e03..fc5b29cc 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,17 @@ To upload a new distribution to PyPI: poetry publish ``` +### Tests + +Run tests using pytest: + +```sh +pytest +# Distribute tests across multiple cores. +# https://github.com/pytest-dev/pytest-xdist +pytest -n auto +``` + ## Citing When using this resource, please cite the software [publication](https://physionet.org/content/wfdb-python/) oh PhysioNet. diff --git a/poetry.lock b/poetry.lock index 706379ee..716a1543 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,25 @@ +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.4.0" +description = "Classes Without Boilerplate" +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] + [[package]] name = "certifi" version = "2021.10.8" @@ -17,6 +39,14 @@ python-versions = ">=3.5.0" [package.extras] unicode_backport = ["unicodedata2"] +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "cycler" version = "0.11.0" @@ -25,6 +55,17 @@ category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "execnet" +version = "1.9.0" +description = "execnet: rapid multi-Python deployment" +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +testing = ["pre-commit"] + [[package]] name = "fonttools" version = "4.32.0" @@ -54,6 +95,31 @@ category = "main" optional = false python-versions = ">=3.5" +[[package]] +name = "importlib-metadata" +version = "4.11.3" +description = "Read metadata from Python packages" +category = "main" +optional = true +python-versions = ">=3.7" + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +perf = ["ipython"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "main" +optional = true +python-versions = "*" + [[package]] name = "kiwisolver" version = "1.4.2" @@ -84,14 +150,6 @@ pyparsing = ">=2.2.1" python-dateutil = ">=2.7" setuptools_scm = ">=4" -[[package]] -name = "nose" -version = "1.3.7" -description = "nose extends unittest to make testing easier" -category = "main" -optional = true -python-versions = "*" - [[package]] name = "numpy" version = "1.21.1" @@ -139,6 +197,29 @@ python-versions = ">=3.7" docs = ["olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinx-rtd-theme (>=1.0)", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "main" +optional = true +python-versions = ">=3.6" + +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "pyparsing" version = "3.0.8" @@ -150,6 +231,58 @@ python-versions = ">=3.6.8" [package.extras] diagrams = ["railroad-diagrams", "jinja2"] +[[package]] +name = "pytest" +version = "7.1.1" +description = "pytest: simple powerful testing with Python" +category = "main" +optional = true +python-versions = ">=3.7" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +tomli = ">=1.0.0" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-forked" +version = "1.4.0" +description = "run tests in isolated forked subprocesses" +category = "main" +optional = true +python-versions = ">=3.6" + +[package.dependencies] +py = "*" +pytest = ">=3.10" + +[[package]] +name = "pytest-xdist" +version = "2.5.0" +description = "pytest xdist plugin for distributed testing and loop-on-failing modes" +category = "main" +optional = true +python-versions = ">=3.6" + +[package.dependencies] +execnet = ">=1.1" +pytest = ">=6.2.0" +pytest-forked = "*" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -251,15 +384,35 @@ brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +[[package]] +name = "zipp" +version = "3.8.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = true +python-versions = ">=3.7" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] + [extras] -dev = ["nose"] +dev = ["pytest", "pytest-xdist"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "1cfc9fad8f7f149573d271b2f21a0c5ef5d84bfbb7400e5dcdde083310fd33f0" +content-hash = "c6c4a7b3fae4ba46a2ca543ab32f536b734eb47dd014c907f7f3ce18347c4c38" [metadata.files] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, + {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, +] certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, @@ -268,10 +421,18 @@ charset-normalizer = [ {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] cycler = [ {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, ] +execnet = [ + {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, + {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, +] fonttools = [ {file = "fonttools-4.32.0-py3-none-any.whl", hash = "sha256:b038d1a0dee0079de7ade57071e2e2aced6e35bd697de244ac62938b2b1628c1"}, {file = "fonttools-4.32.0.zip", hash = "sha256:59a90de72149893167e3d552ae2402c6874e006b9adc3feaf5f6d706fe20d392"}, @@ -280,6 +441,14 @@ idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] +importlib-metadata = [ + {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, + {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] kiwisolver = [ {file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e395ece147f0692ca7cdb05a028d31b83b72c369f7b4a2c1798f4b96af1e3d8"}, {file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b7f50a1a25361da3440f07c58cd1d79957c2244209e4f166990e770256b6b0b"}, @@ -362,11 +531,6 @@ matplotlib = [ {file = "matplotlib-3.5.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14334b9902ec776461c4b8c6516e26b450f7ebe0b3ef8703bf5cdfbbaecf774a"}, {file = "matplotlib-3.5.1.tar.gz", hash = "sha256:b2e9810e09c3a47b73ce9cab5a72243a1258f61e7900969097a817232246ce1c"}, ] -nose = [ - {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, - {file = "nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac"}, - {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, -] numpy = [ {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, @@ -467,10 +631,30 @@ pillow = [ {file = "Pillow-9.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458"}, {file = "Pillow-9.1.0.tar.gz", hash = "sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97"}, ] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +py = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] pyparsing = [ {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, ] +pytest = [ + {file = "pytest-7.1.1-py3-none-any.whl", hash = "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea"}, + {file = "pytest-7.1.1.tar.gz", hash = "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63"}, +] +pytest-forked = [ + {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, + {file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"}, +] +pytest-xdist = [ + {file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"}, + {file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"}, +] python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, @@ -524,3 +708,7 @@ urllib3 = [ {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] +zipp = [ + {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, + {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, +] diff --git a/pyproject.toml b/pyproject.toml index db065e97..f9c849b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,10 +12,11 @@ scipy = "^1.0.0" pandas = "^1.0.0" matplotlib = "^3.3.4" requests = "^2.8.1" -nose = {version = "^1.3.7", optional = true} +pytest = {version = "^7.1.1", optional = true} +pytest-xdist = {version = "^2.5.0", optional = true} [tool.poetry.extras] -dev = ["nose"] +dev = ["pytest", "pytest-xdist"] # Do NOT use [tool.poetry.dev-dependencies]. See: https://github.com/python-poetry/poetry/issues/3514 From 3b408f23f50889c7d1c6fee9329c76b739b9f667 Mon Sep 17 00:00:00 2001 From: cx1111 Date: Tue, 26 Apr 2022 07:42:16 -0700 Subject: [PATCH 018/287] Add pylint and black. Apply formatting (#364) * Install pylint and black * Add black config and pylintrc file * Apply black formatting * Add black format to workflow --- .github/workflows/run-tests.yml | 2 + docs/conf.py | 64 +- poetry.lock | 360 +++- pylintrc | 564 +++++++ pyproject.toml | 8 +- tests/__init__.py | 2 +- tests/test_annotation.py | 204 ++- tests/test_plot.py | 22 +- tests/test_processing.py | 170 +- tests/test_record.py | 529 +++--- tests/test_url.py | 103 +- wfdb/__init__.py | 46 +- wfdb/io/__init__.py | 47 +- wfdb/io/_header.py | 501 +++--- wfdb/io/_signal.py | 851 ++++++---- wfdb/io/_url.py | 174 +- wfdb/io/annotation.py | 1726 +++++++++++++------- wfdb/io/download.py | 108 +- wfdb/io/record.py | 2721 +++++++++++++++++++------------ wfdb/io/tff.py | 114 +- wfdb/plot/plot.py | 358 ++-- wfdb/processing/__init__.py | 16 +- wfdb/processing/basic.py | 57 +- wfdb/processing/evaluate.py | 202 ++- wfdb/processing/hr.py | 32 +- wfdb/processing/peaks.py | 96 +- wfdb/processing/qrs.py | 377 +++-- wfdb/version.py | 2 +- 28 files changed, 6373 insertions(+), 3083 deletions(-) create mode 100644 pylintrc diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 18a39019..dc4d76a1 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -33,6 +33,8 @@ jobs: run: pytest - name: Validate poetry file run: poetry check + - name: Format files + run: black . test-deb10-i386: runs-on: ubuntu-latest diff --git a/docs/conf.py b/docs/conf.py index 9f9758db..1a236b0b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,16 +20,19 @@ import os import sys -sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, os.path.abspath("..")) # For dependencies from unittest.mock import MagicMock + + class Mock(MagicMock): @classmethod def __getattr__(cls, name): - return MagicMock() + return MagicMock() -MOCK_MODULES = ['numpy', 'matplotlib', 'matplotlib.pyplot', 'pandas', 'scipy'] + +MOCK_MODULES = ["numpy", "matplotlib", "matplotlib.pyplot", "pandas", "scipy"] sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) # -- General configuration ------------------------------------------------ @@ -41,26 +44,26 @@ def __getattr__(cls, name): # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.autodoc'] +extensions = ["sphinx.ext.autodoc"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'wfdb' -copyright = '2018, MIT Lab for Computational Physiology' -author = 'MIT Lab for Computational Physiology' +project = "wfdb" +copyright = "2018, MIT Lab for Computational Physiology" +author = "MIT Lab for Computational Physiology" -with open('../wfdb/version.py') as f: +with open("../wfdb/version.py") as f: __version__ = f.read().split()[-1].strip("'") # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -81,10 +84,10 @@ def __getattr__(cls, name): # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -95,7 +98,7 @@ def __getattr__(cls, name): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'classic' +html_theme = "classic" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -106,7 +109,7 @@ def __getattr__(cls, name): # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -114,9 +117,9 @@ def __getattr__(cls, name): # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { - '**': [ - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', + "**": [ + "relations.html", # needs 'show_related': True theme option to display + "searchbox.html", ] } @@ -124,7 +127,7 @@ def __getattr__(cls, name): # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'wfdbdoc' +htmlhelp_basename = "wfdbdoc" # -- Options for LaTeX output --------------------------------------------- @@ -133,15 +136,12 @@ def __getattr__(cls, name): # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -151,8 +151,7 @@ def __getattr__(cls, name): # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'wfdb.tex', 'wfdb Documentation', - author, 'manual'), + (master_doc, "wfdb.tex", "wfdb Documentation", author, "manual"), ] @@ -160,10 +159,7 @@ def __getattr__(cls, name): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'wfdb', 'wfdb Documentation', - [author], 1) -] +man_pages = [(master_doc, "wfdb", "wfdb Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -172,7 +168,13 @@ def __getattr__(cls, name): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'wfdb', 'wfdb Documentation', - author, 'wfdb', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "wfdb", + "wfdb Documentation", + author, + "wfdb", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/poetry.lock b/poetry.lock index 716a1543..8734e175 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,17 @@ +[[package]] +name = "astroid" +version = "2.11.3" +description = "An abstract syntax tree for Python with inference support." +category = "main" +optional = true +python-versions = ">=3.6.2" + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} +typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +wrapt = ">=1.11,<2" + [[package]] name = "atomicwrites" version = "1.4.0" @@ -20,6 +34,29 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] +[[package]] +name = "black" +version = "22.3.0" +description = "The uncompromising code formatter." +category = "main" +optional = true +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "certifi" version = "2021.10.8" @@ -39,6 +76,18 @@ python-versions = ">=3.5.0" [package.extras] unicode_backport = ["unicodedata2"] +[[package]] +name = "click" +version = "8.1.2" +description = "Composable command line interface toolkit" +category = "main" +optional = true +python-versions = ">=3.7" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + [[package]] name = "colorama" version = "0.4.4" @@ -55,6 +104,17 @@ category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "dill" +version = "0.3.4" +description = "serialize all of python" +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*" + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + [[package]] name = "execnet" version = "1.9.0" @@ -68,19 +128,20 @@ testing = ["pre-commit"] [[package]] name = "fonttools" -version = "4.32.0" +version = "4.33.0" description = "Tools to manipulate font files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] +all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["scipy", "munkres"] lxml = ["lxml (>=4.0,<5)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] @@ -120,6 +181,20 @@ category = "main" optional = true python-versions = "*" +[[package]] +name = "isort" +version = "5.10.1" +description = "A Python utility / library to sort Python imports." +category = "main" +optional = true +python-versions = ">=3.6.1,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] + [[package]] name = "kiwisolver" version = "1.4.2" @@ -131,6 +206,14 @@ python-versions = ">=3.7" [package.dependencies] typing-extensions = {version = "*", markers = "python_version < \"3.8\""} +[[package]] +name = "lazy-object-proxy" +version = "1.7.1" +description = "A fast and thorough lazy object proxy." +category = "main" +optional = true +python-versions = ">=3.6" + [[package]] name = "matplotlib" version = "3.5.1" @@ -150,6 +233,22 @@ pyparsing = ">=2.2.1" python-dateutil = ">=2.7" setuptools_scm = ">=4" +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +category = "main" +optional = true +python-versions = ">=3.6" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "main" +optional = true +python-versions = "*" + [[package]] name = "numpy" version = "1.21.1" @@ -185,6 +284,14 @@ pytz = ">=2017.2" [package.extras] test = ["pytest (>=4.0.2)", "pytest-xdist", "hypothesis (>=3.58)"] +[[package]] +name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "main" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + [[package]] name = "pillow" version = "9.1.0" @@ -197,6 +304,18 @@ python-versions = ">=3.7" docs = ["olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinx-rtd-theme (>=1.0)", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +[[package]] +name = "platformdirs" +version = "2.5.2" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "main" +optional = true +python-versions = ">=3.7" + +[package.extras] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] + [[package]] name = "pluggy" version = "1.0.0" @@ -220,6 +339,27 @@ category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "pylint" +version = "2.13.7" +description = "python code static checker" +category = "main" +optional = true +python-versions = ">=3.6.2" + +[package.dependencies] +astroid = ">=2.11.3,<=2.12.0-dev0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +dill = ">=0.2" +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +testutil = ["gitpython (>3)"] + [[package]] name = "pyparsing" version = "3.0.8" @@ -363,6 +503,14 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "typed-ast" +version = "1.5.3" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "main" +optional = true +python-versions = ">=3.6" + [[package]] name = "typing-extensions" version = "4.2.0" @@ -384,6 +532,14 @@ brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +[[package]] +name = "wrapt" +version = "1.14.0" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + [[package]] name = "zipp" version = "3.8.0" @@ -397,14 +553,18 @@ docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [extras] -dev = ["pytest", "pytest-xdist"] +dev = ["pytest", "pytest-xdist", "pylint", "black"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "c6c4a7b3fae4ba46a2ca543ab32f536b734eb47dd014c907f7f3ce18347c4c38" +content-hash = "a5fb02dcee08f3bbddd7e75c3b5a58b6c82f8d86337d8e9d6deddc0df53fcaf4" [metadata.files] +astroid = [ + {file = "astroid-2.11.3-py3-none-any.whl", hash = "sha256:f1af57483cd17e963b2eddce8361e00fc593d1520fe19948488e94ff6476bd71"}, + {file = "astroid-2.11.3.tar.gz", hash = "sha256:4e5ba10571e197785e312966ea5efb2f5783176d4c1a73fa922d474ae2be59f7"}, +] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -413,6 +573,31 @@ attrs = [ {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] +black = [ + {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, + {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, + {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, + {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, + {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, + {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, + {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, + {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, + {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, + {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, + {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, + {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, + {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, + {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, + {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, + {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, + {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, + {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, + {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, +] certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, @@ -421,6 +606,10 @@ charset-normalizer = [ {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] +click = [ + {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, + {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, +] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, @@ -429,13 +618,17 @@ cycler = [ {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, ] +dill = [ + {file = "dill-0.3.4-py2.py3-none-any.whl", hash = "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f"}, + {file = "dill-0.3.4.zip", hash = "sha256:9f9734205146b2b353ab3fec9af0070237b6ddae78452af83d2fca84d739e675"}, +] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, ] fonttools = [ - {file = "fonttools-4.32.0-py3-none-any.whl", hash = "sha256:b038d1a0dee0079de7ade57071e2e2aced6e35bd697de244ac62938b2b1628c1"}, - {file = "fonttools-4.32.0.zip", hash = "sha256:59a90de72149893167e3d552ae2402c6874e006b9adc3feaf5f6d706fe20d392"}, + {file = "fonttools-4.33.0-py3-none-any.whl", hash = "sha256:14b94aab22439b9bd46c8f44b057b1d2f4b7ebe86556f9b15a1b25694bb12519"}, + {file = "fonttools-4.33.0.zip", hash = "sha256:65d14ab1fe70cbd2f18fca538d98bd45d73e9b065defb843da71dc3c454deb45"}, ] idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, @@ -449,6 +642,10 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +isort = [ + {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, + {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, +] kiwisolver = [ {file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e395ece147f0692ca7cdb05a028d31b83b72c369f7b4a2c1798f4b96af1e3d8"}, {file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b7f50a1a25361da3440f07c58cd1d79957c2244209e4f166990e770256b6b0b"}, @@ -494,6 +691,45 @@ kiwisolver = [ {file = "kiwisolver-1.4.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42f6ef9b640deb6f7d438e0a371aedd8bef6ddfde30683491b2e6f568b4e884e"}, {file = "kiwisolver-1.4.2.tar.gz", hash = "sha256:7f606d91b8a8816be476513a77fd30abe66227039bd6f8b406c348cb0247dcc9"}, ] +lazy-object-proxy = [ + {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, + {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, +] matplotlib = [ {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:456cc8334f6d1124e8ff856b42d2cc1c84335375a16448189999496549f7182b"}, {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8a77906dc2ef9b67407cec0bdbf08e3971141e535db888974a915be5e1e3efc6"}, @@ -531,6 +767,14 @@ matplotlib = [ {file = "matplotlib-3.5.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14334b9902ec776461c4b8c6516e26b450f7ebe0b3ef8703bf5cdfbbaecf774a"}, {file = "matplotlib-3.5.1.tar.gz", hash = "sha256:b2e9810e09c3a47b73ce9cab5a72243a1258f61e7900969097a817232246ce1c"}, ] +mccabe = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] numpy = [ {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, @@ -591,6 +835,10 @@ pandas = [ {file = "pandas-1.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:edda9bacc3843dfbeebaf7a701763e68e741b08fccb889c003b0a52f0ee95782"}, {file = "pandas-1.1.5.tar.gz", hash = "sha256:f10fc41ee3c75a474d3bdf68d396f10782d013d7f67db99c0efbfd0acb99701b"}, ] +pathspec = [ + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] pillow = [ {file = "Pillow-9.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea"}, {file = "Pillow-9.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652"}, @@ -631,6 +879,10 @@ pillow = [ {file = "Pillow-9.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458"}, {file = "Pillow-9.1.0.tar.gz", hash = "sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97"}, ] +platformdirs = [ + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, +] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, @@ -639,6 +891,10 @@ py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] +pylint = [ + {file = "pylint-2.13.7-py3-none-any.whl", hash = "sha256:13ddbbd8872c804574149e81197c28877eba75224ba6b76cd8652fc31df55c1c"}, + {file = "pylint-2.13.7.tar.gz", hash = "sha256:911d3a97c808f7554643bcc5416028cfdc42eae34ed129b150741888c688d5d5"}, +] pyparsing = [ {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, @@ -700,6 +956,32 @@ tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +typed-ast = [ + {file = "typed_ast-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ad3b48cf2b487be140072fb86feff36801487d4abb7382bb1929aaac80638ea"}, + {file = "typed_ast-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:542cd732351ba8235f20faa0fc7398946fe1a57f2cdb289e5497e1e7f48cfedb"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc2c11ae59003d4a26dda637222d9ae924387f96acae9492df663843aefad55"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd5df1313915dbd70eaaa88c19030b441742e8b05e6103c631c83b75e0435ccc"}, + {file = "typed_ast-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:e34f9b9e61333ecb0f7d79c21c28aa5cd63bec15cb7e1310d7d3da6ce886bc9b"}, + {file = "typed_ast-1.5.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f818c5b81966d4728fec14caa338e30a70dfc3da577984d38f97816c4b3071ec"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3042bfc9ca118712c9809201f55355479cfcdc17449f9f8db5e744e9625c6805"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fff9fdcce59dc61ec1b317bdb319f8f4e6b69ebbe61193ae0a60c5f9333dc49"}, + {file = "typed_ast-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8e0b8528838ffd426fea8d18bde4c73bcb4167218998cc8b9ee0a0f2bfe678a6"}, + {file = "typed_ast-1.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ef1d96ad05a291f5c36895d86d1375c0ee70595b90f6bb5f5fdbee749b146db"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed44e81517364cb5ba367e4f68fca01fba42a7a4690d40c07886586ac267d9b9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f60d9de0d087454c91b3999a296d0c4558c1666771e3460621875021bf899af9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9e237e74fd321a55c90eee9bc5d44be976979ad38a29bbd734148295c1ce7617"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee852185964744987609b40aee1d2eb81502ae63ee8eef614558f96a56c1902d"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27e46cdd01d6c3a0dd8f728b6a938a6751f7bd324817501c15fb056307f918c6"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d64dabc6336ddc10373922a146fa2256043b3b43e61f28961caec2a5207c56d5"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8cdf91b0c466a6c43f36c1964772918a2c04cfa83df8001ff32a89e357f8eb06"}, + {file = "typed_ast-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:9cc9e1457e1feb06b075c8ef8aeb046a28ec351b1958b42c7c31c989c841403a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e20d196815eeffb3d76b75223e8ffed124e65ee62097e4e73afb5fec6b993e7a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:37e5349d1d5de2f4763d534ccb26809d1c24b180a477659a12c4bde9dd677d74"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f1a27592fac87daa4e3f16538713d705599b0a27dfe25518b80b6b017f0a6d"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8831479695eadc8b5ffed06fdfb3e424adc37962a75925668deeb503f446c0a3"}, + {file = "typed_ast-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:20d5118e494478ef2d3a2702d964dae830aedd7b4d3b626d003eea526be18718"}, + {file = "typed_ast-1.5.3.tar.gz", hash = "sha256:27f25232e2dd0edfe1f019d6bfaaf11e86e657d9bdb7b0956db95f560cceb2b3"}, +] typing-extensions = [ {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, @@ -708,6 +990,72 @@ urllib3 = [ {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] +wrapt = [ + {file = "wrapt-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:5a9a1889cc01ed2ed5f34574c90745fab1dd06ec2eee663e8ebeefe363e8efd7"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9a3ff5fb015f6feb78340143584d9f8a0b91b6293d6b5cf4295b3e95d179b88c"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4b847029e2d5e11fd536c9ac3136ddc3f54bc9488a75ef7d040a3900406a91eb"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:9a5a544861b21e0e7575b6023adebe7a8c6321127bb1d238eb40d99803a0e8bd"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:88236b90dda77f0394f878324cfbae05ae6fde8a84d548cfe73a75278d760291"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f0408e2dbad9e82b4c960274214af533f856a199c9274bd4aff55d4634dedc33"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9d8c68c4145041b4eeae96239802cfdfd9ef927754a5be3f50505f09f309d8c6"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:22626dca56fd7f55a0733e604f1027277eb0f4f3d95ff28f15d27ac25a45f71b"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:65bf3eb34721bf18b5a021a1ad7aa05947a1767d1aa272b725728014475ea7d5"}, + {file = "wrapt-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09d16ae7a13cff43660155383a2372b4aa09109c7127aa3f24c3cf99b891c330"}, + {file = "wrapt-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:debaf04f813ada978d7d16c7dfa16f3c9c2ec9adf4656efdc4defdf841fc2f0c"}, + {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748df39ed634851350efa87690c2237a678ed794fe9ede3f0d79f071ee042561"}, + {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1807054aa7b61ad8d8103b3b30c9764de2e9d0c0978e9d3fc337e4e74bf25faa"}, + {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763a73ab377390e2af26042f685a26787c402390f682443727b847e9496e4a2a"}, + {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8529b07b49b2d89d6917cfa157d3ea1dfb4d319d51e23030664a827fe5fd2131"}, + {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:68aeefac31c1f73949662ba8affaf9950b9938b712fb9d428fa2a07e40ee57f8"}, + {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59d7d92cee84a547d91267f0fea381c363121d70fe90b12cd88241bd9b0e1763"}, + {file = "wrapt-1.14.0-cp310-cp310-win32.whl", hash = "sha256:3a88254881e8a8c4784ecc9cb2249ff757fd94b911d5df9a5984961b96113fff"}, + {file = "wrapt-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a242871b3d8eecc56d350e5e03ea1854de47b17f040446da0e47dc3e0b9ad4d"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a65bffd24409454b889af33b6c49d0d9bcd1a219b972fba975ac935f17bdf627"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9d9fcd06c952efa4b6b95f3d788a819b7f33d11bea377be6b8980c95e7d10775"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:db6a0ddc1282ceb9032e41853e659c9b638789be38e5b8ad7498caac00231c23"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:14e7e2c5f5fca67e9a6d5f753d21f138398cad2b1159913ec9e9a67745f09ba3"}, + {file = "wrapt-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:6d9810d4f697d58fd66039ab959e6d37e63ab377008ef1d63904df25956c7db0"}, + {file = "wrapt-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:d808a5a5411982a09fef6b49aac62986274ab050e9d3e9817ad65b2791ed1425"}, + {file = "wrapt-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b77159d9862374da213f741af0c361720200ab7ad21b9f12556e0eb95912cd48"}, + {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36a76a7527df8583112b24adc01748cd51a2d14e905b337a6fefa8b96fc708fb"}, + {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0057b5435a65b933cbf5d859cd4956624df37b8bf0917c71756e4b3d9958b9e"}, + {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0a4ca02752ced5f37498827e49c414d694ad7cf451ee850e3ff160f2bee9d3"}, + {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8c6be72eac3c14baa473620e04f74186c5d8f45d80f8f2b4eda6e1d18af808e8"}, + {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:21b1106bff6ece8cb203ef45b4f5778d7226c941c83aaaa1e1f0f4f32cc148cd"}, + {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:493da1f8b1bb8a623c16552fb4a1e164c0200447eb83d3f68b44315ead3f9036"}, + {file = "wrapt-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:89ba3d548ee1e6291a20f3c7380c92f71e358ce8b9e48161401e087e0bc740f8"}, + {file = "wrapt-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:729d5e96566f44fccac6c4447ec2332636b4fe273f03da128fff8d5559782b06"}, + {file = "wrapt-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:891c353e95bb11abb548ca95c8b98050f3620a7378332eb90d6acdef35b401d4"}, + {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23f96134a3aa24cc50614920cc087e22f87439053d886e474638c68c8d15dc80"}, + {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6807bcee549a8cb2f38f73f469703a1d8d5d990815c3004f21ddb68a567385ce"}, + {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6915682f9a9bc4cf2908e83caf5895a685da1fbd20b6d485dafb8e218a338279"}, + {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f2f3bc7cd9c9fcd39143f11342eb5963317bd54ecc98e3650ca22704b69d9653"}, + {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3a71dbd792cc7a3d772ef8cd08d3048593f13d6f40a11f3427c000cf0a5b36a0"}, + {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5a0898a640559dec00f3614ffb11d97a2666ee9a2a6bad1259c9facd01a1d4d9"}, + {file = "wrapt-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:167e4793dc987f77fd476862d32fa404d42b71f6a85d3b38cbce711dba5e6b68"}, + {file = "wrapt-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d066ffc5ed0be00cd0352c95800a519cf9e4b5dd34a028d301bdc7177c72daf3"}, + {file = "wrapt-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d9bdfa74d369256e4218000a629978590fd7cb6cf6893251dad13d051090436d"}, + {file = "wrapt-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2498762814dd7dd2a1d0248eda2afbc3dd9c11537bc8200a4b21789b6df6cd38"}, + {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f24ca7953f2643d59a9c87d6e272d8adddd4a53bb62b9208f36db408d7aafc7"}, + {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b835b86bd5a1bdbe257d610eecab07bf685b1af2a7563093e0e69180c1d4af1"}, + {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b21650fa6907e523869e0396c5bd591cc326e5c1dd594dcdccac089561cacfb8"}, + {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:354d9fc6b1e44750e2a67b4b108841f5f5ea08853453ecbf44c81fdc2e0d50bd"}, + {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f83e9c21cd5275991076b2ba1cd35418af3504667affb4745b48937e214bafe"}, + {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61e1a064906ccba038aa3c4a5a82f6199749efbbb3cef0804ae5c37f550eded0"}, + {file = "wrapt-1.14.0-cp38-cp38-win32.whl", hash = "sha256:28c659878f684365d53cf59dc9a1929ea2eecd7ac65da762be8b1ba193f7e84f"}, + {file = "wrapt-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:b0ed6ad6c9640671689c2dbe6244680fe8b897c08fd1fab2228429b66c518e5e"}, + {file = "wrapt-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3f7e671fb19734c872566e57ce7fc235fa953d7c181bb4ef138e17d607dc8a1"}, + {file = "wrapt-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87fa943e8bbe40c8c1ba4086971a6fefbf75e9991217c55ed1bcb2f1985bd3d4"}, + {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4775a574e9d84e0212f5b18886cace049a42e13e12009bb0491562a48bb2b758"}, + {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d57677238a0c5411c76097b8b93bdebb02eb845814c90f0b01727527a179e4d"}, + {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00108411e0f34c52ce16f81f1d308a571df7784932cc7491d1e94be2ee93374b"}, + {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d332eecf307fca852d02b63f35a7872de32d5ba8b4ec32da82f45df986b39ff6"}, + {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:01f799def9b96a8ec1ef6b9c1bbaf2bbc859b87545efbecc4a78faea13d0e3a0"}, + {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47045ed35481e857918ae78b54891fac0c1d197f22c95778e66302668309336c"}, + {file = "wrapt-1.14.0-cp39-cp39-win32.whl", hash = "sha256:2eca15d6b947cfff51ed76b2d60fd172c6ecd418ddab1c5126032d27f74bc350"}, + {file = "wrapt-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:bb36fbb48b22985d13a6b496ea5fb9bb2a076fea943831643836c9f6febbcfdc"}, + {file = "wrapt-1.14.0.tar.gz", hash = "sha256:8323a43bd9c91f62bb7d4be74cc9ff10090e7ef820e27bfe8815c57e68261311"}, +] zipp = [ {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, diff --git a/pylintrc b/pylintrc new file mode 100644 index 00000000..3253109f --- /dev/null +++ b/pylintrc @@ -0,0 +1,564 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Files or directories to be skipped. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the ignore-list. The +# regex matches against paths and can be in Posix or Windows format. +ignore-paths= + +# Files or directories matching the regex patterns are skipped. The regex +# matches against base names, not paths. +ignore-patterns=^\.# + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + pylint.extensions.check_elif, + pylint.extensions.bad_builtin, + pylint.extensions.docparams, + pylint.extensions.for_any_all, + pylint.extensions.set_membership, + pylint.extensions.code_style, + pylint.extensions.overlapping_exceptions, + pylint.extensions.typing, + pylint.extensions.redefined_variable_type, + pylint.extensions.comparison_placement, + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=1 + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-allow-list= + +# Minimum supported python version +py-version = 3.7.2 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# Specify a score threshold to be exceeded before program exits with error. +fail-under=10.0 + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +# confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable= + use-symbolic-message-instead, + useless-suppression, + fixme + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then re-enable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" + +disable= + attribute-defined-outside-init, + duplicate-code, + invalid-name, + missing-docstring, + protected-access, + too-few-public-methods, + # handled by black + format, + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables 'fatal', 'error', 'warning', 'refactor', 'convention' +# and 'info', which contain the number of messages in each category, as +# well as 'statement', which is the total number of statements analyzed. This +# score is used by the global evaluation report (RP0004). +evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Activate the evaluation score. +score=yes + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + +# Regular expression of note tags to take in consideration. +#notes-rgx= + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Signatures are removed from the similarity computation +ignore-signatures=no + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of names allowed to shadow builtins +allowed-redefined-builtins= + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.* + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Maximum number of lines in a module +max-module-lines=2000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[BASIC] + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,}$ + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. +#class-const-rgx= + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,}$ + +# Regular expression which can overwrite the naming style set by typevar-naming-style. +#typevar-rgx= + +# Regular expression which should only match function or class names that do +# not require a docstring. Use ^(?!__init__$)_ to also check __init__. +no-docstring-rgx=__.*__ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# List of decorators that define properties, such as abc.abstractproperty. +property-classes=abc.abstractproperty + + +[TYPECHECK] + +# Regex pattern to define which classes are considered mixins if ignore-mixin- +# members is set to 'yes' +mixin-class-rgx=.*MixIn + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=SQLObject, optparse.Values, thread._local, _thread._local + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent,argparse.Namespace + +# List of decorators that create context managers from functions, such as +# contextlib.contextmanager. +contextmanager-decorators=contextlib.contextmanager + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# List of comma separated words that should be considered directives if they +# appear and the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=10 + +# Maximum number of locals for function / method body +max-locals=25 + +# Maximum number of return / yield for function / method body +max-returns=11 + +# Maximum number of branch for function / method body +max-branches=27 + +# Maximum number of statements in function / method body +max-statements=100 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# List of qualified class names to ignore when counting class parents (see R0901). +ignored-parents= + +# Maximum number of attributes for a class (see R0902). +max-attributes=11 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=25 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# List of regular expressions of class ancestor names to +# ignore when counting public methods (see R0903). +exclude-too-few-public-methods= + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp,__post_init__ + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception + + +[TYPING] + +# Set to ``no`` if the app / library does **NOT** need to support runtime +# introspection of type annotations. If you use type annotations +# **exclusively** for type checking of an application, you're probably fine. +# For libraries, evaluate if some users what to access the type hints at +# runtime first, e.g., through ``typing.get_type_hints``. Applies to Python +# versions 3.7 - 3.9 +runtime-typing = no + + +[DEPRECATED_BUILTINS] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,input + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. +check-str-concat-over-line-jumps=no + + +[CODE_STYLE] + +# Max line length for which to sill emit suggestions. Used to prevent optional +# suggestions which would get split by a code formatter (e.g., black). Will +# default to the setting for ``max-line-length``. +#max-line-length-suggestions= diff --git a/pyproject.toml b/pyproject.toml index f9c849b5..96469450 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,12 +14,18 @@ matplotlib = "^3.3.4" requests = "^2.8.1" pytest = {version = "^7.1.1", optional = true} pytest-xdist = {version = "^2.5.0", optional = true} +pylint = {version = "^2.13.7", optional = true} +black = {version = "^22.3.0", optional = true} [tool.poetry.extras] -dev = ["pytest", "pytest-xdist"] +dev = ["pytest", "pytest-xdist", "pylint", "black"] # Do NOT use [tool.poetry.dev-dependencies]. See: https://github.com/python-poetry/poetry/issues/3514 +[tool.black] +line-length = 80 +target-version = ['py37'] + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/tests/__init__.py b/tests/__init__.py index 65ad25c1..b280897f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -8,7 +8,7 @@ def setup_module(): # Raise exceptions for arithmetic errors, except underflow global _np_error_state _np_error_state = np.seterr() - np.seterr('raise', under='ignore') + np.seterr("raise", under="ignore") def teardown_module(): diff --git a/tests/test_annotation.py b/tests/test_annotation.py index c7d0f4d3..d4b2bcb1 100644 --- a/tests/test_annotation.py +++ b/tests/test_annotation.py @@ -21,60 +21,76 @@ def test_1(self): Target file created with: rdann -r sample-data/100 -a atr > ann-1 """ - annotation = wfdb.rdann('sample-data/100', 'atr') - + annotation = wfdb.rdann("sample-data/100", "atr") # This is not the fault of the script. The annotation file specifies a # length 3 - annotation.aux_note[0] = '(N' + annotation.aux_note[0] = "(N" # aux_note field with a null written after '(N' which the script correctly picks up. I am just # getting rid of the null in this unit test to compare with the regexp output below which has # no null to detect in the output text file of rdann. # Target data from WFDB software package - lines = tuple(open('tests/target-output/ann-1', 'r')) + lines = tuple(open("tests/target-output/ann-1", "r")) nannot = len(lines) target_time = [None] * nannot - target_sample = np.empty(nannot, dtype='object') + target_sample = np.empty(nannot, dtype="object") target_symbol = [None] * nannot - target_subtype = np.empty(nannot, dtype='object') - target_chan = np.empty(nannot, dtype='object') - target_num = np.empty(nannot, dtype='object') + target_subtype = np.empty(nannot, dtype="object") + target_chan = np.empty(nannot, dtype="object") + target_num = np.empty(nannot, dtype="object") target_aux_note = [None] * nannot RXannot = re.compile( - '[ \t]*(?P