weblog+jinja2+markdown2-2.5 0040755 0001750 0000000 00000000000 11337076075 0014704 5 ustar 00henry wheel weblog+jinja2+markdown2-2.5/contrib 0040755 0001750 0000000 00000000000 11337076062 0016340 5 ustar 00henry wheel weblog+jinja2+markdown2-2.5/contrib/migrate.py 0100644 0001750 0000000 00000007022 11337076062 0020417 0 ustar 00henry wheel import os import sys import ConfigParser from optparse import OptionParser, SUPPRESS_HELP from weblog.publish import load_post_list from weblog.post import Post def main(): parser = OptionParser() parser.add_option("-s", "--source_dir", dest="source_dir", default='.', help='The source directory where the blog posts are ' 'located. [default: \'%default\']', metavar="DIR") parser.add_option("-o", "--output_dir", dest="output_dir", default='output', help='The directory where all the generated files are ' 'written. If it does not exist it is created.' '[default: \'%default\']', metavar="DIR") parser.add_option('-e', '--encoding', dest='encoding', default='utf-8') parser.add_option('--redirections-only', dest='redirection_only', default=False, action='store_true', help='Generate only redirection files.') (options, args) = parser.parse_args() if options.redirection_only: print 'Creating config.py ...' config = ConfigParser.SafeConfigParser() filename = os.path.join(options.source_dir, 'weblog.ini') if os.path.isfile(filename): config.read(filename) else: raise SystemExit(filename + " doesn't exist") string_values = ('title', 'url', 'description', 'source_dir', 'output_dir', 'encoding', 'author') integer_values = ('post_per_page', 'feed_limit') obsolete_values = ('html_head', 'html_header', 'html_footer') output = open(os.path.join(options.output_dir, 'config.py'), 'w') def _config_get(key): try: return config.get('weblog', key) except ConfigParser.NoOptionError: return for key in string_values: value = _config_get(key) if value: output.write('%s = %r\n' % (key, value)) for key in integer_values: value = _config_get(key) if value is not None: output.write('%s = %d\n' % (key, int(value))) obsoletes = list() for key in obsolete_values: if _config_get(key): print ('Warning: %s are now obsolete. Check documentation.' % ', '.join(obsolete_values)) break print 'done' if options.encoding: Post.DEFAULT_ENCODING = options.encoding print 'Creating redirections ...' _REDIRECTION_FILE = \ ('\n' '
a file
It will copy ``picture.png`` and ``directory/file``. If ``directory`` does not
exist, it will be created.
You can specify multiple files like this::
files: image1.png image2.png
Space characters act as the separators. This means that filenames cannot
contain spaces.
How URL's in content are handled
--------------------------------
Sometime, URL's have to be changed to make sure they point to the correct
location.
Relative links (````) are rewritten in HTML files to make
sure it always point to the root of the output directory.
Absolute links (````) are not rewritten. It always
point to the correct location regardless of the context.
Note that Weblog considers ``/`` as the root directory. If ``base_url`` is
``http://example.com/``; ``test.html`` and ``/test.html`` are both rewritten to
``http://example.com/test.html``.
.. _style:
Customizing Weblog's appearance
-------------------------------
To customize Weblog's appearance you need to change the templates used to
generate the pages. To learn how to modify the templates, check `Jinja 2`_
documentation, also a basic knowledge of HTML and CSS is needed.
You can find the templates in ``weblog/templates`` in your Weblog's
installation directory. Copy the files you want to modify into the
``templates`` directory inside of your source directory::
$ mkdir source/directory/templates
$ cp /path/to/weblog/templates/base.html source/directory/templates
``base.html`` is probably the file you want to modify to customize Weblog's
global appearance. All other templates extend it.
``index.html`` is the main page and ``archives.html`` is the archive page,
listing all the posts on your blog.
``post.html`` is used to generate individual post's page.
There is also a template named ``feed.atom`` you should not modify this one. It
is used to generate the Atom feed.
CSS and HTML resources
~~~~~~~~~~~~~~~~~~~~~~
CSS is hard. The CSS syntax tend to be confusing for beginners. The numerous
browser incompatibilities makes the designer's work even more complicated. Here
is a list of useful resources regarding this subject:
- SitePoint_ CSS Reference is very helpful. It lists all CSS properties and
document how well they are supported by the different browsers.
- HtmlHelp_ contains a complete HTML 4 reference.
.. _Jinja 2: http://jinja.pocoo.org/2/documentation/
.. _HtmlHelp: http://htmlhelp.com/reference/html40/
.. _SitePoint: http://reference.sitepoint.com/css
Command line parameters
-----------------------
Usage: weblog [option] command
Commands:
publish
date
Options:
-h, --help show this help message and exit
-s DIR, --source_dir=DIR
The source directory where the blog posts are located.
[default: '.']
-o DIR, --output_dir=DIR
The directory where all the generated files are
written. If it does not exist it is created.[default:
'output']
-c FILE, --conf=FILE The configuration file to use. If the file is not
present in the current directory, the source directory
is searched. [default: 'config.py']
-q, --quiet Do not output anything except critical error messages
Configuration file
------------------
Weblog's configuration file is a Python script. If you don't know Python, don't
worry, the syntax is straightforward and you need very little knowledge to get
started with Weblog.
Example ``config.py``::
title = "Blog's title"
url = "http://example.com"
description = "A sample blog"
author = "Me A paragraph
Emphased words, and Strong words.
Adding a picture ---------------- Create a directory named ``images`` in your blog's directory. That's where the images will be stored. Copy a picture you would like to publish into ``images``. Let's call it ``weblog.png``. ``post_image.txt``:: title: Posting an image files: images/weblog.png  The `files` parameter tells Weblog to copy `images/weblog.png` into the output directory. Note that the path is preserved; the file is copied to `output/images/weblog.png`. You can copy all kinds of files, not just images. What next? ---------- To learn more about Weblog and how to use it check :ref:`reference_manual` and how to customize its appearance check :ref:`style`. .. _Markdown: http://daringfireball.net/projects/markdown/syntax#overview .. vim:se tw=79 sw=2 ts=2 et: weblog+jinja2+markdown2-2.5/doc/update.sh 0100755 0001750 0000000 00000000315 11337076062 0017341 0 ustar 00henry wheel #!/bin/ksh dst=${DST:-"${HOME}/henry.precheur.org/weblog/"} if [[ -d $dst ]]; then ${HOME}/env/sphinx/bin/sphinx-build -b html -E . $dst || echo 'Error' else echo "$dst doesn't exist" fi weblog+jinja2+markdown2-2.5/.hg_archival.txt 0100644 0001750 0000000 00000000223 11337076062 0020037 0 ustar 00henry wheel repo: 00ecfb3367fecf6d8ba7a94c3f995bc789c18d1e node: 35376e9bf8d1e47e534a8065262615d1c784d9e9 branch: default latesttag: 2.4 latesttagdistance: 16 weblog+jinja2+markdown2-2.5/.hgignore 0100644 0001750 0000000 00000000101 11337076062 0016547 0 ustar 00henry wheel syntax: glob *.pyc *~ .*.swp build weblog.egg-info doc/.build/* weblog+jinja2+markdown2-2.5/.hgtags 0100644 0001750 0000000 00000002070 11337076062 0016231 0 ustar 00henry wheel 9bafbb9dfb928172d988390ea61932b610278ea3 0.1 7053f6c08fab7af1c5b76d78a9bb6e41fe6a8b5a 0.2 ebe752dc0a655b451babdc2acb6027a523ac8474 0.3 9cc6b91a2fb95946b5443461201c8a57ad301a53 0.4 85db8e1cb11890a15f38b3d161dc59962e00b135 0.5 fcd5f323c67112916c0d43d776f52a96064bef53 0.5 44abff8da985b456545fa393a2f634932400476b 0.5 a0a1dd94b8b2371f45536e90ee03074dae314f71 0.6 657340b5fa4b2a1747e139809da6e576d7699290 0.7 f4075497305adf1cada74fa556a227049a2ccae5 0.8 8377a76875c476b8697cbfc25be7b3d1fe961028 0.9 2b7a9f4e897d42683ac16491822eddeab8f5b3b7 1.0 1ed0521ffc52335e6560d2135b0f85dc4aab01b2 1.0 e54c184ffac370252b0f34933a307cf741f92f97 1.1 96cef61f3ee4410144cb01064177b0fa1d03380f 1.2 09f6a45625e6b75335109406a7755b993cb137de 1.3 ef58aed7dbc44603f3ca10af11a74df407a1943d 2.0 8b9be5dcd7fac0a9b9a4e51a84314f7c6d3bd0f2 2.1 5f8669ae7a1aeabe763c0ac1c5d8a9a82c3d2c5a 2.1 57c5f28ca0550ec5ddebaadb559add2727e771aa 2.2 7d13ebee58c5b3b7934a6013a6361d8215f260ab 2.3 e71349aa1608fe904c79504d9b3117b8e38dc3aa 2.4 e71349aa1608fe904c79504d9b3117b8e38dc3aa 2.4 4a48bc0e343915c2ce760d9aad0bd0c8915a0cad 2.4 weblog+jinja2+markdown2-2.5/COPYING 0100644 0001750 0000000 00000012017 11337076075 0016014 0 ustar 00henry wheel Copyright (c) 2007, 2008, Henry PrecheurSome UTF-8 characters: ËÃØ ...
{# vim:set ft=htmljinja: #} weblog+jinja2+markdown2-2.5/test/template_encoding/config.py 0100644 0001750 0000000 00000000054 11337076062 0023232 0 ustar 00henry wheel url = 'http://test.org/' encoding = 'UTF-8' weblog+jinja2+markdown2-2.5/setup.cfg 0100644 0001750 0000000 00000000047 11337076062 0016576 0 ustar 00henry wheel [nosetests] verbosity=3 with-doctest=1 weblog+jinja2+markdown2-2.5/setup.py 0100644 0001750 0000000 00000002606 11337076062 0016472 0 ustar 00henry wheel try: from setuptools import setup except: from distutils.core import setup from os.path import join, dirname import weblog short_description = open(join(dirname(__file__), 'doc', 'short_description.txt')).read() long_description = (short_description + '''\n To get news and updates about Weblog check the author's blog: http://henry.precheur.org/ or check Weblog's homepage: http://henry.precheur.org/weblog/''') setup(name="weblog", version=weblog.__version__, packages=['weblog'], package_dir={'weblog': 'weblog'}, package_data={'weblog': ['templates/*.tmpl']}, requires=['Jinja2'], install_requires=['Jinja2'], # unzip the egg so we can access to documentation & templates zip_safe=False, # metadata for upload to PyPI author='Henry Precheur', author_email='henry@precheur.org', description=short_description, long_description=long_description, license="ISCL", keywords="weblog blog journal diary atom", url="http://henry.precheur.org/weblog/", classifiers=[ 'Development Status :: 5 - Production/Stable', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: News/Diary', 'Intended Audience :: End Users/Desktop', 'Programming Language :: Python'], entry_points=dict(console_scripts=('weblog = weblog:main',))) weblog+jinja2+markdown2-2.5/test.py 0100644 0001750 0000000 00000030654 11337076062 0016315 0 ustar 00henry wheel from __future__ import with_statement import os import shutil import tempfile import unittest import email import datetime from optparse import Values from weblog.markup import markups from weblog.page import Page, Error, Author from weblog.publish import load_posts from weblog.date import command_date from weblog.publish import command_publish from weblog import configuration from weblog.html_full_url import FullUrlHtmlParser from weblog.utf8_html_parser import UTF8HTMLParser from weblog.rfc3339 import LocalTimeTestCase _DIRNAME = os.path.dirname(__file__) def _test_filename(filename): return os.path.join(_DIRNAME, 'test', filename) def _default_dict(**kwargs): d = dict(author=Author(''), url='/', encoding='ascii', filesystem_encoding='ascii', ignore_dirs=['templates'], post_per_page=10, feed_limit=10) d.update(kwargs) return d class TestSimpleLoad(unittest.TestCase): def test_load_post_list(self): post_list = load_posts(_test_filename('simple'), _default_dict()) self.assertEqual(len(post_list), 3) sorted_list = sorted(post_list) self.assertEqual(sorted_list[0].title, 'post1') self.assertEqual(sorted_list[1].title, 'post2') self.assertEqual(sorted_list[2].title, 'post3') def test_load_post_list_encoding_failure(self): self.assertRaises(Error, load_posts, _test_filename('encoding'), _default_dict()) def test_load_post_list_encoding(self): post_list = load_posts(_test_filename('encoding'), _default_dict(encoding='UTF-8')) self.assertEqual(len(post_list), 2) sorted_list = sorted(post_list) self.assertEqual(sorted_list[0].title, u'UTF-8 post \xd6\xc9\xc8\xc4 ...') self.assertEqual(sorted_list[0].body, u'\xd6\xe9\xe8\xe4\n') self.assertEqual(sorted_list[1].title, u'latin post \xd6\xc9\xc8\xc4 ...') self.assertEqual(sorted_list[1].body, u'\xd6\xe9\xe8\xe4\n') def test_load_posts_duplicate(self): self.assertRaises(IOError, load_posts, _test_filename('duplicate'), _default_dict()) class TestPage(unittest.TestCase): def test_empty(self): self.assertRaises(ValueError, Page) def test_simple(self): sample_post = ('title: test\ndate: 2008-1-1\nauthor: test author\n' 'encoding: ascii\n\ntest.') post = Page(content=sample_post) self.assertEqual(post.title, u'test') self.assertEqual(post.date, datetime.date(2008, 1, 1)) self.assertEqual(post.author, u'test author') self.assertEqual(post.encoding, 'ascii') self.assertEqual(post.body, u'test.') def test_encoding(self): sample_post = (u'title: Test UTF-8 \xdcTF-8 ?\n' u'author: Henry Pr\xeacheurhtml
test
html
test
html
test
boo
\n\nboo
\n\nboo
\n' u'boo
\n' u'{{ description|escape|decode }}
{% endif %} {% for post in posts[:(post_per_page or 10)] %}{{ post.date.isoformat(' ') if post.date.__class__.__name__ == 'datetime' else post.date.isoformat() }} {%- if post.author %} , {% endif %}
{%- if date.__class__.__name__ == 'datetime' -%} {{ date.isoformat(' ') }} {%- else -%} {{ date.isoformat() }} {%- endif -%} {%- if author %} , {% endif %}
'
'''
if attrs:
if tag in (u'img', u'script', u'iframe'):
attrs = self.make_full_url(u'src', attrs)
elif tag in (u'a', u'area'):
attrs = self.make_full_url(u'href', attrs)
elif tag == u'object':
attrs = self.make_full_url(u'data', attrs)
attrs = self.make_full_url(u'codebase', attrs)
return u'<%s %s%s>' % (tag,
self.html_attrs(attrs),
endtag)
else:
return u'<%s%s>' % (tag, endtag)
def handle_starttag(self, tag, attrs):
self.output.append(self.rewrite_tag(tag, attrs))
def handle_startendtag(self, tag, attrs):
self.output.append(self.rewrite_tag(tag, attrs, endtag=u'/'))
def html_full_url(base_url, text):
'''
Appends ``base_url`` to relative uri's in the HTML
document ``text``.
Example with ``base_url=http://example.com``::
'' becomes ''
'
' becomes '
'
but
' is not changed since it is an
*absolute* URI.
>>> html_full_url('http://example.com', '')
u''
>>> html_full_url('http://example.com', '
')
u'
'
'''
p = FullUrlHtmlParser(base_url)
p.feed(text)
return p.get_value()
if __name__ == '__main__':
import doctest
doctest.testmod()
weblog+jinja2+markdown2-2.5/weblog/html_to_xhtml.py 0100644 0001750 0000000 00000003337 11337076062 0021475 0 ustar 00henry wheel import logging
from htmlentitydefs import name2codepoint, entitydefs
from utf8_html_parser import UTF8HTMLParser
class _Parser(UTF8HTMLParser):
'''
Parse an HTML document and convert it to valid xhtml.
'''
_EMPTY_HTML_TAGS = ('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr',
'img', 'input', 'isindex', 'link', 'meta', 'param')
_XML_ENTITIES = ('amp', 'gt', 'lt', 'quot')
def handle_starttag(self, tag, attrs):
if tag in self._EMPTY_HTML_TAGS:
self.handle_startendtag(tag, attrs)
elif attrs:
self.output.append(u'<%s %s>' % (tag, self.html_attrs(attrs)))
else:
self.output.append(u'<%s>' % tag)
def handle_startendtag(self, tag, attrs):
if attrs:
self.output.append(u'<%s %s />' % (tag, self.html_attrs(attrs)))
else:
self.output.append('<%s />' % tag)
def handle_entityref(self, name):
if name in self._XML_ENTITIES:
self.output.append(u'&%s;' % name)
elif name in name2codepoint:
self.output.append(u'%d;' % name2codepoint[name])
else:
logging.warning('Unknown XHTML entiry: &%s;' % name);
def html_to_xhtml(html):
'''
Convert html to xhtml
>>> html_to_xhtml('Hello
World
Hello
World
Hello world
") >>> parser.get_value() u'Hello world
' >>> parser.feed('Another
sentence.
Hello world
Another
sentence.
%s
' % escape(x) for x in result)) class Markup(unicode): r"""Marks a string as being safe for inclusion in HTML/XML output without needing to be escaped. This implements the `__html__` interface a couple of frameworks and web applications use. :class:`Markup` is a direct subclass of `unicode` and provides all the methods of `unicode` just that it escapes arguments passed and always returns `Markup`. The `escape` function returns markup objects so that double escaping can't happen. If you want to use autoescaping in Jinja just enable the autoescaping feature in the environment. The constructor of the :class:`Markup` class can be used for three different things: When passed an unicode object it's assumed to be safe, when passed an object with an HTML representation (has an `__html__` method) that representation is used, otherwise the object passed is converted into a unicode string and then assumed to be safe: >>> Markup("Hello World!") Markup(u'Hello World!') >>> class Foo(object): ... def __html__(self): ... return 'foo' ... >>> Markup(Foo()) Markup(u'foo') If you want object passed being always treated as unsafe you can use the :meth:`escape` classmethod to create a :class:`Markup` object: >>> Markup.escape("Hello World!") Markup(u'Hello <em>World</em>!') Operations on a markup string are markup aware which means that all arguments are passed through the :func:`escape` function: >>> em = Markup("%s") >>> em % "foo & bar" Markup(u'foo & bar') >>> strong = Markup("%(text)s") >>> strong % {'text': ''} Markup(u'<blink>hacker here</blink>') >>> Markup("Hello ") + "| {{ column }} | {%- endfor %}