#!/usr/bin/env python
from setuptools import setup
setup(
  name = 'cs.logutils',
  author = 'Cameron Simpson',
  author_email = 'cs@cskk.id.au',
  version = '20200518',
  url = 'https://bitbucket.org/cameron_simpson/css/commits/all',
  description =
    'Logging convenience routines.',
  long_description =
    ('Logging convenience routines.\n'    
 '\n'    
 '*Latest release 20200518*:\n'    
 '* Sweeping removal of cs.obj.O, universally supplanted by '    
 'types.SimpleNamespace.\n'    
 '* Default to logging level TRACK if stderr is a tty instead of '    
 'logging.INFO.\n'    
 '* New ifverbose function with leading `verbose` parameter: if None, log at '    
 'INFO otherwise if true, log at TRACK, otherwise do not log.\n'    
 '* BREAKING: remove global logging_level and trace_level variables, put it '    
 'all in the global loginfo.\n'    
 '* Make STATUS just below TRACK so that it is above INFO instead of below.\n'    
 '* New status() function for cs.upd messages.\n'    
 '* UpdHandler: treat status_level as special, going directly to Upd.out.\n'    
 '* Improved source line recitation on modern Python.\n'    
 '* Default level if sys.stderr.isatty() now STATUS, not TRACK.\n'    
 '* Some fixes for loginfo initialisation and setting cs.pfx.cmd.\n'    
 '\n'    
 'The logging package is very useful, but a little painful to use.\n'    
 'This package provides low impact logging setup and some extremely\n'    
 'useful if unconventional context hooks for logging.\n'    
 '\n'    
 'The default logging verbosity output format has different defaults\n'    
 'based on whether an output log file is a tty\n'    
 'and whether the environment variable $DEBUG is set, and to what.\n'    
 '\n'    
 'On terminals warnings and errors get ANSI colouring.\n'    
 '\n'    
 'A mode is available that uses cs.upd.\n'    
 '\n'    
 'Some examples:\n'    
 '--------------\n'    
 '\n'    
 'Program initialisation::\n'    
 '\n'    
 '    from cs.logutils import setup_logging\n'    
 '\n'    
 '    def main(argv):\n'    
 '      cmd = os.path.basename(argv.pop(0))\n'    
 '      setup_logging(cmd)\n'    
 '\n'    
 'Basic logging from anywhere::\n'    
 '\n'    
 '    from cs.logutils import info, warning, error\n'    
 '    [...]\n'    
 '    def some_function(...):\n'    
 '        [...]\n'    
 '        error("nastiness found! bad value=%r", bad_value)\n'    
 '\n'    
 "## Function `add_logfile(filename, logger=None, mode='a', encoding=None, "    
 'delay=False, format=None, no_prefix=False)`\n'    
 '\n'    
 'Add a FileHandler logging to the specified `filename`;\n'    
 'return the chosen logger and the new handler.\n'    
 '\n'    
 'Parameters:\n'    
 '* `logger`: if supplied and not None, add the FileHandler to that\n'    
 '  Logger, otherwise to the root Logger. If `logger` is a string, call\n'    
 '  `logging.getLogger(logger)` to obtain the logger.\n'    
 '* `mode`, `encoding` and `delay`: passed to the logging.FileHandler\n'    
 '  initialiser.\n'    
 "* `format`: used to override the handler's default format.\n"    
 '* `no_prefix`: if true, do not put the Pfx context onto the front of the '    
 'message.\n'    
 '\n'    
 '## Function `critical(*a, **kw)`\n'    
 '\n'    
 'Emit a log at `logging.CRITICAL` `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `D(msg, *args)`\n'    
 '\n'    
 'Print formatted debug string straight to `sys.stderr` if\n'    
 '`D_mode` is true, bypassing the logging modules entirely.\n'    
 "A quick'n'dirty debug tool.\n"    
 '\n'    
 '## Function `debug(*a, **kw)`\n'    
 '\n'    
 'Emit a log at `logging.DEBUG` `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `error(*a, **kw)`\n'    
 '\n'    
 'Emit a log at `logging.ERROR` `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `exception(msg, *args)`\n'    
 '\n'    
 'Emit an exception log with the current Pfx prefix.\n'    
 '\n'    
 '## Function `ftrace(func)`\n'    
 '\n'    
 'Decorator to trace a function if `__module__.DEBUG` is true.\n'    
 '\n'    
 '## Function `ifdebug()`\n'    
 '\n'    
 'Test the `loginfo.level` against `logging.DEBUG`.\n'    
 '\n'    
 '## Function `ifverbose(*a, **kw)`\n'    
 '\n'    
 'Conditionally log a message.\n'    
 'If verbose is `None`\n'    
 'then the caller has not indicated a specific verbosity\n'    
 'and we use the `track` function.\n'    
 'If verbose is true\n'    
 'then we use the `info` function.\n'    
 '\n'    
 '## Function `infer_logging_level(env_debug=None, environ=None, '    
 'verbose=None)`\n'    
 '\n'    
 'Infer a logging level from the `env_debug`, which by default\n'    
 'comes from the environment variable `$DEBUG`.\n'    
 '\n'    
 'Usually default to logging.WARNING, but if sys.stderr is a terminal,\n'    
 'default to TRACK.\n'    
 '\n'    
 'Parse the environment variable $DEBUG as a comma separated\n'    
 'list of flags.\n'    
 '\n'    
 'Examine the in sequence flags to affect the logging level:\n'    
 '* `numeric < 1`: `logging.WARNING`\n'    
 '* `numeric >= 1 and < 2`: `logging.INFO`\n'    
 '* `numeric >= 2`: `logging.DEBUG`\n'    
 '* `"DEBUG"`: `logging.DEBUG`\n'    
 '* `"STATUS"`: `STATUS`\n'    
 '* `"INFO"`: `logging.INFO`\n'    
 '* `"TRACK"`: `TRACK`\n'    
 '* `"WARNING"`: `logging.WARNING`\n'    
 '* `"ERROR"`: `logging.ERROR`\n'    
 '\n'    
 'Return an object with the following attributes:\n'    
 '* `.level`: A logging level.\n'    
 '* `.flags`: All the words from $DEBUG as separated by commas and '    
 'uppercased.\n'    
 '* `.module_names`: Module names to be debugged.\n'    
 '* `.function_names`: Functions to be traced in the for '    
 '"module_name.func_name()".\n'    
 '\n'    
 '## Function `info(*a, **kw)`\n'    
 '\n'    
 'Emit a log at `logging.INFO` `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `log(*a, **kw)`\n'    
 '\n'    
 'Emit a log at the specified `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `logException(exc_type, exc_value, exc_tb)`\n'    
 '\n'    
 'Replacement for sys.excepthook that reports via the cs.logutils\n'    
 'logging wrappers.\n'    
 '\n'    
 '## Class `LogTime`\n'    
 '\n'    
 'LogTime is a content manager that logs the elapsed time of the enclosed\n'    
 'code. After the run, the field .elapsed contains the elapsed time in\n'    
 'seconds.\n'    
 '\n'    
 '### Method `LogTime.__init__(self, tag, *args, **kwargs)`\n'    
 '\n'    
 'Set up a LogTime.\n'    
 '\n'    
 'Parameters:\n'    
 '* `tag`: label included at the start of the log entry\n'    
 '* `args`: optional array; if not empty `args` is applied to\n'    
 '  `tag` with `%`\n'    
 '* `level`: keyword argument specifying a log level for a\n'    
 '  default log entry, default `logging.INFO`\n'    
 '* `threshold`: keyword argument specifying minimum time to\n'    
 '  cause a log, default None (no minimum)\n'    
 '* `warning_level`: keyword argument specifying the log level\n'    
 '  for a warning log entry, default `logging.WARNING`\n'    
 '* `warning_threshold`: keyword argument specifying a time\n'    
 '  which raises the log level to `warning_level`\n'    
 '\n'    
 "## Function `logTo(filename, logger=None, mode='a', encoding=None, "    
 'delay=False, format=None, no_prefix=False)`\n'    
 '\n'    
 'Add a FileHandler logging to the specified `filename`;\n'    
 'return the chosen logger and the new handler.\n'    
 '\n'    
 'Parameters:\n'    
 '* `logger`: if supplied and not None, add the FileHandler to that\n'    
 '  Logger, otherwise to the root Logger. If `logger` is a string, call\n'    
 '  `logging.getLogger(logger)` to obtain the logger.\n'    
 '* `mode`, `encoding` and `delay`: passed to the logging.FileHandler\n'    
 '  initialiser.\n'    
 "* `format`: used to override the handler's default format.\n"    
 '* `no_prefix`: if true, do not put the Pfx context onto the front of the '    
 'message.\n'    
 '\n'    
 '## Class `NullHandler(logging.Handler,logging.Filterer)`\n'    
 '\n'    
 'A Handler which discards its requests.\n'    
 '\n'    
 '## Class `PfxFormatter(logging.Formatter)`\n'    
 '\n'    
 "A Formatter subclass that has access to the program's cmd and `Pfx` state.\n"    
 '\n'    
 '### Method `PfxFormatter.__init__(self, fmt=None, datefmt=None, cmd=None)`\n'    
 '\n'    
 'Initialise the `PfxFormatter`.\n'    
 '\n'    
 'Parameters:\n'    
 '* `fmt`: format template,\n'    
 "  default from `DEFAULT_PFX_FORMAT` `'%(asctime)s %(levelname)s %(pfx)s: "    
 "%(message)s'`.\n"    
 '  Passed through to `Formatter.__init__`.\n'    
 '* `datefmt`:\n'    
 '  Passed through to `Formatter.__init__`.\n'    
 '* `cmd`: the "command prefix" made available to format strings.\n'    
 '  If not set, `cs.pfx.cmd` is presented.\n'    
 '\n'    
 '## Function `setup_logging(cmd_name=None, main_log=None, format=None, '    
 'level=None, flags=None, upd_mode=None, ansi_mode=None, trace_mode=None, '    
 'module_names=None, function_names=None, verbose=None)`\n'    
 '\n'    
 'Arrange basic logging setup for conventional UNIX command\n'    
 'line error messaging; return an object with informative attributes.\n'    
 'That object is also available as the global `cs.lgutils.loginfo`.\n'    
 '\n'    
 'Parameters:\n'    
 '* `cmd_name`: program name, default from `basename(sys.argv[0])`.\n'    
 '  Side-effect: sets `cs.pfx.cmd` to this value.\n'    
 '* `main_log`: default logging system.\n'    
 '  If None, the main log will go to sys.stderr;\n'    
 '  if `main_log` is a string, is it used as a filename to\n'    
 '  open in append mode;\n'    
 '  otherwise main_log should be a stream suitable\n'    
 '  for use with `logging.StreamHandler()`.\n'    
 '  The resulting log handler is added to the `logging` root logger.\n'    
 '* `format`: the message format for `main_log`.\n'    
 '  If `None`, use `DEFAULT_PFX_FORMAT_TTY`\n'    
 '  when `main_log` is a tty or FIFO,\n'    
 '  otherwise `DEFAULT_PFX_FORMAT`.\n'    
 '* `level`: `main_log` logging level.\n'    
 '  If None, infer a level from the environment\n'    
 '  using `infer_logging_level()`.\n'    
 '* `flags`: a string containing debugging flags separated by commas.\n'    
 '  If `None`, infer the flags from the environment using\n'    
 '  `infer_logging_level()`.\n'    
 '  The following flags have meaning:\n'    
 '  `D`: set cs.logutils.D_mode to True;\n'    
 '  `TDUMP`: attach a signal handler to SIGHUP to do a thread stack dump;\n'    
 '  `TRACE`: enable various noisy tracing facilities;\n'    
 '  `UPD`, `NOUPD`: set the default for `upd_mode` to True or False '    
 'respectively.\n'    
 '* `upd_mode`: a Boolean to activate cs.upd as the `main_log` method;\n'    
 "  if `None`, set it to `True` if `flags` contains 'UPD',\n"    
 "  otherwise to `False` if `flags` contains 'NOUPD',\n"    
 '  otherwise set it from `main_log.isatty()`.\n'    
 '  A true value causes the root logger to use `cs.upd` for logging.\n'    
 '* `ansi_mode`: if `None`, set it from `main_log.isatty()`.\n'    
 '  A true value causes the root logger to colour certain logging levels\n'    
 '  using ANSI terminal sequences (currently only if `cs.upd` is used).\n'    
 '* `trace_mode`: if `None`, set it according to the presence of\n'    
 "  'TRACE' in flags. Otherwise if `trace_mode` is true, set the\n"    
 '  global `loginfo.trace_level` to `loginfo.level`; otherwise it defaults\n'    
 '  to `logging.DEBUG`.\n'    
 '* `verbose`: if `None`, then if stderr is a tty then the log\n'    
 '  level is `INFO` otherwise `WARNING`. Otherwise, if `verbose` is\n'    
 '  true then the log level is `INFO` otherwise `WARNING`.\n'    
 '\n'    
 '## Function `status(*a, **kw)`\n'    
 '\n'    
 'Emit a log at `STATUS` `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `trace(*a, **kw)`\n'    
 '\n'    
 'Emit a log message at `loginfo.trace_level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `track(*a, **kw)`\n'    
 '\n'    
 'Emit a log at `TRACK` `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `upd(*a, **kw)`\n'    
 '\n'    
 "If we're using an `UpdHandler`,\n"    
 'update the status line otherwise write an info message.\n'    
 '\n'    
 'Note that this calls `Upd.out` directly with `msg%args`\n'    
 'and thus does not include the current `Pfx` prefix.\n'    
 'You may well want to use the `status()` function instead.\n'    
 '\n'    
 '## Class '    
 '`UpdHandler(logging.StreamHandler,logging.Handler,logging.Filterer)`\n'    
 '\n'    
 'A `StreamHandler` subclass whose `.emit` method\n'    
 'uses a `cs.upd.Upd` for transcription.\n'    
 '\n'    
 '### Method `UpdHandler.__init__(self, strm=None, upd_level=None, '    
 'ansi_mode=None)`\n'    
 '\n'    
 'Initialise the `UpdHandler`.\n'    
 '\n'    
 'Parameters:\n'    
 '* `strm`: the output stream, default `sys.stderr`.\n'    
 '* `upd_level`: the magic logging level which updates the status line\n'    
 '  via `Upd`. Default: `STATUS`.\n'    
 '* `ansi_mode`: if `None`, set from `strm.isatty()`.\n'    
 '  A true value causes the handler to colour certain logging levels\n'    
 '  using ANSI terminal sequences.\n'    
 '\n'    
 '## Function `warning(*a, **kw)`\n'    
 '\n'    
 'Emit a log at `logging.WARNING` `level` with the current Pfx prefix.\n'    
 '\n'    
 '## Function `with_log(filename, **kw)`\n'    
 '\n'    
 'Context manager to add a Logger to the output logs temporarily.\n'    
 '\n'    
 '# Release Log\n'    
 '\n'    
 '\n'    
 '\n'    
 '*Release 20200518*:\n'    
 '* Sweeping removal of cs.obj.O, universally supplanted by '    
 'types.SimpleNamespace.\n'    
 '* Default to logging level TRACK if stderr is a tty instead of '    
 'logging.INFO.\n'    
 '* New ifverbose function with leading `verbose` parameter: if None, log at '    
 'INFO otherwise if true, log at TRACK, otherwise do not log.\n'    
 '* BREAKING: remove global logging_level and trace_level variables, put it '    
 'all in the global loginfo.\n'    
 '* Make STATUS just below TRACK so that it is above INFO instead of below.\n'    
 '* New status() function for cs.upd messages.\n'    
 '* UpdHandler: treat status_level as special, going directly to Upd.out.\n'    
 '* Improved source line recitation on modern Python.\n'    
 '* Default level if sys.stderr.isatty() now STATUS, not TRACK.\n'    
 '* Some fixes for loginfo initialisation and setting cs.pfx.cmd.\n'    
 '\n'    
 '*Release 20200229*:\n'    
 '* Update for new Upd.without context manager.\n'    
 '* setup_logging: default `upd_mode` to `main_log.isatty()`, was previously '    
 'False.\n'    
 '* Drop UpdHandler.upd method, shadowed by instance attribute, never used.\n'    
 '\n'    
 '*Release 20190923*:\n'    
 '* New `TRACK` constant equal to `logging.INFO+5` to provide a level higher '    
 'than `INFO`\n'    
 '* (which seems unreasonably noisy) and lower than `WARNING`\n'    
 '* warning for tracking salient events.\n'    
 '* New `track()` function to match.\n'    
 '\n'    
 '*Release 20190220*:\n'    
 'Improvements to upd_mode.\n'    
 '\n'    
 '*Release 20190103*:\n'    
 'Documentation updates.\n'    
 '\n'    
 '*Release 20190101*:\n'    
 'Bugfix for @contextmanager usage.\n'    
 '\n'    
 '*Release 20171030*:\n'    
 'Assorted fixes from recent module reshuffle. Other small features and '    
 'cleanups. Drop a couple of unused functions.\n'    
 '\n'    
 '*Release 20160828*:\n'    
 'Use "install_requires" instead of "requires" in DISTINFO.\n'    
 '\n'    
 '*Release 20160827*:\n'    
 '* Pfx: import __exit__ handler\n'    
 '* Preliminary per-module and per-function syntax accepted in $DEBUG envvar.\n'    
 '* Improvements to X(), add DP() and XP() prefixed flavours.\n'    
 '* status() function to update terminal status line.\n'    
 '* New X_via_tty global flag: directs X() to tty instead of sys.stderr.\n'    
 '* Assorted other minor improvements.\n'    
 '\n'    
 '*Release 20150118*:\n'    
 'metadata updates\n'    
 '\n'    
 '*Release 20150110*:\n'    
 'Initial PyPI release.'),
  classifiers = ['Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Operating System :: OS Independent', 'Topic :: Software Development :: Libraries :: Python Modules', 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)'],
  install_requires = ['cs.ansi_colour', 'cs.deco', 'cs.lex', 'cs.pfx', 'cs.py.func', 'cs.upd'],
  keywords = ['python2', 'python3'],
  license = 'GNU General Public License v3 or later (GPLv3+)',
  long_description_content_type = 'text/markdown',
  package_dir = {'': 'lib/python'},
  py_modules = ['cs.logutils'],
)
