Beginning with documentation of code
This commit is contained in:
parent
d5b2048869
commit
611b35e035
|
@ -13,7 +13,7 @@ dist/
|
|||
build/
|
||||
*.egg-info/
|
||||
|
||||
_build
|
||||
_build/
|
||||
|
||||
bin/
|
||||
lib/
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,178 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = u'GoatNet :: Retro Blog'
|
||||
copyright = u'2018, Julian Knauer'
|
||||
author = u'Julian Knauer'
|
||||
|
||||
# The short X.Y version
|
||||
version = u''
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u''
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.coverage',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# The default sidebars (for documents that don't match any pattern) are
|
||||
# defined by theme itself. Builtin themes are using these templates by
|
||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||
# 'searchbox.html']``.
|
||||
#
|
||||
# html_sidebars = {}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'GoatNetRetroBlogdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'GoatNetRetroBlog.tex', u'GoatNet :: Retro Blog Documentation',
|
||||
u'Julian Knauer', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'goatnetretroblog', u'GoatNet :: Retro Blog Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'GoatNetRetroBlog', u'GoatNet -- Retro Blog Documentation',
|
||||
author, 'GoatNetRetroBlog', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Epub output -------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#
|
||||
# epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
|
@ -0,0 +1,12 @@
|
|||
=======
|
||||
goatnet
|
||||
=======
|
||||
|
||||
.. automodule:: goatnet
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: goatnet.blogstore
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
.. GoatNet -- Retro Blog documentation master file, created by
|
||||
sphinx-quickstart on Tue Dec 25 10:17:59 2018.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to GoatNet :: Retro Blog's documentation!
|
||||
=================================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
goatnet
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
|
@ -1,10 +1,8 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim:fenc=utf-8
|
||||
#
|
||||
# Copyright © 2018 jpk <jpk+dev@goatpr0n.de>
|
||||
#
|
||||
# Distributed under terms of the MIT license.
|
||||
"""
|
||||
GoatNet Blog Application
|
||||
|
||||
.. moduleauthor:: Julian Knauer <jpk+dev@goatpr0n.de>
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
|
@ -13,6 +11,14 @@ from flask import Flask
|
|||
|
||||
|
||||
def create_app(test_config=None):
|
||||
"""Create and initialize the application context.
|
||||
|
||||
Args:
|
||||
test_config (dict): Application configuration
|
||||
|
||||
Returns:
|
||||
The Flask application.
|
||||
"""
|
||||
# create and configure the app
|
||||
app = Flask(__name__, instance_relative_config=True)
|
||||
app.config.from_mapping(
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
"""
|
||||
Blog posts are stored as YAML files.
|
||||
|
||||
.. [1] Blog post file structure.
|
||||
|
||||
The YAML file is structured as follows::
|
||||
|
||||
meta:
|
||||
author: <name of author|username>
|
||||
title: <title of blog entry>
|
||||
created: <unix timestamp in hex>
|
||||
modified: <unix timestamp in hex>
|
||||
body: |
|
||||
<A reStructuredText formatted text>
|
||||
|
||||
.. moduleauthor:: Julian Knauer <jpk+dev@goatpr0n.de>
|
||||
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
@ -11,21 +29,46 @@ from flask import current_app, g
|
|||
from flask.cli import with_appcontext
|
||||
|
||||
|
||||
#: Definition of literal scalar string formatter.
|
||||
literal = ruamel.yaml.scalarstring.LiteralScalarString
|
||||
|
||||
|
||||
def transform_newline(line):
|
||||
"""Replace Windows newline with Unix newline.
|
||||
|
||||
Args:
|
||||
line (string): Input to search and replace all windows newlines.
|
||||
|
||||
Returns:
|
||||
The input is transformed with Unix style newlines.
|
||||
"""
|
||||
return line.replace('\r\n', '\n')
|
||||
|
||||
|
||||
class BlogStore():
|
||||
"""BlogStore manages and organizes the blog posts and files.
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
"""Initialize the blog file store.
|
||||
|
||||
Args:
|
||||
path (string): Points to the directory storing the blog YAML files.
|
||||
"""
|
||||
self.path = path
|
||||
|
||||
@staticmethod
|
||||
def read_file(filename):
|
||||
"""Open YAML file and return the post content
|
||||
"""Open YAML file and return the post content.
|
||||
|
||||
Args:
|
||||
filename (string): Blog post YAML file to open.
|
||||
|
||||
Returns:
|
||||
A dict mapping of the blog posts meta data and the post body
|
||||
itself.
|
||||
|
||||
The YAML file is structured as shown in [1]_.
|
||||
"""
|
||||
with open(filename, 'r') as ymlfile:
|
||||
yaml = YAML(typ='safe')
|
||||
|
@ -33,6 +76,14 @@ class BlogStore():
|
|||
return data
|
||||
|
||||
def locate_file(self, entry):
|
||||
"""Locate the filename and path of the entry.
|
||||
|
||||
Args:
|
||||
entry (str): A unix timestamp in hex representation.
|
||||
|
||||
Returns:
|
||||
The full path to the file within the blog storage filesystem.
|
||||
"""
|
||||
ts = int(entry, base=16)
|
||||
date_dir = datetime.utcfromtimestamp(ts).strftime('%Y/%m')
|
||||
filename = os.path.join(self.path, date_dir, f'{entry}.yaml')
|
||||
|
@ -41,6 +92,11 @@ class BlogStore():
|
|||
return None
|
||||
|
||||
def get_posts(self):
|
||||
"""Return all blog posts found within the blog storage filesystem.
|
||||
|
||||
Returns:
|
||||
A list of dict returned by :func:`read_file`.
|
||||
"""
|
||||
posts = []
|
||||
for root, _, files in os.walk(self.path):
|
||||
for filename in files:
|
||||
|
@ -51,6 +107,19 @@ class BlogStore():
|
|||
return posts
|
||||
|
||||
def get_post(self, entry):
|
||||
"""Get a single post by its Unix timestamp hexadecimal represented ID.
|
||||
|
||||
Args:
|
||||
entry (str): Unix timestamp hexadecimal representation.
|
||||
|
||||
Returns:
|
||||
The function returns either ``None`` or a dict returned by
|
||||
:func:`read_file`.
|
||||
|
||||
If the entry is not correctly formatted as unix timestring in
|
||||
hexadecimal or the entry cannot be located in the blog store
|
||||
filesystem, the function will return ``None``.
|
||||
"""
|
||||
try:
|
||||
ts = int(entry, base=16)
|
||||
except:
|
||||
|
@ -63,10 +132,14 @@ class BlogStore():
|
|||
return None
|
||||
|
||||
def update_post(self, entry, post):
|
||||
"""Modify the blog post and update the file.
|
||||
|
||||
Args:
|
||||
entry (str): Unix timestamp hexadecimal representation.
|
||||
post (dict): Blog post as provided by :func:`read_file`.
|
||||
"""
|
||||
post['meta']['modified'] = hex(int(time.time()))[2:]
|
||||
post['body'] = literal(post['body'])
|
||||
if 'entry' in post:
|
||||
del post['entry']
|
||||
|
||||
filename = self.locate_file(entry)
|
||||
with open(os.path.join(self.path, filename), 'w') as ymlfile:
|
||||
|
@ -74,6 +147,17 @@ class BlogStore():
|
|||
yaml.dump(post, ymlfile, transform=transform_newline)
|
||||
|
||||
def create_post(self, title, body, author):
|
||||
"""Create a new blog post and save it in the blog post filesystem.
|
||||
|
||||
The YAML file is structured as shown in [1]_.
|
||||
|
||||
Args:
|
||||
title (str): Title of the blog post.
|
||||
body (str): A `reStructuredText`_ formatted content.
|
||||
author (str): Username or name of the author.
|
||||
|
||||
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
||||
"""
|
||||
tstamp = hex(int(time.time()))[2:]
|
||||
post = {
|
||||
'meta': {
|
||||
|
@ -94,18 +178,39 @@ class BlogStore():
|
|||
yaml.dump(post, ymlfile, transform=transform_newline)
|
||||
|
||||
def delete_post(self, entry):
|
||||
"""Delete a blog post and the file.
|
||||
|
||||
As a safe guard, the ``filename`` of the blog post is checked against
|
||||
the ``path`` set during setup of :mod:`BlogStore`. The ``filename``
|
||||
must be within ``path`` in order to be deleted.
|
||||
|
||||
Args:
|
||||
entry (str): Unix timestamp hexadecimal representation.
|
||||
"""
|
||||
filename = self.locate_file(entry)
|
||||
if self.path in filename:
|
||||
os.remove(filename)
|
||||
|
||||
|
||||
def get_blogstore():
|
||||
"""Return a :mod:`BlogStore` object per application.
|
||||
|
||||
The :mod:`BlogStore` object is initialized with the parameter set in the
|
||||
configuration file for the application. The initialized :mod:`BlogStore`
|
||||
object is stored in the global variable store :mod:`flask.g`.
|
||||
|
||||
Returns:
|
||||
Per application context a single :mod:`BlogStore` is initialized and
|
||||
returned.
|
||||
"""
|
||||
if 'blogstore' not in g:
|
||||
g.blogstore = BlogStore(current_app.config['BLOGSTORE'])
|
||||
return g.blogstore
|
||||
|
||||
|
||||
def init_blogstore():
|
||||
"""Create the filesystem structure for the blog store.
|
||||
"""
|
||||
blogstore = get_blogstore()
|
||||
|
||||
try:
|
||||
|
@ -116,6 +221,10 @@ def init_blogstore():
|
|||
|
||||
|
||||
def close_blogstore(e=None):
|
||||
"""Context aware tear down of the blog store.
|
||||
|
||||
Removes the :mod:`BlogStore` from the :mod:`flask.g` global variable store.
|
||||
"""
|
||||
blogstore = g.pop('blogstore', None)
|
||||
|
||||
if blogstore is not None:
|
||||
|
@ -124,6 +233,8 @@ def close_blogstore(e=None):
|
|||
|
||||
|
||||
def purge_blogstore():
|
||||
"""Delete all blog posts and directories.
|
||||
"""
|
||||
if os.path.exists(current_app.config['BLOGSTORE']):
|
||||
shutil.rmtree(current_app.config['BLOGSTORE'])
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
astroid==2.1.0
|
||||
atomicwrites==1.2.1
|
||||
attrs==18.2.0
|
||||
Click==7.0
|
||||
|
@ -8,13 +9,17 @@ email-validator==1.0.3
|
|||
Flask==1.0.2
|
||||
Flask-Uploads==0.2.1
|
||||
idna==2.8
|
||||
isort==4.3.4
|
||||
itsdangerous==1.1.0
|
||||
Jinja2==2.10
|
||||
lazy-object-proxy==1.3.1
|
||||
MarkupSafe==1.1.0
|
||||
mccabe==0.6.1
|
||||
more-itertools==4.3.0
|
||||
pluggy==0.8.0
|
||||
py==1.7.0
|
||||
Pygments==2.3.1
|
||||
pylint==2.2.2
|
||||
pytest==4.0.2
|
||||
ruamel.appconfig==0.5.4
|
||||
ruamel.std.argparse==0.8.1
|
||||
|
@ -23,3 +28,4 @@ ruamel.yaml==0.15.81
|
|||
ryd==0.3.0
|
||||
six==1.12.0
|
||||
Werkzeug==0.14.1
|
||||
wrapt==1.10.11
|
||||
|
|
Loading…
Reference in New Issue