PKh|Fnnsphinxcontrib/__init__.py# -*- coding: utf-8 -*- """ sphinxcontrib ~~~~~~~~~~~~~ This package is a namespace package that contains all extensions distributed in the ``sphinx-contrib`` distribution. :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ __import__('pkg_resources').declare_namespace(__name__) PK9Hjr99"sphinxcontrib/packages/__init__.py# Copyright Louis Paternault 2015 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . 1 """This is a sphinx extension providing some directives to show system information. Its main purpose is to display a list of tools available on readthedocs: http://packages.readthedocs.org """ import collections import glob import operator import os import pkg_resources import platform import re import subprocess from docutils import nodes from docutils.statemachine import StringList from docutils.parsers.rst.directives import flag, unchanged from sphinx.util.compat import Directive from sphinx.util.nodes import nested_parse_with_titles from docutils.parsers.rst import directives __version__ = "0.1.1" def node_or_str(text): """Return argument, converted to a node if necessary.""" if isinstance(text, str): return nodes.paragraph(text=text) else: return text def simple_compound(*items): """Return a compound node.""" compound = nodes.compound() for item in items: compound.append(item) return compound def simple_link(text, target): """Returns a link node to `target`, displaying `text`.""" container = nodes.paragraph() reference = nodes.reference("", "", internal=False, refuri=target) reference.append(nodes.paragraph(text=text)) container.append(reference) return container def simple_table(ncolumns, headers, body): """Return a table node. :param int ncolumns: Number of columns. :param list headers: Headers, as a list of nodes (or strings), or ``None``, if there is no headers. :param list body: Body, as a list of lists of nodes (or strings). """ def _build_table_row(data): """Return the node corresponding to a row of the table.""" row = nodes.row() for cell in data: entry = nodes.entry() row += entry entry.append(node_or_str(cell)) return row table = nodes.table() tgroup = nodes.tgroup(cols=2) table += tgroup for colwidth in [10]*ncolumns: colspec = nodes.colspec(colwidth=colwidth) tgroup += colspec # HEAD thead = nodes.thead() tgroup += thead if headers is not None: for row in [headers]: thead += _build_table_row(row) # BODY tbody = nodes.tbody() tgroup += tbody for row in body: tbody += _build_table_row(row) return table def simple_bulletlist(items): """Return a bullet list nodes of arguments.""" return nodes.bullet_list("", *[nodes.list_item('', node_or_str(item)) for item in items]) def iter_paths(): """Iterate over existing paths.""" for string in os.getenv("PATH").split(":"): path = os.path.expanduser(os.path.expandvars(string)) if os.path.exists(path) and os.path.isdir(path): yield path def python_versions(): """Iterate over [binary, version] lists of available python executables.""" binaries = set() for path in iter_paths(): for binary in glob.glob(os.path.join(path, "python*")): binaries.add(binary) pythonre = re.compile(r".*/python[.0123456789]*$") for binary in binaries: if pythonre.match(binary): try: yield [ nodes.literal(text=binary), subprocess.check_output( [binary, "--version"], stdin=subprocess.DEVNULL, stderr=subprocess.STDOUT, universal_newlines=True, ).strip(), ] except subprocess.CalledProcessError: continue class PlatformDirective(Directive): """Print platform information (processors, architecture, etc.)""" has_content = False @staticmethod def body(): """Iterator to the platform information.""" for attr in [ "machine", "platform", "system", "release", "version", "processor", ]: yield [attr.replace("_", " ").capitalize(), str(getattr(platform, attr)())] for attr in [ "architecture", "linux_distribution", ]: yield [ attr.replace("_", " ").capitalize(), " ".join([str(item) for item in getattr(platform, attr)()]), ] def run(self): return [simple_table( 2, [], self.body(), )] class PythonVersionsDirective(Directive): """Print list of available python versions""" has_content = False @staticmethod def body(): """Iterator to the versions.""" return sorted( python_versions(), key=operator.itemgetter(1), ) def run(self): return [simple_table( 2, ["Binary", "Version"], self.body(), )] class BinDirective(Directive): """Display the list of available binaries.""" @staticmethod def dirs(): """Iterator over couples `(path, binaries)`. - `path` is a path of the ``PATH`` variable; - `binaries` is the list of binaries available in this path. """ for path in iter_paths(): binaries = [] for binary in sorted(os.listdir(path)): if ( os.path.isfile(os.path.join(path, binary)) and os.access(os.path.join(path, binary), os.X_OK) ): binaries.append(binary) yield (path, binaries) def run(self): items = [] for path, binaries in self.dirs(): item = simple_compound(nodes.literal(text=path)) cells = [] for binary in binaries: cells.append([nodes.paragraph(text=binary)]) if cells: item.append(simple_table( 1, [], cells, )) else: item.append(nodes.emphasis(text="empty")) items.append(item) return [simple_bulletlist(items)] def deepdict_factory(depth): """Return a dict of dicts of dicts of ... of dicts of lists. The dicts are :class:`collections.defaultdict`. >>> d = deepdict_factory(2)() >>> type(d) >>> type(d[0]) >>> type(d[0]["foo"]) """ if depth == 0: return list else: def deepdict(): """Return a deepdict, less deep than the current one.""" return collections.defaultdict(deepdict_factory(depth - 1)) return deepdict class CmdDirective(Directive): """Abstract directive that executes a command, and return its output as array(s). """ command = [] regexp = "(?P.*)" headers = {} sections = [] sortkey = None show_headers = True def section_names(self, name): # pylint: disable=no-self-use """Return the displayed name corresponding to section ``name``. """ return name def filter(self, match): # pylint: disable=no-self-use """Perform some post-processing on matched lines, and iterate over result. Iterate over resulting objects. In particular, it can iterate zero objects (to discard argument), or iterate over several objects (if argument corresponds to several objects). This function is to be overloaded, if necessary, by subclasses. """ yield match def _iter_match(self, output): """Iterator over matched lines of the output.""" compiled_re = re.compile(self.regexp) for line in output: match = compiled_re.match(line.decode("utf8").strip()) if match: yield from self.filter(match.groupdict()) def _render_deepdict(self, deepdict): """Render a :class:`deepdict`. - If it is a deepdict, render it a bullet list of :class:`deepdict`; - if it is a list, render it as a table. """ if isinstance(deepdict, list): items = dict() for item in deepdict: items[item[self.sortkey]] = [item[key] for key in self.headers] if self.show_headers: headers = self.headers.values() else: headers = None return simple_table( len(self.headers), headers, [items[key] for key in sorted(items.keys())], ) else: return simple_bulletlist([ simple_compound( nodes.paragraph(text=self.section_names(key)), self._render_deepdict(deepdict[key]) ) for key in sorted(deepdict) ]) def run(self): try: process = subprocess.Popen( self.command, stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE, ) deepdict = deepdict_factory(len(self.sections))() for match in self._iter_match(process.stdout): subdict = deepdict for section in self.sections: subdict = subdict[match[section]] subdict.append(match) process.wait() except FileNotFoundError as exception: error = nodes.error() error.append(nodes.paragraph(text=str(exception))) return [error] return [self._render_deepdict(deepdict)] class DebDirective(CmdDirective): """Display the list of installed debian packages""" regexp = 'ii *\t' + r'\t'.join([ r'(?P<{}>[^\t]*)'.format(key) for key in ['section', 'package', 'version', 'homepage', 'summary'] ]) command = [ "dpkg-query", "--show", "--showformat=${db:Status-Abbrev}\t${Section}\t${binary:Package}\t${Version}\t${Homepage}\t${binary:Summary}\n", # pylint: disable=line-too-long ] headers = collections.OrderedDict([ ("package_node", "Package name"), ("version", "Version"), ("summary", "Summary"), ]) sortkey = "package" sections = ["section"] def filter(self, match): if match['homepage']: match['package_node'] = simple_link(text=match['package'], target=match['homepage']) else: match['package_node'] = match['package'] yield match class PyDirective(CmdDirective): """Abstract class to display available python modules.""" regexp = r'\t'.join([r'(?P<{}>[^\t]*)'.format(key) for key in ['package', 'version', 'path']]) headers = collections.OrderedDict([ ("package", "Package name"), ("version", "Version"), ]) sortkey = "package" python = "python" option_spec = {'bin':directives.unchanged} def filter(self, match): if os.path.splitext(match['path'])[0] != os.path.splitext(self.command[1])[0]: yield match @property def command(self): """Return the command to perform to list modules.""" if "bin" not in self.options: self.options["bin"] = self.python return [ self.options["bin"], pkg_resources.resource_filename( __name__, os.path.join("data", "bin", "list_modules.py"), ), ] class Py3Directive(PyDirective): """Display available python3 modules.""" python = "python3" class Py2Directive(PyDirective): """Display available python2 modules.""" python = "python2" class CDirective(CmdDirective): """Display available C libraries.""" regexp = r'^ *(?P[^ ]*) ' headers = collections.OrderedDict([ ("library", "Library"), ]) command = ["/sbin/ldconfig", "-p"] sortkey = "library" show_headers = False class LatexDirective(CmdDirective): """Display available LaTeX packages.""" command = ["kpsepath", "tex"] sortkey = "package" headers = {'package': 'Package'} sections = ["type"] section_names = { "class": "Classes", "package": "Packages", }.get show_headers = False @staticmethod def _sty_or_cls(file): """Check if argument is a package or a class. Returns ``"package"`` or ``"class"`` if one of them, ``False`` otherwise. """ if file.endswith(".sty"): return "package" elif file.endswith(".cls"): return "class" else: return False def _find(self, path): """Iterator over .sty and .clsfiles in argument. Argument is a string representing a (maybe non-existing) path. """ for __root, __dirs, files in os.walk(path): for file in files: if self._sty_or_cls(file): yield file def filter(self, match): for item in match['line'].split(':'): if item.startswith("!!"): item = item[2:] yield from [ dict([('package', file), ('type', self._sty_or_cls(file))]) for file in self._find(item) ] def setup(app): """Register directives.""" app.add_directive('packages:platform', PlatformDirective) app.add_directive('packages:pyversions', PythonVersionsDirective) app.add_directive('packages:bin', BinDirective) app.add_directive('packages:deb', DebDirective) app.add_directive('packages:python', PyDirective) app.add_directive('packages:python2', Py2Directive) app.add_directive('packages:python3', Py3Directive) app.add_directive('packages:c', CDirective) app.add_directive('packages:latex', LatexDirective) PKIFwq /sphinxcontrib/packages/data/bin/list_modules.py#!/usr/bin/env python # Copyright Louis Paternault 2015 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . 1 """List all python modules available to python.""" import logging import os import pkgutil import sys import types LOGGER = logging.getLogger() LOGGER.addHandler(logging.StreamHandler()) __version__ = "0.1.1" VERSION_NAMES = [ "version", "Version", "VERSION", "__version__", "__Version__", "__VERSION__", ] def get_version(module): """Guess the version of argument, and returns it, as a string.""" candidates = [getattr(module, attr) for attr in VERSION_NAMES if hasattr(module, attr)] while candidates: first = candidates.pop() if callable(first): return str(first()) elif isinstance(first, types.ModuleType): candidates.extend([ getattr(first, attr) for attr in VERSION_NAMES if hasattr(first, attr) ]) else: return str(first) return "" def module_list(): """Yield the list of modules (with version and path).""" while True: try: sys.path.remove(os.getcwd()) except ValueError: break for __importer, name, __ignored in pkgutil.iter_modules(): if name.startswith("_"): continue try: module = __import__(name) yield name, get_version(module), module.__file__ except BaseException as error: # pylint: disable=broad-except LOGGER.warning("Error while importing {}: {}.".format(name, error)) if __name__ == "__main__": for package, version, path in module_list(): print("{}\t{}\t{}".format(package, version, path)) PK9HVⓍ6sphinxcontrib_packages-0.1.1.dist-info/DESCRIPTION.rstDescription of the `sphinxcontrib-packages` Sphinx Extension ============================================================ |sources| |pypi| |documentation| |license| This `sphinx `__ extension provides some directives to see what tools are available on the compiling machine. I wrote this because I was developping a sphinx extension calling system commands, and I wanted to be able to use is on `readthedocs `__, but I did not know which tools were available there: the `official list of installed tools `__ is pretty scarce… What's new? ----------- See `changelog `_. Install ------- This module is compatible with both python 2 and 3. See the end of list for a (quick and dirty) Debian package. * From sources: * Download: https://pypi.python.org/pypi/sphinxcontrib-packages * Install (in a `virtualenv`, if you do not want to mess with your distribution installation system):: python setup.py install * From pip:: pip install sphinxcontrib-packages * Quick and dirty Debian (and Ubuntu?) package This requires `stdeb `_ to be installed:: python setup.py --command-packages=stdeb.command bdist_deb sudo dpkg -i deb_dist/python3-sphinxcontrib-packages-_all.deb Documentation ------------- The documentation is available on `readthedocs `_. You can build it using:: cd doc && make html .. |documentation| image:: http://readthedocs.org/projects/packages/badge :target: http://packages.readthedocs.org .. |pypi| image:: https://img.shields.io/pypi/v/sphinxcontrib-packages.svg :target: http://pypi.python.org/pypi/sphinxcontrib-packages .. |license| image:: https://img.shields.io/pypi/l/sphinxcontrib-packages.svg :target: http://www.gnu.org/licenses/agpl-3.0.html .. |sources| image:: https://img.shields.io/badge/sources-sphinxcontrib--packages-brightgreen.svg :target: http://git.framasoft.org/spalax/sphinxcontrib-packages PK9H +4sphinxcontrib_packages-0.1.1.dist-info/metadata.json{"classifiers": ["Development Status :: 4 - Beta", "Framework :: Sphinx :: Extension", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", "Operating System :: Unix", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Documentation :: Sphinx", "Topic :: Software Development :: Libraries :: Python Modules"], "extensions": {"python.details": {"contacts": [{"email": "spalax@gresille.org", "name": "Louis Paternault", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://git.framasoft.org/spalax/packages"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "license": "GPLv3 or any later version", "metadata_version": "2.0", "name": "sphinxcontrib-packages", "run_requires": [{"requires": ["sphinx"]}], "summary": "This packages contains the Packages sphinx extension, which provides directives to display packages installed on the host machine", "version": "0.1.1"}PK׳9HjP4sphinxcontrib_packages-0.1.1.dist-info/top_level.txtsphinxcontrib PK9H}\\,sphinxcontrib_packages-0.1.1.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py3-none-any PK9H /sphinxcontrib_packages-0.1.1.dist-info/METADATAMetadata-Version: 2.0 Name: sphinxcontrib-packages Version: 0.1.1 Summary: This packages contains the Packages sphinx extension, which provides directives to display packages installed on the host machine Home-page: http://git.framasoft.org/spalax/packages Author: Louis Paternault Author-email: spalax@gresille.org License: GPLv3 or any later version Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Framework :: Sphinx :: Extension Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+) Classifier: Operating System :: Unix Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Documentation :: Sphinx Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Dist: sphinx Description of the `sphinxcontrib-packages` Sphinx Extension ============================================================ |sources| |pypi| |documentation| |license| This `sphinx `__ extension provides some directives to see what tools are available on the compiling machine. I wrote this because I was developping a sphinx extension calling system commands, and I wanted to be able to use is on `readthedocs `__, but I did not know which tools were available there: the `official list of installed tools `__ is pretty scarce… What's new? ----------- See `changelog `_. Install ------- This module is compatible with both python 2 and 3. See the end of list for a (quick and dirty) Debian package. * From sources: * Download: https://pypi.python.org/pypi/sphinxcontrib-packages * Install (in a `virtualenv`, if you do not want to mess with your distribution installation system):: python setup.py install * From pip:: pip install sphinxcontrib-packages * Quick and dirty Debian (and Ubuntu?) package This requires `stdeb `_ to be installed:: python setup.py --command-packages=stdeb.command bdist_deb sudo dpkg -i deb_dist/python3-sphinxcontrib-packages-_all.deb Documentation ------------- The documentation is available on `readthedocs `_. You can build it using:: cd doc && make html .. |documentation| image:: http://readthedocs.org/projects/packages/badge :target: http://packages.readthedocs.org .. |pypi| image:: https://img.shields.io/pypi/v/sphinxcontrib-packages.svg :target: http://pypi.python.org/pypi/sphinxcontrib-packages .. |license| image:: https://img.shields.io/pypi/l/sphinxcontrib-packages.svg :target: http://www.gnu.org/licenses/agpl-3.0.html .. |sources| image:: https://img.shields.io/badge/sources-sphinxcontrib--packages-brightgreen.svg :target: http://git.framasoft.org/spalax/sphinxcontrib-packages PK9H