Source code for bootstrap_py.package

# -*- coding: utf-8 -*-
"""bootstrap_py.package."""
import os
import shutil
import tempfile
from datetime import datetime
from jinja2 import PackageLoader, Environment
from pguard import guard
from pguard import guard_cl as g
from bootstrap_py.classifiers import Classifiers
from bootstrap_py.vcs import VCS
from bootstrap_py.docs import build_sphinx


# pylint: disable=too-few-public-methods
[docs]class PackageData: """Package meta data class.""" #: Configured the default "version" of setup.setup(). default_version = '0.1.0' #: Users should rewrite parameters after they generate Python package. warning_message = '##### ToDo: Rewrite me #####' # pylint: disable=fixme def __init__(self, args): """Initialize Package.""" self.metadata = Classifiers() if hasattr(args, '__dict__'): for name, value in vars(args).items(): self._set_param(name, value) self._check_or_set_default_params() def _set_param(self, name, value): """Set name:value property to Package object.""" if name == 'status': setattr(self, name, self.metadata.status().get(value)) elif name == 'license': setattr(self, name, self.metadata.licenses().get(value)) elif name == 'name': setattr(self, name, value) setattr(self, 'module_name', value.replace('-', '_')) else: setattr(self, name, value) def _check_or_set_default_params(self): """Check key and set default vaule when it does not exists.""" if not hasattr(self, 'date'): self._set_param('date', datetime.utcnow().strftime('%Y-%m-%d')) if not hasattr(self, 'version'): self._set_param('version', self.default_version) # pylint: disable=no-member if not hasattr(self, 'description') or self.description is None: getattr(self, '_set_param')('description', self.warning_message)
[docs] def to_dict(self): """Convert the package data to dict.""" return self.__dict__
[docs]class PackageTree: """Package directory tree class.""" #: Jinja2 template name template_name = 'bootstrap_py' #: the suffix name of working directory for generating suffix = '-bootstrap-py' #: init filename init = '__init__.py' #: default permission exec_perm = 0o755 #: include directories to packages pkg_dirs = ['{module_name}', '{module_name}/tests'] def __init__(self, pkg_data): """Initialize.""" self.cwd = os.getcwd() self.name = pkg_data.name self.outdir = os.path.abspath(pkg_data.outdir) self.tmpdir = tempfile.mkdtemp(suffix=self.suffix) self.templates = Environment(loader=PackageLoader(self.template_name)) self.pkg_data = pkg_data def _init_py(self, dir_path): return os.path.join(self.tmpdir, dir_path.format(**self.pkg_data.to_dict()), self.init) def _sample_py(self, file_path): return os.path.join(self.tmpdir, self.pkg_data.module_name, os.path.splitext(file_path)[0]) def _tmpl_path(self, file_path): return os.path.join(self.tmpdir, os.path.splitext(file_path)[0]) def _generate_dirs(self): dirs = [os.path.dirname(tmpl) for tmpl in self.templates.list_templates() if tmpl.find('/') > -1] + self.pkg_dirs for dir_path in dirs: if not os.path.isdir( os.path.join(self.tmpdir, dir_path.format(**self.pkg_data.to_dict()))): os.makedirs(os.path.join(self.tmpdir, dir_path.format( **self.pkg_data.to_dict())), self.exec_perm) def _generate_docs(self): docs_path = os.path.join(self.tmpdir, 'docs') os.makedirs(docs_path) build_sphinx(self.pkg_data, docs_path) def _list_module_dirs(self): return [dir_path for dir_path in self.pkg_dirs if dir_path.find('{module_name}') == 0] def _generate_init(self): tmpl = self.templates.get_template('__init__.py.j2') for dir_path in self._list_module_dirs(): if not os.path.isfile(self._init_py(dir_path)): with open(self._init_py(dir_path), 'w') as fobj: # pylint: disable=no-member fobj.write( tmpl.render(**self.pkg_data.to_dict()) + '\n') return True def _generate_file(self, file_path): tmpl = self.templates.get_template(file_path) with open(self._tmpl_path(file_path), 'w') as fobj: fobj.write( tmpl.render(**self.pkg_data.to_dict()) + '\n') return True def _generate_exec_file(self, file_path): self._generate_file(file_path) os.chmod(self._tmpl_path(file_path), self.exec_perm) return True def _generate_samples(self, file_path): if not self.pkg_data.with_samples: return False tmpl = self.templates.get_template(file_path) if file_path == 'sample.py.j2': with open(self._sample_py(file_path), 'w') as fobj: fobj.write( tmpl.render( **self.pkg_data.to_dict()) + '\n') elif file_path == 'test_sample.py.j2': with open(self._sample_py(os.path.join('tests', file_path)), 'w') as fobj: fobj.write( tmpl.render( **self.pkg_data.to_dict()) + '\n') return True def _generate_files(self): generator = (lambda f: guard( g(self._generate_init, f == '__init__.py.j2'), g(self._generate_exec_file, f == 'utils/pre-commit.j2', (f,)), g(self._generate_samples, f.endswith('sample.py.j2'), (f,)), g(self._generate_file, params=(f,)))) for file_path in self.templates.list_templates(): generator(file_path) os.chdir(self.tmpdir) os.symlink('../../README.rst', 'docs/source/README.rst') os.chdir(self.cwd)
[docs] def move(self): """Move directory from working directory to output directory.""" if not os.path.isdir(self.outdir): os.makedirs(self.outdir) shutil.move(self.tmpdir, os.path.join(self.outdir, self.name))
[docs] def clean(self): """Clean up working directory.""" shutil.rmtree(self.tmpdir)
[docs] def generate(self): """Generate package directory tree.""" self._generate_docs() self._generate_dirs() self._generate_files()
[docs] def vcs_init(self): """Initialize VCS repository.""" VCS(os.path.join(self.outdir, self.name), self.pkg_data)