diff mbox series

[libgpiod,v2,v3,2/4] bindings: python: add examples

Message ID 20221007145521.329614-3-brgl@bgdev.pl
State New
Headers show
Series bindings: implement python bindings for libgpiod v2 | expand

Commit Message

Bartosz Golaszewski Oct. 7, 2022, 2:55 p.m. UTC
This adds the regular set of example programs implemented using libgpiod
python bindings.

Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
 bindings/python/examples/Makefile.am   | 10 +++++++
 bindings/python/examples/gpiodetect.py | 17 ++++++++++++
 bindings/python/examples/gpiofind.py   | 20 ++++++++++++++
 bindings/python/examples/gpioget.py    | 31 +++++++++++++++++++++
 bindings/python/examples/gpioinfo.py   | 35 ++++++++++++++++++++++++
 bindings/python/examples/gpiomon.py    | 28 +++++++++++++++++++
 bindings/python/examples/gpioset.py    | 37 ++++++++++++++++++++++++++
 7 files changed, 178 insertions(+)
 create mode 100644 bindings/python/examples/Makefile.am
 create mode 100755 bindings/python/examples/gpiodetect.py
 create mode 100755 bindings/python/examples/gpiofind.py
 create mode 100755 bindings/python/examples/gpioget.py
 create mode 100755 bindings/python/examples/gpioinfo.py
 create mode 100755 bindings/python/examples/gpiomon.py
 create mode 100755 bindings/python/examples/gpioset.py

Comments

Kent Gibson Oct. 13, 2022, 3:09 a.m. UTC | #1
On Fri, Oct 07, 2022 at 04:55:19PM +0200, Bartosz Golaszewski wrote:
> This adds the regular set of example programs implemented using libgpiod
> python bindings.
> 
> Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
> ---
>  bindings/python/examples/Makefile.am   | 10 +++++++
>  bindings/python/examples/gpiodetect.py | 17 ++++++++++++
>  bindings/python/examples/gpiofind.py   | 20 ++++++++++++++
>  bindings/python/examples/gpioget.py    | 31 +++++++++++++++++++++
>  bindings/python/examples/gpioinfo.py   | 35 ++++++++++++++++++++++++
>  bindings/python/examples/gpiomon.py    | 28 +++++++++++++++++++
>  bindings/python/examples/gpioset.py    | 37 ++++++++++++++++++++++++++
>  7 files changed, 178 insertions(+)
>  create mode 100644 bindings/python/examples/Makefile.am
>  create mode 100755 bindings/python/examples/gpiodetect.py
>  create mode 100755 bindings/python/examples/gpiofind.py
>  create mode 100755 bindings/python/examples/gpioget.py
>  create mode 100755 bindings/python/examples/gpioinfo.py
>  create mode 100755 bindings/python/examples/gpiomon.py
>  create mode 100755 bindings/python/examples/gpioset.py
> 
> diff --git a/bindings/python/examples/Makefile.am b/bindings/python/examples/Makefile.am
> new file mode 100644
> index 0000000..f42b80e
> --- /dev/null
> +++ b/bindings/python/examples/Makefile.am
> @@ -0,0 +1,10 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
> +
> +EXTRA_DIST = \
> +	gpiodetect.py \
> +	gpiofind.py \
> +	gpioget.py \
> +	gpioinfo.py \
> +	gpiomon.py \
> +	gpioset.py
> diff --git a/bindings/python/examples/gpiodetect.py b/bindings/python/examples/gpiodetect.py
> new file mode 100755
> index 0000000..c32014f
> --- /dev/null
> +++ b/bindings/python/examples/gpiodetect.py
> @@ -0,0 +1,17 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
> +
> +"""Reimplementation of the gpiodetect tool in Python."""
> +
> +import gpiod
> +import os
> +
> +if __name__ == "__main__":
> +    for entry in os.scandir("/dev/"):
> +        if gpiod.is_gpiochip_device(entry.path):

Add a helper generator function that returns the available chip paths?
And in order might be nice too.

