Cole Robinsonhttps://blog.wikichoon.com/2019-04-09T14:01:00-04:00Cole's dev logHost 'Network Interfaces' panel removed from virt-manager2019-04-09T14:01:00-04:002019-04-09T14:01:00-04:00Cole Robinsontag:blog.wikichoon.com,2019-04-09:/2019/04/host-network-interfaces-panel-removed.html<p>I released <a href="https://www.redhat.com/archives/virt-tools-list/2018-October/msg00087.html">virt-manager 2.0.0</a> in October 2018. Since the release contained the full port to python3, it seemed like a good opportunity to drop some baggage from the app.</p> <p>The biggest piece we removed was the UI for managing host network interfaces. This is the Connection Details->Network …</p><p>I released <a href="https://www.redhat.com/archives/virt-tools-list/2018-October/msg00087.html">virt-manager 2.0.0</a> in October 2018. Since the release contained the full port to python3, it seemed like a good opportunity to drop some baggage from the app.</p> <p>The biggest piece we removed was the UI for managing host network interfaces. This is the Connection Details->Network Interfaces panel, and the 'New Interface' wizard for defining host network definitions for things like bridges, bonds, and vlan devices. The main screen of the old UI looked like this:</p> <p><img alt="Old host interfaces panel" height="280" src="https://blog.wikichoon.com/images/074-host-network-interfaces-panel-removed-1.png" width="400"></p> <p>Behind the scenes, this UI was using libvirt's Interface APIs, which also power the 'virsh iface-*' commands. These APIs are little more than a wrapper around the <a href="https://pagure.io/netcf">netcf</a> library.</p> <p>netcf aimed to be a linux distro independent API for network device configuration. On Red Hat distros this meant turning the API's XML format into an /etc/sysconfig/network script. There were even pie-in-the-sky ideas about NetworkManager one day using netcf.</p> <p>In practice though the library never really took off. It was years before a debian backend showed up, contributed by a Red Hatter in the hope of increasing library uptake, though it didn't seem to help. netcf basically only existed to serve the libvirt Interface APIs, yet those APIs were never really used by any major libvirt consuming app, besides virt-manager. And in virt-manager's case it was largely just slapping some UI over the XML format and lifecycle operations.</p> <p>For virt-manager's usecases we hoped that netcf would make it trivial to bridge the host's network interface, which when used with VMs would give them first class IP addresses on the host network setup, not NAT like the 'default' virtual network. Unfortunately though the UI would create the ifcfg files well enough, behind the scenes nothing played well with NetworkManager for years and years. The standard suggestion for was to disable NetworkManager if you wanted to bridge your host NIC. Not very user friendly. Some people did manage to use the UI to that effect but it was never a trivial process.</p> <p>Nowadays NetworkManager can handle bridging natively and is much more powerful than what virt-manager/libvirt/netcf provide. The virt-manager UI was more likely to shoot you in the foot than make things simple. And it had become increasingly clear that virt-manager was not the place to maintain host network config UI.</p> <p>So we made the decision to drop all this from virt-manager in 2.0.0. netcf and the libvirt interface APIs still exist. If you're interested in some more history on the interface API/netcf difficulties, check out <a href="https://www.redhat.com/archives/virt-tools-list/2018-October/msg00049.html">Laine's email</a> to virt-tools-list.</p>python-bugzilla + bugzilla 5.0 API keys2019-01-09T17:58:00-05:002019-01-09T17:58:00-05:00Cole Robinsontag:blog.wikichoon.com,2019-01-09:/2019/01/python-bugzilla-bugzilla-50-api-keys.html<p>For many uses of /usr/bin/bugzilla and python-bugzilla, it's necessary to actually be logged in to a bugzilla server. Creating bugs, editing bugs, querying private data, etc.</p> <p>Up until now anyone that's used the command line tool has periodically had to do a 'bugzilla login' to refresh their authentication …</p><p>For many uses of /usr/bin/bugzilla and python-bugzilla, it's necessary to actually be logged in to a bugzilla server. Creating bugs, editing bugs, querying private data, etc.</p> <p>Up until now anyone that's used the command line tool has periodically had to do a 'bugzilla login' to refresh their authentication cache. In older bugzilla versions this was an HTTP cookie, more recently it's a bugzilla API token. Generally 'login' calls were needed infrequently on a single machine as tokens would remain valid for a long time.</p> <p>Recently, bugzilla.redhat.com received a big update to bugzilla 5.0. However with that update it seems like API tokens now expire after a week, which has necessitated lots more 'bugzilla login' calls than I'm used to.</p> <p>Thankfully with bugzilla 5.0 and later there's a better option: API keys. Here's how to to use them transparently with /usr/bin/bugzilla and all python-bugzilla library usage. Here's steps for enabling API keys with bugzilla.redhat.com, but the same process should roughly apply to other bugzilla instances too.</p> <p>Login to the bugzilla web UI, click your email, select Preferences, select API Keys. Generate an API key with an optional comment like 'python-bugzilla'. Afterwards the screen will look something like this:</p> <p><img alt="Bugzilla web UI API key setup" height="384" src="https://blog.wikichoon.com/images/073-python-bugzilla-bugzilla-50-api-keys-1.png" width="640"></p> <p>MY-EXAMPLE-API-KEY is not my actual key, I just replaced it for demo purposes. The actual key is a long string of characters and numbers. Copy that string value and write a bugzillarc file like this:</p> <div class="highlight"><pre><span></span><span class="na">$ cat ~/.config/python-bugzilla/bugzillarc</span> <span class="k">[bugzilla.redhat.com]</span> <span class="na">api_key</span><span class="o">=</span><span class="s">MY-EXAMPLE-API-KEY</span> </pre></div> <p>That's it, /usr/bin/bugzilla and python-bugzilla using tools should pick it up automagically. Note, API keys are as good as passwords in certain ways, so treat it with the same secrecy you would treat a password.</p>Setting custom network names on Fedora2018-10-04T21:27:00-04:002018-10-04T21:27:00-04:00Cole Robinsontag:blog.wikichoon.com,2018-10-04:/2018/10/setting-custom-network-names-on-fedora.html<p><a href="https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/">systemd predictable network names</a> give us host interface names like <strong>enp3s0</strong>. On one of my hosts, I have two interfaces: one that is my regular hard wired connection, and another I only plug in occasionally for some virt network testing. I can never remember the systemd names, so I want …</p><p><a href="https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/">systemd predictable network names</a> give us host interface names like <strong>enp3s0</strong>. On one of my hosts, I have two interfaces: one that is my regular hard wired connection, and another I only plug in occasionally for some virt network testing. I can never remember the systemd names, so I want to rename the interfaces to something more descriptive for my needs. in my case <strong>lan0main</strong> and <strong>lan1pcie</strong></p> <p>The page referenced says to use systemd links. However after struggling with that for a while I'm that's only relevant to systemd-networkd usage and doesn't apply to Fedora's default use of NetworkManager. So I needed another way.</p> <p>Long story short I ended up with some custom udev rules that are patterned after the old 70-persistent-net.rules file:</p> <div class="highlight"><pre><span></span><span class="gp">$</span> cat /etc/udev/rules.d/99-cole-nic-names.rules <span class="go">SUBSYSTEM==&quot;net&quot;, ACTION==&quot;add&quot;, DRIVERS==&quot;?*&quot;, ATTR{address}==&quot;70:8b:cd:80:e5:5f&quot;, ATTR{type}==&quot;1&quot;, NAME=&quot;lan0main&quot;</span> <span class="go">SUBSYSTEM==&quot;net&quot;, ACTION==&quot;add&quot;, DRIVERS==&quot;?*&quot;, ATTR{address}==&quot;68:05:ca:1a:f5:da&quot;, ATTR{type}==&quot;1&quot;, NAME=&quot;lan1pcie&quot;</span> </pre></div>Configuring offlineimap + dovecot + thunderbird2017-05-18T08:01:00-04:002017-05-18T08:01:00-04:00Cole Robinsontag:blog.wikichoon.com,2017-05-18:/2017/05/configuring-offlineimap-dovecot.html<p>Recently some internal discussions at Red Hat motivated me to look into using <a href="https://github.com/OfflineIMAP/offlineimap">offlineimap</a>. I had thought about doing this for some time as a step towards giving <a href="https://www.mutt.org/">mutt</a> a try, but for now I decided to keep my original thunderbird setup. This turned out to be a bit more …</p><p>Recently some internal discussions at Red Hat motivated me to look into using <a href="https://github.com/OfflineIMAP/offlineimap">offlineimap</a>. I had thought about doing this for some time as a step towards giving <a href="https://www.mutt.org/">mutt</a> a try, but for now I decided to keep my original thunderbird setup. This turned out to be a bit more work than I anticipated, so I'm documenting it here.</p> <p>The primary difficulty is that offlineimap stores mail locally in Maildir format, but thunderbird only reads mbox format. The common solution to this is to serve the offlineimap mail via a local mail server, and have thunderbird connect to that. For the mail server I'm using <a href="https://www.dovecot.org/">dovecot</a>. Getting offlineimap output and dovecot to play nicely together in a format that thunderbird can consume was a bit tricky...</p> <p>Here's the ~/.offlineimaprc I settled on:</p> <div class="highlight"><pre><span></span><span class="k">[general]</span> <span class="na">accounts</span> <span class="o">=</span> <span class="s">work </span> <span class="k">[Account work]</span> <span class="na">localrepository</span> <span class="o">=</span> <span class="s">local-work</span> <span class="na">remoterepository</span> <span class="o">=</span> <span class="s">remote-work</span> <span class="c1"># Do a full check every 2 minutes</span> <span class="c1"># autorefresh = 2</span> <span class="c1"># Do 5 quick checks between every full check</span> <span class="c1"># quick = 5</span> <span class="k">[Repository local-work]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">Maildir</span> <span class="na">localfolders</span> <span class="o">=</span> <span class="s">~/.maildir</span> <span class="c1"># Translate your maildir folder names to the format the remote server expects</span> <span class="c1"># So this reverses the change we make with the remote nametrans setting</span> <span class="na">nametrans</span> <span class="o">=</span> <span class="s">lambda name: re.sub(&#39;^\.&#39;, &#39;&#39;, name)</span> <span class="k">[Repository remote-work]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">IMAP</span> <span class="na">keepalive</span> <span class="o">=</span> <span class="s">300</span> <span class="na">ssl</span> <span class="o">=</span> <span class="s">yes</span> <span class="na">sslcacertfile</span> <span class="o">=</span> <span class="s">/etc/ssl/certs/ca-bundle.crt</span> <span class="na">remotehost</span> <span class="o">=</span> <span class="s">$YOUR-WORK-MAIL-SERVER</span> <span class="na">remoteuser</span> <span class="o">=</span> <span class="s">$YOUR-USERNAME</span> <span class="c1"># You can specify remotepass= , but my work setup implicitly uses kerberos</span> <span class="c1"># Turn this on if you are manually messing with your maildir at all</span> <span class="c1"># I lost some mail in my experiments :(</span> <span class="c1">#readonly = yes</span> <span class="c1"># Need to exclude &#39;&#39; otherwise it complains about infinite naming loop?</span> <span class="na">folderfilter</span> <span class="o">=</span> <span class="s">lambda foldername: foldername not in [&#39;&#39;]</span> <span class="c1"># For Dovecot to see the folders right I want them starting with a dot,</span> <span class="c1"># and dovecot set to look for .INBOX as the toplevel Maildir</span> <span class="na">nametrans</span> <span class="o">=</span> <span class="s">lambda name: &#39;.&#39; + name</span> </pre></div> <p>A few notes here:</p> <ul> <li>autorefresh/quick are commented out because I'm not using them: I'm invoking 'offlineimap -o' with cron ever 2 minutes, with a small wrapper that ensures offlineimap isn't already running (not sure if that will have nasty side effects), and also checks that I'm on my work VPN (checking for a /sys/net/class/ path). I went with this setup because running offlineimap persistently will exit if it can't resolve the remote server after a few attempts, which will trigger if I leave the VPN. Maybe there's a setting to keep it running persistently but I couldn't find it.</li> <li>Enable the 'readonly' option and 'offlineimap --dry-run' when initially configuring things or messing with maildir layout: I lost a few hours of mail somehow during the setup process :/</li> <li>My setup implicitly depends on having authenticated with my companies kerberos. Still haven't figured out a good way of keeping the kerberos ticket fresh on a machine that moves on and off the VPN regularly. I know <a href="https://jhrozek.wordpress.com/2015/07/17/get-rid-of-calling-manually-calling-kinit-with-sssds-help/">SSSD can kinda handle</a> it but it seems to tie local login to work infrastructure which I'm not sure I want.</li> </ul> <p>For dovecot, I just needed to drop this into /etc/dovecot/local.conf and start/enable the service:</p> <div class="highlight"><pre><span></span><span class="na">protocols</span> <span class="o">=</span> <span class="s">imap imaps</span> <span class="na">listen</span> <span class="o">=</span> <span class="s">127.0.0.1</span> <span class="na">mail_location</span> <span class="o">=</span> <span class="s">maildir:~/.maildir:INBOX=~/.maildir/.INBOX</span> </pre></div> <p>Then configure thunderbird to connect to 127.0.0.1. User and password are the same as your local machine user account.</p> <p>The tricky part seems to be formatting the maildir directory names in a way that dovecot will understand and properly advertise as folders/subfolders. I played with dovecot LAYOUT=fs, various sep/separator values and offlineimap renamings, but the above config is the only thing I found that gave expected results (and I can't take credit for that setup, I eventually found it on an internal wiki page :) )</p> <p>Here's some (trimmed) directories in my ~/.maildir:</p> <div class="highlight"><pre><span></span><span class="gp">$</span> ls -1da .maildir/ <span class="go">.Drafts</span> <span class="go">.INBOX</span> <span class="go">.INBOX.fedora</span> <span class="go">.INBOX.libvirt</span> <span class="go">.INBOX.qemu</span> <span class="go">.INBOX.virt-tools</span> <span class="go">.Junk</span> </pre></div> <p>So .Drafts, .INBOX, .Junk are all top level folders, and things like .INBOX.fedora is a 'fedora' subfolder of my inbox. That's the naming scheme the default dovecot config seems to expect.</p>Easy qemu commandline passthrough with virt-xml2017-03-24T21:30:00-04:002017-03-24T21:30:00-04:00Cole Robinsontag:blog.wikichoon.com,2017-03-24:/2017/03/easy-qemu-commandline-passthrough-with.html<p>Libvirt has supported <a href="https://libvirt.org/drvqemu.html#qemucommand">qemu commandline option passthrough</a> for qemu/kvm VMs for quite a while. The format for it is a bit of a pain though since it requires setting a magic xmlns value at the top of the domain XML. Basically doing it by hand kinda sucks.</p> <p>In the …</p><p>Libvirt has supported <a href="https://libvirt.org/drvqemu.html#qemucommand">qemu commandline option passthrough</a> for qemu/kvm VMs for quite a while. The format for it is a bit of a pain though since it requires setting a magic xmlns value at the top of the domain XML. Basically doing it by hand kinda sucks.</p> <p>In the recently released <a href="https://blog.wikichoon.com/2017/03/virt-manager-141-released.html">virt-manager 1.4.1</a>, we added a virt-install/virt-xml option <strong>--qemu-commandline</strong> that tweaks option passthrough for new or existing VMs. So for example, if you wanted to add the qemu option string '-device FOO' to an existing VM named <strong>f25</strong>, you can do:</p> <div class="highlight"><pre><span></span>$ ./virt-xml f25 --edit --confirm --qemu-commandline=&quot;-device FOO&quot; <span class="gd">--- Original XML</span> <span class="gi">+++ Altered XML</span> <span class="gu">@@ -1,4 +1,4 @@</span> <span class="gd">-&lt;domain type=&quot;kvm&quot;&gt;</span> <span class="gi">+&lt;domain xmlns:qemu=&quot;https://libvirt.org/schemas/domain/qemu/1.0&quot; type=&quot;kvm&quot;&gt;</span> &lt;name&gt;f25&lt;/name&gt; &lt;uuid&gt;9b6f1795-c88b-452a-a54c-f8579ddc18dd&lt;/uuid&gt; &lt;memory unit=&quot;KiB&quot;&gt;4194304&lt;/memory&gt; <span class="gu">@@ -104,4 +104,8 @@</span> &lt;address type=&quot;pci&quot; domain=&quot;0x0000&quot; bus=&quot;0x00&quot; slot=&quot;0x0a&quot; function=&quot;0x0&quot;/&gt; &lt;/rng&gt; &lt;/devices&gt; <span class="gi">+ &lt;qemu:commandline&gt;</span> <span class="gi">+ &lt;qemu:arg value=&quot;-device&quot;/&gt;</span> <span class="gi">+ &lt;qemu:arg value=&quot;foo&quot;/&gt;</span> <span class="gi">+ &lt;/qemu:commandline&gt;</span> &lt;/domain&gt; Define &#39;f25&#39; with the changed XML? (y/n): </pre></div>virt-manager 1.4.1 released!2017-03-08T19:15:00-05:002017-03-08T19:15:00-05:00Cole Robinsontag:blog.wikichoon.com,2017-03-08:/2017/03/virt-manager-141-released.html<p>I've just released virt-manager 1.4.1. The highlights are:</p> <ul> <li>storage/nodedev event API support (Jovanka Gulicoska)</li> <li>UI options for enabling spice GL (Marc-André Lureau)</li> <li>Add default virtio-rng /dev/urandom for supported guest OS</li> <li>Cloning and rename support for UEFI VMs (Pavel Hrdina)</li> <li>libguestfs inspection UI improvements (Pino Toscano)</li> <li>virt-install …</li></ul><p>I've just released virt-manager 1.4.1. The highlights are:</p> <ul> <li>storage/nodedev event API support (Jovanka Gulicoska)</li> <li>UI options for enabling spice GL (Marc-André Lureau)</li> <li>Add default virtio-rng /dev/urandom for supported guest OS</li> <li>Cloning and rename support for UEFI VMs (Pavel Hrdina)</li> <li>libguestfs inspection UI improvements (Pino Toscano)</li> <li>virt-install: Add --qemu-commandline</li> <li>virt-install: Add --network vhostuser (Chen Hanxiao)</li> <li>virt-install: Add --sysinfo (Charles Arnold)</li> </ul> <p>Plus the usual slew of bug fixes and small improvements.</p>python-bugzilla 2.0.0 released!2017-02-08T16:22:00-05:002017-02-08T16:22:00-05:00Cole Robinsontag:blog.wikichoon.com,2017-02-08:/2017/02/python-bugzilla-200-released.html<p>I'm happy to announce a new release of python-bugzilla, version 2.0.0.</p> <p>This release contains several small to medium API breaks as <a href="https://blog.wikichoon.com/2016/06/python-bugzilla-api-changes-in-git.html">previously mentioned</a> on the blog. If you hit any issues, check that page first to see if it's an expected change.   The major changes in the release …</p><p>I'm happy to announce a new release of python-bugzilla, version 2.0.0.</p> <p>This release contains several small to medium API breaks as <a href="https://blog.wikichoon.com/2016/06/python-bugzilla-api-changes-in-git.html">previously mentioned</a> on the blog. If you hit any issues, check that page first to see if it's an expected change.   The major changes in the release are:</p> <ul> <li>Several fixes for use with bugzilla 5</li> <li>This release contains several smallish API breaks:</li> <li>Bugzilla.bug_autorefresh now defaults to False</li> <li>Credentials are now cached in ~/.cache/python-bugzilla/</li> <li>bin/bugzilla was converted to argparse</li> <li>bugzilla query --boolean_chart option is removed</li> <li>Unify command line flags across sub commands</li> <li>More details at: <a href="https://blog.wikichoon.com/2016/06/python-bugzilla-api-changes-in-git.html">https://blog.wikichoon.com/2016/06/python-bugzilla-api-changes-in-git.html</a></li> </ul>UEFI virt roms now in official Fedora repos2016-06-29T13:27:00-04:002016-06-29T13:27:00-04:00Cole Robinsontag:blog.wikichoon.com,2016-06-29:/2016/06/uefi-virt-support-now-in-official.html<p><a href="https://kparal.wordpress.com/2016/06/27/uefi-for-qemu-now-in-fedora-repositories/">Kamil</a> got to it first, but just a note that UEFI roms for x86 and aarch64 virt are now shipped in the standard Fedora repos, where previously the recommended place to grab them was an external nightly repo. Kamil has updated the <a href="https://fedoraproject.org/w/index.php?title=Using_UEFI_with_QEMU">UEFI+QEMU wiki page</a> to reflect this change …</p><p><a href="https://kparal.wordpress.com/2016/06/27/uefi-for-qemu-now-in-fedora-repositories/">Kamil</a> got to it first, but just a note that UEFI roms for x86 and aarch64 virt are now shipped in the standard Fedora repos, where previously the recommended place to grab them was an external nightly repo. Kamil has updated the <a href="https://fedoraproject.org/w/index.php?title=Using_UEFI_with_QEMU">UEFI+QEMU wiki page</a> to reflect this change.</p> <p>On up to date Fedora 23+ these roms will be installed automatically with the relevant qemu packages, and libvirt is properly configured to advertise the rom files to applications, so <a href="https://blog.wikichoon.com/2016/01/uefi-support-in-virt-install-and-virt.html">enabling this with tools like virt-manager</a> is available out of the box.</p> <p>For the curious, the reason we can now ship these binaries in Fedora is because the problematic EDK2 'FatPkg' code, which had a <a href="https://fedoraproject.org/w/index.php?title=Using_UEFI_with_QEMU&amp;diff=431056&amp;oldid=423634#EDK2_Licensing_Issues">Fedora incompatible license</a>, was replaced with an implementation with a less restrictive (and more Fedora friendly) license.</p>virt-manager 1.4.0 release2016-06-18T11:06:00-04:002016-06-18T11:06:00-04:00Cole Robinsontag:blog.wikichoon.com,2016-06-18:/2016/06/virt-manager-140-release.html<p>I've just released virt-manager 1.4.0. Besides the <a href="https://blog.wikichoon.com/2016/05/spice-openglvirgl-acceleration-on.html">spice GL bits that I previously talked about</a>, nothing too much exciting in this release except a lot of virt-install/virt-xml command line extensions.</p> <p>The changelog highlights:</p> <ul> <li>virt-manager: spice GL console support (Marc-André Lureau, Cole Robinson)</li> <li>Bump gtk and pygobject deps …</li></ul><p>I've just released virt-manager 1.4.0. Besides the <a href="https://blog.wikichoon.com/2016/05/spice-openglvirgl-acceleration-on.html">spice GL bits that I previously talked about</a>, nothing too much exciting in this release except a lot of virt-install/virt-xml command line extensions.</p> <p>The changelog highlights:</p> <ul> <li>virt-manager: spice GL console support (Marc-André Lureau, Cole Robinson)</li> <li>Bump gtk and pygobject deps to 3.14</li> <li>virt-manager: add checkbox to forget keyring password (Pavel Hrdina)</li> <li>cli: add --graphics gl= (Marc-André Lureau)</li> <li>cli: add --video accel3d= (Marc-André Lureau)</li> <li>cli: add --graphics listen=none (Marc-André Lureau)</li> <li>cli: add --transient flag (Richard W.M. Jones)</li> <li>cli: --features gic= support, and set a default for it (Pavel Hrdina)</li> <li>cli: Expose --video heads, ram, vram, vgamem</li> <li>cli: add --graphics listen=socket</li> <li>cli: add device address.type/address.bus/...</li> <li>cli: add --disk seclabelX.model (and .label, .relabel)</li> <li>cli: add --cpu cellX.id (and .cpus, and .memory)</li> <li>cli: add --network rom_bar= and rom_file=</li> <li>cli: add --disk backing_format=</li> </ul>check-pylint: mini tool for running pylint anywhere2016-06-10T08:46:00-04:002016-06-10T08:46:00-04:00Cole Robinsontag:blog.wikichoon.com,2016-06-10:/2016/06/check-pylint-mini-tool-for-running.html<p>pylint and pep8 are indispensable tools for python development IMO. For projects I maintain I've long ago added a 'setup pylint' sub-command to run both commands, and I've documented this as a necessary step in the contributor guidelines.</p> <p>But over the years I've accumulated many repos for small bits of …</p><p>pylint and pep8 are indispensable tools for python development IMO. For projects I maintain I've long ago added a 'setup pylint' sub-command to run both commands, and I've documented this as a necessary step in the contributor guidelines.</p> <p>But over the years I've accumulated many repos for small bits of python code that never have need for a setup.py script, but I still want the convenience of being able to run pylint and pep8 with a single command and a reasonable set of options.</p> <p>So, a while back I wrote this tiny '<a href="https://github.com/crobinso/check-pylint">check-pylint</a>' script which does exactly that. The main bit it adds is automatically searching the current directory for python scripts and modules and passing them to pylint/pep8. From the README:</p> <blockquote> <p>Simple helper script that scoops up all python modules and scripts beneath the current directory, and passes them through pylint and pep8. Has a bit of smarts to ignore .git directory, and handle files that don't end in .py</p> <p>The point is that you can just fire off 'check-pylint' in any directory containing python code and get a quick report.</p> </blockquote>