Docstring cleanups for documentation

This commit is contained in:
Eric Torres 2019-04-14 14:56:09 -07:00
parent 2155cc4b7a
commit 386b200e9d
12 changed files with 108 additions and 121 deletions

View File

@ -1,7 +1,7 @@
""" """
.. :author:: Eric Torres .. :author:: Eric Torres
.. :module:: rbackup.config .. :module:: rbackup.config
.. :synopsis: Functions for handling config files. :synopsis: Functions for handling config files.
""" """
import configparser import configparser
import logging import logging
@ -45,7 +45,7 @@ def merge_files(files):
Any files included that do not exist send a warning to the log. Any files included that do not exist send a warning to the log.
>>> merge_files(get_files_by_suffix('')) # doctest: +ELLIPSIS >>> merge_files(get_files_by_suffix('-include.conf')) # doctest: +ELLIPSIS
PosixPath('/tmp/...') PosixPath('/tmp/...')
:param files: files including paths to read from :param files: files including paths to read from

View File

@ -1,6 +1,6 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
.. module:: rbackup.packagemanager .. module:: rbackup.package_managers.packagemanager
:synopsis: Module for package manager plugins :synopsis: Module for package manager plugins
""" """
import logging import logging
@ -41,8 +41,8 @@ class PackageManager:
it is to be assumed that no file was created, therefore there it is to be assumed that no file was created, therefore there
is no file to cleanup. is no file to cleanup.
Note that this method is internal and is .. note:: This method is internal and is meant to be called from
meant to be called from a subclass in a separate module. a subclass in a separate module.
:returns: path to temporary file :returns: path to temporary file
:rtype: path-like object :rtype: path-like object
@ -63,12 +63,12 @@ class PackageManager:
def gen_db_archive(self, compress=None): def gen_db_archive(self, compress=None):
"""Generate a database archive for this package manager. """Generate a database archive for this package manager.
Note that this method is internal and is
meant to be called from a subclass in a separate module.
All arguments and keyword-only arguments are passed directly All arguments and keyword-only arguments are passed directly
to the PackageManager object. to the PackageManager object.
.. note:: This method is internal and is meant to be called from
a subclass in a separate module.
:param compress: compression mode :param compress: compression mode
:type compress: str :type compress: str
:returns: the path to the created file :returns: the path to the created file
@ -95,24 +95,24 @@ class PackageManager:
@property @property
def cache_directory(self): def cache_directory(self):
"""Return the cache directory of this package manager. """
:returns: the cache directory of this package manager.
:rtype: path-like object :rtype: path-like object
""" """
return self._cachedir return self._cachedir
@property @property
def database_path(self): def database_path(self):
"""Return the database path of this package manager. """
:returns: the database path of this package manager.
:rtype: path-like object :rtype: path-like object
""" """
return self._db_path return self._db_path
@property @property
def pkglist_cmd(self): def pkglist_cmd(self):
"""Return the package listing command of this package manager. """
:returns: the package listing command of this package manager.
:rtype: iterable or str :rtype: iterable or str
""" """
return self._pkglist_cmd return self._pkglist_cmd

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
.. module:: rbackup.package_managers.pacman .. module:: rbackup.package_managers.pacman
:synopsis: Implementation class for the Pacman package manager. :synopsis: Implementation class for the Pacman package manager.
""" """

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
.. module:: rbackup.rsync .. module:: rbackup.rsync
:synopsis: helper functions for running the rsync backend :synopsis: helper functions for running the rsync backend
""" """

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
.. module:: rbackup.struct.hierarchy .. module:: rbackup.struct.hierarchy
:synopsis: Classes for creating the backup hierarchy. :synopsis: Classes for creating the backup hierarchy.
""" """
@ -22,23 +22,10 @@ class Hierarchy(PathLike):
"""A class for organizing the backup root hierarchy. """A class for organizing the backup root hierarchy.
Upon creation of a Hierarchy object, it is up to the caller Upon creation of a Hierarchy object, it is up to the caller
to call either shutil.mkdir() or a related method to create to call either :func:`shutil.mkdir` or a related method to create
the directory structure it emulates. the directory structure it emulates.
For consistency, Hierarchy objects always store and return absolute paths. For consistency, ``Hierarchy`` objects always store and return absolute paths.
Attributes
----------
* Hierarchy.path
* Hierarchy.name
* Hierarchy.metadata_path
Methods
-------
* gen_metadata - generate the metadata for this Hierarchy
* read_metadata - read this Hierarchy's metadata from a file
and return it
* write_metadata - write this Hierarchy's metadata to a file
""" """
def __init__(self, dest): def __init__(self, dest):
@ -60,30 +47,31 @@ class Hierarchy(PathLike):
@property @property
def path(self): def path(self):
"""Return the base directory of this hierarchy. """
:returns: the base directory of this hierarchy
:rtype: path-like object :rtype: path-like object
""" """
return self._path return self._path
@property @property
def name(self): def name(self):
"""Return the name of this hierarchy. """
:returns: the name of this hierarchy.
:rtype: str :rtype: str
""" """
return self._name return self._name
@property @property
def metadata_path(self): def metadata_path(self):
"""Return the path of this hierarchy's metadata file. """
:returns: the path of this hierarchy's metadata file.
:rtype: path-like object :rtype: path-like object
""" """
return self._metadata_path return self._metadata_path
def gen_metadata(self): def gen_metadata(self):
"""Generate metadata for this repository. """Generate metadata for this repository.
After this method is called, the data necessary for this hierarchy has been created. After this method is called, the data necessary for this hierarchy has been created.
""" """
raise NotImplementedError("This method must be called in a child class.") raise NotImplementedError("This method must be called in a child class.")
@ -99,11 +87,12 @@ class Hierarchy(PathLike):
return json.load(mfile) return json.load(mfile)
def write_metadata(self, attr): def write_metadata(self, attr):
"""Write this repository's metadata to its file. """Write this repository's metadata to its metadata file.
Note that this write operation is atomic to the caller.
:param attr: data to write to file .. note:: This write operation is atomic to the caller.
:type attr: class member to write
:param attr: class data to write to file
:type attr: any type
""" """
syslog.debug(f"Writing metadata to {self.metadata_path}") syslog.debug(f"Writing metadata to {self.metadata_path}")

