Source code for asv.feed

# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
Minimal Atom feed writer.
"""

import datetime
import hashlib
import xml.etree.ElementTree as ET

from . import util

__all__ = ['FeedEntry', 'write_atom']


ATOM_NS = "{http://www.w3.org/2005/Atom}"
XML_NS = "{http://www.w3.org/XML/1998/namespace}"


[docs] class FeedEntry: """ Atom feed entry. Parameters ---------- title : str Title of the entry updated : datetime Update date link : str, optional Link (alternate) for the entry content : str, optional Body HTML text for the entry. id_context : list of str, optional Material to generate unique IDs from. Feed readers show each id as a separate entry, so if an entry is updated, it appears as a new entry only if the id_context changes. Default: [title, link, content] id_date : datetime Date to include in the id. Default: same as *updated* """ def __init__(self, title, updated, link=None, content=None, id_context=None, id_date=None):
[docs] self.title = title
[docs] self.updated = updated
[docs] self.content = content
[docs] self.id_context = id_context
[docs] self.id_date = id_date
[docs] def get_atom(self, id_prefix, language): item = ET.Element(f'{ATOM_NS}entry') id_context = ["entry"] if self.id_context is None: id_context += [self.title, self.link, self.content] else: id_context += list(self.id_context) if self.id_date is None: id_date = self.updated else: id_date = self.id_date el = ET.Element(f'{ATOM_NS}id') el.text = _get_id(id_prefix, id_date, id_context) item.append(el) el = ET.Element(f'{ATOM_NS}title') el.attrib[f'{XML_NS}lang'] = language el.text = self.title item.append(el) el = ET.Element(f'{ATOM_NS}updated') el.text = self.updated.strftime('%Y-%m-%dT%H:%M:%SZ') item.append(el) if self.link: el = ET.Element(f'{ATOM_NS}link') el.attrib[f'{ATOM_NS}href'] = self.link item.append(el) el = ET.Element(f'{ATOM_NS}content') el.attrib[f'{XML_NS}lang'] = language if self.content: el.text = self.content el.attrib[f'{ATOM_NS}type'] = 'html' else: el.text = ' ' item.append(el) return item
[docs] def write_atom(dest, entries, author, title, address, updated=None, link=None, language="en"): """ Write an atom feed to a file. Parameters ---------- dest : str Destination file path, or a file-like object entries : list of FeedEntry Feed entries. author : str Author of the feed. title : str Title for the feed. address : str Address (domain name or email) to be used in building unique IDs. updated : datetime, optional Time stamp for the feed. If not given, take from the newest entry. link : str, optional Link for the feed. language : str, optional Language of the feed. Default is 'en'. """ if updated is None: if entries: updated = max(entry.updated for entry in entries) else: updated = datetime.datetime.now(datetime.timezone.utc) root = ET.Element(f'{ATOM_NS}feed') # id (obligatory) el = ET.Element(f'{ATOM_NS}id') el.text = _get_id(address, None, ["feed", author, title]) root.append(el) # author (obligatory) el = ET.Element(f'{ATOM_NS}author') el2 = ET.Element(f'{ATOM_NS}name') el2.text = author el.append(el2) root.append(el) # title (obligatory) el = ET.Element(f'{ATOM_NS}title') el.attrib[f'{XML_NS}lang'] = language el.text = title root.append(el) # updated (obligatory) el = ET.Element(f'{ATOM_NS}updated') el.text = updated.strftime('%Y-%m-%dT%H:%M:%SZ') root.append(el) # link if link is not None: el = ET.Element(f'{ATOM_NS}link') el.attrib[f'{ATOM_NS}href'] = link root.append(el) # entries for entry in entries: root.append(entry.get_atom(address, language)) tree = ET.ElementTree(root) def write(f): tree.write(f, xml_declaration=True, default_namespace=ATOM_NS[1:-1], encoding="utf-8") if hasattr(dest, 'write'): write(dest) else: with util.long_path_open(dest, 'wb') as f: write(f)
def _get_id(owner, date, content): """ Generate an unique Atom id for the given content """ h = hashlib.sha256() # Hash still contains the original project url, keep as is h.update(b"github.com/spacetelescope/asv") for x in content: if x is None: h.update(b",") else: h.update(x.encode('utf-8')) h.update(b",") if date is None: date = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc) return f"tag:{owner},{date.strftime('%Y-%m-%d')}:/{h.hexdigest()}"