Codebase list fabulous / 4f99627
Imported Upstream version 0.1.5+dfsg1 SVN-Git Migration 8 years ago
32 changed file(s) with 3101 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 syntax: glob
1 *.pyc
2 *.pyo
3 *.pyc
4 *.o
5 *.so
6 *~
7 *.rej
8 *.orig
9 *.mo
10
11 .figleaf*
12 *.egg-info
13 *.egg
14 build
15 deps
16 local_settings.py
17 .build
18 dist
19 pip-log.txt
20
21 syntax: regexp
22 (.*/)?\#[^/]*\#$
0 f0b97fffad309fd8dea60efd7d989fff4ba3058a 0.1
1 f0b97fffad309fd8dea60efd7d989fff4ba3058a 0.1
2 c6a2348d3455d5b25849d50d9fe497192dd62deb 0.1
3 2a1837cbbaa1b99ff7caeae5b320584ffda3c8a9 0.1.1
4 dfc04f2f18769e08d3d8b5f32bfabc20970e6c6b 0.1.2
5 48ffde688a2e85ec80d72b59eb6107f46c8d39e4 0.1.3
6 a7cfbe73acd2a137607bb29abbcb250f8b465571 0.1.4
0 Copyright (c) 2010 J.A. Roberts Tunney
1
2 Permission is hereby granted, free of charge, to any person obtaining
3 a copy of this software and associated documentation files (the
4 "Software"), to deal in the Software without restriction, including
5 without limitation the rights to use, copy, modify, merge, publish,
6 distribute, sublicense, and/or sell copies of the Software, and to
7 permit persons to whom the Software is furnished to do so, subject to
8 the following conditions:
9
10 The above copyright notice and this permission notice shall be
11 included in all copies or substantial portions of the Software.
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
17 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0 Metadata-Version: 1.0
1 Name: fabulous
2 Version: 0.1.5
3 Summary: Makes your terminal output totally fabulous
4 Home-page: http://lobstertech.com/fabulous.html
5 Author: J.A. Roberts Tunney
6 Author-email: jtunney@lobstertech.com
7 License: MIT
8 Download-URL: http://lobstertech.com/media/file/fabulous/fabulous-0.1.5.tar.gz
9 Description: .. -*-restructuredtext-*-
10
11 ==========
12 Fabulous
13 ==========
14
15 ---------------------------------------------
16 Makes Your Terminal Output Totally Fabulous
17 ---------------------------------------------
18
19 :Version: 0.1
20 :Date: 2009-12-07
21 :Copyright: Copyright (c) 2009 Lobstertech, Inc.
22 :Manual section: 3
23 :Manual group: Library Calls
24
25
26 Getting Started
27 ===============
28
29 Download and extract the latest version::
30
31 sudo apt-get install gcc python-imaging python-setuptools
32 sudo python setup.py install
33
34 Run the demo to see what's available::
35
36 python -m fabulous.demo
37
38
39 Basic Examples
40 ==============
41
42 Colors
43 ------
44
45 4-bit color. These colors and styles are standard and work almost
46 everywhere. They are useful in helping make your program output
47 easier to read::
48
49 from fabulous import bold, magenta, highlight_red
50
51 print bold(magenta('hello kitty'))
52 print highlight_red('DANGER DANGER!')
53
54 print bold('hello') + ' ' + magenta( kitty')
55
56 assert len(bold('test')) == 4
57
58 8-bit color. If you want to spice things up a bit, Fabulous supports
59 xterm256 colors::
60
61 from fabulous import fg256, bg256
62 print fg256('#F0F', 'hello kitty')
63 print fg256('magenta', 'hello kitty')
64
65
66 Fancy Text
67 ----------
68
69 Way cool text. This is something neat you can use when you program
70 starts up to display its name with style::
71
72 from fabulous import text
73 print text.Text("Fabulous", color='#0099ff', shadow=True, scew=5)
74
75
76 Images
77 ------
78
79 Fabulous lets you print images, which is more fun than useful.
80 Fabulous' unique method of printing images really shines when used
81 with semi-transparent PNG files. When blending backgrounds, Fabulous
82 assumes by default that your terminal has a black background. Don't
83 worry if your image is huge, it'll be resized by default to fit your
84 terminal::
85
86 from fabulous import utils, image
87 print image.Image("balls.png")
88
89 # adjust for a white background
90 utils.term.bgcolor = 'white'
91 print image.Image("balls.png")
92
93 It's scriptable too (like img2txt) ::
94
95 python -m fabulous.image balls.png >balls.txt
96 cat balls.txt
97
98
99 Transient Logging
100 -----------------
101
102 This is very useful tool for monitoring what your Python scripts are
103 doing. It allows you to have full verbosity without drowning out
104 important error messages::
105
106 import time, logging
107 from fabulous import logs
108 logs.basicConfig(level='WARNING')
109
110 for n in range(20):
111 logging.debug("verbose stuff you don't care about")
112 time.sleep(0.1)
113 logging.warning("something bad happened!")
114 for n in range(20):
115 logging.debug("verbose stuff you don't care about")
116 time.sleep(0.1)
117
118
119 Why Fabulous?
120 =============
121
122 Here's how Fabulous compares to other similar libraries:
123
124 - fabulous_: Licensed MIT. Focuses on delivering useful features in
125 the simplest, most user-friendly way possible (without a repulsive
126 name.) Written in pure-python but will attempt to auto-magically
127 compile/link a speedup library. ~1,000 lines of code.
128
129 - libcaca_: WTFPL. This is the established and respected standard for
130 doing totally insane things with ascii art (ever wanted to watch a
131 movie on the command line?) Weighing in at ~72k lines of C, this
132 project is a monster. It uses an older, more complex
133 text/dithering-based rendering method. Compared to fabulous, some
134 images look better, some worse. I found the docs somewhat difficult
135 to follow and couldn't find support for transparency or 256-colors.
136
137 - asciiporn_: GPL. Similar to libcaca but has an interesting feature
138 for drawing math graphs to the terminal... Needs to compile C code,
139 requires numpy/python2.6, and I couldn't get the darn thing to work.
140 Aprox 17k lines of code.
141
142 - pygments_: BSD. Has *excellent* support for terminal syntax highlighting.
143
144 - termcolor_: GPL. Only supports 4-bit ANSI colors.
145
146 .. _fabulous: http://pypi.python.org/pypi/fabulous
147 .. _libcaca: http://caca.zoy.org/
148 .. _termcolor: http://pypi.python.org/pypi/termcolor
149 .. _pygments: http://pygments.org/
150 .. _asciiporn: http://pypi.python.org/pypi/asciiporn/2009.05.01
151
152
153 ToDo
154 ====
155
156 - <http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/>
157
158 Platform: UNKNOWN
159 Classifier: Development Status :: 2 - Pre-Alpha
160 Classifier: License :: OSI Approved :: MIT License
161 Classifier: Environment :: Console
162 Classifier: Intended Audience :: Developers
163 Classifier: Programming Language :: C
164 Classifier: Programming Language :: Python
165 Classifier: Topic :: Utilities
166 Classifier: Topic :: Artistic Software
167 Classifier: Topic :: System :: Logging
168 Classifier: Topic :: Multimedia :: Graphics
0 .. -*-restructuredtext-*-
1
2 ==========
3 Fabulous
4 ==========
5
6 ---------------------------------------------
7 Makes Your Terminal Output Totally Fabulous
8 ---------------------------------------------
9
10 :Version: 0.1
11 :Date: 2009-12-07
12 :Copyright: Copyright (c) 2009 Lobstertech, Inc.
13 :Manual section: 3
14 :Manual group: Library Calls
15
16
17 Getting Started
18 ===============
19
20 Download and extract the latest version::
21
22 sudo apt-get install gcc python-imaging python-setuptools
23 sudo python setup.py install
24
25 Run the demo to see what's available::
26
27 python -m fabulous.demo
28
29
30 Basic Examples
31 ==============
32
33 Colors
34 ------
35
36 4-bit color. These colors and styles are standard and work almost
37 everywhere. They are useful in helping make your program output
38 easier to read::
39
40 from fabulous import bold, magenta, highlight_red
41
42 print bold(magenta('hello kitty'))
43 print highlight_red('DANGER DANGER!')
44
45 print bold('hello') + ' ' + magenta( kitty')
46
47 assert len(bold('test')) == 4
48
49 8-bit color. If you want to spice things up a bit, Fabulous supports
50 xterm256 colors::
51
52 from fabulous import fg256, bg256
53 print fg256('#F0F', 'hello kitty')
54 print fg256('magenta', 'hello kitty')
55
56
57 Fancy Text
58 ----------
59
60 Way cool text. This is something neat you can use when you program
61 starts up to display its name with style::
62
63 from fabulous import text
64 print text.Text("Fabulous", color='#0099ff', shadow=True, scew=5)
65
66
67 Images
68 ------
69
70 Fabulous lets you print images, which is more fun than useful.
71 Fabulous' unique method of printing images really shines when used
72 with semi-transparent PNG files. When blending backgrounds, Fabulous
73 assumes by default that your terminal has a black background. Don't
74 worry if your image is huge, it'll be resized by default to fit your
75 terminal::
76
77 from fabulous import utils, image
78 print image.Image("balls.png")
79
80 # adjust for a white background
81 utils.term.bgcolor = 'white'
82 print image.Image("balls.png")
83
84 It's scriptable too (like img2txt) ::
85
86 python -m fabulous.image balls.png >balls.txt
87 cat balls.txt
88
89
90 Transient Logging
91 -----------------
92
93 This is very useful tool for monitoring what your Python scripts are
94 doing. It allows you to have full verbosity without drowning out
95 important error messages::
96
97 import time, logging
98 from fabulous import logs
99 logs.basicConfig(level='WARNING')
100
101 for n in range(20):
102 logging.debug("verbose stuff you don't care about")
103 time.sleep(0.1)
104 logging.warning("something bad happened!")
105 for n in range(20):
106 logging.debug("verbose stuff you don't care about")
107 time.sleep(0.1)
108
109
110 Why Fabulous?
111 =============
112
113 Here's how Fabulous compares to other similar libraries:
114
115 - fabulous_: Licensed MIT. Focuses on delivering useful features in
116 the simplest, most user-friendly way possible (without a repulsive
117 name.) Written in pure-python but will attempt to auto-magically
118 compile/link a speedup library. ~1,000 lines of code.
119
120 - libcaca_: WTFPL. This is the established and respected standard for
121 doing totally insane things with ascii art (ever wanted to watch a
122 movie on the command line?) Weighing in at ~72k lines of C, this
123 project is a monster. It uses an older, more complex
124 text/dithering-based rendering method. Compared to fabulous, some
125 images look better, some worse. I found the docs somewhat difficult
126 to follow and couldn't find support for transparency or 256-colors.
127
128 - asciiporn_: GPL. Similar to libcaca but has an interesting feature
129 for drawing math graphs to the terminal... Needs to compile C code,
130 requires numpy/python2.6, and I couldn't get the darn thing to work.
131 Aprox 17k lines of code.
132
133 - pygments_: BSD. Has *excellent* support for terminal syntax highlighting.
134
135 - termcolor_: GPL. Only supports 4-bit ANSI colors.
136
137 .. _fabulous: http://pypi.python.org/pypi/fabulous
138 .. _libcaca: http://caca.zoy.org/
139 .. _termcolor: http://pypi.python.org/pypi/termcolor
140 .. _pygments: http://pygments.org/
141 .. _asciiporn: http://pypi.python.org/pypi/asciiporn/2009.05.01
142
143
144 ToDo
145 ====
146
147 - <http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/>
0 # Makefile for Sphinx documentation
1 #
2
3 # You can set these variables from the command line.
4 SPHINXOPTS =
5 SPHINXBUILD = sphinx-build
6 PAPER =
7 BUILDDIR = _build
8
9 # Internal variables.
10 PAPEROPT_a4 = -D latex_paper_size=a4
11 PAPEROPT_letter = -D latex_paper_size=letter
12 ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
13
14 .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
15
16 help:
17 @echo "Please use \`make <target>' where <target> is one of"
18 @echo " html to make standalone HTML files"
19 @echo " dirhtml to make HTML files named index.html in directories"
20 @echo " pickle to make pickle files"
21 @echo " json to make JSON files"
22 @echo " htmlhelp to make HTML files and a HTML help project"
23 @echo " qthelp to make HTML files and a qthelp project"
24 @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
25 @echo " changes to make an overview of all changed/added/deprecated items"
26 @echo " linkcheck to check all external links for integrity"
27 @echo " doctest to run all doctests embedded in the documentation (if enabled)"
28
29 clean:
30 -rm -rf $(BUILDDIR)/*
31
32 html:
33 $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
34 @echo
35 @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
36
37 dirhtml:
38 $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
39 @echo
40 @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
41
42 pickle:
43 $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
44 @echo
45 @echo "Build finished; now you can process the pickle files."
46
47 json:
48 $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
49 @echo
50 @echo "Build finished; now you can process the JSON files."
51
52 htmlhelp:
53 $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
54 @echo
55 @echo "Build finished; now you can run HTML Help Workshop with the" \
56 ".hhp project file in $(BUILDDIR)/htmlhelp."
57
58 qthelp:
59 $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
60 @echo
61 @echo "Build finished; now you can run "qcollectiongenerator" with the" \
62 ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
63 @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/nemesis.qhcp"
64 @echo "To view the help file:"
65 @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nemesis.qhc"
66
67 latex:
68 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
69 @echo
70 @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
71 @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
72 "run these through (pdf)latex."
73
74 changes:
75 $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
76 @echo
77 @echo "The overview file is in $(BUILDDIR)/changes."
78
79 linkcheck:
80 $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
81 @echo
82 @echo "Link check complete; look for any errors in the above output " \
83 "or in $(BUILDDIR)/linkcheck/output.txt."
84
85 doctest:
86 $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
87 @echo "Testing of doctests in the sources finished, look at the " \
88 "results in $(BUILDDIR)/doctest/output.txt."
0 # -*- coding: utf-8 -*-
1 #
2 # fabulous documentation build configuration file, created by
3 # sphinx-quickstart on Tue Apr 20 02:12:28 2010.
4 #
5 # This file is execfile()d with the current directory set to its containing dir.
6 #
7 # Note that not all possible configuration values are present in this
8 # autogenerated file.
9 #
10 # All configuration values have a default; values that are commented out
11 # serve to show the default.
12
13 import sys, os
14 import fabulous
15
16 # If extensions (or modules to document with autodoc) are in another directory,
17 # add these directories to sys.path here. If the directory is relative to the
18 # documentation root, use os.path.abspath to make it absolute, like shown here.
19 # sys.path.append(os.path.abspath('..'))
20
21 # -- General configuration -----------------------------------------------------
22
23 # Add any Sphinx extension module names here, as strings. They can be extensions
24 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
25 extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.pngmath']
26
27 # Add any paths that contain templates here, relative to this directory.
28 templates_path = ['_templates']
29
30 # The suffix of source filenames.
31 source_suffix = '.rst'
32
33 # The encoding of source files.
34 #source_encoding = 'utf-8'
35
36 # The master toctree document.
37 master_doc = 'index'
38
39 # General information about the project.
40 project = u'fabulous'
41 copyright = u'2010, J.A. Roberts Tunney'
42
43 # The version info for the project you're documenting, acts as replacement for
44 # |version| and |release|, also used in various other places throughout the
45 # built documents.
46 #
47 # The short X.Y version.
48 version = fabulous.__version__
49 # The full version, including alpha/beta/rc tags.
50 release = fabulous.__version__
51
52 # The language for content autogenerated by Sphinx. Refer to documentation
53 # for a list of supported languages.
54 #language = None
55
56 # There are two options for replacing |today|: either, you set today to some
57 # non-false value, then it is used:
58 #today = ''
59 # Else, today_fmt is used as the format for a strftime call.
60 #today_fmt = '%B %d, %Y'
61
62 # List of documents that shouldn't be included in the build.
63 #unused_docs = []
64
65 # List of directories, relative to source directory, that shouldn't be searched
66 # for source files.
67 exclude_trees = ['_build']
68
69 # The reST default role (used for this markup: `text`) to use for all documents.
70 #default_role = None
71
72 # If true, '()' will be appended to :func: etc. cross-reference text.
73 #add_function_parentheses = True
74
75 # If true, the current module name will be prepended to all description
76 # unit titles (such as .. function::).
77 #add_module_names = True
78
79 # If true, sectionauthor and moduleauthor directives will be shown in the
80 # output. They are ignored by default.
81 #show_authors = False
82
83 # The name of the Pygments (syntax highlighting) style to use.
84 pygments_style = 'sphinx'
85
86 # A list of ignored prefixes for module index sorting.
87 #modindex_common_prefix = []
88
89
90 # -- Options for HTML output ---------------------------------------------------
91
92 # The theme to use for HTML and HTML Help pages. Major themes that come with
93 # Sphinx are currently 'default' and 'sphinxdoc'.
94 html_theme = 'default'
95
96 # Theme options are theme-specific and customize the look and feel of a theme
97 # further. For a list of options available for each theme, see the
98 # documentation.
99 #html_theme_options = {}
100
101 # Add any paths that contain custom themes here, relative to this directory.
102 #html_theme_path = []
103
104 # The name for this set of Sphinx documents. If None, it defaults to
105 # "<project> v<release> documentation".
106 #html_title = None
107
108 # A shorter title for the navigation bar. Default is the same as html_title.
109 #html_short_title = None
110
111 # The name of an image file (relative to this directory) to place at the top
112 # of the sidebar.
113 #html_logo = None
114
115 # The name of an image file (within the static path) to use as favicon of the
116 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
117 # pixels large.
118 #html_favicon = None
119
120 # Add any paths that contain custom static files (such as style sheets) here,
121 # relative to this directory. They are copied after the builtin static files,
122 # so a file named "default.css" will overwrite the builtin "default.css".
123 html_static_path = ['_static']
124
125 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
126 # using the given strftime format.
127 #html_last_updated_fmt = '%b %d, %Y'
128
129 # If true, SmartyPants will be used to convert quotes and dashes to
130 # typographically correct entities.
131 #html_use_smartypants = True
132
133 # Custom sidebar templates, maps document names to template names.
134 #html_sidebars = {}
135
136 # Additional templates that should be rendered to pages, maps page names to
137 # template names.
138 #html_additional_pages = {}
139
140 # If false, no module index is generated.
141 #html_use_modindex = True
142
143 # If false, no index is generated.
144 #html_use_index = True
145
146 # If true, the index is split into individual pages for each letter.
147 #html_split_index = False
148
149 # If true, links to the reST sources are added to the pages.
150 #html_show_sourcelink = True
151
152 # If true, an OpenSearch description file will be output, and all pages will
153 # contain a <link> tag referring to it. The value of this option must be the
154 # base URL from which the finished HTML is served.
155 #html_use_opensearch = ''
156
157 # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
158 #html_file_suffix = ''
159
160 # Output file base name for HTML help builder.
161 htmlhelp_basename = 'fabulousdoc'
162
163
164 # -- Options for LaTeX output --------------------------------------------------
165
166 # The paper size ('letter' or 'a4').
167 #latex_paper_size = 'letter'
168
169 # The font size ('10pt', '11pt' or '12pt').
170 #latex_font_size = '10pt'
171
172 # Grouping the document tree into LaTeX files. List of tuples
173 # (source start file, target name, title, author, documentclass [howto/manual]).
174 latex_documents = [
175 ('index', 'fabulous.tex', u'Fabulous Documentation',
176 u'J.A. Roberts Tunney', 'manual'),
177 ]
178
179 # The name of an image file (relative to this directory) to place at the top of
180 # the title page.
181 #latex_logo = None
182
183 # For "manual" documents, if this is true, then toplevel headings are parts,
184 # not chapters.
185 #latex_use_parts = False
186
187 # Additional stuff for the LaTeX preamble.
188 #latex_preamble = ''
189
190 # Documents to append as an appendix to all manuals.
191 #latex_appendices = []
192
193 # If false, no module index is generated.
194 #latex_use_modindex = True
195
196
197 # Example configuration for intersphinx: refer to the Python standard library.
198 intersphinx_mapping = {'http://docs.python.org/': None}
0 .. fabulous documentation master file, created by
1 sphinx-quickstart on Tue Apr 20 02:12:28 2010.
2 You can adapt this file completely to your liking, but it should at least
3 contain the root `toctree` directive.
4
5 ==========
6 Fabulous
7 ==========
8
9 .. toctree::
10 :maxdepth: 1
11
12 :Version: 0.1
13 :Copyright: Copyright (c) 2010 J.A. Roberts Tunney
14
15
16 Installation
17 ============
18
19 Run the following commands::
20
21 sudo apt-get install python-imaging
22 sudo python setup.py install
23
24
25 Modules
26 =======
27
28 .. automodule:: fabulous.color
29 :members:
30 .. automodule:: fabulous.xterm256
31 :members:
32 .. automodule:: fabulous.logs
33 :members:
34 .. automodule:: fabulous.text
35 :members:
36 .. automodule:: fabulous.image
37 :members:
38 .. automodule:: fabulous.utils
39 :members:
40 .. automodule:: fabulous.gotham
41 :members:
42 .. automodule:: fabulous.rotating_cube
43 :members:
44 .. automodule:: fabulous.debug
45 :members:
0 #!python
1 """Bootstrap setuptools installation
2
3 If you want to use setuptools in your package's setup.py, just include this
4 file in the same directory with it, and add this to the top of your setup.py::
5
6 from ez_setup import use_setuptools
7 use_setuptools()
8
9 If you want to require a specific version of setuptools, set a download
10 mirror, or use an alternate download directory, you can do so by supplying
11 the appropriate options to ``use_setuptools()``.
12
13 This file can also be run as a script to install or upgrade setuptools.
14 """
15 import sys
16 DEFAULT_VERSION = "0.6c11"
17 DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
18
19 md5_data = {
20 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
21 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
22 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
23 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
24 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
25 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
26 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
27 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
28 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
29 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
30 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
31 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
32 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
33 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
34 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
35 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
36 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
37 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
38 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
39 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
40 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
41 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
42 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
43 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
44 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
45 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
46 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
47 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
48 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
49 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
50 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
51 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
52 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
53 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
54 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
55 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
56 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
57 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
58 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
59 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
60 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
61 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
62 }
63
64 import sys, os
65 try: from hashlib import md5
66 except ImportError: from md5 import md5
67
68 def _validate_md5(egg_name, data):
69 if egg_name in md5_data:
70 digest = md5(data).hexdigest()
71 if digest != md5_data[egg_name]:
72 print >>sys.stderr, (
73 "md5 validation of %s failed! (Possible download problem?)"
74 % egg_name
75 )
76 sys.exit(2)
77 return data
78
79 def use_setuptools(
80 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
81 download_delay=15
82 ):
83 """Automatically find/download setuptools and make it available on sys.path
84
85 `version` should be a valid setuptools version number that is available
86 as an egg for download under the `download_base` URL (which should end with
87 a '/'). `to_dir` is the directory where setuptools will be downloaded, if
88 it is not already available. If `download_delay` is specified, it should
89 be the number of seconds that will be paused before initiating a download,
90 should one be required. If an older version of setuptools is installed,
91 this routine will print a message to ``sys.stderr`` and raise SystemExit in
92 an attempt to abort the calling script.
93 """
94 was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
95 def do_download():
96 egg = download_setuptools(version, download_base, to_dir, download_delay)
97 sys.path.insert(0, egg)
98 import setuptools; setuptools.bootstrap_install_from = egg
99 try:
100 import pkg_resources
101 except ImportError:
102 return do_download()
103 try:
104 pkg_resources.require("setuptools>="+version); return
105 except pkg_resources.VersionConflict, e:
106 if was_imported:
107 print >>sys.stderr, (
108 "The required version of setuptools (>=%s) is not available, and\n"
109 "can't be installed while this script is running. Please install\n"
110 " a more recent version first, using 'easy_install -U setuptools'."
111 "\n\n(Currently using %r)"
112 ) % (version, e.args[0])
113 sys.exit(2)
114 else:
115 del pkg_resources, sys.modules['pkg_resources'] # reload ok
116 return do_download()
117 except pkg_resources.DistributionNotFound:
118 return do_download()
119
120 def download_setuptools(
121 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
122 delay = 15
123 ):
124 """Download setuptools from a specified location and return its filename
125
126 `version` should be a valid setuptools version number that is available
127 as an egg for download under the `download_base` URL (which should end
128 with a '/'). `to_dir` is the directory where the egg will be downloaded.
129 `delay` is the number of seconds to pause before an actual download attempt.
130 """
131 import urllib2, shutil
132 egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
133 url = download_base + egg_name
134 saveto = os.path.join(to_dir, egg_name)
135 src = dst = None
136 if not os.path.exists(saveto): # Avoid repeated downloads
137 try:
138 from distutils import log
139 if delay:
140 log.warn("""
141 ---------------------------------------------------------------------------
142 This script requires setuptools version %s to run (even to display
143 help). I will attempt to download it for you (from
144 %s), but
145 you may need to enable firewall access for this script first.
146 I will start the download in %d seconds.
147
148 (Note: if this machine does not have network access, please obtain the file
149
150 %s
151
152 and place it in this directory before rerunning this script.)
153 ---------------------------------------------------------------------------""",
154 version, download_base, delay, url
155 ); from time import sleep; sleep(delay)
156 log.warn("Downloading %s", url)
157 src = urllib2.urlopen(url)
158 # Read/write all in one block, so we don't create a corrupt file
159 # if the download is interrupted.
160 data = _validate_md5(egg_name, src.read())
161 dst = open(saveto,"wb"); dst.write(data)
162 finally:
163 if src: src.close()
164 if dst: dst.close()
165 return os.path.realpath(saveto)
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 def main(argv, version=DEFAULT_VERSION):
203 """Install or upgrade setuptools and EasyInstall"""
204 try:
205 import setuptools
206 except ImportError:
207 egg = None
208 try:
209 egg = download_setuptools(version, delay=0)
210 sys.path.insert(0,egg)
211 from setuptools.command.easy_install import main
212 return main(list(argv)+[egg]) # we're done here
213 finally:
214 if egg and os.path.exists(egg):
215 os.unlink(egg)
216 else:
217 if setuptools.__version__ == '0.0.1':
218 print >>sys.stderr, (
219 "You have an obsolete version of setuptools installed. Please\n"
220 "remove it from your system entirely before rerunning this script."
221 )
222 sys.exit(2)
223
224 req = "setuptools>="+version
225 import pkg_resources
226 try:
227 pkg_resources.require(req)
228 except pkg_resources.VersionConflict:
229 try:
230 from setuptools.command.easy_install import main
231 except ImportError:
232 from easy_install import main
233 main(list(argv)+[download_setuptools(delay=0)])
234 sys.exit(0) # try to force an exit
235 else:
236 if argv:
237 from setuptools.command.easy_install import main
238 main(argv)
239 else:
240 print "Setuptools version",version,"or greater has been installed."
241 print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
242
243 def update_md5(filenames):
244 """Update our built-in md5 registry"""
245
246 import re
247
248 for name in filenames:
249 base = os.path.basename(name)
250 f = open(name,'rb')
251 md5_data[base] = md5(f.read()).hexdigest()
252 f.close()
253
254 data = [" %r: %r,\n" % it for it in md5_data.items()]
255 data.sort()
256 repl = "".join(data)
257
258 import inspect
259 srcfile = inspect.getsourcefile(sys.modules[__name__])
260 f = open(srcfile, 'rb'); src = f.read(); f.close()
261
262 match = re.search("\nmd5_data = {\n([^}]+)}", src)
263 if not match:
264 print >>sys.stderr, "Internal error!"
265 sys.exit(2)
266
267 src = src[:match.start(1)] + repl + src[match.end(1):]
268 f = open(srcfile,'w')
269 f.write(src)
270 f.close()
271
272
273 if __name__=='__main__':
274 if len(sys.argv)>2 and sys.argv[1]=='--md5update':
275 update_md5(sys.argv[2:])
276 else:
277 main(sys.argv[1:])
278
279
280
281
282
0 VERSION = (0, 1, 5, 'final', 0)
1 __version__ = '0.1.5'
0 /**
1 * Optimized Code For Quantizing Colors to xterm256
2 *
3 * These functions are equivalent to the ones found in xterm256.py but
4 * orders of a magnitude faster and should compile quickly (fractions
5 * of a second) on most systems with very little risk of
6 * complications.
7 *
8 * Color quantization is very complex. This works by treating RGB
9 * values as 3D euclidean space and brute-force searching for the
10 * nearest neighbor.
11 */
12
13 typedef struct {
14 int r;
15 int g;
16 int b;
17 } rgb_t;
18
19 int CUBE_STEPS[] = { 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF };
20 rgb_t BASIC16[] = { { 0, 0, 0 }, { 205, 0, 0}, { 0, 205, 0 },
21 { 205, 205, 0 }, { 0, 0, 238}, { 205, 0, 205 },
22 { 0, 205, 205 }, { 229, 229, 229}, { 127, 127, 127 },
23 { 255, 0, 0 }, { 0, 255, 0}, { 255, 255, 0 },
24 { 92, 92, 255 }, { 255, 0, 255}, { 0, 255, 255 },
25 { 255, 255, 255 } };
26 rgb_t COLOR_TABLE[256];
27
28
29 rgb_t xterm_to_rgb(int xcolor)
30 {
31 rgb_t res;
32 if (xcolor < 16) {
33 res = BASIC16[xcolor];
34 } else if (16 <= xcolor && xcolor <= 231) {
35 xcolor -= 16;
36 res.r = CUBE_STEPS[(xcolor / 36) % 6];
37 res.g = CUBE_STEPS[(xcolor / 6) % 6];
38 res.b = CUBE_STEPS[xcolor % 6];
39 } else if (232 <= xcolor && xcolor <= 255) {
40 res.r = res.g = res.b = 8 + (xcolor - 232) * 0x0A;
41 }
42 return res;
43 }
44
45 /**
46 * This function provides a quick and dirty way to serialize an rgb_t
47 * struct to an int which can be decoded by our Python code using
48 * ctypes.
49 */
50 int xterm_to_rgb_i(int xcolor)
51 {
52 rgb_t res = xterm_to_rgb(xcolor);
53 return (res.r << 16) | (res.g << 8) | (res.b << 0);
54 }
55
56 #define sqr(x) ((x) * (x))
57
58 /**
59 * Quantize RGB values to an xterm 256-color ID
60 */
61 int rgb_to_xterm(int r, int g, int b)
62 {
63 int best_match = 0;
64 int smallest_distance = 1000000000;
65 int c, d;
66 for (c = 16; c < 256; c++) {
67 d = sqr(COLOR_TABLE[c].r - r) +
68 sqr(COLOR_TABLE[c].g - g) +
69 sqr(COLOR_TABLE[c].b - b);
70 if (d < smallest_distance) {
71 smallest_distance = d;
72 best_match = c;
73 }
74 }
75 return best_match;
76 }
77
78 /* int rgb_to_xterm(int r, int g, int b) */
79 /* { */
80 /* int best_match = 0; */
81 /* int smallest_distance = 1000000000; */
82 /* int c, d; */
83 /* for (c = 0; c < 16; c++) { */
84 /* d = sqr(BASIC16[c].r - r) + */
85 /* sqr(BASIC16[c].g - g) + */
86 /* sqr(BASIC16[c].b - b); */
87 /* if (d < smallest_distance) { */
88 /* smallest_distance = d; */
89 /* best_match = c; */
90 /* } */
91 /* } */
92 /* return best_match; */
93 /* } */
94
95 int init()
96 {
97 int c;
98 for (c = 0; c < 256; c++) {
99 COLOR_TABLE[c] = xterm_to_rgb(c);
100 }
101 return 0;
102 }
0 # -*- coding: utf-8 -*-
1 """
2 fabulous.color
3 ~~~~~~~~~~~~~~
4
5 I implement support for standard 16-color color terminals.
6
7 """
8
9 import sys
10 import functools
11
12 from fabulous import utils, xterm256
13
14 import grapefruit
15
16
17 OVERLINE = u'\u203e'
18
19
20 def esc(*codes):
21 return "\x1b[%sm" % (";".join([str(c) for c in codes]))
22
23
24 class ColorString(object):
25 r"""A colorized string-like object that gives correct length
26
27 If anyone knows a way to be able to make this behave like a string
28 object without creating a bug minefield let me know::
29
30 >>> str(red("hello"))
31 '\x1b[31mhello\x1b[39m'
32 >>> len(red("hello"))
33 5
34 >>> len(str(red("hello")))
35 15
36 >>> str(bold(red("hello")))
37 '\x1b[1m\x1b[31mhello\x1b[39m\x1b[22m'
38 >>> len(bold(red("hello")))
39 5
40 >>> len(bold("hello ", red("world")))
41 11
42
43 """
44 sep = ""
45 fmt = "%s"
46
47 def __init__(self, *items):
48 self.items = items
49
50 def __str__(self):
51 return self.fmt % (self.sep.join([unicode(s) for s in self.items]))
52
53 def __repr__(self):
54 return repr(unicode(self))
55
56 def __len__(self):
57 return sum([len(item) for item in self.items])
58
59 def __add__(self, cs):
60 if not isinstance(cs, (basestring, ColorString)):
61 msg = "Concatenatation failed: %r + %r (Not a ColorString or str)"
62 raise TypeError(msg % (type(cs), type(self)))
63 return ColorString(self, cs)
64
65 def __radd__(self, cs):
66 if not isinstance(cs, (basestring, ColorString)):
67 msg = "Concatenatation failed: %r + %r (Not a ColorString or str)"
68 raise TypeError(msg % (type(self), type(cs)))
69 return ColorString(cs, self)
70
71 @property
72 def as_utf8(self):
73 """A more readable way to say ``unicode(color).encode('utf8')``
74 """
75 return unicode(self).encode('utf8')
76
77
78 class ColorString256(ColorString):
79 def __init__(self, color, *items):
80 (r, g, b) = parse_color(color)
81 self.color = xterm256.rgb_to_xterm(r, g, b)
82 self.items = items
83
84 def __str__(self):
85 return self.fmt % (
86 self.color, self.sep.join([unicode(s) for s in self.items]))
87
88
89 class plain(ColorString):
90 r"""A passive wrapper that preserves proper length reporting
91
92 >>> len(plain("hello ", bold("kitty")))
93 11
94 """
95 pass
96
97
98 class bold(ColorString):
99 fmt = esc(1) + "%s" + esc(22)
100 class italic(ColorString):
101 fmt = esc(3) + "%s" + esc(23)
102 class underline(ColorString):
103 fmt = esc(4) + "%s" + esc(24)
104 class underline2(ColorString):
105 fmt = esc(21) + "%s" + esc(24)
106 class strike(ColorString):
107 fmt = esc(9) + "%s" + esc(29)
108 class blink(ColorString):
109 fmt = esc(5) + "%s" + esc(25)
110 class flip(ColorString):
111 fmt = esc(7) + "%s" + esc(27)
112
113
114 class black(ColorString):
115 fmt = esc(30) + "%s" + esc(39)
116 class red(ColorString):
117 fmt = esc(31) + "%s" + esc(39)
118 class green(ColorString):
119 fmt = esc(32) + "%s" + esc(39)
120 class yellow(ColorString):
121 fmt = esc(33) + "%s" + esc(39)
122 class blue(ColorString):
123 fmt = esc(34) + "%s" + esc(39)
124 class magenta(ColorString):
125 fmt = esc(35) + "%s" + esc(39)
126 class cyan(ColorString):
127 fmt = esc(36) + "%s" + esc(39)
128 class white(ColorString):
129 fmt = esc(37) + "%s" + esc(39)
130
131
132 class highlight_black(ColorString):
133 fmt = esc(1, 30, 7) + "%s" + esc(22, 27, 39)
134 class highlight_red(ColorString):
135 fmt = esc(1, 31, 7) + "%s" + esc(22, 27, 39)
136 class highlight_green(ColorString):
137 fmt = esc(1, 32, 7) + "%s" + esc(22, 27, 39)
138 class highlight_yellow(ColorString):
139 fmt = esc(1, 33, 7) + "%s" + esc(22, 27, 39)
140 class highlight_blue(ColorString):
141 fmt = esc(1, 34, 7) + "%s" + esc(22, 27, 39)
142 class highlight_magenta(ColorString):
143 fmt = esc(1, 35, 7) + "%s" + esc(22, 27, 39)
144 class highlight_cyan(ColorString):
145 fmt = esc(1, 36, 7) + "%s" + esc(22, 27, 39)
146 class highlight_white(ColorString):
147 fmt = esc(1, 37, 7) + "%s" + esc(22, 27, 39)
148
149
150 class black_bg(ColorString):
151 fmt = esc(40) + "%s" + esc(49)
152 class red_bg(ColorString):
153 fmt = esc(41) + "%s" + esc(49)
154 class green_bg(ColorString):
155 fmt = esc(42) + "%s" + esc(49)
156 class yellow_bg(ColorString):
157 fmt = esc(43) + "%s" + esc(49)
158 class blue_bg(ColorString):
159 fmt = esc(44) + "%s" + esc(49)
160 class magenta_bg(ColorString):
161 fmt = esc(45) + "%s" + esc(49)
162 class cyan_bg(ColorString):
163 fmt = esc(46) + "%s" + esc(49)
164 class white_bg(ColorString):
165 fmt = esc(47) + "%s" + esc(49)
166
167
168 class fg256(ColorString256):
169 fmt = esc(38, 5, "%d") + "%s" + esc(39)
170
171
172 class bg256(ColorString256):
173 fmt = esc(48, 5, "%d") + "%s" + esc(49)
174
175
176 class highlight256(ColorString256):
177 fmt = esc(1, 38, 5, "%d", 7) + "%s" + esc(27, 39, 22)
178
179
180 class complement256(ColorString256):
181 fmt = esc(1, 38, 5, "%d", 48, 5, "%d") + "%s" + esc(49, 39, 22)
182
183 def __init__(self, color, *items):
184 self.bg = xterm256.rgb_to_xterm(*parse_color(color))
185 self.fg = xterm256.rgb_to_xterm(*complement(color))
186 self.items = items
187
188 def __str__(self):
189 return self.fmt % (
190 self.fg, self.bg,
191 self.sep.join([unicode(s) for s in self.items]))
192
193
194 def h1(title, line=OVERLINE):
195 width = utils.term.width
196 print bold(title.center(width)).as_utf8
197 print bold((line * width)[:width]).as_utf8
198
199
200 def parse_color(color):
201 r"""Turns a color into an (r, g, b) tuple
202
203 >>> parse_color('white')
204 (255, 255, 255)
205 >>> parse_color('#ff0000')
206 (255, 0, 0)
207 >>> parse_color('#f00')
208 (255, 0, 0)
209 >>> parse_color((255, 0, 0))
210 (255, 0, 0)
211 >>> import grapefruit
212 >>> parse_color(grapefruit.Color((0.0, 1.0, 0.0)))
213 (0, 255, 0)
214 """
215 if isinstance(color, basestring):
216 color = grapefruit.Color.NewFromHtml(color)
217 if isinstance(color, int):
218 (r, g, b) = xterm256.xterm_to_rgb(color)
219 elif hasattr(color, 'rgb'):
220 (r, g, b) = [int(c * 255.0) for c in color.rgb]
221 else:
222 (r, g, b) = color
223 assert isinstance(r, int) and 0 <= r <= 255
224 assert isinstance(g, int) and 0 <= g <= 255
225 assert isinstance(b, int) and 0 <= b <= 255
226 return (r, g, b)
227
228
229 def complement(color):
230 r"""Gives you the polar opposite of your color
231
232 This isn't guaranteed to look good >_> (especially with
233 brighter, higher intensity colors.)
234
235 >>> complement('red')
236 (0, 255, 76)
237 >>> complement((0, 100, 175))
238 (175, 101, 0)
239 """
240 (r, g, b) = parse_color(color)
241 gcolor = grapefruit.Color((r / 255.0, g / 255.0, b / 255.0))
242 complement = gcolor.ComplementaryColor()
243 (r, g, b) = [int(c * 255.0) for c in complement.rgb]
244 return (r, g, b)
245
246
247 def section(title, bar=OVERLINE, strm=sys.stdout):
248 """Helper function for testing demo routines
249 """
250 width = utils.term.width
251 print >>strm, bold(title.center(width)).as_utf8
252 print >>strm, bold((bar * width)[:width]).as_utf8
253
254
255 def main(args):
256 """I provide a command-line interface for this module
257 """
258 section("Fabulous 4-Bit Colors")
259
260 print ("style(...): " +
261 bold("bold") +" "+
262 underline("underline") +" "+
263 flip("flip") +
264 " (YMMV: " + italic("italic") +" "+
265 underline2("underline2") +" "+
266 strike("strike") +" "+
267 blink("blink") + ")\n").as_utf8
268
269 print ("color(...) " +
270 black("black") +" "+
271 red("red") +" "+
272 green("green") +" "+
273 yellow("yellow") +" "+
274 blue("blue") +" "+
275 magenta("magenta") +" "+
276 cyan("cyan") +" "+
277 white("white")).as_utf8
278
279 print ("bold(color(...)) " +
280 bold(black("black") +" "+
281 red("red") +" "+
282 green("green") +" "+
283 yellow("yellow") +" "+
284 blue("blue") +" "+
285 magenta("magenta") +" "+
286 cyan("cyan") +" "+
287 white("white"))).as_utf8
288
289 print plain(
290 'highlight_color(...) ',
291 highlight_black('black'), ' ', highlight_red('red'), ' ',
292 highlight_green('green'), ' ', highlight_yellow('yellow'), ' ',
293 highlight_blue('blue'), ' ', highlight_magenta('magenta'), ' ',
294 highlight_cyan('cyan'), ' ', highlight_white('white')).as_utf8
295
296 print ("bold(color_bg(...)) " +
297 bold(black_bg("black") +" "+
298 red_bg("red") +" "+
299 green_bg("green") +" "+
300 yellow_bg("yellow") +" "+
301 blue_bg("blue") +" "+
302 magenta_bg("magenta") +" "+
303 cyan_bg("cyan") +" "+
304 white_bg("white"))).as_utf8
305
306 section("Fabulous 8-Bit Colors")
307
308 for code in ["bold(fg256('red', ' lorem ipsum '))",
309 "bold(bg256('#ff0000', ' lorem ipsum '))",
310 "highlight256((255, 0, 0), ' lorem ipsum ')",
311 "highlight256('#09a', ' lorem ipsum ')",
312 "highlight256('green', ' lorem ipsum ')",
313 "highlight256('magenta', ' lorem ipsum ')",
314 "highlight256('indigo', ' lorem ipsum ')",
315 "highlight256('orange', ' lorem ipsum ')",
316 "highlight256('orangered', ' lorem ipsum ')"]:
317 print "%-42s %s" % (code, eval(code))
318 print ''
319
320 # grayscales
321 line = " "
322 for xc in range(232, 256):
323 line += bg256(xc, ' ')
324 print line
325 line = " "
326 for xc in range(232, 256)[::-1]:
327 line += bg256(xc, ' ')
328 print line
329 print ''
330
331 cube_color = lambda x,y,z: 16 + x + y*6 + z*6*6
332 for y in range(6):
333 line = " "
334 for z in range(6):
335 for x in range(6):
336 line += bg256(cube_color(x, y, z), ' ')
337 line += " "
338 print line.as_utf8
339
0 """
1 fabulous.debug
2 ~~~~~~~~~~~~~~
3
4 """
5
6 import sys
7 import itertools
8
9 from fabulous import image
10
11
12 class DebugImage(image.Image):
13 """Visualize optimization techniques used by :class:`Image`
14 """
15
16 def reduce(self, colors):
17 need_reset = False
18 line = ''
19 for color, items in itertools.groupby(colors):
20 if color is None:
21 if need_reset:
22 line = line[:-1] + ">"
23 need_reset = False
24 line += 'T' + (self.pad * len(list(items)))[1:]
25 elif color == "EOL":
26 if need_reset:
27 line = line[:-1] + ">"
28 need_reset = False
29 yield line.rstrip(' T')
30 else:
31 yield line.rstrip(' T')
32 line = ''
33 else:
34 need_reset = True
35 line += '<' + (self.pad * len(list(items)))[1:]
36
37
38 def main(args):
39 """I provide a command-line interface for this module
40 """
41 for imgpath in sys.argv[1:]:
42 for line in DebugImage(imgpath):
43 print line
44
45
46 if __name__ == '__main__':
47 main(sys.argv)
0
1 import os
2 import fabulous
3 from fabulous.color import *
4 from fabulous import text, utils, image, debug, xterm256
5
6
7 def wait():
8 raw_input("\nPress " + bold("enter") + " for more fun... ")
9 print ""
10
11
12 def demo_image():
13 section("Semi-Transparent PNG")
14 imp = " from fabulous import image\n "
15 print bold(imp + 'print image.Image("balls.png")\n')
16
17 balls = 'balls.png'
18 fabdir = os.path.dirname(fabulous.__file__)
19
20 for fn in ['balls.png',
21 'fabulous/balls.png',
22 os.path.join(fabdir, 'balls.png')]:
23 if os.path.exists(fn):
24 balls = fn
25 break
26
27 if not os.path.exists(balls):
28 import urllib
29 ugh = urllib.urlopen('http://lobstertech.com/media/img/balls.png')
30 open('balls.png', 'w').write(ugh.read())
31 balls = 'balls.png'
32
33 for line in image.Image(balls):
34 print line
35 wait()
36
37 section("Yes the output is optimized (JELLY-FISH)")
38 imp = " from fabulous import debug\n "
39 print bold(imp + 'print debug.DebugImage("balls.png")\n')
40 for line in debug.DebugImage(balls):
41 print line
42 wait()
43
44
45 def demo_text():
46 section('Fabulous Text Rendering')
47
48 imp = " from fabulous import text\n "
49 # print bold(imp + 'print text.Text("Fabulous")\n')
50 # print text.Text("Fabulous")
51 # wait()
52
53 print bold(imp + 'print text.Text("Fabulous", shadow=True, skew=5)\n')
54 print text.Text("Fabulous", shadow=True, skew=5)
55 wait()
56
57
58 def demo_color_4bit():
59 section("Fabulous 4-Bit Colors")
60
61 print ("style(...): " +
62 bold("bold") +" "+
63 underline("underline") +" "+
64 flip("flip") +
65 " (YMMV: " + italic("italic") +" "+
66 underline2("underline2") +" "+
67 strike("strike") +" "+
68 blink("blink") + ")\n").as_utf8
69
70 print ("color(...) " +
71 black("black") +" "+
72 red("red") +" "+
73 green("green") +" "+
74 yellow("yellow") +" "+
75 blue("blue") +" "+
76 magenta("magenta") +" "+
77 cyan("cyan") +" "+
78 white("white")).as_utf8
79
80 print ("bold(color(...)) " +
81 bold(black("black") +" "+
82 red("red") +" "+
83 green("green") +" "+
84 yellow("yellow") +" "+
85 blue("blue") +" "+
86 magenta("magenta") +" "+
87 cyan("cyan") +" "+
88 white("white"))).as_utf8
89
90 print plain(
91 'highlight_color(...) ',
92 highlight_black('black'), ' ', highlight_red('red'), ' ',
93 highlight_green('green'), ' ', highlight_yellow('yellow'), ' ',
94 highlight_blue('blue'), ' ', highlight_magenta('magenta'), ' ',
95 highlight_cyan('cyan'), ' ', highlight_white('white')).as_utf8
96
97 print ("bold(color_bg(...)) " +
98 bold(black_bg("black") +" "+
99 red_bg("red") +" "+
100 green_bg("green") +" "+
101 yellow_bg("yellow") +" "+
102 blue_bg("blue") +" "+
103 magenta_bg("magenta") +" "+
104 cyan_bg("cyan") +" "+
105 white_bg("white"))).as_utf8
106
107 wait()
108
109
110 def demo_color_8bit():
111 section("Fabulous 8-Bit Colors")
112
113 for code in ["bold(fg256('red', ' lorem ipsum '))",
114 "bold(bg256('#ff0000', ' lorem ipsum '))",
115 "highlight256((255, 0, 0), ' lorem ipsum ')",
116 "highlight256('#09a', ' lorem ipsum ')",
117 "highlight256('green', ' lorem ipsum ')",
118 "highlight256('magenta', ' lorem ipsum ')",
119 "highlight256('indigo', ' lorem ipsum ')",
120 "highlight256('orange', ' lorem ipsum ')",
121 "highlight256('orangered', ' lorem ipsum ')"]:
122 print "%-42s %s" % (code, eval(code))
123 print ''
124
125 # grayscales
126 line = " "
127 for xc in range(232, 256):
128 line += bg256(xc, ' ')
129 print line
130 line = " "
131 for xc in range(232, 256)[::-1]:
132 line += bg256(xc, ' ')
133 print line
134 print ''
135
136 cube_color = lambda x,y,z: 16 + x + y*6 + z*6*6
137 for y in range(6):
138 line = " "
139 for z in range(6):
140 for x in range(6):
141 line += bg256(cube_color(x, y, z), ' ')
142 line += " "
143 print line.as_utf8
144
145 wait()
146
147
148 def full_chart():
149 # grayscales
150 line = " "
151 for xc in range(232, 256):
152 line += bg256(xc, ' ')
153 print line
154 line = " "
155 for xc in range(232, 256)[::-1]:
156 line += bg256(xc, ' ')
157 print line
158 print ''
159
160 # cube
161 print ""
162 cube_color = lambda x,y,z: 16 + x + y*6 + z*6*6
163 for y in range(6):
164 line = " "
165 for z in range(6):
166 for x in range(6):
167 line += bg256(cube_color(x, y, z), ' ')
168 line += " "
169 print line.as_utf8
170 print ""
171
172 def f(xc):
173 s = highlight256(xc, "color %03d" % (xc))
174 rgb = xterm256.xterm_to_rgb(xc)
175 rgbs = ' (%3d, %3d, %3d)' % rgb
176 if rgb[0] == rgb[1] == rgb[2]:
177 s += bold(rgbs)
178 else:
179 s += rgbs
180 s += ' (%08d, %08d, %08d)' % tuple([int(bin(n)[2:]) for n in rgb])
181 return s
182
183 def l(c1, c2):
184 c1, c2 = f(c1), f(c2)
185 assert len(c1) == len(c2)
186 half = width // 2
187 assert half > len(c1)
188 pad = " " * ((width // 2 - len(c1)) // 2)
189 print "%(pad)s%(c1)s%(pad)s%(pad)s%(c2)s" % {'pad': pad, 'c1': c1, 'c2': c2}
190
191 width = utils.term.width
192 for z1, z2 in zip((0, 2, 4), (1, 3, 5)):
193 for y1, y2 in zip(range(6), range(6)):
194 for x1, x2 in zip(range(6), range(6)):
195 l(cube_color(x1, y1, z1), cube_color(x2, y2, z2))
196 print ""
197
198
199 if __name__ == '__main__':
200 # full_chart()
201 demo_color_4bit()
202 demo_color_8bit()
203 demo_text()
204 demo_image()
205
206
207 # if __name__ == '__main__':
208 # def sect(s):
209 # print "\n" * term_height()
210 # print bold("=" * term_width())
211 # pad = " " * (term_width() // 2 - len(s) // 2)
212 # print bold(pad + s)
213 # print bold("=" * term_width())
214 # print ""
215
216 # sect("Agent Orange")
217 # for line in Image('orange.png'):
218 # print line
219 # wait()
220
221 # sect("LOL Cat (JPEGs are not its forte)")
222 # for line in Image('lolcat.jpg'):
223 # print line
224 # wait()
225
226 # sect("Semi-Transparent PNG")
227 # for line in Image('balls.png'):
228 # print line
229 # wait()
230
231 # sect("Yes the output is optimized (JELLY-FISH)")
232 # for line in DebugImage('balls.png'):
233 # print line
234 # wait()
235
236 # basicConfig(level=logging.WARNING)
237
238 # sect("Transient Style Logging (Uses standard python logger)")
239 # test_transientlogger()
240
241 # sect("More Transient Logging (Teen Goth Poetry Engine Included)")
242 # test_transientlogger2()
0
1 from __future__ import with_statement
2
3 import time
4 import curses
5
6
7 class Canvas(object):
8 def __init__(self, encoding='UTF-8'):
9 self.encoding = encoding
10
11 def __enter__(self):
12 self.win = curses.initscr()
13 curses.start_color()
14 curses.init_color(200, 1000, 300, 0)
15 curses.init_pair(1, 200, curses.COLOR_WHITE)
16 return self
17
18 def __exit__(self, type_, value, traceback):
19 curses.endwin()
20
21 def __setitem__(self, xy, val):
22 self.win.attron(curses.color_pair(1))
23 (x, y) = xy
24 self.win.addch(x, y, val)
25
26
27 if __name__ == '__main__':
28 import locale
29 locale.setlocale(locale.LC_ALL, '')
30 encoding = locale.getpreferredencoding()
31 with Canvas(encoding=encoding) as canvas:
32 canvas[5, 5] = 'Y'
33 canvas.win.refresh()
34 time.sleep(5.0)
0 """
1 fabulous.gotham
2 ~~~~~~~~~~~~~~~
3
4 I implement functions to satisfy your darker side.
5
6 """
7
8 import sys
9 import random
10 import itertools
11
12
13 them = ['angels', 'mourners', 'shadows', 'storm clouds', 'memories', 'condemned',
14 'hand of Heaven', 'stroke of death', 'damned', 'witches', 'corpses']
15 them_verb = ['follow', 'hover close', 'approach', 'loom', 'taunt',
16 'laugh', 'surround', 'compell', 'scour']
17 adj = ['cold', 'dead', 'dark', 'frozen', 'angry', 'ghastly', 'unholy', 'cunning', 'deep',
18 'morose', 'maligned', 'rotting', 'sickly']
19 me_part = ['neck', 'heart', 'head', 'eyes', 'soul', 'blood', 'essence', 'wisdom']
20 feeling = ['pain', 'horror', 'frenzy', 'agony', 'numbness', 'fear', 'love',
21 'terror', 'madness', 'torment', 'bitterness', 'misery']
22 angst = ['care', 'understand', 'question']
23 me_verb = ['flee', 'dance', 'flail madly', 'fall limply', 'hang my head', 'try to run',
24 'cry out', 'call your name', 'beg forgiveness', 'bleed', 'tremble', 'hear']
25 action = ['sever', 'crush', 'mutilate', 'slay', 'wound', 'smite', 'drip',
26 'melt', 'cast', 'mourn', 'avenge']
27 place = ['the witching hour', 'the gates of hell', 'the door', 'the path', 'death',
28 'my doom', 'oblivion', 'the end of life', 'Hell', 'nothingness', 'purgatory',
29 'void', 'earth', 'tomb', 'broken ground', 'barren land', 'swirling dust']
30
31
32 def lorem_gotham():
33 """Cheesy Gothic Poetry Generator
34
35 Uses Python generators to yield eternal angst.
36
37 When you need to generate random verbiage to test your code or
38 typographic design, let's face it... Lorem Ipsum and "the quick
39 brown fox" are old and boring!
40
41 What you need is something with *flavor*, the kind of thing a
42 depressed teenager with a lot of black makeup would write.
43 """
44 w = lambda l: l[random.randrange(len(l))]
45 er = lambda w: w[:-1]+'ier' if w.endswith('y') else (w+'r' if w.endswith('e') else w+'er')
46 s = lambda w: w+'s'
47 punc = lambda c, *l: " ".join(l)+c
48 sentence = lambda *l: lambda: " ".join(l)
49 pick = lambda *l: (l[random.randrange(len(l))])()
50 while True:
51 yield pick(
52 sentence('the',w(adj),w(them),'and the',w(them),w(them_verb)),
53 sentence('delivering me to',w(place)),
54 sentence('they',w(action),'my',w(me_part),'and',w(me_verb),'with all my',w(feeling)),
55 sentence('in the',w(place),'my',w(feeling),'shall',w(me_verb)),
56 sentence(punc(',', er(w(adj)),'than the a petty',w(feeling))),
57 sentence(er(w(adj)),'than',w(them),'in',w(place)),
58 sentence(punc('!','oh my',w(me_part)),punc('!','the',w(feeling))),
59 sentence('no one',s(w(angst)),'why the',w(them),w(them_verb + me_verb)))
60
61
62 def lorem_gotham_title():
63 """Names your poem
64 """
65 w = lambda l: l[random.randrange(len(l))]
66 sentence = lambda *l: lambda: " ".join(l)
67 pick = lambda *l: (l[random.randrange(len(l))])()
68 return pick(
69 sentence('why i',w(me_verb)),
70 sentence(w(place)),
71 sentence('a',w(adj),w(adj),w(place)),
72 sentence('the',w(them)))
73
74
75 def main(args):
76 """I provide a command-line interface for this module
77 """
78 print
79 print "-~*~--~*~--~*~--~*~--~*~--~*~--~*~--~*~--~*~--~*~-"
80 print lorem_gotham_title().center(50)
81 print "-~*~--~*~--~*~--~*~--~*~--~*~--~*~--~*~--~*~--~*~-"
82 print
83 poem = lorem_gotham()
84 for n in range(16):
85 if n in (4, 8, 12):
86 print
87 print poem.next()
88 print
89
90
91 if __name__ == '__main__':
92 main(sys.argv)
0 """
1 fabulous.image
2 ~~~~~~~~~~~~~~
3
4 """
5
6 import sys
7 import itertools
8
9 import grapefruit as gf
10
11 from fabulous import utils, xterm256
12
13
14 class Image(object):
15 """Printing image files to a terminal
16
17 I use :mod:`PIL` to turn your image file into a bitmap, resize it
18 so it'll fit inside your terminal, and implement methods so I can
19 behave like a string or iterable.
20
21 When resizing, I'll assume that a single character on the terminal
22 display is one pixel wide and two pixels tall. For most fonts
23 this is the best way to preserve the aspect ratio of your image.
24
25 All colors are are quantized by :mod:`fabulous.xterm256` to the
26 256 colors supported by modern terminals. When quantizing
27 semi-transparant pixels (common in text or PNG files) I'll ask
28 :class:`TerminalInfo` for the background color I should use to
29 solidify the color. Fully transparent pixels will be rendered as
30 a blank space without color so we don't need to mix in a
31 background color.
32
33 I also put a lot of work into optimizing the output line-by-line
34 so it needs as few ANSI escape sequences as possible. If your
35 terminal is kinda slow, you're gonna want to buy me a drink ;) You
36 can use :class:`DebugImage` to visualize these optimizations.
37
38 The generated output will only include spaces with different
39 background colors. In the future routines will be provided to
40 overlay text on top of these images.
41
42 """
43
44 pad = ' '
45
46 def __init__(self, path, width=None):
47 utils.pil_check()
48 from PIL import Image as PillsPillsPills
49 self.img = PillsPillsPills.open(path)
50 # when reading pixels, gifs will return colors corresponding
51 # to a palette if we don't do this :\
52 self.img = self.img.convert("RGBA")
53 self.resize(width)
54
55 def __iter__(self):
56 """I allow Image to behave as an iterable
57
58 By using me with a for loop, you can use each line as they're
59 created. When printing a large image, this helps you not have
60 to wait for the whole thing to be converted.
61
62 :return: Yields lines of text (without line end character)
63 """
64 # strip out blank lines
65 for line in self.reduce(self.convert()):
66 if line.strip():
67 yield line
68 yield ""
69
70 def __str__(self):
71 """I return the entire image as one big string
72
73 Unlike the iteration approach, you have to wait for the entire
74 image to be converted.
75
76 :return: String containing all lines joined together.
77 """
78 return "\n".join(self)
79
80 @property
81 def size(self):
82 """Returns size of image
83 """
84 return self.img.size
85
86 def resize(self, width=None):
87 """Resizes image to fit inside terminal
88
89 Called by the constructor automatically.
90 """
91 (iw, ih) = self.size
92 if width is None:
93 width = min(iw, utils.term.width)
94 elif isinstance(width, basestring):
95 percents = dict([(pct, '%s%%' % (pct)) for pct in range(101)])
96 width = percents[width]
97 height = int(float(ih) * (float(width) / float(iw)))
98 height //= 2
99 self.img = self.img.resize((width, height))
100
101 def reduce(self, colors):
102 """Converts color codes into optimized text
103
104 This optimizer works by merging adjacent colors so we don't
105 have to repeat the same escape codes for each pixel. There is
106 no loss of information.
107
108 :param colors: Iterable yielding an xterm color code for each
109 pixel, None to indicate a transparent pixel, or
110 ``'EOL'`` to indicate th end of a line.
111
112 :return: Yields lines of optimized text.
113
114 """
115 need_reset = False
116 line = []
117 for color, items in itertools.groupby(colors):
118 if color is None:
119 if need_reset:
120 line.append("\x1b[49m")
121 need_reset = False
122 line.append(self.pad * len(list(items)))
123 elif color == "EOL":
124 if need_reset:
125 line.append("\x1b[49m")
126 need_reset = False
127 yield "".join(line)
128 else:
129 line.pop()
130 yield "".join(line)
131 line = []
132 else:
133 need_reset = True
134 line.append("\x1b[48;5;%dm%s" % (
135 color, self.pad * len(list(items))))
136
137 def convert(self):
138 """Yields xterm color codes for each pixel in image
139 """
140 (width, height) = self.img.size
141 bgcolor = utils.term.bgcolor
142 self.img.load()
143 for y in xrange(height):
144 for x in xrange(width):
145 rgba = self.img.getpixel((x, y))
146 if len(rgba) == 4 and rgba[3] == 0:
147 yield None
148 elif len(rgba) == 3 or rgba[3] == 255:
149 yield xterm256.rgb_to_xterm(*rgba[:3])
150 else:
151 color = gf.Color.NewFromRgb(*[c / 255.0 for c in rgba])
152 rgba = gf.Color.AlphaBlend(color, bgcolor).rgb
153 yield xterm256.rgb_to_xterm(
154 *[int(c * 255.0) for c in rgba])
155 yield "EOL"
156
157
158 def main(args):
159 """I provide a command-line interface for this module
160 """
161 for imgpath in args:
162 for line in Image(imgpath):
163 print line
164
165
166 if __name__ == '__main__':
167 main(sys.argv[1:])
0 """
1 fabulous.logs
2 ~~~~~~~~~~~~~
3
4 I provide utilities for making your logs look fabulous.
5
6 """
7
8 import sys
9 import logging
10
11 from fabulous import utils
12
13
14 class TransientStreamHandler(logging.StreamHandler):
15 """Standard Python logging Handler for Transient Console Logging
16
17 Logging transiently means that verbose logging messages like DEBUG
18 will only appear on the last line of your terminal for a short
19 period of time and important messages like WARNING will scroll
20 like normal text.
21
22 This allows you to log lots of messages without the important
23 stuff getting drowned out.
24
25 This module integrates with the standard Python logging module.
26 """
27
28 def __init__(self, strm=sys.stderr, level=logging.WARNING):
29 logging.StreamHandler.__init__(self, strm)
30 if isinstance(level, int):
31 self.levelno = level
32 else:
33 self.levelno = logging._levelNames[level]
34 self.need_cr = False
35 self.last = ""
36 self.parent = logging.StreamHandler
37
38 def close(self):
39 if self.need_cr:
40 self.stream.write("\n")
41 self.need_cr = False
42 self.parent.close(self)
43
44 def write(self, data):
45 if self.need_cr:
46 width = max(min(utils.term.width, len(self.last)), len(data))
47 fmt = "\r%-" + str(width) + "s\n" + self.last
48 else:
49 fmt = "%s\n"
50 try:
51 self.stream.write(fmt % (data))
52 except UnicodeError:
53 self.stream.write(fmt % (data.encode("UTF-8")))
54
55 def transient_write(self, data):
56 if self.need_cr:
57 self.stream.write('\r')
58 else:
59 self.need_cr = True
60 width = utils.term.width
61 for line in data.rstrip().split('\n'):
62 if line:
63 if len(line) > width:
64 line = line[:width - 3] + '...'
65 line_width = max(min(width, len(self.last)), len(line))
66 fmt = "%-" + str(line_width) + "s"
67 self.last = line
68 try:
69 self.stream.write(fmt % (line))
70 except UnicodeError:
71 self.stream.write(fmt % (line.encode("UTF-8")))
72 else:
73 self.stream.write('\r')
74 self.stream.flush()
75
76 def emit(self, record):
77 try:
78 msg = self.format(record)
79 if record.levelno >= self.levelno:
80 self.write(msg)
81 else:
82 self.transient_write(msg)
83 except (KeyboardInterrupt, SystemExit):
84 raise
85 except:
86 self.handleError(record)
87
88
89 def basicConfig(level=logging.WARNING, transient_level=logging.NOTSET):
90 """Shortcut for setting up transient logging
91
92 I am a replica of ``logging.basicConfig`` which installs a
93 transient logging handler to stderr.
94 """
95 fmt = "%(asctime)s [%(levelname)s] [%(name)s:%(lineno)d] %(message)s"
96 logging.root.setLevel(transient_level) # <--- IMPORTANT
97 hand = TransientStreamHandler(level=level)
98 hand.setFormatter(logging.Formatter(fmt))
99 logging.root.addHandler(hand)
0 """
1 fabulous.rotating_cube
2 ~~~~~~~~~~~~~~~~~~~~~~
3
4 Completely pointless terminal renderer of rotating cube
5
6 Uses a faux 2D rendering technique to create what appears to be a
7 wireframe 3d cube.
8
9 This doesn't use the curses library, but rather prints entire
10 frames sized to fill the entire terminal display.
11
12 """
13
14 from __future__ import with_statement
15
16 import sys
17 import time
18 from math import cos, sin, pi
19
20 from fabulous import color, utils
21
22
23 class Frame(object):
24 """Canvas object for drawing a frame to be printed
25 """
26
27 def __enter__(self):
28 self.width = utils.term.width
29 self.height = utils.term.height * 2
30 self.canvas = [[' ' for x in range(self.width)]
31 for y in range(self.height // 2)]
32 return self
33
34 def __exit__(self, type_, value, traceback):
35 sys.stdout.write(self.render())
36 sys.stdout.flush()
37
38 def __setitem__(self, p, c):
39 (x, y) = p
40 self.canvas[int(y // 2)][int(x)] = c
41
42 def line(self, x0, y0, x1, y1, c='*'):
43 r"""Draws a line
44
45 Who would have thought this would be so complicated? Thanks
46 again Wikipedia_ <3
47
48 .. _Wikipedia: http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
49 """
50 steep = abs(y1 - y0) > abs(x1 - x0)
51 if steep:
52 (x0, y0) = (y0, x0)
53 (x1, y1) = (y1, x1)
54 if x0 > x1:
55 (x0, x1) = (x1, x0)
56 (y0, y1) = (y1, y0)
57 deltax = x1 - x0
58 deltay = abs(y1 - y0)
59 error = deltax / 2
60 y = y0
61 if y0 < y1:
62 ystep = 1
63 else:
64 ystep = -1
65 for x in range(x0, x1 - 1):
66 if steep:
67 self[y, x] = c
68 else:
69 self[x, y] = c
70 error = error - deltay
71 if error < 0:
72 y = y + ystep
73 error = error + deltax
74
75 def render(self):
76 return "\n".join(["".join(line) for line in self.canvas])
77
78
79 def rotating_cube(degree_change=3, frame_rate=10):
80 """Rotating cube program
81
82 How it works:
83
84 1. Create two imaginary ellipses
85 2. Sized to fit in the top third and bottom third of screen
86 3. Create four imaginary points on each ellipse
87 4. Make those points the top and bottom corners of your cube
88 5. Connect the lines and render
89 6. Rotate the points on the ellipses and repeat
90
91 """
92 degrees = 0
93 while True:
94 t1 = time.time()
95
96 with Frame() as frame:
97 oval_width = frame.width
98 oval_height = frame.height / 3.0
99 cube_height = oval_height * 2
100
101 (p1_x, p1_y) = ellipse_point(degrees, oval_width, oval_height)
102 (p2_x, p2_y) = ellipse_point(degrees + 90, oval_width, oval_height)
103 (p3_x, p3_y) = ellipse_point(degrees + 180, oval_width, oval_height)
104 (p4_x, p4_y) = ellipse_point(degrees + 270, oval_width, oval_height)
105 degrees = (degrees + degree_change) % 360
106
107 # connect square thing at top
108 frame.line(p1_x, p1_y, p2_x, p2_y)
109 frame.line(p2_x, p2_y, p3_x, p3_y)
110 frame.line(p3_x, p3_y, p4_x, p4_y)
111 frame.line(p4_x, p4_y, p1_x, p1_y)
112
113 # connect top to bottom
114 frame.line(p1_x, p1_y, p1_x, p1_y + cube_height)
115 frame.line(p2_x, p2_y, p2_x, p2_y + cube_height)
116 frame.line(p3_x, p3_y, p3_x, p3_y + cube_height)
117 frame.line(p4_x, p4_y, p4_x, p4_y + cube_height)
118
119 # connect square thing at bottom
120 frame.line(p1_x, p1_y + cube_height, p2_x, p2_y + cube_height)
121 frame.line(p2_x, p2_y + cube_height, p3_x, p3_y + cube_height)
122 frame.line(p3_x, p3_y + cube_height, p4_x, p4_y + cube_height)
123 frame.line(p4_x, p4_y + cube_height, p1_x, p1_y + cube_height)
124
125 elapsed = (time.time() - t1)
126 time.sleep(abs(1.0 / frame_rate - elapsed))
127
128
129 def ellipse_point(degrees, width, height):
130 """I hate math so much :'(
131 """
132 width -= 1
133 height -= 1
134 radians = degrees * (pi / 180.0)
135 x = width/2.0 * cos(1) * sin(radians) - width/2.0 * sin(1) * cos(radians)
136 y = height/2.0 * sin(1) * sin(radians) + height/2.0 * cos(1) * cos(radians)
137 x = int(x + width/2.0)
138 y = int(y + height/2.0)
139 return (x, y)
140
141
142 if __name__ == '__main__':
143 try:
144 rotating_cube()
145 except KeyboardInterrupt:
146 pass
0
1 import logging
2
3 from fabulous.logs import *
4 from fabulous.gotham import *
5 from fabulous.color import *
6
7
8 logger = logging.getLogger('fabulous')
9
10
11 def luv():
12 msg = "hello there how are you? i love you! sincerely compy <3 <3"
13 while True:
14 for n in range(len(msg)) + list(reversed(range(len(msg)))):
15 yield msg[:n+1]
16
17
18 def bad_things():
19 yield red("godzilla attack")
20 yield bold(red("magnetic poles reverse"))
21 yield red("caffeine use criminalized")
22 yield bold(red("more horrible things happening...."))
23 yield highlight_red("THIS INFORMATION IS NOT BEING DROWNED OUT!")
24 yield bold(red("hip hip hooray"))
25
26
27 def test_transientlogger():
28 import random, time
29 happy, nightmare = luv(), bad_things()
30 try:
31 while True:
32 if random.randrange(60) == 0:
33 logger.warning(nightmare.next())
34 else:
35 logger.debug(happy.next())
36 time.sleep(0.02)
37 except StopIteration:
38 pass
39
40
41 def test_transientlogger2():
42 import time, random
43 gothic = lorem_gotham()
44 try:
45 while True:
46 if random.randrange(20) == 0:
47 logger.warning(red(gothic.next()))
48 else:
49 logger.debug(gothic.next())
50 time.sleep(0.1)
51 except StopIteration:
52 pass
53
54
55 if __name__ == '__main__':
56 basicConfig(level=logging.WARNING)
57 logging.warning("RUNNING TEST: test_transientlogger()")
58 test_transientlogger()
59 logging.warning("RUNNING TEST: test_transientlogger2()")
60 test_transientlogger2()
0 """
1 fabulous.text
2 ~~~~~~~~~~~~~
3
4 I let you print TrueType text to your terminal. The easiest way
5 to get started with me is by running::
6
7 jart@compy:~$ python -m fabulous.text --help
8
9 To make things simple, Fabulous comes with my favorite serif,
10 non-serif, and monospace fonts:
11
12 - IndUni-H-Bold: Open Source Helvetica Bold clone (sans-serif)
13
14 This is the real deal and not some cheap ripoff like Verdana.
15 IndUni-H-Bold is the default because not only does it look
16 great, but also renders *perfectly*. and is also used for the
17 Fabulous logo. Commonly found on stret signs.
18
19 This font is licensed under the GPL. If you're developing
20 proprietary software you might want to ask its author or a
21 lawyer if Fabulous' use of IndUni-H would be considered a "GPL
22 Barrier."
23
24 - cmr10: Computer Modern (serif)
25
26 Donald Knuth wrote 23,000 lines for the sole purpose of
27 bestowing this jewel upon the world. This font is commonly seen
28 in scholarly papers.
29
30 - DejaVuSansMono: DejaVu Sans Mono (formerly Bitstream Vera Sans Mono)
31
32 At point size 8, this is my favorite programming/terminal font.
33
34 For other fonts, I'll try my best to figure out where your font
35 files are stored. If I have trouble finding your font, try using
36 an absolute path *with* the extension. You could also try putting
37 the font in your ``~/.fonts`` folder and running ``fc-cache -fv
38 ~/.fonts``.
39
40 """
41
42 import os
43 import sys
44
45 import grapefruit
46
47 from fabulous import utils, image
48
49
50 class Text(image.Image):
51 """Renders TrueType Text to Terminal
52
53 I'm a sub-class of :class:`fabulous.image.Image`. My job is
54 limited to simply getting things ready. I do this by:
55
56 - Turning your text into an RGB-Alpha bitmap image using
57 :mod:`PIL`
58
59 - Applying way cool effects (if you choose to enable them)
60
61 For example::
62
63 >>> assert Text("Fabulous", shadow=True, skew=5)
64
65 >>> txt = Text("lorem ipsum", font="IndUni-H-Bold")
66 >>> len(str(txt)) > 0
67 True
68 >>> txt = Text("lorem ipsum", font="cmr10")
69 >>> len(str(txt)) > 0
70 True
71 >>> txt = Text("lorem ipsum", font="DejaVuSansMono")
72 >>> len(str(txt)) > 0
73 True
74
75 :param text: The text you want to display as a string.
76
77 :param fsize: The font size in points. This obviously end up
78 looking much larger because in fabulous a single
79 character is treated as one horizontal pixel and two
80 vertical pixels.
81
82 :param color: The color (specified as you would in HTML/CSS) of
83 your text. For example Red could be specified as
84 follows: ``red``, ``#00F`` or ``#0000FF``.
85
86 :param shadow: If true, render a simple drop-shadow beneath text.
87 The Fabulous logo uses this feature.
88
89 :param skew: Skew size in pixels. This applies an affine
90 transform to shift the top-most pixels to the right.
91 The Fabulous logo uses a five pixel skew.
92
93 :param font: The TrueType font you want. If this is not an
94 absolute path, Fabulous will search for your font by
95 globbing the specified name in various directories.
96 """
97
98 def __init__(self, text, fsize=20, color="#0099ff", shadow=False,
99 skew=None, font='IndUni-H-Bold'):
100 utils.pil_check()
101 from PIL import Image, ImageFont, ImageDraw
102 self.text = text
103 self.color = grapefruit.Color.NewFromHtml(color)
104 self.font = ImageFont.truetype(resolve_font(font), fsize)
105 size = tuple([n + 3 for n in self.font.getsize(self.text)])
106 self.img = Image.new("RGBA", size, (0, 0, 0, 0))
107 cvs = ImageDraw.Draw(self.img)
108 if shadow:
109 cvs.text((2, 2), self.text,
110 font=self.font,
111 fill=(150, 150, 150, 150))
112 cvs.text((1, 1), self.text,
113 font=self.font,
114 fill=self.color.html)
115 if skew:
116 self.img = self.img.transform(
117 size, Image.AFFINE, (1.0, 0.1 * skew, -1.0 * skew,
118 0.0, 1.0, 0.0))
119 self.resize(None)
120
121
122 class FontNotFound(ValueError):
123 """I get raised when the font-searching hueristics fail
124
125 This class extends the standard :exc:`ValueError` exception so you
126 don't have to import me if you don't want to.
127 """
128
129
130 def resolve_font(name):
131 """Sloppy way to turn font names into absolute filenames
132
133 This isn't intended to be a proper font lookup tool but rather a
134 dirty tool to not have to specify the absolute filename every
135 time.
136
137 For example::
138
139 >>> path = resolve_font('IndUni-H-Bold')
140
141 >>> fontdir = os.path.join(os.path.dirname(__file__), 'fonts')
142 >>> indunih_path = os.path.join(fontdir, 'IndUni-H-Bold.ttf')
143 >>> assert path == indunih_path
144
145 This isn't case-sensitive::
146
147 >>> assert resolve_font('induni-h') == indunih_path
148
149 Raises :exc:`FontNotFound` on failure::
150
151 >>> resolve_font('blahahaha')
152 Traceback (most recent call last):
153 ...
154 FontNotFound: Can't find 'blahahaha' :'( Try adding it to ~/.fonts
155
156 """
157 for fontdir, fontfiles in get_font_files():
158 for fontfile in fontfiles:
159 if name.lower() in fontfile.lower():
160 return os.path.join(fontdir, fontfile)
161 raise FontNotFound("Can't find %r :'( Try adding it to ~/.fonts")
162
163
164 @utils.memoize
165 def get_font_files():
166 """Returns a list of all font files we could find
167
168 Returned as a list of dir/files tuples::
169
170 get_font_files() -> [('/some/dir', ['font1.ttf', ...]), ...]
171
172 For example::
173
174 >>> fabfonts = os.path.join(os.path.dirname(__file__), 'fonts')
175 >>> 'IndUni-H-Bold.ttf' in get_font_files()[fabfontdir]
176 True
177 >>> 'DejaVuSansMono.ttf' in get_font_files()[fabfontdir]
178 True
179 >>> 'cmr10.ttf' in get_font_files()[fabfontdir]
180 True
181
182 >>> assert len(get_font_files()) > 0
183 >>> for dirname, filename in get_font_files():
184 ... assert os.path.exists(os.path.join(dirname, filename))
185 ...
186
187 """
188 dirs = [os.path.join(os.path.dirname(__file__), 'fonts'),
189 os.path.expanduser('~/.fonts')]
190 try:
191 # this is where ubuntu puts fonts
192 dirname = '/usr/share/fonts/truetype'
193 dirs += [os.path.join(dirname, subdir)
194 for subdir in os.listdir(dirname)]
195 except OSError:
196 pass
197 return [(p, os.listdir(p)) for p in dirs if os.path.isdir(p)]
198
199
200 def main(args):
201 """I provide a command-line interface for this module
202 """
203 import optparse
204 parser = optparse.OptionParser()
205 parser.add_option(
206 "-S", "--skew", dest="skew", type="int", default=None,
207 help=("Apply skew effect (measured in pixels) to make it look "
208 "extra cool. For example, Fabulous' logo logo is skewed "
209 "by 5 pixels. Default: %default"))
210 parser.add_option(
211 "-C", "--color", dest="color", default="#0099ff",
212 help=("Color of your text. This can be specified as you would "
213 "using HTML/CSS. Default: %default"))
214 parser.add_option(
215 "-B", "--term-color", dest="term_color", default=None,
216 help=("If you terminal background isn't black, please change "
217 "this value to the proper background so semi-transparent "
218 "pixels will blend properly."))
219 parser.add_option(
220 "-F", "--font", dest="font", default='IndUni-H-Bold',
221 help=("Path to font file you wish to use. This defaults to a "
222 "free Helvetica-Bold clone which is included with Fabulous. "
223 "Default value: %default"))
224 parser.add_option(
225 "-Z", "--size", dest="fsize", type="int", default=20,
226 help=("Size of font in points. Default: %default"))
227 parser.add_option(
228 "-s", "--shadow", dest="shadow", action="store_true", default=False,
229 help=("Size of font in points. Default: %default"))
230 (options, args) = parser.parse_args(args=args)
231
232 if options.term_color:
233 utils.term.bgcolor = options.term_color
234
235 for line in " ".join(args).split("\n"):
236 fab_text = Text(line, skew=options.skew, color=options.color,
237 font=options.font, fsize=options.fsize,
238 shadow=options.shadow)
239 for chunk in fab_text:
240 print chunk
241
242
243 if __name__ == '__main__':
244 main(sys.argv[1:])
0 """
1 fabulous.utils
2 ~~~~~~~~~~~~~~
3
4 """
5
6 import os
7 import sys
8 import fcntl
9 import struct
10 import termios
11 import textwrap
12 import functools
13
14 import grapefruit
15
16
17 def memoize(function):
18 """A very simple memoize decorator to optimize pure-ish functions
19
20 Don't use this unless you've examined the code and see the
21 potential risks.
22 """
23 cache = {}
24 @functools.wraps(function)
25 def _memoize(*args):
26 if args in cache:
27 return cache[args]
28 result = function(*args)
29 cache[args] = result
30 return result
31 return function
32
33
34 class TerminalInfo(object):
35 """Quick and easy access to some terminal information
36
37 I'll tell you the terminal width/height and it's background color.
38
39 You don't need to use me directly. Just access the global
40 :data:`term` instance::
41
42 >>> assert term.width > 0
43 >>> assert term.height > 0
44
45 It's important to know the background color when rendering PNG
46 images with semi-transparency. Because there's no way to detect
47 this, black will be the default::
48
49 >>> term.bgcolor
50 (0.0, 0.0, 0.0, 1.0)
51 >>> import grapefruit
52 >>> isinstance(term.bgcolor, grapefruit.Color)
53 True
54
55 If you use a white terminal, you'll need to manually change this::
56
57 >>> term.bgcolor = 'white'
58 >>> term.bgcolor
59 (1.0, 1.0, 1.0, 1.0)
60 >>> term.bgcolor = grapefruit.Color.NewFromRgb(0.0, 0.0, 0.0, 1.0)
61 >>> term.bgcolor
62 (0.0, 0.0, 0.0, 1.0)
63
64 """
65
66 def __init__(self, bgcolor='black'):
67 self.bgcolor = bgcolor
68
69 @property
70 def termfd(self):
71 """Returns file descriptor number of terminal
72
73 This will look at all three standard i/o file descriptors and
74 return whichever one is actually a TTY in case you're
75 redirecting i/o through pipes.
76 """
77 for fd in (2, 1, 0):
78 if os.isatty(fd):
79 return fd
80 raise Exception("No TTY could be found")
81
82 @property
83 def dimensions(self):
84 """Returns terminal dimensions
85
86 Don't save this information for long periods of time because
87 the user might resize their terminal.
88
89 :return: Returns ``(width, height)``. If there's no terminal
90 to be found, we'll just return ``(79, 40)``.
91 """
92 try:
93 call = fcntl.ioctl(self.termfd, termios.TIOCGWINSZ, "\000" * 8)
94 except:
95 return (79, 40)
96 else:
97 height, width = struct.unpack("hhhh", call)[:2]
98 return (width, height)
99
100 @property
101 def width(self):
102 """Returns width of terminal in characters
103 """
104 return self.dimensions[0]
105
106 @property
107 def height(self):
108 """Returns height of terminal in lines
109 """
110 return self.dimensions[1]
111
112 def _get_bgcolor(self):
113 return self._bgcolor
114
115 def _set_bgcolor(self, color):
116 if isinstance(color, grapefruit.Color):
117 self._bgcolor = color
118 else:
119 self._bgcolor = grapefruit.Color.NewFromHtml(color)
120
121 bgcolor = property(_get_bgcolor, _set_bgcolor)
122
123
124 term = TerminalInfo()
125
126
127 def pil_check():
128 """Check for PIL library, printing friendly error if not found
129
130 We need PIL for the :mod:`fabulous.text` and :mod:`fabulous.image`
131 modules to work. Because PIL can be very tricky to install, it's
132 not listed in the ``setup.py`` requirements list.
133
134 Not everyone is going to have PIL installed so it's best that we
135 offer as much help as possible so they don't have to suffer like I
136 have in the past :'(
137 """
138 try:
139 import PIL
140 except ImportError:
141 raise ImportError(textwrap.dedent("""
142 Oh no! You don't have the evil PIL library!
143
144 Here's how you get it:
145
146 Ubuntu/Debian:
147
148 sudo apt-get install python-imaging
149
150 Mac OS X:
151
152 http://pythonmac.org/packages/py24-fat/index.html
153 http://pythonmac.org/packages/py25-fat/index.html
154
155 Windows:
156
157 http://effbot.org/downloads/PIL-1.1.7.win32-py%(pyversion)s.exe
158
159 Everyone Else:
160
161 This is like the hardest library in the world to
162 manually install. If your package manager doesn't have
163 it, you can try running ``sudo easy_install pil`` once
164 you get your hands on a C compiler as well as the
165 following libraries (including the development headers)
166 for Python, libz, libjpeg, libgif, libpng, libungif4,
167 libfreetype6, and maybe more >_>
168
169 """ % {'pyversion': "%s.%s" % sys.version_info[:2]}))
0 """
1 fabulous.xterm256
2 ~~~~~~~~~~~~~~~~~
3
4 Implements Support for the 256 colors supported by xterm as well
5 as quantizing 24-bit RGB color to xterm color ids.
6
7 Color quantization is very very slow so when this module is
8 loaded, it'll attempt to automatically compile a speedup module
9 using gcc. A :mod:`logging` message will be emitted if it fails
10 and we'll fallback on the Python code.
11
12 """
13
14 import logging
15
16
17 CUBE_STEPS = [0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF]
18 BASIC16 = ((0, 0, 0), (205, 0, 0), (0, 205, 0), (205, 205, 0),
19 (0, 0, 238), (205, 0, 205), (0, 205, 205), (229, 229, 229),
20 (127, 127, 127), (255, 0, 0), (0, 255, 0), (255, 255, 0),
21 (92, 92, 255), (255, 0, 255), (0, 255, 255), (255, 255, 255))
22
23
24 def xterm_to_rgb(xcolor):
25 """Convert xterm Color ID to an RGB value
26
27 All 256 values are precalculated and stored in :data:`COLOR_TABLE`
28 """
29 assert 0 <= xcolor <= 255
30 if xcolor < 16:
31 # basic colors
32 return BASIC16[xcolor]
33 elif 16 <= xcolor <= 231:
34 # color cube
35 xcolor -= 16
36 return (CUBE_STEPS[(xcolor / 36) % 6],
37 CUBE_STEPS[(xcolor / 6) % 6],
38 CUBE_STEPS[xcolor % 6])
39 elif 232 <= xcolor <= 255:
40 # gray tone
41 c = 8 + (xcolor - 232) * 0x0A
42 return (c, c, c)
43
44
45 COLOR_TABLE = [xterm_to_rgb(i) for i in xrange(256)]
46
47
48 def rgb_to_xterm(r, g, b):
49 """Quantize RGB values to an xterm 256-color ID
50
51 This works by envisioning the RGB values for all 256 xterm colors
52 as 3D euclidean space and brute-force searching for the nearest
53 neighbor.
54
55 This is very slow. If you're very lucky, :func:`compile_speedup`
56 will replace this function automatically with routines in
57 `_xterm256.c`.
58 """
59 if r < 5 and g < 5 and b < 5:
60 return 16
61 best_match = 0
62 smallest_distance = 10000000000
63 for c in xrange(16, 256):
64 d = (COLOR_TABLE[c][0] - r) ** 2 + \
65 (COLOR_TABLE[c][1] - g) ** 2 + \
66 (COLOR_TABLE[c][2] - b) ** 2
67 if d < smallest_distance:
68 smallest_distance = d
69 best_match = c
70 return best_match
71
72
73 def compile_speedup():
74 """Tries to compile/link the C version of this module
75
76 Like it really makes a huge difference. With a little bit of luck
77 this should *just work* for you.
78
79 You need:
80
81 - Python >= 2.5 for ctypes library
82 - gcc (``sudo apt-get install gcc``)
83
84 """
85 import os
86 import ctypes
87 from os.path import join, dirname, getmtime, exists, expanduser
88 # library = join(dirname(__file__), '_xterm256.so')
89 library = expanduser('~/.xterm256.so')
90 sauce = join(dirname(__file__), '_xterm256.c')
91 if not exists(library) or getmtime(sauce) > getmtime(library):
92 build = "gcc -fPIC -shared -o %s %s" % (library, sauce)
93 assert os.system(build + " >/dev/null 2>&1") == 0
94 xterm256_c = ctypes.cdll.LoadLibrary(library)
95 xterm256_c.init()
96 def xterm_to_rgb(xcolor):
97 res = xterm256_c.xterm_to_rgb_i(xcolor)
98 return ((res >> 16) & 0xFF, (res >> 8) & 0xFF, res & 0xFF)
99 return (xterm256_c.rgb_to_xterm, xterm_to_rgb)
100
101
102 try:
103 (rgb_to_xterm, xterm_to_rgb) = compile_speedup()
104 except:
105 logging.debug("fabulous failed to compile xterm256 speedup code")
0 Metadata-Version: 1.0
1 Name: fabulous
2 Version: 0.1.5
3 Summary: Makes your terminal output totally fabulous
4 Home-page: http://lobstertech.com/fabulous.html
5 Author: J.A. Roberts Tunney
6 Author-email: jtunney@lobstertech.com
7 License: MIT
8 Download-URL: http://lobstertech.com/media/file/fabulous/fabulous-0.1.5.tar.gz
9 Description: .. -*-restructuredtext-*-
10
11 ==========
12 Fabulous
13 ==========
14
15 ---------------------------------------------
16 Makes Your Terminal Output Totally Fabulous
17 ---------------------------------------------
18
19 :Version: 0.1
20 :Date: 2009-12-07
21 :Copyright: Copyright (c) 2009 Lobstertech, Inc.
22 :Manual section: 3
23 :Manual group: Library Calls
24
25
26 Getting Started
27 ===============
28
29 Download and extract the latest version::
30
31 sudo apt-get install gcc python-imaging python-setuptools
32 sudo python setup.py install
33
34 Run the demo to see what's available::
35
36 python -m fabulous.demo
37
38
39 Basic Examples
40 ==============
41
42 Colors
43 ------
44
45 4-bit color. These colors and styles are standard and work almost
46 everywhere. They are useful in helping make your program output
47 easier to read::
48
49 from fabulous import bold, magenta, highlight_red
50
51 print bold(magenta('hello kitty'))
52 print highlight_red('DANGER DANGER!')
53
54 print bold('hello') + ' ' + magenta( kitty')
55
56 assert len(bold('test')) == 4
57
58 8-bit color. If you want to spice things up a bit, Fabulous supports
59 xterm256 colors::
60
61 from fabulous import fg256, bg256
62 print fg256('#F0F', 'hello kitty')
63 print fg256('magenta', 'hello kitty')
64
65
66 Fancy Text
67 ----------
68
69 Way cool text. This is something neat you can use when you program
70 starts up to display its name with style::
71
72 from fabulous import text
73 print text.Text("Fabulous", color='#0099ff', shadow=True, scew=5)
74
75
76 Images
77 ------
78
79 Fabulous lets you print images, which is more fun than useful.
80 Fabulous' unique method of printing images really shines when used
81 with semi-transparent PNG files. When blending backgrounds, Fabulous
82 assumes by default that your terminal has a black background. Don't
83 worry if your image is huge, it'll be resized by default to fit your
84 terminal::
85
86 from fabulous import utils, image
87 print image.Image("balls.png")
88
89 # adjust for a white background
90 utils.term.bgcolor = 'white'
91 print image.Image("balls.png")
92
93 It's scriptable too (like img2txt) ::
94
95 python -m fabulous.image balls.png >balls.txt
96 cat balls.txt
97
98
99 Transient Logging
100 -----------------
101
102 This is very useful tool for monitoring what your Python scripts are
103 doing. It allows you to have full verbosity without drowning out
104 important error messages::
105
106 import time, logging
107 from fabulous import logs
108 logs.basicConfig(level='WARNING')
109
110 for n in range(20):
111 logging.debug("verbose stuff you don't care about")
112 time.sleep(0.1)
113 logging.warning("something bad happened!")
114 for n in range(20):
115 logging.debug("verbose stuff you don't care about")
116 time.sleep(0.1)
117
118
119 Why Fabulous?
120 =============
121
122 Here's how Fabulous compares to other similar libraries:
123
124 - fabulous_: Licensed MIT. Focuses on delivering useful features in
125 the simplest, most user-friendly way possible (without a repulsive
126 name.) Written in pure-python but will attempt to auto-magically
127 compile/link a speedup library. ~1,000 lines of code.
128
129 - libcaca_: WTFPL. This is the established and respected standard for
130 doing totally insane things with ascii art (ever wanted to watch a
131 movie on the command line?) Weighing in at ~72k lines of C, this
132 project is a monster. It uses an older, more complex
133 text/dithering-based rendering method. Compared to fabulous, some
134 images look better, some worse. I found the docs somewhat difficult
135 to follow and couldn't find support for transparency or 256-colors.
136
137 - asciiporn_: GPL. Similar to libcaca but has an interesting feature
138 for drawing math graphs to the terminal... Needs to compile C code,
139 requires numpy/python2.6, and I couldn't get the darn thing to work.
140 Aprox 17k lines of code.
141
142 - pygments_: BSD. Has *excellent* support for terminal syntax highlighting.
143
144 - termcolor_: GPL. Only supports 4-bit ANSI colors.
145
146 .. _fabulous: http://pypi.python.org/pypi/fabulous
147 .. _libcaca: http://caca.zoy.org/
148 .. _termcolor: http://pypi.python.org/pypi/termcolor
149 .. _pygments: http://pygments.org/
150 .. _asciiporn: http://pypi.python.org/pypi/asciiporn/2009.05.01
151
152
153 ToDo
154 ====
155
156 - <http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/>
157
158 Platform: UNKNOWN
159 Classifier: Development Status :: 2 - Pre-Alpha
160 Classifier: License :: OSI Approved :: MIT License
161 Classifier: Environment :: Console
162 Classifier: Intended Audience :: Developers
163 Classifier: Programming Language :: C
164 Classifier: Programming Language :: Python
165 Classifier: Topic :: Utilities
166 Classifier: Topic :: Artistic Software
167 Classifier: Topic :: System :: Logging
168 Classifier: Topic :: Multimedia :: Graphics
0 .hgignore
1 .hgtags
2 COPYING
3 README
4 ez_setup.py
5 setup.py
6 docs/Makefile
7 docs/conf.py
8 docs/index.rst
9 fabulous/__init__.py
10 fabulous/_xterm256.c
11 fabulous/color.py
12 fabulous/debug.py
13 fabulous/demo.py
14 fabulous/gotham.py
15 fabulous/image.py
16 fabulous/logs.py
17 fabulous/rotating_cube.py
18 fabulous/test_transientlogging.py
19 fabulous/text.py
20 fabulous/utils.py
21 fabulous/xterm256.py
22 fabulous.egg-info/PKG-INFO
23 fabulous.egg-info/SOURCES.txt
24 fabulous.egg-info/dependency_links.txt
25 fabulous.egg-info/not-zip-safe
26 fabulous.egg-info/requires.txt
27 fabulous.egg-info/top_level.txt
28 fabulous/experimental/__init__.py
29 fabulous/experimental/canvas.py
30 fabulous/fonts/DejaVuSansMono.ttf
31 fabulous/fonts/IndUni-H-Bold.otf
32 fabulous/fonts/cmr10.ttf
0 [egg_info]
1 tag_build =
2 tag_date = 0
3 tag_svn_revision = 0
4
0
1 # http://packages.python.org/distribute/setuptools.html
2 # http://diveintopython3.org/packaging.html
3 # http://wiki.python.org/moin/CheeseShopTutorial
4 # http://pypi.python.org/pypi?:action=list_classifiers
5
6 from ez_setup import use_setuptools
7 use_setuptools(version='0.6c11')
8
9 import os
10 from setuptools import setup, find_packages
11
12 def read(fname):
13 return open(os.path.join(os.path.dirname(__file__), fname)).read()
14
15 version = __import__('fabulous').__version__
16
17 setup(
18 name = 'fabulous',
19 version = version,
20 url = 'http://lobstertech.com/fabulous.html',
21 author = 'J.A. Roberts Tunney',
22 author_email = 'jtunney@lobstertech.com',
23 description = 'Makes your terminal output totally fabulous',
24 download_url = ('http://lobstertech.com/media/file/fabulous/'
25 'fabulous-' + version + '.tar.gz'),
26 long_description = read('README'),
27 license = 'MIT',
28 install_requires = ['grapefruit'],
29 packages = find_packages(),
30 zip_safe = False,
31 include_package_data = True,
32 classifiers = [
33 "Development Status :: 2 - Pre-Alpha",
34 "License :: OSI Approved :: MIT License",
35 "Environment :: Console",
36 "Intended Audience :: Developers",
37 "Programming Language :: C",
38 "Programming Language :: Python",
39 "Topic :: Utilities",
40 "Topic :: Artistic Software",
41 "Topic :: System :: Logging",
42 "Topic :: Multimedia :: Graphics"
43 ],
44 )