you can now specify the output when using `couleur.Shell`
This commit is contained in:
parent
dd796b3f0c
commit
0720d90e39
104
README.md
104
README.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
238
test_couleur.py
238
test_couleur.py
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue