From fc17ba7b6a5d59fee842fe1d0ebf10a5d1e5561e Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Sun, 13 Dec 2015 13:14:42 -0800 Subject: [PATCH 01/39] made gh-pages build script more robust --- Sources/build_gh_pages.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/build_gh_pages.sh b/Sources/build_gh_pages.sh index f8b947e..a89ad22 100755 --- a/Sources/build_gh_pages.sh +++ b/Sources/build_gh_pages.sh @@ -12,5 +12,6 @@ cp -R build/html/ ../../PythonTopics_gh_pages/ cd ../../PythonTopics_gh_pages git checkout gh-pages git add * # in case there are new files added -git commit -a +git commit -a -m "updating published version" +git pull -s ours --no-edit git push From d92e51c2b823d308a6df3478888a183e003ec5e1 Mon Sep 17 00:00:00 2001 From: "Christopher H.Barker, PhD" Date: Mon, 15 Jan 2018 19:38:33 -0800 Subject: [PATCH 02/39] tiny bit of editing --- Sources/source/where_to_put_tests.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/source/where_to_put_tests.rst b/Sources/source/where_to_put_tests.rst index fa68372..6778a9e 100644 --- a/Sources/source/where_to_put_tests.rst +++ b/Sources/source/where_to_put_tests.rst @@ -1,6 +1,6 @@ -******************** -where to put tests? -******************** +******************* +Where to Put Tests? +******************* ====== TL; DR @@ -18,7 +18,7 @@ Test system recommendations https://pytest.org/latest/goodpractises.html -I need to add links for ``nose`` and ``unittest``.... +I need to add links for ``nose`` and ``unittest``.... PR's accepted! Two Options From e5cc3817353c2b0e17c47c03d4153bda98546782 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Sat, 31 Mar 2018 23:03:11 -0700 Subject: [PATCH 03/39] added Automatic Gain control example --- .../interfacing_with_c/agc_example/agc_c.c | 31 +++ .../agc_example/agc_c_cy.pyx | 22 ++ .../agc_example/agc_cython.pyx | 80 +++++++ .../agc_example/agc_program.f | 95 ++++++++ .../agc_example/agc_python.py | 45 ++++ .../agc_example/agc_subroutine.f | 31 +++ .../agc_example/agc_subroutine.pyf | 16 ++ .../agc_example/plot_agc.py | 49 ++++ .../interfacing_with_c/agc_example/setup.py | 24 ++ .../agc_example/test_agc.py | 72 ++++++ .../source/interfacing_with_c/c_python.rst | 55 +++++ .../interfacing_with_c/fortran_python.rst | 213 ++++++++++++++++++ 12 files changed, 733 insertions(+) create mode 100644 Sources/source/interfacing_with_c/agc_example/agc_c.c create mode 100644 Sources/source/interfacing_with_c/agc_example/agc_c_cy.pyx create mode 100644 Sources/source/interfacing_with_c/agc_example/agc_cython.pyx create mode 100644 Sources/source/interfacing_with_c/agc_example/agc_program.f create mode 100644 Sources/source/interfacing_with_c/agc_example/agc_python.py create mode 100644 Sources/source/interfacing_with_c/agc_example/agc_subroutine.f create mode 100644 Sources/source/interfacing_with_c/agc_example/agc_subroutine.pyf create mode 100644 Sources/source/interfacing_with_c/agc_example/plot_agc.py create mode 100755 Sources/source/interfacing_with_c/agc_example/setup.py create mode 100644 Sources/source/interfacing_with_c/agc_example/test_agc.py create mode 100644 Sources/source/interfacing_with_c/c_python.rst create mode 100644 Sources/source/interfacing_with_c/fortran_python.rst diff --git a/Sources/source/interfacing_with_c/agc_example/agc_c.c b/Sources/source/interfacing_with_c/agc_example/agc_c.c new file mode 100644 index 0000000..a655671 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/agc_c.c @@ -0,0 +1,31 @@ +/* C version of AGC code */ + +#include + +void AGC(int nAGC, int npts, float *amp, float *ampAGC); + +void AGC(int nAGC, int npts, float *amp, float *ampAGC) { + + float fmax; + float absamp[npts]; + int i, j, nAGC2; + + + for (i = 0; i < npts; i++){ + ampAGC[i] = 0.0; + absamp[i] = fabs(amp[i]); + } + nAGC2 = nAGC / 2; + + for (i = nAGC2; i < npts-nAGC2; i++){ + fmax = 0.0; + for ( j=(i-nAGC2); j < i+nAGC2+1; j++ ){ + if ( absamp[j] > fmax ) { + fmax = absamp[j]; + } + } + ampAGC[i] = amp[i] / fmax; + } + return; + } + diff --git a/Sources/source/interfacing_with_c/agc_example/agc_c_cy.pyx b/Sources/source/interfacing_with_c/agc_example/agc_c_cy.pyx new file mode 100644 index 0000000..dc1f720 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/agc_c_cy.pyx @@ -0,0 +1,22 @@ +""" +Cython file to call the C routine +""" + +import numpy as np +cimport numpy as cnp + +cdef extern: + void AGC(int nAGC, int npts, float *amp, float *ampAGC) + + +def agc (int nAGC, float[:] amp): + + # create the output array + cdef cnp.ndarray[float, ndim=1] ampAGC = np.zeros_like(amp) + + npts = amp.shape[0] + + # call the C function + AGC(nAGC, npts, &[0], &AGC[0]) + + return ampAGC diff --git a/Sources/source/interfacing_with_c/agc_example/agc_cython.pyx b/Sources/source/interfacing_with_c/agc_example/agc_cython.pyx new file mode 100644 index 0000000..2495e8e --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/agc_cython.pyx @@ -0,0 +1,80 @@ +#!/usr/bin/env python + +""" +cython version version of the Automatic Gain Control function + +Timings: + first version (pure python): + +In [23]: timeit agc_cython.agc(10, np.arange(1000, dtype=np.float32)) +100 loops, best of 3: 10.7 ms per loop + +typing inputs: + +100 loops, best of 3: 17.3 ms per loop + +Typing counters and memoryviews of arrays +1000 loops, best of 3: 1.68 ms per loop + +typing loop counters +1000 loops, best of 3: 613 us per loop + +forgot to type fmax: +10000 loops, best of 3: 119 us per loop + +added boundscheck=False +10000 loops, best of 3: 117 us per loop + +use memoryviews of cython arrays +10000 loops, best of 3: 39.4 us per loop + +use cython arrays: +100 loops, best of 3: 6.12 ms per loop + +c array for temp array: +100 loops, best of 3: 6.34 ms per loop + +""" + +import cython +import numpy as np +cimport numpy as cnp + +#from libc.stdlib cimport malloc, free + +@cython.boundscheck(False) +@cython.cdivision(True) +def agc( int nAGC, cnp.ndarray[float, ndim=1, mode='c'] amp): + """ + run an automatic gain control filter onver the input array + + :param nAGC: width of window, number of elements. + :type nAGC: integer + + :param amp: input amplitude data + :type amp: 1-d numpy array of float32 + + :returns ampAGC: a numpy array of the filtered data. + + """ + + cdef float fmax + cdef unsigned int i, j + + cdef unsigned int npts = amp.shape[0] + + cdef unsigned int nAGC2 = nAGC / 2 + + cdef cnp.ndarray[float, ndim=1, mode='c'] ampAGC = np.zeros_like(amp) + cdef cnp.ndarray[float, ndim=1, mode='c'] absamp = np.abs(amp) + + + for i in range(nAGC2, npts - nAGC2): + fmax=0.0 + for j in range(i-nAGC2,i+nAGC2+1): + if absamp[j] > fmax: + fmax = absamp[j] + ampAGC[i] = amp[i]/fmax + + return ampAGC + diff --git a/Sources/source/interfacing_with_c/agc_example/agc_program.f b/Sources/source/interfacing_with_c/agc_example/agc_program.f new file mode 100644 index 0000000..2a01c65 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/agc_program.f @@ -0,0 +1,95 @@ +c +c Program to read in a time series, AGC it, dump out a new time series. +c +c +c +c +c23456789012345678901234567890123456789012345678901234567890123456789012 + + parameter(npts0=1000000) + character*180 infile,outfile + real amp(npts0),ampAGC(npts0),ampAGC2(npts0),absamp(npts0) + + print *,'Enter input timeseries' + read (*,'(a)') infile + + print *,'Enter output filename ' + read (*,'(a)') outfile + + print *,'Enter npts length of AGC window' + read *,nAGC + + nAGC2=nAGC/2 + nrepeat=20 + +c--------- read in file & zero out the ampAGC array + + open(4,file=infile) + do i=1,npts0 + read(4,*,end=201) amp(i) + ampAGC(i)=0. + ampAGC2(i)=0. + absamp(i)=abs(amp(i)) + enddo +201 close(4) + npts=i-1 + +c-------- less code, simpler, waaay slower + + call system_clock(count_rate=icr) + call system_clock (i1) + do irepeat=1,nrepeat !----- loop over it many times, just for timing purposes + + do i=nAGC2+1,npts-nAGC2 + fmax=0. + do j=i-nAGC2,i+nAGC2 + if (absamp(j).gt.fmax) fmax=absamp(j) + enddo + ampAGC(i)=amp(i)/fmax + enddo + + enddo !----- do irepeat=1,nrepeat + call system_clock (i2) + print *, 'Slow time= ', real(i2-i1)/icr + +c--------- Automatic Gain Control +c Only 'rescan' the window for a max if the previous window's +c max came from the very first point in it's window. + + call system_clock(count_rate=icr) + call system_clock (i1) + do irepeat=1,nrepeat + + fmax=0. + do i=1,nAGC + if (absamp(i).gt.fmax) fmax=absamp(i) + enddo + ampAGC2(nAGC2+1)=amp(nAGC2+1)/fmax + do i=nAGC2+2,npts-nAGC2 + j0=i-nAGC2-1 + j1=i-nAGC2 + j2=i+nAGC2 + fmax=max(fmax,absamp(j2)) + if (absamp(j0).eq.fmax) then + fmax=0. + do j=j1,j2 + if (absamp(j).gt.fmax) fmax=absamp(j) + enddo + endif + ampAGC2(i)=amp(i)/fmax + enddo + + enddo !----- do irepeat=1,nrepeat + call system_clock (i2) + print *, 'Fast time= ', real(i2-i1)/icr + +c--------- write output + + open(4,file=outfile) + do i=1,npts + write(4,*) i,amp(i),ampAGC(i),ampAGC2(i) + enddo + close(4) + + end + diff --git a/Sources/source/interfacing_with_c/agc_example/agc_python.py b/Sources/source/interfacing_with_c/agc_example/agc_python.py new file mode 100644 index 0000000..df506f6 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/agc_python.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +""" +Pure python (and not bery numpy smart) version of the Automatic Gain Control function +""" + +import numpy as np + +def agc(nAGC, amp): + """ + run an automatic gain control filter onver the input array + + :param nAGC: width of window, number of elements. + :type nAGC: integer + + :param amp: input amplitude data + :type amp: 1-d numpy array of float32 + + :returns ampAGC: a numpy array of the filtered data. + + """ + + #make sure input array is as expected: + amp = np.asarray(amp, dtype=np.float32) + if len(amp.shape) != 1: + raise ValueError("amp must be a rank-1 array") + + npts = amp.shape[0] + + nAGC2=nAGC/2 + ampAGC = np.zeros_like(amp) + absamp = np.zeros_like(amp) + + absamp = np.abs(amp) + + + for i in xrange(nAGC2, npts - nAGC2): + fmax=0.0 + for j in range(i-nAGC2,i+nAGC2+1): + if absamp[j] > fmax: + fmax = absamp[j] + ampAGC[i] = amp[i]/fmax + + return ampAGC + diff --git a/Sources/source/interfacing_with_c/agc_example/agc_subroutine.f b/Sources/source/interfacing_with_c/agc_example/agc_subroutine.f new file mode 100644 index 0000000..365f2e2 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/agc_subroutine.f @@ -0,0 +1,31 @@ +c +c Subrooutine to compute an automatic gain control filter. +c +c + subroutine AGC(nAGC,npts,amp,ampAGC) + +CF2PY INTENT(OUT) :: ampAGC +CF2PY INTENT(HIDE) :: npts + + real fmax,amp(npts),absamp(npts),ampAGC(npts) + integer i,j,npts,nAGC,nAGC2 + + do i=1,npts + ampAGC(i)=0. + absamp(i)=abs(amp(i)) + enddo + + nAGC2=nAGC/2 + + do i=nAGC2+1,npts-nAGC2 + fmax=0. + do j=i-nAGC2,i+nAGC2 + if (absamp(j).gt.fmax) fmax=absamp(j) + enddo + ampAGC(i)=amp(i)/fmax + enddo + + return + + end + diff --git a/Sources/source/interfacing_with_c/agc_example/agc_subroutine.pyf b/Sources/source/interfacing_with_c/agc_example/agc_subroutine.pyf new file mode 100644 index 0000000..53dfa82 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/agc_subroutine.pyf @@ -0,0 +1,16 @@ +! -*- f90 -*- +! Note: the context of this file is case sensitive. + +python module agc_subroutine ! in + interface ! in :agc_subroutine + subroutine agc(nagc,npts,amp,ampagc) ! in :agc_subroutine:agc_subroutine.f + integer :: nagc + integer, optional,intent(hide),check(len(amp)>=npts),depend(amp) :: npts=len(amp) + real dimension(npts) :: amp + real dimension(npts),intent(out),depend(npts) :: ampagc + end subroutine agc + end interface +end python module agc_subroutine + +! This file was auto-generated with f2py (version:2). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/Sources/source/interfacing_with_c/agc_example/plot_agc.py b/Sources/source/interfacing_with_c/agc_example/plot_agc.py new file mode 100644 index 0000000..76738f8 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/plot_agc.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +test code for the "agc_subroutine" extension, generated from fortran by f2py +""" +import numpy as np +import matplotlib.pyplot as plt + +import agc_subroutine +import agc_python + +print "the doctring for agc:" +print agc_subroutine.agc.__doc__ + +# to call it: +# create a noisy array: + +t = np.linspace(0,20,100).astype(np.float32) + +signal = np.sin(t) + +# add some noise +signal += (np.random.random(signal.shape)-0.5) * 0.3 + +# create an array for the result: +#filtered = np.zeros_like(signal) + +# run it through the AGC filter: +filtered = agc_subroutine.agc(10, signal) + +# try the python version +filtered2 = agc_python.agc(10, signal) + +if np.allclose(filtered2, filtered2): + print "the same" +else: + print "not the same" + +## plot the results + +fig = plt.figure(figsize=(10,5)) +ax = fig.add_subplot(1,1,1) +ax.plot(t, signal, t, filtered, t, filtered2) + +plt.show() + + + + diff --git a/Sources/source/interfacing_with_c/agc_example/setup.py b/Sources/source/interfacing_with_c/agc_example/setup.py new file mode 100755 index 0000000..e7c248f --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/setup.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +from distutils.core import setup +from Cython.Build import cythonize +from distutils.extension import Extension + +import numpy + +cy = Extension("agc_cython", + ["agc_cython.pyx",], + include_dirs = [numpy.get_include(),], + ) +c_wrap = Extension("agc_c_cy", + ["agc_c_cy.pyx", "agc_c.c"], + include_dirs = [numpy.get_include(),], + ) + +setup( + # ext_modules = [cythonize("agc_cython.pyx"), + # cythonize([c_wrap]), + # ] + ext_modules = cythonize( [cy, c_wrap] ), +) + diff --git a/Sources/source/interfacing_with_c/agc_example/test_agc.py b/Sources/source/interfacing_with_c/agc_example/test_agc.py new file mode 100644 index 0000000..7a1cf42 --- /dev/null +++ b/Sources/source/interfacing_with_c/agc_example/test_agc.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +""" +test code for various AGC modules + +designed to be run with py.test or nose + +some timing code to cut&paste into iPython: + +import numpy as np +import agc_cython +import agc_python +import agc_subroutine +import agc_c_cy + +timeit agc_cython.agc(10, np.arange(1000, dtype=np.float32)) + +timeit agc_python.agc(10, np.arange(1000, dtype=np.float32)) + +timeit agc_subroutine.agc(10, np.arange(1000, dtype=np.float32)) + +timeit agc_c_cy.agc(10, np.arange(1000, dtype=np.float32)) + +""" + +import numpy as np + +import agc_cython +import agc_python +import agc_c_cy +import agc_subroutine + +def test_cython(): + # just make sure it runs. + signal = np.arange(20, dtype=np.float32) + + result = agc_cython.agc(4, signal) + +def test_c_wrap(): + # just make sure it runs. + signal = np.arange(20, dtype=np.float32) + + result = agc_c_cy.agc(4, signal) + +def test_subroutine(): + # just make sure it runs. + signal = np.arange(20, dtype=np.float32) + + result = agc_subroutine.agc(4, signal) + + + + +def test_cy_py_same(): + signal = np.arange(20, dtype=np.float32) + + cy_result = agc_cython.agc(4, signal) + py_result = agc_python.agc(4, signal) + c_cy_result = agc_c_cy.agc(4, signal) + sub_result = agc_subroutine.agc(4, signal) + + print "cy:", cy_result + print "py:", py_result + print "c_cy", c_cy_result + print "subroutine", sub_result + + assert np.array_equal(cy_result, py_result) + assert np.array_equal(cy_result, c_cy_result) + assert np.array_equal(cy_result, sub_result) + + + diff --git a/Sources/source/interfacing_with_c/c_python.rst b/Sources/source/interfacing_with_c/c_python.rst new file mode 100644 index 0000000..bc01e93 --- /dev/null +++ b/Sources/source/interfacing_with_c/c_python.rst @@ -0,0 +1,55 @@ +Interfacing C and Python +################################ + +Sorry, not much here + +NOTE: this is all about the CPython interpreter -- not PyPy, IronPython, JPython, etc. + +Documentation: +================ + +Core docs for the C API: + + + + +Interfacing methods: +====================== + +There a bunch of ways to interface C and Python: + +Hand write against the C API: +------------------------------ + +The python interpeter exposes a full API to all teh pyton objects, etc. You can essentially do anything, but it's a lot of hand-work. + +And reference counting is really hard to get right! + +http://docs.python.org/2/c-api/ + +Cython: +------------------ + +Cython can be described as a "python-like language for writing python extensions" + +It can be used essentially to speed up Python, but also to Call Python from C + +(derived from Pyrex) + +XDress +........ + +ctypes +-------- + + +SWIG, SIP, ETC. +---------------- + +Auto wrapper generators. + + +EXAMPLE: +============ + +Same as the one for fortran: a automatic gain control filter. \ No newline at end of file diff --git a/Sources/source/interfacing_with_c/fortran_python.rst b/Sources/source/interfacing_with_c/fortran_python.rst new file mode 100644 index 0000000..df5cfa6 --- /dev/null +++ b/Sources/source/interfacing_with_c/fortran_python.rst @@ -0,0 +1,213 @@ +Interfacing Fortran and Python +################################ + +Documentation: +================ + +A nice reference for Python for Fortran programmers: + +http://fortran90.org/src/rosetta.html + + +Fortran best practices (including interfacing with Python) + +http://fortran90.org/src/best-practices.html + +http://fortran90.org/src/best-practices.html#interfacing-with-python + +Interfacing methods: +====================== + +There a a handful of ways to interface Fortran and Python: + +f2py: +----- + +http://docs.scipy.org/doc/numpy/user/c-info.python-as-glue.html#f2py + +Been around a long time, and maintained (at least a little) as part of the numpy project -- but more useful with older fortran -- not up to modern fortran standards. Perhaps the best option for interfacing with old-style fortran. + + +fwrap: +-------- + +http://fwrap.sourceforge.net/ + +Very promising, but its development has stalled out -- so probably not a good bet unless you want to actually work on it yourself. + + +Cython and iso_c_binding: +--------------------------- + +http://fortran90.org/src/best-practices.html#interfacing-with-python + +By using the iso_binding calls to extend a C interace to your fortran code, you can call it with Cython. And Cython is very useful for calling C, optimizing Python, and adding "thick" wrappers to either C or fortran. + + +An Example: +============ + +The following is an example of using Cython to call fortran from Python. + +The problem at hand is an automatic gain control function function, expressed in fortran as:: + + subroutine AGC(nAGC,npts,amp,ampAGC) + real fmax,amp(npts),absamp(npts),ampAGC(npts) + integer i,j,npts,nAGC,nAGC2 + + do i=1,npts + ampAGC(i)=0. + absamp(i)=abs(amp(i)) + enddo + + nAGC2=nAGC/2 + + do i=nAGC2+1,npts-nAGC2 + fmax=0. + do j=i-nAGC2,i+nAGC2 + if (absamp(j).gt.fmax) fmax=absamp(j) + enddo + ampAGC(i)=amp(i)/fmax + enddo + + return + + end + +f2py: +------- + +f2py is a command line utility that comes with numpy. You can build a default simple wrapper with the f2py command:: + + f2py -m agc_subroutine agc_subroutine.f + + +This will result in the file `agc_subroutinemodule.c`, which is hte c source for a python extension module. Or you can have f2py build the module itself all at once:: + + f2py -m -c agc_subroutine agc_subroutine.f + +This will generate a compiled python extension named agc_subroutine that can be imported in python as:: + + import agc_subroutine + +f2p automatically generates a docstring for the function it created:: + + agc - Function signature: + agc(nagc,amp,ampagc,[npts]) + Required arguments: + nagc : input int + amp : input rank-1 array('f') with bounds (npts) + ampagc : input rank-1 array('f') with bounds (npts) + Optional arguments: + npts := len(amp) input int + +So it can be called like so:: + + agc_subroutine.agc(5, signal, filtered) + +where `signal` and `filtered` are 1-d arrays of float32 values, both of the same length. + +Giving f2py extra information: +............................... + +f2py can build an interface to a fortran subroutine, but it can't do it all that well without some extra information. For instnce, note from the docstring that the argument `ampagc` is listed as an input argument, when it is really intended to be used for output. + +To get f2py to generate an interface file use the -h option:: + + f2py -h agc_subroutine.pyf -m agc_subroutine agc_subroutine.f + +This command leaves the file agc_subroutine.pyf in the current directory, which contains:: + + ! -*- f90 -*- + ! Note: the context of this file is case sensitive. + + python module agc_subroutine ! in + interface ! in :agc_subroutine + subroutine agc(nagc,npts,amp,ampagc) ! in :agc_subroutine:agc_subroutine.f + integer :: nagc + integer, optional,check(len(amp)>=npts),depend(amp) :: npts=len(amp) + real dimension(npts) :: amp + real dimension(npts),depend(npts) :: ampagc + end subroutine agc + end interface + end python module agc_subroutine + + ! This file was auto-generated with f2py (version:2). + ! See http://cens.ioc.ee/projects/f2py2e/ + +You can then add to the interface file by placing intent directives and checking code. This will clean up the interface quite a bit so that the Python module method is both easier to use and more robust. This is the edited version:: + + ! -*- f90 -*- + ! Note: the context of this file is case sensitive. + + python module agc_subroutine ! in + interface ! in :agc_subroutine + subroutine agc(nagc,npts,amp,ampagc) ! in :agc_subroutine:agc_subroutine.f + integer :: nagc + integer, optional,intent(hide),check(len(amp)>=npts),depend(amp) :: npts=len(amp) + real dimension(npts) :: amp + real dimension(npts),intent(out),depend(npts) :: ampagc + end subroutine agc + end interface + end python module agc_subroutine + + ! This file was auto-generated with f2py (version:2). + ! Then hand edited for a better interface. + ! See http://cens.ioc.ee/projects/f2py2e/ + + +The intent directive, intent(out) is used to tell f2py that ampagc is an output variable and should be created by the interface before being passed to the underlying code. The intent(hide) directive tells f2py to not allow the user to specify the variable, npts, but instead to get it from the size of amp. + +Inserting directives in the Fortran source +........................................... + +Directives can alternatively be inserted in the fortran source as special comments:: + + c + c Subrooutine to compute an automatic gain control filter. + c + c + subroutine AGC(nAGC,npts,amp,ampAGC) + + CF2PY INTENT(OUT) :: ampAGC + CF2PY INTENT(HIDE) :: npts + + real fmax,amp(npts),absamp(npts),ampAGC(npts) + integer i,j,npts,nAGC,nAGC2 + +This is probably an easier and clearer option if you maintaining the fortran source yourself. + +Either way, you get a nicer, more pythonic and safer interface:: + + agc - Function signature: + ampagc = agc(nagc,amp) + Required arguments: + nagc : input int + amp : input rank-1 array('f') with bounds (npts) + Return objects: + ampagc : rank-1 array('f') with bounds (npts) + +called like so:: + + filtered = agc_subroutine.agc(10, signal) + +You can see that you don't need (and can't) specify the length of the array, and the output array is automatically created by the wrappers, and memory-managed by python. + + + + + + + + + + + + + + + + + + + From f234a24ff6be4be1ecfe36045be8fdffeb546c9b Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 11 Jul 2018 23:33:59 -0500 Subject: [PATCH 04/39] cleaned it up a bit --- Sources/source/conf.py | 4 +- .../source/interfacing_with_c/c_python.rst | 30 ++++++------- .../interfacing_with_c/fortran_python.rst | 10 ++--- Sources/source/where_to_put_your_code.rst | 42 ++++++++++++------- 4 files changed, 51 insertions(+), 35 deletions(-) diff --git a/Sources/source/conf.py b/Sources/source/conf.py index bf722c4..bb0a801 100644 --- a/Sources/source/conf.py +++ b/Sources/source/conf.py @@ -34,10 +34,10 @@ 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', - 'sphinx.ext.pngmath', + 'sphinx.ext.imgmath', 'sphinx.ext.ifconfig', 'IPython.sphinxext.ipython_console_highlighting', - 'IPython.sphinxext.ipython_directive', + # 'IPython.sphinxext.ipython_directive', ] # Add any paths that contain templates here, relative to this directory. diff --git a/Sources/source/interfacing_with_c/c_python.rst b/Sources/source/interfacing_with_c/c_python.rst index bc01e93..039b4f8 100644 --- a/Sources/source/interfacing_with_c/c_python.rst +++ b/Sources/source/interfacing_with_c/c_python.rst @@ -1,12 +1,13 @@ +######################## Interfacing C and Python -################################ +######################## -Sorry, not much here +Sorry, not much here yet. NOTE: this is all about the CPython interpreter -- not PyPy, IronPython, JPython, etc. Documentation: -================ +============== Core docs for the C API: @@ -14,42 +15,43 @@ Core docs for the C API: Interfacing methods: -====================== +==================== There a bunch of ways to interface C and Python: Hand write against the C API: ------------------------------- +----------------------------- -The python interpeter exposes a full API to all teh pyton objects, etc. You can essentially do anything, but it's a lot of hand-work. +The python interpeter exposes a full API to all the python objects, etc. You can essentially do anything, but it's a lot of hand-work. And reference counting is really hard to get right! -http://docs.python.org/2/c-api/ +http://docs.python.org/3/c-api/ Cython: ------------------- +------- Cython can be described as a "python-like language for writing python extensions" -It can be used essentially to speed up Python, but also to Call Python from C +It can be used essentially to speed up Python, but also to call Python from C. (derived from Pyrex) XDress -........ +...... ctypes --------- +------ SWIG, SIP, ETC. ----------------- +--------------- Auto wrapper generators. EXAMPLE: -============ +======== + +Same as the one for fortran: a automatic gain control filter. -Same as the one for fortran: a automatic gain control filter. \ No newline at end of file diff --git a/Sources/source/interfacing_with_c/fortran_python.rst b/Sources/source/interfacing_with_c/fortran_python.rst index df5cfa6..651d2c2 100644 --- a/Sources/source/interfacing_with_c/fortran_python.rst +++ b/Sources/source/interfacing_with_c/fortran_python.rst @@ -1,8 +1,8 @@ Interfacing Fortran and Python -################################ +############################## Documentation: -================ +============== A nice reference for Python for Fortran programmers: @@ -16,7 +16,7 @@ http://fortran90.org/src/best-practices.html http://fortran90.org/src/best-practices.html#interfacing-with-python Interfacing methods: -====================== +==================== There a a handful of ways to interface Fortran and Python: @@ -75,7 +75,7 @@ The problem at hand is an automatic gain control function function, expressed in end f2py: -------- +----- f2py is a command line utility that comes with numpy. You can build a default simple wrapper with the f2py command:: @@ -108,7 +108,7 @@ So it can be called like so:: where `signal` and `filtered` are 1-d arrays of float32 values, both of the same length. Giving f2py extra information: -............................... +.............................. f2py can build an interface to a fortran subroutine, but it can't do it all that well without some extra information. For instnce, note from the docstring that the argument `ampagc` is listed as an input argument, when it is really intended to be used for output. diff --git a/Sources/source/where_to_put_your_code.rst b/Sources/source/where_to_put_your_code.rst index e968ac8..ac650ce 100644 --- a/Sources/source/where_to_put_your_code.rst +++ b/Sources/source/where_to_put_your_code.rst @@ -2,6 +2,8 @@ Where to put your custom code? ****************************** +(You can find this page at: http://bit.ly/JustPackage) + A suggestion for how to manage your personal library of python functions you might use for scripting, data analysis, etc. TL; DR @@ -14,13 +16,19 @@ Make a "package" out of it so you can manage it in one place, and use it in othe Introduction ------------ -Many folks find they have a collection of little scripts and utilities that they want to be able to use and re-use for various projects. It is really NOT a good idea to simply copy and paste these around for use with each project -- you will regret that! +Many scientists and engineers that do a little coding find they have a collection of little scripts and utilities that they want to be able to use and re-use for various projects. It is really NOT a good idea to simply copy and paste these around for use with each project -- you will regret that! It is also not a good idea to use the ``PYTHONPATH`` environment variable to set up a directory in which to dump stuff. (Google a bit if you want to know why). -The best way to do this with Python is to use the python package mechanism. +The best way to do this with Python is to use the Python package mechanism. + +A Python "package" is a collection of modules and scripts -- we usually think of these as something carefully developed for a particular purpose and distributed to a wide audience for re-use -- the packages you can install with pip. + +Indeed that is the case, but the "collection of modules and scripts" part can be used for your own code that no one else is ever going to touch, and the overhead is small if you use it only this way. + +The challenge is that most of the documentation about python packaging is focused on creating a package of a library that you want to distribute to the community. In that case, it's very important to have full and proper meta data, tests, documentation, etc. As a result, the packaging documentation makes the whole process seem complicated and cumbersome. -A Python "package" is a collection of modules and scripts -- we usually think of these as something carefully developed for particular purpose and distributed to a wide audience for re-use -- the packages you can install with pip. Indeed that is the case, but the "collection of modules and scripts" part can be used for your own code that no one else is ever going to touch, and the overhead is small if you use it only this way. +But making a simple package for your own use can be very simple, and very useful. Step by step: ------------- @@ -33,18 +41,18 @@ Step by step: 4) In the outer dir, put in a file (we'll fill it in later) called ``setup.py``. -So you shoudl have:: +So you should have:: my_code my_code __init__.py setup.py -The inner my_code dir is now a python "package" -- any directory with a __init__.py file is a package. But how to use it? +The inner my_code dir is now a python "package" -- any directory with a ``__init__.py`` file is a package. But how to use it? -The setup.py file is where you specify for python how this package is setup. You can do a lot in there, and if you ever want to share your code with anyone else, you should follow: +The ``setup.py`` file is where you specify for python how this package is setup. You can do a lot in there, and if you ever want to share your code with anyone else, you should follow: -https://packaging.python.org/tutorials/distributing-packages/. +https://packaging.python.org/tutorials/distributing-packages/ But for now, we are going to make it as *simple* as possible:: @@ -56,6 +64,7 @@ But for now, we are going to make it as *simple* as possible:: That's it -- really! There is a lot you can do here to support multiple packages, scripts, etc, but this is enough to get you started. + Putting in your code -------------------- @@ -80,15 +89,19 @@ Create a file for your code, and put it in the inner my_code dir: OK -- now you have a (useless) package with some code in it - how to use it? -To use this package, you need to "install" it into the python environment that you want to use. Some of us have a single python install -- maybe Anaconda's root environment, or the python.org python installer, or.... Some of us use virtualenv or conda environments. In any case, get yourself into that environment with a command line in the outer my_code dir, and type:: +To use this package, you need to "install" it into the python environment that you want to use. Some of us have a single python install -- maybe Anaconda's root environment, or the python.org python installer, or ... + +Some of us use virtualenv, or pipienv, or conda environments. In any case, get yourself into that environment at a command line and put yourself (``cd`` in Terminal, DOS box, etc...) in the outer my_code dir (where the setup.py is), and type:: + + pip install -e . - python setup.py develop +``pip install`` installs a package. ``-e`` means "do an editable install", and the dot (``.``) tells pip to install the package in the current directory. ``pip`` will look for a ``setup.py`` file in the current working dir. An editable install is like install, but instead of copying the code into the python environment, it adds it to the Python search path (only that particular environment's Python) so you can import it, but it will always be importing the current version of the files if you change things. -"develop" is like install, but instead of copying the code into the python environment, it adds it to the python search path (only that particular python instances search path!) so you can import it, but it will always be importing the current version of the files if you change things. +This means you can be actively maintaining your shared code, and other projects that use it will always get the latest version. -Now you can fire up python (or ipython, or a Jupyter notebook, or write code in a script, or...) and do:: +Now you can fire up Python (or iPython, or a Jupyter notebook, or write code in a script, or...) and do: - from my_code import some_code +.. code-block:: ipython In [2]: from my_code import some_code @@ -108,12 +121,13 @@ If you have only a little bit of code, you can do all this with a single module, If you have more than a few modules, it would probably make sense to keep them in separate packages, organized by functionality. -This is only the very simplest way to do it what you really SHOULD do is be more formal about the process: +This is only the very simplest way to do it. What you really SHOULD do is be more formal about the process: - Do some versioning of the package - Keep it in source code version control system (like git, etc) + - add tests of your code... and others... -Look up "Software Carpentry" for many more ideas how better to manage your software for Science. +Look up "Software Carpentry" for many more ideas about how better to manage your Software for Science. From a31881f9ccfd40a1424e7e5907b25685045c5dde Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 11 Jul 2018 23:42:21 -0500 Subject: [PATCH 05/39] removed *.pyc file from my_code --- Sources/code/my_code.zip | Bin 3096 -> 2678 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Sources/code/my_code.zip b/Sources/code/my_code.zip index 84c8ad81df1cbea1bccd665c71222667ca44ddf5..a4c361e3ebf3043e8fa23c9975f17cf7879b4e0a 100644 GIT binary patch delta 1272 zcmbOs@lAv;z?+$civa{o_P+L+$R{HubjK~48Hms1i!gv>MHo1M&;lguqFT=blmTIo z?AsZJT!$P4T>l?wV4SV1`Z1P#KXjdW zqjvV3AH$75A!iua6`W1tQ|@p`3qxdUbUn zr(%nM(;i0Y9J8NqvN;s@O{jlX^PyzH>Ws&qTl}I;`@VtL$#G80OWdq)U2a^rs4_#c zo&WKQSR@$0!2k&)YinRQfP)K4a54xm#K-$O zI{ODl=!Zt|Fo1#&gkix4)d$ozxrR{{9JG4 z7U+m50Xb!IJCiPlAkaDxo>+K+1uQs$Sr>;zVCn137H~a4i-H+5Cug%5O0WZsFv?#Y z4s$ugX*xNRx3CzofFvisV!6q5IBT*QyBZ5Ch@Zf|m<5zf2fHxzPC^N!e z;DDU$$Ds#LI}jC!fI$sU9vIi*uVXAD19Iqcz(W_G5rPcJMofVlG1-!f+afdq-4KLJ zzerx+V*<3j0*Gah3|Z26nQ^iqm+<5}jJ)+646rytb^|D?VD1Ld0!Z55IwmqPFyvOo zC+DZ6>ceQ5LqMh>2N@`avKTsYHvvrnr9DX`la@5jpL~~7!59|d$SwfsLv{hOzQ2wu zCL3@m7{k&gx_!tVS3$AwJy4&_Bo^o}N#lK1M7S2GmXsFg d6;y&u0wvC~1t61H*+9!QlBqGEM8 z2v2^*bb-Yxfy;ApHlwVRLe=VU5Qgc2m*+glGb}a`IXxU5*VvM}VA(aL6`hT^u%nHT`9_KxndM31*C(JdwpvA`NJU zQ9imgIx&-Pu^6#{{4`mB^`1c6iIz)QpQ8 zC69fd`p~=S)={^$tulXjI{$Ka?l1qbnD5O(Q)w11rRdEX@6DFfr|y0IxF^J?^1ni( zc%{~M%UF)GO_xflKDjWxiVouh?MyF!eSf#DnwBU0AkC~$;J2o$H5 zlosd}RDyyu1QfHPY>QdIQMZRpOBR+a1H2iTM41sOD2t&Zchh8McD-m=(uAl$BthhO z<7D80aUK3TngbmYAMfkv>>nJV9~!~I087W{MojKumtxLiWSG2>QN$cw8Nw}JB(Lu= z0h(U{#4<=WEooc})cb)^UW$VOn=8R-UYA3P#hQtMVe&@~5mQ*=NA@i!D8Rl2n$9A@ zz#xfYLnRZ#KpS8=1H%)iIHZ`Hm>DMXut>>Z`W7jF$#P0Dp9CvZm%wh`^T^4S zoHC5@lc#YiiNUfEvSWc6=p0bNipj4zl}$jwS^|twWCb8UBPR%16yNM*o&1JVE*F@+ zIN;d}SvM%r*jYLC)dRy~JrE0^=+ Date: Sat, 11 May 2019 13:36:47 -0700 Subject: [PATCH 06/39] adding a dictaable dataclass decorator --- .../code/dict_making/dictable_dataclass.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Sources/code/dict_making/dictable_dataclass.py diff --git a/Sources/code/dict_making/dictable_dataclass.py b/Sources/code/dict_making/dictable_dataclass.py new file mode 100644 index 0000000..d4796b8 --- /dev/null +++ b/Sources/code/dict_making/dictable_dataclass.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python + +""" +A prototype of a decorator that adds an iterator to a dataclass +so it can be passed in to the dict() constructor to make a dict. + +If this is thought to be useful it could be added to the dataclass +decorator itself, to give all decorators this functionality. +""" + + +from dataclasses import dataclass + + +class DataClassIterator: + """ + Iterator for dataclasses + + This used the class' __dataclass_fields__ dict to iterate through the + fields and their values + """ + + def __init__(self, dataclass_instance): + self.dataclass_instance = dataclass_instance + self.keys_iter = iter(dataclass_instance.__dataclass_fields__.keys()) + + def __iter__(self): + return self + + def __next__(self): + key = next(self.keys_iter) + return (key, getattr(self.dataclass_instance, key)) + + +def _dunder_iter(self): + """ + function used as the __iter__ method in the dictable_dataclass decorator + """ + return DataClassIterator(self) + + +def dictable_dataclass(the_dataclass): + """ + class decorator for making a dataclass iterable in a way that is compatible + with the dict() constructor + """ + the_dataclass.__iter__ = _dunder_iter + + return the_dataclass + + +# Example from the dataclass docs: +@dictable_dataclass +@dataclass +class InventoryItem: + '''Class for keeping track of an item in inventory.''' + name: str + unit_price: float + quantity_on_hand: int = 0 + + def total_cost(self) -> float: + return self.unit_price * self.quantity_on_hand + + +if __name__ == "__main__": + # try it out: + inv_item = InventoryItem("sneakers", 50.0, 20) + + print("an InventoryItem:\n", inv_item) + print() + + print("And the dict you can make from it:") + print(dict(inv_item)) + + From 29c69c01e566fc009d1d6418bafb0ebf24bdb9d4 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Sat, 11 May 2019 15:03:54 -0700 Subject: [PATCH 07/39] adding a mapping protocol example --- Sources/code/dict_making/dict_making.py | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Sources/code/dict_making/dict_making.py diff --git a/Sources/code/dict_making/dict_making.py b/Sources/code/dict_making/dict_making.py new file mode 100644 index 0000000..17bc8da --- /dev/null +++ b/Sources/code/dict_making/dict_making.py @@ -0,0 +1,51 @@ +""" +an exploration of how the dict constructor knows whether it is +working with a MApping of a general iterable. It looks like +the code is something like this: + +if isinstance(input, collections.abc.Mapping): + self.update = {key: input[key] key in input} +else: + self.update = {key: val for key, val in input} + +So if your custom class present themapping interface -- that is, iterating +over it returns the keys, than you want to be a MApping ABC subclass.ABC + +But if your custom class is not a Mapping, then you want __iter__ to return an +iterator over teh key, value pairs. +""" + +from collections.abc import Mapping + + +def test_iter(instance): + yield ("this") + yield ("that") + + +class DictTest(Mapping): + + def __init__(self, this="this", that="that"): + self.this = this + self.that = that + + def __iter__(self): + print("iter called") + return test_iter(self) + + def __getitem__(self, key): + return getattr(self, key) + + def __len__(self): + print("__len__ called") + + +if __name__ == "__main__": + + dt = DictTest() + print(dict(dt)) + + dt = DictTest(this=45, that=654) + print(dict(dt)) + + From 9ecddfd786e37d595c737451f015d6a26ea512de Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 10 Jul 2019 09:34:18 -0700 Subject: [PATCH 08/39] some updating (I forgot what) --- Sources/source/conf.py | 50 ++++++++----------- Sources/source/index.rst | 32 ++++-------- .../source/interfacing_with_c/c_python.rst | 14 ++++-- Sources/source/where_to_put_tests.rst | 11 ++-- 4 files changed, 46 insertions(+), 61 deletions(-) diff --git a/Sources/source/conf.py b/Sources/source/conf.py index bb0a801..0eec8d7 100644 --- a/Sources/source/conf.py +++ b/Sources/source/conf.py @@ -269,39 +269,29 @@ #texinfo_no_detailmenu = False -# -- Hieroglyph Slide Configuration ------------ - -extensions += [ - 'hieroglyph', -] - -slide_title = "PythonTopics" -slide_theme = 'slides2' -slide_levels = 3 - # Place custom static assets in the _static directory and uncomment # the following lines to include them -slide_theme_options = { - 'subtitle': 'Interesting Corners of Python Programming', - 'custom_css': 'custom.css', - # 'custom_js': 'custom.js', - 'presenters': [ - { - 'name': u'Christopher Barker', - 'email': u'PythonCHB@gmail.com', - 'github': u'https://github.com/PythonCHB', - 'company': u'Christopher Barker, PhD' - }, - # { - # 'name': 'Cris Ewing', - # 'twitter': '@crisewing', - # 'www': 'http://crisewing.com', - # 'github': 'http://github.com/cewing', - # 'company': 'Cris Ewing, Developer LLC' - # }, - ] -} +# slide_theme_options = { +# 'subtitle': 'Interesting Corners of Python Programming', +# 'custom_css': 'custom.css', +# # 'custom_js': 'custom.js', +# 'presenters': [ +# { +# 'name': u'Christopher Barker', +# 'email': u'PythonCHB@gmail.com', +# 'github': u'https://github.com/PythonCHB', +# 'company': u'Christopher Barker, PhD' +# }, +# # { +# # 'name': 'Cris Ewing', +# # 'twitter': '@crisewing', +# # 'www': 'http://crisewing.com', +# # 'github': 'http://github.com/cewing', +# # 'company': 'Cris Ewing, Developer LLC' +# # }, +# ] +# } # ---------------------------------------------- diff --git a/Sources/source/index.rst b/Sources/source/index.rst index e6193b8..bba1855 100644 --- a/Sources/source/index.rst +++ b/Sources/source/index.rst @@ -1,32 +1,18 @@ In This Collection ================== -.. ifslides:: +Topics: +------- - +-------------------------------+ - | Topics: | - +===============================+ - | .. toctree:: | - | :maxdepth: 1 | - | | - | weak_references | - | persistance_serialization | - +-------------------------------+ +.. toctree:: + :maxdepth: 1 -.. ifnotslides:: + weak_references + persistance_serialization + where_to_put_tests + where_to_put_your_code + interfacing_with_c/index - Topics: - ------- - - .. toctree:: - :maxdepth: 1 - - weak_references - persistance_serialization - where_to_put_tests - where_to_put_your_code - -.. rst-class:: credit These materials copyright Christopher H. Barker diff --git a/Sources/source/interfacing_with_c/c_python.rst b/Sources/source/interfacing_with_c/c_python.rst index 039b4f8..82e7568 100644 --- a/Sources/source/interfacing_with_c/c_python.rst +++ b/Sources/source/interfacing_with_c/c_python.rst @@ -12,6 +12,7 @@ Documentation: Core docs for the C API: +https://docs.python.org/3/extending/ Interfacing methods: @@ -19,6 +20,7 @@ Interfacing methods: There a bunch of ways to interface C and Python: + Hand write against the C API: ----------------------------- @@ -35,14 +37,14 @@ Cython can be described as a "python-like language for writing python extensions It can be used essentially to speed up Python, but also to call Python from C. -(derived from Pyrex) +https://cython.org/ -XDress -...... ctypes ------ +Ctypes comes with PYthon out of the box. + SWIG, SIP, ETC. --------------- @@ -53,5 +55,9 @@ Auto wrapper generators. EXAMPLE: ======== -Same as the one for fortran: a automatic gain control filter. +Same as the one for fortran: a automatic gain control filter: + +:download:`agc_example.zip` + + diff --git a/Sources/source/where_to_put_tests.rst b/Sources/source/where_to_put_tests.rst index 6778a9e..c30ea38 100644 --- a/Sources/source/where_to_put_tests.rst +++ b/Sources/source/where_to_put_tests.rst @@ -18,13 +18,13 @@ Test system recommendations https://pytest.org/latest/goodpractises.html -I need to add links for ``nose`` and ``unittest``.... PR's accepted! +I need to add links for ``nose`` and ``unittest`` ... PR's accepted! Two Options ----------- -In Python packaging, there seems is no consensus on where you should put your test suite. This thread: +In Python packaging, there is no consensus on where you should put your test suite. This thread: https://mail.python.org/pipermail/distutils-sig/2015-October/027003.html @@ -50,7 +50,10 @@ https://packaging.python.org/en/latest/ for recommendations. -2) The other options is to put your test code in a sub-package inside your package. In this case, it should be inside your package, and *be* a package itself (i.e. have an ``__init__.py``):: +In the this case, the directory with all the tests shouls not be a python package -- this is, it should not have a ``__init__.py`` file. + + +2) The other options is to put your test code in a sub-package inside your package. In this case, it should be inside your package, and *be* a python package itself (i.e. have an ``__init__.py``):: my_package __init__.py @@ -61,7 +64,7 @@ for recommendations. test_1.py test_2.py -Self contained +Self Contained -------------- The advantage of keeping test code self-contained is that you can have a large suite of tests with sample data and who knows what, and it won't bloat and complicate the installed package (and test code can write to the test dirs, etc. Also, you can then run the test suite against an installed version that may not be exactly the same as the current live code. From fc2a46ab7f7a78e5ca0d89d285958555b53dd6c0 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 10 Jul 2019 13:49:10 -0700 Subject: [PATCH 09/39] first version of script to build a simple pacakage --- Sources/code/make_my_package.py | 70 +++++++++++++++++++++++ Sources/source/where_to_put_your_code.rst | 6 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 Sources/code/make_my_package.py diff --git a/Sources/code/make_my_package.py b/Sources/code/make_my_package.py new file mode 100644 index 0000000..c85f306 --- /dev/null +++ b/Sources/code/make_my_package.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +""" +A simple script that builds a as_simple_as_possible package +to use for your own code. +""" +import sys, os + +USAGE = """ +python make_my_package.py your_package_name + +Running the script will create a minimal package +you can use to manage your personal code +""" + +setup_template = """#!/usr/bin/env python +from setuptools import setup + +setup(name='{package_name}', + packages=['{package_name}'], + ) + +""" + +test_code = '''#!/usr/bin/env python + +""" +Just an example, but this could be a collection of utility functions, etc. + +Here would be documentation of what's in this file + +In this case, just one function to make sure it works. +""" + +def test_fun(): + print("yup -- this worked!!") + +''' + +if __name__ == "__main__": + + + try: + package_name = sys.argv[1] + except IndexError: + print("You need to provide a name for your package") + print(USAGE) + sys.exit(1) + + this_dir = os.curdir + os.mkdir(package_name) + os.chdir(package_name) + with open("setup.py", 'w') as setupfile: + setupfile.write(setup_template.format(package_name=package_name)) + os.mkdir(package_name) + os.chdir(package_name) + with open("__init__.py", 'w') as initfile: + initfile.write("#!/usr/bin/env python\n\n" + "__version__ = '0.0.0'\n" + ) + + with open("test_code.py", 'w') as initfile: + initfile.write(test_code) + + os.chdir("../..") + + + + + diff --git a/Sources/source/where_to_put_your_code.rst b/Sources/source/where_to_put_your_code.rst index ac650ce..4c1fb28 100644 --- a/Sources/source/where_to_put_your_code.rst +++ b/Sources/source/where_to_put_your_code.rst @@ -6,6 +6,7 @@ Where to put your custom code? A suggestion for how to manage your personal library of python functions you might use for scripting, data analysis, etc. + TL; DR ====== @@ -13,6 +14,9 @@ If you have a collection of your own code you want access to for various project Make a "package" out of it so you can manage it in one place, and use it in other places. +You DO NOT NEED TO PUT IT ON PYPI ! + + Introduction ------------ @@ -35,7 +39,7 @@ Step by step: 1) Create a directory in your user (or home, or ... ) dir for your code. Let's call it "my_code". -2) This is going to seem odd, but create another dir with the same name inside that -- this is where the actual code goes. (it's a convention to name the top dir the same thing as the "package" name, but it doesn't matter. But the inner name does -- that is the name of your package. +2) This is going to seem odd, but create another dir with the same name inside that -- this is where the actual code goes. (it's a convention to name the top directory the same thing as the "package" name, but you don't have to follow that convention. But the inner name does -- that is the name of your package. 3) In that dir, put in an empty, for now, file called ``__init__.py``. From e4bc8de31b1c9db9bb730afec0df92c6f3fc3b7a Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Thu, 11 Jul 2019 08:27:01 -0700 Subject: [PATCH 10/39] added note about gitHub repo --- Sources/source/where_to_put_your_code.rst | 78 ++++++++++++++++++++--- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/Sources/source/where_to_put_your_code.rst b/Sources/source/where_to_put_your_code.rst index 4c1fb28..54a18f3 100644 --- a/Sources/source/where_to_put_your_code.rst +++ b/Sources/source/where_to_put_your_code.rst @@ -2,15 +2,22 @@ Where to put your custom code? ****************************** + +A Package Just for You! +======================= + (You can find this page at: http://bit.ly/JustPackage) +.. note:: This page is generated from a Sphinx document managed in this gitHub repo: https://github.com/PythonCHB/PythonTopics. I welcome questions, comments, and, of course, Pull Requests. + + A suggestion for how to manage your personal library of python functions you might use for scripting, data analysis, etc. TL; DR ====== -If you have a collection of your own code you want access to for various projects: +If you have a collection of your own code you want to access for various projects: Make a "package" out of it so you can manage it in one place, and use it in other places. @@ -20,9 +27,40 @@ You DO NOT NEED TO PUT IT ON PYPI ! Introduction ------------ -Many scientists and engineers that do a little coding find they have a collection of little scripts and utilities that they want to be able to use and re-use for various projects. It is really NOT a good idea to simply copy and paste these around for use with each project -- you will regret that! +Many scientists and engineers that do a little coding find they have a collection of little scripts and utilities that they want to be able to use and re-use for various projects. + +Options for Handling Your Code Collection: +------------------------------------------ + + 1) Keep your code in one place, and copy and paste the functions you need into each new project. + + +DON'T DO THAT! +.............. + +REALLY! +....... + + +It is really NOT a good idea to simply copy and paste code around for use with each project. You will end up with multiple versions scattered all over the place -- **you will regret that!** + + 2) Put your code in a single directory and add it to the ``PYTHONPATH`` environment variable + + +DON'T DO THAT! +.............. + -It is also not a good idea to use the ``PYTHONPATH`` environment variable to set up a directory in which to dump stuff. (Google a bit if you want to know why). +REALLY! +....... + +``PTYHONPATH`` is shared by all installs of Python. What with Python2, Python3, virtual environments, etc -- it's really not a good idea. + +If you don't believe me: **Google It** + + +What you should do is make a "package" +-------------------------------------- The best way to do this with Python is to use the Python package mechanism. @@ -30,11 +68,27 @@ A Python "package" is a collection of modules and scripts -- we usually think of Indeed that is the case, but the "collection of modules and scripts" part can be used for your own code that no one else is ever going to touch, and the overhead is small if you use it only this way. +Why Don't People Tend to figure this out for themselves? +........................................................ + +The Packaging Documentation is mostly about Making a "proper" package for distribution to a wide audience. + +So newbies tend to either: + +* Think: "I don't want/need to do all that", and then move on and copy and past their code around like they have already done. + +or + +* Go ahead and follow the instructions, and end up putting their tiny little not-useful-to-anyone-else package up on PyPi. + + The challenge is that most of the documentation about python packaging is focused on creating a package of a library that you want to distribute to the community. In that case, it's very important to have full and proper meta data, tests, documentation, etc. As a result, the packaging documentation makes the whole process seem complicated and cumbersome. -But making a simple package for your own use can be very simple, and very useful. +Making a simple package just for your own use can be very simple, and very useful. +.................................................................................. -Step by step: + +Step by Step: ------------- 1) Create a directory in your user (or home, or ... ) dir for your code. Let's call it "my_code". @@ -50,6 +104,7 @@ So you should have:: my_code my_code __init__.py + some_code.py setup.py The inner my_code dir is now a python "package" -- any directory with a ``__init__.py`` file is a package. But how to use it? @@ -68,6 +123,11 @@ But for now, we are going to make it as *simple* as possible:: That's it -- really! There is a lot you can do here to support multiple packages, scripts, etc, but this is enough to get you started. +Here: :download:`make_my_package.py <../code/make_my_package.py>` is a little script that will build an empty package for you:: + + python make_my_package.py your_package_name + +will do it for you. Putting in your code -------------------- @@ -95,7 +155,7 @@ OK -- now you have a (useless) package with some code in it - how to use it? To use this package, you need to "install" it into the python environment that you want to use. Some of us have a single python install -- maybe Anaconda's root environment, or the python.org python installer, or ... -Some of us use virtualenv, or pipienv, or conda environments. In any case, get yourself into that environment at a command line and put yourself (``cd`` in Terminal, DOS box, etc...) in the outer my_code dir (where the setup.py is), and type:: +Some of us use virtualenv, or pipenv, or conda environments. In any case, get yourself into that environment at a command line and put yourself (``cd`` in Terminal, DOS box, etc...) in the outer my_code dir (where the setup.py is), and type:: pip install -e . @@ -107,15 +167,15 @@ Now you can fire up Python (or iPython, or a Jupyter notebook, or write code in .. code-block:: ipython - In [2]: from my_code import some_code + In [2]: from test_package import test_code - In [3]: some_code.test_fun() + In [3]: test_code.test_fun() yup -- this worked!! And you are good to go! -Here is a zip file of my simple example package: :download:`my_code.zip <../code/my_code.zip>` +.. Here is a zip file of my simple example package: :download:`my_code.zip <../code/my_code.zip>` NOTES: From d7e5277534f404565d7383a6dee99607e001829e Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Thu, 11 Jul 2019 13:07:00 -0700 Subject: [PATCH 11/39] a bit of copy editing --- Sources/source/where_to_put_your_code.rst | 34 +++++++++++------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/Sources/source/where_to_put_your_code.rst b/Sources/source/where_to_put_your_code.rst index 54a18f3..72d7a64 100644 --- a/Sources/source/where_to_put_your_code.rst +++ b/Sources/source/where_to_put_your_code.rst @@ -35,11 +35,9 @@ Options for Handling Your Code Collection: 1) Keep your code in one place, and copy and paste the functions you need into each new project. -DON'T DO THAT! -.............. +**DON'T DO THAT!** -REALLY! -....... +**REALLY!** It is really NOT a good idea to simply copy and paste code around for use with each project. You will end up with multiple versions scattered all over the place -- **you will regret that!** @@ -47,14 +45,12 @@ It is really NOT a good idea to simply copy and paste code around for use with e 2) Put your code in a single directory and add it to the ``PYTHONPATH`` environment variable -DON'T DO THAT! -.............. +**DON'T DO THAT!** +**REALLY!** -REALLY! -....... -``PTYHONPATH`` is shared by all installs of Python. What with Python2, Python3, virtual environments, etc -- it's really not a good idea. +``PYTHONPATH`` is shared by all installs of Python. What with Python2, Python3, virtual environments, etc -- it's really not a good idea. If you don't believe me: **Google It** @@ -68,24 +64,24 @@ A Python "package" is a collection of modules and scripts -- we usually think of Indeed that is the case, but the "collection of modules and scripts" part can be used for your own code that no one else is ever going to touch, and the overhead is small if you use it only this way. -Why Don't People Tend to figure this out for themselves? + +Why Don't People Tend to Figure This out for Themselves? ........................................................ -The Packaging Documentation is mostly about Making a "proper" package for distribution to a wide audience. +The packaging documentation is mostly about making a "proper" package for distribution to a wide audience. So newbies tend to either: -* Think: "I don't want/need to do all that", and then move on and copy and past their code around like they have already done. +* Think: "I don't want/need to do all that", and then move on and copy and past their code around like they have already been doing. or -* Go ahead and follow the instructions, and end up putting their tiny little not-useful-to-anyone-else package up on PyPi. +* Go ahead and follow all the instructions, and end up putting their tiny little not-useful-to-anyone-else package up on PyPi. The challenge is that most of the documentation about python packaging is focused on creating a package of a library that you want to distribute to the community. In that case, it's very important to have full and proper meta data, tests, documentation, etc. As a result, the packaging documentation makes the whole process seem complicated and cumbersome. -Making a simple package just for your own use can be very simple, and very useful. -.................................................................................. +.. rubric:: Making a simple package just for your own use can be very simple, and very useful. Step by Step: @@ -93,7 +89,9 @@ Step by Step: 1) Create a directory in your user (or home, or ... ) dir for your code. Let's call it "my_code". -2) This is going to seem odd, but create another dir with the same name inside that -- this is where the actual code goes. (it's a convention to name the top directory the same thing as the "package" name, but you don't have to follow that convention. But the inner name does -- that is the name of your package. +2) This is going to seem odd, but create another dir with the same name inside that -- this is where the actual code goes. (it's a convention to name the top directory the same thing as the "package" name, but you don't have to follow that convention. But the inner name does matter -- that is the name of your package, and how you will import it into Python. + +Be thoughtful about what you name your package: you want a easy to remember and fairly easy to type name, but also one that is not used already for any of the standard library or commonly used third party packages. Once you come up with a name, google "the_name python" just to make sure it's not already in use. 3) In that dir, put in an empty, for now, file called ``__init__.py``. @@ -188,9 +186,9 @@ If you have more than a few modules, it would probably make sense to keep them i This is only the very simplest way to do it. What you really SHOULD do is be more formal about the process: - Do some versioning of the package - Keep it in source code version control system (like git, etc) - - add tests of your code... + - Add tests of your code... -and others... +and others. But this is enough to get you started, and you can extend it as you develop more software carpentry skills. Look up "Software Carpentry" for many more ideas about how better to manage your Software for Science. From 8193877e947141c88fc9090e815e52fedb3dc9b9 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Mon, 24 Aug 2020 22:58:26 +0530 Subject: [PATCH 12/39] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index bbd8c0e..12682b4 100644 --- a/README.rst +++ b/README.rst @@ -4,7 +4,7 @@ PythonTopics Presentations/notes on various Python topics -Included in the repo are assorted notes and presentationa about selected Python topics. +Included in the repo are assorted notes and presentations about selected Python topics. A rendered version is available on gitHub pages at: From 073a932a78973dd0c2e20f0b3e9fae85b1da5e7a Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Mon, 24 Aug 2020 23:20:08 +0530 Subject: [PATCH 13/39] Update where_to_put_tests.rst fixed broken link --- Sources/source/where_to_put_tests.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/source/where_to_put_tests.rst b/Sources/source/where_to_put_tests.rst index c30ea38..7e20ba2 100644 --- a/Sources/source/where_to_put_tests.rst +++ b/Sources/source/where_to_put_tests.rst @@ -16,7 +16,7 @@ Test system recommendations ``pytest`` has a bit of discussion of the issue here: -https://pytest.org/latest/goodpractises.html +https://docs.pytest.org/en/stable/goodpractices.html I need to add links for ``nose`` and ``unittest`` ... PR's accepted! From 28630b350be16faf71db684554593be636c0df01 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Mon, 24 Aug 2020 10:59:06 -0700 Subject: [PATCH 14/39] some formatting improvements to where to put your code. --- Sources/source/where_to_put_your_code.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Sources/source/where_to_put_your_code.rst b/Sources/source/where_to_put_your_code.rst index 72d7a64..6b556b4 100644 --- a/Sources/source/where_to_put_your_code.rst +++ b/Sources/source/where_to_put_your_code.rst @@ -32,22 +32,23 @@ Many scientists and engineers that do a little coding find they have a collectio Options for Handling Your Code Collection: ------------------------------------------ - 1) Keep your code in one place, and copy and paste the functions you need into each new project. +**(1)** Keep your code in one place and copy and paste the functions you need into each new project. +.. centered:: **DON'T DO THAT!** -**DON'T DO THAT!** +.. centered:: **REALLY!** -**REALLY!** +It is really NOT a good idea to simply copy and paste code around for use with each project. You will end up with multiple versions scattered all over the place ... -It is really NOT a good idea to simply copy and paste code around for use with each project. You will end up with multiple versions scattered all over the place -- **you will regret that!** +.. centered:: **You will regret that!** - 2) Put your code in a single directory and add it to the ``PYTHONPATH`` environment variable +**(2)** Put your code in a single directory and add it to the ``PYTHONPATH`` environment variable -**DON'T DO THAT!** +.. centered:: **DON'T DO THAT!** -**REALLY!** +.. centered:: **REALLY!** ``PYTHONPATH`` is shared by all installs of Python. What with Python2, Python3, virtual environments, etc -- it's really not a good idea. From 4e1d6292a7e767e89dc1b8cc4a58311612f4f156 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Mon, 24 Aug 2020 11:03:19 -0700 Subject: [PATCH 15/39] fixed a couple typos. --- Sources/source/where_to_put_tests.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/source/where_to_put_tests.rst b/Sources/source/where_to_put_tests.rst index 7e20ba2..cabc36c 100644 --- a/Sources/source/where_to_put_tests.rst +++ b/Sources/source/where_to_put_tests.rst @@ -50,7 +50,7 @@ https://packaging.python.org/en/latest/ for recommendations. -In the this case, the directory with all the tests shouls not be a python package -- this is, it should not have a ``__init__.py`` file. +In the this case, the directory with all the tests should not be a python package -- this is, it should not have a ``__init__.py`` file. 2) The other options is to put your test code in a sub-package inside your package. In this case, it should be inside your package, and *be* a python package itself (i.e. have an ``__init__.py``):: @@ -73,3 +73,5 @@ Sub-package ----------- The advantage of test being a sub-package is that your test code gets installed with the package, so users (including yourself, if you are deploying the code) can install the package, and run the test to make sure the install all went well. You can also have the tests use relative imports, so you can run it all without installing (though with develop mode I don't think that is much of an advantage) + + From 9619356df495cc1133b4dd5c083518c729291deb Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Mon, 24 Aug 2020 23:41:08 +0530 Subject: [PATCH 16/39] Update where_to_put_tests.rst Added links for relevant links for nose and unittest --- Sources/source/where_to_put_tests.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/source/where_to_put_tests.rst b/Sources/source/where_to_put_tests.rst index 7e20ba2..2532f89 100644 --- a/Sources/source/where_to_put_tests.rst +++ b/Sources/source/where_to_put_tests.rst @@ -18,7 +18,9 @@ Test system recommendations https://docs.pytest.org/en/stable/goodpractices.html -I need to add links for ``nose`` and ``unittest`` ... PR's accepted! +For ``nose``, read https://nose.readthedocs.io/en/latest/finding_tests.html + +and for ``unittest`` read https://docs.python.org/3/library/unittest.html#test-discovery . Two Options From 26308e63ba499125a2139df7632a1a2490df4213 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 11:03:14 +0530 Subject: [PATCH 17/39] Update requirements.txt --- Sources/requirements.txt | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Sources/requirements.txt b/Sources/requirements.txt index 4666c46..69b433d 100644 --- a/Sources/requirements.txt +++ b/Sources/requirements.txt @@ -1,11 +1,10 @@ -Jinja2==2.7.2 -MarkupSafe==0.19 -Pygments==1.6 -Sphinx==1.2.2 -docutils==0.11 -sphinx-rtd-theme==0.1.6 -gnureadline==6.2.5 -# hieroglyph==0.7.dev --e git+https://github.com/nyergler/hieroglyph.git#egg=hieroglyph -ipython==2.3.0 -libsass==0.5.1 +Jinja2 +MarkupSafe +Pygments +Sphinx +docutils +sphinx-rtd-theme +gnureadline +hieroglyph +ipython +libsass From aff4b55358b6ffe81cfd63a337bc4cd04ab44883 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 11:03:54 +0530 Subject: [PATCH 18/39] Create main.yml --- .github/workflows/main.yml | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..a17a980 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,41 @@ +name: Python package + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f Sources/requirements.txt ]; then pip install -r Sources/requirements.txt; fi + # - name: Lint with flake8 + # run: | + # stop the build if there are Python syntax errors or undefined names + # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + #- name: Test with pytest + # run: | + # pytest + - name: Build static site + run: | + cd ./Sources; make html + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./Sources/build/html From 59b6be3223335ae6cbb561ff987cc1e8fe3e0a2d Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 11:09:01 +0530 Subject: [PATCH 19/39] Update where_to_put_tests.rst minor edit (also to test the buildout using github workflow). --- Sources/source/where_to_put_tests.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/source/where_to_put_tests.rst b/Sources/source/where_to_put_tests.rst index c569af6..ef68f21 100644 --- a/Sources/source/where_to_put_tests.rst +++ b/Sources/source/where_to_put_tests.rst @@ -20,7 +20,7 @@ https://docs.pytest.org/en/stable/goodpractices.html For ``nose``, read https://nose.readthedocs.io/en/latest/finding_tests.html -and for ``unittest`` read https://docs.python.org/3/library/unittest.html#test-discovery . +and for ``unittest`` read https://docs.python.org/3/library/unittest.html#test-discovery. Two Options From a8c538ab1d0e068b144eb1d242addee927ccee70 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 17:15:44 +0530 Subject: [PATCH 20/39] Create autopep8.yml --- .github/workflows/autopep8.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/autopep8.yml diff --git a/.github/workflows/autopep8.yml b/.github/workflows/autopep8.yml new file mode 100644 index 0000000..8db8ec6 --- /dev/null +++ b/.github/workflows/autopep8.yml @@ -0,0 +1,24 @@ +name: Format python code +on: push +jobs: + autopep8: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: autopep8 + uses: peter-evans/autopep8@v1 + with: + args: --recursive --in-place --aggressive --aggressive . + - name: Create Pull Request + uses: peter-evans/create-pull-request@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: autopep8 action fixes + committer: Peter Evans + title: Fixes by autopep8 action + body: This is an auto-generated PR with fixes by autopep8. + labels: autopep8, automated pr + reviewers: peter-evans + branch: autopep8-patches + + From 96e9c05c8da25a94958520e3ee26225e4eff65a1 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 17:19:13 +0530 Subject: [PATCH 21/39] Delete autopep8.yml --- .github/workflows/autopep8.yml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .github/workflows/autopep8.yml diff --git a/.github/workflows/autopep8.yml b/.github/workflows/autopep8.yml deleted file mode 100644 index 8db8ec6..0000000 --- a/.github/workflows/autopep8.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Format python code -on: push -jobs: - autopep8: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: autopep8 - uses: peter-evans/autopep8@v1 - with: - args: --recursive --in-place --aggressive --aggressive . - - name: Create Pull Request - uses: peter-evans/create-pull-request@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: autopep8 action fixes - committer: Peter Evans - title: Fixes by autopep8 action - body: This is an auto-generated PR with fixes by autopep8. - labels: autopep8, automated pr - reviewers: peter-evans - branch: autopep8-patches - - From d7d1732429974e8851cf9c1db33956e3706c9176 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 21:53:05 +0530 Subject: [PATCH 22/39] Create flake.yml --- .github/workflows/flake.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/flake.yml diff --git a/.github/workflows/flake.yml b/.github/workflows/flake.yml new file mode 100644 index 0000000..272c489 --- /dev/null +++ b/.github/workflows/flake.yml @@ -0,0 +1,23 @@ +name: Code Quality + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + lint: + name: Python Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: "2.7" + - name: Run flake8 + uses: julianwachholz/flake8-action@v1 + with: + checkName: "Python Lint" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From bcb710d3923d1bf7ced15bfc569ede6689aee399 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 22:02:56 +0530 Subject: [PATCH 23/39] Update flake.yml --- .github/workflows/flake.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/flake.yml b/.github/workflows/flake.yml index 272c489..7286f7e 100644 --- a/.github/workflows/flake.yml +++ b/.github/workflows/flake.yml @@ -16,8 +16,7 @@ jobs: with: python-version: "2.7" - name: Run flake8 - uses: julianwachholz/flake8-action@v1 + uses: TrueBrain/actions-flake8@master with: - checkName: "Python Lint" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + src: Sources/code + ignore: E9,F63,F7,F82 From bfe9ee19744f97a26ab5415214bef94cccc5c767 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 22:26:49 +0530 Subject: [PATCH 24/39] Update and rename flake.yml to flake8.yml --- .github/workflows/{flake.yml => flake8.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{flake.yml => flake8.yml} (93%) diff --git a/.github/workflows/flake.yml b/.github/workflows/flake8.yml similarity index 93% rename from .github/workflows/flake.yml rename to .github/workflows/flake8.yml index 7286f7e..c615676 100644 --- a/.github/workflows/flake.yml +++ b/.github/workflows/flake8.yml @@ -18,5 +18,5 @@ jobs: - name: Run flake8 uses: TrueBrain/actions-flake8@master with: - src: Sources/code + path: Sources/code ignore: E9,F63,F7,F82 From 0687cf68ffdbd335bf6091a16fb4567796485b35 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 22:40:02 +0530 Subject: [PATCH 25/39] Update flake8.yml --- .github/workflows/flake8.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index c615676..fa920bc 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -19,4 +19,4 @@ jobs: uses: TrueBrain/actions-flake8@master with: path: Sources/code - ignore: E9,F63,F7,F82 + ignore: E9,F63,F7,F82, E203, W293, E231, W391, E265, E266, E226, E301, E228 From 1ae258de059406816dc089606b86c146be5ab061 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 22:45:17 +0530 Subject: [PATCH 26/39] Update flake8.yml --- .github/workflows/flake8.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index fa920bc..a72b751 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -19,4 +19,4 @@ jobs: uses: TrueBrain/actions-flake8@master with: path: Sources/code - ignore: E9,F63,F7,F82, E203, W293, E231, W391, E265, E266, E226, E301, E228 + ignore: E9,F63,F7,F82, E203, W293, E231, W391, E265, E266, E226, E301, E228, E401, E303 From 88bf9a98a99bd342581e58e8ae55059526b4eb4a Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 22:49:28 +0530 Subject: [PATCH 27/39] Update flake8.yml --- .github/workflows/flake8.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index a72b751..a9159ec 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -19,4 +19,4 @@ jobs: uses: TrueBrain/actions-flake8@master with: path: Sources/code - ignore: E9,F63,F7,F82, E203, W293, E231, W391, E265, E266, E226, E301, E228, E401, E303 + ignore: E9,F63,F7,F82,E203,W293,E231,W391,E265,E266,E226,E301,E228,E401,E303 From 3d22907ead1f9e80cbfa8d161d66bf81ad95599b Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 22:53:16 +0530 Subject: [PATCH 28/39] Update flake8.yml --- .github/workflows/flake8.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index a9159ec..d9c5d0e 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -19,4 +19,7 @@ jobs: uses: TrueBrain/actions-flake8@master with: path: Sources/code - ignore: E9,F63,F7,F82,E203,W293,E231,W391,E265,E266,E226,E301,E228,E401,E303 + ignore: E9,F63,F7,F82,E303 + + + From 440678ab041fcfd70d3b0f2ea7eb6d7df6708d2d Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 23:18:17 +0530 Subject: [PATCH 29/39] Update flake8.yml --- .github/workflows/flake8.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index d9c5d0e..5e495f2 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -19,7 +19,8 @@ jobs: uses: TrueBrain/actions-flake8@master with: path: Sources/code - ignore: E9,F63,F7,F82,E303 + ignore: E9,F63,F7,F82,E203,W293,E231,W391,E265,E266,E226,E301,E228,E401,E303 + From 75ef457a20b2d4ebf2359882919c1ba34b3a1729 Mon Sep 17 00:00:00 2001 From: Ashok Bakthavathsalam Date: Wed, 26 Aug 2020 23:24:34 +0530 Subject: [PATCH 30/39] Update flake8.yml --- .github/workflows/flake8.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index 5e495f2..ef1acaf 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -19,7 +19,7 @@ jobs: uses: TrueBrain/actions-flake8@master with: path: Sources/code - ignore: E9,F63,F7,F82,E203,W293,E231,W391,E265,E266,E226,E301,E228,E401,E303 + ignore: E9,F63,F7,F82,E203,W293,E231,W291,W391,E265,E266,E226,E301,E228,E401,E303,E201,E202,E305,E501,E261 From 100c9a82d5d99a7c7e59d571215229ab5b656d9a Mon Sep 17 00:00:00 2001 From: "Christopher H.Barker, PhD" Date: Fri, 16 May 2025 12:35:43 -0700 Subject: [PATCH 31/39] added unit test example / lesson a unit testing example -- starter code. --- Sources/code/test_sum_13.py | 148 ++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 Sources/code/test_sum_13.py diff --git a/Sources/code/test_sum_13.py b/Sources/code/test_sum_13.py new file mode 100644 index 0000000..a13a87a --- /dev/null +++ b/Sources/code/test_sum_13.py @@ -0,0 +1,148 @@ +""" + +Test driven development: + + +Example from Coding Bat: List-2 > sum13 + +https://codingbat.com/prob/p167025 + +Return the sum of the numbers in the array, returning 0 for an empty array. Except the number 13 is very unlucky, so it does not count and numbers that come immediately after a 13 also do not count. + + +sum13([1, 2, 2, 1]) → 6 +sum13([1, 1]) → 2 +sum13([1, 2, 2, 1, 13]) → 6 +sum13([1, 2, 2, 1]) → 6 +sum13([1, 1]) → 2 +sum13([1, 2, 2, 1, 13]) → 6 +sum13([1, 2, 13, 2, 1, 13]) → 4 +sum13([13, 1, 2, 13, 2, 1, 13]) → 3 +sum13([]) → 0 +sum13([13]) → 0 +sum13([13, 13]) → 0 +sum13([13, 0, 13]) → 0 +sum13([13, 1, 13]) → 0 +sum13([5, 7, 2]) → 14 +sum13([5, 13, 2]) → 5 +sum13([0]) → 0 +sum13([13, 0]) → 0 +""" + +import pytest + +# def sum13(nums): +# """ +# non-functional -- but the tests will run (and fail) +# """ +# return None + +# def sum13(nums): +# """ +# simple sum -- no special handling of 13 -- should pass some tests. +# """ +# return sum(nums) + + +# def sum13(nums): +# """ +# using a comprehension to filter out the 13s + +# - more tests should pass, but not all. +# """ +# return sum(n for n in nums if n!=13) + + +# def sum13(nums): +# """ +# darn -- comprehension can't handle the "after a 13" case + +# do it from scratch with while loop + +# fails the two 13s in a row test! +# """ +# total = 0 +# i = 0 +# while i < len(nums): +# if nums[i] != 13: +# total += nums[i] +# else: +# i += 1 +# i += 1 +# return total + + +# def sum13(nums): +# """ +# Use a for loop, and keep track of the previous 13 + +# passes all tests! +# """ +# print(nums) +# total = 0 +# prev_13 = False +# for i, n in enumerate(nums): +# if n == 13: +# prev_13 = True +# continue +# elif prev_13: +# prev_13 = False +# continue +# else: +# total += n +# return total + + +def sum13(nums): + """ + Use the iterator protocol -- nifty? but not any simpler really. + + Fails for repeated 13 in middle + + Works with any iterable, so that's nice. + """ + total = 0 + nums_i = iter(nums) + for n in nums_i: + if n != 13: + total += n + else: + try: + next(nums_i) + # this is necessary for the case where there's a 13 at the end. + except StopIteration: + break + return total + +# Using the nifty pytest.parametrize, so we only have to write one test + +test_data = [ + ([1, 2, 2, 1], 6), + ([1, 1], 2), + ([1, 2, 2, 1, 13], 6), + ([1, 2, 2, 1], 6), + ([1, 1], 2), + ([1, 2, 2, 1, 13], 6), + ([1, 2, 13, 2, 1, 13], 4), + ([13, 1, 2, 13, 2, 1, 13], 3), + ([], 0), + ([13], 0), + ([13, 13], 0), + ([13, 0, 13], 0), + ([13, 1, 13], 0), + ([5, 7, 2], 14), + ([5, 13, 2], 5), + ([0], 0), + ([13, 0], 0), + # These are not part of original test suite + # ([3, 13, 13, 2, 5], 8), + # (iter([13, 1, 2, 13, 2, 1, 13]), 3), # Does it work with an iterable? + ] + +@pytest.mark.parametrize('nums, result', test_data) +def test_sum13(nums, result): + assert sum13(nums) == result + + + + From b38ef4198961c64def0a733a208dd624f7dfe111 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 17:32:40 -0700 Subject: [PATCH 32/39] some updates, and adding the interfacing notes. --- Sources/requirements.txt | 2 +- Sources/source/conf.py | 26 +++++++++---------- .../source/interfacing_with_c/c_python.rst | 11 ++++++-- Sources/source/weak_references.rst | 2 ++ 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Sources/requirements.txt b/Sources/requirements.txt index 69b433d..60a72e9 100644 --- a/Sources/requirements.txt +++ b/Sources/requirements.txt @@ -5,6 +5,6 @@ Sphinx docutils sphinx-rtd-theme gnureadline -hieroglyph +# hieroglyph ipython libsass diff --git a/Sources/source/conf.py b/Sources/source/conf.py index 0eec8d7..9efb5a4 100644 --- a/Sources/source/conf.py +++ b/Sources/source/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Pyhton Topics build configuration file, created by +# Python Topics build configuration file, created by # sphinx-quickstart on Wed Apr 2 18:42:06 2014. # # This file is execfile()d with the current directory set to its @@ -30,12 +30,12 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', +# 'sphinx.ext.doctest', +# 'sphinx.ext.intersphinx', 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.imgmath', - 'sphinx.ext.ifconfig', +# 'sphinx.ext.coverage', +# 'sphinx.ext.imgmath', +# 'sphinx.ext.ifconfig', 'IPython.sphinxext.ipython_console_highlighting', # 'IPython.sphinxext.ipython_directive', ] @@ -53,17 +53,17 @@ master_doc = 'index' # General information about the project. -project = u'Python Topics' -copyright = u'2014, Christopher Barker' +project = 'Python Topics' +copyright = '2014-2025, Christopher Barker' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '1.0' +version = '2.0' # The full version, including alpha/beta/rc tags. -release = '1.0.0' +release = '2.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -116,8 +116,8 @@ #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# html_theme_path = [] +# html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". @@ -368,4 +368,4 @@ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} +# intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/Sources/source/interfacing_with_c/c_python.rst b/Sources/source/interfacing_with_c/c_python.rst index 82e7568..400542f 100644 --- a/Sources/source/interfacing_with_c/c_python.rst +++ b/Sources/source/interfacing_with_c/c_python.rst @@ -43,7 +43,7 @@ https://cython.org/ ctypes ------ -Ctypes comes with PYthon out of the box. +Ctypes comes with Python out of the box. SWIG, SIP, ETC. @@ -57,7 +57,14 @@ EXAMPLE: Same as the one for fortran: a automatic gain control filter: -:download:`agc_example.zip` +:download:`agc_example/agc_c.c` + +:download:`agc_example/agc_c_cy.pyx` + +:download:`agc_example/agc_cython.pyx` + +:download:`agc_example/agc_python.py` + diff --git a/Sources/source/weak_references.rst b/Sources/source/weak_references.rst index aae3fe1..f470565 100644 --- a/Sources/source/weak_references.rst +++ b/Sources/source/weak_references.rst @@ -13,6 +13,8 @@ Chris Barker ``https://github.com/PythonCHB`` +**NOTE:** These notes were written for Python 2. The principles remain the same (for now... work on a GIL-free python is close!), but Python 3 has stronger and smarter support for garbage collection, so this is all less critical (though still good to understand!) + ================== Memory Management ================== From e0a0101f3e85948e9b06344a9c374eee8e9b6f05 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 17:42:17 -0700 Subject: [PATCH 33/39] added publish workflow -- not tested ... --- .github/workflows/publish.yaml | 29 +++++++++++++++++++++ Sources/source/interfacing_with_c/index.rst | 11 ++++++++ 2 files changed, 40 insertions(+) create mode 100644 .github/workflows/publish.yaml create mode 100644 Sources/source/interfacing_with_c/index.rst diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..3c0f608 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,29 @@ +name: documentation + +on: [push, pull_request, workflow_dispatch] + +permissions: + contents: write + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + - name: Install dependencies + run: | + pip install -r Sources/requirements.txt + - name: Sphinx build + run: | + make html +# sphinx-build doc _build + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + with: + publish_branch: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: Sources/build/html + force_orphan: true + diff --git a/Sources/source/interfacing_with_c/index.rst b/Sources/source/interfacing_with_c/index.rst new file mode 100644 index 0000000..075206e --- /dev/null +++ b/Sources/source/interfacing_with_c/index.rst @@ -0,0 +1,11 @@ +Interfacing with Compiled Code +============================== + +Topics: +------- + +.. toctree:: + :maxdepth: 1 + + c_python.rst + fortran_python.rst From 4290993b4e3ce3fd5b5f03b2b65577e31c1db263 Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 22:50:50 -0700 Subject: [PATCH 34/39] set branch to master for publish --- .github/workflows/publish.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 3c0f608..3bf2a01 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -1,6 +1,8 @@ name: documentation -on: [push, pull_request, workflow_dispatch] +on: + push: + branches: [master] # branch to trigger deployment permissions: contents: write @@ -20,7 +22,7 @@ jobs: # sphinx-build doc _build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} with: publish_branch: gh-pages github_token: ${{ secrets.GITHUB_TOKEN }} From b61da494fac5f6ac4071fb824e8ffd1f44d4214b Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 22:57:11 -0700 Subject: [PATCH 35/39] updated actions --- .github/workflows/main.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a17a980..55fa176 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,8 @@ -name: Python package +name: Publish Pages on: [push] + push: + branches: [master] # branch to trigger deployment jobs: build: @@ -8,12 +10,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8] + python-version: [3.12] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 7277d6de381f2ff18af403bfcafb7b5e1f8abe1f Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 22:58:47 -0700 Subject: [PATCH 36/39] removed new non working publish workflow --- .github/workflows/publish.yaml | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index 3bf2a01..0000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: documentation - -on: - push: - branches: [master] # branch to trigger deployment - -permissions: - contents: write - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - - name: Install dependencies - run: | - pip install -r Sources/requirements.txt - - name: Sphinx build - run: | - make html -# sphinx-build doc _build - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - with: - publish_branch: gh-pages - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: Sources/build/html - force_orphan: true - From 7666b6bbb2b15aa235c04b5d53d9a1e45da292db Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 23:01:11 -0700 Subject: [PATCH 37/39] fixed yaml --- .github/workflows/flake8.yml | 26 -------------------------- .github/workflows/main.yml | 9 +++++++-- 2 files changed, 7 insertions(+), 28 deletions(-) delete mode 100644 .github/workflows/flake8.yml diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml deleted file mode 100644 index ef1acaf..0000000 --- a/.github/workflows/flake8.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Code Quality - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - lint: - name: Python Lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: "2.7" - - name: Run flake8 - uses: TrueBrain/actions-flake8@master - with: - path: Sources/code - ignore: E9,F63,F7,F82,E203,W293,E231,W291,W391,E265,E266,E226,E301,E228,E401,E303,E201,E202,E305,E501,E261 - - - - diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 55fa176..48f5bad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,8 +1,13 @@ name: Publish Pages -on: [push] +on: push: - branches: [master] # branch to trigger deployment + branches: [main] # branch to trigger deployment + +concurrency: + group: gh-${{ github.ref }} + cancel-in-progress: true + jobs: build: From 7e5152da290683918288c3122b3f39e0665ada6b Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 23:03:05 -0700 Subject: [PATCH 38/39] run on master --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 48f5bad..3daee83 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: Publish Pages on: push: - branches: [main] # branch to trigger deployment + branches: [master] # branch to trigger deployment concurrency: group: gh-${{ github.ref }} From 1469daf03e4c8febe820f776e7e17c8379345afa Mon Sep 17 00:00:00 2001 From: Chris Barker Date: Wed, 24 Sep 2025 23:05:31 -0700 Subject: [PATCH 39/39] updated publish action version --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3daee83..0c567ca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,6 @@ concurrency: group: gh-${{ github.ref }} cancel-in-progress: true - jobs: build: @@ -42,7 +41,7 @@ jobs: cd ./Sources; make html - name: Deploy - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./Sources/build/html