feat: add docs

This commit is contained in:
Dmitriy Pleshevskiy 2019-07-24 17:05:09 +03:00
parent 0a1d77100f
commit fa2d0fa957
10 changed files with 454 additions and 11 deletions

View file

@ -7,6 +7,9 @@ verify_ssl = true
pytest = "*" pytest = "*"
coverage = "*" coverage = "*"
coveralls = "*" coveralls = "*"
docutils = "*"
Sphinx = "*"
sphinx-autodoc-typehints = "*"
[packages] [packages]
lxml = "*" lxml = "*"

129
Pipfile.lock generated
View file

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "f0911fe39e4694db48dedc159ec16cbf28529b922b8b1ec5fdbdfd67d70cdcf3" "sha256": "71e76379da4946d895b9c0c272ef7eac1a54a5c13bcd5d9d719285d66ed27940"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -56,6 +56,13 @@
} }
}, },
"develop": { "develop": {
"alabaster": {
"hashes": [
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
],
"version": "==0.7.12"
},
"asn1crypto": { "asn1crypto": {
"hashes": [ "hashes": [
"sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87",
@ -77,6 +84,13 @@
], ],
"version": "==19.1.0" "version": "==19.1.0"
}, },
"babel": {
"hashes": [
"sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab",
"sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28"
],
"version": "==2.7.0"
},
"certifi": { "certifi": {
"hashes": [ "hashes": [
"sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
@ -212,6 +226,13 @@
], ],
"version": "==0.6.2" "version": "==0.6.2"
}, },
"docutils": {
"hashes": [
"sha256:ba4584f9107571ced0d2c7f56a5499c696215ba90797849c92d395979da68521"
],
"index": "pypi",
"version": "==0.15.post1"
},
"enum34": { "enum34": {
"hashes": [ "hashes": [
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
@ -237,6 +258,13 @@
], ],
"version": "==2.8" "version": "==2.8"
}, },
"imagesize": {
"hashes": [
"sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8",
"sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"
],
"version": "==1.1.0"
},
"importlib-metadata": { "importlib-metadata": {
"hashes": [ "hashes": [
"sha256:6dfd58dfe281e8d240937776065dd3624ad5469c835248219bd16cf2e12dbeb7", "sha256:6dfd58dfe281e8d240937776065dd3624ad5469c835248219bd16cf2e12dbeb7",
@ -251,6 +279,46 @@
], ],
"version": "==1.0.22" "version": "==1.0.22"
}, },
"jinja2": {
"hashes": [
"sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013",
"sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"
],
"version": "==2.10.1"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
],
"version": "==1.1.1"
},
"more-itertools": { "more-itertools": {
"hashes": [ "hashes": [
"sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4", "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4",
@ -295,6 +363,13 @@
], ],
"version": "==2.19" "version": "==2.19"
}, },
"pygments": {
"hashes": [
"sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127",
"sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"
],
"version": "==2.4.2"
},
"pyopenssl": { "pyopenssl": {
"hashes": [ "hashes": [
"sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200", "sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200",
@ -304,10 +379,10 @@
}, },
"pyparsing": { "pyparsing": {
"hashes": [ "hashes": [
"sha256:530d8bf8cc93a34019d08142593cf4d78a05c890da8cf87ffa3120af53772238", "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a",
"sha256:f78e99616b6f1a4745c0580e170251ef1bbafc0d0513e270c4bd281bf29d2800" "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"
], ],
"version": "==2.4.1" "version": "==2.4.0"
}, },
"pytest": { "pytest": {
"hashes": [ "hashes": [
@ -317,6 +392,14 @@
"index": "pypi", "index": "pypi",
"version": "==4.6.4" "version": "==4.6.4"
}, },
"pytz": {
"hashes": [
"sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda",
"sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141"
],
"index": "pypi",
"version": "==2019.1"
},
"requests": { "requests": {
"hashes": [ "hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
@ -348,6 +431,44 @@
], ],
"version": "==1.12.0" "version": "==1.12.0"
}, },
"snowballstemmer": {
"hashes": [
"sha256:9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9"
],
"version": "==1.9.0"
},
"sphinx": {
"hashes": [
"sha256:9f3e17c64b34afc653d7c5ec95766e03043cc6d80b0de224f59b6b6e19d37c3c",
"sha256:c7658aab75c920288a8cf6f09f244c6cfdae30d82d803ac1634d9f223a80ca08"
],
"index": "pypi",
"version": "==1.8.5"
},
"sphinx-autodoc-typehints": {
"hashes": [
"sha256:19fe0b426b7c008181f67f816060da7f046bd8a42723f67a685d26d875bcefd7",
"sha256:f9c06acfec80766fe8f542a6d6a042e751fcf6ce2e2711a7dc00d8b6daf8aa36"
],
"index": "pypi",
"version": "==1.6.0"
},
"sphinxcontrib-websupport": {
"hashes": [
"sha256:1501befb0fdf1d1c29a800fdbf4ef5dc5369377300ddbdd16d2cd40e54c6eefc",
"sha256:e02f717baf02d0b6c3dd62cf81232ffca4c9d5c331e03766982e3ff9f1d2bc3f"
],
"version": "==1.1.2"
},
"typing": {
"hashes": [
"sha256:38566c558a0a94d6531012c8e917b1b8518a41e418f7f15f00e129cc80162ad3",
"sha256:53765ec4f83a2b720214727e319607879fec4acde22c4fbb54fa2604e79e44ce",
"sha256:84698954b4e6719e912ef9a42a2431407fe3755590831699debda6fba92aac55"
],
"markers": "python_version < '3.5'",
"version": "==3.7.4"
},
"urllib3": { "urllib3": {
"extras": [ "extras": [
"secure" "secure"

0
docs/.nojekyll Normal file
View file

23
docs/Makefile Normal file
View file

@ -0,0 +1,23 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
github:
@make html
@cp -a _build/html/. .
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

180
docs/conf.py Normal file
View file

@ -0,0 +1,180 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../'))
# -- Project information -----------------------------------------------------
project = 'GenRSS'
copyright = '2019, Dmitriy Pleshevskiy'
author = 'Dmitriy Pleshevskiy'
# The short X.Y version
version = '1.0'
# The full version, including alpha/beta/rc tags
release = '1.0.0'
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.coverage',
'sphinx_autodoc_typehints'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'GenRSSdoc'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'GenRSS.tex', 'GenRSS Documentation',
'Dmitriy Pleshevskiy', 'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'genrss', 'GenRSS Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'GenRSS', 'GenRSS Documentation',
author, 'GenRSS', 'One line description of project.',
'Miscellaneous'),
]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# -- Extension configuration -------------------------------------------------

22
docs/index.rst Normal file
View file

@ -0,0 +1,22 @@
.. GenRSS documentation master file, created by
sphinx-quickstart on Wed Jul 24 11:05:33 2019.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to GenRSS's documentation!
==================================
.. automodule:: genrss
:members:
.. toctree::
:maxdepth: 2
:caption: Contents:
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

35
docs/make.bat Normal file
View file

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd

3
docs/requirements.txt Normal file
View file

@ -0,0 +1,3 @@
docutils==0.15
Sphinx==1.8.5
sphinx-autodoc-typehints==1.6.0

View file

@ -1,18 +1,30 @@
import mimetypes import mimetypes
from lxml.etree import Element, CDATA, tostring from lxml.etree import Element, CDATA, tostring
from typing import Optional, List, NoReturn from typing import Optional, List, TypeVar, Dict, Any
from datetime import datetime from datetime import datetime
from collections import namedtuple from collections import namedtuple
import pytz import pytz
__all__ = ('GenRSS', 'Enclosure',)
ElementT = TypeVar('ElementT')
Enclosure = namedtuple('Enclosure', ('url', 'size', 'type')) Enclosure = namedtuple('Enclosure', ('url', 'size', 'type'))
Enclosure.__new__.__defaults__ = (None, None, None) Enclosure.__new__.__defaults__ = (None, None, None)
Enclosure.__doc__ = 'Creates information for enclosure tag.'
RSS_DEFAULT_GENERATOR = f'Generated by genrss for python' RSS_DEFAULT_GENERATOR = f'Generated by genrss for python'
def create_element(name: str, text=None, children=None, **kwargs) -> Element: def create_element(name: str, text: Any = None, children: List[ElementT] = None,
**kwargs) -> ElementT:
"""Creates xml node with text or children elements.
:param name: Tag name of node with namespace
:param text: Text of node
:param children: Appends elements as child nodes
"""
el = Element(name, **kwargs) el = Element(name, **kwargs)
if text: if text:
if isinstance(text, datetime): if isinstance(text, datetime):
@ -26,6 +38,22 @@ def create_element(name: str, text=None, children=None, **kwargs) -> Element:
class GenRSS: class GenRSS:
"""Generates RSS feed of channel.
:param title: Title of your site or feed
:param site_url: Absolute url to the site that the feed is for
:param feed_url: Absolute url to the rss feed
:param description: A short description of feed
:param image_url: Image absolute url for channel
:param author: Author of channel
:param pub_date: Datetime in utc when last item was published
:param copyright: Copyright information for this feed
:param language: The language of the content of this feed.
:param editor: Who manages content in this feed
:param webmaster: Who manages feed availability and technical support
:param generator: Feed generator
"""
def __init__(self, title: str, site_url: str, feed_url: str, **kwargs): def __init__(self, title: str, site_url: str, feed_url: str, **kwargs):
self.title: str = title self.title: str = title
self.site_url: str = site_url self.site_url: str = site_url
@ -42,13 +70,36 @@ class GenRSS:
self.categories: List[str] = kwargs.pop('categories', []) self.categories: List[str] = kwargs.pop('categories', [])
self.items: List[Element] = [] self.items: List[Element] = []
self.generator = kwargs.pop('generator', RSS_DEFAULT_GENERATOR) self.generator: str = kwargs.pop('generator', RSS_DEFAULT_GENERATOR)
self.root_version = '2.0' self.root_version: str = '2.0'
self.root_nsmap = { self.root_nsmap: Dict[str, str] = {
'atom': 'http://www.w3.org/2005/Atom' 'atom': 'http://www.w3.org/2005/Atom'
} }
def item(self, title: str, **kwargs) -> NoReturn: def item(self, title: str, **kwargs):
"""Adds item to the feed.
An item can be used for recipes, blog entries, project update, log
entry, etc. Your RSS feed can have any number of items.
:param title: Title of this particular item
:param description: Content for the item. Can contain html but
link and image urls must be absolute path including hostname
:param url: Url to the item. This could be a blog entry
:param guid: A unique string feed readers use to know if an item
is new or has already been seen. If you use a guid never change
it. If you don't provide a guid then your item urls must be unique
:param author: If included it is the name of the item's creator.
If not provided the item author will be the same as the feed
author. This is typical except on multi-author blogs
:param categories: If provided, each array item will be added as a
category element
:param enclosure: An enclosure object
:param pub_date: The date and time of when the item was created.
Feed readers use this to determine the sort order. Some readers
will also use it to determine if the content should be presented
as unread
"""
description: str = kwargs.pop('description', '') description: str = kwargs.pop('description', '')
url: Optional[str] = kwargs.pop('url', None) url: Optional[str] = kwargs.pop('url', None)
guid: Optional[str] = kwargs.pop('guid', None) guid: Optional[str] = kwargs.pop('guid', None)
@ -97,6 +148,10 @@ class GenRSS:
self.items.append(item) self.items.append(item)
def xml(self, pretty: bool = False) -> str: def xml(self, pretty: bool = False) -> str:
"""Returns the XML as a string.
:param pretty: Pretty print xml
"""
root = Element('rss', nsmap=self.root_nsmap, version=self.root_version) root = Element('rss', nsmap=self.root_nsmap, version=self.root_version)
channel = create_element('channel', children=[ channel = create_element('channel', children=[
create_element('title', CDATA(self.title)), create_element('title', CDATA(self.title)),
@ -136,4 +191,5 @@ class GenRSS:
root.append(channel) root.append(channel)
return '<?xml version="1.0" encoding="UTF-8"?>\n' \ return '<?xml version="1.0" encoding="UTF-8"?>\n' \
+ ('\n' if pretty else '') \
+ tostring(root, pretty_print=pretty).decode('utf-8') + tostring(root, pretty_print=pretty).decode('utf-8')

View file

@ -8,7 +8,7 @@ with open('README.md', 'r') as f:
if __name__ == '__main__': if __name__ == '__main__':
setup( setup(
name='genrss', name='genrss',
version='1.0.0', version='1.0.1',
author='Dmitriy Pleshevskiy', author='Dmitriy Pleshevskiy',
author_email='dmitriy@ideascup.me', author_email='dmitriy@ideascup.me',
description='RSS feed generator for python', description='RSS feed generator for python',