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

View File

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

View File

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

View File

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