proglog-0.1.9/0000755000000000000000000000000013303315512013124 5ustar rootroot00000000000000proglog-0.1.9/README.rst0000775000000000000000000001475113274551361014643 0ustar rootroot00000000000000.. raw:: html

Proglog Logo

Proglog is a progress logging system for Python. It allows to build complex libraries while giving the user control on the management of logs, callbacks and progress bars. **What problems does it solve ?** Libraries like `tqdm `_ or `progress `_ are great for quickly adding progress bars to your scripts, but become difficult to manage when building larger projects. For instance, you will need to write different code depending on whether you are displaying the progress in a console, a Jupyter notebook, or a website. Sometimes you need to channel the progress logs of different components into a same logger, at which case you may also let the final user choose which progress bars they want to display or to mute, even when these are handled deep down in your programs. .. raw:: html

You may also want to log more than just progress bars, have specific callback fonctions, print the logs in human-readable format... Proglog provides all these features. Usage ------- Assume that you are writing a library called ``my_library`` in which you define a routine as follows: .. code:: python import time # for simulating computing time from proglog import TqdmProgressBarLogger def my_routine(iterations=10, logger='bars'): """Run several loops to showcase Proglog.""" if logger == 'bars': logger = TqdmProgressBarLogger() for i in logger.iter_bar(iteration=range(iterations)): for j in logger.iter_bar(animal=['dog', 'cat', 'rat', 'duck']): time.sleep(0.1) # Simulate some computing time Now when the library users run a program in the console, they will get a console progress bar: .. code:: python from my_library import my_routine my_routine() .. raw:: html

If the users run the routine inside a Jupyter/IPython notebook, they only need to write ``proglog.notebook()`` at the beginning of the notebook to obtain HTML progress bars: .. code:: python import proglog proglog.notebook() from my_library import my_routine my_routine() .. raw:: html

If the user wishes to turn off all progress bars: .. code:: python from my_library import my_routine from proglog import MuteProgressBarLogger my_routine(logger=MuteProgressBarLogger()) If the user is running the routine on a web server and would want to attach the data to an asynchronous Python-RQ job, all they need is yet a different logger: .. code:: python from proglog import RqWorkerBarLogger from my_library import my_routine logger = RqWorkerBarLogger(job=some_python_rq_job) my_routine(logger=logger) This allows to then display progress bars on the website such as these (see the `EGF CUBA `_ project for an example of website using Proglog): .. raw:: html

The user may also want a custom progress logger which selectively ignores the ``animals`` progress bar, and only updates its bars every second (to save computing time): .. code:: python from proglog import TqdmProgressBarLogger from my_library import my_routine logger = TqdmProgressBarLogger(ignored_bars=('animal',), min_time_interval=1.0) my_routine(logger=logger) Proglog loggers can be used for much more than just progress bars. They can in fact store any kind of data with a simple API: .. code:: python logger(message='Now running the main program, be patient...') logger(current_animal='cat') logger(last_number_tried=1235) For more complex customization, such as adding callback functions which will be executed every time the logger's state is updated, simply create a new logger class: .. code:: python from proglog import ProgressBarLogger from my_library import my_routine class MyBarLogger(ProgressBarLogger): def callback(self, **changes): # Every time the logger is updated, this function is called with # the `changes` dictionnary of the form `parameter: new value`. for (parameter, new_value) in changes.items(): print ('Parameter %s is now %s' % (parameter, value)) logger = MyBarLogger() my_routine(logger=logger) When writing libraries which all log progress and may depend on each other, simply pass the Proglog logger from one program to its dependencies, to obtain one logger keeping track of all progress across libraries at once: (this implies that not two librairies use the same variables or loop names, which can be avoided by attributing prefixes to these names): .. raw:: html