> +            with gpiod.Chip(entry.path) as chip:
> +                info = chip.get_info()
> +                print(
> +                    "{} [{}] ({} lines)".format(info.name, info.label, info.num_lines)
> +                )
> diff --git a/bindings/python/examples/gpiofind.py b/bindings/python/examples/gpiofind.py
> new file mode 100755
> index 0000000..2f30445
> --- /dev/null
> +++ b/bindings/python/examples/gpiofind.py
> @@ -0,0 +1,20 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
> +
> +"""Reimplementation of the gpiofind tool in Python."""
> +
> +import gpiod
> +import os
> +import sys
> +
> +if __name__ == "__main__":
> +    for entry in os.scandir("/dev/"):
> +        if gpiod.is_gpiochip_device(entry.path):
> +            with gpiod.Chip(entry.path) as chip:
> +                offset = chip.map_line(sys.argv[1])

                            chip.offset_from_id(...

> +                if offset is not None:
> +                    print("{} {}".format(chip.get_info().name, offset))
> +                    sys.exit(0)
> +
> +    sys.exit(1)
> diff --git a/bindings/python/examples/gpioget.py b/bindings/python/examples/gpioget.py
> new file mode 100755
> index 0000000..d441535
> --- /dev/null
> +++ b/bindings/python/examples/gpioget.py
> @@ -0,0 +1,31 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
> +
> +"""Simplified reimplementation of the gpioget tool in Python."""
> +
> +import gpiod
> +import sys
> +
> +from gpiod.line import Direction
> +
> +if __name__ == "__main__":
> +    if len(sys.argv) < 3:
> +        raise TypeError("usage: gpioget.py <gpiochip> <offset1> <offset2> ...")
> +
> +    path = sys.argv[1]
> +    lines = []
> +    for line in sys.argv[2:]:
> +        lines.append(int(line) if line.isdigit() else line)
> +

Just leave the line ids as string?

else use a list comprehension:

    lines = [ int(id) if id.isdigit() else id for id in sys.argv[2:] ]

Similarly elsewhere.

> +    request = gpiod.request_lines(
> +        path,
> +        consumer="gpioget.py",
> +        config={tuple(lines): gpiod.LineSettings(direction=Direction.INPUT)},
> +    )
> +
> +    vals = request.get_values()
> +
> +    for val in vals:
> +        print("{} ".format(val.value), end="")
> +    print()
> diff --git a/bindings/python/examples/gpioinfo.py b/bindings/python/examples/gpioinfo.py
> new file mode 100755
> index 0000000..e8c7d46
> --- /dev/null
> +++ b/bindings/python/examples/gpioinfo.py
> @@ -0,0 +1,35 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
> +
> +"""Simplified reimplementation of the gpioinfo tool in Python."""
> +
> +import gpiod
> +import os
> +
> +if __name__ == "__main__":
> +    for entry in os.scandir("/dev/"):
> +        if gpiod.is_gpiochip_device(entry.path):
> +            with gpiod.Chip(entry.path) as chip:
> +                cinfo = chip.get_info()
> +                print("{} - {} lines:".format(cinfo.name, cinfo.num_lines))
> +
> +                for offset in range(0, cinfo.num_lines):
> +                    linfo = chip.get_line_info(offset)
> +                    offset = linfo.offset
> +                    name = linfo.name
> +                    consumer = linfo.consumer
> +                    direction = linfo.direction

                    is_input = linfo.direction == gpiod.line.Direction.INPUT

That is for space saving below.
Drop the others as they are only referenced once (if you follow the
suggestion below).

> +                    active_low = linfo.active_low
> +
> +                    print(
> +                        "\tline {:>3}: {:>18} {:>12} {:>8} {:>10}".format(
> +                            offset,
> +                            "unnamed" if name is None else name,
> +                            "unused" if consumer is None else consumer,
> +                            "input"
> +                            if direction == gpiod.line.Direction.INPUT
> +                            else "output",
> +                            "active-low" if active_low else "active-high",
                        linfo.offset,
                        linfo.name or "unnamed",
                        linfo.consumer or "unused",
                        is_input and "input" or "output",
                        linfo.active_low and "active_low" or "active-high",

> +                        )
> +                    )
> diff --git a/bindings/python/examples/gpiomon.py b/bindings/python/examples/gpiomon.py
> new file mode 100755
> index 0000000..e0db16f
> --- /dev/null
> +++ b/bindings/python/examples/gpiomon.py
> @@ -0,0 +1,28 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
> +
> +"""Simplified reimplementation of the gpiomon tool in Python."""
> +
> +import gpiod
> +import sys
> +
> +from gpiod.line import Edge
> +
> +if __name__ == "__main__":
> +    if len(sys.argv) < 3:
> +        raise TypeError("usage: gpiomon.py <gpiochip> <offset1> <offset2> ...")
> +
> +    path = sys.argv[1]
> +    lines = []
> +    for line in sys.argv[2:]:
> +        lines.append(int(line) if line.isdigit() else line)
> +
> +    with gpiod.request_lines(
> +        path,
> +        consumer="gpiomon.py",
> +        config={tuple(lines): gpiod.LineSettings(edge_detection=Edge.BOTH)},
> +    ) as request:
> +        while True:
> +            for event in request.read_edge_event():
> +                print(event)
> diff --git a/bindings/python/examples/gpioset.py b/bindings/python/examples/gpioset.py
> new file mode 100755
> index 0000000..f0b0681
> --- /dev/null
> +++ b/bindings/python/examples/gpioset.py
> @@ -0,0 +1,37 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
> +
> +"""Simplified reimplementation of the gpioset tool in Python."""
> +
> +import gpiod
> +import sys
> +
> +from gpiod.line import Direction, Value
> +
> +if __name__ == "__main__":
> +    if len(sys.argv) < 3:
> +        raise TypeError(
> +            "usage: gpioset.py <gpiochip> <offset1>=<value1> <offset2>=<value2> ..."
> +        )
> +
> +    path = sys.argv[1]
> +    values = dict()
> +    lines = []
> +    for arg in sys.argv[2:]:
> +        arg = arg.split("=")
> +        key = int(arg[0]) if arg[0].isdigit() else arg[0]
> +        val = int(arg[1])
> +
> +        lines.append(key)
> +        values[key] = Value(val)
> +

        lvs = [ arg.split('=') for arg in sys.argv[2:] ]
        lines = [ x[0] for x in lvs ]
        values = dict[lvs]

> +    request = gpiod.request_lines(
> +        path,
> +        consumer="gpioset.py",
> +        config={tuple(lines): gpiod.LineSettings(direction=Direction.OUTPUT)},
> +    )
> +
> +    vals = request.set_values(values)
> +
> +    input()
> -- 

No gpiowatch?

Add some examples for features the tools don't use, like requests with
both inputs and outputs, and reconfigure?

Cheers,
Kent.
Kent Gibson Oct. 17, 2022, 12:11 p.m. UTC | #2
On Mon, Oct 17, 2022 at 02:00:15PM +0200, Bartosz Golaszewski wrote:
> On Thu, Oct 13, 2022 at 5:09 AM Kent Gibson <warthog618@gmail.com> wrote:
> >
> > On Fri, Oct 07, 2022 at 04:55:19PM +0200, Bartosz Golaszewski wrote:
> > > This adds the regular set of example programs implemented using libgpiod
> > > python bindings.
> > >
> > > Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
> > > +    path = sys.argv[1]
> > > +    values = dict()
> > > +    lines = []
> > > +    for arg in sys.argv[2:]:
> > > +        arg = arg.split("=")
> > > +        key = int(arg[0]) if arg[0].isdigit() else arg[0]
> > > +        val = int(arg[1])
> > > +
> > > +        lines.append(key)
> > > +        values[key] = Value(val)
> > > +
> >
> >         lvs = [ arg.split('=') for arg in sys.argv[2:] ]
            lvs = [ (x,int(y)) for (x,y) in lvs ]
> >         lines = [ x[0] for x in lvs ]
> >         values = dict(lvs)
> 

An extra pass to fix the int values.
You could do it in one with a more appropriate parser function.

Cheers,
Kent.
Andy Shevchenko Oct. 17, 2022, 1:49 p.m. UTC | #3
On Mon, Oct 17, 2022 at 08:11:28PM +0800, Kent Gibson wrote:
> On Mon, Oct 17, 2022 at 02:00:15PM +0200, Bartosz Golaszewski wrote:
> > On Thu, Oct 13, 2022 at 5:09 AM Kent Gibson <warthog618@gmail.com> wrote:
> > > On Fri, Oct 07, 2022 at 04:55:19PM +0200, Bartosz Golaszewski wrote:
> > > > This adds the regular set of example programs implemented using libgpiod
> > > > python bindings.
> > > >
> > > > Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
> > > > +    path = sys.argv[1]
> > > > +    values = dict()
> > > > +    lines = []
> > > > +    for arg in sys.argv[2:]:
> > > > +        arg = arg.split("=")
> > > > +        key = int(arg[0]) if arg[0].isdigit() else arg[0]
> > > > +        val = int(arg[1])
> > > > +
> > > > +        lines.append(key)
> > > > +        values[key] = Value(val)
> > > > +
> > >
> > >         lvs = [ arg.split('=') for arg in sys.argv[2:] ]
>             lvs = [ (x,int(y)) for (x,y) in lvs ]
> > >         lines = [ x[0] for x in lvs ]
> > >         values = dict(lvs)
> > 
> 
> An extra pass to fix the int values.

In Python we have map(), which I think is the best for that kind of job.

> You could do it in one with a more appropriate parser function.

It seems we need some Python guru to revisit the code, because to me
it looks a bit C:ish :-)

