linuxpy


Namelinuxpy JSON
Version 0.20.0 PyPI version JSON
download
home_pageNone
SummaryHuman friendly interface to linux subsystems using python
upload_time2024-10-21 05:59:35
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseGPL-3.0-or-later
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # linuxpy

[![linuxpy][pypi-version]](https://pypi.python.org/pypi/linuxpy)
[![Python Versions][pypi-python-versions]](https://pypi.python.org/pypi/linuxpy)
![License][license]
[![CI][CI]](https://github.com/tiagocoutinho/linuxpy/actions/workflows/ci.yml)

[![Source][source]](https://github.com/tiagocoutinho/linuxpy/)
[![Documentation][documentation]](https://tiagocoutinho.github.io/linuxpy/)

Human friendly interface to linux subsystems using python.

Provides python access to several linux subsystems like V4L2, GPIO, Led, thermal,
input and MIDI.

There is experimental, undocumented, incomplete and unstable access to USB.

Requirements:
* python >= 3.9
* Fairly recent linux kernel
* Installed kernel modules you want to access

And yes, it is true: there are no python libraries required! Also there are no
C libraries required. Everything is done here through direct ioctl, read and
write calls. Ain't linux wonderful?

## Installation

From within your favorite python environment:

```console
$ pip install linuxpy
```

To run the examples you'll need:

```console
$ pip install linuxpy[examples]
```

To develop, run tests, build package, lint, etc you'll need:

```console
$ pip install linuxpy[dev]
```

## Subsystems

### Video

Video for Linux 2 (V4L2) python library

Without further ado:

```python
>>> from linuxpy.video.device import Device
>>> with Device.from_id(0) as cam:
>>>     for i, frame in enumerate(cam):
...         print(f"frame #{i}: {len(frame)} bytes")
...         if i > 9:
...             break
...
frame #0: 54630 bytes
frame #1: 50184 bytes
frame #2: 44054 bytes
frame #3: 42822 bytes
frame #4: 42116 bytes
frame #5: 41868 bytes
frame #6: 41322 bytes
frame #7: 40896 bytes
frame #8: 40844 bytes
frame #9: 40714 bytes
frame #10: 40662 bytes
```

Getting information about the device:

```python
>>> from linuxpy.video.device import Device, BufferType

>>> cam = Device.from_id(0)
>>> cam.open()
>>> cam.info.card
'Integrated_Webcam_HD: Integrate'

>>> cam.info.capabilities
<Capability.STREAMING|EXT_PIX_FORMAT|VIDEO_CAPTURE: 69206017>

>>> cam.info.formats
[ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'Motion-JPEG',
             flags=<ImageFormatFlag.COMPRESSED: 1>, pixelformat=<PixelFormat.MJPEG: 1196444237>),
 ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'YUYV 4:2:2',
             flags=<ImageFormatFlag.0: 0>, pixelformat=<PixelFormat.YUYV: 1448695129>)]

>>> cam.get_format(BufferType.VIDEO_CAPTURE)
Format(width=640, height=480, pixelformat=<PixelFormat.MJPEG: 1196444237>}

>>> for ctrl in cam.controls.values(): print(ctrl)
<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>
<IntegerControl contrast min=0 max=255 step=1 default=32 value=32>
...
<BooleanControl exposure_dynamic_framerate default=False value=False>

>>> cam.controls.brightness
<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>
>>> cam.controls.brightness.value = 64
>>> cam.controls.brightness
<IntegerControl brightness min=0 max=255 step=1 default=128 value=64>
```

(see also [v4l2py-ctl](examples/video/v4l2py-ctl.py) example)

#### asyncio

linuxpy.video is asyncio friendly:

```console
$ python -m asyncio

>>> from linuxpy.video.device import Device
>>> with Device.from_id(0) as camera:
...     async for frame in camera:
...         print(f"frame {len(frame)}")
frame 10224
frame 10304
frame 10224
frame 10136
...
```

(check [basic async](examples/video/basic_async.py) and [web async](examples/video/web/async.py) examples)

#### gevent

linuxpy.video is also gevent friendly:

```
$ python

>>> from linuxpy.io import GeventIO
>>> from linuxpy.video.device import Device
>>> with Device.from_id(0, io=GeventIO) as camera:
...     for frame in camera:
...         print(f"frame {len(frame)}")
frame 10224
frame 10304
frame 10224
frame 10136
...
```

(check [basic gevent](examples/basic_gevent.py) and [web gevent](examples/web/sync.py) examples)

#### Video output

It is possible to write to a video output capable device (ex: v4l2loopback).
The following example shows how to grab frames from device 0 and write them
to device 10

```console
>>> from linuxpy.video.device import Device, VideoOutput, BufferType
>>> dev_source = Device.from_id(0)
>>> dev_sink = Device.from_id(10)
>>> with dev_source, dev_target:
>>>     source = VideoCapture(dev_source)
>>>     sink = VideoOutput(dev_sink)
>>>     source.set_format(640, 480, "MJPG")
>>>     sink.set_format(640, 480, "MJPG")
>>>     with source, sink:
>>>         for frame in source:
>>>             sink.write(frame.data)
```

#### Bonus track

You've been patient enough to read until here so, just for you,
a 20 line gem: a flask web server displaying your device on the web:

```console
$ pip install flask
```

```python
# web.py

import flask
from linuxpy.video.device import Device

app = flask.Flask('basic-web-cam')

def gen_frames():
    with Device.from_id(0) as cam:
        for frame in cam:
            yield b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + frame.data + b"\r\n"

@app.route("/")
def index():
    return '<html><img src="/stream" /></html>'

@app.route("/stream")
def stream():
    return flask.Response(
        gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
```

run with:

```console
$ FLASK_APP=web flask run -h 0.0.0.0
```

Point your browser to [127.0.0.1:5000](http://127.0.0.1:5000) and you should see
your camera rolling!

#### v4l2loopback

Start from scratch:
```console
# Remove kernel module and all devices (no client can be connected at this point)
sudo modprobe -r v4l2loopback

# Install some devices
sudo modprobe v4l2loopback video_nr=20,21 card_label="Loopback 0","Loopback 1"
```

#### References

See the ``linux/videodev2.h`` header file for details.


* [V4L2 (Latest)](https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/v4l2.html) ([videodev.h](https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/videodev.html))
* [V4L2 6.2](https://www.kernel.org/doc/html/v6.2/userspace-api/media/v4l/v4l2.html) ([videodev.h](https://www.kernel.org/doc/html/v6.2/userspace-api/media/v4l/videodev.html))


### Input

API not documented yet. Just this example:

```python
import time
from linuxpy.input.device import find_gamepads

pad = next(find_gamepads())
abs = pad.absolute

with pad:
    while True:
	    print(f"X:{abs.x:>3} | Y:{abs.y:>3} | RX:{abs.rx:>3} | RY:{abs.ry:>3}", end="\r", flush=True)
	    time.sleep(0.1)
```

#### asyncio

```console
$ python -m asyncio

>>> from linuxpy.input.device import find_gamepads
>>> with next(find_gamepads()) as pad:
...     async for event in pad:
...         print(event)
InputEvent(time=1697520475.348099, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0)
InputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1)
InputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.Y: 1>, value=1)
InputEvent(time=1697520475.361564, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0)
InputEvent(time=1697520475.371128, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1)
InputEvent(time=1697520475.371128, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0)
...
```

#### References

* [Input (Latest)](https://www.kernel.org/doc/html/latest/input/)
* [Input 6.2](https://www.kernel.org/doc/html/v6.2/input/)

### MIDI Sequencer

```console
$ python

>>> from linuxpy.midi.device import Sequencer, event_stream

>>> seq = Sequencer()
>>> with seq:
        port = seq.create_port()
        port.connect_from(14, 0)
        for event in seq:
            print(event)
 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0
 14:0   Clock                queue=0, pad=b''
 14:0   System exclusive     F0 61 62 63 F7
 14:0   Note off             channel=0, note=55, velocity=3, off_velocity=0, duration=0
```

#### asyncio

asyncio is a first class citizen to linuxpy.midi:

```console
$ python -m asyncio

>>> from linuxpy.midi.device import Sequencer, async_event_stream

>>> seq = Sequencer()
>>> with seq:
        port = seq.create_port()
        port.connect_from(14, 0)
        async for event in async_event_stream(seq):
            print(event)
 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0
 14:0   Clock                queue=0, pad=b''
 14:0   System exclusive     F0 61 62 63 F7
 14:0   Note off             channel=0, note=55, velocity=3, off_velocity=0, duration=0
```

#### CLI

A basic CLI is provided that allows listing MIDI clients & ports
and dumping MIDI sequencer events:

```console
$ python -m linuxpy.midi.cli ls
 Port   Client                   Port                     Type                           Capabilities
  0:0   System                   Timer                    0                              SR, W, R
  0:1   System                   Announce                 0                              SR, R
 14:0   Midi Through             Midi Through Port-0      PORT, SOFTWARE, MIDI_GENERIC   SW, SR, W, R
```

```console
$ python -m linuxpy.midi.cli listen 0:1 14:0
  0:1   Port subscribed      sender=(client=0, port=1), dest=(client=128, port=0)
  0:1   Port start           client=128, port=1
  0:1   Port subscribed      sender=(client=14, port=0), dest=(client=128, port=1)
  0:1   Client start         client=130, port=0
  0:1   Port start           client=130, port=0
  0:1   Port subscribed      sender=(client=130, port=0), dest=(client=14, port=0)
 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0
  0:1   Port unsubscribed    sender=(client=130, port=0), dest=(client=14, port=0)
  0:1   Port exit            client=130, port=0
  0:1   Client exit          client=130, port=0
  0:1   Port exit            client=129, port=0
  0:1   Client exit          client=129, port=0
  0:1   Client start         client=129, port=0
  0:1   Port start           client=129, port=0
 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0
 14:0   Note on              channel=0, note=0, velocity=255, off_velocity=0, duration=0
 14:0   Note on              channel=0, note=0, velocity=255, off_velocity=0, duration=0
```

[pypi-python-versions]: https://img.shields.io/pypi/pyversions/linuxpy.svg
[pypi-version]: https://img.shields.io/pypi/v/linuxpy.svg
[pypi-status]: https://img.shields.io/pypi/status/linuxpy.svg
[license]: https://img.shields.io/pypi/l/linuxpy.svg
[CI]: https://github.com/tiagocoutinho/linuxpy/actions/workflows/ci.yml/badge.svg
[documentation]: https://img.shields.io/badge/Documentation-blue?color=grey&logo=mdBook
[source]: https://img.shields.io/badge/Source-grey?logo=git

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "linuxpy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": null,
    "author": null,
    "author_email": "Jose Tiago Macara Coutinho <coutinhotiago@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/9b/29/68e915cd8b2e35161830c06afd7527e0fae8cd4f44f203ffc1b7df484368/linuxpy-0.20.0.tar.gz",
    "platform": null,
    "description": "# linuxpy\n\n[![linuxpy][pypi-version]](https://pypi.python.org/pypi/linuxpy)\n[![Python Versions][pypi-python-versions]](https://pypi.python.org/pypi/linuxpy)\n![License][license]\n[![CI][CI]](https://github.com/tiagocoutinho/linuxpy/actions/workflows/ci.yml)\n\n[![Source][source]](https://github.com/tiagocoutinho/linuxpy/)\n[![Documentation][documentation]](https://tiagocoutinho.github.io/linuxpy/)\n\nHuman friendly interface to linux subsystems using python.\n\nProvides python access to several linux subsystems like V4L2, GPIO, Led, thermal,\ninput and MIDI.\n\nThere is experimental, undocumented, incomplete and unstable access to USB.\n\nRequirements:\n* python >= 3.9\n* Fairly recent linux kernel\n* Installed kernel modules you want to access\n\nAnd yes, it is true: there are no python libraries required! Also there are no\nC libraries required. Everything is done here through direct ioctl, read and\nwrite calls. Ain't linux wonderful?\n\n## Installation\n\nFrom within your favorite python environment:\n\n```console\n$ pip install linuxpy\n```\n\nTo run the examples you'll need:\n\n```console\n$ pip install linuxpy[examples]\n```\n\nTo develop, run tests, build package, lint, etc you'll need:\n\n```console\n$ pip install linuxpy[dev]\n```\n\n## Subsystems\n\n### Video\n\nVideo for Linux 2 (V4L2) python library\n\nWithout further ado:\n\n```python\n>>> from linuxpy.video.device import Device\n>>> with Device.from_id(0) as cam:\n>>>     for i, frame in enumerate(cam):\n...         print(f\"frame #{i}: {len(frame)} bytes\")\n...         if i > 9:\n...             break\n...\nframe #0: 54630 bytes\nframe #1: 50184 bytes\nframe #2: 44054 bytes\nframe #3: 42822 bytes\nframe #4: 42116 bytes\nframe #5: 41868 bytes\nframe #6: 41322 bytes\nframe #7: 40896 bytes\nframe #8: 40844 bytes\nframe #9: 40714 bytes\nframe #10: 40662 bytes\n```\n\nGetting information about the device:\n\n```python\n>>> from linuxpy.video.device import Device, BufferType\n\n>>> cam = Device.from_id(0)\n>>> cam.open()\n>>> cam.info.card\n'Integrated_Webcam_HD: Integrate'\n\n>>> cam.info.capabilities\n<Capability.STREAMING|EXT_PIX_FORMAT|VIDEO_CAPTURE: 69206017>\n\n>>> cam.info.formats\n[ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'Motion-JPEG',\n             flags=<ImageFormatFlag.COMPRESSED: 1>, pixelformat=<PixelFormat.MJPEG: 1196444237>),\n ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'YUYV 4:2:2',\n             flags=<ImageFormatFlag.0: 0>, pixelformat=<PixelFormat.YUYV: 1448695129>)]\n\n>>> cam.get_format(BufferType.VIDEO_CAPTURE)\nFormat(width=640, height=480, pixelformat=<PixelFormat.MJPEG: 1196444237>}\n\n>>> for ctrl in cam.controls.values(): print(ctrl)\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>\n<IntegerControl contrast min=0 max=255 step=1 default=32 value=32>\n...\n<BooleanControl exposure_dynamic_framerate default=False value=False>\n\n>>> cam.controls.brightness\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>\n>>> cam.controls.brightness.value = 64\n>>> cam.controls.brightness\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=64>\n```\n\n(see also [v4l2py-ctl](examples/video/v4l2py-ctl.py) example)\n\n#### asyncio\n\nlinuxpy.video is asyncio friendly:\n\n```console\n$ python -m asyncio\n\n>>> from linuxpy.video.device import Device\n>>> with Device.from_id(0) as camera:\n...     async for frame in camera:\n...         print(f\"frame {len(frame)}\")\nframe 10224\nframe 10304\nframe 10224\nframe 10136\n...\n```\n\n(check [basic async](examples/video/basic_async.py) and [web async](examples/video/web/async.py) examples)\n\n#### gevent\n\nlinuxpy.video is also gevent friendly:\n\n```\n$ python\n\n>>> from linuxpy.io import GeventIO\n>>> from linuxpy.video.device import Device\n>>> with Device.from_id(0, io=GeventIO) as camera:\n...     for frame in camera:\n...         print(f\"frame {len(frame)}\")\nframe 10224\nframe 10304\nframe 10224\nframe 10136\n...\n```\n\n(check [basic gevent](examples/basic_gevent.py) and [web gevent](examples/web/sync.py) examples)\n\n#### Video output\n\nIt is possible to write to a video output capable device (ex: v4l2loopback).\nThe following example shows how to grab frames from device 0 and write them\nto device 10\n\n```console\n>>> from linuxpy.video.device import Device, VideoOutput, BufferType\n>>> dev_source = Device.from_id(0)\n>>> dev_sink = Device.from_id(10)\n>>> with dev_source, dev_target:\n>>>     source = VideoCapture(dev_source)\n>>>     sink = VideoOutput(dev_sink)\n>>>     source.set_format(640, 480, \"MJPG\")\n>>>     sink.set_format(640, 480, \"MJPG\")\n>>>     with source, sink:\n>>>         for frame in source:\n>>>             sink.write(frame.data)\n```\n\n#### Bonus track\n\nYou've been patient enough to read until here so, just for you,\na 20 line gem: a flask web server displaying your device on the web:\n\n```console\n$ pip install flask\n```\n\n```python\n# web.py\n\nimport flask\nfrom linuxpy.video.device import Device\n\napp = flask.Flask('basic-web-cam')\n\ndef gen_frames():\n    with Device.from_id(0) as cam:\n        for frame in cam:\n            yield b\"--frame\\r\\nContent-Type: image/jpeg\\r\\n\\r\\n\" + frame.data + b\"\\r\\n\"\n\n@app.route(\"/\")\ndef index():\n    return '<html><img src=\"/stream\" /></html>'\n\n@app.route(\"/stream\")\ndef stream():\n    return flask.Response(\n        gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')\n```\n\nrun with:\n\n```console\n$ FLASK_APP=web flask run -h 0.0.0.0\n```\n\nPoint your browser to [127.0.0.1:5000](http://127.0.0.1:5000) and you should see\nyour camera rolling!\n\n#### v4l2loopback\n\nStart from scratch:\n```console\n# Remove kernel module and all devices (no client can be connected at this point)\nsudo modprobe -r v4l2loopback\n\n# Install some devices\nsudo modprobe v4l2loopback video_nr=20,21 card_label=\"Loopback 0\",\"Loopback 1\"\n```\n\n#### References\n\nSee the ``linux/videodev2.h`` header file for details.\n\n\n* [V4L2 (Latest)](https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/v4l2.html) ([videodev.h](https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/videodev.html))\n* [V4L2 6.2](https://www.kernel.org/doc/html/v6.2/userspace-api/media/v4l/v4l2.html) ([videodev.h](https://www.kernel.org/doc/html/v6.2/userspace-api/media/v4l/videodev.html))\n\n\n### Input\n\nAPI not documented yet. Just this example:\n\n```python\nimport time\nfrom linuxpy.input.device import find_gamepads\n\npad = next(find_gamepads())\nabs = pad.absolute\n\nwith pad:\n    while True:\n\t    print(f\"X:{abs.x:>3} | Y:{abs.y:>3} | RX:{abs.rx:>3} | RY:{abs.ry:>3}\", end=\"\\r\", flush=True)\n\t    time.sleep(0.1)\n```\n\n#### asyncio\n\n```console\n$ python -m asyncio\n\n>>> from linuxpy.input.device import find_gamepads\n>>> with next(find_gamepads()) as pad:\n...     async for event in pad:\n...         print(event)\nInputEvent(time=1697520475.348099, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0)\nInputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1)\nInputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.Y: 1>, value=1)\nInputEvent(time=1697520475.361564, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0)\nInputEvent(time=1697520475.371128, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1)\nInputEvent(time=1697520475.371128, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0)\n...\n```\n\n#### References\n\n* [Input (Latest)](https://www.kernel.org/doc/html/latest/input/)\n* [Input 6.2](https://www.kernel.org/doc/html/v6.2/input/)\n\n### MIDI Sequencer\n\n```console\n$ python\n\n>>> from linuxpy.midi.device import Sequencer, event_stream\n\n>>> seq = Sequencer()\n>>> with seq:\n        port = seq.create_port()\n        port.connect_from(14, 0)\n        for event in seq:\n            print(event)\n 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0\n 14:0   Clock                queue=0, pad=b''\n 14:0   System exclusive     F0 61 62 63 F7\n 14:0   Note off             channel=0, note=55, velocity=3, off_velocity=0, duration=0\n```\n\n#### asyncio\n\nasyncio is a first class citizen to linuxpy.midi:\n\n```console\n$ python -m asyncio\n\n>>> from linuxpy.midi.device import Sequencer, async_event_stream\n\n>>> seq = Sequencer()\n>>> with seq:\n        port = seq.create_port()\n        port.connect_from(14, 0)\n        async for event in async_event_stream(seq):\n            print(event)\n 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0\n 14:0   Clock                queue=0, pad=b''\n 14:0   System exclusive     F0 61 62 63 F7\n 14:0   Note off             channel=0, note=55, velocity=3, off_velocity=0, duration=0\n```\n\n#### CLI\n\nA basic CLI is provided that allows listing MIDI clients & ports\nand dumping MIDI sequencer events:\n\n```console\n$ python -m linuxpy.midi.cli ls\n Port   Client                   Port                     Type                           Capabilities\n  0:0   System                   Timer                    0                              SR, W, R\n  0:1   System                   Announce                 0                              SR, R\n 14:0   Midi Through             Midi Through Port-0      PORT, SOFTWARE, MIDI_GENERIC   SW, SR, W, R\n```\n\n```console\n$ python -m linuxpy.midi.cli listen 0:1 14:0\n  0:1   Port subscribed      sender=(client=0, port=1), dest=(client=128, port=0)\n  0:1   Port start           client=128, port=1\n  0:1   Port subscribed      sender=(client=14, port=0), dest=(client=128, port=1)\n  0:1   Client start         client=130, port=0\n  0:1   Port start           client=130, port=0\n  0:1   Port subscribed      sender=(client=130, port=0), dest=(client=14, port=0)\n 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0\n  0:1   Port unsubscribed    sender=(client=130, port=0), dest=(client=14, port=0)\n  0:1   Port exit            client=130, port=0\n  0:1   Client exit          client=130, port=0\n  0:1   Port exit            client=129, port=0\n  0:1   Client exit          client=129, port=0\n  0:1   Client start         client=129, port=0\n  0:1   Port start           client=129, port=0\n 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0\n 14:0   Note on              channel=0, note=0, velocity=255, off_velocity=0, duration=0\n 14:0   Note on              channel=0, note=0, velocity=255, off_velocity=0, duration=0\n```\n\n[pypi-python-versions]: https://img.shields.io/pypi/pyversions/linuxpy.svg\n[pypi-version]: https://img.shields.io/pypi/v/linuxpy.svg\n[pypi-status]: https://img.shields.io/pypi/status/linuxpy.svg\n[license]: https://img.shields.io/pypi/l/linuxpy.svg\n[CI]: https://github.com/tiagocoutinho/linuxpy/actions/workflows/ci.yml/badge.svg\n[documentation]: https://img.shields.io/badge/Documentation-blue?color=grey&logo=mdBook\n[source]: https://img.shields.io/badge/Source-grey?logo=git\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-or-later",
    "summary": "Human friendly interface to linux subsystems using python",
    "version": "0.20.0",
    "project_urls": {
        "Documentation": "https://tiagocoutinho.github.io/linuxpy/",
        "Homepage": "https://github.com/tiagocoutinho/linuxpy",
        "Source": "https://github.com/tiagocoutinho/linuxpy"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "46b54e10fe456fa42e2f1493aba627ed7d9f24cb07657ed59b5d960632761c21",
                "md5": "36702c161ebbb826331f2d0d148260df",
                "sha256": "b3e926aa89ca92e885bff7a94026bd68377a489ab8f6af140385527b85ece50c"
            },
            "downloads": -1,
            "filename": "linuxpy-0.20.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "36702c161ebbb826331f2d0d148260df",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 451154,
            "upload_time": "2024-10-21T05:59:32",
            "upload_time_iso_8601": "2024-10-21T05:59:32.564994Z",
            "url": "https://files.pythonhosted.org/packages/46/b5/4e10fe456fa42e2f1493aba627ed7d9f24cb07657ed59b5d960632761c21/linuxpy-0.20.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9b2968e915cd8b2e35161830c06afd7527e0fae8cd4f44f203ffc1b7df484368",
                "md5": "f9a4a2a7a9eeb61e0216e9b603d06e7f",
                "sha256": "98d5a6ce5e7618465410bdeaf1c3f9f6ac4c76e1b58a382cbc6a03e5d7521bde"
            },
            "downloads": -1,
            "filename": "linuxpy-0.20.0.tar.gz",
            "has_sig": false,
            "md5_digest": "f9a4a2a7a9eeb61e0216e9b603d06e7f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 450101,
            "upload_time": "2024-10-21T05:59:35",
            "upload_time_iso_8601": "2024-10-21T05:59:35.700583Z",
            "url": "https://files.pythonhosted.org/packages/9b/29/68e915cd8b2e35161830c06afd7527e0fae8cd4f44f203ffc1b7df484368/linuxpy-0.20.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-21 05:59:35",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tiagocoutinho",
    "github_project": "linuxpy",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "linuxpy"
}
        
Elapsed time: 0.37865s