Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hychen/ucltip

A library to make creating command line tool Python binding easier
https://github.com/hychen/ucltip

Last synced: 3 months ago
JSON representation

A library to make creating command line tool Python binding easier

Awesome Lists containing this project

README

        

# vim:syn=rst:
========================================
UCLTIP - Use command line tool in Python
========================================

This library makes you use command line tool in Python more easier.
The original idea are from GitPython project `http://pypi.python.org/pypi/GitPython/`

The basic concept is to transform:

1) command as a instance,
2) command options as arguments or function/method keyword arguments.

Feature:

- Transform CLI Tool arguments to Python function/method arguments
- Transform CLI Tool Boolean option style to Python function/method keyword arguments
- Transform CLI Tool Key-Value option style to Python function/method keyword arguments
- Transform CLI Tool Key-Value option style to Python function/method keyword arguments
- Transform CLI Command as Python Class and use it in your script
- Set default options of Command for multiple use

-------
Example
-------

::

>>>expr = ucltip.Cmd('expr')
>>>ret = expr(3, '+', 4)
>>>ret
"7\n"

create a Cmd callable object

::
>>>expr = ucltip.Cmd('expr')

run Cmd object as a function to get result like executing `expr 3 + 4` in shell,
the result will be storeged in '''ret''' variable, as the following shows, you can think
command line tool arguments as Python function arguments.

::
>>>ret = expr(3, '+', 4)

if you want to only check what command string will be combined, you can doing dry run,
but ramind the command string will be split as a list.

::
>>>expr = ucltip.Cmd('expr')
>>>expr.conf.dry_run = True
>>>expr(3, "+", 4)
['expr', '3', '+', '4']

please note that jhe command be executed by subprocess.call, it bypass the shell.

::

# the result is $HOME, and it will not show output directly
print Cmd('echo')("$HOME")

if you want execute command via shell and use shell enviroment variable, please
do as follow, if args of function includes '''via_shell=True''', the command be executed by os.system

::

# the result is "/home/somebody", and show output directly
Cmd('echo')("$HOME", via_shell=True)

-----------------------------------
Handling Error of command execution
-----------------------------------
if the command you want to use is not exists, the exception ucltip.CommandNotFound raises

::

>> a=ucltip.Cmd('oo')
Traceback (most recent call last):
File "", line 1, in
File "ucltip/__init__.py", line 103, in __init__
raise CommandNotFound()
ucltip.CommandNotFound

if the command be executed falied, the exception ucltip.CommandExecutedError raises

::