Maybe I can ask colleague of mine, if he has time for a such...
No guarantees, though.
Kent Gibson Oct. 17, 2022, 2:07 p.m. UTC | #4
On Mon, Oct 17, 2022 at 04:49:55PM +0300, Andy Shevchenko wrote:
> On Mon, Oct 17, 2022 at 08:11:28PM +0800, Kent Gibson wrote:
> > On Mon, Oct 17, 2022 at 02:00:15PM +0200, Bartosz Golaszewski wrote:
> > > On Thu, Oct 13, 2022 at 5:09 AM Kent Gibson <warthog618@gmail.com> wrote:
> > > > On Fri, Oct 07, 2022 at 04:55:19PM +0200, Bartosz Golaszewski wrote:
> > > > > This adds the regular set of example programs implemented using libgpiod
> > > > > python bindings.
> > > > >
> > > > > Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
> > > > > +    path = sys.argv[1]
> > > > > +    values = dict()
> > > > > +    lines = []
> > > > > +    for arg in sys.argv[2:]:
> > > > > +        arg = arg.split("=")
> > > > > +        key = int(arg[0]) if arg[0].isdigit() else arg[0]
> > > > > +        val = int(arg[1])
> > > > > +
> > > > > +        lines.append(key)
> > > > > +        values[key] = Value(val)
> > > > > +
> > > >
> > > >         lvs = [ arg.split('=') for arg in sys.argv[2:] ]
> >             lvs = [ (x,int(y)) for (x,y) in lvs ]
> > > >         lines = [ x[0] for x in lvs ]
> > > >         values = dict(lvs)
> > > 
> > 
> > An extra pass to fix the int values.
> 
> In Python we have map(), which I think is the best for that kind of job.
> 

