sh: 'subprocess.Popen' for humans

sh is a full-fledged subprocess replacement for Python 2.6 - 3.5, PyPy and PyPy3 that allows you to call any program as if it were a function.

It handles many tasks that make working with ‘Popen’ tedious:

  • Easy, and concise way of passing arguments
  • Handling of exit codes
  • Output redirection (!)
  • Piping
  • Background processing

and much more! for example:

from sh import ifconfig
print(ifconfig("wlan0"))

wlan0 Link encap:Ethernet HWaddr 00:00:00:00:00:00
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: ffff::ffff:ffff:ffff:fff/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0 GB) TX bytes:0 (0 GB)

Note that these aren’t Python functions, these are running the binary commands on your system by dynamically resolving your $PATH, much like Bash does, and then wrapping the binary in a function. In this way, all the programs on your system are easily available to you from within Python.

Installation

$ pip install sh

Docs & more: amoffat.github.io/sh

Disclaimer

I didn’t write sh, I’m just a fan :)

Updating neovim python client automatically in Ubuntu

First of all, I’ve been using vim exclusively since my The Road to Mastering Vim blog post! Actually I’m not using vim at all. I decided to use neovim, which is literally the future of vim, instead. I’ve also decided to donate a monthly sum to their Bountysource.

anyway, neovim has a python client that implements support for python plugins in neovim. It also serves as a library for connecting to and scripting neovim processes through its msgpack-rpc API.

That poses an issue: pip doesn’t have an auto update mechanism. So how do I update the client packages every time neovim is updated, automatically?

Read More

One Dark theme for tmux

I’ve created a dark tmux color scheme for terminals that support True Color, based on onedark.vim.

One Dark is an extremely popular theme for the Atom text editor.

Why?

I wanted both vim and tmux to share the same color scheme.
I tried tmuxline.vim but it didn’t render the colors correctly.
Furthermore, with tmuxline.vim, you can’t control the widgets on right status bar, which is a key feature IMO.

How?

Installation is extremely easy, and you can customize the widgets on the right status bar by setting the @onedark-widgets tmux variable.

Interested? head over to tmux-onedark-theme and follow the instructions.

preview-terminal

Scriptable tmux status line

tmux is awsome, but creating scripts for the status line is a lot of work. I’ve looked into different scripts at the tmux-plugins repo and saw a recurring pattern. Or dare I say, a lot of copy-n-pasting of the same code from one plugin to another. Many of them lay the same groundwork:

  • Add utils function to get or set tmux options
  • Add code that transforms the status line and calls the scripts
  • Add a caching layer to make sure no redudant calls are made

I’ve taken the liberty to create a plugin, tmux-status-variables, that helps creating and using status line scripts extremely easy.

Read More

Removing unused packages in debian

Until flatpak | snaps become the de-facto standard, we’ll have to cleanup our system from time to time (I’m not talking about apt-clean!)

anyway, linux is not windows, so figuring out which packages haven’t been used in a long time can be automated without a lot of effort. specifically, with apt and yum you can fetch the timetsamp of all installed binaries and figure out their corresponding packages.

But why work so hard when you’ve got an open source project who does all that?

Read More

tiny os.getenv idiom

Many times I add the possibility to control constant values via environment variables, and add a default value when no such variable is set. for instance:

import os  
A_CONSTANT_NUMBER = int(os.getenv(CONSTANT_NUMBER, 10))

I find myself writing this code again and again. IMO, a more idiomic solution would be:

import os

def getenv(varname, default=None, typecast_fn=None):
"""
Return the value of the environment variable varname if it exists, or default if it doesn't.
default defaults to None.

:typecast_fn: a function that performs the typecast. if not supplied, defaults to type(value)
"""

if not typecast_fn:
typecast_fn = type(default) if default else lambda x: x

assert callable(typecast_fn), "typecast_fn is not callable!"

value = os.getenv(varname)

return typecast_fn(value) if value else default

Now, you can write the following:

A_NUMBER = getenv(A_NUMBER)  

the above code will behave just like os.getenv.

A_NUMBER = getenv(A_NUMBER, typecast_fn=int)  

Now the code will lookup the environment variable A_NUMBER . if successful, will cast it to int and return it. otherwise, will return None (just like os.getenv):

A_NUMBER = getenv(A_NUMBER, 10)  

the above code will lookup the environment variable A_NUMBER.
if successful, will cast it to int and return it. otherwise, will return the default.

Developers NEED SysAdmin Experience

I just read Professor Beekums’s Software Developers Should Have Sysadmin Experience blog post, and loved it.

I actually believe that in order to be a great developer, one must know how to tweak, hack and fix the platform He’s working on.

When I was in the army, I encountered manydevelopers that only knew how to open Visual Studio. Once they had issues with a specific installation, hardware or an app - they had no idea what to do.

I think it’s fundamental to know how to fix broken installations & replace hardware parts, feel comfortable with the command line & writesscripts that automate work.

Don’t underestimate or patronize the sysadmin (which often happens) - learn from them. They probably knows a few tricks that would significantly boost your productivity.

direnv -- Unclutter your .profile

Many of my projects need specific environment variables to run. Usually I create a export.sh script that I source when I cd into the directory, or add them into my docker compose file.

There’s a better way, which I highly recommend: direnv.

direnv is an environment switcher for the shell. It knows how to hook into bash, zsh, tcsh and fish shell to load or unload environment variables depending on the current directory. This allows project-specific environment variables without cluttering the ~/.profile file.

Before each prompt, direnv checks for the existence of a .envrc file in the current and parent directories. If the file exists (and is authorized), it is loaded into a bash sub-shell and all exported variables are then captured by direnv and then made available to the current shell.

It also has a robust standard library which even allows activating virtualenv’s automatically!

screencasts

All these screencasts were taken from the projects screencasts doc.

direnv installation on OS X with Homebrew

The direnv security model

Handling ruby versions with direnv