View File

@ -1,8 +1,7 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
.. module:: rbackup.struct.repository .. module:: rbackup.struct.repository
:synopsis: Classes for structuring a backup repository.
:synopsis: Module for helpers for structuring a backup repository.
""" """
import datetime import datetime
import logging import logging
@ -31,56 +30,58 @@ class Repository(Hierarchy):
directory that contains backup data sequestered into snapshots directory that contains backup data sequestered into snapshots
and a symlink to the most recently created snapshot. and a symlink to the most recently created snapshot.
Properties
* Each snapshot in a repository is unaware of one another, * Each snapshot in a repository is unaware of one another,
this is the job of the repository to organize this is the job of the repository to organize
* The only way snapshots are linked together is in files * The only way snapshots are linked together is in files
that are hard-linked together that are hard-linked together
Attributes Snapshots can be accessed on a one-by-one basis through iteration.
----------
* Repository.path (inherited from Hierarchy)
* Repository.name (inherited from Hierarchy)
* Repository.metadata_path (inherited from Hierarchy)
* Repository.snapshots - a list of snapshots stored in this repository
* Repository.snapshot_dir - the snapshot storage location of this repository
Methods ::
-------
* cleanup - clean all repository data
* create_snapshot - create a new snapshot
* gen_metadata (inherited from Hierarchy)
* is_valid_snapshot_name - validate a potential name for a snapshot
* read_metadata (inherited from Hierarchy)
* write_metadata (inherited from Hierarchy)
Directory Structure >>> for snapshot in Repository('backup'):
------------------- >>> print(snapshot.path)
* "data" directory for storing snapshots first
* Each snapshot is its own directory with its own sub-hierarchy second
* Each snapshot has an "old" directory for storing deleted data ...
* rsync hardlinks unchanged files between snapshots
* A symlink in the root of the repository symlinking to the
most recent snapshot
Iteration Snapshots on repositories can be retrieved by index using python's
--------- list slicing syntax.
To support checking all snapshots for hardlinking, the Repository class
can be iterated through. ::
>>> print(Repository('backup')[:])
[Snapshot(...), ...]
Membership of a snapshot in a repository can be checked by name.
::
>>> Repository('backup').create_snapshot('test')
>>> 'test' in Repository('backup')
True
Number of snapshots in a repository can be checked as well
::
>>> Repository('backup').create_snapshot()
>>> len(Repository('backup'))
1
""" """
"""Snapshots are serialized as their names relative to the repository """Snapshots are serialized as their names relative to the repository
data directory, but have their full paths during runtime. data directory, but have their full paths during runtime.
Private Attributes Private Attributes
------------------
* _snapshots - list of Snapshot objects created and accessed at runtime * _snapshots - list of Snapshot objects created and accessed at runtime
* _snapshot_metadata - list of Snapshot names serialized and deserialized * _snapshot_metadata - list of Snapshot names serialized and deserialized
when this Repository is first created when this Repository is first created
""" """
def __init__(self, dest): def __init__(self, dest):
"""Default constructor for the Repository class. """Default constructor for the Repository class."""
"""
super().__init__(dest) super().__init__(dest)
if self.metadata_path.exists(): if self.metadata_path.exists():
@ -95,8 +96,9 @@ class Repository(Hierarchy):
self._snapshot_iterator = iter(self._snapshots) self._snapshot_iterator = iter(self._snapshots)
def __contains__(self, name): def __contains__(self, name):
"""Check whether a Snapshot is in this Repository by name. """Check membership of a Snapshot in this Repository by name.
:returns: True if name is the name of a Snapshot in this Repository
:type name: str :type name: str
:rtype: bool :rtype: bool
""" """
@ -126,43 +128,43 @@ class Repository(Hierarchy):
"""Check if the given name is a valid name. """Check if the given name is a valid name.
Invalid Names: Invalid Names:
--------------
* Contain slashes * Contain slashes
* Are empty values * Are empty values
Valid names match the regex Valid names:
r'[\\w]+[^/]*'
* Match the regex r'[\\w]+[^/]*'
:param name: name to validate :param name: name to validate
:type name: str :type name: str
:returns: true if this name is deemed valid :returns: true if this name is deemed valid, otherwise False
:rtype: bool :rtype: bool
""" """
return bool(re.match(VALID_SNAPSHOT_NAME, name)) return bool(re.match(VALID_SNAPSHOT_NAME, name))
@property @property
def snapshot_dir(self): def snapshot_dir(self):
"""Return the directory in this Repository in which snapshots """
:returns: the directory in this Repository in which snapshots
are stored. are stored.
:rtype: path-like object :rtype: path-like object
""" """
return self.path / "data" return self.path / "data"
@property @property
def snapshots(self): def snapshots(self):
"""Return a list of snapshots stored in this Repository. """
:returns: all snapshots stored in this repository
:returns: the names of all snapshots in this repository sorted by
date
:rtype: list of Snapshot objects :rtype: list of Snapshot objects
""" """
return self._snapshots return self._snapshots
@property @property
def empty(self): def empty(self):
"""Determine whether or not this Repository is empty. """
:returns: True if there are no Snapshots in this Repository,
False otherwise
:rtype: bool :rtype: bool
""" """
return not self.snapshots return not self.snapshots
@ -179,9 +181,14 @@ class Repository(Hierarchy):
def create_snapshot(self, name=None): def create_snapshot(self, name=None):
"""Create a new snapshot in this repository. """Create a new snapshot in this repository.
This method is non-intrusive in that it will not This operation is non-intrusive in that it will not
make any changes in the filesystem when called. make any changes in the filesystem when called.
If name is not given, then the new snapshot's name is the current
UTC date in ISO format.
If name is given, then it is the name for the new snapshot.
If name is given and it is the name of a snapshot already If name is given and it is the name of a snapshot already
on the repository, that snapshot is overwritten instead. on the repository, that snapshot is overwritten instead.
@ -221,7 +228,7 @@ class Repository(Hierarchy):
:param remove_snapshots: delete the data directory of this repository :param remove_snapshots: delete the data directory of this repository
:type remove_snapshots: bool :type remove_snapshots: bool
:param remove_repo_dir: remove the top-directory level of this repository :param remove_repo_dir: remove the top-level directory of this repository
:type remove_repo_dir: bool :type remove_repo_dir: bool
""" """
# We don't want to risk symlink attacks # We don't want to risk symlink attacks

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
.. module:: rbackup.struct.snapshot .. module:: rbackup.struct.snapshot
:synopsis: Classes for creating the backup hierarchy. :synopsis: Classes for creating the backup hierarchy.
""" """
@ -14,18 +14,12 @@ syslog = logging.getLogger(__name__)
# ========== Classes ========== # ========== Classes ==========
class Snapshot(Hierarchy): class Snapshot(Hierarchy):
"""Hierarchy for a single snapshot. """Hierarchy for a single snapshot.
Attributes
----------
* Snapshot.path (inherited from Hierarchy)
* Snapshot.name (inherited from Hierarchy)
* Snapshot.metadata_path (inherited from Hierarchy)
* Snapshot.pkg_dir
Methods Data from each run of a backup script is intended to go here.
-------
* gen_metadata (inherited from Hierarchy) Snapshots are unaware of one another, it is up to a third-party caller
* read_metadata (inherited from Hierarchy) to orchestrate operations such as hardlinking between snapshots and
* write_metadata (inherited from Hierarchy) ordering snapshots.
""" """
def __init__(self, path): def __init__(self, path):
@ -40,16 +34,13 @@ class Snapshot(Hierarchy):
@property @property
def pkg_dir(self): def pkg_dir(self):
"""Retrieve the package manager backup directory of this snapshot. """
:returns: the package manager backup directory of this snapshot.
:rtype: path-like object :rtype: path-like object
""" """
return self._pkg_dir return self._pkg_dir
def gen_metadata(self): def gen_metadata(self):
"""Generate metadata for this repository.
After this method is called, the data necessary for this snapshot has been created.
"""
pass pass

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
Tests for the rbackup.config module. Tests for the rbackup.config module.
""" """

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
Tests for the rbackup.struct.hierarchy module. Tests for the rbackup.struct.hierarchy module.
""" """

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
:synopsis: Unit tests for the PackageManager module. :synopsis: Unit tests for the PackageManager module.
""" """
import subprocess import subprocess

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
Tests for the rbackup.struct.repository module. Tests for the rbackup.struct.repository module.
""" """

View File

@ -1,5 +1,5 @@
""" """
.. author:: Eric Torres .. moduleauthor:: Eric Torres
Unit tests for the rbackup.struct.snapshot module. Unit tests for the rbackup.struct.snapshot module.
""" """