Archive

Posts Tagged ‘command line’

Python command line = Linux Bash command line

August 15, 2010 2 comments

Some of our technical staff are doing a fair amount of Python coding and also are preparing for the Linux Certification (LPIC-1) exam.
One of the first topics we have been studying is the Linux bash command line, command history and command editing.

Guess what, you may be surprised that modern Python interpreters use the GNU readline library… in plain English: you should be able to practice the skills you’ve gained during your Linux study sessions whenever you work with your Python interpreter, i.e.:

* Line editing
* History substitution
* Auto-completion

Cool.

This requires you to:

1) Add line to your bash start up script ~/.bashrc (or your ~/.bash_profile):
export PYTHONSTARTUP=/home/user/.pystartup
(changing /home/user to your home directory, e.g. /home/mtarruella)

2) create the file: .pystartup (see below) in your home directory

Python will execute the contents of a file identified by the PYTHONSTARTUP
environment variable when you start an interactive interpreter.

How do you use it ?

i) use the Emacs key bindings you learnt for bash
e.g. CTRL-A moves the cursor to the beginning of the line.

However, if you are more inclined to the Vim key bindings
you will need to configure readline placing the command:
set editing-mode vi
in the file ~/.inputrc

ii) Retrieve commands from your history by using CTRL-P (Previous command) and
CTRL-N
(Next command) or the useful ‘reversy’: CTRL-R (search command backwards).

iii) Start using command completion as if you were in the Linux bash command line e.g. start typing imp and press <Tab> you should then see:
>>> import
The whole word “import” should be auto-completed.

More detailed information on the topic: Python interactive

Happy Linux! and now Happy Python too!

Note that this is valid for *nix and Mac’s too.

By: Marcos Tarruella

An example of .pystartup file:


# Add auto-completion and a stored history file of commands to your Python
# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is
# bound to the Esc key by default (you can change it - see readline docs).
#
# Store the file in ~/.pystartup, and set an environment variable to point
# to it:  "export PYTHONSTARTUP=/home/user/.pystartup" in bash.
#
# Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the
# full path to your home directory.

import atexit
import os
import readline
import rlcompleter

historyPath = os.path.expanduser("~/.pyhistory")

def save_history(historyPath=historyPath):
import readline
readline.write_history_file(historyPath)

if os.path.exists(historyPath):
readline.read_history_file(historyPath)

atexit.register(save_history)
del os, atexit, readline, rlcompleter, save_history, historyPath

Advertisements

How to Mask Command Line Output from the Python run() Method

June 10, 2009 Comments off

Recently, We were tasked with creating automated deployment for our Python Django project. For our purposes, this involved creating python modules for programatically logging onto servers and carrying out all the necessary deployment tasks. We decided to use Fabric to make this work. We encountered difficulty, however, when using the run() method to execute commands in remote environments.

The problem is, with every command that Fabric executes on the remote machine, the command itself is always echoed to standard-out when the run() method executes, displaying (in plain text!) any password arguments you may be passing to the command being executed.

We worked around this by “monkey-patching” stdout itself with a wrapper class that checks specifically for the password provided, and replacing any output to standard out matching the password with something else (like “****”).

The wrapper class looks something like this:

class StdoutWrapper:


  def __init__(self, stdout, mask):
    self.stdout = stdout
    self.mask = mask


  def __getattr__(self, attr_name):
    return getattr(self.stdout, attr_name)


  def write(self, text):
    if text.find(self.mask) > -1:
      self.stdout.write(text.replace(self.mask, '****'))
    else:
      self.stdout.write(text)

Then, when you want to execute the command whose output you wish to mask, you simply use the StdoutWrapper class like so:

import getpass.getpass, sys


def some_fabric_method():
  config.username = prompt('Enter Username:')
  config.passwd = getpass('Enter Password:')
  config.app_path = '/path/to/your/app'
  config.svn_url = 'http://some.svn.checkout/'
  out = StdoutWrapper(sys.stdout, config.passwd)
  sys.stdout = out
  try:
    run("svn revert -R $(app_path")
    run("svn switch --username $(username) --password $(svn_password) $(svn_url) $(app_path)")
  finally:
    sys.stdout = sys.__stdout__

Obviously, this is a less-than-ideal solution; it accomplishes what we want, but having to resort to temporarily monkey-patching standard out itself seems like overkill. Has anyone else out there found a more preferable solution for suppressing plain-text password output while using Fabric for Python?

By: Brett McClelland