Compare commits

...

No commits in common. "master" and "gh-pages" have entirely different histories.

97 changed files with 18654 additions and 6550 deletions

20
.gitignore vendored
View file

@ -1,17 +1,5 @@
.idea/
venv
*.pyc
*.pyo
*.swp
feedgen/tests/tmp_Atomfeed.xml
feedgen/tests/tmp_Rssfeed.xml
tmp_Atomfeed.xml
tmp_Rssfeed.xml
# testing artifacts
.coverage
*.egg-info/
/MANIFEST
/docs
/dist
/doc

View file

@ -1,9 +0,0 @@
# Authorized licenses in lower case
# There is no project rule against adding new licenses as long as they are
# compatible with the project's license.
[Licenses]
authorized_licenses:
BSD
MIT

View file

@ -1,25 +0,0 @@
language: python
dist: bionic
# https://devguide.python.org/#branchstatus
python:
- 3.6
- 3.7
- 3.8
install:
- pip install bandit flake8 python-coveralls coverage liccheck
- pip install -r requirements.txt
- python setup.py bdist_wheel
- pip install dist/feedgen*
script:
- make test
- liccheck -s .licenses.ini
- python -m feedgen
- python -m feedgen atom
- python -m feedgen rss
after_success:
- coveralls

1
CNAME Normal file
View file

@ -0,0 +1 @@
feedgen.kiesow.be

View file

@ -1,2 +0,0 @@
include license.bsd license.lgpl readme.rst
recursive-include docs *.html *.css *.png *.gif *.js

View file

@ -1,54 +0,0 @@
sdist: doc
python setup.py sdist
bdist_wheel: doc
python setup.py bdist_wheel
clean: doc-clean
@echo Removing binary files...
@rm -f `find feedgen -name '*.pyc'`
@rm -f `find feedgen -name '*.pyo'`
@rm -rf feedgen.egg-info/ build/
@echo Removing source distribution files...
@rm -rf dist/
@rm -f MANIFEST
@rm -f tmp_Atomfeed.xml tmp_Rssfeed.xml
doc: doc-clean doc-html doc-man
doc-clean:
@echo Removing docs...
@make -C doc clean
@rm -rf docs
doc-html:
@echo 'Generating HTML'
@make -C doc html
@mkdir -p docs/html
@echo 'Copying html to into docs dir'
@cp doc/_build/html/*.html docs/html/
@cp doc/_build/html/*.js docs/html/
@cp -r doc/_build/html/_static/ docs/html/
@cp -r doc/_build/html/ext/ docs/html/
doc-man:
@echo 'Generating manpage'
@make -C doc man
@mkdir -p docs/man
@echo 'Copying manpage to into docs dir'
@cp doc/_build/man/*.1 docs/man/
doc-latexpdf:
@echo 'Generating pdf'
@make -C doc latexpdf
@mkdir -p docs/pdf
@echo 'Copying pdf to into docs dir'
@cp doc/_build/latex/*.pdf docs/pdf/
publish:
twine upload dist/*
test:
coverage run --source=feedgen -m unittest discover -s tests
flake8 $$(find setup.py tests feedgen -name '*.py')
bandit -r feedgen

View file

@ -1,17 +0,0 @@
Security Policy
===============
Supported Versions
------------------
Only the latest version of this library is supported.
We are doing our best to make updates as easy as possible
so that keeping up-to-date is usually pretty easy.
Reporting a Vulnerability
-------------------------
If you find a security vulnerability,
please report it by sending a mail to security@lkiesow.de.
We will discuss the problem internally and, if necessary, release a patched version as soon as possible.

BIN
_static/ajax-loader.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
_static/alert_info_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

676
_static/basic.css Normal file
View file

@ -0,0 +1,676 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox form.search {
overflow: hidden;
}
div.sphinxsidebar #searchbox input[type="text"] {
float: left;
width: 80%;
padding: 0.25em;
box-sizing: border-box;
}
div.sphinxsidebar #searchbox input[type="submit"] {
float: left;
width: 20%;
border-left: none;
padding: 0.25em;
box-sizing: border-box;
}
img {
border: 0;
max-width: 100%;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
margin-left: auto;
margin-right: auto;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable ul {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
table.indextable > tbody > tr > td > ul {
padding-left: 0em;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- domain module index --------------------------------------------------- */
table.modindextable td {
padding: 2px;
border-collapse: collapse;
}
/* -- general body styles --------------------------------------------------- */
div.body {
min-width: 59em;
max-width: 70em;
}
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: auto;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink,
caption:hover > a.headerlink,
p.caption:hover > a.headerlink,
div.code-block-caption:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
table caption span.caption-number {
font-style: italic;
}
table caption span.caption-text {
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- figures --------------------------------------------------------------- */
div.figure {
margin: 0.5em;
padding: 0.5em;
}
div.figure p.caption {
padding: 0.3em;
}
div.figure p.caption span.caption-number {
font-style: italic;
}
div.figure p.caption span.caption-text {
}
/* -- field list styles ----------------------------------------------------- */
table.field-list td, table.field-list th {
border: 0 !important;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.field-name {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}
/* -- hlist styles ---------------------------------------------------------- */
table.hlist td {
vertical-align: top;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, span.highlighted {
background-color: #fbe54e;
}
rect.highlighted {
fill: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.optional {
font-size: 1.3em;
}
.sig-paren {
font-size: larger;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
span.pre {
-moz-hyphens: none;
-ms-hyphens: none;
-webkit-hyphens: none;
hyphens: none;
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
div.code-block-caption {
padding: 2px 5px;
font-size: small;
}
div.code-block-caption code {
background-color: transparent;
}
div.code-block-caption + div > div.highlight > pre {
margin-top: 0;
}
div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;
}
div.code-block-caption span.caption-text {
}
div.literal-block-wrapper {
padding: 1em 1em 0;
}
div.literal-block-wrapper div.highlight {
margin: 0;
}
code.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
code.descclassname {
background-color: transparent;
}
code.xref, a code {
background-color: transparent;
font-weight: bold;
}
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
span.eqno a.headerlink {
position: relative;
left: 0px;
z-index: 1;
}
div.math:hover a.headerlink {
visibility: visible;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

BIN
_static/bg-page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

BIN
_static/bullet_orange.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
_static/comment-bright.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 B

BIN
_static/comment-close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

BIN
_static/comment.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

315
_static/doctools.js Normal file
View file

@ -0,0 +1,315 @@
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s === 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node, addItems) {
if (node.nodeType === 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 &&
!jQuery(node.parentNode).hasClass(className) &&
!jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
} else {
span = document.createElement("span");
span.className = className;
}
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
if (isInSVG) {
var bbox = span.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute('class', className);
var parentOfText = node.parentNode.parentNode;
addItems.push({
"parent": node.parentNode,
"target": rect});
}
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this, addItems);
});
}
}
var addItems = [];
var result = this.each(function() {
highlight(this, addItems);
});
for (var i = 0; i < addItems.length; ++i) {
jQuery(addItems[i].parent).before(addItems[i].target);
}
return result;
};
/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {
this.initOnKeyListeners();
}
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated === 'undefined')
return string;
return (typeof translated === 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated === 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
* see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
if (!body.length) {
body = $('body');
}
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) === 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this === '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
},
initOnKeyListeners: function() {
$(document).keyup(function(event) {
var activeElementType = document.activeElement.tagName;
// don't navigate when in search box or textarea
if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
switch (event.keyCode) {
case 37: // left
var prevHref = $('link[rel="prev"]').prop('href');
if (prevHref) {
window.location.href = prevHref;
return false;
}
case 39: // right
var nextHref = $('link[rel="next"]').prop('href');
if (nextHref) {
window.location.href = nextHref;
return false;
}
}
}
});
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});

View file

@ -0,0 +1,10 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.8.0',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
NAVIGATION_WITH_KEYS: false,
};

BIN
_static/down-pressed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

BIN
_static/down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

BIN
_static/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

376
_static/haiku.css Normal file
View file

@ -0,0 +1,376 @@
/*
* haiku.css_t
* ~~~~~~~~~~~
*
* Sphinx stylesheet -- haiku theme.
*
* Adapted from http://haiku-os.org/docs/Haiku-doc.css.
* Original copyright message:
*
* Copyright 2008-2009, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Francois Revol <revol@free.fr>
* Stephan Assmus <superstippi@gmx.de>
* Braden Ewing <brewin@gmail.com>
* Humdinger <humdingerb@gmail.com>
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
html {
margin: 0px;
padding: 0px;
background: #FFF url(bg-page.png) top left repeat-x;
}
body {
line-height: 1.5;
margin: auto;
padding: 0px;
font-family: "DejaVu Sans", Arial, Helvetica, sans-serif;
min-width: 59em;
max-width: 70em;
color: #333333;
}
div.footer {
padding: 8px;
font-size: 11px;
text-align: center;
letter-spacing: 0.5px;
}
/* link colors and text decoration */
a:link {
font-weight: bold;
text-decoration: none;
color: #dc3c01;
}
a:visited {
font-weight: bold;
text-decoration: none;
color: #892601;
}
a:hover, a:active {
text-decoration: underline;
color: #ff4500;
}
/* Some headers act as anchors, don't give them a hover effect */
h1 a:hover, a:active {
text-decoration: none;
color: #0c3762;
}
h2 a:hover, a:active {
text-decoration: none;
color: #0c3762;
}
h3 a:hover, a:active {
text-decoration: none;
color: #0c3762;
}
h4 a:hover, a:active {
text-decoration: none;
color: #0c3762;
}
a.headerlink {
color: #a7ce38;
padding-left: 5px;
}
a.headerlink:hover {
color: #a7ce38;
}
/* basic text elements */
div.content {
margin-top: 20px;
margin-left: 40px;
margin-right: 40px;
margin-bottom: 50px;
font-size: 0.9em;
}
/* heading and navigation */
div.header {
position: relative;
left: 0px;
top: 0px;
height: 85px;
/* background: #eeeeee; */
padding: 0 40px;
}
div.header h1 {
font-size: 1.6em;
font-weight: normal;
letter-spacing: 1px;
color: #0c3762;
border: 0;
margin: 0;
padding-top: 15px;
}
div.header h1 a {
font-weight: normal;
color: #0c3762;
}
div.header h2 {
font-size: 1.3em;
font-weight: normal;
letter-spacing: 1px;
text-transform: uppercase;
color: #aaa;
border: 0;
margin-top: -3px;
padding: 0;
}
div.header img.rightlogo {
float: right;
}
div.title {
font-size: 1.3em;
font-weight: bold;
color: #0c3762;
border-bottom: dotted thin #e0e0e0;
margin-bottom: 25px;
}
div.topnav {
/* background: #e0e0e0; */
}
div.topnav p {
margin-top: 0;
margin-left: 40px;
margin-right: 40px;
margin-bottom: 0px;
text-align: right;
font-size: 0.8em;
}
div.bottomnav {
background: #eeeeee;
}
div.bottomnav p {
margin-right: 40px;
text-align: right;
font-size: 0.8em;
}
a.uplink {
font-weight: normal;
}
/* contents box */
table.index {
margin: 0px 0px 30px 30px;
padding: 1px;
border-width: 1px;
border-style: dotted;
border-color: #e0e0e0;
}
table.index tr.heading {
background-color: #e0e0e0;
text-align: center;
font-weight: bold;
font-size: 1.1em;
}
table.index tr.index {
background-color: #eeeeee;
}
table.index td {
padding: 5px 20px;
}
table.index a:link, table.index a:visited {
font-weight: normal;
text-decoration: none;
color: #dc3c01;
}
table.index a:hover, table.index a:active {
text-decoration: underline;
color: #ff4500;
}
/* Haiku User Guide styles and layout */
/* Rounded corner boxes */
/* Common declarations */
div.admonition {
-webkit-border-radius: 10px;
-khtml-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
border-style: dotted;
border-width: thin;
border-color: #dcdcdc;
padding: 10px 15px 10px 15px;
margin-bottom: 15px;
margin-top: 15px;
}
div.note {
padding: 10px 15px 10px 80px;
background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat;
min-height: 42px;
}
div.warning {
padding: 10px 15px 10px 80px;
background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat;
min-height: 42px;
}
div.seealso {
background: #e4ffde;
}
/* More layout and styles */
h1 {
font-size: 1.3em;
font-weight: bold;
color: #0c3762;
border-bottom: dotted thin #e0e0e0;
margin-top: 30px;
}
h2 {
font-size: 1.2em;
font-weight: normal;
color: #0c3762;
border-bottom: dotted thin #e0e0e0;
margin-top: 30px;
}
h3 {
font-size: 1.1em;
font-weight: normal;
color: #0c3762;
margin-top: 30px;
}
h4 {
font-size: 1.0em;
font-weight: normal;
color: #0c3762;
margin-top: 30px;
}
p {
text-align: justify;
}
p.last {
margin-bottom: 0;
}
ol {
padding-left: 20px;
}
ul {
padding-left: 5px;
margin-top: 3px;
}
li {
line-height: 1.3;
}
div.content ul > li {
-moz-background-clip:border;
-moz-background-inline-policy:continuous;
-moz-background-origin:padding;
background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em;
list-style-image: none;
list-style-type: none;
padding: 0 0 0 1.666em;
margin-bottom: 3px;
}
td {
vertical-align: top;
}
code {
background-color: #e2e2e2;
font-size: 1.0em;
font-family: monospace;
}
pre {
border-color: #0c3762;
border-style: dotted;
border-width: thin;
margin: 0 0 12px 0;
padding: 0.8em;
background-color: #f0f0f0;
}
hr {
border-top: 1px solid #ccc;
border-bottom: 0;
border-right: 0;
border-left: 0;
margin-bottom: 10px;
margin-top: 20px;
}
/* printer only pretty stuff */
@media print {
.noprint {
display: none;
}
/* for acronyms we want their definitions inlined at print time */
acronym[title]:after {
font-size: small;
content: " (" attr(title) ")";
font-style: italic;
}
/* and not have mozilla dotted underline */
acronym {
border: none;
}
div.topnav, div.bottomnav, div.header, table.index {
display: none;
}
div.content {
margin: 0px;
padding: 0px;
}
html {
background: #FFF;
}
}
.viewcode-back {
font-family: "DejaVu Sans", Arial, Helvetica, sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
margin: -1px -10px;
padding: 0 12px;
}
/* math display */
div.math p {
text-align: center;
}

10253
_static/jquery-3.2.1.js vendored Normal file

File diff suppressed because it is too large Load diff

4
_static/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

297
_static/language_data.js Normal file
View file