My understanding is map/filter is old school and list comprehensions
have replaced map, as generators have replaced filter.

i.e.
    list(map(function, iterable))
becomes
    [function(x) for x in iterable]

Either way, what we are missing here is a parser function that gives us
exactly the (offset,value) output we want from the command line string.

Oh, and we need both the lines list and the values dict, both of which
are easily created from the interim lvs.

> > You could do it in one with a more appropriate parser function.
> 
> It seems we need some Python guru to revisit the code, because to me
> it looks a bit C:ish :-)
> 

The for loop or the list comprehension?
Last I checked only one of those is available in C.
And yeah, the for loop version reads as C, so not at all Pythonic,
which is why I suggested the list comprehension.

> Maybe I can ask colleague of mine, if he has time for a such...
> No guarantees, though.
> 

Maybe I'm wrong and they've flipped back to map/filter.
Stanger things have happened.

Cheers,
Kent.
Bartosz Golaszewski Oct. 17, 2022, 3:53 p.m. UTC | #5
On Mon, Oct 17, 2022 at 4:19 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Mon, Oct 17, 2022 at 10:07:17PM +0800, Kent Gibson wrote:
> > On Mon, Oct 17, 2022 at 04:49:55PM +0300, Andy Shevchenko wrote:
> > > On Mon, Oct 17, 2022 at 08:11:28PM +0800, Kent Gibson wrote:
> > > > On Mon, Oct 17, 2022 at 02:00:15PM +0200, Bartosz Golaszewski wrote:
> > > > > On Thu, Oct 13, 2022 at 5:09 AM Kent Gibson <warthog618@gmail.com> wrote:
> > > > > > On Fri, Oct 07, 2022 at 04:55:19PM +0200, Bartosz Golaszewski wrote:
>
> ...
>
> > > > > >         lvs = [ arg.split('=') for arg in sys.argv[2:] ]
> > > >             lvs = [ (x,int(y)) for (x,y) in lvs ]
> > > > > >         lines = [ x[0] for x in lvs ]
> > > > > >         values = dict(lvs)
> > > > >
> > > >
> > > > An extra pass to fix the int values.
> > >
> > > In Python we have map(), which I think is the best for that kind of job.
> > >
> >
> > My understanding is map/filter is old school and list comprehensions
> > have replaced map, as generators have replaced filter.
> >
> > i.e.
> >     list(map(function, iterable))
> > becomes
> >     [function(x) for x in iterable]
>
> Definitely it does not cover all the cases map() is taking care of.
> So it can't be old school :-)
>
> * Yes, in this particular case it may be map() or list comprehension.
>   But I think with map() the two lines can become one.
>
> > Either way, what we are missing here is a parser function that gives us
> > exactly the (offset,value) output we want from the command line string.
> >
> > Oh, and we need both the lines list and the values dict, both of which
> > are easily created from the interim lvs.
> >
> > > > You could do it in one with a more appropriate parser function.
> > >
> > > It seems we need some Python guru to revisit the code, because to me
> > > it looks a bit C:ish :-)
> >
> > The for loop or the list comprehension?
> > Last I checked only one of those is available in C.
> > And yeah, the for loop version reads as C, so not at all Pythonic,
> > which is why I suggested the list comprehension.
>
> Yes, but I believe it does not utilize the powerfulness of the current Python.
> Anyway, I'm not a Py guru, take my remarks with a grain of salt.
>

