库pyudev是libudev的python封装,libudev提拱了对本地设备的列举与查询API。

1.安装

pip install pyudev

2. 使用

2.1 开始

导入pyudev,验证库版本。

In [1]: import pyudev
In [2]: print pyudev.__version__
0.21.0
In [3]: print pyudev.udev_version()
229

 2.2 列举(Enumerate)设备

  • 创建上下文(Context)对象。Context是pyudev的中心对象,在pyudev程序中几乎都会需要它。
In [5]: context = pyudev.Context()
  • 列举全部设备。
In [6]: for device in context.list_devices():
...: print device
...:
Device(u'/sys/devices/LNXSYSTM:00')
......
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata1/ata_port/ata1')
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata1/host0')
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/scsi_host/host0')
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata1/link1/ata_link/link1')
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata1/link1/dev1.0/ata_device/dev1.0')
  • 也可给带参数使用list_devices(),从而对设备进行过滤选择。设置过滤条件需要了解linux系统是如何对设备进行分类的。有2种过滤方法:一是使用关键参数(keyword arguments),二是使用自定义过滤器函数对象(matcher_*。

    • 使用keyword arguments。
In [8]: for device in context.list_devices(subsystem='block', DEVTYPE='partition'):
...: print device
...:
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda/sda1')
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda/sda2')
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda/sda3')
Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda/sda4')
......
    • 使用matcher_*函数对象。例子略...

2.3 直接访问设备

可通过设备路径\子系统+设备名\设备文件等三种方法来直接创建设备对象。

In [10]: pyudev.Devices.from_path(context, '/sys/block/sda')
Out[10]: Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda')
In [11]: pyudev.Devices.from_name(context, 'block', 'sda')
Out[11]: Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda')
In [12]: pyudev.Devices.from_device_file(context, '/dev/sda')
Out[12]: Device(u'/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda')

这三种方法所获取的对象是同一个设备。

In [16]: pyudev.Devices.from_device_file(context, '/dev/sda') == pyudev.Devices.from_name(context, 'block', 'sda')
Out[16]: True
In [17]: pyudev.Devices.from_name(context, 'block', 'sda') == pyudev.Devices.from_path(context, '/sys/block/sda')
Out[17]: True

2.4 查询设备属性

由列举设备或直接访问所返回的设备对象(Device)都对应于udev数据库中的一个设备,每个设备有“属性”,以描述设备的性能、特点,与其它设备的关系,...等等。查询设备的属性有三种方法:

  • 像普通python对象一样获取属性。如下面的代码打印出所有块设备(block)的device_node和device_type属性。
In [19]: for device in context.list_devices(subsystem='block'):
....: print '{0}({1})'.format(device.device_node, device.device_type)
....:
/dev/sda(disk)
/dev/sda2(partition)
/dev/sda3(partition)
/dev/sda4(partition)
/dev/sda5(partition)
/dev/sda6(partition)
/dev/sda7(partition)
/dev/sda8(partition)
/dev/sda9(partition)
/dev/loop0(disk)
/dev/loop1(disk)
/dev/loop2(disk)
......
  • 以类似字典的方法获取属性。
In [20]: for device in context.list_devices(subsystem='block'):
....: print '({0}({1})'.format(device['DEVNAME'], device['DEVTYPE'])
....:
(/dev/sda(disk)
(/dev/sda1(partition)
(/dev/sda2(partition)
(/dev/sda3(partition)
(/dev/sda4(partition)
(/dev/sda5(partition)
(/dev/sda6(partition)
(/dev/sda7(partition)
(/dev/sda8(partition)
(/dev/sda9(partition)
(/dev/loop0(disk)
(/dev/loop1(disk)
(/dev/loop2(disk)
......
  • 通过接口函数get()访问设备属性
In [24]: for device in context.list_devices(subsystem='block', DEVTYPE='partition'):
....: print '{0}({1})'.format(device.device_node, device.get('ID_FS_TYPE'))
....:
/dev/sda1(ntfs)
/dev/sda2(vfat)
/dev/sda3(vfat)
/dev/sda4(None)
/dev/sda5(ntfs)
/dev/sda6(ntfs)
/dev/sda7(ntfs)
/dev/sda8(None)
/dev/sda9(swap)
......

上面三种方法中,推荐使用接口函数来返回设备属性。当试图返回一个并不存在的属性时,get函数可返回指定的缺省值(通过参数设置),也可抛出KeyError异常。

此外,可用Device.attributes来查看设备有哪些属性,尽管大多数时间不需要这么做。

2.5 检索设备层级(hierarchy)

udev中设备是具有层次属性的,即设备之间可能存在父-子关系,如分区设备(partition)就是某磁盘设备的子设备。用Device对象的parent属性可返回其父设备对象。

In [25]: for device in context.list_devices(subsystem='block', DEVTYPE='partition'):
....: print '{0} is located on {1}'.format(device.device_node, device.parent.device_node)
....:
/dev/sda1 is located on /dev/sda
/dev/sda2 is located on /dev/sda
/dev/sda3 is located on /dev/sda
/dev/sda4 is located on /dev/sda
/dev/sda5 is located on /dev/sda
/dev/sda6 is located on /dev/sda
/dev/sda7 is located on /dev/sda
/dev/sda8 is located on /dev/sda
/dev/sda9 is located on /dev/sda

除了上面“硬”访问之外,更常用的是用搜索的方法返回父设备,即使用find_parent函数。

In [26]: for device in context.list_devices(subsystem='block', DEVTYPE='partition'):
....: print '{0} is located on {1}'.format(device.device_node, device.find_parent('block').device_node)
....:
/dev/sda1 is located on /dev/sda
/dev/sda2 is located on /dev/sda
/dev/sda3 is located on /dev/sda
/dev/sda4 is located on /dev/sda
/dev/sda5 is located on /dev/sda
/dev/sda6 is located on /dev/sda
/dev/sda7 is located on /dev/sda
/dev/sda8 is located on /dev/sda
/dev/sda9 is located on /dev/sda

find_parent使用更加灵活,且能够简化多层设备间的追溯,可直接返回祖父级、曾祖父级...的设备而不需要逐级搜索。如从分区设备直接返回其所在磁盘的IDE控制器或SCSI控制器的PCI插槽的名字。

In [27]: for device in context.list_devices(subsystem='block', DEVTYPE='partition'):
....: print '{0} attatched to PCI slot {1}'.format(device.device_node, device.find_parent('pci')['PCI_SLOT_NAME'])
....:
/dev/sda1 attatched to PCI slot 0000:00:1f.2
/dev/sda2 attatched to PCI slot 0000:00:1f.2
/dev/sda3 attatched to PCI slot 0000:00:1f.2
/dev/sda4 attatched to PCI slot 0000:00:1f.2
/dev/sda5 attatched to PCI slot 0000:00:1f.2
/dev/sda6 attatched to PCI slot 0000:00:1f.2
/dev/sda7 attatched to PCI slot 0000:00:1f.2
/dev/sda8 attatched to PCI slot 0000:00:1f.2
/dev/sda9 attatched to PCI slot 0000:00:1f.2

上面的例子直接从partition对象返回其相关的pci对象,打印其'PCI_SLOT_NAME‘属性。

2.6 设备监控(Monitor)

当添加、移除(如插、拔USB设备),或者设备属性变化(如电池充电等级变化)时,Linux核心将发送设备事件以便应用程序进行处理。pyudev程序监控系统设备事件的步骤是:创建监控器(Monitor)对象,设置监控器的过滤器(即设置需要处理的哪些事件),最后启用监控器。启用监控器有二种形式:同步监控、异步监控。

  • 同步监控

应用程序收到设备事件后获取系统控制权并进行处理,系统核心挂起等待应用程序处理完毕,应用程序完成处理后返回并交回系统控制权。这种方式效率低,仅适合处理过程简单的情况。

In [28]: monitor = pyudev.Monitor.from_netlink(context)

In [29]: monitor.filter_by('block')

In [30]: for device in iter(monitor.poll, None):
....: if 'ID_FS_TYPE' in device:
....: print '{0} partition {1}'.format(device.action, device.get('ID_FS_LABLE'))
....:
add partition None
add partition None

停止同步监控需要从处理过程中break循环或抛出异常(raise exeption)。

此外,为Monitor设置过滤器可以用filter_by()或filter_by_tag()函数。

  • 异步监控

应用程序创建监控器、事件处理程序(回调函数),将其插入系统核心的事件响应链,即安装观察器(Observer)。当期望的事件发生时,系统根据事件响应链启动一个新的线程调用回调函数,系统核心本身并不挂起。需要停止监控时,应从处理线程外部调用Obsever的stop函数从系统的事件响应链中观察器,如果要在事件处理程序中停止观察器,应调用send_stop()函数通知Observer进行间接停止。

In [3]: monitor = pyudev.Monitor.from_netlink(context)

In [4]: monitor.filter_by('block')

In [5]: def log_event(action, device):
...: if 'ID_FS_TYPE' in device:
...: with open('filesystem.log', 'a+') as stream:
...: stream.write('{0} - {1}/n'.format(action, device.get('ID_FS_LABLE')))
...: In [6]: observer = pyudev.MonitorObserver(monitor, log_event) In [7]: observer.start() In [8]: observer.stop()

 3. 与GUI库的集成

pyudev库支持多种GUI库,模块对应关系如下:

pyudev.pyqt5<--------->Qt5

pyudev.pyqt4<--------->Qt4

pyudev.glib<------------>PyGtk2

pyudev.wx<------------->wxWidgets / wxPython

例子略...可参考Using pyudev.pyqt5 within PyQt5's event loop

Python库之pyudev (一)的更多相关文章

  1. 11个并不广为人知,但值得了解的Python库

    这是一篇译文,文中提及了一些不常见但是有用的Python库 原文地址:http://blog.yhathq.com/posts/11-python-libraries-you-might-not-kn ...

  2. python自动化测试(4)-使用第三方python库技术实现

    python自动化测试(4)-使用第三方python库技术实现 1   概述 关于测试的方法论,都是建立在之前的文章里面提到的观点: 功能测试不建议做自动化 接口测试性价比最高 接口测试可以做自动化 ...

  3. OSX下 pip更新及安装python库

    直接执行安装命令 $ pip install builtwith 提示pip当前版本为7.1.2,要使用"pip install --upgrade pip"升级到8.1.2 $  ...

  4. protocol buffer c++ python库安装

    c++库安装较简单,不要用源码,还得下载依赖,就被墙了 https://github.com/google/protobuf/releases  下载一个最新的release安装 #protoc -- ...

  5. Windows版的各种Python库安装包下载地址与安装过程

    在用Python开发时(Windows环境),会碰到需要安装某个版本的第三方库,为了以后查找.安装方便,总结如下: windows版的各种Python库安装包下载地址:http://www.lfd.u ...

  6. Python 库大全

    作者:Lingfeng Ai链接:http://www.zhihu.com/question/24590883/answer/92420471来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非 ...

  7. python库tkinter、pygame中几点需要注意的问题

    恍然之间已经16年快四月份了,已经好久都没有写过东西了.. 最近在用python做一些小的游戏,在网上找了一些Python库,Python中游戏编程最常用的还是pygame了,其次是Tkinter p ...

  8. Robot Framework: 自定义自己的python库

    利用Robot Framework编写测试用例,往往需要开发自己的关键字,有的关键字需要通过自己编写python代码来实现.这在rf中,就需要自己定义python库.这个过程其实不复杂,本文来介绍下. ...

  9. Python数据分析Python库介绍(1)

    一直想写点Python的笔记了,今天就闲着无聊随便抄点,(*^__^*) 嘻嘻…… ---------------------------------------------------------- ...

随机推荐

  1. java的反射机制(重要)

    1,反射的概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...

  2. linux内核(三)文件系统

    1.为什么需要根文件系统 (1)init进程的应用程序在根文件系统上(2)根文件系统提供了根目录/(3)内核启动后的应用层配置(etc目录)在根文件系统上.几乎可以认为:发行版=内核+rootfs(4 ...

  3. vue2 router中的 @ 符号表示src

    vue2 router中的 @ 符号表示src 学习了:https://segmentfault.com/q/1010000009549802 这个是webpack起的别名: 在build/webpa ...

  4. Android高级控件(一)——ListView绑定CheckBox实现全选,添加和删除等功能

    Android高级控件(一)--ListView绑定CheckBox实现全选,添加和删除等功能 这个控件还是挺复杂的.也是项目中应该算是比較经常使用的了,所以写了一个小Demo来讲讲,主要是自己定义a ...

  5. poj3249 Test for job 【图的DAG dp】

    #include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> ...

  6. Hibernate中的HQL

    一.查询所有的时候 List<Company> list=session.createQuery("from Company as c order by c.cid desc&q ...

  7. [jzoj 5177] [NOIP2017提高组模拟6.28] TRAVEL 解题报告 (二分)

    题目链接: https://jzoj.net/senior/#main/show/5177 题目: 题解: 首先选出的泡泡怪一定是连续的一段 L,R 然后 L 一定属于虫洞左边界中的某一个 R 也同样 ...

  8. node,koa 图片批量添加水印,可手动配置水印位置

    公司设计在处理京东上架商品图片的时候,需要给设计好的图片添加京东的“logo”,并且logo位置得根据图片来摆放,需要通过计算得出logo位置.那样太麻烦了,于是就用node,koa写了批量给图片添加 ...

  9. hiho 1620 - 股票价格3 - 无限制的单调队列?

    题目链接 小Hi最近在关注股票,为了计算股票可能的盈利,他获取了一只股票最近N天的价格A1~AN. 小Hi想知道,对于第i天的股票价格Ai,几天之后股价会第一次超过Ai. 假设A=[69, 73, 6 ...

  10. lua中调用C++函数

    lua中调用C++函数 我们产品中提供了很多lua-C API给用户在lua中调用,之前一直没用深究其实现原理,只是根据已有的代码在编码.显然这不是一个好的习惯,没用达到知其所以然的目的. 一.基本原 ...