you can now specify the output when using `couleur.Shell`

This commit is contained in:
Gabriel Falcao 2013-02-22 14:48:13 -05:00
parent dd796b3f0c
commit 0720d90e39
4 changed files with 197 additions and 167 deletions

104
README.md
View File

@ -22,61 +22,71 @@ unix terminal
#### further
>>> import sys, couleur
```python
import sys, couleur
>>> couleur.proxy(sys.stdout).enable()
couleur.proxy(sys.stdout).enable()
print "#{bold}#{blue}#{on:black}This is#{normal} a test"
couleur.proxy(sys.stdout).ignore()
>>> print "#{bold}#{red}#{on:yellow}This is#{normal} a test"
u'\x1b[1;31;43mThis is\x1b[39m a test'
>>> couleur.proxy(sys.stdout).ignore()
>>> print "#{bold}#{red}#{on:yellow}This is#{normal} a test"
u'This is a test'
>>> couleur.proxy(sys.stdout).disable()
print "#{green}#{on:black}This is#{normal} a test"
couleur.proxy(sys.stdout).disable()
```
### dynamic methods
couleur has a syntax sugar that is semantically nice:
import couleur
sh = couleur.Shell(indent=4)
```python
import couleur
sh = couleur.Shell(indent=4)
sh.bold_black_on_white('Nice highlight')
# prints '\033[47m\033[1m\033[30mNice highlight\033[0m'
sh.bold_black_on_white('Nice highlight')
# prints '\033[47m\033[1m\033[30mNice highlight\033[0m'
sh.indent()
# will increase a internal indentation factor in couleur.Shell instance
sh.indent()
# will increase a internal indentation factor in couleur.Shell instance
sh.green('Just green')
# prints indented as well ' \033[32mJust Green\033[0m'
sh.green('Just green')
# prints indented as well ' \033[32mJust Green\033[0m'
sh.dedent()
# will decrease that indentation factor (above)
sh.dedent()
# will decrease that indentation factor (above)
# syntax sugar
sh.green_and_nornal_and_blue('this will be printed in green| and |this in blue')
# see: '\033[32mthis will be printed in green\033[0m and \033[34mthis in blue\033[0m'
# syntax sugar
sh.green_and_normal_and_blue('this will be printed in green| and |this in blue')
# see: '\033[32mthis will be printed in green\033[0m and \033[34mthis in blue\033[0m'
```
couleur can overwrite output, so that you can make things like printing progress bars, show percentage and so on:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
```python
import time
import couleur
import time
import couleur
shell = couleur.Shell(linebreak=True, bold=True)
shell = couleur.Shell(linebreak=True, bold=True)
for num in range(101):
if num == 0:
print
for num in range(101):
if num == 0:
print
shell.yellow_and_red("Downloading file: |%d%%" % num, replace=True)
time.sleep(0.01)
shell.yellow_and_red("Downloading file: |%d%%" % num, replace=True)
time.sleep(0.05)
shell.white_and_green("Downloading file: |DONE!", replace=True)
```
#### Writing to other streams
Simply pass the output as first argument of the `Shell`
```python
import couleur
with open('output.log', 'w') as output:
shell = couleur.Shell(output, linebreak=True, bold=True)
shell.white_and_green("done with | Some task")
```
shell.white_and_green("Downloading file: |DONE!", replace=True)
### furthermore
@ -107,13 +117,12 @@ Available colors:
Example chaining modifiers:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
```python
import couleur
import couleur
shell = couleur.Shell(linebreak=True)
shell.bold_italic_underline_yellow_on_black_and_italic_black_on_white("WOO| HOO")
shell = couleur.Shell(linebreak=True)
shell.bold_italic_underline_green_on_black_and_italic_black_on_white("WOO| HOO")
```
## free software
@ -124,10 +133,13 @@ To contribute back with this project, all you need to do is write code, and test
You will need to install [nose](http://somethingaboutorange.com/mrl/projects/nose/0.11.3/ "a pretty way for testing in python").
And run:
user@machine:~/Projects$ git clone git://github.com/gabrielfalcao/couleur.git
user@machine:~/Projects$ cd couleur
user@machine:~/Projects$ pip install -r requirements.pip
user@machine:~/Projects/couleur$ make
```shell
user@machine:~/Projects$ git clone git://github.com/gabrielfalcao/couleur.git
user@machine:~/Projects$ cd couleur
user@machine:~/Projects$ pip install -r requirements.pip
user@machine:~/Projects/couleur$ make
```
## nomenclature
@ -135,6 +147,6 @@ And run:
## Licensing
Copyright (c) 2010 Gabriel Falcão
Copyright (c) 2010-2013 Gabriel Falcão
Licensed under Apache License 2.0
http://www.apache.org/licenses/LICENSE-2.0.html

View File

@ -216,7 +216,7 @@ _sep2 = u'_and_'
class Shell(object):
def __init__(self, indent=2, linebreak=False, bold=False,
def __init__(self, output=None, indent=2, linebreak=False, bold=False,
disabled=not SUPPORTS_ANSI):
self._indentation_factor = indent
self._indent = 0
@ -224,6 +224,8 @@ class Shell(object):
self._bold = bold
self._in_format = False
self._disabled = disabled
self.output = output or sys.stdout
if disabled:
self._backcolors = empty()
self._forecolors = empty()
@ -279,8 +281,8 @@ class Shell(object):
def dec(z, replace=False):
pre = unicode(replace and self._modifiers.up or u'')
sys.stdout.write(pre)
sys.stdout.write(string % unicode(z.decode('utf-8')))
self.output.write(pre)
self.output.write(string % unicode(z.decode('utf-8')))
return dec
@ -295,19 +297,19 @@ class Shell(object):
string = string.replace(ur'\|', unique)
parts = string.split(ur"|")
if replace:
sys.stdout.write(self._modifiers.up)
self.output.write(self._modifiers.up)
if self._indent:
sys.stdout.write(u' ' * self._indent)
self.output.write(u' ' * self._indent)
if self._bold:
sys.stdout.write(self._modifiers.bold)
self.output.write(self._modifiers.bold)
for part, output in zip(parts, printers):
output(part.replace(unique, ur"|"))
if self._linebreak:
sys.stdout.write(u"\n")
self.output.write(u"\n")
self._in_format = False

View File

@ -1,4 +1,4 @@
distribute==0.6.27
nose==1.1.2
sure==1.0.6
wsgiref==0.1.2
nose==1.2.1
steadymark==0.4.5
sure==1.1.7

View File

@ -16,154 +16,170 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from StringIO import StringIO
from nose.tools import with_setup, assert_equals
from couleur import ansify
from sure import scenario, action_for, expect
from couleur import Shell
def prepare_stdout():
if isinstance(sys.stdout, StringIO):
del sys.stdout
std = StringIO()
sys.stdout = std
def prepare_output_stream(context):
context.output = StringIO()
def assert_stdout(expected):
string = sys.stdout.getvalue()
assert_equals(string, expected)
@action_for(context, provides=['check_output'])
def check_output(expected):
context.output.getvalue().should.equal(expected)
def test_ansify():
"couleur.ansify wraps ansi code for proper pythonic output"
assert_equals(ansify(0), '\033[0m')
@action_for(context, provides=['check_output'])
def make_shell(*args, **kw):
context.sh = Shell(context.output, *args, **kw)
@with_setup(prepare_stdout)
def test_output_black_foreground():
def test_default_output():
"Shell.output should default to sys.stdout"
sh = Shell()
expect(sh.output).to.equal(sys.stdout)
@scenario(prepare_output_stream)
def test_output_black_foreground(spec):
"Test output: black foreground"
sh = Shell()
sh.black("Hello Black!")
assert_stdout('\033[30mHello Black!\033[0m')
spec.make_shell()
spec.sh.black("Hello Black!")
spec.check_output('\033[30mHello Black!\033[0m')
@with_setup(prepare_stdout)
def test_output_black_foreground_on_white_background():
@scenario(prepare_output_stream)
def test_output_black_foreground_on_white_background(spec):
"Test output: black foreground on white background"
sh = Shell()
sh.black_on_white("Hello Black!")
assert_stdout('\033[47m\033[30mHello Black!\033[0m')
spec.make_shell()
spec.sh.black_on_white("Hello Black!")
spec.check_output('\033[47m\033[30mHello Black!\033[0m')
@with_setup(prepare_stdout)
def test_output_green_foreground():
@scenario(prepare_output_stream)
def test_output_green_foreground(spec):
"Test output: green foreground"
sh = Shell()
sh.green("Hello World!")
assert_stdout('\033[32mHello World!\033[0m')
spec.make_shell()
spec.sh.green("Hello World!")
spec.check_output('\033[32mHello World!\033[0m')
@with_setup(prepare_stdout)
def test_mixed_output():
@scenario(prepare_output_stream)
def test_mixed_output(spec):
"green_and_red_and_white is a valid call"
sh = Shell()
sh.green_and_red_and_white("Hello |World |for you!")
assert_stdout(
spec.make_shell()
spec.sh.green_and_red_and_white("Hello |World |for you!")
spec.check_output(
'\033[32mHello \033[0m\033[31mWorld \033[0m\033[37mfor you!\033[0m'
)
@with_setup(prepare_stdout)
def test_mixed_output_with_escaped_separator():
@scenario(prepare_output_stream)
def test_mixed_output_with_escaped_separator(spec):
"green_and_red_on_yellow works is a valid call"
sh = Shell()
sh.green_and_red_on_yellow("Hello |World \|for you!")
assert_stdout(
spec.make_shell()
spec.sh.green_and_red_on_yellow("Hello |World \|for you!")
spec.check_output(
'\033[32mHello \033[0m\033[43m\033[31mWorld |for you!\033[0m'
)
@with_setup(prepare_stdout)
def test_mixed_output_with_backgrounds():
@scenario(prepare_output_stream)
def test_mixed_output_with_backgrounds(spec):
"green_on_magenta_and_red_and_white_on_blue is a valid call"
sh = Shell()
sh.green_on_magenta_and_red_and_white_on_blue("Hello |World |for you!")
assert_stdout('\033[45m\033[32mHello \033[0m\033[31mWorld \033[0m\033[44m\033[37mfor you!\033[0m'
spec.make_shell()
spec.sh.green_on_magenta_and_red_and_white_on_blue("Hello |World |for you!")
spec.check_output('\033[45m\033[32mHello \033[0m\033[31mWorld \033[0m\033[44m\033[37mfor you!\033[0m'
)
@with_setup(prepare_stdout)
def test_indent():
@scenario(prepare_output_stream)
def test_indent(spec):
"indentation"
sh = Shell(indent=4, linebreak=True)
sh.normal_on_blue("Hello")
sh.indent()
sh.normal_on_red("World")
assert_stdout('\033[44m\033[39mHello\033[0m\n \033[41m\033[39mWorld\033[0m\n')
spec.make_shell(indent=4, linebreak=True)
spec.sh.normal_on_blue("Hello")
spec.sh.indent()
spec.sh.normal_on_red("World")
spec.check_output('\033[44m\033[39mHello\033[0m\n \033[41m\033[39mWorld\033[0m\n')
@with_setup(prepare_stdout)
def test_dedent():
@scenario(prepare_output_stream)
def test_dedent(spec):
"de-indentation"
sh = Shell(indent=4, linebreak=True)
sh.indent()
sh.normal_on_blue("Hello")
sh.dedent()
sh.normal_on_red("World")
assert_stdout(' \033[44m\033[39mHello\033[0m\n\033[41m\033[39mWorld\033[0m\n')
spec.make_shell(indent=4, linebreak=True)
spec.sh.indent()
spec.sh.normal_on_blue("Hello")
spec.sh.dedent()
spec.sh.normal_on_red("World")
spec.check_output(' \033[44m\033[39mHello\033[0m\n\033[41m\033[39mWorld\033[0m\n')
@with_setup(prepare_stdout)
def test_bold():
@scenario(prepare_output_stream)
def test_bold(spec):
"bold text"
sh = Shell(bold=True)
sh.normal_on_blue("Hello")
sh.normal_on_red("World")
assert_stdout('\033[1m\033[44m\033[39mHello\033[0m\033[1m\033[41m\033[39mWorld\033[0m')
spec.make_shell(bold=True)
spec.sh.normal_on_blue("Hello")
spec.sh.normal_on_red("World")
spec.check_output('\033[1m\033[44m\033[39mHello\033[0m\033[1m\033[41m\033[39mWorld\033[0m')
@with_setup(prepare_stdout)
def test_bold_inline():
@scenario(prepare_output_stream)
def test_bold_inline(spec):
"bold text with inline call"
sh = Shell()
sh.bold_normal_on_blue("Hello")
sh.bold_normal_on_red("World")
assert_stdout('\033[44m\033[1m\033[39mHello\033[0m\033[41m\033[1m\033[39mWorld\033[0m')
spec.make_shell()
spec.sh.bold_normal_on_blue("Hello")
spec.sh.bold_normal_on_red("World")
spec.check_output('\033[44m\033[1m\033[39mHello\033[0m\033[41m\033[1m\033[39mWorld\033[0m')
@with_setup(prepare_stdout)
def test_update_shell():
@scenario(prepare_output_stream)
def test_update_shell(spec):
"updating the shell, replacing the last output"
sh = Shell(indent=6)
sh.yellow("Yellow")
sh.indent()
sh.red("Red", True)
assert_stdout('\033[33mYellow\033[0m\r\033[A \033[31mRed\033[0m')
spec.make_shell(indent=6)
spec.sh.yellow("Yellow")
spec.sh.indent()
spec.sh.red("Red", True)
spec.check_output('\033[33mYellow\033[0m\r\033[A \033[31mRed\033[0m')
@with_setup(prepare_stdout)
def test_update_shell_mixed_with_linebreak():
@scenario(prepare_output_stream)
def test_update_shell_mixed_with_linebreak(spec):
"updating the shell with mixed output and linebreak enabled"
sh = Shell(linebreak=True)
sh.yellow("Yellow")
sh.yellow_and_normal_and_red("Yellow| and |Red", True)
sh.green("Green")
assert_stdout('\033[33mYellow\033[0m\n\r\033[A\033[33mYellow\033[0m\033[39m and \033[0m\033[31mRed\033[0m\n\033[32mGreen\033[0m\n')
spec.make_shell(linebreak=True)
spec.sh.yellow("Yellow")
spec.sh.yellow_and_normal_and_red("Yellow| and |Red", True)
spec.sh.green("Green")
spec.check_output('\033[33mYellow\033[0m\n\r\033[A\033[33mYellow\033[0m\033[39m and \033[0m\033[31mRed\033[0m\n\033[32mGreen\033[0m\n')
@with_setup(prepare_stdout)
def test_update_shell_mixed_with_indentation():
@scenario(prepare_output_stream)
def test_update_shell_mixed_with_indentation(spec):
"updating the shell with mixed output and indentation"
sh = Shell(linebreak=True)
sh.yellow("Yellow")
sh.indent()
sh.yellow_and_normal_and_red("Yellow| and |Red", True)
sh.dedent()
sh.green("Green")
assert_stdout('\033[33mYellow\033[0m\n\r\033[A \033[33mYellow\033[0m\033[39m and \033[0m\033[31mRed\033[0m\n\033[32mGreen\033[0m\n')
spec.make_shell(linebreak=True)
spec.sh.yellow("Yellow")
spec.sh.indent()
spec.sh.yellow_and_normal_and_red("Yellow| and |Red", True)
spec.sh.dedent()
spec.sh.green("Green")
spec.check_output('\033[33mYellow\033[0m\n\r\033[A \033[33mYellow\033[0m\033[39m and \033[0m\033[31mRed\033[0m\n\033[32mGreen\033[0m\n')
@with_setup(prepare_stdout)
def test_update_shell_mixed_with_bold():
@scenario(prepare_output_stream)
def test_update_shell_mixed_with_bold(spec):
"updating the shell with mixed output and bold enabled"
sh = Shell(bold=True)
sh.yellow("Yellow")
sh.yellow_and_normal_and_red("Yellow| and |Red", True)
sh.green("Green")
assert_stdout('\033[1m\033[33mYellow\033[0m\r\033[A\033[1m\033[33mYellow\033[0m\033[39m and \033[0m\033[31mRed\033[0m\033[1m\033[32mGreen\033[0m')
spec.make_shell(bold=True)
spec.sh.yellow("Yellow")
spec.sh.yellow_and_normal_and_red("Yellow| and |Red", True)
spec.sh.green("Green")
spec.check_output('\033[1m\033[33mYellow\033[0m\r\033[A\033[1m\033[33mYellow\033[0m\033[39m and \033[0m\033[31mRed\033[0m\033[1m\033[32mGreen\033[0m')
@with_setup(prepare_stdout)
def test_dont_print_colors_if_set_as_disabled():
@scenario(prepare_output_stream)
def test_dont_print_colors_if_set_as_disabled(spec):
"disable colors"
sh = Shell(disabled=True, linebreak=True, bold=True)
sh.yellow("Yellow")
sh.indent()
sh.indent()
sh.yellow_and_red_on_yellow("Yellow| and Red", True)
sh.dedent()
sh.green("Green")
assert_stdout('Yellow\n\r\033[A Yellow and Red\n Green\n')
spec.make_shell(disabled=True, linebreak=True, bold=True)
spec.sh.yellow("Yellow")
spec.sh.indent()
spec.sh.indent()
spec.sh.yellow_and_red_on_yellow("Yellow| and Red", True)
spec.sh.dedent()
spec.sh.green("Green")
spec.check_output('Yellow\n\r\033[A Yellow and Red\n Green\n')