How about this?

    lvs = list(
        map(
            lambda val: [val[0], Value(int(val[1]))],
            [arg.split("=") for arg in sys.argv[2:]],
        )
    )
    lines = [x[0] for x in lvs]
    values = dict(lvs)

It's so much less readable but at least it's pythonic, look at those
lambdas and comprehension lists and even a map! :)

Anyway - unlike the programming interface - these are just
implementation details that can be always improved later.

Bart
Kent Gibson Oct. 17, 2022, 4:20 p.m. UTC | #6
On Tue, Oct 18, 2022 at 12:09:10AM +0800, Kent Gibson wrote:
> On Mon, Oct 17, 2022 at 05:53:52PM +0200, Bartosz Golaszewski wrote:
> > On Mon, Oct 17, 2022 at 4:19 PM Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> wrote:
> > >
> > > On Mon, Oct 17, 2022 at 10:07:17PM +0800, Kent Gibson wrote:
> > > > On Mon, Oct 17, 2022 at 04:49:55PM +0300, Andy Shevchenko wrote:
> > > > > On Mon, Oct 17, 2022 at 08:11:28PM +0800, Kent Gibson wrote:
> > > > > > On Mon, Oct 17, 2022 at 02:00:15PM +0200, Bartosz Golaszewski wrote:
> > > > > > > On Thu, Oct 13, 2022 at 5:09 AM Kent Gibson <warthog618@gmail.com> wrote:
> > > > > > > > On Fri, Oct 07, 2022 at 04:55:19PM +0200, Bartosz Golaszewski wrote:
> > >
> > > ...
> > >
> > > > > > > >         lvs = [ arg.split('=') for arg in sys.argv[2:] ]
> > > > > >             lvs = [ (x,int(y)) for (x,y) in lvs ]
> > > > > > > >         lines = [ x[0] for x in lvs ]
> > > > > > > >         values = dict(lvs)
> > > > > > >
> > > > > >
> > > > > > An extra pass to fix the int values.
> > > > >
> > > > > In Python we have map(), which I think is the best for that kind of job.
> > > > >
> > > >
> > > > My understanding is map/filter is old school and list comprehensions
> > > > have replaced map, as generators have replaced filter.
> > > >
> > > > i.e.
> > > >     list(map(function, iterable))
> > > > becomes
> > > >     [function(x) for x in iterable]
> > >
> > > Definitely it does not cover all the cases map() is taking care of.
> > > So it can't be old school :-)
> > >
> > > * Yes, in this particular case it may be map() or list comprehension.
> > >   But I think with map() the two lines can become one.
> > >
> > > > Either way, what we are missing here is a parser function that gives us
> > > > exactly the (offset,value) output we want from the command line string.
> > > >
> > > > Oh, and we need both the lines list and the values dict, both of which
> > > > are easily created from the interim lvs.
> > > >
> > > > > > You could do it in one with a more appropriate parser function.
> > > > >
> > > > > It seems we need some Python guru to revisit the code, because to me
> > > > > it looks a bit C:ish :-)
> > > >
> > > > The for loop or the list comprehension?
> > > > Last I checked only one of those is available in C.
> > > > And yeah, the for loop version reads as C, so not at all Pythonic,
> > > > which is why I suggested the list comprehension.
> > >
> > > Yes, but I believe it does not utilize the powerfulness of the current Python.
> > > Anyway, I'm not a Py guru, take my remarks with a grain of salt.
> > >
> > 
> > How about this?
> > 
> >     lvs = list(
> >         map(
> >             lambda val: [val[0], Value(int(val[1]))],
> >             [arg.split("=") for arg in sys.argv[2:]],
> >         )
> >     )
> 
> which is the same as
> 
>     lvs = [ (x,Value(int(y))) for (x,y) in [ arg.split("=") for arg in sys.argv[2:]] ]
> 
> which is the same as my two liner, just nested - though it may only
> iterate through the list once if the inner list comprehension is
> treated as a generator.  Not sure.
> 
> Either way, not too fussed - it is only example code.
> As long as it isn't a for loop ;-).
> 