@ -0,0 +1,297 @@
/*
* language_data.js
* ~~~~~~~~~~~~~~~~
*
* This script contains the language-specific data used by searchtools.js,
* namely the list of stopwords, stemmer, scorer and splitter.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
/* Non-minified version JS is _stemmer.js if file is provided */
/**
* Porter Stemmer
*/
var Stemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
var splitChars = (function() {
var result = {};
var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
var i, j, start, end;
for (i = 0; i < singles.length; i++) {
result[singles[i]] = true;
}
var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
[722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
[1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
[1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
[1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
[2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
[2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
[2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
[2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
[2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
[2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
[2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
[3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
[3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
[3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
[3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
[3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
[3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
[4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
[4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
[4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
[4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
[5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
[6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
[6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
[6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
[6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
[7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
[7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
[8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
[8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
[8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
[10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
[11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
[12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
[12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
[12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
[19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
[42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
[42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
[43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
[43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
[43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
[43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
[44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
[57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
[64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
[65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
[65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
for (i = 0; i < ranges.length; i++) {
start = ranges[i][0];
end = ranges[i][1];
for (j = start; j <= end; j++) {
result[j] = true;
}
}
return result;
})();
function splitQuery(query) {
var result = [];
var start = -1;
for (var i = 0; i < query.length; i++) {
if (splitChars[query.charCodeAt(i)]) {
if (start !== -1) {
result.push(query.slice(start, i));
start = -1;
}
} else if (start === -1) {
start = i;
}
}
if (start !== -1) {
result.push(query.slice(start));
}
return result;
}

BIN
_static/minus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

BIN
_static/plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

69
_static/pygments.css Normal file
View file

@ -0,0 +1,69 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #333333 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #208050 } /* Literal.Number.Bin */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sa { color: #4070a0 } /* Literal.String.Affix */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06287e } /* Name.Function.Magic */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */

481
_static/searchtools.js Normal file
View file

@ -0,0 +1,481 @@
/*
* searchtools.js
* ~~~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilities for the full-text search.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
if (!Scorer) {
/**
* Simple result scoring code.
*/
var Scorer = {
// Implement the following function to further tweak the score for each result
// The function takes a result array [filename, title, anchor, descr, score]
// and returns the new score.
/*
score: function(result) {
return result[4];
},
*/
// query matches the full name of an object
objNameMatch: 11,
// or matches in the last dotted part of the object name
objPartialMatch: 6,
// Additive scores depending on the priority of the object
objPrio: {0: 15, // used to be importantResults
1: 5, // used to be objectResults
2: -5}, // used to be unimportantResults
// Used when the priority is not in the mapping.
objPrioDefault: 0,
// query found in title
title: 15,
// query found in terms
term: 5
};
}
if (!splitQuery) {
function splitQuery(query) {
return query.split(/\s+/);
}
}
/**
* Search Module
*/
var Search = {
_index : null,
_queued_query : null,
_pulse_status : -1,
init : function() {
var params = $.getQueryParameters();
if (params.q) {
var query = params.q[0];
$('input[name="q"]')[0].value = query;
this.performSearch(query);
}
},
loadIndex : function(url) {
$.ajax({type: "GET", url: url, data: null,
dataType: "script", cache: true,
complete: function(jqxhr, textstatus) {
if (textstatus != "success") {
document.getElementById("searchindexloader").src = url;
}
}});
},
setIndex : function(index) {
var q;
this._index = index;
if ((q = this._queued_query) !== null) {
this._queued_query = null;
Search.query(q);
}
},
hasIndex : function() {
return this._index !== null;
},
deferQuery : function(query) {
this._queued_query = query;
},
stopPulse : function() {
this._pulse_status = 0;
},
startPulse : function() {
if (this._pulse_status >= 0)
return;
function pulse() {
var i;
Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = '';
for (i = 0; i < Search._pulse_status; i++)
dotString += '.';
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
}
pulse();
},
/**
* perform a search for something (or wait until index is loaded)
*/
performSearch : function(query) {
// create the required interface elements
this.out = $('#search-results');
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
this.dots = $('<span></span>').appendTo(this.title);
this.status = $('<p style="display: none"></p>').appendTo(this.out);
this.output = $('<ul class="search"/>').appendTo(this.out);
$('#search-progress').text(_('Preparing search...'));
this.startPulse();
// index already loaded, the browser was quick!
if (this.hasIndex())
this.query(query);
else
this.deferQuery(query);
},
/**
* execute search (requires search index to be loaded)
*/
query : function(query) {
var i;
// stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = splitQuery(query);
var objectterms = [];
for (i = 0; i < tmp.length; i++) {
if (tmp[i] !== "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
tmp[i] === "") {
// skip this "word"
continue;
}
// stem the word
var word = stemmer.stemWord(tmp[i].toLowerCase());
// prevent stemmer from cutting word smaller than two chars
if(word.length < 3 && tmp[i].length >= 3) {
word = tmp[i];
}
var toAppend;
// select the correct list
if (word[0] == '-') {
toAppend = excluded;
word = word.substr(1);
}
else {
toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase());
}
// only add if not already in the list
if (!$u.contains(toAppend, word))
toAppend.push(word);
}
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:');
// console.info('required: ', searchterms);
// console.info('excluded: ', excluded);
// prepare search
var terms = this._index.terms;
var titleterms = this._index.titleterms;
// array of [filename, title, anchor, descr, score]
var results = [];
$('#search-progress').empty();
// lookup as object
for (i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0, i),
objectterms.slice(i+1, objectterms.length));
results = results.concat(this.performObjectSearch(objectterms[i], others));
}
// lookup as search terms in fulltext
results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
// let the scorer override scores with a custom scoring function
if (Scorer.score) {
for (i = 0; i < results.length; i++)
results[i][4] = Scorer.score(results[i]);
}
// now sort the results by score (in opposite order of appearance, since the
// display function below uses pop() to retrieve items) and then
// alphabetically
results.sort(function(a, b) {
var left = a[4];
var right = b[4];
if (left > right) {
return 1;
} else if (left < right) {
return -1;
} else {
// same score: sort alphabetically
left = a[1].toLowerCase();
right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0);
}
});
// for debugging
//Search.lastresults = results.slice(); // a copy
//console.info('search results:', Search.lastresults);
// print the results
var resultCount = results.length;
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li style="display:none"></li>');
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
// dirhtml builder
var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) {
dirname = dirname.substring(0, dirname.length-6);
} else if (dirname == 'index/') {
dirname = '';
}
listItem.append($('<a/>').attr('href',
DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
highlightstring + item[2]).html(item[1]));
} else {
// normal html builders
listItem.append($('<a/>').attr('href',
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
highlightstring + item[2]).html(item[1]));
}
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX;
if (suffix === undefined) {
suffix = '.txt';
}
$.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix),
dataType: "text",
complete: function(jqxhr, textstatus) {
var data = jqxhr.responseText;
if (data !== '' && data !== undefined) {
listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
}
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}});
} else {
// no source available, just display title
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
},
/**
* search for object names
*/
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var docnames = this._index.docnames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
var i;
var results = [];
for (var prefix in objects) {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
var score = 0;
var parts = fullname.split('.');
// check for different match types: exact matches of full name or
// "last name" (i.e. last dotted part)
if (fullname == object || parts[parts.length - 1] == object) {
score += Scorer.objNameMatch;
// matches in last name
} else if (parts[parts.length - 1].indexOf(object) > -1) {
score += Scorer.objPartialMatch;
}
var match = objects[prefix][name];
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
var anchor = match[3];
if (anchor === '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
// add custom score for some objects according to scorer
if (Scorer.objPrio.hasOwnProperty(match[2])) {
score += Scorer.objPrio[match[2]];
} else {
score += Scorer.objPrioDefault;
}
results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
}
}
}
return results;
},
/**
* search for full-text terms in the index
*/
performTermsSearch : function(searchterms, excluded, terms, titleterms) {
var docnames = this._index.docnames;
var filenames = this._index.filenames;
var titles = this._index.titles;
var i, j, file;
var fileMap = {};
var scoreMap = {};
var results = [];
// perform the search on the required terms
for (i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
var files = [];
var _o = [
{files: terms[word], score: Scorer.term},
{files: titleterms[word], score: Scorer.title}
];
// no match but word was a required one
if ($u.every(_o, function(o){return o.files === undefined;})) {
break;
}
// found search word in contents
$u.each(_o, function(o) {
var _files = o.files;
if (_files === undefined)
return
if (_files.length === undefined)
_files = [_files];
files = files.concat(_files);
// set score for the word in each file to Scorer.term
for (j = 0; j < _files.length; j++) {
file = _files[j];
if (!(file in scoreMap))
scoreMap[file] = {}
scoreMap[file][word] = o.score;
}
});
// create the mapping
for (j = 0; j < files.length; j++) {
file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (file in fileMap) {
var valid = true;
// check if all requirements are matched
if (fileMap[file].length != searchterms.length)
continue;
// ensure that none of the excluded terms is in the search result
for (i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
titleterms[excluded[i]] == file ||
$u.contains(terms[excluded[i]] || [], file) ||
$u.contains(titleterms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it to the result list
if (valid) {
// select one (max) score for the file.
// for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
}
}
return results;
},
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurrence, the
* latter for highlighting it.
*/
makeSearchSummary : function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
};
$(document).ready(function() {
Search.init();
});

999
_static/underscore-1.3.1.js Normal file
View file

@ -0,0 +1,999 @@
// Underscore.js 1.3.1
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function() {
// Baseline setup
// --------------
// Establish the root object, `window` in the browser, or `global` on the server.
var root = this;
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
// Establish the object that gets returned to break out of a loop iteration.
var breaker = {};
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
// Create quick reference variables for speed access to core prototypes.
var slice = ArrayProto.slice,
unshift = ArrayProto.unshift,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var
nativeForEach = ArrayProto.forEach,
nativeMap = ArrayProto.map,
nativeReduce = ArrayProto.reduce,
nativeReduceRight = ArrayProto.reduceRight,
nativeFilter = ArrayProto.filter,
nativeEvery = ArrayProto.every,
nativeSome = ArrayProto.some,
nativeIndexOf = ArrayProto.indexOf,
nativeLastIndexOf = ArrayProto.lastIndexOf,
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind;
// Create a safe reference to the Underscore object for use below.
var _ = function(obj) { return new wrapper(obj); };
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
// the browser, add `_` as a global object via a string identifier,
// for Closure Compiler "advanced" mode.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
root['_'] = _;
}
// Current version.
_.VERSION = '1.3.1';
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles objects with the built-in `forEach`, arrays, and raw objects.
// Delegates to **ECMAScript 5**'s native `forEach` if available.
var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
if (_.has(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
};
// Return the results of applying the iterator to each element.
// Delegates to **ECMAScript 5**'s native `map` if available.
_.map = _.collect = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function(value, index, list) {
results[results.length] = iterator.call(context, value, index, list);
});
if (obj.length === +obj.length) results.length = obj.length;
return results;
};
// **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
var initial = arguments.length > 2;
if (obj == null) obj = [];
if (nativeReduce && obj.reduce === nativeReduce) {
if (context) iterator = _.bind(iterator, context);
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
}
each(obj, function(value, index, list) {
if (!initial) {
memo = value;
initial = true;
} else {
memo = iterator.call(context, memo, value, index, list);
}
});
if (!initial) throw new TypeError('Reduce of empty array with no initial value');
return memo;
};
// The right-associative version of reduce, also known as `foldr`.
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
var initial = arguments.length > 2;
if (obj == null) obj = [];
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
if (context) iterator = _.bind(iterator, context);
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
}
var reversed = _.toArray(obj).reverse();
if (context && !initial) iterator = _.bind(iterator, context);
return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
};
// Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, iterator, context) {
var result;
any(obj, function(value, index, list) {
if (iterator.call(context, value, index, list)) {
result = value;
return true;
}
});
return result;
};
// Return all the elements that pass a truth test.
// Delegates to **ECMAScript 5**'s native `filter` if available.
// Aliased as `select`.
_.filter = _.select = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
each(obj, function(value, index, list) {
if (iterator.call(context, value, index, list)) results[results.length] = value;
});
return results;
};
// Return all the elements for which a truth test fails.
_.reject = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
each(obj, function(value, index, list) {
if (!iterator.call(context, value, index, list)) results[results.length] = value;
});
return results;
};
// Determine whether all of the elements match a truth test.
// Delegates to **ECMAScript 5**'s native `every` if available.
// Aliased as `all`.
_.every = _.all = function(obj, iterator, context) {
var result = true;
if (obj == null) return result;
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
each(obj, function(value, index, list) {
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
});
return result;
};
// Determine if at least one element in the object matches a truth test.
// Delegates to **ECMAScript 5**'s native `some` if available.
// Aliased as `any`.
var any = _.some = _.any = function(obj, iterator, context) {
iterator || (iterator = _.identity);
var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) {
if (result || (result = iterator.call(context, value, index, list))) return breaker;
});
return !!result;
};
// Determine if a given value is included in the array or object using `===`.
// Aliased as `contains`.
_.include = _.contains = function(obj, target) {
var found = false;
if (obj == null) return found;
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
found = any(obj, function(value) {
return value === target;
});
return found;
};
// Invoke a method (with arguments) on every item in a collection.
_.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
return _.map(obj, function(value) {
return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
});
};
// Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) {
return _.map(obj, function(value){ return value[key]; });
};
// Return the maximum element or (element-based computation).
_.max = function(obj, iterator, context) {
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
if (!iterator && _.isEmpty(obj)) return -Infinity;
var result = {computed : -Infinity};
each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
computed >= result.computed && (result = {value : value, computed : computed});
});
return result.value;
};
// Return the minimum element (or element-based computation).
_.min = function(obj, iterator, context) {
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
if (!iterator && _.isEmpty(obj)) return Infinity;
var result = {computed : Infinity};
each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
computed < result.computed && (result = {value : value, computed : computed});
});
return result.value;
};
// Shuffle an array.
_.shuffle = function(obj) {
var shuffled = [], rand;
each(obj, function(value, index, list) {
if (index == 0) {
shuffled[0] = value;
} else {
rand = Math.floor(Math.random() * (index + 1));
shuffled[index] = shuffled[rand];
shuffled[rand] = value;
}
});
return shuffled;
};
// Sort the object's values by a criterion produced by an iterator.
_.sortBy = function(obj, iterator, context) {
return _.pluck(_.map(obj, function(value, index, list) {
return {
value : value,
criteria : iterator.call(context, value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
}), 'value');
};
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = function(obj, val) {
var result = {};
var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
each(obj, function(value, index) {
var key = iterator(value, index);
(result[key] || (result[key] = [])).push(value);
});
return result;
};
// Use a comparator function to figure out at what index an object should
// be inserted so as to maintain order. Uses binary search.
_.sortedIndex = function(array, obj, iterator) {
iterator || (iterator = _.identity);
var low = 0, high = array.length;
while (low < high) {
var mid = (low + high) >> 1;
iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
}
return low;
};
// Safely convert anything iterable into a real, live array.
_.toArray = function(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
if (_.isArray(iterable)) return slice.call(iterable);
if (_.isArguments(iterable)) return slice.call(iterable);
return _.values(iterable);
};
// Return the number of elements in an object.
_.size = function(obj) {
return _.toArray(obj).length;
};
// Array Functions
// ---------------
// Get the first element of an array. Passing **n** will return the first N
// values in the array. Aliased as `head`. The **guard** check allows it to work
// with `_.map`.
_.first = _.head = function(array, n, guard) {
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
};
// Returns everything but the last entry of the array. Especcialy useful on
// the arguments object. Passing **n** will return all the values in
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
_.initial = function(array, n, guard) {
return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) {
if ((n != null) && !guard) {
return slice.call(array, Math.max(array.length - n, 0));
} else {
return array[array.length - 1];
}
};
// Returns everything but the first entry of the array. Aliased as `tail`.
// Especially useful on the arguments object. Passing an **index** will return
// the rest of the values in the array from that index onward. The **guard**
// check allows it to work with `_.map`.
_.rest = _.tail = function(array, index, guard) {
return slice.call(array, (index == null) || guard ? 1 : index);
};
// Trim out all falsy values from an array.
_.compact = function(array) {
return _.filter(array, function(value){ return !!value; });
};
// Return a completely flattened version of an array.
_.flatten = function(array, shallow) {
return _.reduce(array, function(memo, value) {
if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
memo[memo.length] = value;
return memo;
}, []);
};
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
return _.difference(array, slice.call(arguments, 1));
};
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
_.uniq = _.unique = function(array, isSorted, iterator) {
var initial = iterator ? _.map(array, iterator) : array;
var result = [];
_.reduce(initial, function(memo, el, i) {
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
memo[memo.length] = el;
result[result.length] = array[i];
}
return memo;
}, []);
return result;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
return _.uniq(_.flatten(arguments, true));
};
// Produce an array that contains every item shared between all the
// passed-in arrays. (Aliased as "intersect" for back-compat.)
_.intersection = _.intersect = function(array) {
var rest = slice.call(arguments, 1);
return _.filter(_.uniq(array), function(item) {
return _.every(rest, function(other) {
return _.indexOf(other, item) >= 0;
});
});
};
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
var rest = _.flatten(slice.call(arguments, 1));
return _.filter(array, function(value){ return !_.include(rest, value); });
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.zip = function() {
var args = slice.call(arguments);
var length = _.max(_.pluck(args, 'length'));
var results = new Array(length);
for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
return results;
};
// If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
// we need this function. Return the position of the first occurrence of an
// item in an array, or -1 if the item is not included in the array.
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) {
if (array == null) return -1;
var i, l;
if (isSorted) {
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
return -1;
};
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
_.lastIndexOf = function(array, item) {
if (array == null) return -1;
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
var i = array.length;
while (i--) if (i in array && array[i] === item) return i;
return -1;
};
// Generate an integer Array containing an arithmetic progression. A port of
// the native Python `range()` function. See
// [the Python documentation](http://docs.python.org/library/functions.html#range).
_.range = function(start, stop, step) {
if (arguments.length <= 1) {
stop = start || 0;
start = 0;
}
step = arguments[2] || 1;
var len = Math.max(Math.ceil((stop - start) / step), 0);
var idx = 0;
var range = new Array(len);
while(idx < len) {
range[idx++] = start;
start += step;
}
return range;
};
// Function (ahem) Functions
// ------------------
// Reusable constructor function for prototype setting.
var ctor = function(){};
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Binding with arguments is also known as `curry`.
// Delegates to **ECMAScript 5**'s native `Function.bind` if available.
// We check for `func.bind` first, to fail fast when `func` is undefined.
_.bind = function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
// Bind all of an object's methods to that object. Useful for ensuring that
// all callbacks defined on an object belong to it.
_.bindAll = function(obj) {
var funcs = slice.call(arguments, 1);
if (funcs.length == 0) funcs = _.functions(obj);
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
return obj;
};
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memo = {};
hasher || (hasher = _.identity);
return function() {
var key = hasher.apply(this, arguments);
return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
};
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(func, args); }, wait);
};
// Defers a function, scheduling it to run after the current call stack has
// cleared.
_.defer = function(func) {
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time.
_.throttle = function(func, wait) {
var context, args, timeout, throttling, more;
var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
return function() {
context = this; args = arguments;
var later = function() {
timeout = null;
if (more) func.apply(context, args);
whenDone();
};
if (!timeout) timeout = setTimeout(later, wait);
if (throttling) {
more = true;
} else {
func.apply(context, args);
}
whenDone();
throttling = true;
};
};
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds.
_.debounce = function(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
// Returns a function that will be executed at most one time, no matter how
// often you call it. Useful for lazy initialization.
_.once = function(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
return memo = func.apply(this, arguments);
};
};
// Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
return function() {
var args = [func].concat(slice.call(arguments, 0));
return wrapper.apply(this, args);
};
};
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
var funcs = arguments;
return function() {
var args = arguments;
for (var i = funcs.length - 1; i >= 0; i--) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
// Returns a function that will only be executed after being called N times.
_.after = function(times, func) {
if (times <= 0) return func();
return function() {
if (--times < 1) { return func.apply(this, arguments); }
};
};
// Object Functions
// ----------------
// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = nativeKeys || function(obj) {
if (obj !== Object(obj)) throw new TypeError('Invalid object');
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
return keys;
};
// Retrieve the values of an object's properties.
_.values = function(obj) {
return _.map(obj, _.identity);
};
// Return a sorted list of the function names available on the object.
// Aliased as `methods`
_.functions = _.methods = function(obj) {
var names = [];
for (var key in obj) {
if (_.isFunction(obj[key])) names.push(key);
}
return names.sort();
};
// Extend a given object with all the properties in passed-in object(s).
_.extend = function(obj) {
each(slice.call(arguments, 1), function(source) {
for (var prop in source) {
obj[prop] = source[prop];
}
});
return obj;
};
// Fill in a given object with default properties.
_.defaults = function(obj) {
each(slice.call(arguments, 1), function(source) {
for (var prop in source) {
if (obj[prop] == null) obj[prop] = source[prop];
}
});
return obj;
};
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
// Invokes interceptor with the obj, and then returns obj.
// The primary purpose of this method is to "tap into" a method chain, in
// order to perform operations on intermediate results within the chain.
_.tap = function(obj, interceptor) {
interceptor(obj);
return obj;
};
// Internal recursive comparison function.
function eq(a, b, stack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
if (a === b) return a !== 0 || 1 / a == 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
// Invoke a custom `isEqual` method if one is provided.
if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className != toString.call(b)) return false;
switch (className) {
// Strings, numbers, dates, and booleans are compared by value.
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
return a == String(b);
case '[object Number]':
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
// other numeric values.
return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
return +a == +b;
// RegExps are compared by their source patterns and flags.
case '[object RegExp]':
return a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
}
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = stack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (stack[length] == a) return true;
}
// Add the first object to the stack of traversed objects.
stack.push(a);
var size = 0, result = true;
// Recursively compare objects and arrays.
if (className == '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
result = size == b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
// Ensure commutative equality for sparse arrays.
if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
}
}
} else {
// Objects with different constructors are not equivalent.
if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
// Deep compare objects.
for (var key in a) {
if (_.has(a, key)) {
// Count the expected number of properties.
size++;
// Deep compare each member.
if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
}
}
// Ensure that both objects contain the same number of properties.
if (result) {
for (key in b) {
if (_.has(b, key) && !(size--)) break;
}
result = !size;
}
}
// Remove the first object from the stack of traversed objects.
stack.pop();
return result;
}
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
return eq(a, b, []);
};
// Is a given array, string, or object empty?
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false;
return true;
};
// Is a given value a DOM element?
_.isElement = function(obj) {
return !!(obj && obj.nodeType == 1);
};
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) == '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
return obj === Object(obj);
};
// Is a given variable an arguments object?
_.isArguments = function(obj) {
return toString.call(obj) == '[object Arguments]';
};
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
return !!(obj && _.has(obj, 'callee'));
};
}
// Is a given value a function?
_.isFunction = function(obj) {
return toString.call(obj) == '[object Function]';
};
// Is a given value a string?
_.isString = function(obj) {
return toString.call(obj) == '[object String]';
};
// Is a given value a number?
_.isNumber = function(obj) {
return toString.call(obj) == '[object Number]';
};
// Is the given value `NaN`?
_.isNaN = function(obj) {
// `NaN` is the only value for which `===` is not reflexive.
return obj !== obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};
// Is a given value a date?
_.isDate = function(obj) {
return toString.call(obj) == '[object Date]';
};
// Is the given value a regular expression?
_.isRegExp = function(obj) {
return toString.call(obj) == '[object RegExp]';
};
// Is a given value equal to null?
_.isNull = function(obj) {
return obj === null;
};
// Is a given variable undefined?
_.isUndefined = function(obj) {
return obj === void 0;
};
// Has own property?
_.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
};
// Utility Functions
// -----------------
// Run Underscore.js in *noConflict* mode, returning the `_` variable to its
// previous owner. Returns a reference to the Underscore object.
_.noConflict = function() {
root._ = previousUnderscore;
return this;
};
// Keep the identity function around for default iterators.
_.identity = function(value) {
return value;
};
// Run a function **n** times.
_.times = function (n, iterator, context) {
for (var i = 0; i < n; i++) iterator.call(context, i);
};
// Escape a string for HTML interpolation.
_.escape = function(string) {
return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
};
// Add your own custom functions to the Underscore object, ensuring that
// they're correctly added to the OOP wrapper as well.
_.mixin = function(obj) {
each(_.functions(obj), function(name){
addToWrapper(name, _[name] = obj[name]);
});
};
// Generate a unique integer id (unique within the entire client session).
// Useful for temporary DOM ids.
var idCounter = 0;
_.uniqueId = function(prefix) {
var id = idCounter++;
return prefix ? prefix + id : id;
};
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
var noMatch = /.^/;
// Within an interpolation, evaluation, or escaping, remove HTML escaping
// that had been previously added.
var unescape = function(code) {
return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'");
};
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
_.template = function(str, data) {
var c = _.templateSettings;
var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
'with(obj||{}){__p.push(\'' +
str.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(c.escape || noMatch, function(match, code) {
return "',_.escape(" + unescape(code) + "),'";
})
.replace(c.interpolate || noMatch, function(match, code) {
return "'," + unescape(code) + ",'";
})
.replace(c.evaluate || noMatch, function(match, code) {
return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('";
})
.replace(/\r/g, '\\r')
.replace(/\n/g, '\\n')
.replace(/\t/g, '\\t')
+ "');}return __p.join('');";
var func = new Function('obj', '_', tmpl);
if (data) return func(data, _);
return function(data) {
return func.call(this, data, _);
};
};
// Add a "chain" function, which will delegate to the wrapper.
_.chain = function(obj) {
return _(obj).chain();
};
// The OOP Wrapper
// ---------------
// If Underscore is called as a function, it returns a wrapped object that
// can be used OO-style. This wrapper holds altered versions of all the
// underscore functions. Wrapped objects may be chained.
var wrapper = function(obj) { this._wrapped = obj; };
// Expose `wrapper.prototype` as `_.prototype`
_.prototype = wrapper.prototype;
// Helper function to continue chaining intermediate results.
var result = function(obj, chain) {
return chain ? _(obj).chain() : obj;
};
// A method to easily add functions to the OOP wrapper.
var addToWrapper = function(name, func) {
wrapper.prototype[name] = function() {
var args = slice.call(arguments);
unshift.call(args, this._wrapped);
return result(func.apply(_, args), this._chain);
};
};
// Add all of the Underscore functions to the wrapper object.
_.mixin(_);
// Add all mutator Array functions to the wrapper.
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = ArrayProto[name];
wrapper.prototype[name] = function() {
var wrapped = this._wrapped;
method.apply(wrapped, arguments);
var length = wrapped.length;
if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
return result(wrapped, this._chain);
};
});
// Add all accessor Array functions to the wrapper.
each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name];
wrapper.prototype[name] = function() {
return result(method.apply(this._wrapped, arguments), this._chain);
};
});
// Start chaining a wrapped Underscore object.
wrapper.prototype.chain = function() {
this._chain = true;
return this;
};
// Extracts the result from a wrapped and chained object.
wrapper.prototype.value = function() {
return this._wrapped;
};
}).call(this);

31
_static/underscore.js Normal file
View file

@ -0,0 +1,31 @@
// Underscore.js 1.3.1
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),
function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);

BIN
_static/up-pressed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

BIN
_static/up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

808
_static/websupport.js Normal file
View file

@ -0,0 +1,808 @@
/*
* websupport.js
* ~~~~~~~~~~~~~
*
* sphinx.websupport utilities for all documentation.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
(function($) {
$.fn.autogrow = function() {
return this.each(function() {
var textarea = this;
$.fn.autogrow.resize(textarea);
$(textarea)
.focus(function() {
textarea.interval = setInterval(function() {
$.fn.autogrow.resize(textarea);
}, 500);
})
.blur(function() {
clearInterval(textarea.interval);
});
});
};
$.fn.autogrow.resize = function(textarea) {
var lineHeight = parseInt($(textarea).css('line-height'), 10);
var lines = textarea.value.split('\n');
var columns = textarea.cols;
var lineCount = 0;
$.each(lines, function() {
lineCount += Math.ceil(this.length / columns) || 1;
});
var height = lineHeight * (lineCount + 1);
$(textarea).css('height', height);
};
})(jQuery);
(function($) {
var comp, by;
function init() {
initEvents();
initComparator();
}
function initEvents() {
$(document).on("click", 'a.comment-close', function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
});
$(document).on("click", 'a.vote', function(event) {
event.preventDefault();
handleVote($(this));
});
$(document).on("click", 'a.reply', function(event) {
event.preventDefault();
openReply($(this).attr('id').substring(2));
});
$(document).on("click", 'a.close-reply', function(event) {
event.preventDefault();
closeReply($(this).attr('id').substring(2));
});
$(document).on("click", 'a.sort-option', function(event) {
event.preventDefault();
handleReSort($(this));
});
$(document).on("click", 'a.show-proposal', function(event) {
event.preventDefault();
showProposal($(this).attr('id').substring(2));
});
$(document).on("click", 'a.hide-proposal', function(event) {
event.preventDefault();
hideProposal($(this).attr('id').substring(2));
});
$(document).on("click", 'a.show-propose-change', function(event) {
event.preventDefault();
showProposeChange($(this).attr('id').substring(2));
});
$(document).on("click", 'a.hide-propose-change', function(event) {
event.preventDefault();
hideProposeChange($(this).attr('id').substring(2));
});
$(document).on("click", 'a.accept-comment', function(event) {
event.preventDefault();
acceptComment($(this).attr('id').substring(2));
});
$(document).on("click", 'a.delete-comment', function(event) {
event.preventDefault();
deleteComment($(this).attr('id').substring(2));
});
$(document).on("click", 'a.comment-markup', function(event) {
event.preventDefault();
toggleCommentMarkupBox($(this).attr('id').substring(2));
});
}
/**
* Set comp, which is a comparator function used for sorting and
* inserting comments into the list.
*/
function setComparator() {
// If the first three letters are "asc", sort in ascending order
// and remove the prefix.
if (by.substring(0,3) == 'asc') {
var i = by.substring(3);
comp = function(a, b) { return a[i] - b[i]; };
} else {
// Otherwise sort in descending order.
comp = function(a, b) { return b[by] - a[by]; };
}
// Reset link styles and format the selected sort option.
$('a.sel').attr('href', '#').removeClass('sel');
$('a.by' + by).removeAttr('href').addClass('sel');
}
/**
* Create a comp function. If the user has preferences stored in
* the sortBy cookie, use those, otherwise use the default.
*/
function initComparator() {
by = 'rating'; // Default to sort by rating.
// If the sortBy cookie is set, use that instead.
if (document.cookie.length > 0) {
var start = document.cookie.indexOf('sortBy=');
if (start != -1) {
start = start + 7;
var end = document.cookie.indexOf(";", start);
if (end == -1) {
end = document.cookie.length;
by = unescape(document.cookie.substring(start, end));
}
}
}
setComparator();
}
/**
* Show a comment div.
*/
function show(id) {
$('#ao' + id).hide();
$('#ah' + id).show();
var context = $.extend({id: id}, opts);
var popup = $(renderTemplate(popupTemplate, context)).hide();
popup.find('textarea[name="proposal"]').hide();
popup.find('a.by' + by).addClass('sel');
var form = popup.find('#cf' + id);
form.submit(function(event) {
event.preventDefault();
addComment(form);
});
$('#s' + id).after(popup);
popup.slideDown('fast', function() {
getComments(id);
});
}
/**
* Hide a comment div.
*/
function hide(id) {
$('#ah' + id).hide();
$('#ao' + id).show();
var div = $('#sc' + id);
div.slideUp('fast', function() {
div.remove();
});
}
/**
* Perform an ajax request to get comments for a node
* and insert the comments into the comments tree.
*/
function getComments(id) {
$.ajax({
type: 'GET',
url: opts.getCommentsURL,
data: {node: id},
success: function(data, textStatus, request) {
var ul = $('#cl' + id);
var speed = 100;
$('#cf' + id)
.find('textarea[name="proposal"]')
.data('source', data.source);
if (data.comments.length === 0) {
ul.html('<li>No comments yet.</li>');
ul.data('empty', true);
} else {
// If there are comments, sort them and put them in the list.
var comments = sortComments(data.comments);
speed = data.comments.length * 100;
appendComments(comments, ul);
ul.data('empty', false);
}
$('#cn' + id).slideUp(speed + 200);
ul.slideDown(speed);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem retrieving the comments.');
},
dataType: 'json'
});
}
/**
* Add a comment via ajax and insert the comment into the comment tree.
*/
function addComment(form) {
var node_id = form.find('input[name="node"]').val();
var parent_id = form.find('input[name="parent"]').val();
var text = form.find('textarea[name="comment"]').val();
var proposal = form.find('textarea[name="proposal"]').val();
if (text == '') {
showError('Please enter a comment.');
return;
}
// Disable the form that is being submitted.
form.find('textarea,input').attr('disabled', 'disabled');
// Send the comment to the server.
$.ajax({
type: "POST",
url: opts.addCommentURL,
dataType: 'json',
data: {
node: node_id,
parent: parent_id,
text: text,
proposal: proposal
},
success: function(data, textStatus, error) {
// Reset the form.
if (node_id) {
hideProposeChange(node_id);
}
form.find('textarea')
.val('')
.add(form.find('input'))
.removeAttr('disabled');
var ul = $('#cl' + (node_id || parent_id));
if (ul.data('empty')) {
$(ul).empty();
ul.data('empty', false);
}
insertComment(data.comment);
var ao = $('#ao' + node_id);
ao.find('img').attr({'src': opts.commentBrightImage});
if (node_id) {
// if this was a "root" comment, remove the commenting box
// (the user can get it back by reopening the comment popup)
$('#ca' + node_id).slideUp();
}
},
error: function(request, textStatus, error) {
form.find('textarea,input').removeAttr('disabled');
showError('Oops, there was a problem adding the comment.');
}
});
}
/**
* Recursively append comments to the main comment list and children
* lists, creating the comment tree.
*/
function appendComments(comments, ul) {
$.each(comments, function() {
var div = createCommentDiv(this);
ul.append($(document.createElement('li')).html(div));
appendComments(this.children, div.find('ul.comment-children'));
// To avoid stagnating data, don't store the comments children in data.
this.children = null;
div.data('comment', this);
});
}
/**
* After adding a new comment, it must be inserted in the correct
* location in the comment tree.
*/
function insertComment(comment) {
var div = createCommentDiv(comment);
// To avoid stagnating data, don't store the comments children in data.
comment.children = null;
div.data('comment', comment);
var ul = $('#cl' + (comment.node || comment.parent));
var siblings = getChildren(ul);
var li = $(document.createElement('li'));
li.hide();
// Determine where in the parents children list to insert this comment.
for(var i=0; i < siblings.length; i++) {
if (comp(comment, siblings[i]) <= 0) {
$('#cd' + siblings[i].id)
.parent()
.before(li.html(div));
li.slideDown('fast');
return;
}
}
// If we get here, this comment rates lower than all the others,
// or it is the only comment in the list.
ul.append(li.html(div));
li.slideDown('fast');
}
function acceptComment(id) {
$.ajax({
type: 'POST',
url: opts.acceptCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
$('#cm' + id).fadeOut('fast');
$('#cd' + id).removeClass('moderate');
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem accepting the comment.');
}
});
}
function deleteComment(id) {
$.ajax({
type: 'POST',
url: opts.deleteCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
var div = $('#cd' + id);
if (data == 'delete') {
// Moderator mode: remove the comment and all children immediately
div.slideUp('fast', function() {
div.remove();
});
return;
}
// User mode: only mark the comment as deleted
div
.find('span.user-id:first')
.text('[deleted]').end()
.find('div.comment-text:first')
.text('[deleted]').end()
.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
.remove();
var comment = div.data('comment');
comment.username = '[deleted]';
comment.text = '[deleted]';
div.data('comment', comment);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem deleting the comment.');
}
});
}
function showProposal(id) {
$('#sp' + id).hide();
$('#hp' + id).show();
$('#pr' + id).slideDown('fast');
}
function hideProposal(id) {
$('#hp' + id).hide();
$('#sp' + id).show();
$('#pr' + id).slideUp('fast');
}
function showProposeChange(id) {
$('#pc' + id).hide();
$('#hc' + id).show();
var textarea = $('#pt' + id);
textarea.val(textarea.data('source'));
$.fn.autogrow.resize(textarea[0]);
textarea.slideDown('fast');
}
function hideProposeChange(id) {
$('#hc' + id).hide();
$('#pc' + id).show();
var textarea = $('#pt' + id);
textarea.val('').removeAttr('disabled');
textarea.slideUp('fast');
}
function toggleCommentMarkupBox(id) {
$('#mb' + id).toggle();
}
/** Handle when the user clicks on a sort by link. */
function handleReSort(link) {
var classes = link.attr('class').split(/\s+/);
for (var i=0; i<classes.length; i++) {
if (classes[i] != 'sort-option') {
by = classes[i].substring(2);
}
}
setComparator();
// Save/update the sortBy cookie.
var expiration = new Date();
expiration.setDate(expiration.getDate() + 365);
document.cookie= 'sortBy=' + escape(by) +
';expires=' + expiration.toUTCString();
$('ul.comment-ul').each(function(index, ul) {
var comments = getChildren($(ul), true);
comments = sortComments(comments);
appendComments(comments, $(ul).empty());
});
}
/**
* Function to process a vote when a user clicks an arrow.
*/
function handleVote(link) {
if (!opts.voting) {
showError("You'll need to login to vote.");
return;
}
var id = link.attr('id');
if (!id) {
// Didn't click on one of the voting arrows.
return;
}
// If it is an unvote, the new vote value is 0,
// Otherwise it's 1 for an upvote, or -1 for a downvote.
var value = 0;
if (id.charAt(1) != 'u') {
value = id.charAt(0) == 'u' ? 1 : -1;
}
// The data to be sent to the server.
var d = {
comment_id: id.substring(2),
value: value
};
// Swap the vote and unvote links.
link.hide();
$('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
.show();
// The div the comment is displayed in.
var div = $('div#cd' + d.comment_id);
var data = div.data('comment');
// If this is not an unvote, and the other vote arrow has
// already been pressed, unpress it.
if ((d.value !== 0) && (data.vote === d.value * -1)) {
$('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
$('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
}
// Update the comments rating in the local data.
data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
data.vote = d.value;
div.data('comment', data);
// Change the rating text.
div.find('.rating:first')
.text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
// Send the vote information to the server.
$.ajax({
type: "POST",
url: opts.processVoteURL,
data: d,
error: function(request, textStatus, error) {
showError('Oops, there was a problem casting that vote.');
}
});
}
/**
* Open a reply form used to reply to an existing comment.
*/
function openReply(id) {
// Swap out the reply link for the hide link
$('#rl' + id).hide();
$('#cr' + id).show();
// Add the reply li to the children ul.
var div = $(renderTemplate(replyTemplate, {id: id})).hide();
$('#cl' + id)
.prepend(div)
// Setup the submit handler for the reply form.
.find('#rf' + id)
.submit(function(event) {
event.preventDefault();
addComment($('#rf' + id));
closeReply(id);
})
.find('input[type=button]')
.click(function() {
closeReply(id);
});
div.slideDown('fast', function() {
$('#rf' + id).find('textarea').focus();
});
}
/**
* Close the reply form opened with openReply.
*/
function closeReply(id) {
// Remove the reply div from the DOM.
$('#rd' + id).slideUp('fast', function() {
$(this).remove();
});
// Swap out the hide link for the reply link
$('#cr' + id).hide();
$('#rl' + id).show();
}
/**
* Recursively sort a tree of comments using the comp comparator.
*/
function sortComments(comments) {
comments.sort(comp);
$.each(comments, function() {
this.children = sortComments(this.children);
});
return comments;
}
/**
* Get the children comments from a ul. If recursive is true,
* recursively include childrens' children.
*/
function getChildren(ul, recursive) {
var children = [];
ul.children().children("[id^='cd']")
.each(function() {
var comment = $(this).data('comment');
if (recursive)
comment.children = getChildren($(this).find('#cl' + comment.id), true);
children.push(comment);
});
return children;
}
/** Create a div to display a comment in. */
function createCommentDiv(comment) {
if (!comment.displayed && !opts.moderator) {
return $('<div class="moderate">Thank you! Your comment will show up '
+ 'once it is has been approved by a moderator.</div>');
}
// Prettify the comment rating.
comment.pretty_rating = comment.rating + ' point' +
(comment.rating == 1 ? '' : 's');
// Make a class (for displaying not yet moderated comments differently)
comment.css_class = comment.displayed ? '' : ' moderate';
// Create a div for this comment.
var context = $.extend({}, opts, comment);
var div = $(renderTemplate(commentTemplate, context));
// If the user has voted on this comment, highlight the correct arrow.
if (comment.vote) {
var direction = (comment.vote == 1) ? 'u' : 'd';
div.find('#' + direction + 'v' + comment.id).hide();
div.find('#' + direction + 'u' + comment.id).show();
}
if (opts.moderator || comment.text != '[deleted]') {
div.find('a.reply').show();
if (comment.proposal_diff)
div.find('#sp' + comment.id).show();
if (opts.moderator && !comment.displayed)
div.find('#cm' + comment.id).show();
if (opts.moderator || (opts.username == comment.username))
div.find('#dc' + comment.id).show();
}
return div;
}
/**
* A simple template renderer. Placeholders such as <%id%> are replaced
* by context['id'] with items being escaped. Placeholders such as <#id#>
* are not escaped.
*/
function renderTemplate(template, context) {
var esc = $(document.createElement('div'));
function handle(ph, escape) {
var cur = context;
$.each(ph.split('.'), function() {
cur = cur[this];
});
return escape ? esc.text(cur || "").html() : cur;
}
return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
return handle(arguments[2], arguments[1] == '%' ? true : false);
});
}
/** Flash an error message briefly. */
function showError(message) {
$(document.createElement('div')).attr({'class': 'popup-error'})
.append($(document.createElement('div'))
.attr({'class': 'error-message'}).text(message))
.appendTo('body')
.fadeIn("slow")
.delay(2000)
.fadeOut("slow");
}
/** Add a link the user uses to open the comments popup. */
$.fn.comment = function() {
return this.each(function() {
var id = $(this).attr('id').substring(1);
var count = COMMENT_METADATA[id];
var title = count + ' comment' + (count == 1 ? '' : 's');
var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
var addcls = count == 0 ? ' nocomment' : '';
$(this)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-open' + addcls,
id: 'ao' + id
})
.append($(document.createElement('img')).attr({
src: image,
alt: 'comment',
title: title
}))
.click(function(event) {
event.preventDefault();
show($(this).attr('id').substring(2));
})
)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-close hidden',
id: 'ah' + id
})
.append($(document.createElement('img')).attr({
src: opts.closeCommentImage,
alt: 'close',
title: 'close'
}))
.click(function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
})
);
});
};
var opts = {
processVoteURL: '/_process_vote',
addCommentURL: '/_add_comment',
getCommentsURL: '/_get_comments',
acceptCommentURL: '/_accept_comment',
deleteCommentURL: '/_delete_comment',
commentImage: '/static/_static/comment.png',
closeCommentImage: '/static/_static/comment-close.png',
loadingImage: '/static/_static/ajax-loader.gif',
commentBrightImage: '/static/_static/comment-bright.png',
upArrow: '/static/_static/up.png',
downArrow: '/static/_static/down.png',
upArrowPressed: '/static/_static/up-pressed.png',
downArrowPressed: '/static/_static/down-pressed.png',
voting: false,
moderator: false
};
if (typeof COMMENT_OPTIONS != "undefined") {
opts = jQuery.extend(opts, COMMENT_OPTIONS);
}
var popupTemplate = '\
<div class="sphinx-comments" id="sc<%id%>">\
<p class="sort-options">\
Sort by:\
<a href="#" class="sort-option byrating">best rated</a>\
<a href="#" class="sort-option byascage">newest</a>\
<a href="#" class="sort-option byage">oldest</a>\
</p>\
<div class="comment-header">Comments</div>\
<div class="comment-loading" id="cn<%id%>">\
loading comments... <img src="<%loadingImage%>" alt="" /></div>\
<ul id="cl<%id%>" class="comment-ul"></ul>\
<div id="ca<%id%>">\
<p class="add-a-comment">Add a comment\
(<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
<div class="comment-markup-box" id="mb<%id%>">\
reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
<code>``code``</code>, \
code blocks: <code>::</code> and an indented block after blank line</div>\
<form method="post" id="cf<%id%>" class="comment-form" action="">\
<textarea name="comment" cols="80"></textarea>\
<p class="propose-button">\
<a href="#" id="pc<%id%>" class="show-propose-change">\
Propose a change &#9657;\
</a>\
<a href="#" id="hc<%id%>" class="hide-propose-change">\
Propose a change &#9663;\
</a>\
</p>\
<textarea name="proposal" id="pt<%id%>" cols="80"\
spellcheck="false"></textarea>\
<input type="submit" value="Add comment" />\
<input type="hidden" name="node" value="<%id%>" />\
<input type="hidden" name="parent" value="" />\
</form>\
</div>\
</div>';
var commentTemplate = '\
<div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
<div class="vote">\
<div class="arrow">\
<a href="#" id="uv<%id%>" class="vote" title="vote up">\
<img src="<%upArrow%>" />\
</a>\
<a href="#" id="uu<%id%>" class="un vote" title="vote up">\
<img src="<%upArrowPressed%>" />\
</a>\
</div>\
<div class="arrow">\
<a href="#" id="dv<%id%>" class="vote" title="vote down">\
<img src="<%downArrow%>" id="da<%id%>" />\
</a>\
<a href="#" id="du<%id%>" class="un vote" title="vote down">\
<img src="<%downArrowPressed%>" />\
</a>\
</div>\
</div>\
<div class="comment-content">\
<p class="tagline comment">\
<span class="user-id"><%username%></span>\
<span class="rating"><%pretty_rating%></span>\
<span class="delta"><%time.delta%></span>\
</p>\
<div class="comment-text comment"><#text#></div>\
<p class="comment-opts comment">\
<a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
<a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
<a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
<a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
<a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
<span id="cm<%id%>" class="moderation hidden">\
<a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
</span>\
</p>\
<pre class="proposal" id="pr<%id%>">\
<#proposal_diff#>\
</pre>\
<ul class="comment-children" id="cl<%id%>"></ul>\
</div>\
<div class="clearleft"></div>\
</div>\
</div>';
var replyTemplate = '\
<li>\
<div class="reply-div" id="rd<%id%>">\
<form id="rf<%id%>">\
<textarea name="comment" cols="80"></textarea>\
<input type="submit" value="Add reply" />\
<input type="button" value="Cancel" />\
<input type="hidden" name="parent" value="<%id%>" />\
<input type="hidden" name="node" value="" />\
</form>\
</div>\
</li>';
$(document).ready(function() {
init();
});
})(jQuery);
$(document).ready(function() {
// add comment anchors for all paragraphs that are commentable
$('.sphinx-has-comment').comment();
// highlight search words in search results
$("div.context").each(function() {
var params = $.getQueryParameters();
var terms = (params.q) ? params.q[0].split(/\s+/) : [];
var result = $(this);
$.each(terms, function() {
result.highlightText(this.toLowerCase(), 'highlighted');
});
});
// directly open comment window if requested
var anchor = document.location.hash;
if (anchor.substring(0, 9) == '#comment-') {
$('#ao' + anchor.substring(9)).click();
document.location.hash = '#s' + anchor.substring(9);
}
});

592
api.entry.html Normal file
View file

