#!/usr/bin/env python
from setuptools import setup
setup(
  name = 'cs.result',
  author = 'Cameron Simpson',
  author_email = 'cs@cskk.id.au',
  version = '20200521',
  url = 'https://bitbucket.org/cameron_simpson/css/commits/all',
  description =
    'Result and friends: various classable classes for deferred delivery of values.',
  long_description =
    ('Result and friends: various classable classes for deferred delivery of '    
 'values.\n'    
 '\n'    
 '*Latest release 20200521*:\n'    
 '* OnDemandResult: bugfixes and improvements.\n'    
 '* Result.bg: accept optional _name parameter to specify the Result.name.\n'    
 '\n'    
 'A Result is the base class for several callable subclasses\n'    
 'which will receive values at a later point in time,\n'    
 'and can also be used standalone without subclassing.\n'    
 '\n'    
 'A call to a Result will block until the value is received or the Result is '    
 'cancelled,\n'    
 'which will raise an exception in the caller.\n'    
 'A Result may be called by multiple users, before or after the value has been '    
 'delivered;\n'    
 'if the value has been delivered the caller returns with it immediately.\n'    
 "A Result's state may be inspected (pending, running, ready, cancelled).\n"    
 "Callbacks can be registered via a Result's .notify method.\n"    
 '\n'    
 'An incomplete Result can be told to call a function to compute its value;\n'    
 'the function return will be stored as the value unless the function raises '    
 'an exception,\n'    
 'in which case the exception information is recorded instead.\n'    
 'If an exception occurred, it will be reraised for any caller of the Result.\n'    
 '\n'    
 'Trite example::\n'    
 '\n'    
 '  R = Result(name="my demo")\n'    
 '\n'    
 '  Thread 1:\n'    
 '    # this blocks until the Result is ready\n'    
 '    value = R()\n'    
 '    print(value)\n'    
 '    # prints 3 once Thread 2 (below) assigns to it\n'    
 '\n'    
 '  Thread 2:\n'    
 '    R.result = 3\n'    
 '\n'    
 '  Thread 3:\n'    
 '    value = R()\n'    
 '    # returns immediately with 3\n'    
 '\n'    
 'You can also collect multiple Results in completion order using the report() '    
 'function::\n'    
 '\n'    
 '  Rs = [ ... list of Results of whatever type ... ]\n'    
 '  ...\n'    
 '  for R in report(Rs):\n'    
 '    x = R()     # collect result, will return immediately because\n'    
 '                # the Result is complete\n'    
 '    print(x)    # print result\n'    
 '\n'    
 '## Function `after(Rs, R, func, *a, **kw)`\n'    
 '\n'    
 'After the completion of `Rs` call `func(*a,**kw)` and return\n'    
 'its result via `R`; return the `Result` object.\n'    
 '\n'    
 'Parameters:\n'    
 '* `Rs`: an iterable of Results.\n'    
 '* `R`: a `Result` to collect to result of calling `func`.\n'    
 '  If `None`, one will be created.\n'    
 '* `func`, `a`, `kw`: a callable and its arguments.\n'    
 '\n'    
 '## Class `AsynchState(enum.Enum)`\n'    
 '\n'    
 'State tokens for `Result`s.\n'    
 '\n'    
 '## Function `bg(func, *a, **kw)`\n'    
 '\n'    
 'Dispatch a `Thread` to run `func`, return a `Result` to collect its value.\n'    
 '\n'    
 '## Class `CancellationError(builtins.Exception,builtins.BaseException)`\n'    
 '\n'    
 'Raised when accessing result or exc_info after cancellation.\n'    
 '\n'    
 '## Class `OnDemandFunction(Result)`\n'    
 '\n'    
 'Wrap a callable, run it when required.\n'    
 '\n'    
 '## Class `OnDemandResult(Result)`\n'    
 '\n'    
 'Wrap a callable, run it when required.\n'    
 '\n'    
 '## Function `report(LFs)`\n'    
 '\n'    
 'Generator which yields completed `Result`s.\n'    
 '\n'    
 'This is a generator that yields `Result`s as they complete,\n'    
 'useful for waiting for a sequence of `Result`s\n'    
 'that may complete in an arbitrary order.\n'    
 '\n'    
 '## Class `Result`\n'    
 '\n'    
 'Basic class for asynchronous collection of a result.\n'    
 'This is also used to make OnDemandFunctions, LateFunctions and other\n'    
 'objects with asynchronous termination.\n'    
 '\n'    
 '### Method `Result.__init__(self, name=None, lock=None, result=None)`\n'    
 '\n'    
 'Base initialiser for `Result` objects and subclasses.\n'    
 '\n'    
 'Parameter:\n'    
 '* `name`: optional parameter naming this object.\n'    
 '* `lock`: optional locking object, defaults to a new `threading.Lock`.\n'    
 '* `result`: if not `None`, prefill the `.result` property.\n'    
 '\n'    
 '## Class `ResultState(enum.Enum)`\n'    
 '\n'    
 'State tokens for `Result`s.\n'    
 '\n'    
 '# Release Log\n'    
 '\n'    
 '\n'    
 '\n'    
 '*Release 20200521*:\n'    
 '* OnDemandResult: bugfixes and improvements.\n'    
 '* Result.bg: accept optional _name parameter to specify the Result.name.\n'    
 '\n'    
 '*Release 20191007*:\n'    
 '* Simplify ResultState definition.\n'    
 '* Result.bg: use cs.threads.bg to dispatch the Thread.\n'    
 '\n'    
 '*Release 20190522*:\n'    
 '* Result.__call__ now accepts an optional callable and args.\n'    
 '* Result.call: set the Result state to "running" before dispatching the '    
 'function.\n'    
 '* Rename OnDemandFunction to OnDemandResult, keep old name around for '    
 'compatibility.\n'    
 '* Result._complete: also permitted if state==cancelled.\n'    
 '\n'    
 '*Release 20190309*:\n'    
 'Small bugfix.\n'    
 '\n'    
 '*Release 20181231*:\n'    
 '* Result.call: report baser exceptions than BaseException.\n'    
 '* Drop _PendingFunction abstract class.\n'    
 '\n'    
 '*Release 20181109.1*:\n'    
 'DISTINFO update.\n'    
 '\n'    
 '*Release 20181109*:\n'    
 '* Derive CancellationError from Exception instead of RuntimeError, fix '    
 'initialiser.\n'    
 '* Rename AsynchState to ResultState and make it an Enum.\n'    
 '* Make Results hashable and comparable for equality for use as mapping keys: '    
 'equality is identity.\n'    
 '* New Result.collected attribute, set true if .result or .exc_info are '    
 'accessed, logs an error if Result.__del__ is called when false, may be set '    
 'true externally if a Result is not required.\n'    
 '* Drop `final` parameter; never used and supplanted by Result.notify.\n'    
 '* Result.join: return the .result and .exc_info properties in order to mark '    
 'the Result as collected.\n'    
 '* Result: set .collected to True when a notifier has been called '    
 'successfully.\n'    
 '* Bugfix Result.cancel: apply the new cancelled state.\n'    
 '\n'    
 '*Release 20171231*:\n'    
 '* Bugfix Result.call to catch BaseException instead of Exception.\n'    
 '* New convenience function bg(func) to dispatch `func` in a separate Thread '    
 'and return a Result to collect its value.\n'    
 '\n'    
 '*Release 20171030.1*:\n'    
 'Fix module requirements specification.\n'    
 '\n'    
 '*Release 20171030*:\n'    
 'New Result.bg(func, *a, **kw) method to dispatch function in separate Thread '    
 'to compute the Result value.\n'    
 '\n'    
 '*Release 20170903*:\n'    
 'rename cs.asynchron to cs.result'),
  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.logutils', 'cs.pfx', 'cs.py.func', 'cs.py3', 'cs.seq', 'cs.threads', 'icontract'],
  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.result'],
)
