Source code for regparser.api_writer

import codecs
import logging
import os
import os.path
import shutil

import requests
from git import Repo
from git.exc import InvalidGitRepositoryError

from regparser.notice.encoder import AmendmentEncoder
from regparser.tree.struct import Node, NodeEncoder

logger = logging.getLogger(__name__)


[docs]class AmendmentNodeEncoder(AmendmentEncoder, NodeEncoder): pass
[docs]class FSWriteContent: """This writer places the contents in the file system """ def __init__(self, *path_parts): self.path = os.path.join(*path_parts)
[docs] def write(self, python_obj): """Write the object as json to disk""" logger.debug("Writing %s", self.path) dir_path = os.path.split(self.path)[0] if not os.path.exists(dir_path): os.makedirs(dir_path) with open(self.path, 'w') as out: text = AmendmentNodeEncoder( sort_keys=True, indent=4, separators=(', ', ': ')).encode(python_obj) out.write(text)
[docs]class APIWriteContent: """This writer writes the contents to the specified API""" def __init__(self, *path_parts): self.path = "/".join(path_parts)
[docs] def write(self, python_obj): """Write the object (as json) to the API""" logger.debug("Writing %s", self.path) requests.post( self.path, data=AmendmentNodeEncoder().encode(python_obj), headers={'content-type': 'application/json'})
[docs]class GitWriteContent: """This writer places the content in a git repo on the file system""" def __init__(self, *path_parts): self.path = os.path.join(*path_parts) @staticmethod
[docs] def folder_name(node): """Directories are generally just the last element a node's label, but subparts and interpretations are a little special.""" if node.node_type == Node.SUBPART: return '-'.join(node.label[-2:]) elif len(node.label) > 2 and node.label[-1] == Node.INTERP_MARK: return '-'.join(node.label[-2:]) else: return node.label[-1]
[docs] def write_tree(self, root_path, node): """Given a file system path and a node, write the node's contents and recursively write its children to the provided location.""" if not os.path.exists(root_path): os.makedirs(root_path) node_text = u"---\n" if node.title: node_text += 'title: "' + node.title + '"\n' node_text += 'node_type: ' + node.node_type + '\n' child_folders = [self.folder_name(child) for child in node.children] node_text += 'children: [' node_text += ', '.join('"' + f + '"' for f in child_folders) node_text += ']\n' node_text += '---\n' + node.text with codecs.open(root_path + os.sep + 'index.md', 'w', 'utf-8') as f: f.write(node_text) for idx, child in enumerate(node.children): child_path = root_path + os.sep + child_folders[idx] shutil.rmtree(child_path, ignore_errors=True) self.write_tree(child_path, child)
[docs] def write(self, python_object): logger.debug("Writing %s", self.path) if "regulation" in self.path: dir_path, version_id = os.path.split(self.path) cfr_part = os.path.split(dir_path)[1] if not os.path.exists(dir_path): os.makedirs(dir_path) try: repo = Repo(dir_path) except InvalidGitRepositoryError: repo = Repo.init(dir_path) repo.index.commit("Initial commit for " + cfr_part) # Write all files (and delete any old ones) self.write_tree(dir_path, python_object) # Add and new files to git repo.index.add(repo.untracked_files) # Delete and modify files as needed deleted, modified = [], [] for diff in repo.index.diff(None): if diff.deleted_file: deleted.append(diff.a_blob.path) else: modified.append(diff.a_blob.path) if modified: repo.index.add(modified) if deleted: repo.index.remove(deleted) # Commit with the notice id as the commit message repo.index.commit(version_id)
[docs]class Client: """A Client for writing regulation(s) and meta data.""" def __init__(self, base): if base.startswith('file://'): base = base[len('file://'):] if base.startswith('http://') or base.startswith('https://'): self.writer_class = APIWriteContent self.base = base # keep the protocol, etc. elif base.startswith('git://'): self.writer_class = GitWriteContent self.base = base[len('git://'):] else: self.writer_class = FSWriteContent self.base = base
[docs] def regulation(self, label, doc_number): return self.writer_class(self.base, "regulation", label, doc_number)
[docs] def layer(self, layer_name, doc_type, doc_id): return self.writer_class(self.base, "layer", layer_name, doc_type, doc_id)
[docs] def notice(self, doc_number): return self.writer_class(self.base, "notice", doc_number)
[docs] def diff(self, label, old_version, new_version): return self.writer_class(self.base, "diff", label, old_version, new_version)
[docs] def preamble(self, doc_number): return self.writer_class(self.base, "preamble", doc_number)