@ -0,0 +1,592 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.entry &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="feedgen.util" href="api.util.html" />
<link rel="prev" title="feedgen.feed" href="api.feed.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.entry</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="api.feed.html">feedgen.feed</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.util.html">feedgen.util</a>&#160;&#160;»
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.entry"></span><div class="section" id="feedgen-entry">
<h1>feedgen.entry<a class="headerlink" href="#feedgen-entry" title="Permalink to this headline"></a></h1>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013, Lars Kiesow &lt;<a class="reference external" href="mailto:lkiesow&#37;&#52;&#48;uos&#46;de">lkiesow<span>&#64;</span>uos<span>&#46;</span>de</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="class">
<dt id="feedgen.entry.FeedEntry">
<em class="property">class </em><code class="descclassname">feedgen.entry.</code><code class="descname">FeedEntry</code><a class="headerlink" href="#feedgen.entry.FeedEntry" title="Permalink to this definition"></a></dt>
<dd><p>FeedEntry call representing an ATOM feeds entry node or an RSS feeds item
node.</p>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.atom_entry">
<code class="descname">atom_entry</code><span class="sig-paren">(</span><em>extensions=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.atom_entry" title="Permalink to this definition"></a></dt>
<dd><p>Create an ATOM entry and return it.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.author">
<code class="descname">author</code><span class="sig-paren">(</span><em>author=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.author" title="Permalink to this definition"></a></dt>
<dd><p>Get or set author data. An author element is a dict containing a
name, an email address and a uri. Name is mandatory for ATOM, email is
mandatory for RSS.</p>
<p>This method can be called with:
- the fields of an author as keyword arguments
- the fields of an author as a dictionary
- a list of dictionaries containing the author fields</p>
<p>An author has the following fields:
- <em>name</em> conveys a human-readable name for the person.
- <em>uri</em> contains a home page for the person.
- <em>email</em> contains an email address for the person.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>author</strong> Dict or list of dicts with author data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">author</span><span class="p">({</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span> <span class="s1">&#39;email&#39;</span><span class="p">:</span><span class="s1">&#39;jdoe@example.com&#39;</span><span class="p">})</span>
<span class="go">[{&#39;name&#39;:&#39;John Doe&#39;,&#39;email&#39;:&#39;jdoe@example.com&#39;}]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">author</span><span class="p">([{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Mr. X&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Max&#39;</span><span class="p">}])</span>
<span class="go">[{&#39;name&#39;:&#39;John Doe&#39;,&#39;email&#39;:&#39;jdoe@example.com&#39;},</span>
<span class="go"> {&#39;name&#39;:&#39;John Doe&#39;}, {&#39;name&#39;:&#39;Max&#39;}]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">author</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s1">&#39;jdoe@example.com&#39;</span><span class="p">,</span> <span class="n">replace</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="go">[{&#39;name&#39;:&#39;John Doe&#39;,&#39;email&#39;:&#39;jdoe@example.com&#39;}]</span>
</pre></div>
</div>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.category">
<code class="descname">category</code><span class="sig-paren">(</span><em>category=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.category" title="Permalink to this definition"></a></dt>
<dd><p>Get or set categories that the entry belongs to.</p>
<p>This method can be called with:
- the fields of a category as keyword arguments
- the fields of a category as a dictionary
- a list of dictionaries containing the category fields</p>
<p>A categories has the following fields:
- <em>term</em> identifies the category
- <em>scheme</em> identifies the categorization scheme via a URI.
- <em>label</em> provides a human-readable label for display</p>
<p>If a label is present it is used for the RSS feeds. Otherwise the term
is used. The scheme is used for the domain attribute in RSS.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>category</strong> Dict or list of dicts with data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of category data.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.comments">
<code class="descname">comments</code><span class="sig-paren">(</span><em>comments=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.comments" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the value of comments which is the URL of the comments
page for the item. This is a RSS only value.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>comments</strong> URL to the comments page.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">URL to the comments page.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.content">
<code class="descname">content</code><span class="sig-paren">(</span><em>content=None</em>, <em>src=None</em>, <em>type=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.content" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the content of the entry which contains or links to the
complete content of the entry. Content must be provided for ATOM
entries if there is no alternate link, and should be provided if there
is no summary. If the content is set (not linked) it will also set
rss:description.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>content</strong> The content of the feed entry.</li>
<li><strong>src</strong> Link to the entries content.</li>
<li><strong>type</strong> If type is CDATA content would not be escaped.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Content element of the entry.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.contributor">
<code class="descname">contributor</code><span class="sig-paren">(</span><em>contributor=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.contributor" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the contributor data of the feed. This is an ATOM only
value.</p>
<p>This method can be called with:
- the fields of an contributor as keyword arguments
- the fields of an contributor as a dictionary
- a list of dictionaries containing the contributor fields</p>
<p>An contributor has the following fields:
- <em>name</em> conveys a human-readable name for the person.
- <em>uri</em> contains a home page for the person.
- <em>email</em> contains an email address for the person.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>contributor</strong> Dictionary or list of dictionaries with contributor
data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of contributors as dictionaries.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.description">
<code class="descname">description</code><span class="sig-paren">(</span><em>description=None</em>, <em>isSummary=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.description" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the description value which is the item synopsis.
Description is an RSS only element. For ATOM feeds it is split in
summary and content. The isSummary parameter can be used to control
which ATOM value is set when setting description.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>description</strong> Description of the entry.</li>
<li><strong>isSummary</strong> If the description should be used as content or
summary.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">The entries description.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.enclosure">
<code class="descname">enclosure</code><span class="sig-paren">(</span><em>url=None</em>, <em>length=None</em>, <em>type=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.enclosure" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the value of enclosure which describes a media object
that is attached to the item. This is a RSS only value which is
represented by link(rel=enclosure) in ATOM. ATOM feeds can furthermore
contain several enclosures while RSS may contain only one. That is why
this method, if repeatedly called, will add more than one enclosures to
the feed. However, only the last one is used for RSS.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>url</strong> URL of the media object.</li>
<li><strong>length</strong> Size of the media in bytes.</li>
<li><strong>type</strong> Mimetype of the linked media.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Data of the enclosure element.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.guid">
<code class="descname">guid</code><span class="sig-paren">(</span><em>guid=None</em>, <em>permalink=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.guid" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the entries guid which is a string that uniquely
identifies the item. This will also set atom:id.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>guid</strong> Id of the entry.</li>
<li><strong>permalink</strong> If this is a permanent identifier for this item</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Id and permalink setting of the entry.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.id">
<code class="descname">id</code><span class="sig-paren">(</span><em>id=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.id" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the entry id which identifies the entry using a
universally unique and permanent URI. Two entries in a feed can have
the same value for id if they represent the same entry at different
points in time. This method will also set rss:guid with permalink set
to False. Id is mandatory for an ATOM entry.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>id</strong> New Id of the entry.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Id of the entry.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.link">
<code class="descname">link</code><span class="sig-paren">(</span><em>link=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.link" title="Permalink to this definition"></a></dt>
<dd><p>Get or set link data. An link element is a dict with the fields
href, rel, type, hreflang, title, and length. Href is mandatory for
ATOM.</p>
<p>This method can be called with:
- the fields of a link as keyword arguments
- the fields of a link as a dictionary
- a list of dictionaries containing the link fields</p>
<p>A link has the following fields:</p>
<ul>
<li><p class="first"><em>href</em> is the URI of the referenced resource (typically a Web page)</p>
</li>
<li><p class="first"><em>rel</em> contains a single link relationship type. It can be a full URI,
or one of the following predefined values (default=alternate):</p>
<blockquote>
<div><ul class="simple">
<li><em>alternate</em> an alternate representation of the entry or feed, for
example a permalink to the html version of the entry, or the
front page of the weblog.</li>
<li><em>enclosure</em> a related resource which is potentially large in size
and might require special handling, for example an audio or video
recording.</li>
<li><em>related</em> an document related to the entry or feed.</li>
<li><em>self</em> the feed itself.</li>
<li><em>via</em> the source of the information provided in the entry.</li>
</ul>
</div></blockquote>
</li>
<li><p class="first"><em>type</em> indicates the media type of the resource.</p>
</li>
<li><p class="first"><em>hreflang</em> indicates the language of the referenced resource.</p>
</li>
<li><p class="first"><em>title</em> human readable information about the link, typically for
display purposes.</p>
</li>
<li><p class="first"><em>length</em> the length of the resource, in bytes.</p>
</li>
</ul>
<p>RSS only supports one link with nothing but a URL. So for the RSS link
element the last link with rel=alternate is used.</p>
<p>RSS also supports one enclusure element per entry which is covered by
the link element in ATOM feed entries. So for the RSS enclusure element
the last link with rel=enclosure is used.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>link</strong> Dict or list of dicts with data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of link data.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.load_extension">
<code class="descname">load_extension</code><span class="sig-paren">(</span><em>name</em>, <em>atom=True</em>, <em>rss=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.load_extension" title="Permalink to this definition"></a></dt>
<dd><p>Load a specific extension by name.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>name</strong> Name of the extension to load.</li>
<li><strong>atom</strong> If the extension should be used for ATOM feeds.</li>
<li><strong>rss</strong> If the extension should be used for RSS feeds.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.pubDate">
<code class="descname">pubDate</code><span class="sig-paren">(</span><em>pubDate=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.pubDate" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the pubDate of the entry which indicates when the entry
was published. This method is just another name for the published(…)
method.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.pubdate">
<code class="descname">pubdate</code><span class="sig-paren">(</span><em>pubDate=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.pubdate" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the pubDate of the entry which indicates when the entry
was published. This method is just another name for the published(…)
method.</p>
<p>pubdate(…) is deprecated and may be removed in feedgen ≥ 0.8. Use
pubDate(…) instead.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.published">
<code class="descname">published</code><span class="sig-paren">(</span><em>published=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.published" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the published value which contains the time of the initial
creation or first availability of the entry.</p>
<p>The value can either be a string which will automatically be parsed or
a datetime.datetime object. In any case it is necessary that the value
include timezone information.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>published</strong> The creation date.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Creation date as datetime.datetime</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.register_extension">
<code class="descname">register_extension</code><span class="sig-paren">(</span><em>namespace</em>, <em>extension_class_entry=None</em>, <em>atom=True</em>, <em>rss=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.register_extension" title="Permalink to this definition"></a></dt>
<dd><p>Register a specific extension by classes to a namespace.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>namespace</strong> namespace for the extension</li>
<li><strong>extension_class_entry</strong> Class of the entry extension to load.</li>
<li><strong>atom</strong> If the extension should be used for ATOM feeds.</li>
<li><strong>rss</strong> If the extension should be used for RSS feeds.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.rights">
<code class="descname">rights</code><span class="sig-paren">(</span><em>rights=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.rights" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the rights value of the entry which conveys information
about rights, e.g. copyrights, held in and over the entry. This ATOM
value will also set rss:copyright.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>rights</strong> Rights information of the feed.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Rights information of the feed.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.rss_entry">
<code class="descname">rss_entry</code><span class="sig-paren">(</span><em>extensions=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.rss_entry" title="Permalink to this definition"></a></dt>
<dd><p>Create a RSS item and return it.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.source">
<code class="descname">source</code><span class="sig-paren">(</span><em>url=None</em>, <em>title=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.source" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the source for the current feed entry.</p>
<p>Note that ATOM feeds support a lot more sub elements than title and URL
(which is what RSS supports) but these are currently not supported.
Patches are welcome.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>url</strong> Link to the source.</li>
<li><strong>title</strong> Title of the linked resource</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Source element as dictionaries.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.summary">
<code class="descname">summary</code><span class="sig-paren">(</span><em>summary=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.summary" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the summary element of an entry which conveys a short
summary, abstract, or excerpt of the entry. Summary is an ATOM only
element and should be provided if there either is no content provided
for the entry, or that content is not inline (i.e., contains a src
attribute), or if the content is encoded in base64. This method will
also set the rss:description field if it wasnt previously set or
contains the old value of summary.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>summary</strong> Summary of the entries contents.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Summary of the entries contents.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.title">
<code class="descname">title</code><span class="sig-paren">(</span><em>title=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.title" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the title value of the entry. It should contain a human
readable title for the entry. Title is mandatory for both ATOM and RSS
and should not be blank.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>title</strong> The new title of the entry.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The entriess title.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.ttl">
<code class="descname">ttl</code><span class="sig-paren">(</span><em>ttl=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.ttl" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the ttl value. It is an RSS only element. ttl stands for
time to live. Its a number of minutes that indicates how long a
channel can be cached before refreshing from the source.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>ttl</strong> Integer value representing the time to live.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Time to live of of the entry.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.entry.FeedEntry.updated">
<code class="descname">updated</code><span class="sig-paren">(</span><em>updated=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.entry.FeedEntry.updated" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the updated value which indicates the last time the entry
was modified in a significant way.</p>
<p>The value can either be a string which will automatically be parsed or
a datetime.datetime object. In any case it is necessary that the value
include timezone information.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>updated</strong> The modification date.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Modification date as datetime.datetime</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="api.feed.html">feedgen.feed</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.util.html">feedgen.util</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

965
api.feed.html Normal file
View file

@ -0,0 +1,965 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.feed &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="feedgen.entry" href="api.entry.html" />
<link rel="prev" title="API Documentation" href="api.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.feed</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="api.html">API Documentation</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.entry.html">feedgen.entry</a>&#160;&#160;»
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.feed"></span><div class="section" id="feedgen-feed">
<h1>feedgen.feed<a class="headerlink" href="#feedgen-feed" title="Permalink to this headline"></a></h1>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013-2016, Lars Kiesow &lt;<a class="reference external" href="mailto:lkiesow&#37;&#52;&#48;uos&#46;de">lkiesow<span>&#64;</span>uos<span>&#46;</span>de</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="class">
<dt id="feedgen.feed.FeedGenerator">
<em class="property">class </em><code class="descclassname">feedgen.feed.</code><code class="descname">FeedGenerator</code><a class="headerlink" href="#feedgen.feed.FeedGenerator" title="Permalink to this definition"></a></dt>
<dd><p>FeedGenerator for generating ATOM and RSS feeds.</p>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.add_entry">
<code class="descname">add_entry</code><span class="sig-paren">(</span><em>feedEntry=None</em>, <em>order='prepend'</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.add_entry" title="Permalink to this definition"></a></dt>
<dd><p>This method will add a new entry to the feed. If the feedEntry
argument is omittet a new Entry object is created automatically. This
is the preferred way to add new entries to a feed.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>feedEntry</strong> FeedEntry object to add.</li>
<li><strong>order</strong> If <cite>prepend</cite> is chosen, the entry will be inserted
at the beginning of the feed. If <cite>append</cite> is chosen,
the entry will be appended to the feed.
(default: <cite>prepend</cite>).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">FeedEntry object created or passed to this function.</p>
</td>
</tr>
</tbody>
</table>
<p>Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">entry</span> <span class="o">=</span> <span class="n">feedgen</span><span class="o">.</span><span class="n">add_entry</span><span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">entry</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">&#39;First feed entry&#39;</span><span class="p">)</span>
</pre></div>
</div>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.add_item">
<code class="descname">add_item</code><span class="sig-paren">(</span><em>item=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.add_item" title="Permalink to this definition"></a></dt>
<dd><p>This method will add a new item to the feed. If the item argument is
omittet a new FeedEntry object is created automatically. This is just
another name for add_entry(…)</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.atom_file">
<code class="descname">atom_file</code><span class="sig-paren">(</span><em>filename</em>, <em>extensions=True</em>, <em>pretty=False</em>, <em>encoding='UTF-8'</em>, <em>xml_declaration=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.atom_file" title="Permalink to this definition"></a></dt>
<dd><p>Generates an ATOM feed and write the resulting XML to a file.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>filename</strong> Name of file to write or a file-like object or a URL.</li>
<li><strong>extensions</strong> Enable or disable the loaded extensions for the xml
generation (default: enabled).</li>
<li><strong>pretty</strong> If the feed should be split into multiple lines and
properly indented.</li>
<li><strong>encoding</strong> Encoding used in the XML file (default: UTF-8).</li>
<li><strong>xml_declaration</strong> If an XML declaration should be added to the
output (Default: enabled).</li>
</ul>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.atom_str">
<code class="descname">atom_str</code><span class="sig-paren">(</span><em>pretty=False</em>, <em>extensions=True</em>, <em>encoding='UTF-8'</em>, <em>xml_declaration=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.atom_str" title="Permalink to this definition"></a></dt>
<dd><p>Generates an ATOM feed and returns the feed XML as string.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>pretty</strong> If the feed should be split into multiple lines and
properly indented.</li>
<li><strong>extensions</strong> Enable or disable the loaded extensions for the xml
generation (default: enabled).</li>
<li><strong>encoding</strong> Encoding used in the XML file (default: UTF-8).</li>
<li><strong>xml_declaration</strong> If an XML declaration should be added to the
output (Default: enabled).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">String representation of the ATOM feed.</p>
</td>
</tr>
</tbody>
</table>
<p><strong>Return type:</strong> The return type may vary between different Python
versions and your encoding parameters passed to this method. For
details have a look at the <a class="reference external" href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.tostring">lxml documentation</a></p>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.author">
<code class="descname">author</code><span class="sig-paren">(</span><em>author=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.author" title="Permalink to this definition"></a></dt>
<dd><p>Get or set author data. An author element is a dictionary containing
a name, an email address and a URI. Name is mandatory for ATOM, email
is mandatory for RSS.</p>
<p>This method can be called with:</p>
<ul class="simple">
<li>the fields of an author as keyword arguments</li>
<li>the fields of an author as a dictionary</li>
<li>a list of dictionaries containing the author fields</li>
</ul>
<p>An author has the following fields:</p>
<ul class="simple">
<li><em>name</em> conveys a human-readable name for the person.</li>
<li><em>uri</em> contains a home page for the person.</li>
<li><em>email</em> contains an email address for the person.</li>
</ul>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>author</strong> Dictionary or list of dictionaries with author data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of authors as dictionaries.</p>
</td>
</tr>
</tbody>
</table>
<p>Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">feedgen</span><span class="o">.</span><span class="n">author</span><span class="p">({</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span> <span class="s1">&#39;email&#39;</span><span class="p">:</span><span class="s1">&#39;jdoe@example.com&#39;</span><span class="p">})</span>
<span class="go">[{&#39;name&#39;:&#39;John Doe&#39;,&#39;email&#39;:&#39;jdoe@example.com&#39;}]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">feedgen</span><span class="o">.</span><span class="n">author</span><span class="p">([{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;Mr. X&#39;</span><span class="p">},{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;Max&#39;</span><span class="p">}])</span>
<span class="go">[{&#39;name&#39;:&#39;John Doe&#39;,&#39;email&#39;:&#39;jdoe@example.com&#39;},</span>
<span class="go"> {&#39;name&#39;:&#39;John Doe&#39;}, {&#39;name&#39;:&#39;Max&#39;}]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">feedgen</span><span class="o">.</span><span class="n">author</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s1">&#39;jdoe@example.com&#39;</span><span class="p">,</span>
<span class="go"> replace=True)</span>
<span class="go">[{&#39;name&#39;:&#39;John Doe&#39;,&#39;email&#39;:&#39;jdoe@example.com&#39;}]</span>
</pre></div>
</div>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.category">
<code class="descname">category</code><span class="sig-paren">(</span><em>category=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.category" title="Permalink to this definition"></a></dt>
<dd><p>Get or set categories that the feed belongs to.</p>
<p>This method can be called with:</p>
<ul class="simple">
<li>the fields of a category as keyword arguments</li>
<li>the fields of a category as a dictionary</li>
<li>a list of dictionaries containing the category fields</li>
</ul>
<p>A categories has the following fields:</p>
<ul class="simple">
<li><em>term</em> identifies the category</li>
<li><em>scheme</em> identifies the categorization scheme via a URI.</li>
<li><em>label</em> provides a human-readable label for display</li>
</ul>
<p>If a label is present it is used for the RSS feeds. Otherwise the term
is used. The scheme is used for the domain attribute in RSS.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>link</strong> Dict or list of dicts with data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of category data.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.cloud">
<code class="descname">cloud</code><span class="sig-paren">(</span><em>domain=None</em>, <em>port=None</em>, <em>path=None</em>, <em>registerProcedure=None</em>, <em>protocol=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.cloud" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the cloud data of the feed. It is an RSS only attribute.
It specifies a web service that supports the rssCloud interface which
can be implemented in HTTP-POST, XML-RPC or SOAP 1.1.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>domain</strong> The domain where the webservice can be found.</li>
<li><strong>port</strong> The port the webservice listens to.</li>
<li><strong>path</strong> The path of the webservice.</li>
<li><strong>registerProcedure</strong> The procedure to call.</li>
<li><strong>protocol</strong> Can be either HTTP-POST, XML-RPC or SOAP 1.1.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Dictionary containing the cloud data.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.contributor">
<code class="descname">contributor</code><span class="sig-paren">(</span><em>contributor=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.contributor" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the contributor data of the feed. This is an ATOM only
value.</p>
<p>This method can be called with:
- the fields of an contributor as keyword arguments
- the fields of an contributor as a dictionary
- a list of dictionaries containing the contributor fields</p>
<p>An contributor has the following fields:
- <em>name</em> conveys a human-readable name for the person.
- <em>uri</em> contains a home page for the person.
- <em>email</em> contains an email address for the person.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>contributor</strong> Dictionary or list of dictionaries with contributor
data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of contributors as dictionaries.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.copyright">
<code class="descname">copyright</code><span class="sig-paren">(</span><em>copyright=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.copyright" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the copyright notice for content in the channel. This RSS
value will also set the atom:rights value.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>copyright</strong> The copyright notice.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The copyright notice.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.description">
<code class="descname">description</code><span class="sig-paren">(</span><em>description=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.description" title="Permalink to this definition"></a></dt>
<dd><p>Set and get the description of the feed. This is an RSS only element
which is a phrase or sentence describing the channel. It is mandatory
for RSS feeds. It is roughly the same as atom:subtitle. Thus setting
this will also set atom:subtitle.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>description</strong> Description of the channel.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Description of the channel.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.docs">
<code class="descname">docs</code><span class="sig-paren">(</span><em>docs=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.docs" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the docs value of the feed. This is an RSS only value. It
is a URL that points to the documentation for the format used in the
RSS file. It is probably a pointer to [1]. It is for people who might
stumble across an RSS file on a Web server 25 years from now and wonder
what it is.</p>
<p>[1]: <a class="reference external" href="http://www.rssboard.org/rss-specification">http://www.rssboard.org/rss-specification</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>docs</strong> URL of the format documentation.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">URL of the format documentation.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.entry">
<code class="descname">entry</code><span class="sig-paren">(</span><em>entry=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.entry" title="Permalink to this definition"></a></dt>
<dd><p>Get or set feed entries. Use the add_entry() method instead to
automatically create the FeedEntry objects.</p>
<p>This method takes both a single FeedEntry object or a list of objects.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>entry</strong> FeedEntry object or list of FeedEntry objects.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">List ob all feed entries.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.generator">
<code class="descname">generator</code><span class="sig-paren">(</span><em>generator=None</em>, <em>version=None</em>, <em>uri=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.generator" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the generator of the feed which identifies the software
used to generate the feed, for debugging and other purposes. Both the
uri and version attributes are optional and only available in the ATOM
feed.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>generator</strong> Software used to create the feed.</li>
<li><strong>version</strong> Version of the software.</li>
<li><strong>uri</strong> URI the software can be found.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.icon">
<code class="descname">icon</code><span class="sig-paren">(</span><em>icon=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.icon" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the icon of the feed which is a small image which
provides iconic visual identification for the feed. Icons should be
square. This is an ATOM only value.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>icon</strong> URI of the feeds icon.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">URI of the feeds icon.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.id">
<code class="descname">id</code><span class="sig-paren">(</span><em>id=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.id" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the feed id which identifies the feed using a universally
unique and permanent URI. If you have a long-term, renewable lease on
your Internet domain name, then you can feel free to use your websites
address. This field is for ATOM only. It is mandatory for ATOM.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>id</strong> New Id of the ATOM feed.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Id of the feed.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.image">
<code class="descname">image</code><span class="sig-paren">(</span><em>url=None</em>, <em>title=None</em>, <em>link=None</em>, <em>width=None</em>, <em>height=None</em>, <em>description=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.image" title="Permalink to this definition"></a></dt>
<dd><p>Set the image of the feed. This element is roughly equivalent to
atom:logo.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>url</strong> The URL of a GIF, JPEG or PNG image.</li>
<li><strong>title</strong> Describes the image. The default value is the feeds
title.</li>
<li><strong>link</strong> URL of the site the image will link to. The default is to
use the feeds first altertate link.</li>
<li><strong>width</strong> Width of the image in pixel. The maximum is 144.</li>
<li><strong>height</strong> The height of the image. The maximum is 400.</li>
<li><strong>description</strong> Title of the link.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Data of the image as dictionary.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.item">
<code class="descname">item</code><span class="sig-paren">(</span><em>item=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.item" title="Permalink to this definition"></a></dt>
<dd><p>Get or set feed items. This is just another name for entry(…)</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.language">
<code class="descname">language</code><span class="sig-paren">(</span><em>language=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.language" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the language of the feed. It indicates the language the
channel is written in. This allows aggregators to group all Italian
language sites, for example, on a single page. This is an RSS only
field. However, this value will also be used to set the xml:lang
property of the ATOM feed node.
The value should be an IETF language tag.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>language</strong> Language of the feed.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Language of the feed.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.lastBuildDate">
<code class="descname">lastBuildDate</code><span class="sig-paren">(</span><em>lastBuildDate=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.lastBuildDate" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the lastBuildDate value which indicates the last time the
content of the channel changed.</p>
<p>The value can either be a string which will automatically be parsed or
a datetime.datetime object. In any case it is necessary that the value
include timezone information.</p>
<p>This will set both atom:updated and rss:lastBuildDate.</p>
<dl class="docutils">
<dt>Default value</dt>
<dd>If not set, lastBuildDate has as value the current date and time.</dd>
</dl>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>lastBuildDate</strong> The modification date.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Modification date as datetime.datetime</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.link">
<code class="descname">link</code><span class="sig-paren">(</span><em>link=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.link" title="Permalink to this definition"></a></dt>
<dd><p>Get or set link data. An link element is a dict with the fields
href, rel, type, hreflang, title, and length. Href is mandatory for
ATOM.</p>
<p>This method can be called with:</p>
<ul class="simple">
<li>the fields of a link as keyword arguments</li>
<li>the fields of a link as a dictionary</li>
<li>a list of dictionaries containing the link fields</li>
</ul>
<p>A link has the following fields:</p>
<ul>
<li><p class="first"><em>href</em> is the URI of the referenced resource (typically a Web page)</p>
</li>
<li><p class="first"><em>rel</em> contains a single link relationship type. It can be a full URI,
or one of the following predefined values (default=alternate):</p>
<blockquote>
<div><ul class="simple">
<li><em>alternate</em> an alternate representation of the entry or feed, for
example a permalink to the html version of the entry, or the
front page of the weblog.</li>
<li><em>enclosure</em> a related resource which is potentially large in size
and might require special handling, for example an audio or video
recording.</li>
<li><em>related</em> an document related to the entry or feed.</li>
<li><em>self</em> the feed itself.</li>
<li><em>via</em> the source of the information provided in the entry.</li>
</ul>
</div></blockquote>
</li>
<li><p class="first"><em>type</em> indicates the media type of the resource.</p>
</li>
<li><p class="first"><em>hreflang</em> indicates the language of the referenced resource.</p>
</li>
<li><p class="first"><em>title</em> human readable information about the link, typically for
display purposes.</p>
</li>
<li><p class="first"><em>length</em> the length of the resource, in bytes.</p>
</li>
</ul>
<p>RSS only supports one link with URL only.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>link</strong> Dict or list of dicts with data.</li>
<li><strong>replace</strong> If old links are to be replaced (default: False)</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Current set of link data</p>
</td>
</tr>
</tbody>
</table>
<p>Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">feedgen</span><span class="o">.</span><span class="n">link</span><span class="p">(</span> <span class="n">href</span><span class="o">=</span><span class="s1">&#39;http://example.com/&#39;</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="s1">&#39;self&#39;</span><span class="p">)</span>
<span class="go">[{&#39;href&#39;:&#39;http://example.com/&#39;, &#39;rel&#39;:&#39;self&#39;}]</span>
</pre></div>
</div>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.load_extension">
<code class="descname">load_extension</code><span class="sig-paren">(</span><em>name</em>, <em>atom=True</em>, <em>rss=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.load_extension" title="Permalink to this definition"></a></dt>
<dd><p>Load a specific extension by name.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>name</strong> Name of the extension to load.</li>
<li><strong>atom</strong> If the extension should be used for ATOM feeds.</li>
<li><strong>rss</strong> If the extension should be used for RSS feeds.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.logo">
<code class="descname">logo</code><span class="sig-paren">(</span><em>logo=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.logo" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the logo of the feed which is a larger image which
provides visual identification for the feed. Images should be twice as
wide as they are tall. This is an ATOM value but will also set the
rss:image value.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>logo</strong> Logo of the feed.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Logo of the feed.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.managingEditor">
<code class="descname">managingEditor</code><span class="sig-paren">(</span><em>managingEditor=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.managingEditor" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the value for managingEditor which is the email address
for person responsible for editorial content. This is a RSS only
value.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>managingEditor</strong> Email address of the managing editor.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Email address of the managing editor.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.pubDate">
<code class="descname">pubDate</code><span class="sig-paren">(</span><em>pubDate=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.pubDate" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the publication date for the content in the channel. For
example, the New York Times publishes on a daily basis, the publication
date flips once every 24 hours. Thats when the pubDate of the channel
changes.</p>
<p>The value can either be a string which will automatically be parsed or
a datetime.datetime object. In any case it is necessary that the value
include timezone information.</p>
<p>This will set both atom:updated and rss:lastBuildDate.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>pubDate</strong> The publication date.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Publication date as datetime.datetime</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.rating">
<code class="descname">rating</code><span class="sig-paren">(</span><em>rating=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.rating" title="Permalink to this definition"></a></dt>
<dd><p>Set and get the PICS rating for the channel. It is an RSS only
value.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.register_extension">
<code class="descname">register_extension</code><span class="sig-paren">(</span><em>namespace</em>, <em>extension_class_feed=None</em>, <em>extension_class_entry=None</em>, <em>atom=True</em>, <em>rss=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.register_extension" title="Permalink to this definition"></a></dt>
<dd><p>Registers an extension by class.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>namespace</strong> namespace for the extension</li>
<li><strong>extension_class_feed</strong> Class of the feed extension to load.</li>
<li><strong>extension_class_entry</strong> Class of the entry extension to load</li>
<li><strong>atom</strong> If the extension should be used for ATOM feeds.</li>
<li><strong>rss</strong> If the extension should be used for RSS feeds.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.remove_entry">
<code class="descname">remove_entry</code><span class="sig-paren">(</span><em>entry</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.remove_entry" title="Permalink to this definition"></a></dt>
<dd><p>Remove a single entry from the feed. This method accepts both the
FeedEntry object to remove or the index of the entry as argument.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>entry</strong> Entry or index of entry to remove.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.remove_item">
<code class="descname">remove_item</code><span class="sig-paren">(</span><em>item</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.remove_item" title="Permalink to this definition"></a></dt>
<dd><p>Remove a single item from the feed. This is another name for
remove_entry.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.rights">
<code class="descname">rights</code><span class="sig-paren">(</span><em>rights=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.rights" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the rights value of the feed which conveys information
about rights, e.g. copyrights, held in and over the feed. This ATOM
value will also set rss:copyright.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>rights</strong> Rights information of the feed.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.rss_file">
<code class="descname">rss_file</code><span class="sig-paren">(</span><em>filename</em>, <em>extensions=True</em>, <em>pretty=False</em>, <em>encoding='UTF-8'</em>, <em>xml_declaration=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.rss_file" title="Permalink to this definition"></a></dt>
<dd><p>Generates an RSS feed and write the resulting XML to a file.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>filename</strong> Name of file to write or a file-like object or a URL.</li>
<li><strong>extensions</strong> Enable or disable the loaded extensions for the xml
generation (default: enabled).</li>
<li><strong>pretty</strong> If the feed should be split into multiple lines and
properly indented.</li>
<li><strong>encoding</strong> Encoding used in the XML file (default: UTF-8).</li>
<li><strong>xml_declaration</strong> If an XML declaration should be added to the
output (Default: enabled).</li>
</ul>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.rss_str">
<code class="descname">rss_str</code><span class="sig-paren">(</span><em>pretty=False</em>, <em>extensions=True</em>, <em>encoding='UTF-8'</em>, <em>xml_declaration=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.rss_str" title="Permalink to this definition"></a></dt>
<dd><p>Generates an RSS feed and returns the feed XML as string.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>pretty</strong> If the feed should be split into multiple lines and
properly indented.</li>
<li><strong>extensions</strong> Enable or disable the loaded extensions for the xml
generation (default: enabled).</li>
<li><strong>encoding</strong> Encoding used in the XML file (default: UTF-8).</li>
<li><strong>xml_declaration</strong> If an XML declaration should be added to the
output (Default: enabled).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">String representation of the RSS feed.</p>
</td>
</tr>
</tbody>
</table>
<p><strong>Return type:</strong> The return type may vary between different Python
versions and your encoding parameters passed to this method. For
details have a look at the <a class="reference external" href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.tostring">lxml documentation</a></p>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.skipDays">
<code class="descname">skipDays</code><span class="sig-paren">(</span><em>days=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.skipDays" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the value of skipDays, a hint for aggregators telling
them which days they can skip This is an RSS only value.</p>
<p>This method can be called with a day name or a list of day names. The
days are represented as strings from Monday to Sunday.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>hours</strong> List of days the feedreaders should not check the feed.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of days the feedreaders should not check the feed.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.skipHours">
<code class="descname">skipHours</code><span class="sig-paren">(</span><em>hours=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.skipHours" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the value of skipHours, a hint for aggregators telling
them which hours they can skip. This is an RSS only value.</p>
<p>This method can be called with an hour or a list of hours. The hours
are represented as integer values from 0 to 23.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>hours</strong> List of hours the feedreaders should not check the feed.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of hours the feedreaders should not check the feed.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.subtitle">
<code class="descname">subtitle</code><span class="sig-paren">(</span><em>subtitle=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.subtitle" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the subtitle value of the cannel which contains a
human-readable description or subtitle for the feed. This ATOM property
will also set the value for rss:description.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>subtitle</strong> The subtitle of the feed.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The subtitle of the feed.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.textInput">
<code class="descname">textInput</code><span class="sig-paren">(</span><em>title=None</em>, <em>description=None</em>, <em>name=None</em>, <em>link=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.textInput" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the value of textInput. This is an RSS only field. The
purpose of the &lt;textInput&gt; element is something of a mystery. You can
use it to specify a search engine box. Or to allow a reader to provide
feedback. Most aggregators ignore it.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>title</strong> The label of the Submit button in the text input area.</li>
<li><strong>description</strong> Explains the text input area.</li>
<li><strong>name</strong> The name of the text object in the text input area.</li>
<li><strong>link</strong> The URL of the CGI script that processes text input
requests.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Dictionary containing textInput values.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.title">
<code class="descname">title</code><span class="sig-paren">(</span><em>title=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.title" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the title value of the feed. It should contain a human
readable title for the feed. Often the same as the title of the
associated website. Title is mandatory for both ATOM and RSS and should
not be blank.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>title</strong> The new title of the feed.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The feeds title.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.ttl">
<code class="descname">ttl</code><span class="sig-paren">(</span><em>ttl=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.ttl" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the ttl value. It is an RSS only element. ttl stands for
time to live. Its a number of minutes that indicates how long a
channel can be cached before refreshing from the source.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>ttl</strong> Integer value indicating how long the channel may be
cached.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Time to live.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.updated">
<code class="descname">updated</code><span class="sig-paren">(</span><em>updated=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.updated" title="Permalink to this definition"></a></dt>
<dd><p>Set or get the updated value which indicates the last time the feed
was modified in a significant way.</p>
<p>The value can either be a string which will automatically be parsed or
a datetime.datetime object. In any case it is necessary that the value
include timezone information.</p>
<p>This will set both atom:updated and rss:lastBuildDate.</p>
<dl class="docutils">
<dt>Default value</dt>
<dd>If not set, updated has as value the current date and time.</dd>
</dl>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>updated</strong> The modification date.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Modification date as datetime.datetime</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.feed.FeedGenerator.webMaster">
<code class="descname">webMaster</code><span class="sig-paren">(</span><em>webMaster=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.feed.FeedGenerator.webMaster" title="Permalink to this definition"></a></dt>
<dd><p>Get and set the value of webMaster, which represents the email
address for the person responsible for technical issues relating to the
feed. This is an RSS only value.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>webMaster</strong> Email address of the webmaster.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Email address of the webmaster.</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="api.html">API Documentation</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.entry.html">feedgen.entry</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

200
api.html Normal file
View file

@ -0,0 +1,200 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>API Documentation &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="feedgen.feed" href="api.feed.html" />
<link rel="prev" title="Feedgenerator" href="index.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>API Documentation</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="index.html">Feedgenerator</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.feed.html">feedgen.feed</a>&#160;&#160;»
</p>
</div>
<div class="content">
<div class="section" id="module-feedgen">
<span id="api-documentation"></span><h1>API Documentation<a class="headerlink" href="#module-feedgen" title="Permalink to this headline"></a></h1>
<div class="section" id="feedgen">
<h2>feedgen<a class="headerlink" href="#feedgen" title="Permalink to this headline"></a></h2>
<p>This module can be used to generate web feeds in both ATOM and RSS format.
It has support for extensions. Included is for example an extension to
produce Podcasts.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013 by Lars Kiesow</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<div class="section" id="create-a-feed">
<h3>Create a Feed<a class="headerlink" href="#create-a-feed" title="Permalink to this headline"></a></h3>
<p>To create a feed simply instantiate the FeedGenerator class and insert some
data:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">feedgen.feed</span> <span class="k">import</span> <span class="n">FeedGenerator</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span> <span class="o">=</span> <span class="n">FeedGenerator</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">id</span><span class="p">(</span><span class="s1">&#39;http://lernfunk.de/media/654321&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">&#39;Some Testfeed&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">author</span><span class="p">(</span> <span class="p">{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span><span class="s1">&#39;email&#39;</span><span class="p">:</span><span class="s1">&#39;john@example.de&#39;</span><span class="p">}</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">link</span><span class="p">(</span> <span class="n">href</span><span class="o">=</span><span class="s1">&#39;http://example.com&#39;</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="s1">&#39;alternate&#39;</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">logo</span><span class="p">(</span><span class="s1">&#39;http://ex.com/logo.jpg&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">subtitle</span><span class="p">(</span><span class="s1">&#39;This is a cool feed!&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">link</span><span class="p">(</span> <span class="n">href</span><span class="o">=</span><span class="s1">&#39;http://larskiesow.de/test.atom&#39;</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="s1">&#39;self&#39;</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">language</span><span class="p">(</span><span class="s1">&#39;en&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>Note that for the methods which set fields that can occur more than once in
a feed you can use all of the following ways to provide data:</p>
<ul class="simple">
<li>Provide the data for that element as keyword arguments</li>
<li>Provide the data for that element as dictionary</li>
<li>Provide a list of dictionaries with the data for several elements</li>
</ul>
<p>Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&gt;&gt;&gt; fg.contributor(name=&#39;John Doe&#39;, email=&#39;jdoe@example.com&#39; )
&gt;&gt;&gt; fg.contributor({&#39;name&#39;:&#39;John Doe&#39;, &#39;email&#39;:&#39;jdoe@example.com&#39;})
&gt;&gt;&gt; fg.contributor([{&#39;name&#39;:&#39;John&#39;, &#39;email&#39;:&#39;jdoe@example.com&#39;}, …])
</pre></div>
</div>
</div>
<div class="section" id="generate-the-feed">
<h3>Generate the Feed<a class="headerlink" href="#generate-the-feed" title="Permalink to this headline"></a></h3>
<p>After that you can generate both RSS or ATOM by calling the respective
method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">atomfeed</span> <span class="o">=</span> <span class="n">fg</span><span class="o">.</span><span class="n">atom_str</span><span class="p">(</span><span class="n">pretty</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># Get the ATOM feed as string</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">rssfeed</span> <span class="o">=</span> <span class="n">fg</span><span class="o">.</span><span class="n">rss_str</span><span class="p">(</span><span class="n">pretty</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># Get the RSS feed as string</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">atom_file</span><span class="p">(</span><span class="s1">&#39;atom.xml&#39;</span><span class="p">)</span> <span class="c1"># Write the ATOM feed to a file</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">rss_file</span><span class="p">(</span><span class="s1">&#39;rss.xml&#39;</span><span class="p">)</span> <span class="c1"># Write the RSS feed to a file</span>
</pre></div>
</div>
</div>
<div class="section" id="add-feed-entries">
<h3>Add Feed Entries<a class="headerlink" href="#add-feed-entries" title="Permalink to this headline"></a></h3>
<p>To add entries (items) to a feed you need to create new FeedEntry objects
and append them to the list of entries in the FeedGenerator. The most
convenient way to go is to use the FeedGenerator itself for the
instantiation of the FeedEntry object:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span> <span class="o">=</span> <span class="n">fg</span><span class="o">.</span><span class="n">add_entry</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">id</span><span class="p">(</span><span class="s1">&#39;http://lernfunk.de/media/654321/1&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">&#39;The First Episode&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>The FeedGenerators method add_entry(…) without argument provides will
automatically generate a new FeedEntry object, append it to the feeds
internal list of entries and return it, so that additional data can be
added.</p>
</div>
<div class="section" id="extensions">
<h3>Extensions<a class="headerlink" href="#extensions" title="Permalink to this headline"></a></h3>
<p>The FeedGenerator supports extension to include additional data into the
XML structure of the feeds. Extensions can be loaded like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">load_extension</span><span class="p">(</span><span class="s1">&#39;someext&#39;</span><span class="p">,</span> <span class="n">atom</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">rss</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>This will try to load the extension “someext” from the file
<cite>ext/someext.py</cite>. It is required that <cite>someext.py</cite> contains a class named
“SomextExtension” which is required to have at least the two methods
<cite>extend_rss(…)</cite> and <cite>extend_atom(…)</cite>. Although not required, it is
strongly suggested to use BaseExtension from <cite>ext/base.py</cite> as superclass.</p>
<p><cite>load_extension(someext, …)</cite> will also try to load a class named
“SomextEntryExtension” for every entry of the feed. This class can be
located either in the same file as SomextExtension or in
<cite>ext/someext_entry.py</cite> which is suggested especially for large extensions.</p>
<p>The parameters <cite>atom</cite> and <cite>rss</cite> tell the FeedGenerator if the extensions
should only be used for either ATOM or RSS feeds. The default value for
both parameters is true which means that the extension would be used for
both kinds of feeds.</p>
<p><strong>Example: Producing a Podcast</strong></p>
<p>One extension already provided is the podcast extension. A podcast is an
RSS feed with some additional elements for ITunes.</p>
<p>To produce a podcast simply load the <cite>podcast</cite> extension:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">feedgen.feed</span> <span class="k">import</span> <span class="n">FeedGenerator</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span> <span class="o">=</span> <span class="n">FeedGenerator</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">load_extension</span><span class="p">(</span><span class="s1">&#39;podcast&#39;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">podcast</span><span class="o">.</span><span class="n">itunes_category</span><span class="p">(</span><span class="s1">&#39;Technology&#39;</span><span class="p">,</span> <span class="s1">&#39;Podcasting&#39;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">rss_str</span><span class="p">(</span><span class="n">pretty</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">rss_file</span><span class="p">(</span><span class="s1">&#39;podcast.xml&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>Of cause the extension has to be loaded for the FeedEntry objects as well
but this is done automatically by the FeedGenerator for every feed entry if
the extension is loaded for the whole feed. You can, however, load an
extension for a specific FeedEntry by calling <cite>load_extension(…)</cite> on that
entry. But this is a rather uncommon use.</p>
<p>Of cause you can still produce a normal ATOM or RSS feed, even if you have
loaded some plugins by temporary disabling them during the feed generation.
This can be done by calling the generating method with the keyword argument
<cite>extensions</cite> set to <cite>False</cite>.</p>
</div>
<div class="section" id="testing-the-generator">
<h3>Testing the Generator<a class="headerlink" href="#testing-the-generator" title="Permalink to this headline"></a></h3>
<p>You can test the module by simply executing:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ python -m feedgen
</pre></div>
</div>
</div>
</div>
<p>Contents:</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="api.feed.html">feedgen.feed</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.entry.html">feedgen.entry</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.util.html">feedgen.util</a></li>
<li class="toctree-l1"><a class="reference internal" href="ext/api.ext.base.html">feedgen.ext.base</a></li>
<li class="toctree-l1"><a class="reference internal" href="ext/api.ext.dc.html">feedgen.ext.dc</a></li>
<li class="toctree-l1"><a class="reference internal" href="ext/api.ext.podcast.html">feedgen.ext.podcast</a></li>
<li class="toctree-l1"><a class="reference internal" href="ext/api.ext.podcast_entry.html">feedgen.ext.podcast_entry</a></li>
<li class="toctree-l1"><a class="reference internal" href="ext/api.ext.torrent.html">feedgen.ext.torrent</a></li>
</ul>
</div>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="index.html">Feedgenerator</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.feed.html">feedgen.feed</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

109
api.util.html Normal file
View file

@ -0,0 +1,109 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.util &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="feedgen.ext.base" href="ext/api.ext.base.html" />
<link rel="prev" title="feedgen.entry" href="api.entry.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.util</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="api.entry.html">feedgen.entry</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="ext/api.ext.base.html">feedgen.ext.base</a>&#160;&#160;»
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.util"></span><div class="section" id="feedgen-util">
<h1>feedgen.util<a class="headerlink" href="#feedgen-util" title="Permalink to this headline"></a></h1>
<p>This file contains helper functions for the feed generator module.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013, Lars Kiesow &lt;<a class="reference external" href="mailto:lkiesow&#37;&#52;&#48;uos&#46;de">lkiesow<span>&#64;</span>uos<span>&#46;</span>de</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="function">
<dt id="feedgen.util.ensure_format">
<code class="descclassname">feedgen.util.</code><code class="descname">ensure_format</code><span class="sig-paren">(</span><em>val</em>, <em>allowed</em>, <em>required</em>, <em>allowed_values=None</em>, <em>defaults=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.util.ensure_format" title="Permalink to this definition"></a></dt>
<dd><p>Takes a dictionary or a list of dictionaries and check if all keys are in
the set of allowed keys, if all required keys are present and if the values
of a specific key are ok.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>val</strong> Dictionaries to check.</li>
<li><strong>allowed</strong> Set of allowed keys.</li>
<li><strong>required</strong> Set of required keys.</li>
<li><strong>allowed_values</strong> Dictionary with keys and sets of their allowed
values.</li>
<li><strong>defaults</strong> Dictionary with default values.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of checked dictionaries.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="function">
<dt id="feedgen.util.formatRFC2822">
<code class="descclassname">feedgen.util.</code><code class="descname">formatRFC2822</code><span class="sig-paren">(</span><em>date</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.util.formatRFC2822" title="Permalink to this definition"></a></dt>
<dd><p>Make sure the locale setting do not interfere with the time format.</p>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="api.entry.html">feedgen.entry</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="ext/api.ext.base.html">feedgen.ext.base</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

View file

@ -1,155 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
#SPHINXBUILD = python /home/lars/master-thesis/code/modules/core/venv/bin/sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
@echo 'Cleaning build directory'
@rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Lernfunk3.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Lernfunk3.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Lernfunk3"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Lernfunk3"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.entry
:members:

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.feed
:members:

View file

@ -1,20 +0,0 @@
=================
API Documentation
=================
.. automodule:: feedgen
:members:
Contents:
.. toctree::
:maxdepth: 2
api.feed
api.entry
api.util
ext/api.ext.base
ext/api.ext.dc
ext/api.ext.podcast
ext/api.ext.podcast_entry
ext/api.ext.torrent

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.util
:members:

View file

@ -1,269 +0,0 @@
# -*- coding: utf-8 -*-
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import codecs
import re
# 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.
sys.path.insert(0, os.path.abspath('../'))
sys.path.insert(0, os.path.abspath('.'))
import feedgen.version
# -- 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.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.autodoc'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'python-feedgen'
copyright = u'2013-2016, Lars Kiesow'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = feedgen.version.version_minor_str
# The full version, including alpha/beta/rc tags.
release = feedgen.version.version_full_str
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- 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 = 'default'
html_theme = 'haiku'
html_style = 'lernfunk.css'
# 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 themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = '_static/logo.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# 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']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'pyFeedGen'
# -- 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': '',
}
# Grouping the document tree into LaTeX files. List of tuples (source start
# file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'pyFeedGen.tex', u'pyFeedGen Documentation', u'Lars Kiesow',
'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output -------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'pyFeedGen.tex', u'pyFeedGen Documentation',
[u'Lars Kiesow'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- 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 = [
('index', 'pyFeedGen.tex', u'pyFeedGen Documentation',
u'Lars Kiesow', 'Lernfunk3', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}
# Include the GitHub readme file in index.rst
r = re.compile(r'\[`*([^\]`]+)`*\]\(([^\)]+)\)')
r2 = re.compile(r'.. include-github-readme')
def substitute_link(app, docname, text):
if docname == 'index':
readme_text = ''
with codecs.open(os.path.abspath('../readme.rst'), 'r', 'utf-8') as f:
readme_text = r.sub(r'`\1 <\2>`_', f.read())
text[0] = r2.sub(readme_text, text[0])
def setup(app):
app.connect('source-read', substitute_link)

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.ext.base
:members:

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.ext.dc
:members:

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.ext.podcast
:members:

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.ext.podcast_entry
:members:

View file

@ -1,8 +0,0 @@
.. raw:: html
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div>
.. automodule:: feedgen.ext.torrent
:members:

View file

@ -1,25 +0,0 @@
.. contents:: Table of Contents
.. include-github-readme
.. raw:: html
<hr />
====================
Module documentation
====================
.. toctree::
:maxdepth: 2
api
==================
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

128
ext/api.ext.base.html Normal file
View file

@ -0,0 +1,128 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.ext.base &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="../_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="../_static/language_data.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="feedgen.ext.dc" href="api.ext.dc.html" />
<link rel="prev" title="feedgen.util" href="../api.util.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="../index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.ext.base</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="../api.util.html">feedgen.util</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.dc.html">feedgen.ext.dc</a>&#160;&#160;»
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.ext.base"></span><div class="section" id="feedgen-ext-base">
<h1>feedgen.ext.base<a class="headerlink" href="#feedgen-ext-base" title="Permalink to this headline"></a></h1>
<p>Basic FeedGenerator extension which does nothing but provides all necessary
methods.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013, Lars Kiesow &lt;<a class="reference external" href="mailto:lkiesow&#37;&#52;&#48;uos&#46;de">lkiesow<span>&#64;</span>uos<span>&#46;</span>de</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="class">
<dt id="feedgen.ext.base.BaseEntryExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.base.</code><code class="descname">BaseEntryExtension</code><a class="headerlink" href="#feedgen.ext.base.BaseEntryExtension" title="Permalink to this definition"></a></dt>
<dd><p>Basic FeedEntry extension.</p>
</dd></dl>
<dl class="class">
<dt id="feedgen.ext.base.BaseExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.base.</code><code class="descname">BaseExtension</code><a class="headerlink" href="#feedgen.ext.base.BaseExtension" title="Permalink to this definition"></a></dt>
<dd><p>Basic FeedGenerator extension.</p>
<dl class="method">
<dt id="feedgen.ext.base.BaseExtension.extend_atom">
<code class="descname">extend_atom</code><span class="sig-paren">(</span><em>feed</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.base.BaseExtension.extend_atom" title="Permalink to this definition"></a></dt>
<dd><p>Extend an ATOM feed xml structure containing all previously set
fields.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>feed</strong> The feed xml root element.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The feed root element.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.base.BaseExtension.extend_ns">
<code class="descname">extend_ns</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.base.BaseExtension.extend_ns" title="Permalink to this definition"></a></dt>
<dd><p>Returns a dict that will be used in the namespace map for the feed.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.base.BaseExtension.extend_rss">
<code class="descname">extend_rss</code><span class="sig-paren">(</span><em>feed</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.base.BaseExtension.extend_rss" title="Permalink to this definition"></a></dt>
<dd><p>Extend a RSS feed xml structure containing all previously set fields.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>feed</strong> The feed xml root element.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The feed root element.</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="../api.util.html">feedgen.util</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.dc.html">feedgen.ext.dc</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

535
ext/api.ext.dc.html Normal file
View file

@ -0,0 +1,535 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.ext.dc &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="../_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="../_static/language_data.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="feedgen.ext.podcast" href="api.ext.podcast.html" />
<link rel="prev" title="feedgen.ext.base" href="api.ext.base.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="../index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.ext.dc</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="api.ext.base.html">feedgen.ext.base</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.podcast.html">feedgen.ext.podcast</a>&#160;&#160;»
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.ext.dc"></span><div class="section" id="feedgen-ext-dc">
<h1>feedgen.ext.dc<a class="headerlink" href="#feedgen-ext-dc" title="Permalink to this headline"></a></h1>
<p>Extends the FeedGenerator to add Dubline Core Elements to the feeds.</p>
<p>Descriptions partly taken from
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-coverage">http://dublincore.org/documents/dcmi-terms/#elements-coverage</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013-2017, Lars Kiesow &lt;<a class="reference external" href="mailto:lkiesow&#37;&#52;&#48;uos&#46;de">lkiesow<span>&#64;</span>uos<span>&#46;</span>de</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="class">
<dt id="feedgen.ext.dc.DcBaseExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.dc.</code><code class="descname">DcBaseExtension</code><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension" title="Permalink to this definition"></a></dt>
<dd><p>Dublin Core Elements extension for podcasts.</p>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_contributor">
<code class="descname">dc_contributor</code><span class="sig-paren">(</span><em>contributor=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_contributor" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:contributor which is an entity responsible for
making contributions to the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-contributor">http://dublincore.org/documents/dcmi-terms/#elements-contributor</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>contributor</strong> Contributor or list of contributors.</li>
<li><strong>replace</strong> Replace alredy set contributors (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of contributors.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_coverage">
<code class="descname">dc_coverage</code><span class="sig-paren">(</span><em>coverage=None</em>, <em>replace=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_coverage" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:coverage which indicated the spatial or temporal
topic of the resource, the spatial applicability of the resource, or
the jurisdiction under which the resource is relevant.</p>
<p>Spatial topic and spatial applicability may be a named place or a
location specified by its geographic coordinates. Temporal topic may be
a named period, date, or date range. A jurisdiction may be a named
administrative entity or a geographic place to which the resource
applies. Recommended best practice is to use a controlled vocabulary
such as the Thesaurus of Geographic Names [TGN]. Where appropriate,
named places or time periods can be used in preference to numeric
identifiers such as sets of coordinates or date ranges.</p>
<p>References:
[TGN] <a class="reference external" href="http://www.getty.edu/research/tools/vocabulary/tgn/index.html">http://www.getty.edu/research/tools/vocabulary/tgn/index.html</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>coverage</strong> Coverage of the feed.</li>
<li><strong>replace</strong> Replace already set coverage (default: True).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Coverage of the feed.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_creator">
<code class="descname">dc_creator</code><span class="sig-paren">(</span><em>creator=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_creator" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:creator which is an entity primarily responsible
for making the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-creator">http://dublincore.org/documents/dcmi-terms/#elements-creator</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>creator</strong> Creator or list of creators.</li>
<li><strong>replace</strong> Replace alredy set creators (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of creators.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_date">
<code class="descname">dc_date</code><span class="sig-paren">(</span><em>date=None</em>, <em>replace=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_date" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:date which describes a point or period of time
associated with an event in the lifecycle of the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-date">http://dublincore.org/documents/dcmi-terms/#elements-date</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>date</strong> Date or list of dates.</li>
<li><strong>replace</strong> Replace alredy set dates (deault: True).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of dates.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_description">
<code class="descname">dc_description</code><span class="sig-paren">(</span><em>description=None</em>, <em>replace=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_description" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:description which is an account of the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-description">http://dublincore.org/documents/dcmi-terms/#elements-description</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>description</strong> Description or list of descriptions.</li>
<li><strong>replace</strong> Replace alredy set descriptions (deault: True).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of descriptions.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_format">
<code class="descname">dc_format</code><span class="sig-paren">(</span><em>format=None</em>, <em>replace=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_format" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:format which describes the file format, physical
medium, or dimensions of the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-format">http://dublincore.org/documents/dcmi-terms/#elements-format</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>format</strong> Format of the resource or list of formats.</li>
<li><strong>replace</strong> Replace alredy set format (deault: True).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Format of the resource.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_identifier">
<code class="descname">dc_identifier</code><span class="sig-paren">(</span><em>identifier=None</em>, <em>replace=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_identifier" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:identifier which should be an unambiguous
reference to the resource within a given context.</p>
<p>For more inidentifierion see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-identifier">http://dublincore.org/documents/dcmi-terms/#elements-identifier</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>identifier</strong> Identifier of the resource or list of identifiers.</li>
<li><strong>replace</strong> Replace alredy set identifier (deault: True).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">Identifiers of the resource.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_language">
<code class="descname">dc_language</code><span class="sig-paren">(</span><em>language=None</em>, <em>replace=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_language" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:language which describes a language of the
resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-language">http://dublincore.org/documents/dcmi-terms/#elements-language</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>language</strong> Language or list of languages.</li>
<li><strong>replace</strong> Replace alredy set languages (deault: True).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of languages.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_publisher">
<code class="descname">dc_publisher</code><span class="sig-paren">(</span><em>publisher=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_publisher" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:publisher which is an entity responsible for
making the resource available.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-publisher">http://dublincore.org/documents/dcmi-terms/#elements-publisher</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>publisher</strong> Publisher or list of publishers.</li>
<li><strong>replace</strong> Replace alredy set publishers (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of publishers.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_relation">
<code class="descname">dc_relation</code><span class="sig-paren">(</span><em>relation=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_relation" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:relation which describes a related resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-relation">http://dublincore.org/documents/dcmi-terms/#elements-relation</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>relation</strong> Relation or list of relations.</li>
<li><strong>replace</strong> Replace alredy set relations (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of relations.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_rights">
<code class="descname">dc_rights</code><span class="sig-paren">(</span><em>rights=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_rights" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:rights which may contain information about rights
held in and over the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-rights">http://dublincore.org/documents/dcmi-terms/#elements-rights</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>rights</strong> Rights information or list of rights information.</li>
<li><strong>replace</strong> Replace alredy set rightss (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of rights information.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_source">
<code class="descname">dc_source</code><span class="sig-paren">(</span><em>source=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_source" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:source which is a related resource from which the
described resource is derived.</p>
<p>The described resource may be derived from the related resource in
whole or in part. Recommended best practice is to identify the related
resource by means of a string conforming to a formal identification
system.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-source">http://dublincore.org/documents/dcmi-terms/#elements-source</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>source</strong> Source or list of sources.</li>
<li><strong>replace</strong> Replace alredy set sources (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of sources.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_subject">
<code class="descname">dc_subject</code><span class="sig-paren">(</span><em>subject=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_subject" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:subject which describes the topic of the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-subject">http://dublincore.org/documents/dcmi-terms/#elements-subject</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>subject</strong> Subject or list of subjects.</li>
<li><strong>replace</strong> Replace alredy set subjects (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of subjects.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_title">
<code class="descname">dc_title</code><span class="sig-paren">(</span><em>title=None</em>, <em>replace=True</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_title" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:title which is a name given to the resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-title">http://dublincore.org/documents/dcmi-terms/#elements-title</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>title</strong> Title or list of titles.</li>
<li><strong>replace</strong> Replace alredy set titles (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of titles.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.dc_type">
<code class="descname">dc_type</code><span class="sig-paren">(</span><em>type=None</em>, <em>replace=False</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.dc_type" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the dc:type which describes the nature or genre of the
resource.</p>
<p>For more information see:
<a class="reference external" href="http://dublincore.org/documents/dcmi-terms/#elements-type">http://dublincore.org/documents/dcmi-terms/#elements-type</a></p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>type</strong> Type or list of types.</li>
<li><strong>replace</strong> Replace alredy set types (deault: False).</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of types.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.extend_atom">
<code class="descname">extend_atom</code><span class="sig-paren">(</span><em>atom_feed</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.extend_atom" title="Permalink to this definition"></a></dt>
<dd><p>Extend an Atom feed with the set DC fields.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>atom_feed</strong> The feed root element</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The feed root element</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.extend_ns">
<code class="descname">extend_ns</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.extend_ns" title="Permalink to this definition"></a></dt>
<dd><p>Returns a dict that will be used in the namespace map for the feed.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcBaseExtension.extend_rss">
<code class="descname">extend_rss</code><span class="sig-paren">(</span><em>rss_feed</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcBaseExtension.extend_rss" title="Permalink to this definition"></a></dt>
<dd><p>Extend a RSS feed with the set DC fields.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>rss_feed</strong> The feed root element</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The feed root element.</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="feedgen.ext.dc.DcEntryExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.dc.</code><code class="descname">DcEntryExtension</code><a class="headerlink" href="#feedgen.ext.dc.DcEntryExtension" title="Permalink to this definition"></a></dt>
<dd><p>Dublin Core Elements extension for podcasts.</p>
<dl class="method">
<dt id="feedgen.ext.dc.DcEntryExtension.extend_atom">
<code class="descname">extend_atom</code><span class="sig-paren">(</span><em>entry</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcEntryExtension.extend_atom" title="Permalink to this definition"></a></dt>
<dd><p>Add dc elements to an atom item. Alters the item itself.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>entry</strong> An atom entry element.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The entry element.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.dc.DcEntryExtension.extend_rss">
<code class="descname">extend_rss</code><span class="sig-paren">(</span><em>item</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.dc.DcEntryExtension.extend_rss" title="Permalink to this definition"></a></dt>
<dd><p>Add dc elements to a RSS item. Alters the item itself.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>item</strong> A RSS item element.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The item element.</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="feedgen.ext.dc.DcExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.dc.</code><code class="descname">DcExtension</code><a class="headerlink" href="#feedgen.ext.dc.DcExtension" title="Permalink to this definition"></a></dt>
<dd><p>Dublin Core Elements extension for podcasts.</p>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="api.ext.base.html">feedgen.ext.base</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.podcast.html">feedgen.ext.podcast</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

347
ext/api.ext.podcast.html Normal file
View file

@ -0,0 +1,347 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.ext.podcast &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="../_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="../_static/language_data.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="feedgen.ext.podcast_entry" href="api.ext.podcast_entry.html" />
<link rel="prev" title="feedgen.ext.dc" href="api.ext.dc.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="../index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.ext.podcast</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="api.ext.dc.html">feedgen.ext.dc</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.podcast_entry.html">feedgen.ext.podcast_entry</a>&#160;&#160;»
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.ext.podcast"></span><div class="section" id="feedgen-ext-podcast">
<h1>feedgen.ext.podcast<a class="headerlink" href="#feedgen-ext-podcast" title="Permalink to this headline"></a></h1>
<p>Extends the FeedGenerator to produce podcasts.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013, Lars Kiesow &lt;<a class="reference external" href="mailto:lkiesow&#37;&#52;&#48;uos&#46;de">lkiesow<span>&#64;</span>uos<span>&#46;</span>de</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="class">
<dt id="feedgen.ext.podcast.PodcastExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.podcast.</code><code class="descname">PodcastExtension</code><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension" title="Permalink to this definition"></a></dt>
<dd><p>FeedGenerator extension for podcasts.</p>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.extend_ns">
<code class="descname">extend_ns</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.extend_ns" title="Permalink to this definition"></a></dt>
<dd><p>Returns a dict that will be used in the namespace map for the feed.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.extend_rss">
<code class="descname">extend_rss</code><span class="sig-paren">(</span><em>rss_feed</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.extend_rss" title="Permalink to this definition"></a></dt>
<dd><p>Extend an RSS feed root with set itunes fields.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Returns:</th><td class="field-body">The feed root element.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_author">
<code class="descname">itunes_author</code><span class="sig-paren">(</span><em>itunes_author=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_author" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:author. The content of this tag is shown in
the Artist column in iTunes. If the tag is not present, iTunes uses the
contents of the &lt;author&gt; tag. If &lt;itunes:author&gt; is not present at the
feed level, iTunes will use the contents of &lt;managingEditor&gt;.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_author</strong> The author of the podcast.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The author of the podcast.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_block">
<code class="descname">itunes_block</code><span class="sig-paren">(</span><em>itunes_block=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_block" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the ITunes block attribute. Use this to prevent the
entire podcast from appearing in the iTunes podcast directory.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_block</strong> Block the podcast.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">If the podcast is blocked.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_category">
<code class="descname">itunes_category</code><span class="sig-paren">(</span><em>itunes_category=None</em>, <em>replace=False</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_category" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the ITunes category which appears in the category column
and in iTunes Store Browser.</p>
<p>The (sub-)category has to be one from the values defined at
<a class="reference external" href="http://www.apple.com/itunes/podcasts/specs.html#categories">http://www.apple.com/itunes/podcasts/specs.html#categories</a></p>
<p>This method can be called with:</p>
<ul class="simple">
<li>the fields of an itunes_category as keyword arguments</li>
<li>the fields of an itunes_category as a dictionary</li>
<li>a list of dictionaries containing the itunes_category fields</li>
</ul>
<p>An itunes_category has the following fields:</p>
<ul class="simple">
<li><em>cat</em> name for a category.</li>
<li><em>sub</em> name for a subcategory, child of category</li>
</ul>
<p>If a podcast has more than one subcategory from the same category, the
category is called more than once.</p>
<p>Likei the parameter:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[{</span><span class="s2">&quot;cat&quot;</span><span class="p">:</span><span class="s2">&quot;Arts&quot;</span><span class="p">,</span><span class="s2">&quot;sub&quot;</span><span class="p">:</span><span class="s2">&quot;Design&quot;</span><span class="p">},{</span><span class="s2">&quot;cat&quot;</span><span class="p">:</span><span class="s2">&quot;Arts&quot;</span><span class="p">,</span><span class="s2">&quot;sub&quot;</span><span class="p">:</span><span class="s2">&quot;Food&quot;</span><span class="p">}]</span>
</pre></div>
</div>
<p>…would become:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">itunes</span><span class="p">:</span><span class="n">category</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;Arts&quot;</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">itunes</span><span class="p">:</span><span class="n">category</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;Design&quot;</span><span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="n">itunes</span><span class="p">:</span><span class="n">category</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;Food&quot;</span><span class="o">/&gt;</span>
<span class="o">&lt;/</span><span class="n">itunes</span><span class="p">:</span><span class="n">category</span><span class="o">&gt;</span>
</pre></div>
</div>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>itunes_category</strong> Dictionary or list of dictionaries with
itunes_category data.</li>
<li><strong>replace</strong> Add or replace old data.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first last">List of itunes_categories as dictionaries.</p>
</td>
</tr>
</tbody>
</table>
<p></p>
<p><strong>Important note about deprecated parameter syntax:</strong> Old version of
the feedgen did only support one category plus one subcategory which
would be passed to this ducntion as first two parameters. For
compatibility reasons, this still works but should not be used any may
be removed at any time.</p>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_complete">
<code class="descname">itunes_complete</code><span class="sig-paren">(</span><em>itunes_complete=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_complete" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:complete value of the podcast. This tag can be
used to indicate the completion of a podcast.</p>
<p>If you populate this tag with “yes”, you are indicating that no more
episodes will be added to the podcast. If the &lt;itunes:complete&gt; tag is
present and has any other value (e.g. “no”), it will have no effect on
the podcast.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_complete</strong> If the podcast is complete.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">If the podcast is complete.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_explicit">
<code class="descname">itunes_explicit</code><span class="sig-paren">(</span><em>itunes_explicit=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_explicit" title="Permalink to this definition"></a></dt>
<dd><p>Get or the the itunes:explicit value of the podcast. This tag should
be used to indicate whether your podcast contains explicit material.
The three values for this tag are “yes”, “no”, and “clean”.</p>
<p>If you populate this tag with “yes”, an “explicit” parental advisory
graphic will appear next to your podcast artwork on the iTunes Store
and in the Name column in iTunes. If the value is “clean”, the parental
advisory type is considered Clean, meaning that no explicit language or
adult content is included anywhere in the episodes, and a “clean”
graphic will appear. If the explicit tag is present and has any other
value (e.g., “no”), you see no indicator — blank is the default
advisory type.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_explicit</strong> If the podcast contains explicit material.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">If the podcast contains explicit material.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_image">
<code class="descname">itunes_image</code><span class="sig-paren">(</span><em>itunes_image=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_image" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the image for the podcast. This tag specifies the artwork
for your podcast. Put the URL to the image in the href attribute.
iTunes prefers square .jpg images that are at least 1400x1400 pixels,
which is different from what is specified for the standard RSS image
tag. In order for a podcast to be eligible for an iTunes Store feature,
the accompanying image must be at least 1400x1400 pixels.</p>
<p>iTunes supports images in JPEG and PNG formats with an RGB color space
(CMYK is not supported). The URL must end in “.jpg” or “.png”. If the
&lt;itunes:image&gt; tag is not present, iTunes will use the contents of the
RSS image tag.</p>
<p>If you change your podcasts image, also change the files name. iTunes
may not change the image if it checks your feed and the image URL is
the same. The server hosting your cover art image must allow HTTP head
requests for iTS to be able to automatically update your cover art.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_image</strong> Image of the podcast.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Image of the podcast.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_new_feed_url">
<code class="descname">itunes_new_feed_url</code><span class="sig-paren">(</span><em>itunes_new_feed_url=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_new_feed_url" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the new-feed-url property of the podcast. This tag allows
you to change the URL where the podcast feed is located</p>
<p>After adding the tag to your old feed, you should maintain the old feed
for 48 hours before retiring it. At that point, iTunes will have
updated the directory with the new feed URL.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_new_feed_url</strong> New feed URL.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">New feed URL.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_owner">
<code class="descname">itunes_owner</code><span class="sig-paren">(</span><em>name=None</em>, <em>email=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_owner" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:owner of the podcast. This tag contains
information that will be used to contact the owner of the podcast for
communication specifically about the podcast. It will not be publicly
displayed.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_owner</strong> The owner of the feed.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Data of the owner of the feed.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_subtitle">
<code class="descname">itunes_subtitle</code><span class="sig-paren">(</span><em>itunes_subtitle=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_subtitle" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:subtitle value for the podcast. The contents of
this tag are shown in the Description column in iTunes. The subtitle
displays best if it is only a few words long.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_subtitle</strong> Subtitle of the podcast.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Subtitle of the podcast.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast.PodcastExtension.itunes_summary">
<code class="descname">itunes_summary</code><span class="sig-paren">(</span><em>itunes_summary=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast.PodcastExtension.itunes_summary" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:summary value for the podcast. The contents of
this tag are shown in a separate window that appears when the “circled
i” in the Description column is clicked. It also appears on the iTunes
page for your podcast. This field can be up to 4000 characters. If
<cite>&lt;itunes:summary&gt;</cite> is not included, the contents of the &lt;description&gt;
tag are used.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_summary</strong> Summary of the podcast.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Summary of the podcast.</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="api.ext.dc.html">feedgen.ext.dc</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.podcast_entry.html">feedgen.ext.podcast_entry</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

View file

@ -0,0 +1,298 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.ext.podcast_entry &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="../_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="../_static/language_data.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="feedgen.ext.torrent" href="api.ext.torrent.html" />
<link rel="prev" title="feedgen.ext.podcast" href="api.ext.podcast.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="../index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.ext.podcast_entry</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="api.ext.podcast.html">feedgen.ext.podcast</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.torrent.html">feedgen.ext.torrent</a>&#160;&#160;»
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.ext.podcast_entry"></span><div class="section" id="feedgen-ext-podcast-entry">
<h1>feedgen.ext.podcast_entry<a class="headerlink" href="#feedgen-ext-podcast-entry" title="Permalink to this headline"></a></h1>
<p>Extends the feedgen to produce podcasts.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2013-2016, Lars Kiesow &lt;<a class="reference external" href="mailto:lkiesow&#37;&#52;&#48;uos&#46;de">lkiesow<span>&#64;</span>uos<span>&#46;</span>de</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="class">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.podcast_entry.</code><code class="descname">PodcastEntryExtension</code><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension" title="Permalink to this definition"></a></dt>
<dd><p>FeedEntry extension for podcasts.</p>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.extend_rss">
<code class="descname">extend_rss</code><span class="sig-paren">(</span><em>entry</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.extend_rss" title="Permalink to this definition"></a></dt>
<dd><p>Add additional fields to an RSS item.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>feed</strong> The RSS item XML element to use.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_author">
<code class="descname">itunes_author</code><span class="sig-paren">(</span><em>itunes_author=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_author" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:author of the podcast episode. The content of
this tag is shown in the Artist column in iTunes. If the tag is not
present, iTunes uses the contents of the &lt;author&gt; tag. If
&lt;itunes:author&gt; is not present at the feed level, iTunes will use the
contents of &lt;managingEditor&gt;.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_author</strong> The author of the podcast.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The author of the podcast.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_block">
<code class="descname">itunes_block</code><span class="sig-paren">(</span><em>itunes_block=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_block" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the ITunes block attribute. Use this to prevent episodes
from appearing in the iTunes podcast directory.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_block</strong> Block podcast episodes.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">If the podcast episode is blocked.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_duration">
<code class="descname">itunes_duration</code><span class="sig-paren">(</span><em>itunes_duration=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_duration" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the duration of the podcast episode. The content of this
tag is shown in the Time column in iTunes.</p>
<p>The tag can be formatted HH:MM:SS, H:MM:SS, MM:SS, or M:SS (H = hours,
M = minutes, S = seconds). If an integer is provided (no colon
present), the value is assumed to be in seconds. If one colon is
present, the number to the left is assumed to be minutes, and the
number to the right is assumed to be seconds. If more than two colons
are present, the numbers farthest to the right are ignored.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_duration</strong> Duration of the podcast episode.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Duration of the podcast episode.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_explicit">
<code class="descname">itunes_explicit</code><span class="sig-paren">(</span><em>itunes_explicit=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_explicit" title="Permalink to this definition"></a></dt>
<dd><p>Get or the the itunes:explicit value of the podcast episode. This
tag should be used to indicate whether your podcast episode contains
explicit material. The three values for this tag are “yes”, “no”, and
“clean”.</p>
<p>If you populate this tag with “yes”, an “explicit” parental advisory
graphic will appear next to your podcast artwork on the iTunes Store
and in the Name column in iTunes. If the value is “clean”, the parental
advisory type is considered Clean, meaning that no explicit language or
adult content is included anywhere in the episodes, and a “clean”
graphic will appear. If the explicit tag is present and has any other
value (e.g., “no”), you see no indicator — blank is the default
advisory type.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_explicit</strong> If the podcast episode contains explicit
material.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">If the podcast episode contains explicit material.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_image">
<code class="descname">itunes_image</code><span class="sig-paren">(</span><em>itunes_image=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_image" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the image for the podcast episode. This tag specifies the
artwork for your podcast. Put the URL to the image in the href
attribute. iTunes prefers square .jpg images that are at least
1400x1400 pixels, which is different from what is specified for the
standard RSS image tag. In order for a podcast to be eligible for an
iTunes Store feature, the accompanying image must be at least 1400x1400
pixels.</p>
<p>iTunes supports images in JPEG and PNG formats with an RGB color space
(CMYK is not supported). The URL must end in “.jpg” or “.png”. If the
&lt;itunes:image&gt; tag is not present, iTunes will use the contents of the
RSS image tag.</p>
<p>If you change your podcasts image, also change the files name. iTunes
may not change the image if it checks your feed and the image URL is
the same. The server hosting your cover art image must allow HTTP head
requests for iTS to be able to automatically update your cover art.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_image</strong> Image of the podcast.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Image of the podcast.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_is_closed_captioned">
<code class="descname">itunes_is_closed_captioned</code><span class="sig-paren">(</span><em>itunes_is_closed_captioned=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_is_closed_captioned" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the is_closed_captioned value of the podcast episode.
This tag should be used if your podcast includes a video episode with
embedded closed captioning support. The two values for this tag are
“yes” and “no”.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>is_closed_captioned</strong> If the episode has closed captioning
support.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">If the episode has closed captioning support.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_order">
<code class="descname">itunes_order</code><span class="sig-paren">(</span><em>itunes_order=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_order" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:order value of the podcast episode. This tag
can be used to override the default ordering of episodes on the store.</p>
<p>This tag is used at an &lt;item&gt; level by populating with the number value
in which you would like the episode to appear on the store. For
example, if you would like an &lt;item&gt; to appear as the first episode in
the podcast, you would populate the &lt;itunes:order&gt; tag with “1”. If
conflicting order values are present in multiple episodes, the store
will use default ordering (pubDate).</p>
<p>To remove the order from the episode set the order to a value below
zero.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_order</strong> The order of the episode.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The order of the episode.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_subtitle">
<code class="descname">itunes_subtitle</code><span class="sig-paren">(</span><em>itunes_subtitle=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_subtitle" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:subtitle value for the podcast episode. The
contents of this tag are shown in the Description column in iTunes. The
subtitle displays best if it is only a few words long.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_subtitle</strong> Subtitle of the podcast episode.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Subtitle of the podcast episode.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_summary">
<code class="descname">itunes_summary</code><span class="sig-paren">(</span><em>itunes_summary=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_summary" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the itunes:summary value for the podcast episode. The
contents of this tag are shown in a separate window that appears when
the “circled i” in the Description column is clicked. It also appears
on the iTunes page for your podcast. This field can be up to 4000
characters. If &lt;itunes:summary&gt; is not included, the contents of the
&lt;description&gt; tag are used.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>itunes_summary</strong> Summary of the podcast episode.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">Summary of the podcast episode.</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="api.ext.podcast.html">feedgen.ext.podcast</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.ext.torrent.html">feedgen.ext.torrent</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

199
ext/api.ext.torrent.html Normal file
View file

@ -0,0 +1,199 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>feedgen.ext.torrent &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="../_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="../_static/language_data.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="prev" title="feedgen.ext.podcast_entry" href="api.ext.podcast_entry.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="../index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>feedgen.ext.torrent</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
«&#160;&#160;<a href="api.ext.podcast_entry.html">feedgen.ext.podcast_entry</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
</p>
</div>
<div class="content">
<script type=application/javascript src=_static/theme_extras.js></script>
<div class="apititle"><b>Contents</b></div>
<div class="apitoc"></div><span class="target" id="module-feedgen.ext.torrent"></span><div class="section" id="feedgen-ext-torrent">
<h1>feedgen.ext.torrent<a class="headerlink" href="#feedgen-ext-torrent" title="Permalink to this headline"></a></h1>
<p>Extends the FeedGenerator to produce torrent feeds.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">copyright:</th><td class="field-body">2016, Raspbeguy &lt;<a class="reference external" href="mailto:raspbeguy&#37;&#52;&#48;hashtagueule&#46;fr">raspbeguy<span>&#64;</span>hashtagueule<span>&#46;</span>fr</a>&gt;</td>
</tr>
<tr class="field-even field"><th class="field-name">license:</th><td class="field-body">FreeBSD and LGPL, see license.* for more details.</td>
</tr>
</tbody>
</table>
<dl class="class">
<dt id="feedgen.ext.torrent.TorrentEntryExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.torrent.</code><code class="descname">TorrentEntryExtension</code><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension" title="Permalink to this definition"></a></dt>
<dd><p>FeedEntry extension for torrent feeds</p>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentEntryExtension.contentlength">
<code class="descname">contentlength</code><span class="sig-paren">(</span><em>torrent_contentlength=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension.contentlength" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the size of the target file.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>torrent_contentlength</strong> The target file size.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The target file size.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentEntryExtension.extend_rss">
<code class="descname">extend_rss</code><span class="sig-paren">(</span><em>entry</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension.extend_rss" title="Permalink to this definition"></a></dt>
<dd><p>Add additional fields to an RSS item.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>feed</strong> The RSS item XML element to use.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentEntryExtension.filename">
<code class="descname">filename</code><span class="sig-paren">(</span><em>torrent_filename=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension.filename" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the name of the torrent file.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>torrent_filename</strong> The name of the torrent file.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The name of the torrent file.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentEntryExtension.infohash">
<code class="descname">infohash</code><span class="sig-paren">(</span><em>torrent_infohash=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension.infohash" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the hash of the target file.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>torrent_infohash</strong> The target file hash.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The target hash file.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentEntryExtension.peers">
<code class="descname">peers</code><span class="sig-paren">(</span><em>torrent_peers=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension.peers" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the number od peers</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>torrent_infohash</strong> The peers number.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The peers number.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentEntryExtension.seeds">
<code class="descname">seeds</code><span class="sig-paren">(</span><em>torrent_seeds=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension.seeds" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the number of seeds.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>torrent_seeds</strong> The seeds number.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The seeds number.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentEntryExtension.verified">
<code class="descname">verified</code><span class="sig-paren">(</span><em>torrent_verified=None</em><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentEntryExtension.verified" title="Permalink to this definition"></a></dt>
<dd><p>Get or set the number of verified peers.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>torrent_infohash</strong> The verified peers number.</td>
</tr>
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The verified peers number.</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="feedgen.ext.torrent.TorrentExtension">
<em class="property">class </em><code class="descclassname">feedgen.ext.torrent.</code><code class="descname">TorrentExtension</code><a class="headerlink" href="#feedgen.ext.torrent.TorrentExtension" title="Permalink to this definition"></a></dt>
<dd><p>FeedGenerator extension for torrent feeds.</p>
<dl class="method">
<dt id="feedgen.ext.torrent.TorrentExtension.extend_ns">
<code class="descname">extend_ns</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#feedgen.ext.torrent.TorrentExtension.extend_ns" title="Permalink to this definition"></a></dt>
<dd><p>Returns a dict that will be used in the namespace map for the feed.</p>
</dd></dl>
</dd></dl>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
«&#160;&#160;<a href="api.ext.podcast_entry.html">feedgen.ext.podcast_entry</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="../index.html">Contents</a>
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

View file

@ -1,137 +0,0 @@
# -*- coding: utf-8 -*-
"""
=======
feedgen
=======
This module can be used to generate web feeds in both ATOM and RSS format.
It has support for extensions. Included is for example an extension to
produce Podcasts.
:copyright: 2013 by Lars Kiesow
:license: FreeBSD and LGPL, see license.* for more details.
-------------
Create a Feed
-------------
To create a feed simply instantiate the FeedGenerator class and insert some
data::
>>> from feedgen.feed import FeedGenerator
>>> fg = FeedGenerator()
>>> fg.id('http://lernfunk.de/media/654321')
>>> fg.title('Some Testfeed')
>>> fg.author( {'name':'John Doe','email':'john@example.de'} )
>>> fg.link( href='http://example.com', rel='alternate' )
>>> fg.logo('http://ex.com/logo.jpg')
>>> fg.subtitle('This is a cool feed!')
>>> fg.link( href='http://larskiesow.de/test.atom', rel='self' )
>>> fg.language('en')
Note that for the methods which set fields that can occur more than once in
a feed you can use all of the following ways to provide data:
- Provide the data for that element as keyword arguments
- Provide the data for that element as dictionary
- Provide a list of dictionaries with the data for several elements
Example::
>>> fg.contributor(name='John Doe', email='jdoe@example.com' )
>>> fg.contributor({'name':'John Doe', 'email':'jdoe@example.com'})
>>> fg.contributor([{'name':'John', 'email':'jdoe@example.com'}, ])
-----------------
Generate the Feed
-----------------
After that you can generate both RSS or ATOM by calling the respective
method::
>>> atomfeed = fg.atom_str(pretty=True) # Get the ATOM feed as string
>>> rssfeed = fg.rss_str(pretty=True) # Get the RSS feed as string
>>> fg.atom_file('atom.xml') # Write the ATOM feed to a file
>>> fg.rss_file('rss.xml') # Write the RSS feed to a file
----------------
Add Feed Entries
----------------
To add entries (items) to a feed you need to create new FeedEntry objects
and append them to the list of entries in the FeedGenerator. The most
convenient way to go is to use the FeedGenerator itself for the
instantiation of the FeedEntry object::
>>> fe = fg.add_entry()
>>> fe.id('http://lernfunk.de/media/654321/1')
>>> fe.title('The First Episode')
The FeedGenerators method add_entry(...) without argument provides will
automatically generate a new FeedEntry object, append it to the feeds
internal list of entries and return it, so that additional data can be
added.
----------
Extensions
----------
The FeedGenerator supports extension to include additional data into the
XML structure of the feeds. Extensions can be loaded like this::
>>> fg.load_extension('someext', atom=True, rss=True)
This will try to load the extension someext from the file
`ext/someext.py`. It is required that `someext.py` contains a class named
SomextExtension which is required to have at least the two methods
`extend_rss(...)` and `extend_atom(...)`. Although not required, it is
strongly suggested to use BaseExtension from `ext/base.py` as superclass.
`load_extension('someext', ...)` will also try to load a class named
SomextEntryExtension for every entry of the feed. This class can be
located either in the same file as SomextExtension or in
`ext/someext_entry.py` which is suggested especially for large extensions.
The parameters `atom` and `rss` tell the FeedGenerator if the extensions
should only be used for either ATOM or RSS feeds. The default value for
both parameters is true which means that the extension would be used for
both kinds of feeds.
**Example: Producing a Podcast**
One extension already provided is the podcast extension. A podcast is an
RSS feed with some additional elements for ITunes.
To produce a podcast simply load the `podcast` extension::
>>> from feedgen.feed import FeedGenerator
>>> fg = FeedGenerator()
>>> fg.load_extension('podcast')
...
>>> fg.podcast.itunes_category('Technology', 'Podcasting')
...
>>> fg.rss_str(pretty=True)
>>> fg.rss_file('podcast.xml')
Of cause the extension has to be loaded for the FeedEntry objects as well
but this is done automatically by the FeedGenerator for every feed entry if
the extension is loaded for the whole feed. You can, however, load an
extension for a specific FeedEntry by calling `load_extension(...)` on that
entry. But this is a rather uncommon use.
Of cause you can still produce a normal ATOM or RSS feed, even if you have
loaded some plugins by temporary disabling them during the feed generation.
This can be done by calling the generating method with the keyword argument
`extensions` set to `False`.
---------------------
Testing the Generator
---------------------
You can test the module by simply executing::
$ python -m feedgen
"""

View file

@ -1,145 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen
~~~~~~~
:copyright: 2013-2016, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
import sys
from feedgen.feed import FeedGenerator
USAGE = '''
Usage: python -m feedgen [OPTION]
Use one of the following options:
File options:
<file>.atom -- Generate ATOM test feed
<file>.rss -- Generate RSS test teed
Stdout options:
atom -- Generate ATOM test output
rss -- Generate RSS test output
podcast -- Generate Podcast test output
dc.atom -- Generate DC extension test output (atom format)
dc.rss -- Generate DC extension test output (rss format)
syndication.atom -- Generate syndication extension test output (atom format)
syndication.rss -- Generate syndication extension test output (rss format)
torrent -- Generate Torrent test output
'''
def print_enc(s):
'''Print function compatible with both python2 and python3 accepting strings
and byte arrays.
'''
if sys.version_info[0] >= 3:
print(s.decode('utf-8') if isinstance(s, bytes) else s)
else:
print(s)
def main():
if len(sys.argv) != 2 or not (
sys.argv[1].endswith('rss') or
sys.argv[1].endswith('atom') or
sys.argv[1] == 'torrent' or
sys.argv[1] == 'podcast'):
print(USAGE)
exit()
arg = sys.argv[1]
fg = FeedGenerator()
fg.id('http://lernfunk.de/_MEDIAID_123')
fg.title('Testfeed')
fg.author({'name': 'Lars Kiesow', 'email': 'lkiesow@uos.de'})
fg.link(href='http://example.com', rel='alternate')
fg.category(term='test')
fg.contributor(name='Lars Kiesow', email='lkiesow@uos.de')
fg.contributor(name='John Doe', email='jdoe@example.com')
fg.icon('http://ex.com/icon.jpg')
fg.logo('http://ex.com/logo.jpg')
fg.rights('cc-by')
fg.subtitle('This is a cool feed!')
fg.link(href='http://larskiesow.de/test.atom', rel='self')
fg.language('de')
fe = fg.add_entry()
fe.id('http://lernfunk.de/_MEDIAID_123#1')
fe.title('First Element')
fe.content('''Lorem ipsum dolor sit amet, consectetur adipiscing elit. Tamen
aberramus a proposito, et, ne longius, prorsus, inquam, Piso, si
ista mala sunt, placet. Aut etiam, ut vestitum, sic sententiam
habeas aliam domesticam, aliam forensem, ut in fronte ostentatio
sit, intus veritas occultetur? Cum id fugiunt, re eadem defendunt,
quae Peripatetici, verba.''')
fe.summary(u'Lorem ipsum dolor sit amet, consectetur adipiscing elit…')
fe.link(href='http://example.com', rel='alternate')
fe.author(name='Lars Kiesow', email='lkiesow@uos.de')
if arg == 'atom':
print_enc(fg.atom_str(pretty=True))
elif arg == 'rss':
print_enc(fg.rss_str(pretty=True))
elif arg == 'podcast':
# Load the podcast extension. It will automatically be loaded for all
# entries in the feed, too. Thus also for our “fe”.
fg.load_extension('podcast')
fg.podcast.itunes_author('Lars Kiesow')
fg.podcast.itunes_category('Technology', 'Podcasting')
fg.podcast.itunes_explicit('no')
fg.podcast.itunes_complete('no')
fg.podcast.itunes_new_feed_url('http://example.com/new-feed.rss')
fg.podcast.itunes_owner('John Doe', 'john@example.com')
fg.podcast.itunes_summary('Lorem ipsum dolor sit amet, consectetur ' +
'adipiscing elit. Verba tu fingas et ea ' +
'dicas, quae non sentias?')
fe.podcast.itunes_author('Lars Kiesow')
print_enc(fg.rss_str(pretty=True))
elif arg == 'torrent':
fg.load_extension('torrent')
fe.link(href='http://example.com/torrent/debian-8-netint.iso.torrent',
rel='alternate',
type='application/x-bittorrent, length=1000')
fe.torrent.filename('debian-8.4.0-i386-netint.iso.torrent')
fe.torrent.infohash('7661229811ef32014879ceedcdf4a48f256c88ba')
fe.torrent.contentlength('331350016')
fe.torrent.seeds('789')
fe.torrent.peers('456')
fe.torrent.verified('123')
print_enc(fg.rss_str(pretty=True))
elif arg.startswith('dc.'):
fg.load_extension('dc')
fg.dc.dc_contributor('Lars Kiesow')
if arg.endswith('.atom'):
print_enc(fg.atom_str(pretty=True))
else:
print_enc(fg.rss_str(pretty=True))
elif arg.startswith('syndication'):
fg.load_extension('syndication')
fg.syndication.update_period('daily')
fg.syndication.update_frequency(2)
fg.syndication.update_base('2000-01-01T12:00+00:00')
if arg.endswith('.rss'):
print_enc(fg.rss_str(pretty=True))
else:
print_enc(fg.atom_str(pretty=True))
elif arg.endswith('atom'):
fg.atom_file(arg)
elif arg.endswith('rss'):
fg.rss_file(arg)
if __name__ == '__main__':
main()

View file

@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
import sys
if sys.version_info[0] >= 3:
string_types = str
else:
string_types = basestring # noqa: F821

View file

@ -1,738 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.entry
~~~~~~~~~~~~~
:copyright: 2013-2020, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
from datetime import datetime
import dateutil.parser
import dateutil.tz
import warnings
from lxml.etree import CDATA # nosec - adding CDATA entry is safe
from feedgen.compat import string_types
from feedgen.util import ensure_format, formatRFC2822, xml_fromstring, xml_elem
def _add_text_elm(entry, data, name):
"""Add a text subelement to an entry"""
if not data:
return
elm = xml_elem(name, entry)
type_ = data.get('type')
if data.get('src'):
if name != 'content':
raise ValueError("Only the 'content' element of an entry can "
"contain a 'src' attribute")
elm.attrib['src'] = data['src']
elif data.get(name):
# Surround xhtml with a div tag, parse it and embed it
if type_ == 'xhtml':
xhtml = '<div xmlns="http://www.w3.org/1999/xhtml">' \
+ data.get(name) + '</div>'
elm.append(xml_fromstring(xhtml))
elif type_ == 'CDATA':
elm.text = CDATA(data.get(name))
# Parse XML and embed it
elif type_ and (type_.endswith('/xml') or type_.endswith('+xml')):
elm.append(xml_fromstring(data[name]))
# Embed the text in escaped form
elif not type_ or type_.startswith('text') or type_ == 'html':
elm.text = data.get(name)
# Everything else should be included base64 encoded
else:
raise NotImplementedError(
'base64 encoded {} is not supported at the moment. '
'Pull requests adding support are welcome.'.format(name)
)
# Add type description of the content
if type_:
elm.attrib['type'] = type_
class FeedEntry(object):
'''FeedEntry call representing an ATOM feeds entry node or an RSS feeds item
node.
'''
def __init__(self):
# ATOM
# required
self.__atom_id = None
self.__atom_title = None
self.__atom_updated = datetime.now(dateutil.tz.tzutc())
# recommended
self.__atom_author = None
self.__atom_content = None
self.__atom_link = None
self.__atom_summary = None
# optional
self.__atom_category = None
self.__atom_contributor = None
self.__atom_published = None
self.__atom_source = None
self.__atom_rights = None
# RSS
self.__rss_author = None
self.__rss_category = None
self.__rss_comments = None
self.__rss_description = None
self.__rss_content = None
self.__rss_enclosure = None
self.__rss_guid = {}
self.__rss_link = None
self.__rss_pubDate = None
self.__rss_source = None
self.__rss_title = None
# Extension list:
self.__extensions = {}
self.__extensions_register = {}
def atom_entry(self, extensions=True):
'''Create an ATOM entry and return it.'''
entry = xml_elem('entry')
if not (self.__atom_id and self.__atom_title and self.__atom_updated):
raise ValueError('Required fields not set')
id = xml_elem('id', entry)
id.text = self.__atom_id
title = xml_elem('title', entry)
title.text = self.__atom_title
updated = xml_elem('updated', entry)
updated.text = self.__atom_updated.isoformat()
# An entry must contain an alternate link if there is no content
# element.
if not self.__atom_content:
links = self.__atom_link or []
if not [l for l in links if l.get('rel') == 'alternate']:
raise ValueError('Entry must contain an alternate link or ' +
'a content element.')
# Add author elements
for a in self.__atom_author or []:
# Atom requires a name. Skip elements without.
if not a.get('name'):
continue
author = xml_elem('author', entry)
name = xml_elem('name', author)
name.text = a.get('name')
if a.get('email'):
email = xml_elem('email', author)
email.text = a.get('email')
if a.get('uri'):
uri = xml_elem('uri', author)
uri.text = a.get('uri')
_add_text_elm(entry, self.__atom_content, 'content')
for l in self.__atom_link or []:
link = xml_elem('link', entry, href=l['href'])
if l.get('rel'):
link.attrib['rel'] = l['rel']
if l.get('type'):
link.attrib['type'] = l['type']
if l.get('hreflang'):
link.attrib['hreflang'] = l['hreflang']
if l.get('title'):
link.attrib['title'] = l['title']
if l.get('length'):
link.attrib['length'] = l['length']
_add_text_elm(entry, self.__atom_summary, 'summary')
for c in self.__atom_category or []:
cat = xml_elem('category', entry, term=c['term'])
if c.get('scheme'):
cat.attrib['scheme'] = c['scheme']
if c.get('label'):
cat.attrib['label'] = c['label']
# Add author elements
for c in self.__atom_contributor or []:
# Atom requires a name. Skip elements without.
if not c.get('name'):
continue
contrib = xml_elem('contributor', entry)
name = xml_elem('name', contrib)
name.text = c.get('name')
if c.get('email'):
email = xml_elem('email', contrib)
email.text = c.get('email')
if c.get('uri'):
uri = xml_elem('uri', contrib)
uri.text = c.get('uri')
if self.__atom_published:
published = xml_elem('published', entry)
published.text = self.__atom_published.isoformat()
if self.__atom_rights:
rights = xml_elem('rights', entry)
rights.text = self.__atom_rights
if self.__atom_source:
source = xml_elem('source', entry)
if self.__atom_source.get('title'):
source_title = xml_elem('title', source)
source_title.text = self.__atom_source['title']
if self.__atom_source.get('link'):
xml_elem('link', source, href=self.__atom_source['link'])
if extensions:
for ext in self.__extensions.values() or []:
if ext.get('atom'):
ext['inst'].extend_atom(entry)
return entry
def rss_entry(self, extensions=True):
'''Create a RSS item and return it.'''
entry = xml_elem('item')
if not (self.__rss_title or
self.__rss_description or
self.__rss_content):
raise ValueError('Required fields not set')
if self.__rss_title:
title = xml_elem('title', entry)
title.text = self.__rss_title
if self.__rss_link:
link = xml_elem('link', entry)
link.text = self.__rss_link
if self.__rss_description and self.__rss_content:
description = xml_elem('description', entry)
description.text = self.__rss_description
XMLNS_CONTENT = 'http://purl.org/rss/1.0/modules/content/'
content = xml_elem('{%s}encoded' % XMLNS_CONTENT, entry)
content.text = CDATA(self.__rss_content['content']) \
if self.__rss_content.get('type', '') == 'CDATA' \
else self.__rss_content['content']
elif self.__rss_description:
description = xml_elem('description', entry)
description.text = self.__rss_description
elif self.__rss_content:
description = xml_elem('description', entry)
description.text = CDATA(self.__rss_content['content']) \
if self.__rss_content.get('type', '') == 'CDATA' \
else self.__rss_content['content']
for a in self.__rss_author or []:
author = xml_elem('author', entry)
author.text = a
if self.__rss_guid.get('guid'):
guid = xml_elem('guid', entry)
guid.text = self.__rss_guid['guid']
permaLink = str(self.__rss_guid.get('permalink', False)).lower()
guid.attrib['isPermaLink'] = permaLink
for cat in self.__rss_category or []:
category = xml_elem('category', entry)
category.text = cat['value']
if cat.get('domain'):
category.attrib['domain'] = cat['domain']
if self.__rss_comments:
comments = xml_elem('comments', entry)
comments.text = self.__rss_comments
if self.__rss_enclosure:
enclosure = xml_elem('enclosure', entry)
enclosure.attrib['url'] = self.__rss_enclosure['url']
enclosure.attrib['length'] = self.__rss_enclosure['length']
enclosure.attrib['type'] = self.__rss_enclosure['type']
if self.__rss_pubDate:
pubDate = xml_elem('pubDate', entry)
pubDate.text = formatRFC2822(self.__rss_pubDate)
if self.__rss_source:
source = xml_elem('source', entry, url=self.__rss_source['url'])
source.text = self.__rss_source['title']
if extensions:
for ext in self.__extensions.values() or []:
if ext.get('rss'):
ext['inst'].extend_rss(entry)
return entry
def title(self, title=None):
'''Get or set the title value of the entry. It should contain a human
readable title for the entry. Title is mandatory for both ATOM and RSS
and should not be blank.
:param title: The new title of the entry.
:returns: The entriess title.
'''
if title is not None:
self.__atom_title = title
self.__rss_title = title
return self.__atom_title
def id(self, id=None):
'''Get or set the entry id which identifies the entry using a
universally unique and permanent URI. Two entries in a feed can have
the same value for id if they represent the same entry at different
points in time. This method will also set rss:guid with permalink set
to False. Id is mandatory for an ATOM entry.
:param id: New Id of the entry.
:returns: Id of the entry.
'''
if id is not None:
self.__atom_id = id
self.__rss_guid = {'guid': id, 'permalink': False}
return self.__atom_id
def guid(self, guid=None, permalink=False):
'''Get or set the entries guid which is a string that uniquely
identifies the item. This will also set atom:id.
:param guid: Id of the entry.
:param permalink: If this is a permanent identifier for this item
:returns: Id and permalink setting of the entry.
'''
if guid is not None:
self.__atom_id = guid
self.__rss_guid = {'guid': guid, 'permalink': permalink}
return self.__rss_guid
def updated(self, updated=None):
'''Set or get the updated value which indicates the last time the entry
was modified in a significant way.
The value can either be a string which will automatically be parsed or
a datetime.datetime object. In any case it is necessary that the value
include timezone information.
:param updated: The modification date.
:returns: Modification date as datetime.datetime
'''
if updated is not None:
if isinstance(updated, string_types):
updated = dateutil.parser.parse(updated)
if not isinstance(updated, datetime):
raise ValueError('Invalid datetime format')
if updated.tzinfo is None:
raise ValueError('Datetime object has no timezone info')
self.__atom_updated = updated
self.__rss_lastBuildDate = updated
return self.__atom_updated
def author(self, author=None, replace=False, **kwargs):
'''Get or set author data. An author element is a dict containing a
name, an email address and a uri. Name is mandatory for ATOM, email is
mandatory for RSS.
This method can be called with:
- the fields of an author as keyword arguments
- the fields of an author as a dictionary
- a list of dictionaries containing the author fields
An author has the following fields:
- *name* conveys a human-readable name for the person.
- *uri* contains a home page for the person.
- *email* contains an email address for the person.
:param author: Dict or list of dicts with author data.
:param replace: Add or replace old data.
Example::
>>> author({'name':'John Doe', 'email':'jdoe@example.com'})
[{'name':'John Doe','email':'jdoe@example.com'}]
>>> author([{'name': 'Mr. X'}, {'name': 'Max'}])
[{'name':'John Doe','email':'jdoe@example.com'},
{'name':'John Doe'}, {'name':'Max'}]
>>> author(name='John Doe', email='jdoe@example.com', replace=True)
[{'name':'John Doe','email':'jdoe@example.com'}]
'''
if author is None and kwargs:
author = kwargs
if author is not None:
if replace or self.__atom_author is None:
self.__atom_author = []
self.__atom_author += ensure_format(author,
set(['name', 'email', 'uri']),
set())
self.__rss_author = []
for a in self.__atom_author:
if a.get('email'):
if a.get('name'):
self.__rss_author.append('%(email)s (%(name)s)' % a)
else:
self.__rss_author.append('%(email)s' % a)
return self.__atom_author
def content(self, content=None, src=None, type=None):
'''Get or set the content of the entry which contains or links to the
complete content of the entry. Content must be provided for ATOM
entries if there is no alternate link, and should be provided if there
is no summary. If the content is set (not linked) it will also set
rss:description.
:param content: The content of the feed entry.
:param src: Link to the entries content.
:param type: If type is CDATA content would not be escaped.
:returns: Content element of the entry.
'''
if src is not None:
self.__atom_content = {'src': src}
elif content is not None:
self.__atom_content = {'content': content}
self.__rss_content = {'content': content}
if type is not None:
self.__atom_content['type'] = type
self.__rss_content['type'] = type
return self.__atom_content
def link(self, link=None, replace=False, **kwargs):
'''Get or set link data. An link element is a dict with the fields
href, rel, type, hreflang, title, and length. Href is mandatory for
ATOM.
This method can be called with:
- the fields of a link as keyword arguments
- the fields of a link as a dictionary
- a list of dictionaries containing the link fields
A link has the following fields:
- *href* is the URI of the referenced resource (typically a Web page)
- *rel* contains a single link relationship type. It can be a full URI,
or one of the following predefined values (default=alternate):
- *alternate* an alternate representation of the entry or feed, for
example a permalink to the html version of the entry, or the
front page of the weblog.
- *enclosure* a related resource which is potentially large in size
and might require special handling, for example an audio or video
recording.
- *related* an document related to the entry or feed.
- *self* the feed itself.
- *via* the source of the information provided in the entry.
- *type* indicates the media type of the resource.
- *hreflang* indicates the language of the referenced resource.
- *title* human readable information about the link, typically for
display purposes.
- *length* the length of the resource, in bytes.
RSS only supports one link with nothing but a URL. So for the RSS link
element the last link with rel=alternate is used.
RSS also supports one enclusure element per entry which is covered by
the link element in ATOM feed entries. So for the RSS enclusure element
the last link with rel=enclosure is used.
:param link: Dict or list of dicts with data.
:param replace: Add or replace old data.
:returns: List of link data.
'''
if link is None and kwargs:
link = kwargs
if link is not None:
if replace or self.__atom_link is None:
self.__atom_link = []
self.__atom_link += ensure_format(
link,
set(['href', 'rel', 'type', 'hreflang', 'title', 'length']),
set(['href']),
{'rel': ['alternate', 'enclosure', 'related', 'self', 'via']},
{'rel': 'alternate'})
# RSS only needs one URL. We use the first link for RSS:
for l in self.__atom_link:
if l.get('rel') == 'alternate':
self.__rss_link = l['href']
elif l.get('rel') == 'enclosure':
self.__rss_enclosure = {'url': l['href']}
self.__rss_enclosure['type'] = l.get('type')
self.__rss_enclosure['length'] = l.get('length') or '0'
# return the set with more information (atom)
return self.__atom_link
def summary(self, summary=None, type=None):
'''Get or set the summary element of an entry which conveys a short
summary, abstract, or excerpt of the entry. Summary is an ATOM only
element and should be provided if there either is no content provided
for the entry, or that content is not inline (i.e., contains a src
attribute), or if the content is encoded in base64. This method will
also set the rss:description field if it wasn't previously set or
contains the old value of summary.
:param summary: Summary of the entries contents.
:returns: Summary of the entries contents.
'''
if summary is not None:
# Replace the RSS description with the summary if it was the
# summary before. Not if it is the description.
if not self.__rss_description or (
self.__atom_summary and
self.__rss_description == self.__atom_summary.get("summary")
):
self.__rss_description = summary
self.__atom_summary = {'summary': summary}
if type is not None:
self.__atom_summary['type'] = type
return self.__atom_summary
def description(self, description=None, isSummary=False):
'''Get or set the description value which is the item synopsis.
Description is an RSS only element. For ATOM feeds it is split in
summary and content. The isSummary parameter can be used to control
which ATOM value is set when setting description.
:param description: Description of the entry.
:param isSummary: If the description should be used as content or
summary.
:returns: The entries description.
'''
if description is not None:
self.__rss_description = description
if isSummary:
self.__atom_summary = description
else:
self.__atom_content = {'content': description}
return self.__rss_description
def category(self, category=None, replace=False, **kwargs):
'''Get or set categories that the entry belongs to.
This method can be called with:
- the fields of a category as keyword arguments
- the fields of a category as a dictionary
- a list of dictionaries containing the category fields
A categories has the following fields:
- *term* identifies the category
- *scheme* identifies the categorization scheme via a URI.
- *label* provides a human-readable label for display
If a label is present it is used for the RSS feeds. Otherwise the term
is used. The scheme is used for the domain attribute in RSS.
:param category: Dict or list of dicts with data.
:param replace: Add or replace old data.
:returns: List of category data.
'''
if category is None and kwargs:
category = kwargs
if category is not None:
if replace or self.__atom_category is None:
self.__atom_category = []
self.__atom_category += ensure_format(
category,
set(['term', 'scheme', 'label']),
set(['term']))
# Map the ATOM categories to RSS categories. Use the atom:label as
# name or if not present the atom:term. The atom:scheme is the
# rss:domain.
self.__rss_category = []
for cat in self.__atom_category:
rss_cat = {}
rss_cat['value'] = cat.get('label', cat['term'])
if cat.get('scheme'):
rss_cat['domain'] = cat['scheme']
self.__rss_category.append(rss_cat)
return self.__atom_category
def contributor(self, contributor=None, replace=False, **kwargs):
'''Get or set the contributor data of the feed. This is an ATOM only
value.
This method can be called with:
- the fields of an contributor as keyword arguments
- the fields of an contributor as a dictionary
- a list of dictionaries containing the contributor fields
An contributor has the following fields:
- *name* conveys a human-readable name for the person.
- *uri* contains a home page for the person.
- *email* contains an email address for the person.
:param contributor: Dictionary or list of dictionaries with contributor
data.
:param replace: Add or replace old data.
:returns: List of contributors as dictionaries.
'''
if contributor is None and kwargs:
contributor = kwargs
if contributor is not None:
if replace or self.__atom_contributor is None:
self.__atom_contributor = []
self.__atom_contributor += ensure_format(
contributor, set(['name', 'email', 'uri']), set(['name']))
return self.__atom_contributor
def published(self, published=None):
'''Set or get the published value which contains the time of the initial
creation or first availability of the entry.
The value can either be a string which will automatically be parsed or
a datetime.datetime object. In any case it is necessary that the value
include timezone information.
:param published: The creation date.
:returns: Creation date as datetime.datetime
'''
if published is not None:
if isinstance(published, string_types):
published = dateutil.parser.parse(published)
if not isinstance(published, datetime):
raise ValueError('Invalid datetime format')
if published.tzinfo is None:
raise ValueError('Datetime object has no timezone info')
self.__atom_published = published
self.__rss_pubDate = published
return self.__atom_published
def pubDate(self, pubDate=None):
'''Get or set the pubDate of the entry which indicates when the entry
was published. This method is just another name for the published(...)
method.
'''
return self.published(pubDate)
def pubdate(self, pubDate=None):
'''Get or set the pubDate of the entry which indicates when the entry
was published. This method is just another name for the published(...)
method.
pubdate() is deprecated and may be removed in feedgen 0.8. Use
pubDate() instead.
'''
warnings.warn('pubdate(…) is deprecated and may be removed in feedgen '
'≥ 0.8. Use pubDate(…) instead.')
return self.published(pubDate)
def rights(self, rights=None):
'''Get or set the rights value of the entry which conveys information
about rights, e.g. copyrights, held in and over the entry. This ATOM
value will also set rss:copyright.
:param rights: Rights information of the feed.
:returns: Rights information of the feed.
'''
if rights is not None:
self.__atom_rights = rights
return self.__atom_rights
def comments(self, comments=None):
'''Get or set the value of comments which is the URL of the comments
page for the item. This is a RSS only value.
:param comments: URL to the comments page.
:returns: URL to the comments page.
'''
if comments is not None:
self.__rss_comments = comments
return self.__rss_comments
def source(self, url=None, title=None):
'''Get or set the source for the current feed entry.
Note that ATOM feeds support a lot more sub elements than title and URL
(which is what RSS supports) but these are currently not supported.
Patches are welcome.
:param url: Link to the source.
:param title: Title of the linked resource
:returns: Source element as dictionaries.
'''
if url is not None and title is not None:
self.__rss_source = {'url': url, 'title': title}
self.__atom_source = {'link': url, 'title': title}
return self.__rss_source
def enclosure(self, url=None, length=None, type=None):
'''Get or set the value of enclosure which describes a media object
that is attached to the item. This is a RSS only value which is
represented by link(rel=enclosure) in ATOM. ATOM feeds can furthermore
contain several enclosures while RSS may contain only one. That is why
this method, if repeatedly called, will add more than one enclosures to
the feed. However, only the last one is used for RSS.
:param url: URL of the media object.
:param length: Size of the media in bytes.
:param type: Mimetype of the linked media.
:returns: Data of the enclosure element.
'''
if url is not None:
self.link(href=url, rel='enclosure', type=type, length=length)
return self.__rss_enclosure
def ttl(self, ttl=None):
'''Get or set the ttl value. It is an RSS only element. ttl stands for
time to live. It's a number of minutes that indicates how long a
channel can be cached before refreshing from the source.
:param ttl: Integer value representing the time to live.
:returns: Time to live of of the entry.
'''
if ttl is not None:
self.__rss_ttl = int(ttl)
return self.__rss_ttl
def load_extension(self, name, atom=True, rss=True):
'''Load a specific extension by name.
:param name: Name of the extension to load.
:param atom: If the extension should be used for ATOM feeds.
:param rss: If the extension should be used for RSS feeds.
'''
# Check loaded extensions
if not isinstance(self.__extensions, dict):
self.__extensions = {}
if name in self.__extensions.keys():
raise ImportError('Extension already loaded')
# Load extension
extname = name[0].upper() + name[1:] + 'EntryExtension'
try:
supmod = __import__('feedgen.ext.%s_entry' % name)
extmod = getattr(supmod.ext, name + '_entry')
except ImportError:
# Use FeedExtension module instead
supmod = __import__('feedgen.ext.%s' % name)
extmod = getattr(supmod.ext, name)
ext = getattr(extmod, extname)
self.register_extension(name, ext, atom, rss)
def register_extension(self, namespace, extension_class_entry=None,
atom=True, rss=True):
'''Register a specific extension by classes to a namespace.
:param namespace: namespace for the extension
:param extension_class_entry: Class of the entry extension to load.
:param atom: If the extension should be used for ATOM feeds.
:param rss: If the extension should be used for RSS feeds.
'''
# Check loaded extensions
# `load_extension` ignores the "Extension" suffix.
if not isinstance(self.__extensions, dict):
self.__extensions = {}
if namespace in self.__extensions.keys():
raise ImportError('Extension already loaded')
if not extension_class_entry:
raise ImportError('No extension class')
extinst = extension_class_entry()
setattr(self, namespace, extinst)
# `load_extension` registry
self.__extensions[namespace] = {
'inst': extinst,
'extension_class_entry': extension_class_entry,
'atom': atom,
'rss': rss
}

View file

@ -1,6 +0,0 @@
# -*- coding: utf-8 -*-
"""
===========
feedgen.ext
===========
"""

View file

@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.base
~~~~~~~~~~~~~~~~
Basic FeedGenerator extension which does nothing but provides all necessary
methods.
:copyright: 2013, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
class BaseExtension(object):
'''Basic FeedGenerator extension.
'''
def extend_ns(self):
'''Returns a dict that will be used in the namespace map for the feed.
'''
return dict()
def extend_rss(self, feed):
'''Extend a RSS feed xml structure containing all previously set fields.
:param feed: The feed xml root element.
:returns: The feed root element.
'''
return feed
def extend_atom(self, feed):
'''Extend an ATOM feed xml structure containing all previously set
fields.
:param feed: The feed xml root element.
:returns: The feed root element.
'''
return feed
class BaseEntryExtension(BaseExtension):
'''Basic FeedEntry extension.
'''

View file

@ -1,407 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.dc
~~~~~~~~~~~~~~~~~~~
Extends the FeedGenerator to add Dubline Core Elements to the feeds.
Descriptions partly taken from
http://dublincore.org/documents/dcmi-terms/#elements-coverage
:copyright: 2013-2017, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
from feedgen.ext.base import BaseExtension
from feedgen.util import xml_elem
class DcBaseExtension(BaseExtension):
'''Dublin Core Elements extension for podcasts.
'''
def __init__(self):
# http://dublincore.org/documents/usageguide/elements.shtml
# http://dublincore.org/documents/dces/
# http://dublincore.org/documents/dcmi-terms/
self._dcelem_contributor = None
self._dcelem_coverage = None
self._dcelem_creator = None
self._dcelem_date = None
self._dcelem_description = None
self._dcelem_format = None
self._dcelem_identifier = None
self._dcelem_language = None
self._dcelem_publisher = None
self._dcelem_relation = None
self._dcelem_rights = None
self._dcelem_source = None
self._dcelem_subject = None
self._dcelem_title = None
self._dcelem_type = None
def extend_ns(self):
return {'dc': 'http://purl.org/dc/elements/1.1/'}
def _extend_xml(self, xml_element):
'''Extend xml_element with set DC fields.
:param xml_element: etree element
'''
DCELEMENTS_NS = 'http://purl.org/dc/elements/1.1/'
for elem in ['contributor', 'coverage', 'creator', 'date',
'description', 'language', 'publisher', 'relation',
'rights', 'source', 'subject', 'title', 'type', 'format',
'identifier']:
if hasattr(self, '_dcelem_%s' % elem):
for val in getattr(self, '_dcelem_%s' % elem) or []:
node = xml_elem('{%s}%s' % (DCELEMENTS_NS, elem),
xml_element)
node.text = val
def extend_atom(self, atom_feed):
'''Extend an Atom feed with the set DC fields.
:param atom_feed: The feed root element
:returns: The feed root element
'''
self._extend_xml(atom_feed)
return atom_feed
def extend_rss(self, rss_feed):
'''Extend a RSS feed with the set DC fields.
:param rss_feed: The feed root element
:returns: The feed root element.
'''
channel = rss_feed[0]
self._extend_xml(channel)
return rss_feed
def dc_contributor(self, contributor=None, replace=False):
'''Get or set the dc:contributor which is an entity responsible for
making contributions to the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-contributor
:param contributor: Contributor or list of contributors.
:param replace: Replace alredy set contributors (deault: False).
:returns: List of contributors.
'''
if contributor is not None:
if not isinstance(contributor, list):
contributor = [contributor]
if replace or not self._dcelem_contributor:
self._dcelem_contributor = []
self._dcelem_contributor += contributor
return self._dcelem_contributor
def dc_coverage(self, coverage=None, replace=True):
'''Get or set the dc:coverage which indicated the spatial or temporal
topic of the resource, the spatial applicability of the resource, or
the jurisdiction under which the resource is relevant.
Spatial topic and spatial applicability may be a named place or a
location specified by its geographic coordinates. Temporal topic may be
a named period, date, or date range. A jurisdiction may be a named
administrative entity or a geographic place to which the resource
applies. Recommended best practice is to use a controlled vocabulary
such as the Thesaurus of Geographic Names [TGN]. Where appropriate,
named places or time periods can be used in preference to numeric
identifiers such as sets of coordinates or date ranges.
References:
[TGN] http://www.getty.edu/research/tools/vocabulary/tgn/index.html
:param coverage: Coverage of the feed.
:param replace: Replace already set coverage (default: True).
:returns: Coverage of the feed.
'''
if coverage is not None:
if not isinstance(coverage, list):
coverage = [coverage]
if replace or not self._dcelem_coverage:
self._dcelem_coverage = []
self._dcelem_coverage = coverage
return self._dcelem_coverage
def dc_creator(self, creator=None, replace=False):
'''Get or set the dc:creator which is an entity primarily responsible
for making the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-creator
:param creator: Creator or list of creators.
:param replace: Replace alredy set creators (deault: False).
:returns: List of creators.
'''
if creator is not None:
if not isinstance(creator, list):
creator = [creator]
if replace or not self._dcelem_creator:
self._dcelem_creator = []
self._dcelem_creator += creator
return self._dcelem_creator
def dc_date(self, date=None, replace=True):
'''Get or set the dc:date which describes a point or period of time
associated with an event in the lifecycle of the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-date
:param date: Date or list of dates.
:param replace: Replace alredy set dates (deault: True).
:returns: List of dates.
'''
if date is not None:
if not isinstance(date, list):
date = [date]
if replace or not self._dcelem_date:
self._dcelem_date = []
self._dcelem_date += date
return self._dcelem_date
def dc_description(self, description=None, replace=True):
'''Get or set the dc:description which is an account of the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-description
:param description: Description or list of descriptions.
:param replace: Replace alredy set descriptions (deault: True).
:returns: List of descriptions.
'''
if description is not None:
if not isinstance(description, list):
description = [description]
if replace or not self._dcelem_description:
self._dcelem_description = []
self._dcelem_description += description
return self._dcelem_description
def dc_format(self, format=None, replace=True):
'''Get or set the dc:format which describes the file format, physical
medium, or dimensions of the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-format
:param format: Format of the resource or list of formats.
:param replace: Replace alredy set format (deault: True).
:returns: Format of the resource.
'''
if format is not None:
if not isinstance(format, list):
format = [format]
if replace or not self._dcelem_format:
self._dcelem_format = []
self._dcelem_format += format
return self._dcelem_format
def dc_identifier(self, identifier=None, replace=True):
'''Get or set the dc:identifier which should be an unambiguous
reference to the resource within a given context.
For more inidentifierion see:
http://dublincore.org/documents/dcmi-terms/#elements-identifier
:param identifier: Identifier of the resource or list of identifiers.
:param replace: Replace alredy set identifier (deault: True).
:returns: Identifiers of the resource.
'''
if identifier is not None:
if not isinstance(identifier, list):
identifier = [identifier]
if replace or not self._dcelem_identifier:
self._dcelem_identifier = []
self._dcelem_identifier += identifier
return self._dcelem_identifier
def dc_language(self, language=None, replace=True):
'''Get or set the dc:language which describes a language of the
resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-language
:param language: Language or list of languages.
:param replace: Replace alredy set languages (deault: True).
:returns: List of languages.
'''
if language is not None:
if not isinstance(language, list):
language = [language]
if replace or not self._dcelem_language:
self._dcelem_language = []
self._dcelem_language += language
return self._dcelem_language
def dc_publisher(self, publisher=None, replace=False):
'''Get or set the dc:publisher which is an entity responsible for
making the resource available.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-publisher
:param publisher: Publisher or list of publishers.
:param replace: Replace alredy set publishers (deault: False).
:returns: List of publishers.
'''
if publisher is not None:
if not isinstance(publisher, list):
publisher = [publisher]
if replace or not self._dcelem_publisher:
self._dcelem_publisher = []
self._dcelem_publisher += publisher
return self._dcelem_publisher
def dc_relation(self, relation=None, replace=False):
'''Get or set the dc:relation which describes a related resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-relation
:param relation: Relation or list of relations.
:param replace: Replace alredy set relations (deault: False).
:returns: List of relations.
'''
if relation is not None:
if not isinstance(relation, list):
relation = [relation]
if replace or not self._dcelem_relation:
self._dcelem_relation = []
self._dcelem_relation += relation
return self._dcelem_relation
def dc_rights(self, rights=None, replace=False):
'''Get or set the dc:rights which may contain information about rights
held in and over the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-rights
:param rights: Rights information or list of rights information.
:param replace: Replace alredy set rightss (deault: False).
:returns: List of rights information.
'''
if rights is not None:
if not isinstance(rights, list):
rights = [rights]
if replace or not self._dcelem_rights:
self._dcelem_rights = []
self._dcelem_rights += rights
return self._dcelem_rights
def dc_source(self, source=None, replace=False):
'''Get or set the dc:source which is a related resource from which the
described resource is derived.
The described resource may be derived from the related resource in
whole or in part. Recommended best practice is to identify the related
resource by means of a string conforming to a formal identification
system.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-source
:param source: Source or list of sources.
:param replace: Replace alredy set sources (deault: False).
:returns: List of sources.
'''
if source is not None:
if not isinstance(source, list):
source = [source]
if replace or not self._dcelem_source:
self._dcelem_source = []
self._dcelem_source += source
return self._dcelem_source
def dc_subject(self, subject=None, replace=False):
'''Get or set the dc:subject which describes the topic of the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-subject
:param subject: Subject or list of subjects.
:param replace: Replace alredy set subjects (deault: False).
:returns: List of subjects.
'''
if subject is not None:
if not isinstance(subject, list):
subject = [subject]
if replace or not self._dcelem_subject:
self._dcelem_subject = []
self._dcelem_subject += subject
return self._dcelem_subject
def dc_title(self, title=None, replace=True):
'''Get or set the dc:title which is a name given to the resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-title
:param title: Title or list of titles.
:param replace: Replace alredy set titles (deault: False).
:returns: List of titles.
'''
if title is not None:
if not isinstance(title, list):
title = [title]
if replace or not self._dcelem_title:
self._dcelem_title = []
self._dcelem_title += title
return self._dcelem_title
def dc_type(self, type=None, replace=False):
'''Get or set the dc:type which describes the nature or genre of the
resource.
For more information see:
http://dublincore.org/documents/dcmi-terms/#elements-type
:param type: Type or list of types.
:param replace: Replace alredy set types (deault: False).
:returns: List of types.
'''
if type is not None:
if not isinstance(type, list):
type = [type]
if replace or not self._dcelem_type:
self._dcelem_type = []
self._dcelem_type += type
return self._dcelem_type
class DcExtension(DcBaseExtension):
'''Dublin Core Elements extension for podcasts.
'''
class DcEntryExtension(DcBaseExtension):
'''Dublin Core Elements extension for podcasts.
'''
def extend_atom(self, entry):
'''Add dc elements to an atom item. Alters the item itself.
:param entry: An atom entry element.
:returns: The entry element.
'''
self._extend_xml(entry)
return entry
def extend_rss(self, item):
'''Add dc elements to a RSS item. Alters the item itself.
:param item: A RSS item element.
:returns: The item element.
'''
self._extend_xml(item)
return item

View file

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.geo
~~~~~~~~~~~~~~~~~~~
Extends the FeedGenerator to produce Simple GeoRSS feeds.
:copyright: 2017, Bob Breznak <bob.breznak@gmail.com>
:license: FreeBSD and LGPL, see license.* for more details.
'''
from feedgen.ext.base import BaseExtension
class GeoExtension(BaseExtension):
'''FeedGenerator extension for Simple GeoRSS.
'''
def extend_ns(self):
return {'georss': 'http://www.georss.org/georss'}

View file

@ -1,329 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.geo_entry
~~~~~~~~~~~~~~~~~~~
Extends the FeedGenerator to produce Simple GeoRSS feeds.
:copyright: 2017, Bob Breznak <bob.breznak@gmail.com>
:license: FreeBSD and LGPL, see license.* for more details.
'''
import numbers
import warnings
from feedgen.ext.base import BaseEntryExtension
from feedgen.util import xml_elem
class GeoRSSPolygonInteriorWarning(Warning):
"""
Simple placeholder for warning about ignored polygon interiors.
Stores the original geom on a ``geom`` attribute (if required warnings are
raised as errors).
"""
def __init__(self, geom, *args, **kwargs):
self.geom = geom
super(GeoRSSPolygonInteriorWarning, self).__init__(*args, **kwargs)
def __str__(self):
return '{:d} interiors of polygon ignored'.format(
len(self.geom.__geo_interface__['coordinates']) - 1
) # ignore exterior in count
class GeoRSSGeometryError(ValueError):
"""
Subclass of ValueError for a GeoRSS geometry error
Only some geometries are supported in Simple GeoRSS, so if not raise an
error. Offending geometry is stored on the ``geom`` attribute.
"""
def __init__(self, geom, *args, **kwargs):
self.geom = geom
super(GeoRSSGeometryError, self).__init__(*args, **kwargs)
def __str__(self):
msg = "Geometry of type '{}' not in Point, Linestring or Polygon"
return msg.format(
self.geom.__geo_interface__['type']
)
class GeoEntryExtension(BaseEntryExtension):
'''FeedEntry extension for Simple GeoRSS.
'''
def __init__(self):
'''Simple GeoRSS tag'''
# geometries
self.__point = None
self.__line = None
self.__polygon = None
self.__box = None
# additional properties
self.__featuretypetag = None
self.__relationshiptag = None
self.__featurename = None
# elevation
self.__elev = None
self.__floor = None
# radius
self.__radius = None
def extend_file(self, entry):
'''Add additional fields to an RSS item.
:param feed: The RSS item XML element to use.
'''
GEO_NS = 'http://www.georss.org/georss'
if self.__point:
point = xml_elem('{%s}point' % GEO_NS, entry)
point.text = self.__point
if self.__line:
line = xml_elem('{%s}line' % GEO_NS, entry)
line.text = self.__line
if self.__polygon:
polygon = xml_elem('{%s}polygon' % GEO_NS, entry)
polygon.text = self.__polygon
if self.__box:
box = xml_elem('{%s}box' % GEO_NS, entry)
box.text = self.__box
if self.__featuretypetag:
featuretypetag = xml_elem('{%s}featuretypetag' % GEO_NS, entry)
featuretypetag.text = self.__featuretypetag
if self.__relationshiptag:
relationshiptag = xml_elem('{%s}relationshiptag' % GEO_NS, entry)
relationshiptag.text = self.__relationshiptag
if self.__featurename:
featurename = xml_elem('{%s}featurename' % GEO_NS, entry)
featurename.text = self.__featurename
if self.__elev:
elevation = xml_elem('{%s}elev' % GEO_NS, entry)
elevation.text = str(self.__elev)
if self.__floor:
floor = xml_elem('{%s}floor' % GEO_NS, entry)
floor.text = str(self.__floor)
if self.__radius:
radius = xml_elem('{%s}radius' % GEO_NS, entry)
radius.text = str(self.__radius)
return entry
def extend_rss(self, entry):
return self.extend_file(entry)
def extend_atom(self, entry):
return self.extend_file(entry)
def point(self, point=None):
'''Get or set the georss:point of the entry.
:param point: The GeoRSS formatted point (i.e. "42.36 -71.05")
:returns: The current georss:point of the entry.
'''
if point is not None:
self.__point = point
return self.__point
def line(self, line=None):
'''Get or set the georss:line of the entry
:param point: The GeoRSS formatted line (i.e. "45.256 -110.45 46.46
-109.48 43.84 -109.86")
:return: The current georss:line of the entry
'''
if line is not None:
self.__line = line
return self.__line
def polygon(self, polygon=None):
'''Get or set the georss:polygon of the entry
:param polygon: The GeoRSS formatted polygon (i.e. "45.256 -110.45
46.46 -109.48 43.84 -109.86 45.256 -110.45")
:return: The current georss:polygon of the entry
'''
if polygon is not None:
self.__polygon = polygon
return self.__polygon
def box(self, box=None):
'''
Get or set the georss:box of the entry
:param box: The GeoRSS formatted box (i.e. "42.943 -71.032 43.039
-69.856")
:return: The current georss:box of the entry
'''
if box is not None:
self.__box = box
return self.__box
def featuretypetag(self, featuretypetag=None):
'''
Get or set the georss:featuretypetag of the entry
:param featuretypetag: The GeoRSS feaaturertyptag (e.g. "city")
:return: The current georss:featurertypetag
'''
if featuretypetag is not None:
self.__featuretypetag = featuretypetag
return self.__featuretypetag
def relationshiptag(self, relationshiptag=None):
'''
Get or set the georss:relationshiptag of the entry
:param relationshiptag: The GeoRSS relationshiptag (e.g.
"is-centred-at")
:return: the current georss:relationshiptag
'''
if relationshiptag is not None:
self.__relationshiptag = relationshiptag
return self.__relationshiptag
def featurename(self, featurename=None):
'''
Get or set the georss:featurename of the entry
:param featuretypetag: The GeoRSS featurename (e.g. "Footscray")
:return: the current georss:featurename
'''
if featurename is not None:
self.__featurename = featurename
return self.__featurename
def elev(self, elev=None):
'''
Get or set the georss:elev of the entry
:param elev: The GeoRSS elevation (e.g. 100.3)
:type elev: numbers.Number
:return: the current georss:elev
'''
if elev is not None:
if not isinstance(elev, numbers.Number):
raise ValueError("elev tag must be numeric: {}".format(elev))
self.__elev = elev
return self.__elev
def floor(self, floor=None):
'''
Get or set the georss:floor of the entry
:param floor: The GeoRSS floor (e.g. 4)
:type floor: int
:return: the current georss:floor
'''
if floor is not None:
if not isinstance(floor, int):
raise ValueError("floor tag must be int: {}".format(floor))
self.__floor = floor
return self.__floor
def radius(self, radius=None):
'''
Get or set the georss:radius of the entry
:param radius: The GeoRSS radius (e.g. 100.3)
:type radius: numbers.Number
:return: the current georss:radius
'''
if radius is not None:
if not isinstance(radius, numbers.Number):
raise ValueError(
"radius tag must be numeric: {}".format(radius)
)
self.__radius = radius
return self.__radius
def geom_from_geo_interface(self, geom):
'''
Generate a georss geometry from some Python object with a
``__geo_interface__`` property (see the `geo_interface specification by
Sean Gillies`_geointerface )
Note only a subset of GeoJSON (see `geojson.org`_geojson ) can be
easily converted to GeoRSS:
- Point
- LineString
- Polygon (if there are holes / donuts in the polygons a warning will
be generaated
Other GeoJson types will raise a ``ValueError``.
.. note:: The geometry is assumed to be x, y as longitude, latitude in
the WGS84 projection.
.. _geointerface: https://gist.github.com/sgillies/2217756
.. _geojson: https://geojson.org/
:param geom: Geometry object with a __geo_interface__ property
:return: the formatted GeoRSS geometry
'''
geojson = geom.__geo_interface__
if geojson['type'] not in ('Point', 'LineString', 'Polygon'):
raise GeoRSSGeometryError(geom)
if geojson['type'] == 'Point':
coords = '{:f} {:f}'.format(
geojson['coordinates'][1], # latitude is y
geojson['coordinates'][0]
)
return self.point(coords)
elif geojson['type'] == 'LineString':
coords = ' '.join(
'{:f} {:f}'.format(vertex[1], vertex[0])
for vertex in
geojson['coordinates']
)
return self.line(coords)
elif geojson['type'] == 'Polygon':
if len(geojson['coordinates']) > 1:
warnings.warn(GeoRSSPolygonInteriorWarning(geom))
coords = ' '.join(
'{:f} {:f}'.format(vertex[1], vertex[0])
for vertex in
geojson['coordinates'][0]
)
return self.polygon(coords)

View file

@ -1,183 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.media
~~~~~~~~~~~~~~~~~
Extends the feedgen to produce media tags.
:copyright: 2013-2017, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
from feedgen.ext.base import BaseEntryExtension, BaseExtension
from feedgen.util import ensure_format, xml_elem
MEDIA_NS = 'http://search.yahoo.com/mrss/'
class MediaExtension(BaseExtension):
'''FeedGenerator extension for torrent feeds.
'''
def extend_ns(self):
return {'media': MEDIA_NS}
class MediaEntryExtension(BaseEntryExtension):
'''FeedEntry extension for media tags.
'''
def __init__(self):
self.__media_content = []
self.__media_thumbnail = []
def extend_atom(self, entry):
'''Add additional fields to an RSS item.
:param feed: The RSS item XML element to use.
'''
groups = {None: entry}
for media_content in self.__media_content:
# Define current media:group
group = groups.get(media_content.get('group'))
if group is None:
group = xml_elem('{%s}group' % MEDIA_NS, entry)
groups[media_content.get('group')] = group
# Add content
content = xml_elem('{%s}content' % MEDIA_NS, group)
for attr in ('url', 'fileSize', 'type', 'medium', 'isDefault',
'expression', 'bitrate', 'framerate', 'samplingrate',
'channels', 'duration', 'height', 'width', 'lang'):
if media_content.get(attr):
content.set(attr, media_content[attr])
for media_thumbnail in self.__media_thumbnail:
# Define current media:group
group = groups.get(media_thumbnail.get('group'))
if group is None:
group = xml_elem('{%s}group' % MEDIA_NS, entry)
groups[media_thumbnail.get('group')] = group
# Add thumbnails
thumbnail = xml_elem('{%s}thumbnail' % MEDIA_NS, group)
for attr in ('url', 'height', 'width', 'time'):
if media_thumbnail.get(attr):
thumbnail.set(attr, media_thumbnail[attr])
return entry
def extend_rss(self, item):
return self.extend_atom(item)
def content(self, content=None, replace=False, group='default', **kwargs):
'''Get or set media:content data.
This method can be called with:
- the fields of a media:content as keyword arguments
- the fields of a media:content as a dictionary
- a list of dictionaries containing the media:content fields
<media:content> is a sub-element of either <item> or <media:group>.
Media objects that are not the same content should not be included in
the same <media:group> element. The sequence of these items implies
the order of presentation. While many of the attributes appear to be
audio/video specific, this element can be used to publish any type
of media. It contains 14 attributes, most of which are optional.
media:content has the following fields:
- *url* should specify the direct URL to the media object.
- *fileSize* number of bytes of the media object.
- *type* standard MIME type of the object.
- *medium* type of object (image | audio | video | document |
executable).
- *isDefault* determines if this is the default object.
- *expression* determines if the object is a sample or the full version
of the object, or even if it is a continuous stream (sample | full |
nonstop).
- *bitrate* kilobits per second rate of media.
- *framerate* number of frames per second for the media object.
- *samplingrate* number of samples per second taken to create the media
object. It is expressed in thousands of samples per second (kHz).
- *channels* number of audio channels in the media object.
- *duration* number of seconds the media object plays.
- *height* height of the media object.
- *width* width of the media object.
- *lang* is the primary language encapsulated in the media object.
:param content: Dictionary or list of dictionaries with content data.
:param replace: Add or replace old data.
:param group: Media group to put this content in.
:returns: The media content tag.
'''
# Handle kwargs
if content is None and kwargs:
content = kwargs
# Handle new data
if content is not None:
# Reset data if we want to replace them
if replace or self.__media_content is None:
self.__media_content = []
# Ensure list
if not isinstance(content, list):
content = [content]
# define media group
for c in content:
c['group'] = c.get('group', group)
self.__media_content += ensure_format(
content,
set(['url', 'fileSize', 'type', 'medium', 'isDefault',
'expression', 'bitrate', 'framerate', 'samplingrate',
'channels', 'duration', 'height', 'width', 'lang',
'group']),
set(['url', 'group']))
return self.__media_content
def thumbnail(self, thumbnail=None, replace=False, group='default',
**kwargs):
'''Get or set media:thumbnail data.
This method can be called with:
- the fields of a media:content as keyword arguments
- the fields of a media:content as a dictionary
- a list of dictionaries containing the media:content fields
Allows particular images to be used as representative images for
the media object. If multiple thumbnails are included, and time
coding is not at play, it is assumed that the images are in order
of importance. It has one required attribute and three optional
attributes.
media:thumbnail has the following fields:
- *url* should specify the direct URL to the media object.
- *height* height of the media object.
- *width* width of the media object.
- *time* specifies the time offset in relation to the media object.
:param thumbnail: Dictionary or list of dictionaries with thumbnail
data.
:param replace: Add or replace old data.
:param group: Media group to put this content in.
:returns: The media thumbnail tag.
'''
# Handle kwargs
if thumbnail is None and kwargs:
thumbnail = kwargs
# Handle new data
if thumbnail is not None:
# Reset data if we want to replace them
if replace or self.__media_thumbnail is None:
self.__media_thumbnail = []
# Ensure list
if not isinstance(thumbnail, list):
thumbnail = [thumbnail]
# Define media group
for t in thumbnail:
t['group'] = t.get('group', group)
self.__media_thumbnail += ensure_format(
thumbnail,
set(['url', 'height', 'width', 'time', 'group']),
set(['url', 'group']))
return self.__media_thumbnail

View file

@ -1,355 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.podcast
~~~~~~~~~~~~~~~~~~~
Extends the FeedGenerator to produce podcasts.
:copyright: 2013, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
from feedgen.compat import string_types
from feedgen.ext.base import BaseExtension
from feedgen.util import ensure_format, xml_elem
class PodcastExtension(BaseExtension):
'''FeedGenerator extension for podcasts.
'''
def __init__(self):
# ITunes tags
# http://www.apple.com/itunes/podcasts/specs.html#rss
self.__itunes_author = None
self.__itunes_block = None
self.__itunes_category = None
self.__itunes_image = None
self.__itunes_explicit = None
self.__itunes_complete = None
self.__itunes_new_feed_url = None
self.__itunes_owner = None
self.__itunes_subtitle = None
self.__itunes_summary = None
def extend_ns(self):
return {'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd'}
def extend_rss(self, rss_feed):
'''Extend an RSS feed root with set itunes fields.
:returns: The feed root element.
'''
ITUNES_NS = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
channel = rss_feed[0]
if self.__itunes_author:
author = xml_elem('{%s}author' % ITUNES_NS, channel)
author.text = self.__itunes_author
if self.__itunes_block is not None:
block = xml_elem('{%s}block' % ITUNES_NS, channel)
block.text = 'yes' if self.__itunes_block else 'no'
for c in self.__itunes_category or []:
if not c.get('cat'):
continue
category = channel.find(
'{%s}category[@text="%s"]' % (ITUNES_NS, c.get('cat')))
if category is None:
category = xml_elem('{%s}category' % ITUNES_NS, channel)
category.attrib['text'] = c.get('cat')
if c.get('sub'):
subcategory = xml_elem('{%s}category' % ITUNES_NS, category)
subcategory.attrib['text'] = c.get('sub')
if self.__itunes_image:
image = xml_elem('{%s}image' % ITUNES_NS, channel)
image.attrib['href'] = self.__itunes_image
if self.__itunes_explicit in ('yes', 'no', 'clean'):
explicit = xml_elem('{%s}explicit' % ITUNES_NS, channel)
explicit.text = self.__itunes_explicit
if self.__itunes_complete in ('yes', 'no'):
complete = xml_elem('{%s}complete' % ITUNES_NS, channel)
complete.text = self.__itunes_complete
if self.__itunes_new_feed_url:
new_feed_url = xml_elem('{%s}new-feed-url' % ITUNES_NS, channel)
new_feed_url.text = self.__itunes_new_feed_url
if self.__itunes_owner:
owner = xml_elem('{%s}owner' % ITUNES_NS, channel)
owner_name = xml_elem('{%s}name' % ITUNES_NS, owner)
owner_name.text = self.__itunes_owner.get('name')
owner_email = xml_elem('{%s}email' % ITUNES_NS, owner)
owner_email.text = self.__itunes_owner.get('email')
if self.__itunes_subtitle:
subtitle = xml_elem('{%s}subtitle' % ITUNES_NS, channel)
subtitle.text = self.__itunes_subtitle
if self.__itunes_summary:
summary = xml_elem('{%s}summary' % ITUNES_NS, channel)
summary.text = self.__itunes_summary
return rss_feed
def itunes_author(self, itunes_author=None):
'''Get or set the itunes:author. The content of this tag is shown in
the Artist column in iTunes. If the tag is not present, iTunes uses the
contents of the <author> tag. If <itunes:author> is not present at the
feed level, iTunes will use the contents of <managingEditor>.
:param itunes_author: The author of the podcast.
:returns: The author of the podcast.
'''
if itunes_author is not None:
self.__itunes_author = itunes_author
return self.__itunes_author
def itunes_block(self, itunes_block=None):
'''Get or set the ITunes block attribute. Use this to prevent the
entire podcast from appearing in the iTunes podcast directory.
:param itunes_block: Block the podcast.
:returns: If the podcast is blocked.
'''
if itunes_block is not None:
self.__itunes_block = itunes_block
return self.__itunes_block
def itunes_category(self, itunes_category=None, replace=False, **kwargs):
'''Get or set the ITunes category which appears in the category column
and in iTunes Store Browser.
The (sub-)category has to be one from the values defined at
http://www.apple.com/itunes/podcasts/specs.html#categories
This method can be called with:
- the fields of an itunes_category as keyword arguments
- the fields of an itunes_category as a dictionary
- a list of dictionaries containing the itunes_category fields
An itunes_category has the following fields:
- *cat* name for a category.
- *sub* name for a subcategory, child of category
If a podcast has more than one subcategory from the same category, the
category is called more than once.
Likei the parameter::
[{"cat":"Arts","sub":"Design"},{"cat":"Arts","sub":"Food"}]
would become::
<itunes:category text="Arts">
<itunes:category text="Design"/>
<itunes:category text="Food"/>
</itunes:category>
:param itunes_category: Dictionary or list of dictionaries with
itunes_category data.
:param replace: Add or replace old data.
:returns: List of itunes_categories as dictionaries.
---
**Important note about deprecated parameter syntax:** Old version of
the feedgen did only support one category plus one subcategory which
would be passed to this ducntion as first two parameters. For
compatibility reasons, this still works but should not be used any may
be removed at any time.
'''
# Ensure old API still works for now. Note that the API is deprecated
# and this fallback may be removed at any time.
if isinstance(itunes_category, string_types):
itunes_category = {'cat': itunes_category}
if replace:
itunes_category['sub'] = replace
replace = True
if itunes_category is None and kwargs:
itunes_category = kwargs
if itunes_category is not None:
if replace or self.__itunes_category is None:
self.__itunes_category = []
self.__itunes_category += ensure_format(itunes_category,
set(['cat', 'sub']),
set(['cat']))
return self.__itunes_category
def itunes_image(self, itunes_image=None):
'''Get or set the image for the podcast. This tag specifies the artwork
for your podcast. Put the URL to the image in the href attribute.
iTunes prefers square .jpg images that are at least 1400x1400 pixels,
which is different from what is specified for the standard RSS image
tag. In order for a podcast to be eligible for an iTunes Store feature,
the accompanying image must be at least 1400x1400 pixels.
iTunes supports images in JPEG and PNG formats with an RGB color space
(CMYK is not supported). The URL must end in ".jpg" or ".png". If the
<itunes:image> tag is not present, iTunes will use the contents of the
RSS image tag.
If you change your podcasts image, also change the files name. iTunes
may not change the image if it checks your feed and the image URL is
the same. The server hosting your cover art image must allow HTTP head
requests for iTS to be able to automatically update your cover art.
:param itunes_image: Image of the podcast.
:returns: Image of the podcast.
'''
if itunes_image is not None:
if itunes_image.endswith('.jpg') or itunes_image.endswith('.png'):
self.__itunes_image = itunes_image
else:
ValueError('Image file must be png or jpg')
return self.__itunes_image
def itunes_explicit(self, itunes_explicit=None):
'''Get or the the itunes:explicit value of the podcast. This tag should
be used to indicate whether your podcast contains explicit material.
The three values for this tag are "yes", "no", and "clean".
If you populate this tag with "yes", an "explicit" parental advisory
graphic will appear next to your podcast artwork on the iTunes Store
and in the Name column in iTunes. If the value is "clean", the parental
advisory type is considered Clean, meaning that no explicit language or
adult content is included anywhere in the episodes, and a "clean"
graphic will appear. If the explicit tag is present and has any other
value (e.g., "no"), you see no indicator blank is the default
advisory type.
:param itunes_explicit: If the podcast contains explicit material.
:returns: If the podcast contains explicit material.
'''
if itunes_explicit is not None:
if itunes_explicit not in ('', 'yes', 'no', 'clean'):
raise ValueError('Invalid value for explicit tag')
self.__itunes_explicit = itunes_explicit
return self.__itunes_explicit
def itunes_complete(self, itunes_complete=None):
'''Get or set the itunes:complete value of the podcast. This tag can be
used to indicate the completion of a podcast.
If you populate this tag with "yes", you are indicating that no more
episodes will be added to the podcast. If the <itunes:complete> tag is
present and has any other value (e.g. no), it will have no effect on
the podcast.
:param itunes_complete: If the podcast is complete.
:returns: If the podcast is complete.
'''
if itunes_complete is not None:
if itunes_complete not in ('yes', 'no', '', True, False):
raise ValueError('Invalid value for complete tag')
if itunes_complete is True:
itunes_complete = 'yes'
if itunes_complete is False:
itunes_complete = 'no'
self.__itunes_complete = itunes_complete
return self.__itunes_complete
def itunes_new_feed_url(self, itunes_new_feed_url=None):
'''Get or set the new-feed-url property of the podcast. This tag allows
you to change the URL where the podcast feed is located
After adding the tag to your old feed, you should maintain the old feed
for 48 hours before retiring it. At that point, iTunes will have
updated the directory with the new feed URL.
:param itunes_new_feed_url: New feed URL.
:returns: New feed URL.
'''
if itunes_new_feed_url is not None:
self.__itunes_new_feed_url = itunes_new_feed_url
return self.__itunes_new_feed_url
def itunes_owner(self, name=None, email=None):
'''Get or set the itunes:owner of the podcast. This tag contains
information that will be used to contact the owner of the podcast for
communication specifically about the podcast. It will not be publicly
displayed.
:param itunes_owner: The owner of the feed.
:returns: Data of the owner of the feed.
'''
if name is not None:
if name and email:
self.__itunes_owner = {'name': name, 'email': email}
elif not name and not email:
self.__itunes_owner = None
else:
raise ValueError('Both name and email have to be set.')
return self.__itunes_owner
def itunes_subtitle(self, itunes_subtitle=None):
'''Get or set the itunes:subtitle value for the podcast. The contents of
this tag are shown in the Description column in iTunes. The subtitle
displays best if it is only a few words long.
:param itunes_subtitle: Subtitle of the podcast.
:returns: Subtitle of the podcast.
'''
if itunes_subtitle is not None:
self.__itunes_subtitle = itunes_subtitle
return self.__itunes_subtitle
def itunes_summary(self, itunes_summary=None):
'''Get or set the itunes:summary value for the podcast. The contents of
this tag are shown in a separate window that appears when the "circled
i" in the Description column is clicked. It also appears on the iTunes
page for your podcast. This field can be up to 4000 characters. If
`<itunes:summary>` is not included, the contents of the <description>
tag are used.
:param itunes_summary: Summary of the podcast.
:returns: Summary of the podcast.
'''
if itunes_summary is not None:
self.__itunes_summary = itunes_summary
return self.__itunes_summary
_itunes_categories = {
'Arts': [
'Design', 'Fashion & Beauty', 'Food', 'Literature',
'Performing Arts', 'Visual Arts'],
'Business': [
'Business News', 'Careers', 'Investing',
'Management & Marketing', 'Shopping'],
'Comedy': [],
'Education': [
'Education', 'Education Technology', 'Higher Education',
'K-12', 'Language Courses', 'Training'],
'Games & Hobbies': [
'Automotive', 'Aviation', 'Hobbies', 'Other Games',
'Video Games'],
'Government & Organizations': [
'Local', 'National', 'Non-Profit', 'Regional'],
'Health': [
'Alternative Health', 'Fitness & Nutrition', 'Self-Help',
'Sexuality'],
'Kids & Family': [],
'Music': [],
'News & Politics': [],
'Religion & Spirituality': [
'Buddhism', 'Christianity', 'Hinduism', 'Islam', 'Judaism',
'Other', 'Spirituality'],
'Science & Medicine': [
'Medicine', 'Natural Sciences', 'Social Sciences'],
'Society & Culture': [
'History', 'Personal Journals', 'Philosophy',
'Places & Travel'],
'Sports & Recreation': [
'Amateur', 'College & High School', 'Outdoor', 'Professional'],
'Technology': [
'Gadgets', 'Tech News', 'Podcasting', 'Software How-To'],
'TV & Film': []}

View file

@ -1,244 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.podcast_entry
~~~~~~~~~~~~~~~~~~~~~~~~~
Extends the feedgen to produce podcasts.
:copyright: 2013-2016, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
from feedgen.ext.base import BaseEntryExtension
from feedgen.util import xml_elem
class PodcastEntryExtension(BaseEntryExtension):
'''FeedEntry extension for podcasts.
'''
def __init__(self):
# ITunes tags
# http://www.apple.com/itunes/podcasts/specs.html#rss
self.__itunes_author = None
self.__itunes_block = None
self.__itunes_image = None
self.__itunes_duration = None
self.__itunes_explicit = None
self.__itunes_is_closed_captioned = None
self.__itunes_order = None
self.__itunes_subtitle = None
self.__itunes_summary = None
def extend_rss(self, entry):
'''Add additional fields to an RSS item.
:param feed: The RSS item XML element to use.
'''
ITUNES_NS = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
if self.__itunes_author:
author = xml_elem('{%s}author' % ITUNES_NS, entry)
author.text = self.__itunes_author
if self.__itunes_block is not None:
block = xml_elem('{%s}block' % ITUNES_NS, entry)
block.text = 'yes' if self.__itunes_block else 'no'
if self.__itunes_image:
image = xml_elem('{%s}image' % ITUNES_NS, entry)
image.attrib['href'] = self.__itunes_image
if self.__itunes_duration:
duration = xml_elem('{%s}duration' % ITUNES_NS, entry)
duration.text = self.__itunes_duration
if self.__itunes_explicit in ('yes', 'no', 'clean'):
explicit = xml_elem('{%s}explicit' % ITUNES_NS, entry)
explicit.text = self.__itunes_explicit
if self.__itunes_is_closed_captioned is not None:
is_closed_captioned = xml_elem(
'{%s}isClosedCaptioned' % ITUNES_NS, entry)
if self.__itunes_is_closed_captioned:
is_closed_captioned.text = 'yes'
else:
is_closed_captioned.text = 'no'
if self.__itunes_order is not None and self.__itunes_order >= 0:
order = xml_elem('{%s}order' % ITUNES_NS, entry)
order.text = str(self.__itunes_order)
if self.__itunes_subtitle:
subtitle = xml_elem('{%s}subtitle' % ITUNES_NS, entry)
subtitle.text = self.__itunes_subtitle
if self.__itunes_summary:
summary = xml_elem('{%s}summary' % ITUNES_NS, entry)
summary.text = self.__itunes_summary
return entry
def itunes_author(self, itunes_author=None):
'''Get or set the itunes:author of the podcast episode. The content of
this tag is shown in the Artist column in iTunes. If the tag is not
present, iTunes uses the contents of the <author> tag. If
<itunes:author> is not present at the feed level, iTunes will use the
contents of <managingEditor>.
:param itunes_author: The author of the podcast.
:returns: The author of the podcast.
'''
if itunes_author is not None:
self.__itunes_author = itunes_author
return self.__itunes_author
def itunes_block(self, itunes_block=None):
'''Get or set the ITunes block attribute. Use this to prevent episodes
from appearing in the iTunes podcast directory.
:param itunes_block: Block podcast episodes.
:returns: If the podcast episode is blocked.
'''
if itunes_block is not None:
self.__itunes_block = itunes_block
return self.__itunes_block
def itunes_image(self, itunes_image=None):
'''Get or set the image for the podcast episode. This tag specifies the
artwork for your podcast. Put the URL to the image in the href
attribute. iTunes prefers square .jpg images that are at least
1400x1400 pixels, which is different from what is specified for the
standard RSS image tag. In order for a podcast to be eligible for an
iTunes Store feature, the accompanying image must be at least 1400x1400
pixels.
iTunes supports images in JPEG and PNG formats with an RGB color space
(CMYK is not supported). The URL must end in ".jpg" or ".png". If the
<itunes:image> tag is not present, iTunes will use the contents of the
RSS image tag.
If you change your podcasts image, also change the files name. iTunes
may not change the image if it checks your feed and the image URL is
the same. The server hosting your cover art image must allow HTTP head
requests for iTS to be able to automatically update your cover art.
:param itunes_image: Image of the podcast.
:returns: Image of the podcast.
'''
if itunes_image is not None:
if itunes_image.endswith('.jpg') or itunes_image.endswith('.png'):
self.__itunes_image = itunes_image
else:
raise ValueError('Image file must be png or jpg')
return self.__itunes_image
def itunes_duration(self, itunes_duration=None):
'''Get or set the duration of the podcast episode. The content of this
tag is shown in the Time column in iTunes.
The tag can be formatted HH:MM:SS, H:MM:SS, MM:SS, or M:SS (H = hours,
M = minutes, S = seconds). If an integer is provided (no colon
present), the value is assumed to be in seconds. If one colon is
present, the number to the left is assumed to be minutes, and the
number to the right is assumed to be seconds. If more than two colons
are present, the numbers farthest to the right are ignored.
:param itunes_duration: Duration of the podcast episode.
:returns: Duration of the podcast episode.
'''
if itunes_duration is not None:
itunes_duration = str(itunes_duration)
if len(itunes_duration.split(':')) > 3 or \
itunes_duration.lstrip('0123456789:') != '':
raise ValueError('Invalid duration format')
self.__itunes_duration = itunes_duration
return self.__itunes_duration
def itunes_explicit(self, itunes_explicit=None):
'''Get or the the itunes:explicit value of the podcast episode. This
tag should be used to indicate whether your podcast episode contains
explicit material. The three values for this tag are "yes", "no", and
"clean".
If you populate this tag with "yes", an "explicit" parental advisory
graphic will appear next to your podcast artwork on the iTunes Store
and in the Name column in iTunes. If the value is "clean", the parental
advisory type is considered Clean, meaning that no explicit language or
adult content is included anywhere in the episodes, and a "clean"
graphic will appear. If the explicit tag is present and has any other
value (e.g., "no"), you see no indicator blank is the default
advisory type.
:param itunes_explicit: If the podcast episode contains explicit
material.
:returns: If the podcast episode contains explicit material.
'''
if itunes_explicit is not None:
if itunes_explicit not in ('', 'yes', 'no', 'clean'):
raise ValueError('Invalid value for explicit tag')
self.__itunes_explicit = itunes_explicit
return self.__itunes_explicit
def itunes_is_closed_captioned(self, itunes_is_closed_captioned=None):
'''Get or set the is_closed_captioned value of the podcast episode.
This tag should be used if your podcast includes a video episode with
embedded closed captioning support. The two values for this tag are
"yes" and "no”.
:param is_closed_captioned: If the episode has closed captioning
support.
:returns: If the episode has closed captioning support.
'''
if itunes_is_closed_captioned is not None:
self.__itunes_is_closed_captioned = \
itunes_is_closed_captioned in ('yes', True)
return self.__itunes_is_closed_captioned
def itunes_order(self, itunes_order=None):
'''Get or set the itunes:order value of the podcast episode. This tag
can be used to override the default ordering of episodes on the store.
This tag is used at an <item> level by populating with the number value
in which you would like the episode to appear on the store. For
example, if you would like an <item> to appear as the first episode in
the podcast, you would populate the <itunes:order> tag with 1. If
conflicting order values are present in multiple episodes, the store
will use default ordering (pubDate).
To remove the order from the episode set the order to a value below
zero.
:param itunes_order: The order of the episode.
:returns: The order of the episode.
'''
if itunes_order is not None:
self.__itunes_order = int(itunes_order)
return self.__itunes_order
def itunes_subtitle(self, itunes_subtitle=None):
'''Get or set the itunes:subtitle value for the podcast episode. The
contents of this tag are shown in the Description column in iTunes. The
subtitle displays best if it is only a few words long.
:param itunes_subtitle: Subtitle of the podcast episode.
:returns: Subtitle of the podcast episode.
'''
if itunes_subtitle is not None:
self.__itunes_subtitle = itunes_subtitle
return self.__itunes_subtitle
def itunes_summary(self, itunes_summary=None):
'''Get or set the itunes:summary value for the podcast episode. The
contents of this tag are shown in a separate window that appears when
the "circled i" in the Description column is clicked. It also appears
on the iTunes page for your podcast. This field can be up to 4000
characters. If <itunes:summary> is not included, the contents of the
<description> tag are used.
:param itunes_summary: Summary of the podcast episode.
:returns: Summary of the podcast episode.
'''
if itunes_summary is not None:
self.__itunes_summary = itunes_summary
return self.__itunes_summary

View file

@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright 2015 Kenichi Sato <ksato9700@gmail.com>
#
'''
Extends FeedGenerator to support Syndication module
See below for details
http://web.resource.org/rss/1.0/modules/syndication/
'''
from feedgen.ext.base import BaseExtension
from feedgen.util import xml_elem
SYNDICATION_NS = 'http://purl.org/rss/1.0/modules/syndication/'
PERIOD_TYPE = ('hourly', 'daily', 'weekly', 'monthly', 'yearly')
def _set_value(channel, name, value):
if value:
newelem = xml_elem('{%s}' % SYNDICATION_NS + name, channel)
newelem.text = value
class SyndicationExtension(BaseExtension):
def __init__(self):
self._update_period = None
self._update_freq = None
self._update_base = None
def extend_ns(self):
return {'sy': SYNDICATION_NS}
def extend_rss(self, rss_feed):
channel = rss_feed[0]
_set_value(channel, 'UpdatePeriod', self._update_period)
_set_value(channel, 'UpdateFrequency', str(self._update_freq))
_set_value(channel, 'UpdateBase', self._update_base)
def update_period(self, value):
if value not in PERIOD_TYPE:
raise ValueError('Invalid update period value')
self._update_period = value
return self._update_period
def update_frequency(self, value):
if type(value) is not int or value <= 0:
raise ValueError('Invalid update frequency value')
self._update_freq = value
return self._update_freq
def update_base(self, value):
# the value should be in W3CDTF format
self._update_base = value
return self._update_base
class SyndicationEntryExtension(BaseExtension):
pass

View file

@ -1,126 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.ext.torrent
~~~~~~~~~~~~~~~~~~~
Extends the FeedGenerator to produce torrent feeds.
:copyright: 2016, Raspbeguy <raspbeguy@hashtagueule.fr>
:license: FreeBSD and LGPL, see license.* for more details.
'''
from feedgen.ext.base import BaseEntryExtension, BaseExtension
from feedgen.util import xml_elem
TORRENT_NS = 'http://xmlns.ezrss.it/0.1/dtd/'
class TorrentExtension(BaseExtension):
'''FeedGenerator extension for torrent feeds.
'''
def extend_ns(self):
return {'torrent': TORRENT_NS}
class TorrentEntryExtension(BaseEntryExtension):
'''FeedEntry extension for torrent feeds
'''
def __init__(self):
self.__torrent_filename = None
self.__torrent_infohash = None
self.__torrent_contentlength = None
self.__torrent_seeds = None
self.__torrent_peers = None
self.__torrent_verified = None
def extend_rss(self, entry):
'''Add additional fields to an RSS item.
:param feed: The RSS item XML element to use.
'''
if self.__torrent_filename:
filename = xml_elem('{%s}filename' % TORRENT_NS, entry)
filename.text = self.__torrent_filename
if self.__torrent_contentlength:
contentlength = xml_elem('{%s}contentlength' % TORRENT_NS, entry)
contentlength.text = self.__torrent_contentlength
if self.__torrent_infohash:
infohash = xml_elem('{%s}infohash' % TORRENT_NS, entry)
infohash.text = self.__torrent_infohash
magnet = xml_elem('{%s}magneturi' % TORRENT_NS, entry)
magnet.text = 'magnet:?xt=urn:btih:' + self.__torrent_infohash
if self.__torrent_seeds:
seeds = xml_elem('{%s}seed' % TORRENT_NS, entry)
seeds.text = self.__torrent_seeds
if self.__torrent_peers:
peers = xml_elem('{%s}peers' % TORRENT_NS, entry)
peers.text = self.__torrent_peers
if self.__torrent_verified:
verified = xml_elem('{%s}verified' % TORRENT_NS, entry)
verified.text = self.__torrent_verified
def filename(self, torrent_filename=None):
'''Get or set the name of the torrent file.
:param torrent_filename: The name of the torrent file.
:returns: The name of the torrent file.
'''
if torrent_filename is not None:
self.__torrent_filename = torrent_filename
return self.__torrent_filename
def infohash(self, torrent_infohash=None):
'''Get or set the hash of the target file.
:param torrent_infohash: The target file hash.
:returns: The target hash file.
'''
if torrent_infohash is not None:
self.__torrent_infohash = torrent_infohash
return self.__torrent_infohash
def contentlength(self, torrent_contentlength=None):
'''Get or set the size of the target file.
:param torrent_contentlength: The target file size.
:returns: The target file size.
'''
if torrent_contentlength is not None:
self.__torrent_contentlength = torrent_contentlength
return self.__torrent_contentlength
def seeds(self, torrent_seeds=None):
'''Get or set the number of seeds.
:param torrent_seeds: The seeds number.
:returns: The seeds number.
'''
if torrent_seeds is not None:
self.__torrent_seeds = torrent_seeds
return self.__torrent_seeds
def peers(self, torrent_peers=None):
'''Get or set the number od peers
:param torrent_infohash: The peers number.
:returns: The peers number.
'''
if torrent_peers is not None:
self.__torrent_peers = torrent_peers
return self.__torrent_peers
def verified(self, torrent_verified=None):
'''Get or set the number of verified peers.
:param torrent_infohash: The verified peers number.
:returns: The verified peers number.
'''
if torrent_verified is not None:
self.__torrent_verified = torrent_verified
return self.__torrent_verified

File diff suppressed because it is too large Load diff

View file

@ -1,96 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.util
~~~~~~~~~~~~
This file contains helper functions for the feed generator module.
:copyright: 2013, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
import locale
import sys
import lxml # nosec - we configure a safe parser below
# Configure a safe parser which does not allow XML entity expansion
parser = lxml.etree.XMLParser(
attribute_defaults=False,
dtd_validation=False,
load_dtd=False,
no_network=True,
recover=False,
remove_pis=True,
resolve_entities=False,
huge_tree=False)
def xml_fromstring(xmlstring):
return lxml.etree.fromstring(xmlstring, parser) # nosec - safe parser
def xml_elem(name, parent=None, **kwargs):
if parent is not None:
return lxml.etree.SubElement(parent, name, **kwargs)
return lxml.etree.Element(name, **kwargs)
def ensure_format(val, allowed, required, allowed_values=None, defaults=None):
'''Takes a dictionary or a list of dictionaries and check if all keys are in
the set of allowed keys, if all required keys are present and if the values
of a specific key are ok.
:param val: Dictionaries to check.
:param allowed: Set of allowed keys.
:param required: Set of required keys.
:param allowed_values: Dictionary with keys and sets of their allowed
values.
:param defaults: Dictionary with default values.
:returns: List of checked dictionaries.
'''
if not val:
return []
if allowed_values is None:
allowed_values = {}
if defaults is None:
defaults = {}
# Make shure that we have a list of dicts. Even if there is only one.
if not isinstance(val, list):
val = [val]
for elem in val:
if not isinstance(elem, dict):
raise ValueError('Invalid data (value is no dictionary)')
# Set default values
version = sys.version_info[0]
if version == 2:
items = defaults.iteritems()
else:
items = defaults.items()
for k, v in items:
elem[k] = elem.get(k, v)
if not set(elem.keys()) <= allowed:
raise ValueError('Data contains invalid keys')
if not set(elem.keys()) >= required:
raise ValueError('Data contains not all required keys')
if version == 2:
values = allowed_values.iteritems()
else:
values = allowed_values.items()
for k, v in values:
if elem.get(k) and not elem[k] in v:
raise ValueError('Invalid value for %s' % k)
return val
def formatRFC2822(date):
'''Make sure the locale setting do not interfere with the time format.
'''
old = locale.setlocale(locale.LC_ALL)
locale.setlocale(locale.LC_ALL, 'C')
date = date.strftime('%a, %d %b %Y %H:%M:%S %z')
locale.setlocale(locale.LC_ALL, old)
return date

View file

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
'''
feedgen.version
~~~~~~~~~~~~~~~
:copyright: 2013-2018, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see license.* for more details.
'''
'Version of python-feedgen represented as tuple'
version = (0, 9, 0)
'Version of python-feedgen represented as string'
version_str = '.'.join([str(x) for x in version])
version_major = version[:1]
version_minor = version[:2]
version_full = version
version_major_str = '.'.join([str(x) for x in version_major])
version_minor_str = '.'.join([str(x) for x in version_minor])
version_full_str = '.'.join([str(x) for x in version_full])

518
genindex.html Normal file
View file

@ -0,0 +1,518 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="#" />
<link rel="search" title="Search" href="search.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>Index</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
<a class="uplink" href="index.html">Contents</a>
</p>
</div>
<div class="content">
<h1 id="index">Index</h1>
<div class="genindex-jumpbox">
<a href="#A"><strong>A</strong></a>
| <a href="#B"><strong>B</strong></a>
| <a href="#C"><strong>C</strong></a>
| <a href="#D"><strong>D</strong></a>
| <a href="#E"><strong>E</strong></a>
| <a href="#F"><strong>F</strong></a>
| <a href="#G"><strong>G</strong></a>
| <a href="#I"><strong>I</strong></a>
| <a href="#L"><strong>L</strong></a>
| <a href="#M"><strong>M</strong></a>
| <a href="#P"><strong>P</strong></a>
| <a href="#R"><strong>R</strong></a>
| <a href="#S"><strong>S</strong></a>
| <a href="#T"><strong>T</strong></a>
| <a href="#U"><strong>U</strong></a>
| <a href="#V"><strong>V</strong></a>
| <a href="#W"><strong>W</strong></a>
</div>
<h2 id="A">A</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.add_entry">add_entry() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.add_item">add_item() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.atom_entry">atom_entry() (feedgen.entry.FeedEntry method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.atom_file">atom_file() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.atom_str">atom_str() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.author">author() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.author">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="B">B</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.base.html#feedgen.ext.base.BaseEntryExtension">BaseEntryExtension (class in feedgen.ext.base)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.base.html#feedgen.ext.base.BaseExtension">BaseExtension (class in feedgen.ext.base)</a>
</li>
</ul></td>
</tr></table>
<h2 id="C">C</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.category">category() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.category">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.cloud">cloud() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.comments">comments() (feedgen.entry.FeedEntry method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.content">content() (feedgen.entry.FeedEntry method)</a>
</li>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension.contentlength">contentlength() (feedgen.ext.torrent.TorrentEntryExtension method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.contributor">contributor() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.contributor">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.copyright">copyright() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="D">D</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_contributor">dc_contributor() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_coverage">dc_coverage() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_creator">dc_creator() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_date">dc_date() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_description">dc_description() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_format">dc_format() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_identifier">dc_identifier() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_language">dc_language() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_publisher">dc_publisher() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_relation">dc_relation() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_rights">dc_rights() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_source">dc_source() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_subject">dc_subject() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_title">dc_title() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.dc_type">dc_type() (feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension">DcBaseExtension (class in feedgen.ext.dc)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcEntryExtension">DcEntryExtension (class in feedgen.ext.dc)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcExtension">DcExtension (class in feedgen.ext.dc)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.description">description() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.description">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.docs">docs() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="E">E</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.enclosure">enclosure() (feedgen.entry.FeedEntry method)</a>
</li>
<li><a href="api.util.html#feedgen.util.ensure_format">ensure_format() (in module feedgen.util)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.entry">entry() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="ext/api.ext.base.html#feedgen.ext.base.BaseExtension.extend_atom">extend_atom() (feedgen.ext.base.BaseExtension method)</a>
<ul>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.extend_atom">(feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcEntryExtension.extend_atom">(feedgen.ext.dc.DcEntryExtension method)</a>
</li>
</ul></li>
<li><a href="ext/api.ext.base.html#feedgen.ext.base.BaseExtension.extend_ns">extend_ns() (feedgen.ext.base.BaseExtension method)</a>
<ul>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.extend_ns">(feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.extend_ns">(feedgen.ext.podcast.PodcastExtension method)</a>
</li>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentExtension.extend_ns">(feedgen.ext.torrent.TorrentExtension method)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.base.html#feedgen.ext.base.BaseExtension.extend_rss">extend_rss() (feedgen.ext.base.BaseExtension method)</a>
<ul>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcBaseExtension.extend_rss">(feedgen.ext.dc.DcBaseExtension method)</a>
</li>
<li><a href="ext/api.ext.dc.html#feedgen.ext.dc.DcEntryExtension.extend_rss">(feedgen.ext.dc.DcEntryExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.extend_rss">(feedgen.ext.podcast.PodcastExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.extend_rss">(feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension.extend_rss">(feedgen.ext.torrent.TorrentEntryExtension method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="F">F</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry">FeedEntry (class in feedgen.entry)</a>
</li>
<li><a href="api.html#module-feedgen">feedgen (module)</a>
</li>
<li><a href="api.entry.html#module-feedgen.entry">feedgen.entry (module)</a>
</li>
<li><a href="ext/api.ext.base.html#module-feedgen.ext.base">feedgen.ext.base (module)</a>
</li>
<li><a href="ext/api.ext.dc.html#module-feedgen.ext.dc">feedgen.ext.dc (module)</a>
</li>
<li><a href="ext/api.ext.podcast.html#module-feedgen.ext.podcast">feedgen.ext.podcast (module)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.podcast_entry.html#module-feedgen.ext.podcast_entry">feedgen.ext.podcast_entry (module)</a>
</li>
<li><a href="ext/api.ext.torrent.html#module-feedgen.ext.torrent">feedgen.ext.torrent (module)</a>
</li>
<li><a href="api.feed.html#module-feedgen.feed">feedgen.feed (module)</a>
</li>
<li><a href="api.util.html#module-feedgen.util">feedgen.util (module)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator">FeedGenerator (class in feedgen.feed)</a>
</li>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension.filename">filename() (feedgen.ext.torrent.TorrentEntryExtension method)</a>
</li>
<li><a href="api.util.html#feedgen.util.formatRFC2822">formatRFC2822() (in module feedgen.util)</a>
</li>
</ul></td>
</tr></table>
<h2 id="G">G</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.generator">generator() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.guid">guid() (feedgen.entry.FeedEntry method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="I">I</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.icon">icon() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.id">id() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.id">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.image">image() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension.infohash">infohash() (feedgen.ext.torrent.TorrentEntryExtension method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.item">item() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_author">itunes_author() (feedgen.ext.podcast.PodcastExtension method)</a>
<ul>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_author">(feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
</ul></li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_block">itunes_block() (feedgen.ext.podcast.PodcastExtension method)</a>
<ul>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_block">(feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
</ul></li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_category">itunes_category() (feedgen.ext.podcast.PodcastExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_complete">itunes_complete() (feedgen.ext.podcast.PodcastExtension method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_duration">itunes_duration() (feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_explicit">itunes_explicit() (feedgen.ext.podcast.PodcastExtension method)</a>
<ul>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_explicit">(feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
</ul></li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_image">itunes_image() (feedgen.ext.podcast.PodcastExtension method)</a>
<ul>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_image">(feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
</ul></li>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_is_closed_captioned">itunes_is_closed_captioned() (feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_new_feed_url">itunes_new_feed_url() (feedgen.ext.podcast.PodcastExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_order">itunes_order() (feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_owner">itunes_owner() (feedgen.ext.podcast.PodcastExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_subtitle">itunes_subtitle() (feedgen.ext.podcast.PodcastExtension method)</a>
<ul>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_subtitle">(feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
</ul></li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension.itunes_summary">itunes_summary() (feedgen.ext.podcast.PodcastExtension method)</a>
<ul>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension.itunes_summary">(feedgen.ext.podcast_entry.PodcastEntryExtension method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="L">L</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.language">language() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.lastBuildDate">lastBuildDate() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.link">link() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.link">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.load_extension">load_extension() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.load_extension">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.logo">logo() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="M">M</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.managingEditor">managingEditor() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="P">P</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension.peers">peers() (feedgen.ext.torrent.TorrentEntryExtension method)</a>
</li>
<li><a href="ext/api.ext.podcast_entry.html#feedgen.ext.podcast_entry.PodcastEntryExtension">PodcastEntryExtension (class in feedgen.ext.podcast_entry)</a>
</li>
<li><a href="ext/api.ext.podcast.html#feedgen.ext.podcast.PodcastExtension">PodcastExtension (class in feedgen.ext.podcast)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.pubDate">pubDate() (feedgen.entry.FeedEntry method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.pubdate">pubdate() (feedgen.entry.FeedEntry method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.pubDate">pubDate() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.published">published() (feedgen.entry.FeedEntry method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.rating">rating() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.register_extension">register_extension() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.register_extension">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.remove_entry">remove_entry() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.remove_item">remove_item() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.rights">rights() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.rights">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.rss_entry">rss_entry() (feedgen.entry.FeedEntry method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.rss_file">rss_file() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.rss_str">rss_str() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="S">S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension.seeds">seeds() (feedgen.ext.torrent.TorrentEntryExtension method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.skipDays">skipDays() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.skipHours">skipHours() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.source">source() (feedgen.entry.FeedEntry method)</a>
</li>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.subtitle">subtitle() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.summary">summary() (feedgen.entry.FeedEntry method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="T">T</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.textInput">textInput() (feedgen.feed.FeedGenerator method)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.title">title() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.title">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension">TorrentEntryExtension (class in feedgen.ext.torrent)</a>
</li>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentExtension">TorrentExtension (class in feedgen.ext.torrent)</a>
</li>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.ttl">ttl() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.ttl">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="U">U</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.entry.html#feedgen.entry.FeedEntry.updated">updated() (feedgen.entry.FeedEntry method)</a>
<ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.updated">(feedgen.feed.FeedGenerator method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="V">V</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ext/api.ext.torrent.html#feedgen.ext.torrent.TorrentEntryExtension.verified">verified() (feedgen.ext.torrent.TorrentEntryExtension method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="W">W</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.feed.html#feedgen.feed.FeedGenerator.webMaster">webMaster() (feedgen.feed.FeedGenerator method)</a>
</li>
</ul></td>
</tr></table>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
<a class="uplink" href="index.html">Contents</a>
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

246
index.html Normal file
View file

@ -0,0 +1,246 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Feedgenerator &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="API Documentation" href="api.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="#">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>Feedgenerator</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
<a class="uplink" href="#">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.html">API Documentation</a>&#160;&#160;»
</p>
</div>
<div class="content">
<div class="contents topic" id="table-of-contents">
<p class="topic-title first">Table of Contents</p>
<ul class="simple">
<li><a class="reference internal" href="#feedgenerator" id="id1">Feedgenerator</a><ul>
<li><a class="reference internal" href="#installation" id="id2">Installation</a></li>
<li><a class="reference internal" href="#create-a-feed" id="id3">Create a Feed</a></li>
<li><a class="reference internal" href="#generate-the-feed" id="id4">Generate the Feed</a></li>
<li><a class="reference internal" href="#add-feed-entries" id="id5">Add Feed Entries</a></li>
<li><a class="reference internal" href="#extensions" id="id6">Extensions</a></li>
<li><a class="reference internal" href="#testing-the-generator" id="id7">Testing the Generator</a></li>
</ul>
</li>
<li><a class="reference internal" href="#module-documentation" id="id8">Module documentation</a></li>
<li><a class="reference internal" href="#indices-and-tables" id="id9">Indices and tables</a></li>
</ul>
</div>
<div class="section" id="feedgenerator">
<h1><a class="toc-backref" href="#id1">Feedgenerator</a><a class="headerlink" href="#feedgenerator" title="Permalink to this headline"></a></h1>
<a class="reference external image-reference" href="https://travis-ci.org/lkiesow/python-feedgen"><img alt="Build Status" src="https://travis-ci.org/lkiesow/python-feedgen.svg?branch=master" /></a>
<a class="reference external image-reference" href="https://coveralls.io/github/lkiesow/python-feedgen?branch=master"><img alt="Test Coverage Status" src="https://coveralls.io/repos/github/lkiesow/python-feedgen/badge.svg?branch=master" /></a>
<p>This module can be used to generate web feeds in both ATOM and RSS format. It
has support for extensions. Included is for example an extension to produce
Podcasts.</p>
<p>It is licensed under the terms of both, the FreeBSD license and the LGPLv3+.
Choose the one which is more convenient for you. For more details have a look
at license.bsd and license.lgpl.</p>
<p>More details about the project:</p>
<ul class="simple">
<li>Repository: <a class="reference external" href="https://github.com/lkiesow/python-feedgen">https://github.com/lkiesow/python-feedgen</a></li>
<li>Documentation: <a class="reference external" href="https://lkiesow.github.io/python-feedgen/">https://lkiesow.github.io/python-feedgen/</a></li>
<li>Python Package Index: <a class="reference external" href="https://pypi.python.org/pypi/feedgen/">https://pypi.python.org/pypi/feedgen/</a></li>
</ul>
<div class="section" id="installation">
<h2><a class="toc-backref" href="#id2">Installation</a><a class="headerlink" href="#installation" title="Permalink to this headline"></a></h2>
<p><strong>Prebuild packages</strong></p>
<p>If your distribution includes this project as package, like Fedora Linux does,
you can simply use your package manager to install the package. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ dnf install python3-feedgen
</pre></div>
</div>
<p><strong>Using pip</strong></p>
<p>You can also use pip to install the feedgen module. Simply run:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ pip install feedgen
</pre></div>
</div>
</div>
<div class="section" id="create-a-feed">
<h2><a class="toc-backref" href="#id3">Create a Feed</a><a class="headerlink" href="#create-a-feed" title="Permalink to this headline"></a></h2>
<p>To create a feed simply instantiate the FeedGenerator class and insert some
data:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">feedgen.feed</span> <span class="k">import</span> <span class="n">FeedGenerator</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span> <span class="o">=</span> <span class="n">FeedGenerator</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">id</span><span class="p">(</span><span class="s1">&#39;http://lernfunk.de/media/654321&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">&#39;Some Testfeed&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">author</span><span class="p">(</span> <span class="p">{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span><span class="s1">&#39;email&#39;</span><span class="p">:</span><span class="s1">&#39;john@example.de&#39;</span><span class="p">}</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">link</span><span class="p">(</span> <span class="n">href</span><span class="o">=</span><span class="s1">&#39;http://example.com&#39;</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="s1">&#39;alternate&#39;</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">logo</span><span class="p">(</span><span class="s1">&#39;http://ex.com/logo.jpg&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">subtitle</span><span class="p">(</span><span class="s1">&#39;This is a cool feed!&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">link</span><span class="p">(</span> <span class="n">href</span><span class="o">=</span><span class="s1">&#39;http://larskiesow.de/test.atom&#39;</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="s1">&#39;self&#39;</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">language</span><span class="p">(</span><span class="s1">&#39;en&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>Note that for the methods which set fields that can occur more than once in a
feed you can use all of the following ways to provide data:</p>
<ul class="simple">
<li>Provide the data for that element as keyword arguments</li>
<li>Provide the data for that element as dictionary</li>
<li>Provide a list of dictionaries with the data for several elements</li>
</ul>
<p>Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">contributor</span><span class="p">(</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s1">&#39;jdoe@example.com&#39;</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">contributor</span><span class="p">({</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span> <span class="s1">&#39;email&#39;</span><span class="p">:</span><span class="s1">&#39;jdoe@example.com&#39;</span><span class="p">})</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">contributor</span><span class="p">([{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;John Doe&#39;</span><span class="p">,</span> <span class="s1">&#39;email&#39;</span><span class="p">:</span><span class="s1">&#39;jdoe@example.com&#39;</span><span class="p">},</span> <span class="o">...</span><span class="p">])</span>
</pre></div>
</div>
</div>
<div class="section" id="generate-the-feed">
<h2><a class="toc-backref" href="#id4">Generate the Feed</a><a class="headerlink" href="#generate-the-feed" title="Permalink to this headline"></a></h2>
<p>After that you can generate both RSS or ATOM by calling the respective method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">atomfeed</span> <span class="o">=</span> <span class="n">fg</span><span class="o">.</span><span class="n">atom_str</span><span class="p">(</span><span class="n">pretty</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># Get the ATOM feed as string</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">rssfeed</span> <span class="o">=</span> <span class="n">fg</span><span class="o">.</span><span class="n">rss_str</span><span class="p">(</span><span class="n">pretty</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># Get the RSS feed as string</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">atom_file</span><span class="p">(</span><span class="s1">&#39;atom.xml&#39;</span><span class="p">)</span> <span class="c1"># Write the ATOM feed to a file</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">rss_file</span><span class="p">(</span><span class="s1">&#39;rss.xml&#39;</span><span class="p">)</span> <span class="c1"># Write the RSS feed to a file</span>
</pre></div>
</div>
</div>
<div class="section" id="add-feed-entries">
<h2><a class="toc-backref" href="#id5">Add Feed Entries</a><a class="headerlink" href="#add-feed-entries" title="Permalink to this headline"></a></h2>
<p>To add entries (items) to a feed you need to create new FeedEntry objects and
append them to the list of entries in the FeedGenerator. The most convenient
way to go is to use the FeedGenerator itself for the instantiation of the
FeedEntry object:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span> <span class="o">=</span> <span class="n">fg</span><span class="o">.</span><span class="n">add_entry</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">id</span><span class="p">(</span><span class="s1">&#39;http://lernfunk.de/media/654321/1&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">&#39;The First Episode&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">link</span><span class="p">(</span><span class="n">href</span><span class="o">=</span><span class="s2">&quot;http://lernfunk.de/feed&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The FeedGenerators method <cite>add_entry(…)</cite> without argument provides will
automatically generate a new FeedEntry object, append it to the feeds internal
list of entries and return it, so that additional data can be added.</p>
</div>
<div class="section" id="extensions">
<h2><a class="toc-backref" href="#id6">Extensions</a><a class="headerlink" href="#extensions" title="Permalink to this headline"></a></h2>
<p>The FeedGenerator supports extension to include additional data into the XML
structure of the feeds. Extensions can be loaded like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">load_extension</span><span class="p">(</span><span class="s1">&#39;someext&#39;</span><span class="p">,</span> <span class="n">atom</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">rss</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>This will try to load the extension “someext” from the file <cite>ext/someext.py</cite>.
It is required that <cite>someext.py</cite> contains a class named “SomextExtension” which
is required to have at least the two methods <cite>extend_rss(…)</cite> and
<cite>extend_atom(…)</cite>. Although not required, it is strongly suggested to use
<cite>BaseExtension</cite> from <cite>ext/base.py</cite> as superclass.</p>
<p><cite>load_extension(someext, …)</cite> will also try to load a class named
“SomextEntryExtension” for every entry of the feed. This class can be located
either in the same file as SomextExtension or in <cite>ext/someext_entry.py</cite> which
is suggested especially for large extensions.</p>
<p>The parameters <cite>atom</cite> and <cite>rss</cite> control if the extension is used for ATOM and
RSS feeds, respectively. The default value for both parameters is <cite>true</cite>
meaning the extension is used for both kinds of feeds.</p>
<p><strong>Example: Producing a Podcast</strong></p>
<p>One extension already provided is the podcast extension. A podcast is an RSS
feed with some additional elements for ITunes.</p>
<p>To produce a podcast simply load the <cite>podcast</cite> extension:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">feedgen.feed</span> <span class="k">import</span> <span class="n">FeedGenerator</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span> <span class="o">=</span> <span class="n">FeedGenerator</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">load_extension</span><span class="p">(</span><span class="s1">&#39;podcast&#39;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">podcast</span><span class="o">.</span><span class="n">itunes_category</span><span class="p">(</span><span class="s1">&#39;Technology&#39;</span><span class="p">,</span> <span class="s1">&#39;Podcasting&#39;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span> <span class="o">=</span> <span class="n">fg</span><span class="o">.</span><span class="n">add_entry</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">id</span><span class="p">(</span><span class="s1">&#39;http://lernfunk.de/media/654321/1/file.mp3&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">&#39;The First Episode&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">description</span><span class="p">(</span><span class="s1">&#39;Enjoy our first episode.&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fe</span><span class="o">.</span><span class="n">enclosure</span><span class="p">(</span><span class="s1">&#39;http://lernfunk.de/media/654321/1/file.mp3&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">&#39;audio/mpeg&#39;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">rss_str</span><span class="p">(</span><span class="n">pretty</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fg</span><span class="o">.</span><span class="n">rss_file</span><span class="p">(</span><span class="s1">&#39;podcast.xml&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>If the FeedGenerator class is used to load an extension, it is automatically
loaded for every feed entry as well. You can, however, load an extension for a
specific FeedEntry only by calling <cite>load_extension(…)</cite> on that entry.</p>
<p>Even if extensions are loaded, they can be temporarily disabled during the feed
generation by calling the generating method with the keyword argument
<cite>extensions</cite> set to <cite>False</cite>.</p>
<p><strong>Custom Extensions</strong></p>
<p>If you want to load custom extensions which are not part of the feedgen
package, you can use the method <cite>register_extension</cite> instead. You can directly
pass the classes for the feed and the entry extension to this method meaning
that you can define them everywhere.</p>
</div>
<div class="section" id="testing-the-generator">
<h2><a class="toc-backref" href="#id7">Testing the Generator</a><a class="headerlink" href="#testing-the-generator" title="Permalink to this headline"></a></h2>
<p>You can test the module by simply executing:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ python -m feedgen
</pre></div>
</div>
<p>If you want to have a look at the code for this test to have a working code
example for a whole feed generation process, you can find it in the
<a class="reference external" href="https://github.com/lkiesow/python-feedgen/blob/master/feedgen/__main__.py">__main__.py</a>.</p>
<hr /></div>
</div>
<div class="section" id="module-documentation">
<h1><a class="toc-backref" href="#id8">Module documentation</a><a class="headerlink" href="#module-documentation" title="Permalink to this headline"></a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="api.html">API Documentation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api.html#feedgen">feedgen</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.feed.html">feedgen.feed</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.entry.html">feedgen.entry</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.util.html">feedgen.util</a></li>
<li class="toctree-l2"><a class="reference internal" href="ext/api.ext.base.html">feedgen.ext.base</a></li>
<li class="toctree-l2"><a class="reference internal" href="ext/api.ext.dc.html">feedgen.ext.dc</a></li>
<li class="toctree-l2"><a class="reference internal" href="ext/api.ext.podcast.html">feedgen.ext.podcast</a></li>
<li class="toctree-l2"><a class="reference internal" href="ext/api.ext.podcast_entry.html">feedgen.ext.podcast_entry</a></li>
<li class="toctree-l2"><a class="reference internal" href="ext/api.ext.torrent.html">feedgen.ext.torrent</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="indices-and-tables">
<h1><a class="toc-backref" href="#id9">Indices and tables</a><a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></li>
<li><a class="reference internal" href="py-modindex.html"><span class="std std-ref">Module Index</span></a></li>
<li><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></li>
</ul>
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
<a class="uplink" href="#">Contents</a>
&#160;&#160;::&#160;&#160;
<a href="api.html">API Documentation</a>&#160;&#160;»
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

View file

@ -1,25 +0,0 @@
BSD 2-Clause License
Copyright 2011, Lars Kiesow <lkiesow@uos.de>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

111
py-modindex.html Normal file
View file

@ -0,0 +1,111 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Python Module Index &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>Python Module Index</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
<a class="uplink" href="index.html">Contents</a>
</p>
</div>
<div class="content">
<h1>Python Module Index</h1>
<div class="modindex-jumpbox">
<a href="#cap-f"><strong>f</strong></a>
</div>
<table class="indextable modindextable">
<tr class="pcap"><td></td><td>&#160;</td><td></td></tr>
<tr class="cap" id="cap-f"><td></td><td>
<strong>f</strong></td><td></td></tr>
<tr>
<td><img src="_static/minus.png" class="toggler"
id="toggle-1" style="display: none" alt="-" /></td>
<td>
<a href="api.html#module-feedgen"><code class="xref">feedgen</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="api.entry.html#module-feedgen.entry"><code class="xref">feedgen.entry</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="ext/api.ext.base.html#module-feedgen.ext.base"><code class="xref">feedgen.ext.base</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="ext/api.ext.dc.html#module-feedgen.ext.dc"><code class="xref">feedgen.ext.dc</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="ext/api.ext.podcast.html#module-feedgen.ext.podcast"><code class="xref">feedgen.ext.podcast</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="ext/api.ext.podcast_entry.html#module-feedgen.ext.podcast_entry"><code class="xref">feedgen.ext.podcast_entry</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="ext/api.ext.torrent.html#module-feedgen.ext.torrent"><code class="xref">feedgen.ext.torrent</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="api.feed.html#module-feedgen.feed"><code class="xref">feedgen.feed</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="api.util.html#module-feedgen.util"><code class="xref">feedgen.util</code></a></td><td>
<em></em></td></tr>
</table>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
<a class="uplink" href="index.html">Contents</a>
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

View file

@ -1,86 +0,0 @@
%global pypi_name feedgen
Name: python-%{pypi_name}
Version: 0.9.0
Release: 1%{?dist}
Summary: Feed Generator (ATOM, RSS, Podcasts)
License: BSD or LGPLv3
URL: http://lkiesow.github.io/python-feedgen
Source0: https://github.com/lkiesow/%{name}/archive/v%{version}.tar.gz
BuildArch: noarch
BuildRequires: python2-dateutil
BuildRequires: python2-devel
BuildRequires: python2-lxml
BuildRequires: python2-setuptools
BuildRequires: python3-dateutil
BuildRequires: python3-devel
BuildRequires: python3-lxml
BuildRequires: python3-setuptools
%description
Feedgenerator This module can be used to generate web feeds in both ATOM and
RSS format. It has support for extensions. Included is for example an extension
to produce Podcasts.
%package -n python2-%{pypi_name}
Summary: %{summary}
%{?python_provide:%python_provide python2-%{pypi_name}}
Requires: python2-dateutil
Requires: python2-lxml
%description -n python2-%{pypi_name}
Feedgenerator This module can be used to generate web feeds in both ATOM and
RSS format. It has support for extensions. Included is for example an extension
to produce Podcasts.
%package -n python3-%{pypi_name}
Summary: %{summary}
%{?python_provide:%python_provide python3-%{pypi_name}}
Requires: python3-dateutil
Requires: python3-lxml
%description -n python3-%{pypi_name}
Feedgenerator This module can be used to generate web feeds in both ATOM and
RSS format. It has support for extensions. Included is for example an extension
to produce Podcasts.
%prep
%autosetup
# Remove bundled egg-info
rm -rf %{pypi_name}.egg-info
%build
%py2_build
%py3_build
%install
%py2_install
%py3_install
%check
%{__python2} setup.py test
%{__python3} setup.py test
%files -n python2-%{pypi_name}
%license license.lgpl license.bsd
%doc readme.rst
%{python2_sitelib}/%{pypi_name}
%{python2_sitelib}/%{pypi_name}-%{version}-py?.?.egg-info
%files -n python3-%{pypi_name}
%license license.lgpl license.bsd
%doc readme.rst
%{python3_sitelib}/%{pypi_name}
%{python3_sitelib}/%{pypi_name}-%{version}-py?.?.egg-info
%changelog
* Sat May 19 2018 Lars Kiesow <lkiesow@uos.de> - 0.7.0-1
- Update to 0.7.0
* Tue Oct 24 2017 Lumir Balhar <lbalhar@redhat.com> - 0.6.1-1
- Initial package.

View file

@ -1,193 +0,0 @@
=============
Feedgenerator
=============
.. image:: https://travis-ci.org/lkiesow/python-feedgen.svg?branch=master
:target: https://travis-ci.org/lkiesow/python-feedgen
:alt: Build Status
.. image:: https://coveralls.io/repos/github/lkiesow/python-feedgen/badge.svg?branch=master
:target: https://coveralls.io/github/lkiesow/python-feedgen?branch=master
:alt: Test Coverage Status
This module can be used to generate web feeds in both ATOM and RSS format. It
has support for extensions. Included is for example an extension to produce
Podcasts.
It is licensed under the terms of both, the FreeBSD license and the LGPLv3+.
Choose the one which is more convenient for you. For more details have a look
at license.bsd and license.lgpl.
More details about the project:
- `Repository <https://github.com/lkiesow/python-feedgen>`_
- `Documentation <https://lkiesow.github.io/python-feedgen/>`_
- `Python Package Index <https://pypi.python.org/pypi/feedgen/>`_
------------
Installation
------------
**Prebuild packages**
If your distribution includes this project as package, like Fedora Linux does,
you can simply use your package manager to install the package. For example::
$ dnf install python3-feedgen
**Using pip**
You can also use pip to install the feedgen module. Simply run::
$ pip install feedgen
-------------
Create a Feed
-------------
To create a feed simply instantiate the FeedGenerator class and insert some
data:
.. code-block:: python
from feedgen.feed import FeedGenerator
fg = FeedGenerator()
fg.id('http://lernfunk.de/media/654321')
fg.title('Some Testfeed')
fg.author( {'name':'John Doe','email':'john@example.de'} )
fg.link( href='http://example.com', rel='alternate' )
fg.logo('http://ex.com/logo.jpg')
fg.subtitle('This is a cool feed!')
fg.link( href='http://larskiesow.de/test.atom', rel='self' )
fg.language('en')
Note that for the methods which set fields that can occur more than once in a
feed you can use all of the following ways to provide data:
- Provide the data for that element as keyword arguments
- Provide the data for that element as dictionary
- Provide a list of dictionaries with the data for several elements
Example:
.. code-block:: python
fg.contributor( name='John Doe', email='jdoe@example.com' )
fg.contributor({'name':'John Doe', 'email':'jdoe@example.com'})
fg.contributor([{'name':'John Doe', 'email':'jdoe@example.com'}, ...])
-----------------
Generate the Feed
-----------------
After that you can generate both RSS or ATOM by calling the respective method:
.. code-block:: python
atomfeed = fg.atom_str(pretty=True) # Get the ATOM feed as string
rssfeed = fg.rss_str(pretty=True) # Get the RSS feed as string
fg.atom_file('atom.xml') # Write the ATOM feed to a file
fg.rss_file('rss.xml') # Write the RSS feed to a file
----------------
Add Feed Entries
----------------
To add entries (items) to a feed you need to create new FeedEntry objects and
append them to the list of entries in the FeedGenerator. The most convenient
way to go is to use the FeedGenerator itself for the instantiation of the
FeedEntry object:
.. code-block:: python
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654321/1')
fe.title('The First Episode')
fe.link(href="http://lernfunk.de/feed")
The FeedGenerator's method `add_entry(...)` will generate a new FeedEntry
object, automatically append it to the feeds internal list of entries and
return it, so that additional data can be added.
----------
Extensions
----------
The FeedGenerator supports extensions to include additional data into the XML
structure of the feeds. Extensions can be loaded like this:
.. code-block:: python
fg.load_extension('someext', atom=True, rss=True)
This example would try to load the extension “someext” from the file
`ext/someext.py`. It is required that `someext.py` contains a class named
“SomextExtension” which is required to have at least the two methods
`extend_rss(...)` and `extend_atom(...)`. Although not required, it is strongly
suggested to use `BaseExtension` from `ext/base.py` as superclass.
`load_extension('someext', ...)` will also try to load a class named
“SomextEntryExtension” for every entry of the feed. This class can be located
either in the same file as SomextExtension or in `ext/someext_entry.py` which
is suggested especially for large extensions.
The parameters `atom` and `rss` control if the extension is used for ATOM and
RSS feeds respectively. The default value for both parameters is `True`,
meaning the extension is used for both kinds of feeds.
**Example: Producing a Podcast**
One extension already provided is the podcast extension. A podcast is an RSS
feed with some additional elements for ITunes.
To produce a podcast simply load the `podcast` extension:
.. code-block:: python
from feedgen.feed import FeedGenerator
fg = FeedGenerator()
fg.load_extension('podcast')
...
fg.podcast.itunes_category('Technology', 'Podcasting')
...
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654321/1/file.mp3')
fe.title('The First Episode')
fe.description('Enjoy our first episode.')
fe.enclosure('http://lernfunk.de/media/654321/1/file.mp3', 0, 'audio/mpeg')
...
fg.rss_str(pretty=True)
fg.rss_file('podcast.xml')
If the FeedGenerator class is used to load an extension, it is automatically
loaded for every feed entry as well. You can, however, load an extension for a
specific FeedEntry only by calling `load_extension(...)` on that entry.
Even if extensions are loaded, they can be temporarily disabled during the feed
generation by calling the generating method with the keyword argument
`extensions` set to `False`.
**Custom Extensions**
If you want to load custom extensions which are not part of the feedgen
package, you can use the method `register_extension` instead. You can directly
pass the classes for the feed and the entry extension to this method meaning
that you can define them everywhere.
---------------------
Testing the Generator
---------------------
You can test the module by simply executing::
$ python -m feedgen
If you want to have a look at the code for this test to have a working code
example for a whole feed generation process, you can find it in the
`__main__.py <https://github.com/lkiesow/python-feedgen/blob/master/feedgen/__main__.py>`_.

View file

@ -1,2 +0,0 @@
lxml==4.2.5
python_dateutil==2.8.0

81
search.html Normal file
View file

@ -0,0 +1,81 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &#8212; python-feedgen 0.8.0 documentation</title>
<link rel="stylesheet" href="_static/lernfunk.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="#" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
<script type="text/javascript" id="searchindexloader"></script>
</head><body>
<div class="header" role="banner"><h1 class="heading"><a href="index.html">
<span>python-feedgen 0.8.0 documentation</span></a></h1>
<h2 class="heading"><span>Search</span></h2>
</div>
<div class="topnav" role="navigation" aria-label="top navigation">
<p>
<a class="uplink" href="index.html">Contents</a>
</p>
</div>
<div class="content">
<h1 id="search-documentation">Search</h1>
<div id="fallback" class="admonition warning">
<script type="text/javascript">$('#fallback').hide();</script>
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
<p>
From here you can search these documents. Enter your search
words into the box below and click "search". Note that the search
function will automatically search for all of the words. Pages
containing fewer words won't appear in the result list.
</p>
<form action="" method="get">
<input type="text" name="q" value="" />
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
<div class="bottomnav" role="navigation" aria-label="bottom navigation">
<p>
<a class="uplink" href="index.html">Contents</a>
</p>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2013-2016, Lars Kiesow.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.4.
</div>
</body>
</html>

1
searchindex.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
[bdist_wheel]
universal=1

View file

@ -1,51 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import setup
import feedgen.version
packages = ['feedgen', 'feedgen/ext']
setup(name='feedgen',
packages=packages,
version=feedgen.version.version_full_str,
description='Feed Generator (ATOM, RSS, Podcasts)',
author='Lars Kiesow',
author_email='lkiesow@uos.de',
url='https://lkiesow.github.io/python-feedgen',
keywords=['feed', 'ATOM', 'RSS', 'podcast'],
license='FreeBSD and LGPLv3+',
install_requires=['lxml', 'python-dateutil'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: BSD License',
'License :: OSI Approved :: GNU Lesser General Public License v3 ' +
'or later (LGPLv3+)',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Communications',
'Topic :: Internet',
'Topic :: Text Processing',
'Topic :: Text Processing :: Markup',
'Topic :: Text Processing :: Markup :: XML'
],
test_suite="tests",
long_description='''\
Feedgenerator
=============
This module can be used to generate web feeds in both ATOM and RSS format. It
has support for extensions. Included is for example an extension to produce
Podcasts.
It is licensed under the terms of both, the FreeBSD license and the LGPLv3+.
Choose the one which is more convenient for you. For more details have a look
at license.bsd and license.lgpl.
''')

View file

@ -1,179 +0,0 @@
# -*- coding: utf-8 -*-
"""
Tests for a basic entry
These are test cases for a basic entry.
"""
import unittest
from feedgen.feed import FeedGenerator
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
fg = FeedGenerator()
self.feedId = 'http://example.com'
self.title = 'Some Testfeed'
fg.id(self.feedId)
fg.title(self.title)
fg.link(href='http://lkiesow.de', rel='alternate')[0]
fg.description('...')
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654321/1')
fe.title('The First Episode')
fe.content(u'')
# Use also the different name add_item
fe = fg.add_item()
fe.id('http://lernfunk.de/media/654321/1')
fe.title('The Second Episode')
fe.content(u'')
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654321/1')
fe.title('The Third Episode')
fe.content(u'')
self.fg = fg
def test_setEntries(self):
fg2 = FeedGenerator()
fg2.entry(self.fg.entry())
assert len(fg2.entry()) == 3
assert self.fg.entry() == fg2.entry()
def test_loadExtension(self):
fe = self.fg.add_item()
fe.id('1')
fe.title(u'')
fe.content(u'')
fe.load_extension('base')
assert fe.base
assert self.fg.atom_str()
def test_checkEntryNumbers(self):
fg = self.fg
assert len(fg.entry()) == 3
def test_TestEntryItems(self):
fe = self.fg.add_item()
fe.title('qwe')
assert fe.title() == 'qwe'
author = fe.author(email='ldoe@example.com')[0]
assert not author.get('name')
assert author.get('email') == 'ldoe@example.com'
author = fe.author(name='John Doe', email='jdoe@example.com',
replace=True)[0]
assert author.get('name') == 'John Doe'
assert author.get('email') == 'jdoe@example.com'
contributor = fe.contributor(name='John Doe', email='jdoe@ex.com')[0]
assert contributor == fe.contributor()[0]
assert contributor.get('name') == 'John Doe'
assert contributor.get('email') == 'jdoe@ex.com'
link = fe.link(href='http://lkiesow.de', rel='alternate')[0]
assert link == fe.link()[0]
assert link.get('href') == 'http://lkiesow.de'
assert link.get('rel') == 'alternate'
fe.guid('123')
assert fe.guid().get('guid') == '123'
fe.updated('2017-02-05 13:26:58+01:00')
assert fe.updated().year == 2017
fe.summary('asdf')
assert fe.summary() == {'summary': 'asdf'}
fe.description('asdfx')
assert fe.description() == 'asdfx'
fe.pubDate('2017-02-05 13:26:58+01:00')
assert fe.pubDate().year == 2017
fe.rights('asdfx')
assert fe.rights() == 'asdfx'
source = fe.source(url='https://example.com', title='Test')
assert source.get('title') == 'Test'
assert source.get('url') == 'https://example.com'
fe.comments('asdfx')
assert fe.comments() == 'asdfx'
fe.enclosure(url='http://lkiesow.de', type='text/plain', length='1')
assert fe.enclosure().get('url') == 'http://lkiesow.de'
fe.ttl(8)
assert fe.ttl() == 8
self.fg.rss_str()
self.fg.atom_str()
def test_checkItemNumbers(self):
fg = self.fg
assert len(fg.item()) == 3
def test_checkEntryContent(self):
fg = self.fg
assert fg.entry()
def test_removeEntryByIndex(self):
fg = FeedGenerator()
self.feedId = 'http://example.com'
self.title = 'Some Testfeed'
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654321/1')
fe.title('The Third Episode')
assert len(fg.entry()) == 1
fg.remove_entry(0)
assert len(fg.entry()) == 0
def test_removeEntryByEntry(self):
fg = FeedGenerator()
self.feedId = 'http://example.com'
self.title = 'Some Testfeed'
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654321/1')
fe.title('The Third Episode')
assert len(fg.entry()) == 1
fg.remove_entry(fe)
assert len(fg.entry()) == 0
def test_categoryHasDomain(self):
fg = FeedGenerator()
fg.title('some title')
fg.link(href='http://www.dontcare.com', rel='alternate')
fg.description('description')
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654321/1')
fe.title('some title')
fe.category([
{'term': 'category',
'scheme': 'http://www.somedomain.com/category',
'label': 'Category',
}])
result = fg.rss_str()
assert b'domain="http://www.somedomain.com/category"' in result
def test_content_cdata_type(self):
fg = FeedGenerator()
fg.title('some title')
fg.id('http://lernfunk.de/media/654322/1')
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654322/1')
fe.title('some title')
fe.content('content', type='CDATA')
result = fg.atom_str()
assert b'<content type="CDATA"><![CDATA[content]]></content>' in result
def test_summary_html_type(self):
fg = FeedGenerator()
fg.title('some title')
fg.id('http://lernfunk.de/media/654322/1')
fe = fg.add_entry()
fe.id('http://lernfunk.de/media/654322/1')
fe.title('some title')
fe.link(href='http://lernfunk.de/media/654322/1')
fe.summary('<p>summary</p>', type='html')
result = fg.atom_str()
expected = b'<summary type="html">&lt;p&gt;summary&lt;/p&gt;</summary>'
assert expected in result

View file

@ -1,31 +0,0 @@
import unittest
from feedgen.feed import FeedGenerator
class TestExtensionDc(unittest.TestCase):
def setUp(self):
self.fg = FeedGenerator()
self.fg.load_extension('dc')
self.fg.title('title')
self.fg.link(href='http://example.com', rel='self')
self.fg.description('description')
def test_entryLoadExtension(self):
fe = self.fg.add_item()
try:
fe.load_extension('dc')
except ImportError:
pass # Extension already loaded
def test_elements(self):
for method in dir(self.fg.dc):
if method.startswith('dc_'):
m = getattr(self.fg.dc, method)
m(method)
assert m() == [method]
self.fg.id('123')
assert self.fg.atom_str()
assert self.fg.rss_str()

View file

@ -1,429 +0,0 @@
from itertools import chain
import unittest
import warnings
from lxml import etree
from feedgen.feed import FeedGenerator
from feedgen.ext.geo_entry import GeoRSSPolygonInteriorWarning, GeoRSSGeometryError # noqa: E501
class Geom(object):
"""
Dummy geom to make testing easier
When we use the geo-interface we need a class with a `__geo_interface__`
property. Makes it easier for the other tests as well.
Ultimately this could be used to generate dummy geometries for testing
a wider variety of values (e.g. with the faker library, or the hypothesis
library)
"""
def __init__(self, geom_type, coords):
self.geom_type = geom_type
self.coords = coords
def __str__(self):
if self.geom_type == 'Point':
coords = '{:f} {:f}'.format(
self.coords[1], # latitude is y
self.coords[0]
)
return coords
elif self.geom_type == 'LineString':
coords = ' '.join(
'{:f} {:f}'.format(vertex[1], vertex[0])
for vertex in
self.coords
)
return coords
elif self.geom_type == 'Polygon':
coords = ' '.join(
'{:f} {:f}'.format(vertex[1], vertex[0])
for vertex in
self.coords[0]
)
return coords
elif self.geom_type == 'Box':
# box not really supported by GeoJSON, but it's a handy cheat here
# for testing
coords = ' '.join(
'{:f} {:f}'.format(vertex[1], vertex[0])
for vertex in
self.coords
)
return coords[:2]
else:
return 'Not a supported geometry'
@property
def __geo_interface__(self):
return {
'type': self.geom_type,
'coordinates': self.coords
}
class TestExtensionGeo(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.point = Geom('Point', [-71.05, 42.36])
cls.line = Geom('LineString', [[-71.05, 42.36], [-71.15, 42.46]])
cls.polygon = Geom(
'Polygon',
[[[-71.05, 42.36], [-71.15, 42.46], [-71.15, 42.36]]]
)
cls.box = Geom('Box', [[-71.05, 42.36], [-71.15, 42.46]])
cls.polygon_with_interior = Geom(
'Polygon',
[
[ # exterior
[0, 0],
[0, 1],
[1, 1],
[1, 0],
[0, 0]
],
[ # interior
[0.25, 0.25],
[0.25, 0.75],
[0.75, 0.75],
[0.75, 0.25],
[0.25, 0.25]
]
]
)
def setUp(self):
self.fg = FeedGenerator()
self.fg.load_extension('geo')
self.fg.title('title')
self.fg.link(href='http://example.com', rel='self')
self.fg.description('description')
def test_point(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.point(str(self.point))
self.assertEqual(fe.geo.point(), str(self.point))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
point = root.xpath('/rss/channel/item/georss:point/text()',
namespaces=ns)
self.assertEqual(point, [str(self.point)])
def test_line(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.line(str(self.line))
self.assertEqual(fe.geo.line(), str(self.line))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
line = root.xpath(
'/rss/channel/item/georss:line/text()',
namespaces=ns
)
self.assertEqual(line, [str(self.line)])
def test_polygon(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.polygon(str(self.polygon))
self.assertEqual(fe.geo.polygon(), str(self.polygon))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
poly = root.xpath(
'/rss/channel/item/georss:polygon/text()',
namespaces=ns
)
self.assertEqual(poly, [str(self.polygon)])
def test_box(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.box(str(self.box))
self.assertEqual(fe.geo.box(), str(self.box))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
box = root.xpath(
'/rss/channel/item/georss:box/text()',
namespaces=ns
)
self.assertEqual(box, [str(self.box)])
def test_featuretypetag(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.featuretypetag('city')
self.assertEqual(fe.geo.featuretypetag(), 'city')
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
featuretypetag = root.xpath(
'/rss/channel/item/georss:featuretypetag/text()',
namespaces=ns
)
self.assertEqual(featuretypetag, ['city'])
def test_relationshiptag(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.relationshiptag('is-centred-at')
self.assertEqual(fe.geo.relationshiptag(), 'is-centred-at')
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
relationshiptag = root.xpath(
'/rss/channel/item/georss:relationshiptag/text()',
namespaces=ns
)
self.assertEqual(relationshiptag, ['is-centred-at'])
def test_featurename(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.featurename('Footscray')
self.assertEqual(fe.geo.featurename(), 'Footscray')
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
featurename = root.xpath(
'/rss/channel/item/georss:featurename/text()',
namespaces=ns
)
self.assertEqual(featurename, ['Footscray'])
def test_elev(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.elev(100.3)
self.assertEqual(fe.geo.elev(), 100.3)
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
elev = root.xpath(
'/rss/channel/item/georss:elev/text()',
namespaces=ns
)
self.assertEqual(elev, ['100.3'])
def test_elev_fails_nonnumeric(self):
fe = self.fg.add_item()
fe.title('y')
with self.assertRaises(ValueError):
fe.geo.elev('100.3')
def test_floor(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.floor(4)
self.assertEqual(fe.geo.floor(), 4)
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
floor = root.xpath(
'/rss/channel/item/georss:floor/text()',
namespaces=ns
)
self.assertEqual(floor, ['4'])
def test_floor_fails_nonint(self):
fe = self.fg.add_item()
fe.title('y')
with self.assertRaises(ValueError):
fe.geo.floor(100.3)
with self.assertRaises(ValueError):
fe.geo.floor('4')
def test_radius(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.radius(100.3)
self.assertEqual(fe.geo.radius(), 100.3)
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
radius = root.xpath(
'/rss/channel/item/georss:radius/text()',
namespaces=ns
)
self.assertEqual(radius, ['100.3'])
def test_radius_fails_nonnumeric(self):
fe = self.fg.add_item()
fe.title('y')
with self.assertRaises(ValueError):
fe.geo.radius('100.3')
def test_geom_from_geointerface_point(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.geom_from_geo_interface(self.point)
self.assertEqual(fe.geo.point(), str(self.point))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
point = root.xpath('/rss/channel/item/georss:point/text()',
namespaces=ns)
self.assertEqual(point, [str(self.point)])
coords = [float(c) for c in point[0].split()]
try:
self.assertCountEqual(
coords,
self.point.coords
)
except AttributeError: # was assertItemsEqual in Python 2.7
self.assertItemsEqual(
coords,
self.point.coords
)
def test_geom_from_geointerface_line(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.geom_from_geo_interface(self.line)
self.assertEqual(fe.geo.line(), str(self.line))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
line = root.xpath('/rss/channel/item/georss:line/text()',
namespaces=ns)
self.assertEqual(line, [str(self.line)])
coords = [float(c) for c in line[0].split()]
try:
self.assertCountEqual(
coords,
list(chain.from_iterable(self.line.coords))
)
except AttributeError: # was assertItemsEqual in Python 2.7
self.assertItemsEqual(
coords,
list(chain.from_iterable(self.line.coords))
)
def test_geom_from_geointerface_poly(self):
fe = self.fg.add_item()
fe.title('y')
fe.geo.geom_from_geo_interface(self.polygon)
self.assertEqual(fe.geo.polygon(), str(self.polygon))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
poly = root.xpath('/rss/channel/item/georss:polygon/text()',
namespaces=ns)
self.assertEqual(poly, [str(self.polygon)])
coords = [float(c) for c in poly[0].split()]
try:
self.assertCountEqual(
coords,
list(chain.from_iterable(self.polygon.coords[0]))
)
except AttributeError: # was assertItemsEqual in Python 2.7
self.assertItemsEqual(
coords,
list(chain.from_iterable(self.polygon.coords[0]))
)
def test_geom_from_geointerface_fail_other_geom(self):
fe = self.fg.add_item()
fe.title('y')
with self.assertRaises(GeoRSSGeometryError):
fe.geo.geom_from_geo_interface(self.box)
def test_geom_from_geointerface_fail_requires_geo_interface(self):
fe = self.fg.add_item()
fe.title('y')
with self.assertRaises(AttributeError):
fe.geo.geom_from_geo_interface(str(self.box))
def test_geom_from_geointerface_warn_poly_interior(self):
"""
Test complex polygons warn as expected. Taken from
https://stackoverflow.com/a/3892301/379566 and
https://docs.python.org/2.7/library/warnings.html#testing-warnings
"""
fe = self.fg.add_item()
fe.title('y')
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
# Trigger a warning.
fe.geo.geom_from_geo_interface(self.polygon_with_interior)
# Verify some things
assert len(w) == 1
assert issubclass(w[-1].category, GeoRSSPolygonInteriorWarning)
self.assertEqual(fe.geo.polygon(), str(self.polygon_with_interior))
# Check that we have the item in the resulting XML
ns = {'georss': 'http://www.georss.org/georss'}
root = etree.fromstring(self.fg.rss_str())
poly = root.xpath('/rss/channel/item/georss:polygon/text()',
namespaces=ns)
self.assertEqual(poly, [str(self.polygon_with_interior)])
coords = [float(c) for c in poly[0].split()]
try:
self.assertCountEqual(
coords,
list(chain.from_iterable(self.polygon_with_interior.coords[0]))
)
except AttributeError: # was assertItemsEqual in Python 2.7
self.assertItemsEqual(
coords,
list(chain.from_iterable(self.polygon_with_interior.coords[0]))
)

View file

@ -1,83 +0,0 @@
import unittest
from lxml import etree
from feedgen.feed import FeedGenerator
class TestExtensionMedia(unittest.TestCase):
def setUp(self):
self.fg = FeedGenerator()
self.fg.load_extension('media')
self.fg.id('id')
self.fg.title('title')
self.fg.link(href='http://example.com', rel='self')
self.fg.description('description')
def test_media_content(self):
fe = self.fg.add_item()
fe.id('id')
fe.title('title')
fe.content('content')
fe.media.content(url='file1.xy')
fe.media.content(url='file2.xy')
fe.media.content(url='file1.xy', group=2)
fe.media.content(url='file2.xy', group=2)
fe.media.content(url='file.xy', group=None)
ns = {'media': 'http://search.yahoo.com/mrss/',
'a': 'http://www.w3.org/2005/Atom'}
# Check that we have the item in the resulting RSS
root = etree.fromstring(self.fg.rss_str())
url = root.xpath('/rss/channel/item/media:group/media:content[1]/@url',
namespaces=ns)
assert url == ['file1.xy', 'file1.xy']
# There is one without a group
url = root.xpath('/rss/channel/item/media:content[1]/@url',
namespaces=ns)
assert url == ['file.xy']
# Check that we have the item in the resulting Atom feed
root = etree.fromstring(self.fg.atom_str())
url = root.xpath('/a:feed/a:entry/media:group/media:content[1]/@url',
namespaces=ns)
assert url == ['file1.xy', 'file1.xy']
fe.media.content(content=[], replace=True)
assert fe.media.content() == []
def test_media_thumbnail(self):
fe = self.fg.add_item()
fe.id('id')
fe.title('title')
fe.content('content')
fe.media.thumbnail(url='file1.xy')
fe.media.thumbnail(url='file2.xy')
fe.media.thumbnail(url='file1.xy', group=2)
fe.media.thumbnail(url='file2.xy', group=2)
fe.media.thumbnail(url='file.xy', group=None)
ns = {'media': 'http://search.yahoo.com/mrss/',
'a': 'http://www.w3.org/2005/Atom'}
# Check that we have the item in the resulting RSS
root = etree.fromstring(self.fg.rss_str())
url = root.xpath(
'/rss/channel/item/media:group/media:thumbnail[1]/@url',
namespaces=ns)
assert url == ['file1.xy', 'file1.xy']
# There is one without a group
url = root.xpath('/rss/channel/item/media:thumbnail[1]/@url',
namespaces=ns)
assert url == ['file.xy']
# Check that we have the item in the resulting Atom feed
root = etree.fromstring(self.fg.atom_str())
url = root.xpath('/a:feed/a:entry/media:group/media:thumbnail[1]/@url',
namespaces=ns)
assert url == ['file1.xy', 'file1.xy']
fe.media.thumbnail(thumbnail=[], replace=True)
assert fe.media.thumbnail() == []

View file

@ -1,96 +0,0 @@
import unittest
from lxml import etree
from feedgen.feed import FeedGenerator
class TestExtensionPodcast(unittest.TestCase):
def setUp(self):
self.fg = FeedGenerator()
self.fg.load_extension('podcast')
self.fg.title('title')
self.fg.link(href='http://example.com', rel='self')
self.fg.description('description')
def test_category_new(self):
self.fg.podcast.itunes_category([{'cat': 'Technology',
'sub': 'Podcasting'}])
self.fg.podcast.itunes_explicit('no')
self.fg.podcast.itunes_complete('no')
self.fg.podcast.itunes_new_feed_url('http://example.com/new-feed.rss')
self.fg.podcast.itunes_owner('John Doe', 'john@example.com')
ns = {'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd'}
root = etree.fromstring(self.fg.rss_str())
cat = root.xpath('/rss/channel/itunes:category/@text', namespaces=ns)
scat = root.xpath('/rss/channel/itunes:category/itunes:category/@text',
namespaces=ns)
assert cat[0] == 'Technology'
assert scat[0] == 'Podcasting'
def test_category(self):
self.fg.podcast.itunes_category('Technology', 'Podcasting')
self.fg.podcast.itunes_explicit('no')
self.fg.podcast.itunes_complete('no')
self.fg.podcast.itunes_new_feed_url('http://example.com/new-feed.rss')
self.fg.podcast.itunes_owner('John Doe', 'john@example.com')
ns = {'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd'}
root = etree.fromstring(self.fg.rss_str())
cat = root.xpath('/rss/channel/itunes:category/@text', namespaces=ns)
scat = root.xpath('/rss/channel/itunes:category/itunes:category/@text',
namespaces=ns)
assert cat[0] == 'Technology'
assert scat[0] == 'Podcasting'
def test_podcastItems(self):
fg = self.fg
fg.podcast.itunes_author('Lars Kiesow')
fg.podcast.itunes_block('x')
fg.podcast.itunes_complete(False)
fg.podcast.itunes_explicit('no')
fg.podcast.itunes_image('x.png')
fg.podcast.itunes_subtitle('x')
fg.podcast.itunes_summary('x')
assert fg.podcast.itunes_author() == 'Lars Kiesow'
assert fg.podcast.itunes_block() == 'x'
assert fg.podcast.itunes_complete() == 'no'
assert fg.podcast.itunes_explicit() == 'no'
assert fg.podcast.itunes_image() == 'x.png'
assert fg.podcast.itunes_subtitle() == 'x'
assert fg.podcast.itunes_summary() == 'x'
# Check that we have the item in the resulting XML
ns = {'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd'}
root = etree.fromstring(self.fg.rss_str())
author = root.xpath('/rss/channel/itunes:author/text()', namespaces=ns)
assert author == ['Lars Kiesow']
def test_podcastEntryItems(self):
fe = self.fg.add_item()
fe.title('y')
fe.podcast.itunes_author('Lars Kiesow')
fe.podcast.itunes_block('x')
fe.podcast.itunes_duration('00:01:30')
fe.podcast.itunes_explicit('no')
fe.podcast.itunes_image('x.png')
fe.podcast.itunes_is_closed_captioned('yes')
fe.podcast.itunes_order(1)
fe.podcast.itunes_subtitle('x')
fe.podcast.itunes_summary('x')
assert fe.podcast.itunes_author() == 'Lars Kiesow'
assert fe.podcast.itunes_block() == 'x'
assert fe.podcast.itunes_duration() == '00:01:30'
assert fe.podcast.itunes_explicit() == 'no'
assert fe.podcast.itunes_image() == 'x.png'
assert fe.podcast.itunes_is_closed_captioned()
assert fe.podcast.itunes_order() == 1
assert fe.podcast.itunes_subtitle() == 'x'
assert fe.podcast.itunes_summary() == 'x'
# Check that we have the item in the resulting XML
ns = {'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd'}
root = etree.fromstring(self.fg.rss_str())
author = root.xpath('/rss/channel/item/itunes:author/text()',
namespaces=ns)
assert author == ['Lars Kiesow']

View file

@ -1,40 +0,0 @@
import unittest
from lxml import etree
from feedgen.feed import FeedGenerator
class TestExtensionSyndication(unittest.TestCase):
SYN_NS = {'sy': 'http://purl.org/rss/1.0/modules/syndication/'}
def setUp(self):
self.fg = FeedGenerator()
self.fg.load_extension('syndication')
self.fg.title('title')
self.fg.link(href='http://example.com', rel='self')
self.fg.description('description')
def test_update_period(self):
for period_type in ('hourly', 'daily', 'weekly', 'monthly', 'yearly'):
self.fg.syndication.update_period(period_type)
root = etree.fromstring(self.fg.rss_str())
a = root.xpath('/rss/channel/sy:UpdatePeriod',
namespaces=self.SYN_NS)
assert a[0].text == period_type
def test_update_frequency(self):
for frequency in (1, 100, 2000, 100000):
self.fg.syndication.update_frequency(frequency)
root = etree.fromstring(self.fg.rss_str())
a = root.xpath('/rss/channel/sy:UpdateFrequency',
namespaces=self.SYN_NS)
assert a[0].text == str(frequency)
def test_update_base(self):
base = '2000-01-01T12:00+00:00'
self.fg.syndication.update_base(base)
root = etree.fromstring(self.fg.rss_str())
a = root.xpath('/rss/channel/sy:UpdateBase', namespaces=self.SYN_NS)
assert a[0].text == base

View file

@ -1,38 +0,0 @@
import unittest
from lxml import etree
from feedgen.feed import FeedGenerator
class TestExtensionTorrent(unittest.TestCase):
def setUp(self):
self.fg = FeedGenerator()
self.fg.load_extension('torrent')
self.fg.title('title')
self.fg.link(href='http://example.com', rel='self')
self.fg.description('description')
def test_podcastEntryItems(self):
fe = self.fg.add_item()
fe.title('y')
fe.torrent.filename('file.xy')
fe.torrent.infohash('123')
fe.torrent.contentlength('23')
fe.torrent.seeds('1')
fe.torrent.peers('2')
fe.torrent.verified('1')
assert fe.torrent.filename() == 'file.xy'
assert fe.torrent.infohash() == '123'
assert fe.torrent.contentlength() == '23'
assert fe.torrent.seeds() == '1'
assert fe.torrent.peers() == '2'
assert fe.torrent.verified() == '1'
# Check that we have the item in the resulting XML
ns = {'torrent': 'http://xmlns.ezrss.it/0.1/dtd/'}
root = etree.fromstring(self.fg.rss_str())
filename = root.xpath('/rss/channel/item/torrent:filename/text()',
namespaces=ns)
assert filename == ['file.xy']

View file

@ -1,340 +0,0 @@
# -*- coding: utf-8 -*-
"""
Tests for a basic feed
These are test cases for a basic feed.
A basic feed does not contain entries so far.
"""
import os
import tempfile
import unittest
from lxml import etree
from feedgen.ext.dc import DcEntryExtension, DcExtension
from feedgen.feed import FeedGenerator
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
fg = FeedGenerator()
self.nsAtom = "http://www.w3.org/2005/Atom"
self.nsRss = "http://purl.org/rss/1.0/modules/content/"
self.feedId = 'http://lernfunk.de/media/654321'
self.title = 'Some Testfeed'
self.authorName = 'John Doe'
self.authorMail = 'john@example.de'
self.author = {'name': self.authorName, 'email': self.authorMail}
self.linkHref = 'http://example.com'
self.linkRel = 'alternate'
self.logo = 'http://ex.com/logo.jpg'
self.subtitle = 'This is a cool feed!'
self.link2Href = 'http://larskiesow.de/test.atom'
self.link2Rel = 'self'
self.language = 'en'
self.categoryTerm = 'This category term'
self.categoryScheme = 'This category scheme'
self.categoryLabel = 'This category label'
self.cloudDomain = 'example.com'
self.cloudPort = '4711'
self.cloudPath = '/ws/example'
self.cloudRegisterProcedure = 'registerProcedure'
self.cloudProtocol = 'SOAP 1.1'
self.icon = "http://example.com/icon.png"
self.contributor = {'name': "Contributor Name",
'uri': "Contributor Uri",
'email': 'Contributor email'}
self.copyright = "The copyright notice"
self.docs = 'http://www.rssboard.org/rss-specification'
self.managingEditor = 'mail@example.com'
self.rating = '(PICS-1.1 "http://www.classify.org/safesurf/" ' + \
'1 r (SS~~000 1))'
self.skipDays = 'Tuesday'
self.skipHours = 23
self.textInputTitle = "Text input title"
self.textInputDescription = "Text input description"
self.textInputName = "Text input name"
self.textInputLink = "Text input link"
self.ttl = 900
self.webMaster = 'webmaster@example.com'
fg.id(self.feedId)
fg.title(self.title)
fg.author(self.author)
fg.link(href=self.linkHref, rel=self.linkRel)
fg.logo(self.logo)
fg.subtitle(self.subtitle)
fg.link(href=self.link2Href, rel=self.link2Rel)
fg.language(self.language)
fg.cloud(domain=self.cloudDomain, port=self.cloudPort,
path=self.cloudPath,
registerProcedure=self.cloudRegisterProcedure,
protocol=self.cloudProtocol)
fg.icon(self.icon)
fg.category(term=self.categoryTerm, scheme=self.categoryScheme,
label=self.categoryLabel)
fg.contributor(self.contributor)
fg.copyright(self.copyright)
fg.docs(docs=self.docs)
fg.managingEditor(self.managingEditor)
fg.rating(self.rating)
fg.skipDays(self.skipDays)
fg.skipHours(self.skipHours)
fg.textInput(title=self.textInputTitle,
description=self.textInputDescription,
name=self.textInputName, link=self.textInputLink)
fg.ttl(self.ttl)
fg.webMaster(self.webMaster)
fg.updated('2017-02-05 13:26:58+01:00')
fg.pubDate('2017-02-05 13:26:58+01:00')
fg.generator('python-feedgen', 'x', uri='http://github.com/lkie...')
fg.image(url=self.logo,
title=self.title,
link=self.link2Href,
width='123',
height='123',
description='Example Inage')
self.fg = fg
def test_baseFeed(self):
fg = self.fg
assert fg.id() == self.feedId
assert fg.title() == self.title
assert fg.author()[0]['name'] == self.authorName
assert fg.author()[0]['email'] == self.authorMail
assert fg.link()[0]['href'] == self.linkHref
assert fg.link()[0]['rel'] == self.linkRel
assert fg.logo() == self.logo
assert fg.subtitle() == self.subtitle
assert fg.link()[1]['href'] == self.link2Href
assert fg.link()[1]['rel'] == self.link2Rel
assert fg.language() == self.language
def test_atomFeedFile(self):
fg = self.fg
fh, filename = tempfile.mkstemp()
fg.atom_file(filename=filename, pretty=True, xml_declaration=False)
with open(filename, "r") as myfile:
atomString = myfile.read().replace('\n', '')
self.checkAtomString(atomString)
os.close(fh)
os.remove(filename)
def test_atomFeedString(self):
fg = self.fg
atomString = fg.atom_str(pretty=True, xml_declaration=False)
self.checkAtomString(atomString)
def test_rel_values_for_atom(self):
values_for_rel = [
'about', 'alternate', 'appendix', 'archives', 'author', 'bookmark',
'canonical', 'chapter', 'collection', 'contents', 'copyright',
'create-form', 'current', 'derivedfrom', 'describedby',
'describes', 'disclosure', 'duplicate', 'edit', 'edit-form',
'edit-media', 'enclosure', 'first', 'glossary', 'help', 'hosts',
'hub', 'icon', 'index', 'item', 'last', 'latest-version',
'license', 'lrdd', 'memento', 'monitor', 'monitor-group', 'next',
'next-archive', 'nofollow', 'noreferrer', 'original', 'payment',
'predecessor-version', 'prefetch', 'prev', 'preview', 'previous',
'prev-archive', 'privacy-policy', 'profile', 'related', 'replies',
'search', 'section', 'self', 'service', 'start', 'stylesheet',
'subsection', 'successor-version', 'tag', 'terms-of-service',
'timegate', 'timemap', 'type', 'up', 'version-history', 'via',
'working-copy', 'working-copy-of']
links = [{'href': '%s/%s' % (self.linkHref,
val.replace('-', '_')), 'rel': val}
for val in values_for_rel]
fg = self.fg
fg.link(links, replace=True)
atomString = fg.atom_str(pretty=True, xml_declaration=False)
feed = etree.fromstring(atomString)
nsAtom = self.nsAtom
feed_links = feed.findall("{%s}link" % nsAtom)
idx = 0
assert len(links) == len(feed_links)
while idx < len(values_for_rel):
assert feed_links[idx].get('href') == links[idx]['href']
assert feed_links[idx].get('rel') == links[idx]['rel']
idx += 1
def test_rel_values_for_rss(self):
values_for_rel = [
'about', 'alternate', 'appendix', 'archives', 'author', 'bookmark',
'canonical', 'chapter', 'collection', 'contents', 'copyright',
'create-form', 'current', 'derivedfrom', 'describedby',
'describes', 'disclosure', 'duplicate', 'edit', 'edit-form',
'edit-media', 'enclosure', 'first', 'glossary', 'help', 'hosts',
'hub', 'icon', 'index', 'item', 'last', 'latest-version',
'license', 'lrdd', 'memento', 'monitor', 'monitor-group', 'next',
'next-archive', 'nofollow', 'noreferrer', 'original', 'payment',
'predecessor-version', 'prefetch', 'prev', 'preview', 'previous',
'prev-archive', 'privacy-policy', 'profile', 'related', 'replies',
'search', 'section', 'self', 'service', 'start', 'stylesheet',
'subsection', 'successor-version', 'tag', 'terms-of-service',
'timegate', 'timemap', 'type', 'up', 'version-history', 'via',
'working-copy', 'working-copy-of']
links = [{'href': '%s/%s' % (self.linkHref,
val.replace('-', '_')), 'rel': val}
for val in values_for_rel]
fg = self.fg
fg.link(links, replace=True)
rssString = fg.rss_str(pretty=True, xml_declaration=False)
feed = etree.fromstring(rssString)
channel = feed.find("channel")
nsAtom = self.nsAtom
atom_links = channel.findall("{%s}link" % nsAtom)
# rss feed only implements atom's 'self' link
assert len(atom_links) == 1
assert atom_links[0].get('href') == '%s/%s' % (self.linkHref, 'self')
assert atom_links[0].get('rel') == 'self'
rss_links = channel.findall('link')
# RSS only needs one URL. We use the first link for RSS:
assert len(rss_links) == 1
assert rss_links[0].text == '%s/%s' % \
(self.linkHref, 'working-copy-of'.replace('-', '_'))
def checkAtomString(self, atomString):
feed = etree.fromstring(atomString)
nsAtom = self.nsAtom
assert feed.find("{%s}title" % nsAtom).text == self.title
assert feed.find("{%s}updated" % nsAtom).text is not None
assert feed.find("{%s}id" % nsAtom).text == self.feedId
assert feed.find("{%s}category" % nsAtom)\
.get('term') == self.categoryTerm
assert feed.find("{%s}category" % nsAtom)\
.get('label') == self.categoryLabel
assert feed.find("{%s}author" % nsAtom)\
.find("{%s}name" % nsAtom).text == self.authorName
assert feed.find("{%s}author" % nsAtom)\
.find("{%s}email" % nsAtom).text == self.authorMail
assert feed.findall("{%s}link" % nsAtom)[0]\
.get('href') == self.linkHref
assert feed.findall("{%s}link" % nsAtom)[0].get('rel') == self.linkRel
assert feed.findall("{%s}link" % nsAtom)[1]\
.get('href') == self.link2Href
assert feed.findall("{%s}link" % nsAtom)[1].get('rel') == self.link2Rel
assert feed.find("{%s}logo" % nsAtom).text == self.logo
assert feed.find("{%s}icon" % nsAtom).text == self.icon
assert feed.find("{%s}subtitle" % nsAtom).text == self.subtitle
assert feed.find("{%s}contributor" % nsAtom)\
.find("{%s}name" % nsAtom).text == self.contributor['name']
assert feed.find("{%s}contributor" % nsAtom)\
.find("{%s}email" % nsAtom).text == self.contributor['email']
assert feed.find("{%s}contributor" % nsAtom)\
.find("{%s}uri" % nsAtom).text == self.contributor['uri']
assert feed.find("{%s}rights" % nsAtom).text == self.copyright
def test_rssFeedFile(self):
fg = self.fg
_, filename = tempfile.mkstemp()
fg.rss_file(filename=filename, pretty=True, xml_declaration=False)
with open(filename, "r") as myfile:
rssString = myfile.read().replace('\n', '')
self.checkRssString(rssString)
def test_rssFeedString(self):
fg = self.fg
rssString = fg.rss_str(pretty=True, xml_declaration=False)
self.checkRssString(rssString)
def test_loadPodcastExtension(self):
fg = self.fg
fg.add_entry()
fg.load_extension('podcast', atom=True, rss=True)
fg.add_entry()
def test_loadDcExtension(self):
fg = self.fg
fg.add_entry()
fg.load_extension('dc', atom=True, rss=True)
fg.add_entry()
def test_extensionAlreadyLoaded(self):
fg = self.fg
fg.load_extension('dc', atom=True, rss=True)
with self.assertRaises(ImportError):
fg.load_extension('dc')
def test_registerCustomExtension(self):
fg = self.fg
fg.add_entry()
fg.register_extension('dc', DcExtension, DcEntryExtension)
fg.add_entry()
def checkRssString(self, rssString):
feed = etree.fromstring(rssString)
nsAtom = self.nsAtom
ch = feed.find("channel")
assert ch is not None
assert ch.find("title").text == self.title
assert ch.find("description").text == self.subtitle
assert ch.find("lastBuildDate").text is not None
docs = "http://www.rssboard.org/rss-specification"
assert ch.find("docs").text == docs
assert ch.find("generator").text == "python-feedgen"
assert ch.findall("{%s}link" % nsAtom)[0].get('href') == self.link2Href
assert ch.findall("{%s}link" % nsAtom)[0].get('rel') == self.link2Rel
assert ch.find("image").find("url").text == self.logo
assert ch.find("image").find("title").text == self.title
assert ch.find("image").find("link").text == self.link2Href
assert ch.find("category").text == self.categoryLabel
assert ch.find("cloud").get('domain') == self.cloudDomain
assert ch.find("cloud").get('port') == self.cloudPort
assert ch.find("cloud").get('path') == self.cloudPath
assert ch.find("cloud").get('registerProcedure') == \
self.cloudRegisterProcedure
assert ch.find("cloud").get('protocol') == self.cloudProtocol
assert ch.find("copyright").text == self.copyright
assert ch.find("docs").text == self.docs
assert ch.find("managingEditor").text == self.managingEditor
assert ch.find("rating").text == self.rating
assert ch.find("skipDays").find("day").text == self.skipDays
assert int(ch.find("skipHours").find("hour").text) == self.skipHours
assert ch.find("textInput").get('title') == self.textInputTitle
assert ch.find("textInput").get('description') == \
self.textInputDescription
assert ch.find("textInput").get('name') == self.textInputName
assert ch.find("textInput").get('link') == self.textInputLink
assert int(ch.find("ttl").text) == self.ttl
assert ch.find("webMaster").text == self.webMaster
if __name__ == '__main__':
unittest.main()

View file

@ -1,42 +0,0 @@
# -*- coding: utf-8 -*-
'''
Tests for feedgen main
'''
import os
import sys
import tempfile
import unittest
from feedgen import __main__
class TestSequenceFunctions(unittest.TestCase):
def test_usage(self):
sys.argv = ['feedgen']
try:
__main__.main()
except BaseException as e:
assert e.code is None
def test_feed(self):
for ftype in 'rss', 'atom', 'podcast', 'torrent', 'dc.rss', 'dc.atom',\
'syndication.rss', 'syndication.atom':
sys.argv = ['feedgen', ftype]
try:
__main__.main()
except Exception:
assert False
def test_file(self):
for extemsion in '.atom', '.rss':
fh, filename = tempfile.mkstemp(extemsion)
sys.argv = ['feedgen', filename]
try:
__main__.main()
except Exception:
assert False
os.close(fh)
os.remove(filename)