Installation ------------- You can install Proglog through PIP .. code:: shell sudo pip install proglog Alternatively, you can unzip the sources in a folder and type .. code:: shell sudo python setup.py install To use the ``tqdm`` notebook-style progress bars you need to install and enable iwidgets: .. code:: shell sudo pip install ipywidgets sudo jupyter nbextension enable --py --sys-prefix widgetsnbextension Contribute ! ------------- Proglog is an open-source software originally written at the `Edinburgh Genome Foundry `_ by `Zulko `_ and `released on Github `_ under the MIT licence (copyright Edinburgh Genome Foundry). Proglog was not written by loggology experts, it *just works* with our projects and we use it a lot. Everyone is welcome to contribute if you find bugs or limitations ! proglog-0.1.9/proglog/0000755000000000000000000000000013303315512014575 5ustar rootroot00000000000000proglog-0.1.9/proglog/proglog.py0000664000000000000000000003170213303223107016623 0ustar rootroot00000000000000"""Implements the generic progress logger class, and the ProgressBar class. """ from tqdm import tqdm, tqdm_notebook from collections import OrderedDict import time SETTINGS = { 'notebook': False } def notebook(turn='on'): SETTINGS['notebook'] = True if (turn == 'on') else False def troncate_string(s, max_length=25): return s if (len(s) < max_length) else (s[:max_length] + "...") class ProgressLogger: """Generic class for progress loggers. A progress logger contains a "state" dictionnary. Parameters ---------- init_state Dictionnary representing the initial state. """ def __init__(self, init_state=None): self.state = {} self.stored = {} self.logs = [] self.log_indent = 0 if init_state is not None: self.state.update(init_state) def log(self, message): self.logs.append((' ' * self.log_indent) + message) def dump_logs(self, filepath=None): if filepath is not None: with open(filepath, 'a') as f: f.write("\n".join(self.logs)) else: return "\n".join(self.logs) def callback(self, **kw): """Execute something after the state has been updated by the given state elements. This default callback does nothing, overwrite it by subclassing """ pass def store(self, **kw): """Store objects in the logger and trigger ``self.store_callback``. This works exactly like ``logger()``, but the later is meant for simple data objects (text, numbers) that will be sent over the network or written to a file. The ``store`` method expects rather large objects which are not necessarily serializable, and will be used eg to draw plots on the fly. """ self.stored.update(kw) self.store_callback(**kw) def store_callback(self, **kw): """Execute something after the store has been updated by the given state elements. This default callback does nothing, overwrite it by subclassing """ pass def iter(self, **kw): """Iterate through a list while updating the state. Examples -------- >>> for username in logger.iter(user=['tom', 'tim', 'lea']: >>> # At every loop, logger.state['user'] is updated >>> print (username) """ for field, iterable in kw.items(): for it in iterable: self(**{field: it}) yield it def __call__(self, **kw): self.state.update(kw) self.callback(**kw) class ProgressBarLogger(ProgressLogger): """Generic class for progress loggers. A progress logger contains a "state" dictionnary Parameters ---------- init_state Initial state of the logger bars Either None (will be initialized with no bar) or a list/tuple of bar names (``['main', 'sub']``) which will be initialized with index -1 and no total, or a dictionary (possibly ordered) of bars, of the form ``{bar_1: {title: 'bar1', index: 2, total:23}, bar_2: {...}}`` ignored_bars Either None (newly met bars will be added) or a list of blacklisted bar names, or ``'all_others'`` to signify that all bar names not already in ``self.bars`` will be ignored. """ bar_indent = 2 def __init__(self, init_state=None, bars=None, ignored_bars=None, logged_bars='all', min_time_interval=0, ignore_bars_under=0): ProgressLogger.__init__(self, init_state) if bars is None: bars = OrderedDict() elif isinstance(bars, (list, tuple)): bars = OrderedDict([ (b, dict(title=b, index=-1, total=None, message=None, indent=0)) for b in bars ]) if isinstance(ignored_bars, (list, tuple)): ignored_bars = set(ignored_bars) self.ignored_bars = ignored_bars self.logged_bars = logged_bars self.state['bars'] = bars self.min_time_interval = min_time_interval self.ignore_bars_under = ignore_bars_under @property def bars(self): """Return ``self.state['bars'].``""" return self.state['bars'] def bar_is_ignored(self, bar): if self.ignored_bars is None: return False elif self.ignored_bars == 'all_others': return (bar not in self.bars) else: return bar in self.ignored_bars def bar_is_logged(self, bar): if (not self.logged_bars): return False elif self.logged_bars == 'all': return True else: return bar in self.logged_bars def iterable_is_too_short(self, iterable): length = len(iterable) if hasattr(iterable, '__len__') else None return (length is not None) and (length < self.ignore_bars_under) def iter_bar(self, bar_prefix='', **kw): """Iterate through a list while updating a state bar. Examples -------- >>> for username in logger.iter_bar(user=['tom', 'tim', 'lea']): >>> # At every loop, logger.state['bars']['user'] is updated >>> # to {index: i, total: 3, title:'user'} >>> print (username) """ if 'bar_message' in kw: bar_message = kw.pop('bar_message') else: bar_message = None bar, iterable = kw.popitem() if self.bar_is_ignored(bar) or self.iterable_is_too_short(iterable): return iterable bar = bar_prefix + bar if hasattr(iterable, '__len__'): self(**{bar + '__total': len(iterable)}) def new_iterable(): last_time = time.time() i = 0 # necessary in case the iterator is empty for i, it in enumerate(iterable): now_time = time.time() if (i == 0) or (now_time - last_time > self.min_time_interval): if bar_message is not None: self(**{bar + '__message': bar_message(it)}) self(**{bar + '__index': i}) last_time = now_time yield it if self.bars[bar]['index'] != i: self(**{bar + '__index': i}) self(**{bar + '__index': i + 1}) return new_iterable() def bars_callback(self, bar, attr, value, old_value=None): """Execute a custom action after the progress bars are updated. Parameters ---------- bar Name/ID of the bar to be modified. attr Attribute of the bar attribute to be modified value New value of the attribute old_value Previous value of this bar's attribute. This default callback does nothing, overwrite it by subclassing. """ pass def __call__(self, **kw): items = sorted(kw.items(), key=lambda kv: not kv[0].endswith('total')) for key, value in items: if '__' in key: bar, attr = key.split('__') if self.bar_is_ignored(bar): continue kw.pop(key) if bar not in self.bars: self.bars[bar] = dict(title=bar, index=-1, total=None, message=None) old_value = self.bars[bar][attr] if self.bar_is_logged(bar): new_bar = (attr == 'index') and (value < old_value) if (attr == 'total') or (new_bar): self.bars[bar]['indent'] = self.log_indent else: self.log_indent = self.bars[bar]['indent'] self.log("[%s] %s: %s" % (bar, attr, value)) self.log_indent += self.bar_indent self.bars[bar][attr] = value self.bars_callback(bar, attr, value, old_value) self.state.update(kw) self.callback(**kw) class TqdmProgressBarLogger(ProgressBarLogger): """Tqdm-powered progress bar for console or Notebooks. Parameters ---------- init_state Initial state of the logger bars Either None (will be initialized with no bar) or a list/tuple of bar names (``['main', 'sub']``) which will be initialized with index -1 and no total, or a dictionary (possibly ordered) of bars, of the form ``{bar_1: {title: 'bar1', index: 2, total:23}, bar_2: {...}}`` ignored_bars Either None (newly met bars will be added) or a list of blacklisted bar names, or ``'all_others'`` to signify that all bar names not already in ``self.bars`` will be ignored. leave_bars notebook True will make the bars look nice (HTML) in the jupyter notebook. It is advised to leave to 'default' as the default can be globally set from inside a notebook with ``import proglog; proglog.notebook_mode()``. print_messages If True, every ``logger(message='something')`` will print a message in the console / notebook """ def __init__(self, init_state=None, bars=None, leave_bars=False, ignored_bars=None, logged_bars='all', notebook='default', print_messages=True, min_time_interval=0, ignore_bars_under=0): ProgressBarLogger.__init__(self, init_state=init_state, bars=bars, ignored_bars=ignored_bars, logged_bars=logged_bars, ignore_bars_under=ignore_bars_under, min_time_interval=min_time_interval) self.leave_bars = leave_bars self.tqdm_bars = OrderedDict([ (bar, None) for bar in self.bars ]) if notebook == 'default': notebook = SETTINGS['notebook'] self.notebook = notebook self.print_messages = print_messages self.tqdm = (tqdm_notebook if self.notebook else tqdm) def new_tqdm_bar(self, bar): """Create a new tqdm bar, possibly replacing an existing one.""" if (bar in self.tqdm_bars) and (self.tqdm_bars[bar] is not None): self.close_tqdm_bar(bar) infos = self.bars[bar] self.tqdm_bars[bar] = self.tqdm( total=infos['total'], desc=infos['title'], postfix=dict(now=troncate_string(str(infos['message']))), leave=self.leave_bars ) def close_tqdm_bar(self, bar): """Close and erase the tqdm bar""" self.tqdm_bars[bar].close() if not self.notebook: self.tqdm_bars[bar] = None def bars_callback(self, bar, attr, value, old_value): if (bar not in self.tqdm_bars) or (self.tqdm_bars[bar] is None): self.new_tqdm_bar(bar) if attr == 'index': if value >= old_value: total = self.bars[bar]['total'] if total and (value >= total): self.close_tqdm_bar(bar) else: self.tqdm_bars[bar].update(value - old_value) else: self.new_tqdm_bar(bar) self.tqdm_bars[bar].update(value + 1) elif attr == 'message': self.tqdm_bars[bar].set_postfix(now=troncate_string(str(value))) self.tqdm_bars[bar].update(0) def callback(self, **kw): if self.print_messages and ('message' in kw) and kw['message']: if self.notebook: print(kw['message']) else: self.tqdm.write(kw['message']) class RqWorkerProgressLogger: def __init__(self, job): self.job = job if 'progress_data' not in self.job.meta: self.job.meta['progress_data'] = {} self.job.save() def callback(self, **kw): self.job.meta['progress_data'] = self.state self.job.save() class RqWorkerBarLogger(RqWorkerProgressLogger, ProgressBarLogger): def __init__(self, job, init_state=None, bars=None, ignored_bars=(), logged_bars='all', min_time_interval=0): RqWorkerProgressLogger.__init__(self, job) ProgressBarLogger.__init__(self, init_state=init_state, bars=bars, ignored_bars=ignored_bars, logged_bars=logged_bars, min_time_interval=min_time_interval) class MuteProgressBarLogger(ProgressBarLogger): def bar_is_ignored(self, bar): return True def default_bar_logger(logger, bars=None, ignored_bars=None, logged_bars='all', min_time_interval=0, ignore_bars_under=0): if logger == 'bar': return TqdmProgressBarLogger( bars=bars, ignored_bars=ignored_bars, logged_bars=logged_bars, min_time_interval=min_time_interval, ignore_bars_under=ignore_bars_under ) elif logger is None: return MuteProgressBarLogger() else: return logger proglog-0.1.9/proglog/__init__.py0000777000000000000000000000045613303222772016727 0ustar rootroot00000000000000""" geneblocks/__init__.py """ # __all__ = [] from .proglog import (ProgressLogger, ProgressBarLogger, TqdmProgressBarLogger, notebook, RqWorkerProgressLogger, RqWorkerBarLogger, MuteProgressBarLogger, default_bar_logger) from .version import __version__ proglog-0.1.9/proglog/version.py0000777000000000000000000000002613303315201016634 0ustar rootroot00000000000000__version__ = "0.1.9" proglog-0.1.9/ez_setup.py0000777000000000000000000002050013123300122015327 0ustar rootroot00000000000000 #!python """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from ez_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import os import shutil import sys import tempfile import tarfile import optparse import subprocess from distutils import log try: from site import USER_SITE except ImportError: USER_SITE = None DEFAULT_VERSION = "0.9.6" DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/" def _python_cmd(*args): args = (sys.executable,) + args return subprocess.call(args) == 0 def _install(tarball, install_args=()): # extracting the tarball tmpdir = tempfile.mkdtemp() log.warn('Extracting in %s', tmpdir) old_wd = os.getcwd() try: os.chdir(tmpdir) tar = tarfile.open(tarball) _extractall(tar) tar.close() # going in the directory subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) os.chdir(subdir) log.warn('Now working in %s', subdir) # installing log.warn('Installing Setuptools') if not _python_cmd('setup.py', 'install', *install_args): log.warn('Something went wrong during the installation.') log.warn('See the error message above.') # exitcode will be 2 return 2 finally: os.chdir(old_wd) shutil.rmtree(tmpdir) def _build_egg(egg, tarball, to_dir): # extracting the tarball tmpdir = tempfile.mkdtemp() log.warn('Extracting in %s', tmpdir) old_wd = os.getcwd() try: os.chdir(tmpdir) tar = tarfile.open(tarball) _extractall(tar) tar.close() # going in the directory subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) os.chdir(subdir) log.warn('Now working in %s', subdir) # building an egg log.warn('Building a Setuptools egg in %s', to_dir) _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) finally: os.chdir(old_wd) shutil.rmtree(tmpdir) # returning the result log.warn(egg) if not os.path.exists(egg): raise IOError('Could not build the egg.') def _do_download(version, download_base, to_dir, download_delay): egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg' % (version, sys.version_info[0], sys.version_info[1])) if not os.path.exists(egg): tarball = download_setuptools(version, download_base, to_dir, download_delay) _build_egg(egg, tarball, to_dir) sys.path.insert(0, egg) import setuptools setuptools.bootstrap_install_from = egg def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15): # making sure we use the absolute path to_dir = os.path.abspath(to_dir) was_imported = 'pkg_resources' in sys.modules or \ 'setuptools' in sys.modules try: import pkg_resources except ImportError: return _do_download(version, download_base, to_dir, download_delay) try: pkg_resources.require("setuptools>=" + version) return except pkg_resources.VersionConflict: e = sys.exc_info()[1] if was_imported: sys.stderr.write( "The required version of setuptools (>=%s) is not available,\n" "and can't be installed while this script is running. Please\n" "install a more recent version first, using\n" "'easy_install -U setuptools'." "\n\n(Currently using %r)\n" % (version, e.args[0])) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok return _do_download(version, download_base, to_dir, download_delay) except pkg_resources.DistributionNotFound: return _do_download(version, download_base, to_dir, download_delay) def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay=15): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ # making sure we use the absolute path to_dir = os.path.abspath(to_dir) try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen tgz_name = "setuptools-%s.tar.gz" % version url = download_base + tgz_name saveto = os.path.join(to_dir, tgz_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: log.warn("Downloading %s", url) src = urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = src.read() dst = open(saveto, "wb") dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def _extractall(self, path=".", members=None): """Extract all members from the archive to the current working directory and set owner, modification time and permissions on directories afterwards. `path' specifies a different directory to extract to. `members' is optional and must be a subset of the list returned by getmembers(). """ import copy import operator from tarfile import ExtractError directories = [] if members is None: members = self for tarinfo in members: if tarinfo.isdir(): # Extract directories with a safe mode. directories.append(tarinfo) tarinfo = copy.copy(tarinfo) tarinfo.mode = 448 # decimal for oct 0700 self.extract(tarinfo, path) # Reverse sort directories. if sys.version_info < (2, 4): def sorter(dir1, dir2): return cmp(dir1.name, dir2.name) directories.sort(sorter) directories.reverse() else: directories.sort(key=operator.attrgetter('name'), reverse=True) # Set correct owner, mtime and filemode on directories. for tarinfo in directories: dirpath = os.path.join(path, tarinfo.name) try: self.chown(tarinfo, dirpath) self.utime(tarinfo, dirpath) self.chmod(tarinfo, dirpath) except ExtractError: e = sys.exc_info()[1] if self.errorlevel > 1: raise else: self._dbg(1, "tarfile: %s" % e) def _build_install_args(options): """ Build the arguments to 'python setup.py install' on the setuptools package """ install_args = [] if options.user_install: if sys.version_info < (2, 6): log.warn("--user requires Python 2.6 or later") raise SystemExit(1) install_args.append('--user') return install_args def _parse_args(): """ Parse the command line for options """ parser = optparse.OptionParser() parser.add_option( '--user', dest='user_install', action='store_true', default=False, help='install in user site package (requires Python 2.6 or later)') parser.add_option( '--download-base', dest='download_base', metavar="URL", default=DEFAULT_URL, help='alternative URL from where to download the setuptools package') options, args = parser.parse_args() # positional arguments are ignored return options def main(version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" options = _parse_args() tarball = download_setuptools(download_base=options.download_base) return _install(tarball, _build_install_args(options)) if __name__ == '__main__': sys.exit(main()) proglog-0.1.9/setup.cfg0000644000000000000000000000004613303315512014745 0ustar rootroot00000000000000[egg_info] tag_build = tag_date = 0 proglog-0.1.9/proglog.egg-info/0000755000000000000000000000000013303315512016267 5ustar rootroot00000000000000proglog-0.1.9/proglog.egg-info/SOURCES.txt0000664000000000000000000000043313303315512020155 0ustar rootroot00000000000000LICENCE.txt MANIFEST.in README.rst ez_setup.py pypi-readme.rst setup.py proglog/__init__.py proglog/proglog.py proglog/version.py proglog.egg-info/PKG-INFO proglog.egg-info/SOURCES.txt proglog.egg-info/dependency_links.txt proglog.egg-info/requires.txt proglog.egg-info/top_level.txtproglog-0.1.9/proglog.egg-info/top_level.txt0000664000000000000000000000001013303315512021012 0ustar rootroot00000000000000proglog proglog-0.1.9/proglog.egg-info/PKG-INFO0000664000000000000000000000153013303315512017365 0ustar rootroot00000000000000Metadata-Version: 1.0 Name: proglog Version: 0.1.9 Summary: Log and progress bar manager for console, notebooks, web... Home-page: UNKNOWN Author: Zulko Author-email: UNKNOWN License: MIT - copyright Edinburgh Genome Foundry Description: Proglog =================== Proglog is a progress logging system for Python. It allows to build complex libraries while giving the user control on the management of logs, callbacks and progress bars. Infos ----- **PIP installation:** .. code:: bash pip install proglog **Github Page** ``_ **License:** MIT, Copyright Edinburgh Genome Foundry Keywords: logger log progress bar Platform: UNKNOWN proglog-0.1.9/proglog.egg-info/dependency_links.txt0000664000000000000000000000000113303315512022337 0ustar rootroot00000000000000 proglog-0.1.9/proglog.egg-info/requires.txt0000664000000000000000000000000513303315512020664 0ustar rootroot00000000000000tqdm proglog-0.1.9/PKG-INFO0000644000000000000000000000153013303315512014220 0ustar rootroot00000000000000Metadata-Version: 1.0 Name: proglog Version: 0.1.9 Summary: Log and progress bar manager for console, notebooks, web... Home-page: UNKNOWN Author: Zulko Author-email: UNKNOWN License: MIT - copyright Edinburgh Genome Foundry Description: Proglog =================== Proglog is a progress logging system for Python. It allows to build complex libraries while giving the user control on the management of logs, callbacks and progress bars. Infos ----- **PIP installation:** .. code:: bash pip install proglog **Github Page** ``_ **License:** MIT, Copyright Edinburgh Genome Foundry Keywords: logger log progress bar Platform: UNKNOWN proglog-0.1.9/pypi-readme.rst0000664000000000000000000000062513303315445016104 0ustar rootroot00000000000000Proglog =================== Proglog is a progress logging system for Python. It allows to build complex libraries while giving the user control on the management of logs, callbacks and progress bars. Infos ----- **PIP installation:** .. code:: bash pip install proglog **Github Page** ``_ **License:** MIT, Copyright Edinburgh Genome Foundry proglog-0.1.9/setup.py0000777000000000000000000000101413303315427014646 0ustar rootroot00000000000000import ez_setup ez_setup.use_setuptools() from setuptools import setup, find_packages exec(open('proglog/version.py').read()) # loads __version__ setup(name='proglog', version=__version__, author='Zulko', description='Log and progress bar manager for console, notebooks, web...', long_description=open('pypi-readme.rst').read(), license='MIT - copyright Edinburgh Genome Foundry', keywords="logger log progress bar", install_requires=['tqdm'], packages= find_packages(exclude='docs')) proglog-0.1.9/LICENCE.txt0000777000000000000000000000216213143677502014753 0ustar rootroot00000000000000 The MIT License (MIT) [OSI Approved License] The MIT License (MIT) Copyright (c) 2017 Edinburgh Genome Foundry Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. proglog-0.1.9/MANIFEST.in0000777000000000000000000000006013144124614014671 0ustar rootroot00000000000000include *.txt include *.rst include ez_setup.py