Oh, btw, the parser fn version would be something like:

def parse_value(arg):
     (x,y) = arg.split("=")
     return (x, Value(int(y)))

lvs = [ parse_value(arg) for arg in sys.argv[2:]
...

Is that clearer?

Cheers,
Kent.
Kent Gibson Oct. 17, 2022, 4:39 p.m. UTC | #7
On Mon, Oct 17, 2022 at 07:24:40PM +0300, Andy Shevchenko wrote:
> On Mon, Oct 17, 2022 at 05:53:52PM +0200, Bartosz Golaszewski wrote:
> > On Mon, Oct 17, 2022 at 4:19 PM Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> wrote:
> 
> ...
> 
> > How about this?
> > 
> >     lvs = list(
> >         map(
> >             lambda val: [val[0], Value(int(val[1]))],
> >             [arg.split("=") for arg in sys.argv[2:]],
> >         )
> >     )
> 
> Yeah, this looks ugly... So initial variant with two lines looks to me
> like this:
> 
>   lvs = [arg.split("=") for arg in sys.argv[2:]] # btw, needs handling 2 exceptions
>   values = dict((x, Value(int(y))) for (x,y) in lvs) # needs to handle an exception
>   # Perhaps you need ordered dict?
>   lines = values.keys()
> 

Indeed, an OrderedDict keys would provide the lines in argv order, so values.keys()
could be used in place of lines.

And if you use a parser function then it can deal with the parsing exceptions.

   values = OrderedDict([ parse(arg) for args in sys.argv[2:] ])

Cheers,
Kent.

> >     lines = [x[0] for x in lvs]
> >     values = dict(lvs)
> 
> > It's so much less readable but at least it's pythonic, look at those
> > lambdas and comprehension lists and even a map! :)
> 
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
>
Andy Shevchenko Oct. 17, 2022, 4:57 p.m. UTC | #8
On Mon, Oct 17, 2022 at 07:55:41PM +0300, Andy Shevchenko wrote:
> On Tue, Oct 18, 2022 at 12:20:18AM +0800, Kent Gibson wrote:
> > On Tue, Oct 18, 2022 at 12:09:10AM +0800, Kent Gibson wrote:

...