>>> a=ucltip.Cmd('ls')
>>> a
Cmd object bound 'ls'
>>> a(ccc=True)
Traceback (most recent call last):
File "", line 1, in
File "ucltip/__init__.py", line 109, in __call__
return self._callProcess(*args, **kwargs)
File "ucltip/__init__.py", line 126, in _callProcess
return self.execute(call, **_kwargs)
File "ucltip/__init__.py", line 169, in execute
raise CommandExecutedError(status, stderr_value)
ucltip.CommandExecutedError: ls: unrecognized option '--ccc'
Try `ls --help' for more information.

here is a example to hanlde error:

::

try:
print ucltip.Cmd('ls')
except ucltip.CommandExecutedError as e:
print e

--------------
Command Option
--------------

so far, we already leanr how to execute command with arguments, but how about command options?
it is pretty easy also, just think command option like python keyword arguments.

''Boolean option''

when the type of keyword arguments's value is boolean, then this kind of keyword arguments
will be converted to command boolean option, for example, `-a` is equal '''func(a=True)'''

::
>>>ls('/tmp', a=True)
['ls', '/tmp', '-a']

Key-Value option
================

when the type of keyword arguments's value is interge number or string, then these of keyword
arguments will be coverted to command key-value option, for example, '--quoting_style 1' is equal
'''func(quoting_style=1)'''

::
>>>ls('tmp', quoting_style='c')
['ls', '--quoting-style', 'c']

also, you can change option style by set '''opt_style''' attribute, support option style are `gnu`,
`posix`,`java`, the default value is `posix`.

note: java option style is not fully supported.

::
>>>ls.conf.opt_style = 'gnu'
>>>ls('tmp', quoting_style='c')
['ls', '--quoting-style=c']

some options is mutiple, which means the name is name, but you can give
many different values, for example

::
# `foo -a -b -o Dir=/var -o Dir::Cache=/tmp`
# so you need to use make_optargs to create args if the opt name is duplicate
optargs = ucltip.make_optargs('o', ('Dir=/var','Dir::Cache=/tmp'))
Cmd('foo')(optargs, a=True, b=True)

-------------
CmdDispatcher
-------------

The CmdDispatcher is an object for mapping some command tools has sub command,
like `git`, `zenity`, `pbuilder`, `apt-get`, etc.

method name indicates as sub command name, method arguements indicates sub command arguments,
and method keyword arguments indicates sub command options.

::
>>apt_get = ucltip.CmdDispatcher('apt-get')
>>apt_get.conf.dry_run = True
>>apt_get.install('vim')
['apt-get', 'install', 'vim']

if sub command has prefix string, you can use '''subcmd_prefix''' attribute to set it.

::

>>zenity = ucltip.CmdDispatcher('zenity')
>>zenity.subcmd_prefix = '--'
>>zenity.conf.dry_run = True
>>zenity.info(text='hello')
['zenity', '--info', '--text hello']

--------------
Default Option
--------------

the options does not be stored after you execute command, if you want to keep options
for multiple using, you can use ''''opts''' function to set default options as the following

::

>>>ls = ucltip.Cmd('ls)
>>>ls.conf.dry_run=True
>>>ls.opts(l=True)
>>>ls('/tmp')
['ls', '/tmp', '-l']

CmdDispatcher sub command will load default options from its parent, in this case,
'''apt_get.install.opts()''' is the same as '''apt_get.opts()'''

::

>>>apt_get = ucltip.CmdDispatcher('apt-get')
>>>apt_get.conf.dry_run = True
>>>apt_get.opts(t='maverick')
>>>apt_get.install.opts()
{t':'maverick'}
>>>apt_get.install('vim')
apt-get', 'install', 'vim', '-t maverick']
>>>apt_get.opts(t=False)
>>>apt_get.install('vim')
['apt-get', 'install', 'vim']

Pipe
====
In subprocess, the way for doing pipeline is

::

>>>p1 = Popen(["dmesg"], stdout=PIPE)
>>>p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
>>>output = p2.communicate()[0]

which is not convenience when you want to pipe many commands.

Pipe class provide similar interface as C library `libpipeline` (http://libpipeline.nongnu.org/)
that manipulating pipelines of subprocesses in a flexible and convenient way in C.

firstly, you need to create a Pipe instance

::
>>>pipe = ucltip.Pipe()

and then add some command arguments as you want

::

>>>pipe.add('expr', 1, '+' 3)
>>>pipe.add('sed', 's/4/5/', '--posix')

finally run the process, wait it terminate and get its output

::

>>>pipe.wait()
>>>pipe.stdout.read()
5
# get error message in case command executed error
>>>pipe.stderr.read()

the first argument of Pipe.add function can be Cmd or SubCmd,
please remaind the usage of add function is changed in this case

::
>>>pipe = ucltip.Pipe()
>>>pipe.add(Cmd('expr'), 1, '+', 3)
>>>pipe.add(Cmd('sed'), 's/4/5', posix=True)
>>>pipe.wait()
>>>pipe.stdout.read()
5

::

>>>apt_cache = ucltip.CmdDispatcher('apt-cache')
>>>pipe = ucltip.Pipe()
>>>pipe.add(apt_cache.search, 'vim-common')
>>>pipe.add(Cmd('grep'), 'vim')
>>>pipe.wait()
>>>pipe.stdout.read()

Helper
======

regcmds is used to register multiple command in built-in environment one time

::

>>>ucltip.regcmds('ls', 'wget', 'sed')
>>> ls
Cmd object bound 'ls'
>>> wget
Cmd object bound 'wget'
>>> sed
Cmd object bound 'sed'

avaliabl for specify class

::

>>>ucltip.regcmds('apt-get', 'apt-cache', cls=ucltip.CmdDispatcher)
>>> apt_get

>>> apt_cache

ucltip can also check the command name you want to register is in the list that
command has sub command or not for reduce the class to CmdDispatcher by auto.

the list is ucltip.__CMDDISPATCHERS_LIST__, request to add new command are welcome

`global_config` is used to set up global configure of All class

To change executing behavior of Cmd or CmdDispatcher

::
# executing command, default setting
>>>ucltip.global_config(execmod='process')

# produce command arguments only, same as dry_run
>>>ucltip.global_config(execmod='list')
>>>ucltip.Cmd('ls')(a=True)
['ls', '-a']

# produce command string only
>>>ucltip.global_config(execmod='string')
>>>ucltip.Cmd('ls')(a=True)
'ls -a'

To force all command executed by os.system

::
>>>ucltip.global_config(via_shell=True)

Debugging
=========

ucltip provid debug output in /var/log/syslog after you enable debug mode

::
>>> ucltip.global_config(debug=True)

Get invlolved
=============

if you are interesting to help, please contact author,
Hychen, his email is .

The VCS of code is avaliabl on http://github.com/hychen/ucltip