def infos(self, exists=True): """ get VenvInfo instances generator. Usage ----- :: for venv_info in venvs.infos(): pass :param exists: the virtualenv must exist to be included in the generator :type exists: bool """ if not self.in_virtualenv and not self.defined: raise NoAvailableVirtualenv() value = self._ver_attr if not is_sequence(value): value = [value] try: for ver in value: venv_info = VenvInfo(ver) if exists: if venv_info.exists(): yield venv_info else: yield venv_info except Exception as ex: error(str(ex))
def _app_output(options): # noinspection PyArgumentEqualDefault with LocalShell(verbose=False) as local: if Project.main is not None: # noinspection PyBroadException executable = "" try: executable = os.path.join(Project.herringfile_dir, Project.package, Project.main) text = local.system( "{exe} {options}".format(exe=executable, options=options), verbose=False ) if text: return text except Exception as ex: error('Error running "{exe}" - {why}'.format(exe=executable, why=str(ex))) console_scripts = _console_scripts() output = [] for script in console_scripts: try: text = local.system( "python -m {exe} {options}".format(exe=script, options=options), verbose=False ) # info("text: {text}".format(text=text)) if text: output.append(text) except Exception as ex: error('Error running "{exe}" - {ex}'.format(exe=script, ex=str(ex))) return "\n".join(output)
def readme(): """Update the README.rst from the application's package docstring""" if Project.generate_readme: # noinspection PyBroadException try: # make sure the project's directory is on the system path so python can find import modules this_dir = os.path.abspath(Project.herringfile_dir) parent_dir = os.path.dirname(this_dir) if this_dir in sys.path: sys.path.remove(this_dir) if parent_dir in sys.path: sys.path.remove(parent_dir) sys.path.insert(0, parent_dir) sys.path.insert(1, this_dir) debug("sys.path: %s" % pformat(sys.path)) debug("package: {pkg}".format(pkg=Project.package)) app_module = importlib.import_module(Project.package) text = app_module.__doc__ debug(text) if text: with open(Project.readme_file, 'w') as readme_file: readme_file.write(text) except Exception as ex: error('Can not write {file} - {why}'.format(file=Project.readme_file, why=str(ex)))
def run_process(self, cmd_args, env=None, out_stream=sys.stdout, verbose=True, timeout=0, timeout_interval=.001): """ Run the process yield for each output line from the process. :param out_stream: :param cmd_args: command line components :type cmd_args: list :param env: environment :type env: dict :param verbose: outputs the method call if True :type verbose: bool :param timeout: :type timeout: int :param timeout_interval: :type timeout_interval: int :yields: each line of output as it is generated :ytype: str """ self.display("run_process(%s, %s)\n\n" % (cmd_args, env), out_stream=out_stream, verbose=verbose) sub_env = os.environ.copy() if env: for key, value in env.items(): sub_env[key] = value with GracefulInterruptHandler() as handler: try: # info("PATH={path}".format(path=pformat(sub_env['PATH'].split(':')))) # info("sys.path={path}".format(path=pformat(sys.path))) process = subprocess.Popen(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=sub_env) fido = Watchdog(timeout) try: while process.poll() is None: # returns None while subprocess is running if handler.interrupted: process.kill() while True: line = self._non_block_read(process.stdout) if not line: break yield line sleep(timeout_interval) except Watchdog: process.kill() fido.stop() line = self._non_block_read(process.stdout) if line: yield line except OSError as ex: error("Error: Unable to run process: {cmd_args} - {err}".format(cmd_args=repr(cmd_args), err=str(ex)))
def _replace_version_txt_file(version_str, project_package=None): file_name = _file_spec('VERSION.txt', project_package) try: with open(file_name, 'w') as version_file: version_file.write(version_str) except IOError as ex2: error(ex2) file_name = _file_spec('VERSION.txt', Project.herringfile_dir) try: with open(file_name, 'w') as version_file: version_file.write(version_str) except IOError as ex2: error(ex2)
def release(): """Releases the project to github and pypi""" if not os.path.exists(os.path.expanduser('~/.pypirc')): error('You must have a configured ~/.pypirc file. ' 'See http://peterdowns.com/posts/first-time-with-pypi.html' 'Hint, do not use comments in your .pypirc') return github() pypi_test() if query_yes_no('Is the new package on pypi-test (http://testpypi.python.org/pypi)?'): pypi_live() upload_docs()
def set_project_version(version_str, project_package=None): """ Set the version in __init__.py :param version_str: the new version string :type version_str: str :param project_package: the root package :type project_package: str """ try: _edit_package_version(version_str=version_str, project_package=project_package) file_name = _file_spec('VERSION.txt', project_package) if os.path.exists(file_name): os.remove(file_name) except (AttributeError, IOError) as ex: error(ex) _replace_version_txt_file(version_str=version_str, project_package=project_package)
def clean_directory(directory): """ remove all files and directories from the target html directory :param directory: the directory to clean :type directory: str """ info("clean_directory Project.docs_html_path = {dir}".format(dir=directory)) if os.path.isdir(directory): for the_file in os.listdir(directory): if the_file.startswith("."): continue file_path = os.path.join(directory, the_file) try: if os.path.isfile(file_path): info("unlink {file}".format(file=file_path)) os.unlink(file_path) elif os.path.isdir(file_path): info("rmtree {file}".format(file=file_path)) shutil.rmtree(file_path) except Exception as e: error(str(e))
def __check_missing_required_attributes(self): missing_keys = self.__missing_required_attributes() for missing_key in missing_keys: error("Missing required '{key}' in Project.metadata call in the herringfile.".format(key=missing_key)) if missing_keys: raise Exception('The herringfiles has missing required keys. Please correct and try again.')
def _create_from_template(self, src_filename, dest_filename, **kwargs): """ Render the destination file from the source template file Scans the templates directory and create any corresponding files relative to the root directory. If the file is a .template, then renders the file, else simply copy it. Template files are just string templates which will be formatted with the following named arguments: name, package, author, author_email, and description. Note, be sure to escape curly brackets ('{', '}') with double curly brackets ('{{', '}}'). :param src_filename: the template file :param dest_filename: the rendered file """ info("creating {dest} from {src}".format(dest=dest_filename, src=src_filename)) with open(src_filename) as in_file: template = in_file.read() new_filename = None try: # we just want the unique temp file name, we will delete it in the finally block tf = tempfile.NamedTemporaryFile(delete=False) new_filename = tf.name tf.close() rendered = template.format(**kwargs) with open(new_filename, 'w') as out_file: try: out_file.write(rendered) # catching all exceptions # pylint: disable=W0703 except Exception as ex: error(ex) # if there is a dest_filename, then handle backing it up if os.path.isfile(dest_filename): # new_filename contains the just rendered template # dest_filename contains the original content # if new_filename contents equal dest_filename contents, then we are done if md5sum(new_filename)[0] == md5sum(dest_filename)[0]: return # new_filename content and dest_filename content differ # so if there is a backup file and if the backup file contents diff from the dest_filename contents, # then we rename the dest_filename to then incremented backup_filename (one past the highest # existing value) backup_filename = next_backup_filename(name=dest_filename) os.rename(dest_filename, backup_filename) # next we remove the dest_filename then move new_filename to dest_filename if os.path.isfile(dest_filename): os.remove(dest_filename) shutil.copyfile(new_filename, dest_filename) except Exception as ex: error("Error rendering template ({file}) - {err}\n{trace}".format(file=src_filename, err=str(ex), trace=traceback.format_exc())) error("kwargs:\n{kwargs}".format(kwargs=pformat(kwargs))) finally: if new_filename is not None: if os.path.isfile(new_filename): os.remove(new_filename)
def generate(): """Generate API documents""" if doc.doc_errors: error(pformat(doc.doc_errors)) info("{cnt} errors.".format(cnt=len(doc.doc_errors)))
# noinspection PyUnresolvedReferences from herring.herring_app import task # noinspection PyUnresolvedReferences from herringlib.venv import VirtualenvInfo # noinspection PyUnresolvedReferences from herringlib.project_settings import Project # noinspection PyUnresolvedReferences from herringlib.local_shell import LocalShell # noinspection PyUnresolvedReferences from herringlib.simple_logger import error, info, warning # noinspection PyUnresolvedReferences from herringlib.remote_shell import RemoteShell except ImportError as ex: from herringlib.simple_logger import error error("Problem importing: {msg}".format(msg=str(ex))) __docformat__ = 'restructuredtext en' # noinspection PyBroadException try: def _dist_wheel_files(): pattern = "{name}-{version}-*.whl".format(name=Project.base_name, version=Project.version) project_wheel_names = [os.path.basename(path) for path in glob(os.path.join(Project.herringfile_dir, 'dist', pattern))] dist_wheel_files = [] for project_wheel_name in project_wheel_names: dist_wheel_files.append(os.path.join(Project.herringfile_dir, 'dist', project_wheel_name)) return dist_wheel_files
def generate_no_api(): """Generate API documents without the API""" global doc_errors if doc_errors: error(pformat(doc_errors)) info("{cnt} errors.".format(cnt=len(doc_errors)))