> > Oh, btw, the parser fn version would be something like:
> > 
> > def parse_value(arg):
> >      (x,y) = arg.split("=")
> >      return (x, Value(int(y)))
> 
> Not a lisp, no need for too many parentheses. Also, we could use splices:
> 
> 	eqidx = arg.index('=')
> 	return arg[:eqidx], Value(int(arg[eqidx + 1:]))
> 
> or with split()
> 
> 	l, v = arg.split('=')
> 	return l, Value(int(v))
> 
> > lvs = [ parse_value(arg) for arg in sys.argv[2:]
> 
> Dunno why you put spaces inside outer [], but okay.

and this actually can be directly put to the dict constructor:

	values = OrderedDict(parse_value(arg) for arg in sys.argv[2:])

This looks short enough and readable.
Bartosz Golaszewski Oct. 17, 2022, 5:26 p.m. UTC | #9
On Mon, Oct 17, 2022 at 6:57 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Mon, Oct 17, 2022 at 07:55:41PM +0300, Andy Shevchenko wrote:
> > On Tue, Oct 18, 2022 at 12:20:18AM +0800, Kent Gibson wrote:
> > > On Tue, Oct 18, 2022 at 12:09:10AM +0800, Kent Gibson wrote:
>
> ...
>
> > > Oh, btw, the parser fn version would be something like:
> > >
> > > def parse_value(arg):
> > >      (x,y) = arg.split("=")
> > >      return (x, Value(int(y)))
> >
> > Not a lisp, no need for too many parentheses. Also, we could use splices:
> >
> >       eqidx = arg.index('=')
> >       return arg[:eqidx], Value(int(arg[eqidx + 1:]))
> >
> > or with split()
> >
> >       l, v = arg.split('=')
> >       return l, Value(int(v))
> >
> > > lvs = [ parse_value(arg) for arg in sys.argv[2:]
> >
> > Dunno why you put spaces inside outer [], but okay.
>
> and this actually can be directly put to the dict constructor:
>
>         values = OrderedDict(parse_value(arg) for arg in sys.argv[2:])
>
> This looks short enough and readable.
>

Let's stop bikeshedding, I'll move on to stuff that really matters now. :)

Bartosz
diff mbox series

Patch

diff --git a/bindings/python/examples/Makefile.am b/bindings/python/examples/Makefile.am
new file mode 100644
index 0000000..f42b80e
--- /dev/null
+++ b/bindings/python/examples/Makefile.am
@@ -0,0 +1,10 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+EXTRA_DIST = \
+	gpiodetect.py \
+	gpiofind.py \
+	gpioget.py \
+	gpioinfo.py \
+	gpiomon.py \
+	gpioset.py
diff --git a/bindings/python/examples/gpiodetect.py b/bindings/python/examples/gpiodetect.py
new file mode 100755
index 0000000..c32014f
--- /dev/null
+++ b/bindings/python/examples/gpiodetect.py
@@ -0,0 +1,17 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+"""Reimplementation of the gpiodetect tool in Python."""
+
+import gpiod
+import os
+
+if __name__ == "__main__":
+    for entry in os.scandir("/dev/"):
+        if gpiod.is_gpiochip_device(entry.path):
+            with gpiod.Chip(entry.path) as chip:
+                info = chip.get_info()
+                print(
+                    "{} [{}] ({} lines)".format(info.name, info.label, info.num_lines)
+                )
diff --git a/bindings/python/examples/gpiofind.py b/bindings/python/examples/gpiofind.py
new file mode 100755
index 0000000..2f30445
--- /dev/null
+++ b/bindings/python/examples/gpiofind.py
@@ -0,0 +1,20 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+"""Reimplementation of the gpiofind tool in Python."""
+
+import gpiod
+import os
+import sys
+
+if __name__ == "__main__":
+    for entry in os.scandir("/dev/"):
+        if gpiod.is_gpiochip_device(entry.path):
+            with gpiod.Chip(entry.path) as chip:
+                offset = chip.map_line(sys.argv[1])
+                if offset is not None:
+                    print("{} {}".format(chip.get_info().name, offset))
+                    sys.exit(0)
+
+    sys.exit(1)
diff --git a/bindings/python/examples/gpioget.py b/bindings/python/examples/gpioget.py
new file mode 100755
index 0000000..d441535
--- /dev/null
+++ b/bindings/python/examples/gpioget.py
@@ -0,0 +1,31 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+"""Simplified reimplementation of the gpioget tool in Python."""
+
+import gpiod
+import sys
+
+from gpiod.line import Direction
+
+if __name__ == "__main__":
+    if len(sys.argv) < 3:
+        raise TypeError("usage: gpioget.py <gpiochip> <offset1> <offset2> ...")
+
+    path = sys.argv[1]
+    lines = []
+    for line in sys.argv[2:]:
+        lines.append(int(line) if line.isdigit() else line)
+
+    request = gpiod.request_lines(
+        path,
+        consumer="gpioget.py",
+        config={tuple(lines): gpiod.LineSettings(direction=Direction.INPUT)},
+    )
+
+    vals = request.get_values()
+
+    for val in vals:
+        print("{} ".format(val.value), end="")
+    print()
diff --git a/bindings/python/examples/gpioinfo.py b/bindings/python/examples/gpioinfo.py
new file mode 100755
index 0000000..e8c7d46
--- /dev/null
+++ b/bindings/python/examples/gpioinfo.py
@@ -0,0 +1,35 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+"""Simplified reimplementation of the gpioinfo tool in Python."""
+
+import gpiod
+import os
+
+if __name__ == "__main__":
+    for entry in os.scandir("/dev/"):
+        if gpiod.is_gpiochip_device(entry.path):
+            with gpiod.Chip(entry.path) as chip:
+                cinfo = chip.get_info()
+                print("{} - {} lines:".format(cinfo.name, cinfo.num_lines))
+
+                for offset in range(0, cinfo.num_lines):
+                    linfo = chip.get_line_info(offset)
+                    offset = linfo.offset
+                    name = linfo.name
+                    consumer = linfo.consumer
+                    direction = linfo.direction
+                    active_low = linfo.active_low
+
+                    print(
+                        "\tline {:>3}: {:>18} {:>12} {:>8} {:>10}".format(
+                            offset,
+                            "unnamed" if name is None else name,
+                            "unused" if consumer is None else consumer,
+                            "input"
+                            if direction == gpiod.line.Direction.INPUT
+                            else "output",
+                            "active-low" if active_low else "active-high",
+                        )
+                    )
diff --git a/bindings/python/examples/gpiomon.py b/bindings/python/examples/gpiomon.py
new file mode 100755
index 0000000..e0db16f
--- /dev/null
+++ b/bindings/python/examples/gpiomon.py
@@ -0,0 +1,28 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+"""Simplified reimplementation of the gpiomon tool in Python."""
+
+import gpiod
+import sys
+
+from gpiod.line import Edge
+
+if __name__ == "__main__":
+    if len(sys.argv) < 3:
+        raise TypeError("usage: gpiomon.py <gpiochip> <offset1> <offset2> ...")
+
+    path = sys.argv[1]
+    lines = []
+    for line in sys.argv[2:]:
+        lines.append(int(line) if line.isdigit() else line)
+
+    with gpiod.request_lines(
+        path,
+        consumer="gpiomon.py",
+        config={tuple(lines): gpiod.LineSettings(edge_detection=Edge.BOTH)},
+    ) as request:
+        while True:
+            for event in request.read_edge_event():
+                print(event)
diff --git a/bindings/python/examples/gpioset.py b/bindings/python/examples/gpioset.py
new file mode 100755
index 0000000..f0b0681
--- /dev/null
+++ b/bindings/python/examples/gpioset.py
@@ -0,0 +1,37 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+"""Simplified reimplementation of the gpioset tool in Python."""
+
+import gpiod
+import sys
+
+from gpiod.line import Direction, Value
+
+if __name__ == "__main__":
+    if len(sys.argv) < 3:
+        raise TypeError(
+            "usage: gpioset.py <gpiochip> <offset1>=<value1> <offset2>=<value2> ..."
+        )
+
+    path = sys.argv[1]
+    values = dict()
+    lines = []
+    for arg in sys.argv[2:]:
+        arg = arg.split("=")
+        key = int(arg[0]) if arg[0].isdigit() else arg[0]
+        val = int(arg[1])
+
+        lines.append(key)
+        values[key] = Value(val)
+
+    request = gpiod.request_lines(
+        path,
+        consumer="gpioset.py",
+        config={tuple(lines): gpiod.LineSettings(direction=Direction.OUTPUT)},
+    )
+
+    vals = request.set_values(values)
+
+    input()