File "/usr/bin/bpytop", line 1266, in refresh
for f in os.listdir(d):
FileNotFoundError: [Errno 2] No such file or directory: '/home/josuer08/.config/bpytop/themes'
+12/02/21 (20:24:49) | ERROR: [Errno 2] No such file or directory: '/home/josuer08/.config/bpytop/themes'
+Traceback (most recent call last):
+ File "/usr/bin/bpytop", line 1319, in refresh
+ for f in os.listdir(d):
+FileNotFoundError: [Errno 2] No such file or directory: '/home/josuer08/.config/bpytop/themes'
let g:netrw_dirhistmax =10
-let g:netrw_dirhistcnt =6
+let g:netrw_dirhistcnt =9
+let g:netrw_dirhist_9='/home/josuer08/Documents/josueBlogXYZ/src'
+let g:netrw_dirhist_8='/home/josuer08/Documents/tinysh'
+let g:netrw_dirhist_7='/home/josuer08'
let g:netrw_dirhist_6='/home/josuer08/.dotfiles/.config/nvim/plugin'
let g:netrw_dirhist_5='/home/josuer08/.dotfiles/.config/nvim'
let g:netrw_dirhist_4='/home/josuer08/.dotfiles/.config'
let g:netrw_dirhist_2='/home/josuer08/Documents/tinysh'
let g:netrw_dirhist_1='/home/josuer08/Documents'
let g:netrw_dirhist_0='/home/josuer08/.dotfiles/.config/bashrc'
-let g:netrw_dirhist_9='/home/josuer08/.dotfiles/.config'
-let g:netrw_dirhist_8='/home/josuer08/.dotfiles'
-let g:netrw_dirhist_7='/home/josuer08/.dotfiles/.config/bashrc'
[window]
-width=1366
-height=729
+width=958
+height=1039
sinkInputType=1
sourceOutputType=1
sinkType=0
--- /dev/null
+https://web.telegram.org/#/im?p=s1412291195_5912359752663674650 Telegram Web
[FileDialog]
-history=file:///home/josuer08/Documents/work/zabbix-systemd-service-monitoring, file:///home/josuer08/Documents/work, file:///home/josuer08/Pictures, file:///home/josuer08, file:///home/josuer08/Downloads
-lastVisited=file:///home/josuer08/Downloads
+history=file:///home/josuer08/Pictures, file:///home/josuer08, file:///home/josuer08/Downloads, file:///home/josuer08/Pictures/backgrounds, file:///home/josuer08/Videos
+lastVisited=file:///home/josuer08/Pictures
qtVersion=5.15.2
shortcuts=file:, file:///home/josuer08
sidebarWidth=83
-treeViewHeader=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1\xb5\0\0\0\x4\x1\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x4\0\0\0\xe1\0\0\0\x1\0\0\0\0\0\0\0\x39\0\0\0\x1\0\0\0\0\0\0\0\x39\0\0\0\x1\0\0\0\0\0\0\0\x62\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\xff\xff\xff\xff)
+treeViewHeader=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\x3\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1\xb5\0\0\0\x4\x1\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x4\0\0\0\xe1\0\0\0\x1\0\0\0\0\0\0\0\x39\0\0\0\x1\0\0\0\0\0\0\0\x39\0\0\0\x1\0\0\0\0\0\0\0\x62\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\xff\xff\xff\xff)
viewMode=Detail
+++ /dev/null
-from pkgutil import extend_path
-
-__path__ = extend_path(__path__, __name__)
+++ /dev/null
-# Copyright 2009 Brian Quinlan. All Rights Reserved.
-# Licensed to PSF under a Contributor Agreement.
-
-"""Execute computations asynchronously using threads or processes."""
-
-__author__ = 'Brian Quinlan (brian@sweetapp.com)'
-
-from concurrent.futures._base import (FIRST_COMPLETED,
- FIRST_EXCEPTION,
- ALL_COMPLETED,
- CancelledError,
- TimeoutError,
- Future,
- Executor,
- wait,
- as_completed)
-from concurrent.futures.thread import ThreadPoolExecutor
-
-try:
- from concurrent.futures.process import ProcessPoolExecutor
-except ImportError:
- # some platforms don't have multiprocessing
- pass
+++ /dev/null
-# Copyright 2009 Brian Quinlan. All Rights Reserved.
-# Licensed to PSF under a Contributor Agreement.
-
-import collections
-import logging
-import threading
-import itertools
-import time
-import types
-
-__author__ = 'Brian Quinlan (brian@sweetapp.com)'
-
-FIRST_COMPLETED = 'FIRST_COMPLETED'
-FIRST_EXCEPTION = 'FIRST_EXCEPTION'
-ALL_COMPLETED = 'ALL_COMPLETED'
-_AS_COMPLETED = '_AS_COMPLETED'
-
-# Possible future states (for internal use by the futures package).
-PENDING = 'PENDING'
-RUNNING = 'RUNNING'
-# The future was cancelled by the user...
-CANCELLED = 'CANCELLED'
-# ...and _Waiter.add_cancelled() was called by a worker.
-CANCELLED_AND_NOTIFIED = 'CANCELLED_AND_NOTIFIED'
-FINISHED = 'FINISHED'
-
-_FUTURE_STATES = [
- PENDING,
- RUNNING,
- CANCELLED,
- CANCELLED_AND_NOTIFIED,
- FINISHED
-]
-
-_STATE_TO_DESCRIPTION_MAP = {
- PENDING: "pending",
- RUNNING: "running",
- CANCELLED: "cancelled",
- CANCELLED_AND_NOTIFIED: "cancelled",
- FINISHED: "finished"
-}
-
-# Logger for internal use by the futures package.
-LOGGER = logging.getLogger("concurrent.futures")
-
-class Error(Exception):
- """Base class for all future-related exceptions."""
- pass
-
-class CancelledError(Error):
- """The Future was cancelled."""
- pass
-
-class TimeoutError(Error):
- """The operation exceeded the given deadline."""
- pass
-
-class _Waiter(object):
- """Provides the event that wait() and as_completed() block on."""
- def __init__(self):
- self.event = threading.Event()
- self.finished_futures = []
-
- def add_result(self, future):
- self.finished_futures.append(future)
-
- def add_exception(self, future):
- self.finished_futures.append(future)
-
- def add_cancelled(self, future):
- self.finished_futures.append(future)
-
-class _AsCompletedWaiter(_Waiter):
- """Used by as_completed()."""
-
- def __init__(self):
- super(_AsCompletedWaiter, self).__init__()
- self.lock = threading.Lock()
-
- def add_result(self, future):
- with self.lock:
- super(_AsCompletedWaiter, self).add_result(future)
- self.event.set()
-
- def add_exception(self, future):
- with self.lock:
- super(_AsCompletedWaiter, self).add_exception(future)
- self.event.set()
-
- def add_cancelled(self, future):
- with self.lock:
- super(_AsCompletedWaiter, self).add_cancelled(future)
- self.event.set()
-
-class _FirstCompletedWaiter(_Waiter):
- """Used by wait(return_when=FIRST_COMPLETED)."""
-
- def add_result(self, future):
- super(_FirstCompletedWaiter, self).add_result(future)
- self.event.set()
-
- def add_exception(self, future):
- super(_FirstCompletedWaiter, self).add_exception(future)
- self.event.set()
-
- def add_cancelled(self, future):
- super(_FirstCompletedWaiter, self).add_cancelled(future)
- self.event.set()
-
-class _AllCompletedWaiter(_Waiter):
- """Used by wait(return_when=FIRST_EXCEPTION and ALL_COMPLETED)."""
-
- def __init__(self, num_pending_calls, stop_on_exception):
- self.num_pending_calls = num_pending_calls
- self.stop_on_exception = stop_on_exception
- self.lock = threading.Lock()
- super(_AllCompletedWaiter, self).__init__()
-
- def _decrement_pending_calls(self):
- with self.lock:
- self.num_pending_calls -= 1
- if not self.num_pending_calls:
- self.event.set()
-
- def add_result(self, future):
- super(_AllCompletedWaiter, self).add_result(future)
- self._decrement_pending_calls()
-
- def add_exception(self, future):
- super(_AllCompletedWaiter, self).add_exception(future)
- if self.stop_on_exception:
- self.event.set()
- else:
- self._decrement_pending_calls()
-
- def add_cancelled(self, future):
- super(_AllCompletedWaiter, self).add_cancelled(future)
- self._decrement_pending_calls()
-
-class _AcquireFutures(object):
- """A context manager that does an ordered acquire of Future conditions."""
-
- def __init__(self, futures):
- self.futures = sorted(futures, key=id)
-
- def __enter__(self):
- for future in self.futures:
- future._condition.acquire()
-
- def __exit__(self, *args):
- for future in self.futures:
- future._condition.release()
-
-def _create_and_install_waiters(fs, return_when):
- if return_when == _AS_COMPLETED:
- waiter = _AsCompletedWaiter()
- elif return_when == FIRST_COMPLETED:
- waiter = _FirstCompletedWaiter()
- else:
- pending_count = sum(
- f._state not in [CANCELLED_AND_NOTIFIED, FINISHED] for f in fs)
-
- if return_when == FIRST_EXCEPTION:
- waiter = _AllCompletedWaiter(pending_count, stop_on_exception=True)
- elif return_when == ALL_COMPLETED:
- waiter = _AllCompletedWaiter(pending_count, stop_on_exception=False)
- else:
- raise ValueError("Invalid return condition: %r" % return_when)
-
- for f in fs:
- f._waiters.append(waiter)
-
- return waiter
-
-
-def _yield_finished_futures(fs, waiter, ref_collect):
- """
- Iterate on the list *fs*, yielding finished futures one by one in
- reverse order.
- Before yielding a future, *waiter* is removed from its waiters
- and the future is removed from each set in the collection of sets
- *ref_collect*.
-
- The aim of this function is to avoid keeping stale references after
- the future is yielded and before the iterator resumes.
- """
- while fs:
- f = fs[-1]
- for futures_set in ref_collect:
- futures_set.remove(f)
- with f._condition:
- f._waiters.remove(waiter)
- del f
- # Careful not to keep a reference to the popped value
- yield fs.pop()
-
-
-def as_completed(fs, timeout=None):
- """An iterator over the given futures that yields each as it completes.
-
- Args:
- fs: The sequence of Futures (possibly created by different Executors) to
- iterate over.
- timeout: The maximum number of seconds to wait. If None, then there
- is no limit on the wait time.
-
- Returns:
- An iterator that yields the given Futures as they complete (finished or
- cancelled). If any given Futures are duplicated, they will be returned
- once.
-
- Raises:
- TimeoutError: If the entire result iterator could not be generated
- before the given timeout.
- """
- if timeout is not None:
- end_time = timeout + time.time()
-
- fs = set(fs)
- total_futures = len(fs)
- with _AcquireFutures(fs):
- finished = set(
- f for f in fs
- if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
- pending = fs - finished
- waiter = _create_and_install_waiters(fs, _AS_COMPLETED)
- finished = list(finished)
- try:
- for f in _yield_finished_futures(finished, waiter,
- ref_collect=(fs,)):
- f = [f]
- yield f.pop()
-
- while pending:
- if timeout is None:
- wait_timeout = None
- else:
- wait_timeout = end_time - time.time()
- if wait_timeout < 0:
- raise TimeoutError(
- '%d (of %d) futures unfinished' % (
- len(pending), total_futures))
-
- waiter.event.wait(wait_timeout)
-
- with waiter.lock:
- finished = waiter.finished_futures
- waiter.finished_futures = []
- waiter.event.clear()
-
- # reverse to keep finishing order
- finished.reverse()
- for f in _yield_finished_futures(finished, waiter,
- ref_collect=(fs, pending)):
- f = [f]
- yield f.pop()
-
- finally:
- # Remove waiter from unfinished futures
- for f in fs:
- with f._condition:
- f._waiters.remove(waiter)
-
-DoneAndNotDoneFutures = collections.namedtuple(
- 'DoneAndNotDoneFutures', 'done not_done')
-def wait(fs, timeout=None, return_when=ALL_COMPLETED):
- """Wait for the futures in the given sequence to complete.
-
- Args:
- fs: The sequence of Futures (possibly created by different Executors) to
- wait upon.
- timeout: The maximum number of seconds to wait. If None, then there
- is no limit on the wait time.
- return_when: Indicates when this function should return. The options
- are:
-
- FIRST_COMPLETED - Return when any future finishes or is
- cancelled.
- FIRST_EXCEPTION - Return when any future finishes by raising an
- exception. If no future raises an exception
- then it is equivalent to ALL_COMPLETED.
- ALL_COMPLETED - Return when all futures finish or are cancelled.
-
- Returns:
- A named 2-tuple of sets. The first set, named 'done', contains the
- futures that completed (is finished or cancelled) before the wait
- completed. The second set, named 'not_done', contains uncompleted
- futures.
- """
- with _AcquireFutures(fs):
- done = set(f for f in fs
- if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
- not_done = set(fs) - done
-
- if (return_when == FIRST_COMPLETED) and done:
- return DoneAndNotDoneFutures(done, not_done)
- elif (return_when == FIRST_EXCEPTION) and done:
- if any(f for f in done
- if not f.cancelled() and f.exception() is not None):
- return DoneAndNotDoneFutures(done, not_done)
-
- if len(done) == len(fs):
- return DoneAndNotDoneFutures(done, not_done)
-
- waiter = _create_and_install_waiters(fs, return_when)
-
- waiter.event.wait(timeout)
- for f in fs:
- with f._condition:
- f._waiters.remove(waiter)
-
- done.update(waiter.finished_futures)
- return DoneAndNotDoneFutures(done, set(fs) - done)
-
-class Future(object):
- """Represents the result of an asynchronous computation."""
-
- def __init__(self):
- """Initializes the future. Should not be called by clients."""
- self._condition = threading.Condition()
- self._state = PENDING
- self._result = None
- self._exception = None
- self._traceback = None
- self._waiters = []
- self._done_callbacks = []
-
- def _invoke_callbacks(self):
- for callback in self._done_callbacks:
- try:
- callback(self)
- except Exception:
- LOGGER.exception('exception calling callback for %r', self)
- except BaseException:
- # Explicitly let all other new-style exceptions through so
- # that we can catch all old-style exceptions with a simple
- # "except:" clause below.
- #
- # All old-style exception objects are instances of
- # types.InstanceType, but "except types.InstanceType:" does
- # not catch old-style exceptions for some reason. Thus, the
- # only way to catch all old-style exceptions without catching
- # any new-style exceptions is to filter out the new-style
- # exceptions, which all derive from BaseException.
- raise
- except:
- # Because of the BaseException clause above, this handler only
- # executes for old-style exception objects.
- LOGGER.exception('exception calling callback for %r', self)
-
- def __repr__(self):
- with self._condition:
- if self._state == FINISHED:
- if self._exception:
- return '<%s at %#x state=%s raised %s>' % (
- self.__class__.__name__,
- id(self),
- _STATE_TO_DESCRIPTION_MAP[self._state],
- self._exception.__class__.__name__)
- else:
- return '<%s at %#x state=%s returned %s>' % (
- self.__class__.__name__,
- id(self),
- _STATE_TO_DESCRIPTION_MAP[self._state],
- self._result.__class__.__name__)
- return '<%s at %#x state=%s>' % (
- self.__class__.__name__,
- id(self),
- _STATE_TO_DESCRIPTION_MAP[self._state])
-
- def cancel(self):
- """Cancel the future if possible.
-
- Returns True if the future was cancelled, False otherwise. A future
- cannot be cancelled if it is running or has already completed.
- """
- with self._condition:
- if self._state in [RUNNING, FINISHED]:
- return False
-
- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
- return True
-
- self._state = CANCELLED
- self._condition.notify_all()
-
- self._invoke_callbacks()
- return True
-
- def cancelled(self):
- """Return True if the future was cancelled."""
- with self._condition:
- return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]
-
- def running(self):
- """Return True if the future is currently executing."""
- with self._condition:
- return self._state == RUNNING
-
- def done(self):
- """Return True of the future was cancelled or finished executing."""
- with self._condition:
- return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]
-
- def __get_result(self):
- if self._exception:
- if isinstance(self._exception, types.InstanceType):
- # The exception is an instance of an old-style class, which
- # means type(self._exception) returns types.ClassType instead
- # of the exception's actual class type.
- exception_type = self._exception.__class__
- else:
- exception_type = type(self._exception)
- raise exception_type, self._exception, self._traceback
- else:
- return self._result
-
- def add_done_callback(self, fn):
- """Attaches a callable that will be called when the future finishes.
-
- Args:
- fn: A callable that will be called with this future as its only
- argument when the future completes or is cancelled. The callable
- will always be called by a thread in the same process in which
- it was added. If the future has already completed or been
- cancelled then the callable will be called immediately. These
- callables are called in the order that they were added.
- """
- with self._condition:
- if self._state not in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]:
- self._done_callbacks.append(fn)
- return
- fn(self)
-
- def result(self, timeout=None):
- """Return the result of the call that the future represents.
-
- Args:
- timeout: The number of seconds to wait for the result if the future
- isn't done. If None, then there is no limit on the wait time.
-
- Returns:
- The result of the call that the future represents.
-
- Raises:
- CancelledError: If the future was cancelled.
- TimeoutError: If the future didn't finish executing before the given
- timeout.
- Exception: If the call raised then that exception will be raised.
- """
- with self._condition:
- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
- raise CancelledError()
- elif self._state == FINISHED:
- return self.__get_result()
-
- self._condition.wait(timeout)
-
- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
- raise CancelledError()
- elif self._state == FINISHED:
- return self.__get_result()
- else:
- raise TimeoutError()
-
- def exception_info(self, timeout=None):
- """Return a tuple of (exception, traceback) raised by the call that the
- future represents.
-
- Args:
- timeout: The number of seconds to wait for the exception if the
- future isn't done. If None, then there is no limit on the wait
- time.
-
- Returns:
- The exception raised by the call that the future represents or None
- if the call completed without raising.
-
- Raises:
- CancelledError: If the future was cancelled.
- TimeoutError: If the future didn't finish executing before the given
- timeout.
- """
- with self._condition:
- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
- raise CancelledError()
- elif self._state == FINISHED:
- return self._exception, self._traceback
-
- self._condition.wait(timeout)
-
- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
- raise CancelledError()
- elif self._state == FINISHED:
- return self._exception, self._traceback
- else:
- raise TimeoutError()
-
- def exception(self, timeout=None):
- """Return the exception raised by the call that the future represents.
-
- Args:
- timeout: The number of seconds to wait for the exception if the
- future isn't done. If None, then there is no limit on the wait
- time.
-
- Returns:
- The exception raised by the call that the future represents or None
- if the call completed without raising.
-
- Raises:
- CancelledError: If the future was cancelled.
- TimeoutError: If the future didn't finish executing before the given
- timeout.
- """
- return self.exception_info(timeout)[0]
-
- # The following methods should only be used by Executors and in tests.
- def set_running_or_notify_cancel(self):
- """Mark the future as running or process any cancel notifications.
-
- Should only be used by Executor implementations and unit tests.
-
- If the future has been cancelled (cancel() was called and returned
- True) then any threads waiting on the future completing (though calls
- to as_completed() or wait()) are notified and False is returned.
-
- If the future was not cancelled then it is put in the running state
- (future calls to running() will return True) and True is returned.
-
- This method should be called by Executor implementations before
- executing the work associated with this future. If this method returns
- False then the work should not be executed.
-
- Returns:
- False if the Future was cancelled, True otherwise.
-
- Raises:
- RuntimeError: if this method was already called or if set_result()
- or set_exception() was called.
- """
- with self._condition:
- if self._state == CANCELLED:
- self._state = CANCELLED_AND_NOTIFIED
- for waiter in self._waiters:
- waiter.add_cancelled(self)
- # self._condition.notify_all() is not necessary because
- # self.cancel() triggers a notification.
- return False
- elif self._state == PENDING:
- self._state = RUNNING
- return True
- else:
- LOGGER.critical('Future %s in unexpected state: %s',
- id(self),
- self._state)
- raise RuntimeError('Future in unexpected state')
-
- def set_result(self, result):
- """Sets the return value of work associated with the future.
-
- Should only be used by Executor implementations and unit tests.
- """
- with self._condition:
- self._result = result
- self._state = FINISHED
- for waiter in self._waiters:
- waiter.add_result(self)
- self._condition.notify_all()
- self._invoke_callbacks()
-
- def set_exception_info(self, exception, traceback):
- """Sets the result of the future as being the given exception
- and traceback.
-
- Should only be used by Executor implementations and unit tests.
- """
- with self._condition:
- self._exception = exception
- self._traceback = traceback
- self._state = FINISHED
- for waiter in self._waiters:
- waiter.add_exception(self)
- self._condition.notify_all()
- self._invoke_callbacks()
-
- def set_exception(self, exception):
- """Sets the result of the future as being the given exception.
-
- Should only be used by Executor implementations and unit tests.
- """
- self.set_exception_info(exception, None)
-
-class Executor(object):
- """This is an abstract base class for concrete asynchronous executors."""
-
- def submit(self, fn, *args, **kwargs):
- """Submits a callable to be executed with the given arguments.
-
- Schedules the callable to be executed as fn(*args, **kwargs) and returns
- a Future instance representing the execution of the callable.
-
- Returns:
- A Future representing the given call.
- """
- raise NotImplementedError()
-
- def map(self, fn, *iterables, **kwargs):
- """Returns an iterator equivalent to map(fn, iter).
-
- Args:
- fn: A callable that will take as many arguments as there are
- passed iterables.
- timeout: The maximum number of seconds to wait. If None, then there
- is no limit on the wait time.
-
- Returns:
- An iterator equivalent to: map(func, *iterables) but the calls may
- be evaluated out-of-order.
-
- Raises:
- TimeoutError: If the entire result iterator could not be generated
- before the given timeout.
- Exception: If fn(*args) raises for any values.
- """
- timeout = kwargs.get('timeout')
- if timeout is not None:
- end_time = timeout + time.time()
-
- fs = [self.submit(fn, *args) for args in itertools.izip(*iterables)]
-
- # Yield must be hidden in closure so that the futures are submitted
- # before the first iterator value is required.
- def result_iterator():
- try:
- # reverse to keep finishing order
- fs.reverse()
- while fs:
- # Careful not to keep a reference to the popped future
- if timeout is None:
- yield fs.pop().result()
- else:
- yield fs.pop().result(end_time - time.time())
- finally:
- for future in fs:
- future.cancel()
- return result_iterator()
-
- def shutdown(self, wait=True):
- """Clean-up the resources associated with the Executor.
-
- It is safe to call this method several times. Otherwise, no other
- methods can be called after this one.
-
- Args:
- wait: If True then shutdown will not return until all running
- futures have finished executing and the resources used by the
- executor have been reclaimed.
- """
- pass
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.shutdown(wait=True)
- return False
+++ /dev/null
-# Copyright 2009 Brian Quinlan. All Rights Reserved.
-# Licensed to PSF under a Contributor Agreement.
-
-"""Implements ProcessPoolExecutor.
-
-The follow diagram and text describe the data-flow through the system:
-
-|======================= In-process =====================|== Out-of-process ==|
-
-+----------+ +----------+ +--------+ +-----------+ +---------+
-| | => | Work Ids | => | | => | Call Q | => | |
-| | +----------+ | | +-----------+ | |
-| | | ... | | | | ... | | |
-| | | 6 | | | | 5, call() | | |
-| | | 7 | | | | ... | | |
-| Process | | ... | | Local | +-----------+ | Process |
-| Pool | +----------+ | Worker | | #1..n |
-| Executor | | Thread | | |
-| | +----------- + | | +-----------+ | |
-| | <=> | Work Items | <=> | | <= | Result Q | <= | |
-| | +------------+ | | +-----------+ | |
-| | | 6: call() | | | | ... | | |
-| | | future | | | | 4, result | | |
-| | | ... | | | | 3, except | | |
-+----------+ +------------+ +--------+ +-----------+ +---------+
-
-Executor.submit() called:
-- creates a uniquely numbered _WorkItem and adds it to the "Work Items" dict
-- adds the id of the _WorkItem to the "Work Ids" queue
-
-Local worker thread:
-- reads work ids from the "Work Ids" queue and looks up the corresponding
- WorkItem from the "Work Items" dict: if the work item has been cancelled then
- it is simply removed from the dict, otherwise it is repackaged as a
- _CallItem and put in the "Call Q". New _CallItems are put in the "Call Q"
- until "Call Q" is full. NOTE: the size of the "Call Q" is kept small because
- calls placed in the "Call Q" can no longer be cancelled with Future.cancel().
-- reads _ResultItems from "Result Q", updates the future stored in the
- "Work Items" dict and deletes the dict entry
-
-Process #1..n:
-- reads _CallItems from "Call Q", executes the calls, and puts the resulting
- _ResultItems in "Request Q"
-"""
-
-import atexit
-from concurrent.futures import _base
-import Queue as queue
-import multiprocessing
-import threading
-import weakref
-import sys
-
-__author__ = 'Brian Quinlan (brian@sweetapp.com)'
-
-# Workers are created as daemon threads and processes. This is done to allow the
-# interpreter to exit when there are still idle processes in a
-# ProcessPoolExecutor's process pool (i.e. shutdown() was not called). However,
-# allowing workers to die with the interpreter has two undesirable properties:
-# - The workers would still be running during interpretor shutdown,
-# meaning that they would fail in unpredictable ways.
-# - The workers could be killed while evaluating a work item, which could
-# be bad if the callable being evaluated has external side-effects e.g.
-# writing to a file.
-#
-# To work around this problem, an exit handler is installed which tells the
-# workers to exit when their work queues are empty and then waits until the
-# threads/processes finish.
-
-_threads_queues = weakref.WeakKeyDictionary()
-_shutdown = False
-
-def _python_exit():
- global _shutdown
- _shutdown = True
- items = list(_threads_queues.items()) if _threads_queues else ()
- for t, q in items:
- q.put(None)
- for t, q in items:
- t.join(sys.maxint)
-
-# Controls how many more calls than processes will be queued in the call queue.
-# A smaller number will mean that processes spend more time idle waiting for
-# work while a larger number will make Future.cancel() succeed less frequently
-# (Futures in the call queue cannot be cancelled).
-EXTRA_QUEUED_CALLS = 1
-
-class _WorkItem(object):
- def __init__(self, future, fn, args, kwargs):
- self.future = future
- self.fn = fn
- self.args = args
- self.kwargs = kwargs
-
-class _ResultItem(object):
- def __init__(self, work_id, exception=None, result=None):
- self.work_id = work_id
- self.exception = exception
- self.result = result
-
-class _CallItem(object):
- def __init__(self, work_id, fn, args, kwargs):
- self.work_id = work_id
- self.fn = fn
- self.args = args
- self.kwargs = kwargs
-
-def _process_worker(call_queue, result_queue):
- """Evaluates calls from call_queue and places the results in result_queue.
-
- This worker is run in a separate process.
-
- Args:
- call_queue: A multiprocessing.Queue of _CallItems that will be read and
- evaluated by the worker.
- result_queue: A multiprocessing.Queue of _ResultItems that will written
- to by the worker.
- shutdown: A multiprocessing.Event that will be set as a signal to the
- worker that it should exit when call_queue is empty.
- """
- while True:
- call_item = call_queue.get(block=True)
- if call_item is None:
- # Wake up queue management thread
- result_queue.put(None)
- return
- try:
- r = call_item.fn(*call_item.args, **call_item.kwargs)
- except:
- e = sys.exc_info()[1]
- result_queue.put(_ResultItem(call_item.work_id,
- exception=e))
- else:
- result_queue.put(_ResultItem(call_item.work_id,
- result=r))
-
-def _add_call_item_to_queue(pending_work_items,
- work_ids,
- call_queue):
- """Fills call_queue with _WorkItems from pending_work_items.
-
- This function never blocks.
-
- Args:
- pending_work_items: A dict mapping work ids to _WorkItems e.g.
- {5: <_WorkItem...>, 6: <_WorkItem...>, ...}
- work_ids: A queue.Queue of work ids e.g. Queue([5, 6, ...]). Work ids
- are consumed and the corresponding _WorkItems from
- pending_work_items are transformed into _CallItems and put in
- call_queue.
- call_queue: A multiprocessing.Queue that will be filled with _CallItems
- derived from _WorkItems.
- """
- while True:
- if call_queue.full():
- return
- try:
- work_id = work_ids.get(block=False)
- except queue.Empty:
- return
- else:
- work_item = pending_work_items[work_id]
-
- if work_item.future.set_running_or_notify_cancel():
- call_queue.put(_CallItem(work_id,
- work_item.fn,
- work_item.args,
- work_item.kwargs),
- block=True)
- else:
- del pending_work_items[work_id]
- continue
-
-def _queue_management_worker(executor_reference,
- processes,
- pending_work_items,
- work_ids_queue,
- call_queue,
- result_queue):
- """Manages the communication between this process and the worker processes.
-
- This function is run in a local thread.
-
- Args:
- executor_reference: A weakref.ref to the ProcessPoolExecutor that owns
- this thread. Used to determine if the ProcessPoolExecutor has been
- garbage collected and that this function can exit.
- process: A list of the multiprocessing.Process instances used as
- workers.
- pending_work_items: A dict mapping work ids to _WorkItems e.g.
- {5: <_WorkItem...>, 6: <_WorkItem...>, ...}
- work_ids_queue: A queue.Queue of work ids e.g. Queue([5, 6, ...]).
- call_queue: A multiprocessing.Queue that will be filled with _CallItems
- derived from _WorkItems for processing by the process workers.
- result_queue: A multiprocessing.Queue of _ResultItems generated by the
- process workers.
- """
- nb_shutdown_processes = [0]
- def shutdown_one_process():
- """Tell a worker to terminate, which will in turn wake us again"""
- call_queue.put(None)
- nb_shutdown_processes[0] += 1
- while True:
- _add_call_item_to_queue(pending_work_items,
- work_ids_queue,
- call_queue)
-
- result_item = result_queue.get(block=True)
- if result_item is not None:
- work_item = pending_work_items[result_item.work_id]
- del pending_work_items[result_item.work_id]
-
- if result_item.exception:
- work_item.future.set_exception(result_item.exception)
- else:
- work_item.future.set_result(result_item.result)
- # Delete references to object. See issue16284
- del work_item
- # Check whether we should start shutting down.
- executor = executor_reference()
- # No more work items can be added if:
- # - The interpreter is shutting down OR
- # - The executor that owns this worker has been collected OR
- # - The executor that owns this worker has been shutdown.
- if _shutdown or executor is None or executor._shutdown_thread:
- # Since no new work items can be added, it is safe to shutdown
- # this thread if there are no pending work items.
- if not pending_work_items:
- while nb_shutdown_processes[0] < len(processes):
- shutdown_one_process()
- # If .join() is not called on the created processes then
- # some multiprocessing.Queue methods may deadlock on Mac OS
- # X.
- for p in processes:
- p.join()
- call_queue.close()
- return
- del executor
-
-_system_limits_checked = False
-_system_limited = None
-def _check_system_limits():
- global _system_limits_checked, _system_limited
- if _system_limits_checked:
- if _system_limited:
- raise NotImplementedError(_system_limited)
- _system_limits_checked = True
- try:
- import os
- nsems_max = os.sysconf("SC_SEM_NSEMS_MAX")
- except (AttributeError, ValueError):
- # sysconf not available or setting not available
- return
- if nsems_max == -1:
- # indetermine limit, assume that limit is determined
- # by available memory only
- return
- if nsems_max >= 256:
- # minimum number of semaphores available
- # according to POSIX
- return
- _system_limited = "system provides too few semaphores (%d available, 256 necessary)" % nsems_max
- raise NotImplementedError(_system_limited)
-
-
-class ProcessPoolExecutor(_base.Executor):
- def __init__(self, max_workers=None):
- """Initializes a new ProcessPoolExecutor instance.
-
- Args:
- max_workers: The maximum number of processes that can be used to
- execute the given calls. If None or not given then as many
- worker processes will be created as the machine has processors.
- """
- _check_system_limits()
-
- if max_workers is None:
- self._max_workers = multiprocessing.cpu_count()
- else:
- if max_workers <= 0:
- raise ValueError("max_workers must be greater than 0")
-
- self._max_workers = max_workers
-
- # Make the call queue slightly larger than the number of processes to
- # prevent the worker processes from idling. But don't make it too big
- # because futures in the call queue cannot be cancelled.
- self._call_queue = multiprocessing.Queue(self._max_workers +
- EXTRA_QUEUED_CALLS)
- self._result_queue = multiprocessing.Queue()
- self._work_ids = queue.Queue()
- self._queue_management_thread = None
- self._processes = set()
-
- # Shutdown is a two-step process.
- self._shutdown_thread = False
- self._shutdown_lock = threading.Lock()
- self._queue_count = 0
- self._pending_work_items = {}
-
- def _start_queue_management_thread(self):
- # When the executor gets lost, the weakref callback will wake up
- # the queue management thread.
- def weakref_cb(_, q=self._result_queue):
- q.put(None)
- if self._queue_management_thread is None:
- self._queue_management_thread = threading.Thread(
- target=_queue_management_worker,
- args=(weakref.ref(self, weakref_cb),
- self._processes,
- self._pending_work_items,
- self._work_ids,
- self._call_queue,
- self._result_queue))
- self._queue_management_thread.daemon = True
- self._queue_management_thread.start()
- _threads_queues[self._queue_management_thread] = self._result_queue
-
- def _adjust_process_count(self):
- for _ in range(len(self._processes), self._max_workers):
- p = multiprocessing.Process(
- target=_process_worker,
- args=(self._call_queue,
- self._result_queue))
- p.start()
- self._processes.add(p)
-
- def submit(self, fn, *args, **kwargs):
- with self._shutdown_lock:
- if self._shutdown_thread:
- raise RuntimeError('cannot schedule new futures after shutdown')
-
- f = _base.Future()
- w = _WorkItem(f, fn, args, kwargs)
-
- self._pending_work_items[self._queue_count] = w
- self._work_ids.put(self._queue_count)
- self._queue_count += 1
- # Wake up queue management thread
- self._result_queue.put(None)
-
- self._start_queue_management_thread()
- self._adjust_process_count()
- return f
- submit.__doc__ = _base.Executor.submit.__doc__
-
- def shutdown(self, wait=True):
- with self._shutdown_lock:
- self._shutdown_thread = True
- if self._queue_management_thread:
- # Wake up queue management thread
- self._result_queue.put(None)
- if wait:
- self._queue_management_thread.join(sys.maxint)
- # To reduce the risk of openning too many files, remove references to
- # objects that use file descriptors.
- self._queue_management_thread = None
- self._call_queue = None
- self._result_queue = None
- self._processes = None
- shutdown.__doc__ = _base.Executor.shutdown.__doc__
-
-atexit.register(_python_exit)
+++ /dev/null
-# Copyright 2009 Brian Quinlan. All Rights Reserved.
-# Licensed to PSF under a Contributor Agreement.
-
-"""Implements ThreadPoolExecutor."""
-
-import atexit
-from concurrent.futures import _base
-import itertools
-import Queue as queue
-import threading
-import weakref
-import sys
-
-try:
- from multiprocessing import cpu_count
-except ImportError:
- # some platforms don't have multiprocessing
- def cpu_count():
- return None
-
-__author__ = 'Brian Quinlan (brian@sweetapp.com)'
-
-# Workers are created as daemon threads. This is done to allow the interpreter
-# to exit when there are still idle threads in a ThreadPoolExecutor's thread
-# pool (i.e. shutdown() was not called). However, allowing workers to die with
-# the interpreter has two undesirable properties:
-# - The workers would still be running during interpretor shutdown,
-# meaning that they would fail in unpredictable ways.
-# - The workers could be killed while evaluating a work item, which could
-# be bad if the callable being evaluated has external side-effects e.g.
-# writing to a file.
-#
-# To work around this problem, an exit handler is installed which tells the
-# workers to exit when their work queues are empty and then waits until the
-# threads finish.
-
-_threads_queues = weakref.WeakKeyDictionary()
-_shutdown = False
-
-def _python_exit():
- global _shutdown
- _shutdown = True
- items = list(_threads_queues.items()) if _threads_queues else ()
- for t, q in items:
- q.put(None)
- for t, q in items:
- t.join(sys.maxint)
-
-atexit.register(_python_exit)
-
-class _WorkItem(object):
- def __init__(self, future, fn, args, kwargs):
- self.future = future
- self.fn = fn
- self.args = args
- self.kwargs = kwargs
-
- def run(self):
- if not self.future.set_running_or_notify_cancel():
- return
-
- try:
- result = self.fn(*self.args, **self.kwargs)
- except:
- e, tb = sys.exc_info()[1:]
- self.future.set_exception_info(e, tb)
- else:
- self.future.set_result(result)
-
-def _worker(executor_reference, work_queue):
- try:
- while True:
- work_item = work_queue.get(block=True)
- if work_item is not None:
- work_item.run()
- # Delete references to object. See issue16284
- del work_item
-
- # attempt to increment idle count
- executor = executor_reference()
- if executor is not None:
- executor._idle_semaphore.release()
- del executor
- continue
- executor = executor_reference()
- # Exit if:
- # - The interpreter is shutting down OR
- # - The executor that owns the worker has been collected OR
- # - The executor that owns the worker has been shutdown.
- if _shutdown or executor is None or executor._shutdown:
- # Notice other workers
- work_queue.put(None)
- return
- del executor
- except:
- _base.LOGGER.critical('Exception in worker', exc_info=True)
-
-
-class ThreadPoolExecutor(_base.Executor):
-
- # Used to assign unique thread names when thread_name_prefix is not supplied.
- _counter = itertools.count().next
-
- def __init__(self, max_workers=None, thread_name_prefix=''):
- """Initializes a new ThreadPoolExecutor instance.
-
- Args:
- max_workers: The maximum number of threads that can be used to
- execute the given calls.
- thread_name_prefix: An optional name prefix to give our threads.
- """
- if max_workers is None:
- # Use this number because ThreadPoolExecutor is often
- # used to overlap I/O instead of CPU work.
- max_workers = (cpu_count() or 1) * 5
- if max_workers <= 0:
- raise ValueError("max_workers must be greater than 0")
-
- self._max_workers = max_workers
- self._work_queue = queue.Queue()
- self._idle_semaphore = threading.Semaphore(0)
- self._threads = set()
- self._shutdown = False
- self._shutdown_lock = threading.Lock()
- self._thread_name_prefix = (thread_name_prefix or
- ("ThreadPoolExecutor-%d" % self._counter()))
-
- def submit(self, fn, *args, **kwargs):
- with self._shutdown_lock:
- if self._shutdown:
- raise RuntimeError('cannot schedule new futures after shutdown')
-
- f = _base.Future()
- w = _WorkItem(f, fn, args, kwargs)
-
- self._work_queue.put(w)
- self._adjust_thread_count()
- return f
- submit.__doc__ = _base.Executor.submit.__doc__
-
- def _adjust_thread_count(self):
- # if idle threads are available, don't spin new threads
- if self._idle_semaphore.acquire(False):
- return
-
- # When the executor gets lost, the weakref callback will wake up
- # the worker threads.
- def weakref_cb(_, q=self._work_queue):
- q.put(None)
-
- num_threads = len(self._threads)
- if num_threads < self._max_workers:
- thread_name = '%s_%d' % (self._thread_name_prefix or self,
- num_threads)
- t = threading.Thread(name=thread_name, target=_worker,
- args=(weakref.ref(self, weakref_cb),
- self._work_queue))
- t.daemon = True
- t.start()
- self._threads.add(t)
- _threads_queues[t] = self._work_queue
-
- def shutdown(self, wait=True):
- with self._shutdown_lock:
- self._shutdown = True
- self._work_queue.put(None)
- if wait:
- for t in self._threads:
- t.join(sys.maxint)
- shutdown.__doc__ = _base.Executor.shutdown.__doc__
+++ /dev/null
-PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
---------------------------------------------
-
-1. This LICENSE AGREEMENT is between the Python Software Foundation
-("PSF"), and the Individual or Organization ("Licensee") accessing and
-otherwise using this software ("Python") in source or binary form and
-its associated documentation.
-
-2. Subject to the terms and conditions of this License Agreement, PSF
-hereby grants Licensee a nonexclusive, royalty-free, world-wide
-license to reproduce, analyze, test, perform and/or display publicly,
-prepare derivative works, distribute, and otherwise use Python
-alone or in any derivative version, provided, however, that PSF's
-License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
-2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights
-Reserved" are retained in Python alone or in any derivative version
-prepared by Licensee.
-
-3. In the event Licensee prepares a derivative work that is based on
-or incorporates Python or any part thereof, and wants to make
-the derivative work available to others as provided herein, then
-Licensee hereby agrees to include in any such work a brief summary of
-the changes made to Python.
-
-4. PSF is making Python available to Licensee on an "AS IS"
-basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
-IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
-DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
-FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
-INFRINGE ANY THIRD PARTY RIGHTS.
-
-5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
-FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
-A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
-OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
-
-6. This License Agreement will automatically terminate upon a material
-breach of its terms and conditions.
-
-7. Nothing in this License Agreement shall be deemed to create any
-relationship of agency, partnership, or joint venture between PSF and
-Licensee. This License Agreement does not grant permission to use PSF
-trademarks or trade name in a trademark sense to endorse or promote
-products or services of Licensee, or any third party.
-
-8. By copying, installing or otherwise using Python, Licensee
-agrees to be bound by the terms and conditions of this License
-Agreement.
+++ /dev/null
-Metadata-Version: 2.1
-Name: futures
-Version: 3.3.0
-Summary: Backport of the concurrent.futures package from Python 3
-Home-page: https://github.com/agronholm/pythonfutures
-Author: Brian Quinlan
-Author-email: brian@sweetapp.com
-Maintainer: Alex Grönholm
-Maintainer-email: alex.gronholm@nextday.fi
-License: PSF
-Platform: UNKNOWN
-Classifier: License :: OSI Approved :: Python Software Foundation License
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 2 :: Only
-Requires-Python: >=2.6, <3
-
-.. image:: https://travis-ci.org/agronholm/pythonfutures.svg?branch=master
- :target: https://travis-ci.org/agronholm/pythonfutures
- :alt: Build Status
-
-This is a backport of the `concurrent.futures`_ standard library module to Python 2.
-
-It **does not** work on Python 3 due to Python 2 syntax being used in the codebase.
-Python 3 users should not attempt to install it, since the package is already included in the
-standard library.
-
-To conditionally require this library only on Python 2, you can do this in your ``setup.py``:
-
-.. code-block:: python
-
- setup(
- ...
- extras_require={
- ':python_version == "2.7"': ['futures']
- }
- )
-
-Or, using the newer syntax:
-
-.. code-block:: python
-
- setup(
- ...
- install_requires={
- 'futures; python_version == "2.7"'
- }
- )
-
-.. warning:: The ``ProcessPoolExecutor`` class has known (unfixable) problems on Python 2 and
- should not be relied on for mission critical work. Please see `Issue 29 <https://github.com/agronholm/pythonfutures/issues/29>`_ and `upstream bug report <https://bugs.python.org/issue9205>`_ for more details.
-
-.. _concurrent.futures: https://docs.python.org/library/concurrent.futures.html
-
-
+++ /dev/null
-concurrent/__init__.py,sha256=qEFeq3yuf3lQKVseALmL8aPM8fpCS54B_5pry00M3hk,76\r
-concurrent/__init__.pyc,,\r
-concurrent/futures/__init__.py,sha256=lErVwp1Kv_co1PKmfYCHvBhWZ_ONtg-bk9v74BG1Q8w,887\r
-concurrent/futures/__init__.pyc,,\r
-concurrent/futures/_base.py,sha256=7SaxfmjweeKgw5bYMqCE09V_w4Q0A7N5MtcFdyV8ypI,23798\r
-concurrent/futures/_base.pyc,,\r
-concurrent/futures/process.py,sha256=XWNXGq8Pgnt__2Yz49bCV9dyuaWiZLlkRwt4IQMKaOQ,14986\r
-concurrent/futures/process.pyc,,\r
-concurrent/futures/thread.py,sha256=l5xiZysJdECLjizJmixi8xQj4iCWcpvGnoUiXpJTRhc,5923\r
-concurrent/futures/thread.pyc,,\r
-futures-3.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4\r
-futures-3.3.0.dist-info/LICENSE,sha256=ppi9XUQeShavbJkrjoDL-hJ1XXLZEIVPofsR1N6wBZo,2395\r
-futures-3.3.0.dist-info/METADATA,sha256=ruUlmMgekwudpLJ8s0fW5FMaGFbqSXmTRYq9ejavcP0,1915\r
-futures-3.3.0.dist-info/RECORD,,\r
-futures-3.3.0.dist-info/WHEEL,sha256=Ph_z28wTcU7HnQwSQ6yCQ-zkcGK4h4ehDfP8b6UoHVE,92\r
-futures-3.3.0.dist-info/top_level.txt,sha256=elL7bzFlkyVZr3M0gg0AeLUPt5OJ2F9uJcmu63VMt7A,11\r
+++ /dev/null
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.33.4)
-Root-Is-Purelib: true
-Tag: py2-none-any
-
+++ /dev/null
-concurrent
+++ /dev/null
-Original Authors
-----------------
-* Armin Rigo
-* Christian Tismer
-
-Contributors
-------------
-* Al Stone
-* Alexander Schmidt
-* Alexey Borzenkov
-* Andreas Schwab
-* Armin Ronacher
-* Bin Wang <feisuzhu@163.com>
-* Bob Ippolito
-* ChangBo Guo
-* Christoph Gohlke
-* Denis Bilenko
-* Dirk Mueller
-* Donovan Preston
-* Fantix King
-* Floris Bruynooghe
-* Fredrik Fornwall
-* Gerd Woetzel
-* Giel van Schijndel
-* Gökhan Karabulut
-* Gustavo Niemeyer
-* Guy Rozendorn
-* Hye-Shik Chang
-* Jared Kuolt
-* Jason Madden
-* Josh Snyder
-* Kyle Ambroff
-* Laszlo Boszormenyi
-* Mao Han
-* Marc Abramowitz
-* Marc Schlaich
-* Marcin Bachry
-* Matt Madison
-* Matt Turner
-* Michael Ellerman
-* Michael Matz
-* Ralf Schmitt
-* Robie Basak
-* Ronny Pfannschmidt
-* Samual M. Rushing
-* Tony Bowles
-* Tony Breeds
-* Trevor Bowen
-* Tulio Magno Quites Machado Filho
-* Ulrich Weigand
-* Victor Stinner
+++ /dev/null
-The following files are derived from Stackless Python and are subject to the
-same license as Stackless Python:
-
- slp_platformselect.h
- files in platform/ directory
-
-See LICENSE.PSF and http://www.stackless.com/ for details.
-
-Unless otherwise noted, the files in greenlet have been released under the
-following MIT license:
-
-Copyright (c) Armin Rigo, Christian Tismer and contributors
-
-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.
+++ /dev/null
-PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
---------------------------------------------
-
-1. This LICENSE AGREEMENT is between the Python Software Foundation
-("PSF"), and the Individual or Organization ("Licensee") accessing and
-otherwise using this software ("Python") in source or binary form and
-its associated documentation.
-
-2. Subject to the terms and conditions of this License Agreement, PSF hereby
-grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
-analyze, test, perform and/or display publicly, prepare derivative works,
-distribute, and otherwise use Python alone or in any derivative version,
-provided, however, that PSF's License Agreement and PSF's notice of copyright,
-i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-2011 Python Software Foundation; All Rights Reserved" are retained in Python
-alone or in any derivative version prepared by Licensee.
-
-3. In the event Licensee prepares a derivative work that is based on
-or incorporates Python or any part thereof, and wants to make
-the derivative work available to others as provided herein, then
-Licensee hereby agrees to include in any such work a brief summary of
-the changes made to Python.
-
-4. PSF is making Python available to Licensee on an "AS IS"
-basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
-IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
-DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
-FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
-INFRINGE ANY THIRD PARTY RIGHTS.
-
-5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
-FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
-A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
-OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
-
-6. This License Agreement will automatically terminate upon a material
-breach of its terms and conditions.
-
-7. Nothing in this License Agreement shall be deemed to create any
-relationship of agency, partnership, or joint venture between PSF and
-Licensee. This License Agreement does not grant permission to use PSF
-trademarks or trade name in a trademark sense to endorse or promote
-products or services of Licensee, or any third party.
-
-8. By copying, installing or otherwise using Python, Licensee
-agrees to be bound by the terms and conditions of this License
-Agreement.
+++ /dev/null
-Metadata-Version: 2.1
-Name: greenlet
-Version: 0.4.17
-Summary: Lightweight in-process concurrent programming
-Home-page: https://github.com/python-greenlet/greenlet
-Author: UNKNOWN
-Author-email: UNKNOWN
-License: MIT License
-Platform: any
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Natural Language :: English
-Classifier: Programming Language :: C
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.4
-Classifier: Programming Language :: Python :: 2.5
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.0
-Classifier: Programming Language :: Python :: 3.1
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Operating System :: OS Independent
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-
-.. image:: https://secure.travis-ci.org/python-greenlet/greenlet.png
- :target: http://travis-ci.org/python-greenlet/greenlet
-
-The greenlet package is a spin-off of Stackless, a version of CPython
-that supports micro-threads called "tasklets". Tasklets run
-pseudo-concurrently (typically in a single or a few OS-level threads)
-and are synchronized with data exchanges on "channels".
-
-A "greenlet", on the other hand, is a still more primitive notion of
-micro-thread with no implicit scheduling; coroutines, in other
-words. This is useful when you want to control exactly when your code
-runs. You can build custom scheduled micro-threads on top of greenlet;
-however, it seems that greenlets are useful on their own as a way to
-make advanced control flow structures. For example, we can recreate
-generators; the difference with Python's own generators is that our
-generators can call nested functions and the nested functions can
-yield values too. Additionally, you don't need a "yield" keyword. See
-the example in tests/test_generator.py.
-
-Greenlets are provided as a C extension module for the regular
-unmodified interpreter.
-
-Greenlets are lightweight coroutines for in-process concurrent
-programming.
-
-Who is using Greenlet?
-======================
-
-There are several libraries that use Greenlet as a more flexible
-alternative to Python's built in coroutine support:
-
- - `Concurrence`_
- - `Eventlet`_
- - `Gevent`_
-
-.. _Concurrence: http://opensource.hyves.org/concurrence/
-.. _Eventlet: http://eventlet.net/
-.. _Gevent: http://www.gevent.org/
-
-Getting Greenlet
-================
-
-The easiest way to get Greenlet is to install it with pip or
-easy_install::
-
- pip install greenlet
- easy_install greenlet
-
-
-Source code archives and windows installers are available on the
-python package index at https://pypi.python.org/pypi/greenlet
-
-The source code repository is hosted on github:
-https://github.com/python-greenlet/greenlet
-
-Documentation is available on readthedocs.org:
-https://greenlet.readthedocs.io
-
-
+++ /dev/null
-../../../include/python2.7/greenlet/greenlet.h,sha256=lMxw5Z2sk1jjSXhqzBI13iCh4wQsv70PYnOVVam6kZI,4176\r
-greenlet-0.4.17.dist-info/AUTHORS,sha256=swW28t2knVRxRkaEQNZtO7MP9Sgnompb7B6cNgJM8Gk,849\r
-greenlet-0.4.17.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4\r
-greenlet-0.4.17.dist-info/LICENSE,sha256=u95V1UVqHpEmM-0_ZtHb2VBOPj3OT0wgFQQ83LxW5pc,1408\r
-greenlet-0.4.17.dist-info/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424\r
-greenlet-0.4.17.dist-info/METADATA,sha256=1JfIvgi_IrGEShdtXql0SnoBTO20gM-UFaAskiMksOg,3378\r
-greenlet-0.4.17.dist-info/RECORD,,\r
-greenlet-0.4.17.dist-info/WHEEL,sha256=v_WvMd9LcJo7UEU8YDntezoLIPEhS-iS69BF1ftVDNw,110\r
-greenlet-0.4.17.dist-info/top_level.txt,sha256=YSnRsCRoO61JGlP57o8iKL6rdLWDWuiyKD8ekpWUsDc,9\r
-greenlet.so,sha256=Rq5cYBkxxo_w_Q8CN741z3c3LZSt20-xraTKOPVfr44,98183\r
+++ /dev/null
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.34.2)
-Root-Is-Purelib: false
-Tag: cp27-cp27mu-manylinux1_x86_64
-
+++ /dev/null
-Metadata-Version: 1.0
-Name: neovim
-Version: 0.3.1
-Summary: Transition packgage for pynvim
-Home-page: http://github.com/neovim/python-client
-Author: Thiago de Arruda
-Author-email: tpadilha84@gmail.com
-License: Apache
-Description: UNKNOWN
-Platform: UNKNOWN
+++ /dev/null
-setup.cfg
-setup.py
-neovim.egg-info/PKG-INFO
-neovim.egg-info/SOURCES.txt
-neovim.egg-info/dependency_links.txt
-neovim.egg-info/not-zip-safe
-neovim.egg-info/requires.txt
-neovim.egg-info/top_level.txt
\ No newline at end of file
+++ /dev/null
-PKG-INFO
-SOURCES.txt
-dependency_links.txt
-not-zip-safe
-requires.txt
-top_level.txt
+++ /dev/null
-pynvim>=0.3.1
+++ /dev/null
-"""Python client for Nvim.
-
-This is a transition package. New projects should instead import pynvim package.
-"""
-import pynvim
-from pynvim import *
-
-__all__ = pynvim.__all__
+++ /dev/null
-"""Nvim API subpackage.
-
-This is a transition package. New projects should instead import pynvim.api.
-"""
-from pynvim import api
-from pynvim.api import *
-
-__all__ = api.__all__
+++ /dev/null
-Metadata-Version: 2.1
-Name: pynvim
-Version: 0.4.2
-Summary: Python client to neovim
-Home-page: http://github.com/neovim/pynvim
-Author: Thiago de Arruda
-Author-email: tpadilha84@gmail.com
-License: Apache
-Download-URL: https://github.com/neovim/pynvim/archive/0.4.2.tar.gz
-Description: UNKNOWN
-Platform: UNKNOWN
-Provides-Extra: pyuv
-Provides-Extra: test
+++ /dev/null
-LICENSE
-MANIFEST.in
-README.md
-setup.cfg
-setup.py
-neovim/__init__.py
-neovim/api/__init__.py
-pynvim/__init__.py
-pynvim/compat.py
-pynvim/util.py
-pynvim.egg-info/PKG-INFO
-pynvim.egg-info/SOURCES.txt
-pynvim.egg-info/dependency_links.txt
-pynvim.egg-info/not-zip-safe
-pynvim.egg-info/requires.txt
-pynvim.egg-info/top_level.txt
-pynvim/api/__init__.py
-pynvim/api/buffer.py
-pynvim/api/common.py
-pynvim/api/nvim.py
-pynvim/api/tabpage.py
-pynvim/api/window.py
-pynvim/msgpack_rpc/__init__.py
-pynvim/msgpack_rpc/async_session.py
-pynvim/msgpack_rpc/msgpack_stream.py
-pynvim/msgpack_rpc/session.py
-pynvim/msgpack_rpc/event_loop/__init__.py
-pynvim/msgpack_rpc/event_loop/asyncio.py
-pynvim/msgpack_rpc/event_loop/base.py
-pynvim/msgpack_rpc/event_loop/uv.py
-pynvim/plugin/__init__.py
-pynvim/plugin/decorators.py
-pynvim/plugin/host.py
-pynvim/plugin/script_host.py
-test/conftest.py
-test/test_buffer.py
-test/test_client_rpc.py
-test/test_concurrency.py
-test/test_decorators.py
-test/test_events.py
-test/test_host.py
-test/test_logging.py
-test/test_tabpage.py
-test/test_vim.py
-test/test_window.py
\ No newline at end of file
+++ /dev/null
-../neovim/__init__.py
-../neovim/__init__.pyc
-../neovim/api/__init__.py
-../neovim/api/__init__.pyc
-../pynvim/__init__.py
-../pynvim/__init__.pyc
-../pynvim/api/__init__.py
-../pynvim/api/__init__.pyc
-../pynvim/api/buffer.py
-../pynvim/api/buffer.pyc
-../pynvim/api/common.py
-../pynvim/api/common.pyc
-../pynvim/api/nvim.py
-../pynvim/api/nvim.pyc
-../pynvim/api/tabpage.py
-../pynvim/api/tabpage.pyc
-../pynvim/api/window.py
-../pynvim/api/window.pyc
-../pynvim/compat.py
-../pynvim/compat.pyc
-../pynvim/msgpack_rpc/__init__.py
-../pynvim/msgpack_rpc/__init__.pyc
-../pynvim/msgpack_rpc/async_session.py
-../pynvim/msgpack_rpc/async_session.pyc
-../pynvim/msgpack_rpc/event_loop/__init__.py
-../pynvim/msgpack_rpc/event_loop/__init__.pyc
-../pynvim/msgpack_rpc/event_loop/asyncio.py
-../pynvim/msgpack_rpc/event_loop/asyncio.pyc
-../pynvim/msgpack_rpc/event_loop/base.py
-../pynvim/msgpack_rpc/event_loop/base.pyc
-../pynvim/msgpack_rpc/event_loop/uv.py
-../pynvim/msgpack_rpc/event_loop/uv.pyc
-../pynvim/msgpack_rpc/msgpack_stream.py
-../pynvim/msgpack_rpc/msgpack_stream.pyc
-../pynvim/msgpack_rpc/session.py
-../pynvim/msgpack_rpc/session.pyc
-../pynvim/plugin/__init__.py
-../pynvim/plugin/__init__.pyc
-../pynvim/plugin/decorators.py
-../pynvim/plugin/decorators.pyc
-../pynvim/plugin/host.py
-../pynvim/plugin/host.pyc
-../pynvim/plugin/script_host.py
-../pynvim/plugin/script_host.pyc
-../pynvim/util.py
-../pynvim/util.pyc
-PKG-INFO
-SOURCES.txt
-dependency_links.txt
-not-zip-safe
-requires.txt
-top_level.txt
+++ /dev/null
-msgpack>=0.5.0
-trollius
-greenlet
-
-[pyuv]
-pyuv>=1.0.0
-
-[test]
-pytest>=3.4.0
+++ /dev/null
-neovim
-pynvim
+++ /dev/null
-"""Python client for Nvim.
-
-Client library for talking with Nvim processes via its msgpack-rpc API.
-"""
-import logging
-import os
-import sys
-
-from pynvim.api import Nvim, NvimError
-from pynvim.compat import IS_PYTHON3
-from pynvim.msgpack_rpc import (ErrorResponse, child_session, socket_session,
- stdio_session, tcp_session)
-from pynvim.plugin import (Host, autocmd, command, decode, encoding, function,
- plugin, rpc_export, shutdown_hook)
-from pynvim.util import VERSION, Version
-
-
-__all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
- 'start_host', 'autocmd', 'command', 'encoding', 'decode',
- 'function', 'plugin', 'rpc_export', 'Host', 'Nvim', 'NvimError',
- 'Version', 'VERSION', 'shutdown_hook', 'attach', 'setup_logging',
- 'ErrorResponse')
-
-
-def start_host(session=None):
- """Promote the current process into python plugin host for Nvim.
-
- Start msgpack-rpc event loop for `session`, listening for Nvim requests
- and notifications. It registers Nvim commands for loading/unloading
- python plugins.
-
- The sys.stdout and sys.stderr streams are redirected to Nvim through
- `session`. That means print statements probably won't work as expected
- while this function doesn't return.
-
- This function is normally called at program startup and could have been
- defined as a separate executable. It is exposed as a library function for
- testing purposes only.
- """
- plugins = []
- for arg in sys.argv:
- _, ext = os.path.splitext(arg)
- if ext == '.py':
- plugins.append(arg)
- elif os.path.isdir(arg):
- init = os.path.join(arg, '__init__.py')
- if os.path.isfile(init):
- plugins.append(arg)
-
- # This is a special case to support the old workaround of
- # adding an empty .py file to make a package directory
- # visible, and it should be removed soon.
- for path in list(plugins):
- dup = path + ".py"
- if os.path.isdir(path) and dup in plugins:
- plugins.remove(dup)
-
- # Special case: the legacy scripthost receives a single relative filename
- # while the rplugin host will receive absolute paths.
- if plugins == ["script_host.py"]:
- name = "script"
- else:
- name = "rplugin"
-
- setup_logging(name)
-
- if not session:
- session = stdio_session()
- nvim = Nvim.from_session(session)
-
- if nvim.version.api_level < 1:
- sys.stderr.write("This version of pynvim "
- "requires nvim 0.1.6 or later")
- sys.exit(1)
-
- host = Host(nvim)
- host.start(plugins)
-
-
-def attach(session_type, address=None, port=None,
- path=None, argv=None, decode=None):
- """Provide a nicer interface to create python api sessions.
-
- Previous machinery to create python api sessions is still there. This only
- creates a facade function to make things easier for the most usual cases.
- Thus, instead of:
- from pynvim import socket_session, Nvim
- session = tcp_session(address=<address>, port=<port>)
- nvim = Nvim.from_session(session)
- You can now do:
- from pynvim import attach
- nvim = attach('tcp', address=<address>, port=<port>)
- And also:
- nvim = attach('socket', path=<path>)
- nvim = attach('child', argv=<argv>)
- nvim = attach('stdio')
-
- When the session is not needed anymore, it is recommended to explicitly
- close it:
- nvim.close()
- It is also possible to use the session as a context mangager:
- with attach('socket', path=thepath) as nvim:
- print(nvim.funcs.getpid())
- print(nvim.current.line)
- This will automatically close the session when you're done with it, or
- when an error occured.
-
-
- """
- session = (tcp_session(address, port) if session_type == 'tcp' else
- socket_session(path) if session_type == 'socket' else
- stdio_session() if session_type == 'stdio' else
- child_session(argv) if session_type == 'child' else
- None)
-
- if not session:
- raise Exception('Unknown session type "%s"' % session_type)
-
- if decode is None:
- decode = IS_PYTHON3
-
- return Nvim.from_session(session).with_decode(decode)
-
-
-def setup_logging(name):
- """Setup logging according to environment variables."""
- logger = logging.getLogger(__name__)
- if 'NVIM_PYTHON_LOG_FILE' in os.environ:
- prefix = os.environ['NVIM_PYTHON_LOG_FILE'].strip()
- major_version = sys.version_info[0]
- logfile = '{}_py{}_{}'.format(prefix, major_version, name)
- handler = logging.FileHandler(logfile, 'w', 'utf-8')
- handler.formatter = logging.Formatter(
- '%(asctime)s [%(levelname)s @ '
- '%(filename)s:%(funcName)s:%(lineno)s] %(process)s - %(message)s')
- logging.root.addHandler(handler)
- level = logging.INFO
- env_log_level = os.environ.get('NVIM_PYTHON_LOG_LEVEL', None)
- if env_log_level is not None:
- lvl = getattr(logging, env_log_level.strip(), None)
- if isinstance(lvl, int):
- level = lvl
- else:
- logger.warning('Invalid NVIM_PYTHON_LOG_LEVEL: %r, using INFO.',
- env_log_level)
- logger.setLevel(level)
-
-
-# Required for python 2.6
-class NullHandler(logging.Handler):
- def emit(self, record):
- pass
-
-
-if not logging.root.handlers:
- logging.root.addHandler(NullHandler())
+++ /dev/null
-"""Nvim API subpackage.
-
-This package implements a higher-level API that wraps msgpack-rpc `Session`
-instances.
-"""
-
-from pynvim.api.buffer import Buffer
-from pynvim.api.common import decode_if_bytes, walk
-from pynvim.api.nvim import Nvim, NvimError
-from pynvim.api.tabpage import Tabpage
-from pynvim.api.window import Window
-
-
-__all__ = ('Nvim', 'Buffer', 'Window', 'Tabpage', 'NvimError',
- 'decode_if_bytes', 'walk')
+++ /dev/null
-"""API for working with a Nvim Buffer."""
-from pynvim.api.common import Remote
-from pynvim.compat import IS_PYTHON3, check_async
-
-
-__all__ = ('Buffer')
-
-
-if IS_PYTHON3:
- basestring = str
-
-
-def adjust_index(idx, default=None):
- """Convert from python indexing convention to nvim indexing convention."""
- if idx is None:
- return default
- elif idx < 0:
- return idx - 1
- else:
- return idx
-
-
-class Buffer(Remote):
-
- """A remote Nvim buffer."""
-
- _api_prefix = "nvim_buf_"
-
- def __len__(self):
- """Return the number of lines contained in a Buffer."""
- return self.request('nvim_buf_line_count')
-
- def __getitem__(self, idx):
- """Get a buffer line or slice by integer index.
-
- Indexes may be negative to specify positions from the end of the
- buffer. For example, -1 is the last line, -2 is the line before that
- and so on.
-
- When retrieving slices, omiting indexes(eg: `buffer[:]`) will bring
- the whole buffer.
- """
- if not isinstance(idx, slice):
- i = adjust_index(idx)
- return self.request('nvim_buf_get_lines', i, i + 1, True)[0]
- start = adjust_index(idx.start, 0)
- end = adjust_index(idx.stop, -1)
- return self.request('nvim_buf_get_lines', start, end, False)
-
- def __setitem__(self, idx, item):
- """Replace a buffer line or slice by integer index.
-
- Like with `__getitem__`, indexes may be negative.
-
- When replacing slices, omiting indexes(eg: `buffer[:]`) will replace
- the whole buffer.
- """
- if not isinstance(idx, slice):
- i = adjust_index(idx)
- lines = [item] if item is not None else []
- return self.request('nvim_buf_set_lines', i, i + 1, True, lines)
- lines = item if item is not None else []
- start = adjust_index(idx.start, 0)
- end = adjust_index(idx.stop, -1)
- return self.request('nvim_buf_set_lines', start, end, False, lines)
-
- def __iter__(self):
- """Iterate lines of a buffer.
-
- This will retrieve all lines locally before iteration starts. This
- approach is used because for most cases, the gain is much greater by
- minimizing the number of API calls by transfering all data needed to
- work.
- """
- lines = self[:]
- for line in lines:
- yield line
-
- def __delitem__(self, idx):
- """Delete line or slice of lines from the buffer.
-
- This is the same as __setitem__(idx, [])
- """
- self.__setitem__(idx, None)
-
- def __ne__(self, other):
- """Test inequality of Buffers.
-
- Necessary for Python 2 compatibility.
- """
- return not self.__eq__(other)
-
- def append(self, lines, index=-1):
- """Append a string or list of lines to the buffer."""
- if isinstance(lines, (basestring, bytes)):
- lines = [lines]
- return self.request('nvim_buf_set_lines', index, index, True, lines)
-
- def mark(self, name):
- """Return (row, col) tuple for a named mark."""
- return self.request('nvim_buf_get_mark', name)
-
- def range(self, start, end):
- """Return a `Range` object, which represents part of the Buffer."""
- return Range(self, start, end)
-
- def add_highlight(self, hl_group, line, col_start=0,
- col_end=-1, src_id=-1, async_=None,
- **kwargs):
- """Add a highlight to the buffer."""
- async_ = check_async(async_, kwargs, src_id != 0)
- return self.request('nvim_buf_add_highlight', src_id, hl_group,
- line, col_start, col_end, async_=async_)
-
- def clear_highlight(self, src_id, line_start=0, line_end=-1, async_=None,
- **kwargs):
- """Clear highlights from the buffer."""
- async_ = check_async(async_, kwargs, True)
- self.request('nvim_buf_clear_highlight', src_id,
- line_start, line_end, async_=async_)
-
- def update_highlights(self, src_id, hls, clear_start=0, clear_end=-1,
- clear=False, async_=True):
- """Add or update highlights in batch to avoid unnecessary redraws.
-
- A `src_id` must have been allocated prior to use of this function. Use
- for instance `nvim.new_highlight_source()` to get a src_id for your
- plugin.
-
- `hls` should be a list of highlight items. Each item should be a list
- or tuple on the form `("GroupName", linenr, col_start, col_end)` or
- `("GroupName", linenr)` to highlight an entire line.
-
- By default existing highlights are preserved. Specify a line range with
- clear_start and clear_end to replace highlights in this range. As a
- shorthand, use clear=True to clear the entire buffer before adding the
- new highlights.
- """
- if clear and clear_start is None:
- clear_start = 0
- lua = self._session._get_lua_private()
- lua.update_highlights(self, src_id, hls, clear_start, clear_end,
- async_=async_)
-
- @property
- def name(self):
- """Get the buffer name."""
- return self.request('nvim_buf_get_name')
-
- @name.setter
- def name(self, value):
- """Set the buffer name. BufFilePre/BufFilePost are triggered."""
- return self.request('nvim_buf_set_name', value)
-
- @property
- def valid(self):
- """Return True if the buffer still exists."""
- return self.request('nvim_buf_is_valid')
-
- @property
- def number(self):
- """Get the buffer number."""
- return self.handle
-
-
-class Range(object):
- def __init__(self, buffer, start, end):
- self._buffer = buffer
- self.start = start - 1
- self.end = end - 1
-
- def __len__(self):
- return self.end - self.start + 1
-
- def __getitem__(self, idx):
- if not isinstance(idx, slice):
- return self._buffer[self._normalize_index(idx)]
- start = self._normalize_index(idx.start)
- end = self._normalize_index(idx.stop)
- if start is None:
- start = self.start
- if end is None:
- end = self.end + 1
- return self._buffer[start:end]
-
- def __setitem__(self, idx, lines):
- if not isinstance(idx, slice):
- self._buffer[self._normalize_index(idx)] = lines
- return
- start = self._normalize_index(idx.start)
- end = self._normalize_index(idx.stop)
- if start is None:
- start = self.start
- if end is None:
- end = self.end
- self._buffer[start:end + 1] = lines
-
- def __iter__(self):
- for i in range(self.start, self.end + 1):
- yield self._buffer[i]
-
- def append(self, lines, i=None):
- i = self._normalize_index(i)
- if i is None:
- i = self.end + 1
- self._buffer.append(lines, i)
-
- def _normalize_index(self, index):
- if index is None:
- return None
- if index < 0:
- index = self.end
- else:
- index += self.start
- if index > self.end:
- index = self.end
- return index
+++ /dev/null
-"""Code shared between the API classes."""
-import functools
-
-from msgpack import unpackb
-
-from pynvim.compat import unicode_errors_default
-
-__all__ = ()
-
-
-class NvimError(Exception):
- pass
-
-
-class Remote(object):
-
- """Base class for Nvim objects(buffer/window/tabpage).
-
- Each type of object has it's own specialized class with API wrappers around
- the msgpack-rpc session. This implements equality which takes the remote
- object handle into consideration.
- """
-
- def __init__(self, session, code_data):
- """Initialize from session and code_data immutable object.
-
- The `code_data` contains serialization information required for
- msgpack-rpc calls. It must be immutable for Buffer equality to work.
- """
- self._session = session
- self.code_data = code_data
- self.handle = unpackb(code_data[1])
- self.api = RemoteApi(self, self._api_prefix)
- self.vars = RemoteMap(self, self._api_prefix + 'get_var',
- self._api_prefix + 'set_var',
- self._api_prefix + 'del_var')
- self.options = RemoteMap(self, self._api_prefix + 'get_option',
- self._api_prefix + 'set_option')
-
- def __repr__(self):
- """Get text representation of the object."""
- return '<%s(handle=%r)>' % (
- self.__class__.__name__,
- self.handle,
- )
-
- def __eq__(self, other):
- """Return True if `self` and `other` are the same object."""
- return (hasattr(other, 'code_data')
- and other.code_data == self.code_data)
-
- def __hash__(self):
- """Return hash based on remote object id."""
- return self.code_data.__hash__()
-
- def request(self, name, *args, **kwargs):
- """Wrapper for nvim.request."""
- return self._session.request(name, self, *args, **kwargs)
-
-
-class RemoteApi(object):
-
- """Wrapper to allow api methods to be called like python methods."""
-
- def __init__(self, obj, api_prefix):
- """Initialize a RemoteApi with object and api prefix."""
- self._obj = obj
- self._api_prefix = api_prefix
-
- def __getattr__(self, name):
- """Return wrapper to named api method."""
- return functools.partial(self._obj.request, self._api_prefix + name)
-
-
-def transform_keyerror(exc):
- if isinstance(exc, NvimError):
- if exc.args[0].startswith('Key not found:'):
- return KeyError(exc.args[0])
- if exc.args[0].startswith('Invalid option name:'):
- return KeyError(exc.args[0])
- return exc
-
-
-class RemoteMap(object):
- """Represents a string->object map stored in Nvim.
-
- This is the dict counterpart to the `RemoteSequence` class, but it is used
- as a generic way of retrieving values from the various map-like data
- structures present in Nvim.
-
- It is used to provide a dict-like API to vim variables and options.
- """
-
- _set = None
- _del = None
-
- def __init__(self, obj, get_method, set_method=None, del_method=None):
- """Initialize a RemoteMap with session, getter/setter."""
- self._get = functools.partial(obj.request, get_method)
- if set_method:
- self._set = functools.partial(obj.request, set_method)
- if del_method:
- self._del = functools.partial(obj.request, del_method)
-
- def __getitem__(self, key):
- """Return a map value by key."""
- try:
- return self._get(key)
- except NvimError as exc:
- raise transform_keyerror(exc)
-
- def __setitem__(self, key, value):
- """Set a map value by key(if the setter was provided)."""
- if not self._set:
- raise TypeError('This dict is read-only')
- self._set(key, value)
-
- def __delitem__(self, key):
- """Delete a map value by associating None with the key."""
- if not self._del:
- raise TypeError('This dict is read-only')
- try:
- return self._del(key)
- except NvimError as exc:
- raise transform_keyerror(exc)
-
- def __contains__(self, key):
- """Check if key is present in the map."""
- try:
- self._get(key)
- return True
- except Exception:
- return False
-
- def get(self, key, default=None):
- """Return value for key if present, else a default value."""
- try:
- return self.__getitem__(key)
- except KeyError:
- return default
-
-
-class RemoteSequence(object):
-
- """Represents a sequence of objects stored in Nvim.
-
- This class is used to wrap msgapck-rpc functions that work on Nvim
- sequences(of lines, buffers, windows and tabpages) with an API that
- is similar to the one provided by the python-vim interface.
-
- For example, the 'windows' property of the `Nvim` class is a RemoteSequence
- sequence instance, and the expression `nvim.windows[0]` is translated to
- session.request('nvim_list_wins')[0].
-
- One important detail about this class is that all methods will fetch the
- sequence into a list and perform the necessary manipulation
- locally(iteration, indexing, counting, etc).
- """
-
- def __init__(self, session, method):
- """Initialize a RemoteSequence with session, method."""
- self._fetch = functools.partial(session.request, method)
-
- def __len__(self):
- """Return the length of the remote sequence."""
- return len(self._fetch())
-
- def __getitem__(self, idx):
- """Return a sequence item by index."""
- if not isinstance(idx, slice):
- return self._fetch()[idx]
- return self._fetch()[idx.start:idx.stop]
-
- def __iter__(self):
- """Return an iterator for the sequence."""
- items = self._fetch()
- for item in items:
- yield item
-
- def __contains__(self, item):
- """Check if an item is present in the sequence."""
- return item in self._fetch()
-
-
-def _identity(obj, session, method, kind):
- return obj
-
-
-def decode_if_bytes(obj, mode=True):
- """Decode obj if it is bytes."""
- if mode is True:
- mode = unicode_errors_default
- if isinstance(obj, bytes):
- return obj.decode("utf-8", errors=mode)
- return obj
-
-
-def walk(fn, obj, *args, **kwargs):
- """Recursively walk an object graph applying `fn`/`args` to objects."""
- if type(obj) in [list, tuple]:
- return list(walk(fn, o, *args) for o in obj)
- if type(obj) is dict:
- return dict((walk(fn, k, *args), walk(fn, v, *args)) for k, v in
- obj.items())
- return fn(obj, *args, **kwargs)
+++ /dev/null
-"""Main Nvim interface."""
-import os
-import sys
-import threading
-from functools import partial
-from traceback import format_stack
-
-from msgpack import ExtType
-
-from pynvim.api.buffer import Buffer
-from pynvim.api.common import (NvimError, Remote, RemoteApi, RemoteMap, RemoteSequence,
- decode_if_bytes, walk)
-from pynvim.api.tabpage import Tabpage
-from pynvim.api.window import Window
-from pynvim.compat import IS_PYTHON3
-from pynvim.util import Version, format_exc_skip
-
-__all__ = ('Nvim')
-
-
-os_chdir = os.chdir
-
-lua_module = """
-local a = vim.api
-local function update_highlights(buf, src_id, hls, clear_first, clear_end)
- if clear_first ~= nil then
- a.nvim_buf_clear_highlight(buf, src_id, clear_first, clear_end)
- end
- for _,hl in pairs(hls) do
- local group, line, col_start, col_end = unpack(hl)
- if col_start == nil then
- col_start = 0
- end
- if col_end == nil then
- col_end = -1
- end
- a.nvim_buf_add_highlight(buf, src_id, group, line, col_start, col_end)
- end
-end
-
-local chid = ...
-local mod = {update_highlights=update_highlights}
-_G["_pynvim_"..chid] = mod
-"""
-
-
-class Nvim(object):
-
- """Class that represents a remote Nvim instance.
-
- This class is main entry point to Nvim remote API, it is a wrapper
- around Session instances.
-
- The constructor of this class must not be called directly. Instead, the
- `from_session` class method should be used to create the first instance
- from a raw `Session` instance.
-
- Subsequent instances for the same session can be created by calling the
- `with_decode` instance method to change the decoding behavior or
- `SubClass.from_nvim(nvim)` where `SubClass` is a subclass of `Nvim`, which
- is useful for having multiple `Nvim` objects that behave differently
- without one affecting the other.
-
- When this library is used on python3.4+, asyncio event loop is guaranteed
- to be used. It is available as the "loop" attribute of this class. Note
- that asyncio callbacks cannot make blocking requests, which includes
- accessing state-dependent attributes. They should instead schedule another
- callback using nvim.async_call, which will not have this restriction.
- """
-
- @classmethod
- def from_session(cls, session):
- """Create a new Nvim instance for a Session instance.
-
- This method must be called to create the first Nvim instance, since it
- queries Nvim metadata for type information and sets a SessionHook for
- creating specialized objects from Nvim remote handles.
- """
- session.error_wrapper = lambda e: NvimError(decode_if_bytes(e[1]))
- channel_id, metadata = session.request(b'nvim_get_api_info')
-
- if IS_PYTHON3:
- # decode all metadata strings for python3
- metadata = walk(decode_if_bytes, metadata)
-
- types = {
- metadata['types']['Buffer']['id']: Buffer,
- metadata['types']['Window']['id']: Window,
- metadata['types']['Tabpage']['id']: Tabpage,
- }
-
- return cls(session, channel_id, metadata, types)
-
- @classmethod
- def from_nvim(cls, nvim):
- """Create a new Nvim instance from an existing instance."""
- return cls(nvim._session, nvim.channel_id, nvim.metadata,
- nvim.types, nvim._decode, nvim._err_cb)
-
- def __init__(self, session, channel_id, metadata, types,
- decode=False, err_cb=None):
- """Initialize a new Nvim instance. This method is module-private."""
- self._session = session
- self.channel_id = channel_id
- self.metadata = metadata
- version = metadata.get("version", {"api_level": 0})
- self.version = Version(**version)
- self.types = types
- self.api = RemoteApi(self, 'nvim_')
- self.vars = RemoteMap(self, 'nvim_get_var', 'nvim_set_var', 'nvim_del_var')
- self.vvars = RemoteMap(self, 'nvim_get_vvar', None, None)
- self.options = RemoteMap(self, 'nvim_get_option', 'nvim_set_option')
- self.buffers = Buffers(self)
- self.windows = RemoteSequence(self, 'nvim_list_wins')
- self.tabpages = RemoteSequence(self, 'nvim_list_tabpages')
- self.current = Current(self)
- self.session = CompatibilitySession(self)
- self.funcs = Funcs(self)
- self.lua = LuaFuncs(self)
- self.error = NvimError
- self._decode = decode
- self._err_cb = err_cb
-
- # only on python3.4+ we expose asyncio
- if IS_PYTHON3:
- self.loop = self._session.loop._loop
-
- def _from_nvim(self, obj, decode=None):
- if decode is None:
- decode = self._decode
- if type(obj) is ExtType:
- cls = self.types[obj.code]
- return cls(self, (obj.code, obj.data))
- if decode:
- obj = decode_if_bytes(obj, decode)
- return obj
-
- def _to_nvim(self, obj):
- if isinstance(obj, Remote):
- return ExtType(*obj.code_data)
- return obj
-
- def _get_lua_private(self):
- if not getattr(self._session, "_has_lua", False):
- self.exec_lua(lua_module, self.channel_id)
- self._session._has_lua = True
- return getattr(self.lua, "_pynvim_{}".format(self.channel_id))
-
- def request(self, name, *args, **kwargs):
- r"""Send an API request or notification to nvim.
-
- It is rarely needed to call this function directly, as most API
- functions have python wrapper functions. The `api` object can
- be also be used to call API functions as methods:
-
- vim.api.err_write('ERROR\n', async_=True)
- vim.current.buffer.api.get_mark('.')
-
- is equivalent to
-
- vim.request('nvim_err_write', 'ERROR\n', async_=True)
- vim.request('nvim_buf_get_mark', vim.current.buffer, '.')
-
-
- Normally a blocking request will be sent. If the `async_` flag is
- present and True, a asynchronous notification is sent instead. This
- will never block, and the return value or error is ignored.
- """
- if (self._session._loop_thread is not None
- and threading.current_thread() != self._session._loop_thread):
-
- msg = ("Request from non-main thread.\n"
- "Requests from different threads should be wrapped "
- "with nvim.async_call(cb, ...) \n{}\n"
- .format('\n'.join(format_stack(None, 5)[:-1])))
-
- self.async_call(self._err_cb, msg)
- raise NvimError("request from non-main thread")
-
- decode = kwargs.pop('decode', self._decode)
- args = walk(self._to_nvim, args)
- res = self._session.request(name, *args, **kwargs)
- return walk(self._from_nvim, res, decode=decode)
-
- def next_message(self):
- """Block until a message(request or notification) is available.
-
- If any messages were previously enqueued, return the first in queue.
- If not, run the event loop until one is received.
- """
- msg = self._session.next_message()
- if msg:
- return walk(self._from_nvim, msg)
-
- def run_loop(self, request_cb, notification_cb,
- setup_cb=None, err_cb=None):
- """Run the event loop to receive requests and notifications from Nvim.
-
- This should not be called from a plugin running in the host, which
- already runs the loop and dispatches events to plugins.
- """
- if err_cb is None:
- err_cb = sys.stderr.write
- self._err_cb = err_cb
-
- def filter_request_cb(name, args):
- name = self._from_nvim(name)
- args = walk(self._from_nvim, args)
- try:
- result = request_cb(name, args)
- except Exception:
- msg = ("error caught in request handler '{} {}'\n{}\n\n"
- .format(name, args, format_exc_skip(1)))
- self._err_cb(msg)
- raise
- return walk(self._to_nvim, result)
-
- def filter_notification_cb(name, args):
- name = self._from_nvim(name)
- args = walk(self._from_nvim, args)
- try:
- notification_cb(name, args)
- except Exception:
- msg = ("error caught in notification handler '{} {}'\n{}\n\n"
- .format(name, args, format_exc_skip(1)))
- self._err_cb(msg)
- raise
-
- self._session.run(filter_request_cb, filter_notification_cb, setup_cb)
-
- def stop_loop(self):
- """Stop the event loop being started with `run_loop`."""
- self._session.stop()
-
- def close(self):
- """Close the nvim session and release its resources."""
- self._session.close()
-
- def __enter__(self):
- """Enter nvim session as a context manager."""
- return self
-
- def __exit__(self, *exc_info):
- """Exit nvim session as a context manager.
-
- Closes the event loop.
- """
- self.close()
-
- def with_decode(self, decode=True):
- """Initialize a new Nvim instance."""
- return Nvim(self._session, self.channel_id,
- self.metadata, self.types, decode, self._err_cb)
-
- def ui_attach(self, width, height, rgb=None, **kwargs):
- """Register as a remote UI.
-
- After this method is called, the client will receive redraw
- notifications.
- """
- options = kwargs
- if rgb is not None:
- options['rgb'] = rgb
- return self.request('nvim_ui_attach', width, height, options)
-
- def ui_detach(self):
- """Unregister as a remote UI."""
- return self.request('nvim_ui_detach')
-
- def ui_try_resize(self, width, height):
- """Notify nvim that the client window has resized.
-
- If possible, nvim will send a redraw request to resize.
- """
- return self.request('ui_try_resize', width, height)
-
- def subscribe(self, event):
- """Subscribe to a Nvim event."""
- return self.request('nvim_subscribe', event)
-
- def unsubscribe(self, event):
- """Unsubscribe to a Nvim event."""
- return self.request('nvim_unsubscribe', event)
-
- def command(self, string, **kwargs):
- """Execute a single ex command."""
- return self.request('nvim_command', string, **kwargs)
-
- def command_output(self, string):
- """Execute a single ex command and return the output."""
- return self.request('nvim_command_output', string)
-
- def eval(self, string, **kwargs):
- """Evaluate a vimscript expression."""
- return self.request('nvim_eval', string, **kwargs)
-
- def call(self, name, *args, **kwargs):
- """Call a vimscript function."""
- return self.request('nvim_call_function', name, args, **kwargs)
-
- def exec_lua(self, code, *args, **kwargs):
- """Execute lua code.
-
- Additional parameters are available as `...` inside the lua chunk.
- Only statements are executed. To evaluate an expression, prefix it
- with `return`: `return my_function(...)`
-
- There is a shorthand syntax to call lua functions with arguments:
-
- nvim.lua.func(1,2)
- nvim.lua.mymod.myfunction(data, async_=True)
-
- is equivalent to
-
- nvim.exec_lua("return func(...)", 1, 2)
- nvim.exec_lua("mymod.myfunction(...)", data, async_=True)
-
- Note that with `async_=True` there is no return value.
- """
- return self.request('nvim_execute_lua', code, args, **kwargs)
-
- def strwidth(self, string):
- """Return the number of display cells `string` occupies.
-
- Tab is counted as one cell.
- """
- return self.request('nvim_strwidth', string)
-
- def list_runtime_paths(self):
- """Return a list of paths contained in the 'runtimepath' option."""
- return self.request('nvim_list_runtime_paths')
-
- def foreach_rtp(self, cb):
- """Invoke `cb` for each path in 'runtimepath'.
-
- Call the given callable for each path in 'runtimepath' until either
- callable returns something but None, the exception is raised or there
- are no longer paths. If stopped in case callable returned non-None,
- vim.foreach_rtp function returns the value returned by callable.
- """
- for path in self.request('nvim_list_runtime_paths'):
- try:
- if cb(path) is not None:
- break
- except Exception:
- break
-
- def chdir(self, dir_path):
- """Run os.chdir, then all appropriate vim stuff."""
- os_chdir(dir_path)
- return self.request('nvim_set_current_dir', dir_path)
-
- def feedkeys(self, keys, options='', escape_csi=True):
- """Push `keys` to Nvim user input buffer.
-
- Options can be a string with the following character flags:
- - 'm': Remap keys. This is default.
- - 'n': Do not remap keys.
- - 't': Handle keys as if typed; otherwise they are handled as if coming
- from a mapping. This matters for undo, opening folds, etc.
- """
- return self.request('nvim_feedkeys', keys, options, escape_csi)
-
- def input(self, bytes):
- """Push `bytes` to Nvim low level input buffer.
-
- Unlike `feedkeys()`, this uses the lowest level input buffer and the
- call is not deferred. It returns the number of bytes actually
- written(which can be less than what was requested if the buffer is
- full).
- """
- return self.request('nvim_input', bytes)
-
- def replace_termcodes(self, string, from_part=False, do_lt=True,
- special=True):
- r"""Replace any terminal code strings by byte sequences.
-
- The returned sequences are Nvim's internal representation of keys,
- for example:
-
- <esc> -> '\x1b'
- <cr> -> '\r'
- <c-l> -> '\x0c'
- <up> -> '\x80ku'
-
- The returned sequences can be used as input to `feedkeys`.
- """
- return self.request('nvim_replace_termcodes', string,
- from_part, do_lt, special)
-
- def out_write(self, msg, **kwargs):
- r"""Print `msg` as a normal message.
-
- The message is buffered (won't display) until linefeed ("\n").
- """
- return self.request('nvim_out_write', msg, **kwargs)
-
- def err_write(self, msg, **kwargs):
- r"""Print `msg` as an error message.
-
- The message is buffered (won't display) until linefeed ("\n").
- """
- if self._thread_invalid():
- # special case: if a non-main thread writes to stderr
- # i.e. due to an uncaught exception, pass it through
- # without raising an additional exception.
- self.async_call(self.err_write, msg, **kwargs)
- return
- return self.request('nvim_err_write', msg, **kwargs)
-
- def _thread_invalid(self):
- return (self._session._loop_thread is not None
- and threading.current_thread() != self._session._loop_thread)
-
- def quit(self, quit_command='qa!'):
- """Send a quit command to Nvim.
-
- By default, the quit command is 'qa!' which will make Nvim quit without
- saving anything.
- """
- try:
- self.command(quit_command)
- except OSError:
- # sending a quit command will raise an IOError because the
- # connection is closed before a response is received. Safe to
- # ignore it.
- pass
-
- def new_highlight_source(self):
- """Return new src_id for use with Buffer.add_highlight."""
- return self.current.buffer.add_highlight("", 0, src_id=0)
-
- def async_call(self, fn, *args, **kwargs):
- """Schedule `fn` to be called by the event loop soon.
-
- This function is thread-safe, and is the only way code not
- on the main thread could interact with nvim api objects.
-
- This function can also be called in a synchronous
- event handler, just before it returns, to defer execution
- that shouldn't block neovim.
- """
- call_point = ''.join(format_stack(None, 5)[:-1])
-
- def handler():
- try:
- fn(*args, **kwargs)
- except Exception as err:
- msg = ("error caught while executing async callback:\n"
- "{!r}\n{}\n \nthe call was requested at\n{}"
- .format(err, format_exc_skip(1), call_point))
- self._err_cb(msg)
- raise
- self._session.threadsafe_call(handler)
-
-
-class Buffers(object):
-
- """Remote NVim buffers.
-
- Currently the interface for interacting with remote NVim buffers is the
- `nvim_list_bufs` msgpack-rpc function. Most methods fetch the list of
- buffers from NVim.
-
- Conforms to *python-buffers*.
- """
-
- def __init__(self, nvim):
- """Initialize a Buffers object with Nvim object `nvim`."""
- self._fetch_buffers = nvim.api.list_bufs
-
- def __len__(self):
- """Return the count of buffers."""
- return len(self._fetch_buffers())
-
- def __getitem__(self, number):
- """Return the Buffer object matching buffer number `number`."""
- for b in self._fetch_buffers():
- if b.number == number:
- return b
- raise KeyError(number)
-
- def __contains__(self, b):
- """Return whether Buffer `b` is a known valid buffer."""
- return isinstance(b, Buffer) and b.valid
-
- def __iter__(self):
- """Return an iterator over the list of buffers."""
- return iter(self._fetch_buffers())
-
-
-class CompatibilitySession(object):
-
- """Helper class for API compatibility."""
-
- def __init__(self, nvim):
- self.threadsafe_call = nvim.async_call
-
-
-class Current(object):
-
- """Helper class for emulating vim.current from python-vim."""
-
- def __init__(self, session):
- self._session = session
- self.range = None
-
- @property
- def line(self):
- return self._session.request('nvim_get_current_line')
-
- @line.setter
- def line(self, line):
- return self._session.request('nvim_set_current_line', line)
-
- @line.deleter
- def line(self):
- return self._session.request('nvim_del_current_line')
-
- @property
- def buffer(self):
- return self._session.request('nvim_get_current_buf')
-
- @buffer.setter
- def buffer(self, buffer):
- return self._session.request('nvim_set_current_buf', buffer)
-
- @property
- def window(self):
- return self._session.request('nvim_get_current_win')
-
- @window.setter
- def window(self, window):
- return self._session.request('nvim_set_current_win', window)
-
- @property
- def tabpage(self):
- return self._session.request('nvim_get_current_tabpage')
-
- @tabpage.setter
- def tabpage(self, tabpage):
- return self._session.request('nvim_set_current_tabpage', tabpage)
-
-
-class Funcs(object):
-
- """Helper class for functional vimscript interface."""
-
- def __init__(self, nvim):
- self._nvim = nvim
-
- def __getattr__(self, name):
- return partial(self._nvim.call, name)
-
-
-class LuaFuncs(object):
-
- """Wrapper to allow lua functions to be called like python methods."""
-
- def __init__(self, nvim, name=""):
- self._nvim = nvim
- self.name = name
-
- def __getattr__(self, name):
- """Return wrapper to named api method."""
- prefix = self.name + "." if self.name else ""
- return LuaFuncs(self._nvim, prefix + name)
-
- def __call__(self, *args, **kwargs):
- # first new function after keyword rename, be a bit noisy
- if 'async' in kwargs:
- raise ValueError('"async" argument is not allowed. '
- 'Use "async_" instead.')
- async_ = kwargs.get('async_', False)
- pattern = "return {}(...)" if not async_ else "{}(...)"
- code = pattern.format(self.name)
- return self._nvim.exec_lua(code, *args, **kwargs)
+++ /dev/null
-"""API for working with Nvim tabpages."""
-from pynvim.api.common import Remote, RemoteSequence
-
-
-__all__ = ('Tabpage')
-
-
-class Tabpage(Remote):
- """A remote Nvim tabpage."""
-
- _api_prefix = "nvim_tabpage_"
-
- def __init__(self, *args):
- """Initialize from session and code_data immutable object.
-
- The `code_data` contains serialization information required for
- msgpack-rpc calls. It must be immutable for Buffer equality to work.
- """
- super(Tabpage, self).__init__(*args)
- self.windows = RemoteSequence(self, 'nvim_tabpage_list_wins')
-
- @property
- def window(self):
- """Get the `Window` currently focused on the tabpage."""
- return self.request('nvim_tabpage_get_win')
-
- @property
- def valid(self):
- """Return True if the tabpage still exists."""
- return self.request('nvim_tabpage_is_valid')
-
- @property
- def number(self):
- """Get the tabpage number."""
- return self.request('nvim_tabpage_get_number')
+++ /dev/null
-"""API for working with Nvim windows."""
-from pynvim.api.common import Remote
-
-
-__all__ = ('Window')
-
-
-class Window(Remote):
-
- """A remote Nvim window."""
-
- _api_prefix = "nvim_win_"
-
- @property
- def buffer(self):
- """Get the `Buffer` currently being displayed by the window."""
- return self.request('nvim_win_get_buf')
-
- @property
- def cursor(self):
- """Get the (row, col) tuple with the current cursor position."""
- return self.request('nvim_win_get_cursor')
-
- @cursor.setter
- def cursor(self, pos):
- """Set the (row, col) tuple as the new cursor position."""
- return self.request('nvim_win_set_cursor', pos)
-
- @property
- def height(self):
- """Get the window height in rows."""
- return self.request('nvim_win_get_height')
-
- @height.setter
- def height(self, height):
- """Set the window height in rows."""
- return self.request('nvim_win_set_height', height)
-
- @property
- def width(self):
- """Get the window width in rows."""
- return self.request('nvim_win_get_width')
-
- @width.setter
- def width(self, width):
- """Set the window height in rows."""
- return self.request('nvim_win_set_width', width)
-
- @property
- def row(self):
- """0-indexed, on-screen window position(row) in display cells."""
- return self.request('nvim_win_get_position')[0]
-
- @property
- def col(self):
- """0-indexed, on-screen window position(col) in display cells."""
- return self.request('nvim_win_get_position')[1]
-
- @property
- def tabpage(self):
- """Get the `Tabpage` that contains the window."""
- return self.request('nvim_win_get_tabpage')
-
- @property
- def valid(self):
- """Return True if the window still exists."""
- return self.request('nvim_win_is_valid')
-
- @property
- def number(self):
- """Get the window number."""
- return self.request('nvim_win_get_number')
+++ /dev/null
-"""Code for compatibility across Python versions."""
-
-import sys
-import warnings
-from imp import find_module as original_find_module
-
-
-IS_PYTHON3 = sys.version_info >= (3, 0)
-
-
-if IS_PYTHON3:
- def find_module(fullname, path):
- """Compatibility wrapper for imp.find_module.
-
- Automatically decodes arguments of find_module, in Python3
- they must be Unicode
- """
- if isinstance(fullname, bytes):
- fullname = fullname.decode()
- if isinstance(path, bytes):
- path = path.decode()
- elif isinstance(path, list):
- newpath = []
- for element in path:
- if isinstance(element, bytes):
- newpath.append(element.decode())
- else:
- newpath.append(element)
- path = newpath
- return original_find_module(fullname, path)
-
- # There is no 'long' type in Python3 just int
- long = int
- unicode_errors_default = 'surrogateescape'
-else:
- find_module = original_find_module
- unicode_errors_default = 'ignore'
-
-NUM_TYPES = (int, long, float)
-
-
-def check_async(async_, kwargs, default):
- """Return a value of 'async' in kwargs or default when async_ is None.
-
- This helper function exists for backward compatibility (See #274).
- It shows a warning message when 'async' in kwargs is used to note users.
- """
- if async_ is not None:
- return async_
- elif 'async' in kwargs:
- warnings.warn(
- '"async" attribute is deprecated. Use "async_" instead.',
- DeprecationWarning,
- )
- return kwargs.pop('async')
- else:
- return default
+++ /dev/null
-"""Msgpack-rpc subpackage.
-
-This package implements a msgpack-rpc client. While it was designed for
-handling some Nvim particularities(server->client requests for example), the
-code here should work with other msgpack-rpc servers.
-"""
-from pynvim.msgpack_rpc.async_session import AsyncSession
-from pynvim.msgpack_rpc.event_loop import EventLoop
-from pynvim.msgpack_rpc.msgpack_stream import MsgpackStream
-from pynvim.msgpack_rpc.session import ErrorResponse, Session
-from pynvim.util import get_client_info
-
-
-__all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
- 'ErrorResponse')
-
-
-def session(transport_type='stdio', *args, **kwargs):
- loop = EventLoop(transport_type, *args, **kwargs)
- msgpack_stream = MsgpackStream(loop)
- async_session = AsyncSession(msgpack_stream)
- session = Session(async_session)
- session.request(b'nvim_set_client_info',
- *get_client_info('client', 'remote', {}), async_=True)
- return session
-
-
-def tcp_session(address, port=7450):
- """Create a msgpack-rpc session from a tcp address/port."""
- return session('tcp', address, port)
-
-
-def socket_session(path):
- """Create a msgpack-rpc session from a unix domain socket."""
- return session('socket', path)
-
-
-def stdio_session():
- """Create a msgpack-rpc session from stdin/stdout."""
- return session('stdio')
-
-
-def child_session(argv):
- """Create a msgpack-rpc session from a new Nvim instance."""
- return session('child', argv)
+++ /dev/null
-"""Asynchronous msgpack-rpc handling in the event loop pipeline."""
-import logging
-from traceback import format_exc
-
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-
-class AsyncSession(object):
-
- """Asynchronous msgpack-rpc layer that wraps a msgpack stream.
-
- This wraps the msgpack stream interface for reading/writing msgpack
- documents and exposes an interface for sending and receiving msgpack-rpc
- requests and notifications.
- """
-
- def __init__(self, msgpack_stream):
- """Wrap `msgpack_stream` on a msgpack-rpc interface."""
- self._msgpack_stream = msgpack_stream
- self._next_request_id = 1
- self._pending_requests = {}
- self._request_cb = self._notification_cb = None
- self._handlers = {
- 0: self._on_request,
- 1: self._on_response,
- 2: self._on_notification
- }
- self.loop = msgpack_stream.loop
-
- def threadsafe_call(self, fn):
- """Wrapper around `MsgpackStream.threadsafe_call`."""
- self._msgpack_stream.threadsafe_call(fn)
-
- def request(self, method, args, response_cb):
- """Send a msgpack-rpc request to Nvim.
-
- A msgpack-rpc with method `method` and argument `args` is sent to
- Nvim. The `response_cb` function is called with when the response
- is available.
- """
- request_id = self._next_request_id
- self._next_request_id = request_id + 1
- self._msgpack_stream.send([0, request_id, method, args])
- self._pending_requests[request_id] = response_cb
-
- def notify(self, method, args):
- """Send a msgpack-rpc notification to Nvim.
-
- A msgpack-rpc with method `method` and argument `args` is sent to
- Nvim. This will have the same effect as a request, but no response
- will be recieved
- """
- self._msgpack_stream.send([2, method, args])
-
- def run(self, request_cb, notification_cb):
- """Run the event loop to receive requests and notifications from Nvim.
-
- While the event loop is running, `request_cb` and `notification_cb`
- will be called whenever requests or notifications are respectively
- available.
- """
- self._request_cb = request_cb
- self._notification_cb = notification_cb
- self._msgpack_stream.run(self._on_message)
- self._request_cb = None
- self._notification_cb = None
-
- def stop(self):
- """Stop the event loop."""
- self._msgpack_stream.stop()
-
- def close(self):
- """Close the event loop."""
- self._msgpack_stream.close()
-
- def _on_message(self, msg):
- try:
- self._handlers.get(msg[0], self._on_invalid_message)(msg)
- except Exception:
- err_str = format_exc(5)
- pass # replaces next logging statement
- #warn(err_str)
- self._msgpack_stream.send([1, 0, err_str, None])
-
- def _on_request(self, msg):
- # request
- # - msg[1]: id
- # - msg[2]: method name
- # - msg[3]: arguments
- pass # replaces next logging statement
- #debug('received request: %s, %s', msg[2], msg[3])
- self._request_cb(msg[2], msg[3], Response(self._msgpack_stream,
- msg[1]))
-
- def _on_response(self, msg):
- # response to a previous request:
- # - msg[1]: the id
- # - msg[2]: error(if any)
- # - msg[3]: result(if not errored)
- pass # replaces next logging statement
- #debug('received response: %s, %s', msg[2], msg[3])
- self._pending_requests.pop(msg[1])(msg[2], msg[3])
-
- def _on_notification(self, msg):
- # notification/event
- # - msg[1]: event name
- # - msg[2]: arguments
- pass # replaces next logging statement
- #debug('received notification: %s, %s', msg[1], msg[2])
- self._notification_cb(msg[1], msg[2])
-
- def _on_invalid_message(self, msg):
- error = 'Received invalid message %s' % msg
- pass # replaces next logging statement
- #warn(error)
- self._msgpack_stream.send([1, 0, error, None])
-
-
-class Response(object):
-
- """Response to a msgpack-rpc request that came from Nvim.
-
- When Nvim sends a msgpack-rpc request, an instance of this class is
- created for remembering state required to send a response.
- """
-
- def __init__(self, msgpack_stream, request_id):
- """Initialize the Response instance."""
- self._msgpack_stream = msgpack_stream
- self._request_id = request_id
-
- def send(self, value, error=False):
- """Send the response.
-
- If `error` is True, it will be sent as an error.
- """
- if error:
- resp = [1, self._request_id, value, None]
- else:
- resp = [1, self._request_id, None, value]
- pass # replaces next logging statement
- #debug('sending response to request %d: %s', self._request_id, resp)
- self._msgpack_stream.send(resp)
+++ /dev/null
-"""Event loop abstraction subpackage.
-
-Tries to use pyuv as a backend, falling back to the asyncio implementation.
-"""
-
-from pynvim.compat import IS_PYTHON3
-
-# on python3 we only support asyncio, as we expose it to plugins
-if IS_PYTHON3:
- from pynvim.msgpack_rpc.event_loop.asyncio import AsyncioEventLoop
- EventLoop = AsyncioEventLoop
-else:
- try:
- # libuv is fully implemented in C, use it when available
- from pynvim.msgpack_rpc.event_loop.uv import UvEventLoop
- EventLoop = UvEventLoop
- except ImportError:
- # asyncio(trollius on python 2) is pure python and should be more
- # portable across python implementations
- from pynvim.msgpack_rpc.event_loop.asyncio import AsyncioEventLoop
- EventLoop = AsyncioEventLoop
-
-
-__all__ = ('EventLoop')
+++ /dev/null
-"""Event loop implementation that uses the `asyncio` standard module.
-
-The `asyncio` module was added to python standard library on 3.4, and it
-provides a pure python implementation of an event loop library. It is used
-as a fallback in case pyuv is not available(on python implementations other
-than CPython).
-
-Earlier python versions are supported through the `trollius` package, which
-is a backport of `asyncio` that works on Python 2.6+.
-"""
-from __future__ import absolute_import
-
-import logging
-import os
-import sys
-from collections import deque
-
-try:
- # For python 3.4+, use the standard library module
- import asyncio
-except (ImportError, SyntaxError):
- # Fallback to trollius
- import trollius as asyncio
-
-from pynvim.msgpack_rpc.event_loop.base import BaseEventLoop
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-loop_cls = asyncio.SelectorEventLoop
-if os.name == 'nt':
- from asyncio.windows_utils import PipeHandle
- import msvcrt
-
- # On windows use ProactorEventLoop which support pipes and is backed by the
- # more powerful IOCP facility
- # NOTE: we override in the stdio case, because it doesn't work.
- loop_cls = asyncio.ProactorEventLoop
-
-
-class AsyncioEventLoop(BaseEventLoop, asyncio.Protocol,
- asyncio.SubprocessProtocol):
-
- """`BaseEventLoop` subclass that uses `asyncio` as a backend."""
-
- def connection_made(self, transport):
- """Used to signal `asyncio.Protocol` of a successful connection."""
- self._transport = transport
- self._raw_transport = transport
- if isinstance(transport, asyncio.SubprocessTransport):
- self._transport = transport.get_pipe_transport(0)
-
- def connection_lost(self, exc):
- """Used to signal `asyncio.Protocol` of a lost connection."""
- self._on_error(exc.args[0] if exc else 'EOF')
-
- def data_received(self, data):
- """Used to signal `asyncio.Protocol` of incoming data."""
- if self._on_data:
- self._on_data(data)
- return
- self._queued_data.append(data)
-
- def pipe_connection_lost(self, fd, exc):
- """Used to signal `asyncio.SubprocessProtocol` of a lost connection."""
- self._on_error(exc.args[0] if exc else 'EOF')
-
- def pipe_data_received(self, fd, data):
- """Used to signal `asyncio.SubprocessProtocol` of incoming data."""
- if fd == 2: # stderr fd number
- self._on_stderr(data)
- elif self._on_data:
- self._on_data(data)
- else:
- self._queued_data.append(data)
-
- def process_exited(self):
- """Used to signal `asyncio.SubprocessProtocol` when the child exits."""
- self._on_error('EOF')
-
- def _init(self):
- self._loop = loop_cls()
- self._queued_data = deque()
- self._fact = lambda: self
- self._raw_transport = None
-
- def _connect_tcp(self, address, port):
- coroutine = self._loop.create_connection(self._fact, address, port)
- self._loop.run_until_complete(coroutine)
-
- def _connect_socket(self, path):
- if os.name == 'nt':
- coroutine = self._loop.create_pipe_connection(self._fact, path)
- else:
- coroutine = self._loop.create_unix_connection(self._fact, path)
- self._loop.run_until_complete(coroutine)
-
- def _connect_stdio(self):
- if os.name == 'nt':
- pipe = PipeHandle(msvcrt.get_osfhandle(sys.stdin.fileno()))
- else:
- pipe = sys.stdin
- coroutine = self._loop.connect_read_pipe(self._fact, pipe)
- self._loop.run_until_complete(coroutine)
- pass # replaces next logging statement
- #debug("native stdin connection successful")
-
- # Make sure subprocesses don't clobber stdout,
- # send the output to stderr instead.
- rename_stdout = os.dup(sys.stdout.fileno())
- os.dup2(sys.stderr.fileno(), sys.stdout.fileno())
-
- if os.name == 'nt':
- pipe = PipeHandle(msvcrt.get_osfhandle(rename_stdout))
- else:
- pipe = os.fdopen(rename_stdout, 'wb')
- coroutine = self._loop.connect_write_pipe(self._fact, pipe)
- self._loop.run_until_complete(coroutine)
- pass # replaces next logging statement
- #debug("native stdout connection successful")
-
- def _connect_child(self, argv):
- if os.name != 'nt':
- self._child_watcher = asyncio.get_child_watcher()
- self._child_watcher.attach_loop(self._loop)
- coroutine = self._loop.subprocess_exec(self._fact, *argv)
- self._loop.run_until_complete(coroutine)
-
- def _start_reading(self):
- pass
-
- def _send(self, data):
- self._transport.write(data)
-
- def _run(self):
- while self._queued_data:
- self._on_data(self._queued_data.popleft())
- self._loop.run_forever()
-
- def _stop(self):
- self._loop.stop()
-
- def _close(self):
- if self._raw_transport is not None:
- self._raw_transport.close()
- self._loop.close()
-
- def _threadsafe_call(self, fn):
- self._loop.call_soon_threadsafe(fn)
-
- def _setup_signals(self, signals):
- if os.name == 'nt':
- # add_signal_handler is not supported in win32
- self._signals = []
- return
-
- self._signals = list(signals)
- for signum in self._signals:
- self._loop.add_signal_handler(signum, self._on_signal, signum)
-
- def _teardown_signals(self):
- for signum in self._signals:
- self._loop.remove_signal_handler(signum)
+++ /dev/null
-"""Common code for event loop implementations."""
-import logging
-import signal
-import threading
-
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-
-# When signals are restored, the event loop library may reset SIGINT to SIG_DFL
-# which exits the program. To be able to restore the python interpreter to it's
-# default state, we keep a reference to the default handler
-default_int_handler = signal.getsignal(signal.SIGINT)
-main_thread = threading.current_thread()
-
-
-class BaseEventLoop(object):
-
- """Abstract base class for all event loops.
-
- Event loops act as the bottom layer for Nvim sessions created by this
- library. They hide system/transport details behind a simple interface for
- reading/writing bytes to the connected Nvim instance.
-
- This class exposes public methods for interacting with the underlying
- event loop and delegates implementation-specific work to the following
- methods, which subclasses are expected to implement:
-
- - `_init()`: Implementation-specific initialization
- - `_connect_tcp(address, port)`: connect to Nvim using tcp/ip
- - `_connect_socket(path)`: Same as tcp, but use a UNIX domain socket or
- named pipe.
- - `_connect_stdio()`: Use stdin/stdout as the connection to Nvim
- - `_connect_child(argv)`: Use the argument vector `argv` to spawn an
- embedded Nvim that has its stdin/stdout connected to the event loop.
- - `_start_reading()`: Called after any of _connect_* methods. Can be used
- to perform any post-connection setup or validation.
- - `_send(data)`: Send `data`(byte array) to Nvim. The data is only
- - `_run()`: Runs the event loop until stopped or the connection is closed.
- calling the following methods when some event happens:
- actually sent when the event loop is running.
- - `_on_data(data)`: When Nvim sends some data.
- - `_on_signal(signum)`: When a signal is received.
- - `_on_error(message)`: When a non-recoverable error occurs(eg:
- connection lost)
- - `_stop()`: Stop the event loop
- - `_interrupt(data)`: Like `stop()`, but may be called from other threads
- this.
- - `_setup_signals(signals)`: Add implementation-specific listeners for
- for `signals`, which is a list of OS-specific signal numbers.
- - `_teardown_signals()`: Removes signal listeners set by `_setup_signals`
- """
-
- def __init__(self, transport_type, *args):
- """Initialize and connect the event loop instance.
-
- The only arguments are the transport type and transport-specific
- configuration, like this:
-
- >>> BaseEventLoop('tcp', '127.0.0.1', 7450)
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
- >>> BaseEventLoop('socket', '/tmp/nvim-socket')
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
- >>> BaseEventLoop('stdio')
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
- >>> BaseEventLoop('child',
- ['nvim', '--embed', '--headless', '-u', 'NONE'])
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
-
- This calls the implementation-specific initialization
- `_init`, one of the `_connect_*` methods(based on `transport_type`)
- and `_start_reading()`
- """
- self._transport_type = transport_type
- self._signames = dict((k, v) for v, k in signal.__dict__.items()
- if v.startswith('SIG'))
- self._on_data = None
- self._error = None
- self._init()
- try:
- getattr(self, '_connect_{}'.format(transport_type))(*args)
- except Exception as e:
- self.close()
- raise e
- self._start_reading()
-
- def connect_tcp(self, address, port):
- """Connect to tcp/ip `address`:`port`. Delegated to `_connect_tcp`."""
- pass # replaces next logging statement
- #info('Connecting to TCP address: %s:%d', address, port)
- self._connect_tcp(address, port)
-
- def connect_socket(self, path):
- """Connect to socket at `path`. Delegated to `_connect_socket`."""
- pass # replaces next logging statement
- #info('Connecting to %s', path)
- self._connect_socket(path)
-
- def connect_stdio(self):
- """Connect using stdin/stdout. Delegated to `_connect_stdio`."""
- pass # replaces next logging statement
- #info('Preparing stdin/stdout for streaming data')
- self._connect_stdio()
-
- def connect_child(self, argv):
- """Connect a new Nvim instance. Delegated to `_connect_child`."""
- pass # replaces next logging statement
- #info('Spawning a new nvim instance')
- self._connect_child(argv)
-
- def send(self, data):
- """Queue `data` for sending to Nvim."""
- pass # replaces next logging statement
- #debug("Sending '%s'", data)
- self._send(data)
-
- def threadsafe_call(self, fn):
- """Call a function in the event loop thread.
-
- This is the only safe way to interact with a session from other
- threads.
- """
- self._threadsafe_call(fn)
-
- def run(self, data_cb):
- """Run the event loop."""
- if self._error:
- err = self._error
- if isinstance(self._error, KeyboardInterrupt):
- # KeyboardInterrupt is not destructive(it may be used in
- # the REPL).
- # After throwing KeyboardInterrupt, cleanup the _error field
- # so the loop may be started again
- self._error = None
- raise err
- self._on_data = data_cb
- if threading.current_thread() == main_thread:
- self._setup_signals([signal.SIGINT, signal.SIGTERM])
- pass # replaces next logging statement
- #debug('Entering event loop')
- self._run()
- pass # replaces next logging statement
- #debug('Exited event loop')
- if threading.current_thread() == main_thread:
- self._teardown_signals()
- signal.signal(signal.SIGINT, default_int_handler)
- self._on_data = None
-
- def stop(self):
- """Stop the event loop."""
- self._stop()
- pass # replaces next logging statement
- #debug('Stopped event loop')
-
- def close(self):
- """Stop the event loop."""
- self._close()
- pass # replaces next logging statement
- #debug('Closed event loop')
-
- def _on_signal(self, signum):
- msg = 'Received {}'.format(self._signames[signum])
- pass # replaces next logging statement
- #debug(msg)
- if signum == signal.SIGINT and self._transport_type == 'stdio':
- # When the transport is stdio, we are probably running as a Nvim
- # child process. In that case, we don't want to be killed by
- # ctrl+C
- return
- cls = Exception
- if signum == signal.SIGINT:
- cls = KeyboardInterrupt
- self._error = cls(msg)
- self.stop()
-
- def _on_error(self, error):
- pass # replaces next logging statement
- #debug(error)
- self._error = OSError(error)
- self.stop()
-
- def _on_interrupt(self):
- self.stop()
+++ /dev/null
-"""Event loop implementation that uses pyuv(libuv-python bindings)."""
-import sys
-from collections import deque
-
-import pyuv
-
-from pynvim.msgpack_rpc.event_loop.base import BaseEventLoop
-
-
-class UvEventLoop(BaseEventLoop):
-
- """`BaseEventLoop` subclass that uses `pvuv` as a backend."""
-
- def _init(self):
- self._loop = pyuv.Loop()
- self._async = pyuv.Async(self._loop, self._on_async)
- self._connection_error = None
- self._error_stream = None
- self._callbacks = deque()
-
- def _on_connect(self, stream, error):
- self.stop()
- if error:
- msg = 'Cannot connect to {}: {}'.format(
- self._connect_address, pyuv.errno.strerror(error))
- self._connection_error = OSError(msg)
- return
- self._read_stream = self._write_stream = stream
-
- def _on_read(self, handle, data, error):
- if error or not data:
- msg = pyuv.errno.strerror(error) if error else 'EOF'
- self._on_error(msg)
- return
- if handle == self._error_stream:
- return
- self._on_data(data)
-
- def _on_write(self, handle, error):
- if error:
- msg = pyuv.errno.strerror(error)
- self._on_error(msg)
-
- def _on_exit(self, handle, exit_status, term_signal):
- self._on_error('EOF')
-
- def _disconnected(self, *args):
- raise OSError('Not connected to Nvim')
-
- def _connect_tcp(self, address, port):
- stream = pyuv.TCP(self._loop)
- self._connect_address = '{}:{}'.format(address, port)
- stream.connect((address, port), self._on_connect)
-
- def _connect_socket(self, path):
- stream = pyuv.Pipe(self._loop)
- self._connect_address = path
- stream.connect(path, self._on_connect)
-
- def _connect_stdio(self):
- self._read_stream = pyuv.Pipe(self._loop)
- self._read_stream.open(sys.stdin.fileno())
- self._write_stream = pyuv.Pipe(self._loop)
- self._write_stream.open(sys.stdout.fileno())
-
- def _connect_child(self, argv):
- self._write_stream = pyuv.Pipe(self._loop)
- self._read_stream = pyuv.Pipe(self._loop)
- self._error_stream = pyuv.Pipe(self._loop)
- stdin = pyuv.StdIO(self._write_stream,
- flags=pyuv.UV_CREATE_PIPE + pyuv.UV_READABLE_PIPE)
- stdout = pyuv.StdIO(self._read_stream,
- flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
- stderr = pyuv.StdIO(self._error_stream,
- flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
- pyuv.Process.spawn(self._loop,
- args=argv,
- exit_callback=self._on_exit,
- flags=pyuv.UV_PROCESS_WINDOWS_HIDE,
- stdio=(stdin, stdout, stderr,))
- self._error_stream.start_read(self._on_read)
-
- def _start_reading(self):
- if self._transport_type in ['tcp', 'socket']:
- self._loop.run()
- if self._connection_error:
- self.run = self.send = self._disconnected
- raise self._connection_error
- self._read_stream.start_read(self._on_read)
-
- def _send(self, data):
- self._write_stream.write(data, self._on_write)
-
- def _run(self):
- self._loop.run(pyuv.UV_RUN_DEFAULT)
-
- def _stop(self):
- self._loop.stop()
-
- def _close(self):
- pass
-
- def _threadsafe_call(self, fn):
- self._callbacks.append(fn)
- self._async.send()
-
- def _on_async(self, handle):
- while self._callbacks:
- self._callbacks.popleft()()
-
- def _setup_signals(self, signals):
- self._signal_handles = []
-
- def handler(h, signum):
- self._on_signal(signum)
-
- for signum in signals:
- handle = pyuv.Signal(self._loop)
- handle.start(handler, signum)
- self._signal_handles.append(handle)
-
- def _teardown_signals(self):
- for handle in self._signal_handles:
- handle.stop()
+++ /dev/null
-"""Msgpack handling in the event loop pipeline."""
-import logging
-
-from msgpack import Packer, Unpacker
-
-from pynvim.compat import unicode_errors_default
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-
-class MsgpackStream(object):
-
- """Two-way msgpack stream that wraps a event loop byte stream.
-
- This wraps the event loop interface for reading/writing bytes and
- exposes an interface for reading/writing msgpack documents.
- """
-
- def __init__(self, event_loop):
- """Wrap `event_loop` on a msgpack-aware interface."""
- self.loop = event_loop
- self._packer = Packer(unicode_errors=unicode_errors_default)
- self._unpacker = Unpacker(unicode_errors=unicode_errors_default)
- self._message_cb = None
-
- def threadsafe_call(self, fn):
- """Wrapper around `BaseEventLoop.threadsafe_call`."""
- self.loop.threadsafe_call(fn)
-
- def send(self, msg):
- """Queue `msg` for sending to Nvim."""
- pass # replaces next logging statement
- #debug('sent %s', msg)
- self.loop.send(self._packer.pack(msg))
-
- def run(self, message_cb):
- """Run the event loop to receive messages from Nvim.
-
- While the event loop is running, `message_cb` will be called whenever
- a message has been successfully parsed from the input stream.
- """
- self._message_cb = message_cb
- self.loop.run(self._on_data)
- self._message_cb = None
-
- def stop(self):
- """Stop the event loop."""
- self.loop.stop()
-
- def close(self):
- """Close the event loop."""
- self.loop.close()
-
- def _on_data(self, data):
- self._unpacker.feed(data)
- while True:
- try:
- pass # replaces next logging statement
- #debug('waiting for message...')
- msg = next(self._unpacker)
- pass # replaces next logging statement
- #debug('received message: %s', msg)
- self._message_cb(msg)
- except StopIteration:
- pass # replaces next logging statement
- #debug('unpacker needs more data...')
- break
+++ /dev/null
-"""Synchronous msgpack-rpc session layer."""
-import logging
-import threading
-from collections import deque
-from traceback import format_exc
-
-import greenlet
-
-from pynvim.compat import check_async
-
-logger = logging.getLogger(__name__)
-error, debug, info, warn = (logger.error, logger.debug, logger.info,
- logger.warning,)
-
-
-class Session(object):
-
- """Msgpack-rpc session layer that uses coroutines for a synchronous API.
-
- This class provides the public msgpack-rpc API required by this library.
- It uses the greenlet module to handle requests and notifications coming
- from Nvim with a synchronous API.
- """
-
- def __init__(self, async_session):
- """Wrap `async_session` on a synchronous msgpack-rpc interface."""
- self._async_session = async_session
- self._request_cb = self._notification_cb = None
- self._pending_messages = deque()
- self._is_running = False
- self._setup_exception = None
- self.loop = async_session.loop
- self._loop_thread = None
-
- def threadsafe_call(self, fn, *args, **kwargs):
- """Wrapper around `AsyncSession.threadsafe_call`."""
- def handler():
- try:
- fn(*args, **kwargs)
- except Exception:
- pass # replaces next logging statement
- #warn("error caught while excecuting async callback\n%s\n",
- #format_exc())
-
- def greenlet_wrapper():
- gr = greenlet.greenlet(handler)
- gr.switch()
-
- self._async_session.threadsafe_call(greenlet_wrapper)
-
- def next_message(self):
- """Block until a message(request or notification) is available.
-
- If any messages were previously enqueued, return the first in queue.
- If not, run the event loop until one is received.
- """
- if self._is_running:
- raise Exception('Event loop already running')
- if self._pending_messages:
- return self._pending_messages.popleft()
- self._async_session.run(self._enqueue_request_and_stop,
- self._enqueue_notification_and_stop)
- if self._pending_messages:
- return self._pending_messages.popleft()
-
- def request(self, method, *args, **kwargs):
- """Send a msgpack-rpc request and block until as response is received.
-
- If the event loop is running, this method must have been called by a
- request or notification handler running on a greenlet. In that case,
- send the quest and yield to the parent greenlet until a response is
- available.
-
- When the event loop is not running, it will perform a blocking request
- like this:
- - Send the request
- - Run the loop until the response is available
- - Put requests/notifications received while waiting into a queue
-
- If the `async_` flag is present and True, a asynchronous notification
- is sent instead. This will never block, and the return value or error
- is ignored.
- """
- async_ = check_async(kwargs.pop('async_', None), kwargs, False)
- if async_:
- self._async_session.notify(method, args)
- return
-
- if kwargs:
- raise ValueError("request got unsupported keyword argument(s): {}"
- .format(', '.join(kwargs.keys())))
-
- if self._is_running:
- v = self._yielding_request(method, args)
- else:
- v = self._blocking_request(method, args)
- if not v:
- # EOF
- raise OSError('EOF')
- err, rv = v
- if err:
- pass # replaces next logging statement
- #info("'Received error: %s", err)
- raise self.error_wrapper(err)
- return rv
-
- def run(self, request_cb, notification_cb, setup_cb=None):
- """Run the event loop to receive requests and notifications from Nvim.
-
- Like `AsyncSession.run()`, but `request_cb` and `notification_cb` are
- inside greenlets.
- """
- self._request_cb = request_cb
- self._notification_cb = notification_cb
- self._is_running = True
- self._setup_exception = None
- self._loop_thread = threading.current_thread()
-
- def on_setup():
- try:
- setup_cb()
- except Exception as e:
- self._setup_exception = e
- self.stop()
-
- if setup_cb:
- # Create a new greenlet to handle the setup function
- gr = greenlet.greenlet(on_setup)
- gr.switch()
-
- if self._setup_exception:
- pass # replaces next logging statement
- #error('Setup error: {}'.format(self._setup_exception))
- raise self._setup_exception
-
- # Process all pending requests and notifications
- while self._pending_messages:
- msg = self._pending_messages.popleft()
- getattr(self, '_on_{}'.format(msg[0]))(*msg[1:])
- self._async_session.run(self._on_request, self._on_notification)
- self._is_running = False
- self._request_cb = None
- self._notification_cb = None
- self._loop_thread = None
-
- if self._setup_exception:
- raise self._setup_exception
-
- def stop(self):
- """Stop the event loop."""
- self._async_session.stop()
-
- def close(self):
- """Close the event loop."""
- self._async_session.close()
-
- def _yielding_request(self, method, args):
- gr = greenlet.getcurrent()
- parent = gr.parent
-
- def response_cb(err, rv):
- pass # replaces next logging statement
- #debug('response is available for greenlet %s, switching back', gr)
- gr.switch(err, rv)
-
- self._async_session.request(method, args, response_cb)
- pass # replaces next logging statement
- #debug('yielding from greenlet %s to wait for response', gr)
- return parent.switch()
-
- def _blocking_request(self, method, args):
- result = []
-
- def response_cb(err, rv):
- result.extend([err, rv])
- self.stop()
-
- self._async_session.request(method, args, response_cb)
- self._async_session.run(self._enqueue_request,
- self._enqueue_notification)
- return result
-
- def _enqueue_request_and_stop(self, name, args, response):
- self._enqueue_request(name, args, response)
- self.stop()
-
- def _enqueue_notification_and_stop(self, name, args):
- self._enqueue_notification(name, args)
- self.stop()
-
- def _enqueue_request(self, name, args, response):
- self._pending_messages.append(('request', name, args, response,))
-
- def _enqueue_notification(self, name, args):
- self._pending_messages.append(('notification', name, args,))
-
- def _on_request(self, name, args, response):
- def handler():
- try:
- rv = self._request_cb(name, args)
- pass # replaces next logging statement
- #debug('greenlet %s finished executing, '
- #+ 'sending %s as response', gr, rv)
- response.send(rv)
- except ErrorResponse as err:
- pass # replaces next logging statement
- #warn("error response from request '%s %s': %s", name,
- #args, format_exc())
- response.send(err.args[0], error=True)
- except Exception as err:
- pass # replaces next logging statement
- #warn("error caught while processing request '%s %s': %s", name,
- #args, format_exc())
- response.send(repr(err) + "\n" + format_exc(5), error=True)
- pass # replaces next logging statement
- #debug('greenlet %s is now dying...', gr)
-
- # Create a new greenlet to handle the request
- gr = greenlet.greenlet(handler)
- pass # replaces next logging statement
- #debug('received rpc request, greenlet %s will handle it', gr)
- gr.switch()
-
- def _on_notification(self, name, args):
- def handler():
- try:
- self._notification_cb(name, args)
- pass # replaces next logging statement
- #debug('greenlet %s finished executing', gr)
- except Exception:
- pass # replaces next logging statement
- #warn("error caught while processing notification '%s %s': %s",
- #name, args, format_exc())
-
- pass # replaces next logging statement
- #debug('greenlet %s is now dying...', gr)
-
- gr = greenlet.greenlet(handler)
- pass # replaces next logging statement
- #debug('received rpc notification, greenlet %s will handle it', gr)
- gr.switch()
-
-
-class ErrorResponse(BaseException):
-
- """Raise this in a request handler to respond with a given error message.
-
- Unlike when other exceptions are caught, this gives full control off the
- error response sent. When "ErrorResponse(msg)" is caught "msg" will be
- sent verbatim as the error response.No traceback will be appended.
- """
-
- pass
+++ /dev/null
-"""Nvim plugin/host subpackage."""
-
-from pynvim.plugin.decorators import (autocmd, command, decode, encoding, function,
- plugin, rpc_export, shutdown_hook)
-from pynvim.plugin.host import Host
-
-
-__all__ = ('Host', 'plugin', 'rpc_export', 'command', 'autocmd',
- 'function', 'encoding', 'decode', 'shutdown_hook')
+++ /dev/null
-"""Decorators used by python host plugin system."""
-
-import inspect
-import logging
-
-from pynvim.compat import IS_PYTHON3, unicode_errors_default
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-__all__ = ('plugin', 'rpc_export', 'command', 'autocmd', 'function',
- 'encoding', 'decode', 'shutdown_hook')
-
-
-def plugin(cls):
- """Tag a class as a plugin.
-
- This decorator is required to make the class methods discoverable by the
- plugin_load method of the host.
- """
- cls._nvim_plugin = True
- # the _nvim_bind attribute is set to True by default, meaning that
- # decorated functions have a bound Nvim instance as first argument.
- # For methods in a plugin-decorated class this is not required, because
- # the class initializer will already receive the nvim object.
- predicate = lambda fn: hasattr(fn, '_nvim_bind')
- for _, fn in inspect.getmembers(cls, predicate):
- if IS_PYTHON3:
- fn._nvim_bind = False
- else:
- fn.im_func._nvim_bind = False
- return cls
-
-
-def rpc_export(rpc_method_name, sync=False):
- """Export a function or plugin method as a msgpack-rpc request handler."""
- def dec(f):
- f._nvim_rpc_method_name = rpc_method_name
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = False
- return f
- return dec
-
-
-def command(name, nargs=0, complete=None, range=None, count=None, bang=False,
- register=False, sync=False, allow_nested=False, eval=None):
- """Tag a function or plugin method as a Nvim command handler."""
- def dec(f):
- f._nvim_rpc_method_name = 'command:{}'.format(name)
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = True
-
- opts = {}
-
- if range is not None:
- opts['range'] = '' if range is True else str(range)
- elif count is not None:
- opts['count'] = count
-
- if bang:
- opts['bang'] = ''
-
- if register:
- opts['register'] = ''
-
- if nargs:
- opts['nargs'] = nargs
-
- if complete:
- opts['complete'] = complete
-
- if eval:
- opts['eval'] = eval
-
- if not sync and allow_nested:
- rpc_sync = "urgent"
- else:
- rpc_sync = sync
-
- f._nvim_rpc_spec = {
- 'type': 'command',
- 'name': name,
- 'sync': rpc_sync,
- 'opts': opts
- }
- return f
- return dec
-
-
-def autocmd(name, pattern='*', sync=False, allow_nested=False, eval=None):
- """Tag a function or plugin method as a Nvim autocommand handler."""
- def dec(f):
- f._nvim_rpc_method_name = 'autocmd:{}:{}'.format(name, pattern)
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = True
-
- opts = {
- 'pattern': pattern
- }
-
- if eval:
- opts['eval'] = eval
-
- if not sync and allow_nested:
- rpc_sync = "urgent"
- else:
- rpc_sync = sync
-
- f._nvim_rpc_spec = {
- 'type': 'autocmd',
- 'name': name,
- 'sync': rpc_sync,
- 'opts': opts
- }
- return f
- return dec
-
-
-def function(name, range=False, sync=False, allow_nested=False, eval=None):
- """Tag a function or plugin method as a Nvim function handler."""
- def dec(f):
- f._nvim_rpc_method_name = 'function:{}'.format(name)
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = True
-
- opts = {}
-
- if range:
- opts['range'] = '' if range is True else str(range)
-
- if eval:
- opts['eval'] = eval
-
- if not sync and allow_nested:
- rpc_sync = "urgent"
- else:
- rpc_sync = sync
-
- f._nvim_rpc_spec = {
- 'type': 'function',
- 'name': name,
- 'sync': rpc_sync,
- 'opts': opts
- }
- return f
- return dec
-
-
-def shutdown_hook(f):
- """Tag a function or method as a shutdown hook."""
- f._nvim_shutdown_hook = True
- f._nvim_bind = True
- return f
-
-
-def decode(mode=unicode_errors_default):
- """Configure automatic encoding/decoding of strings."""
- def dec(f):
- f._nvim_decode = mode
- return f
- return dec
-
-
-def encoding(encoding=True):
- """DEPRECATED: use pynvim.decode()."""
- if isinstance(encoding, str):
- encoding = True
-
- def dec(f):
- f._nvim_decode = encoding
- return f
- return dec
+++ /dev/null
-"""Implements a Nvim host for python plugins."""
-import imp
-import inspect
-import logging
-import os
-import os.path
-import re
-from functools import partial
-from traceback import format_exc
-
-from pynvim.api import decode_if_bytes, walk
-from pynvim.compat import IS_PYTHON3, find_module
-from pynvim.msgpack_rpc import ErrorResponse
-from pynvim.plugin import script_host
-from pynvim.util import format_exc_skip, get_client_info
-
-__all__ = ('Host')
-
-logger = logging.getLogger(__name__)
-error, debug, info, warn = (logger.error, logger.debug, logger.info,
- logger.warning,)
-
-host_method_spec = {"poll": {}, "specs": {"nargs": 1}, "shutdown": {}}
-
-
-class Host(object):
-
- """Nvim host for python plugins.
-
- Takes care of loading/unloading plugins and routing msgpack-rpc
- requests/notifications to the appropriate handlers.
- """
-
- def __init__(self, nvim):
- """Set handlers for plugin_load/plugin_unload."""
- self.nvim = nvim
- self._specs = {}
- self._loaded = {}
- self._load_errors = {}
- self._notification_handlers = {
- 'nvim_error_event': self._on_error_event
- }
- self._request_handlers = {
- 'poll': lambda: 'ok',
- 'specs': self._on_specs_request,
- 'shutdown': self.shutdown
- }
-
- # Decode per default for Python3
- self._decode_default = IS_PYTHON3
-
- def _on_async_err(self, msg):
- # uncaught python exception
- self.nvim.err_write(msg, async_=True)
-
- def _on_error_event(self, kind, msg):
- # error from nvim due to async request
- # like nvim.command(..., async_=True)
- errmsg = "{}: Async request caused an error:\n{}\n".format(
- self.name, decode_if_bytes(msg))
- self.nvim.err_write(errmsg, async_=True)
- return errmsg
-
- def start(self, plugins):
- """Start listening for msgpack-rpc requests and notifications."""
- self.nvim.run_loop(self._on_request,
- self._on_notification,
- lambda: self._load(plugins),
- err_cb=self._on_async_err)
-
- def shutdown(self):
- """Shutdown the host."""
- self._unload()
- self.nvim.stop_loop()
-
- def _wrap_delayed_function(self, cls, delayed_handlers, name, sync,
- module_handlers, path, *args):
- # delete the delayed handlers to be sure
- for handler in delayed_handlers:
- method_name = handler._nvim_registered_name
- if handler._nvim_rpc_sync:
- del self._request_handlers[method_name]
- else:
- del self._notification_handlers[method_name]
- # create an instance of the plugin and pass the nvim object
- plugin = cls(self._configure_nvim_for(cls))
-
- # discover handlers in the plugin instance
- self._discover_functions(plugin, module_handlers, path, False)
-
- if sync:
- self._request_handlers[name](*args)
- else:
- self._notification_handlers[name](*args)
-
- def _wrap_function(self, fn, sync, decode, nvim_bind, name, *args):
- if decode:
- args = walk(decode_if_bytes, args, decode)
- if nvim_bind is not None:
- args.insert(0, nvim_bind)
- try:
- return fn(*args)
- except Exception:
- if sync:
- msg = ("error caught in request handler '{} {}':\n{}"
- .format(name, args, format_exc_skip(1)))
- raise ErrorResponse(msg)
- else:
- msg = ("error caught in async handler '{} {}'\n{}\n"
- .format(name, args, format_exc_skip(1)))
- self._on_async_err(msg + "\n")
-
- def _on_request(self, name, args):
- """Handle a msgpack-rpc request."""
- if IS_PYTHON3:
- name = decode_if_bytes(name)
- handler = self._request_handlers.get(name, None)
- if not handler:
- msg = self._missing_handler_error(name, 'request')
- pass # replaces next logging statement
- #error(msg)
- raise ErrorResponse(msg)
-
- pass # replaces next logging statement
- #debug('calling request handler for "%s", args: "%s"', name, args)
- rv = handler(*args)
- pass # replaces next logging statement
- #debug("request handler for '%s %s' returns: %s", name, args, rv)
- return rv
-
- def _on_notification(self, name, args):
- """Handle a msgpack-rpc notification."""
- if IS_PYTHON3:
- name = decode_if_bytes(name)
- handler = self._notification_handlers.get(name, None)
- if not handler:
- msg = self._missing_handler_error(name, 'notification')
- pass # replaces next logging statement
- #error(msg)
- self._on_async_err(msg + "\n")
- return
-
- pass # replaces next logging statement
- #debug('calling notification handler for "%s", args: "%s"', name, args)
- handler(*args)
-
- def _missing_handler_error(self, name, kind):
- msg = 'no {} handler registered for "{}"'.format(kind, name)
- pathmatch = re.match(r'(.+):[^:]+:[^:]+', name)
- if pathmatch:
- loader_error = self._load_errors.get(pathmatch.group(1))
- if loader_error is not None:
- msg = msg + "\n" + loader_error
- return msg
-
- def _load(self, plugins):
- has_script = False
- for path in plugins:
- err = None
- if path in self._loaded:
- pass # replaces next logging statement
- #error('{} is already loaded'.format(path))
- continue
- try:
- if path == "script_host.py":
- module = script_host
- has_script = True
- else:
- directory, name = os.path.split(os.path.splitext(path)[0])
- file, pathname, descr = find_module(name, [directory])
- module = imp.load_module(name, file, pathname, descr)
- handlers = []
- self._discover_classes(module, handlers, path)
- self._discover_functions(module, handlers, path, False)
- if not handlers:
- pass # replaces next logging statement
- #error('{} exports no handlers'.format(path))
- continue
- self._loaded[path] = {'handlers': handlers, 'module': module}
- except Exception as e:
- err = ('Encountered {} loading plugin at {}: {}\n{}'
- .format(type(e).__name__, path, e, format_exc(5)))
- pass # replaces next logging statement
- #error(err)
- self._load_errors[path] = err
-
- kind = ("script-host" if len(plugins) == 1 and has_script
- else "rplugin-host")
- info = get_client_info(kind, 'host', host_method_spec)
- self.name = info[0]
- self.nvim.api.set_client_info(*info, async_=True)
-
- def _unload(self):
- for path, plugin in self._loaded.items():
- handlers = plugin['handlers']
- for handler in handlers:
- method_name = handler._nvim_registered_name
- if hasattr(handler, '_nvim_shutdown_hook'):
- handler()
- elif handler._nvim_rpc_sync:
- del self._request_handlers[method_name]
- else:
- del self._notification_handlers[method_name]
- self._specs = {}
- self._loaded = {}
-
- def _discover_classes(self, module, handlers, plugin_path):
- for _, cls in inspect.getmembers(module, inspect.isclass):
- if getattr(cls, '_nvim_plugin', False):
- # discover handlers in the plugin instance
- self._discover_functions(cls, handlers, plugin_path, True)
-
- def _discover_functions(self, obj, handlers, plugin_path, delay):
- def predicate(o):
- return hasattr(o, '_nvim_rpc_method_name')
-
- cls_handlers = []
- specs = []
- objdecode = getattr(obj, '_nvim_decode', self._decode_default)
- for _, fn in inspect.getmembers(obj, predicate):
- method = fn._nvim_rpc_method_name
- if fn._nvim_prefix_plugin_path:
- method = '{}:{}'.format(plugin_path, method)
- sync = fn._nvim_rpc_sync
- if delay:
- fn_wrapped = partial(self._wrap_delayed_function, obj,
- cls_handlers, method, sync,
- handlers, plugin_path)
- else:
- decode = getattr(fn, '_nvim_decode', objdecode)
- nvim_bind = None
- if fn._nvim_bind:
- nvim_bind = self._configure_nvim_for(fn)
-
- fn_wrapped = partial(self._wrap_function, fn,
- sync, decode, nvim_bind, method)
- self._copy_attributes(fn, fn_wrapped)
- fn_wrapped._nvim_registered_name = method
- # register in the rpc handler dict
- if sync:
- if method in self._request_handlers:
- raise Exception(('Request handler for "{}" is '
- + 'already registered').format(method))
- self._request_handlers[method] = fn_wrapped
- else:
- if method in self._notification_handlers:
- raise Exception(('Notification handler for "{}" is '
- + 'already registered').format(method))
- self._notification_handlers[method] = fn_wrapped
- if hasattr(fn, '_nvim_rpc_spec'):
- specs.append(fn._nvim_rpc_spec)
- handlers.append(fn_wrapped)
- cls_handlers.append(fn_wrapped)
- if specs:
- self._specs[plugin_path] = specs
-
- def _copy_attributes(self, fn, fn2):
- # Copy _nvim_* attributes from the original function
- for attr in dir(fn):
- if attr.startswith('_nvim_'):
- setattr(fn2, attr, getattr(fn, attr))
-
- def _on_specs_request(self, path):
- if IS_PYTHON3:
- path = decode_if_bytes(path)
- if path in self._load_errors:
- self.nvim.out_write(self._load_errors[path] + '\n')
- return self._specs.get(path, 0)
-
- def _configure_nvim_for(self, obj):
- # Configure a nvim instance for obj (checks encoding configuration)
- nvim = self.nvim
- decode = getattr(obj, '_nvim_decode', self._decode_default)
- if decode:
- nvim = nvim.with_decode(decode)
- return nvim
+++ /dev/null
-"""Legacy python/python3-vim emulation."""
-import imp
-import io
-import logging
-import os
-import sys
-from types import ModuleType
-
-from pynvim.api import Nvim, walk
-from pynvim.compat import IS_PYTHON3
-from pynvim.msgpack_rpc import ErrorResponse
-from pynvim.plugin.decorators import plugin, rpc_export
-from pynvim.util import format_exc_skip
-
-__all__ = ('ScriptHost',)
-
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warn,)
-
-if IS_PYTHON3:
- basestring = str
-
- if sys.version_info >= (3, 4):
- from importlib.machinery import PathFinder
-
- PYTHON_SUBDIR = 'python3'
-else:
- PYTHON_SUBDIR = 'python2'
-
-
-@plugin
-class ScriptHost(object):
-
- """Provides an environment for running python plugins created for Vim."""
-
- def __init__(self, nvim):
- """Initialize the legacy python-vim environment."""
- self.setup(nvim)
- # context where all code will run
- self.module = ModuleType('__main__')
- nvim.script_context = self.module
- # it seems some plugins assume 'sys' is already imported, so do it now
- exec('import sys', self.module.__dict__)
- self.legacy_vim = LegacyVim.from_nvim(nvim)
- sys.modules['vim'] = self.legacy_vim
- # mimic Vim by importing vim module by default.
- exec('import vim', self.module.__dict__)
- # Handle DirChanged. #296
- nvim.command(
- 'au DirChanged * call rpcnotify({}, "python_chdir", v:event.cwd)'
- .format(nvim.channel_id), async_=True)
- # XXX: Avoid race condition.
- # https://github.com/neovim/pynvim/pull/296#issuecomment-358970531
- # TODO(bfredl): when host initialization has been refactored,
- # to make __init__ safe again, the following should work:
- # os.chdir(nvim.eval('getcwd()', async_=False))
- nvim.command('call rpcnotify({}, "python_chdir", getcwd())'
- .format(nvim.channel_id), async_=True)
-
- def setup(self, nvim):
- """Setup import hooks and global streams.
-
- This will add import hooks for importing modules from runtime
- directories and patch the sys module so 'print' calls will be
- forwarded to Nvim.
- """
- self.nvim = nvim
- pass # replaces next logging statement
- #info('install import hook/path')
- self.hook = path_hook(nvim)
- sys.path_hooks.append(self.hook)
- nvim.VIM_SPECIAL_PATH = '_vim_path_'
- sys.path.append(nvim.VIM_SPECIAL_PATH)
- pass # replaces next logging statement
- #info('redirect sys.stdout and sys.stderr')
- self.saved_stdout = sys.stdout
- self.saved_stderr = sys.stderr
- sys.stdout = RedirectStream(lambda data: nvim.out_write(data))
- sys.stderr = RedirectStream(lambda data: nvim.err_write(data))
-
- def teardown(self):
- """Restore state modified from the `setup` call."""
- nvim = self.nvim
- pass # replaces next logging statement
- #info('uninstall import hook/path')
- sys.path.remove(nvim.VIM_SPECIAL_PATH)
- sys.path_hooks.remove(self.hook)
- pass # replaces next logging statement
- #info('restore sys.stdout and sys.stderr')
- sys.stdout = self.saved_stdout
- sys.stderr = self.saved_stderr
-
- @rpc_export('python_execute', sync=True)
- def python_execute(self, script, range_start, range_stop):
- """Handle the `python` ex command."""
- self._set_current_range(range_start, range_stop)
- try:
- exec(script, self.module.__dict__)
- except Exception:
- raise ErrorResponse(format_exc_skip(1))
-
- @rpc_export('python_execute_file', sync=True)
- def python_execute_file(self, file_path, range_start, range_stop):
- """Handle the `pyfile` ex command."""
- self._set_current_range(range_start, range_stop)
- with open(file_path) as f:
- script = compile(f.read(), file_path, 'exec')
- try:
- exec(script, self.module.__dict__)
- except Exception:
- raise ErrorResponse(format_exc_skip(1))
-
- @rpc_export('python_do_range', sync=True)
- def python_do_range(self, start, stop, code):
- """Handle the `pydo` ex command."""
- self._set_current_range(start, stop)
- nvim = self.nvim
- start -= 1
- fname = '_vim_pydo'
-
- # define the function
- function_def = 'def %s(line, linenr):\n %s' % (fname, code,)
- exec(function_def, self.module.__dict__)
- # get the function
- function = self.module.__dict__[fname]
- while start < stop:
- # Process batches of 5000 to avoid the overhead of making multiple
- # API calls for every line. Assuming an average line length of 100
- # bytes, approximately 488 kilobytes will be transferred per batch,
- # which can be done very quickly in a single API call.
- sstart = start
- sstop = min(start + 5000, stop)
- lines = nvim.current.buffer.api.get_lines(sstart, sstop, True)
-
- exception = None
- newlines = []
- linenr = sstart + 1
- for i, line in enumerate(lines):
- result = function(line, linenr)
- if result is None:
- # Update earlier lines, and skip to the next
- if newlines:
- end = sstart + len(newlines) - 1
- nvim.current.buffer.api.set_lines(sstart, end,
- True, newlines)
- sstart += len(newlines) + 1
- newlines = []
- pass
- elif isinstance(result, basestring):
- newlines.append(result)
- else:
- exception = TypeError('pydo should return a string '
- + 'or None, found %s instead'
- % result.__class__.__name__)
- break
- linenr += 1
-
- start = sstop
- if newlines:
- end = sstart + len(newlines)
- nvim.current.buffer.api.set_lines(sstart, end, True, newlines)
- if exception:
- raise exception
- # delete the function
- del self.module.__dict__[fname]
-
- @rpc_export('python_eval', sync=True)
- def python_eval(self, expr):
- """Handle the `pyeval` vim function."""
- return eval(expr, self.module.__dict__)
-
- @rpc_export('python_chdir', sync=False)
- def python_chdir(self, cwd):
- """Handle working directory changes."""
- os.chdir(cwd)
-
- def _set_current_range(self, start, stop):
- current = self.legacy_vim.current
- current.range = current.buffer.range(start, stop)
-
-
-class RedirectStream(io.IOBase):
- def __init__(self, redirect_handler):
- self.redirect_handler = redirect_handler
-
- def write(self, data):
- self.redirect_handler(data)
-
- def writelines(self, seq):
- self.redirect_handler('\n'.join(seq))
-
-
-if IS_PYTHON3:
- num_types = (int, float)
-else:
- num_types = (int, long, float) # noqa: F821
-
-
-def num_to_str(obj):
- if isinstance(obj, num_types):
- return str(obj)
- else:
- return obj
-
-
-class LegacyVim(Nvim):
- def eval(self, expr):
- obj = self.request("vim_eval", expr)
- return walk(num_to_str, obj)
-
-
-# Copied/adapted from :help if_pyth.
-def path_hook(nvim):
- def _get_paths():
- if nvim._thread_invalid():
- return []
- return discover_runtime_directories(nvim)
-
- def _find_module(fullname, oldtail, path):
- idx = oldtail.find('.')
- if idx > 0:
- name = oldtail[:idx]
- tail = oldtail[idx + 1:]
- fmr = imp.find_module(name, path)
- module = imp.find_module(fullname[:-len(oldtail)] + name, *fmr)
- return _find_module(fullname, tail, module.__path__)
- else:
- return imp.find_module(fullname, path)
-
- class VimModuleLoader(object):
- def __init__(self, module):
- self.module = module
-
- def load_module(self, fullname, path=None):
- # Check sys.modules, required for reload (see PEP302).
- try:
- return sys.modules[fullname]
- except KeyError:
- pass
- return imp.load_module(fullname, *self.module)
-
- class VimPathFinder(object):
- @staticmethod
- def find_module(fullname, path=None):
- """Method for Python 2.7 and 3.3."""
- try:
- return VimModuleLoader(
- _find_module(fullname, fullname, path or _get_paths()))
- except ImportError:
- return None
-
- @staticmethod
- def find_spec(fullname, target=None):
- """Method for Python 3.4+."""
- return PathFinder.find_spec(fullname, _get_paths(), target)
-
- def hook(path):
- if path == nvim.VIM_SPECIAL_PATH:
- return VimPathFinder
- else:
- raise ImportError
-
- return hook
-
-
-def discover_runtime_directories(nvim):
- rv = []
- for rtp in nvim.list_runtime_paths():
- if not os.path.exists(rtp):
- continue
- for subdir in ['pythonx', PYTHON_SUBDIR]:
- path = os.path.join(rtp, subdir)
- if os.path.exists(path):
- rv.append(path)
- return rv
+++ /dev/null
-"""Shared utility functions."""
-
-import sys
-from traceback import format_exception
-
-
-def format_exc_skip(skip, limit=None):
- """Like traceback.format_exc but allow skipping the first frames."""
- etype, val, tb = sys.exc_info()
- for i in range(skip):
- tb = tb.tb_next
- return (''.join(format_exception(etype, val, tb, limit))).rstrip()
-
-
-# Taken from SimpleNamespace in python 3
-class Version:
- """Helper class for version info."""
-
- def __init__(self, **kwargs):
- """Create the Version object."""
- self.__dict__.update(kwargs)
-
- def __repr__(self):
- """Return str representation of the Version."""
- keys = sorted(self.__dict__)
- items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
- return "{}({})".format(type(self).__name__, ", ".join(items))
-
- def __eq__(self, other):
- """Check if version is same as other."""
- return self.__dict__ == other.__dict__
-
-
-def get_client_info(kind, type_, method_spec):
- """Returns a tuple describing the client."""
- name = "python{}-{}".format(sys.version_info[0], kind)
- attributes = {"license": "Apache v2",
- "website": "github.com/neovim/pynvim"}
- return (name, VERSION.__dict__, type_, method_spec, attributes)
-
-
-VERSION = Version(major=0, minor=4, patch=2, prerelease='')
+++ /dev/null
-Metadata-Version: 2.1
-Name: trollius
-Version: 2.2.post1
-Summary: Deprecated, unmaintained port of the asyncio module (PEP 3156) on Python 2
-Home-page: https://github.com/jamadden/trollius
-Author: Victor Stinner
-Author-email: victor.stinner@gmail.com
-License: Apache License 2.0
-Description: ========
- Trollius
- ========
-
- .. image:: http://unmaintained.tech/badge.svg
- :target: http://unmaintained.tech/
- :alt: No Maintenance Intended
-
- .. warning::
- The Trollius project is deprecated and unsupported. It is on PyPI
- to support existing dependencies only.
-
-Keywords: Deprecated Unmaintained asyncio backport
-Platform: UNKNOWN
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.7
-Classifier: License :: OSI Approved :: Apache Software License
-Requires-Python: >=2.7, < 3
-Description-Content-Type: text/x-rst
+++ /dev/null
-.travis.yml
-AUTHORS
-COPYING
-MANIFEST.in
-Makefile
-README.rst
-TODO.rst
-appveyor.yml
-check.py
-overlapped.c
-pypi.bat
-releaser.conf
-runtests.py
-setup.cfg
-setup.py
-tox.ini
-update-asyncio-step1.sh
-update-asyncio-step2.sh
-update-asyncio-step3.sh
-doc/Makefile
-doc/asyncio.rst
-doc/changelog.rst
-doc/conf.py
-doc/deprecated.rst
-doc/dev.rst
-doc/index.rst
-doc/install.rst
-doc/libraries.rst
-doc/make.bat
-doc/trollius.jpg
-doc/using.rst
-examples/cacheclt.py
-examples/cachesvr.py
-examples/child_process.py
-examples/crawl.py
-examples/echo_client_tulip.py
-examples/echo_server_tulip.py
-examples/fetch0.py
-examples/fetch1.py
-examples/fetch2.py
-examples/fetch3.py
-examples/fuzz_as_completed.py
-examples/hello_callback.py
-examples/hello_coroutine.py
-examples/interop_asyncio.py
-examples/shell.py
-examples/simple_tcp_server.py
-examples/sink.py
-examples/source.py
-examples/source1.py
-examples/stacks.py
-examples/subprocess_attach_read_pipe.py
-examples/subprocess_attach_write_pipe.py
-examples/subprocess_shell.py
-examples/tcp_echo.py
-examples/timing_tcp_server.py
-examples/udp_echo.py
-tests/echo.py
-tests/echo2.py
-tests/echo3.py
-tests/keycert3.pem
-tests/pycacert.pem
-tests/sample.crt
-tests/sample.key
-tests/ssl_cert.pem
-tests/ssl_key.pem
-tests/test_asyncio.py
-tests/test_base_events.py
-tests/test_events.py
-tests/test_futures.py
-tests/test_locks.py
-tests/test_proactor_events.py
-tests/test_queues.py
-tests/test_selector_events.py
-tests/test_selectors.py
-tests/test_sslproto.py
-tests/test_streams.py
-tests/test_subprocess.py
-tests/test_tasks.py
-tests/test_transports.py
-tests/test_unix_events.py
-tests/test_windows_events.py
-tests/test_windows_utils.py
-trollius/__init__.py
-trollius/base_events.py
-trollius/base_subprocess.py
-trollius/compat.py
-trollius/constants.py
-trollius/coroutines.py
-trollius/events.py
-trollius/executor.py
-trollius/futures.py
-trollius/locks.py
-trollius/log.py
-trollius/proactor_events.py
-trollius/protocols.py
-trollius/py27_weakrefset.py
-trollius/py33_exceptions.py
-trollius/py33_winapi.py
-trollius/py3_ssl.py
-trollius/queues.py
-trollius/selector_events.py
-trollius/selectors.py
-trollius/sslproto.py
-trollius/streams.py
-trollius/subprocess.py
-trollius/tasks.py
-trollius/test_support.py
-trollius/test_utils.py
-trollius/time_monotonic.py
-trollius/transports.py
-trollius/unix_events.py
-trollius/windows_events.py
-trollius/windows_utils.py
-trollius.egg-info/PKG-INFO
-trollius.egg-info/SOURCES.txt
-trollius.egg-info/dependency_links.txt
-trollius.egg-info/not-zip-safe
-trollius.egg-info/requires.txt
-trollius.egg-info/top_level.txt
\ No newline at end of file
+++ /dev/null
-../trollius/__init__.py
-../trollius/__init__.pyc
-../trollius/base_events.py
-../trollius/base_events.pyc
-../trollius/base_subprocess.py
-../trollius/base_subprocess.pyc
-../trollius/compat.py
-../trollius/compat.pyc
-../trollius/constants.py
-../trollius/constants.pyc
-../trollius/coroutines.py
-../trollius/coroutines.pyc
-../trollius/events.py
-../trollius/events.pyc
-../trollius/executor.py
-../trollius/executor.pyc
-../trollius/futures.py
-../trollius/futures.pyc
-../trollius/locks.py
-../trollius/locks.pyc
-../trollius/log.py
-../trollius/log.pyc
-../trollius/proactor_events.py
-../trollius/proactor_events.pyc
-../trollius/protocols.py
-../trollius/protocols.pyc
-../trollius/py27_weakrefset.py
-../trollius/py27_weakrefset.pyc
-../trollius/py33_exceptions.py
-../trollius/py33_exceptions.pyc
-../trollius/py33_winapi.py
-../trollius/py33_winapi.pyc
-../trollius/py3_ssl.py
-../trollius/py3_ssl.pyc
-../trollius/queues.py
-../trollius/queues.pyc
-../trollius/selector_events.py
-../trollius/selector_events.pyc
-../trollius/selectors.py
-../trollius/selectors.pyc
-../trollius/sslproto.py
-../trollius/sslproto.pyc
-../trollius/streams.py
-../trollius/streams.pyc
-../trollius/subprocess.py
-../trollius/subprocess.pyc
-../trollius/tasks.py
-../trollius/tasks.pyc
-../trollius/test_support.py
-../trollius/test_support.pyc
-../trollius/test_utils.py
-../trollius/test_utils.pyc
-../trollius/time_monotonic.py
-../trollius/time_monotonic.pyc
-../trollius/transports.py
-../trollius/transports.pyc
-../trollius/unix_events.py
-../trollius/unix_events.pyc
-../trollius/windows_events.py
-../trollius/windows_events.pyc
-../trollius/windows_utils.py
-../trollius/windows_utils.pyc
-PKG-INFO
-SOURCES.txt
-dependency_links.txt
-not-zip-safe
-requires.txt
-top_level.txt
+++ /dev/null
-six
-futures
+++ /dev/null
-"""The trollius package, tracking PEP 3156."""
-
-import sys
-
-# The selectors module is in the stdlib in Python 3.4 but not in 3.3.
-# Do this first, so the other submodules can use "from . import selectors".
-# Prefer asyncio/selectors.py over the stdlib one, as ours may be newer.
-try:
- from . import selectors
-except ImportError:
- import selectors # Will also be exported.
-
-if sys.platform == 'win32':
- # Similar thing for _overlapped.
- try:
- from . import _overlapped
- except ImportError:
- import _overlapped # Will also be exported.
-
-# This relies on each of the submodules having an __all__ variable.
-from .base_events import *
-from .coroutines import *
-from .events import *
-from .futures import *
-from .locks import *
-from .protocols import *
-from .py33_exceptions import *
-from .queues import *
-from .streams import *
-from .subprocess import *
-from .tasks import *
-from .transports import *
-
-__all__ = (base_events.__all__ +
- coroutines.__all__ +
- events.__all__ +
- py33_exceptions.__all__ +
- futures.__all__ +
- locks.__all__ +
- protocols.__all__ +
- queues.__all__ +
- streams.__all__ +
- subprocess.__all__ +
- tasks.__all__ +
- transports.__all__)
-
-if sys.platform == 'win32': # pragma: no cover
- from .windows_events import *
- __all__ += windows_events.__all__
-else:
- from .unix_events import * # pragma: no cover
- __all__ += unix_events.__all__
-
-try:
- from .py3_ssl import *
- __all__ += py3_ssl.__all__
-except ImportError:
- # SSL support is optionnal
- pass
+++ /dev/null
-"""Base implementation of event loop.
-
-The event loop can be broken up into a multiplexer (the part
-responsible for notifying us of I/O events) and the event loop proper,
-which wraps a multiplexer with functionality for scheduling callbacks,
-immediately or at a given time in the future.
-
-Whenever a public API takes a callback, subsequent positional
-arguments will be passed to the callback if/when it is called. This
-avoids the proliferation of trivial lambdas implementing closures.
-Keyword arguments for the callback are not supported; this is a
-conscious design decision, leaving the door open for keyword arguments
-to modify the meaning of the API call itself.
-"""
-
-
-import collections
-import heapq
-import inspect
-import logging
-import os
-import socket
-import subprocess
-import sys
-import traceback
-import warnings
-try:
- from collections import OrderedDict
-except ImportError:
- # Python 2.6: use ordereddict backport
- from ordereddict import OrderedDict
-try:
- from threading import get_ident as _get_thread_ident
-except ImportError:
- # Python 2
- from threading import _get_ident as _get_thread_ident
-
-from . import compat
-from . import coroutines
-from . import events
-from . import futures
-from . import tasks
-from .coroutines import coroutine, From, Return
-from .executor import get_default_executor
-from .log import logger
-from .time_monotonic import time_monotonic, time_monotonic_resolution
-
-
-__all__ = ['BaseEventLoop']
-
-
-# Argument for default thread pool executor creation.
-_MAX_WORKERS = 5
-
-# Minimum number of _scheduled timer handles before cleanup of
-# cancelled handles is performed.
-_MIN_SCHEDULED_TIMER_HANDLES = 100
-
-# Minimum fraction of _scheduled timer handles that are cancelled
-# before cleanup of cancelled handles is performed.
-_MIN_CANCELLED_TIMER_HANDLES_FRACTION = 0.5
-
-def _format_handle(handle):
- cb = handle._callback
- if inspect.ismethod(cb) and isinstance(cb.__self__, tasks.Task):
- # format the task
- return repr(cb.__self__)
- else:
- return str(handle)
-
-
-def _format_pipe(fd):
- if fd == subprocess.PIPE:
- return '<pipe>'
- elif fd == subprocess.STDOUT:
- return '<stdout>'
- else:
- return repr(fd)
-
-
-class _StopError(BaseException):
- """Raised to stop the event loop."""
-
-
-def _check_resolved_address(sock, address):
- # Ensure that the address is already resolved to avoid the trap of hanging
- # the entire event loop when the address requires doing a DNS lookup.
- #
- # getaddrinfo() is slow (around 10 us per call): this function should only
- # be called in debug mode
- family = sock.family
-
- if family == socket.AF_INET:
- host, port = address
- elif family == socket.AF_INET6:
- host, port = address[:2]
- else:
- return
-
- # On Windows, socket.inet_pton() is only available since Python 3.4
- if hasattr(socket, 'inet_pton'):
- # getaddrinfo() is slow and has known issue: prefer inet_pton()
- # if available
- try:
- socket.inet_pton(family, host)
- except socket.error as exc:
- raise ValueError("address must be resolved (IP address), "
- "got host %r: %s"
- % (host, exc))
- else:
- # Use getaddrinfo(flags=AI_NUMERICHOST) to ensure that the address is
- # already resolved.
- type_mask = 0
- if hasattr(socket, 'SOCK_NONBLOCK'):
- type_mask |= socket.SOCK_NONBLOCK
- if hasattr(socket, 'SOCK_CLOEXEC'):
- type_mask |= socket.SOCK_CLOEXEC
- try:
- socket.getaddrinfo(host, port,
- family,
- (sock.type & ~type_mask),
- sock.proto,
- socket.AI_NUMERICHOST)
- except socket.gaierror as err:
- raise ValueError("address must be resolved (IP address), "
- "got host %r: %s"
- % (host, err))
-
-def _raise_stop_error(*args):
- raise _StopError
-
-
-def _run_until_complete_cb(fut):
- exc = fut._exception
- if (isinstance(exc, BaseException)
- and not isinstance(exc, Exception)):
- # Issue #22429: run_forever() already finished, no need to
- # stop it.
- return
- _raise_stop_error()
-
-
-class Server(events.AbstractServer):
-
- def __init__(self, loop, sockets):
- self._loop = loop
- self.sockets = sockets
- self._active_count = 0
- self._waiters = []
-
- def __repr__(self):
- return '<%s sockets=%r>' % (self.__class__.__name__, self.sockets)
-
- def _attach(self):
- assert self.sockets is not None
- self._active_count += 1
-
- def _detach(self):
- assert self._active_count > 0
- self._active_count -= 1
- if self._active_count == 0 and self.sockets is None:
- self._wakeup()
-
- def close(self):
- sockets = self.sockets
- if sockets is None:
- return
- self.sockets = None
- for sock in sockets:
- self._loop._stop_serving(sock)
- if self._active_count == 0:
- self._wakeup()
-
- def _wakeup(self):
- waiters = self._waiters
- self._waiters = None
- for waiter in waiters:
- if not waiter.done():
- waiter.set_result(waiter)
-
- @coroutine
- def wait_closed(self):
- if self.sockets is None or self._waiters is None:
- raise Return()
- waiter = futures.Future(loop=self._loop)
- self._waiters.append(waiter)
- yield From(waiter)
-
-
-class BaseEventLoop(events.AbstractEventLoop):
-
- def __init__(self):
- self._timer_cancelled_count = 0
- self._closed = False
- self._ready = collections.deque()
- self._scheduled = []
- self._default_executor = None
- self._internal_fds = 0
- # Identifier of the thread running the event loop, or None if the
- # event loop is not running
- self._thread_id = None
- self._clock_resolution = time_monotonic_resolution
- self._exception_handler = None
- self.set_debug(bool(os.environ.get('TROLLIUSDEBUG')))
- # In debug mode, if the execution of a callback or a step of a task
- # exceed this duration in seconds, the slow callback/task is logged.
- self.slow_callback_duration = 0.1
- self._current_handle = None
- self._task_factory = None
- self._coroutine_wrapper_set = False
-
- def __repr__(self):
- return ('<%s running=%s closed=%s debug=%s>'
- % (self.__class__.__name__, self.is_running(),
- self.is_closed(), self.get_debug()))
-
- def create_task(self, coro):
- """Schedule a coroutine object.
-
- Return a task object.
- """
- self._check_closed()
- if self._task_factory is None:
- task = tasks.Task(coro, loop=self)
- if task._source_traceback:
- del task._source_traceback[-1]
- else:
- task = self._task_factory(self, coro)
- return task
-
- def set_task_factory(self, factory):
- """Set a task factory that will be used by loop.create_task().
-
- If factory is None the default task factory will be set.
-
- If factory is a callable, it should have a signature matching
- '(loop, coro)', where 'loop' will be a reference to the active
- event loop, 'coro' will be a coroutine object. The callable
- must return a Future.
- """
- if factory is not None and not callable(factory):
- raise TypeError('task factory must be a callable or None')
- self._task_factory = factory
-
- def get_task_factory(self):
- """Return a task factory, or None if the default one is in use."""
- return self._task_factory
-
- def _make_socket_transport(self, sock, protocol, waiter=None,
- extra=None, server=None):
- """Create socket transport."""
- raise NotImplementedError
-
- def _make_ssl_transport(self, rawsock, protocol, sslcontext, waiter=None,
- server_side=False, server_hostname=None,
- extra=None, server=None):
- """Create SSL transport."""
- raise NotImplementedError
-
- def _make_datagram_transport(self, sock, protocol,
- address=None, waiter=None, extra=None):
- """Create datagram transport."""
- raise NotImplementedError
-
- def _make_read_pipe_transport(self, pipe, protocol, waiter=None,
- extra=None):
- """Create read pipe transport."""
- raise NotImplementedError
-
- def _make_write_pipe_transport(self, pipe, protocol, waiter=None,
- extra=None):
- """Create write pipe transport."""
- raise NotImplementedError
-
- @coroutine
- def _make_subprocess_transport(self, protocol, args, shell,
- stdin, stdout, stderr, bufsize,
- extra=None, **kwargs):
- """Create subprocess transport."""
- raise NotImplementedError
-
- def _write_to_self(self):
- """Write a byte to self-pipe, to wake up the event loop.
-
- This may be called from a different thread.
-
- The subclass is responsible for implementing the self-pipe.
- """
- raise NotImplementedError
-
- def _process_events(self, event_list):
- """Process selector events."""
- raise NotImplementedError
-
- def _check_closed(self):
- if self._closed:
- raise RuntimeError('Event loop is closed')
-
- def run_forever(self):
- """Run until stop() is called."""
- self._check_closed()
- if self.is_running():
- raise RuntimeError('Event loop is running.')
- self._set_coroutine_wrapper(self._debug)
- self._thread_id = _get_thread_ident()
- try:
- while True:
- try:
- self._run_once()
- except _StopError:
- break
- finally:
- self._thread_id = None
- self._set_coroutine_wrapper(False)
-
- def run_until_complete(self, future):
- """Run until the Future is done.
-
- If the argument is a coroutine, it is wrapped in a Task.
-
- WARNING: It would be disastrous to call run_until_complete()
- with the same coroutine twice -- it would wrap it in two
- different Tasks and that can't be good.
-
- Return the Future's result, or raise its exception.
- """
- self._check_closed()
-
- new_task = not isinstance(future, futures._FUTURE_CLASSES)
- future = tasks.ensure_future(future, loop=self)
- if new_task:
- # An exception is raised if the future didn't complete, so there
- # is no need to log the "destroy pending task" message
- future._log_destroy_pending = False
-
- future.add_done_callback(_run_until_complete_cb)
- try:
- self.run_forever()
- except:
- if new_task and future.done() and not future.cancelled():
- # The coroutine raised a BaseException. Consume the exception
- # to not log a warning, the caller doesn't have access to the
- # local task.
- future.exception()
- raise
- future.remove_done_callback(_run_until_complete_cb)
- if not future.done():
- raise RuntimeError('Event loop stopped before Future completed.')
-
- return future.result()
-
- def stop(self):
- """Stop running the event loop.
-
- Every callback scheduled before stop() is called will run. Callbacks
- scheduled after stop() is called will not run. However, those callbacks
- will run if run_forever is called again later.
- """
- self.call_soon(_raise_stop_error)
-
- def close(self):
- """Close the event loop.
-
- This clears the queues and shuts down the executor,
- but does not wait for the executor to finish.
-
- The event loop must not be running.
- """
- if self.is_running():
- raise RuntimeError("Cannot close a running event loop")
- if self._closed:
- return
- if self._debug:
- logger.debug("Close %r", self)
- self._closed = True
- self._ready.clear()
- del self._scheduled[:]
- executor = self._default_executor
- if executor is not None:
- self._default_executor = None
- executor.shutdown(wait=False)
-
- def is_closed(self):
- """Returns True if the event loop was closed."""
- return self._closed
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self.is_closed():
- warnings.warn("unclosed event loop %r" % self, ResourceWarning)
- if not self.is_running():
- self.close()
-
- def is_running(self):
- """Returns True if the event loop is running."""
- return (self._thread_id is not None)
-
- def time(self):
- """Return the time according to the event loop's clock.
-
- This is a float expressed in seconds since an epoch, but the
- epoch, precision, accuracy and drift are unspecified and may
- differ per event loop.
- """
- return time_monotonic()
-
- def call_later(self, delay, callback, *args):
- """Arrange for a callback to be called at a given time.
-
- Return a Handle: an opaque object with a cancel() method that
- can be used to cancel the call.
-
- The delay can be an int or float, expressed in seconds. It is
- always relative to the current time.
-
- Each callback will be called exactly once. If two callbacks
- are scheduled for exactly the same time, it undefined which
- will be called first.
-
- Any positional arguments after the callback will be passed to
- the callback when it is called.
- """
- timer = self.call_at(self.time() + delay, callback, *args)
- if timer._source_traceback:
- del timer._source_traceback[-1]
- return timer
-
- def call_at(self, when, callback, *args):
- """Like call_later(), but uses an absolute time.
-
- Absolute time corresponds to the event loop's time() method.
- """
- if (coroutines.iscoroutine(callback)
- or coroutines.iscoroutinefunction(callback)):
- raise TypeError("coroutines cannot be used with call_at()")
- self._check_closed()
- if self._debug:
- self._check_thread()
- timer = events.TimerHandle(when, callback, args, self)
- if timer._source_traceback:
- del timer._source_traceback[-1]
- heapq.heappush(self._scheduled, timer)
- timer._scheduled = True
- return timer
-
- def call_soon(self, callback, *args):
- """Arrange for a callback to be called as soon as possible.
-
- This operates as a FIFO queue: callbacks are called in the
- order in which they are registered. Each callback will be
- called exactly once.
-
- Any positional arguments after the callback will be passed to
- the callback when it is called.
- """
- if self._debug:
- self._check_thread()
- handle = self._call_soon(callback, args)
- if handle._source_traceback:
- del handle._source_traceback[-1]
- return handle
-
- def _call_soon(self, callback, args):
- if (coroutines.iscoroutine(callback)
- or coroutines.iscoroutinefunction(callback)):
- raise TypeError("coroutines cannot be used with call_soon()")
- self._check_closed()
- handle = events.Handle(callback, args, self)
- if handle._source_traceback:
- del handle._source_traceback[-1]
- self._ready.append(handle)
- return handle
-
- def _check_thread(self):
- """Check that the current thread is the thread running the event loop.
-
- Non-thread-safe methods of this class make this assumption and will
- likely behave incorrectly when the assumption is violated.
-
- Should only be called when (self._debug == True). The caller is
- responsible for checking this condition for performance reasons.
- """
- if self._thread_id is None:
- return
- thread_id = _get_thread_ident()
- if thread_id != self._thread_id:
- raise RuntimeError(
- "Non-thread-safe operation invoked on an event loop other "
- "than the current one")
-
- def call_soon_threadsafe(self, callback, *args):
- """Like call_soon(), but thread-safe."""
- handle = self._call_soon(callback, args)
- if handle._source_traceback:
- del handle._source_traceback[-1]
- self._write_to_self()
- return handle
-
- def run_in_executor(self, executor, func, *args):
- if (coroutines.iscoroutine(func)
- or coroutines.iscoroutinefunction(func)):
- raise TypeError("coroutines cannot be used with run_in_executor()")
- self._check_closed()
- if isinstance(func, events.Handle):
- assert not args
- assert not isinstance(func, events.TimerHandle)
- if func._cancelled:
- f = futures.Future(loop=self)
- f.set_result(None)
- return f
- func, args = func._callback, func._args
- if executor is None:
- executor = self._default_executor
- if executor is None:
- executor = get_default_executor()
- self._default_executor = executor
- return futures.wrap_future(executor.submit(func, *args), loop=self)
-
- def set_default_executor(self, executor):
- self._default_executor = executor
-
- def _getaddrinfo_debug(self, host, port, family, type, proto, flags):
- msg = ["%s:%r" % (host, port)]
- if family:
- msg.append('family=%r' % family)
- if type:
- msg.append('type=%r' % type)
- if proto:
- msg.append('proto=%r' % proto)
- if flags:
- msg.append('flags=%r' % flags)
- msg = ', '.join(msg)
- logger.debug('Get address info %s', msg)
-
- t0 = self.time()
- addrinfo = socket.getaddrinfo(host, port, family, type, proto, flags)
- dt = self.time() - t0
-
- msg = ('Getting address info %s took %.3f ms: %r'
- % (msg, dt * 1e3, addrinfo))
- if dt >= self.slow_callback_duration:
- logger.info(msg)
- else:
- logger.debug(msg)
- return addrinfo
-
- def getaddrinfo(self, host, port,
- family=0, type=0, proto=0, flags=0):
- if self._debug:
- return self.run_in_executor(None, self._getaddrinfo_debug,
- host, port, family, type, proto, flags)
- else:
- return self.run_in_executor(None, socket.getaddrinfo,
- host, port, family, type, proto, flags)
-
- def getnameinfo(self, sockaddr, flags=0):
- return self.run_in_executor(None, socket.getnameinfo, sockaddr, flags)
-
- @coroutine
- def create_connection(self, protocol_factory, host=None, port=None,
- ssl=None, family=0, proto=0, flags=0, sock=None,
- local_addr=None, server_hostname=None):
- """Connect to a TCP server.
-
- Create a streaming transport connection to a given Internet host and
- port: socket family AF_INET or socket.AF_INET6 depending on host (or
- family if specified), socket type SOCK_STREAM. protocol_factory must be
- a callable returning a protocol instance.
-
- This method is a coroutine which will try to establish the connection
- in the background. When successful, the coroutine returns a
- (transport, protocol) pair.
- """
- if server_hostname is not None and not ssl:
- raise ValueError('server_hostname is only meaningful with ssl')
-
- if server_hostname is None and ssl:
- # Use host as default for server_hostname. It is an error
- # if host is empty or not set, e.g. when an
- # already-connected socket was passed or when only a port
- # is given. To avoid this error, you can pass
- # server_hostname='' -- this will bypass the hostname
- # check. (This also means that if host is a numeric
- # IP/IPv6 address, we will attempt to verify that exact
- # address; this will probably fail, but it is possible to
- # create a certificate for a specific IP address, so we
- # don't judge it here.)
- if not host:
- raise ValueError('You must set server_hostname '
- 'when using ssl without a host')
- server_hostname = host
-
- if host is not None or port is not None:
- if sock is not None:
- raise ValueError(
- 'host/port and sock can not be specified at the same time')
-
- f1 = self.getaddrinfo(
- host, port, family=family,
- type=socket.SOCK_STREAM, proto=proto, flags=flags)
- fs = [f1]
- if local_addr is not None:
- f2 = self.getaddrinfo(
- *local_addr, family=family,
- type=socket.SOCK_STREAM, proto=proto, flags=flags)
- fs.append(f2)
- else:
- f2 = None
-
- yield From(tasks.wait(fs, loop=self))
-
- infos = f1.result()
- if not infos:
- raise socket.error('getaddrinfo() returned empty list')
- if f2 is not None:
- laddr_infos = f2.result()
- if not laddr_infos:
- raise socket.error('getaddrinfo() returned empty list')
-
- exceptions = []
- for family, type, proto, cname, address in infos:
- try:
- sock = socket.socket(family=family, type=type, proto=proto)
- sock.setblocking(False)
- if f2 is not None:
- for _, _, _, _, laddr in laddr_infos:
- try:
- sock.bind(laddr)
- break
- except socket.error as exc:
- exc = socket.error(
- exc.errno, 'error while '
- 'attempting to bind on address '
- '{0!r}: {1}'.format(
- laddr, exc.strerror.lower()))
- exceptions.append(exc)
- else:
- sock.close()
- sock = None
- continue
- if self._debug:
- logger.debug("connect %r to %r", sock, address)
- yield From(self.sock_connect(sock, address))
- except socket.error as exc:
- if sock is not None:
- sock.close()
- exceptions.append(exc)
- except:
- if sock is not None:
- sock.close()
- raise
- else:
- break
- else:
- if len(exceptions) == 1:
- raise exceptions[0]
- else:
- # If they all have the same str(), raise one.
- model = str(exceptions[0])
- if all(str(exc) == model for exc in exceptions):
- raise exceptions[0]
- # Raise a combined exception so the user can see all
- # the various error messages.
- raise socket.error('Multiple exceptions: {0}'.format(
- ', '.join(str(exc) for exc in exceptions)))
-
- elif sock is None:
- raise ValueError(
- 'host and port was not specified and no sock specified')
-
- sock.setblocking(False)
-
- transport, protocol = yield From(self._create_connection_transport(
- sock, protocol_factory, ssl, server_hostname))
- if self._debug:
- # Get the socket from the transport because SSL transport closes
- # the old socket and creates a new SSL socket
- sock = transport.get_extra_info('socket')
- logger.debug("%r connected to %s:%r: (%r, %r)",
- sock, host, port, transport, protocol)
- raise Return(transport, protocol)
-
- @coroutine
- def _create_connection_transport(self, sock, protocol_factory, ssl,
- server_hostname):
- protocol = protocol_factory()
- waiter = futures.Future(loop=self)
- if ssl:
- sslcontext = None if isinstance(ssl, bool) else ssl
- transport = self._make_ssl_transport(
- sock, protocol, sslcontext, waiter,
- server_side=False, server_hostname=server_hostname)
- else:
- transport = self._make_socket_transport(sock, protocol, waiter)
-
- try:
- yield From(waiter)
- except:
- transport.close()
- raise
-
- raise Return(transport, protocol)
-
- @coroutine
- def create_datagram_endpoint(self, protocol_factory,
- local_addr=None, remote_addr=None,
- family=0, proto=0, flags=0):
- """Create datagram connection."""
- if not (local_addr or remote_addr):
- if family == 0:
- raise ValueError('unexpected address family')
- addr_pairs_info = (((family, proto), (None, None)),)
- else:
- # join address by (family, protocol)
- addr_infos = OrderedDict()
- for idx, addr in ((0, local_addr), (1, remote_addr)):
- if addr is not None:
- assert isinstance(addr, tuple) and len(addr) == 2, (
- '2-tuple is expected')
-
- infos = yield From(self.getaddrinfo(
- *addr, family=family, type=socket.SOCK_DGRAM,
- proto=proto, flags=flags))
- if not infos:
- raise socket.error('getaddrinfo() returned empty list')
-
- for fam, _, pro, _, address in infos:
- key = (fam, pro)
- if key not in addr_infos:
- addr_infos[key] = [None, None]
- addr_infos[key][idx] = address
-
- # each addr has to have info for each (family, proto) pair
- addr_pairs_info = [
- (key, addr_pair) for key, addr_pair in addr_infos.items()
- if not ((local_addr and addr_pair[0] is None) or
- (remote_addr and addr_pair[1] is None))]
-
- if not addr_pairs_info:
- raise ValueError('can not get address information')
-
- exceptions = []
-
- for ((family, proto),
- (local_address, remote_address)) in addr_pairs_info:
- sock = None
- r_addr = None
- try:
- sock = socket.socket(
- family=family, type=socket.SOCK_DGRAM, proto=proto)
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.setblocking(False)
-
- if local_addr:
- sock.bind(local_address)
- if remote_addr:
- yield From(self.sock_connect(sock, remote_address))
- r_addr = remote_address
- except socket.error as exc:
- if sock is not None:
- sock.close()
- exceptions.append(exc)
- except:
- if sock is not None:
- sock.close()
- raise
- else:
- break
- else:
- raise exceptions[0]
-
- protocol = protocol_factory()
- waiter = futures.Future(loop=self)
- transport = self._make_datagram_transport(sock, protocol, r_addr,
- waiter)
- if self._debug:
- if local_addr:
- logger.info("Datagram endpoint local_addr=%r remote_addr=%r "
- "created: (%r, %r)",
- local_addr, remote_addr, transport, protocol)
- else:
- logger.debug("Datagram endpoint remote_addr=%r created: "
- "(%r, %r)",
- remote_addr, transport, protocol)
-
- try:
- yield From(waiter)
- except:
- transport.close()
- raise
-
- raise Return(transport, protocol)
-
- @coroutine
- def create_server(self, protocol_factory, host=None, port=None,
- family=socket.AF_UNSPEC,
- flags=socket.AI_PASSIVE,
- sock=None,
- backlog=100,
- ssl=None,
- reuse_address=None):
- """Create a TCP server bound to host and port.
-
- Return a Server object which can be used to stop the service.
-
- This method is a coroutine.
- """
- if isinstance(ssl, bool):
- raise TypeError('ssl argument must be an SSLContext or None')
- if host is not None or port is not None:
- if sock is not None:
- raise ValueError(
- 'host/port and sock can not be specified at the same time')
-
- AF_INET6 = getattr(socket, 'AF_INET6', 0)
- if reuse_address is None:
- reuse_address = os.name == 'posix' and sys.platform != 'cygwin'
- sockets = []
- if host == '':
- host = None
-
- infos = yield From(self.getaddrinfo(
- host, port, family=family,
- type=socket.SOCK_STREAM, proto=0, flags=flags))
- if not infos:
- raise socket.error('getaddrinfo() returned empty list')
-
- completed = False
- try:
- for res in infos:
- af, socktype, proto, canonname, sa = res
- try:
- sock = socket.socket(af, socktype, proto)
- except socket.error:
- # Assume it's a bad family/type/protocol combination.
- if self._debug:
- logger.warning('create_server() failed to create '
- 'socket.socket(%r, %r, %r)',
- af, socktype, proto, exc_info=True)
- continue
- sockets.append(sock)
- if reuse_address:
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,
- True)
- # Disable IPv4/IPv6 dual stack support (enabled by
- # default on Linux) which makes a single socket
- # listen on both address families.
- if af == AF_INET6 and hasattr(socket, 'IPPROTO_IPV6'):
- sock.setsockopt(socket.IPPROTO_IPV6,
- socket.IPV6_V6ONLY,
- True)
- try:
- sock.bind(sa)
- except socket.error as err:
- raise socket.error(err.errno,
- 'error while attempting '
- 'to bind on address %r: %s'
- % (sa, err.strerror.lower()))
- completed = True
- finally:
- if not completed:
- for sock in sockets:
- sock.close()
- else:
- if sock is None:
- raise ValueError('Neither host/port nor sock were specified')
- sockets = [sock]
-
- server = Server(self, sockets)
- for sock in sockets:
- sock.listen(backlog)
- sock.setblocking(False)
- self._start_serving(protocol_factory, sock, ssl, server)
- if self._debug:
- logger.info("%r is serving", server)
- raise Return(server)
-
- @coroutine
- def connect_read_pipe(self, protocol_factory, pipe):
- protocol = protocol_factory()
- waiter = futures.Future(loop=self)
- transport = self._make_read_pipe_transport(pipe, protocol, waiter)
-
- try:
- yield From(waiter)
- except:
- transport.close()
- raise
-
- if self._debug:
- logger.debug('Read pipe %r connected: (%r, %r)',
- pipe.fileno(), transport, protocol)
- raise Return(transport, protocol)
-
- @coroutine
- def connect_write_pipe(self, protocol_factory, pipe):
- protocol = protocol_factory()
- waiter = futures.Future(loop=self)
- transport = self._make_write_pipe_transport(pipe, protocol, waiter)
-
- try:
- yield From(waiter)
- except:
- transport.close()
- raise
-
- if self._debug:
- logger.debug('Write pipe %r connected: (%r, %r)',
- pipe.fileno(), transport, protocol)
- raise Return(transport, protocol)
-
- def _log_subprocess(self, msg, stdin, stdout, stderr):
- info = [msg]
- if stdin is not None:
- info.append('stdin=%s' % _format_pipe(stdin))
- if stdout is not None and stderr == subprocess.STDOUT:
- info.append('stdout=stderr=%s' % _format_pipe(stdout))
- else:
- if stdout is not None:
- info.append('stdout=%s' % _format_pipe(stdout))
- if stderr is not None:
- info.append('stderr=%s' % _format_pipe(stderr))
- logger.debug(' '.join(info))
-
- @coroutine
- def subprocess_shell(self, protocol_factory, cmd, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- universal_newlines=False, shell=True, bufsize=0,
- **kwargs):
- if not isinstance(cmd, compat.string_types):
- raise ValueError("cmd must be a string")
- if universal_newlines:
- raise ValueError("universal_newlines must be False")
- if not shell:
- raise ValueError("shell must be True")
- if bufsize != 0:
- raise ValueError("bufsize must be 0")
- protocol = protocol_factory()
- if self._debug:
- # don't log parameters: they may contain sensitive information
- # (password) and may be too long
- debug_log = 'run shell command %r' % cmd
- self._log_subprocess(debug_log, stdin, stdout, stderr)
- transport = yield From(self._make_subprocess_transport(
- protocol, cmd, True, stdin, stdout, stderr, bufsize, **kwargs))
- if self._debug:
- logger.info('%s: %r' % (debug_log, transport))
- raise Return(transport, protocol)
-
- @coroutine
- def subprocess_exec(self, protocol_factory, program, *args, **kwargs):
- stdin = kwargs.pop('stdin', subprocess.PIPE)
- stdout = kwargs.pop('stdout', subprocess.PIPE)
- stderr = kwargs.pop('stderr', subprocess.PIPE)
- universal_newlines = kwargs.pop('universal_newlines', False)
- shell = kwargs.pop('shell', False)
- bufsize = kwargs.pop('bufsize', 0)
- if universal_newlines:
- raise ValueError("universal_newlines must be False")
- if shell:
- raise ValueError("shell must be False")
- if bufsize != 0:
- raise ValueError("bufsize must be 0")
- popen_args = (program,) + args
- for arg in popen_args:
- if not isinstance(arg, compat.string_types ):
- raise TypeError("program arguments must be "
- "a bytes or text string, not %s"
- % type(arg).__name__)
- protocol = protocol_factory()
- if self._debug:
- # don't log parameters: they may contain sensitive information
- # (password) and may be too long
- debug_log = 'execute program %r' % program
- self._log_subprocess(debug_log, stdin, stdout, stderr)
- transport = yield From(self._make_subprocess_transport(
- protocol, popen_args, False, stdin, stdout, stderr,
- bufsize, **kwargs))
- if self._debug:
- logger.info('%s: %r' % (debug_log, transport))
- raise Return(transport, protocol)
-
- def set_exception_handler(self, handler):
- """Set handler as the new event loop exception handler.
-
- If handler is None, the default exception handler will
- be set.
-
- If handler is a callable object, it should have a
- signature matching '(loop, context)', where 'loop'
- will be a reference to the active event loop, 'context'
- will be a dict object (see `call_exception_handler()`
- documentation for details about context).
- """
- if handler is not None and not callable(handler):
- raise TypeError('A callable object or None is expected, '
- 'got {0!r}'.format(handler))
- self._exception_handler = handler
-
- def default_exception_handler(self, context):
- """Default exception handler.
-
- This is called when an exception occurs and no exception
- handler is set, and can be called by a custom exception
- handler that wants to defer to the default behavior.
-
- The context parameter has the same meaning as in
- `call_exception_handler()`.
- """
- message = context.get('message')
- if not message:
- message = 'Unhandled exception in event loop'
-
- exception = context.get('exception')
- if exception is not None:
- if hasattr(exception, '__traceback__'):
- # Python 3
- tb = exception.__traceback__
- else:
- # call_exception_handler() is usually called indirectly
- # from an except block. If it's not the case, the traceback
- # is undefined...
- tb = sys.exc_info()[2]
- exc_info = (type(exception), exception, tb)
- else:
- exc_info = False
-
- if ('source_traceback' not in context
- and self._current_handle is not None
- and self._current_handle._source_traceback):
- context['handle_traceback'] = self._current_handle._source_traceback
-
- log_lines = [message]
- for key in sorted(context):
- if key in ('message', 'exception'):
- continue
- value = context[key]
- if key == 'source_traceback':
- tb = ''.join(traceback.format_list(value))
- value = 'Object created at (most recent call last):\n'
- value += tb.rstrip()
- elif key == 'handle_traceback':
- tb = ''.join(traceback.format_list(value))
- value = 'Handle created at (most recent call last):\n'
- value += tb.rstrip()
- else:
- value = repr(value)
- log_lines.append('{0}: {1}'.format(key, value))
-
- logger.error('\n'.join(log_lines), exc_info=exc_info)
-
- def call_exception_handler(self, context):
- """Call the current event loop's exception handler.
-
- The context argument is a dict containing the following keys:
-
- - 'message': Error message;
- - 'exception' (optional): Exception object;
- - 'future' (optional): Future instance;
- - 'handle' (optional): Handle instance;
- - 'protocol' (optional): Protocol instance;
- - 'transport' (optional): Transport instance;
- - 'socket' (optional): Socket instance.
-
- New keys maybe introduced in the future.
-
- Note: do not overload this method in an event loop subclass.
- For custom exception handling, use the
- `set_exception_handler()` method.
- """
- if self._exception_handler is None:
- try:
- self.default_exception_handler(context)
- except Exception:
- # Second protection layer for unexpected errors
- # in the default implementation, as well as for subclassed
- # event loops with overloaded "default_exception_handler".
- logger.error('Exception in default exception handler',
- exc_info=True)
- else:
- try:
- self._exception_handler(self, context)
- except Exception as exc:
- # Exception in the user set custom exception handler.
- try:
- # Let's try default handler.
- self.default_exception_handler({
- 'message': 'Unhandled error in exception handler',
- 'exception': exc,
- 'context': context,
- })
- except Exception:
- # Guard 'default_exception_handler' in case it is
- # overloaded.
- logger.error('Exception in default exception handler '
- 'while handling an unexpected error '
- 'in custom exception handler',
- exc_info=True)
-
- def _add_callback(self, handle):
- """Add a Handle to _scheduled (TimerHandle) or _ready."""
- assert isinstance(handle, events.Handle), 'A Handle is required here'
- if handle._cancelled:
- return
- assert not isinstance(handle, events.TimerHandle)
- self._ready.append(handle)
-
- def _add_callback_signalsafe(self, handle):
- """Like _add_callback() but called from a signal handler."""
- self._add_callback(handle)
- self._write_to_self()
-
- def _timer_handle_cancelled(self, handle):
- """Notification that a TimerHandle has been cancelled."""
- if handle._scheduled:
- self._timer_cancelled_count += 1
-
- def _run_once(self):
- """Run one full iteration of the event loop.
-
- This calls all currently ready callbacks, polls for I/O,
- schedules the resulting callbacks, and finally schedules
- 'call_later' callbacks.
- """
-
- sched_count = len(self._scheduled)
- if (sched_count > _MIN_SCHEDULED_TIMER_HANDLES and
- float(self._timer_cancelled_count) / sched_count >
- _MIN_CANCELLED_TIMER_HANDLES_FRACTION):
- # Remove delayed calls that were cancelled if their number
- # is too high
- new_scheduled = []
- for handle in self._scheduled:
- if handle._cancelled:
- handle._scheduled = False
- else:
- new_scheduled.append(handle)
-
- heapq.heapify(new_scheduled)
- self._scheduled = new_scheduled
- self._timer_cancelled_count = 0
- else:
- # Remove delayed calls that were cancelled from head of queue.
- while self._scheduled and self._scheduled[0]._cancelled:
- self._timer_cancelled_count -= 1
- handle = heapq.heappop(self._scheduled)
- handle._scheduled = False
-
- timeout = None
- if self._ready:
- timeout = 0
- elif self._scheduled:
- # Compute the desired timeout.
- when = self._scheduled[0]._when
- timeout = max(0, when - self.time())
-
- if self._debug and timeout != 0:
- t0 = self.time()
- event_list = self._selector.select(timeout)
- dt = self.time() - t0
- if dt >= 1.0:
- level = logging.INFO
- else:
- level = logging.DEBUG
- nevent = len(event_list)
- if timeout is None:
- logger.log(level, 'poll took %.3f ms: %s events',
- dt * 1e3, nevent)
- elif nevent:
- logger.log(level,
- 'poll %.3f ms took %.3f ms: %s events',
- timeout * 1e3, dt * 1e3, nevent)
- elif dt >= 1.0:
- logger.log(level,
- 'poll %.3f ms took %.3f ms: timeout',
- timeout * 1e3, dt * 1e3)
- else:
- event_list = self._selector.select(timeout)
- self._process_events(event_list)
-
- # Handle 'later' callbacks that are ready.
- end_time = self.time() + self._clock_resolution
- while self._scheduled:
- handle = self._scheduled[0]
- if handle._when >= end_time:
- break
- handle = heapq.heappop(self._scheduled)
- handle._scheduled = False
- self._ready.append(handle)
-
- # This is the only place where callbacks are actually *called*.
- # All other places just add them to ready.
- # Note: We run all currently scheduled callbacks, but not any
- # callbacks scheduled by callbacks run this time around --
- # they will be run the next time (after another I/O poll).
- # Use an idiom that is thread-safe without using locks.
- ntodo = len(self._ready)
- for i in range(ntodo):
- handle = self._ready.popleft()
- if handle._cancelled:
- continue
- if self._debug:
- try:
- self._current_handle = handle
- t0 = self.time()
- handle._run()
- dt = self.time() - t0
- if dt >= self.slow_callback_duration:
- logger.warning('Executing %s took %.3f seconds',
- _format_handle(handle), dt)
- finally:
- self._current_handle = None
- else:
- handle._run()
- handle = None # Needed to break cycles when an exception occurs.
-
- def _set_coroutine_wrapper(self, enabled):
- try:
- set_wrapper = sys.set_coroutine_wrapper
- get_wrapper = sys.get_coroutine_wrapper
- except AttributeError:
- return
-
- enabled = bool(enabled)
- if self._coroutine_wrapper_set == enabled:
- return
-
- wrapper = coroutines.debug_wrapper
- current_wrapper = get_wrapper()
-
- if enabled:
- if current_wrapper not in (None, wrapper):
- warnings.warn(
- "loop.set_debug(True): cannot set debug coroutine "
- "wrapper; another wrapper is already set %r" %
- current_wrapper, RuntimeWarning)
- else:
- set_wrapper(wrapper)
- self._coroutine_wrapper_set = True
- else:
- if current_wrapper not in (None, wrapper):
- warnings.warn(
- "loop.set_debug(False): cannot unset debug coroutine "
- "wrapper; another wrapper was set %r" %
- current_wrapper, RuntimeWarning)
- else:
- set_wrapper(None)
- self._coroutine_wrapper_set = False
-
- def get_debug(self):
- return self._debug
-
- def set_debug(self, enabled):
- self._debug = enabled
-
- if self.is_running():
- self._set_coroutine_wrapper(enabled)
+++ /dev/null
-import collections
-import subprocess
-import warnings
-
-from . import compat
-from . import futures
-from . import protocols
-from . import transports
-from .coroutines import coroutine, From, Return
-from .log import logger
-from .py33_exceptions import ProcessLookupError
-
-
-class BaseSubprocessTransport(transports.SubprocessTransport):
-
- def __init__(self, loop, protocol, args, shell,
- stdin, stdout, stderr, bufsize,
- waiter=None, extra=None, **kwargs):
- super(BaseSubprocessTransport, self).__init__(extra)
- self._closed = False
- self._protocol = protocol
- self._loop = loop
- self._proc = None
- self._pid = None
- self._returncode = None
- self._exit_waiters = []
- self._pending_calls = collections.deque()
- self._pipes = {}
- self._finished = False
-
- if stdin == subprocess.PIPE:
- self._pipes[0] = None
- if stdout == subprocess.PIPE:
- self._pipes[1] = None
- if stderr == subprocess.PIPE:
- self._pipes[2] = None
-
- # Create the child process: set the _proc attribute
- try:
- self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,
- stderr=stderr, bufsize=bufsize, **kwargs)
- except:
- self.close()
- raise
-
- self._pid = self._proc.pid
- self._extra['subprocess'] = self._proc
-
- if self._loop.get_debug():
- if isinstance(args, (bytes, str)):
- program = args
- else:
- program = args[0]
- logger.debug('process %r created: pid %s',
- program, self._pid)
-
- self._loop.create_task(self._connect_pipes(waiter))
-
- def __repr__(self):
- info = [self.__class__.__name__]
- if self._closed:
- info.append('closed')
- if self._pid is not None:
- info.append('pid=%s' % self._pid)
- if self._returncode is not None:
- info.append('returncode=%s' % self._returncode)
- elif self._pid is not None:
- info.append('running')
- else:
- info.append('not started')
-
- stdin = self._pipes.get(0)
- if stdin is not None:
- info.append('stdin=%s' % stdin.pipe)
-
- stdout = self._pipes.get(1)
- stderr = self._pipes.get(2)
- if stdout is not None and stderr is stdout:
- info.append('stdout=stderr=%s' % stdout.pipe)
- else:
- if stdout is not None:
- info.append('stdout=%s' % stdout.pipe)
- if stderr is not None:
- info.append('stderr=%s' % stderr.pipe)
-
- return '<%s>' % ' '.join(info)
-
- def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
- raise NotImplementedError
-
- def close(self):
- if self._closed:
- return
- self._closed = True
-
- for proto in self._pipes.values():
- if proto is None:
- continue
- proto.pipe.close()
-
- if (self._proc is not None
- # the child process finished?
- and self._returncode is None
- # the child process finished but the transport was not notified yet?
- and self._proc.poll() is None
- ):
- if self._loop.get_debug():
- logger.warning('Close running child process: kill %r', self)
-
- try:
- self._proc.kill()
- except ProcessLookupError:
- pass
-
- # Don't clear the _proc reference yet: _post_init() may still run
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self._closed:
- warnings.warn("unclosed transport %r" % self, ResourceWarning)
- self.close()
-
- def get_pid(self):
- return self._pid
-
- def get_returncode(self):
- return self._returncode
-
- def get_pipe_transport(self, fd):
- if fd in self._pipes:
- return self._pipes[fd].pipe
- else:
- return None
-
- def _check_proc(self):
- if self._proc is None:
- raise ProcessLookupError()
-
- def send_signal(self, signal):
- self._check_proc()
- self._proc.send_signal(signal)
-
- def terminate(self):
- self._check_proc()
- self._proc.terminate()
-
- def kill(self):
- self._check_proc()
- self._proc.kill()
-
- @coroutine
- def _connect_pipes(self, waiter):
- try:
- proc = self._proc
- loop = self._loop
-
- if proc.stdin is not None:
- _, pipe = yield From(loop.connect_write_pipe(
- lambda: WriteSubprocessPipeProto(self, 0),
- proc.stdin))
- self._pipes[0] = pipe
-
- if proc.stdout is not None:
- _, pipe = yield From(loop.connect_read_pipe(
- lambda: ReadSubprocessPipeProto(self, 1),
- proc.stdout))
- self._pipes[1] = pipe
-
- if proc.stderr is not None:
- _, pipe = yield From(loop.connect_read_pipe(
- lambda: ReadSubprocessPipeProto(self, 2),
- proc.stderr))
- self._pipes[2] = pipe
-
- assert self._pending_calls is not None
-
- loop.call_soon(self._protocol.connection_made, self)
- for callback, data in self._pending_calls:
- loop.call_soon(callback, *data)
- self._pending_calls = None
- except Exception as exc:
- if waiter is not None and not waiter.cancelled():
- waiter.set_exception(exc)
- else:
- if waiter is not None and not waiter.cancelled():
- waiter.set_result(None)
-
- def _call(self, cb, *data):
- if self._pending_calls is not None:
- self._pending_calls.append((cb, data))
- else:
- self._loop.call_soon(cb, *data)
-
- def _pipe_connection_lost(self, fd, exc):
- self._call(self._protocol.pipe_connection_lost, fd, exc)
- self._try_finish()
-
- def _pipe_data_received(self, fd, data):
- self._call(self._protocol.pipe_data_received, fd, data)
-
- def _process_exited(self, returncode):
- assert returncode is not None, returncode
- assert self._returncode is None, self._returncode
- if self._loop.get_debug():
- logger.info('%r exited with return code %r',
- self, returncode)
- self._returncode = returncode
- self._call(self._protocol.process_exited)
- self._try_finish()
-
- # wake up futures waiting for wait()
- for waiter in self._exit_waiters:
- if not waiter.cancelled():
- waiter.set_result(returncode)
- self._exit_waiters = None
-
- @coroutine
- def _wait(self):
- """Wait until the process exit and return the process return code.
-
- This method is a coroutine."""
- if self._returncode is not None:
- raise Return(self._returncode)
-
- waiter = futures.Future(loop=self._loop)
- self._exit_waiters.append(waiter)
- returncode = yield From(waiter)
- raise Return(returncode)
-
- def _try_finish(self):
- assert not self._finished
- if self._returncode is None:
- return
- if all(p is not None and p.disconnected
- for p in self._pipes.values()):
- self._finished = True
- self._call(self._call_connection_lost, None)
-
- def _call_connection_lost(self, exc):
- try:
- self._protocol.connection_lost(exc)
- finally:
- self._loop = None
- self._proc = None
- self._protocol = None
-
-
-class WriteSubprocessPipeProto(protocols.BaseProtocol):
-
- def __init__(self, proc, fd):
- self.proc = proc
- self.fd = fd
- self.pipe = None
- self.disconnected = False
-
- def connection_made(self, transport):
- self.pipe = transport
-
- def __repr__(self):
- return ('<%s fd=%s pipe=%r>'
- % (self.__class__.__name__, self.fd, self.pipe))
-
- def connection_lost(self, exc):
- self.disconnected = True
- self.proc._pipe_connection_lost(self.fd, exc)
- self.proc = None
-
- def pause_writing(self):
- self.proc._protocol.pause_writing()
-
- def resume_writing(self):
- self.proc._protocol.resume_writing()
-
-
-class ReadSubprocessPipeProto(WriteSubprocessPipeProto,
- protocols.Protocol):
-
- def data_received(self, data):
- self.proc._pipe_data_received(self.fd, data)
+++ /dev/null
-"""Compatibility helpers for the different Python versions."""
-
-import six
-import sys
-
-# Python 2.6 or older?
-PY26 = (sys.version_info < (2, 7))
-
-# Python 3.3 or newer?
-PY33 = (sys.version_info >= (3, 3))
-
-# Python 3.4 or newer?
-PY34 = sys.version_info >= (3, 4)
-
-# Python 3.5 or newer?
-PY35 = sys.version_info >= (3, 5)
-
-if six.PY3:
- integer_types = (int,)
- bytes_type = bytes
- text_type = str
- string_types = (bytes, str)
- BYTES_TYPES = (bytes, bytearray, memoryview)
-else:
- integer_types = (int, long,)
- bytes_type = str
- text_type = unicode
- string_types = basestring
- if PY26:
- BYTES_TYPES = (str, bytearray, buffer)
- else: # Python 2.7
- BYTES_TYPES = (str, bytearray, memoryview, buffer)
-
-
-if six.PY3:
- def reraise(tp, value, tb=None):
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
-else:
- exec("""def reraise(tp, value, tb=None): raise tp, value, tb""")
-
-
-def flatten_bytes(data):
- """
- Convert bytes-like objects (bytes, bytearray, memoryview, buffer) to
- a bytes string.
- """
- if not isinstance(data, BYTES_TYPES):
- raise TypeError('data argument must be byte-ish (%r)',
- type(data))
- if PY34:
- # In Python 3.4, socket.send() and bytes.join() accept memoryview
- # and bytearray
- return data
- if not data:
- return b''
- if six.PY2 and isinstance(data, (buffer, bytearray)):
- return str(data)
- elif not PY26 and isinstance(data, memoryview):
- return data.tobytes()
- else:
- return data
-
-
-def flatten_list_bytes(data):
- """Concatenate a sequence of bytes-like objects."""
- data = map(flatten_bytes, data)
- return b''.join(data)
+++ /dev/null
-"""Constants."""
-
-# After the connection is lost, log warnings after this many write()s.
-LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5
-
-# Seconds to wait before retrying accept().
-ACCEPT_RETRY_DELAY = 1
+++ /dev/null
-__all__ = ['coroutine',
- 'iscoroutinefunction', 'iscoroutine',
- 'From', 'Return']
-
-import functools
-import inspect
-import opcode
-import os
-import sys
-import textwrap
-import traceback
-import types
-
-from . import compat
-from . import events
-from . import futures
-from .log import logger
-
-
-# Opcode of "yield from" instruction
-_YIELD_FROM = opcode.opmap.get('YIELD_FROM', None)
-
-# If you set _DEBUG to true, @coroutine will wrap the resulting
-# generator objects in a CoroWrapper instance (defined below). That
-# instance will log a message when the generator is never iterated
-# over, which may happen when you forget to use "yield from" with a
-# coroutine call. Note that the value of the _DEBUG flag is taken
-# when the decorator is used, so to be of any use it must be set
-# before you define your coroutines. A downside of using this feature
-# is that tracebacks show entries for the CoroWrapper.__next__ method
-# when _DEBUG is true.
-_DEBUG = bool(os.environ.get('TROLLIUSDEBUG'))
-
-
-try:
- _types_coroutine = types.coroutine
-except AttributeError:
- _types_coroutine = None
-
-try:
- _inspect_iscoroutinefunction = inspect.iscoroutinefunction
-except AttributeError:
- _inspect_iscoroutinefunction = lambda func: False
-
-try:
- from collections.abc import Coroutine as _CoroutineABC, \
- Awaitable as _AwaitableABC
-except ImportError:
- _CoroutineABC = _AwaitableABC = None
-
-
-if _YIELD_FROM is not None:
- # Check for CPython issue #21209
- exec('''if 1:
- def has_yield_from_bug():
- class MyGen:
- def __init__(self):
- self.send_args = None
- def __iter__(self):
- return self
- def __next__(self):
- return 42
- def send(self, *what):
- self.send_args = what
- return None
- def yield_from_gen(gen):
- yield from gen
- value = (1, 2, 3)
- gen = MyGen()
- coro = yield_from_gen(gen)
- next(coro)
- coro.send(value)
- return gen.send_args != (value,)
-''')
- _YIELD_FROM_BUG = has_yield_from_bug()
- del has_yield_from_bug
-else:
- _YIELD_FROM_BUG = False
-
-
-if compat.PY35:
- return_base_class = Exception
-else:
- return_base_class = StopIteration
-
-class ReturnException(return_base_class):
- def __init__(self, *args):
- return_base_class.__init__(self)
- if not args:
- self.value = None
- elif len(args) == 1:
- self.value = args[0]
- else:
- self.value = args
- self.raised = False
- if _DEBUG:
- frame = sys._getframe(1)
- self._source_traceback = traceback.extract_stack(frame)
- # explicitly clear the reference to avoid reference cycles
- frame = None
- else:
- self._source_traceback = None
-
- def __del__(self):
- if self.raised:
- return
-
- fmt = 'Return(%r) used without raise'
- if self._source_traceback:
- fmt += '\nReturn created at (most recent call last):\n'
- tb = ''.join(traceback.format_list(self._source_traceback))
- fmt += tb.rstrip()
- logger.error(fmt, self.value)
-
-
-if compat.PY33 and not compat.PY35:
- # Don't use the Return class on Python 3.3 and 3.4 to support asyncio
- # coroutines (to avoid the warning emited in Return destructor).
- #
- # The problem is that ReturnException inherits from StopIteration.
- # "yield from trollius_coroutine". Task._step() does not receive the Return
- # exception, because "yield from" handles it internally. So it's not
- # possible to set the raised attribute to True to avoid the warning in
- # Return destructor.
- def Return(*args):
- if not args:
- value = None
- elif len(args) == 1:
- value = args[0]
- else:
- value = args
- return StopIteration(value)
-else:
- Return = ReturnException
-
-
-def debug_wrapper(gen):
- # This function is called from 'sys.set_coroutine_wrapper'.
- # We only wrap here coroutines defined via 'async def' syntax.
- # Generator-based coroutines are wrapped in @coroutine
- # decorator.
- return CoroWrapper(gen, None)
-
-
-def _coroutine_at_yield_from(coro):
- """Test if the last instruction of a coroutine is "yield from".
-
- Return False if the coroutine completed.
- """
- frame = coro.gi_frame
- if frame is None:
- return False
- code = coro.gi_code
- assert frame.f_lasti >= 0
- offset = frame.f_lasti + 1
- instr = code.co_code[offset]
- return (instr == _YIELD_FROM)
-
-
-class CoroWrapper:
- # Wrapper for coroutine object in _DEBUG mode.
-
- def __init__(self, gen, func=None):
- assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
- self.gen = gen
- self.func = func # Used to unwrap @coroutine decorator
- self._source_traceback = traceback.extract_stack(sys._getframe(1))
- self.__name__ = getattr(gen, '__name__', None)
- self.__qualname__ = getattr(gen, '__qualname__', None)
-
- def __repr__(self):
- coro_repr = _format_coroutine(self)
- if self._source_traceback:
- frame = self._source_traceback[-1]
- coro_repr += ', created at %s:%s' % (frame[0], frame[1])
- return '<%s %s>' % (self.__class__.__name__, coro_repr)
-
- def __iter__(self):
- return self
-
- def __next__(self):
- return next(self.gen)
- next = __next__
-
- if _YIELD_FROM_BUG:
- # For for CPython issue #21209: using "yield from" and a custom
- # generator, generator.send(tuple) unpacks the tuple instead of passing
- # the tuple unchanged. Check if the caller is a generator using "yield
- # from" to decide if the parameter should be unpacked or not.
- def send(self, *value):
- frame = sys._getframe()
- caller = frame.f_back
- assert caller.f_lasti >= 0
- if caller.f_code.co_code[caller.f_lasti] != _YIELD_FROM:
- value = value[0]
- return self.gen.send(value)
- else:
- def send(self, value):
- return self.gen.send(value)
-
- def throw(self, exc_type, exc_value=None, exc_tb=None):
- return self.gen.throw(exc_type, exc_value, exc_tb)
-
- def close(self):
- return self.gen.close()
-
- @property
- def gi_frame(self):
- return self.gen.gi_frame
-
- @property
- def gi_running(self):
- return self.gen.gi_running
-
- @property
- def gi_code(self):
- return self.gen.gi_code
-
- if compat.PY35:
-
- __await__ = __iter__ # make compatible with 'await' expression
-
- @property
- def gi_yieldfrom(self):
- return self.gen.gi_yieldfrom
-
- @property
- def cr_await(self):
- return self.gen.cr_await
-
- @property
- def cr_running(self):
- return self.gen.cr_running
-
- @property
- def cr_code(self):
- return self.gen.cr_code
-
- @property
- def cr_frame(self):
- return self.gen.cr_frame
-
- def __del__(self):
- # Be careful accessing self.gen.frame -- self.gen might not exist.
- gen = getattr(self, 'gen', None)
- frame = getattr(gen, 'gi_frame', None)
- if frame is None:
- frame = getattr(gen, 'cr_frame', None)
- if frame is not None and frame.f_lasti == -1:
- msg = '%r was never yielded from' % self
- tb = getattr(self, '_source_traceback', ())
- if tb:
- tb = ''.join(traceback.format_list(tb))
- msg += ('\nCoroutine object created at '
- '(most recent call last):\n')
- msg += tb.rstrip()
- logger.error(msg)
-
-if not compat.PY34:
- # Backport functools.update_wrapper() from Python 3.4:
- # - Python 2.7 fails if assigned attributes don't exist
- # - Python 2.7 and 3.1 don't set the __wrapped__ attribute
- # - Python 3.2 and 3.3 set __wrapped__ before updating __dict__
- def _update_wrapper(wrapper,
- wrapped,
- assigned = functools.WRAPPER_ASSIGNMENTS,
- updated = functools.WRAPPER_UPDATES):
- """Update a wrapper function to look like the wrapped function
-
- wrapper is the function to be updated
- wrapped is the original function
- assigned is a tuple naming the attributes assigned directly
- from the wrapped function to the wrapper function (defaults to
- functools.WRAPPER_ASSIGNMENTS)
- updated is a tuple naming the attributes of the wrapper that
- are updated with the corresponding attribute from the wrapped
- function (defaults to functools.WRAPPER_UPDATES)
- """
- for attr in assigned:
- try:
- value = getattr(wrapped, attr)
- except AttributeError:
- pass
- else:
- setattr(wrapper, attr, value)
- for attr in updated:
- getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
- # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
- # from the wrapped function when updating __dict__
- wrapper.__wrapped__ = wrapped
- # Return the wrapper so this can be used as a decorator via partial()
- return wrapper
-
- def _wraps(wrapped,
- assigned = functools.WRAPPER_ASSIGNMENTS,
- updated = functools.WRAPPER_UPDATES):
- """Decorator factory to apply update_wrapper() to a wrapper function
-
- Returns a decorator that invokes update_wrapper() with the decorated
- function as the wrapper argument and the arguments to wraps() as the
- remaining arguments. Default arguments are as for update_wrapper().
- This is a convenience function to simplify applying partial() to
- update_wrapper().
- """
- return functools.partial(_update_wrapper, wrapped=wrapped,
- assigned=assigned, updated=updated)
-else:
- _wraps = functools.wraps
-
-_PEP479 = (sys.version_info >= (3, 5))
-if _PEP479:
- # Need exec() because yield+return raises a SyntaxError on Python 2
- exec(textwrap.dedent('''
- def pep479_wrapper(func, coro_func):
- @_wraps(func)
- def pep479_wrapped(*args, **kw):
- coro = coro_func(*args, **kw)
- value = None
- error = None
- while True:
- try:
- if error is not None:
- value = coro.throw(error)
- elif value is not None:
- value = coro.send(value)
- else:
- value = next(coro)
- except RuntimeError:
- # FIXME: special case for
- # FIXME: "isinstance(exc.__context__, StopIteration)"?
- raise
- except StopIteration as exc:
- return exc.value
- except Return as exc:
- exc.raised = True
- return exc.value
- except BaseException as exc:
- raise
-
- try:
- value = yield value
- error = None
- except BaseException as exc:
- value = None
- error = exc
-
- return pep479_wrapped
- '''))
-
-
-def coroutine(func):
- """Decorator to mark coroutines.
-
- If the coroutine is not yielded from before it is destroyed,
- an error message is logged.
- """
- if _inspect_iscoroutinefunction(func):
- # In Python 3.5 that's all we need to do for coroutines
- # defiend with "async def".
- # Wrapping in CoroWrapper will happen via
- # 'sys.set_coroutine_wrapper' function.
- return func
-
- if inspect.isgeneratorfunction(func):
- coro = func
- else:
- @_wraps(func)
- def coro(*args, **kw):
- res = func(*args, **kw)
- if (isinstance(res, futures._FUTURE_CLASSES)
- or inspect.isgenerator(res)):
- res = yield From(res)
- elif _AwaitableABC is not None:
- # If 'func' returns an Awaitable (new in 3.5) we
- # want to run it.
- try:
- await_meth = res.__await__
- except AttributeError:
- pass
- else:
- if isinstance(res, _AwaitableABC):
- res = yield From(await_meth())
- raise Return(res)
-
- if _PEP479:
- # FIXME: use @_wraps
- coro = pep479_wrapper(func, coro)
- coro = _wraps(func)(coro)
-
- if not _DEBUG:
- if _types_coroutine is None:
- wrapper = coro
- else:
- wrapper = _types_coroutine(coro)
- else:
- @_wraps(func)
- def wrapper(*args, **kwds):
- w = CoroWrapper(coro(*args, **kwds), func=func)
- if w._source_traceback:
- del w._source_traceback[-1]
- # Python < 3.5 does not implement __qualname__
- # on generator objects, so we set it manually.
- # We use getattr as some callables (such as
- # functools.partial may lack __qualname__).
- w.__name__ = getattr(func, '__name__', None)
- w.__qualname__ = getattr(func, '__qualname__', None)
- return w
-
- wrapper._is_coroutine = True # For iscoroutinefunction().
- return wrapper
-
-
-def iscoroutinefunction(func):
- """Return True if func is a decorated coroutine function."""
- return (getattr(func, '_is_coroutine', False) or
- _inspect_iscoroutinefunction(func))
-
-
-_COROUTINE_TYPES = (types.GeneratorType, CoroWrapper)
-if _CoroutineABC is not None:
- _COROUTINE_TYPES += (_CoroutineABC,)
-if events.asyncio is not None:
- # Accept also asyncio CoroWrapper for interoperability
- if hasattr(events.asyncio, 'coroutines'):
- _COROUTINE_TYPES += (events.asyncio.coroutines.CoroWrapper,)
- else:
- # old asyncio/Python versions
- _COROUTINE_TYPES += (events.asyncio.tasks.CoroWrapper,)
-
-def iscoroutine(obj):
- """Return True if obj is a coroutine object."""
- return isinstance(obj, _COROUTINE_TYPES)
-
-
-def _format_coroutine(coro):
- assert iscoroutine(coro)
-
- coro_name = None
- if isinstance(coro, CoroWrapper):
- func = coro.func
- coro_name = coro.__qualname__
- if coro_name is not None:
- coro_name = '{0}()'.format(coro_name)
- else:
- func = coro
-
- if coro_name is None:
- coro_name = events._format_callback(func, ())
-
- try:
- coro_code = coro.gi_code
- except AttributeError:
- coro_code = coro.cr_code
-
- try:
- coro_frame = coro.gi_frame
- except AttributeError:
- coro_frame = coro.cr_frame
-
- filename = coro_code.co_filename
- if (isinstance(coro, CoroWrapper)
- and not inspect.isgeneratorfunction(coro.func)
- and coro.func is not None):
- filename, lineno = events._get_function_source(coro.func)
- if coro_frame is None:
- coro_repr = ('%s done, defined at %s:%s'
- % (coro_name, filename, lineno))
- else:
- coro_repr = ('%s running, defined at %s:%s'
- % (coro_name, filename, lineno))
- elif coro_frame is not None:
- lineno = coro_frame.f_lineno
- coro_repr = ('%s running at %s:%s'
- % (coro_name, filename, lineno))
- else:
- lineno = coro_code.co_firstlineno
- coro_repr = ('%s done, defined at %s:%s'
- % (coro_name, filename, lineno))
-
- return coro_repr
-
-
-class FromWrapper(object):
- __slots__ = ('obj',)
-
- def __init__(self, obj):
- if isinstance(obj, FromWrapper):
- obj = obj.obj
- assert not isinstance(obj, FromWrapper)
- self.obj = obj
-
-def From(obj):
- if not _DEBUG:
- return obj
- else:
- return FromWrapper(obj)
+++ /dev/null
-"""Event loop and event loop policy."""
-from __future__ import absolute_import
-
-__all__ = ['AbstractEventLoopPolicy',
- 'AbstractEventLoop', 'AbstractServer',
- 'Handle', 'TimerHandle',
- 'get_event_loop_policy', 'set_event_loop_policy',
- 'get_event_loop', 'set_event_loop', 'new_event_loop',
- 'get_child_watcher', 'set_child_watcher',
- ]
-
-import functools
-import inspect
-import socket
-import subprocess
-import sys
-import threading
-import traceback
-try:
- import reprlib # Python 3
-except ImportError:
- import repr as reprlib # Python 2
-
-try:
- import asyncio
-except (ImportError, SyntaxError):
- # ignore SyntaxError for convenience: ignore SyntaxError caused by "yield
- # from" if asyncio module is in the Python path
- asyncio = None
-
-from trollius import compat
-
-
-def _get_function_source(func):
- if compat.PY34:
- func = inspect.unwrap(func)
- elif hasattr(func, '__wrapped__'):
- func = func.__wrapped__
- if inspect.isfunction(func):
- code = func.__code__
- return (code.co_filename, code.co_firstlineno)
- if isinstance(func, functools.partial):
- return _get_function_source(func.func)
- if compat.PY34 and isinstance(func, functools.partialmethod):
- return _get_function_source(func.func)
- return None
-
-
-def _format_args(args):
- """Format function arguments.
-
- Special case for a single parameter: ('hello',) is formatted as ('hello').
- """
- # use reprlib to limit the length of the output
- args_repr = reprlib.repr(args)
- if len(args) == 1 and args_repr.endswith(',)'):
- args_repr = args_repr[:-2] + ')'
- return args_repr
-
-
-def _format_callback(func, args, suffix=''):
- if isinstance(func, functools.partial):
- if args is not None:
- suffix = _format_args(args) + suffix
- return _format_callback(func.func, func.args, suffix)
-
- if hasattr(func, '__qualname__'):
- func_repr = getattr(func, '__qualname__')
- elif hasattr(func, '__name__'):
- func_repr = getattr(func, '__name__')
- else:
- func_repr = repr(func)
-
- if args is not None:
- func_repr += _format_args(args)
- if suffix:
- func_repr += suffix
- return func_repr
-
-def _format_callback_source(func, args):
- func_repr = _format_callback(func, args)
- source = _get_function_source(func)
- if source:
- func_repr += ' at %s:%s' % source
- return func_repr
-
-
-class Handle(object):
- """Object returned by callback registration methods."""
-
- __slots__ = ('_callback', '_args', '_cancelled', '_loop',
- '_source_traceback', '_repr', '__weakref__')
-
- def __init__(self, callback, args, loop):
- assert not isinstance(callback, Handle), 'A Handle is not a callback'
- self._loop = loop
- self._callback = callback
- self._args = args
- self._cancelled = False
- self._repr = None
- if self._loop.get_debug():
- self._source_traceback = traceback.extract_stack(sys._getframe(1))
- else:
- self._source_traceback = None
-
- def _repr_info(self):
- info = [self.__class__.__name__]
- if self._cancelled:
- info.append('cancelled')
- if self._callback is not None:
- info.append(_format_callback_source(self._callback, self._args))
- if self._source_traceback:
- frame = self._source_traceback[-1]
- info.append('created at %s:%s' % (frame[0], frame[1]))
- return info
-
- def __repr__(self):
- if self._repr is not None:
- return self._repr
- info = self._repr_info()
- return '<%s>' % ' '.join(info)
-
- def cancel(self):
- if not self._cancelled:
- self._cancelled = True
- if self._loop.get_debug():
- # Keep a representation in debug mode to keep callback and
- # parameters. For example, to log the warning
- # "Executing <Handle...> took 2.5 second"
- self._repr = repr(self)
- self._callback = None
- self._args = None
-
- def _run(self):
- try:
- self._callback(*self._args)
- except Exception as exc:
- cb = _format_callback_source(self._callback, self._args)
- msg = 'Exception in callback {0}'.format(cb)
- context = {
- 'message': msg,
- 'exception': exc,
- 'handle': self,
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
- self = None # Needed to break cycles when an exception occurs.
-
-
-class TimerHandle(Handle):
- """Object returned by timed callback registration methods."""
-
- __slots__ = ['_scheduled', '_when']
-
- def __init__(self, when, callback, args, loop):
- assert when is not None
- super(TimerHandle, self).__init__(callback, args, loop)
- if self._source_traceback:
- del self._source_traceback[-1]
- self._when = when
- self._scheduled = False
-
- def _repr_info(self):
- info = super(TimerHandle, self)._repr_info()
- pos = 2 if self._cancelled else 1
- info.insert(pos, 'when=%s' % self._when)
- return info
-
- def __hash__(self):
- return hash(self._when)
-
- def __lt__(self, other):
- return self._when < other._when
-
- def __le__(self, other):
- if self._when < other._when:
- return True
- return self.__eq__(other)
-
- def __gt__(self, other):
- return self._when > other._when
-
- def __ge__(self, other):
- if self._when > other._when:
- return True
- return self.__eq__(other)
-
- def __eq__(self, other):
- if isinstance(other, TimerHandle):
- return (self._when == other._when and
- self._callback == other._callback and
- self._args == other._args and
- self._cancelled == other._cancelled)
- return NotImplemented
-
- def __ne__(self, other):
- equal = self.__eq__(other)
- return NotImplemented if equal is NotImplemented else not equal
-
- def cancel(self):
- if not self._cancelled:
- self._loop._timer_handle_cancelled(self)
- super(TimerHandle, self).cancel()
-
-
-class AbstractServer(object):
- """Abstract server returned by create_server()."""
-
- def close(self):
- """Stop serving. This leaves existing connections open."""
- return NotImplemented
-
- def wait_closed(self):
- """Coroutine to wait until service is closed."""
- return NotImplemented
-
-
-if asyncio is not None:
- # Reuse asyncio classes so asyncio.set_event_loop() and
- # asyncio.set_event_loop_policy() accept Trollius event loop and trollius
- # event loop policy
- AbstractEventLoop = asyncio.AbstractEventLoop
- AbstractEventLoopPolicy = asyncio.AbstractEventLoopPolicy
-else:
- class AbstractEventLoop(object):
- """Abstract event loop."""
-
- # Running and stopping the event loop.
-
- def run_forever(self):
- """Run the event loop until stop() is called."""
- raise NotImplementedError
-
- def run_until_complete(self, future):
- """Run the event loop until a Future is done.
-
- Return the Future's result, or raise its exception.
- """
- raise NotImplementedError
-
- def stop(self):
- """Stop the event loop as soon as reasonable.
-
- Exactly how soon that is may depend on the implementation, but
- no more I/O callbacks should be scheduled.
- """
- raise NotImplementedError
-
- def is_running(self):
- """Return whether the event loop is currently running."""
- raise NotImplementedError
-
- def is_closed(self):
- """Returns True if the event loop was closed."""
- raise NotImplementedError
-
- def close(self):
- """Close the loop.
-
- The loop should not be running.
-
- This is idempotent and irreversible.
-
- No other methods should be called after this one.
- """
- raise NotImplementedError
-
- # Methods scheduling callbacks. All these return Handles.
-
- def _timer_handle_cancelled(self, handle):
- """Notification that a TimerHandle has been cancelled."""
- raise NotImplementedError
-
- def call_soon(self, callback, *args):
- return self.call_later(0, callback, *args)
-
- def call_later(self, delay, callback, *args):
- raise NotImplementedError
-
- def call_at(self, when, callback, *args):
- raise NotImplementedError
-
- def time(self):
- raise NotImplementedError
-
- # Method scheduling a coroutine object: create a task.
-
- def create_task(self, coro):
- raise NotImplementedError
-
- # Methods for interacting with threads.
-
- def call_soon_threadsafe(self, callback, *args):
- raise NotImplementedError
-
- def run_in_executor(self, executor, func, *args):
- raise NotImplementedError
-
- def set_default_executor(self, executor):
- raise NotImplementedError
-
- # Network I/O methods returning Futures.
-
- def getaddrinfo(self, host, port, family=0, type=0, proto=0, flags=0):
- raise NotImplementedError
-
- def getnameinfo(self, sockaddr, flags=0):
- raise NotImplementedError
-
- def create_connection(self, protocol_factory, host=None, port=None,
- ssl=None, family=0, proto=0, flags=0, sock=None,
- local_addr=None, server_hostname=None):
- raise NotImplementedError
-
- def create_server(self, protocol_factory, host=None, port=None,
- family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE,
- sock=None, backlog=100, ssl=None, reuse_address=None):
- """A coroutine which creates a TCP server bound to host and port.
-
- The return value is a Server object which can be used to stop
- the service.
-
- If host is an empty string or None all interfaces are assumed
- and a list of multiple sockets will be returned (most likely
- one for IPv4 and another one for IPv6).
-
- family can be set to either AF_INET or AF_INET6 to force the
- socket to use IPv4 or IPv6. If not set it will be determined
- from host (defaults to AF_UNSPEC).
-
- flags is a bitmask for getaddrinfo().
-
- sock can optionally be specified in order to use a preexisting
- socket object.
-
- backlog is the maximum number of queued connections passed to
- listen() (defaults to 100).
-
- ssl can be set to an SSLContext to enable SSL over the
- accepted connections.
-
- reuse_address tells the kernel to reuse a local socket in
- TIME_WAIT state, without waiting for its natural timeout to
- expire. If not specified will automatically be set to True on
- UNIX.
- """
- raise NotImplementedError
-
- def create_unix_connection(self, protocol_factory, path,
- ssl=None, sock=None,
- server_hostname=None):
- raise NotImplementedError
-
- def create_unix_server(self, protocol_factory, path,
- sock=None, backlog=100, ssl=None):
- """A coroutine which creates a UNIX Domain Socket server.
-
- The return value is a Server object, which can be used to stop
- the service.
-
- path is a str, representing a file systsem path to bind the
- server socket to.
-
- sock can optionally be specified in order to use a preexisting
- socket object.
-
- backlog is the maximum number of queued connections passed to
- listen() (defaults to 100).
-
- ssl can be set to an SSLContext to enable SSL over the
- accepted connections.
- """
- raise NotImplementedError
-
- def create_datagram_endpoint(self, protocol_factory,
- local_addr=None, remote_addr=None,
- family=0, proto=0, flags=0):
- raise NotImplementedError
-
- # Pipes and subprocesses.
-
- def connect_read_pipe(self, protocol_factory, pipe):
- """Register read pipe in event loop. Set the pipe to non-blocking mode.
-
- protocol_factory should instantiate object with Protocol interface.
- pipe is a file-like object.
- Return pair (transport, protocol), where transport supports the
- ReadTransport interface."""
- # The reason to accept file-like object instead of just file descriptor
- # is: we need to own pipe and close it at transport finishing
- # Can got complicated errors if pass f.fileno(),
- # close fd in pipe transport then close f and vise versa.
- raise NotImplementedError
-
- def connect_write_pipe(self, protocol_factory, pipe):
- """Register write pipe in event loop.
-
- protocol_factory should instantiate object with BaseProtocol interface.
- Pipe is file-like object already switched to nonblocking.
- Return pair (transport, protocol), where transport support
- WriteTransport interface."""
- # The reason to accept file-like object instead of just file descriptor
- # is: we need to own pipe and close it at transport finishing
- # Can got complicated errors if pass f.fileno(),
- # close fd in pipe transport then close f and vise versa.
- raise NotImplementedError
-
- def subprocess_shell(self, protocol_factory, cmd, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- **kwargs):
- raise NotImplementedError
-
- def subprocess_exec(self, protocol_factory, *args, **kwargs):
- raise NotImplementedError
-
- # Ready-based callback registration methods.
- # The add_*() methods return None.
- # The remove_*() methods return True if something was removed,
- # False if there was nothing to delete.
-
- def add_reader(self, fd, callback, *args):
- raise NotImplementedError
-
- def remove_reader(self, fd):
- raise NotImplementedError
-
- def add_writer(self, fd, callback, *args):
- raise NotImplementedError
-
- def remove_writer(self, fd):
- raise NotImplementedError
-
- # Completion based I/O methods returning Futures.
-
- def sock_recv(self, sock, nbytes):
- raise NotImplementedError
-
- def sock_sendall(self, sock, data):
- raise NotImplementedError
-
- def sock_connect(self, sock, address):
- raise NotImplementedError
-
- def sock_accept(self, sock):
- raise NotImplementedError
-
- # Signal handling.
-
- def add_signal_handler(self, sig, callback, *args):
- raise NotImplementedError
-
- def remove_signal_handler(self, sig):
- raise NotImplementedError
-
- # Task factory.
-
- def set_task_factory(self, factory):
- raise NotImplementedError
-
- def get_task_factory(self):
- raise NotImplementedError
-
- # Error handlers.
-
- def set_exception_handler(self, handler):
- raise NotImplementedError
-
- def default_exception_handler(self, context):
- raise NotImplementedError
-
- def call_exception_handler(self, context):
- raise NotImplementedError
-
- # Debug flag management.
-
- def get_debug(self):
- raise NotImplementedError
-
- def set_debug(self, enabled):
- raise NotImplementedError
-
-
- class AbstractEventLoopPolicy(object):
- """Abstract policy for accessing the event loop."""
-
- def get_event_loop(self):
- """Get the event loop for the current context.
-
- Returns an event loop object implementing the BaseEventLoop interface,
- or raises an exception in case no event loop has been set for the
- current context and the current policy does not specify to create one.
-
- It should never return None."""
- raise NotImplementedError
-
- def set_event_loop(self, loop):
- """Set the event loop for the current context to loop."""
- raise NotImplementedError
-
- def new_event_loop(self):
- """Create and return a new event loop object according to this
- policy's rules. If there's need to set this loop as the event loop for
- the current context, set_event_loop must be called explicitly."""
- raise NotImplementedError
-
- # Child processes handling (Unix only).
-
- def get_child_watcher(self):
- "Get the watcher for child processes."
- raise NotImplementedError
-
- def set_child_watcher(self, watcher):
- """Set the watcher for child processes."""
- raise NotImplementedError
-
-
-class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
- """Default policy implementation for accessing the event loop.
-
- In this policy, each thread has its own event loop. However, we
- only automatically create an event loop by default for the main
- thread; other threads by default have no event loop.
-
- Other policies may have different rules (e.g. a single global
- event loop, or automatically creating an event loop per thread, or
- using some other notion of context to which an event loop is
- associated).
- """
-
- _loop_factory = None
-
- class _Local(threading.local):
- _loop = None
- _set_called = False
-
- def __init__(self):
- self._local = self._Local()
-
- def get_event_loop(self):
- """Get the event loop.
-
- This may be None or an instance of EventLoop.
- """
- if (self._local._loop is None and
- not self._local._set_called and
- isinstance(threading.current_thread(), threading._MainThread)):
- self.set_event_loop(self.new_event_loop())
- if self._local._loop is None:
- raise RuntimeError('There is no current event loop in thread %r.'
- % threading.current_thread().name)
- return self._local._loop
-
- def set_event_loop(self, loop):
- """Set the event loop."""
- self._local._set_called = True
- assert loop is None or isinstance(loop, AbstractEventLoop)
- self._local._loop = loop
-
- def new_event_loop(self):
- """Create a new event loop.
-
- You must call set_event_loop() to make this the current event
- loop.
- """
- return self._loop_factory()
-
-
-# Event loop policy. The policy itself is always global, even if the
-# policy's rules say that there is an event loop per thread (or other
-# notion of context). The default policy is installed by the first
-# call to get_event_loop_policy().
-_event_loop_policy = None
-
-# Lock for protecting the on-the-fly creation of the event loop policy.
-_lock = threading.Lock()
-
-
-def _init_event_loop_policy():
- global _event_loop_policy
- with _lock:
- if _event_loop_policy is None: # pragma: no branch
- from . import DefaultEventLoopPolicy
- _event_loop_policy = DefaultEventLoopPolicy()
-
-
-def get_event_loop_policy():
- """Get the current event loop policy."""
- if _event_loop_policy is None:
- _init_event_loop_policy()
- return _event_loop_policy
-
-
-def set_event_loop_policy(policy):
- """Set the current event loop policy.
-
- If policy is None, the default policy is restored."""
- global _event_loop_policy
- assert policy is None or isinstance(policy, AbstractEventLoopPolicy)
- _event_loop_policy = policy
-
-
-def get_event_loop():
- """Equivalent to calling get_event_loop_policy().get_event_loop()."""
- return get_event_loop_policy().get_event_loop()
-
-
-def set_event_loop(loop):
- """Equivalent to calling get_event_loop_policy().set_event_loop(loop)."""
- get_event_loop_policy().set_event_loop(loop)
-
-
-def new_event_loop():
- """Equivalent to calling get_event_loop_policy().new_event_loop()."""
- return get_event_loop_policy().new_event_loop()
-
-
-def get_child_watcher():
- """Equivalent to calling get_event_loop_policy().get_child_watcher()."""
- return get_event_loop_policy().get_child_watcher()
-
-
-def set_child_watcher(watcher):
- """Equivalent to calling
- get_event_loop_policy().set_child_watcher(watcher)."""
- return get_event_loop_policy().set_child_watcher(watcher)
+++ /dev/null
-from .log import logger
-
-__all__ = (
- 'CancelledError', 'TimeoutError',
- 'FIRST_COMPLETED', 'FIRST_EXCEPTION', 'ALL_COMPLETED',
- )
-
-# Argument for default thread pool executor creation.
-_MAX_WORKERS = 5
-
-try:
- import concurrent.futures
- import concurrent.futures._base
-except ImportError:
- FIRST_COMPLETED = 'FIRST_COMPLETED'
- FIRST_EXCEPTION = 'FIRST_EXCEPTION'
- ALL_COMPLETED = 'ALL_COMPLETED'
-
- class Future(object):
- def __init__(self, callback, args):
- try:
- self._result = callback(*args)
- self._exception = None
- except Exception as err:
- self._result = None
- self._exception = err
- self.callbacks = []
-
- def cancelled(self):
- return False
-
- def done(self):
- return True
-
- def exception(self):
- return self._exception
-
- def result(self):
- if self._exception is not None:
- raise self._exception
- else:
- return self._result
-
- def add_done_callback(self, callback):
- callback(self)
-
- class Error(Exception):
- """Base class for all future-related exceptions."""
- pass
-
- class CancelledError(Error):
- """The Future was cancelled."""
- pass
-
- class TimeoutError(Error):
- """The operation exceeded the given deadline."""
- pass
-
- class SynchronousExecutor:
- """
- Synchronous executor: submit() blocks until it gets the result.
- """
- def submit(self, callback, *args):
- return Future(callback, args)
-
- def shutdown(self, wait):
- pass
-
- def get_default_executor():
- logger.error("concurrent.futures module is missing: "
- "use a synchrounous executor as fallback!")
- return SynchronousExecutor()
-else:
- FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED
- FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION
- ALL_COMPLETED = concurrent.futures.ALL_COMPLETED
-
- Future = concurrent.futures.Future
- Error = concurrent.futures._base.Error
- CancelledError = concurrent.futures.CancelledError
- TimeoutError = concurrent.futures.TimeoutError
-
- def get_default_executor():
- return concurrent.futures.ThreadPoolExecutor(_MAX_WORKERS)
+++ /dev/null
-"""A Future class similar to the one in PEP 3148."""
-
-__all__ = ['CancelledError', 'TimeoutError',
- 'InvalidStateError',
- 'Future', 'wrap_future',
- ]
-
-import logging
-import six
-import sys
-import traceback
-try:
- import reprlib # Python 3
-except ImportError:
- import repr as reprlib # Python 2
-
-from . import compat
-from . import events
-from . import executor
-
-# States for Future.
-_PENDING = 'PENDING'
-_CANCELLED = 'CANCELLED'
-_FINISHED = 'FINISHED'
-
-Error = executor.Error
-CancelledError = executor.CancelledError
-TimeoutError = executor.TimeoutError
-
-STACK_DEBUG = logging.DEBUG - 1 # heavy-duty debugging
-
-
-class InvalidStateError(Error):
- """The operation is not allowed in this state."""
-
-
-class _TracebackLogger(object):
- """Helper to log a traceback upon destruction if not cleared.
-
- This solves a nasty problem with Futures and Tasks that have an
- exception set: if nobody asks for the exception, the exception is
- never logged. This violates the Zen of Python: 'Errors should
- never pass silently. Unless explicitly silenced.'
-
- However, we don't want to log the exception as soon as
- set_exception() is called: if the calling code is written
- properly, it will get the exception and handle it properly. But
- we *do* want to log it if result() or exception() was never called
- -- otherwise developers waste a lot of time wondering why their
- buggy code fails silently.
-
- An earlier attempt added a __del__() method to the Future class
- itself, but this backfired because the presence of __del__()
- prevents garbage collection from breaking cycles. A way out of
- this catch-22 is to avoid having a __del__() method on the Future
- class itself, but instead to have a reference to a helper object
- with a __del__() method that logs the traceback, where we ensure
- that the helper object doesn't participate in cycles, and only the
- Future has a reference to it.
-
- The helper object is added when set_exception() is called. When
- the Future is collected, and the helper is present, the helper
- object is also collected, and its __del__() method will log the
- traceback. When the Future's result() or exception() method is
- called (and a helper object is present), it removes the helper
- object, after calling its clear() method to prevent it from
- logging.
-
- One downside is that we do a fair amount of work to extract the
- traceback from the exception, even when it is never logged. It
- would seem cheaper to just store the exception object, but that
- references the traceback, which references stack frames, which may
- reference the Future, which references the _TracebackLogger, and
- then the _TracebackLogger would be included in a cycle, which is
- what we're trying to avoid! As an optimization, we don't
- immediately format the exception; we only do the work when
- activate() is called, which call is delayed until after all the
- Future's callbacks have run. Since usually a Future has at least
- one callback (typically set by 'yield from') and usually that
- callback extracts the callback, thereby removing the need to
- format the exception.
-
- PS. I don't claim credit for this solution. I first heard of it
- in a discussion about closing files when they are collected.
- """
-
- __slots__ = ('loop', 'source_traceback', 'exc', 'tb')
-
- def __init__(self, future, exc):
- self.loop = future._loop
- self.source_traceback = future._source_traceback
- self.exc = exc
- self.tb = None
-
- def activate(self):
- exc = self.exc
- if exc is not None:
- self.exc = None
- self.tb = traceback.format_exception(exc.__class__, exc,
- exc.__traceback__)
-
- def clear(self):
- self.exc = None
- self.tb = None
-
- def __del__(self):
- if self.tb:
- msg = 'Future/Task exception was never retrieved\n'
- if self.source_traceback:
- src = ''.join(traceback.format_list(self.source_traceback))
- msg += 'Future/Task created at (most recent call last):\n'
- msg += '%s\n' % src.rstrip()
- msg += ''.join(self.tb).rstrip()
- self.loop.call_exception_handler({'message': msg})
-
-
-class Future(object):
- """This class is *almost* compatible with concurrent.futures.Future.
-
- Differences:
-
- - result() and exception() do not take a timeout argument and
- raise an exception when the future isn't done yet.
-
- - Callbacks registered with add_done_callback() are always called
- via the event loop's call_soon_threadsafe().
-
- - This class is not compatible with the wait() and as_completed()
- methods in the concurrent.futures package.
-
- (In Python 3.4 or later we may be able to unify the implementations.)
- """
-
- # Class variables serving as defaults for instance variables.
- _state = _PENDING
- _result = None
- _exception = None
- _loop = None
- _source_traceback = None
-
- _blocking = False # proper use of future (yield vs yield from)
-
- # Used by Python 2 to raise the exception with the original traceback
- # in the exception() method in debug mode
- _exception_tb = None
-
- _log_traceback = False # Used for Python 3.4 and later
- _tb_logger = None # Used for Python 3.3 only
-
- def __init__(self, loop=None):
- """Initialize the future.
-
- The optional event_loop argument allows to explicitly set the event
- loop object used by the future. If it's not provided, the future uses
- the default event loop.
- """
- if loop is None:
- self._loop = events.get_event_loop()
- else:
- self._loop = loop
- self._callbacks = []
- if self._loop.get_debug():
- self._source_traceback = traceback.extract_stack(sys._getframe(1))
-
- def _format_callbacks(self):
- cb = self._callbacks
- size = len(cb)
- if not size:
- cb = ''
-
- def format_cb(callback):
- return events._format_callback_source(callback, ())
-
- if size == 1:
- cb = format_cb(cb[0])
- elif size == 2:
- cb = '{0}, {1}'.format(format_cb(cb[0]), format_cb(cb[1]))
- elif size > 2:
- cb = '{0}, <{1} more>, {2}'.format(format_cb(cb[0]),
- size-2,
- format_cb(cb[-1]))
- return 'cb=[%s]' % cb
-
- def _repr_info(self):
- info = [self._state.lower()]
- if self._state == _FINISHED:
- if self._exception is not None:
- info.append('exception={0!r}'.format(self._exception))
- else:
- # use reprlib to limit the length of the output, especially
- # for very long strings
- result = reprlib.repr(self._result)
- info.append('result={0}'.format(result))
- if self._callbacks:
- info.append(self._format_callbacks())
- if self._source_traceback:
- frame = self._source_traceback[-1]
- info.append('created at %s:%s' % (frame[0], frame[1]))
- return info
-
- def __repr__(self):
- info = self._repr_info()
- return '<%s %s>' % (self.__class__.__name__, ' '.join(info))
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self._log_traceback:
- # set_exception() was not called, or result() or exception()
- # has consumed the exception
- return
- exc = self._exception
- context = {
- 'message': ('%s exception was never retrieved'
- % self.__class__.__name__),
- 'exception': exc,
- 'future': self,
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
-
- def cancel(self):
- """Cancel the future and schedule callbacks.
-
- If the future is already done or cancelled, return False. Otherwise,
- change the future's state to cancelled, schedule the callbacks and
- return True.
- """
- if self._state != _PENDING:
- return False
- self._state = _CANCELLED
- self._schedule_callbacks()
- return True
-
- def _schedule_callbacks(self):
- """Internal: Ask the event loop to call all callbacks.
-
- The callbacks are scheduled to be called as soon as possible. Also
- clears the callback list.
- """
- callbacks = self._callbacks[:]
- if not callbacks:
- return
-
- self._callbacks[:] = []
- for callback in callbacks:
- self._loop.call_soon(callback, self)
-
- def cancelled(self):
- """Return True if the future was cancelled."""
- return self._state == _CANCELLED
-
- # Don't implement running(); see http://bugs.python.org/issue18699
-
- def done(self):
- """Return True if the future is done.
-
- Done means either that a result / exception are available, or that the
- future was cancelled.
- """
- return self._state != _PENDING
-
- def result(self):
- """Return the result this future represents.
-
- If the future has been cancelled, raises CancelledError. If the
- future's result isn't yet available, raises InvalidStateError. If
- the future is done and has an exception set, this exception is raised.
- """
- if self._state == _CANCELLED:
- raise CancelledError
- if self._state != _FINISHED:
- raise InvalidStateError('Result is not ready.')
- self._log_traceback = False
- if self._tb_logger is not None:
- self._tb_logger.clear()
- self._tb_logger = None
- exc_tb = self._exception_tb
- self._exception_tb = None
- if self._exception is not None:
- if exc_tb is not None:
- compat.reraise(type(self._exception), self._exception, exc_tb)
- else:
- raise self._exception
- return self._result
-
- def exception(self):
- """Return the exception that was set on this future.
-
- The exception (or None if no exception was set) is returned only if
- the future is done. If the future has been cancelled, raises
- CancelledError. If the future isn't done yet, raises
- InvalidStateError.
- """
- if self._state == _CANCELLED:
- raise CancelledError
- if self._state != _FINISHED:
- raise InvalidStateError('Exception is not set.')
- self._log_traceback = False
- if self._tb_logger is not None:
- self._tb_logger.clear()
- self._tb_logger = None
- self._exception_tb = None
- return self._exception
-
- def add_done_callback(self, fn):
- """Add a callback to be run when the future becomes done.
-
- The callback is called with a single argument - the future object. If
- the future is already done when this is called, the callback is
- scheduled with call_soon.
- """
- if self._state != _PENDING:
- self._loop.call_soon(fn, self)
- else:
- self._callbacks.append(fn)
-
- # New method not in PEP 3148.
-
- def remove_done_callback(self, fn):
- """Remove all instances of a callback from the "call when done" list.
-
- Returns the number of callbacks removed.
- """
- filtered_callbacks = [f for f in self._callbacks if f != fn]
- removed_count = len(self._callbacks) - len(filtered_callbacks)
- if removed_count:
- self._callbacks[:] = filtered_callbacks
- return removed_count
-
- # So-called internal methods (note: no set_running_or_notify_cancel()).
-
- def _set_result_unless_cancelled(self, result):
- """Helper setting the result only if the future was not cancelled."""
- if self.cancelled():
- return
- self.set_result(result)
-
- def set_result(self, result):
- """Mark the future done and set its result.
-
- If the future is already done when this method is called, raises
- InvalidStateError.
- """
- if self._state != _PENDING:
- raise InvalidStateError('{0}: {1!r}'.format(self._state, self))
- self._result = result
- self._state = _FINISHED
- self._schedule_callbacks()
-
- def _get_exception_tb(self):
- return self._exception_tb
-
- def set_exception(self, exception):
- self._set_exception_with_tb(exception, None)
-
- def _set_exception_with_tb(self, exception, exc_tb):
- """Mark the future done and set an exception.
-
- If the future is already done when this method is called, raises
- InvalidStateError.
- """
- if self._state != _PENDING:
- raise InvalidStateError('{0}: {1!r}'.format(self._state, self))
- if isinstance(exception, type):
- exception = exception()
- self._exception = exception
- if exc_tb is not None:
- self._exception_tb = exc_tb
- exc_tb = None
- elif not six.PY3:
- self._exception_tb = sys.exc_info()[2]
- self._state = _FINISHED
- self._schedule_callbacks()
- if compat.PY34:
- self._log_traceback = True
- else:
- self._tb_logger = _TracebackLogger(self, exception)
- if hasattr(exception, '__traceback__'):
- # Python 3: exception contains a link to the traceback
-
- # Arrange for the logger to be activated after all callbacks
- # have had a chance to call result() or exception().
- self._loop.call_soon(self._tb_logger.activate)
- else:
- if self._loop.get_debug():
- frame = sys._getframe(1)
- tb = ['Traceback (most recent call last):\n']
- if self._exception_tb is not None:
- tb += traceback.format_tb(self._exception_tb)
- else:
- tb += traceback.format_stack(frame)
- tb += traceback.format_exception_only(type(exception), exception)
- self._tb_logger.tb = tb
- else:
- self._tb_logger.tb = traceback.format_exception_only(
- type(exception),
- exception)
-
- self._tb_logger.exc = None
-
- # Truly internal methods.
-
- def _copy_state(self, other):
- """Internal helper to copy state from another Future.
-
- The other Future may be a concurrent.futures.Future.
- """
- assert other.done()
- if self.cancelled():
- return
- assert not self.done()
- if other.cancelled():
- self.cancel()
- else:
- exception = other.exception()
- if exception is not None:
- self.set_exception(exception)
- else:
- result = other.result()
- self.set_result(result)
-
-if events.asyncio is not None:
- # Accept also asyncio Future objects for interoperability
- _FUTURE_CLASSES = (Future, events.asyncio.Future)
-else:
- _FUTURE_CLASSES = Future
-
-def wrap_future(fut, loop=None):
- """Wrap concurrent.futures.Future object."""
- if isinstance(fut, _FUTURE_CLASSES):
- return fut
- assert isinstance(fut, executor.Future), \
- 'concurrent.futures.Future is expected, got {0!r}'.format(fut)
- if loop is None:
- loop = events.get_event_loop()
- new_future = Future(loop=loop)
-
- def _check_cancel_other(f):
- if f.cancelled():
- fut.cancel()
-
- new_future.add_done_callback(_check_cancel_other)
- fut.add_done_callback(
- lambda future: loop.call_soon_threadsafe(
- new_future._copy_state, future))
- return new_future
+++ /dev/null
-"""Synchronization primitives."""
-
-__all__ = ['Lock', 'Event', 'Condition', 'Semaphore', 'BoundedSemaphore']
-
-import collections
-
-from . import compat
-from . import events
-from . import futures
-from .coroutines import coroutine, From, Return
-
-
-class _ContextManager:
- """Context manager.
-
- This enables the following idiom for acquiring and releasing a
- lock around a block:
-
- with (yield From(lock)):
- <block>
-
- while failing loudly when accidentally using:
-
- with lock:
- <block>
- """
-
- def __init__(self, lock):
- self._lock = lock
-
- def __enter__(self):
- # We have no use for the "as ..." clause in the with
- # statement for locks.
- return None
-
- def __exit__(self, *args):
- try:
- self._lock.release()
- finally:
- self._lock = None # Crudely prevent reuse.
-
-
-class _ContextManagerMixin(object):
- def __enter__(self):
- raise RuntimeError(
- '"yield From" should be used as context manager expression')
-
- def __exit__(self, *args):
- # This must exist because __enter__ exists, even though that
- # always raises; that's how the with-statement works.
- pass
-
- # FIXME: support PEP 492?
- # if compat.PY35:
-
- # def __await__(self):
- # # To make "with await lock" work.
- # yield from self.acquire()
- # return _ContextManager(self)
-
- # @coroutine
- # def __aenter__(self):
- # yield from self.acquire()
- # # We have no use for the "as ..." clause in the with
- # # statement for locks.
- # return None
-
- # @coroutine
- # def __aexit__(self, exc_type, exc, tb):
- # self.release()
-
-
-class Lock(_ContextManagerMixin):
- """Primitive lock objects.
-
- A primitive lock is a synchronization primitive that is not owned
- by a particular coroutine when locked. A primitive lock is in one
- of two states, 'locked' or 'unlocked'.
-
- It is created in the unlocked state. It has two basic methods,
- acquire() and release(). When the state is unlocked, acquire()
- changes the state to locked and returns immediately. When the
- state is locked, acquire() blocks until a call to release() in
- another coroutine changes it to unlocked, then the acquire() call
- resets it to locked and returns. The release() method should only
- be called in the locked state; it changes the state to unlocked
- and returns immediately. If an attempt is made to release an
- unlocked lock, a RuntimeError will be raised.
-
- When more than one coroutine is blocked in acquire() waiting for
- the state to turn to unlocked, only one coroutine proceeds when a
- release() call resets the state to unlocked; first coroutine which
- is blocked in acquire() is being processed.
-
- acquire() is a coroutine and should be called with 'yield From'.
-
- Locks also support the context management protocol. '(yield From(lock))'
- should be used as context manager expression.
-
- Usage:
-
- lock = Lock()
- ...
- yield From(lock)
- try:
- ...
- finally:
- lock.release()
-
- Context manager usage:
-
- lock = Lock()
- ...
- with (yield From(lock)):
- ...
-
- Lock objects can be tested for locking state:
-
- if not lock.locked():
- yield From(lock)
- else:
- # lock is acquired
- ...
-
- """
-
- def __init__(self, loop=None):
- self._waiters = collections.deque()
- self._locked = False
- if loop is not None:
- self._loop = loop
- else:
- self._loop = events.get_event_loop()
-
- def __repr__(self):
- res = super(Lock, self).__repr__()
- extra = 'locked' if self._locked else 'unlocked'
- if self._waiters:
- extra = '{0},waiters:{1}'.format(extra, len(self._waiters))
- return '<{0} [{1}]>'.format(res[1:-1], extra)
-
- def locked(self):
- """Return True if lock is acquired."""
- return self._locked
-
- @coroutine
- def acquire(self):
- """Acquire a lock.
-
- This method blocks until the lock is unlocked, then sets it to
- locked and returns True.
- """
- if not self._waiters and not self._locked:
- self._locked = True
- raise Return(True)
-
- fut = futures.Future(loop=self._loop)
- self._waiters.append(fut)
- try:
- yield From(fut)
- self._locked = True
- raise Return(True)
- finally:
- self._waiters.remove(fut)
-
- def release(self):
- """Release a lock.
-
- When the lock is locked, reset it to unlocked, and return.
- If any other coroutines are blocked waiting for the lock to become
- unlocked, allow exactly one of them to proceed.
-
- When invoked on an unlocked lock, a RuntimeError is raised.
-
- There is no return value.
- """
- if self._locked:
- self._locked = False
- # Wake up the first waiter who isn't cancelled.
- for fut in self._waiters:
- if not fut.done():
- fut.set_result(True)
- break
- else:
- raise RuntimeError('Lock is not acquired.')
-
-
-class Event(object):
- """Asynchronous equivalent to threading.Event.
-
- Class implementing event objects. An event manages a flag that can be set
- to true with the set() method and reset to false with the clear() method.
- The wait() method blocks until the flag is true. The flag is initially
- false.
- """
-
- def __init__(self, loop=None):
- self._waiters = collections.deque()
- self._value = False
- if loop is not None:
- self._loop = loop
- else:
- self._loop = events.get_event_loop()
-
- def __repr__(self):
- res = super(Event, self).__repr__()
- extra = 'set' if self._value else 'unset'
- if self._waiters:
- extra = '{0},waiters:{1}'.format(extra, len(self._waiters))
- return '<{0} [{1}]>'.format(res[1:-1], extra)
-
- def is_set(self):
- """Return True if and only if the internal flag is true."""
- return self._value
-
- def set(self):
- """Set the internal flag to true. All coroutines waiting for it to
- become true are awakened. Coroutine that call wait() once the flag is
- true will not block at all.
- """
- if not self._value:
- self._value = True
-
- for fut in self._waiters:
- if not fut.done():
- fut.set_result(True)
-
- def clear(self):
- """Reset the internal flag to false. Subsequently, coroutines calling
- wait() will block until set() is called to set the internal flag
- to true again."""
- self._value = False
-
- @coroutine
- def wait(self):
- """Block until the internal flag is true.
-
- If the internal flag is true on entry, return True
- immediately. Otherwise, block until another coroutine calls
- set() to set the flag to true, then return True.
- """
- if self._value:
- raise Return(True)
-
- fut = futures.Future(loop=self._loop)
- self._waiters.append(fut)
- try:
- yield From(fut)
- raise Return(True)
- finally:
- self._waiters.remove(fut)
-
-
-class Condition(_ContextManagerMixin):
- """Asynchronous equivalent to threading.Condition.
-
- This class implements condition variable objects. A condition variable
- allows one or more coroutines to wait until they are notified by another
- coroutine.
-
- A new Lock object is created and used as the underlying lock.
- """
-
- def __init__(self, lock=None, loop=None):
- if loop is not None:
- self._loop = loop
- else:
- self._loop = events.get_event_loop()
-
- if lock is None:
- lock = Lock(loop=self._loop)
- elif lock._loop is not self._loop:
- raise ValueError("loop argument must agree with lock")
-
- self._lock = lock
- # Export the lock's locked(), acquire() and release() methods.
- self.locked = lock.locked
- self.acquire = lock.acquire
- self.release = lock.release
-
- self._waiters = collections.deque()
-
- def __repr__(self):
- res = super(Condition, self).__repr__()
- extra = 'locked' if self.locked() else 'unlocked'
- if self._waiters:
- extra = '{0},waiters:{1}'.format(extra, len(self._waiters))
- return '<{0} [{1}]>'.format(res[1:-1], extra)
-
- @coroutine
- def wait(self):
- """Wait until notified.
-
- If the calling coroutine has not acquired the lock when this
- method is called, a RuntimeError is raised.
-
- This method releases the underlying lock, and then blocks
- until it is awakened by a notify() or notify_all() call for
- the same condition variable in another coroutine. Once
- awakened, it re-acquires the lock and returns True.
- """
- if not self.locked():
- raise RuntimeError('cannot wait on un-acquired lock')
-
- self.release()
- try:
- fut = futures.Future(loop=self._loop)
- self._waiters.append(fut)
- try:
- yield From(fut)
- raise Return(True)
- finally:
- self._waiters.remove(fut)
-
- except Exception as exc:
- # Workaround CPython bug #23353: using yield/yield-from in an
- # except block of a generator doesn't clear properly
- # sys.exc_info()
- err = exc
- else:
- err = None
-
- if err is not None:
- yield From(self.acquire())
- raise err
-
- yield From(self.acquire())
-
- @coroutine
- def wait_for(self, predicate):
- """Wait until a predicate becomes true.
-
- The predicate should be a callable which result will be
- interpreted as a boolean value. The final predicate value is
- the return value.
- """
- result = predicate()
- while not result:
- yield From(self.wait())
- result = predicate()
- raise Return(result)
-
- def notify(self, n=1):
- """By default, wake up one coroutine waiting on this condition, if any.
- If the calling coroutine has not acquired the lock when this method
- is called, a RuntimeError is raised.
-
- This method wakes up at most n of the coroutines waiting for the
- condition variable; it is a no-op if no coroutines are waiting.
-
- Note: an awakened coroutine does not actually return from its
- wait() call until it can reacquire the lock. Since notify() does
- not release the lock, its caller should.
- """
- if not self.locked():
- raise RuntimeError('cannot notify on un-acquired lock')
-
- idx = 0
- for fut in self._waiters:
- if idx >= n:
- break
-
- if not fut.done():
- idx += 1
- fut.set_result(False)
-
- def notify_all(self):
- """Wake up all threads waiting on this condition. This method acts
- like notify(), but wakes up all waiting threads instead of one. If the
- calling thread has not acquired the lock when this method is called,
- a RuntimeError is raised.
- """
- self.notify(len(self._waiters))
-
-
-class Semaphore(_ContextManagerMixin):
- """A Semaphore implementation.
-
- A semaphore manages an internal counter which is decremented by each
- acquire() call and incremented by each release() call. The counter
- can never go below zero; when acquire() finds that it is zero, it blocks,
- waiting until some other thread calls release().
-
- Semaphores also support the context management protocol.
-
- The optional argument gives the initial value for the internal
- counter; it defaults to 1. If the value given is less than 0,
- ValueError is raised.
- """
-
- def __init__(self, value=1, loop=None):
- if value < 0:
- raise ValueError("Semaphore initial value must be >= 0")
- self._value = value
- self._waiters = collections.deque()
- if loop is not None:
- self._loop = loop
- else:
- self._loop = events.get_event_loop()
-
- def __repr__(self):
- res = super(Semaphore, self).__repr__()
- extra = 'locked' if self.locked() else 'unlocked,value:{0}'.format(
- self._value)
- if self._waiters:
- extra = '{0},waiters:{1}'.format(extra, len(self._waiters))
- return '<{0} [{1}]>'.format(res[1:-1], extra)
-
- def locked(self):
- """Returns True if semaphore can not be acquired immediately."""
- return self._value == 0
-
- @coroutine
- def acquire(self):
- """Acquire a semaphore.
-
- If the internal counter is larger than zero on entry,
- decrement it by one and return True immediately. If it is
- zero on entry, block, waiting until some other coroutine has
- called release() to make it larger than 0, and then return
- True.
- """
- if not self._waiters and self._value > 0:
- self._value -= 1
- raise Return(True)
-
- fut = futures.Future(loop=self._loop)
- self._waiters.append(fut)
- try:
- yield From(fut)
- self._value -= 1
- raise Return(True)
- finally:
- self._waiters.remove(fut)
-
- def release(self):
- """Release a semaphore, incrementing the internal counter by one.
- When it was zero on entry and another coroutine is waiting for it to
- become larger than zero again, wake up that coroutine.
- """
- self._value += 1
- for waiter in self._waiters:
- if not waiter.done():
- waiter.set_result(True)
- break
-
-
-class BoundedSemaphore(Semaphore):
- """A bounded semaphore implementation.
-
- This raises ValueError in release() if it would increase the value
- above the initial value.
- """
-
- def __init__(self, value=1, loop=None):
- self._bound_value = value
- super(BoundedSemaphore, self).__init__(value, loop=loop)
-
- def release(self):
- if self._value >= self._bound_value:
- raise ValueError('BoundedSemaphore released too many times')
- super(BoundedSemaphore, self).release()
+++ /dev/null
-"""Logging configuration."""
-
-import logging
-
-
-# Name the logger after the package.
-logger = logging.getLogger(__package__)
+++ /dev/null
-"""Event loop using a proactor and related classes.
-
-A proactor is a "notify-on-completion" multiplexer. Currently a
-proactor is only implemented on Windows with IOCP.
-"""
-
-__all__ = ['BaseProactorEventLoop']
-
-import socket
-import warnings
-
-from . import base_events
-from . import compat
-from . import constants
-from . import futures
-from . import sslproto
-from . import transports
-from .log import logger
-from .compat import flatten_bytes
-from .py33_exceptions import (BrokenPipeError,
- ConnectionAbortedError, ConnectionResetError)
-
-
-class _ProactorBasePipeTransport(transports._FlowControlMixin,
- transports.BaseTransport):
- """Base class for pipe and socket transports."""
-
- def __init__(self, loop, sock, protocol, waiter=None,
- extra=None, server=None):
- super(_ProactorBasePipeTransport, self).__init__(extra, loop)
- self._set_extra(sock)
- self._sock = sock
- self._protocol = protocol
- self._server = server
- self._buffer = None # None or bytearray.
- self._read_fut = None
- self._write_fut = None
- self._pending_write = 0
- self._conn_lost = 0
- self._closing = False # Set when close() called.
- self._eof_written = False
- if self._server is not None:
- self._server._attach()
- self._loop.call_soon(self._protocol.connection_made, self)
- if waiter is not None:
- # only wake up the waiter when connection_made() has been called
- self._loop.call_soon(waiter._set_result_unless_cancelled, None)
-
- def __repr__(self):
- info = [self.__class__.__name__]
- if self._sock is None:
- info.append('closed')
- elif self._closing:
- info.append('closing')
- if self._sock is not None:
- info.append('fd=%s' % self._sock.fileno())
- if self._read_fut is not None:
- info.append('read=%s' % self._read_fut)
- if self._write_fut is not None:
- info.append("write=%r" % self._write_fut)
- if self._buffer:
- bufsize = len(self._buffer)
- info.append('write_bufsize=%s' % bufsize)
- if self._eof_written:
- info.append('EOF written')
- return '<%s>' % ' '.join(info)
-
- def _set_extra(self, sock):
- self._extra['pipe'] = sock
-
- def close(self):
- if self._closing:
- return
- self._closing = True
- self._conn_lost += 1
- if not self._buffer and self._write_fut is None:
- self._loop.call_soon(self._call_connection_lost, None)
- if self._read_fut is not None:
- self._read_fut.cancel()
- self._read_fut = None
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._sock is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning)
- self.close()
-
- def _fatal_error(self, exc, message='Fatal error on pipe transport'):
- if isinstance(exc, (BrokenPipeError, ConnectionResetError)):
- if self._loop.get_debug():
- logger.debug("%r: %s", self, message, exc_info=True)
- else:
- self._loop.call_exception_handler({
- 'message': message,
- 'exception': exc,
- 'transport': self,
- 'protocol': self._protocol,
- })
- self._force_close(exc)
-
- def _force_close(self, exc):
- if self._closing:
- return
- self._closing = True
- self._conn_lost += 1
- if self._write_fut:
- self._write_fut.cancel()
- self._write_fut = None
- if self._read_fut:
- self._read_fut.cancel()
- self._read_fut = None
- self._pending_write = 0
- self._buffer = None
- self._loop.call_soon(self._call_connection_lost, exc)
-
- def _call_connection_lost(self, exc):
- try:
- self._protocol.connection_lost(exc)
- finally:
- # XXX If there is a pending overlapped read on the other
- # end then it may fail with ERROR_NETNAME_DELETED if we
- # just close our end. First calling shutdown() seems to
- # cure it, but maybe using DisconnectEx() would be better.
- if hasattr(self._sock, 'shutdown'):
- self._sock.shutdown(socket.SHUT_RDWR)
- self._sock.close()
- self._sock = None
- server = self._server
- if server is not None:
- server._detach()
- self._server = None
-
- def get_write_buffer_size(self):
- size = self._pending_write
- if self._buffer is not None:
- size += len(self._buffer)
- return size
-
-
-class _ProactorReadPipeTransport(_ProactorBasePipeTransport,
- transports.ReadTransport):
- """Transport for read pipes."""
-
- def __init__(self, loop, sock, protocol, waiter=None,
- extra=None, server=None):
- super(_ProactorReadPipeTransport, self).__init__(loop, sock, protocol,
- waiter, extra, server)
- self._paused = False
- self._loop.call_soon(self._loop_reading)
-
- def pause_reading(self):
- if self._closing:
- raise RuntimeError('Cannot pause_reading() when closing')
- if self._paused:
- raise RuntimeError('Already paused')
- self._paused = True
- if self._loop.get_debug():
- logger.debug("%r pauses reading", self)
-
- def resume_reading(self):
- if not self._paused:
- raise RuntimeError('Not paused')
- self._paused = False
- if self._closing:
- return
- self._loop.call_soon(self._loop_reading, self._read_fut)
- if self._loop.get_debug():
- logger.debug("%r resumes reading", self)
-
- def _loop_reading(self, fut=None):
- if self._paused:
- return
- data = None
-
- try:
- if fut is not None:
- assert self._read_fut is fut or (self._read_fut is None and
- self._closing)
- self._read_fut = None
- data = fut.result() # deliver data later in "finally" clause
-
- if self._closing:
- # since close() has been called we ignore any read data
- data = None
- return
-
- if data == b'':
- # we got end-of-file so no need to reschedule a new read
- return
-
- # reschedule a new read
- self._read_fut = self._loop._proactor.recv(self._sock, 4096)
- except ConnectionAbortedError as exc:
- if not self._closing:
- self._fatal_error(exc, 'Fatal read error on pipe transport')
- elif self._loop.get_debug():
- logger.debug("Read error on pipe transport while closing",
- exc_info=True)
- except ConnectionResetError as exc:
- self._force_close(exc)
- except OSError as exc:
- self._fatal_error(exc, 'Fatal read error on pipe transport')
- except futures.CancelledError:
- if not self._closing:
- raise
- else:
- self._read_fut.add_done_callback(self._loop_reading)
- finally:
- if data:
- self._protocol.data_received(data)
- elif data is not None:
- if self._loop.get_debug():
- logger.debug("%r received EOF", self)
- keep_open = self._protocol.eof_received()
- if not keep_open:
- self.close()
-
-
-class _ProactorBaseWritePipeTransport(_ProactorBasePipeTransport,
- transports.WriteTransport):
- """Transport for write pipes."""
-
- def write(self, data):
- data = flatten_bytes(data)
- if self._eof_written:
- raise RuntimeError('write_eof() already called')
-
- if not data:
- return
-
- if self._conn_lost:
- if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
- logger.warning('socket.send() raised exception.')
- self._conn_lost += 1
- return
-
- # Observable states:
- # 1. IDLE: _write_fut and _buffer both None
- # 2. WRITING: _write_fut set; _buffer None
- # 3. BACKED UP: _write_fut set; _buffer a bytearray
- # We always copy the data, so the caller can't modify it
- # while we're still waiting for the I/O to happen.
- if self._write_fut is None: # IDLE -> WRITING
- assert self._buffer is None
- # Pass a copy, except if it's already immutable.
- self._loop_writing(data=bytes(data))
- elif not self._buffer: # WRITING -> BACKED UP
- # Make a mutable copy which we can extend.
- self._buffer = bytearray(data)
- self._maybe_pause_protocol()
- else: # BACKED UP
- # Append to buffer (also copies).
- self._buffer.extend(data)
- self._maybe_pause_protocol()
-
- def _loop_writing(self, f=None, data=None):
- try:
- assert f is self._write_fut
- self._write_fut = None
- self._pending_write = 0
- if f:
- f.result()
- if data is None:
- data = self._buffer
- self._buffer = None
- if not data:
- if self._closing:
- self._loop.call_soon(self._call_connection_lost, None)
- if self._eof_written:
- self._sock.shutdown(socket.SHUT_WR)
- # Now that we've reduced the buffer size, tell the
- # protocol to resume writing if it was paused. Note that
- # we do this last since the callback is called immediately
- # and it may add more data to the buffer (even causing the
- # protocol to be paused again).
- self._maybe_resume_protocol()
- else:
- self._write_fut = self._loop._proactor.send(self._sock, data)
- if not self._write_fut.done():
- assert self._pending_write == 0
- self._pending_write = len(data)
- self._write_fut.add_done_callback(self._loop_writing)
- self._maybe_pause_protocol()
- else:
- self._write_fut.add_done_callback(self._loop_writing)
- except ConnectionResetError as exc:
- self._force_close(exc)
- except OSError as exc:
- self._fatal_error(exc, 'Fatal write error on pipe transport')
-
- def can_write_eof(self):
- return True
-
- def write_eof(self):
- self.close()
-
- def abort(self):
- self._force_close(None)
-
-
-class _ProactorWritePipeTransport(_ProactorBaseWritePipeTransport):
- def __init__(self, *args, **kw):
- super(_ProactorWritePipeTransport, self).__init__(*args, **kw)
- self._read_fut = self._loop._proactor.recv(self._sock, 16)
- self._read_fut.add_done_callback(self._pipe_closed)
-
- def _pipe_closed(self, fut):
- if fut.cancelled():
- # the transport has been closed
- return
- assert fut.result() == b''
- if self._closing:
- assert self._read_fut is None
- return
- assert fut is self._read_fut, (fut, self._read_fut)
- self._read_fut = None
- if self._write_fut is not None:
- self._force_close(BrokenPipeError())
- else:
- self.close()
-
-
-class _ProactorDuplexPipeTransport(_ProactorReadPipeTransport,
- _ProactorBaseWritePipeTransport,
- transports.Transport):
- """Transport for duplex pipes."""
-
- def can_write_eof(self):
- return False
-
- def write_eof(self):
- raise NotImplementedError
-
-
-class _ProactorSocketTransport(_ProactorReadPipeTransport,
- _ProactorBaseWritePipeTransport,
- transports.Transport):
- """Transport for connected sockets."""
-
- def _set_extra(self, sock):
- self._extra['socket'] = sock
- try:
- self._extra['sockname'] = sock.getsockname()
- except (socket.error, AttributeError):
- if self._loop.get_debug():
- logger.warning("getsockname() failed on %r",
- sock, exc_info=True)
- if 'peername' not in self._extra:
- try:
- self._extra['peername'] = sock.getpeername()
- except (socket.error, AttributeError):
- if self._loop.get_debug():
- logger.warning("getpeername() failed on %r",
- sock, exc_info=True)
-
- def can_write_eof(self):
- return True
-
- def write_eof(self):
- if self._closing or self._eof_written:
- return
- self._eof_written = True
- if self._write_fut is None:
- self._sock.shutdown(socket.SHUT_WR)
-
-
-class BaseProactorEventLoop(base_events.BaseEventLoop):
-
- def __init__(self, proactor):
- super(BaseProactorEventLoop, self).__init__()
- logger.debug('Using proactor: %s', proactor.__class__.__name__)
- self._proactor = proactor
- self._selector = proactor # convenient alias
- self._self_reading_future = None
- self._accept_futures = {} # socket file descriptor => Future
- proactor.set_loop(self)
- self._make_self_pipe()
-
- def _make_socket_transport(self, sock, protocol, waiter=None,
- extra=None, server=None):
- return _ProactorSocketTransport(self, sock, protocol, waiter,
- extra, server)
-
- def _make_ssl_transport(self, rawsock, protocol, sslcontext, waiter=None,
- server_side=False, server_hostname=None,
- extra=None, server=None):
- if not sslproto._is_sslproto_available():
- raise NotImplementedError("Proactor event loop requires Python 3.5"
- " or newer (ssl.MemoryBIO) to support "
- "SSL")
-
- ssl_protocol = sslproto.SSLProtocol(self, protocol, sslcontext, waiter,
- server_side, server_hostname)
- _ProactorSocketTransport(self, rawsock, ssl_protocol,
- extra=extra, server=server)
- return ssl_protocol._app_transport
-
- def _make_duplex_pipe_transport(self, sock, protocol, waiter=None,
- extra=None):
- return _ProactorDuplexPipeTransport(self,
- sock, protocol, waiter, extra)
-
- def _make_read_pipe_transport(self, sock, protocol, waiter=None,
- extra=None):
- return _ProactorReadPipeTransport(self, sock, protocol, waiter, extra)
-
- def _make_write_pipe_transport(self, sock, protocol, waiter=None,
- extra=None):
- # We want connection_lost() to be called when other end closes
- return _ProactorWritePipeTransport(self,
- sock, protocol, waiter, extra)
-
- def close(self):
- if self.is_running():
- raise RuntimeError("Cannot close a running event loop")
- if self.is_closed():
- return
-
- # Call these methods before closing the event loop (before calling
- # BaseEventLoop.close), because they can schedule callbacks with
- # call_soon(), which is forbidden when the event loop is closed.
- self._stop_accept_futures()
- self._close_self_pipe()
- self._proactor.close()
- self._proactor = None
- self._selector = None
-
- # Close the event loop
- super(BaseProactorEventLoop, self).close()
-
- def sock_recv(self, sock, n):
- return self._proactor.recv(sock, n)
-
- def sock_sendall(self, sock, data):
- return self._proactor.send(sock, data)
-
- def sock_connect(self, sock, address):
- try:
- if self._debug:
- base_events._check_resolved_address(sock, address)
- except ValueError as err:
- fut = futures.Future(loop=self)
- fut.set_exception(err)
- return fut
- else:
- return self._proactor.connect(sock, address)
-
- def sock_accept(self, sock):
- return self._proactor.accept(sock)
-
- def _socketpair(self):
- raise NotImplementedError
-
- def _close_self_pipe(self):
- if self._self_reading_future is not None:
- self._self_reading_future.cancel()
- self._self_reading_future = None
- self._ssock.close()
- self._ssock = None
- self._csock.close()
- self._csock = None
- self._internal_fds -= 1
-
- def _make_self_pipe(self):
- # A self-socket, really. :-)
- self._ssock, self._csock = self._socketpair()
- self._ssock.setblocking(False)
- self._csock.setblocking(False)
- self._internal_fds += 1
- self.call_soon(self._loop_self_reading)
-
- def _loop_self_reading(self, f=None):
- try:
- if f is not None:
- f.result() # may raise
- f = self._proactor.recv(self._ssock, 4096)
- except futures.CancelledError:
- # _close_self_pipe() has been called, stop waiting for data
- return
- except Exception as exc:
- self.call_exception_handler({
- 'message': 'Error on reading from the event loop self pipe',
- 'exception': exc,
- 'loop': self,
- })
- else:
- self._self_reading_future = f
- f.add_done_callback(self._loop_self_reading)
-
- def _write_to_self(self):
- self._csock.send(b'\0')
-
- def _start_serving(self, protocol_factory, sock,
- sslcontext=None, server=None):
-
- def loop(f=None):
- try:
- if f is not None:
- conn, addr = f.result()
- if self._debug:
- logger.debug("%r got a new connection from %r: %r",
- server, addr, conn)
- protocol = protocol_factory()
- if sslcontext is not None:
- self._make_ssl_transport(
- conn, protocol, sslcontext, server_side=True,
- extra={'peername': addr}, server=server)
- else:
- self._make_socket_transport(
- conn, protocol,
- extra={'peername': addr}, server=server)
- if self.is_closed():
- return
- f = self._proactor.accept(sock)
- except OSError as exc:
- if sock.fileno() != -1:
- self.call_exception_handler({
- 'message': 'Accept failed on a socket',
- 'exception': exc,
- 'socket': sock,
- })
- sock.close()
- elif self._debug:
- logger.debug("Accept failed on socket %r",
- sock, exc_info=True)
- except futures.CancelledError:
- sock.close()
- else:
- self._accept_futures[sock.fileno()] = f
- f.add_done_callback(loop)
-
- self.call_soon(loop)
-
- def _process_events(self, event_list):
- # Events are processed in the IocpProactor._poll() method
- pass
-
- def _stop_accept_futures(self):
- for future in self._accept_futures.values():
- future.cancel()
- self._accept_futures.clear()
-
- def _stop_serving(self, sock):
- self._stop_accept_futures()
- self._proactor._stop_serving(sock)
- sock.close()
+++ /dev/null
-"""Abstract Protocol class."""
-
-__all__ = ['BaseProtocol', 'Protocol', 'DatagramProtocol',
- 'SubprocessProtocol']
-
-
-class BaseProtocol(object):
- """Common base class for protocol interfaces.
-
- Usually user implements protocols that derived from BaseProtocol
- like Protocol or ProcessProtocol.
-
- The only case when BaseProtocol should be implemented directly is
- write-only transport like write pipe
- """
-
- def connection_made(self, transport):
- """Called when a connection is made.
-
- The argument is the transport representing the pipe connection.
- To receive data, wait for data_received() calls.
- When the connection is closed, connection_lost() is called.
- """
-
- def connection_lost(self, exc):
- """Called when the connection is lost or closed.
-
- The argument is an exception object or None (the latter
- meaning a regular EOF is received or the connection was
- aborted or closed).
- """
-
- def pause_writing(self):
- """Called when the transport's buffer goes over the high-water mark.
-
- Pause and resume calls are paired -- pause_writing() is called
- once when the buffer goes strictly over the high-water mark
- (even if subsequent writes increases the buffer size even
- more), and eventually resume_writing() is called once when the
- buffer size reaches the low-water mark.
-
- Note that if the buffer size equals the high-water mark,
- pause_writing() is not called -- it must go strictly over.
- Conversely, resume_writing() is called when the buffer size is
- equal or lower than the low-water mark. These end conditions
- are important to ensure that things go as expected when either
- mark is zero.
-
- NOTE: This is the only Protocol callback that is not called
- through EventLoop.call_soon() -- if it were, it would have no
- effect when it's most needed (when the app keeps writing
- without yielding until pause_writing() is called).
- """
-
- def resume_writing(self):
- """Called when the transport's buffer drains below the low-water mark.
-
- See pause_writing() for details.
- """
-
-
-class Protocol(BaseProtocol):
- """Interface for stream protocol.
-
- The user should implement this interface. They can inherit from
- this class but don't need to. The implementations here do
- nothing (they don't raise exceptions).
-
- When the user wants to requests a transport, they pass a protocol
- factory to a utility function (e.g., EventLoop.create_connection()).
-
- When the connection is made successfully, connection_made() is
- called with a suitable transport object. Then data_received()
- will be called 0 or more times with data (bytes) received from the
- transport; finally, connection_lost() will be called exactly once
- with either an exception object or None as an argument.
-
- State machine of calls:
-
- start -> CM [-> DR*] [-> ER?] -> CL -> end
-
- * CM: connection_made()
- * DR: data_received()
- * ER: eof_received()
- * CL: connection_lost()
- """
-
- def data_received(self, data):
- """Called when some data is received.
-
- The argument is a bytes object.
- """
-
- def eof_received(self):
- """Called when the other end calls write_eof() or equivalent.
-
- If this returns a false value (including None), the transport
- will close itself. If it returns a true value, closing the
- transport is up to the protocol.
- """
-
-
-class DatagramProtocol(BaseProtocol):
- """Interface for datagram protocol."""
-
- def datagram_received(self, data, addr):
- """Called when some datagram is received."""
-
- def error_received(self, exc):
- """Called when a send or receive operation raises an OSError.
-
- (Other than BlockingIOError or InterruptedError.)
- """
-
-
-class SubprocessProtocol(BaseProtocol):
- """Interface for protocol for subprocess calls."""
-
- def pipe_data_received(self, fd, data):
- """Called when the subprocess writes data into stdout/stderr pipe.
-
- fd is int file descriptor.
- data is bytes object.
- """
-
- def pipe_connection_lost(self, fd, exc):
- """Called when a file descriptor associated with the child process is
- closed.
-
- fd is the int file descriptor that was closed.
- """
-
- def process_exited(self):
- """Called when subprocess has exited."""
+++ /dev/null
-# Access WeakSet through the weakref module.
-# This code is separated-out because it is needed
-# by abc.py to load everything else at startup.
-
-from _weakref import ref
-
-__all__ = ['WeakSet']
-
-
-class _IterationGuard(object):
- # This context manager registers itself in the current iterators of the
- # weak container, such as to delay all removals until the context manager
- # exits.
- # This technique should be relatively thread-safe (since sets are).
-
- def __init__(self, weakcontainer):
- # Don't create cycles
- self.weakcontainer = ref(weakcontainer)
-
- def __enter__(self):
- w = self.weakcontainer()
- if w is not None:
- w._iterating.add(self)
- return self
-
- def __exit__(self, e, t, b):
- w = self.weakcontainer()
- if w is not None:
- s = w._iterating
- s.remove(self)
- if not s:
- w._commit_removals()
-
-
-class WeakSet(object):
- def __init__(self, data=None):
- self.data = set()
- def _remove(item, selfref=ref(self)):
- self = selfref()
- if self is not None:
- if self._iterating:
- self._pending_removals.append(item)
- else:
- self.data.discard(item)
- self._remove = _remove
- # A list of keys to be removed
- self._pending_removals = []
- self._iterating = set()
- if data is not None:
- self.update(data)
-
- def _commit_removals(self):
- l = self._pending_removals
- discard = self.data.discard
- while l:
- discard(l.pop())
-
- def __iter__(self):
- with _IterationGuard(self):
- for itemref in self.data:
- item = itemref()
- if item is not None:
- yield item
-
- def __len__(self):
- return len(self.data) - len(self._pending_removals)
-
- def __contains__(self, item):
- try:
- wr = ref(item)
- except TypeError:
- return False
- return wr in self.data
-
- def __reduce__(self):
- return (self.__class__, (list(self),),
- getattr(self, '__dict__', None))
-
- __hash__ = None
-
- def add(self, item):
- if self._pending_removals:
- self._commit_removals()
- self.data.add(ref(item, self._remove))
-
- def clear(self):
- if self._pending_removals:
- self._commit_removals()
- self.data.clear()
-
- def copy(self):
- return self.__class__(self)
-
- def pop(self):
- if self._pending_removals:
- self._commit_removals()
- while True:
- try:
- itemref = self.data.pop()
- except KeyError:
- raise KeyError('pop from empty WeakSet')
- item = itemref()
- if item is not None:
- return item
-
- def remove(self, item):
- if self._pending_removals:
- self._commit_removals()
- self.data.remove(ref(item))
-
- def discard(self, item):
- if self._pending_removals:
- self._commit_removals()
- self.data.discard(ref(item))
-
- def update(self, other):
- if self._pending_removals:
- self._commit_removals()
- for element in other:
- self.add(element)
-
- def __ior__(self, other):
- self.update(other)
- return self
-
- def difference(self, other):
- newset = self.copy()
- newset.difference_update(other)
- return newset
- __sub__ = difference
-
- def difference_update(self, other):
- self.__isub__(other)
- def __isub__(self, other):
- if self._pending_removals:
- self._commit_removals()
- if self is other:
- self.data.clear()
- else:
- self.data.difference_update(ref(item) for item in other)
- return self
-
- def intersection(self, other):
- return self.__class__(item for item in other if item in self)
- __and__ = intersection
-
- def intersection_update(self, other):
- self.__iand__(other)
- def __iand__(self, other):
- if self._pending_removals:
- self._commit_removals()
- self.data.intersection_update(ref(item) for item in other)
- return self
-
- def issubset(self, other):
- return self.data.issubset(ref(item) for item in other)
- __le__ = issubset
-
- def __lt__(self, other):
- return self.data < set(ref(item) for item in other)
-
- def issuperset(self, other):
- return self.data.issuperset(ref(item) for item in other)
- __ge__ = issuperset
-
- def __gt__(self, other):
- return self.data > set(ref(item) for item in other)
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return NotImplemented
- return self.data == set(ref(item) for item in other)
-
- def __ne__(self, other):
- opposite = self.__eq__(other)
- if opposite is NotImplemented:
- return NotImplemented
- return not opposite
-
- def symmetric_difference(self, other):
- newset = self.copy()
- newset.symmetric_difference_update(other)
- return newset
- __xor__ = symmetric_difference
-
- def symmetric_difference_update(self, other):
- self.__ixor__(other)
- def __ixor__(self, other):
- if self._pending_removals:
- self._commit_removals()
- if self is other:
- self.data.clear()
- else:
- self.data.symmetric_difference_update(ref(item, self._remove) for item in other)
- return self
-
- def union(self, other):
- return self.__class__(e for s in (self, other) for e in s)
- __or__ = union
-
- def isdisjoint(self, other):
- return len(self.intersection(other)) == 0
+++ /dev/null
-__all__ = ['BlockingIOError', 'BrokenPipeError', 'ChildProcessError',
- 'ConnectionRefusedError', 'ConnectionResetError',
- 'InterruptedError', 'ConnectionAbortedError', 'PermissionError',
- 'FileNotFoundError', 'ProcessLookupError',
- ]
-
-import errno
-import select
-import socket
-import sys
-try:
- import ssl
-except ImportError:
- ssl = None
-
-from .compat import PY33
-
-if PY33:
- import builtins
- BlockingIOError = builtins.BlockingIOError
- BrokenPipeError = builtins.BrokenPipeError
- ChildProcessError = builtins.ChildProcessError
- ConnectionRefusedError = builtins.ConnectionRefusedError
- ConnectionResetError = builtins.ConnectionResetError
- InterruptedError = builtins.InterruptedError
- ConnectionAbortedError = builtins.ConnectionAbortedError
- PermissionError = builtins.PermissionError
- FileNotFoundError = builtins.FileNotFoundError
- ProcessLookupError = builtins.ProcessLookupError
-
-else:
- # Python < 3.3
- class BlockingIOError(OSError):
- pass
-
- class BrokenPipeError(OSError):
- pass
-
- class ChildProcessError(OSError):
- pass
-
- class ConnectionRefusedError(OSError):
- pass
-
- class InterruptedError(OSError):
- pass
-
- class ConnectionResetError(OSError):
- pass
-
- class ConnectionAbortedError(OSError):
- pass
-
- class PermissionError(OSError):
- pass
-
- class FileNotFoundError(OSError):
- pass
-
- class ProcessLookupError(OSError):
- pass
-
-
-_MAP_ERRNO = {
- errno.EACCES: PermissionError,
- errno.EAGAIN: BlockingIOError,
- errno.EALREADY: BlockingIOError,
- errno.ECHILD: ChildProcessError,
- errno.ECONNABORTED: ConnectionAbortedError,
- errno.ECONNREFUSED: ConnectionRefusedError,
- errno.ECONNRESET: ConnectionResetError,
- errno.EINPROGRESS: BlockingIOError,
- errno.EINTR: InterruptedError,
- errno.ENOENT: FileNotFoundError,
- errno.EPERM: PermissionError,
- errno.EPIPE: BrokenPipeError,
- errno.ESHUTDOWN: BrokenPipeError,
- errno.EWOULDBLOCK: BlockingIOError,
- errno.ESRCH: ProcessLookupError,
-}
-
-if sys.platform == 'win32':
- from trollius import _overlapped
- _MAP_ERRNO.update({
- _overlapped.ERROR_CONNECTION_REFUSED: ConnectionRefusedError,
- _overlapped.ERROR_CONNECTION_ABORTED: ConnectionAbortedError,
- _overlapped.ERROR_NETNAME_DELETED: ConnectionResetError,
- })
-
-
-def get_error_class(key, default):
- return _MAP_ERRNO.get(key, default)
-
-
-if sys.version_info >= (3,):
- def reraise(tp, value, tb=None):
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
-else:
- exec("""def reraise(tp, value, tb=None):
- raise tp, value, tb
-""")
-
-
-def _wrap_error(exc, mapping, key):
- if key not in mapping:
- return
- new_err_cls = mapping[key]
- new_err = new_err_cls(*exc.args)
-
- # raise a new exception with the original traceback
- if hasattr(exc, '__traceback__'):
- traceback = exc.__traceback__
- else:
- traceback = sys.exc_info()[2]
- reraise(new_err_cls, new_err, traceback)
-
-
-if not PY33:
- def wrap_error(func, *args, **kw):
- """
- Wrap socket.error, IOError, OSError, select.error to raise new specialized
- exceptions of Python 3.3 like InterruptedError (PEP 3151).
- """
- try:
- return func(*args, **kw)
- except (socket.error, IOError, OSError) as exc:
- if ssl is not None and isinstance(exc, ssl.SSLError):
- raise
- if hasattr(exc, 'winerror'):
- _wrap_error(exc, _MAP_ERRNO, exc.winerror)
- # _MAP_ERRNO does not contain all Windows errors.
- # For some errors like "file not found", exc.errno should
- # be used (ex: ENOENT).
- _wrap_error(exc, _MAP_ERRNO, exc.errno)
- raise
- except select.error as exc:
- if exc.args:
- _wrap_error(exc, _MAP_ERRNO, exc.args[0])
- raise
-else:
- def wrap_error(func, *args, **kw):
- return func(*args, **kw)
+++ /dev/null
-
-__all__ = [
- 'CloseHandle', 'CreateNamedPipe', 'CreateFile', 'ConnectNamedPipe',
- 'NULL',
- 'GENERIC_READ', 'GENERIC_WRITE', 'OPEN_EXISTING', 'INFINITE',
- 'PIPE_ACCESS_INBOUND',
- 'PIPE_ACCESS_DUPLEX', 'PIPE_TYPE_MESSAGE', 'PIPE_READMODE_MESSAGE',
- 'PIPE_WAIT', 'PIPE_UNLIMITED_INSTANCES', 'NMPWAIT_WAIT_FOREVER',
- 'FILE_FLAG_OVERLAPPED', 'FILE_FLAG_FIRST_PIPE_INSTANCE',
- 'WaitForMultipleObjects', 'WaitForSingleObject',
- 'WAIT_OBJECT_0', 'ERROR_IO_PENDING',
- ]
-
-try:
- # FIXME: use _overlapped on Python 3.3? see windows_utils.pipe()
- from _winapi import (
- CloseHandle, CreateNamedPipe, CreateFile, ConnectNamedPipe,
- NULL,
- GENERIC_READ, GENERIC_WRITE, OPEN_EXISTING, INFINITE,
- PIPE_ACCESS_INBOUND,
- PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE, PIPE_READMODE_MESSAGE,
- PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, NMPWAIT_WAIT_FOREVER,
- FILE_FLAG_OVERLAPPED, FILE_FLAG_FIRST_PIPE_INSTANCE,
- WaitForMultipleObjects, WaitForSingleObject,
- WAIT_OBJECT_0, ERROR_IO_PENDING,
- )
-except ImportError:
- # Python < 3.3
- from _multiprocessing import win32
- import _subprocess
-
- from trollius import _overlapped
-
- CloseHandle = win32.CloseHandle
- CreateNamedPipe = win32.CreateNamedPipe
- CreateFile = win32.CreateFile
- NULL = win32.NULL
-
- GENERIC_READ = win32.GENERIC_READ
- GENERIC_WRITE = win32.GENERIC_WRITE
- OPEN_EXISTING = win32.OPEN_EXISTING
- INFINITE = win32.INFINITE
-
- PIPE_ACCESS_INBOUND = win32.PIPE_ACCESS_INBOUND
- PIPE_ACCESS_DUPLEX = win32.PIPE_ACCESS_DUPLEX
- PIPE_READMODE_MESSAGE = win32.PIPE_READMODE_MESSAGE
- PIPE_TYPE_MESSAGE = win32.PIPE_TYPE_MESSAGE
- PIPE_WAIT = win32.PIPE_WAIT
- PIPE_UNLIMITED_INSTANCES = win32.PIPE_UNLIMITED_INSTANCES
- NMPWAIT_WAIT_FOREVER = win32.NMPWAIT_WAIT_FOREVER
-
- FILE_FLAG_OVERLAPPED = 0x40000000
- FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000
-
- WAIT_OBJECT_0 = _subprocess.WAIT_OBJECT_0
- WaitForSingleObject = _subprocess.WaitForSingleObject
- ERROR_IO_PENDING = _overlapped.ERROR_IO_PENDING
-
- def ConnectNamedPipe(handle, overlapped):
- ov = _overlapped.Overlapped()
- ov.ConnectNamedPipe(handle)
- return ov
-
- def WaitForMultipleObjects(events, wait_all, timeout):
- if not wait_all:
- raise NotImplementedError()
-
- for ev in events:
- res = WaitForSingleObject(ev, timeout)
- if res != WAIT_OBJECT_0:
- err = win32.GetLastError()
- msg = _overlapped.FormatMessage(err)
- raise WindowsError(err, msg)
-
- return WAIT_OBJECT_0
+++ /dev/null
-"""
-Backport SSL functions and exceptions:
-- BACKPORT_SSL_ERRORS (bool)
-- SSLWantReadError, SSLWantWriteError, SSLEOFError
-- BACKPORT_SSL_CONTEXT (bool)
-- SSLContext
-- wrap_socket()
-- wrap_ssl_error()
-"""
-import errno
-import ssl
-import sys
-from trollius.py33_exceptions import _wrap_error
-
-__all__ = ["SSLContext", "BACKPORT_SSL_ERRORS", "BACKPORT_SSL_CONTEXT",
- "SSLWantReadError", "SSLWantWriteError", "SSLEOFError",
- ]
-
-try:
- SSLWantReadError = ssl.SSLWantReadError
- SSLWantWriteError = ssl.SSLWantWriteError
- SSLEOFError = ssl.SSLEOFError
- BACKPORT_SSL_ERRORS = False
-except AttributeError:
- # Python < 3.3
- BACKPORT_SSL_ERRORS = True
-
- class SSLWantReadError(ssl.SSLError):
- pass
-
- class SSLWantWriteError(ssl.SSLError):
- pass
-
- class SSLEOFError(ssl.SSLError):
- pass
-
-
-try:
- SSLContext = ssl.SSLContext
- BACKPORT_SSL_CONTEXT = False
- wrap_socket = ssl.wrap_socket
-except AttributeError:
- # Python < 3.2
- BACKPORT_SSL_CONTEXT = True
-
- if (sys.version_info < (2, 6, 6)):
- # SSLSocket constructor has bugs in Python older than 2.6.6:
- # http://bugs.python.org/issue5103
- # http://bugs.python.org/issue7943
- from socket import socket, error as socket_error, _delegate_methods
- import _ssl
-
- class BackportSSLSocket(ssl.SSLSocket):
- # Override SSLSocket.__init__()
- def __init__(self, sock, keyfile=None, certfile=None,
- server_side=False, cert_reqs=ssl.CERT_NONE,
- ssl_version=ssl.PROTOCOL_SSLv23, ca_certs=None,
- do_handshake_on_connect=True,
- suppress_ragged_eofs=True):
- socket.__init__(self, _sock=sock._sock)
- # The initializer for socket overrides the methods send(), recv(), etc.
- # in the instancce, which we don't need -- but we want to provide the
- # methods defined in SSLSocket.
- for attr in _delegate_methods:
- try:
- delattr(self, attr)
- except AttributeError:
- pass
-
- if certfile and not keyfile:
- keyfile = certfile
- # see if it's connected
- try:
- socket.getpeername(self)
- except socket_error as e:
- if e.errno != errno.ENOTCONN:
- raise
- # no, no connection yet
- self._connected = False
- self._sslobj = None
- else:
- # yes, create the SSL object
- self._connected = True
- self._sslobj = _ssl.sslwrap(self._sock, server_side,
- keyfile, certfile,
- cert_reqs, ssl_version, ca_certs)
- if do_handshake_on_connect:
- self.do_handshake()
- self.keyfile = keyfile
- self.certfile = certfile
- self.cert_reqs = cert_reqs
- self.ssl_version = ssl_version
- self.ca_certs = ca_certs
- self.do_handshake_on_connect = do_handshake_on_connect
- self.suppress_ragged_eofs = suppress_ragged_eofs
- self._makefile_refs = 0
-
- def wrap_socket(sock, server_hostname=None, **kwargs):
- # ignore server_hostname parameter, not supported
- kwargs.pop('server_hostname', None)
- return BackportSSLSocket(sock, **kwargs)
- else:
- _wrap_socket = ssl.wrap_socket
-
- def wrap_socket(sock, **kwargs):
- # ignore server_hostname parameter, not supported
- kwargs.pop('server_hostname', None)
- return _wrap_socket(sock, **kwargs)
-
-
- class SSLContext(object):
- def __init__(self, protocol=ssl.PROTOCOL_SSLv23):
- self.protocol = protocol
- self.certfile = None
- self.keyfile = None
-
- def load_cert_chain(self, certfile, keyfile):
- self.certfile = certfile
- self.keyfile = keyfile
-
- def wrap_socket(self, sock, **kwargs):
- return wrap_socket(sock,
- ssl_version=self.protocol,
- certfile=self.certfile,
- keyfile=self.keyfile,
- **kwargs)
-
- @property
- def verify_mode(self):
- return ssl.CERT_NONE
-
-
-if BACKPORT_SSL_ERRORS:
- _MAP_ERRORS = {
- ssl.SSL_ERROR_WANT_READ: SSLWantReadError,
- ssl.SSL_ERROR_WANT_WRITE: SSLWantWriteError,
- ssl.SSL_ERROR_EOF: SSLEOFError,
- }
-
- def wrap_ssl_error(func, *args, **kw):
- try:
- return func(*args, **kw)
- except ssl.SSLError as exc:
- if exc.args:
- _wrap_error(exc, _MAP_ERRORS, exc.args[0])
- raise
-else:
- def wrap_ssl_error(func, *args, **kw):
- return func(*args, **kw)
+++ /dev/null
-"""Queues"""
-
-__all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'QueueFull', 'QueueEmpty']
-
-import collections
-import heapq
-
-from . import compat
-from . import events
-from . import futures
-from . import locks
-from .coroutines import coroutine, From, Return
-
-
-class QueueEmpty(Exception):
- """Exception raised when Queue.get_nowait() is called on a Queue object
- which is empty.
- """
- pass
-
-
-class QueueFull(Exception):
- """Exception raised when the Queue.put_nowait() method is called on a Queue
- object which is full.
- """
- pass
-
-
-class Queue(object):
- """A queue, useful for coordinating producer and consumer coroutines.
-
- If maxsize is less than or equal to zero, the queue size is infinite. If it
- is an integer greater than 0, then "yield from put()" will block when the
- queue reaches maxsize, until an item is removed by get().
-
- Unlike the standard library Queue, you can reliably know this Queue's size
- with qsize(), since your single-threaded asyncio application won't be
- interrupted between calling qsize() and doing an operation on the Queue.
- """
-
- def __init__(self, maxsize=0, loop=None):
- if loop is None:
- self._loop = events.get_event_loop()
- else:
- self._loop = loop
- self._maxsize = maxsize
-
- # Futures.
- self._getters = collections.deque()
- # Futures
- self._putters = collections.deque()
- self._unfinished_tasks = 0
- self._finished = locks.Event(loop=self._loop)
- self._finished.set()
- self._init(maxsize)
-
- # These three are overridable in subclasses.
-
- def _init(self, maxsize):
- self._queue = collections.deque()
-
- def _get(self):
- return self._queue.popleft()
-
- def _put(self, item):
- self._queue.append(item)
-
- # End of the overridable methods.
-
- def __put_internal(self, item):
- self._put(item)
- self._unfinished_tasks += 1
- self._finished.clear()
-
- def __repr__(self):
- return '<{0} at {1:#x} {2}>'.format(
- type(self).__name__, id(self), self._format())
-
- def __str__(self):
- return '<{0} {1}>'.format(type(self).__name__, self._format())
-
- def _format(self):
- result = 'maxsize={0!r}'.format(self._maxsize)
- if getattr(self, '_queue', None):
- result += ' _queue={0!r}'.format(list(self._queue))
- if self._getters:
- result += ' _getters[{0}]'.format(len(self._getters))
- if self._putters:
- result += ' _putters[{0}]'.format(len(self._putters))
- if self._unfinished_tasks:
- result += ' tasks={0}'.format(self._unfinished_tasks)
- return result
-
- def _consume_done_getters(self):
- # Delete waiters at the head of the get() queue who've timed out.
- while self._getters and self._getters[0].done():
- self._getters.popleft()
-
- def _consume_done_putters(self):
- # Delete waiters at the head of the put() queue who've timed out.
- while self._putters and self._putters[0].done():
- self._putters.popleft()
-
- def qsize(self):
- """Number of items in the queue."""
- return len(self._queue)
-
- @property
- def maxsize(self):
- """Number of items allowed in the queue."""
- return self._maxsize
-
- def empty(self):
- """Return True if the queue is empty, False otherwise."""
- return not self._queue
-
- def full(self):
- """Return True if there are maxsize items in the queue.
-
- Note: if the Queue was initialized with maxsize=0 (the default),
- then full() is never True.
- """
- if self._maxsize <= 0:
- return False
- else:
- return self.qsize() >= self._maxsize
-
- @coroutine
- def put(self, item):
- """Put an item into the queue.
-
- Put an item into the queue. If the queue is full, wait until a free
- slot is available before adding item.
-
- This method is a coroutine.
- """
- self._consume_done_getters()
- if self._getters:
- assert not self._queue, (
- 'queue non-empty, why are getters waiting?')
-
- getter = self._getters.popleft()
- self.__put_internal(item)
-
- # getter cannot be cancelled, we just removed done getters
- getter.set_result(self._get())
-
- elif self._maxsize > 0 and self._maxsize <= self.qsize():
- waiter = futures.Future(loop=self._loop)
-
- self._putters.append(waiter)
- yield From(waiter)
- self._put(item)
-
- else:
- self.__put_internal(item)
-
- def put_nowait(self, item):
- """Put an item into the queue without blocking.
-
- If no free slot is immediately available, raise QueueFull.
- """
- self._consume_done_getters()
- if self._getters:
- assert not self._queue, (
- 'queue non-empty, why are getters waiting?')
-
- getter = self._getters.popleft()
- self.__put_internal(item)
-
- # getter cannot be cancelled, we just removed done getters
- getter.set_result(self._get())
-
- elif self._maxsize > 0 and self._maxsize <= self.qsize():
- raise QueueFull
- else:
- self.__put_internal(item)
-
- @coroutine
- def get(self):
- """Remove and return an item from the queue.
-
- If queue is empty, wait until an item is available.
-
- This method is a coroutine.
- """
- self._consume_done_putters()
- if self._putters:
- assert self.full(), 'queue not full, why are putters waiting?'
- putter = self._putters.popleft()
-
- # When a getter runs and frees up a slot so this putter can
- # run, we need to defer the put for a tick to ensure that
- # getters and putters alternate perfectly. See
- # ChannelTest.test_wait.
- self._loop.call_soon(putter._set_result_unless_cancelled, None)
-
- raise Return(self._get())
-
- elif self.qsize():
- raise Return(self._get())
- else:
- waiter = futures.Future(loop=self._loop)
- self._getters.append(waiter)
- try:
- value = (yield From(waiter))
- raise Return(value)
- except futures.CancelledError:
- # if we get CancelledError, it means someone cancelled this
- # get() coroutine. But there is a chance that the waiter
- # already is ready and contains an item that has just been
- # removed from the queue. In this case, we need to put the item
- # back into the front of the queue. This get() must either
- # succeed without fault or, if it gets cancelled, it must be as
- # if it never happened.
- if waiter.done():
- self._put_it_back(waiter.result())
- raise
-
- def _put_it_back(self, item):
- """
- This is called when we have a waiter to get() an item and this waiter
- gets cancelled. In this case, we put the item back: wake up another
- waiter or put it in the _queue.
- """
- self._consume_done_getters()
- if self._getters:
- assert not self._queue, (
- 'queue non-empty, why are getters waiting?')
-
- getter = self._getters.popleft()
- self.__put_internal(item)
-
- # getter cannot be cancelled, we just removed done getters
- getter.set_result(item)
- else:
- self._queue.appendleft(item)
-
- def get_nowait(self):
- """Remove and return an item from the queue.
-
- Return an item if one is immediately available, else raise QueueEmpty.
- """
- self._consume_done_putters()
- if self._putters:
- assert self.full(), 'queue not full, why are putters waiting?'
- putter = self._putters.popleft()
- # Wake putter on next tick.
-
- # getter cannot be cancelled, we just removed done putters
- putter.set_result(None)
-
- return self._get()
-
- elif self.qsize():
- return self._get()
- else:
- raise QueueEmpty
-
- def task_done(self):
- """Indicate that a formerly enqueued task is complete.
-
- Used by queue consumers. For each get() used to fetch a task,
- a subsequent call to task_done() tells the queue that the processing
- on the task is complete.
-
- If a join() is currently blocking, it will resume when all items have
- been processed (meaning that a task_done() call was received for every
- item that had been put() into the queue).
-
- Raises ValueError if called more times than there were items placed in
- the queue.
- """
- if self._unfinished_tasks <= 0:
- raise ValueError('task_done() called too many times')
- self._unfinished_tasks -= 1
- if self._unfinished_tasks == 0:
- self._finished.set()
-
- @coroutine
- def join(self):
- """Block until all items in the queue have been gotten and processed.
-
- The count of unfinished tasks goes up whenever an item is added to the
- queue. The count goes down whenever a consumer calls task_done() to
- indicate that the item was retrieved and all work on it is complete.
- When the count of unfinished tasks drops to zero, join() unblocks.
- """
- if self._unfinished_tasks > 0:
- yield From(self._finished.wait())
-
-
-class PriorityQueue(Queue):
- """A subclass of Queue; retrieves entries in priority order (lowest first).
-
- Entries are typically tuples of the form: (priority number, data).
- """
-
- def _init(self, maxsize):
- self._queue = []
-
- def _put(self, item, heappush=heapq.heappush):
- heappush(self._queue, item)
-
- def _get(self, heappop=heapq.heappop):
- return heappop(self._queue)
-
-
-class LifoQueue(Queue):
- """A subclass of Queue that retrieves most recently added entries first."""
-
- def _init(self, maxsize):
- self._queue = []
-
- def _put(self, item):
- self._queue.append(item)
-
- def _get(self):
- return self._queue.pop()
-
-
-if not compat.PY35:
- JoinableQueue = Queue
- """Deprecated alias for Queue."""
- __all__.append('JoinableQueue')
+++ /dev/null
-"""Event loop using a selector and related classes.
-
-A selector is a "notify-when-ready" multiplexer. For a subclass which
-also includes support for signal handling, see the unix_events sub-module.
-"""
-
-__all__ = ['BaseSelectorEventLoop']
-
-import collections
-import errno
-import functools
-import socket
-import sys
-import warnings
-try:
- import ssl
- from .py3_ssl import wrap_ssl_error, SSLWantReadError, SSLWantWriteError
-except ImportError: # pragma: no cover
- ssl = None
-
-from . import base_events
-from . import compat
-from . import constants
-from . import events
-from . import futures
-from . import selectors
-from . import sslproto
-from . import transports
-from .compat import flatten_bytes
-from .coroutines import coroutine, From
-from .log import logger
-from .py33_exceptions import (wrap_error,
- BlockingIOError, InterruptedError, ConnectionAbortedError, BrokenPipeError,
- ConnectionResetError)
-
-# On Mac OS 10.6 with Python 2.6.1 or OpenIndiana 148 with Python 2.6.4,
-# _SelectorSslTransport._read_ready() hangs if the socket has no data.
-# Example: test_events.test_create_server_ssl()
-_SSL_REQUIRES_SELECT = (sys.version_info < (2, 6, 6))
-if _SSL_REQUIRES_SELECT:
- import select
-
-
-def _get_socket_error(sock, address):
- err = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
- if err != 0:
- # Jump to the except clause below.
- raise OSError(err, 'Connect call failed %s' % (address,))
-
-
-def _test_selector_event(selector, fd, event):
- # Test if the selector is monitoring 'event' events
- # for the file descriptor 'fd'.
- try:
- key = selector.get_key(fd)
- except KeyError:
- return False
- else:
- return bool(key.events & event)
-
-
-class BaseSelectorEventLoop(base_events.BaseEventLoop):
- """Selector event loop.
-
- See events.EventLoop for API specification.
- """
-
- def __init__(self, selector=None):
- super(BaseSelectorEventLoop, self).__init__()
-
- if selector is None:
- selector = selectors.DefaultSelector()
- logger.debug('Using selector: %s', selector.__class__.__name__)
- self._selector = selector
- self._make_self_pipe()
-
- def _make_socket_transport(self, sock, protocol, waiter=None,
- extra=None, server=None):
- return _SelectorSocketTransport(self, sock, protocol, waiter,
- extra, server)
-
- def _make_ssl_transport(self, rawsock, protocol, sslcontext, waiter=None,
- server_side=False, server_hostname=None,
- extra=None, server=None):
- if not sslproto._is_sslproto_available():
- return self._make_legacy_ssl_transport(
- rawsock, protocol, sslcontext, waiter,
- server_side=server_side, server_hostname=server_hostname,
- extra=extra, server=server)
-
- ssl_protocol = sslproto.SSLProtocol(self, protocol, sslcontext, waiter,
- server_side, server_hostname)
- _SelectorSocketTransport(self, rawsock, ssl_protocol,
- extra=extra, server=server)
- return ssl_protocol._app_transport
-
- def _make_legacy_ssl_transport(self, rawsock, protocol, sslcontext,
- waiter,
- server_side=False, server_hostname=None,
- extra=None, server=None):
- # Use the legacy API: SSL_write, SSL_read, etc. The legacy API is used
- # on Python 3.4 and older, when ssl.MemoryBIO is not available.
- return _SelectorSslTransport(
- self, rawsock, protocol, sslcontext, waiter,
- server_side, server_hostname, extra, server)
-
- def _make_datagram_transport(self, sock, protocol,
- address=None, waiter=None, extra=None):
- return _SelectorDatagramTransport(self, sock, protocol,
- address, waiter, extra)
-
- def close(self):
- if self.is_running():
- raise RuntimeError("Cannot close a running event loop")
- if self.is_closed():
- return
- self._close_self_pipe()
- super(BaseSelectorEventLoop, self).close()
- if self._selector is not None:
- self._selector.close()
- self._selector = None
-
- def _socketpair(self):
- raise NotImplementedError
-
- def _close_self_pipe(self):
- self.remove_reader(self._ssock.fileno())
- self._ssock.close()
- self._ssock = None
- self._csock.close()
- self._csock = None
- self._internal_fds -= 1
-
- def _make_self_pipe(self):
- # A self-socket, really. :-)
- self._ssock, self._csock = self._socketpair()
- self._ssock.setblocking(False)
- self._csock.setblocking(False)
- self._internal_fds += 1
- self.add_reader(self._ssock.fileno(), self._read_from_self)
-
- def _process_self_data(self, data):
- pass
-
- def _read_from_self(self):
- while True:
- try:
- data = wrap_error(self._ssock.recv, 4096)
- if not data:
- break
- self._process_self_data(data)
- except InterruptedError:
- continue
- except BlockingIOError:
- break
-
- def _write_to_self(self):
- # This may be called from a different thread, possibly after
- # _close_self_pipe() has been called or even while it is
- # running. Guard for self._csock being None or closed. When
- # a socket is closed, send() raises OSError (with errno set to
- # EBADF, but let's not rely on the exact error code).
- csock = self._csock
- if csock is not None:
- try:
- wrap_error(csock.send, b'\0')
- except OSError:
- if self._debug:
- logger.debug("Fail to write a null byte into the "
- "self-pipe socket",
- exc_info=True)
-
- def _start_serving(self, protocol_factory, sock,
- sslcontext=None, server=None):
- self.add_reader(sock.fileno(), self._accept_connection,
- protocol_factory, sock, sslcontext, server)
-
- def _accept_connection(self, protocol_factory, sock,
- sslcontext=None, server=None):
- try:
- conn, addr = wrap_error(sock.accept)
- if self._debug:
- logger.debug("%r got a new connection from %r: %r",
- server, addr, conn)
- conn.setblocking(False)
- except (BlockingIOError, InterruptedError, ConnectionAbortedError):
- pass # False alarm.
- except socket.error as exc:
- # There's nowhere to send the error, so just log it.
- if exc.errno in (errno.EMFILE, errno.ENFILE,
- errno.ENOBUFS, errno.ENOMEM):
- # Some platforms (e.g. Linux keep reporting the FD as
- # ready, so we remove the read handler temporarily.
- # We'll try again in a while.
- self.call_exception_handler({
- 'message': 'socket.accept() out of system resource',
- 'exception': exc,
- 'socket': sock,
- })
- self.remove_reader(sock.fileno())
- self.call_later(constants.ACCEPT_RETRY_DELAY,
- self._start_serving,
- protocol_factory, sock, sslcontext, server)
- else:
- raise # The event loop will catch, log and ignore it.
- else:
- extra = {'peername': addr}
- accept = self._accept_connection2(protocol_factory, conn, extra,
- sslcontext, server)
- self.create_task(accept)
-
- @coroutine
- def _accept_connection2(self, protocol_factory, conn, extra,
- sslcontext=None, server=None):
- protocol = None
- transport = None
- try:
- protocol = protocol_factory()
- waiter = futures.Future(loop=self)
- if sslcontext:
- transport = self._make_ssl_transport(
- conn, protocol, sslcontext, waiter=waiter,
- server_side=True, extra=extra, server=server)
- else:
- transport = self._make_socket_transport(
- conn, protocol, waiter=waiter, extra=extra,
- server=server)
-
- try:
- yield From(waiter)
- except:
- transport.close()
- raise
-
- # It's now up to the protocol to handle the connection.
- except Exception as exc:
- if self._debug:
- context = {
- 'message': ('Error on transport creation '
- 'for incoming connection'),
- 'exception': exc,
- }
- if protocol is not None:
- context['protocol'] = protocol
- if transport is not None:
- context['transport'] = transport
- self.call_exception_handler(context)
-
- def add_reader(self, fd, callback, *args):
- """Add a reader callback."""
- self._check_closed()
- handle = events.Handle(callback, args, self)
- try:
- key = self._selector.get_key(fd)
- except KeyError:
- self._selector.register(fd, selectors.EVENT_READ,
- (handle, None))
- else:
- mask, (reader, writer) = key.events, key.data
- self._selector.modify(fd, mask | selectors.EVENT_READ,
- (handle, writer))
- if reader is not None:
- reader.cancel()
-
- def remove_reader(self, fd):
- """Remove a reader callback."""
- if self.is_closed():
- return False
- try:
- key = self._selector.get_key(fd)
- except KeyError:
- return False
- else:
- mask, (reader, writer) = key.events, key.data
- mask &= ~selectors.EVENT_READ
- if not mask:
- self._selector.unregister(fd)
- else:
- self._selector.modify(fd, mask, (None, writer))
-
- if reader is not None:
- reader.cancel()
- return True
- else:
- return False
-
- def add_writer(self, fd, callback, *args):
- """Add a writer callback.."""
- self._check_closed()
- handle = events.Handle(callback, args, self)
- try:
- key = self._selector.get_key(fd)
- except KeyError:
- self._selector.register(fd, selectors.EVENT_WRITE,
- (None, handle))
- else:
- mask, (reader, writer) = key.events, key.data
- self._selector.modify(fd, mask | selectors.EVENT_WRITE,
- (reader, handle))
- if writer is not None:
- writer.cancel()
-
- def remove_writer(self, fd):
- """Remove a writer callback."""
- if self.is_closed():
- return False
- try:
- key = self._selector.get_key(fd)
- except KeyError:
- return False
- else:
- mask, (reader, writer) = key.events, key.data
- # Remove both writer and connector.
- mask &= ~selectors.EVENT_WRITE
- if not mask:
- self._selector.unregister(fd)
- else:
- self._selector.modify(fd, mask, (reader, None))
-
- if writer is not None:
- writer.cancel()
- return True
- else:
- return False
-
- def sock_recv(self, sock, n):
- """Receive data from the socket.
-
- The return value is a bytes object representing the data received.
- The maximum amount of data to be received at once is specified by
- nbytes.
-
- This method is a coroutine.
- """
- if self._debug and sock.gettimeout() != 0:
- raise ValueError("the socket must be non-blocking")
- fut = futures.Future(loop=self)
- self._sock_recv(fut, False, sock, n)
- return fut
-
- def _sock_recv(self, fut, registered, sock, n):
- # _sock_recv() can add itself as an I/O callback if the operation can't
- # be done immediately. Don't use it directly, call sock_recv().
- fd = sock.fileno()
- if registered:
- # Remove the callback early. It should be rare that the
- # selector says the fd is ready but the call still returns
- # EAGAIN, and I am willing to take a hit in that case in
- # order to simplify the common case.
- self.remove_reader(fd)
- if fut.cancelled():
- return
- try:
- data = wrap_error(sock.recv, n)
- except (BlockingIOError, InterruptedError):
- self.add_reader(fd, self._sock_recv, fut, True, sock, n)
- except Exception as exc:
- fut.set_exception(exc)
- else:
- fut.set_result(data)
-
- def sock_sendall(self, sock, data):
- """Send data to the socket.
-
- The socket must be connected to a remote socket. This method continues
- to send data from data until either all data has been sent or an
- error occurs. None is returned on success. On error, an exception is
- raised, and there is no way to determine how much data, if any, was
- successfully processed by the receiving end of the connection.
-
- This method is a coroutine.
- """
- if self._debug and sock.gettimeout() != 0:
- raise ValueError("the socket must be non-blocking")
- fut = futures.Future(loop=self)
- if data:
- self._sock_sendall(fut, False, sock, data)
- else:
- fut.set_result(None)
- return fut
-
- def _sock_sendall(self, fut, registered, sock, data):
- fd = sock.fileno()
-
- if registered:
- self.remove_writer(fd)
- if fut.cancelled():
- return
-
- try:
- n = wrap_error(sock.send, data)
- except (BlockingIOError, InterruptedError):
- n = 0
- except Exception as exc:
- fut.set_exception(exc)
- return
-
- if n == len(data):
- fut.set_result(None)
- else:
- if n:
- data = data[n:]
- self.add_writer(fd, self._sock_sendall, fut, True, sock, data)
-
- def sock_connect(self, sock, address):
- """Connect to a remote socket at address.
-
- The address must be already resolved to avoid the trap of hanging the
- entire event loop when the address requires doing a DNS lookup. For
- example, it must be an IP address, not an hostname, for AF_INET and
- AF_INET6 address families. Use getaddrinfo() to resolve the hostname
- asynchronously.
-
- This method is a coroutine.
- """
- if self._debug and sock.gettimeout() != 0:
- raise ValueError("the socket must be non-blocking")
- fut = futures.Future(loop=self)
- try:
- if self._debug:
- base_events._check_resolved_address(sock, address)
- except ValueError as err:
- fut.set_exception(err)
- else:
- self._sock_connect(fut, sock, address)
- return fut
-
- def _sock_connect(self, fut, sock, address):
- fd = sock.fileno()
- try:
- wrap_error(sock.connect, address)
- except (BlockingIOError, InterruptedError):
- # Issue #23618: When the C function connect() fails with EINTR, the
- # connection runs in background. We have to wait until the socket
- # becomes writable to be notified when the connection succeed or
- # fails.
- fut.add_done_callback(functools.partial(self._sock_connect_done,
- fd))
- self.add_writer(fd, self._sock_connect_cb, fut, sock, address)
- except Exception as exc:
- fut.set_exception(exc)
- else:
- fut.set_result(None)
-
- def _sock_connect_done(self, fd, fut):
- self.remove_writer(fd)
-
- def _sock_connect_cb(self, fut, sock, address):
- if fut.cancelled():
- return
-
- try:
- wrap_error(_get_socket_error, sock, address)
- except (BlockingIOError, InterruptedError):
- # socket is still registered, the callback will be retried later
- pass
- except Exception as exc:
- fut.set_exception(exc)
- else:
- fut.set_result(None)
-
- def sock_accept(self, sock):
- """Accept a connection.
-
- The socket must be bound to an address and listening for connections.
- The return value is a pair (conn, address) where conn is a new socket
- object usable to send and receive data on the connection, and address
- is the address bound to the socket on the other end of the connection.
-
- This method is a coroutine.
- """
- if self._debug and sock.gettimeout() != 0:
- raise ValueError("the socket must be non-blocking")
- fut = futures.Future(loop=self)
- self._sock_accept(fut, False, sock)
- return fut
-
- def _sock_accept(self, fut, registered, sock):
- fd = sock.fileno()
- if registered:
- self.remove_reader(fd)
- if fut.cancelled():
- return
- try:
- conn, address = wrap_error(sock.accept)
- conn.setblocking(False)
- except (BlockingIOError, InterruptedError):
- self.add_reader(fd, self._sock_accept, fut, True, sock)
- except Exception as exc:
- fut.set_exception(exc)
- else:
- fut.set_result((conn, address))
-
- def _process_events(self, event_list):
- for key, mask in event_list:
- fileobj, (reader, writer) = key.fileobj, key.data
- if mask & selectors.EVENT_READ and reader is not None:
- if reader._cancelled:
- self.remove_reader(fileobj)
- else:
- self._add_callback(reader)
- if mask & selectors.EVENT_WRITE and writer is not None:
- if writer._cancelled:
- self.remove_writer(fileobj)
- else:
- self._add_callback(writer)
-
- def _stop_serving(self, sock):
- self.remove_reader(sock.fileno())
- sock.close()
-
-
-class _SelectorTransport(transports._FlowControlMixin,
- transports.Transport):
-
- max_size = 256 * 1024 # Buffer size passed to recv().
-
- _buffer_factory = bytearray # Constructs initial value for self._buffer.
-
- # Attribute used in the destructor: it must be set even if the constructor
- # is not called (see _SelectorSslTransport which may start by raising an
- # exception)
- _sock = None
-
- def __init__(self, loop, sock, protocol, extra=None, server=None):
- super(_SelectorTransport, self).__init__(extra, loop)
- self._extra['socket'] = sock
- self._extra['sockname'] = sock.getsockname()
- if 'peername' not in self._extra:
- try:
- self._extra['peername'] = sock.getpeername()
- except socket.error:
- self._extra['peername'] = None
- self._sock = sock
- self._sock_fd = sock.fileno()
- self._protocol = protocol
- self._protocol_connected = True
- self._server = server
- self._buffer = self._buffer_factory()
- self._conn_lost = 0 # Set when call to connection_lost scheduled.
- self._closing = False # Set when close() called.
- if self._server is not None:
- self._server._attach()
-
- def __repr__(self):
- info = [self.__class__.__name__]
- if self._sock is None:
- info.append('closed')
- elif self._closing:
- info.append('closing')
- info.append('fd=%s' % self._sock_fd)
- # test if the transport was closed
- if self._loop is not None and not self._loop.is_closed():
- polling = _test_selector_event(self._loop._selector,
- self._sock_fd, selectors.EVENT_READ)
- if polling:
- info.append('read=polling')
- else:
- info.append('read=idle')
-
- polling = _test_selector_event(self._loop._selector,
- self._sock_fd,
- selectors.EVENT_WRITE)
- if polling:
- state = 'polling'
- else:
- state = 'idle'
-
- bufsize = self.get_write_buffer_size()
- info.append('write=<%s, bufsize=%s>' % (state, bufsize))
- return '<%s>' % ' '.join(info)
-
- def abort(self):
- self._force_close(None)
-
- def close(self):
- if self._closing:
- return
- self._closing = True
- self._loop.remove_reader(self._sock_fd)
- if not self._buffer:
- self._conn_lost += 1
- self._loop.call_soon(self._call_connection_lost, None)
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._sock is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning)
- self._sock.close()
-
- def _fatal_error(self, exc, message='Fatal error on transport'):
- # Should be called from exception handler only.
- if isinstance(exc, (BrokenPipeError,
- ConnectionResetError, ConnectionAbortedError)):
- if self._loop.get_debug():
- logger.debug("%r: %s", self, message, exc_info=True)
- else:
- self._loop.call_exception_handler({
- 'message': message,
- 'exception': exc,
- 'transport': self,
- 'protocol': self._protocol,
- })
- self._force_close(exc)
-
- def _force_close(self, exc):
- if self._conn_lost:
- return
- if self._buffer:
- del self._buffer[:]
- self._loop.remove_writer(self._sock_fd)
- if not self._closing:
- self._closing = True
- self._loop.remove_reader(self._sock_fd)
- self._conn_lost += 1
- self._loop.call_soon(self._call_connection_lost, exc)
-
- def _call_connection_lost(self, exc):
- try:
- if self._protocol_connected:
- self._protocol.connection_lost(exc)
- finally:
- self._sock.close()
- self._sock = None
- self._protocol = None
- self._loop = None
- server = self._server
- if server is not None:
- server._detach()
- self._server = None
-
- def get_write_buffer_size(self):
- return len(self._buffer)
-
-
-class _SelectorSocketTransport(_SelectorTransport):
-
- def __init__(self, loop, sock, protocol, waiter=None,
- extra=None, server=None):
- super(_SelectorSocketTransport, self).__init__(loop, sock, protocol, extra, server)
- self._eof = False
- self._paused = False
-
- self._loop.call_soon(self._protocol.connection_made, self)
- # only start reading when connection_made() has been called
- self._loop.call_soon(self._loop.add_reader,
- self._sock_fd, self._read_ready)
- if waiter is not None:
- # only wake up the waiter when connection_made() has been called
- self._loop.call_soon(waiter._set_result_unless_cancelled, None)
-
- def pause_reading(self):
- if self._closing:
- raise RuntimeError('Cannot pause_reading() when closing')
- if self._paused:
- raise RuntimeError('Already paused')
- self._paused = True
- self._loop.remove_reader(self._sock_fd)
- if self._loop.get_debug():
- logger.debug("%r pauses reading", self)
-
- def resume_reading(self):
- if not self._paused:
- raise RuntimeError('Not paused')
- self._paused = False
- if self._closing:
- return
- self._loop.add_reader(self._sock_fd, self._read_ready)
- if self._loop.get_debug():
- logger.debug("%r resumes reading", self)
-
- def _read_ready(self):
- try:
- data = wrap_error(self._sock.recv, self.max_size)
- except (BlockingIOError, InterruptedError):
- pass
- except Exception as exc:
- self._fatal_error(exc, 'Fatal read error on socket transport')
- else:
- if data:
- self._protocol.data_received(data)
- else:
- if self._loop.get_debug():
- logger.debug("%r received EOF", self)
- keep_open = self._protocol.eof_received()
- if keep_open:
- # We're keeping the connection open so the
- # protocol can write more, but we still can't
- # receive more, so remove the reader callback.
- self._loop.remove_reader(self._sock_fd)
- else:
- self.close()
-
- def write(self, data):
- data = flatten_bytes(data)
- if self._eof:
- raise RuntimeError('Cannot call write() after write_eof()')
- if not data:
- return
-
- if self._conn_lost:
- if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
- logger.warning('socket.send() raised exception.')
- self._conn_lost += 1
- return
-
- if not self._buffer:
- # Optimization: try to send now.
- try:
- n = wrap_error(self._sock.send, data)
- except (BlockingIOError, InterruptedError):
- pass
- except Exception as exc:
- self._fatal_error(exc, 'Fatal write error on socket transport')
- return
- else:
- data = data[n:]
- if not data:
- return
- # Not all was written; register write handler.
- self._loop.add_writer(self._sock_fd, self._write_ready)
-
- # Add it to the buffer.
- self._buffer.extend(data)
- self._maybe_pause_protocol()
-
- def _write_ready(self):
- assert self._buffer, 'Data should not be empty'
-
- data = flatten_bytes(self._buffer)
- try:
- n = wrap_error(self._sock.send, data)
- except (BlockingIOError, InterruptedError):
- pass
- except Exception as exc:
- self._loop.remove_writer(self._sock_fd)
- del self._buffer[:]
- self._fatal_error(exc, 'Fatal write error on socket transport')
- else:
- if n:
- del self._buffer[:n]
- self._maybe_resume_protocol() # May append to buffer.
- if not self._buffer:
- self._loop.remove_writer(self._sock_fd)
- if self._closing:
- self._call_connection_lost(None)
- elif self._eof:
- self._sock.shutdown(socket.SHUT_WR)
-
- def write_eof(self):
- if self._eof:
- return
- self._eof = True
- if not self._buffer:
- self._sock.shutdown(socket.SHUT_WR)
-
- def can_write_eof(self):
- return True
-
-
-class _SelectorSslTransport(_SelectorTransport):
-
- _buffer_factory = bytearray
-
- def __init__(self, loop, rawsock, protocol, sslcontext, waiter=None,
- server_side=False, server_hostname=None,
- extra=None, server=None):
- if ssl is None:
- raise RuntimeError('stdlib ssl module not available')
-
- if not sslcontext:
- sslcontext = sslproto._create_transport_context(server_side, server_hostname)
-
- wrap_kwargs = {
- 'server_side': server_side,
- 'do_handshake_on_connect': False,
- }
- if server_hostname and not server_side:
- wrap_kwargs['server_hostname'] = server_hostname
- sslsock = sslcontext.wrap_socket(rawsock, **wrap_kwargs)
-
- super(_SelectorSslTransport, self).__init__(loop, sslsock, protocol, extra, server)
- # the protocol connection is only made after the SSL handshake
- self._protocol_connected = False
-
- self._server_hostname = server_hostname
- self._waiter = waiter
- self._sslcontext = sslcontext
- self._paused = False
-
- # SSL-specific extra info. (peercert is set later)
- self._extra.update(sslcontext=sslcontext)
-
- if self._loop.get_debug():
- logger.debug("%r starts SSL handshake", self)
- start_time = self._loop.time()
- else:
- start_time = None
- self._on_handshake(start_time)
-
- def _wakeup_waiter(self, exc=None):
- if self._waiter is None:
- return
- if not self._waiter.cancelled():
- if exc is not None:
- self._waiter.set_exception(exc)
- else:
- self._waiter.set_result(None)
- self._waiter = None
-
- def _on_handshake(self, start_time):
- try:
- wrap_ssl_error(self._sock.do_handshake)
- except SSLWantReadError:
- self._loop.add_reader(self._sock_fd,
- self._on_handshake, start_time)
- return
- except SSLWantWriteError:
- self._loop.add_writer(self._sock_fd,
- self._on_handshake, start_time)
- return
- except BaseException as exc:
- if self._loop.get_debug():
- logger.warning("%r: SSL handshake failed",
- self, exc_info=True)
- self._loop.remove_reader(self._sock_fd)
- self._loop.remove_writer(self._sock_fd)
- self._sock.close()
- self._wakeup_waiter(exc)
- if isinstance(exc, Exception):
- return
- else:
- raise
-
- self._loop.remove_reader(self._sock_fd)
- self._loop.remove_writer(self._sock_fd)
-
- peercert = self._sock.getpeercert()
- if not hasattr(self._sslcontext, 'check_hostname'):
- # Verify hostname if requested, Python 3.4+ uses check_hostname
- # and checks the hostname in do_handshake()
- if (self._server_hostname and
- self._sslcontext.verify_mode != ssl.CERT_NONE):
- try:
- ssl.match_hostname(peercert, self._server_hostname)
- except Exception as exc:
- if self._loop.get_debug():
- logger.warning("%r: SSL handshake failed "
- "on matching the hostname",
- self, exc_info=True)
- self._sock.close()
- self._wakeup_waiter(exc)
- return
-
- # Add extra info that becomes available after handshake.
- self._extra.update(peercert=peercert,
- cipher=self._sock.cipher(),
- )
- if hasattr(self._sock, 'compression'):
- self._extra['compression'] = self._sock.compression()
-
- self._read_wants_write = False
- self._write_wants_read = False
- self._loop.add_reader(self._sock_fd, self._read_ready)
- self._protocol_connected = True
- self._loop.call_soon(self._protocol.connection_made, self)
- # only wake up the waiter when connection_made() has been called
- self._loop.call_soon(self._wakeup_waiter)
-
- if self._loop.get_debug():
- dt = self._loop.time() - start_time
- logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
-
- def pause_reading(self):
- # XXX This is a bit icky, given the comment at the top of
- # _read_ready(). Is it possible to evoke a deadlock? I don't
- # know, although it doesn't look like it; write() will still
- # accept more data for the buffer and eventually the app will
- # call resume_reading() again, and things will flow again.
-
- if self._closing:
- raise RuntimeError('Cannot pause_reading() when closing')
- if self._paused:
- raise RuntimeError('Already paused')
- self._paused = True
- self._loop.remove_reader(self._sock_fd)
- if self._loop.get_debug():
- logger.debug("%r pauses reading", self)
-
- def resume_reading(self):
- if not self._paused:
- raise RuntimeError('Not paused')
- self._paused = False
- if self._closing:
- return
- self._loop.add_reader(self._sock_fd, self._read_ready)
- if self._loop.get_debug():
- logger.debug("%r resumes reading", self)
-
- def _sock_recv(self):
- return wrap_ssl_error(self._sock.recv, self.max_size)
-
- def _read_ready(self):
- if self._write_wants_read:
- self._write_wants_read = False
- self._write_ready()
-
- if self._buffer:
- self._loop.add_writer(self._sock_fd, self._write_ready)
-
- try:
- if _SSL_REQUIRES_SELECT:
- rfds = (self._sock.fileno(),)
- rfds = select.select(rfds, (), (), 0.0)[0]
- if not rfds:
- # False alarm.
- return
- data = wrap_error(self._sock_recv)
- except (BlockingIOError, InterruptedError, SSLWantReadError):
- pass
- except SSLWantWriteError:
- self._read_wants_write = True
- self._loop.remove_reader(self._sock_fd)
- self._loop.add_writer(self._sock_fd, self._write_ready)
- except Exception as exc:
- self._fatal_error(exc, 'Fatal read error on SSL transport')
- else:
- if data:
- self._protocol.data_received(data)
- else:
- try:
- if self._loop.get_debug():
- logger.debug("%r received EOF", self)
- keep_open = self._protocol.eof_received()
- if keep_open:
- logger.warning('returning true from eof_received() '
- 'has no effect when using ssl')
- finally:
- self.close()
-
- def _write_ready(self):
- if self._read_wants_write:
- self._read_wants_write = False
- self._read_ready()
-
- if not (self._paused or self._closing):
- self._loop.add_reader(self._sock_fd, self._read_ready)
-
- if self._buffer:
- data = flatten_bytes(self._buffer)
- try:
- n = wrap_error(self._sock.send, data)
- except (BlockingIOError, InterruptedError, SSLWantWriteError):
- n = 0
- except SSLWantReadError:
- n = 0
- self._loop.remove_writer(self._sock_fd)
- self._write_wants_read = True
- except Exception as exc:
- self._loop.remove_writer(self._sock_fd)
- del self._buffer[:]
- self._fatal_error(exc, 'Fatal write error on SSL transport')
- return
-
- if n:
- del self._buffer[:n]
-
- self._maybe_resume_protocol() # May append to buffer.
-
- if not self._buffer:
- self._loop.remove_writer(self._sock_fd)
- if self._closing:
- self._call_connection_lost(None)
-
- def write(self, data):
- data = flatten_bytes(data)
- if not data:
- return
-
- if self._conn_lost:
- if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
- logger.warning('socket.send() raised exception.')
- self._conn_lost += 1
- return
-
- if not self._buffer:
- self._loop.add_writer(self._sock_fd, self._write_ready)
-
- # Add it to the buffer.
- self._buffer.extend(data)
- self._maybe_pause_protocol()
-
- def can_write_eof(self):
- return False
-
-
-class _SelectorDatagramTransport(_SelectorTransport):
-
- _buffer_factory = collections.deque
-
- def __init__(self, loop, sock, protocol, address=None,
- waiter=None, extra=None):
- super(_SelectorDatagramTransport, self).__init__(loop, sock,
- protocol, extra)
- self._address = address
- self._loop.call_soon(self._protocol.connection_made, self)
- # only start reading when connection_made() has been called
- self._loop.call_soon(self._loop.add_reader,
- self._sock_fd, self._read_ready)
- if waiter is not None:
- # only wake up the waiter when connection_made() has been called
- self._loop.call_soon(waiter._set_result_unless_cancelled, None)
-
- def get_write_buffer_size(self):
- return sum(len(data) for data, _ in self._buffer)
-
- def _read_ready(self):
- try:
- data, addr = wrap_error(self._sock.recvfrom, self.max_size)
- except (BlockingIOError, InterruptedError):
- pass
- except OSError as exc:
- self._protocol.error_received(exc)
- except Exception as exc:
- self._fatal_error(exc, 'Fatal read error on datagram transport')
- else:
- self._protocol.datagram_received(data, addr)
-
- def sendto(self, data, addr=None):
- data = flatten_bytes(data)
- if not data:
- return
-
- if self._address and addr not in (None, self._address):
- raise ValueError('Invalid address: must be None or %s' %
- (self._address,))
-
- if self._conn_lost and self._address:
- if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
- logger.warning('socket.send() raised exception.')
- self._conn_lost += 1
- return
-
- if not self._buffer:
- # Attempt to send it right away first.
- try:
- if self._address:
- wrap_error(self._sock.send, data)
- else:
- wrap_error(self._sock.sendto, data, addr)
- return
- except (BlockingIOError, InterruptedError):
- self._loop.add_writer(self._sock_fd, self._sendto_ready)
- except OSError as exc:
- self._protocol.error_received(exc)
- return
- except Exception as exc:
- self._fatal_error(exc,
- 'Fatal write error on datagram transport')
- return
-
- # Ensure that what we buffer is immutable.
- self._buffer.append((bytes(data), addr))
- self._maybe_pause_protocol()
-
- def _sendto_ready(self):
- while self._buffer:
- data, addr = self._buffer.popleft()
- try:
- if self._address:
- wrap_error(self._sock.send, data)
- else:
- wrap_error(self._sock.sendto, data, addr)
- except (BlockingIOError, InterruptedError):
- self._buffer.appendleft((data, addr)) # Try again later.
- break
- except OSError as exc:
- self._protocol.error_received(exc)
- return
- except Exception as exc:
- self._fatal_error(exc,
- 'Fatal write error on datagram transport')
- return
-
- self._maybe_resume_protocol() # May append to buffer.
- if not self._buffer:
- self._loop.remove_writer(self._sock_fd)
- if self._closing:
- self._call_connection_lost(None)
+++ /dev/null
-"""Selectors module.
-
-This module allows high-level and efficient I/O multiplexing, built upon the
-`select` module primitives.
-"""
-
-
-from abc import ABCMeta, abstractmethod
-from collections import namedtuple, Mapping
-import math
-import select
-import sys
-
-from .py33_exceptions import wrap_error, InterruptedError
-from .compat import integer_types
-
-
-# generic events, that must be mapped to implementation-specific ones
-EVENT_READ = (1 << 0)
-EVENT_WRITE = (1 << 1)
-
-
-def _fileobj_to_fd(fileobj):
- """Return a file descriptor from a file object.
-
- Parameters:
- fileobj -- file object or file descriptor
-
- Returns:
- corresponding file descriptor
-
- Raises:
- ValueError if the object is invalid
- """
- if isinstance(fileobj, integer_types):
- fd = fileobj
- else:
- try:
- fd = int(fileobj.fileno())
- except (AttributeError, TypeError, ValueError):
- raise ValueError("Invalid file object: "
- "{0!r}".format(fileobj))
- if fd < 0:
- raise ValueError("Invalid file descriptor: {0}".format(fd))
- return fd
-
-
-SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
-"""Object used to associate a file object to its backing file descriptor,
-selected event mask and attached data."""
-
-
-class _SelectorMapping(Mapping):
- """Mapping of file objects to selector keys."""
-
- def __init__(self, selector):
- self._selector = selector
-
- def __len__(self):
- return len(self._selector._fd_to_key)
-
- def __getitem__(self, fileobj):
- try:
- fd = self._selector._fileobj_lookup(fileobj)
- return self._selector._fd_to_key[fd]
- except KeyError:
- raise KeyError("{0!r} is not registered".format(fileobj))
-
- def __iter__(self):
- return iter(self._selector._fd_to_key)
-
-
-class BaseSelector(object):
- """Selector abstract base class.
-
- A selector supports registering file objects to be monitored for specific
- I/O events.
-
- A file object is a file descriptor or any object with a `fileno()` method.
- An arbitrary object can be attached to the file object, which can be used
- for example to store context information, a callback, etc.
-
- A selector can use various implementations (select(), poll(), epoll()...)
- depending on the platform. The default `Selector` class uses the most
- efficient implementation on the current platform.
- """
- __metaclass__ = ABCMeta
-
- @abstractmethod
- def register(self, fileobj, events, data=None):
- """Register a file object.
-
- Parameters:
- fileobj -- file object or file descriptor
- events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
- data -- attached data
-
- Returns:
- SelectorKey instance
-
- Raises:
- ValueError if events is invalid
- KeyError if fileobj is already registered
- OSError if fileobj is closed or otherwise is unacceptable to
- the underlying system call (if a system call is made)
-
- Note:
- OSError may or may not be raised
- """
- raise NotImplementedError
-
- @abstractmethod
- def unregister(self, fileobj):
- """Unregister a file object.
-
- Parameters:
- fileobj -- file object or file descriptor
-
- Returns:
- SelectorKey instance
-
- Raises:
- KeyError if fileobj is not registered
-
- Note:
- If fileobj is registered but has since been closed this does
- *not* raise OSError (even if the wrapped syscall does)
- """
- raise NotImplementedError
-
- def modify(self, fileobj, events, data=None):
- """Change a registered file object monitored events or attached data.
-
- Parameters:
- fileobj -- file object or file descriptor
- events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
- data -- attached data
-
- Returns:
- SelectorKey instance
-
- Raises:
- Anything that unregister() or register() raises
- """
- self.unregister(fileobj)
- return self.register(fileobj, events, data)
-
- @abstractmethod
- def select(self, timeout=None):
- """Perform the actual selection, until some monitored file objects are
- ready or a timeout expires.
-
- Parameters:
- timeout -- if timeout > 0, this specifies the maximum wait time, in
- seconds
- if timeout <= 0, the select() call won't block, and will
- report the currently ready file objects
- if timeout is None, select() will block until a monitored
- file object becomes ready
-
- Returns:
- list of (key, events) for ready file objects
- `events` is a bitwise mask of EVENT_READ|EVENT_WRITE
- """
- raise NotImplementedError
-
- def close(self):
- """Close the selector.
-
- This must be called to make sure that any underlying resource is freed.
- """
- pass
-
- def get_key(self, fileobj):
- """Return the key associated to a registered file object.
-
- Returns:
- SelectorKey for this file object
- """
- mapping = self.get_map()
- if mapping is None:
- raise RuntimeError('Selector is closed')
- try:
- return mapping[fileobj]
- except KeyError:
- raise KeyError("{0!r} is not registered".format(fileobj))
-
- @abstractmethod
- def get_map(self):
- """Return a mapping of file objects to selector keys."""
- raise NotImplementedError
-
- def __enter__(self):
- return self
-
- def __exit__(self, *args):
- self.close()
-
-
-class _BaseSelectorImpl(BaseSelector):
- """Base selector implementation."""
-
- def __init__(self):
- # this maps file descriptors to keys
- self._fd_to_key = {}
- # read-only mapping returned by get_map()
- self._map = _SelectorMapping(self)
-
- def _fileobj_lookup(self, fileobj):
- """Return a file descriptor from a file object.
-
- This wraps _fileobj_to_fd() to do an exhaustive search in case
- the object is invalid but we still have it in our map. This
- is used by unregister() so we can unregister an object that
- was previously registered even if it is closed. It is also
- used by _SelectorMapping.
- """
- try:
- return _fileobj_to_fd(fileobj)
- except ValueError:
- # Do an exhaustive search.
- for key in self._fd_to_key.values():
- if key.fileobj is fileobj:
- return key.fd
- # Raise ValueError after all.
- raise
-
- def register(self, fileobj, events, data=None):
- if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
- raise ValueError("Invalid events: {0!r}".format(events))
-
- key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
-
- if key.fd in self._fd_to_key:
- raise KeyError("{0!r} (FD {1}) is already registered"
- .format(fileobj, key.fd))
-
- self._fd_to_key[key.fd] = key
- return key
-
- def unregister(self, fileobj):
- try:
- key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
- except KeyError:
- raise KeyError("{0!r} is not registered".format(fileobj))
- return key
-
- def modify(self, fileobj, events, data=None):
- # TODO: Subclasses can probably optimize this even further.
- try:
- key = self._fd_to_key[self._fileobj_lookup(fileobj)]
- except KeyError:
- raise KeyError("{0!r} is not registered".format(fileobj))
- if events != key.events:
- self.unregister(fileobj)
- key = self.register(fileobj, events, data)
- elif data != key.data:
- # Use a shortcut to update the data.
- key = key._replace(data=data)
- self._fd_to_key[key.fd] = key
- return key
-
- def close(self):
- self._fd_to_key.clear()
- self._map = None
-
- def get_map(self):
- return self._map
-
- def _key_from_fd(self, fd):
- """Return the key associated to a given file descriptor.
-
- Parameters:
- fd -- file descriptor
-
- Returns:
- corresponding key, or None if not found
- """
- try:
- return self._fd_to_key[fd]
- except KeyError:
- return None
-
-
-class SelectSelector(_BaseSelectorImpl):
- """Select-based selector."""
-
- def __init__(self):
- super(SelectSelector, self).__init__()
- self._readers = set()
- self._writers = set()
-
- def register(self, fileobj, events, data=None):
- key = super(SelectSelector, self).register(fileobj, events, data)
- if events & EVENT_READ:
- self._readers.add(key.fd)
- if events & EVENT_WRITE:
- self._writers.add(key.fd)
- return key
-
- def unregister(self, fileobj):
- key = super(SelectSelector, self).unregister(fileobj)
- self._readers.discard(key.fd)
- self._writers.discard(key.fd)
- return key
-
- if sys.platform == 'win32':
- def _select(self, r, w, _, timeout=None):
- r, w, x = select.select(r, w, w, timeout)
- return r, w + x, []
- else:
- def _select(self, r, w, x, timeout=None):
- return select.select(r, w, x, timeout)
-
- def select(self, timeout=None):
- timeout = None if timeout is None else max(timeout, 0)
- ready = []
- try:
- r, w, _ = wrap_error(self._select,
- self._readers, self._writers, [], timeout)
- except InterruptedError:
- return ready
- r = set(r)
- w = set(w)
- for fd in r | w:
- events = 0
- if fd in r:
- events |= EVENT_READ
- if fd in w:
- events |= EVENT_WRITE
-
- key = self._key_from_fd(fd)
- if key:
- ready.append((key, events & key.events))
- return ready
-
-
-if hasattr(select, 'poll'):
-
- class PollSelector(_BaseSelectorImpl):
- """Poll-based selector."""
-
- def __init__(self):
- super(PollSelector, self).__init__()
- self._poll = select.poll()
-
- def register(self, fileobj, events, data=None):
- key = super(PollSelector, self).register(fileobj, events, data)
- poll_events = 0
- if events & EVENT_READ:
- poll_events |= select.POLLIN
- if events & EVENT_WRITE:
- poll_events |= select.POLLOUT
- self._poll.register(key.fd, poll_events)
- return key
-
- def unregister(self, fileobj):
- key = super(PollSelector, self).unregister(fileobj)
- self._poll.unregister(key.fd)
- return key
-
- def select(self, timeout=None):
- if timeout is None:
- timeout = None
- elif timeout <= 0:
- timeout = 0
- else:
- # poll() has a resolution of 1 millisecond, round away from
- # zero to wait *at least* timeout seconds.
- timeout = int(math.ceil(timeout * 1e3))
- ready = []
- try:
- fd_event_list = wrap_error(self._poll.poll, timeout)
- except InterruptedError:
- return ready
- for fd, event in fd_event_list:
- events = 0
- if event & ~select.POLLIN:
- events |= EVENT_WRITE
- if event & ~select.POLLOUT:
- events |= EVENT_READ
-
- key = self._key_from_fd(fd)
- if key:
- ready.append((key, events & key.events))
- return ready
-
-
-if hasattr(select, 'epoll'):
-
- class EpollSelector(_BaseSelectorImpl):
- """Epoll-based selector."""
-
- def __init__(self):
- super(EpollSelector, self).__init__()
- self._epoll = select.epoll()
-
- def fileno(self):
- return self._epoll.fileno()
-
- def register(self, fileobj, events, data=None):
- key = super(EpollSelector, self).register(fileobj, events, data)
- epoll_events = 0
- if events & EVENT_READ:
- epoll_events |= select.EPOLLIN
- if events & EVENT_WRITE:
- epoll_events |= select.EPOLLOUT
- self._epoll.register(key.fd, epoll_events)
- return key
-
- def unregister(self, fileobj):
- key = super(EpollSelector, self).unregister(fileobj)
- try:
- self._epoll.unregister(key.fd)
- except IOError:
- # This can happen if the FD was closed since it
- # was registered.
- pass
- return key
-
- def select(self, timeout=None):
- if timeout is None:
- timeout = -1
- elif timeout <= 0:
- timeout = 0
- else:
- # epoll_wait() has a resolution of 1 millisecond, round away
- # from zero to wait *at least* timeout seconds.
- timeout = math.ceil(timeout * 1e3) * 1e-3
-
- # epoll_wait() expects `maxevents` to be greater than zero;
- # we want to make sure that `select()` can be called when no
- # FD is registered.
- max_ev = max(len(self._fd_to_key), 1)
-
- ready = []
- try:
- fd_event_list = wrap_error(self._epoll.poll, timeout, max_ev)
- except InterruptedError:
- return ready
- for fd, event in fd_event_list:
- events = 0
- if event & ~select.EPOLLIN:
- events |= EVENT_WRITE
- if event & ~select.EPOLLOUT:
- events |= EVENT_READ
-
- key = self._key_from_fd(fd)
- if key:
- ready.append((key, events & key.events))
- return ready
-
- def close(self):
- self._epoll.close()
- super(EpollSelector, self).close()
-
-
-if hasattr(select, 'devpoll'):
-
- class DevpollSelector(_BaseSelectorImpl):
- """Solaris /dev/poll selector."""
-
- def __init__(self):
- super(DevpollSelector, self).__init__()
- self._devpoll = select.devpoll()
-
- def fileno(self):
- return self._devpoll.fileno()
-
- def register(self, fileobj, events, data=None):
- key = super(DevpollSelector, self).register(fileobj, events, data)
- poll_events = 0
- if events & EVENT_READ:
- poll_events |= select.POLLIN
- if events & EVENT_WRITE:
- poll_events |= select.POLLOUT
- self._devpoll.register(key.fd, poll_events)
- return key
-
- def unregister(self, fileobj):
- key = super(DevpollSelector, self).unregister(fileobj)
- self._devpoll.unregister(key.fd)
- return key
-
- def select(self, timeout=None):
- if timeout is None:
- timeout = None
- elif timeout <= 0:
- timeout = 0
- else:
- # devpoll() has a resolution of 1 millisecond, round away from
- # zero to wait *at least* timeout seconds.
- timeout = math.ceil(timeout * 1e3)
- ready = []
- try:
- fd_event_list = self._devpoll.poll(timeout)
- except InterruptedError:
- return ready
- for fd, event in fd_event_list:
- events = 0
- if event & ~select.POLLIN:
- events |= EVENT_WRITE
- if event & ~select.POLLOUT:
- events |= EVENT_READ
-
- key = self._key_from_fd(fd)
- if key:
- ready.append((key, events & key.events))
- return ready
-
- def close(self):
- self._devpoll.close()
- super(DevpollSelector, self).close()
-
-
-if hasattr(select, 'kqueue'):
-
- class KqueueSelector(_BaseSelectorImpl):
- """Kqueue-based selector."""
-
- def __init__(self):
- super(KqueueSelector, self).__init__()
- self._kqueue = select.kqueue()
-
- def fileno(self):
- return self._kqueue.fileno()
-
- def register(self, fileobj, events, data=None):
- key = super(KqueueSelector, self).register(fileobj, events, data)
- if events & EVENT_READ:
- kev = select.kevent(key.fd, select.KQ_FILTER_READ,
- select.KQ_EV_ADD)
- self._kqueue.control([kev], 0, 0)
- if events & EVENT_WRITE:
- kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
- select.KQ_EV_ADD)
- self._kqueue.control([kev], 0, 0)
- return key
-
- def unregister(self, fileobj):
- key = super(KqueueSelector, self).unregister(fileobj)
- if key.events & EVENT_READ:
- kev = select.kevent(key.fd, select.KQ_FILTER_READ,
- select.KQ_EV_DELETE)
- try:
- self._kqueue.control([kev], 0, 0)
- except OSError:
- # This can happen if the FD was closed since it
- # was registered.
- pass
- if key.events & EVENT_WRITE:
- kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
- select.KQ_EV_DELETE)
- try:
- self._kqueue.control([kev], 0, 0)
- except OSError:
- # See comment above.
- pass
- return key
-
- def select(self, timeout=None):
- timeout = None if timeout is None else max(timeout, 0)
- max_ev = len(self._fd_to_key)
- ready = []
- try:
- kev_list = wrap_error(self._kqueue.control,
- None, max_ev, timeout)
- except InterruptedError:
- return ready
- for kev in kev_list:
- fd = kev.ident
- flag = kev.filter
- events = 0
- if flag == select.KQ_FILTER_READ:
- events |= EVENT_READ
- if flag == select.KQ_FILTER_WRITE:
- events |= EVENT_WRITE
-
- key = self._key_from_fd(fd)
- if key:
- ready.append((key, events & key.events))
- return ready
-
- def close(self):
- self._kqueue.close()
- super(KqueueSelector, self).close()
-
-
-# Choose the best implementation, roughly:
-# epoll|kqueue|devpoll > poll > select.
-# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
-if 'KqueueSelector' in globals():
- DefaultSelector = KqueueSelector
-elif 'EpollSelector' in globals():
- DefaultSelector = EpollSelector
-elif 'DevpollSelector' in globals():
- DefaultSelector = DevpollSelector
-elif 'PollSelector' in globals():
- DefaultSelector = PollSelector
-else:
- DefaultSelector = SelectSelector
+++ /dev/null
-import collections
-import warnings
-try:
- import ssl
- from .py3_ssl import BACKPORT_SSL_CONTEXT
-except ImportError: # pragma: no cover
- ssl = None
-
-from . import compat
-from . import protocols
-from . import transports
-from .log import logger
-from .py33_exceptions import BrokenPipeError, ConnectionResetError
-
-
-def _create_transport_context(server_side, server_hostname):
- if server_side:
- raise ValueError('Server side SSL needs a valid SSLContext')
-
- # Client side may pass ssl=True to use a default
- # context; in that case the sslcontext passed is None.
- # The default is secure for client connections.
- if hasattr(ssl, 'create_default_context'):
- # Python 3.4+: use up-to-date strong settings.
- sslcontext = ssl.create_default_context()
- if not server_hostname:
- sslcontext.check_hostname = False
- else:
- # Fallback for Python 3.3.
- sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- if not BACKPORT_SSL_CONTEXT:
- sslcontext.options |= ssl.OP_NO_SSLv2
- sslcontext.options |= ssl.OP_NO_SSLv3
- sslcontext.set_default_verify_paths()
- sslcontext.verify_mode = ssl.CERT_REQUIRED
- return sslcontext
-
-
-def _is_sslproto_available():
- return hasattr(ssl, "MemoryBIO")
-
-
-# States of an _SSLPipe.
-_UNWRAPPED = "UNWRAPPED"
-_DO_HANDSHAKE = "DO_HANDSHAKE"
-_WRAPPED = "WRAPPED"
-_SHUTDOWN = "SHUTDOWN"
-
-if ssl is not None:
- if hasattr(ssl, 'CertificateError'):
- _SSL_ERRORS = (ssl.SSLError, ssl.CertificateError)
- else:
- _SSL_ERRORS = ssl.SSLError
-
-
-class _SSLPipe(object):
- """An SSL "Pipe".
-
- An SSL pipe allows you to communicate with an SSL/TLS protocol instance
- through memory buffers. It can be used to implement a security layer for an
- existing connection where you don't have access to the connection's file
- descriptor, or for some reason you don't want to use it.
-
- An SSL pipe can be in "wrapped" and "unwrapped" mode. In unwrapped mode,
- data is passed through untransformed. In wrapped mode, application level
- data is encrypted to SSL record level data and vice versa. The SSL record
- level is the lowest level in the SSL protocol suite and is what travels
- as-is over the wire.
-
- An SslPipe initially is in "unwrapped" mode. To start SSL, call
- do_handshake(). To shutdown SSL again, call unwrap().
- """
-
- max_size = 256 * 1024 # Buffer size passed to read()
-
- def __init__(self, context, server_side, server_hostname=None):
- """
- The *context* argument specifies the ssl.SSLContext to use.
-
- The *server_side* argument indicates whether this is a server side or
- client side transport.
-
- The optional *server_hostname* argument can be used to specify the
- hostname you are connecting to. You may only specify this parameter if
- the _ssl module supports Server Name Indication (SNI).
- """
- self._context = context
- self._server_side = server_side
- self._server_hostname = server_hostname
- self._state = _UNWRAPPED
- self._incoming = ssl.MemoryBIO()
- self._outgoing = ssl.MemoryBIO()
- self._sslobj = None
- self._need_ssldata = False
- self._handshake_cb = None
- self._shutdown_cb = None
-
- @property
- def context(self):
- """The SSL context passed to the constructor."""
- return self._context
-
- @property
- def ssl_object(self):
- """The internal ssl.SSLObject instance.
-
- Return None if the pipe is not wrapped.
- """
- return self._sslobj
-
- @property
- def need_ssldata(self):
- """Whether more record level data is needed to complete a handshake
- that is currently in progress."""
- return self._need_ssldata
-
- @property
- def wrapped(self):
- """
- Whether a security layer is currently in effect.
-
- Return False during handshake.
- """
- return self._state == _WRAPPED
-
- def do_handshake(self, callback=None):
- """Start the SSL handshake.
-
- Return a list of ssldata. A ssldata element is a list of buffers
-
- The optional *callback* argument can be used to install a callback that
- will be called when the handshake is complete. The callback will be
- called with None if successful, else an exception instance.
- """
- if self._state != _UNWRAPPED:
- raise RuntimeError('handshake in progress or completed')
- self._sslobj = self._context.wrap_bio(
- self._incoming, self._outgoing,
- server_side=self._server_side,
- server_hostname=self._server_hostname)
- self._state = _DO_HANDSHAKE
- self._handshake_cb = callback
- ssldata, appdata = self.feed_ssldata(b'', only_handshake=True)
- assert len(appdata) == 0
- return ssldata
-
- def shutdown(self, callback=None):
- """Start the SSL shutdown sequence.
-
- Return a list of ssldata. A ssldata element is a list of buffers
-
- The optional *callback* argument can be used to install a callback that
- will be called when the shutdown is complete. The callback will be
- called without arguments.
- """
- if self._state == _UNWRAPPED:
- raise RuntimeError('no security layer present')
- if self._state == _SHUTDOWN:
- raise RuntimeError('shutdown in progress')
- assert self._state in (_WRAPPED, _DO_HANDSHAKE)
- self._state = _SHUTDOWN
- self._shutdown_cb = callback
- ssldata, appdata = self.feed_ssldata(b'')
- assert appdata == [] or appdata == [b'']
- return ssldata
-
- def feed_eof(self):
- """Send a potentially "ragged" EOF.
-
- This method will raise an SSL_ERROR_EOF exception if the EOF is
- unexpected.
- """
- self._incoming.write_eof()
- ssldata, appdata = self.feed_ssldata(b'')
- assert appdata == [] or appdata == [b'']
-
- def feed_ssldata(self, data, only_handshake=False):
- """Feed SSL record level data into the pipe.
-
- The data must be a bytes instance. It is OK to send an empty bytes
- instance. This can be used to get ssldata for a handshake initiated by
- this endpoint.
-
- Return a (ssldata, appdata) tuple. The ssldata element is a list of
- buffers containing SSL data that needs to be sent to the remote SSL.
-
- The appdata element is a list of buffers containing plaintext data that
- needs to be forwarded to the application. The appdata list may contain
- an empty buffer indicating an SSL "close_notify" alert. This alert must
- be acknowledged by calling shutdown().
- """
- if self._state == _UNWRAPPED:
- # If unwrapped, pass plaintext data straight through.
- if data:
- appdata = [data]
- else:
- appdata = []
- return ([], appdata)
-
- self._need_ssldata = False
- if data:
- self._incoming.write(data)
-
- ssldata = []
- appdata = []
- try:
- if self._state == _DO_HANDSHAKE:
- # Call do_handshake() until it doesn't raise anymore.
- self._sslobj.do_handshake()
- self._state = _WRAPPED
- if self._handshake_cb:
- self._handshake_cb(None)
- if only_handshake:
- return (ssldata, appdata)
- # Handshake done: execute the wrapped block
-
- if self._state == _WRAPPED:
- # Main state: read data from SSL until close_notify
- while True:
- chunk = self._sslobj.read(self.max_size)
- appdata.append(chunk)
- if not chunk: # close_notify
- break
-
- elif self._state == _SHUTDOWN:
- # Call shutdown() until it doesn't raise anymore.
- self._sslobj.unwrap()
- self._sslobj = None
- self._state = _UNWRAPPED
- if self._shutdown_cb:
- self._shutdown_cb()
-
- elif self._state == _UNWRAPPED:
- # Drain possible plaintext data after close_notify.
- appdata.append(self._incoming.read())
- except _SSL_ERRORS as exc:
- if getattr(exc, 'errno', None) not in (
- ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE,
- ssl.SSL_ERROR_SYSCALL):
- if self._state == _DO_HANDSHAKE and self._handshake_cb:
- self._handshake_cb(exc)
- raise
- self._need_ssldata = (exc.errno == ssl.SSL_ERROR_WANT_READ)
-
- # Check for record level data that needs to be sent back.
- # Happens for the initial handshake and renegotiations.
- if self._outgoing.pending:
- ssldata.append(self._outgoing.read())
- return (ssldata, appdata)
-
- def feed_appdata(self, data, offset=0):
- """Feed plaintext data into the pipe.
-
- Return an (ssldata, offset) tuple. The ssldata element is a list of
- buffers containing record level data that needs to be sent to the
- remote SSL instance. The offset is the number of plaintext bytes that
- were processed, which may be less than the length of data.
-
- NOTE: In case of short writes, this call MUST be retried with the SAME
- buffer passed into the *data* argument (i.e. the id() must be the
- same). This is an OpenSSL requirement. A further particularity is that
- a short write will always have offset == 0, because the _ssl module
- does not enable partial writes. And even though the offset is zero,
- there will still be encrypted data in ssldata.
- """
- assert 0 <= offset <= len(data)
- if self._state == _UNWRAPPED:
- # pass through data in unwrapped mode
- if offset < len(data):
- ssldata = [data[offset:]]
- else:
- ssldata = []
- return (ssldata, len(data))
-
- ssldata = []
- view = memoryview(data)
- while True:
- self._need_ssldata = False
- try:
- if offset < len(view):
- offset += self._sslobj.write(view[offset:])
- except ssl.SSLError as exc:
- # It is not allowed to call write() after unwrap() until the
- # close_notify is acknowledged. We return the condition to the
- # caller as a short write.
- if exc.reason == 'PROTOCOL_IS_SHUTDOWN':
- exc.errno = ssl.SSL_ERROR_WANT_READ
- if exc.errno not in (ssl.SSL_ERROR_WANT_READ,
- ssl.SSL_ERROR_WANT_WRITE,
- ssl.SSL_ERROR_SYSCALL):
- raise
- self._need_ssldata = (exc.errno == ssl.SSL_ERROR_WANT_READ)
-
- # See if there's any record level data back for us.
- if self._outgoing.pending:
- ssldata.append(self._outgoing.read())
- if offset == len(view) or self._need_ssldata:
- break
- return (ssldata, offset)
-
-
-class _SSLProtocolTransport(transports._FlowControlMixin,
- transports.Transport):
-
- def __init__(self, loop, ssl_protocol, app_protocol):
- self._loop = loop
- self._ssl_protocol = ssl_protocol
- self._app_protocol = app_protocol
- self._closed = False
-
- def get_extra_info(self, name, default=None):
- """Get optional transport information."""
- return self._ssl_protocol._get_extra_info(name, default)
-
- def close(self):
- """Close the transport.
-
- Buffered data will be flushed asynchronously. No more data
- will be received. After all buffered data is flushed, the
- protocol's connection_lost() method will (eventually) called
- with None as its argument.
- """
- self._closed = True
- self._ssl_protocol._start_shutdown()
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self._closed:
- warnings.warn("unclosed transport %r" % self, ResourceWarning)
- self.close()
-
- def pause_reading(self):
- """Pause the receiving end.
-
- No data will be passed to the protocol's data_received()
- method until resume_reading() is called.
- """
- self._ssl_protocol._transport.pause_reading()
-
- def resume_reading(self):
- """Resume the receiving end.
-
- Data received will once again be passed to the protocol's
- data_received() method.
- """
- self._ssl_protocol._transport.resume_reading()
-
- def set_write_buffer_limits(self, high=None, low=None):
- """Set the high- and low-water limits for write flow control.
-
- These two values control when to call the protocol's
- pause_writing() and resume_writing() methods. If specified,
- the low-water limit must be less than or equal to the
- high-water limit. Neither value can be negative.
-
- The defaults are implementation-specific. If only the
- high-water limit is given, the low-water limit defaults to a
- implementation-specific value less than or equal to the
- high-water limit. Setting high to zero forces low to zero as
- well, and causes pause_writing() to be called whenever the
- buffer becomes non-empty. Setting low to zero causes
- resume_writing() to be called only once the buffer is empty.
- Use of zero for either limit is generally sub-optimal as it
- reduces opportunities for doing I/O and computation
- concurrently.
- """
- self._ssl_protocol._transport.set_write_buffer_limits(high, low)
-
- def get_write_buffer_size(self):
- """Return the current size of the write buffer."""
- return self._ssl_protocol._transport.get_write_buffer_size()
-
- def write(self, data):
- """Write some data bytes to the transport.
-
- This does not block; it buffers the data and arranges for it
- to be sent out asynchronously.
- """
- if not isinstance(data, (bytes, bytearray, memoryview)):
- raise TypeError("data: expecting a bytes-like instance, got {!r}"
- .format(type(data).__name__))
- if not data:
- return
- self._ssl_protocol._write_appdata(data)
-
- def can_write_eof(self):
- """Return True if this transport supports write_eof(), False if not."""
- return False
-
- def abort(self):
- """Close the transport immediately.
-
- Buffered data will be lost. No more data will be received.
- The protocol's connection_lost() method will (eventually) be
- called with None as its argument.
- """
- self._ssl_protocol._abort()
-
-
-class SSLProtocol(protocols.Protocol):
- """SSL protocol.
-
- Implementation of SSL on top of a socket using incoming and outgoing
- buffers which are ssl.MemoryBIO objects.
- """
-
- def __init__(self, loop, app_protocol, sslcontext, waiter,
- server_side=False, server_hostname=None):
- if ssl is None:
- raise RuntimeError('stdlib ssl module not available')
-
- if not sslcontext:
- sslcontext = _create_transport_context(server_side, server_hostname)
-
- self._server_side = server_side
- if server_hostname and not server_side:
- self._server_hostname = server_hostname
- else:
- self._server_hostname = None
- self._sslcontext = sslcontext
- # SSL-specific extra info. More info are set when the handshake
- # completes.
- self._extra = dict(sslcontext=sslcontext)
-
- # App data write buffering
- self._write_backlog = collections.deque()
- self._write_buffer_size = 0
-
- self._waiter = waiter
- self._loop = loop
- self._app_protocol = app_protocol
- self._app_transport = _SSLProtocolTransport(self._loop,
- self, self._app_protocol)
- self._sslpipe = None
- self._session_established = False
- self._in_handshake = False
- self._in_shutdown = False
- self._transport = None
-
- def _wakeup_waiter(self, exc=None):
- if self._waiter is None:
- return
- if not self._waiter.cancelled():
- if exc is not None:
- self._waiter.set_exception(exc)
- else:
- self._waiter.set_result(None)
- self._waiter = None
-
- def connection_made(self, transport):
- """Called when the low-level connection is made.
-
- Start the SSL handshake.
- """
- self._transport = transport
- self._sslpipe = _SSLPipe(self._sslcontext,
- self._server_side,
- self._server_hostname)
- self._start_handshake()
-
- def connection_lost(self, exc):
- """Called when the low-level connection is lost or closed.
-
- The argument is an exception object or None (the latter
- meaning a regular EOF is received or the connection was
- aborted or closed).
- """
- if self._session_established:
- self._session_established = False
- self._loop.call_soon(self._app_protocol.connection_lost, exc)
- self._transport = None
- self._app_transport = None
-
- def pause_writing(self):
- """Called when the low-level transport's buffer goes over
- the high-water mark.
- """
- self._app_protocol.pause_writing()
-
- def resume_writing(self):
- """Called when the low-level transport's buffer drains below
- the low-water mark.
- """
- self._app_protocol.resume_writing()
-
- def data_received(self, data):
- """Called when some SSL data is received.
-
- The argument is a bytes object.
- """
- try:
- ssldata, appdata = self._sslpipe.feed_ssldata(data)
- except ssl.SSLError as e:
- if self._loop.get_debug():
- logger.warning('%r: SSL error %s (reason %s)',
- self, e.errno, e.reason)
- self._abort()
- return
-
- for chunk in ssldata:
- self._transport.write(chunk)
-
- for chunk in appdata:
- if chunk:
- self._app_protocol.data_received(chunk)
- else:
- self._start_shutdown()
- break
-
- def eof_received(self):
- """Called when the other end of the low-level stream
- is half-closed.
-
- If this returns a false value (including None), the transport
- will close itself. If it returns a true value, closing the
- transport is up to the protocol.
- """
- try:
- if self._loop.get_debug():
- logger.debug("%r received EOF", self)
-
- self._wakeup_waiter(ConnectionResetError)
-
- if not self._in_handshake:
- keep_open = self._app_protocol.eof_received()
- if keep_open:
- logger.warning('returning true from eof_received() '
- 'has no effect when using ssl')
- finally:
- self._transport.close()
-
- def _get_extra_info(self, name, default=None):
- if name in self._extra:
- return self._extra[name]
- else:
- return self._transport.get_extra_info(name, default)
-
- def _start_shutdown(self):
- if self._in_shutdown:
- return
- self._in_shutdown = True
- self._write_appdata(b'')
-
- def _write_appdata(self, data):
- self._write_backlog.append((data, 0))
- self._write_buffer_size += len(data)
- self._process_write_backlog()
-
- def _start_handshake(self):
- if self._loop.get_debug():
- logger.debug("%r starts SSL handshake", self)
- self._handshake_start_time = self._loop.time()
- else:
- self._handshake_start_time = None
- self._in_handshake = True
- # (b'', 1) is a special value in _process_write_backlog() to do
- # the SSL handshake
- self._write_backlog.append((b'', 1))
- self._loop.call_soon(self._process_write_backlog)
-
- def _on_handshake_complete(self, handshake_exc):
- self._in_handshake = False
-
- sslobj = self._sslpipe.ssl_object
- try:
- if handshake_exc is not None:
- raise handshake_exc
-
- peercert = sslobj.getpeercert()
- if not hasattr(self._sslcontext, 'check_hostname'):
- # Verify hostname if requested, Python 3.4+ uses check_hostname
- # and checks the hostname in do_handshake()
- if (self._server_hostname
- and self._sslcontext.verify_mode != ssl.CERT_NONE):
- ssl.match_hostname(peercert, self._server_hostname)
- except BaseException as exc:
- if self._loop.get_debug():
- if (hasattr(ssl, 'CertificateError')
- and isinstance(exc, ssl.CertificateError)):
- logger.warning("%r: SSL handshake failed "
- "on verifying the certificate",
- self, exc_info=True)
- else:
- logger.warning("%r: SSL handshake failed",
- self, exc_info=True)
- self._transport.close()
- if isinstance(exc, Exception):
- self._wakeup_waiter(exc)
- return
- else:
- raise
-
- if self._loop.get_debug():
- dt = self._loop.time() - self._handshake_start_time
- logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
-
- # Add extra info that becomes available after handshake.
- self._extra.update(peercert=peercert,
- cipher=sslobj.cipher(),
- compression=sslobj.compression(),
- )
- self._app_protocol.connection_made(self._app_transport)
- self._wakeup_waiter()
- self._session_established = True
- # In case transport.write() was already called. Don't call
- # immediatly _process_write_backlog(), but schedule it:
- # _on_handshake_complete() can be called indirectly from
- # _process_write_backlog(), and _process_write_backlog() is not
- # reentrant.
- self._loop.call_soon(self._process_write_backlog)
-
- def _process_write_backlog(self):
- # Try to make progress on the write backlog.
- if self._transport is None:
- return
-
- try:
- for i in range(len(self._write_backlog)):
- data, offset = self._write_backlog[0]
- if data:
- ssldata, offset = self._sslpipe.feed_appdata(data, offset)
- elif offset:
- ssldata = self._sslpipe.do_handshake(
- self._on_handshake_complete)
- offset = 1
- else:
- ssldata = self._sslpipe.shutdown(self._finalize)
- offset = 1
-
- for chunk in ssldata:
- self._transport.write(chunk)
-
- if offset < len(data):
- self._write_backlog[0] = (data, offset)
- # A short write means that a write is blocked on a read
- # We need to enable reading if it is paused!
- assert self._sslpipe.need_ssldata
- if self._transport._paused:
- self._transport.resume_reading()
- break
-
- # An entire chunk from the backlog was processed. We can
- # delete it and reduce the outstanding buffer size.
- del self._write_backlog[0]
- self._write_buffer_size -= len(data)
- except BaseException as exc:
- if self._in_handshake:
- # BaseExceptions will be re-raised in _on_handshake_complete.
- self._on_handshake_complete(exc)
- else:
- self._fatal_error(exc, 'Fatal error on SSL transport')
- if not isinstance(exc, Exception):
- # BaseException
- raise
-
- def _fatal_error(self, exc, message='Fatal error on transport'):
- # Should be called from exception handler only.
- if isinstance(exc, (BrokenPipeError, ConnectionResetError)):
- if self._loop.get_debug():
- logger.debug("%r: %s", self, message, exc_info=True)
- else:
- self._loop.call_exception_handler({
- 'message': message,
- 'exception': exc,
- 'transport': self._transport,
- 'protocol': self,
- })
- if self._transport:
- self._transport._force_close(exc)
-
- def _finalize(self):
- if self._transport is not None:
- self._transport.close()
-
- def _abort(self):
- if self._transport is not None:
- try:
- self._transport.abort()
- finally:
- self._finalize()
+++ /dev/null
-"""Stream-related things."""
-
-__all__ = ['StreamReader', 'StreamWriter', 'StreamReaderProtocol',
- 'open_connection', 'start_server',
- 'IncompleteReadError',
- ]
-
-import socket
-
-if hasattr(socket, 'AF_UNIX'):
- __all__.extend(['open_unix_connection', 'start_unix_server'])
-
-from . import coroutines
-from . import compat
-from . import events
-from . import futures
-from . import protocols
-from .coroutines import coroutine, From, Return
-from .py33_exceptions import ConnectionResetError
-from .log import logger
-
-
-_DEFAULT_LIMIT = 2**16
-
-
-class IncompleteReadError(EOFError):
- """
- Incomplete read error. Attributes:
-
- - partial: read bytes string before the end of stream was reached
- - expected: total number of expected bytes
- """
- def __init__(self, partial, expected):
- EOFError.__init__(self, "%s bytes read on a total of %s expected bytes"
- % (len(partial), expected))
- self.partial = partial
- self.expected = expected
-
-
-@coroutine
-def open_connection(host=None, port=None,
- loop=None, limit=_DEFAULT_LIMIT, **kwds):
- """A wrapper for create_connection() returning a (reader, writer) pair.
-
- The reader returned is a StreamReader instance; the writer is a
- StreamWriter instance.
-
- The arguments are all the usual arguments to create_connection()
- except protocol_factory; most common are positional host and port,
- with various optional keyword arguments following.
-
- Additional optional keyword arguments are loop (to set the event loop
- instance to use) and limit (to set the buffer limit passed to the
- StreamReader).
-
- (If you want to customize the StreamReader and/or
- StreamReaderProtocol classes, just copy the code -- there's
- really nothing special here except some convenience.)
- """
- if loop is None:
- loop = events.get_event_loop()
- reader = StreamReader(limit=limit, loop=loop)
- protocol = StreamReaderProtocol(reader, loop=loop)
- transport, _ = yield From(loop.create_connection(
- lambda: protocol, host, port, **kwds))
- writer = StreamWriter(transport, protocol, reader, loop)
- raise Return(reader, writer)
-
-
-@coroutine
-def start_server(client_connected_cb, host=None, port=None,
- loop=None, limit=_DEFAULT_LIMIT, **kwds):
- """Start a socket server, call back for each client connected.
-
- The first parameter, `client_connected_cb`, takes two parameters:
- client_reader, client_writer. client_reader is a StreamReader
- object, while client_writer is a StreamWriter object. This
- parameter can either be a plain callback function or a coroutine;
- if it is a coroutine, it will be automatically converted into a
- Task.
-
- The rest of the arguments are all the usual arguments to
- loop.create_server() except protocol_factory; most common are
- positional host and port, with various optional keyword arguments
- following. The return value is the same as loop.create_server().
-
- Additional optional keyword arguments are loop (to set the event loop
- instance to use) and limit (to set the buffer limit passed to the
- StreamReader).
-
- The return value is the same as loop.create_server(), i.e. a
- Server object which can be used to stop the service.
- """
- if loop is None:
- loop = events.get_event_loop()
-
- def factory():
- reader = StreamReader(limit=limit, loop=loop)
- protocol = StreamReaderProtocol(reader, client_connected_cb,
- loop=loop)
- return protocol
-
- server = yield From(loop.create_server(factory, host, port, **kwds))
- raise Return(server)
-
-
-if hasattr(socket, 'AF_UNIX'):
- # UNIX Domain Sockets are supported on this platform
-
- @coroutine
- def open_unix_connection(path=None,
- loop=None, limit=_DEFAULT_LIMIT, **kwds):
- """Similar to `open_connection` but works with UNIX Domain Sockets."""
- if loop is None:
- loop = events.get_event_loop()
- reader = StreamReader(limit=limit, loop=loop)
- protocol = StreamReaderProtocol(reader, loop=loop)
- transport, _ = yield From(loop.create_unix_connection(
- lambda: protocol, path, **kwds))
- writer = StreamWriter(transport, protocol, reader, loop)
- raise Return(reader, writer)
-
-
- @coroutine
- def start_unix_server(client_connected_cb, path=None,
- loop=None, limit=_DEFAULT_LIMIT, **kwds):
- """Similar to `start_server` but works with UNIX Domain Sockets."""
- if loop is None:
- loop = events.get_event_loop()
-
- def factory():
- reader = StreamReader(limit=limit, loop=loop)
- protocol = StreamReaderProtocol(reader, client_connected_cb,
- loop=loop)
- return protocol
-
- server = (yield From(loop.create_unix_server(factory, path, **kwds)))
- raise Return(server)
-
-
-class FlowControlMixin(protocols.Protocol):
- """Reusable flow control logic for StreamWriter.drain().
-
- This implements the protocol methods pause_writing(),
- resume_reading() and connection_lost(). If the subclass overrides
- these it must call the super methods.
-
- StreamWriter.drain() must wait for _drain_helper() coroutine.
- """
-
- def __init__(self, loop=None):
- if loop is None:
- self._loop = events.get_event_loop()
- else:
- self._loop = loop
- self._paused = False
- self._drain_waiter = None
- self._connection_lost = False
-
- def pause_writing(self):
- assert not self._paused
- self._paused = True
- if self._loop.get_debug():
- logger.debug("%r pauses writing", self)
-
- def resume_writing(self):
- assert self._paused
- self._paused = False
- if self._loop.get_debug():
- logger.debug("%r resumes writing", self)
-
- waiter = self._drain_waiter
- if waiter is not None:
- self._drain_waiter = None
- if not waiter.done():
- waiter.set_result(None)
-
- def connection_lost(self, exc):
- self._connection_lost = True
- # Wake up the writer if currently paused.
- if not self._paused:
- return
- waiter = self._drain_waiter
- if waiter is None:
- return
- self._drain_waiter = None
- if waiter.done():
- return
- if exc is None:
- waiter.set_result(None)
- else:
- waiter.set_exception(exc)
-
- @coroutine
- def _drain_helper(self):
- if self._connection_lost:
- raise ConnectionResetError('Connection lost')
- if not self._paused:
- return
- waiter = self._drain_waiter
- assert waiter is None or waiter.cancelled()
- waiter = futures.Future(loop=self._loop)
- self._drain_waiter = waiter
- yield From(waiter)
-
-
-class StreamReaderProtocol(FlowControlMixin, protocols.Protocol):
- """Helper class to adapt between Protocol and StreamReader.
-
- (This is a helper class instead of making StreamReader itself a
- Protocol subclass, because the StreamReader has other potential
- uses, and to prevent the user of the StreamReader to accidentally
- call inappropriate methods of the protocol.)
- """
-
- def __init__(self, stream_reader, client_connected_cb=None, loop=None):
- super(StreamReaderProtocol, self).__init__(loop=loop)
- self._stream_reader = stream_reader
- self._stream_writer = None
- self._client_connected_cb = client_connected_cb
-
- def connection_made(self, transport):
- self._stream_reader.set_transport(transport)
- if self._client_connected_cb is not None:
- self._stream_writer = StreamWriter(transport, self,
- self._stream_reader,
- self._loop)
- res = self._client_connected_cb(self._stream_reader,
- self._stream_writer)
- if coroutines.iscoroutine(res):
- self._loop.create_task(res)
-
- def connection_lost(self, exc):
- if exc is None:
- self._stream_reader.feed_eof()
- else:
- self._stream_reader.set_exception(exc)
- super(StreamReaderProtocol, self).connection_lost(exc)
-
- def data_received(self, data):
- self._stream_reader.feed_data(data)
-
- def eof_received(self):
- self._stream_reader.feed_eof()
- return True
-
-
-class StreamWriter(object):
- """Wraps a Transport.
-
- This exposes write(), writelines(), [can_]write_eof(),
- get_extra_info() and close(). It adds drain() which returns an
- optional Future on which you can wait for flow control. It also
- adds a transport property which references the Transport
- directly.
- """
-
- def __init__(self, transport, protocol, reader, loop):
- self._transport = transport
- self._protocol = protocol
- # drain() expects that the reader has a exception() method
- assert reader is None or isinstance(reader, StreamReader)
- self._reader = reader
- self._loop = loop
-
- def __repr__(self):
- info = [self.__class__.__name__, 'transport=%r' % self._transport]
- if self._reader is not None:
- info.append('reader=%r' % self._reader)
- return '<%s>' % ' '.join(info)
-
- @property
- def transport(self):
- return self._transport
-
- def write(self, data):
- self._transport.write(data)
-
- def writelines(self, data):
- self._transport.writelines(data)
-
- def write_eof(self):
- return self._transport.write_eof()
-
- def can_write_eof(self):
- return self._transport.can_write_eof()
-
- def close(self):
- return self._transport.close()
-
- def get_extra_info(self, name, default=None):
- return self._transport.get_extra_info(name, default)
-
- @coroutine
- def drain(self):
- """Flush the write buffer.
-
- The intended use is to write
-
- w.write(data)
- yield From(w.drain())
- """
- if self._reader is not None:
- exc = self._reader.exception()
- if exc is not None:
- raise exc
- yield From(self._protocol._drain_helper())
-
-
-class StreamReader(object):
-
- def __init__(self, limit=_DEFAULT_LIMIT, loop=None):
- # The line length limit is a security feature;
- # it also doubles as half the buffer limit.
- self._limit = limit
- if loop is None:
- self._loop = events.get_event_loop()
- else:
- self._loop = loop
- self._buffer = bytearray()
- self._eof = False # Whether we're done.
- self._waiter = None # A future used by _wait_for_data()
- self._exception = None
- self._transport = None
- self._paused = False
-
- def __repr__(self):
- info = ['StreamReader']
- if self._buffer:
- info.append('%d bytes' % len(info))
- if self._eof:
- info.append('eof')
- if self._limit != _DEFAULT_LIMIT:
- info.append('l=%d' % self._limit)
- if self._waiter:
- info.append('w=%r' % self._waiter)
- if self._exception:
- info.append('e=%r' % self._exception)
- if self._transport:
- info.append('t=%r' % self._transport)
- if self._paused:
- info.append('paused')
- return '<%s>' % ' '.join(info)
-
- def exception(self):
- return self._exception
-
- def set_exception(self, exc):
- self._exception = exc
-
- waiter = self._waiter
- if waiter is not None:
- self._waiter = None
- if not waiter.cancelled():
- waiter.set_exception(exc)
-
- def _wakeup_waiter(self):
- """Wakeup read() or readline() function waiting for data or EOF."""
- waiter = self._waiter
- if waiter is not None:
- self._waiter = None
- if not waiter.cancelled():
- waiter.set_result(None)
-
- def set_transport(self, transport):
- assert self._transport is None, 'Transport already set'
- self._transport = transport
-
- def _maybe_resume_transport(self):
- if self._paused and len(self._buffer) <= self._limit:
- self._paused = False
- self._transport.resume_reading()
-
- def feed_eof(self):
- self._eof = True
- self._wakeup_waiter()
-
- def at_eof(self):
- """Return True if the buffer is empty and 'feed_eof' was called."""
- return self._eof and not self._buffer
-
- def feed_data(self, data):
- assert not self._eof, 'feed_data after feed_eof'
-
- if not data:
- return
-
- self._buffer.extend(data)
- self._wakeup_waiter()
-
- if (self._transport is not None and
- not self._paused and
- len(self._buffer) > 2*self._limit):
- try:
- self._transport.pause_reading()
- except NotImplementedError:
- # The transport can't be paused.
- # We'll just have to buffer all data.
- # Forget the transport so we don't keep trying.
- self._transport = None
- else:
- self._paused = True
-
- @coroutine
- def _wait_for_data(self, func_name):
- """Wait until feed_data() or feed_eof() is called."""
- # StreamReader uses a future to link the protocol feed_data() method
- # to a read coroutine. Running two read coroutines at the same time
- # would have an unexpected behaviour. It would not possible to know
- # which coroutine would get the next data.
- if self._waiter is not None:
- raise RuntimeError('%s() called while another coroutine is '
- 'already waiting for incoming data' % func_name)
-
- # In asyncio, there is no need to recheck if we got data or EOF thanks
- # to "yield from". In trollius, a StreamReader method can be called
- # after the _wait_for_data() coroutine is scheduled and before it is
- # really executed.
- if self._buffer or self._eof:
- return
-
- self._waiter = futures.Future(loop=self._loop)
- try:
- yield From(self._waiter)
- finally:
- self._waiter = None
-
- @coroutine
- def readline(self):
- if self._exception is not None:
- raise self._exception
-
- line = bytearray()
- not_enough = True
-
- while not_enough:
- while self._buffer and not_enough:
- ichar = self._buffer.find(b'\n')
- if ichar < 0:
- line.extend(self._buffer)
- del self._buffer[:]
- else:
- ichar += 1
- line.extend(self._buffer[:ichar])
- del self._buffer[:ichar]
- not_enough = False
-
- if len(line) > self._limit:
- self._maybe_resume_transport()
- raise ValueError('Line is too long')
-
- if self._eof:
- break
-
- if not_enough:
- yield From(self._wait_for_data('readline'))
-
- self._maybe_resume_transport()
- raise Return(bytes(line))
-
- @coroutine
- def read(self, n=-1):
- if self._exception is not None:
- raise self._exception
-
- if not n:
- raise Return(b'')
-
- if n < 0:
- # This used to just loop creating a new waiter hoping to
- # collect everything in self._buffer, but that would
- # deadlock if the subprocess sends more than self.limit
- # bytes. So just call self.read(self._limit) until EOF.
- blocks = []
- while True:
- block = yield From(self.read(self._limit))
- if not block:
- break
- blocks.append(block)
- raise Return(b''.join(blocks))
- else:
- if not self._buffer and not self._eof:
- yield From(self._wait_for_data('read'))
-
- if n < 0 or len(self._buffer) <= n:
- data = bytes(self._buffer)
- del self._buffer[:]
- else:
- # n > 0 and len(self._buffer) > n
- data = bytes(self._buffer[:n])
- del self._buffer[:n]
-
- self._maybe_resume_transport()
- raise Return(data)
-
- @coroutine
- def readexactly(self, n):
- if self._exception is not None:
- raise self._exception
-
- # There used to be "optimized" code here. It created its own
- # Future and waited until self._buffer had at least the n
- # bytes, then called read(n). Unfortunately, this could pause
- # the transport if the argument was larger than the pause
- # limit (which is twice self._limit). So now we just read()
- # into a local buffer.
-
- blocks = []
- while n > 0:
- block = yield From(self.read(n))
- if not block:
- partial = b''.join(blocks)
- raise IncompleteReadError(partial, len(partial) + n)
- blocks.append(block)
- n -= len(block)
-
- raise Return(b''.join(blocks))
-
- # FIXME: should we support __aiter__ and __anext__ in Trollius?
- #if compat.PY35:
- # @coroutine
- # def __aiter__(self):
- # return self
- #
- # @coroutine
- # def __anext__(self):
- # val = yield from self.readline()
- # if val == b'':
- # raise StopAsyncIteration
- # return val
+++ /dev/null
-from __future__ import absolute_import
-
-__all__ = ['create_subprocess_exec', 'create_subprocess_shell']
-
-import subprocess
-
-from . import events
-from . import protocols
-from . import streams
-from . import tasks
-from .coroutines import coroutine, From, Return
-from .py33_exceptions import BrokenPipeError, ConnectionResetError
-from .log import logger
-
-
-PIPE = subprocess.PIPE
-STDOUT = subprocess.STDOUT
-if hasattr(subprocess, 'DEVNULL'):
- DEVNULL = subprocess.DEVNULL
-
-
-class SubprocessStreamProtocol(streams.FlowControlMixin,
- protocols.SubprocessProtocol):
- """Like StreamReaderProtocol, but for a subprocess."""
-
- def __init__(self, limit, loop):
- super(SubprocessStreamProtocol, self).__init__(loop=loop)
- self._limit = limit
- self.stdin = self.stdout = self.stderr = None
- self._transport = None
-
- def __repr__(self):
- info = [self.__class__.__name__]
- if self.stdin is not None:
- info.append('stdin=%r' % self.stdin)
- if self.stdout is not None:
- info.append('stdout=%r' % self.stdout)
- if self.stderr is not None:
- info.append('stderr=%r' % self.stderr)
- return '<%s>' % ' '.join(info)
-
- def connection_made(self, transport):
- self._transport = transport
-
- stdout_transport = transport.get_pipe_transport(1)
- if stdout_transport is not None:
- self.stdout = streams.StreamReader(limit=self._limit,
- loop=self._loop)
- self.stdout.set_transport(stdout_transport)
-
- stderr_transport = transport.get_pipe_transport(2)
- if stderr_transport is not None:
- self.stderr = streams.StreamReader(limit=self._limit,
- loop=self._loop)
- self.stderr.set_transport(stderr_transport)
-
- stdin_transport = transport.get_pipe_transport(0)
- if stdin_transport is not None:
- self.stdin = streams.StreamWriter(stdin_transport,
- protocol=self,
- reader=None,
- loop=self._loop)
-
- def pipe_data_received(self, fd, data):
- if fd == 1:
- reader = self.stdout
- elif fd == 2:
- reader = self.stderr
- else:
- reader = None
- if reader is not None:
- reader.feed_data(data)
-
- def pipe_connection_lost(self, fd, exc):
- if fd == 0:
- pipe = self.stdin
- if pipe is not None:
- pipe.close()
- self.connection_lost(exc)
- return
- if fd == 1:
- reader = self.stdout
- elif fd == 2:
- reader = self.stderr
- else:
- reader = None
- if reader != None:
- if exc is None:
- reader.feed_eof()
- else:
- reader.set_exception(exc)
-
- def process_exited(self):
- self._transport.close()
- self._transport = None
-
-
-class Process:
- def __init__(self, transport, protocol, loop):
- self._transport = transport
- self._protocol = protocol
- self._loop = loop
- self.stdin = protocol.stdin
- self.stdout = protocol.stdout
- self.stderr = protocol.stderr
- self.pid = transport.get_pid()
-
- def __repr__(self):
- return '<%s %s>' % (self.__class__.__name__, self.pid)
-
- @property
- def returncode(self):
- return self._transport.get_returncode()
-
- @coroutine
- def wait(self):
- """Wait until the process exit and return the process return code.
-
- This method is a coroutine."""
- return_code = yield From(self._transport._wait())
- raise Return(return_code)
-
- def send_signal(self, signal):
- self._transport.send_signal(signal)
-
- def terminate(self):
- self._transport.terminate()
-
- def kill(self):
- self._transport.kill()
-
- @coroutine
- def _feed_stdin(self, input):
- debug = self._loop.get_debug()
- self.stdin.write(input)
- if debug:
- logger.debug('%r communicate: feed stdin (%s bytes)',
- self, len(input))
- try:
- yield From(self.stdin.drain())
- except (BrokenPipeError, ConnectionResetError) as exc:
- # communicate() ignores BrokenPipeError and ConnectionResetError
- if debug:
- logger.debug('%r communicate: stdin got %r', self, exc)
-
- if debug:
- logger.debug('%r communicate: close stdin', self)
- self.stdin.close()
-
- @coroutine
- def _noop(self):
- return None
-
- @coroutine
- def _read_stream(self, fd):
- transport = self._transport.get_pipe_transport(fd)
- if fd == 2:
- stream = self.stderr
- else:
- assert fd == 1
- stream = self.stdout
- if self._loop.get_debug():
- name = 'stdout' if fd == 1 else 'stderr'
- logger.debug('%r communicate: read %s', self, name)
- output = yield From(stream.read())
- if self._loop.get_debug():
- name = 'stdout' if fd == 1 else 'stderr'
- logger.debug('%r communicate: close %s', self, name)
- transport.close()
- raise Return(output)
-
- @coroutine
- def communicate(self, input=None):
- if input:
- stdin = self._feed_stdin(input)
- else:
- stdin = self._noop()
- if self.stdout is not None:
- stdout = self._read_stream(1)
- else:
- stdout = self._noop()
- if self.stderr is not None:
- stderr = self._read_stream(2)
- else:
- stderr = self._noop()
- stdin, stdout, stderr = yield From(tasks.gather(stdin, stdout, stderr,
- loop=self._loop))
- yield From(self.wait())
- raise Return(stdout, stderr)
-
-
-@coroutine
-def create_subprocess_shell(cmd, **kwds):
- stdin = kwds.pop('stdin', None)
- stdout = kwds.pop('stdout', None)
- stderr = kwds.pop('stderr', None)
- loop = kwds.pop('loop', None)
- limit = kwds.pop('limit', streams._DEFAULT_LIMIT)
- if loop is None:
- loop = events.get_event_loop()
- protocol_factory = lambda: SubprocessStreamProtocol(limit=limit,
- loop=loop)
- transport, protocol = yield From(loop.subprocess_shell(
- protocol_factory,
- cmd, stdin=stdin, stdout=stdout,
- stderr=stderr, **kwds))
- raise Return(Process(transport, protocol, loop))
-
-@coroutine
-def create_subprocess_exec(program, *args, **kwds):
- stdin = kwds.pop('stdin', None)
- stdout = kwds.pop('stdout', None)
- stderr = kwds.pop('stderr', None)
- loop = kwds.pop('loop', None)
- limit = kwds.pop('limit', streams._DEFAULT_LIMIT)
- if loop is None:
- loop = events.get_event_loop()
- protocol_factory = lambda: SubprocessStreamProtocol(limit=limit,
- loop=loop)
- transport, protocol = yield From(loop.subprocess_exec(
- protocol_factory,
- program, *args,
- stdin=stdin, stdout=stdout,
- stderr=stderr, **kwds))
- raise Return(Process(transport, protocol, loop))
+++ /dev/null
-"""Support for tasks, coroutines and the scheduler."""
-from __future__ import print_function
-
-__all__ = ['Task',
- 'FIRST_COMPLETED', 'FIRST_EXCEPTION', 'ALL_COMPLETED',
- 'wait', 'wait_for', 'as_completed', 'sleep', 'async',
- 'gather', 'shield', 'ensure_future',
- ]
-
-import functools
-import linecache
-import traceback
-import warnings
-try:
- from weakref import WeakSet
-except ImportError:
- # Python 2.6
- from .py27_weakrefset import WeakSet
-
-from . import compat
-from . import coroutines
-from . import events
-from . import executor
-from . import futures
-from .locks import Lock, Condition, Semaphore, _ContextManager
-from .coroutines import coroutine, From, Return, ReturnException
-
-
-
-@coroutine
-def _lock_coroutine(lock):
- yield From(lock.acquire())
- raise Return(_ContextManager(lock))
-
-
-class Task(futures.Future):
- """A coroutine wrapped in a Future."""
-
- # An important invariant maintained while a Task not done:
- #
- # - Either _fut_waiter is None, and _step() is scheduled;
- # - or _fut_waiter is some Future, and _step() is *not* scheduled.
- #
- # The only transition from the latter to the former is through
- # _wakeup(). When _fut_waiter is not None, one of its callbacks
- # must be _wakeup().
-
- # Weak set containing all tasks alive.
- _all_tasks = WeakSet()
-
- # Dictionary containing tasks that are currently active in
- # all running event loops. {EventLoop: Task}
- _current_tasks = {}
-
- # If False, don't log a message if the task is destroyed whereas its
- # status is still pending
- _log_destroy_pending = True
-
- @classmethod
- def current_task(cls, loop=None):
- """Return the currently running task in an event loop or None.
-
- By default the current task for the current event loop is returned.
-
- None is returned when called not in the context of a Task.
- """
- if loop is None:
- loop = events.get_event_loop()
- return cls._current_tasks.get(loop)
-
- @classmethod
- def all_tasks(cls, loop=None):
- """Return a set of all tasks for an event loop.
-
- By default all tasks for the current event loop are returned.
- """
- if loop is None:
- loop = events.get_event_loop()
- return set(t for t in cls._all_tasks if t._loop is loop)
-
- def __init__(self, coro, loop=None):
- assert coroutines.iscoroutine(coro), repr(coro)
- super(Task, self).__init__(loop=loop)
- if self._source_traceback:
- del self._source_traceback[-1]
- self._coro = coro
- self._fut_waiter = None
- self._must_cancel = False
- self._loop.call_soon(self._step)
- self.__class__._all_tasks.add(self)
-
- # On Python 3.3 or older, objects with a destructor that are part of a
- # reference cycle are never destroyed. That's not the case any more on
- # Python 3.4 thanks to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._state == futures._PENDING and self._log_destroy_pending:
- context = {
- 'task': self,
- 'message': 'Task was destroyed but it is pending!',
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
- futures.Future.__del__(self)
-
- def _repr_info(self):
- info = super(Task, self)._repr_info()
-
- if self._must_cancel:
- # replace status
- info[0] = 'cancelling'
-
- coro = coroutines._format_coroutine(self._coro)
- info.insert(1, 'coro=<%s>' % coro)
-
- if self._fut_waiter is not None:
- info.insert(2, 'wait_for=%r' % self._fut_waiter)
- return info
-
- def get_stack(self, limit=None):
- """Return the list of stack frames for this task's coroutine.
-
- If the coroutine is not done, this returns the stack where it is
- suspended. If the coroutine has completed successfully or was
- cancelled, this returns an empty list. If the coroutine was
- terminated by an exception, this returns the list of traceback
- frames.
-
- The frames are always ordered from oldest to newest.
-
- The optional limit gives the maximum number of frames to
- return; by default all available frames are returned. Its
- meaning differs depending on whether a stack or a traceback is
- returned: the newest frames of a stack are returned, but the
- oldest frames of a traceback are returned. (This matches the
- behavior of the traceback module.)
-
- For reasons beyond our control, only one stack frame is
- returned for a suspended coroutine.
- """
- frames = []
- try:
- # 'async def' coroutines
- f = self._coro.cr_frame
- except AttributeError:
- f = self._coro.gi_frame
- if f is not None:
- while f is not None:
- if limit is not None:
- if limit <= 0:
- break
- limit -= 1
- frames.append(f)
- f = f.f_back
- frames.reverse()
- elif self._exception is not None:
- tb = self._exception.__traceback__
- while tb is not None:
- if limit is not None:
- if limit <= 0:
- break
- limit -= 1
- frames.append(tb.tb_frame)
- tb = tb.tb_next
- return frames
-
- def print_stack(self, limit=None, file=None):
- """Print the stack or traceback for this task's coroutine.
-
- This produces output similar to that of the traceback module,
- for the frames retrieved by get_stack(). The limit argument
- is passed to get_stack(). The file argument is an I/O stream
- to which the output is written; by default output is written
- to sys.stderr.
- """
- extracted_list = []
- checked = set()
- for f in self.get_stack(limit=limit):
- lineno = f.f_lineno
- co = f.f_code
- filename = co.co_filename
- name = co.co_name
- if filename not in checked:
- checked.add(filename)
- linecache.checkcache(filename)
- line = linecache.getline(filename, lineno, f.f_globals)
- extracted_list.append((filename, lineno, name, line))
- exc = self._exception
- if not extracted_list:
- print('No stack for %r' % self, file=file)
- elif exc is not None:
- print('Traceback for %r (most recent call last):' % self,
- file=file)
- else:
- print('Stack for %r (most recent call last):' % self,
- file=file)
- traceback.print_list(extracted_list, file=file)
- if exc is not None:
- for line in traceback.format_exception_only(exc.__class__, exc):
- print(line, file=file, end='')
-
- def cancel(self):
- """Request that this task cancel itself.
-
- This arranges for a CancelledError to be thrown into the
- wrapped coroutine on the next cycle through the event loop.
- The coroutine then has a chance to clean up or even deny
- the request using try/except/finally.
-
- Unlike Future.cancel, this does not guarantee that the
- task will be cancelled: the exception might be caught and
- acted upon, delaying cancellation of the task or preventing
- cancellation completely. The task may also return a value or
- raise a different exception.
-
- Immediately after this method is called, Task.cancelled() will
- not return True (unless the task was already cancelled). A
- task will be marked as cancelled when the wrapped coroutine
- terminates with a CancelledError exception (even if cancel()
- was not called).
- """
- if self.done():
- return False
- if self._fut_waiter is not None:
- if self._fut_waiter.cancel():
- # Leave self._fut_waiter; it may be a Task that
- # catches and ignores the cancellation so we may have
- # to cancel it again later.
- return True
- # It must be the case that self._step is already scheduled.
- self._must_cancel = True
- return True
-
- def _step(self, value=None, exc=None, exc_tb=None):
- assert not self.done(), \
- '_step(): already done: {0!r}, {1!r}, {2!r}'.format(self, value, exc)
-
- if self._must_cancel:
- if not isinstance(exc, futures.CancelledError):
- exc = futures.CancelledError()
- self._must_cancel = False
- coro = self._coro
- self._fut_waiter = None
-
- if exc_tb is not None:
- init_exc = exc
- else:
- init_exc = None
- self.__class__._current_tasks[self._loop] = self
- # Call either coro.throw(exc) or coro.send(value).
- try:
- if exc is not None:
- if exc_tb is not None:
- result = coro.throw(exc, None, exc_tb)
- else:
- result = coro.throw(exc)
- else:
- result = coro.send(value)
- # On Python 3.3 and Python 3.4, ReturnException is not used in
- # practice. But this except is kept to have a single code base
- # for all Python versions.
- except coroutines.ReturnException as exc:
- if isinstance(exc, ReturnException):
- exc.raised = True
- result = exc.value
- else:
- result = None
- self.set_result(result)
- except StopIteration as exc:
- if compat.PY33:
- # asyncio Task object? get the result of the coroutine
- result = exc.value
- else:
- if isinstance(exc, ReturnException):
- exc.raised = True
- result = exc.value
- else:
- result = None
- self.set_result(result)
- except futures.CancelledError as exc:
- super(Task, self).cancel() # I.e., Future.cancel(self).
- except BaseException as exc:
- if exc is init_exc:
- self._set_exception_with_tb(exc, exc_tb)
- exc_tb = None
- else:
- self.set_exception(exc)
-
- if not isinstance(exc, Exception):
- # reraise BaseException
- raise
- else:
- if coroutines._DEBUG:
- if not coroutines._coroutine_at_yield_from(self._coro):
- # trollius coroutine must "yield From(...)"
- if not isinstance(result, coroutines.FromWrapper):
- self._loop.call_soon(
- self._step, None,
- RuntimeError("yield used without From"))
- return
- result = result.obj
- else:
- # asyncio coroutine using "yield from ..."
- if isinstance(result, coroutines.FromWrapper):
- result = result.obj
- elif isinstance(result, coroutines.FromWrapper):
- result = result.obj
-
- if coroutines.iscoroutine(result):
- # "yield coroutine" creates a task, the current task
- # will wait until the new task is done
- result = self._loop.create_task(result)
- # FIXME: faster check. common base class? hasattr?
- elif isinstance(result, (Lock, Condition, Semaphore)):
- coro = _lock_coroutine(result)
- result = self._loop.create_task(coro)
-
- if isinstance(result, futures._FUTURE_CLASSES):
- # Yielded Future must come from Future.__iter__().
- result.add_done_callback(self._wakeup)
- self._fut_waiter = result
- if self._must_cancel:
- if self._fut_waiter.cancel():
- self._must_cancel = False
- elif result is None:
- # Bare yield relinquishes control for one event loop iteration.
- self._loop.call_soon(self._step)
- else:
- # Yielding something else is an error.
- self._loop.call_soon(
- self._step, None,
- RuntimeError(
- 'Task got bad yield: {0!r}'.format(result)))
- finally:
- self.__class__._current_tasks.pop(self._loop)
- self = None # Needed to break cycles when an exception occurs.
-
- def _wakeup(self, future):
- if (future._state == futures._FINISHED
- and future._exception is not None):
- # Get the traceback before calling exception(), because calling
- # the exception() method clears the traceback
- exc_tb = future._get_exception_tb()
- exc = future.exception()
- self._step(None, exc, exc_tb)
- exc_tb = None
- else:
- try:
- value = future.result()
- except Exception as exc:
- # This may also be a cancellation.
- self._step(None, exc)
- else:
- self._step(value, None)
- self = None # Needed to break cycles when an exception occurs.
-
-
-# wait() and as_completed() similar to those in PEP 3148.
-
-# Export symbols in trollius.tasks for compatibility with asyncio
-FIRST_COMPLETED = executor.FIRST_COMPLETED
-FIRST_EXCEPTION = executor.FIRST_EXCEPTION
-ALL_COMPLETED = executor.ALL_COMPLETED
-
-
-@coroutine
-def wait(fs, loop=None, timeout=None, return_when=ALL_COMPLETED):
- """Wait for the Futures and coroutines given by fs to complete.
-
- The sequence futures must not be empty.
-
- Coroutines will be wrapped in Tasks.
-
- Returns two sets of Future: (done, pending).
-
- Usage:
-
- done, pending = yield From(asyncio.wait(fs))
-
- Note: This does not raise TimeoutError! Futures that aren't done
- when the timeout occurs are returned in the second set.
- """
- if isinstance(fs, futures._FUTURE_CLASSES) or coroutines.iscoroutine(fs):
- raise TypeError("expect a list of futures, not %s" % type(fs).__name__)
- if not fs:
- raise ValueError('Set of coroutines/Futures is empty.')
- if return_when not in (FIRST_COMPLETED, FIRST_EXCEPTION, ALL_COMPLETED):
- raise ValueError('Invalid return_when value: {0}'.format(return_when))
-
- if loop is None:
- loop = events.get_event_loop()
-
- fs = set(ensure_future(f, loop=loop) for f in set(fs))
-
- result = yield From(_wait(fs, timeout, return_when, loop))
- raise Return(result)
-
-
-def _release_waiter(waiter, *args):
- if not waiter.done():
- waiter.set_result(None)
-
-
-@coroutine
-def wait_for(fut, timeout, loop=None):
- """Wait for the single Future or coroutine to complete, with timeout.
-
- Coroutine will be wrapped in Task.
-
- Returns result of the Future or coroutine. When a timeout occurs,
- it cancels the task and raises TimeoutError. To avoid the task
- cancellation, wrap it in shield().
-
- If the wait is cancelled, the task is also cancelled.
-
- This function is a coroutine.
- """
- if loop is None:
- loop = events.get_event_loop()
-
- if timeout is None:
- result = yield From(fut)
- raise Return(result)
-
- waiter = futures.Future(loop=loop)
- timeout_handle = loop.call_later(timeout, _release_waiter, waiter)
- cb = functools.partial(_release_waiter, waiter)
-
- fut = ensure_future(fut, loop=loop)
- fut.add_done_callback(cb)
-
- try:
- # wait until the future completes or the timeout
- try:
- yield From(waiter)
- except futures.CancelledError:
- fut.remove_done_callback(cb)
- fut.cancel()
- raise
-
- if fut.done():
- raise Return(fut.result())
- else:
- fut.remove_done_callback(cb)
- fut.cancel()
- raise futures.TimeoutError()
- finally:
- timeout_handle.cancel()
-
-
-@coroutine
-def _wait(fs, timeout, return_when, loop):
- """Internal helper for wait() and _wait_for().
-
- The fs argument must be a collection of Futures.
- """
- assert fs, 'Set of Futures is empty.'
- waiter = futures.Future(loop=loop)
- timeout_handle = None
- if timeout is not None:
- timeout_handle = loop.call_later(timeout, _release_waiter, waiter)
- non_local = {'counter': len(fs)}
-
- def _on_completion(f):
- non_local['counter'] -= 1
- if (non_local['counter'] <= 0 or
- return_when == FIRST_COMPLETED or
- return_when == FIRST_EXCEPTION and (not f.cancelled() and
- f.exception() is not None)):
- if timeout_handle is not None:
- timeout_handle.cancel()
- if not waiter.done():
- waiter.set_result(None)
-
- for f in fs:
- f.add_done_callback(_on_completion)
-
- try:
- yield From(waiter)
- finally:
- if timeout_handle is not None:
- timeout_handle.cancel()
-
- done, pending = set(), set()
- for f in fs:
- f.remove_done_callback(_on_completion)
- if f.done():
- done.add(f)
- else:
- pending.add(f)
- raise Return(done, pending)
-
-
-# This is *not* a @coroutine! It is just an iterator (yielding Futures).
-def as_completed(fs, loop=None, timeout=None):
- """Return an iterator whose values are coroutines.
-
- When waiting for the yielded coroutines you'll get the results (or
- exceptions!) of the original Futures (or coroutines), in the order
- in which and as soon as they complete.
-
- This differs from PEP 3148; the proper way to use this is:
-
- for f in as_completed(fs):
- result = yield From(f) # The 'yield' may raise.
- # Use result.
-
- If a timeout is specified, the 'yield' will raise
- TimeoutError when the timeout occurs before all Futures are done.
-
- Note: The futures 'f' are not necessarily members of fs.
- """
- if isinstance(fs, futures._FUTURE_CLASSES) or coroutines.iscoroutine(fs):
- raise TypeError("expect a list of futures, not %s" % type(fs).__name__)
- loop = loop if loop is not None else events.get_event_loop()
- todo = set(ensure_future(f, loop=loop) for f in set(fs))
- from .queues import Queue # Import here to avoid circular import problem.
- done = Queue(loop=loop)
- timeout_handle = None
-
- def _on_timeout():
- for f in todo:
- f.remove_done_callback(_on_completion)
- done.put_nowait(None) # Queue a dummy value for _wait_for_one().
- todo.clear() # Can't do todo.remove(f) in the loop.
-
- def _on_completion(f):
- if not todo:
- return # _on_timeout() was here first.
- todo.remove(f)
- done.put_nowait(f)
- if not todo and timeout_handle is not None:
- timeout_handle.cancel()
-
- @coroutine
- def _wait_for_one():
- f = yield From(done.get())
- if f is None:
- # Dummy value from _on_timeout().
- raise futures.TimeoutError
- raise Return(f.result()) # May raise f.exception().
-
- for f in todo:
- f.add_done_callback(_on_completion)
- if todo and timeout is not None:
- timeout_handle = loop.call_later(timeout, _on_timeout)
- for _ in range(len(todo)):
- yield _wait_for_one()
-
-
-@coroutine
-def sleep(delay, result=None, loop=None):
- """Coroutine that completes after a given time (in seconds)."""
- future = futures.Future(loop=loop)
- h = future._loop.call_later(delay,
- future._set_result_unless_cancelled, result)
- try:
- result = yield From(future)
- raise Return(result)
- finally:
- h.cancel()
-
-
-def async(coro_or_future, loop=None):
- """Wrap a coroutine in a future.
-
- If the argument is a Future, it is returned directly.
-
- This function is deprecated in 3.5. Use asyncio.ensure_future() instead.
- """
-
- warnings.warn("asyncio.async() function is deprecated, use ensure_future()",
- DeprecationWarning)
-
- return ensure_future(coro_or_future, loop=loop)
-
-
-def ensure_future(coro_or_future, loop=None):
- """Wrap a coroutine in a future.
-
- If the argument is a Future, it is returned directly.
- """
- # FIXME: only check if coroutines._DEBUG is True?
- if isinstance(coro_or_future, coroutines.FromWrapper):
- coro_or_future = coro_or_future.obj
- if isinstance(coro_or_future, futures._FUTURE_CLASSES):
- if loop is not None and loop is not coro_or_future._loop:
- raise ValueError('loop argument must agree with Future')
- return coro_or_future
- elif coroutines.iscoroutine(coro_or_future):
- if loop is None:
- loop = events.get_event_loop()
- task = loop.create_task(coro_or_future)
- if task._source_traceback:
- del task._source_traceback[-1]
- return task
- else:
- raise TypeError('A Future or coroutine is required')
-
-
-class _GatheringFuture(futures.Future):
- """Helper for gather().
-
- This overrides cancel() to cancel all the children and act more
- like Task.cancel(), which doesn't immediately mark itself as
- cancelled.
- """
-
- def __init__(self, children, loop=None):
- super(_GatheringFuture, self).__init__(loop=loop)
- self._children = children
-
- def cancel(self):
- if self.done():
- return False
- for child in self._children:
- child.cancel()
- return True
-
-
-def gather(*coros_or_futures, **kw):
- """Return a future aggregating results from the given coroutines
- or futures.
-
- All futures must share the same event loop. If all the tasks are
- done successfully, the returned future's result is the list of
- results (in the order of the original sequence, not necessarily
- the order of results arrival). If *return_exceptions* is True,
- exceptions in the tasks are treated the same as successful
- results, and gathered in the result list; otherwise, the first
- raised exception will be immediately propagated to the returned
- future.
-
- Cancellation: if the outer Future is cancelled, all children (that
- have not completed yet) are also cancelled. If any child is
- cancelled, this is treated as if it raised CancelledError --
- the outer Future is *not* cancelled in this case. (This is to
- prevent the cancellation of one child to cause other children to
- be cancelled.)
- """
- loop = kw.pop('loop', None)
- return_exceptions = kw.pop('return_exceptions', False)
- if kw:
- raise TypeError("unexpected keyword")
-
- if not coros_or_futures:
- outer = futures.Future(loop=loop)
- outer.set_result([])
- return outer
-
- arg_to_fut = {}
- for arg in set(coros_or_futures):
- if not isinstance(arg, futures._FUTURE_CLASSES):
- fut = ensure_future(arg, loop=loop)
- if loop is None:
- loop = fut._loop
- # The caller cannot control this future, the "destroy pending task"
- # warning should not be emitted.
- fut._log_destroy_pending = False
- else:
- fut = arg
- if loop is None:
- loop = fut._loop
- elif fut._loop is not loop:
- raise ValueError("futures are tied to different event loops")
- arg_to_fut[arg] = fut
-
- children = [arg_to_fut[arg] for arg in coros_or_futures]
- nchildren = len(children)
- outer = _GatheringFuture(children, loop=loop)
- non_local = {'nfinished': 0}
- results = [None] * nchildren
-
- def _done_callback(i, fut):
- if outer.done():
- if not fut.cancelled():
- # Mark exception retrieved.
- fut.exception()
- return
-
- if fut.cancelled():
- res = futures.CancelledError()
- if not return_exceptions:
- outer.set_exception(res)
- return
- elif fut._exception is not None:
- res = fut.exception() # Mark exception retrieved.
- if not return_exceptions:
- outer.set_exception(res)
- return
- else:
- res = fut._result
- results[i] = res
- non_local['nfinished'] += 1
- if non_local['nfinished'] == nchildren:
- outer.set_result(results)
-
- for i, fut in enumerate(children):
- fut.add_done_callback(functools.partial(_done_callback, i))
- return outer
-
-
-def shield(arg, loop=None):
- """Wait for a future, shielding it from cancellation.
-
- The statement
-
- res = yield From(shield(something()))
-
- is exactly equivalent to the statement
-
- res = yield From(something())
-
- *except* that if the coroutine containing it is cancelled, the
- task running in something() is not cancelled. From the POV of
- something(), the cancellation did not happen. But its caller is
- still cancelled, so the yield-from expression still raises
- CancelledError. Note: If something() is cancelled by other means
- this will still cancel shield().
-
- If you want to completely ignore cancellation (not recommended)
- you can combine shield() with a try/except clause, as follows:
-
- try:
- res = yield From(shield(something()))
- except CancelledError:
- res = None
- """
- inner = ensure_future(arg, loop=loop)
- if inner.done():
- # Shortcut.
- return inner
- loop = inner._loop
- outer = futures.Future(loop=loop)
-
- def _done_callback(inner):
- if outer.cancelled():
- if not inner.cancelled():
- # Mark inner's result as retrieved.
- inner.exception()
- return
-
- if inner.cancelled():
- outer.cancel()
- else:
- exc = inner.exception()
- if exc is not None:
- outer.set_exception(exc)
- else:
- outer.set_result(inner.result())
-
- inner.add_done_callback(_done_callback)
- return outer
+++ /dev/null
-# Subset of test.support from CPython 3.5, just what we need to run asyncio
-# test suite. The code is copied from CPython 3.5 to not depend on the test
-# module because it is rarely installed.
-
-# Ignore symbol TEST_HOME_DIR: test_events works without it
-
-from __future__ import absolute_import
-import functools
-import gc
-import os
-import platform
-import re
-import socket
-import subprocess
-import sys
-import time
-
-from trollius import test_utils
-
-# A constant likely larger than the underlying OS pipe buffer size, to
-# make writes blocking.
-# Windows limit seems to be around 512 B, and many Unix kernels have a
-# 64 KiB pipe buffer size or 16 * PAGE_SIZE: take a few megs to be sure.
-# (see issue #17835 for a discussion of this number).
-PIPE_MAX_SIZE = 4 * 1024 * 1024 + 1
-
-def strip_python_stderr(stderr):
- """Strip the stderr of a Python process from potential debug output
- emitted by the interpreter.
-
- This will typically be run on the result of the communicate() method
- of a subprocess.Popen object.
- """
- stderr = re.sub(br"\[\d+ refs, \d+ blocks\]\r?\n?", b"", stderr).strip()
- return stderr
-
-
-# Executing the interpreter in a subprocess
-def _assert_python(expected_success, *args, **env_vars):
- if '__isolated' in env_vars:
- isolated = env_vars.pop('__isolated')
- else:
- isolated = not env_vars
- cmd_line = [sys.executable]
- if sys.version_info >= (3, 3):
- cmd_line.extend(('-X', 'faulthandler'))
- if isolated and sys.version_info >= (3, 4):
- # isolated mode: ignore Python environment variables, ignore user
- # site-packages, and don't add the current directory to sys.path
- cmd_line.append('-I')
- elif not env_vars:
- # ignore Python environment variables
- cmd_line.append('-E')
- # Need to preserve the original environment, for in-place testing of
- # shared library builds.
- env = os.environ.copy()
- # But a special flag that can be set to override -- in this case, the
- # caller is responsible to pass the full environment.
- if env_vars.pop('__cleanenv', None):
- env = {}
- env.update(env_vars)
- cmd_line.extend(args)
- p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- env=env)
- try:
- out, err = p.communicate()
- finally:
- subprocess._cleanup()
- p.stdout.close()
- p.stderr.close()
- rc = p.returncode
- err = strip_python_stderr(err)
- if (rc and expected_success) or (not rc and not expected_success):
- raise AssertionError(
- "Process return code is %d, "
- "stderr follows:\n%s" % (rc, err.decode('ascii', 'ignore')))
- return rc, out, err
-
-
-def assert_python_ok(*args, **env_vars):
- """
- Assert that running the interpreter with `args` and optional environment
- variables `env_vars` succeeds (rc == 0) and return a (return code, stdout,
- stderr) tuple.
-
- If the __cleanenv keyword is set, env_vars is used a fresh environment.
-
- Python is started in isolated mode (command line option -I),
- except if the __isolated keyword is set to False.
- """
- return _assert_python(True, *args, **env_vars)
-
-
-is_jython = sys.platform.startswith('java')
-
-def gc_collect():
- """Force as many objects as possible to be collected.
-
- In non-CPython implementations of Python, this is needed because timely
- deallocation is not guaranteed by the garbage collector. (Even in CPython
- this can be the case in case of reference cycles.) This means that __del__
- methods may be called later than expected and weakrefs may remain alive for
- longer than expected. This function tries its best to force all garbage
- objects to disappear.
- """
- gc.collect()
- if is_jython:
- time.sleep(0.1)
- gc.collect()
- gc.collect()
-
-
-HOST = "127.0.0.1"
-HOSTv6 = "::1"
-
-
-def _is_ipv6_enabled():
- """Check whether IPv6 is enabled on this host."""
- if socket.has_ipv6:
- sock = None
- try:
- sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- sock.bind((HOSTv6, 0))
- return True
- except OSError:
- pass
- finally:
- if sock:
- sock.close()
- return False
-
-IPV6_ENABLED = _is_ipv6_enabled()
-
-
-def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM):
- """Returns an unused port that should be suitable for binding. This is
- achieved by creating a temporary socket with the same family and type as
- the 'sock' parameter (default is AF_INET, SOCK_STREAM), and binding it to
- the specified host address (defaults to 0.0.0.0) with the port set to 0,
- eliciting an unused ephemeral port from the OS. The temporary socket is
- then closed and deleted, and the ephemeral port is returned.
-
- Either this method or bind_port() should be used for any tests where a
- server socket needs to be bound to a particular port for the duration of
- the test. Which one to use depends on whether the calling code is creating
- a python socket, or if an unused port needs to be provided in a constructor
- or passed to an external program (i.e. the -accept argument to openssl's
- s_server mode). Always prefer bind_port() over find_unused_port() where
- possible. Hard coded ports should *NEVER* be used. As soon as a server
- socket is bound to a hard coded port, the ability to run multiple instances
- of the test simultaneously on the same host is compromised, which makes the
- test a ticking time bomb in a buildbot environment. On Unix buildbots, this
- may simply manifest as a failed test, which can be recovered from without
- intervention in most cases, but on Windows, the entire python process can
- completely and utterly wedge, requiring someone to log in to the buildbot
- and manually kill the affected process.
-
- (This is easy to reproduce on Windows, unfortunately, and can be traced to
- the SO_REUSEADDR socket option having different semantics on Windows versus
- Unix/Linux. On Unix, you can't have two AF_INET SOCK_STREAM sockets bind,
- listen and then accept connections on identical host/ports. An EADDRINUSE
- OSError will be raised at some point (depending on the platform and
- the order bind and listen were called on each socket).
-
- However, on Windows, if SO_REUSEADDR is set on the sockets, no EADDRINUSE
- will ever be raised when attempting to bind two identical host/ports. When
- accept() is called on each socket, the second caller's process will steal
- the port from the first caller, leaving them both in an awkwardly wedged
- state where they'll no longer respond to any signals or graceful kills, and
- must be forcibly killed via OpenProcess()/TerminateProcess().
-
- The solution on Windows is to use the SO_EXCLUSIVEADDRUSE socket option
- instead of SO_REUSEADDR, which effectively affords the same semantics as
- SO_REUSEADDR on Unix. Given the propensity of Unix developers in the Open
- Source world compared to Windows ones, this is a common mistake. A quick
- look over OpenSSL's 0.9.8g source shows that they use SO_REUSEADDR when
- openssl.exe is called with the 's_server' option, for example. See
- http://bugs.python.org/issue2550 for more info. The following site also
- has a very thorough description about the implications of both REUSEADDR
- and EXCLUSIVEADDRUSE on Windows:
- http://msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx)
-
- XXX: although this approach is a vast improvement on previous attempts to
- elicit unused ports, it rests heavily on the assumption that the ephemeral
- port returned to us by the OS won't immediately be dished back out to some
- other process when we close and delete our temporary socket but before our
- calling code has a chance to bind the returned port. We can deal with this
- issue if/when we come across it.
- """
-
- tempsock = socket.socket(family, socktype)
- port = bind_port(tempsock)
- tempsock.close()
- del tempsock
- return port
-
-def bind_port(sock, host=HOST):
- """Bind the socket to a free port and return the port number. Relies on
- ephemeral ports in order to ensure we are using an unbound port. This is
- important as many tests may be running simultaneously, especially in a
- buildbot environment. This method raises an exception if the sock.family
- is AF_INET and sock.type is SOCK_STREAM, *and* the socket has SO_REUSEADDR
- or SO_REUSEPORT set on it. Tests should *never* set these socket options
- for TCP/IP sockets. The only case for setting these options is testing
- multicasting via multiple UDP sockets.
-
- Additionally, if the SO_EXCLUSIVEADDRUSE socket option is available (i.e.
- on Windows), it will be set on the socket. This will prevent anyone else
- from bind()'ing to our host/port for the duration of the test.
- """
-
- if sock.family == socket.AF_INET and sock.type == socket.SOCK_STREAM:
- if hasattr(socket, 'SO_REUSEADDR'):
- if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) == 1:
- raise TestFailed("tests should never set the SO_REUSEADDR "
- "socket option on TCP/IP sockets!")
- if hasattr(socket, 'SO_REUSEPORT'):
- try:
- reuse = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT)
- if reuse == 1:
- raise TestFailed("tests should never set the SO_REUSEPORT "
- "socket option on TCP/IP sockets!")
- except OSError:
- # Python's socket module was compiled using modern headers
- # thus defining SO_REUSEPORT but this process is running
- # under an older kernel that does not support SO_REUSEPORT.
- pass
- if hasattr(socket, 'SO_EXCLUSIVEADDRUSE'):
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
-
- sock.bind((host, 0))
- port = sock.getsockname()[1]
- return port
-
-def requires_mac_ver(*min_version):
- """Decorator raising SkipTest if the OS is Mac OS X and the OS X
- version if less than min_version.
-
- For example, @requires_mac_ver(10, 5) raises SkipTest if the OS X version
- is lesser than 10.5.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kw):
- if sys.platform == 'darwin':
- version_txt = platform.mac_ver()[0]
- try:
- version = tuple(map(int, version_txt.split('.')))
- except ValueError:
- pass
- else:
- if version < min_version:
- min_version_txt = '.'.join(map(str, min_version))
- raise test_utils.SkipTest(
- "Mac OS X %s or higher required, not %s"
- % (min_version_txt, version_txt))
- return func(*args, **kw)
- wrapper.min_version = min_version
- return wrapper
- return decorator
-
-def _requires_unix_version(sysname, min_version):
- """Decorator raising SkipTest if the OS is `sysname` and the version is
- less than `min_version`.
-
- For example, @_requires_unix_version('FreeBSD', (7, 2)) raises SkipTest if
- the FreeBSD version is less than 7.2.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kw):
- if platform.system() == sysname:
- version_txt = platform.release().split('-', 1)[0]
- try:
- version = tuple(map(int, version_txt.split('.')))
- except ValueError:
- pass
- else:
- if version < min_version:
- min_version_txt = '.'.join(map(str, min_version))
- raise test_utils.SkipTest(
- "%s version %s or higher required, not %s"
- % (sysname, min_version_txt, version_txt))
- return func(*args, **kw)
- wrapper.min_version = min_version
- return wrapper
- return decorator
-
-def requires_freebsd_version(*min_version):
- """Decorator raising SkipTest if the OS is FreeBSD and the FreeBSD version
- is less than `min_version`.
-
- For example, @requires_freebsd_version(7, 2) raises SkipTest if the FreeBSD
- version is less than 7.2.
- """
- return _requires_unix_version('FreeBSD', min_version)
-
-# Use test.support if available
-try:
- from test.support import *
-except ImportError:
- pass
-
-# Use test.script_helper if available
-try:
- from test.script_helper import assert_python_ok
-except ImportError:
- pass
+++ /dev/null
-"""Utilities shared by tests."""
-
-import collections
-import contextlib
-import io
-import logging
-import os
-import re
-import socket
-import sys
-import tempfile
-import threading
-import time
-
-from wsgiref.simple_server import WSGIRequestHandler, WSGIServer
-
-import six
-
-try:
- import socketserver
- from http.server import HTTPServer
-except ImportError:
- # Python 2
- import SocketServer as socketserver
- from BaseHTTPServer import HTTPServer
-
-try:
- from unittest import mock
-except ImportError:
- # Python < 3.3
- import mock
-
-try:
- import ssl
- from .py3_ssl import SSLContext, wrap_socket
-except ImportError: # pragma: no cover
- # SSL support disabled in Python
- ssl = None
-
-from . import base_events
-from . import compat
-from . import events
-from . import futures
-from . import selectors
-from . import tasks
-from .coroutines import coroutine
-from .log import logger
-
-
-if sys.platform == 'win32': # pragma: no cover
- from .windows_utils import socketpair
-else:
- from socket import socketpair # pragma: no cover
-
-try:
- # Prefer unittest2 if available (on Python 2)
- import unittest2 as unittest
-except ImportError:
- import unittest
-
-skipIf = unittest.skipIf
-skipUnless = unittest.skipUnless
-SkipTest = unittest.SkipTest
-
-
-if not hasattr(unittest.TestCase, 'assertRaisesRegex'):
- class _BaseTestCaseContext:
-
- def __init__(self, test_case):
- self.test_case = test_case
-
- def _raiseFailure(self, standardMsg):
- msg = self.test_case._formatMessage(self.msg, standardMsg)
- raise self.test_case.failureException(msg)
-
-
- class _AssertRaisesBaseContext(_BaseTestCaseContext):
-
- def __init__(self, expected, test_case, callable_obj=None,
- expected_regex=None):
- _BaseTestCaseContext.__init__(self, test_case)
- self.expected = expected
- self.test_case = test_case
- if callable_obj is not None:
- try:
- self.obj_name = callable_obj.__name__
- except AttributeError:
- self.obj_name = str(callable_obj)
- else:
- self.obj_name = None
- if isinstance(expected_regex, (bytes, str)):
- expected_regex = re.compile(expected_regex)
- self.expected_regex = expected_regex
- self.msg = None
-
- def handle(self, name, callable_obj, args, kwargs):
- """
- If callable_obj is None, assertRaises/Warns is being used as a
- context manager, so check for a 'msg' kwarg and return self.
- If callable_obj is not None, call it passing args and kwargs.
- """
- if callable_obj is None:
- self.msg = kwargs.pop('msg', None)
- return self
- with self:
- callable_obj(*args, **kwargs)
-
-
- class _AssertRaisesContext(_AssertRaisesBaseContext):
- """A context manager used to implement TestCase.assertRaises* methods."""
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- if exc_type is None:
- try:
- exc_name = self.expected.__name__
- except AttributeError:
- exc_name = str(self.expected)
- if self.obj_name:
- self._raiseFailure("{0} not raised by {1}".format(exc_name,
- self.obj_name))
- else:
- self._raiseFailure("{0} not raised".format(exc_name))
- if not issubclass(exc_type, self.expected):
- # let unexpected exceptions pass through
- return False
- self.exception = exc_value
- if self.expected_regex is None:
- return True
-
- expected_regex = self.expected_regex
- if not expected_regex.search(str(exc_value)):
- self._raiseFailure('"{0}" does not match "{1}"'.format(
- expected_regex.pattern, str(exc_value)))
- return True
-
-
-def dummy_ssl_context():
- if ssl is None:
- return None
- else:
- return SSLContext(ssl.PROTOCOL_SSLv23)
-
-
-def run_briefly(loop, steps=1):
- @coroutine
- def once():
- pass
- for step in range(steps):
- gen = once()
- t = loop.create_task(gen)
- # Don't log a warning if the task is not done after run_until_complete().
- # It occurs if the loop is stopped or if a task raises a BaseException.
- t._log_destroy_pending = False
- try:
- loop.run_until_complete(t)
- finally:
- gen.close()
-
-
-def run_until(loop, pred, timeout=30):
- deadline = time.time() + timeout
- while not pred():
- if timeout is not None:
- timeout = deadline - time.time()
- if timeout <= 0:
- raise futures.TimeoutError()
- loop.run_until_complete(tasks.sleep(0.001, loop=loop))
-
-
-def run_once(loop):
- """loop.stop() schedules _raise_stop_error()
- and run_forever() runs until _raise_stop_error() callback.
- this wont work if test waits for some IO events, because
- _raise_stop_error() runs before any of io events callbacks.
- """
- loop.stop()
- loop.run_forever()
-
-
-class SilentWSGIRequestHandler(WSGIRequestHandler):
-
- def get_stderr(self):
- return io.StringIO()
-
- def log_message(self, format, *args):
- pass
-
-
-class SilentWSGIServer(WSGIServer, object):
-
- request_timeout = 2
-
- def get_request(self):
- request, client_addr = super(SilentWSGIServer, self).get_request()
- request.settimeout(self.request_timeout)
- return request, client_addr
-
- def handle_error(self, request, client_address):
- pass
-
-
-class SSLWSGIServerMixin:
-
- def finish_request(self, request, client_address):
- # The relative location of our test directory (which
- # contains the ssl key and certificate files) differs
- # between the stdlib and stand-alone asyncio.
- # Prefer our own if we can find it.
- here = os.path.join(os.path.dirname(__file__), '..', 'tests')
- if not os.path.isdir(here):
- here = os.path.join(os.path.dirname(os.__file__),
- 'test', 'test_asyncio')
- keyfile = os.path.join(here, 'ssl_key.pem')
- certfile = os.path.join(here, 'ssl_cert.pem')
- ssock = wrap_socket(request,
- keyfile=keyfile,
- certfile=certfile,
- server_side=True)
- try:
- self.RequestHandlerClass(ssock, client_address, self)
- ssock.close()
- except OSError:
- # maybe socket has been closed by peer
- pass
-
-
-class SSLWSGIServer(SSLWSGIServerMixin, SilentWSGIServer):
- pass
-
-
-def _run_test_server(address, use_ssl, server_cls, server_ssl_cls):
-
- def app(environ, start_response):
- status = '200 OK'
- headers = [('Content-type', 'text/plain')]
- start_response(status, headers)
- return [b'Test message']
-
- # Run the test WSGI server in a separate thread in order not to
- # interfere with event handling in the main thread
- server_class = server_ssl_cls if use_ssl else server_cls
- httpd = server_class(address, SilentWSGIRequestHandler)
- httpd.set_app(app)
- httpd.address = httpd.server_address
- server_thread = threading.Thread(
- target=lambda: httpd.serve_forever(poll_interval=0.05))
- server_thread.start()
- try:
- yield httpd
- finally:
- httpd.shutdown()
- httpd.server_close()
- server_thread.join()
-
-
-if hasattr(socket, 'AF_UNIX'):
-
- class UnixHTTPServer(socketserver.UnixStreamServer, HTTPServer, object):
-
- def server_bind(self):
- socketserver.UnixStreamServer.server_bind(self)
- self.server_name = '127.0.0.1'
- self.server_port = 80
-
-
- class UnixWSGIServer(UnixHTTPServer, WSGIServer, object):
-
- request_timeout = 2
-
- def server_bind(self):
- UnixHTTPServer.server_bind(self)
- self.setup_environ()
-
- def get_request(self):
- request, client_addr = super(UnixWSGIServer, self).get_request()
- request.settimeout(self.request_timeout)
- # Code in the stdlib expects that get_request
- # will return a socket and a tuple (host, port).
- # However, this isn't true for UNIX sockets,
- # as the second return value will be a path;
- # hence we return some fake data sufficient
- # to get the tests going
- return request, ('127.0.0.1', '')
-
-
- class SilentUnixWSGIServer(UnixWSGIServer):
-
- def handle_error(self, request, client_address):
- pass
-
-
- class UnixSSLWSGIServer(SSLWSGIServerMixin, SilentUnixWSGIServer):
- pass
-
-
- def gen_unix_socket_path():
- with tempfile.NamedTemporaryFile() as file:
- return file.name
-
-
- @contextlib.contextmanager
- def unix_socket_path():
- path = gen_unix_socket_path()
- try:
- yield path
- finally:
- try:
- os.unlink(path)
- except OSError:
- pass
-
-
- @contextlib.contextmanager
- def run_test_unix_server(use_ssl=False):
- with unix_socket_path() as path:
- for item in _run_test_server(address=path, use_ssl=use_ssl,
- server_cls=SilentUnixWSGIServer,
- server_ssl_cls=UnixSSLWSGIServer):
- yield item
-
-
-@contextlib.contextmanager
-def run_test_server(host='127.0.0.1', port=0, use_ssl=False):
- for item in _run_test_server(address=(host, port), use_ssl=use_ssl,
- server_cls=SilentWSGIServer,
- server_ssl_cls=SSLWSGIServer):
- yield item
-
-
-def make_test_protocol(base):
- dct = {}
- for name in dir(base):
- if name.startswith('__') and name.endswith('__'):
- # skip magic names
- continue
- dct[name] = MockCallback(return_value=None)
- return type('TestProtocol', (base,) + base.__bases__, dct)()
-
-
-class TestSelector(selectors.BaseSelector):
-
- def __init__(self):
- self.keys = {}
-
- def register(self, fileobj, events, data=None):
- key = selectors.SelectorKey(fileobj, 0, events, data)
- self.keys[fileobj] = key
- return key
-
- def unregister(self, fileobj):
- return self.keys.pop(fileobj)
-
- def select(self, timeout):
- return []
-
- def get_map(self):
- return self.keys
-
-
-class TestLoop(base_events.BaseEventLoop):
- """Loop for unittests.
-
- It manages self time directly.
- If something scheduled to be executed later then
- on next loop iteration after all ready handlers done
- generator passed to __init__ is calling.
-
- Generator should be like this:
-
- def gen():
- ...
- when = yield ...
- ... = yield time_advance
-
- Value returned by yield is absolute time of next scheduled handler.
- Value passed to yield is time advance to move loop's time forward.
- """
-
- def __init__(self, gen=None):
- super(TestLoop, self).__init__()
-
- if gen is None:
- def gen():
- yield
- self._check_on_close = False
- else:
- self._check_on_close = True
-
- self._gen = gen()
- next(self._gen)
- self._time = 0
- self._clock_resolution = 1e-9
- self._timers = []
- self._selector = TestSelector()
-
- self.readers = {}
- self.writers = {}
- self.reset_counters()
-
- def time(self):
- return self._time
-
- def advance_time(self, advance):
- """Move test time forward."""
- if advance:
- self._time += advance
-
- def close(self):
- super(TestLoop, self).close()
- if self._check_on_close:
- try:
- self._gen.send(0)
- except StopIteration:
- pass
- else: # pragma: no cover
- raise AssertionError("Time generator is not finished")
-
- def add_reader(self, fd, callback, *args):
- self.readers[fd] = events.Handle(callback, args, self)
-
- def remove_reader(self, fd):
- self.remove_reader_count[fd] += 1
- if fd in self.readers:
- del self.readers[fd]
- return True
- else:
- return False
-
- def assert_reader(self, fd, callback, *args):
- assert fd in self.readers, 'fd {0} is not registered'.format(fd)
- handle = self.readers[fd]
- assert handle._callback == callback, '{0!r} != {1!r}'.format(
- handle._callback, callback)
- assert handle._args == args, '{0!r} != {1!r}'.format(
- handle._args, args)
-
- def add_writer(self, fd, callback, *args):
- self.writers[fd] = events.Handle(callback, args, self)
-
- def remove_writer(self, fd):
- self.remove_writer_count[fd] += 1
- if fd in self.writers:
- del self.writers[fd]
- return True
- else:
- return False
-
- def assert_writer(self, fd, callback, *args):
- assert fd in self.writers, 'fd {0} is not registered'.format(fd)
- handle = self.writers[fd]
- assert handle._callback == callback, '{0!r} != {1!r}'.format(
- handle._callback, callback)
- assert handle._args == args, '{0!r} != {1!r}'.format(
- handle._args, args)
-
- def reset_counters(self):
- self.remove_reader_count = collections.defaultdict(int)
- self.remove_writer_count = collections.defaultdict(int)
-
- def _run_once(self):
- super(TestLoop, self)._run_once()
- for when in self._timers:
- advance = self._gen.send(when)
- self.advance_time(advance)
- self._timers = []
-
- def call_at(self, when, callback, *args):
- self._timers.append(when)
- return super(TestLoop, self).call_at(when, callback, *args)
-
- def _process_events(self, event_list):
- return
-
- def _write_to_self(self):
- pass
-
-
-def MockCallback(**kwargs):
- return mock.Mock(spec=['__call__'], **kwargs)
-
-
-class MockPattern(str):
- """A regex based str with a fuzzy __eq__.
-
- Use this helper with 'mock.assert_called_with', or anywhere
- where a regex comparison between strings is needed.
-
- For instance:
- mock_call.assert_called_with(MockPattern('spam.*ham'))
- """
- def __eq__(self, other):
- return bool(re.search(str(self), other, re.S))
-
-
-def get_function_source(func):
- source = events._get_function_source(func)
- if source is None:
- raise ValueError("unable to get the source of %r" % (func,))
- return source
-
-
-class TestCase(unittest.TestCase):
- def set_event_loop(self, loop, cleanup=True):
- assert loop is not None
- # ensure that the event loop is passed explicitly in asyncio
- events.set_event_loop(None)
- if cleanup:
- self.addCleanup(loop.close)
-
- def new_test_loop(self, gen=None):
- loop = TestLoop(gen)
- self.set_event_loop(loop)
- return loop
-
- def tearDown(self):
- events.set_event_loop(None)
-
- # Detect CPython bug #23353: ensure that yield/yield-from is not used
- # in an except block of a generator
- if sys.exc_info()[0] == SkipTest:
- if six.PY2:
- sys.exc_clear()
- else:
- pass #self.assertEqual(sys.exc_info(), (None, None, None))
-
- def check_soure_traceback(self, source_traceback, lineno_delta):
- frame = sys._getframe(1)
- filename = frame.f_code.co_filename
- lineno = frame.f_lineno + lineno_delta
- name = frame.f_code.co_name
- self.assertIsInstance(source_traceback, list)
- self.assertEqual(source_traceback[-1][:3],
- (filename,
- lineno,
- name))
-
-
-@contextlib.contextmanager
-def disable_logger():
- """Context manager to disable asyncio logger.
-
- For example, it can be used to ignore warnings in debug mode.
- """
- old_level = logger.level
- try:
- logger.setLevel(logging.CRITICAL+1)
- yield
- finally:
- logger.setLevel(old_level)
-
-def mock_nonblocking_socket():
- """Create a mock of a non-blocking socket."""
- sock = mock.Mock(socket.socket)
- sock.gettimeout.return_value = 0.0
- return sock
-
-
-def force_legacy_ssl_support():
- return mock.patch('trollius.sslproto._is_sslproto_available',
- return_value=False)
+++ /dev/null
-"""
-Backport of time.monotonic() of Python 3.3 (PEP 418) for Python 2.7.
-
-- time_monotonic(). This clock may or may not be monotonic depending on the
- operating system.
-- time_monotonic_resolution: Resolution of time_monotonic() clock in second
-
-Support Windows, Mac OS X, Linux, FreeBSD, OpenBSD and Solaris, but requires
-the ctypes module.
-"""
-import os
-import sys
-from .log import logger
-from .py33_exceptions import get_error_class
-
-__all__ = ('time_monotonic',)
-
-# default implementation: system clock (non monotonic!)
-from time import time as time_monotonic
-# the worst resolution is 15.6 ms on Windows
-time_monotonic_resolution = 0.050
-
-if os.name == "nt":
- # Windows: use GetTickCount64() or GetTickCount()
- try:
- import ctypes
- from ctypes import windll
- from ctypes.wintypes import DWORD
- except ImportError:
- logger.error("time_monotonic import error", exc_info=True)
- else:
- # GetTickCount64() requires Windows Vista, Server 2008 or later
- if hasattr(windll.kernel32, 'GetTickCount64'):
- ULONGLONG = ctypes.c_uint64
-
- GetTickCount64 = windll.kernel32.GetTickCount64
- GetTickCount64.restype = ULONGLONG
- GetTickCount64.argtypes = ()
-
- def time_monotonic():
- return GetTickCount64() * 1e-3
- time_monotonic_resolution = 1e-3
- else:
- GetTickCount = windll.kernel32.GetTickCount
- GetTickCount.restype = DWORD
- GetTickCount.argtypes = ()
-
- # Detect GetTickCount() integer overflow (32 bits, roll-over after 49.7
- # days). It increases an internal epoch (reference time) by 2^32 each
- # time that an overflow is detected. The epoch is stored in the
- # process-local state and so the value of time_monotonic() may be
- # different in two Python processes running for more than 49 days.
- def time_monotonic():
- ticks = GetTickCount()
- if ticks < time_monotonic.last:
- # Integer overflow detected
- time_monotonic.delta += 2**32
- time_monotonic.last = ticks
- return (ticks + time_monotonic.delta) * 1e-3
- time_monotonic.last = 0
- time_monotonic.delta = 0
- time_monotonic_resolution = 1e-3
-
-elif sys.platform == 'darwin':
- # Mac OS X: use mach_absolute_time() and mach_timebase_info()
- try:
- import ctypes
- import ctypes.util
- libc_name = ctypes.util.find_library('c')
- except ImportError:
- logger.error("time_monotonic import error", exc_info=True)
- libc_name = None
- if libc_name:
- libc = ctypes.CDLL(libc_name, use_errno=True)
-
- mach_absolute_time = libc.mach_absolute_time
- mach_absolute_time.argtypes = ()
- mach_absolute_time.restype = ctypes.c_uint64
-
- class mach_timebase_info_data_t(ctypes.Structure):
- _fields_ = (
- ('numer', ctypes.c_uint32),
- ('denom', ctypes.c_uint32),
- )
- mach_timebase_info_data_p = ctypes.POINTER(mach_timebase_info_data_t)
-
- mach_timebase_info = libc.mach_timebase_info
- mach_timebase_info.argtypes = (mach_timebase_info_data_p,)
- mach_timebase_info.restype = ctypes.c_int
-
- def time_monotonic():
- return mach_absolute_time() * time_monotonic.factor
-
- timebase = mach_timebase_info_data_t()
- mach_timebase_info(ctypes.byref(timebase))
- time_monotonic.factor = float(timebase.numer) / timebase.denom * 1e-9
- time_monotonic_resolution = time_monotonic.factor
- del timebase
-
-elif sys.platform.startswith(("linux", "freebsd", "openbsd", "sunos")):
- # Linux, FreeBSD, OpenBSD: use clock_gettime(CLOCK_MONOTONIC)
- # Solaris: use clock_gettime(CLOCK_HIGHRES)
-
- library = None
- try:
- import ctypes
- import ctypes.util
- except ImportError:
- logger.error("time_monotonic import error", exc_info=True)
- libraries = ()
- else:
- if sys.platform.startswith(("freebsd", "openbsd")):
- libraries = ('c',)
- elif sys.platform.startswith("linux"):
- # Linux: in glibc 2.17+, clock_gettime() is provided by the libc,
- # on older versions, it is provided by librt
- libraries = ('c', 'rt')
- else:
- # Solaris
- libraries = ('rt',)
-
- for name in libraries:
- filename = ctypes.util.find_library(name)
- if not filename:
- continue
- library = ctypes.CDLL(filename, use_errno=True)
- if not hasattr(library, 'clock_gettime'):
- library = None
-
- if library is not None:
- if sys.platform.startswith("openbsd"):
- import platform
- release = platform.release()
- release = tuple(map(int, release.split('.')))
- if release >= (5, 5):
- time_t = ctypes.c_int64
- else:
- time_t = ctypes.c_int32
- else:
- time_t = ctypes.c_long
- clockid_t = ctypes.c_int
-
- class timespec(ctypes.Structure):
- _fields_ = (
- ('tv_sec', time_t),
- ('tv_nsec', ctypes.c_long),
- )
- timespec_p = ctypes.POINTER(timespec)
-
- clock_gettime = library.clock_gettime
- clock_gettime.argtypes = (clockid_t, timespec_p)
- clock_gettime.restype = ctypes.c_int
-
- def ctypes_oserror():
- errno = ctypes.get_errno()
- message = os.strerror(errno)
- error_class = get_error_class(errno, OSError)
- return error_class(errno, message)
-
- def time_monotonic():
- ts = timespec()
- err = clock_gettime(time_monotonic.clk_id, ctypes.byref(ts))
- if err:
- raise ctypes_oserror()
- return ts.tv_sec + ts.tv_nsec * 1e-9
-
- if sys.platform.startswith("linux"):
- time_monotonic.clk_id = 1 # CLOCK_MONOTONIC
- elif sys.platform.startswith("freebsd"):
- time_monotonic.clk_id = 4 # CLOCK_MONOTONIC
- elif sys.platform.startswith("openbsd"):
- time_monotonic.clk_id = 3 # CLOCK_MONOTONIC
- else:
- assert sys.platform.startswith("sunos")
- time_monotonic.clk_id = 4 # CLOCK_HIGHRES
-
- def get_resolution():
- _clock_getres = library.clock_getres
- _clock_getres.argtypes = (clockid_t, timespec_p)
- _clock_getres.restype = ctypes.c_int
-
- ts = timespec()
- err = _clock_getres(time_monotonic.clk_id, ctypes.byref(ts))
- if err:
- raise ctypes_oserror()
- return ts.tv_sec + ts.tv_nsec * 1e-9
- time_monotonic_resolution = get_resolution()
- del get_resolution
-
-else:
- logger.error("time_monotonic: unspported platform %r", sys.platform)
-
+++ /dev/null
-"""Abstract Transport class."""
-
-from trollius import compat
-
-__all__ = ['BaseTransport', 'ReadTransport', 'WriteTransport',
- 'Transport', 'DatagramTransport', 'SubprocessTransport',
- ]
-
-
-class BaseTransport(object):
- """Base class for transports."""
-
- def __init__(self, extra=None):
- if extra is None:
- extra = {}
- self._extra = extra
-
- def get_extra_info(self, name, default=None):
- """Get optional transport information."""
- return self._extra.get(name, default)
-
- def close(self):
- """Close the transport.
-
- Buffered data will be flushed asynchronously. No more data
- will be received. After all buffered data is flushed, the
- protocol's connection_lost() method will (eventually) called
- with None as its argument.
- """
- raise NotImplementedError
-
-
-class ReadTransport(BaseTransport):
- """Interface for read-only transports."""
-
- def pause_reading(self):
- """Pause the receiving end.
-
- No data will be passed to the protocol's data_received()
- method until resume_reading() is called.
- """
- raise NotImplementedError
-
- def resume_reading(self):
- """Resume the receiving end.
-
- Data received will once again be passed to the protocol's
- data_received() method.
- """
- raise NotImplementedError
-
-
-class WriteTransport(BaseTransport):
- """Interface for write-only transports."""
-
- def set_write_buffer_limits(self, high=None, low=None):
- """Set the high- and low-water limits for write flow control.
-
- These two values control when to call the protocol's
- pause_writing() and resume_writing() methods. If specified,
- the low-water limit must be less than or equal to the
- high-water limit. Neither value can be negative.
-
- The defaults are implementation-specific. If only the
- high-water limit is given, the low-water limit defaults to a
- implementation-specific value less than or equal to the
- high-water limit. Setting high to zero forces low to zero as
- well, and causes pause_writing() to be called whenever the
- buffer becomes non-empty. Setting low to zero causes
- resume_writing() to be called only once the buffer is empty.
- Use of zero for either limit is generally sub-optimal as it
- reduces opportunities for doing I/O and computation
- concurrently.
- """
- raise NotImplementedError
-
- def get_write_buffer_size(self):
- """Return the current size of the write buffer."""
- raise NotImplementedError
-
- def write(self, data):
- """Write some data bytes to the transport.
-
- This does not block; it buffers the data and arranges for it
- to be sent out asynchronously.
- """
- raise NotImplementedError
-
- def writelines(self, list_of_data):
- """Write a list (or any iterable) of data bytes to the transport.
-
- The default implementation concatenates the arguments and
- calls write() on the result.
- """
- data = compat.flatten_list_bytes(list_of_data)
- self.write(data)
-
- def write_eof(self):
- """Close the write end after flushing buffered data.
-
- (This is like typing ^D into a UNIX program reading from stdin.)
-
- Data may still be received.
- """
- raise NotImplementedError
-
- def can_write_eof(self):
- """Return True if this transport supports write_eof(), False if not."""
- raise NotImplementedError
-
- def abort(self):
- """Close the transport immediately.
-
- Buffered data will be lost. No more data will be received.
- The protocol's connection_lost() method will (eventually) be
- called with None as its argument.
- """
- raise NotImplementedError
-
-
-class Transport(ReadTransport, WriteTransport):
- """Interface representing a bidirectional transport.
-
- There may be several implementations, but typically, the user does
- not implement new transports; rather, the platform provides some
- useful transports that are implemented using the platform's best
- practices.
-
- The user never instantiates a transport directly; they call a
- utility function, passing it a protocol factory and other
- information necessary to create the transport and protocol. (E.g.
- EventLoop.create_connection() or EventLoop.create_server().)
-
- The utility function will asynchronously create a transport and a
- protocol and hook them up by calling the protocol's
- connection_made() method, passing it the transport.
-
- The implementation here raises NotImplemented for every method
- except writelines(), which calls write() in a loop.
- """
-
-
-class DatagramTransport(BaseTransport):
- """Interface for datagram (UDP) transports."""
-
- def sendto(self, data, addr=None):
- """Send data to the transport.
-
- This does not block; it buffers the data and arranges for it
- to be sent out asynchronously.
- addr is target socket address.
- If addr is None use target address pointed on transport creation.
- """
- raise NotImplementedError
-
- def abort(self):
- """Close the transport immediately.
-
- Buffered data will be lost. No more data will be received.
- The protocol's connection_lost() method will (eventually) be
- called with None as its argument.
- """
- raise NotImplementedError
-
-
-class SubprocessTransport(BaseTransport):
-
- def get_pid(self):
- """Get subprocess id."""
- raise NotImplementedError
-
- def get_returncode(self):
- """Get subprocess returncode.
-
- See also
- http://docs.python.org/3/library/subprocess#subprocess.Popen.returncode
- """
- raise NotImplementedError
-
- def get_pipe_transport(self, fd):
- """Get transport for pipe with number fd."""
- raise NotImplementedError
-
- def send_signal(self, signal):
- """Send signal to subprocess.
-
- See also:
- docs.python.org/3/library/subprocess#subprocess.Popen.send_signal
- """
- raise NotImplementedError
-
- def terminate(self):
- """Stop the subprocess.
-
- Alias for close() method.
-
- On Posix OSs the method sends SIGTERM to the subprocess.
- On Windows the Win32 API function TerminateProcess()
- is called to stop the subprocess.
-
- See also:
- http://docs.python.org/3/library/subprocess#subprocess.Popen.terminate
- """
- raise NotImplementedError
-
- def kill(self):
- """Kill the subprocess.
-
- On Posix OSs the function sends SIGKILL to the subprocess.
- On Windows kill() is an alias for terminate().
-
- See also:
- http://docs.python.org/3/library/subprocess#subprocess.Popen.kill
- """
- raise NotImplementedError
-
-
-class _FlowControlMixin(Transport):
- """All the logic for (write) flow control in a mix-in base class.
-
- The subclass must implement get_write_buffer_size(). It must call
- _maybe_pause_protocol() whenever the write buffer size increases,
- and _maybe_resume_protocol() whenever it decreases. It may also
- override set_write_buffer_limits() (e.g. to specify different
- defaults).
-
- The subclass constructor must call super(Class, self).__init__(extra). This
- will call set_write_buffer_limits().
-
- The user may call set_write_buffer_limits() and
- get_write_buffer_size(), and their protocol's pause_writing() and
- resume_writing() may be called.
- """
-
- def __init__(self, extra=None, loop=None):
- super(_FlowControlMixin, self).__init__(extra)
- assert loop is not None
- self._loop = loop
- self._protocol_paused = False
- self._set_write_buffer_limits()
-
- def _maybe_pause_protocol(self):
- size = self.get_write_buffer_size()
- if size <= self._high_water:
- return
- if not self._protocol_paused:
- self._protocol_paused = True
- try:
- self._protocol.pause_writing()
- except Exception as exc:
- self._loop.call_exception_handler({
- 'message': 'protocol.pause_writing() failed',
- 'exception': exc,
- 'transport': self,
- 'protocol': self._protocol,
- })
-
- def _maybe_resume_protocol(self):
- if (self._protocol_paused and
- self.get_write_buffer_size() <= self._low_water):
- self._protocol_paused = False
- try:
- self._protocol.resume_writing()
- except Exception as exc:
- self._loop.call_exception_handler({
- 'message': 'protocol.resume_writing() failed',
- 'exception': exc,
- 'transport': self,
- 'protocol': self._protocol,
- })
-
- def get_write_buffer_limits(self):
- return (self._low_water, self._high_water)
-
- def _set_write_buffer_limits(self, high=None, low=None):
- if high is None:
- if low is None:
- high = 64*1024
- else:
- high = 4*low
- if low is None:
- low = high // 4
- if not high >= low >= 0:
- raise ValueError('high (%r) must be >= low (%r) must be >= 0' %
- (high, low))
- self._high_water = high
- self._low_water = low
-
- def set_write_buffer_limits(self, high=None, low=None):
- self._set_write_buffer_limits(high=high, low=low)
- self._maybe_pause_protocol()
-
- def get_write_buffer_size(self):
- raise NotImplementedError
+++ /dev/null
-"""Selector event loop for Unix with signal handling."""
-from __future__ import absolute_import
-
-import errno
-import os
-import signal
-import socket
-import stat
-import subprocess
-import sys
-import threading
-import warnings
-
-
-from . import base_events
-from . import base_subprocess
-from . import compat
-from . import constants
-from . import coroutines
-from . import events
-from . import futures
-from . import selector_events
-from . import selectors
-from . import transports
-from .compat import flatten_bytes
-from .coroutines import coroutine, From, Return
-from .log import logger
-from .py33_exceptions import (
- reraise, wrap_error,
- BlockingIOError, BrokenPipeError, ConnectionResetError,
- InterruptedError, ChildProcessError)
-
-
-__all__ = ['SelectorEventLoop',
- 'AbstractChildWatcher', 'SafeChildWatcher',
- 'FastChildWatcher', 'DefaultEventLoopPolicy',
- ]
-
-if sys.platform == 'win32': # pragma: no cover
- raise ImportError('Signals are not really supported on Windows')
-
-
-if compat.PY33:
- def _sighandler_noop(signum, frame):
- """Dummy signal handler."""
- pass
-
-
-class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop):
- """Unix event loop.
-
- Adds signal handling and UNIX Domain Socket support to SelectorEventLoop.
- """
-
- def __init__(self, selector=None):
- super(_UnixSelectorEventLoop, self).__init__(selector)
- self._signal_handlers = {}
-
- def _socketpair(self):
- return socket.socketpair()
-
- def close(self):
- super(_UnixSelectorEventLoop, self).close()
- for sig in list(self._signal_handlers):
- self.remove_signal_handler(sig)
-
- # On Python <= 3.2, the C signal handler of Python writes a null byte into
- # the wakeup file descriptor. We cannot retrieve the signal numbers from
- # the file descriptor.
- if compat.PY33:
- def _process_self_data(self, data):
- for signum in data:
- if not signum:
- # ignore null bytes written by _write_to_self()
- continue
- self._handle_signal(signum)
-
- def add_signal_handler(self, sig, callback, *args):
- """Add a handler for a signal. UNIX only.
-
- Raise ValueError if the signal number is invalid or uncatchable.
- Raise RuntimeError if there is a problem setting up the handler.
- """
- if (coroutines.iscoroutine(callback)
- or coroutines.iscoroutinefunction(callback)):
- raise TypeError("coroutines cannot be used "
- "with add_signal_handler()")
- self._check_signal(sig)
- self._check_closed()
- try:
- # set_wakeup_fd() raises ValueError if this is not the
- # main thread. By calling it early we ensure that an
- # event loop running in another thread cannot add a signal
- # handler.
- signal.set_wakeup_fd(self._csock.fileno())
- except (ValueError, OSError) as exc:
- raise RuntimeError(str(exc))
-
- handle = events.Handle(callback, args, self)
- self._signal_handlers[sig] = handle
-
- try:
- if compat.PY33:
- # On Python 3.3 and newer, the C signal handler writes the
- # signal number into the wakeup file descriptor and then calls
- # Py_AddPendingCall() to schedule the Python signal handler.
- #
- # Register a dummy signal handler to ask Python to write the
- # signal number into the wakup file descriptor.
- # _process_self_data() will read signal numbers from this file
- # descriptor to handle signals.
- signal.signal(sig, _sighandler_noop)
- else:
- # On Python 3.2 and older, the C signal handler first calls
- # Py_AddPendingCall() to schedule the Python signal handler,
- # and then write a null byte into the wakeup file descriptor.
- signal.signal(sig, self._handle_signal)
-
- # Set SA_RESTART to limit EINTR occurrences.
- signal.siginterrupt(sig, False)
- except (RuntimeError, OSError) as exc:
- # On Python 2, signal.signal(signal.SIGKILL, signal.SIG_IGN) raises
- # RuntimeError(22, 'Invalid argument'). On Python 3,
- # OSError(22, 'Invalid argument') is raised instead.
- exc_type, exc_value, tb = sys.exc_info()
-
- del self._signal_handlers[sig]
- if not self._signal_handlers:
- try:
- signal.set_wakeup_fd(-1)
- except (ValueError, OSError) as nexc:
- logger.info('set_wakeup_fd(-1) failed: %s', nexc)
-
- if isinstance(exc, RuntimeError) or exc.errno == errno.EINVAL:
- raise RuntimeError('sig {0} cannot be caught'.format(sig))
- else:
- reraise(exc_type, exc_value, tb)
-
- def _handle_signal(self, sig, frame=None):
- """Internal helper that is the actual signal handler."""
- handle = self._signal_handlers.get(sig)
- if handle is None:
- return # Assume it's some race condition.
- if handle._cancelled:
- self.remove_signal_handler(sig) # Remove it properly.
- else:
- self._add_callback_signalsafe(handle)
-
- def remove_signal_handler(self, sig):
- """Remove a handler for a signal. UNIX only.
-
- Return True if a signal handler was removed, False if not.
- """
- self._check_signal(sig)
- try:
- del self._signal_handlers[sig]
- except KeyError:
- return False
-
- if sig == signal.SIGINT:
- handler = signal.default_int_handler
- else:
- handler = signal.SIG_DFL
-
- try:
- signal.signal(sig, handler)
- except OSError as exc:
- if exc.errno == errno.EINVAL:
- raise RuntimeError('sig {0} cannot be caught'.format(sig))
- else:
- raise
-
- if not self._signal_handlers:
- try:
- signal.set_wakeup_fd(-1)
- except (ValueError, OSError) as exc:
- logger.info('set_wakeup_fd(-1) failed: %s', exc)
-
- return True
-
- def _check_signal(self, sig):
- """Internal helper to validate a signal.
-
- Raise ValueError if the signal number is invalid or uncatchable.
- Raise RuntimeError if there is a problem setting up the handler.
- """
- if not isinstance(sig, int):
- raise TypeError('sig must be an int, not {0!r}'.format(sig))
-
- if not (1 <= sig < signal.NSIG):
- raise ValueError(
- 'sig {0} out of range(1, {1})'.format(sig, signal.NSIG))
-
- def _make_read_pipe_transport(self, pipe, protocol, waiter=None,
- extra=None):
- return _UnixReadPipeTransport(self, pipe, protocol, waiter, extra)
-
- def _make_write_pipe_transport(self, pipe, protocol, waiter=None,
- extra=None):
- return _UnixWritePipeTransport(self, pipe, protocol, waiter, extra)
-
- @coroutine
- def _make_subprocess_transport(self, protocol, args, shell,
- stdin, stdout, stderr, bufsize,
- extra=None, **kwargs):
- with events.get_child_watcher() as watcher:
- waiter = futures.Future(loop=self)
- transp = _UnixSubprocessTransport(self, protocol, args, shell,
- stdin, stdout, stderr, bufsize,
- waiter=waiter, extra=extra,
- **kwargs)
-
- watcher.add_child_handler(transp.get_pid(),
- self._child_watcher_callback, transp)
- try:
- yield From(waiter)
- except Exception as exc:
- # Workaround CPython bug #23353: using yield/yield-from in an
- # except block of a generator doesn't clear properly
- # sys.exc_info()
- err = exc
- else:
- err = None
-
- if err is not None:
- transp.close()
- yield From(transp._wait())
- raise err
-
- raise Return(transp)
-
- def _child_watcher_callback(self, pid, returncode, transp):
- self.call_soon_threadsafe(transp._process_exited, returncode)
-
- @coroutine
- def create_unix_connection(self, protocol_factory, path,
- ssl=None, sock=None,
- server_hostname=None):
- assert server_hostname is None or isinstance(server_hostname, str)
- if ssl:
- if server_hostname is None:
- raise ValueError(
- 'you have to pass server_hostname when using ssl')
- else:
- if server_hostname is not None:
- raise ValueError('server_hostname is only meaningful with ssl')
-
- if path is not None:
- if sock is not None:
- raise ValueError(
- 'path and sock can not be specified at the same time')
-
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
- try:
- sock.setblocking(False)
- yield From(self.sock_connect(sock, path))
- except:
- sock.close()
- raise
-
- else:
- if sock is None:
- raise ValueError('no path and sock were specified')
- sock.setblocking(False)
-
- transport, protocol = yield From(self._create_connection_transport(
- sock, protocol_factory, ssl, server_hostname))
- raise Return(transport, protocol)
-
- @coroutine
- def create_unix_server(self, protocol_factory, path=None,
- sock=None, backlog=100, ssl=None):
- if isinstance(ssl, bool):
- raise TypeError('ssl argument must be an SSLContext or None')
-
- if path is not None:
- if sock is not None:
- raise ValueError(
- 'path and sock can not be specified at the same time')
-
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-
- try:
- sock.bind(path)
- except socket.error as exc:
- sock.close()
- if exc.errno == errno.EADDRINUSE:
- # Let's improve the error message by adding
- # with what exact address it occurs.
- msg = 'Address {0!r} is already in use'.format(path)
- raise OSError(errno.EADDRINUSE, msg)
- else:
- raise
- except:
- sock.close()
- raise
- else:
- if sock is None:
- raise ValueError(
- 'path was not specified, and no sock specified')
-
- if sock.family != socket.AF_UNIX:
- raise ValueError(
- 'A UNIX Domain Socket was expected, got {0!r}'.format(sock))
-
- server = base_events.Server(self, [sock])
- sock.listen(backlog)
- sock.setblocking(False)
- self._start_serving(protocol_factory, sock, ssl, server)
- return server
-
-
-if hasattr(os, 'set_blocking'):
- # Python 3.5 and newer
- def _set_nonblocking(fd):
- os.set_blocking(fd, False)
-else:
- import fcntl
-
- def _set_nonblocking(fd):
- flags = fcntl.fcntl(fd, fcntl.F_GETFL)
- flags = flags | os.O_NONBLOCK
- fcntl.fcntl(fd, fcntl.F_SETFL, flags)
-
-
-class _UnixReadPipeTransport(transports.ReadTransport):
-
- max_size = 256 * 1024 # max bytes we read in one event loop iteration
-
- def __init__(self, loop, pipe, protocol, waiter=None, extra=None):
- super(_UnixReadPipeTransport, self).__init__(extra)
- self._extra['pipe'] = pipe
- self._loop = loop
- self._pipe = pipe
- self._fileno = pipe.fileno()
- mode = os.fstat(self._fileno).st_mode
- if not (stat.S_ISFIFO(mode) or
- stat.S_ISSOCK(mode) or
- stat.S_ISCHR(mode)):
- raise ValueError("Pipe transport is for pipes/sockets only.")
- _set_nonblocking(self._fileno)
- self._protocol = protocol
- self._closing = False
- self._loop.call_soon(self._protocol.connection_made, self)
- # only start reading when connection_made() has been called
- self._loop.call_soon(self._loop.add_reader,
- self._fileno, self._read_ready)
- if waiter is not None:
- # only wake up the waiter when connection_made() has been called
- self._loop.call_soon(waiter._set_result_unless_cancelled, None)
-
- def __repr__(self):
- info = [self.__class__.__name__]
- if self._pipe is None:
- info.append('closed')
- elif self._closing:
- info.append('closing')
- info.append('fd=%s' % self._fileno)
- if self._pipe is not None:
- polling = selector_events._test_selector_event(
- self._loop._selector,
- self._fileno, selectors.EVENT_READ)
- if polling:
- info.append('polling')
- else:
- info.append('idle')
- else:
- info.append('closed')
- return '<%s>' % ' '.join(info)
-
- def _read_ready(self):
- try:
- data = wrap_error(os.read, self._fileno, self.max_size)
- except (BlockingIOError, InterruptedError):
- pass
- except OSError as exc:
- self._fatal_error(exc, 'Fatal read error on pipe transport')
- else:
- if data:
- self._protocol.data_received(data)
- else:
- if self._loop.get_debug():
- logger.info("%r was closed by peer", self)
- self._closing = True
- self._loop.remove_reader(self._fileno)
- self._loop.call_soon(self._protocol.eof_received)
- self._loop.call_soon(self._call_connection_lost, None)
-
- def pause_reading(self):
- self._loop.remove_reader(self._fileno)
-
- def resume_reading(self):
- self._loop.add_reader(self._fileno, self._read_ready)
-
- def close(self):
- if not self._closing:
- self._close(None)
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._pipe is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning)
- self._pipe.close()
-
- def _fatal_error(self, exc, message='Fatal error on pipe transport'):
- # should be called by exception handler only
- if (isinstance(exc, OSError) and exc.errno == errno.EIO):
- if self._loop.get_debug():
- logger.debug("%r: %s", self, message, exc_info=True)
- else:
- self._loop.call_exception_handler({
- 'message': message,
- 'exception': exc,
- 'transport': self,
- 'protocol': self._protocol,
- })
- self._close(exc)
-
- def _close(self, exc):
- self._closing = True
- self._loop.remove_reader(self._fileno)
- self._loop.call_soon(self._call_connection_lost, exc)
-
- def _call_connection_lost(self, exc):
- try:
- self._protocol.connection_lost(exc)
- finally:
- self._pipe.close()
- self._pipe = None
- self._protocol = None
- self._loop = None
-
-
-class _UnixWritePipeTransport(transports._FlowControlMixin,
- transports.WriteTransport):
-
- def __init__(self, loop, pipe, protocol, waiter=None, extra=None):
- super(_UnixWritePipeTransport, self).__init__(extra, loop)
- self._extra['pipe'] = pipe
- self._pipe = pipe
- self._fileno = pipe.fileno()
- mode = os.fstat(self._fileno).st_mode
- is_socket = stat.S_ISSOCK(mode)
- if not (is_socket or
- stat.S_ISFIFO(mode) or
- stat.S_ISCHR(mode)):
- raise ValueError("Pipe transport is only for "
- "pipes, sockets and character devices")
- _set_nonblocking(self._fileno)
- self._protocol = protocol
- self._buffer = []
- self._conn_lost = 0
- self._closing = False # Set when close() or write_eof() called.
-
- self._loop.call_soon(self._protocol.connection_made, self)
-
- # On AIX, the reader trick (to be notified when the read end of the
- # socket is closed) only works for sockets. On other platforms it
- # works for pipes and sockets. (Exception: OS X 10.4? Issue #19294.)
- if is_socket or not sys.platform.startswith("aix"):
- # only start reading when connection_made() has been called
- self._loop.call_soon(self._loop.add_reader,
- self._fileno, self._read_ready)
-
- if waiter is not None:
- # only wake up the waiter when connection_made() has been called
- self._loop.call_soon(waiter._set_result_unless_cancelled, None)
-
- def __repr__(self):
- info = [self.__class__.__name__]
- if self._pipe is None:
- info.append('closed')
- elif self._closing:
- info.append('closing')
- info.append('fd=%s' % self._fileno)
- if self._pipe is not None:
- polling = selector_events._test_selector_event(
- self._loop._selector,
- self._fileno, selectors.EVENT_WRITE)
- if polling:
- info.append('polling')
- else:
- info.append('idle')
-
- bufsize = self.get_write_buffer_size()
- info.append('bufsize=%s' % bufsize)
- else:
- info.append('closed')
- return '<%s>' % ' '.join(info)
-
- def get_write_buffer_size(self):
- return sum(len(data) for data in self._buffer)
-
- def _read_ready(self):
- # Pipe was closed by peer.
- if self._loop.get_debug():
- logger.info("%r was closed by peer", self)
- if self._buffer:
- self._close(BrokenPipeError())
- else:
- self._close()
-
- def write(self, data):
- data = flatten_bytes(data)
- if not data:
- return
-
- if self._conn_lost or self._closing:
- if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
- logger.warning('pipe closed by peer or '
- 'os.write(pipe, data) raised exception.')
- self._conn_lost += 1
- return
-
- if not self._buffer:
- # Attempt to send it right away first.
- try:
- n = wrap_error(os.write, self._fileno, data)
- except (BlockingIOError, InterruptedError):
- n = 0
- except Exception as exc:
- self._conn_lost += 1
- self._fatal_error(exc, 'Fatal write error on pipe transport')
- return
- if n == len(data):
- return
- elif n > 0:
- data = data[n:]
- self._loop.add_writer(self._fileno, self._write_ready)
-
- self._buffer.append(data)
- self._maybe_pause_protocol()
-
- def _write_ready(self):
- data = b''.join(self._buffer)
- assert data, 'Data should not be empty'
-
- del self._buffer[:]
- try:
- n = wrap_error(os.write, self._fileno, data)
- except (BlockingIOError, InterruptedError):
- self._buffer.append(data)
- except Exception as exc:
- self._conn_lost += 1
- # Remove writer here, _fatal_error() doesn't it
- # because _buffer is empty.
- self._loop.remove_writer(self._fileno)
- self._fatal_error(exc, 'Fatal write error on pipe transport')
- else:
- if n == len(data):
- self._loop.remove_writer(self._fileno)
- self._maybe_resume_protocol() # May append to buffer.
- if not self._buffer and self._closing:
- self._loop.remove_reader(self._fileno)
- self._call_connection_lost(None)
- return
- elif n > 0:
- data = data[n:]
-
- self._buffer.append(data) # Try again later.
-
- def can_write_eof(self):
- return True
-
- def write_eof(self):
- if self._closing:
- return
- assert self._pipe
- self._closing = True
- if not self._buffer:
- self._loop.remove_reader(self._fileno)
- self._loop.call_soon(self._call_connection_lost, None)
-
- def close(self):
- if self._pipe is not None and not self._closing:
- # write_eof is all what we needed to close the write pipe
- self.write_eof()
-
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._pipe is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning)
- self._pipe.close()
-
- def abort(self):
- self._close(None)
-
- def _fatal_error(self, exc, message='Fatal error on pipe transport'):
- # should be called by exception handler only
- if isinstance(exc, (BrokenPipeError, ConnectionResetError)):
- if self._loop.get_debug():
- logger.debug("%r: %s", self, message, exc_info=True)
- else:
- self._loop.call_exception_handler({
- 'message': message,
- 'exception': exc,
- 'transport': self,
- 'protocol': self._protocol,
- })
- self._close(exc)
-
- def _close(self, exc=None):
- self._closing = True
- if self._buffer:
- self._loop.remove_writer(self._fileno)
- del self._buffer[:]
- self._loop.remove_reader(self._fileno)
- self._loop.call_soon(self._call_connection_lost, exc)
-
- def _call_connection_lost(self, exc):
- try:
- self._protocol.connection_lost(exc)
- finally:
- self._pipe.close()
- self._pipe = None
- self._protocol = None
- self._loop = None
-
-
-if hasattr(os, 'set_inheritable'):
- # Python 3.4 and newer
- _set_inheritable = os.set_inheritable
-else:
- import fcntl
-
- def _set_inheritable(fd, inheritable):
- cloexec_flag = getattr(fcntl, 'FD_CLOEXEC', 1)
-
- old = fcntl.fcntl(fd, fcntl.F_GETFD)
- if not inheritable:
- fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
- else:
- fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag)
-
-
-class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport):
-
- def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
- stdin_w = None
- if stdin == subprocess.PIPE:
- # Use a socket pair for stdin, since not all platforms
- # support selecting read events on the write end of a
- # socket (which we use in order to detect closing of the
- # other end). Notably this is needed on AIX, and works
- # just fine on other platforms.
- stdin, stdin_w = self._loop._socketpair()
-
- # Mark the write end of the stdin pipe as non-inheritable,
- # needed by close_fds=False on Python 3.3 and older
- # (Python 3.4 implements the PEP 446, socketpair returns
- # non-inheritable sockets)
- _set_inheritable(stdin_w.fileno(), False)
- self._proc = subprocess.Popen(
- args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr,
- universal_newlines=False, bufsize=bufsize, **kwargs)
- if stdin_w is not None:
- # Retrieve the file descriptor from stdin_w, stdin_w should not
- # "own" the file descriptor anymore: closing stdin_fd file
- # descriptor must close immediatly the file
- stdin.close()
- if hasattr(stdin_w, 'detach'):
- stdin_fd = stdin_w.detach()
- self._proc.stdin = os.fdopen(stdin_fd, 'wb', bufsize)
- else:
- stdin_dup = os.dup(stdin_w.fileno())
- stdin_w.close()
- self._proc.stdin = os.fdopen(stdin_dup, 'wb', bufsize)
-
-
-class AbstractChildWatcher(object):
- """Abstract base class for monitoring child processes.
-
- Objects derived from this class monitor a collection of subprocesses and
- report their termination or interruption by a signal.
-
- New callbacks are registered with .add_child_handler(). Starting a new
- process must be done within a 'with' block to allow the watcher to suspend
- its activity until the new process if fully registered (this is needed to
- prevent a race condition in some implementations).
-
- Example:
- with watcher:
- proc = subprocess.Popen("sleep 1")
- watcher.add_child_handler(proc.pid, callback)
-
- Notes:
- Implementations of this class must be thread-safe.
-
- Since child watcher objects may catch the SIGCHLD signal and call
- waitpid(-1), there should be only one active object per process.
- """
-
- def add_child_handler(self, pid, callback, *args):
- """Register a new child handler.
-
- Arrange for callback(pid, returncode, *args) to be called when
- process 'pid' terminates. Specifying another callback for the same
- process replaces the previous handler.
-
- Note: callback() must be thread-safe.
- """
- raise NotImplementedError()
-
- def remove_child_handler(self, pid):
- """Removes the handler for process 'pid'.
-
- The function returns True if the handler was successfully removed,
- False if there was nothing to remove."""
-
- raise NotImplementedError()
-
- def attach_loop(self, loop):
- """Attach the watcher to an event loop.
-
- If the watcher was previously attached to an event loop, then it is
- first detached before attaching to the new loop.
-
- Note: loop may be None.
- """
- raise NotImplementedError()
-
- def close(self):
- """Close the watcher.
-
- This must be called to make sure that any underlying resource is freed.
- """
- raise NotImplementedError()
-
- def __enter__(self):
- """Enter the watcher's context and allow starting new processes
-
- This function must return self"""
- raise NotImplementedError()
-
- def __exit__(self, a, b, c):
- """Exit the watcher's context"""
- raise NotImplementedError()
-
-
-class BaseChildWatcher(AbstractChildWatcher):
-
- def __init__(self):
- self._loop = None
-
- def close(self):
- self.attach_loop(None)
-
- def _do_waitpid(self, expected_pid):
- raise NotImplementedError()
-
- def _do_waitpid_all(self):
- raise NotImplementedError()
-
- def attach_loop(self, loop):
- assert loop is None or isinstance(loop, events.AbstractEventLoop)
-
- if self._loop is not None:
- self._loop.remove_signal_handler(signal.SIGCHLD)
-
- self._loop = loop
- if loop is not None:
- loop.add_signal_handler(signal.SIGCHLD, self._sig_chld)
-
- # Prevent a race condition in case a child terminated
- # during the switch.
- self._do_waitpid_all()
-
- def _sig_chld(self):
- try:
- self._do_waitpid_all()
- except Exception as exc:
- # self._loop should always be available here
- # as '_sig_chld' is added as a signal handler
- # in 'attach_loop'
- self._loop.call_exception_handler({
- 'message': 'Unknown exception in SIGCHLD handler',
- 'exception': exc,
- })
-
- def _compute_returncode(self, status):
- if os.WIFSIGNALED(status):
- # The child process died because of a signal.
- return -os.WTERMSIG(status)
- elif os.WIFEXITED(status):
- # The child process exited (e.g sys.exit()).
- return os.WEXITSTATUS(status)
- else:
- # The child exited, but we don't understand its status.
- # This shouldn't happen, but if it does, let's just
- # return that status; perhaps that helps debug it.
- return status
-
-
-class SafeChildWatcher(BaseChildWatcher):
- """'Safe' child watcher implementation.
-
- This implementation avoids disrupting other code spawning processes by
- polling explicitly each process in the SIGCHLD handler instead of calling
- os.waitpid(-1).
-
- This is a safe solution but it has a significant overhead when handling a
- big number of children (O(n) each time SIGCHLD is raised)
- """
-
- def __init__(self):
- super(SafeChildWatcher, self).__init__()
- self._callbacks = {}
-
- def close(self):
- self._callbacks.clear()
- super(SafeChildWatcher, self).close()
-
- def __enter__(self):
- return self
-
- def __exit__(self, a, b, c):
- pass
-
- def add_child_handler(self, pid, callback, *args):
- self._callbacks[pid] = (callback, args)
-
- # Prevent a race condition in case the child is already terminated.
- self._do_waitpid(pid)
-
- def remove_child_handler(self, pid):
- try:
- del self._callbacks[pid]
- return True
- except KeyError:
- return False
-
- def _do_waitpid_all(self):
-
- for pid in list(self._callbacks):
- self._do_waitpid(pid)
-
- def _do_waitpid(self, expected_pid):
- assert expected_pid > 0
-
- try:
- pid, status = os.waitpid(expected_pid, os.WNOHANG)
- except ChildProcessError:
- # The child process is already reaped
- # (may happen if waitpid() is called elsewhere).
- pid = expected_pid
- returncode = 255
- logger.warning(
- "Unknown child process pid %d, will report returncode 255",
- pid)
- else:
- if pid == 0:
- # The child process is still alive.
- return
-
- returncode = self._compute_returncode(status)
- if self._loop.get_debug():
- logger.debug('process %s exited with returncode %s',
- expected_pid, returncode)
-
- try:
- callback, args = self._callbacks.pop(pid)
- except KeyError: # pragma: no cover
- # May happen if .remove_child_handler() is called
- # after os.waitpid() returns.
- if self._loop.get_debug():
- logger.warning("Child watcher got an unexpected pid: %r",
- pid, exc_info=True)
- else:
- callback(pid, returncode, *args)
-
-
-class FastChildWatcher(BaseChildWatcher):
- """'Fast' child watcher implementation.
-
- This implementation reaps every terminated processes by calling
- os.waitpid(-1) directly, possibly breaking other code spawning processes
- and waiting for their termination.
-
- There is no noticeable overhead when handling a big number of children
- (O(1) each time a child terminates).
- """
- def __init__(self):
- super(FastChildWatcher, self).__init__()
- self._callbacks = {}
- self._lock = threading.Lock()
- self._zombies = {}
- self._forks = 0
-
- def close(self):
- self._callbacks.clear()
- self._zombies.clear()
- super(FastChildWatcher, self).close()
-
- def __enter__(self):
- with self._lock:
- self._forks += 1
-
- return self
-
- def __exit__(self, a, b, c):
- with self._lock:
- self._forks -= 1
-
- if self._forks or not self._zombies:
- return
-
- collateral_victims = str(self._zombies)
- self._zombies.clear()
-
- logger.warning(
- "Caught subprocesses termination from unknown pids: %s",
- collateral_victims)
-
- def add_child_handler(self, pid, callback, *args):
- assert self._forks, "Must use the context manager"
- with self._lock:
- try:
- returncode = self._zombies.pop(pid)
- except KeyError:
- # The child is running.
- self._callbacks[pid] = callback, args
- return
-
- # The child is dead already. We can fire the callback.
- callback(pid, returncode, *args)
-
- def remove_child_handler(self, pid):
- try:
- del self._callbacks[pid]
- return True
- except KeyError:
- return False
-
- def _do_waitpid_all(self):
- # Because of signal coalescing, we must keep calling waitpid() as
- # long as we're able to reap a child.
- while True:
- try:
- pid, status = wrap_error(os.waitpid, -1, os.WNOHANG)
- except ChildProcessError:
- # No more child processes exist.
- return
- else:
- if pid == 0:
- # A child process is still alive.
- return
-
- returncode = self._compute_returncode(status)
-
- with self._lock:
- try:
- callback, args = self._callbacks.pop(pid)
- except KeyError:
- # unknown child
- if self._forks:
- # It may not be registered yet.
- self._zombies[pid] = returncode
- if self._loop.get_debug():
- logger.debug('unknown process %s exited '
- 'with returncode %s',
- pid, returncode)
- continue
- callback = None
- else:
- if self._loop.get_debug():
- logger.debug('process %s exited with returncode %s',
- pid, returncode)
-
- if callback is None:
- logger.warning(
- "Caught subprocess termination from unknown pid: "
- "%d -> %d", pid, returncode)
- else:
- callback(pid, returncode, *args)
-
-
-class _UnixDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy):
- """UNIX event loop policy with a watcher for child processes."""
- _loop_factory = _UnixSelectorEventLoop
-
- def __init__(self):
- super(_UnixDefaultEventLoopPolicy, self).__init__()
- self._watcher = None
-
- def _init_watcher(self):
- with events._lock:
- if self._watcher is None: # pragma: no branch
- self._watcher = SafeChildWatcher()
- if isinstance(threading.current_thread(),
- threading._MainThread):
- self._watcher.attach_loop(self._local._loop)
-
- def set_event_loop(self, loop):
- """Set the event loop.
-
- As a side effect, if a child watcher was set before, then calling
- .set_event_loop() from the main thread will call .attach_loop(loop) on
- the child watcher.
- """
-
- super(_UnixDefaultEventLoopPolicy, self).set_event_loop(loop)
-
- if self._watcher is not None and \
- isinstance(threading.current_thread(), threading._MainThread):
- self._watcher.attach_loop(loop)
-
- def get_child_watcher(self):
- """Get the watcher for child processes.
-
- If not yet set, a SafeChildWatcher object is automatically created.
- """
- if self._watcher is None:
- self._init_watcher()
-
- return self._watcher
-
- def set_child_watcher(self, watcher):
- """Set the watcher for child processes."""
-
- assert watcher is None or isinstance(watcher, AbstractChildWatcher)
-
- if self._watcher is not None:
- self._watcher.close()
-
- self._watcher = watcher
-
-SelectorEventLoop = _UnixSelectorEventLoop
-DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy
+++ /dev/null
-"""Selector and proactor event loops for Windows."""
-
-import errno
-import math
-import socket
-import struct
-import weakref
-
-from . import events
-from . import base_subprocess
-from . import futures
-from . import proactor_events
-from . import py33_winapi as _winapi
-from . import selector_events
-from . import tasks
-from . import windows_utils
-from . import _overlapped
-from .coroutines import coroutine, From, Return
-from .log import logger
-from .py33_exceptions import wrap_error, BrokenPipeError, ConnectionResetError
-
-
-__all__ = ['SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor',
- 'DefaultEventLoopPolicy',
- ]
-
-
-NULL = 0
-INFINITE = 0xffffffff
-ERROR_CONNECTION_REFUSED = 1225
-ERROR_CONNECTION_ABORTED = 1236
-
-# Initial delay in seconds for connect_pipe() before retrying to connect
-CONNECT_PIPE_INIT_DELAY = 0.001
-
-# Maximum delay in seconds for connect_pipe() before retrying to connect
-CONNECT_PIPE_MAX_DELAY = 0.100
-
-
-class _OverlappedFuture(futures.Future):
- """Subclass of Future which represents an overlapped operation.
-
- Cancelling it will immediately cancel the overlapped operation.
- """
-
- def __init__(self, ov, loop=None):
- super(_OverlappedFuture, self).__init__(loop=loop)
- if self._source_traceback:
- del self._source_traceback[-1]
- self._ov = ov
-
- def _repr_info(self):
- info = super(_OverlappedFuture, self)._repr_info()
- if self._ov is not None:
- state = 'pending' if self._ov.pending else 'completed'
- info.insert(1, 'overlapped=<%s, %#x>' % (state, self._ov.address))
- return info
-
- def _cancel_overlapped(self):
- if self._ov is None:
- return
- try:
- self._ov.cancel()
- except OSError as exc:
- context = {
- 'message': 'Cancelling an overlapped future failed',
- 'exception': exc,
- 'future': self,
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
- self._ov = None
-
- def cancel(self):
- self._cancel_overlapped()
- return super(_OverlappedFuture, self).cancel()
-
- def set_exception(self, exception):
- super(_OverlappedFuture, self).set_exception(exception)
- self._cancel_overlapped()
-
- def set_result(self, result):
- super(_OverlappedFuture, self).set_result(result)
- self._ov = None
-
-
-class _BaseWaitHandleFuture(futures.Future):
- """Subclass of Future which represents a wait handle."""
-
- def __init__(self, ov, handle, wait_handle, loop=None):
- super(_BaseWaitHandleFuture, self).__init__(loop=loop)
- if self._source_traceback:
- del self._source_traceback[-1]
- # Keep a reference to the Overlapped object to keep it alive until the
- # wait is unregistered
- self._ov = ov
- self._handle = handle
- self._wait_handle = wait_handle
-
- # Should we call UnregisterWaitEx() if the wait completes
- # or is cancelled?
- self._registered = True
-
- def _poll(self):
- # non-blocking wait: use a timeout of 0 millisecond
- return (_winapi.WaitForSingleObject(self._handle, 0) ==
- _winapi.WAIT_OBJECT_0)
-
- def _repr_info(self):
- info = super(_BaseWaitHandleFuture, self)._repr_info()
- info.append('handle=%#x' % self._handle)
- if self._handle is not None:
- state = 'signaled' if self._poll() else 'waiting'
- info.append(state)
- if self._wait_handle is not None:
- info.append('wait_handle=%#x' % self._wait_handle)
- return info
-
- def _unregister_wait_cb(self, fut):
- # The wait was unregistered: it's not safe to destroy the Overlapped
- # object
- self._ov = None
-
- def _unregister_wait(self):
- if not self._registered:
- return
- self._registered = False
-
- wait_handle = self._wait_handle
- self._wait_handle = None
- try:
- _overlapped.UnregisterWait(wait_handle)
- except OSError as exc:
- if exc.winerror != _overlapped.ERROR_IO_PENDING:
- context = {
- 'message': 'Failed to unregister the wait handle',
- 'exception': exc,
- 'future': self,
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
- return
- # ERROR_IO_PENDING means that the unregister is pending
-
- self._unregister_wait_cb(None)
-
- def cancel(self):
- self._unregister_wait()
- return super(_BaseWaitHandleFuture, self).cancel()
-
- def set_exception(self, exception):
- self._unregister_wait()
- super(_BaseWaitHandleFuture, self).set_exception(exception)
-
- def set_result(self, result):
- self._unregister_wait()
- super(_BaseWaitHandleFuture, self).set_result(result)
-
-
-class _WaitCancelFuture(_BaseWaitHandleFuture):
- """Subclass of Future which represents a wait for the cancellation of a
- _WaitHandleFuture using an event.
- """
-
- def __init__(self, ov, event, wait_handle, loop=None):
- super(_WaitCancelFuture, self).__init__(ov, event, wait_handle,
- loop=loop)
-
- self._done_callback = None
-
- def cancel(self):
- raise RuntimeError("_WaitCancelFuture must not be cancelled")
-
- def _schedule_callbacks(self):
- super(_WaitCancelFuture, self)._schedule_callbacks()
- if self._done_callback is not None:
- self._done_callback(self)
-
-
-class _WaitHandleFuture(_BaseWaitHandleFuture):
- def __init__(self, ov, handle, wait_handle, proactor, loop=None):
- super(_WaitHandleFuture, self).__init__(ov, handle, wait_handle,
- loop=loop)
- self._proactor = proactor
- self._unregister_proactor = True
- self._event = _overlapped.CreateEvent(None, True, False, None)
- self._event_fut = None
-
- def _unregister_wait_cb(self, fut):
- if self._event is not None:
- _winapi.CloseHandle(self._event)
- self._event = None
- self._event_fut = None
-
- # If the wait was cancelled, the wait may never be signalled, so
- # it's required to unregister it. Otherwise, IocpProactor.close() will
- # wait forever for an event which will never come.
- #
- # If the IocpProactor already received the event, it's safe to call
- # _unregister() because we kept a reference to the Overlapped object
- # which is used as an unique key.
- self._proactor._unregister(self._ov)
- self._proactor = None
-
- super(_WaitHandleFuture, self)._unregister_wait_cb(fut)
-
- def _unregister_wait(self):
- if not self._registered:
- return
- self._registered = False
-
- wait_handle = self._wait_handle
- self._wait_handle = None
- try:
- _overlapped.UnregisterWaitEx(wait_handle, self._event)
- except OSError as exc:
- if exc.winerror != _overlapped.ERROR_IO_PENDING:
- context = {
- 'message': 'Failed to unregister the wait handle',
- 'exception': exc,
- 'future': self,
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
- return
- # ERROR_IO_PENDING is not an error, the wait was unregistered
-
- self._event_fut = self._proactor._wait_cancel(self._event,
- self._unregister_wait_cb)
-
-
-class PipeServer(object):
- """Class representing a pipe server.
-
- This is much like a bound, listening socket.
- """
- def __init__(self, address):
- self._address = address
- self._free_instances = weakref.WeakSet()
- # initialize the pipe attribute before calling _server_pipe_handle()
- # because this function can raise an exception and the destructor calls
- # the close() method
- self._pipe = None
- self._accept_pipe_future = None
- self._pipe = self._server_pipe_handle(True)
-
- def _get_unconnected_pipe(self):
- # Create new instance and return previous one. This ensures
- # that (until the server is closed) there is always at least
- # one pipe handle for address. Therefore if a client attempt
- # to connect it will not fail with FileNotFoundError.
- tmp, self._pipe = self._pipe, self._server_pipe_handle(False)
- return tmp
-
- def _server_pipe_handle(self, first):
- # Return a wrapper for a new pipe handle.
- if self.closed():
- return None
- flags = _winapi.PIPE_ACCESS_DUPLEX | _winapi.FILE_FLAG_OVERLAPPED
- if first:
- flags |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
- h = wrap_error(_winapi.CreateNamedPipe,
- self._address, flags,
- _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE |
- _winapi.PIPE_WAIT,
- _winapi.PIPE_UNLIMITED_INSTANCES,
- windows_utils.BUFSIZE, windows_utils.BUFSIZE,
- _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
- pipe = windows_utils.PipeHandle(h)
- self._free_instances.add(pipe)
- return pipe
-
- def closed(self):
- return (self._address is None)
-
- def close(self):
- if self._accept_pipe_future is not None:
- self._accept_pipe_future.cancel()
- self._accept_pipe_future = None
- # Close all instances which have not been connected to by a client.
- if self._address is not None:
- for pipe in self._free_instances:
- pipe.close()
- self._pipe = None
- self._address = None
- self._free_instances.clear()
-
- __del__ = close
-
-
-class _WindowsSelectorEventLoop(selector_events.BaseSelectorEventLoop):
- """Windows version of selector event loop."""
-
- def _socketpair(self):
- return windows_utils.socketpair()
-
-
-class ProactorEventLoop(proactor_events.BaseProactorEventLoop):
- """Windows version of proactor event loop using IOCP."""
-
- def __init__(self, proactor=None):
- if proactor is None:
- proactor = IocpProactor()
- super(ProactorEventLoop, self).__init__(proactor)
-
- def _socketpair(self):
- return windows_utils.socketpair()
-
- @coroutine
- def create_pipe_connection(self, protocol_factory, address):
- f = self._proactor.connect_pipe(address)
- pipe = yield From(f)
- protocol = protocol_factory()
- trans = self._make_duplex_pipe_transport(pipe, protocol,
- extra={'addr': address})
- raise Return(trans, protocol)
-
- @coroutine
- def start_serving_pipe(self, protocol_factory, address):
- server = PipeServer(address)
-
- def loop_accept_pipe(f=None):
- pipe = None
- try:
- if f:
- pipe = f.result()
- server._free_instances.discard(pipe)
-
- if server.closed():
- # A client connected before the server was closed:
- # drop the client (close the pipe) and exit
- pipe.close()
- return
-
- protocol = protocol_factory()
- self._make_duplex_pipe_transport(
- pipe, protocol, extra={'addr': address})
-
- pipe = server._get_unconnected_pipe()
- if pipe is None:
- return
-
- f = self._proactor.accept_pipe(pipe)
- except OSError as exc:
- if pipe and pipe.fileno() != -1:
- self.call_exception_handler({
- 'message': 'Pipe accept failed',
- 'exception': exc,
- 'pipe': pipe,
- })
- pipe.close()
- elif self._debug:
- logger.warning("Accept pipe failed on pipe %r",
- pipe, exc_info=True)
- except futures.CancelledError:
- if pipe:
- pipe.close()
- else:
- server._accept_pipe_future = f
- f.add_done_callback(loop_accept_pipe)
-
- self.call_soon(loop_accept_pipe)
- return [server]
-
- @coroutine
- def _make_subprocess_transport(self, protocol, args, shell,
- stdin, stdout, stderr, bufsize,
- extra=None, **kwargs):
- waiter = futures.Future(loop=self)
- transp = _WindowsSubprocessTransport(self, protocol, args, shell,
- stdin, stdout, stderr, bufsize,
- waiter=waiter, extra=extra,
- **kwargs)
- try:
- yield From(waiter)
- except Exception as exc:
- # Workaround CPython bug #23353: using yield/yield-from in an
- # except block of a generator doesn't clear properly sys.exc_info()
- err = exc
- else:
- err = None
-
- if err is not None:
- transp.close()
- yield From(transp._wait())
- raise err
-
- raise Return(transp)
-
-
-class IocpProactor(object):
- """Proactor implementation using IOCP."""
-
- def __init__(self, concurrency=0xffffffff):
- self._loop = None
- self._results = []
- self._iocp = _overlapped.CreateIoCompletionPort(
- _overlapped.INVALID_HANDLE_VALUE, NULL, 0, concurrency)
- self._cache = {}
- self._registered = weakref.WeakSet()
- self._unregistered = []
- self._stopped_serving = weakref.WeakSet()
-
- def __repr__(self):
- return ('<%s overlapped#=%s result#=%s>'
- % (self.__class__.__name__, len(self._cache),
- len(self._results)))
-
- def set_loop(self, loop):
- self._loop = loop
-
- def select(self, timeout=None):
- if not self._results:
- self._poll(timeout)
- tmp = self._results
- self._results = []
- return tmp
-
- def _result(self, value):
- fut = futures.Future(loop=self._loop)
- fut.set_result(value)
- return fut
-
- def recv(self, conn, nbytes, flags=0):
- self._register_with_iocp(conn)
- ov = _overlapped.Overlapped(NULL)
- try:
- if isinstance(conn, socket.socket):
- wrap_error(ov.WSARecv, conn.fileno(), nbytes, flags)
- else:
- wrap_error(ov.ReadFile, conn.fileno(), nbytes)
- except BrokenPipeError:
- return self._result(b'')
-
- def finish_recv(trans, key, ov):
- try:
- return wrap_error(ov.getresult)
- except WindowsError as exc:
- if exc.winerror == _overlapped.ERROR_NETNAME_DELETED:
- raise ConnectionResetError(*exc.args)
- else:
- raise
-
- return self._register(ov, conn, finish_recv)
-
- def send(self, conn, buf, flags=0):
- self._register_with_iocp(conn)
- ov = _overlapped.Overlapped(NULL)
- if isinstance(conn, socket.socket):
- ov.WSASend(conn.fileno(), buf, flags)
- else:
- ov.WriteFile(conn.fileno(), buf)
-
- def finish_send(trans, key, ov):
- try:
- return wrap_error(ov.getresult)
- except WindowsError as exc:
- if exc.winerror == _overlapped.ERROR_NETNAME_DELETED:
- raise ConnectionResetError(*exc.args)
- else:
- raise
-
- return self._register(ov, conn, finish_send)
-
- def accept(self, listener):
- self._register_with_iocp(listener)
- conn = self._get_accept_socket(listener.family)
- ov = _overlapped.Overlapped(NULL)
- ov.AcceptEx(listener.fileno(), conn.fileno())
-
- def finish_accept(trans, key, ov):
- wrap_error(ov.getresult)
- # Use SO_UPDATE_ACCEPT_CONTEXT so getsockname() etc work.
- buf = struct.pack('@P', listener.fileno())
- conn.setsockopt(socket.SOL_SOCKET,
- _overlapped.SO_UPDATE_ACCEPT_CONTEXT, buf)
- conn.settimeout(listener.gettimeout())
- return conn, conn.getpeername()
-
- @coroutine
- def accept_coro(future, conn):
- # Coroutine closing the accept socket if the future is cancelled
- try:
- yield From(future)
- except futures.CancelledError:
- conn.close()
- raise
-
- future = self._register(ov, listener, finish_accept)
- coro = accept_coro(future, conn)
- tasks.ensure_future(coro, loop=self._loop)
- return future
-
- def connect(self, conn, address):
- self._register_with_iocp(conn)
- # The socket needs to be locally bound before we call ConnectEx().
- try:
- _overlapped.BindLocal(conn.fileno(), conn.family)
- except WindowsError as e:
- if e.winerror != errno.WSAEINVAL:
- raise
- # Probably already locally bound; check using getsockname().
- if conn.getsockname()[1] == 0:
- raise
- ov = _overlapped.Overlapped(NULL)
- ov.ConnectEx(conn.fileno(), address)
-
- def finish_connect(trans, key, ov):
- wrap_error(ov.getresult)
- # Use SO_UPDATE_CONNECT_CONTEXT so getsockname() etc work.
- conn.setsockopt(socket.SOL_SOCKET,
- _overlapped.SO_UPDATE_CONNECT_CONTEXT, 0)
- return conn
-
- return self._register(ov, conn, finish_connect)
-
- def accept_pipe(self, pipe):
- self._register_with_iocp(pipe)
- ov = _overlapped.Overlapped(NULL)
- connected = ov.ConnectNamedPipe(pipe.fileno())
-
- if connected:
- # ConnectNamePipe() failed with ERROR_PIPE_CONNECTED which means
- # that the pipe is connected. There is no need to wait for the
- # completion of the connection.
- return self._result(pipe)
-
- def finish_accept_pipe(trans, key, ov):
- wrap_error(ov.getresult)
- return pipe
-
- return self._register(ov, pipe, finish_accept_pipe)
-
- @coroutine
- def connect_pipe(self, address):
- delay = CONNECT_PIPE_INIT_DELAY
- while True:
- # Unfortunately there is no way to do an overlapped connect to a pipe.
- # Call CreateFile() in a loop until it doesn't fail with
- # ERROR_PIPE_BUSY
- try:
- handle = wrap_error(_overlapped.ConnectPipe, address)
- break
- except WindowsError as exc:
- if exc.winerror != _overlapped.ERROR_PIPE_BUSY:
- raise
-
- # ConnectPipe() failed with ERROR_PIPE_BUSY: retry later
- delay = min(delay * 2, CONNECT_PIPE_MAX_DELAY)
- yield From(tasks.sleep(delay, loop=self._loop))
-
- raise Return(windows_utils.PipeHandle(handle))
-
- def wait_for_handle(self, handle, timeout=None):
- """Wait for a handle.
-
- Return a Future object. The result of the future is True if the wait
- completed, or False if the wait did not complete (on timeout).
- """
- return self._wait_for_handle(handle, timeout, False)
-
- def _wait_cancel(self, event, done_callback):
- fut = self._wait_for_handle(event, None, True)
- # add_done_callback() cannot be used because the wait may only complete
- # in IocpProactor.close(), while the event loop is not running.
- fut._done_callback = done_callback
- return fut
-
- def _wait_for_handle(self, handle, timeout, _is_cancel):
- if timeout is None:
- ms = _winapi.INFINITE
- else:
- # RegisterWaitForSingleObject() has a resolution of 1 millisecond,
- # round away from zero to wait *at least* timeout seconds.
- ms = int(math.ceil(timeout * 1e3))
-
- # We only create ov so we can use ov.address as a key for the cache.
- ov = _overlapped.Overlapped(NULL)
- wait_handle = _overlapped.RegisterWaitWithQueue(
- handle, self._iocp, ov.address, ms)
- if _is_cancel:
- f = _WaitCancelFuture(ov, handle, wait_handle, loop=self._loop)
- else:
- f = _WaitHandleFuture(ov, handle, wait_handle, self,
- loop=self._loop)
- if f._source_traceback:
- del f._source_traceback[-1]
-
- def finish_wait_for_handle(trans, key, ov):
- # Note that this second wait means that we should only use
- # this with handles types where a successful wait has no
- # effect. So events or processes are all right, but locks
- # or semaphores are not. Also note if the handle is
- # signalled and then quickly reset, then we may return
- # False even though we have not timed out.
- return f._poll()
-
- self._cache[ov.address] = (f, ov, 0, finish_wait_for_handle)
- return f
-
- def _register_with_iocp(self, obj):
- # To get notifications of finished ops on this objects sent to the
- # completion port, were must register the handle.
- if obj not in self._registered:
- self._registered.add(obj)
- _overlapped.CreateIoCompletionPort(obj.fileno(), self._iocp, 0, 0)
- # XXX We could also use SetFileCompletionNotificationModes()
- # to avoid sending notifications to completion port of ops
- # that succeed immediately.
-
- def _register(self, ov, obj, callback):
- # Return a future which will be set with the result of the
- # operation when it completes. The future's value is actually
- # the value returned by callback().
- f = _OverlappedFuture(ov, loop=self._loop)
- if f._source_traceback:
- del f._source_traceback[-1]
- if not ov.pending:
- # The operation has completed, so no need to postpone the
- # work. We cannot take this short cut if we need the
- # NumberOfBytes, CompletionKey values returned by
- # PostQueuedCompletionStatus().
- try:
- value = callback(None, None, ov)
- except OSError as e:
- f.set_exception(e)
- else:
- f.set_result(value)
- # Even if GetOverlappedResult() was called, we have to wait for the
- # notification of the completion in GetQueuedCompletionStatus().
- # Register the overlapped operation to keep a reference to the
- # OVERLAPPED object, otherwise the memory is freed and Windows may
- # read uninitialized memory.
-
- # Register the overlapped operation for later. Note that
- # we only store obj to prevent it from being garbage
- # collected too early.
- self._cache[ov.address] = (f, ov, obj, callback)
- return f
-
- def _unregister(self, ov):
- """Unregister an overlapped object.
-
- Call this method when its future has been cancelled. The event can
- already be signalled (pending in the proactor event queue). It is also
- safe if the event is never signalled (because it was cancelled).
- """
- self._unregistered.append(ov)
-
- def _get_accept_socket(self, family):
- s = socket.socket(family)
- s.settimeout(0)
- return s
-
- def _poll(self, timeout=None):
- if timeout is None:
- ms = INFINITE
- elif timeout < 0:
- raise ValueError("negative timeout")
- else:
- # GetQueuedCompletionStatus() has a resolution of 1 millisecond,
- # round away from zero to wait *at least* timeout seconds.
- ms = int(math.ceil(timeout * 1e3))
- if ms >= INFINITE:
- raise ValueError("timeout too big")
-
- while True:
- status = _overlapped.GetQueuedCompletionStatus(self._iocp, ms)
- if status is None:
- break
- ms = 0
-
- err, transferred, key, address = status
- try:
- f, ov, obj, callback = self._cache.pop(address)
- except KeyError:
- if self._loop.get_debug():
- self._loop.call_exception_handler({
- 'message': ('GetQueuedCompletionStatus() returned an '
- 'unexpected event'),
- 'status': ('err=%s transferred=%s key=%#x address=%#x'
- % (err, transferred, key, address)),
- })
-
- # key is either zero, or it is used to return a pipe
- # handle which should be closed to avoid a leak.
- if key not in (0, _overlapped.INVALID_HANDLE_VALUE):
- _winapi.CloseHandle(key)
- continue
-
- if obj in self._stopped_serving:
- f.cancel()
- # Don't call the callback if _register() already read the result or
- # if the overlapped has been cancelled
- elif not f.done():
- try:
- value = callback(transferred, key, ov)
- except OSError as e:
- f.set_exception(e)
- self._results.append(f)
- else:
- f.set_result(value)
- self._results.append(f)
-
- # Remove unregisted futures
- for ov in self._unregistered:
- self._cache.pop(ov.address, None)
- del self._unregistered[:]
-
- def _stop_serving(self, obj):
- # obj is a socket or pipe handle. It will be closed in
- # BaseProactorEventLoop._stop_serving() which will make any
- # pending operations fail quickly.
- self._stopped_serving.add(obj)
-
- def close(self):
- # Cancel remaining registered operations.
- for address, (fut, ov, obj, callback) in list(self._cache.items()):
- if fut.cancelled():
- # Nothing to do with cancelled futures
- pass
- elif isinstance(fut, _WaitCancelFuture):
- # _WaitCancelFuture must not be cancelled
- pass
- else:
- try:
- fut.cancel()
- except OSError as exc:
- if self._loop is not None:
- context = {
- 'message': 'Cancelling a future failed',
- 'exception': exc,
- 'future': fut,
- }
- if fut._source_traceback:
- context['source_traceback'] = fut._source_traceback
- self._loop.call_exception_handler(context)
-
- while self._cache:
- if not self._poll(1):
- logger.debug('taking long time to close proactor')
-
- self._results = []
- if self._iocp is not None:
- _winapi.CloseHandle(self._iocp)
- self._iocp = None
-
- def __del__(self):
- self.close()
-
-
-class _WindowsSubprocessTransport(base_subprocess.BaseSubprocessTransport):
-
- def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
- self._proc = windows_utils.Popen(
- args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr,
- bufsize=bufsize, **kwargs)
-
- def callback(f):
- returncode = self._proc.poll()
- self._process_exited(returncode)
-
- f = self._loop._proactor.wait_for_handle(int(self._proc._handle))
- f.add_done_callback(callback)
-
-
-SelectorEventLoop = _WindowsSelectorEventLoop
-
-
-class _WindowsDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy):
- _loop_factory = SelectorEventLoop
-
-
-DefaultEventLoopPolicy = _WindowsDefaultEventLoopPolicy
+++ /dev/null
-"""
-Various Windows specific bits and pieces
-"""
-from __future__ import absolute_import
-
-import sys
-
-if sys.platform != 'win32': # pragma: no cover
- raise ImportError('win32 only')
-
-import itertools
-import msvcrt
-import os
-import socket
-import subprocess
-import tempfile
-import warnings
-
-import six
-
-from . import py33_winapi as _winapi
-from . import compat
-from .py33_exceptions import wrap_error, BlockingIOError, InterruptedError
-
-
-__all__ = ['socketpair', 'pipe', 'Popen', 'PIPE', 'PipeHandle']
-
-
-# Constants/globals
-
-
-BUFSIZE = 8192
-PIPE = subprocess.PIPE
-STDOUT = subprocess.STDOUT
-_mmap_counter = itertools.count()
-
-
-if hasattr(socket, 'socketpair'):
- # Since Python 3.5, socket.socketpair() is now also available on Windows
- socketpair = socket.socketpair
-else:
- # Replacement for socket.socketpair()
- def socketpair(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
- """A socket pair usable as a self-pipe, for Windows.
-
- Origin: https://gist.github.com/4325783, by Geert Jansen.
- Public domain.
- """
- if family == socket.AF_INET:
- host = '127.0.0.1'
- elif family == socket.AF_INET6:
- host = '::1'
- else:
- raise ValueError("Only AF_INET and AF_INET6 socket address "
- "families are supported")
- if type != socket.SOCK_STREAM:
- raise ValueError("Only SOCK_STREAM socket type is supported")
- if proto != 0:
- raise ValueError("Only protocol zero is supported")
-
- # We create a connected TCP socket. Note the trick with setblocking(0)
- # that prevents us from having to create a thread.
- lsock = socket.socket(family, type, proto)
- try:
- lsock.bind((host, 0))
- lsock.listen(1)
- # On IPv6, ignore flow_info and scope_id
- addr, port = lsock.getsockname()[:2]
- csock = socket.socket(family, type, proto)
- try:
- csock.setblocking(False)
- try:
- wrap_error(csock.connect, (addr, port))
- except (BlockingIOError, InterruptedError):
- pass
- csock.setblocking(True)
- ssock, _ = lsock.accept()
- except:
- csock.close()
- raise
- finally:
- lsock.close()
- return (ssock, csock)
-
-
-# Replacement for os.pipe() using handles instead of fds
-
-
-def pipe(duplex=False, overlapped=(True, True), bufsize=BUFSIZE):
- """Like os.pipe() but with overlapped support and using handles not fds."""
- address = tempfile.mktemp(prefix=r'\\.\pipe\python-pipe-%d-%d-' %
- (os.getpid(), next(_mmap_counter)))
-
- if duplex:
- openmode = _winapi.PIPE_ACCESS_DUPLEX
- access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE
- obsize, ibsize = bufsize, bufsize
- else:
- openmode = _winapi.PIPE_ACCESS_INBOUND
- access = _winapi.GENERIC_WRITE
- obsize, ibsize = 0, bufsize
-
- openmode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
-
- if overlapped[0]:
- openmode |= _winapi.FILE_FLAG_OVERLAPPED
-
- if overlapped[1]:
- flags_and_attribs = _winapi.FILE_FLAG_OVERLAPPED
- else:
- flags_and_attribs = 0
-
- h1 = h2 = None
- try:
- h1 = _winapi.CreateNamedPipe(
- address, openmode, _winapi.PIPE_WAIT,
- 1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
-
- h2 = _winapi.CreateFile(
- address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,
- flags_and_attribs, _winapi.NULL)
-
- ov = _winapi.ConnectNamedPipe(h1, overlapped=True)
- if hasattr(ov, 'GetOverlappedResult'):
- # _winapi module of Python 3.3
- ov.GetOverlappedResult(True)
- else:
- # _overlapped module
- wrap_error(ov.getresult, True)
- return h1, h2
- except:
- if h1 is not None:
- _winapi.CloseHandle(h1)
- if h2 is not None:
- _winapi.CloseHandle(h2)
- raise
-
-
-# Wrapper for a pipe handle
-
-
-class PipeHandle(object):
- """Wrapper for an overlapped pipe handle which is vaguely file-object like.
-
- The IOCP event loop can use these instead of socket objects.
- """
- def __init__(self, handle):
- self._handle = handle
-
- def __repr__(self):
- if self._handle is not None:
- handle = 'handle=%r' % self._handle
- else:
- handle = 'closed'
- return '<%s %s>' % (self.__class__.__name__, handle)
-
- @property
- def handle(self):
- return self._handle
-
- def fileno(self):
- if self._handle is None:
- raise ValueError("I/O operatioon on closed pipe")
- return self._handle
-
- def close(self, CloseHandle=_winapi.CloseHandle):
- if self._handle is not None:
- CloseHandle(self._handle)
- self._handle = None
-
- def __del__(self):
- if self._handle is not None:
- if six.PY3:
- warnings.warn("unclosed %r" % self, ResourceWarning)
- self.close()
-
- def __enter__(self):
- return self
-
- def __exit__(self, t, v, tb):
- self.close()
-
-
-# Replacement for subprocess.Popen using overlapped pipe handles
-
-
-class Popen(subprocess.Popen):
- """Replacement for subprocess.Popen using overlapped pipe handles.
-
- The stdin, stdout, stderr are None or instances of PipeHandle.
- """
- def __init__(self, args, stdin=None, stdout=None, stderr=None, **kwds):
- assert not kwds.get('universal_newlines')
- assert kwds.get('bufsize', 0) == 0
- stdin_rfd = stdout_wfd = stderr_wfd = None
- stdin_wh = stdout_rh = stderr_rh = None
- if stdin == PIPE:
- stdin_rh, stdin_wh = pipe(overlapped=(False, True), duplex=True)
- stdin_rfd = msvcrt.open_osfhandle(stdin_rh, os.O_RDONLY)
- else:
- stdin_rfd = stdin
- if stdout == PIPE:
- stdout_rh, stdout_wh = pipe(overlapped=(True, False))
- stdout_wfd = msvcrt.open_osfhandle(stdout_wh, 0)
- else:
- stdout_wfd = stdout
- if stderr == PIPE:
- stderr_rh, stderr_wh = pipe(overlapped=(True, False))
- stderr_wfd = msvcrt.open_osfhandle(stderr_wh, 0)
- elif stderr == STDOUT:
- stderr_wfd = stdout_wfd
- else:
- stderr_wfd = stderr
- try:
- super(Popen, self).__init__(args,
- stdin=stdin_rfd,
- stdout=stdout_wfd,
- stderr=stderr_wfd,
- **kwds)
- except:
- for h in (stdin_wh, stdout_rh, stderr_rh):
- if h is not None:
- _winapi.CloseHandle(h)
- raise
- else:
- if stdin_wh is not None:
- self.stdin = PipeHandle(stdin_wh)
- if stdout_rh is not None:
- self.stdout = PipeHandle(stdout_rh)
- if stderr_rh is not None:
- self.stderr = PipeHandle(stderr_rh)
- finally:
- if stdin == PIPE:
- os.close(stdin_rfd)
- if stdout == PIPE:
- os.close(stdout_wfd)
- if stderr == PIPE:
- os.close(stderr_wfd)
+++ /dev/null
-Original Authors
-----------------
-* Armin Rigo
-* Christian Tismer
-
-Contributors
-------------
-* Al Stone
-* Alexander Schmidt
-* Alexey Borzenkov
-* Andreas Schwab
-* Armin Ronacher
-* Bin Wang <feisuzhu@163.com>
-* Bob Ippolito
-* ChangBo Guo
-* Christoph Gohlke
-* Denis Bilenko
-* Dirk Mueller
-* Donovan Preston
-* Fantix King
-* Floris Bruynooghe
-* Fredrik Fornwall
-* Gerd Woetzel
-* Giel van Schijndel
-* Gökhan Karabulut
-* Gustavo Niemeyer
-* Guy Rozendorn
-* Hye-Shik Chang
-* Jared Kuolt
-* Jason Madden
-* Josh Snyder
-* Kyle Ambroff
-* Laszlo Boszormenyi
-* Mao Han
-* Marc Abramowitz
-* Marc Schlaich
-* Marcin Bachry
-* Matt Madison
-* Matt Turner
-* Michael Ellerman
-* Michael Matz
-* Ralf Schmitt
-* Robie Basak
-* Ronny Pfannschmidt
-* Samual M. Rushing
-* Tony Bowles
-* Tony Breeds
-* Trevor Bowen
-* Tulio Magno Quites Machado Filho
-* Ulrich Weigand
-* Victor Stinner
+++ /dev/null
-The following files are derived from Stackless Python and are subject to the
-same license as Stackless Python:
-
- slp_platformselect.h
- files in platform/ directory
-
-See LICENSE.PSF and http://www.stackless.com/ for details.
-
-Unless otherwise noted, the files in greenlet have been released under the
-following MIT license:
-
-Copyright (c) Armin Rigo, Christian Tismer and contributors
-
-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.
+++ /dev/null
-PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
---------------------------------------------
-
-1. This LICENSE AGREEMENT is between the Python Software Foundation
-("PSF"), and the Individual or Organization ("Licensee") accessing and
-otherwise using this software ("Python") in source or binary form and
-its associated documentation.
-
-2. Subject to the terms and conditions of this License Agreement, PSF hereby
-grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
-analyze, test, perform and/or display publicly, prepare derivative works,
-distribute, and otherwise use Python alone or in any derivative version,
-provided, however, that PSF's License Agreement and PSF's notice of copyright,
-i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-2011 Python Software Foundation; All Rights Reserved" are retained in Python
-alone or in any derivative version prepared by Licensee.
-
-3. In the event Licensee prepares a derivative work that is based on
-or incorporates Python or any part thereof, and wants to make
-the derivative work available to others as provided herein, then
-Licensee hereby agrees to include in any such work a brief summary of
-the changes made to Python.
-
-4. PSF is making Python available to Licensee on an "AS IS"
-basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
-IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
-DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
-FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
-INFRINGE ANY THIRD PARTY RIGHTS.
-
-5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
-FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
-A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
-OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
-
-6. This License Agreement will automatically terminate upon a material
-breach of its terms and conditions.
-
-7. Nothing in this License Agreement shall be deemed to create any
-relationship of agency, partnership, or joint venture between PSF and
-Licensee. This License Agreement does not grant permission to use PSF
-trademarks or trade name in a trademark sense to endorse or promote
-products or services of Licensee, or any third party.
-
-8. By copying, installing or otherwise using Python, Licensee
-agrees to be bound by the terms and conditions of this License
-Agreement.
+++ /dev/null
-Metadata-Version: 2.1
-Name: greenlet
-Version: 0.4.17
-Summary: Lightweight in-process concurrent programming
-Home-page: https://github.com/python-greenlet/greenlet
-Author: UNKNOWN
-Author-email: UNKNOWN
-License: MIT License
-Platform: any
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Natural Language :: English
-Classifier: Programming Language :: C
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.4
-Classifier: Programming Language :: Python :: 2.5
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.0
-Classifier: Programming Language :: Python :: 3.1
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Operating System :: OS Independent
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-
-.. image:: https://secure.travis-ci.org/python-greenlet/greenlet.png
- :target: http://travis-ci.org/python-greenlet/greenlet
-
-The greenlet package is a spin-off of Stackless, a version of CPython
-that supports micro-threads called "tasklets". Tasklets run
-pseudo-concurrently (typically in a single or a few OS-level threads)
-and are synchronized with data exchanges on "channels".
-
-A "greenlet", on the other hand, is a still more primitive notion of
-micro-thread with no implicit scheduling; coroutines, in other
-words. This is useful when you want to control exactly when your code
-runs. You can build custom scheduled micro-threads on top of greenlet;
-however, it seems that greenlets are useful on their own as a way to
-make advanced control flow structures. For example, we can recreate
-generators; the difference with Python's own generators is that our
-generators can call nested functions and the nested functions can
-yield values too. Additionally, you don't need a "yield" keyword. See
-the example in tests/test_generator.py.
-
-Greenlets are provided as a C extension module for the regular
-unmodified interpreter.
-
-Greenlets are lightweight coroutines for in-process concurrent
-programming.
-
-Who is using Greenlet?
-======================
-
-There are several libraries that use Greenlet as a more flexible
-alternative to Python's built in coroutine support:
-
- - `Concurrence`_
- - `Eventlet`_
- - `Gevent`_
-
-.. _Concurrence: http://opensource.hyves.org/concurrence/
-.. _Eventlet: http://eventlet.net/
-.. _Gevent: http://www.gevent.org/
-
-Getting Greenlet
-================
-
-The easiest way to get Greenlet is to install it with pip or
-easy_install::
-
- pip install greenlet
- easy_install greenlet
-
-
-Source code archives and windows installers are available on the
-python package index at https://pypi.python.org/pypi/greenlet
-
-The source code repository is hosted on github:
-https://github.com/python-greenlet/greenlet
-
-Documentation is available on readthedocs.org:
-https://greenlet.readthedocs.io
-
-
+++ /dev/null
-../../../include/python3.9/greenlet/greenlet.h,sha256=lMxw5Z2sk1jjSXhqzBI13iCh4wQsv70PYnOVVam6kZI,4176\r
-greenlet-0.4.17.dist-info/AUTHORS,sha256=swW28t2knVRxRkaEQNZtO7MP9Sgnompb7B6cNgJM8Gk,849\r
-greenlet-0.4.17.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4\r
-greenlet-0.4.17.dist-info/LICENSE,sha256=u95V1UVqHpEmM-0_ZtHb2VBOPj3OT0wgFQQ83LxW5pc,1408\r
-greenlet-0.4.17.dist-info/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424\r
-greenlet-0.4.17.dist-info/METADATA,sha256=1JfIvgi_IrGEShdtXql0SnoBTO20gM-UFaAskiMksOg,3378\r
-greenlet-0.4.17.dist-info/RECORD,,\r
-greenlet-0.4.17.dist-info/WHEEL,sha256=MPzLoODanKXQG5ZYPOvHn6Z_wVzQEe1kTJVxw9nhrDM,108\r
-greenlet-0.4.17.dist-info/top_level.txt,sha256=YSnRsCRoO61JGlP57o8iKL6rdLWDWuiyKD8ekpWUsDc,9\r
-greenlet.cpython-39-x86_64-linux-gnu.so,sha256=drFnGAq74zn8aqMdsmGcmK2m87Rk5fYMGIvPDAWUFgE,112560\r
+++ /dev/null
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.34.2)
-Root-Is-Purelib: false
-Tag: cp39-cp39-manylinux1_x86_64
-
+++ /dev/null
-Metadata-Version: 1.0
-Name: neovim
-Version: 0.3.1
-Summary: Transition packgage for pynvim
-Home-page: http://github.com/neovim/python-client
-Author: Thiago de Arruda
-Author-email: tpadilha84@gmail.com
-License: Apache
-Description: UNKNOWN
-Platform: UNKNOWN
+++ /dev/null
-setup.cfg
-setup.py
-neovim.egg-info/PKG-INFO
-neovim.egg-info/SOURCES.txt
-neovim.egg-info/dependency_links.txt
-neovim.egg-info/not-zip-safe
-neovim.egg-info/requires.txt
-neovim.egg-info/top_level.txt
\ No newline at end of file
+++ /dev/null
-PKG-INFO
-SOURCES.txt
-dependency_links.txt
-not-zip-safe
-requires.txt
-top_level.txt
+++ /dev/null
-pynvim>=0.3.1
+++ /dev/null
-"""Python client for Nvim.
-
-This is a transition package. New projects should instead import pynvim package.
-"""
-import pynvim
-from pynvim import *
-
-__all__ = pynvim.__all__
+++ /dev/null
-"""Nvim API subpackage.
-
-This is a transition package. New projects should instead import pynvim.api.
-"""
-from pynvim import api
-from pynvim.api import *
-
-__all__ = api.__all__
+++ /dev/null
-Metadata-Version: 2.1
-Name: pynvim
-Version: 0.4.2
-Summary: Python client to neovim
-Home-page: http://github.com/neovim/pynvim
-Author: Thiago de Arruda
-Author-email: tpadilha84@gmail.com
-License: Apache
-Download-URL: https://github.com/neovim/pynvim/archive/0.4.2.tar.gz
-Description: UNKNOWN
-Platform: UNKNOWN
-Provides-Extra: pyuv
-Provides-Extra: test
+++ /dev/null
-LICENSE
-MANIFEST.in
-README.md
-setup.cfg
-setup.py
-neovim/__init__.py
-neovim/api/__init__.py
-pynvim/__init__.py
-pynvim/compat.py
-pynvim/util.py
-pynvim.egg-info/PKG-INFO
-pynvim.egg-info/SOURCES.txt
-pynvim.egg-info/dependency_links.txt
-pynvim.egg-info/not-zip-safe
-pynvim.egg-info/requires.txt
-pynvim.egg-info/top_level.txt
-pynvim/api/__init__.py
-pynvim/api/buffer.py
-pynvim/api/common.py
-pynvim/api/nvim.py
-pynvim/api/tabpage.py
-pynvim/api/window.py
-pynvim/msgpack_rpc/__init__.py
-pynvim/msgpack_rpc/async_session.py
-pynvim/msgpack_rpc/msgpack_stream.py
-pynvim/msgpack_rpc/session.py
-pynvim/msgpack_rpc/event_loop/__init__.py
-pynvim/msgpack_rpc/event_loop/asyncio.py
-pynvim/msgpack_rpc/event_loop/base.py
-pynvim/msgpack_rpc/event_loop/uv.py
-pynvim/plugin/__init__.py
-pynvim/plugin/decorators.py
-pynvim/plugin/host.py
-pynvim/plugin/script_host.py
-test/conftest.py
-test/test_buffer.py
-test/test_client_rpc.py
-test/test_concurrency.py
-test/test_decorators.py
-test/test_events.py
-test/test_host.py
-test/test_logging.py
-test/test_tabpage.py
-test/test_vim.py
-test/test_window.py
\ No newline at end of file
+++ /dev/null
-../neovim/__init__.py
-../neovim/__pycache__/__init__.cpython-39.pyc
-../neovim/api/__init__.py
-../neovim/api/__pycache__/__init__.cpython-39.pyc
-../pynvim/__init__.py
-../pynvim/__pycache__/__init__.cpython-39.pyc
-../pynvim/__pycache__/compat.cpython-39.pyc
-../pynvim/__pycache__/util.cpython-39.pyc
-../pynvim/api/__init__.py
-../pynvim/api/__pycache__/__init__.cpython-39.pyc
-../pynvim/api/__pycache__/buffer.cpython-39.pyc
-../pynvim/api/__pycache__/common.cpython-39.pyc
-../pynvim/api/__pycache__/nvim.cpython-39.pyc
-../pynvim/api/__pycache__/tabpage.cpython-39.pyc
-../pynvim/api/__pycache__/window.cpython-39.pyc
-../pynvim/api/buffer.py
-../pynvim/api/common.py
-../pynvim/api/nvim.py
-../pynvim/api/tabpage.py
-../pynvim/api/window.py
-../pynvim/compat.py
-../pynvim/msgpack_rpc/__init__.py
-../pynvim/msgpack_rpc/__pycache__/__init__.cpython-39.pyc
-../pynvim/msgpack_rpc/__pycache__/async_session.cpython-39.pyc
-../pynvim/msgpack_rpc/__pycache__/msgpack_stream.cpython-39.pyc
-../pynvim/msgpack_rpc/__pycache__/session.cpython-39.pyc
-../pynvim/msgpack_rpc/async_session.py
-../pynvim/msgpack_rpc/event_loop/__init__.py
-../pynvim/msgpack_rpc/event_loop/__pycache__/__init__.cpython-39.pyc
-../pynvim/msgpack_rpc/event_loop/__pycache__/asyncio.cpython-39.pyc
-../pynvim/msgpack_rpc/event_loop/__pycache__/base.cpython-39.pyc
-../pynvim/msgpack_rpc/event_loop/__pycache__/uv.cpython-39.pyc
-../pynvim/msgpack_rpc/event_loop/asyncio.py
-../pynvim/msgpack_rpc/event_loop/base.py
-../pynvim/msgpack_rpc/event_loop/uv.py
-../pynvim/msgpack_rpc/msgpack_stream.py
-../pynvim/msgpack_rpc/session.py
-../pynvim/plugin/__init__.py
-../pynvim/plugin/__pycache__/__init__.cpython-39.pyc
-../pynvim/plugin/__pycache__/decorators.cpython-39.pyc
-../pynvim/plugin/__pycache__/host.cpython-39.pyc
-../pynvim/plugin/__pycache__/script_host.cpython-39.pyc
-../pynvim/plugin/decorators.py
-../pynvim/plugin/host.py
-../pynvim/plugin/script_host.py
-../pynvim/util.py
-PKG-INFO
-SOURCES.txt
-dependency_links.txt
-not-zip-safe
-requires.txt
-top_level.txt
+++ /dev/null
-msgpack>=0.5.0
-greenlet
-
-[pyuv]
-pyuv>=1.0.0
-
-[test]
-pytest>=3.4.0
+++ /dev/null
-neovim
-pynvim
+++ /dev/null
-"""Python client for Nvim.
-
-Client library for talking with Nvim processes via its msgpack-rpc API.
-"""
-import logging
-import os
-import sys
-
-from pynvim.api import Nvim, NvimError
-from pynvim.compat import IS_PYTHON3
-from pynvim.msgpack_rpc import (ErrorResponse, child_session, socket_session,
- stdio_session, tcp_session)
-from pynvim.plugin import (Host, autocmd, command, decode, encoding, function,
- plugin, rpc_export, shutdown_hook)
-from pynvim.util import VERSION, Version
-
-
-__all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
- 'start_host', 'autocmd', 'command', 'encoding', 'decode',
- 'function', 'plugin', 'rpc_export', 'Host', 'Nvim', 'NvimError',
- 'Version', 'VERSION', 'shutdown_hook', 'attach', 'setup_logging',
- 'ErrorResponse')
-
-
-def start_host(session=None):
- """Promote the current process into python plugin host for Nvim.
-
- Start msgpack-rpc event loop for `session`, listening for Nvim requests
- and notifications. It registers Nvim commands for loading/unloading
- python plugins.
-
- The sys.stdout and sys.stderr streams are redirected to Nvim through
- `session`. That means print statements probably won't work as expected
- while this function doesn't return.
-
- This function is normally called at program startup and could have been
- defined as a separate executable. It is exposed as a library function for
- testing purposes only.
- """
- plugins = []
- for arg in sys.argv:
- _, ext = os.path.splitext(arg)
- if ext == '.py':
- plugins.append(arg)
- elif os.path.isdir(arg):
- init = os.path.join(arg, '__init__.py')
- if os.path.isfile(init):
- plugins.append(arg)
-
- # This is a special case to support the old workaround of
- # adding an empty .py file to make a package directory
- # visible, and it should be removed soon.
- for path in list(plugins):
- dup = path + ".py"
- if os.path.isdir(path) and dup in plugins:
- plugins.remove(dup)
-
- # Special case: the legacy scripthost receives a single relative filename
- # while the rplugin host will receive absolute paths.
- if plugins == ["script_host.py"]:
- name = "script"
- else:
- name = "rplugin"
-
- setup_logging(name)
-
- if not session:
- session = stdio_session()
- nvim = Nvim.from_session(session)
-
- if nvim.version.api_level < 1:
- sys.stderr.write("This version of pynvim "
- "requires nvim 0.1.6 or later")
- sys.exit(1)
-
- host = Host(nvim)
- host.start(plugins)
-
-
-def attach(session_type, address=None, port=None,
- path=None, argv=None, decode=None):
- """Provide a nicer interface to create python api sessions.
-
- Previous machinery to create python api sessions is still there. This only
- creates a facade function to make things easier for the most usual cases.
- Thus, instead of:
- from pynvim import socket_session, Nvim
- session = tcp_session(address=<address>, port=<port>)
- nvim = Nvim.from_session(session)
- You can now do:
- from pynvim import attach
- nvim = attach('tcp', address=<address>, port=<port>)
- And also:
- nvim = attach('socket', path=<path>)
- nvim = attach('child', argv=<argv>)
- nvim = attach('stdio')
-
- When the session is not needed anymore, it is recommended to explicitly
- close it:
- nvim.close()
- It is also possible to use the session as a context mangager:
- with attach('socket', path=thepath) as nvim:
- print(nvim.funcs.getpid())
- print(nvim.current.line)
- This will automatically close the session when you're done with it, or
- when an error occured.
-
-
- """
- session = (tcp_session(address, port) if session_type == 'tcp' else
- socket_session(path) if session_type == 'socket' else
- stdio_session() if session_type == 'stdio' else
- child_session(argv) if session_type == 'child' else
- None)
-
- if not session:
- raise Exception('Unknown session type "%s"' % session_type)
-
- if decode is None:
- decode = IS_PYTHON3
-
- return Nvim.from_session(session).with_decode(decode)
-
-
-def setup_logging(name):
- """Setup logging according to environment variables."""
- logger = logging.getLogger(__name__)
- if 'NVIM_PYTHON_LOG_FILE' in os.environ:
- prefix = os.environ['NVIM_PYTHON_LOG_FILE'].strip()
- major_version = sys.version_info[0]
- logfile = '{}_py{}_{}'.format(prefix, major_version, name)
- handler = logging.FileHandler(logfile, 'w', 'utf-8')
- handler.formatter = logging.Formatter(
- '%(asctime)s [%(levelname)s @ '
- '%(filename)s:%(funcName)s:%(lineno)s] %(process)s - %(message)s')
- logging.root.addHandler(handler)
- level = logging.INFO
- env_log_level = os.environ.get('NVIM_PYTHON_LOG_LEVEL', None)
- if env_log_level is not None:
- lvl = getattr(logging, env_log_level.strip(), None)
- if isinstance(lvl, int):
- level = lvl
- else:
- logger.warning('Invalid NVIM_PYTHON_LOG_LEVEL: %r, using INFO.',
- env_log_level)
- logger.setLevel(level)
-
-
-# Required for python 2.6
-class NullHandler(logging.Handler):
- def emit(self, record):
- pass
-
-
-if not logging.root.handlers:
- logging.root.addHandler(NullHandler())
+++ /dev/null
-"""Nvim API subpackage.
-
-This package implements a higher-level API that wraps msgpack-rpc `Session`
-instances.
-"""
-
-from pynvim.api.buffer import Buffer
-from pynvim.api.common import decode_if_bytes, walk
-from pynvim.api.nvim import Nvim, NvimError
-from pynvim.api.tabpage import Tabpage
-from pynvim.api.window import Window
-
-
-__all__ = ('Nvim', 'Buffer', 'Window', 'Tabpage', 'NvimError',
- 'decode_if_bytes', 'walk')
+++ /dev/null
-"""API for working with a Nvim Buffer."""
-from pynvim.api.common import Remote
-from pynvim.compat import IS_PYTHON3, check_async
-
-
-__all__ = ('Buffer')
-
-
-if IS_PYTHON3:
- basestring = str
-
-
-def adjust_index(idx, default=None):
- """Convert from python indexing convention to nvim indexing convention."""
- if idx is None:
- return default
- elif idx < 0:
- return idx - 1
- else:
- return idx
-
-
-class Buffer(Remote):
-
- """A remote Nvim buffer."""
-
- _api_prefix = "nvim_buf_"
-
- def __len__(self):
- """Return the number of lines contained in a Buffer."""
- return self.request('nvim_buf_line_count')
-
- def __getitem__(self, idx):
- """Get a buffer line or slice by integer index.
-
- Indexes may be negative to specify positions from the end of the
- buffer. For example, -1 is the last line, -2 is the line before that
- and so on.
-
- When retrieving slices, omiting indexes(eg: `buffer[:]`) will bring
- the whole buffer.
- """
- if not isinstance(idx, slice):
- i = adjust_index(idx)
- return self.request('nvim_buf_get_lines', i, i + 1, True)[0]
- start = adjust_index(idx.start, 0)
- end = adjust_index(idx.stop, -1)
- return self.request('nvim_buf_get_lines', start, end, False)
-
- def __setitem__(self, idx, item):
- """Replace a buffer line or slice by integer index.
-
- Like with `__getitem__`, indexes may be negative.
-
- When replacing slices, omiting indexes(eg: `buffer[:]`) will replace
- the whole buffer.
- """
- if not isinstance(idx, slice):
- i = adjust_index(idx)
- lines = [item] if item is not None else []
- return self.request('nvim_buf_set_lines', i, i + 1, True, lines)
- lines = item if item is not None else []
- start = adjust_index(idx.start, 0)
- end = adjust_index(idx.stop, -1)
- return self.request('nvim_buf_set_lines', start, end, False, lines)
-
- def __iter__(self):
- """Iterate lines of a buffer.
-
- This will retrieve all lines locally before iteration starts. This
- approach is used because for most cases, the gain is much greater by
- minimizing the number of API calls by transfering all data needed to
- work.
- """
- lines = self[:]
- for line in lines:
- yield line
-
- def __delitem__(self, idx):
- """Delete line or slice of lines from the buffer.
-
- This is the same as __setitem__(idx, [])
- """
- self.__setitem__(idx, None)
-
- def __ne__(self, other):
- """Test inequality of Buffers.
-
- Necessary for Python 2 compatibility.
- """
- return not self.__eq__(other)
-
- def append(self, lines, index=-1):
- """Append a string or list of lines to the buffer."""
- if isinstance(lines, (basestring, bytes)):
- lines = [lines]
- return self.request('nvim_buf_set_lines', index, index, True, lines)
-
- def mark(self, name):
- """Return (row, col) tuple for a named mark."""
- return self.request('nvim_buf_get_mark', name)
-
- def range(self, start, end):
- """Return a `Range` object, which represents part of the Buffer."""
- return Range(self, start, end)
-
- def add_highlight(self, hl_group, line, col_start=0,
- col_end=-1, src_id=-1, async_=None,
- **kwargs):
- """Add a highlight to the buffer."""
- async_ = check_async(async_, kwargs, src_id != 0)
- return self.request('nvim_buf_add_highlight', src_id, hl_group,
- line, col_start, col_end, async_=async_)
-
- def clear_highlight(self, src_id, line_start=0, line_end=-1, async_=None,
- **kwargs):
- """Clear highlights from the buffer."""
- async_ = check_async(async_, kwargs, True)
- self.request('nvim_buf_clear_highlight', src_id,
- line_start, line_end, async_=async_)
-
- def update_highlights(self, src_id, hls, clear_start=0, clear_end=-1,
- clear=False, async_=True):
- """Add or update highlights in batch to avoid unnecessary redraws.
-
- A `src_id` must have been allocated prior to use of this function. Use
- for instance `nvim.new_highlight_source()` to get a src_id for your
- plugin.
-
- `hls` should be a list of highlight items. Each item should be a list
- or tuple on the form `("GroupName", linenr, col_start, col_end)` or
- `("GroupName", linenr)` to highlight an entire line.
-
- By default existing highlights are preserved. Specify a line range with
- clear_start and clear_end to replace highlights in this range. As a
- shorthand, use clear=True to clear the entire buffer before adding the
- new highlights.
- """
- if clear and clear_start is None:
- clear_start = 0
- lua = self._session._get_lua_private()
- lua.update_highlights(self, src_id, hls, clear_start, clear_end,
- async_=async_)
-
- @property
- def name(self):
- """Get the buffer name."""
- return self.request('nvim_buf_get_name')
-
- @name.setter
- def name(self, value):
- """Set the buffer name. BufFilePre/BufFilePost are triggered."""
- return self.request('nvim_buf_set_name', value)
-
- @property
- def valid(self):
- """Return True if the buffer still exists."""
- return self.request('nvim_buf_is_valid')
-
- @property
- def number(self):
- """Get the buffer number."""
- return self.handle
-
-
-class Range(object):
- def __init__(self, buffer, start, end):
- self._buffer = buffer
- self.start = start - 1
- self.end = end - 1
-
- def __len__(self):
- return self.end - self.start + 1
-
- def __getitem__(self, idx):
- if not isinstance(idx, slice):
- return self._buffer[self._normalize_index(idx)]
- start = self._normalize_index(idx.start)
- end = self._normalize_index(idx.stop)
- if start is None:
- start = self.start
- if end is None:
- end = self.end + 1
- return self._buffer[start:end]
-
- def __setitem__(self, idx, lines):
- if not isinstance(idx, slice):
- self._buffer[self._normalize_index(idx)] = lines
- return
- start = self._normalize_index(idx.start)
- end = self._normalize_index(idx.stop)
- if start is None:
- start = self.start
- if end is None:
- end = self.end
- self._buffer[start:end + 1] = lines
-
- def __iter__(self):
- for i in range(self.start, self.end + 1):
- yield self._buffer[i]
-
- def append(self, lines, i=None):
- i = self._normalize_index(i)
- if i is None:
- i = self.end + 1
- self._buffer.append(lines, i)
-
- def _normalize_index(self, index):
- if index is None:
- return None
- if index < 0:
- index = self.end
- else:
- index += self.start
- if index > self.end:
- index = self.end
- return index
+++ /dev/null
-"""Code shared between the API classes."""
-import functools
-
-from msgpack import unpackb
-
-from pynvim.compat import unicode_errors_default
-
-__all__ = ()
-
-
-class NvimError(Exception):
- pass
-
-
-class Remote(object):
-
- """Base class for Nvim objects(buffer/window/tabpage).
-
- Each type of object has it's own specialized class with API wrappers around
- the msgpack-rpc session. This implements equality which takes the remote
- object handle into consideration.
- """
-
- def __init__(self, session, code_data):
- """Initialize from session and code_data immutable object.
-
- The `code_data` contains serialization information required for
- msgpack-rpc calls. It must be immutable for Buffer equality to work.
- """
- self._session = session
- self.code_data = code_data
- self.handle = unpackb(code_data[1])
- self.api = RemoteApi(self, self._api_prefix)
- self.vars = RemoteMap(self, self._api_prefix + 'get_var',
- self._api_prefix + 'set_var',
- self._api_prefix + 'del_var')
- self.options = RemoteMap(self, self._api_prefix + 'get_option',
- self._api_prefix + 'set_option')
-
- def __repr__(self):
- """Get text representation of the object."""
- return '<%s(handle=%r)>' % (
- self.__class__.__name__,
- self.handle,
- )
-
- def __eq__(self, other):
- """Return True if `self` and `other` are the same object."""
- return (hasattr(other, 'code_data')
- and other.code_data == self.code_data)
-
- def __hash__(self):
- """Return hash based on remote object id."""
- return self.code_data.__hash__()
-
- def request(self, name, *args, **kwargs):
- """Wrapper for nvim.request."""
- return self._session.request(name, self, *args, **kwargs)
-
-
-class RemoteApi(object):
-
- """Wrapper to allow api methods to be called like python methods."""
-
- def __init__(self, obj, api_prefix):
- """Initialize a RemoteApi with object and api prefix."""
- self._obj = obj
- self._api_prefix = api_prefix
-
- def __getattr__(self, name):
- """Return wrapper to named api method."""
- return functools.partial(self._obj.request, self._api_prefix + name)
-
-
-def transform_keyerror(exc):
- if isinstance(exc, NvimError):
- if exc.args[0].startswith('Key not found:'):
- return KeyError(exc.args[0])
- if exc.args[0].startswith('Invalid option name:'):
- return KeyError(exc.args[0])
- return exc
-
-
-class RemoteMap(object):
- """Represents a string->object map stored in Nvim.
-
- This is the dict counterpart to the `RemoteSequence` class, but it is used
- as a generic way of retrieving values from the various map-like data
- structures present in Nvim.
-
- It is used to provide a dict-like API to vim variables and options.
- """
-
- _set = None
- _del = None
-
- def __init__(self, obj, get_method, set_method=None, del_method=None):
- """Initialize a RemoteMap with session, getter/setter."""
- self._get = functools.partial(obj.request, get_method)
- if set_method:
- self._set = functools.partial(obj.request, set_method)
- if del_method:
- self._del = functools.partial(obj.request, del_method)
-
- def __getitem__(self, key):
- """Return a map value by key."""
- try:
- return self._get(key)
- except NvimError as exc:
- raise transform_keyerror(exc)
-
- def __setitem__(self, key, value):
- """Set a map value by key(if the setter was provided)."""
- if not self._set:
- raise TypeError('This dict is read-only')
- self._set(key, value)
-
- def __delitem__(self, key):
- """Delete a map value by associating None with the key."""
- if not self._del:
- raise TypeError('This dict is read-only')
- try:
- return self._del(key)
- except NvimError as exc:
- raise transform_keyerror(exc)
-
- def __contains__(self, key):
- """Check if key is present in the map."""
- try:
- self._get(key)
- return True
- except Exception:
- return False
-
- def get(self, key, default=None):
- """Return value for key if present, else a default value."""
- try:
- return self.__getitem__(key)
- except KeyError:
- return default
-
-
-class RemoteSequence(object):
-
- """Represents a sequence of objects stored in Nvim.
-
- This class is used to wrap msgapck-rpc functions that work on Nvim
- sequences(of lines, buffers, windows and tabpages) with an API that
- is similar to the one provided by the python-vim interface.
-
- For example, the 'windows' property of the `Nvim` class is a RemoteSequence
- sequence instance, and the expression `nvim.windows[0]` is translated to
- session.request('nvim_list_wins')[0].
-
- One important detail about this class is that all methods will fetch the
- sequence into a list and perform the necessary manipulation
- locally(iteration, indexing, counting, etc).
- """
-
- def __init__(self, session, method):
- """Initialize a RemoteSequence with session, method."""
- self._fetch = functools.partial(session.request, method)
-
- def __len__(self):
- """Return the length of the remote sequence."""
- return len(self._fetch())
-
- def __getitem__(self, idx):
- """Return a sequence item by index."""
- if not isinstance(idx, slice):
- return self._fetch()[idx]
- return self._fetch()[idx.start:idx.stop]
-
- def __iter__(self):
- """Return an iterator for the sequence."""
- items = self._fetch()
- for item in items:
- yield item
-
- def __contains__(self, item):
- """Check if an item is present in the sequence."""
- return item in self._fetch()
-
-
-def _identity(obj, session, method, kind):
- return obj
-
-
-def decode_if_bytes(obj, mode=True):
- """Decode obj if it is bytes."""
- if mode is True:
- mode = unicode_errors_default
- if isinstance(obj, bytes):
- return obj.decode("utf-8", errors=mode)
- return obj
-
-
-def walk(fn, obj, *args, **kwargs):
- """Recursively walk an object graph applying `fn`/`args` to objects."""
- if type(obj) in [list, tuple]:
- return list(walk(fn, o, *args) for o in obj)
- if type(obj) is dict:
- return dict((walk(fn, k, *args), walk(fn, v, *args)) for k, v in
- obj.items())
- return fn(obj, *args, **kwargs)
+++ /dev/null
-"""Main Nvim interface."""
-import os
-import sys
-import threading
-from functools import partial
-from traceback import format_stack
-
-from msgpack import ExtType
-
-from pynvim.api.buffer import Buffer
-from pynvim.api.common import (NvimError, Remote, RemoteApi, RemoteMap, RemoteSequence,
- decode_if_bytes, walk)
-from pynvim.api.tabpage import Tabpage
-from pynvim.api.window import Window
-from pynvim.compat import IS_PYTHON3
-from pynvim.util import Version, format_exc_skip
-
-__all__ = ('Nvim')
-
-
-os_chdir = os.chdir
-
-lua_module = """
-local a = vim.api
-local function update_highlights(buf, src_id, hls, clear_first, clear_end)
- if clear_first ~= nil then
- a.nvim_buf_clear_highlight(buf, src_id, clear_first, clear_end)
- end
- for _,hl in pairs(hls) do
- local group, line, col_start, col_end = unpack(hl)
- if col_start == nil then
- col_start = 0
- end
- if col_end == nil then
- col_end = -1
- end
- a.nvim_buf_add_highlight(buf, src_id, group, line, col_start, col_end)
- end
-end
-
-local chid = ...
-local mod = {update_highlights=update_highlights}
-_G["_pynvim_"..chid] = mod
-"""
-
-
-class Nvim(object):
-
- """Class that represents a remote Nvim instance.
-
- This class is main entry point to Nvim remote API, it is a wrapper
- around Session instances.
-
- The constructor of this class must not be called directly. Instead, the
- `from_session` class method should be used to create the first instance
- from a raw `Session` instance.
-
- Subsequent instances for the same session can be created by calling the
- `with_decode` instance method to change the decoding behavior or
- `SubClass.from_nvim(nvim)` where `SubClass` is a subclass of `Nvim`, which
- is useful for having multiple `Nvim` objects that behave differently
- without one affecting the other.
-
- When this library is used on python3.4+, asyncio event loop is guaranteed
- to be used. It is available as the "loop" attribute of this class. Note
- that asyncio callbacks cannot make blocking requests, which includes
- accessing state-dependent attributes. They should instead schedule another
- callback using nvim.async_call, which will not have this restriction.
- """
-
- @classmethod
- def from_session(cls, session):
- """Create a new Nvim instance for a Session instance.
-
- This method must be called to create the first Nvim instance, since it
- queries Nvim metadata for type information and sets a SessionHook for
- creating specialized objects from Nvim remote handles.
- """
- session.error_wrapper = lambda e: NvimError(decode_if_bytes(e[1]))
- channel_id, metadata = session.request(b'nvim_get_api_info')
-
- if IS_PYTHON3:
- # decode all metadata strings for python3
- metadata = walk(decode_if_bytes, metadata)
-
- types = {
- metadata['types']['Buffer']['id']: Buffer,
- metadata['types']['Window']['id']: Window,
- metadata['types']['Tabpage']['id']: Tabpage,
- }
-
- return cls(session, channel_id, metadata, types)
-
- @classmethod
- def from_nvim(cls, nvim):
- """Create a new Nvim instance from an existing instance."""
- return cls(nvim._session, nvim.channel_id, nvim.metadata,
- nvim.types, nvim._decode, nvim._err_cb)
-
- def __init__(self, session, channel_id, metadata, types,
- decode=False, err_cb=None):
- """Initialize a new Nvim instance. This method is module-private."""
- self._session = session
- self.channel_id = channel_id
- self.metadata = metadata
- version = metadata.get("version", {"api_level": 0})
- self.version = Version(**version)
- self.types = types
- self.api = RemoteApi(self, 'nvim_')
- self.vars = RemoteMap(self, 'nvim_get_var', 'nvim_set_var', 'nvim_del_var')
- self.vvars = RemoteMap(self, 'nvim_get_vvar', None, None)
- self.options = RemoteMap(self, 'nvim_get_option', 'nvim_set_option')
- self.buffers = Buffers(self)
- self.windows = RemoteSequence(self, 'nvim_list_wins')
- self.tabpages = RemoteSequence(self, 'nvim_list_tabpages')
- self.current = Current(self)
- self.session = CompatibilitySession(self)
- self.funcs = Funcs(self)
- self.lua = LuaFuncs(self)
- self.error = NvimError
- self._decode = decode
- self._err_cb = err_cb
-
- # only on python3.4+ we expose asyncio
- if IS_PYTHON3:
- self.loop = self._session.loop._loop
-
- def _from_nvim(self, obj, decode=None):
- if decode is None:
- decode = self._decode
- if type(obj) is ExtType:
- cls = self.types[obj.code]
- return cls(self, (obj.code, obj.data))
- if decode:
- obj = decode_if_bytes(obj, decode)
- return obj
-
- def _to_nvim(self, obj):
- if isinstance(obj, Remote):
- return ExtType(*obj.code_data)
- return obj
-
- def _get_lua_private(self):
- if not getattr(self._session, "_has_lua", False):
- self.exec_lua(lua_module, self.channel_id)
- self._session._has_lua = True
- return getattr(self.lua, "_pynvim_{}".format(self.channel_id))
-
- def request(self, name, *args, **kwargs):
- r"""Send an API request or notification to nvim.
-
- It is rarely needed to call this function directly, as most API
- functions have python wrapper functions. The `api` object can
- be also be used to call API functions as methods:
-
- vim.api.err_write('ERROR\n', async_=True)
- vim.current.buffer.api.get_mark('.')
-
- is equivalent to
-
- vim.request('nvim_err_write', 'ERROR\n', async_=True)
- vim.request('nvim_buf_get_mark', vim.current.buffer, '.')
-
-
- Normally a blocking request will be sent. If the `async_` flag is
- present and True, a asynchronous notification is sent instead. This
- will never block, and the return value or error is ignored.
- """
- if (self._session._loop_thread is not None
- and threading.current_thread() != self._session._loop_thread):
-
- msg = ("Request from non-main thread.\n"
- "Requests from different threads should be wrapped "
- "with nvim.async_call(cb, ...) \n{}\n"
- .format('\n'.join(format_stack(None, 5)[:-1])))
-
- self.async_call(self._err_cb, msg)
- raise NvimError("request from non-main thread")
-
- decode = kwargs.pop('decode', self._decode)
- args = walk(self._to_nvim, args)
- res = self._session.request(name, *args, **kwargs)
- return walk(self._from_nvim, res, decode=decode)
-
- def next_message(self):
- """Block until a message(request or notification) is available.
-
- If any messages were previously enqueued, return the first in queue.
- If not, run the event loop until one is received.
- """
- msg = self._session.next_message()
- if msg:
- return walk(self._from_nvim, msg)
-
- def run_loop(self, request_cb, notification_cb,
- setup_cb=None, err_cb=None):
- """Run the event loop to receive requests and notifications from Nvim.
-
- This should not be called from a plugin running in the host, which
- already runs the loop and dispatches events to plugins.
- """
- if err_cb is None:
- err_cb = sys.stderr.write
- self._err_cb = err_cb
-
- def filter_request_cb(name, args):
- name = self._from_nvim(name)
- args = walk(self._from_nvim, args)
- try:
- result = request_cb(name, args)
- except Exception:
- msg = ("error caught in request handler '{} {}'\n{}\n\n"
- .format(name, args, format_exc_skip(1)))
- self._err_cb(msg)
- raise
- return walk(self._to_nvim, result)
-
- def filter_notification_cb(name, args):
- name = self._from_nvim(name)
- args = walk(self._from_nvim, args)
- try:
- notification_cb(name, args)
- except Exception:
- msg = ("error caught in notification handler '{} {}'\n{}\n\n"
- .format(name, args, format_exc_skip(1)))
- self._err_cb(msg)
- raise
-
- self._session.run(filter_request_cb, filter_notification_cb, setup_cb)
-
- def stop_loop(self):
- """Stop the event loop being started with `run_loop`."""
- self._session.stop()
-
- def close(self):
- """Close the nvim session and release its resources."""
- self._session.close()
-
- def __enter__(self):
- """Enter nvim session as a context manager."""
- return self
-
- def __exit__(self, *exc_info):
- """Exit nvim session as a context manager.
-
- Closes the event loop.
- """
- self.close()
-
- def with_decode(self, decode=True):
- """Initialize a new Nvim instance."""
- return Nvim(self._session, self.channel_id,
- self.metadata, self.types, decode, self._err_cb)
-
- def ui_attach(self, width, height, rgb=None, **kwargs):
- """Register as a remote UI.
-
- After this method is called, the client will receive redraw
- notifications.
- """
- options = kwargs
- if rgb is not None:
- options['rgb'] = rgb
- return self.request('nvim_ui_attach', width, height, options)
-
- def ui_detach(self):
- """Unregister as a remote UI."""
- return self.request('nvim_ui_detach')
-
- def ui_try_resize(self, width, height):
- """Notify nvim that the client window has resized.
-
- If possible, nvim will send a redraw request to resize.
- """
- return self.request('ui_try_resize', width, height)
-
- def subscribe(self, event):
- """Subscribe to a Nvim event."""
- return self.request('nvim_subscribe', event)
-
- def unsubscribe(self, event):
- """Unsubscribe to a Nvim event."""
- return self.request('nvim_unsubscribe', event)
-
- def command(self, string, **kwargs):
- """Execute a single ex command."""
- return self.request('nvim_command', string, **kwargs)
-
- def command_output(self, string):
- """Execute a single ex command and return the output."""
- return self.request('nvim_command_output', string)
-
- def eval(self, string, **kwargs):
- """Evaluate a vimscript expression."""
- return self.request('nvim_eval', string, **kwargs)
-
- def call(self, name, *args, **kwargs):
- """Call a vimscript function."""
- return self.request('nvim_call_function', name, args, **kwargs)
-
- def exec_lua(self, code, *args, **kwargs):
- """Execute lua code.
-
- Additional parameters are available as `...` inside the lua chunk.
- Only statements are executed. To evaluate an expression, prefix it
- with `return`: `return my_function(...)`
-
- There is a shorthand syntax to call lua functions with arguments:
-
- nvim.lua.func(1,2)
- nvim.lua.mymod.myfunction(data, async_=True)
-
- is equivalent to
-
- nvim.exec_lua("return func(...)", 1, 2)
- nvim.exec_lua("mymod.myfunction(...)", data, async_=True)
-
- Note that with `async_=True` there is no return value.
- """
- return self.request('nvim_execute_lua', code, args, **kwargs)
-
- def strwidth(self, string):
- """Return the number of display cells `string` occupies.
-
- Tab is counted as one cell.
- """
- return self.request('nvim_strwidth', string)
-
- def list_runtime_paths(self):
- """Return a list of paths contained in the 'runtimepath' option."""
- return self.request('nvim_list_runtime_paths')
-
- def foreach_rtp(self, cb):
- """Invoke `cb` for each path in 'runtimepath'.
-
- Call the given callable for each path in 'runtimepath' until either
- callable returns something but None, the exception is raised or there
- are no longer paths. If stopped in case callable returned non-None,
- vim.foreach_rtp function returns the value returned by callable.
- """
- for path in self.request('nvim_list_runtime_paths'):
- try:
- if cb(path) is not None:
- break
- except Exception:
- break
-
- def chdir(self, dir_path):
- """Run os.chdir, then all appropriate vim stuff."""
- os_chdir(dir_path)
- return self.request('nvim_set_current_dir', dir_path)
-
- def feedkeys(self, keys, options='', escape_csi=True):
- """Push `keys` to Nvim user input buffer.
-
- Options can be a string with the following character flags:
- - 'm': Remap keys. This is default.
- - 'n': Do not remap keys.
- - 't': Handle keys as if typed; otherwise they are handled as if coming
- from a mapping. This matters for undo, opening folds, etc.
- """
- return self.request('nvim_feedkeys', keys, options, escape_csi)
-
- def input(self, bytes):
- """Push `bytes` to Nvim low level input buffer.
-
- Unlike `feedkeys()`, this uses the lowest level input buffer and the
- call is not deferred. It returns the number of bytes actually
- written(which can be less than what was requested if the buffer is
- full).
- """
- return self.request('nvim_input', bytes)
-
- def replace_termcodes(self, string, from_part=False, do_lt=True,
- special=True):
- r"""Replace any terminal code strings by byte sequences.
-
- The returned sequences are Nvim's internal representation of keys,
- for example:
-
- <esc> -> '\x1b'
- <cr> -> '\r'
- <c-l> -> '\x0c'
- <up> -> '\x80ku'
-
- The returned sequences can be used as input to `feedkeys`.
- """
- return self.request('nvim_replace_termcodes', string,
- from_part, do_lt, special)
-
- def out_write(self, msg, **kwargs):
- r"""Print `msg` as a normal message.
-
- The message is buffered (won't display) until linefeed ("\n").
- """
- return self.request('nvim_out_write', msg, **kwargs)
-
- def err_write(self, msg, **kwargs):
- r"""Print `msg` as an error message.
-
- The message is buffered (won't display) until linefeed ("\n").
- """
- if self._thread_invalid():
- # special case: if a non-main thread writes to stderr
- # i.e. due to an uncaught exception, pass it through
- # without raising an additional exception.
- self.async_call(self.err_write, msg, **kwargs)
- return
- return self.request('nvim_err_write', msg, **kwargs)
-
- def _thread_invalid(self):
- return (self._session._loop_thread is not None
- and threading.current_thread() != self._session._loop_thread)
-
- def quit(self, quit_command='qa!'):
- """Send a quit command to Nvim.
-
- By default, the quit command is 'qa!' which will make Nvim quit without
- saving anything.
- """
- try:
- self.command(quit_command)
- except OSError:
- # sending a quit command will raise an IOError because the
- # connection is closed before a response is received. Safe to
- # ignore it.
- pass
-
- def new_highlight_source(self):
- """Return new src_id for use with Buffer.add_highlight."""
- return self.current.buffer.add_highlight("", 0, src_id=0)
-
- def async_call(self, fn, *args, **kwargs):
- """Schedule `fn` to be called by the event loop soon.
-
- This function is thread-safe, and is the only way code not
- on the main thread could interact with nvim api objects.
-
- This function can also be called in a synchronous
- event handler, just before it returns, to defer execution
- that shouldn't block neovim.
- """
- call_point = ''.join(format_stack(None, 5)[:-1])
-
- def handler():
- try:
- fn(*args, **kwargs)
- except Exception as err:
- msg = ("error caught while executing async callback:\n"
- "{!r}\n{}\n \nthe call was requested at\n{}"
- .format(err, format_exc_skip(1), call_point))
- self._err_cb(msg)
- raise
- self._session.threadsafe_call(handler)
-
-
-class Buffers(object):
-
- """Remote NVim buffers.
-
- Currently the interface for interacting with remote NVim buffers is the
- `nvim_list_bufs` msgpack-rpc function. Most methods fetch the list of
- buffers from NVim.
-
- Conforms to *python-buffers*.
- """
-
- def __init__(self, nvim):
- """Initialize a Buffers object with Nvim object `nvim`."""
- self._fetch_buffers = nvim.api.list_bufs
-
- def __len__(self):
- """Return the count of buffers."""
- return len(self._fetch_buffers())
-
- def __getitem__(self, number):
- """Return the Buffer object matching buffer number `number`."""
- for b in self._fetch_buffers():
- if b.number == number:
- return b
- raise KeyError(number)
-
- def __contains__(self, b):
- """Return whether Buffer `b` is a known valid buffer."""
- return isinstance(b, Buffer) and b.valid
-
- def __iter__(self):
- """Return an iterator over the list of buffers."""
- return iter(self._fetch_buffers())
-
-
-class CompatibilitySession(object):
-
- """Helper class for API compatibility."""
-
- def __init__(self, nvim):
- self.threadsafe_call = nvim.async_call
-
-
-class Current(object):
-
- """Helper class for emulating vim.current from python-vim."""
-
- def __init__(self, session):
- self._session = session
- self.range = None
-
- @property
- def line(self):
- return self._session.request('nvim_get_current_line')
-
- @line.setter
- def line(self, line):
- return self._session.request('nvim_set_current_line', line)
-
- @line.deleter
- def line(self):
- return self._session.request('nvim_del_current_line')
-
- @property
- def buffer(self):
- return self._session.request('nvim_get_current_buf')
-
- @buffer.setter
- def buffer(self, buffer):
- return self._session.request('nvim_set_current_buf', buffer)
-
- @property
- def window(self):
- return self._session.request('nvim_get_current_win')
-
- @window.setter
- def window(self, window):
- return self._session.request('nvim_set_current_win', window)
-
- @property
- def tabpage(self):
- return self._session.request('nvim_get_current_tabpage')
-
- @tabpage.setter
- def tabpage(self, tabpage):
- return self._session.request('nvim_set_current_tabpage', tabpage)
-
-
-class Funcs(object):
-
- """Helper class for functional vimscript interface."""
-
- def __init__(self, nvim):
- self._nvim = nvim
-
- def __getattr__(self, name):
- return partial(self._nvim.call, name)
-
-
-class LuaFuncs(object):
-
- """Wrapper to allow lua functions to be called like python methods."""
-
- def __init__(self, nvim, name=""):
- self._nvim = nvim
- self.name = name
-
- def __getattr__(self, name):
- """Return wrapper to named api method."""
- prefix = self.name + "." if self.name else ""
- return LuaFuncs(self._nvim, prefix + name)
-
- def __call__(self, *args, **kwargs):
- # first new function after keyword rename, be a bit noisy
- if 'async' in kwargs:
- raise ValueError('"async" argument is not allowed. '
- 'Use "async_" instead.')
- async_ = kwargs.get('async_', False)
- pattern = "return {}(...)" if not async_ else "{}(...)"
- code = pattern.format(self.name)
- return self._nvim.exec_lua(code, *args, **kwargs)
+++ /dev/null
-"""API for working with Nvim tabpages."""
-from pynvim.api.common import Remote, RemoteSequence
-
-
-__all__ = ('Tabpage')
-
-
-class Tabpage(Remote):
- """A remote Nvim tabpage."""
-
- _api_prefix = "nvim_tabpage_"
-
- def __init__(self, *args):
- """Initialize from session and code_data immutable object.
-
- The `code_data` contains serialization information required for
- msgpack-rpc calls. It must be immutable for Buffer equality to work.
- """
- super(Tabpage, self).__init__(*args)
- self.windows = RemoteSequence(self, 'nvim_tabpage_list_wins')
-
- @property
- def window(self):
- """Get the `Window` currently focused on the tabpage."""
- return self.request('nvim_tabpage_get_win')
-
- @property
- def valid(self):
- """Return True if the tabpage still exists."""
- return self.request('nvim_tabpage_is_valid')
-
- @property
- def number(self):
- """Get the tabpage number."""
- return self.request('nvim_tabpage_get_number')
+++ /dev/null
-"""API for working with Nvim windows."""
-from pynvim.api.common import Remote
-
-
-__all__ = ('Window')
-
-
-class Window(Remote):
-
- """A remote Nvim window."""
-
- _api_prefix = "nvim_win_"
-
- @property
- def buffer(self):
- """Get the `Buffer` currently being displayed by the window."""
- return self.request('nvim_win_get_buf')
-
- @property
- def cursor(self):
- """Get the (row, col) tuple with the current cursor position."""
- return self.request('nvim_win_get_cursor')
-
- @cursor.setter
- def cursor(self, pos):
- """Set the (row, col) tuple as the new cursor position."""
- return self.request('nvim_win_set_cursor', pos)
-
- @property
- def height(self):
- """Get the window height in rows."""
- return self.request('nvim_win_get_height')
-
- @height.setter
- def height(self, height):
- """Set the window height in rows."""
- return self.request('nvim_win_set_height', height)
-
- @property
- def width(self):
- """Get the window width in rows."""
- return self.request('nvim_win_get_width')
-
- @width.setter
- def width(self, width):
- """Set the window height in rows."""
- return self.request('nvim_win_set_width', width)
-
- @property
- def row(self):
- """0-indexed, on-screen window position(row) in display cells."""
- return self.request('nvim_win_get_position')[0]
-
- @property
- def col(self):
- """0-indexed, on-screen window position(col) in display cells."""
- return self.request('nvim_win_get_position')[1]
-
- @property
- def tabpage(self):
- """Get the `Tabpage` that contains the window."""
- return self.request('nvim_win_get_tabpage')
-
- @property
- def valid(self):
- """Return True if the window still exists."""
- return self.request('nvim_win_is_valid')
-
- @property
- def number(self):
- """Get the window number."""
- return self.request('nvim_win_get_number')
+++ /dev/null
-"""Code for compatibility across Python versions."""
-
-import sys
-import warnings
-from imp import find_module as original_find_module
-
-
-IS_PYTHON3 = sys.version_info >= (3, 0)
-
-
-if IS_PYTHON3:
- def find_module(fullname, path):
- """Compatibility wrapper for imp.find_module.
-
- Automatically decodes arguments of find_module, in Python3
- they must be Unicode
- """
- if isinstance(fullname, bytes):
- fullname = fullname.decode()
- if isinstance(path, bytes):
- path = path.decode()
- elif isinstance(path, list):
- newpath = []
- for element in path:
- if isinstance(element, bytes):
- newpath.append(element.decode())
- else:
- newpath.append(element)
- path = newpath
- return original_find_module(fullname, path)
-
- # There is no 'long' type in Python3 just int
- long = int
- unicode_errors_default = 'surrogateescape'
-else:
- find_module = original_find_module
- unicode_errors_default = 'ignore'
-
-NUM_TYPES = (int, long, float)
-
-
-def check_async(async_, kwargs, default):
- """Return a value of 'async' in kwargs or default when async_ is None.
-
- This helper function exists for backward compatibility (See #274).
- It shows a warning message when 'async' in kwargs is used to note users.
- """
- if async_ is not None:
- return async_
- elif 'async' in kwargs:
- warnings.warn(
- '"async" attribute is deprecated. Use "async_" instead.',
- DeprecationWarning,
- )
- return kwargs.pop('async')
- else:
- return default
+++ /dev/null
-"""Msgpack-rpc subpackage.
-
-This package implements a msgpack-rpc client. While it was designed for
-handling some Nvim particularities(server->client requests for example), the
-code here should work with other msgpack-rpc servers.
-"""
-from pynvim.msgpack_rpc.async_session import AsyncSession
-from pynvim.msgpack_rpc.event_loop import EventLoop
-from pynvim.msgpack_rpc.msgpack_stream import MsgpackStream
-from pynvim.msgpack_rpc.session import ErrorResponse, Session
-from pynvim.util import get_client_info
-
-
-__all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
- 'ErrorResponse')
-
-
-def session(transport_type='stdio', *args, **kwargs):
- loop = EventLoop(transport_type, *args, **kwargs)
- msgpack_stream = MsgpackStream(loop)
- async_session = AsyncSession(msgpack_stream)
- session = Session(async_session)
- session.request(b'nvim_set_client_info',
- *get_client_info('client', 'remote', {}), async_=True)
- return session
-
-
-def tcp_session(address, port=7450):
- """Create a msgpack-rpc session from a tcp address/port."""
- return session('tcp', address, port)
-
-
-def socket_session(path):
- """Create a msgpack-rpc session from a unix domain socket."""
- return session('socket', path)
-
-
-def stdio_session():
- """Create a msgpack-rpc session from stdin/stdout."""
- return session('stdio')
-
-
-def child_session(argv):
- """Create a msgpack-rpc session from a new Nvim instance."""
- return session('child', argv)
+++ /dev/null
-"""Asynchronous msgpack-rpc handling in the event loop pipeline."""
-import logging
-from traceback import format_exc
-
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-
-class AsyncSession(object):
-
- """Asynchronous msgpack-rpc layer that wraps a msgpack stream.
-
- This wraps the msgpack stream interface for reading/writing msgpack
- documents and exposes an interface for sending and receiving msgpack-rpc
- requests and notifications.
- """
-
- def __init__(self, msgpack_stream):
- """Wrap `msgpack_stream` on a msgpack-rpc interface."""
- self._msgpack_stream = msgpack_stream
- self._next_request_id = 1
- self._pending_requests = {}
- self._request_cb = self._notification_cb = None
- self._handlers = {
- 0: self._on_request,
- 1: self._on_response,
- 2: self._on_notification
- }
- self.loop = msgpack_stream.loop
-
- def threadsafe_call(self, fn):
- """Wrapper around `MsgpackStream.threadsafe_call`."""
- self._msgpack_stream.threadsafe_call(fn)
-
- def request(self, method, args, response_cb):
- """Send a msgpack-rpc request to Nvim.
-
- A msgpack-rpc with method `method` and argument `args` is sent to
- Nvim. The `response_cb` function is called with when the response
- is available.
- """
- request_id = self._next_request_id
- self._next_request_id = request_id + 1
- self._msgpack_stream.send([0, request_id, method, args])
- self._pending_requests[request_id] = response_cb
-
- def notify(self, method, args):
- """Send a msgpack-rpc notification to Nvim.
-
- A msgpack-rpc with method `method` and argument `args` is sent to
- Nvim. This will have the same effect as a request, but no response
- will be recieved
- """
- self._msgpack_stream.send([2, method, args])
-
- def run(self, request_cb, notification_cb):
- """Run the event loop to receive requests and notifications from Nvim.
-
- While the event loop is running, `request_cb` and `notification_cb`
- will be called whenever requests or notifications are respectively
- available.
- """
- self._request_cb = request_cb
- self._notification_cb = notification_cb
- self._msgpack_stream.run(self._on_message)
- self._request_cb = None
- self._notification_cb = None
-
- def stop(self):
- """Stop the event loop."""
- self._msgpack_stream.stop()
-
- def close(self):
- """Close the event loop."""
- self._msgpack_stream.close()
-
- def _on_message(self, msg):
- try:
- self._handlers.get(msg[0], self._on_invalid_message)(msg)
- except Exception:
- err_str = format_exc(5)
- pass # replaces next logging statement
- #warn(err_str)
- self._msgpack_stream.send([1, 0, err_str, None])
-
- def _on_request(self, msg):
- # request
- # - msg[1]: id
- # - msg[2]: method name
- # - msg[3]: arguments
- pass # replaces next logging statement
- #debug('received request: %s, %s', msg[2], msg[3])
- self._request_cb(msg[2], msg[3], Response(self._msgpack_stream,
- msg[1]))
-
- def _on_response(self, msg):
- # response to a previous request:
- # - msg[1]: the id
- # - msg[2]: error(if any)
- # - msg[3]: result(if not errored)
- pass # replaces next logging statement
- #debug('received response: %s, %s', msg[2], msg[3])
- self._pending_requests.pop(msg[1])(msg[2], msg[3])
-
- def _on_notification(self, msg):
- # notification/event
- # - msg[1]: event name
- # - msg[2]: arguments
- pass # replaces next logging statement
- #debug('received notification: %s, %s', msg[1], msg[2])
- self._notification_cb(msg[1], msg[2])
-
- def _on_invalid_message(self, msg):
- error = 'Received invalid message %s' % msg
- pass # replaces next logging statement
- #warn(error)
- self._msgpack_stream.send([1, 0, error, None])
-
-
-class Response(object):
-
- """Response to a msgpack-rpc request that came from Nvim.
-
- When Nvim sends a msgpack-rpc request, an instance of this class is
- created for remembering state required to send a response.
- """
-
- def __init__(self, msgpack_stream, request_id):
- """Initialize the Response instance."""
- self._msgpack_stream = msgpack_stream
- self._request_id = request_id
-
- def send(self, value, error=False):
- """Send the response.
-
- If `error` is True, it will be sent as an error.
- """
- if error:
- resp = [1, self._request_id, value, None]
- else:
- resp = [1, self._request_id, None, value]
- pass # replaces next logging statement
- #debug('sending response to request %d: %s', self._request_id, resp)
- self._msgpack_stream.send(resp)
+++ /dev/null
-"""Event loop abstraction subpackage.
-
-Tries to use pyuv as a backend, falling back to the asyncio implementation.
-"""
-
-from pynvim.compat import IS_PYTHON3
-
-# on python3 we only support asyncio, as we expose it to plugins
-if IS_PYTHON3:
- from pynvim.msgpack_rpc.event_loop.asyncio import AsyncioEventLoop
- EventLoop = AsyncioEventLoop
-else:
- try:
- # libuv is fully implemented in C, use it when available
- from pynvim.msgpack_rpc.event_loop.uv import UvEventLoop
- EventLoop = UvEventLoop
- except ImportError:
- # asyncio(trollius on python 2) is pure python and should be more
- # portable across python implementations
- from pynvim.msgpack_rpc.event_loop.asyncio import AsyncioEventLoop
- EventLoop = AsyncioEventLoop
-
-
-__all__ = ('EventLoop')
+++ /dev/null
-"""Event loop implementation that uses the `asyncio` standard module.
-
-The `asyncio` module was added to python standard library on 3.4, and it
-provides a pure python implementation of an event loop library. It is used
-as a fallback in case pyuv is not available(on python implementations other
-than CPython).
-
-Earlier python versions are supported through the `trollius` package, which
-is a backport of `asyncio` that works on Python 2.6+.
-"""
-from __future__ import absolute_import
-
-import logging
-import os
-import sys
-from collections import deque
-
-try:
- # For python 3.4+, use the standard library module
- import asyncio
-except (ImportError, SyntaxError):
- # Fallback to trollius
- import trollius as asyncio
-
-from pynvim.msgpack_rpc.event_loop.base import BaseEventLoop
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-loop_cls = asyncio.SelectorEventLoop
-if os.name == 'nt':
- from asyncio.windows_utils import PipeHandle
- import msvcrt
-
- # On windows use ProactorEventLoop which support pipes and is backed by the
- # more powerful IOCP facility
- # NOTE: we override in the stdio case, because it doesn't work.
- loop_cls = asyncio.ProactorEventLoop
-
-
-class AsyncioEventLoop(BaseEventLoop, asyncio.Protocol,
- asyncio.SubprocessProtocol):
-
- """`BaseEventLoop` subclass that uses `asyncio` as a backend."""
-
- def connection_made(self, transport):
- """Used to signal `asyncio.Protocol` of a successful connection."""
- self._transport = transport
- self._raw_transport = transport
- if isinstance(transport, asyncio.SubprocessTransport):
- self._transport = transport.get_pipe_transport(0)
-
- def connection_lost(self, exc):
- """Used to signal `asyncio.Protocol` of a lost connection."""
- self._on_error(exc.args[0] if exc else 'EOF')
-
- def data_received(self, data):
- """Used to signal `asyncio.Protocol` of incoming data."""
- if self._on_data:
- self._on_data(data)
- return
- self._queued_data.append(data)
-
- def pipe_connection_lost(self, fd, exc):
- """Used to signal `asyncio.SubprocessProtocol` of a lost connection."""
- self._on_error(exc.args[0] if exc else 'EOF')
-
- def pipe_data_received(self, fd, data):
- """Used to signal `asyncio.SubprocessProtocol` of incoming data."""
- if fd == 2: # stderr fd number
- self._on_stderr(data)
- elif self._on_data:
- self._on_data(data)
- else:
- self._queued_data.append(data)
-
- def process_exited(self):
- """Used to signal `asyncio.SubprocessProtocol` when the child exits."""
- self._on_error('EOF')
-
- def _init(self):
- self._loop = loop_cls()
- self._queued_data = deque()
- self._fact = lambda: self
- self._raw_transport = None
-
- def _connect_tcp(self, address, port):
- coroutine = self._loop.create_connection(self._fact, address, port)
- self._loop.run_until_complete(coroutine)
-
- def _connect_socket(self, path):
- if os.name == 'nt':
- coroutine = self._loop.create_pipe_connection(self._fact, path)
- else:
- coroutine = self._loop.create_unix_connection(self._fact, path)
- self._loop.run_until_complete(coroutine)
-
- def _connect_stdio(self):
- if os.name == 'nt':
- pipe = PipeHandle(msvcrt.get_osfhandle(sys.stdin.fileno()))
- else:
- pipe = sys.stdin
- coroutine = self._loop.connect_read_pipe(self._fact, pipe)
- self._loop.run_until_complete(coroutine)
- pass # replaces next logging statement
- #debug("native stdin connection successful")
-
- # Make sure subprocesses don't clobber stdout,
- # send the output to stderr instead.
- rename_stdout = os.dup(sys.stdout.fileno())
- os.dup2(sys.stderr.fileno(), sys.stdout.fileno())
-
- if os.name == 'nt':
- pipe = PipeHandle(msvcrt.get_osfhandle(rename_stdout))
- else:
- pipe = os.fdopen(rename_stdout, 'wb')
- coroutine = self._loop.connect_write_pipe(self._fact, pipe)
- self._loop.run_until_complete(coroutine)
- pass # replaces next logging statement
- #debug("native stdout connection successful")
-
- def _connect_child(self, argv):
- if os.name != 'nt':
- self._child_watcher = asyncio.get_child_watcher()
- self._child_watcher.attach_loop(self._loop)
- coroutine = self._loop.subprocess_exec(self._fact, *argv)
- self._loop.run_until_complete(coroutine)
-
- def _start_reading(self):
- pass
-
- def _send(self, data):
- self._transport.write(data)
-
- def _run(self):
- while self._queued_data:
- self._on_data(self._queued_data.popleft())
- self._loop.run_forever()
-
- def _stop(self):
- self._loop.stop()
-
- def _close(self):
- if self._raw_transport is not None:
- self._raw_transport.close()
- self._loop.close()
-
- def _threadsafe_call(self, fn):
- self._loop.call_soon_threadsafe(fn)
-
- def _setup_signals(self, signals):
- if os.name == 'nt':
- # add_signal_handler is not supported in win32
- self._signals = []
- return
-
- self._signals = list(signals)
- for signum in self._signals:
- self._loop.add_signal_handler(signum, self._on_signal, signum)
-
- def _teardown_signals(self):
- for signum in self._signals:
- self._loop.remove_signal_handler(signum)
+++ /dev/null
-"""Common code for event loop implementations."""
-import logging
-import signal
-import threading
-
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-
-# When signals are restored, the event loop library may reset SIGINT to SIG_DFL
-# which exits the program. To be able to restore the python interpreter to it's
-# default state, we keep a reference to the default handler
-default_int_handler = signal.getsignal(signal.SIGINT)
-main_thread = threading.current_thread()
-
-
-class BaseEventLoop(object):
-
- """Abstract base class for all event loops.
-
- Event loops act as the bottom layer for Nvim sessions created by this
- library. They hide system/transport details behind a simple interface for
- reading/writing bytes to the connected Nvim instance.
-
- This class exposes public methods for interacting with the underlying
- event loop and delegates implementation-specific work to the following
- methods, which subclasses are expected to implement:
-
- - `_init()`: Implementation-specific initialization
- - `_connect_tcp(address, port)`: connect to Nvim using tcp/ip
- - `_connect_socket(path)`: Same as tcp, but use a UNIX domain socket or
- named pipe.
- - `_connect_stdio()`: Use stdin/stdout as the connection to Nvim
- - `_connect_child(argv)`: Use the argument vector `argv` to spawn an
- embedded Nvim that has its stdin/stdout connected to the event loop.
- - `_start_reading()`: Called after any of _connect_* methods. Can be used
- to perform any post-connection setup or validation.
- - `_send(data)`: Send `data`(byte array) to Nvim. The data is only
- - `_run()`: Runs the event loop until stopped or the connection is closed.
- calling the following methods when some event happens:
- actually sent when the event loop is running.
- - `_on_data(data)`: When Nvim sends some data.
- - `_on_signal(signum)`: When a signal is received.
- - `_on_error(message)`: When a non-recoverable error occurs(eg:
- connection lost)
- - `_stop()`: Stop the event loop
- - `_interrupt(data)`: Like `stop()`, but may be called from other threads
- this.
- - `_setup_signals(signals)`: Add implementation-specific listeners for
- for `signals`, which is a list of OS-specific signal numbers.
- - `_teardown_signals()`: Removes signal listeners set by `_setup_signals`
- """
-
- def __init__(self, transport_type, *args):
- """Initialize and connect the event loop instance.
-
- The only arguments are the transport type and transport-specific
- configuration, like this:
-
- >>> BaseEventLoop('tcp', '127.0.0.1', 7450)
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
- >>> BaseEventLoop('socket', '/tmp/nvim-socket')
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
- >>> BaseEventLoop('stdio')
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
- >>> BaseEventLoop('child',
- ['nvim', '--embed', '--headless', '-u', 'NONE'])
- Traceback (most recent call last):
- ...
- AttributeError: 'BaseEventLoop' object has no attribute '_init'
-
- This calls the implementation-specific initialization
- `_init`, one of the `_connect_*` methods(based on `transport_type`)
- and `_start_reading()`
- """
- self._transport_type = transport_type
- self._signames = dict((k, v) for v, k in signal.__dict__.items()
- if v.startswith('SIG'))
- self._on_data = None
- self._error = None
- self._init()
- try:
- getattr(self, '_connect_{}'.format(transport_type))(*args)
- except Exception as e:
- self.close()
- raise e
- self._start_reading()
-
- def connect_tcp(self, address, port):
- """Connect to tcp/ip `address`:`port`. Delegated to `_connect_tcp`."""
- pass # replaces next logging statement
- #info('Connecting to TCP address: %s:%d', address, port)
- self._connect_tcp(address, port)
-
- def connect_socket(self, path):
- """Connect to socket at `path`. Delegated to `_connect_socket`."""
- pass # replaces next logging statement
- #info('Connecting to %s', path)
- self._connect_socket(path)
-
- def connect_stdio(self):
- """Connect using stdin/stdout. Delegated to `_connect_stdio`."""
- pass # replaces next logging statement
- #info('Preparing stdin/stdout for streaming data')
- self._connect_stdio()
-
- def connect_child(self, argv):
- """Connect a new Nvim instance. Delegated to `_connect_child`."""
- pass # replaces next logging statement
- #info('Spawning a new nvim instance')
- self._connect_child(argv)
-
- def send(self, data):
- """Queue `data` for sending to Nvim."""
- pass # replaces next logging statement
- #debug("Sending '%s'", data)
- self._send(data)
-
- def threadsafe_call(self, fn):
- """Call a function in the event loop thread.
-
- This is the only safe way to interact with a session from other
- threads.
- """
- self._threadsafe_call(fn)
-
- def run(self, data_cb):
- """Run the event loop."""
- if self._error:
- err = self._error
- if isinstance(self._error, KeyboardInterrupt):
- # KeyboardInterrupt is not destructive(it may be used in
- # the REPL).
- # After throwing KeyboardInterrupt, cleanup the _error field
- # so the loop may be started again
- self._error = None
- raise err
- self._on_data = data_cb
- if threading.current_thread() == main_thread:
- self._setup_signals([signal.SIGINT, signal.SIGTERM])
- pass # replaces next logging statement
- #debug('Entering event loop')
- self._run()
- pass # replaces next logging statement
- #debug('Exited event loop')
- if threading.current_thread() == main_thread:
- self._teardown_signals()
- signal.signal(signal.SIGINT, default_int_handler)
- self._on_data = None
-
- def stop(self):
- """Stop the event loop."""
- self._stop()
- pass # replaces next logging statement
- #debug('Stopped event loop')
-
- def close(self):
- """Stop the event loop."""
- self._close()
- pass # replaces next logging statement
- #debug('Closed event loop')
-
- def _on_signal(self, signum):
- msg = 'Received {}'.format(self._signames[signum])
- pass # replaces next logging statement
- #debug(msg)
- if signum == signal.SIGINT and self._transport_type == 'stdio':
- # When the transport is stdio, we are probably running as a Nvim
- # child process. In that case, we don't want to be killed by
- # ctrl+C
- return
- cls = Exception
- if signum == signal.SIGINT:
- cls = KeyboardInterrupt
- self._error = cls(msg)
- self.stop()
-
- def _on_error(self, error):
- pass # replaces next logging statement
- #debug(error)
- self._error = OSError(error)
- self.stop()
-
- def _on_interrupt(self):
- self.stop()
+++ /dev/null
-"""Event loop implementation that uses pyuv(libuv-python bindings)."""
-import sys
-from collections import deque
-
-import pyuv
-
-from pynvim.msgpack_rpc.event_loop.base import BaseEventLoop
-
-
-class UvEventLoop(BaseEventLoop):
-
- """`BaseEventLoop` subclass that uses `pvuv` as a backend."""
-
- def _init(self):
- self._loop = pyuv.Loop()
- self._async = pyuv.Async(self._loop, self._on_async)
- self._connection_error = None
- self._error_stream = None
- self._callbacks = deque()
-
- def _on_connect(self, stream, error):
- self.stop()
- if error:
- msg = 'Cannot connect to {}: {}'.format(
- self._connect_address, pyuv.errno.strerror(error))
- self._connection_error = OSError(msg)
- return
- self._read_stream = self._write_stream = stream
-
- def _on_read(self, handle, data, error):
- if error or not data:
- msg = pyuv.errno.strerror(error) if error else 'EOF'
- self._on_error(msg)
- return
- if handle == self._error_stream:
- return
- self._on_data(data)
-
- def _on_write(self, handle, error):
- if error:
- msg = pyuv.errno.strerror(error)
- self._on_error(msg)
-
- def _on_exit(self, handle, exit_status, term_signal):
- self._on_error('EOF')
-
- def _disconnected(self, *args):
- raise OSError('Not connected to Nvim')
-
- def _connect_tcp(self, address, port):
- stream = pyuv.TCP(self._loop)
- self._connect_address = '{}:{}'.format(address, port)
- stream.connect((address, port), self._on_connect)
-
- def _connect_socket(self, path):
- stream = pyuv.Pipe(self._loop)
- self._connect_address = path
- stream.connect(path, self._on_connect)
-
- def _connect_stdio(self):
- self._read_stream = pyuv.Pipe(self._loop)
- self._read_stream.open(sys.stdin.fileno())
- self._write_stream = pyuv.Pipe(self._loop)
- self._write_stream.open(sys.stdout.fileno())
-
- def _connect_child(self, argv):
- self._write_stream = pyuv.Pipe(self._loop)
- self._read_stream = pyuv.Pipe(self._loop)
- self._error_stream = pyuv.Pipe(self._loop)
- stdin = pyuv.StdIO(self._write_stream,
- flags=pyuv.UV_CREATE_PIPE + pyuv.UV_READABLE_PIPE)
- stdout = pyuv.StdIO(self._read_stream,
- flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
- stderr = pyuv.StdIO(self._error_stream,
- flags=pyuv.UV_CREATE_PIPE + pyuv.UV_WRITABLE_PIPE)
- pyuv.Process.spawn(self._loop,
- args=argv,
- exit_callback=self._on_exit,
- flags=pyuv.UV_PROCESS_WINDOWS_HIDE,
- stdio=(stdin, stdout, stderr,))
- self._error_stream.start_read(self._on_read)
-
- def _start_reading(self):
- if self._transport_type in ['tcp', 'socket']:
- self._loop.run()
- if self._connection_error:
- self.run = self.send = self._disconnected
- raise self._connection_error
- self._read_stream.start_read(self._on_read)
-
- def _send(self, data):
- self._write_stream.write(data, self._on_write)
-
- def _run(self):
- self._loop.run(pyuv.UV_RUN_DEFAULT)
-
- def _stop(self):
- self._loop.stop()
-
- def _close(self):
- pass
-
- def _threadsafe_call(self, fn):
- self._callbacks.append(fn)
- self._async.send()
-
- def _on_async(self, handle):
- while self._callbacks:
- self._callbacks.popleft()()
-
- def _setup_signals(self, signals):
- self._signal_handles = []
-
- def handler(h, signum):
- self._on_signal(signum)
-
- for signum in signals:
- handle = pyuv.Signal(self._loop)
- handle.start(handler, signum)
- self._signal_handles.append(handle)
-
- def _teardown_signals(self):
- for handle in self._signal_handles:
- handle.stop()
+++ /dev/null
-"""Msgpack handling in the event loop pipeline."""
-import logging
-
-from msgpack import Packer, Unpacker
-
-from pynvim.compat import unicode_errors_default
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-
-
-class MsgpackStream(object):
-
- """Two-way msgpack stream that wraps a event loop byte stream.
-
- This wraps the event loop interface for reading/writing bytes and
- exposes an interface for reading/writing msgpack documents.
- """
-
- def __init__(self, event_loop):
- """Wrap `event_loop` on a msgpack-aware interface."""
- self.loop = event_loop
- self._packer = Packer(unicode_errors=unicode_errors_default)
- self._unpacker = Unpacker(unicode_errors=unicode_errors_default)
- self._message_cb = None
-
- def threadsafe_call(self, fn):
- """Wrapper around `BaseEventLoop.threadsafe_call`."""
- self.loop.threadsafe_call(fn)
-
- def send(self, msg):
- """Queue `msg` for sending to Nvim."""
- pass # replaces next logging statement
- #debug('sent %s', msg)
- self.loop.send(self._packer.pack(msg))
-
- def run(self, message_cb):
- """Run the event loop to receive messages from Nvim.
-
- While the event loop is running, `message_cb` will be called whenever
- a message has been successfully parsed from the input stream.
- """
- self._message_cb = message_cb
- self.loop.run(self._on_data)
- self._message_cb = None
-
- def stop(self):
- """Stop the event loop."""
- self.loop.stop()
-
- def close(self):
- """Close the event loop."""
- self.loop.close()
-
- def _on_data(self, data):
- self._unpacker.feed(data)
- while True:
- try:
- pass # replaces next logging statement
- #debug('waiting for message...')
- msg = next(self._unpacker)
- pass # replaces next logging statement
- #debug('received message: %s', msg)
- self._message_cb(msg)
- except StopIteration:
- pass # replaces next logging statement
- #debug('unpacker needs more data...')
- break
+++ /dev/null
-"""Synchronous msgpack-rpc session layer."""
-import logging
-import threading
-from collections import deque
-from traceback import format_exc
-
-import greenlet
-
-from pynvim.compat import check_async
-
-logger = logging.getLogger(__name__)
-error, debug, info, warn = (logger.error, logger.debug, logger.info,
- logger.warning,)
-
-
-class Session(object):
-
- """Msgpack-rpc session layer that uses coroutines for a synchronous API.
-
- This class provides the public msgpack-rpc API required by this library.
- It uses the greenlet module to handle requests and notifications coming
- from Nvim with a synchronous API.
- """
-
- def __init__(self, async_session):
- """Wrap `async_session` on a synchronous msgpack-rpc interface."""
- self._async_session = async_session
- self._request_cb = self._notification_cb = None
- self._pending_messages = deque()
- self._is_running = False
- self._setup_exception = None
- self.loop = async_session.loop
- self._loop_thread = None
-
- def threadsafe_call(self, fn, *args, **kwargs):
- """Wrapper around `AsyncSession.threadsafe_call`."""
- def handler():
- try:
- fn(*args, **kwargs)
- except Exception:
- pass # replaces next logging statement
- #warn("error caught while excecuting async callback\n%s\n",
- #format_exc())
-
- def greenlet_wrapper():
- gr = greenlet.greenlet(handler)
- gr.switch()
-
- self._async_session.threadsafe_call(greenlet_wrapper)
-
- def next_message(self):
- """Block until a message(request or notification) is available.
-
- If any messages were previously enqueued, return the first in queue.
- If not, run the event loop until one is received.
- """
- if self._is_running:
- raise Exception('Event loop already running')
- if self._pending_messages:
- return self._pending_messages.popleft()
- self._async_session.run(self._enqueue_request_and_stop,
- self._enqueue_notification_and_stop)
- if self._pending_messages:
- return self._pending_messages.popleft()
-
- def request(self, method, *args, **kwargs):
- """Send a msgpack-rpc request and block until as response is received.
-
- If the event loop is running, this method must have been called by a
- request or notification handler running on a greenlet. In that case,
- send the quest and yield to the parent greenlet until a response is
- available.
-
- When the event loop is not running, it will perform a blocking request
- like this:
- - Send the request
- - Run the loop until the response is available
- - Put requests/notifications received while waiting into a queue
-
- If the `async_` flag is present and True, a asynchronous notification
- is sent instead. This will never block, and the return value or error
- is ignored.
- """
- async_ = check_async(kwargs.pop('async_', None), kwargs, False)
- if async_:
- self._async_session.notify(method, args)
- return
-
- if kwargs:
- raise ValueError("request got unsupported keyword argument(s): {}"
- .format(', '.join(kwargs.keys())))
-
- if self._is_running:
- v = self._yielding_request(method, args)
- else:
- v = self._blocking_request(method, args)
- if not v:
- # EOF
- raise OSError('EOF')
- err, rv = v
- if err:
- pass # replaces next logging statement
- #info("'Received error: %s", err)
- raise self.error_wrapper(err)
- return rv
-
- def run(self, request_cb, notification_cb, setup_cb=None):
- """Run the event loop to receive requests and notifications from Nvim.
-
- Like `AsyncSession.run()`, but `request_cb` and `notification_cb` are
- inside greenlets.
- """
- self._request_cb = request_cb
- self._notification_cb = notification_cb
- self._is_running = True
- self._setup_exception = None
- self._loop_thread = threading.current_thread()
-
- def on_setup():
- try:
- setup_cb()
- except Exception as e:
- self._setup_exception = e
- self.stop()
-
- if setup_cb:
- # Create a new greenlet to handle the setup function
- gr = greenlet.greenlet(on_setup)
- gr.switch()
-
- if self._setup_exception:
- pass # replaces next logging statement
- #error('Setup error: {}'.format(self._setup_exception))
- raise self._setup_exception
-
- # Process all pending requests and notifications
- while self._pending_messages:
- msg = self._pending_messages.popleft()
- getattr(self, '_on_{}'.format(msg[0]))(*msg[1:])
- self._async_session.run(self._on_request, self._on_notification)
- self._is_running = False
- self._request_cb = None
- self._notification_cb = None
- self._loop_thread = None
-
- if self._setup_exception:
- raise self._setup_exception
-
- def stop(self):
- """Stop the event loop."""
- self._async_session.stop()
-
- def close(self):
- """Close the event loop."""
- self._async_session.close()
-
- def _yielding_request(self, method, args):
- gr = greenlet.getcurrent()
- parent = gr.parent
-
- def response_cb(err, rv):
- pass # replaces next logging statement
- #debug('response is available for greenlet %s, switching back', gr)
- gr.switch(err, rv)
-
- self._async_session.request(method, args, response_cb)
- pass # replaces next logging statement
- #debug('yielding from greenlet %s to wait for response', gr)
- return parent.switch()
-
- def _blocking_request(self, method, args):
- result = []
-
- def response_cb(err, rv):
- result.extend([err, rv])
- self.stop()
-
- self._async_session.request(method, args, response_cb)
- self._async_session.run(self._enqueue_request,
- self._enqueue_notification)
- return result
-
- def _enqueue_request_and_stop(self, name, args, response):
- self._enqueue_request(name, args, response)
- self.stop()
-
- def _enqueue_notification_and_stop(self, name, args):
- self._enqueue_notification(name, args)
- self.stop()
-
- def _enqueue_request(self, name, args, response):
- self._pending_messages.append(('request', name, args, response,))
-
- def _enqueue_notification(self, name, args):
- self._pending_messages.append(('notification', name, args,))
-
- def _on_request(self, name, args, response):
- def handler():
- try:
- rv = self._request_cb(name, args)
- pass # replaces next logging statement
- #debug('greenlet %s finished executing, '
- #+ 'sending %s as response', gr, rv)
- response.send(rv)
- except ErrorResponse as err:
- pass # replaces next logging statement
- #warn("error response from request '%s %s': %s", name,
- #args, format_exc())
- response.send(err.args[0], error=True)
- except Exception as err:
- pass # replaces next logging statement
- #warn("error caught while processing request '%s %s': %s", name,
- #args, format_exc())
- response.send(repr(err) + "\n" + format_exc(5), error=True)
- pass # replaces next logging statement
- #debug('greenlet %s is now dying...', gr)
-
- # Create a new greenlet to handle the request
- gr = greenlet.greenlet(handler)
- pass # replaces next logging statement
- #debug('received rpc request, greenlet %s will handle it', gr)
- gr.switch()
-
- def _on_notification(self, name, args):
- def handler():
- try:
- self._notification_cb(name, args)
- pass # replaces next logging statement
- #debug('greenlet %s finished executing', gr)
- except Exception:
- pass # replaces next logging statement
- #warn("error caught while processing notification '%s %s': %s",
- #name, args, format_exc())
-
- pass # replaces next logging statement
- #debug('greenlet %s is now dying...', gr)
-
- gr = greenlet.greenlet(handler)
- pass # replaces next logging statement
- #debug('received rpc notification, greenlet %s will handle it', gr)
- gr.switch()
-
-
-class ErrorResponse(BaseException):
-
- """Raise this in a request handler to respond with a given error message.
-
- Unlike when other exceptions are caught, this gives full control off the
- error response sent. When "ErrorResponse(msg)" is caught "msg" will be
- sent verbatim as the error response.No traceback will be appended.
- """
-
- pass
+++ /dev/null
-"""Nvim plugin/host subpackage."""
-
-from pynvim.plugin.decorators import (autocmd, command, decode, encoding, function,
- plugin, rpc_export, shutdown_hook)
-from pynvim.plugin.host import Host
-
-
-__all__ = ('Host', 'plugin', 'rpc_export', 'command', 'autocmd',
- 'function', 'encoding', 'decode', 'shutdown_hook')
+++ /dev/null
-"""Decorators used by python host plugin system."""
-
-import inspect
-import logging
-
-from pynvim.compat import IS_PYTHON3, unicode_errors_default
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warning,)
-__all__ = ('plugin', 'rpc_export', 'command', 'autocmd', 'function',
- 'encoding', 'decode', 'shutdown_hook')
-
-
-def plugin(cls):
- """Tag a class as a plugin.
-
- This decorator is required to make the class methods discoverable by the
- plugin_load method of the host.
- """
- cls._nvim_plugin = True
- # the _nvim_bind attribute is set to True by default, meaning that
- # decorated functions have a bound Nvim instance as first argument.
- # For methods in a plugin-decorated class this is not required, because
- # the class initializer will already receive the nvim object.
- predicate = lambda fn: hasattr(fn, '_nvim_bind')
- for _, fn in inspect.getmembers(cls, predicate):
- if IS_PYTHON3:
- fn._nvim_bind = False
- else:
- fn.im_func._nvim_bind = False
- return cls
-
-
-def rpc_export(rpc_method_name, sync=False):
- """Export a function or plugin method as a msgpack-rpc request handler."""
- def dec(f):
- f._nvim_rpc_method_name = rpc_method_name
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = False
- return f
- return dec
-
-
-def command(name, nargs=0, complete=None, range=None, count=None, bang=False,
- register=False, sync=False, allow_nested=False, eval=None):
- """Tag a function or plugin method as a Nvim command handler."""
- def dec(f):
- f._nvim_rpc_method_name = 'command:{}'.format(name)
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = True
-
- opts = {}
-
- if range is not None:
- opts['range'] = '' if range is True else str(range)
- elif count is not None:
- opts['count'] = count
-
- if bang:
- opts['bang'] = ''
-
- if register:
- opts['register'] = ''
-
- if nargs:
- opts['nargs'] = nargs
-
- if complete:
- opts['complete'] = complete
-
- if eval:
- opts['eval'] = eval
-
- if not sync and allow_nested:
- rpc_sync = "urgent"
- else:
- rpc_sync = sync
-
- f._nvim_rpc_spec = {
- 'type': 'command',
- 'name': name,
- 'sync': rpc_sync,
- 'opts': opts
- }
- return f
- return dec
-
-
-def autocmd(name, pattern='*', sync=False, allow_nested=False, eval=None):
- """Tag a function or plugin method as a Nvim autocommand handler."""
- def dec(f):
- f._nvim_rpc_method_name = 'autocmd:{}:{}'.format(name, pattern)
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = True
-
- opts = {
- 'pattern': pattern
- }
-
- if eval:
- opts['eval'] = eval
-
- if not sync and allow_nested:
- rpc_sync = "urgent"
- else:
- rpc_sync = sync
-
- f._nvim_rpc_spec = {
- 'type': 'autocmd',
- 'name': name,
- 'sync': rpc_sync,
- 'opts': opts
- }
- return f
- return dec
-
-
-def function(name, range=False, sync=False, allow_nested=False, eval=None):
- """Tag a function or plugin method as a Nvim function handler."""
- def dec(f):
- f._nvim_rpc_method_name = 'function:{}'.format(name)
- f._nvim_rpc_sync = sync
- f._nvim_bind = True
- f._nvim_prefix_plugin_path = True
-
- opts = {}
-
- if range:
- opts['range'] = '' if range is True else str(range)
-
- if eval:
- opts['eval'] = eval
-
- if not sync and allow_nested:
- rpc_sync = "urgent"
- else:
- rpc_sync = sync
-
- f._nvim_rpc_spec = {
- 'type': 'function',
- 'name': name,
- 'sync': rpc_sync,
- 'opts': opts
- }
- return f
- return dec
-
-
-def shutdown_hook(f):
- """Tag a function or method as a shutdown hook."""
- f._nvim_shutdown_hook = True
- f._nvim_bind = True
- return f
-
-
-def decode(mode=unicode_errors_default):
- """Configure automatic encoding/decoding of strings."""
- def dec(f):
- f._nvim_decode = mode
- return f
- return dec
-
-
-def encoding(encoding=True):
- """DEPRECATED: use pynvim.decode()."""
- if isinstance(encoding, str):
- encoding = True
-
- def dec(f):
- f._nvim_decode = encoding
- return f
- return dec
+++ /dev/null
-"""Implements a Nvim host for python plugins."""
-import imp
-import inspect
-import logging
-import os
-import os.path
-import re
-from functools import partial
-from traceback import format_exc
-
-from pynvim.api import decode_if_bytes, walk
-from pynvim.compat import IS_PYTHON3, find_module
-from pynvim.msgpack_rpc import ErrorResponse
-from pynvim.plugin import script_host
-from pynvim.util import format_exc_skip, get_client_info
-
-__all__ = ('Host')
-
-logger = logging.getLogger(__name__)
-error, debug, info, warn = (logger.error, logger.debug, logger.info,
- logger.warning,)
-
-host_method_spec = {"poll": {}, "specs": {"nargs": 1}, "shutdown": {}}
-
-
-class Host(object):
-
- """Nvim host for python plugins.
-
- Takes care of loading/unloading plugins and routing msgpack-rpc
- requests/notifications to the appropriate handlers.
- """
-
- def __init__(self, nvim):
- """Set handlers for plugin_load/plugin_unload."""
- self.nvim = nvim
- self._specs = {}
- self._loaded = {}
- self._load_errors = {}
- self._notification_handlers = {
- 'nvim_error_event': self._on_error_event
- }
- self._request_handlers = {
- 'poll': lambda: 'ok',
- 'specs': self._on_specs_request,
- 'shutdown': self.shutdown
- }
-
- # Decode per default for Python3
- self._decode_default = IS_PYTHON3
-
- def _on_async_err(self, msg):
- # uncaught python exception
- self.nvim.err_write(msg, async_=True)
-
- def _on_error_event(self, kind, msg):
- # error from nvim due to async request
- # like nvim.command(..., async_=True)
- errmsg = "{}: Async request caused an error:\n{}\n".format(
- self.name, decode_if_bytes(msg))
- self.nvim.err_write(errmsg, async_=True)
- return errmsg
-
- def start(self, plugins):
- """Start listening for msgpack-rpc requests and notifications."""
- self.nvim.run_loop(self._on_request,
- self._on_notification,
- lambda: self._load(plugins),
- err_cb=self._on_async_err)
-
- def shutdown(self):
- """Shutdown the host."""
- self._unload()
- self.nvim.stop_loop()
-
- def _wrap_delayed_function(self, cls, delayed_handlers, name, sync,
- module_handlers, path, *args):
- # delete the delayed handlers to be sure
- for handler in delayed_handlers:
- method_name = handler._nvim_registered_name
- if handler._nvim_rpc_sync:
- del self._request_handlers[method_name]
- else:
- del self._notification_handlers[method_name]
- # create an instance of the plugin and pass the nvim object
- plugin = cls(self._configure_nvim_for(cls))
-
- # discover handlers in the plugin instance
- self._discover_functions(plugin, module_handlers, path, False)
-
- if sync:
- self._request_handlers[name](*args)
- else:
- self._notification_handlers[name](*args)
-
- def _wrap_function(self, fn, sync, decode, nvim_bind, name, *args):
- if decode:
- args = walk(decode_if_bytes, args, decode)
- if nvim_bind is not None:
- args.insert(0, nvim_bind)
- try:
- return fn(*args)
- except Exception:
- if sync:
- msg = ("error caught in request handler '{} {}':\n{}"
- .format(name, args, format_exc_skip(1)))
- raise ErrorResponse(msg)
- else:
- msg = ("error caught in async handler '{} {}'\n{}\n"
- .format(name, args, format_exc_skip(1)))
- self._on_async_err(msg + "\n")
-
- def _on_request(self, name, args):
- """Handle a msgpack-rpc request."""
- if IS_PYTHON3:
- name = decode_if_bytes(name)
- handler = self._request_handlers.get(name, None)
- if not handler:
- msg = self._missing_handler_error(name, 'request')
- pass # replaces next logging statement
- #error(msg)
- raise ErrorResponse(msg)
-
- pass # replaces next logging statement
- #debug('calling request handler for "%s", args: "%s"', name, args)
- rv = handler(*args)
- pass # replaces next logging statement
- #debug("request handler for '%s %s' returns: %s", name, args, rv)
- return rv
-
- def _on_notification(self, name, args):
- """Handle a msgpack-rpc notification."""
- if IS_PYTHON3:
- name = decode_if_bytes(name)
- handler = self._notification_handlers.get(name, None)
- if not handler:
- msg = self._missing_handler_error(name, 'notification')
- pass # replaces next logging statement
- #error(msg)
- self._on_async_err(msg + "\n")
- return
-
- pass # replaces next logging statement
- #debug('calling notification handler for "%s", args: "%s"', name, args)
- handler(*args)
-
- def _missing_handler_error(self, name, kind):
- msg = 'no {} handler registered for "{}"'.format(kind, name)
- pathmatch = re.match(r'(.+):[^:]+:[^:]+', name)
- if pathmatch:
- loader_error = self._load_errors.get(pathmatch.group(1))
- if loader_error is not None:
- msg = msg + "\n" + loader_error
- return msg
-
- def _load(self, plugins):
- has_script = False
- for path in plugins:
- err = None
- if path in self._loaded:
- pass # replaces next logging statement
- #error('{} is already loaded'.format(path))
- continue
- try:
- if path == "script_host.py":
- module = script_host
- has_script = True
- else:
- directory, name = os.path.split(os.path.splitext(path)[0])
- file, pathname, descr = find_module(name, [directory])
- module = imp.load_module(name, file, pathname, descr)
- handlers = []
- self._discover_classes(module, handlers, path)
- self._discover_functions(module, handlers, path, False)
- if not handlers:
- pass # replaces next logging statement
- #error('{} exports no handlers'.format(path))
- continue
- self._loaded[path] = {'handlers': handlers, 'module': module}
- except Exception as e:
- err = ('Encountered {} loading plugin at {}: {}\n{}'
- .format(type(e).__name__, path, e, format_exc(5)))
- pass # replaces next logging statement
- #error(err)
- self._load_errors[path] = err
-
- kind = ("script-host" if len(plugins) == 1 and has_script
- else "rplugin-host")
- info = get_client_info(kind, 'host', host_method_spec)
- self.name = info[0]
- self.nvim.api.set_client_info(*info, async_=True)
-
- def _unload(self):
- for path, plugin in self._loaded.items():
- handlers = plugin['handlers']
- for handler in handlers:
- method_name = handler._nvim_registered_name
- if hasattr(handler, '_nvim_shutdown_hook'):
- handler()
- elif handler._nvim_rpc_sync:
- del self._request_handlers[method_name]
- else:
- del self._notification_handlers[method_name]
- self._specs = {}
- self._loaded = {}
-
- def _discover_classes(self, module, handlers, plugin_path):
- for _, cls in inspect.getmembers(module, inspect.isclass):
- if getattr(cls, '_nvim_plugin', False):
- # discover handlers in the plugin instance
- self._discover_functions(cls, handlers, plugin_path, True)
-
- def _discover_functions(self, obj, handlers, plugin_path, delay):
- def predicate(o):
- return hasattr(o, '_nvim_rpc_method_name')
-
- cls_handlers = []
- specs = []
- objdecode = getattr(obj, '_nvim_decode', self._decode_default)
- for _, fn in inspect.getmembers(obj, predicate):
- method = fn._nvim_rpc_method_name
- if fn._nvim_prefix_plugin_path:
- method = '{}:{}'.format(plugin_path, method)
- sync = fn._nvim_rpc_sync
- if delay:
- fn_wrapped = partial(self._wrap_delayed_function, obj,
- cls_handlers, method, sync,
- handlers, plugin_path)
- else:
- decode = getattr(fn, '_nvim_decode', objdecode)
- nvim_bind = None
- if fn._nvim_bind:
- nvim_bind = self._configure_nvim_for(fn)
-
- fn_wrapped = partial(self._wrap_function, fn,
- sync, decode, nvim_bind, method)
- self._copy_attributes(fn, fn_wrapped)
- fn_wrapped._nvim_registered_name = method
- # register in the rpc handler dict
- if sync:
- if method in self._request_handlers:
- raise Exception(('Request handler for "{}" is '
- + 'already registered').format(method))
- self._request_handlers[method] = fn_wrapped
- else:
- if method in self._notification_handlers:
- raise Exception(('Notification handler for "{}" is '
- + 'already registered').format(method))
- self._notification_handlers[method] = fn_wrapped
- if hasattr(fn, '_nvim_rpc_spec'):
- specs.append(fn._nvim_rpc_spec)
- handlers.append(fn_wrapped)
- cls_handlers.append(fn_wrapped)
- if specs:
- self._specs[plugin_path] = specs
-
- def _copy_attributes(self, fn, fn2):
- # Copy _nvim_* attributes from the original function
- for attr in dir(fn):
- if attr.startswith('_nvim_'):
- setattr(fn2, attr, getattr(fn, attr))
-
- def _on_specs_request(self, path):
- if IS_PYTHON3:
- path = decode_if_bytes(path)
- if path in self._load_errors:
- self.nvim.out_write(self._load_errors[path] + '\n')
- return self._specs.get(path, 0)
-
- def _configure_nvim_for(self, obj):
- # Configure a nvim instance for obj (checks encoding configuration)
- nvim = self.nvim
- decode = getattr(obj, '_nvim_decode', self._decode_default)
- if decode:
- nvim = nvim.with_decode(decode)
- return nvim
+++ /dev/null
-"""Legacy python/python3-vim emulation."""
-import imp
-import io
-import logging
-import os
-import sys
-from types import ModuleType
-
-from pynvim.api import Nvim, walk
-from pynvim.compat import IS_PYTHON3
-from pynvim.msgpack_rpc import ErrorResponse
-from pynvim.plugin.decorators import plugin, rpc_export
-from pynvim.util import format_exc_skip
-
-__all__ = ('ScriptHost',)
-
-
-logger = logging.getLogger(__name__)
-debug, info, warn = (logger.debug, logger.info, logger.warn,)
-
-if IS_PYTHON3:
- basestring = str
-
- if sys.version_info >= (3, 4):
- from importlib.machinery import PathFinder
-
- PYTHON_SUBDIR = 'python3'
-else:
- PYTHON_SUBDIR = 'python2'
-
-
-@plugin
-class ScriptHost(object):
-
- """Provides an environment for running python plugins created for Vim."""
-
- def __init__(self, nvim):
- """Initialize the legacy python-vim environment."""
- self.setup(nvim)
- # context where all code will run
- self.module = ModuleType('__main__')
- nvim.script_context = self.module
- # it seems some plugins assume 'sys' is already imported, so do it now
- exec('import sys', self.module.__dict__)
- self.legacy_vim = LegacyVim.from_nvim(nvim)
- sys.modules['vim'] = self.legacy_vim
- # mimic Vim by importing vim module by default.
- exec('import vim', self.module.__dict__)
- # Handle DirChanged. #296
- nvim.command(
- 'au DirChanged * call rpcnotify({}, "python_chdir", v:event.cwd)'
- .format(nvim.channel_id), async_=True)
- # XXX: Avoid race condition.
- # https://github.com/neovim/pynvim/pull/296#issuecomment-358970531
- # TODO(bfredl): when host initialization has been refactored,
- # to make __init__ safe again, the following should work:
- # os.chdir(nvim.eval('getcwd()', async_=False))
- nvim.command('call rpcnotify({}, "python_chdir", getcwd())'
- .format(nvim.channel_id), async_=True)
-
- def setup(self, nvim):
- """Setup import hooks and global streams.
-
- This will add import hooks for importing modules from runtime
- directories and patch the sys module so 'print' calls will be
- forwarded to Nvim.
- """
- self.nvim = nvim
- pass # replaces next logging statement
- #info('install import hook/path')
- self.hook = path_hook(nvim)
- sys.path_hooks.append(self.hook)
- nvim.VIM_SPECIAL_PATH = '_vim_path_'
- sys.path.append(nvim.VIM_SPECIAL_PATH)
- pass # replaces next logging statement
- #info('redirect sys.stdout and sys.stderr')
- self.saved_stdout = sys.stdout
- self.saved_stderr = sys.stderr
- sys.stdout = RedirectStream(lambda data: nvim.out_write(data))
- sys.stderr = RedirectStream(lambda data: nvim.err_write(data))
-
- def teardown(self):
- """Restore state modified from the `setup` call."""
- nvim = self.nvim
- pass # replaces next logging statement
- #info('uninstall import hook/path')
- sys.path.remove(nvim.VIM_SPECIAL_PATH)
- sys.path_hooks.remove(self.hook)
- pass # replaces next logging statement
- #info('restore sys.stdout and sys.stderr')
- sys.stdout = self.saved_stdout
- sys.stderr = self.saved_stderr
-
- @rpc_export('python_execute', sync=True)
- def python_execute(self, script, range_start, range_stop):
- """Handle the `python` ex command."""
- self._set_current_range(range_start, range_stop)
- try:
- exec(script, self.module.__dict__)
- except Exception:
- raise ErrorResponse(format_exc_skip(1))
-
- @rpc_export('python_execute_file', sync=True)
- def python_execute_file(self, file_path, range_start, range_stop):
- """Handle the `pyfile` ex command."""
- self._set_current_range(range_start, range_stop)
- with open(file_path) as f:
- script = compile(f.read(), file_path, 'exec')
- try:
- exec(script, self.module.__dict__)
- except Exception:
- raise ErrorResponse(format_exc_skip(1))
-
- @rpc_export('python_do_range', sync=True)
- def python_do_range(self, start, stop, code):
- """Handle the `pydo` ex command."""
- self._set_current_range(start, stop)
- nvim = self.nvim
- start -= 1
- fname = '_vim_pydo'
-
- # define the function
- function_def = 'def %s(line, linenr):\n %s' % (fname, code,)
- exec(function_def, self.module.__dict__)
- # get the function
- function = self.module.__dict__[fname]
- while start < stop:
- # Process batches of 5000 to avoid the overhead of making multiple
- # API calls for every line. Assuming an average line length of 100
- # bytes, approximately 488 kilobytes will be transferred per batch,
- # which can be done very quickly in a single API call.
- sstart = start
- sstop = min(start + 5000, stop)
- lines = nvim.current.buffer.api.get_lines(sstart, sstop, True)
-
- exception = None
- newlines = []
- linenr = sstart + 1
- for i, line in enumerate(lines):
- result = function(line, linenr)
- if result is None:
- # Update earlier lines, and skip to the next
- if newlines:
- end = sstart + len(newlines) - 1
- nvim.current.buffer.api.set_lines(sstart, end,
- True, newlines)
- sstart += len(newlines) + 1
- newlines = []
- pass
- elif isinstance(result, basestring):
- newlines.append(result)
- else:
- exception = TypeError('pydo should return a string '
- + 'or None, found %s instead'
- % result.__class__.__name__)
- break
- linenr += 1
-
- start = sstop
- if newlines:
- end = sstart + len(newlines)
- nvim.current.buffer.api.set_lines(sstart, end, True, newlines)
- if exception:
- raise exception
- # delete the function
- del self.module.__dict__[fname]
-
- @rpc_export('python_eval', sync=True)
- def python_eval(self, expr):
- """Handle the `pyeval` vim function."""
- return eval(expr, self.module.__dict__)
-
- @rpc_export('python_chdir', sync=False)
- def python_chdir(self, cwd):
- """Handle working directory changes."""
- os.chdir(cwd)
-
- def _set_current_range(self, start, stop):
- current = self.legacy_vim.current
- current.range = current.buffer.range(start, stop)
-
-
-class RedirectStream(io.IOBase):
- def __init__(self, redirect_handler):
- self.redirect_handler = redirect_handler
-
- def write(self, data):
- self.redirect_handler(data)
-
- def writelines(self, seq):
- self.redirect_handler('\n'.join(seq))
-
-
-if IS_PYTHON3:
- num_types = (int, float)
-else:
- num_types = (int, long, float) # noqa: F821
-
-
-def num_to_str(obj):
- if isinstance(obj, num_types):
- return str(obj)
- else:
- return obj
-
-
-class LegacyVim(Nvim):
- def eval(self, expr):
- obj = self.request("vim_eval", expr)
- return walk(num_to_str, obj)
-
-
-# Copied/adapted from :help if_pyth.
-def path_hook(nvim):
- def _get_paths():
- if nvim._thread_invalid():
- return []
- return discover_runtime_directories(nvim)
-
- def _find_module(fullname, oldtail, path):
- idx = oldtail.find('.')
- if idx > 0:
- name = oldtail[:idx]
- tail = oldtail[idx + 1:]
- fmr = imp.find_module(name, path)
- module = imp.find_module(fullname[:-len(oldtail)] + name, *fmr)
- return _find_module(fullname, tail, module.__path__)
- else:
- return imp.find_module(fullname, path)
-
- class VimModuleLoader(object):
- def __init__(self, module):
- self.module = module
-
- def load_module(self, fullname, path=None):
- # Check sys.modules, required for reload (see PEP302).
- try:
- return sys.modules[fullname]
- except KeyError:
- pass
- return imp.load_module(fullname, *self.module)
-
- class VimPathFinder(object):
- @staticmethod
- def find_module(fullname, path=None):
- """Method for Python 2.7 and 3.3."""
- try:
- return VimModuleLoader(
- _find_module(fullname, fullname, path or _get_paths()))
- except ImportError:
- return None
-
- @staticmethod
- def find_spec(fullname, target=None):
- """Method for Python 3.4+."""
- return PathFinder.find_spec(fullname, _get_paths(), target)
-
- def hook(path):
- if path == nvim.VIM_SPECIAL_PATH:
- return VimPathFinder
- else:
- raise ImportError
-
- return hook
-
-
-def discover_runtime_directories(nvim):
- rv = []
- for rtp in nvim.list_runtime_paths():
- if not os.path.exists(rtp):
- continue
- for subdir in ['pythonx', PYTHON_SUBDIR]:
- path = os.path.join(rtp, subdir)
- if os.path.exists(path):
- rv.append(path)
- return rv
+++ /dev/null
-"""Shared utility functions."""
-
-import sys
-from traceback import format_exception
-
-
-def format_exc_skip(skip, limit=None):
- """Like traceback.format_exc but allow skipping the first frames."""
- etype, val, tb = sys.exc_info()
- for i in range(skip):
- tb = tb.tb_next
- return (''.join(format_exception(etype, val, tb, limit))).rstrip()
-
-
-# Taken from SimpleNamespace in python 3
-class Version:
- """Helper class for version info."""
-
- def __init__(self, **kwargs):
- """Create the Version object."""
- self.__dict__.update(kwargs)
-
- def __repr__(self):
- """Return str representation of the Version."""
- keys = sorted(self.__dict__)
- items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
- return "{}({})".format(type(self).__name__, ", ".join(items))
-
- def __eq__(self, other):
- """Check if version is same as other."""
- return self.__dict__ == other.__dict__
-
-
-def get_client_info(kind, type_, method_spec):
- """Returns a tuple describing the client."""
- name = "python{}-{}".format(sys.version_info[0], kind)
- attributes = {"license": "Apache v2",
- "website": "github.com/neovim/pynvim"}
- return (name, VERSION.__dict__, type_, method_spec, attributes)
-
-
-VERSION = Version(major=0, minor=4, patch=2, prerelease='')
+++ /dev/null
-Metadata-Version: 2.1
-Name: pywal
-Version: 3.3.0
-Summary: Generate and change color-schemes on the fly
-Home-page: https://github.com/dylanaraps/pywal
-Author: Dylan Araps
-Author-email: dylan.araps@gmail.com
-License: MIT
-Download-URL: https://github.com/dylanaraps/pywal/archive/3.3.0.tar.gz
-Description: <h3 align="center"><img src="https://i.imgur.com/5WgMACe.gif" width="200px"></h3>
- <p align="center">Generate and change color-schemes on the fly.</p>
-
- <p align="center">
- <a href="https://discord.gg/fK3RhsD"><img src="https://img.shields.io/discord/440354555197128704.svg"></a>
- <a href="https://travis-ci.org/dylanaraps/pywal"><img src="https://travis-ci.org/dylanaraps/pywal.svg?branch=master"></a>
- <a href="./LICENSE.md"><img src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
- <a href="https://pypi.python.org/pypi/pywal/"><img src="https://img.shields.io/pypi/v/pywal.svg"></a>
- <a href="https://www.patreon.com/dyla"><img src="https://img.shields.io/badge/donate-patreon-yellow.svg"></a>
- <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=V7QNJNKS3WYVS"><img src="https://img.shields.io/badge/donate-paypal-green.svg"></a>
- </p>
-
- <img src="https://i.imgur.com/HhK3LDv.jpg" alt="img" align="right" width="400px">
-
- Pywal is a tool that generates a color palette from the dominant colors in an image. It then applies the colors system-wide and on-the-fly in all of your favourite programs.
-
- There are currently 5 supported color generation backends, each providing a different palette of colors from each image. You're bound to find an appealing color-scheme.
-
- Pywal also supports predefined themes and has over 250 themes built-in. You can also create your own theme files to share with others.
-
- The goal of Pywal was to be as out of the way as possible. It doesn't modify any of your existing configuration files. Instead it works around them and provides tools to integrate your system as you see fit.
-
- Terminal emulators and TTYs have their color-schemes updated in real-time with no delay. With minimal configuration this functionality can be extended to almost anything running on your system.
-
- ### More: \[[Installation](https://github.com/dylanaraps/pywal/wiki/Installation)\] \[[Getting Started](https://github.com/dylanaraps/pywal/wiki/Getting-Started)\] \[[Customization](https://github.com/dylanaraps/pywal/wiki/Customization)\] \[[Wiki](https://github.com/dylanaraps/pywal/wiki)\] \[[Screenshots](https://www.reddit.com/r/unixporn/search?q=wal&restrict_sr=on&sort=relevance&t=all)\]
-
-Keywords: wal colorscheme terminal-emulators changing-colorschemes
-Platform: UNKNOWN
-Classifier: Environment :: X11 Applications
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: POSIX :: Linux
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Requires-Python: >=3.5
-Description-Content-Type: text/markdown
+++ /dev/null
-.pylintrc
-LICENSE.md
-MANIFEST.in
-README.md
-setup.cfg
-setup.py
-pywal/__init__.py
-pywal/__main__.py
-pywal/colors.py
-pywal/export.py
-pywal/image.py
-pywal/reload.py
-pywal/sequences.py
-pywal/settings.py
-pywal/theme.py
-pywal/util.py
-pywal/wallpaper.py
-pywal.egg-info/PKG-INFO
-pywal.egg-info/SOURCES.txt
-pywal.egg-info/dependency_links.txt
-pywal.egg-info/entry_points.txt
-pywal.egg-info/not-zip-safe
-pywal.egg-info/top_level.txt
-pywal/backends/__init__.py
-pywal/backends/colorthief.py
-pywal/backends/colorz.py
-pywal/backends/haishoku.py
-pywal/backends/schemer2.py
-pywal/backends/wal.py
-pywal/colorschemes/dark/3024.json
-pywal/colorschemes/dark/ashes.json
-pywal/colorschemes/dark/base16-3024.json
-pywal/colorschemes/dark/base16-apathy.json
-pywal/colorschemes/dark/base16-ashes.json
-pywal/colorschemes/dark/base16-atelier-cave.json
-pywal/colorschemes/dark/base16-atelier-dune.json
-pywal/colorschemes/dark/base16-atelier-estuary.json
-pywal/colorschemes/dark/base16-atelier-forest.json
-pywal/colorschemes/dark/base16-atelier-heath.json
-pywal/colorschemes/dark/base16-atelier-lakeside.json
-pywal/colorschemes/dark/base16-atelier-plateau.json
-pywal/colorschemes/dark/base16-atelier-savanna.json
-pywal/colorschemes/dark/base16-atelier-seaside.json
-pywal/colorschemes/dark/base16-atelier-sulphurpool.json
-pywal/colorschemes/dark/base16-bespin.json
-pywal/colorschemes/dark/base16-black-metal-bathory.json
-pywal/colorschemes/dark/base16-black-metal-burzum.json
-pywal/colorschemes/dark/base16-black-metal-funeral.json
-pywal/colorschemes/dark/base16-black-metal-gorgoroth.json
-pywal/colorschemes/dark/base16-black-metal-immortal.json
-pywal/colorschemes/dark/base16-black-metal-khold.json
-pywal/colorschemes/dark/base16-black-metal-marduk.json
-pywal/colorschemes/dark/base16-black-metal-mayhem.json
-pywal/colorschemes/dark/base16-black-metal-nile.json
-pywal/colorschemes/dark/base16-black-metal-venom.json
-pywal/colorschemes/dark/base16-black-metal.json
-pywal/colorschemes/dark/base16-brewer.json
-pywal/colorschemes/dark/base16-bright.json
-pywal/colorschemes/dark/base16-brushtrees.json
-pywal/colorschemes/dark/base16-chalk.json
-pywal/colorschemes/dark/base16-circus.json
-pywal/colorschemes/dark/base16-classic.json
-pywal/colorschemes/dark/base16-codeschool.json
-pywal/colorschemes/dark/base16-default.json
-pywal/colorschemes/dark/base16-dracula.json
-pywal/colorschemes/dark/base16-eighties.json
-pywal/colorschemes/dark/base16-embers.json
-pywal/colorschemes/dark/base16-flat.json
-pywal/colorschemes/dark/base16-google.json
-pywal/colorschemes/dark/base16-grayscale.json
-pywal/colorschemes/dark/base16-greenscreen.json
-pywal/colorschemes/dark/base16-gruvbox-hard.json
-pywal/colorschemes/dark/base16-gruvbox-medium.json
-pywal/colorschemes/dark/base16-gruvbox-pale.json
-pywal/colorschemes/dark/base16-gruvbox-soft.json
-pywal/colorschemes/dark/base16-harmonic.json
-pywal/colorschemes/dark/base16-hopscotch.json
-pywal/colorschemes/dark/base16-icy.json
-pywal/colorschemes/dark/base16-irblack.json
-pywal/colorschemes/dark/base16-isotope.json
-pywal/colorschemes/dark/base16-macintosh.json
-pywal/colorschemes/dark/base16-marrakesh.json
-pywal/colorschemes/dark/base16-materia.json
-pywal/colorschemes/dark/base16-material-palenight.json
-pywal/colorschemes/dark/base16-material.json
-pywal/colorschemes/dark/base16-materialer.json
-pywal/colorschemes/dark/base16-mellow-purple.json
-pywal/colorschemes/dark/base16-mocha.json
-pywal/colorschemes/dark/base16-monokai.json
-pywal/colorschemes/dark/base16-nord.json
-pywal/colorschemes/dark/base16-ocean.json
-pywal/colorschemes/dark/base16-oceanicnext.json
-pywal/colorschemes/dark/base16-onedark.json
-pywal/colorschemes/dark/base16-outrun.json
-pywal/colorschemes/dark/base16-paraiso.json
-pywal/colorschemes/dark/base16-phd.json
-pywal/colorschemes/dark/base16-pico.json
-pywal/colorschemes/dark/base16-pop.json
-pywal/colorschemes/dark/base16-porple.json
-pywal/colorschemes/dark/base16-railscasts.json
-pywal/colorschemes/dark/base16-rebecca.json
-pywal/colorschemes/dark/base16-seti.json
-pywal/colorschemes/dark/base16-solarflare.json
-pywal/colorschemes/dark/base16-solarized.json
-pywal/colorschemes/dark/base16-spacemacs.json
-pywal/colorschemes/dark/base16-summerfruit.json
-pywal/colorschemes/dark/base16-tomorrow-night.json
-pywal/colorschemes/dark/base16-tube.json
-pywal/colorschemes/dark/base16-twilight.json
-pywal/colorschemes/dark/base16-unikitty.json
-pywal/colorschemes/dark/base16-woodland.json
-pywal/colorschemes/dark/base16-xcode-dusk.json
-pywal/colorschemes/dark/base16-zenburn.json
-pywal/colorschemes/dark/base16tooth.json
-pywal/colorschemes/dark/darktooth.json
-pywal/colorschemes/dark/dkeg-5725.json
-pywal/colorschemes/dark/dkeg-amiox.json
-pywal/colorschemes/dark/dkeg-bark.json
-pywal/colorschemes/dark/dkeg-blend.json
-pywal/colorschemes/dark/dkeg-blok.json
-pywal/colorschemes/dark/dkeg-bluetype.json
-pywal/colorschemes/dark/dkeg-blumune.json
-pywal/colorschemes/dark/dkeg-book.json
-pywal/colorschemes/dark/dkeg-branch.json
-pywal/colorschemes/dark/dkeg-brownstone.json
-pywal/colorschemes/dark/dkeg-bulb.json
-pywal/colorschemes/dark/dkeg-chaires.json
-pywal/colorschemes/dark/dkeg-coco.json
-pywal/colorschemes/dark/dkeg-corduroy.json
-pywal/colorschemes/dark/dkeg-depth.json
-pywal/colorschemes/dark/dkeg-designr.json
-pywal/colorschemes/dark/dkeg-diner.json
-pywal/colorschemes/dark/dkeg-escen.json
-pywal/colorschemes/dark/dkeg-fendr.json
-pywal/colorschemes/dark/dkeg-flapr.json
-pywal/colorschemes/dark/dkeg-forst.json
-pywal/colorschemes/dark/dkeg-fury.json
-pywal/colorschemes/dark/dkeg-harbing.json
-pywal/colorschemes/dark/dkeg-kit.json
-pywal/colorschemes/dark/dkeg-leaf.json
-pywal/colorschemes/dark/dkeg-link.json
-pywal/colorschemes/dark/dkeg-mattd.json
-pywal/colorschemes/dark/dkeg-novmbr.json
-pywal/colorschemes/dark/dkeg-owl.json
-pywal/colorschemes/dark/dkeg-paints.json
-pywal/colorschemes/dark/dkeg-parkd.json
-pywal/colorschemes/dark/dkeg-pastely.json
-pywal/colorschemes/dark/dkeg-petal.json
-pywal/colorschemes/dark/dkeg-poly.json
-pywal/colorschemes/dark/dkeg-prevail.json
-pywal/colorschemes/dark/dkeg-provrb.json
-pywal/colorschemes/dark/dkeg-raild.json
-pywal/colorschemes/dark/dkeg-relax.json
-pywal/colorschemes/dark/dkeg-scag.json
-pywal/colorschemes/dark/dkeg-scape.json
-pywal/colorschemes/dark/dkeg-shade.json
-pywal/colorschemes/dark/dkeg-simplicity.json
-pywal/colorschemes/dark/dkeg-skigh.json
-pywal/colorschemes/dark/dkeg-slate.json
-pywal/colorschemes/dark/dkeg-soundwave.json
-pywal/colorschemes/dark/dkeg-spire.json
-pywal/colorschemes/dark/dkeg-sprout.json
-pywal/colorschemes/dark/dkeg-squares.json
-pywal/colorschemes/dark/dkeg-stv.json
-pywal/colorschemes/dark/dkeg-subtle.json
-pywal/colorschemes/dark/dkeg-sundr.json
-pywal/colorschemes/dark/dkeg-tealights.json
-pywal/colorschemes/dark/dkeg-traffic.json
-pywal/colorschemes/dark/dkeg-transposet.json
-pywal/colorschemes/dark/dkeg-urban.json
-pywal/colorschemes/dark/dkeg-vans.json
-pywal/colorschemes/dark/dkeg-victory.json
-pywal/colorschemes/dark/dkeg-view.json
-pywal/colorschemes/dark/dkeg-wintry.json
-pywal/colorschemes/dark/gruvbox.json
-pywal/colorschemes/dark/hybrid-material.json
-pywal/colorschemes/dark/monokai.json
-pywal/colorschemes/dark/sexy-astromouse.json
-pywal/colorschemes/dark/sexy-belge.json
-pywal/colorschemes/dark/sexy-bitmute.json
-pywal/colorschemes/dark/sexy-cloud.json
-pywal/colorschemes/dark/sexy-colorfulcolors.json
-pywal/colorschemes/dark/sexy-dawn.json
-pywal/colorschemes/dark/sexy-deafened.json
-pywal/colorschemes/dark/sexy-derp.json
-pywal/colorschemes/dark/sexy-digerati.json
-pywal/colorschemes/dark/sexy-doomicideocean.json
-pywal/colorschemes/dark/sexy-dotshare.json
-pywal/colorschemes/dark/sexy-dwmrob.json
-pywal/colorschemes/dark/sexy-eqie6.json
-pywal/colorschemes/dark/sexy-euphrasia.json
-pywal/colorschemes/dark/sexy-gjm.json
-pywal/colorschemes/dark/sexy-gnometerm.json
-pywal/colorschemes/dark/sexy-gotham.json
-pywal/colorschemes/dark/sexy-gslob-nature-suede.json
-pywal/colorschemes/dark/sexy-hund.json
-pywal/colorschemes/dark/sexy-hybrid.json
-pywal/colorschemes/dark/sexy-insignificato.json
-pywal/colorschemes/dark/sexy-invisibone.json
-pywal/colorschemes/dark/sexy-jasonwryan.json
-pywal/colorschemes/dark/sexy-kasugano.json
-pywal/colorschemes/dark/sexy-material.json
-pywal/colorschemes/dark/sexy-mikado.json
-pywal/colorschemes/dark/sexy-mikazuki.json
-pywal/colorschemes/dark/sexy-monokai.json
-pywal/colorschemes/dark/sexy-muse.json
-pywal/colorschemes/dark/sexy-nancy.json
-pywal/colorschemes/dark/sexy-navy-and-ivory.json
-pywal/colorschemes/dark/sexy-neon.json
-pywal/colorschemes/dark/sexy-numixdarkest.json
-pywal/colorschemes/dark/sexy-orangish.json
-pywal/colorschemes/dark/sexy-parker_brothers.json
-pywal/colorschemes/dark/sexy-phrak1.json
-pywal/colorschemes/dark/sexy-pretty-and-pastel.json
-pywal/colorschemes/dark/sexy-rasi.json
-pywal/colorschemes/dark/sexy-rezza.json
-pywal/colorschemes/dark/sexy-rydgel.json
-pywal/colorschemes/dark/sexy-s3r0-modified.json
-pywal/colorschemes/dark/sexy-sexcolors.json
-pywal/colorschemes/dark/sexy-simple_rainbow.json
-pywal/colorschemes/dark/sexy-splurge.json
-pywal/colorschemes/dark/sexy-swayr.json
-pywal/colorschemes/dark/sexy-sweetlove.json
-pywal/colorschemes/dark/sexy-tango.json
-pywal/colorschemes/dark/sexy-tangoesque.json
-pywal/colorschemes/dark/sexy-tartan.json
-pywal/colorschemes/dark/sexy-theme2.json
-pywal/colorschemes/dark/sexy-thwump.json
-pywal/colorschemes/dark/sexy-tlh.json
-pywal/colorschemes/dark/sexy-trim-yer-beard.json
-pywal/colorschemes/dark/sexy-user-77-mashup-colors.json
-pywal/colorschemes/dark/sexy-vacuous2.json
-pywal/colorschemes/dark/sexy-visibone-alt-2.json
-pywal/colorschemes/dark/sexy-visibone.json
-pywal/colorschemes/dark/sexy-x-dotshare.json
-pywal/colorschemes/dark/sexy-zenburn.json
-pywal/colorschemes/dark/solarized.json
-pywal/colorschemes/dark/tempus_autumn.json
-pywal/colorschemes/dark/tempus_dusk.json
-pywal/colorschemes/dark/tempus_future.json
-pywal/colorschemes/dark/tempus_rift.json
-pywal/colorschemes/dark/tempus_spring.json
-pywal/colorschemes/dark/tempus_summer.json
-pywal/colorschemes/dark/tempus_warp.json
-pywal/colorschemes/dark/tempus_winter.json
-pywal/colorschemes/dark/vscode.json
-pywal/colorschemes/dark/zenburn.json
-pywal/colorschemes/light/3024.json
-pywal/colorschemes/light/ashes.json
-pywal/colorschemes/light/base16-atelier-cave.json
-pywal/colorschemes/light/base16-atelier-dune.json
-pywal/colorschemes/light/base16-atelier-estuary.json
-pywal/colorschemes/light/base16-atelier-forest.json
-pywal/colorschemes/light/base16-atelier-heath.json
-pywal/colorschemes/light/base16-atelier-lakeside.json
-pywal/colorschemes/light/base16-atelier-plateau.json
-pywal/colorschemes/light/base16-atelier-savanna.json
-pywal/colorschemes/light/base16-atelier-seaside.json
-pywal/colorschemes/light/base16-atelier-sulphurpool.json
-pywal/colorschemes/light/base16-classic.json
-pywal/colorschemes/light/base16-cupcake.json
-pywal/colorschemes/light/base16-cupertino.json
-pywal/colorschemes/light/base16-default.json
-pywal/colorschemes/light/base16-github.json
-pywal/colorschemes/light/base16-google.json
-pywal/colorschemes/light/base16-grayscale.json
-pywal/colorschemes/light/base16-gruvbox-hard.json
-pywal/colorschemes/light/base16-gruvbox-medium.json
-pywal/colorschemes/light/base16-gruvbox-soft.json
-pywal/colorschemes/light/base16-harmonic.json
-pywal/colorschemes/light/base16-materialer.json
-pywal/colorschemes/light/base16-mexico.json
-pywal/colorschemes/light/base16-one.json
-pywal/colorschemes/light/base16-shapeshifter.json
-pywal/colorschemes/light/base16-solarized.json
-pywal/colorschemes/light/base16-summerfruit.json
-pywal/colorschemes/light/base16-tomorrow.json
-pywal/colorschemes/light/base16-unikitty.json
-pywal/colorschemes/light/github.json
-pywal/colorschemes/light/sexy-mostly-bright.json
-pywal/colorschemes/light/solarized.json
-pywal/colorschemes/light/tempus_dawn.json
-pywal/colorschemes/light/tempus_fugit.json
-pywal/colorschemes/light/tempus_past.json
-pywal/colorschemes/light/tempus_totus.json
-pywal/scripts/gtk_reload.py
-pywal/templates/colors
-pywal/templates/colors-kitty.conf
-pywal/templates/colors-konsole.colorscheme
-pywal/templates/colors-oomox
-pywal/templates/colors-putty.reg
-pywal/templates/colors-rofi-dark.rasi
-pywal/templates/colors-rofi-light.rasi
-pywal/templates/colors-speedcrunch.json
-pywal/templates/colors-sway
-pywal/templates/colors-tty.sh
-pywal/templates/colors-wal-dmenu.h
-pywal/templates/colors-wal-dwm.h
-pywal/templates/colors-wal-st.h
-pywal/templates/colors-wal-tabbed.h
-pywal/templates/colors-wal.vim
-pywal/templates/colors-waybar.css
-pywal/templates/colors.Xresources
-pywal/templates/colors.css
-pywal/templates/colors.hs
-pywal/templates/colors.json
-pywal/templates/colors.scss
-pywal/templates/colors.sh
-pywal/templates/colors.yml
-tests/__init__.py
-tests/test_colors.py
-tests/test_export.py
-tests/test_image.py
-tests/test_sequences.py
-tests/test_util.py
-tests/test_files/test.jpg
-tests/test_files/test.png
-tests/test_files/test2.jpg
-tests/test_files/test_file
-tests/test_files/test_file.json
-tests/test_files/test_file2.json
\ No newline at end of file
+++ /dev/null
-[console_scripts]
-wal = pywal.__main__:main
-
+++ /dev/null
-../../../../bin/wal
-../pywal/__init__.py
-../pywal/__main__.py
-../pywal/__pycache__/__init__.cpython-39.pyc
-../pywal/__pycache__/__main__.cpython-39.pyc
-../pywal/__pycache__/colors.cpython-39.pyc
-../pywal/__pycache__/export.cpython-39.pyc
-../pywal/__pycache__/image.cpython-39.pyc
-../pywal/__pycache__/reload.cpython-39.pyc
-../pywal/__pycache__/sequences.cpython-39.pyc
-../pywal/__pycache__/settings.cpython-39.pyc
-../pywal/__pycache__/theme.cpython-39.pyc
-../pywal/__pycache__/util.cpython-39.pyc
-../pywal/__pycache__/wallpaper.cpython-39.pyc
-../pywal/backends/__init__.py
-../pywal/backends/__pycache__/__init__.cpython-39.pyc
-../pywal/backends/__pycache__/colorthief.cpython-39.pyc
-../pywal/backends/__pycache__/colorz.cpython-39.pyc
-../pywal/backends/__pycache__/haishoku.cpython-39.pyc
-../pywal/backends/__pycache__/schemer2.cpython-39.pyc
-../pywal/backends/__pycache__/wal.cpython-39.pyc
-../pywal/backends/colorthief.py
-../pywal/backends/colorz.py
-../pywal/backends/haishoku.py
-../pywal/backends/schemer2.py
-../pywal/backends/wal.py
-../pywal/colors.py
-../pywal/colorschemes/dark/3024.json
-../pywal/colorschemes/dark/ashes.json
-../pywal/colorschemes/dark/base16-3024.json
-../pywal/colorschemes/dark/base16-apathy.json
-../pywal/colorschemes/dark/base16-ashes.json
-../pywal/colorschemes/dark/base16-atelier-cave.json
-../pywal/colorschemes/dark/base16-atelier-dune.json
-../pywal/colorschemes/dark/base16-atelier-estuary.json
-../pywal/colorschemes/dark/base16-atelier-forest.json
-../pywal/colorschemes/dark/base16-atelier-heath.json
-../pywal/colorschemes/dark/base16-atelier-lakeside.json
-../pywal/colorschemes/dark/base16-atelier-plateau.json
-../pywal/colorschemes/dark/base16-atelier-savanna.json
-../pywal/colorschemes/dark/base16-atelier-seaside.json
-../pywal/colorschemes/dark/base16-atelier-sulphurpool.json
-../pywal/colorschemes/dark/base16-bespin.json
-../pywal/colorschemes/dark/base16-black-metal-bathory.json
-../pywal/colorschemes/dark/base16-black-metal-burzum.json
-../pywal/colorschemes/dark/base16-black-metal-funeral.json
-../pywal/colorschemes/dark/base16-black-metal-gorgoroth.json
-../pywal/colorschemes/dark/base16-black-metal-immortal.json
-../pywal/colorschemes/dark/base16-black-metal-khold.json
-../pywal/colorschemes/dark/base16-black-metal-marduk.json
-../pywal/colorschemes/dark/base16-black-metal-mayhem.json
-../pywal/colorschemes/dark/base16-black-metal-nile.json
-../pywal/colorschemes/dark/base16-black-metal-venom.json
-../pywal/colorschemes/dark/base16-black-metal.json
-../pywal/colorschemes/dark/base16-brewer.json
-../pywal/colorschemes/dark/base16-bright.json
-../pywal/colorschemes/dark/base16-brushtrees.json
-../pywal/colorschemes/dark/base16-chalk.json
-../pywal/colorschemes/dark/base16-circus.json
-../pywal/colorschemes/dark/base16-classic.json
-../pywal/colorschemes/dark/base16-codeschool.json
-../pywal/colorschemes/dark/base16-default.json
-../pywal/colorschemes/dark/base16-dracula.json
-../pywal/colorschemes/dark/base16-eighties.json
-../pywal/colorschemes/dark/base16-embers.json
-../pywal/colorschemes/dark/base16-flat.json
-../pywal/colorschemes/dark/base16-google.json
-../pywal/colorschemes/dark/base16-grayscale.json
-../pywal/colorschemes/dark/base16-greenscreen.json
-../pywal/colorschemes/dark/base16-gruvbox-hard.json
-../pywal/colorschemes/dark/base16-gruvbox-medium.json
-../pywal/colorschemes/dark/base16-gruvbox-pale.json
-../pywal/colorschemes/dark/base16-gruvbox-soft.json
-../pywal/colorschemes/dark/base16-harmonic.json
-../pywal/colorschemes/dark/base16-hopscotch.json
-../pywal/colorschemes/dark/base16-icy.json
-../pywal/colorschemes/dark/base16-irblack.json
-../pywal/colorschemes/dark/base16-isotope.json
-../pywal/colorschemes/dark/base16-macintosh.json
-../pywal/colorschemes/dark/base16-marrakesh.json
-../pywal/colorschemes/dark/base16-materia.json
-../pywal/colorschemes/dark/base16-material-palenight.json
-../pywal/colorschemes/dark/base16-material.json
-../pywal/colorschemes/dark/base16-materialer.json
-../pywal/colorschemes/dark/base16-mellow-purple.json
-../pywal/colorschemes/dark/base16-mocha.json
-../pywal/colorschemes/dark/base16-monokai.json
-../pywal/colorschemes/dark/base16-nord.json
-../pywal/colorschemes/dark/base16-ocean.json
-../pywal/colorschemes/dark/base16-oceanicnext.json
-../pywal/colorschemes/dark/base16-onedark.json
-../pywal/colorschemes/dark/base16-outrun.json
-../pywal/colorschemes/dark/base16-paraiso.json
-../pywal/colorschemes/dark/base16-phd.json
-../pywal/colorschemes/dark/base16-pico.json
-../pywal/colorschemes/dark/base16-pop.json
-../pywal/colorschemes/dark/base16-porple.json
-../pywal/colorschemes/dark/base16-railscasts.json
-../pywal/colorschemes/dark/base16-rebecca.json
-../pywal/colorschemes/dark/base16-seti.json
-../pywal/colorschemes/dark/base16-solarflare.json
-../pywal/colorschemes/dark/base16-solarized.json
-../pywal/colorschemes/dark/base16-spacemacs.json
-../pywal/colorschemes/dark/base16-summerfruit.json
-../pywal/colorschemes/dark/base16-tomorrow-night.json
-../pywal/colorschemes/dark/base16-tube.json
-../pywal/colorschemes/dark/base16-twilight.json
-../pywal/colorschemes/dark/base16-unikitty.json
-../pywal/colorschemes/dark/base16-woodland.json
-../pywal/colorschemes/dark/base16-xcode-dusk.json
-../pywal/colorschemes/dark/base16-zenburn.json
-../pywal/colorschemes/dark/base16tooth.json
-../pywal/colorschemes/dark/darktooth.json
-../pywal/colorschemes/dark/dkeg-5725.json
-../pywal/colorschemes/dark/dkeg-amiox.json
-../pywal/colorschemes/dark/dkeg-bark.json
-../pywal/colorschemes/dark/dkeg-blend.json
-../pywal/colorschemes/dark/dkeg-blok.json
-../pywal/colorschemes/dark/dkeg-bluetype.json
-../pywal/colorschemes/dark/dkeg-blumune.json
-../pywal/colorschemes/dark/dkeg-book.json
-../pywal/colorschemes/dark/dkeg-branch.json
-../pywal/colorschemes/dark/dkeg-brownstone.json
-../pywal/colorschemes/dark/dkeg-bulb.json
-../pywal/colorschemes/dark/dkeg-chaires.json
-../pywal/colorschemes/dark/dkeg-coco.json
-../pywal/colorschemes/dark/dkeg-corduroy.json
-../pywal/colorschemes/dark/dkeg-depth.json
-../pywal/colorschemes/dark/dkeg-designr.json
-../pywal/colorschemes/dark/dkeg-diner.json
-../pywal/colorschemes/dark/dkeg-escen.json
-../pywal/colorschemes/dark/dkeg-fendr.json
-../pywal/colorschemes/dark/dkeg-flapr.json
-../pywal/colorschemes/dark/dkeg-forst.json
-../pywal/colorschemes/dark/dkeg-fury.json
-../pywal/colorschemes/dark/dkeg-harbing.json
-../pywal/colorschemes/dark/dkeg-kit.json
-../pywal/colorschemes/dark/dkeg-leaf.json
-../pywal/colorschemes/dark/dkeg-link.json
-../pywal/colorschemes/dark/dkeg-mattd.json
-../pywal/colorschemes/dark/dkeg-novmbr.json
-../pywal/colorschemes/dark/dkeg-owl.json
-../pywal/colorschemes/dark/dkeg-paints.json
-../pywal/colorschemes/dark/dkeg-parkd.json
-../pywal/colorschemes/dark/dkeg-pastely.json
-../pywal/colorschemes/dark/dkeg-petal.json
-../pywal/colorschemes/dark/dkeg-poly.json
-../pywal/colorschemes/dark/dkeg-prevail.json
-../pywal/colorschemes/dark/dkeg-provrb.json
-../pywal/colorschemes/dark/dkeg-raild.json
-../pywal/colorschemes/dark/dkeg-relax.json
-../pywal/colorschemes/dark/dkeg-scag.json
-../pywal/colorschemes/dark/dkeg-scape.json
-../pywal/colorschemes/dark/dkeg-shade.json
-../pywal/colorschemes/dark/dkeg-simplicity.json
-../pywal/colorschemes/dark/dkeg-skigh.json
-../pywal/colorschemes/dark/dkeg-slate.json
-../pywal/colorschemes/dark/dkeg-soundwave.json
-../pywal/colorschemes/dark/dkeg-spire.json
-../pywal/colorschemes/dark/dkeg-sprout.json
-../pywal/colorschemes/dark/dkeg-squares.json
-../pywal/colorschemes/dark/dkeg-stv.json
-../pywal/colorschemes/dark/dkeg-subtle.json
-../pywal/colorschemes/dark/dkeg-sundr.json
-../pywal/colorschemes/dark/dkeg-tealights.json
-../pywal/colorschemes/dark/dkeg-traffic.json
-../pywal/colorschemes/dark/dkeg-transposet.json
-../pywal/colorschemes/dark/dkeg-urban.json
-../pywal/colorschemes/dark/dkeg-vans.json
-../pywal/colorschemes/dark/dkeg-victory.json
-../pywal/colorschemes/dark/dkeg-view.json
-../pywal/colorschemes/dark/dkeg-wintry.json
-../pywal/colorschemes/dark/gruvbox.json
-../pywal/colorschemes/dark/hybrid-material.json
-../pywal/colorschemes/dark/monokai.json
-../pywal/colorschemes/dark/sexy-astromouse.json
-../pywal/colorschemes/dark/sexy-belge.json
-../pywal/colorschemes/dark/sexy-bitmute.json
-../pywal/colorschemes/dark/sexy-cloud.json
-../pywal/colorschemes/dark/sexy-colorfulcolors.json
-../pywal/colorschemes/dark/sexy-dawn.json
-../pywal/colorschemes/dark/sexy-deafened.json
-../pywal/colorschemes/dark/sexy-derp.json
-../pywal/colorschemes/dark/sexy-digerati.json
-../pywal/colorschemes/dark/sexy-doomicideocean.json
-../pywal/colorschemes/dark/sexy-dotshare.json
-../pywal/colorschemes/dark/sexy-dwmrob.json
-../pywal/colorschemes/dark/sexy-eqie6.json
-../pywal/colorschemes/dark/sexy-euphrasia.json
-../pywal/colorschemes/dark/sexy-gjm.json
-../pywal/colorschemes/dark/sexy-gnometerm.json
-../pywal/colorschemes/dark/sexy-gotham.json
-../pywal/colorschemes/dark/sexy-gslob-nature-suede.json
-../pywal/colorschemes/dark/sexy-hund.json
-../pywal/colorschemes/dark/sexy-hybrid.json
-../pywal/colorschemes/dark/sexy-insignificato.json
-../pywal/colorschemes/dark/sexy-invisibone.json
-../pywal/colorschemes/dark/sexy-jasonwryan.json
-../pywal/colorschemes/dark/sexy-kasugano.json
-../pywal/colorschemes/dark/sexy-material.json
-../pywal/colorschemes/dark/sexy-mikado.json
-../pywal/colorschemes/dark/sexy-mikazuki.json
-../pywal/colorschemes/dark/sexy-monokai.json
-../pywal/colorschemes/dark/sexy-muse.json
-../pywal/colorschemes/dark/sexy-nancy.json
-../pywal/colorschemes/dark/sexy-navy-and-ivory.json
-../pywal/colorschemes/dark/sexy-neon.json
-../pywal/colorschemes/dark/sexy-numixdarkest.json
-../pywal/colorschemes/dark/sexy-orangish.json
-../pywal/colorschemes/dark/sexy-parker_brothers.json
-../pywal/colorschemes/dark/sexy-phrak1.json
-../pywal/colorschemes/dark/sexy-pretty-and-pastel.json
-../pywal/colorschemes/dark/sexy-rasi.json
-../pywal/colorschemes/dark/sexy-rezza.json
-../pywal/colorschemes/dark/sexy-rydgel.json
-../pywal/colorschemes/dark/sexy-s3r0-modified.json
-../pywal/colorschemes/dark/sexy-sexcolors.json
-../pywal/colorschemes/dark/sexy-simple_rainbow.json
-../pywal/colorschemes/dark/sexy-splurge.json
-../pywal/colorschemes/dark/sexy-swayr.json
-../pywal/colorschemes/dark/sexy-sweetlove.json
-../pywal/colorschemes/dark/sexy-tango.json
-../pywal/colorschemes/dark/sexy-tangoesque.json
-../pywal/colorschemes/dark/sexy-tartan.json
-../pywal/colorschemes/dark/sexy-theme2.json
-../pywal/colorschemes/dark/sexy-thwump.json
-../pywal/colorschemes/dark/sexy-tlh.json
-../pywal/colorschemes/dark/sexy-trim-yer-beard.json
-../pywal/colorschemes/dark/sexy-user-77-mashup-colors.json
-../pywal/colorschemes/dark/sexy-vacuous2.json
-../pywal/colorschemes/dark/sexy-visibone-alt-2.json
-../pywal/colorschemes/dark/sexy-visibone.json
-../pywal/colorschemes/dark/sexy-x-dotshare.json
-../pywal/colorschemes/dark/sexy-zenburn.json
-../pywal/colorschemes/dark/solarized.json
-../pywal/colorschemes/dark/tempus_autumn.json
-../pywal/colorschemes/dark/tempus_dusk.json
-../pywal/colorschemes/dark/tempus_future.json
-../pywal/colorschemes/dark/tempus_rift.json
-../pywal/colorschemes/dark/tempus_spring.json
-../pywal/colorschemes/dark/tempus_summer.json
-../pywal/colorschemes/dark/tempus_warp.json
-../pywal/colorschemes/dark/tempus_winter.json
-../pywal/colorschemes/dark/vscode.json
-../pywal/colorschemes/dark/zenburn.json
-../pywal/colorschemes/light/3024.json
-../pywal/colorschemes/light/ashes.json
-../pywal/colorschemes/light/base16-atelier-cave.json
-../pywal/colorschemes/light/base16-atelier-dune.json
-../pywal/colorschemes/light/base16-atelier-estuary.json
-../pywal/colorschemes/light/base16-atelier-forest.json
-../pywal/colorschemes/light/base16-atelier-heath.json
-../pywal/colorschemes/light/base16-atelier-lakeside.json
-../pywal/colorschemes/light/base16-atelier-plateau.json
-../pywal/colorschemes/light/base16-atelier-savanna.json
-../pywal/colorschemes/light/base16-atelier-seaside.json
-../pywal/colorschemes/light/base16-atelier-sulphurpool.json
-../pywal/colorschemes/light/base16-classic.json
-../pywal/colorschemes/light/base16-cupcake.json
-../pywal/colorschemes/light/base16-cupertino.json
-../pywal/colorschemes/light/base16-default.json
-../pywal/colorschemes/light/base16-github.json
-../pywal/colorschemes/light/base16-google.json
-../pywal/colorschemes/light/base16-grayscale.json
-../pywal/colorschemes/light/base16-gruvbox-hard.json
-../pywal/colorschemes/light/base16-gruvbox-medium.json
-../pywal/colorschemes/light/base16-gruvbox-soft.json
-../pywal/colorschemes/light/base16-harmonic.json
-../pywal/colorschemes/light/base16-materialer.json
-../pywal/colorschemes/light/base16-mexico.json
-../pywal/colorschemes/light/base16-one.json
-../pywal/colorschemes/light/base16-shapeshifter.json
-../pywal/colorschemes/light/base16-solarized.json
-../pywal/colorschemes/light/base16-summerfruit.json
-../pywal/colorschemes/light/base16-tomorrow.json
-../pywal/colorschemes/light/base16-unikitty.json
-../pywal/colorschemes/light/github.json
-../pywal/colorschemes/light/sexy-mostly-bright.json
-../pywal/colorschemes/light/solarized.json
-../pywal/colorschemes/light/tempus_dawn.json
-../pywal/colorschemes/light/tempus_fugit.json
-../pywal/colorschemes/light/tempus_past.json
-../pywal/colorschemes/light/tempus_totus.json
-../pywal/export.py
-../pywal/image.py
-../pywal/reload.py
-../pywal/scripts/__pycache__/gtk_reload.cpython-39.pyc
-../pywal/scripts/gtk_reload.py
-../pywal/sequences.py
-../pywal/settings.py
-../pywal/templates/colors
-../pywal/templates/colors-kitty.conf
-../pywal/templates/colors-konsole.colorscheme
-../pywal/templates/colors-oomox
-../pywal/templates/colors-putty.reg
-../pywal/templates/colors-rofi-dark.rasi
-../pywal/templates/colors-rofi-light.rasi
-../pywal/templates/colors-speedcrunch.json
-../pywal/templates/colors-sway
-../pywal/templates/colors-tty.sh
-../pywal/templates/colors-wal-dmenu.h
-../pywal/templates/colors-wal-dwm.h
-../pywal/templates/colors-wal-st.h
-../pywal/templates/colors-wal-tabbed.h
-../pywal/templates/colors-wal.vim
-../pywal/templates/colors-waybar.css
-../pywal/templates/colors.Xresources
-../pywal/templates/colors.css
-../pywal/templates/colors.hs
-../pywal/templates/colors.json
-../pywal/templates/colors.scss
-../pywal/templates/colors.sh
-../pywal/templates/colors.yml
-../pywal/theme.py
-../pywal/util.py
-../pywal/wallpaper.py
-PKG-INFO
-SOURCES.txt
-dependency_links.txt
-entry_points.txt
-not-zip-safe
-top_level.txt
+++ /dev/null
-"""
- '||
-... ... .... ... ... ... ... .... ||
- ||' || '|. | || || | '' .|| ||
- || | '|.| ||| ||| .|' || ||
- ||...' '| | | '|..'|' .||.
- || .. |
-'''' ''
-Created by Dylan Araps.
-"""
-
-from .settings import __version__, __cache_version__
-from . import colors
-from . import export
-from . import image
-from . import reload
-from . import sequences
-from . import theme
-from . import wallpaper
-
-__all__ = [
- "__version__",
- "__cache_version__",
- "colors",
- "export",
- "image",
- "reload",
- "sequences",
- "theme",
- "wallpaper",
-]
+++ /dev/null
-"""
- '||
-... ... .... ... ... ... ... .... ||
- ||' || '|. | || || | '' .|| ||
- || | '|.| ||| ||| .|' || ||
- ||...' '| | | '|..'|' .||.
- || .. |
-'''' ''
-Created by Dylan Araps.
-"""
-
-import argparse
-import logging
-import os
-import shutil
-import sys
-
-from .settings import __version__, CACHE_DIR, CONF_DIR
-from . import colors
-from . import export
-from . import image
-from . import reload
-from . import sequences
-from . import theme
-from . import util
-from . import wallpaper
-
-
-def get_args():
- """Get the script arguments."""
- description = "wal - Generate colorschemes on the fly"
- arg = argparse.ArgumentParser(description=description)
-
- arg.add_argument("-a", metavar="\"alpha\"",
- help="Set terminal background transparency. \
- *Only works in URxvt*")
-
- arg.add_argument("-b", metavar="background",
- help="Custom background color to use.")
-
- arg.add_argument("--backend", metavar="backend",
- help="Which color backend to use. \
- Use 'wal --backend' to list backends.",
- const="list_backends", type=str, nargs="?")
-
- arg.add_argument("--theme", "-f", metavar="/path/to/file or theme_name",
- help="Which colorscheme file to use. \
- Use 'wal --theme' to list builtin themes.",
- const="list_themes", nargs="?")
-
- arg.add_argument("--iterative", action="store_true",
- help="When pywal is given a directory as input and this "
- "flag is used: Go through the images in order "
- "instead of shuffled.")
-
- arg.add_argument("--saturate", metavar="0.0-1.0",
- help="Set the color saturation.")
-
- arg.add_argument("--preview", action="store_true",
- help="Print the current color palette.")
-
- arg.add_argument("--vte", action="store_true",
- help="Fix text-artifacts printed in VTE terminals.")
-
- arg.add_argument("-c", action="store_true",
- help="Delete all cached colorschemes.")
-
- arg.add_argument("-i", metavar="\"/path/to/img.jpg\"",
- help="Which image or directory to use.")
-
- arg.add_argument("-l", action="store_true",
- help="Generate a light colorscheme.")
-
- arg.add_argument("-n", action="store_true",
- help="Skip setting the wallpaper.")
-
- arg.add_argument("-o", metavar="\"script_name\"", action="append",
- help="External script to run after \"wal\".")
-
- arg.add_argument("-q", action="store_true",
- help="Quiet mode, don\'t print anything.")
-
- arg.add_argument("-r", action="store_true",
- help="'wal -r' is deprecated: Use \
- (cat ~/.cache/wal/sequences &) instead.")
-
- arg.add_argument("-R", action="store_true",
- help="Restore previous colorscheme.")
-
- arg.add_argument("-s", action="store_true",
- help="Skip changing colors in terminals.")
-
- arg.add_argument("-t", action="store_true",
- help="Skip changing colors in tty.")
-
- arg.add_argument("-v", action="store_true",
- help="Print \"wal\" version.")
-
- arg.add_argument("-e", action="store_true",
- help="Skip reloading gtk/xrdb/i3/sway/polybar")
-
- return arg
-
-
-def parse_args_exit(parser):
- """Process args that exit."""
- args = parser.parse_args()
-
- if len(sys.argv) <= 1:
- parser.print_help()
- sys.exit(1)
-
- if args.v:
- parser.exit(0, "wal %s\n" % __version__)
-
- if args.preview:
- print("Current colorscheme:", sep='')
- colors.palette()
- sys.exit(0)
-
- if args.i and args.theme:
- parser.error("Conflicting arguments -i and -f.")
-
- if args.r:
- reload.colors()
- sys.exit(0)
-
- if args.c:
- scheme_dir = os.path.join(CACHE_DIR, "schemes")
- shutil.rmtree(scheme_dir, ignore_errors=True)
- sys.exit(0)
-
- if not args.i and \
- not args.theme and \
- not args.R and \
- not args.backend:
- parser.error("No input specified.\n"
- "--backend, --theme, -i or -R are required.")
-
- if args.theme == "list_themes":
- theme.list_out()
- sys.exit(0)
-
- if args.backend == "list_backends":
- print("\n - ".join(["\033[1;32mBackends\033[0m:",
- *colors.list_backends()]))
- sys.exit(0)
-
-
-def parse_args(parser):
- """Process args."""
- args = parser.parse_args()
-
- if args.q:
- logging.getLogger().disabled = True
- sys.stdout = sys.stderr = open(os.devnull, "w")
-
- if args.a:
- util.Color.alpha_num = args.a
-
- if args.i:
- image_file = image.get(args.i, iterative=args.iterative)
- colors_plain = colors.get(image_file, args.l, args.backend,
- sat=args.saturate)
-
- if args.theme:
- colors_plain = theme.file(args.theme, args.l)
-
- if args.R:
- colors_plain = theme.file(os.path.join(CACHE_DIR, "colors.json"))
-
- if args.b:
- args.b = "#%s" % (args.b.strip("#"))
- colors_plain["special"]["background"] = args.b
- colors_plain["colors"]["color0"] = args.b
-
- if not args.n:
- wallpaper.change(colors_plain["wallpaper"])
-
- sequences.send(colors_plain, to_send=not args.s, vte_fix=args.vte)
-
- if sys.stdout.isatty():
- colors.palette()
-
- export.every(colors_plain)
-
- if not args.e:
- reload.env(tty_reload=not args.t)
-
- if args.o:
- for cmd in args.o:
- util.disown([cmd])
-
- if not args.e:
- reload.gtk()
-
-
-def main():
- """Main script function."""
- util.create_dir(os.path.join(CONF_DIR, "templates"))
- util.create_dir(os.path.join(CONF_DIR, "colorschemes/light/"))
- util.create_dir(os.path.join(CONF_DIR, "colorschemes/dark/"))
-
- util.setup_logging()
- parser = get_args()
-
- parse_args_exit(parser)
- parse_args(parser)
-
-
-if __name__ == "__main__":
- main()
+++ /dev/null
-r"""
-Hh ____
-HP "HHF:. `._ :.,-'"" "-.
-F F" :::..'"" "-. `.
-F , \ \ "BACKENDS"
-F j\ / ; `.
-| j `. ` A \
-| | ;_ . 8 \
-J F\_,'| "`-----.\ j `. \
-"""
+++ /dev/null
-"""
-Generate a colorscheme using ColorThief.
-"""
-import logging
-import sys
-
-try:
- from colorthief import ColorThief
-
-except ImportError:
- logging.error("ColorThief wasn't found on your system.")
- logging.error("Try another backend. (wal --backend)")
- sys.exit(1)
-
-from .. import util
-
-
-def gen_colors(img):
- """Loop until 16 colors are generated."""
- color_cmd = ColorThief(img).get_palette
-
- for i in range(0, 10, 1):
- raw_colors = color_cmd(color_count=8 + i)
-
- if len(raw_colors) >= 8:
- break
-
- elif i == 10:
- logging.error("ColorThief couldn't generate a suitable palette.")
- sys.exit(1)
-
- else:
- logging.warning("ColorThief couldn't generate a palette.")
- logging.warning("Trying a larger palette size %s", 8 + i)
-
- return [util.rgb_to_hex(color) for color in raw_colors]
-
-
-def adjust(cols, light):
- """Create palette."""
- cols.sort(key=util.rgb_to_yiq)
- raw_colors = [*cols, *cols]
-
- if light:
- raw_colors[0] = util.lighten_color(cols[0], 0.90)
- raw_colors[7] = util.darken_color(cols[0], 0.75)
-
- else:
- for color in raw_colors:
- color = util.lighten_color(color, 0.40)
-
- raw_colors[0] = util.darken_color(cols[0], 0.80)
- raw_colors[7] = util.lighten_color(cols[0], 0.60)
-
- raw_colors[8] = util.lighten_color(cols[0], 0.20)
- raw_colors[15] = raw_colors[7]
-
- return raw_colors
-
-
-def get(img, light=False):
- """Get colorscheme."""
- cols = gen_colors(img)
- return adjust(cols, light)
+++ /dev/null
-"""
-Generate a colorscheme using Colorz.
-"""
-import logging
-import sys
-
-try:
- import colorz
-
-except ImportError:
- logging.error("colorz wasn't found on your system.")
- logging.error("Try another backend. (wal --backend)")
- sys.exit(1)
-
-from .. import colors
-from .. import util
-
-
-def gen_colors(img):
- """Generate a colorscheme using Colorz."""
- # pylint: disable=not-callable
- raw_colors = colorz.colorz(img, n=6, bold_add=0)
- return [util.rgb_to_hex([*color[0]]) for color in raw_colors]
-
-
-def adjust(cols, light):
- """Create palette."""
- raw_colors = [cols[0], *cols, "#FFFFFF",
- "#000000", *cols, "#FFFFFF"]
-
- return colors.generic_adjust(raw_colors, light)
-
-
-def get(img, light=False):
- """Get colorscheme."""
- cols = gen_colors(img)
-
- if len(cols) < 6:
- logging.error("colorz failed to generate enough colors.")
- logging.error("Try another backend or another image. (wal --backend)")
- sys.exit(1)
-
- return adjust(cols, light)
+++ /dev/null
-"""
-Generate a colorscheme using Haishoku.
-"""
-import logging
-import sys
-
-try:
- from haishoku.haishoku import Haishoku
-
-except ImportError:
- logging.error("Haishoku wasn't found on your system.")
- logging.error("Try another backend. (wal --backend)")
- sys.exit(1)
-
-from .. import colors
-from .. import util
-
-
-def gen_colors(img):
- """Generate a colorscheme using Colorz."""
- palette = Haishoku.getPalette(img)
- return [util.rgb_to_hex(col[1]) for col in palette]
-
-
-def adjust(cols, light):
- """Create palette."""
- cols.sort(key=util.rgb_to_yiq)
- raw_colors = [*cols, *cols]
- raw_colors[0] = util.lighten_color(cols[0], 0.40)
-
- return colors.generic_adjust(raw_colors, light)
-
-
-def get(img, light=False):
- """Get colorscheme."""
- cols = gen_colors(img)
- return adjust(cols, light)
+++ /dev/null
-"""
-Generate a colorscheme using Schemer2.
-"""
-import logging
-import shutil
-import subprocess
-import sys
-
-from .. import colors
-from .. import util
-
-
-def gen_colors(img):
- """Generate a colorscheme using Colorz."""
- cmd = ["schemer2", "-format", "img::colors", "-minBright", "75", "-in"]
- return subprocess.check_output([*cmd, img]).splitlines()
-
-
-def adjust(cols, light):
- """Create palette."""
- cols.sort(key=util.rgb_to_yiq)
- raw_colors = [*cols[8:], *cols[8:]]
-
- return colors.generic_adjust(raw_colors, light)
-
-
-def get(img, light=False):
- """Get colorscheme."""
- if not shutil.which("schemer2"):
- logging.error("Schemer2 wasn't found on your system.")
- logging.error("Try another backend. (wal --backend)")
- sys.exit(1)
-
- cols = [col.decode('UTF-8') for col in gen_colors(img)]
- return adjust(cols, light)
+++ /dev/null
-"""
-Generate a colorscheme using imagemagick.
-"""
-import logging
-import re
-import shutil
-import subprocess
-import sys
-
-from .. import util
-
-
-def imagemagick(color_count, img, magick_command):
- """Call Imagemagick to generate a scheme."""
- flags = ["-resize", "25%", "-colors", str(color_count),
- "-unique-colors", "txt:-"]
- img += "[0]"
-
- return subprocess.check_output([*magick_command, img, *flags]).splitlines()
-
-
-def has_im():
- """Check to see if the user has im installed."""
- if shutil.which("magick"):
- return ["magick", "convert"]
-
- if shutil.which("convert"):
- return ["convert"]
-
- logging.error("Imagemagick wasn't found on your system.")
- logging.error("Try another backend. (wal --backend)")
- sys.exit(1)
-
-
-def gen_colors(img):
- """Format the output from imagemagick into a list
- of hex colors."""
- magick_command = has_im()
-
- for i in range(0, 20, 1):
- raw_colors = imagemagick(16 + i, img, magick_command)
-
- if len(raw_colors) > 16:
- break
-
- elif i == 19:
- logging.error("Imagemagick couldn't generate a suitable palette.")
- sys.exit(1)
-
- else:
- logging.warning("Imagemagick couldn't generate a palette.")
- logging.warning("Trying a larger palette size %s", 16 + i)
-
- return [re.search("#.{6}", str(col)).group(0) for col in raw_colors[1:]]
-
-
-def adjust(colors, light):
- """Adjust the generated colors and store them in a dict that
- we will later save in json format."""
- raw_colors = colors[:1] + colors[8:16] + colors[8:-1]
-
- # Manually adjust colors.
- if light:
- for color in raw_colors:
- color = util.saturate_color(color, 0.5)
-
- raw_colors[0] = util.lighten_color(colors[-1], 0.85)
- raw_colors[7] = colors[0]
- raw_colors[8] = util.darken_color(colors[-1], 0.4)
- raw_colors[15] = colors[0]
-
- else:
- # Darken the background color slightly.
- if raw_colors[0][1] != "0":
- raw_colors[0] = util.darken_color(raw_colors[0], 0.40)
-
- raw_colors[7] = util.blend_color(raw_colors[7], "#EEEEEE")
- raw_colors[8] = util.darken_color(raw_colors[7], 0.30)
- raw_colors[15] = util.blend_color(raw_colors[15], "#EEEEEE")
-
- return raw_colors
-
-
-def get(img, light=False):
- """Get colorscheme."""
- colors = gen_colors(img)
- return adjust(colors, light)
+++ /dev/null
-"""
-Generate a palette using various backends.
-"""
-import logging
-import os
-import random
-import re
-import sys
-
-from . import theme
-from . import util
-from .settings import CACHE_DIR, MODULE_DIR, __cache_version__
-
-
-def list_backends():
- """List color backends."""
- return [b.name.replace(".py", "") for b in
- os.scandir(os.path.join(MODULE_DIR, "backends"))
- if "__" not in b.name]
-
-
-def colors_to_dict(colors, img):
- """Convert list of colors to pywal format."""
- return {
- "wallpaper": img,
- "alpha": util.Color.alpha_num,
-
- "special": {
- "background": colors[0],
- "foreground": colors[15],
- "cursor": colors[15]
- },
-
- "colors": {
- "color0": colors[0],
- "color1": colors[1],
- "color2": colors[2],
- "color3": colors[3],
- "color4": colors[4],
- "color5": colors[5],
- "color6": colors[6],
- "color7": colors[7],
- "color8": colors[8],
- "color9": colors[9],
- "color10": colors[10],
- "color11": colors[11],
- "color12": colors[12],
- "color13": colors[13],
- "color14": colors[14],
- "color15": colors[15]
- }
- }
-
-
-def generic_adjust(colors, light):
- """Generic color adjustment for themers."""
- if light:
- for color in colors:
- color = util.saturate_color(color, 0.60)
- color = util.darken_color(color, 0.5)
-
- colors[0] = util.lighten_color(colors[0], 0.95)
- colors[7] = util.darken_color(colors[0], 0.75)
- colors[8] = util.darken_color(colors[0], 0.25)
- colors[15] = colors[7]
-
- else:
- colors[0] = util.darken_color(colors[0], 0.80)
- colors[7] = util.lighten_color(colors[0], 0.75)
- colors[8] = util.lighten_color(colors[0], 0.25)
- colors[15] = colors[7]
-
- return colors
-
-
-def saturate_colors(colors, amount):
- """Saturate all colors."""
- if amount and float(amount) <= 1.0:
- for i, _ in enumerate(colors):
- if i not in [0, 7, 8, 15]:
- colors[i] = util.saturate_color(colors[i], float(amount))
-
- return colors
-
-
-def cache_fname(img, backend, light, cache_dir, sat=""):
- """Create the cache file name."""
- color_type = "light" if light else "dark"
- file_name = re.sub("[/|\\|.]", "_", img)
-
- file_parts = [file_name, color_type, backend, sat, __cache_version__]
- return [cache_dir, "schemes", "%s_%s_%s_%s_%s.json" % (*file_parts,)]
-
-
-def get_backend(backend):
- """Figure out which backend to use."""
- if backend == "random":
- backends = list_backends()
- random.shuffle(backends)
- return backends[0]
-
- return backend
-
-
-def palette():
- """Generate a palette from the colors."""
- for i in range(0, 16):
- if i % 8 == 0:
- print()
-
- if i > 7:
- i = "8;5;%s" % i
-
- print("\033[4%sm%s\033[0m" % (i, " " * (80 // 20)), end="")
-
- print("\n")
-
-
-def get(img, light=False, backend="wal", cache_dir=CACHE_DIR, sat=""):
- """Generate a palette."""
- # home_dylan_img_jpg_backend_1.2.2.json
- cache_name = cache_fname(img, backend, light, cache_dir, sat)
- cache_file = os.path.join(*cache_name)
-
- if os.path.isfile(cache_file):
- colors = theme.file(cache_file)
- colors["alpha"] = util.Color.alpha_num
- logging.info("Found cached colorscheme.")
-
- else:
- logging.info("Generating a colorscheme.")
- backend = get_backend(backend)
-
- # Dynamically import the backend we want to use.
- # This keeps the dependencies "optional".
- try:
- __import__("pywal.backends.%s" % backend)
- except ImportError:
- __import__("pywal.backends.wal")
- backend = "wal"
-
- logging.info("Using %s backend.", backend)
- backend = sys.modules["pywal.backends.%s" % backend]
- colors = getattr(backend, "get")(img, light)
- colors = colors_to_dict(saturate_colors(colors, sat), img)
-
- util.save_file_json(colors, cache_file)
- logging.info("Generation complete.")
-
- return colors
-
-
-def file(input_file):
- """Deprecated: symbolic link to --> theme.file"""
- return theme.file(input_file)
+++ /dev/null
-{"special":{"background":"#090300","foreground":"#a5a2a2","cursor":"#db2d20"},"colors":{"color0":"#090300","color1":"#db2d20","color2":"#01a252","color3":"#fded02","color4":"#01a0e4","color5":"#a16a94","color6":"#b5e4f4","color7":"#a5a2a2","color8":"#5c5855","color9":"#db2d20","color10":"#01a252","color11":"#fded02","color12":"#01a0e4","color13":"#a16a94","color14":"#b5e4f4","color15":"#f7f7f7"}}
+++ /dev/null
-{"special":{"background":"#1c2023","foreground":"#c7ccd1","cursor":"#c7ae95"},"colors":{"color0":"#1c2023","color1":"#c7ae95","color2":"#95c7ae","color3":"#aec795","color4":"#ae95c7","color5":"#c795ae","color6":"#95aec7","color7":"#c7ccd1","color8":"#747c84","color9":"#c7ae95","color10":"#95c7ae","color11":"#aec795","color12":"#ae95c7","color13":"#c795ae","color14":"#95aec7","color15":"#f3f4f5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#090300","foreground":"#a5a2a2","cursor":"#a5a2a2"},"colors":{"color0":"#090300","color1":"#db2d20","color2":"#01a252","color3":"#fded02","color4":"#01a0e4","color5":"#a16a94","color6":"#b5e4f4","color7":"#a5a2a2","color8":"#5c5855","color9":"#db2d20","color10":"#01a252","color11":"#fded02","color12":"#01a0e4","color13":"#a16a94","color14":"#b5e4f4","color15":"#f7f7f7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#031A16","foreground":"#81B5AC","cursor":"#81B5AC"},"colors":{"color0":"#031A16","color1":"#3E9688","color2":"#883E96","color3":"#3E4C96","color4":"#96883E","color5":"#4C963E","color6":"#963E4C","color7":"#81B5AC","color8":"#2B685E","color9":"#3E9688","color10":"#883E96","color11":"#3E4C96","color12":"#96883E","color13":"#4C963E","color14":"#963E4C","color15":"#D2E7E4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1C2023","foreground":"#C7CCD1","cursor":"#C7CCD1"},"colors":{"color0":"#1C2023","color1":"#C7AE95","color2":"#95C7AE","color3":"#AEC795","color4":"#AE95C7","color5":"#C795AE","color6":"#95AEC7","color7":"#C7CCD1","color8":"#747C84","color9":"#C7AE95","color10":"#95C7AE","color11":"#AEC795","color12":"#AE95C7","color13":"#C795AE","color14":"#95AEC7","color15":"#F3F4F5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#19171c","foreground":"#8b8792","cursor":"#8b8792"},"colors":{"color0":"#19171c","color1":"#be4678","color2":"#2a9292","color3":"#a06e3b","color4":"#576ddb","color5":"#955ae7","color6":"#398bc6","color7":"#8b8792","color8":"#655f6d","color9":"#be4678","color10":"#2a9292","color11":"#a06e3b","color12":"#576ddb","color13":"#955ae7","color14":"#398bc6","color15":"#efecf4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#20201d","foreground":"#a6a28c","cursor":"#a6a28c"},"colors":{"color0":"#20201d","color1":"#d73737","color2":"#60ac39","color3":"#ae9513","color4":"#6684e1","color5":"#b854d4","color6":"#1fad83","color7":"#a6a28c","color8":"#7d7a68","color9":"#d73737","color10":"#60ac39","color11":"#ae9513","color12":"#6684e1","color13":"#b854d4","color14":"#1fad83","color15":"#fefbec"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#22221b","foreground":"#929181","cursor":"#929181"},"colors":{"color0":"#22221b","color1":"#ba6236","color2":"#7d9726","color3":"#a5980d","color4":"#36a166","color5":"#5f9182","color6":"#5b9d48","color7":"#929181","color8":"#6c6b5a","color9":"#ba6236","color10":"#7d9726","color11":"#a5980d","color12":"#36a166","color13":"#5f9182","color14":"#5b9d48","color15":"#f4f3ec"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1b1918","foreground":"#a8a19f","cursor":"#a8a19f"},"colors":{"color0":"#1b1918","color1":"#f22c40","color2":"#7b9726","color3":"#c38418","color4":"#407ee7","color5":"#6666ea","color6":"#3d97b8","color7":"#a8a19f","color8":"#766e6b","color9":"#f22c40","color10":"#7b9726","color11":"#c38418","color12":"#407ee7","color13":"#6666ea","color14":"#3d97b8","color15":"#f1efee"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1b181b","foreground":"#ab9bab","cursor":"#ab9bab"},"colors":{"color0":"#1b181b","color1":"#ca402b","color2":"#918b3b","color3":"#bb8a35","color4":"#516aec","color5":"#7b59c0","color6":"#159393","color7":"#ab9bab","color8":"#776977","color9":"#ca402b","color10":"#918b3b","color11":"#bb8a35","color12":"#516aec","color13":"#7b59c0","color14":"#159393","color15":"#f7f3f7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#161b1d","foreground":"#7ea2b4","cursor":"#7ea2b4"},"colors":{"color0":"#161b1d","color1":"#d22d72","color2":"#568c3b","color3":"#8a8a0f","color4":"#257fad","color5":"#6b6bb8","color6":"#2d8f6f","color7":"#7ea2b4","color8":"#5a7b8c","color9":"#d22d72","color10":"#568c3b","color11":"#8a8a0f","color12":"#257fad","color13":"#6b6bb8","color14":"#2d8f6f","color15":"#ebf8ff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1b1818","foreground":"#8a8585","cursor":"#8a8585"},"colors":{"color0":"#1b1818","color1":"#ca4949","color2":"#4b8b8b","color3":"#a06e3b","color4":"#7272ca","color5":"#8464c4","color6":"#5485b6","color7":"#8a8585","color8":"#655d5d","color9":"#ca4949","color10":"#4b8b8b","color11":"#a06e3b","color12":"#7272ca","color13":"#8464c4","color14":"#5485b6","color15":"#f4ecec"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#171c19","foreground":"#87928a","cursor":"#87928a"},"colors":{"color0":"#171c19","color1":"#b16139","color2":"#489963","color3":"#a07e3b","color4":"#478c90","color5":"#55859b","color6":"#1c9aa0","color7":"#87928a","color8":"#5f6d64","color9":"#b16139","color10":"#489963","color11":"#a07e3b","color12":"#478c90","color13":"#55859b","color14":"#1c9aa0","color15":"#ecf4ee"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#131513","foreground":"#8ca68c","cursor":"#8ca68c"},"colors":{"color0":"#131513","color1":"#e6193c","color2":"#29a329","color3":"#98981b","color4":"#3d62f5","color5":"#ad2bee","color6":"#1999b3","color7":"#8ca68c","color8":"#687d68","color9":"#e6193c","color10":"#29a329","color11":"#98981b","color12":"#3d62f5","color13":"#ad2bee","color14":"#1999b3","color15":"#f4fbf4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#202746","foreground":"#979db4","cursor":"#979db4"},"colors":{"color0":"#202746","color1":"#c94922","color2":"#ac9739","color3":"#c08b30","color4":"#3d8fd1","color5":"#6679cc","color6":"#22a2c9","color7":"#979db4","color8":"#6b7394","color9":"#c94922","color10":"#ac9739","color11":"#c08b30","color12":"#3d8fd1","color13":"#6679cc","color14":"#22a2c9","color15":"#f5f7ff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#28211c","foreground":"#8a8986","cursor":"#8a8986"},"colors":{"color0":"#28211c","color1":"#cf6a4c","color2":"#54be0d","color3":"#f9ee98","color4":"#5ea6ea","color5":"#9b859d","color6":"#afc4db","color7":"#8a8986","color8":"#666666","color9":"#cf6a4c","color10":"#54be0d","color11":"#f9ee98","color12":"#5ea6ea","color13":"#9b859d","color14":"#afc4db","color15":"#baae9e"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#fbcb97","color3":"#e78a53","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#fbcb97","color11":"#e78a53","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#ddeecc","color3":"#99bbaa","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#ddeecc","color11":"#99bbaa","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#d0dfee","color3":"#5f81a5","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#d0dfee","color11":"#5f81a5","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#9b8d7f","color3":"#8c7f70","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#9b8d7f","color11":"#8c7f70","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#7799bb","color3":"#556677","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#7799bb","color11":"#556677","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#eceee3","color3":"#974b46","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#eceee3","color11":"#974b46","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#a5aaa7","color3":"#626b67","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#a5aaa7","color11":"#626b67","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#f3ecd4","color3":"#eecc6c","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#f3ecd4","color11":"#eecc6c","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#aa9988","color3":"#777755","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#aa9988","color11":"#777755","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#f8f7f2","color3":"#79241f","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#f8f7f2","color11":"#79241f","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c1c1c1","cursor":"#c1c1c1"},"colors":{"color0":"#000000","color1":"#5f8787","color2":"#dd9999","color3":"#a06666","color4":"#888888","color5":"#999999","color6":"#aaaaaa","color7":"#c1c1c1","color8":"#333333","color9":"#5f8787","color10":"#dd9999","color11":"#a06666","color12":"#888888","color13":"#999999","color14":"#aaaaaa","color15":"#c1c1c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#0c0d0e","foreground":"#b7b8b9","cursor":"#b7b8b9"},"colors":{"color0":"#0c0d0e","color1":"#e31a1c","color2":"#31a354","color3":"#dca060","color4":"#3182bd","color5":"#756bb1","color6":"#80b1d3","color7":"#b7b8b9","color8":"#737475","color9":"#e31a1c","color10":"#31a354","color11":"#dca060","color12":"#3182bd","color13":"#756bb1","color14":"#80b1d3","color15":"#fcfdfe"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#e0e0e0","cursor":"#e0e0e0"},"colors":{"color0":"#000000","color1":"#fb0120","color2":"#a1c659","color3":"#fda331","color4":"#6fb3d2","color5":"#d381c3","color6":"#76c7b7","color7":"#e0e0e0","color8":"#b0b0b0","color9":"#fb0120","color10":"#a1c659","color11":"#fda331","color12":"#6fb3d2","color13":"#d381c3","color14":"#76c7b7","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#485867","foreground":"#B0C5C8","cursor":"#B0C5C8"},"colors":{"color0":"#485867","color1":"#b38686","color2":"#87b386","color3":"#aab386","color4":"#868cb3","color5":"#b386b2","color6":"#86b3b3","color7":"#B0C5C8","color8":"#8299A1","color9":"#b38686","color10":"#87b386","color11":"#aab386","color12":"#868cb3","color13":"#b386b2","color14":"#86b3b3","color15":"#E3EFEF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#151515","foreground":"#d0d0d0","cursor":"#d0d0d0"},"colors":{"color0":"#151515","color1":"#fb9fb1","color2":"#acc267","color3":"#ddb26f","color4":"#6fc2ef","color5":"#e1a3ee","color6":"#12cfc0","color7":"#d0d0d0","color8":"#505050","color9":"#fb9fb1","color10":"#acc267","color11":"#ddb26f","color12":"#6fc2ef","color13":"#e1a3ee","color14":"#12cfc0","color15":"#f5f5f5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#191919","foreground":"#a7a7a7","cursor":"#a7a7a7"},"colors":{"color0":"#191919","color1":"#dc657d","color2":"#84b97c","color3":"#c3ba63","color4":"#639ee4","color5":"#b888e2","color6":"#4bb1a7","color7":"#a7a7a7","color8":"#5f5a60","color9":"#dc657d","color10":"#84b97c","color11":"#c3ba63","color12":"#639ee4","color13":"#b888e2","color14":"#4bb1a7","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#151515","foreground":"#D0D0D0","cursor":"#D0D0D0"},"colors":{"color0":"#151515","color1":"#AC4142","color2":"#90A959","color3":"#F4BF75","color4":"#6A9FB5","color5":"#AA759F","color6":"#75B5AA","color7":"#D0D0D0","color8":"#505050","color9":"#AC4142","color10":"#90A959","color11":"#F4BF75","color12":"#6A9FB5","color13":"#AA759F","color14":"#75B5AA","color15":"#F5F5F5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#232c31","foreground":"#9ea7a6","cursor":"#9ea7a6"},"colors":{"color0":"#232c31","color1":"#2a5491","color2":"#237986","color3":"#a03b1e","color4":"#484d79","color5":"#c59820","color6":"#b02f30","color7":"#9ea7a6","color8":"#3f4944","color9":"#2a5491","color10":"#237986","color11":"#a03b1e","color12":"#484d79","color13":"#c59820","color14":"#b02f30","color15":"#b5d8f6"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#181818","foreground":"#d8d8d8","cursor":"#d8d8d8"},"colors":{"color0":"#181818","color1":"#ab4642","color2":"#a1b56c","color3":"#f7ca88","color4":"#7cafc2","color5":"#ba8baf","color6":"#86c1b9","color7":"#d8d8d8","color8":"#585858","color9":"#ab4642","color10":"#a1b56c","color11":"#f7ca88","color12":"#7cafc2","color13":"#ba8baf","color14":"#86c1b9","color15":"#f8f8f8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#282936","foreground":"#e9e9f4","cursor":"#e9e9f4"},"colors":{"color0":"#282936","color1":"#ea51b2","color2":"#00f769","color3":"#ebff87","color4":"#62d6e8","color5":"#b45bcf","color6":"#a1efe4","color7":"#e9e9f4","color8":"#4d4f68","color9":"#ea51b2","color10":"#00f769","color11":"#ebff87","color12":"#62d6e8","color13":"#b45bcf","color14":"#a1efe4","color15":"#f7f7fb"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2d2d2d","foreground":"#d3d0c8","cursor":"#d3d0c8"},"colors":{"color0":"#2d2d2d","color1":"#f2777a","color2":"#99cc99","color3":"#ffcc66","color4":"#6699cc","color5":"#cc99cc","color6":"#66cccc","color7":"#d3d0c8","color8":"#747369","color9":"#f2777a","color10":"#99cc99","color11":"#ffcc66","color12":"#6699cc","color13":"#cc99cc","color14":"#66cccc","color15":"#f2f0ec"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#16130F","foreground":"#A39A90","cursor":"#A39A90"},"colors":{"color0":"#16130F","color1":"#826D57","color2":"#57826D","color3":"#6D8257","color4":"#6D5782","color5":"#82576D","color6":"#576D82","color7":"#A39A90","color8":"#5A5047","color9":"#826D57","color10":"#57826D","color11":"#6D8257","color12":"#6D5782","color13":"#82576D","color14":"#576D82","color15":"#DBD6D1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2C3E50","foreground":"#e0e0e0","cursor":"#e0e0e0"},"colors":{"color0":"#2C3E50","color1":"#E74C3C","color2":"#2ECC71","color3":"#F1C40F","color4":"#3498DB","color5":"#9B59B6","color6":"#1ABC9C","color7":"#e0e0e0","color8":"#95A5A6","color9":"#E74C3C","color10":"#2ECC71","color11":"#F1C40F","color12":"#3498DB","color13":"#9B59B6","color14":"#1ABC9C","color15":"#ECF0F1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1d1f21","foreground":"#c5c8c6","cursor":"#c5c8c6"},"colors":{"color0":"#1d1f21","color1":"#CC342B","color2":"#198844","color3":"#FBA922","color4":"#3971ED","color5":"#A36AC7","color6":"#3971ED","color7":"#c5c8c6","color8":"#969896","color9":"#CC342B","color10":"#198844","color11":"#FBA922","color12":"#3971ED","color13":"#A36AC7","color14":"#3971ED","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#101010","foreground":"#b9b9b9","cursor":"#b9b9b9"},"colors":{"color0":"#101010","color1":"#7c7c7c","color2":"#8e8e8e","color3":"#a0a0a0","color4":"#686868","color5":"#747474","color6":"#868686","color7":"#b9b9b9","color8":"#525252","color9":"#7c7c7c","color10":"#8e8e8e","color11":"#a0a0a0","color12":"#686868","color13":"#747474","color14":"#868686","color15":"#f7f7f7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#001100","foreground":"#00bb00","cursor":"#00bb00"},"colors":{"color0":"#001100","color1":"#007700","color2":"#00bb00","color3":"#007700","color4":"#009900","color5":"#00bb00","color6":"#005500","color7":"#00bb00","color8":"#007700","color9":"#007700","color10":"#00bb00","color11":"#007700","color12":"#009900","color13":"#00bb00","color14":"#005500","color15":"#00ff00"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1d2021","foreground":"#d5c4a1","cursor":"#d5c4a1"},"colors":{"color0":"#1d2021","color1":"#fb4934","color2":"#b8bb26","color3":"#fabd2f","color4":"#83a598","color5":"#d3869b","color6":"#8ec07c","color7":"#d5c4a1","color8":"#665c54","color9":"#fb4934","color10":"#b8bb26","color11":"#fabd2f","color12":"#83a598","color13":"#d3869b","color14":"#8ec07c","color15":"#fbf1c7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#282828","foreground":"#d5c4a1","cursor":"#d5c4a1"},"colors":{"color0":"#282828","color1":"#fb4934","color2":"#b8bb26","color3":"#fabd2f","color4":"#83a598","color5":"#d3869b","color6":"#8ec07c","color7":"#d5c4a1","color8":"#665c54","color9":"#fb4934","color10":"#b8bb26","color11":"#fabd2f","color12":"#83a598","color13":"#d3869b","color14":"#8ec07c","color15":"#fbf1c7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#262626","foreground":"#dab997","cursor":"#dab997"},"colors":{"color0":"#262626","color1":"#d75f5f","color2":"#afaf00","color3":"#ffaf00","color4":"#83adad","color5":"#d485ad","color6":"#85ad85","color7":"#dab997","color8":"#8a8a8a","color9":"#d75f5f","color10":"#afaf00","color11":"#ffaf00","color12":"#83adad","color13":"#d485ad","color14":"#85ad85","color15":"#ebdbb2"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#32302f","foreground":"#d5c4a1","cursor":"#d5c4a1"},"colors":{"color0":"#32302f","color1":"#fb4934","color2":"#b8bb26","color3":"#fabd2f","color4":"#83a598","color5":"#d3869b","color6":"#8ec07c","color7":"#d5c4a1","color8":"#665c54","color9":"#fb4934","color10":"#b8bb26","color11":"#fabd2f","color12":"#83a598","color13":"#d3869b","color14":"#8ec07c","color15":"#fbf1c7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#0b1c2c","foreground":"#cbd6e2","cursor":"#cbd6e2"},"colors":{"color0":"#0b1c2c","color1":"#bf8b56","color2":"#56bf8b","color3":"#8bbf56","color4":"#8b56bf","color5":"#bf568b","color6":"#568bbf","color7":"#cbd6e2","color8":"#627e99","color9":"#bf8b56","color10":"#56bf8b","color11":"#8bbf56","color12":"#8b56bf","color13":"#bf568b","color14":"#568bbf","color15":"#f7f9fb"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#322931","foreground":"#b9b5b8","cursor":"#b9b5b8"},"colors":{"color0":"#322931","color1":"#dd464c","color2":"#8fc13e","color3":"#fdcc59","color4":"#1290bf","color5":"#c85e7c","color6":"#149b93","color7":"#b9b5b8","color8":"#797379","color9":"#dd464c","color10":"#8fc13e","color11":"#fdcc59","color12":"#1290bf","color13":"#c85e7c","color14":"#149b93","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#021012","foreground":"#095b67","cursor":"#095b67"},"colors":{"color0":"#021012","color1":"#16c1d9","color2":"#4dd0e1","color3":"#80deea","color4":"#00bcd4","color5":"#00acc1","color6":"#26c6da","color7":"#095b67","color8":"#052e34","color9":"#16c1d9","color10":"#4dd0e1","color11":"#80deea","color12":"#00bcd4","color13":"#00acc1","color14":"#26c6da","color15":"#109cb0"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#b5b3aa","cursor":"#b5b3aa"},"colors":{"color0":"#000000","color1":"#ff6c60","color2":"#a8ff60","color3":"#ffffb6","color4":"#96cbfe","color5":"#ff73fd","color6":"#c6c5fe","color7":"#b5b3aa","color8":"#6c6c66","color9":"#ff6c60","color10":"#a8ff60","color11":"#ffffb6","color12":"#96cbfe","color13":"#ff73fd","color14":"#c6c5fe","color15":"#fdfbee"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#d0d0d0","cursor":"#d0d0d0"},"colors":{"color0":"#000000","color1":"#ff0000","color2":"#33ff00","color3":"#ff0099","color4":"#0066ff","color5":"#cc00ff","color6":"#00ffff","color7":"#d0d0d0","color8":"#808080","color9":"#ff0000","color10":"#33ff00","color11":"#ff0099","color12":"#0066ff","color13":"#cc00ff","color14":"#00ffff","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#c0c0c0","cursor":"#c0c0c0"},"colors":{"color0":"#000000","color1":"#dd0907","color2":"#1fb714","color3":"#fbf305","color4":"#0000d3","color5":"#4700a5","color6":"#02abea","color7":"#c0c0c0","color8":"#808080","color9":"#dd0907","color10":"#1fb714","color11":"#fbf305","color12":"#0000d3","color13":"#4700a5","color14":"#02abea","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#201602","foreground":"#948e48","cursor":"#948e48"},"colors":{"color0":"#201602","color1":"#c35359","color2":"#18974e","color3":"#a88339","color4":"#477ca1","color5":"#8868b3","color6":"#75a738","color7":"#948e48","color8":"#6c6823","color9":"#c35359","color10":"#18974e","color11":"#a88339","color12":"#477ca1","color13":"#8868b3","color14":"#75a738","color15":"#faf0a5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#263238","foreground":"#CDD3DE","cursor":"#CDD3DE"},"colors":{"color0":"#263238","color1":"#EC5F67","color2":"#8BD649","color3":"#FFCC00","color4":"#89DDFF","color5":"#82AAFF","color6":"#80CBC4","color7":"#CDD3DE","color8":"#707880","color9":"#EC5F67","color10":"#8BD649","color11":"#FFCC00","color12":"#89DDFF","color13":"#82AAFF","color14":"#80CBC4","color15":"#FFFFFF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#292D3E","foreground":"#959DCB","cursor":"#959DCB"},"colors":{"color0":"#292D3E","color1":"#F07178","color2":"#C3E88D","color3":"#FFCB6B","color4":"#82AAFF","color5":"#C792EA","color6":"#89DDFF","color7":"#959DCB","color8":"#676E95","color9":"#F07178","color10":"#C3E88D","color11":"#FFCB6B","color12":"#82AAFF","color13":"#C792EA","color14":"#89DDFF","color15":"#FFFFFF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#263238","foreground":"#EEFFFF","cursor":"#EEFFFF"},"colors":{"color0":"#263238","color1":"#F07178","color2":"#C3E88D","color3":"#FFCB6B","color4":"#82AAFF","color5":"#C792EA","color6":"#89DDFF","color7":"#EEFFFF","color8":"#546E7A","color9":"#F07178","color10":"#C3E88D","color11":"#FFCB6B","color12":"#82AAFF","color13":"#C792EA","color14":"#89DDFF","color15":"#FFFFFF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#212121","foreground":"#EEFFFF","cursor":"#EEFFFF"},"colors":{"color0":"#212121","color1":"#F07178","color2":"#C3E88D","color3":"#FFCB6B","color4":"#82AAFF","color5":"#C792EA","color6":"#89DDFF","color7":"#EEFFFF","color8":"#4A4A4A","color9":"#F07178","color10":"#C3E88D","color11":"#FFCB6B","color12":"#82AAFF","color13":"#C792EA","color14":"#89DDFF","color15":"#FFFFFF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1e0528","foreground":"#ffeeff","cursor":"#ffeeff"},"colors":{"color0":"#1e0528","color1":"#00d9e9","color2":"#05cb0d","color3":"#955ae7","color4":"#550068","color5":"#8991bb","color6":"#b900b1","color7":"#ffeeff","color8":"#320f55","color9":"#00d9e9","color10":"#05cb0d","color11":"#955ae7","color12":"#550068","color13":"#8991bb","color14":"#b900b1","color15":"#f8c0ff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#3B3228","foreground":"#d0c8c6","cursor":"#d0c8c6"},"colors":{"color0":"#3B3228","color1":"#cb6077","color2":"#beb55b","color3":"#f4bc87","color4":"#8ab3b5","color5":"#a89bb9","color6":"#7bbda4","color7":"#d0c8c6","color8":"#7e705a","color9":"#cb6077","color10":"#beb55b","color11":"#f4bc87","color12":"#8ab3b5","color13":"#a89bb9","color14":"#7bbda4","color15":"#f5eeeb"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#272822","foreground":"#f8f8f2","cursor":"#f8f8f2"},"colors":{"color0":"#272822","color1":"#f92672","color2":"#a6e22e","color3":"#f4bf75","color4":"#66d9ef","color5":"#ae81ff","color6":"#a1efe4","color7":"#f8f8f2","color8":"#75715e","color9":"#f92672","color10":"#a6e22e","color11":"#f4bf75","color12":"#66d9ef","color13":"#ae81ff","color14":"#a1efe4","color15":"#f9f8f5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2E3440","foreground":"#E5E9F0","cursor":"#E5E9F0"},"colors":{"color0":"#2E3440","color1":"#88C0D0","color2":"#BF616A","color3":"#5E81AC","color4":"#EBCB8B","color5":"#A3BE8C","color6":"#D08770","color7":"#E5E9F0","color8":"#4C566A","color9":"#88C0D0","color10":"#BF616A","color11":"#5E81AC","color12":"#EBCB8B","color13":"#A3BE8C","color14":"#D08770","color15":"#8FBCBB"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2b303b","foreground":"#c0c5ce","cursor":"#c0c5ce"},"colors":{"color0":"#2b303b","color1":"#bf616a","color2":"#a3be8c","color3":"#ebcb8b","color4":"#8fa1b3","color5":"#b48ead","color6":"#96b5b4","color7":"#c0c5ce","color8":"#65737e","color9":"#bf616a","color10":"#a3be8c","color11":"#ebcb8b","color12":"#8fa1b3","color13":"#b48ead","color14":"#96b5b4","color15":"#eff1f5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1B2B34","foreground":"#C0C5CE","cursor":"#C0C5CE"},"colors":{"color0":"#1B2B34","color1":"#EC5f67","color2":"#99C794","color3":"#FAC863","color4":"#6699CC","color5":"#C594C5","color6":"#5FB3B3","color7":"#C0C5CE","color8":"#65737E","color9":"#EC5f67","color10":"#99C794","color11":"#FAC863","color12":"#6699CC","color13":"#C594C5","color14":"#5FB3B3","color15":"#D8DEE9"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#282c34","foreground":"#abb2bf","cursor":"#abb2bf"},"colors":{"color0":"#282c34","color1":"#e06c75","color2":"#98c379","color3":"#e5c07b","color4":"#61afef","color5":"#c678dd","color6":"#56b6c2","color7":"#abb2bf","color8":"#545862","color9":"#e06c75","color10":"#98c379","color11":"#e5c07b","color12":"#61afef","color13":"#c678dd","color14":"#56b6c2","color15":"#c8ccd4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#00002A","foreground":"#D0D0FA","cursor":"#D0D0FA"},"colors":{"color0":"#00002A","color1":"#FF4242","color2":"#59F176","color3":"#F3E877","color4":"#66B0FF","color5":"#F10596","color6":"#0EF0F0","color7":"#D0D0FA","color8":"#50507A","color9":"#FF4242","color10":"#59F176","color11":"#F3E877","color12":"#66B0FF","color13":"#F10596","color14":"#0EF0F0","color15":"#F5F5FF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2f1e2e","foreground":"#a39e9b","cursor":"#a39e9b"},"colors":{"color0":"#2f1e2e","color1":"#ef6155","color2":"#48b685","color3":"#fec418","color4":"#06b6ef","color5":"#815ba4","color6":"#5bc4bf","color7":"#a39e9b","color8":"#776e71","color9":"#ef6155","color10":"#48b685","color11":"#fec418","color12":"#06b6ef","color13":"#815ba4","color14":"#5bc4bf","color15":"#e7e9db"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#061229","foreground":"#b8bbc2","cursor":"#b8bbc2"},"colors":{"color0":"#061229","color1":"#d07346","color2":"#99bf52","color3":"#fbd461","color4":"#5299bf","color5":"#9989cc","color6":"#72b9bf","color7":"#b8bbc2","color8":"#717885","color9":"#d07346","color10":"#99bf52","color11":"#fbd461","color12":"#5299bf","color13":"#9989cc","color14":"#72b9bf","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#5f574f","cursor":"#5f574f"},"colors":{"color0":"#000000","color1":"#ff004d","color2":"#00e756","color3":"#fff024","color4":"#83769c","color5":"#ff77a8","color6":"#29adff","color7":"#5f574f","color8":"#008751","color9":"#ff004d","color10":"#00e756","color11":"#fff024","color12":"#83769c","color13":"#ff77a8","color14":"#29adff","color15":"#fff1e8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#000000","foreground":"#d0d0d0","cursor":"#d0d0d0"},"colors":{"color0":"#000000","color1":"#eb008a","color2":"#37b349","color3":"#f8ca12","color4":"#0e5a94","color5":"#b31e8d","color6":"#00aabb","color7":"#d0d0d0","color8":"#505050","color9":"#eb008a","color10":"#37b349","color11":"#f8ca12","color12":"#0e5a94","color13":"#b31e8d","color14":"#00aabb","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#292c36","foreground":"#d8d8d8","cursor":"#d8d8d8"},"colors":{"color0":"#292c36","color1":"#f84547","color2":"#95c76f","color3":"#efa16b","color4":"#8485ce","color5":"#b74989","color6":"#64878f","color7":"#d8d8d8","color8":"#65568a","color9":"#f84547","color10":"#95c76f","color11":"#efa16b","color12":"#8485ce","color13":"#b74989","color14":"#64878f","color15":"#f8f8f8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2b2b2b","foreground":"#e6e1dc","cursor":"#e6e1dc"},"colors":{"color0":"#2b2b2b","color1":"#da4939","color2":"#a5c261","color3":"#ffc66d","color4":"#6d9cbe","color5":"#b6b3eb","color6":"#519f50","color7":"#e6e1dc","color8":"#5a647e","color9":"#da4939","color10":"#a5c261","color11":"#ffc66d","color12":"#6d9cbe","color13":"#b6b3eb","color14":"#519f50","color15":"#f9f7f3"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#292a44","foreground":"#f1eff8","cursor":"#f1eff8"},"colors":{"color0":"#292a44","color1":"#a0a0c5","color2":"#6dfedf","color3":"#ae81ff","color4":"#2de0a7","color5":"#7aa5ff","color6":"#8eaee0","color7":"#f1eff8","color8":"#666699","color9":"#a0a0c5","color10":"#6dfedf","color11":"#ae81ff","color12":"#2de0a7","color13":"#7aa5ff","color14":"#8eaee0","color15":"#53495d"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#151718","foreground":"#d6d6d6","cursor":"#d6d6d6"},"colors":{"color0":"#151718","color1":"#Cd3f45","color2":"#9fca56","color3":"#e6cd69","color4":"#55b5db","color5":"#a074c4","color6":"#55dbbe","color7":"#d6d6d6","color8":"#41535B","color9":"#Cd3f45","color10":"#9fca56","color11":"#e6cd69","color12":"#55b5db","color13":"#a074c4","color14":"#55dbbe","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#18262F","foreground":"#A6AFB8","cursor":"#A6AFB8"},"colors":{"color0":"#18262F","color1":"#EF5253","color2":"#7CC844","color3":"#E4B51C","color4":"#33B5E1","color5":"#A363D5","color6":"#52CBB0","color7":"#A6AFB8","color8":"#667581","color9":"#EF5253","color10":"#7CC844","color11":"#E4B51C","color12":"#33B5E1","color13":"#A363D5","color14":"#52CBB0","color15":"#F5F7FA"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#002b36","foreground":"#93a1a1","cursor":"#93a1a1"},"colors":{"color0":"#002b36","color1":"#dc322f","color2":"#859900","color3":"#b58900","color4":"#268bd2","color5":"#6c71c4","color6":"#2aa198","color7":"#93a1a1","color8":"#657b83","color9":"#dc322f","color10":"#859900","color11":"#b58900","color12":"#268bd2","color13":"#6c71c4","color14":"#2aa198","color15":"#fdf6e3"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1f2022","foreground":"#a3a3a3","cursor":"#a3a3a3"},"colors":{"color0":"#1f2022","color1":"#f2241f","color2":"#67b11d","color3":"#b1951d","color4":"#4f97d7","color5":"#a31db1","color6":"#2d9574","color7":"#a3a3a3","color8":"#585858","color9":"#f2241f","color10":"#67b11d","color11":"#b1951d","color12":"#4f97d7","color13":"#a31db1","color14":"#2d9574","color15":"#f8f8f8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#151515","foreground":"#D0D0D0","cursor":"#D0D0D0"},"colors":{"color0":"#151515","color1":"#FF0086","color2":"#00C918","color3":"#ABA800","color4":"#3777E6","color5":"#AD00A1","color6":"#1FAAAA","color7":"#D0D0D0","color8":"#505050","color9":"#FF0086","color10":"#00C918","color11":"#ABA800","color12":"#3777E6","color13":"#AD00A1","color14":"#1FAAAA","color15":"#FFFFFF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1d1f21","foreground":"#c5c8c6","cursor":"#c5c8c6"},"colors":{"color0":"#1d1f21","color1":"#cc6666","color2":"#b5bd68","color3":"#f0c674","color4":"#81a2be","color5":"#b294bb","color6":"#8abeb7","color7":"#c5c8c6","color8":"#969896","color9":"#cc6666","color10":"#b5bd68","color11":"#f0c674","color12":"#81a2be","color13":"#b294bb","color14":"#8abeb7","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#231f20","foreground":"#d9d8d8","cursor":"#d9d8d8"},"colors":{"color0":"#231f20","color1":"#ee2e24","color2":"#00853e","color3":"#ffd204","color4":"#009ddc","color5":"#98005d","color6":"#85cebc","color7":"#d9d8d8","color8":"#737171","color9":"#ee2e24","color10":"#00853e","color11":"#ffd204","color12":"#009ddc","color13":"#98005d","color14":"#85cebc","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1e1e1e","foreground":"#a7a7a7","cursor":"#a7a7a7"},"colors":{"color0":"#1e1e1e","color1":"#cf6a4c","color2":"#8f9d6a","color3":"#f9ee98","color4":"#7587a6","color5":"#9b859d","color6":"#afc4db","color7":"#a7a7a7","color8":"#5f5a60","color9":"#cf6a4c","color10":"#8f9d6a","color11":"#f9ee98","color12":"#7587a6","color13":"#9b859d","color14":"#afc4db","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2e2a31","foreground":"#bcbabe","cursor":"#bcbabe"},"colors":{"color0":"#2e2a31","color1":"#d8137f","color2":"#17ad98","color3":"#dc8a0e","color4":"#796af5","color5":"#bb60ea","color6":"#149bda","color7":"#bcbabe","color8":"#838085","color9":"#d8137f","color10":"#17ad98","color11":"#dc8a0e","color12":"#796af5","color13":"#bb60ea","color14":"#149bda","color15":"#f5f4f7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#231e18","foreground":"#cabcb1","cursor":"#cabcb1"},"colors":{"color0":"#231e18","color1":"#d35c5c","color2":"#b7ba53","color3":"#e0ac16","color4":"#88a4d3","color5":"#bb90e2","color6":"#6eb958","color7":"#cabcb1","color8":"#9d8b70","color9":"#d35c5c","color10":"#b7ba53","color11":"#e0ac16","color12":"#88a4d3","color13":"#bb90e2","color14":"#6eb958","color15":"#e4d4c8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#282B35","foreground":"#939599","cursor":"#939599"},"colors":{"color0":"#282B35","color1":"#B21889","color2":"#DF0002","color3":"#438288","color4":"#790EAD","color5":"#B21889","color6":"#00A0BE","color7":"#939599","color8":"#686A71","color9":"#B21889","color10":"#DF0002","color11":"#438288","color12":"#790EAD","color13":"#B21889","color14":"#00A0BE","color15":"#BEBFC2"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#3f3f3f","foreground":"#dcdccc","cursor":"#dcdccc"},"colors":{"color0":"#3f3f3f","color1":"#dca3a3","color2":"#5f7f5f","color3":"#e0cf9f","color4":"#7cb8bb","color5":"#dc8cc3","color6":"#93e0e3","color7":"#dcdccc","color8":"#4f4f4f","color9":"#dca3a3","color10":"#5f7f5f","color11":"#e0cf9f","color12":"#7cb8bb","color13":"#dc8cc3","color14":"#93e0e3","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1D2021","foreground":"#A89984","cursor":"#A89984"},"colors":{"color0":"#1D2021","color1":"#FB543F","color2":"#95C085","color3":"#FAC03B","color4":"#0D6678","color5":"#8F4673","color6":"#8BA59B","color7":"#A89984","color8":"#665C54","color9":"#FB543F","color10":"#95C085","color11":"#FAC03B","color12":"#0D6678","color13":"#8F4673","color14":"#8BA59B","color15":"#FDF4C1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1d2021","foreground":"#a89984","cursor":"#fb543f"},"colors":{"color0":"#1d2021","color1":"#fb543f","color2":"#95c085","color3":"#fac03b","color4":"#0d6678","color5":"#8f4673","color6":"#8ba59b","color7":"#a89984","color8":"#665c54","color9":"#fb543f","color10":"#95c085","color11":"#fac03b","color12":"#0d6678","color13":"#8f4673","color14":"#8ba59b","color15":"#fdf4c1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#353234","foreground":"#c29f6f","cursor":"#363334"},"colors":{"color0":"#353234","color1":"#97544d","color2":"#97a293","color3":"#c29f6f","color4":"#5e606c","color5":"#7a6054","color6":"#78746c","color7":"#c3c1b8","color7":"#c3c1b8","color8":"#5c575b","color9":"#97544d","color10":"#97a293","color11":"#c29f6f","color12":"#5e606c","color13":"#7a6054","color14":"#78746c","color15":"#c3c1b8","color15":"#c3c1b8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#262020","foreground":"#aa9a71","cursor":"#b1a89c"},"colors":{"color0":"#262020","color1":"#925633","color2":"#55634f","color3":"#aa9a71","color4":"#5e6676","color5":"#57464d","color6":"#47676e","color7":"#b1a89c","color7":"#b1a89c","color8":"#514c4c","color9":"#925633","color10":"#55634f","color11":"#aa9a71","color12":"#5e6676","color13":"#57464d","color14":"#47676e","color15":"#b1a89c","color15":"#c8c1b9"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#30272b","foreground":"#978341","cursor":"#bcb8ba"},"colors":{"color0":"#30272b","color1":"#925633","color2":"#697234","color3":"#978341","color4":"#5e6676","color5":"#694e63","color6":"#47676e","color7":"#bcb8ba","color7":"#bcb8ba","color8":"#443c40","color9":"#925633","color10":"#697234","color11":"#978341","color12":"#5e6676","color13":"#694e63","color14":"#47676e","color15":"#bcb8ba","color15":"#bcb8ba"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#272725","foreground":"#bc9f67","cursor":"#282826"},"colors":{"color0":"#272725","color1":"#7d5151","color2":"#959c4f","color3":"#a78749","color4":"#455563","color5":"#9f908d","color6":"#4a5e5b","color7":"#f2f2f2","color7":"#f2f2f2","color8":"#4f4f4b","color9":"#7d5151","color10":"#959c4f","color11":"#a78749","color12":"#455563","color13":"#9f908d","color14":"#4a5e5b","color15":"#f2f2f2","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2c2a2b","foreground":"#baad8a","cursor":"#bab9ba"},"colors":{"color0":"#2c2a2b","color1":"#a67979","color2":"#809f7b","color3":"#baad8a","color4":"#6d7575","color5":"#7d6969","color6":"#7b9899","color7":"#bab9ba","color7":"#bab9ba","color8":"#545253","color9":"#a67979","color10":"#809f7b","color11":"#baad8a","color12":"#6d7575","color13":"#7d6969","color14":"#7b9899","color15":"#bab9ba","color15":"#bab9ba"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#272a2a","foreground":"#80807e","cursor":"#eaeaed"},"colors":{"color0":"#272a2a","color1":"#b05f5f","color2":"#b05f5f","color3":"#88aa55","color4":"#88aa55","color5":"#ccb05f","color6":"#ccb05f","color7":"#556973","color7":"#556973","color8":"#484c4e","color9":"#b05f5f","color10":"#b05f5f","color11":"#88aa55","color12":"#88aa55","color13":"#ccb05f","color14":"#ccb05f","color15":"#556973","color15":"#f6f7f8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1c1f23","foreground":"#7e6b5f","cursor":"#202428"},"colors":{"color0":"#1c1f23","color1":"#234640","color2":"#555552","color3":"#7e6b5f","color4":"#384758","color5":"#444d4d","color6":"#415459","color7":"#ccc7bf","color7":"#ccc7bf","color8":"#33383f","color9":"#234640","color10":"#555552","color11":"#7e6b5f","color12":"#384758","color13":"#444d4d","color14":"#415459","color15":"#ccc7bf","color15":"#e3e0db"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2b2b28","foreground":"#937b5a","cursor":"#2c2c29"},"colors":{"color0":"#2b2b28","color1":"#993f3c","color2":"#78855e","color3":"#937b5a","color4":"#415265","color5":"#885458","color6":"#646666","color7":"#c4c3c0","color7":"#c4c3c0","color8":"#c4c3c0","color9":"#993f3c","color10":"#78855e","color11":"#937b5a","color12":"#415265","color13":"#885458","color14":"#646666","color15":"#c4c3c0","color15":"#c4c3c0"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#32221a","foreground":"#d29b5a","cursor":"#cfc1a9"},"colors":{"color0":"#32221a","color1":"#c2562d","color2":"#96a65e","color3":"#d29b5a","color4":"#3b8e8c","color5":"#c47e5b","color6":"#639a90","color7":"#cfc1a9","color7":"#cfc1a9","color8":"#564a45","color9":"#c2562d","color10":"#96a65e","color11":"#d29b5a","color12":"#3b8e8c","color13":"#c47e5b","color14":"#639a90","color15":"#cfc1a9","color15":"#cfc1a9"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#272825","foreground":"#7e744d","cursor":"#282926"},"colors":{"color0":"#272825","color1":"#674839","color2":"#6e794f","color3":"#7e744d","color4":"#3b474e","color5":"#554c41","color6":"#495355","color7":"#b0b0af","color7":"#b0b0af","color8":"#b0b0af","color9":"#674839","color10":"#6e794f","color11":"#7e744d","color12":"#3b474e","color13":"#554c41","color14":"#495355","color15":"#b0b0af","color15":"#c7c7c7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2c292b","foreground":"#c8a168","cursor":"#312e30"},"colors":{"color0":"#2c292b","color1":"#ab6d4e","color2":"#88885d","color3":"#c8a168","color4":"#45626e","color5":"#7c5545","color6":"#456e66","color7":"#c3b495","color7":"#c3b495","color8":"#c3b495","color9":"#ab6d4e","color10":"#88885d","color11":"#c8a168","color12":"#45626e","color13":"#7c5545","color14":"#456e66","color15":"#c3b495","color15":"#c3b495"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#383844","foreground":"#cba264","cursor":"#cdc5b7"},"colors":{"color0":"#383844","color1":"#a7664a","color2":"#6e8c6e","color3":"#cba264","color4":"#535f6b","color5":"#775a62","color6":"#576e68","color7":"#cdc5b7","color7":"#cdc5b7","color8":"#4f4f60","color9":"#a7664a","color10":"#6e8c6e","color11":"#cba264","color12":"#535f6b","color13":"#775a62","color14":"#576e68","color15":"#cdc5b7","color15":"#cdc5b7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1f1d1d","foreground":"#856237","cursor":"#ccbaad"},"colors":{"color0":"#1f1d1d","color1":"#6b4747","color2":"#8d7138","color3":"#856237","color4":"#3c3c49","color5":"#3c342e","color6":"#5d5a4b","color7":"#ccbaad","color7":"#ccbaad","color8":"#4a4a4a","color9":"#6b4747","color10":"#8d7138","color11":"#856237","color12":"#3c3c49","color13":"#3c342e","color14":"#5d5a4b","color15":"#ccbaad","color15":"#eae2dc"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#27201d","foreground":"#987f4b","cursor":"#b7afa4"},"colors":{"color0":"#27201d","color1":"#663c23","color2":"#5c5933","color3":"#987f4b","color4":"#4b484b","color5":"#9c8065","color6":"#685a50","color7":"#b7afa4","color7":"#b7afa4","color8":"#3c3633","color9":"#663c23","color10":"#5c5933","color11":"#987f4b","color12":"#4b484b","color13":"#9c8065","color14":"#685a50","color15":"#b7afa4","color15":"#b7afa4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2c2833","foreground":"#b7a16c","cursor":"#dbd7b8"},"colors":{"color0":"#2c2833","color1":"#bf6257","color2":"#82a37c","color3":"#b7a16c","color4":"#6d6a80","color5":"#825969","color6":"#938e8f","color7":"#dbd7b8","color7":"#dbd7b8","color8":"#4e4955","color9":"#bf6257","color10":"#82a37c","color11":"#b7a16c","color12":"#6d6a80","color13":"#825969","color14":"#938e8f","color15":"#dbd7b8","color15":"#dbd7b8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#242e32","foreground":"#ac8d6e","cursor":"#c4c4b5"},"colors":{"color0":"#242e32","color1":"#a66959","color2":"#769070","color3":"#ac8d6e","color4":"#607a86","color5":"#8a757e","color6":"#60867f","color7":"#c4c4b5","color7":"#c4c4b5","color8":"#35444b","color9":"#a66959","color10":"#769070","color11":"#ac8d6e","color12":"#607a86","color13":"#8a757e","color14":"#60867f","color15":"#c4c4b5","color15":"#c4c4b5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2e3738","foreground":"#b8af97","cursor":"#aba599"},"colors":{"color0":"#2e3738","color1":"#9c7f5d","color2":"#8e958f","color3":"#b8af97","color4":"#828882","color5":"#bb9a7f","color6":"#9daba2","color7":"#aba599","color7":"#aba599","color8":"#485152","color9":"#9c7f5d","color10":"#8e958f","color11":"#b8af97","color12":"#828882","color13":"#bb9a7f","color14":"#9daba2","color15":"#aba599","color15":"#aba599"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1c2319","foreground":"#be9e61","cursor":"#bcbebb"},"colors":{"color0":"#1c2319","color1":"#c14d38","color2":"#a0ce52","color3":"#be9e61","color4":"#4c7e89","color5":"#814d61","color6":"#79a69d","color7":"#bcbebb","color7":"#bcbebb","color8":"#35422f","color9":"#c14d38","color10":"#a0ce52","color11":"#be9e61","color12":"#4c7e89","color13":"#814d61","color14":"#79a69d","color15":"#bcbebb","color15":"#bcbebb"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#262c1b","foreground":"#d6caaa","cursor":"#c1c5bd"},"colors":{"color0":"#262c1b","color1":"#7f5545","color2":"#677c54","color3":"#bba772","color4":"#6e6a5b","color5":"#92887e","color6":"#7c7562","color7":"#cccdbd","color7":"#cccdbd","color8":"#474c3e","color9":"#7f5545","color10":"#677c54","color11":"#bba772","color12":"#6e6a5b","color13":"#92887e","color14":"#7c7562","color15":"#cccdbd","color15":"#e0e1d7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2f2832","foreground":"#9a8e80","cursor":"#302833"},"colors":{"color0":"#2f2832","color1":"#885d50","color2":"#747965","color3":"#9a8e80","color4":"#4a4e5a","color5":"#76675b","color6":"#59555c","color7":"#bcb5b5","color7":"#bcb5b5","color8":"#4a3f4e","color9":"#885d50","color10":"#747965","color11":"#9a8e80","color12":"#4a4e5a","color13":"#76675b","color14":"#59555c","color15":"#bcb5b5","color15":"#dddada"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#161f14","foreground":"#806420","cursor":"#172015"},"colors":{"color0":"#161f14","color1":"#744425","color2":"#50703f","color3":"#806420","color4":"#56535d","color5":"#71532f","color6":"#45605d","color7":"#aca173","color7":"#aca173","color8":"#2d352b","color9":"#744425","color10":"#50703f","color11":"#806420","color12":"#56535d","color13":"#71532f","color14":"#45605d","color15":"#aca173","color15":"#aca173"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1e1e1e","foreground":"#4c6640","cursor":"#9e9e91"},"colors":{"color0":"#1e1e1e","color1":"#98442f","color2":"#9d8554","color3":"#4c6640","color4":"#4c596b","color5":"#7b6072","color6":"#385853","color7":"#9e9e91","color7":"#9e9e91","color8":"#363636","color9":"#98442f","color10":"#9d8554","color11":"#4c6640","color12":"#4c596b","color13":"#7b6072","color14":"#385853","color15":"#9e9e91","color15":"#9e9e91"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#322b26","foreground":"#d7b18a","cursor":"#c8b49d"},"colors":{"color0":"#322b26","color1":"#bd6151","color2":"#6e9383","color3":"#d7b18a","color4":"#8a8f94","color5":"#bd9a81","color6":"#91a1a5","color7":"#c8b49d","color7":"#c8b49d","color8":"#63554c","color9":"#bd6151","color10":"#6e9383","color11":"#d7b18a","color12":"#8a8f94","color13":"#bd9a81","color14":"#91a1a5","color15":"#c8b49d","color15":"#c8b49d"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#272733","foreground":"#dabe72","cursor":"#cac5b7"},"colors":{"color0":"#272733","color1":"#d65f2f","color2":"#aabf7f","color3":"#dabe72","color4":"#5e7e9b","color5":"#bf6c68","color6":"#5a7273","color7":"#cac5b7","color7":"#cac5b7","color8":"#48485e","color9":"#d65f2f","color10":"#aabf7f","color11":"#dabe72","color12":"#5e7e9b","color13":"#bf6c68","color14":"#5a7273","color15":"#cac5b7","color15":"#d5d1c6"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#303728","foreground":"#d4b06c","cursor":"#b9bcb7"},"colors":{"color0":"#303728","color1":"#d06e5c","color2":"#abbb52","color3":"#d4b06c","color4":"#4c7e89","color5":"#814d61","color6":"#79a69d","color7":"#b9bcb7","color7":"#b9bcb7","color8":"#505847","color9":"#d06e5c","color10":"#abbb52","color11":"#d4b06c","color12":"#4c7e89","color13":"#814d61","color14":"#79a69d","color15":"#b9bcb7","color15":"#b9bcb7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#222222","foreground":"#c5c5b2","cursor":"#242424"},"colors":{"color0":"#222222","color1":"#4d4d4d","color2":"#8a8c84","color3":"#c5c5b2","color4":"#5d5d5d","color5":"#707070","color6":"#898989","color7":"#c2c2c2","color7":"#c2c2c2","color8":"#484848","color9":"#4d4d4d","color10":"#8a8c84","color11":"#c5c5b2","color12":"#5d5d5d","color13":"#707070","color14":"#898989","color15":"#c2c2c2","color15":"#f1f1f1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#20201f","foreground":"#799c6a","cursor":"#b0b0a2"},"colors":{"color0":"#20201f","color1":"#996140","color2":"#9d8554","color3":"#799c6a","color4":"#5f656a","color5":"#7b6064","color6":"#566e6b","color7":"#b0b0a2","color7":"#b0b0a2","color8":"#3a3a38","color9":"#996140","color10":"#9d8554","color11":"#799c6a","color12":"#5f656a","color13":"#7b6064","color14":"#566e6b","color15":"#b0b0a2","color15":"#d3d3cb"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#241d1a","foreground":"#cca75f","cursor":"#251e1b"},"colors":{"color0":"#241d1a","color1":"#9f6434","color2":"#9dac5f","color3":"#cca75f","color4":"#2f7d7c","color5":"#b5896e","color6":"#52877f","color7":"#c7b8ac","color7":"#c7b8ac","color8":"#50413a","color9":"#9f6434","color10":"#9dac5f","color11":"#cca75f","color12":"#2f7d7c","color13":"#b5896e","color14":"#52877f","color15":"#c7b8ac","color15":"#c7b8ac"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2f2b2c","foreground":"#cacaca","cursor":"#dedede"},"colors":{"color0":"#2f2b2c","color1":"#5a5a5a","color2":"#989898","color3":"#cacaca","color4":"#656565","color5":"#b1b1b1","color6":"#7f7f7f","color7":"#dedede","color7":"#dedede","color8":"#504c4e","color9":"#5a5a5a","color10":"#989898","color11":"#cacaca","color12":"#656565","color13":"#b1b1b1","color14":"#7f7f7f","color15":"#dedede","color15":"#FFFFFF"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2f2a2a","foreground":"#b2885d","cursor":"#332e2e"},"colors":{"color0":"#2f2a2a","color1":"#854340","color2":"#668c71","color3":"#b2885d","color4":"#41647b","color5":"#915556","color6":"#477578","color7":"#c9c8c8","color7":"#c9c8c8","color8":"#c9c8c8","color9":"#854340","color10":"#668c71","color11":"#b2885d","color12":"#41647b","color13":"#915556","color14":"#477578","color15":"#c9c8c8","color15":"#c9c8c8"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2b2428","foreground":"#b29d6a","cursor":"#c2b7aa"},"colors":{"color0":"#2b2428","color1":"#89453c","color2":"#59713f","color3":"#b29d6a","color4":"#464e59","color5":"#614e44","color6":"#4f545b","color7":"#c2b7aa","color7":"#c2b7aa","color8":"#413c40","color9":"#89453c","color10":"#59713f","color11":"#b29d6a","color12":"#464e59","color13":"#614e44","color14":"#4f545b","color15":"#c2b7aa","color15":"#c2b7aa"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2c2c2e","foreground":"#87835d","cursor":"#2e2e30"},"colors":{"color0":"#2c2c2e","color1":"#645446","color2":"#59674f","color3":"#87835d","color4":"#4d554f","color5":"#70614f","color6":"#666755","color7":"#aba786","color7":"#aba786","color8":"#aba786","color9":"#645446","color10":"#59674f","color11":"#87835d","color12":"#4d554f","color13":"#70614f","color14":"#666755","color15":"#aba786","color15":"#c4c1aa"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#22211f","foreground":"#827834","cursor":"#252422"},"colors":{"color0":"#22211f","color1":"#785326","color2":"#516941","color3":"#827834","color4":"#42514f","color5":"#6a5632","color6":"#4e5d4d","color7":"#b4b399","color7":"#b4b399","color8":"#b4b399","color9":"#785326","color10":"#516941","color11":"#827834","color12":"#42514f","color13":"#6a5632","color14":"#4e5d4d","color15":"#b4b399","color15":"#c9c9b6"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#231c0d","foreground":"#aead5d","cursor":"#a5a39d"},"colors":{"color0":"#231c0d","color1":"#a47b3d","color2":"#7b9764","color3":"#aead5d","color4":"#628e8f","color5":"#ad9d52","color6":"#709681","color7":"#a5a39d","color7":"#a5a39d","color8":"#3f392a","color9":"#a47b3d","color10":"#7b9764","color11":"#aead5d","color12":"#628e8f","color13":"#ad9d52","color14":"#709681","color15":"#a5a39d","color15":"#a5a39d"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#263139","foreground":"#dac99d","cursor":"#28343c"},"colors":{"color0":"#263139","color1":"#f36f62","color2":"#c5e19c","color3":"#ccb478","color4":"#4c7e89","color5":"#814d61","color6":"#79a69d","color7":"#c4c4b5","color7":"#c4c4b5","color8":"#455867","color9":"#f36f62","color10":"#c5e19c","color11":"#ccb478","color12":"#4c7e89","color13":"#814d61","color14":"#79a69d","color15":"#c4c4b5","color15":"#dbdbd1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#322f30","foreground":"#8d7766","cursor":"#353233"},"colors":{"color0":"#322f30","color1":"#654c51","color2":"#7f8281","color3":"#8d7766","color4":"#5b697e","color5":"#7b6b75","color6":"#7d8592","color7":"#c0bfbf","color7":"#c0bfbf","color8":"#c0bfbf","color9":"#654c51","color10":"#7f8281","color11":"#8d7766","color12":"#5b697e","color13":"#7b6b75","color14":"#7d8592","color15":"#c0bfbf","color15":"#dfdfdf"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#282623","foreground":"#ad8b67","cursor":"#2b2825"},"colors":{"color0":"#282623","color1":"#935334","color2":"#66604d","color3":"#ad8b67","color4":"#504b44","color5":"#634737","color6":"#505349","color7":"#bcbba4","color7":"#bcbba4","color8":"#43403b","color9":"#935334","color10":"#66604d","color11":"#ad8b67","color12":"#504b44","color13":"#634737","color14":"#505349","color15":"#bcbba4","color15":"#dbdace"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#322835","foreground":"#b08960","cursor":"#332836"},"colors":{"color0":"#322835","color1":"#674f4a","color2":"#67786d","color3":"#b08960","color4":"#5e6d79","color5":"#7d6969","color6":"#6a7a76","color7":"#ccbfb3","color7":"#ccbfb3","color8":"#4b3f4e","color9":"#674f4a","color10":"#67786d","color11":"#b08960","color12":"#5e6d79","color13":"#7d6969","color14":"#6a7a76","color15":"#ccbfb3","color15":"#ccbfb3"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#252326","foreground":"#7a8648","cursor":"#c4bbb0"},"colors":{"color0":"#252326","color1":"#93503e","color2":"#9d8554","color3":"#7a8648","color4":"#5f656a","color5":"#7b6064","color6":"#566e6b","color7":"#c4bbb0","color7":"#c4bbb0","color8":"#413f43","color9":"#93503e","color10":"#9d8554","color11":"#7a8648","color12":"#5f656a","color13":"#7b6064","color14":"#566e6b","color15":"#c4bbb0","color15":"#c4bbb0"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#282423","foreground":"#987f4b","cursor":"#b7afa4"},"colors":{"color0":"#282423","color1":"#925633","color2":"#757c60","color3":"#987f4b","color4":"#515962","color5":"#685054","color6":"#506168","color7":"#b7afa4","color7":"#b7afa4","color8":"#3f3d3c","color9":"#925633","color10":"#757c60","color11":"#987f4b","color12":"#515962","color13":"#685054","color14":"#506168","color15":"#b7afa4","color15":"#b7afa4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2c2c2c","foreground":"#d0c57a","cursor":"#ededb7"},"colors":{"color0":"#2c2c2c","color1":"#c77369","color2":"#93988a","color3":"#d0c57a","color4":"#747f89","color5":"#825969","color6":"#938e8f","color7":"#ddddb5","color7":"#ddddb5","color8":"#4e4e4e","color9":"#c77369","color10":"#93988a","color11":"#d0c57a","color12":"#747f89","color13":"#825969","color14":"#938e8f","color15":"#ddddb5","color15":"#ededb7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#28282C","foreground":"#A18673","cursor":"#F3F3F3"},"colors":{"color0":"#28282C","color1":"#BF5C56","color2":"#BF5C56","color3":"#97B19C","color4":"#97B19C","color5":"#D7BD8A","color6":"#D7BD8A","color7":"#545F72","color7":"#545F72","color8":"#404047","color9":"#BF5C56","color10":"#BF5C56","color11":"#97B19C","color12":"#97B19C","color13":"#D7BD8A","color14":"#D7BD8A","color15":"#545F72","color15":"#F4F4F2"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#252a32","foreground":"#b39580","cursor":"#272c34"},"colors":{"color0":"#252a32","color1":"#876058","color2":"#6f7f71","color3":"#b39580","color4":"#546780","color5":"#84787d","color6":"#556f86","color7":"#bab7b5","color7":"#bab7b5","color8":"#bab7b5","color9":"#876058","color10":"#6f7f71","color11":"#b39580","color12":"#546780","color13":"#84787d","color14":"#556f86","color15":"#bab7b5","color15":"#dfdedd"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#242a2b","foreground":"#8d8150","cursor":"#242b2c"},"colors":{"color0":"#242a2b","color1":"#674839","color2":"#6e794f","color3":"#8d8150","color4":"#3b474e","color5":"#554c41","color6":"#495355","color7":"#939381","color7":"#939381","color8":"#939381","color9":"#674839","color10":"#6e794f","color11":"#8d8150","color12":"#3b474e","color13":"#554c41","color14":"#495355","color15":"#939381","color15":"#abab9c"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#29231f","foreground":"#aa8f5f","cursor":"#bcb7aa"},"colors":{"color0":"#29231f","color1":"#675141","color2":"#625438","color3":"#aa8f5f","color4":"#6e6051","color5":"#514540","color6":"#5e4e3c","color7":"#bcb7aa","color7":"#bcb7aa","color8":"#514b49","color9":"#675141","color10":"#625438","color11":"#aa8f5f","color12":"#6e6051","color13":"#514540","color14":"#5e4e3c","color15":"#bcb7aa","color15":"#dedbd5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#262f33","foreground":"#948d65","cursor":"#b5b699"},"colors":{"color0":"#262f33","color1":"#804f4e","color2":"#68786c","color3":"#948d65","color4":"#47575f","color5":"#74636a","color6":"#526562","color7":"#b5b699","color7":"#b5b699","color8":"#464c50","color9":"#804f4e","color10":"#68786c","color11":"#948d65","color12":"#47575f","color13":"#74636a","color14":"#526562","color15":"#b5b699","color15":"#cbcbb7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2d3144","foreground":"#96915d","cursor":"#cfccbe"},"colors":{"color0":"#2d3144","color1":"#8d6d5c","color2":"#6d806d","color3":"#96915d","color4":"#68758d","color5":"#8a747b","color6":"#8d97a8","color7":"#cfccbe","color7":"#cfccbe","color8":"#525a69","color9":"#8d6d5c","color10":"#6d806d","color11":"#96915d","color12":"#68758d","color13":"#8a747b","color14":"#8d97a8","color15":"#cfccbe","color15":"#f0efeb"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#27201f","foreground":"#978341","cursor":"#bebcbc"},"colors":{"color0":"#27201f","color1":"#9b5208","color2":"#75922c","color3":"#978341","color4":"#5e6676","color5":"#824219","color6":"#4e7479","color7":"#bebcbc","color7":"#bebcbc","color8":"#3b3436","color9":"#9b5208","color10":"#75922c","color11":"#978341","color12":"#5e6676","color13":"#824219","color14":"#4e7479","color15":"#bebcbc","color15":"#bebcbc"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2c373d","foreground":"#baad8a","cursor":"#c4c0bb"},"colors":{"color0":"#2c373d","color1":"#a67979","color2":"#809f7b","color3":"#baad8a","color4":"#6d7575","color5":"#8e7d79","color6":"#7b9899","color7":"#c4c0bb","color7":"#c4c0bb","color8":"#4d5459","color9":"#a67979","color10":"#809f7b","color11":"#baad8a","color12":"#6d7575","color13":"#8e7d79","color14":"#7b9899","color15":"#c4c0bb","color15":"#c4c0bb"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2c2c35","foreground":"#6b925a","cursor":"#2d2d36"},"colors":{"color0":"#2c2c35","color1":"#b56550","color2":"#b79b58","color3":"#6b925a","color4":"#6e747b","color5":"#96787d","color6":"#7b8889","color7":"#b4ada4","color7":"#b4ada4","color8":"#45454d","color9":"#b56550","color10":"#b79b58","color11":"#6b925a","color12":"#6e747b","color13":"#96787d","color14":"#7b8889","color15":"#b4ada4","color15":"#b4ada4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2b2320","foreground":"#aa9375","cursor":"#2e2522"},"colors":{"color0":"#2b2320","color1":"#734948","color2":"#768157","color3":"#aa9375","color4":"#585b63","color5":"#6f5a56","color6":"#7d8486","color7":"#bab1a1","color7":"#bab1a1","color8":"#bab1a1","color9":"#734948","color10":"#768157","color11":"#aa9375","color12":"#585b63","color13":"#6f5a56","color14":"#7d8486","color15":"#bab1a1","color15":"#bab1a1"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#25231b","foreground":"#988871","cursor":"#26241c"},"colors":{"color0":"#25231b","color1":"#8e2f34","color2":"#55654a","color3":"#988871","color4":"#848f89","color5":"#9f8c7c","color6":"#9cb4a6","color7":"#c4c1b0","color7":"#c4c1b0","color8":"#423f31","color9":"#8e2f34","color10":"#55654a","color11":"#988871","color12":"#848f89","color13":"#9f8c7c","color14":"#9cb4a6","color15":"#c4c1b0","color15":"#d8d4c5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#272c30","foreground":"#c79e84","cursor":"#cfb9a8"},"colors":{"color0":"#272c30","color1":"#934e46","color2":"#637268","color3":"#c79e84","color4":"#515e67","color5":"#715f5e","color6":"#5c6f7d","color7":"#cfb9a8","color7":"#cfb9a8","color8":"#414a51","color9":"#934e46","color10":"#637268","color11":"#c79e84","color12":"#515e67","color13":"#715f5e","color14":"#5c6f7d","color15":"#cfb9a8","color15":"#ddcec2"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2a2725","foreground":"#bdac8c","cursor":"#2b2927"},"colors":{"color0":"#2a2725","color1":"#8e6f64","color2":"#849385","color3":"#bdac8c","color4":"#4c5467","color5":"#757580","color6":"#64697f","color7":"#b8b2a7","color7":"#b8b2a7","color8":"#474543","color9":"#8e6f64","color10":"#849385","color11":"#bdac8c","color12":"#4c5467","color13":"#757580","color14":"#64697f","color15":"#b8b2a7","color15":"#b8b2a7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#312e39","foreground":"#ae835a","cursor":"#33303b"},"colors":{"color0":"#312e39","color1":"#87404f","color2":"#74934e","color3":"#ae835a","color4":"#615772","color5":"#783e57","color6":"#554757","color7":"#c0a79a","color7":"#c0a79a","color8":"#4f4b58","color9":"#87404f","color10":"#74934e","color11":"#ae835a","color12":"#615772","color13":"#783e57","color14":"#554757","color15":"#c0a79a","color15":"#c0a79a"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2b2c33","foreground":"#e8dfcd","cursor":"#303139"},"colors":{"color0":"#2b2c33","color1":"#b16c7f","color2":"#92ab75","color3":"#bdab77","color4":"#485476","color5":"#746081","color6":"#636f7d","color7":"#d9c1a9","color7":"#d9c1a9","color8":"#d9c1a9","color9":"#b16c7f","color10":"#92ab75","color11":"#bdab77","color12":"#485476","color13":"#746081","color14":"#636f7d","color15":"#d9c1a9","color15":"#e9dbce"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2d2d33","foreground":"#a29474","cursor":"#303036"},"colors":{"color0":"#2d2d33","color1":"#9c6647","color2":"#708684","color3":"#a29474","color4":"#697284","color5":"#796a70","color6":"#47676e","color7":"#c4c4b5","color7":"#c4c4b5","color8":"#44444a","color9":"#9c6647","color10":"#708684","color11":"#a29474","color12":"#697284","color13":"#796a70","color14":"#47676e","color15":"#c4c4b5","color15":"#c4c4b5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2a2d34","foreground":"#86733b","cursor":"#2e3239"},"colors":{"color0":"#2a2d34","color1":"#a2462e","color2":"#5e713d","color3":"#86733b","color4":"#394c5d","color5":"#855646","color6":"#6e727d","color7":"#cababa","color7":"#cababa","color8":"#414550","color9":"#a2462e","color10":"#5e713d","color11":"#86733b","color12":"#394c5d","color13":"#855646","color14":"#6e727d","color15":"#cababa","color15":"#cababa"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#37273a","foreground":"#b3a67d","cursor":"#c3bec3"},"colors":{"color0":"#37273a","color1":"#9c595c","color2":"#8ba07a","color3":"#b3a67d","color4":"#7B6677","color5":"#83466D","color6":"#899079","color7":"#c3bec3","color7":"#c3bec3","color8":"#5e5261","color9":"#9c595c","color10":"#8ba07a","color11":"#b3a67d","color12":"#7B6677","color13":"#83466D","color14":"#899079","color15":"#c3bec3","color15":"#c3bec3"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#282828","foreground":"#a89984","cursor":"#ebdbb2"},"colors":{"color0":"#282828","color1":"#cc241d","color2":"#d79921","color3":"#b58900","color4":"#458588","color5":"#b16286","color6":"#689d6a","color7":"#a89984","color8":"#928374","color9":"#cc241d","color10":"#d79921","color11":"#b58900","color12":"#458588","color13":"#b16286","color14":"#689d6a","color15":"#a89984"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#263238","foreground":"#ffffff","cursor":"#cc6666"},"colors":{"color0":"#263238","color1":"#cc6666","color2":"#f0c674","color3":"#b5bd68","color4":"#8abeb7","color5":"#81a2be","color6":"#b294bb","color7":"#ffffff","color8":"#707880","color9":"#cc6666","color10":"#f0c674","color11":"#b5bd68","color12":"#8abeb7","color13":"#81a2be","color14":"#b294bb","color15":"#ffffff"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#272822","foreground":"#f8f8f2","cursor":"#f92672"},"colors":{"color0":"#272822","color1":"#f92672","color2":"#a6e22e","color3":"#f4bf75","color4":"#66d9ef","color5":"#ae81ff","color6":"#a1efe4","color7":"#f8f8f2","color8":"#75715e","color9":"#f92672","color10":"#a6e22e","color11":"#f4bf75","color12":"#66d9ef","color13":"#ae81ff","color14":"#a1efe4","color15":"#f9f8f5"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#1c1c1c","color1":"#d770af","color2":"#9acc79","color3":"#d0d26b","color4":"#77b6c5","color5":"#a488d9","color6":"#7fcab3","color7":"#8d8d8d","color8":"#3d3a3a","color9":"#d770af","color10":"#9acc79","color11":"#d0d26b","color12":"#77b6c5","color13":"#a488d9","color14":"#7fcab3","color15":"#8d8d8d","color16":"#3d3a3a","color17":"#d28abf"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#d28abf"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#252525","color1":"#ef6769","color2":"#a6e22e","color3":"#fd971f","color4":"#6495ed","color5":"#deb887","color6":"#b0c4de","color7":"#dbdcdc","color8":"#454545","color9":"#ef6769","color10":"#a6e22e","color11":"#fd971f","color12":"#6495ed","color13":"#deb887","color14":"#b0c4de","color15":"#dbdcdc","color16":"#454545","color17":"#fc7ca5"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#fc7ca5"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#282828","color1":"#b76969","color2":"#719d72","color3":"#909858","color4":"#68668f","color5":"#966894","color6":"#688891","color7":"#8e8e8e","color8":"#494949","color9":"#b76969","color10":"#719d72","color11":"#909858","color12":"#68668f","color13":"#966894","color14":"#688891","color15":"#8e8e8e","color16":"#494949","color17":"#b87e7e"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#b87e7e"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#222827","color1":"#d5a8e3","color2":"#9c75dd","color3":"#9898ae","color4":"#654a96","color5":"#625566","color6":"#a9d1df","color7":"#e6ebe5","color8":"#5d6f74","color9":"#d5a8e3","color10":"#9c75dd","color11":"#9898ae","color12":"#654a96","color13":"#625566","color14":"#a9d1df","color15":"#e6ebe5","color16":"#5d6f74","color17":"#cd749c"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#cd749c"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#151515","color1":"#ff8eaf","color2":"#a6e25f","color3":"#f8e578","color4":"#a6e2f0","color5":"#e85b92","color6":"#5f868f","color7":"#d5f1f2","color8":"#696969","color9":"#ff8eaf","color10":"#a6e25f","color11":"#f8e578","color12":"#a6e2f0","color13":"#e85b92","color14":"#5f868f","color15":"#d5f1f2","color16":"#696969","color17":"#ed4c7a"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ed4c7a"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#353535","color1":"#744B40","color2":"#6D6137","color3":"#765636","color4":"#61564B","color5":"#6B4A49","color6":"#435861","color7":"#B3B3B3","color8":"#5F5F5F","color9":"#744B40","color10":"#6D6137","color11":"#765636","color12":"#61564B","color13":"#6B4A49","color14":"#435861","color15":"#B3B3B3","color16":"#5F5F5F","color17":"#785850"},"special":{"foreground":"#9B9081","background":"#181B20","cursor":"#785850"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#3d3e3d","color1":"#755a5b","color2":"#68755a","color3":"#756e5a","color4":"#5b6976","color5":"#755b76","color6":"#465457","color7":"#ccccc6","color8":"#5a5b5c","color9":"#755a5b","color10":"#68755a","color11":"#756e5a","color12":"#5b6976","color13":"#755b76","color14":"#465457","color15":"#ccccc6","color16":"#5a5b5c","color17":"#a37679"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#a37679"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#111111","color1":"#d36265","color2":"#aece91","color3":"#e7e18c","color4":"#5297cf","color5":"#963c59","color6":"#5e7175","color7":"#bebebe","color8":"#666666","color9":"#d36265","color10":"#aece91","color11":"#e7e18c","color12":"#5297cf","color13":"#963c59","color14":"#5e7175","color15":"#bebebe","color16":"#666666","color17":"#ef8171"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ef8171"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#303030","color1":"#c03000","color2":"#b1d631","color3":"#fecf35","color4":"#426870","color5":"#6d506d","color6":"#4bb5c1","color7":"#e2e2e5","color8":"#5f5f5f","color9":"#c03000","color10":"#b1d631","color11":"#fecf35","color12":"#426870","color13":"#6d506d","color14":"#4bb5c1","color15":"#e2e2e5","color16":"#5f5f5f","color17":"#ff3a78"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ff3a78"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#000000","color1":"#571dc2","color2":"#14db49","color3":"#403d70","color4":"#385a70","color5":"#384894","color6":"#4f3a5e","color7":"#999999","color8":"#38372c","color9":"#571dc2","color10":"#14db49","color11":"#403d70","color12":"#385a70","color13":"#384894","color14":"#4f3a5e","color15":"#999999","color16":"#38372c","color17":"#7c54b0"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#7c54b0"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#101010","color1":"#e84f4f","color2":"#b8d68c","color3":"#e1aa5d","color4":"#7dc1cf","color5":"#9b64fb","color6":"#6d878d","color7":"#dddddd","color8":"#404040","color9":"#e84f4f","color10":"#b8d68c","color11":"#e1aa5d","color12":"#7dc1cf","color13":"#9b64fb","color14":"#6d878d","color15":"#dddddd","color16":"#404040","color17":"#d23d3d"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#d23d3d"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#151515","color1":"#bf7979","color2":"#97b26b","color3":"#cdcda1","color4":"#4a5463","color5":"#9c3885","color6":"#88aadd","color7":"#ffffff","color8":"#505450","color9":"#bf7979","color10":"#97b26b","color11":"#cdcda1","color12":"#4a5463","color13":"#9c3885","color14":"#88aadd","color15":"#ffffff","color16":"#505450","color17":"#f4a45f"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#f4a45f"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#222222","color1":"#e84f4f","color2":"#b7ce42","color3":"#fea63c","color4":"#66a9b9","color5":"#b7416e","color6":"#6d878d","color7":"#cccccc","color8":"#666666","color9":"#e84f4f","color10":"#b7ce42","color11":"#fea63c","color12":"#66a9b9","color13":"#b7416e","color14":"#6d878d","color15":"#cccccc","color16":"#666666","color17":"#d23d3d"},"special":{"foreground":"#cccccc","background":"#111111","cursor":"#d23d3d"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#192033","color1":"#a62a3e","color2":"#38912b","color3":"#b27d12","color4":"#355c9a","color5":"#7c4f9f","color6":"#258f8f","color7":"#77858c","color8":"#666666","color9":"#a62a3e","color10":"#38912b","color11":"#b27d12","color12":"#355c9a","color13":"#7c4f9f","color14":"#258f8f","color15":"#77858c","color16":"#666666","color17":"#f04758"},"special":{"foreground":"#1c2027","background":"#cfcfd9","cursor":"#f04758"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#1c1c1c","color1":"#ff005b","color2":"#cee318","color3":"#ffe755","color4":"#048ac7","color5":"#833c9f","color6":"#0ac1cd","color7":"#e5e5e5","color8":"#666666","color9":"#ff005b","color10":"#cee318","color11":"#ffe755","color12":"#048ac7","color13":"#833c9f","color14":"#0ac1cd","color15":"#e5e5e5","color16":"#666666","color17":"#ff00a0"},"special":{"foreground":"#c5c5c5","background":"#1c1c1c","cursor":"#ff00a0"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#000000","color1":"#cc0000","color2":"#4e9a06","color3":"#c4a000","color4":"#3465a4","color5":"#75507b","color6":"#06989a","color7":"#d3d7cf","color8":"#555753","color9":"#cc0000","color10":"#4e9a06","color11":"#c4a000","color12":"#3465a4","color13":"#75507b","color14":"#06989a","color15":"#d3d7cf","color16":"#555753","color17":"#ef2929"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ef2929"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#0a0f14","color1":"#c33027","color2":"#26a98b","color3":"#edb54b","color4":"#195465","color5":"#4e5165","color6":"#33859d","color7":"#98d1ce","color8":"#364b61","color9":"#c33027","color10":"#26a98b","color11":"#edb54b","color12":"#195465","color13":"#4e5165","color14":"#33859d","color15":"#98d1ce","color16":"#10151b","color17":"#d26939"},"special":{"foreground":"#98d1ce","background":"#0a0f14","cursor":"#d26939"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#392925","color1":"#98724c","color2":"#908f32","color3":"#aa964c","color4":"#7b854e","color5":"#6b5644","color6":"#5c5142","color7":"#c8b55b","color8":"#544b2e","color9":"#98724c","color10":"#908f32","color11":"#aa964c","color12":"#7b854e","color13":"#6b5644","color14":"#5c5142","color15":"#c8b55b","color16":"#544b2e","color17":"#af652f"},"special":{"foreground":"#746c48","background":"#170f0d","cursor":"#af652f"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#222222","color1":"#E84F4F","color2":"#B7CE42","color3":"#FEA63C","color4":"#66AABB","color5":"#B7416E","color6":"#6D878D","color7":"#DDDDDD","color8":"#666666","color9":"#E84F4F","color10":"#B7CE42","color11":"#FEA63C","color12":"#66AABB","color13":"#B7416E","color14":"#6D878D","color15":"#DDDDDD","color16":"#666666","color17":"#D23D3D"},"special":{"foreground":"#FFFFFF","background":"#161616","cursor":"#D23D3D"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#393939","color1":"#da4939","color2":"#9acc79","color3":"#d0d26b","color4":"#6d9cbe","color5":"#9f5079","color6":"#435d75","color7":"#c2c2c2","color8":"#474747","color9":"#da4939","color10":"#9acc79","color11":"#d0d26b","color12":"#6d9cbe","color13":"#9f5079","color14":"#435d75","color15":"#c2c2c2","color16":"#474747","color17":"#ff6c5c"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ff6c5c"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#3d3e3d","color1":"#755a5b","color2":"#68755a","color3":"#756e5a","color4":"#5b6976","color5":"#755b76","color6":"#5b7674","color7":"#808080","color8":"#5a5b5c","color9":"#755a5b","color10":"#68755a","color11":"#756e5a","color12":"#5b6976","color13":"#755b76","color14":"#5b7674","color15":"#808080","color16":"#5a5b5c","color17":"#a37679"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#a37679"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#303030","color1":"#D370A3","color2":"#6D9E3F","color3":"#B58858","color4":"#6095C5","color5":"#AC7BDE","color6":"#3BA275","color7":"#CFCFCF","color8":"#686868","color9":"#D370A3","color10":"#6D9E3F","color11":"#B58858","color12":"#6095C5","color13":"#AC7BDE","color14":"#3BA275","color15":"#CFCFCF","color16":"#686868","color17":"#FFA7DA"},"special":{"foreground":"#A0A0A0","background":"#232323","cursor":"#FFA7DA"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#222222","color1":"#9e5641","color2":"#6c7e55","color3":"#caaf2b","color4":"#4c8ea1","color5":"#956d9d","color6":"#7c9aa6","color7":"#909090","color8":"#454545","color9":"#9e5641","color10":"#6c7e55","color11":"#caaf2b","color12":"#4c8ea1","color13":"#956d9d","color14":"#7c9aa6","color15":"#909090","color16":"#454545","color17":"#cc896d"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#cc896d"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#3D3D3D","color1":"#6673BF","color2":"#3EA290","color3":"#B0EAD9","color4":"#31658C","color5":"#596196","color6":"#8292B2","color7":"#C8CACC","color8":"#4D4D4D","color9":"#6673BF","color10":"#3EA290","color11":"#B0EAD9","color12":"#31658C","color13":"#596196","color14":"#8292B2","color15":"#C8CACC","color16":"#4D4D4D","color17":"#899AFF"},"special":{"foreground":"#ffffff","background":"#1b1b1b","cursor":"#899AFF"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#263238","color1":"#ff9800","color2":"#8bc34a","color3":"#ffc107","color4":"#03a9f4","color5":"#e91e63","color6":"#009688","color7":"#cfd8dc","color8":"#37474f","color9":"#ff9800","color10":"#8bc34a","color11":"#ffc107","color12":"#03a9f4","color13":"#e91e63","color14":"#009688","color15":"#cfd8dc","color16":"#37474f","color17":"#ffa74d"},"special":{"foreground":"#eceff1","background":"#263238","cursor":"#ffa74d"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#322a2c","color1":"#a04363","color2":"#9b9329","color3":"#bf7a29","color4":"#6a8c8c","color5":"#856774","color6":"#757978","color7":"#bcbcaf","color8":"#46423b","color9":"#a04363","color10":"#9b9329","color11":"#bf7a29","color12":"#6a8c8c","color13":"#856774","color14":"#757978","color15":"#bcbcaf","color16":"#46423b","color17":"#ae837a"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ae837a"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#2a1d17","color1":"#da1657","color2":"#3ea250","color3":"#e3d33d","color4":"#3ea290","color5":"#ff850d","color6":"#8c16da","color7":"#e9e9e9","color8":"#4f362b","color9":"#da1657","color10":"#3ea250","color11":"#e3d33d","color12":"#3ea290","color13":"#ff850d","color14":"#8c16da","color15":"#e9e9e9","color16":"#4f362b","color17":"#da4375"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#da4375"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#48483e","color1":"#dc2566","color2":"#8fc029","color3":"#d4c96e","color4":"#55bcce","color5":"#9358fe","color6":"#56b7a5","color7":"#acada1","color8":"#76715e","color9":"#dc2566","color10":"#8fc029","color11":"#d4c96e","color12":"#55bcce","color13":"#9358fe","color14":"#56b7a5","color15":"#acada1","color16":"#76715e","color17":"#fa2772"},"special":{"foreground":"#f1ebeb","background":"#272822","cursor":"#fa2772"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#2e3436","color1":"#a31604","color2":"#447241","color3":"#c1951a","color4":"#425387","color5":"#965d98","color6":"#06989a","color7":"#d3d7cf","color8":"#555753","color9":"#a31604","color10":"#447241","color11":"#c1951a","color12":"#425387","color13":"#965d98","color14":"#06989a","color15":"#d3d7cf","color16":"#555753","color17":"#c60001"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#c60001"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#1b1d1e","color1":"#f92672","color2":"#82b414","color3":"#fd971f","color4":"#4e82aa","color5":"#8c54fe","color6":"#465457","color7":"#ccccc6","color8":"#505354","color9":"#f92672","color10":"#82b414","color11":"#fd971f","color12":"#4e82aa","color13":"#8c54fe","color14":"#465457","color15":"#ccccc6","color16":"#505354","color17":"#ff5995"},"special":{"foreground":"#ffffff","background":"#010101","cursor":"#ff5995"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#032c36","color1":"#c2454e","color2":"#7cbf9e","color3":"#8a7a63","color4":"#2e3340","color5":"#ff5879","color6":"#44b5b1","color7":"#f2f1b9","color8":"#065f73","color9":"#c2454e","color10":"#7cbf9e","color11":"#8a7a63","color12":"#2e3340","color13":"#ff5879","color14":"#44b5b1","color15":"#f2f1b9","color16":"#065f73","color17":"#ef5847"},"special":{"foreground":"#e8dfd6","background":"#021b21","cursor":"#ef5847"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#171717","color1":"#d81765","color2":"#97d01a","color3":"#ffa800","color4":"#16b1fb","color5":"#ff2491","color6":"#0fdcb6","color7":"#ebebeb","color8":"#38252c","color9":"#d81765","color10":"#97d01a","color11":"#ffa800","color12":"#16b1fb","color13":"#ff2491","color14":"#0fdcb6","color15":"#ebebeb","color16":"#38252c","color17":"#ff0000"},"special":{"foreground":"#f8f8f8","background":"#171717","cursor":"#ff0000"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#555555","color1":"#9c3528","color2":"#61bc3b","color3":"#f3b43a","color4":"#0d68a8","color5":"#744560","color6":"#288e9c","color7":"#a2a2a2","color8":"#888888","color9":"#9c3528","color10":"#61bc3b","color11":"#f3b43a","color12":"#0d68a8","color13":"#744560","color14":"#288e9c","color15":"#a2a2a2","color16":"#888888","color17":"#d64937"},"special":{"foreground":"#a2a2a2","background":"#282828","cursor":"#d64937"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#251f1f","color1":"#eb4509","color2":"#94e76b","color3":"#ffac18","color4":"#46aede","color5":"#e32c57","color6":"#d6dbac","color7":"#efefef","color8":"#5e5e5e","color9":"#eb4509","color10":"#94e76b","color11":"#ffac18","color12":"#46aede","color13":"#e32c57","color14":"#d6dbac","color15":"#efefef","color16":"#5e5e5e","color17":"#eb4509"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#eb4509"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#322a2c","color1":"#79220e","color2":"#344b1b","color3":"#b45b00","color4":"#434045","color5":"#5c1e25","color6":"#394745","color7":"#ae8842","color8":"#46423b","color9":"#79220e","color10":"#344b1b","color11":"#b45b00","color12":"#434045","color13":"#5c1e25","color14":"#394745","color15":"#ae8842","color16":"#46423b","color17":"#aa261f"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#aa261f"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#000000","color1":"#a80000","color2":"#00a800","color3":"#a85400","color4":"#0000a8","color5":"#a800a8","color6":"#00a8a8","color7":"#a8a8a8","color8":"#545054","color9":"#a80000","color10":"#00a800","color11":"#a85400","color12":"#0000a8","color13":"#a800a8","color14":"#00a8a8","color15":"#a8a8a8","color16":"#545054","color17":"#f85450"},"special":{"foreground":"#a8a8a8","background":"#000000","cursor":"#f85450"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#292929","color1":"#CF6A4C","color2":"#19CB00","color3":"#FAD07A","color4":"#8197BF","color5":"#8787AF","color6":"#668799","color7":"#888888","color8":"#525252","color9":"#CF6A4C","color10":"#19CB00","color11":"#FAD07A","color12":"#8197BF","color13":"#8787AF","color14":"#668799","color15":"#888888","color16":"#525252","color17":"#FF9D80"},"special":{"foreground":"#888888","background":"#151515","cursor":"#FF9D80"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#1b1d1e","color1":"#f92672","color2":"#82b414","color3":"#fd971f","color4":"#4e82aa","color5":"#8c54fe","color6":"#465457","color7":"#ccccc6","color8":"#505354","color9":"#f92672","color10":"#82b414","color11":"#fd971f","color12":"#4e82aa","color13":"#8c54fe","color14":"#465457","color15":"#ccccc6","color16":"#505354","color17":"#ff5995"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ff5995"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#191919","color1":"#803232","color2":"#5b762f","color3":"#aa9943","color4":"#324c80","color5":"#706c9a","color6":"#92b19e","color7":"#ffffff","color8":"#252525","color9":"#803232","color10":"#5b762f","color11":"#aa9943","color12":"#324c80","color13":"#706c9a","color14":"#92b19e","color15":"#ffffff","color16":"#252525","color17":"#982b2b"},"special":{"foreground":"#dddddd","background":"#222222","cursor":"#982b2b"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#303430","color1":"#bf7979","color2":"#97b26b","color3":"#cdcdc1","color4":"#86a2be","color5":"#d9b798","color6":"#a1b5cd","color7":"#ffffff","color8":"#cdb5cd","color9":"#bf7979","color10":"#97b26b","color11":"#cdcdc1","color12":"#86a2be","color13":"#d9b798","color14":"#a1b5cd","color15":"#ffffff","color16":"#cdb5cd","color17":"#f4a45f"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#f4a45f"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#4A3637","color1":"#D17B49","color2":"#7B8748","color3":"#AF865A","color4":"#535C5C","color5":"#775759","color6":"#6D715E","color7":"#C0B18B","color8":"#785f60","color9":"#D17B49","color10":"#7B8748","color11":"#AF865A","color12":"#535C5C","color13":"#775759","color14":"#6D715E","color15":"#C0B18B","color16":"#4A3637","color17":"#D17B49"},"special":{"foreground":"#C0B18B","background":"#1F1F1F","cursor":"#D17B49"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#252525","color1":"#ff9f95","color2":"#a6e22e","color3":"#fd971f","color4":"#435e87","color5":"#789ec6","color6":"#5e7175","color7":"#dbdcdc","color8":"#454545","color9":"#ff9f95","color10":"#a6e22e","color11":"#fd971f","color12":"#435e87","color13":"#789ec6","color14":"#5e7175","color15":"#dbdcdc","color16":"#454545","color17":"#ff8d80"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ff8d80"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#666666","color1":"#ff8278","color2":"#bde077","color3":"#eadc84","color4":"#77bee0","color5":"#dd91f3","color6":"#ffc178","color7":"#dddddd","color8":"#888888","color9":"#ff8278","color10":"#bde077","color11":"#eadc84","color12":"#77bee0","color13":"#dd91f3","color14":"#ffc178","color15":"#dddddd","color16":"#888888","color17":"#ff8278"},"special":{"foreground":"#dcdccc","background":"#575757","cursor":"#ff8278"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#4a4b4a","color1":"#d7699a","color2":"#80d468","color3":"#d7a169","color4":"#6985d7","color5":"#c86ad4","color6":"#6fccd1","color7":"#dbdcdc","color8":"#696969","color9":"#d7699a","color10":"#80d468","color11":"#d7a169","color12":"#6985d7","color13":"#c86ad4","color14":"#6fccd1","color15":"#dbdcdc","color16":"#696969","color17":"#f5a2b5"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#f5a2b5"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#1c1709","color1":"#8e4317","color2":"#787200","color3":"#945c00","color4":"#315094","color5":"#5c2e40","color6":"#00617d","color7":"#c2b9a1","color8":"#4f4939","color9":"#8e4317","color10":"#787200","color11":"#945c00","color12":"#315094","color13":"#5c2e40","color14":"#00617d","color15":"#c2b9a1","color16":"#4f4939","color17":"#f07935"},"special":{"foreground":"#c2b9a1","background":"#1c1709","cursor":"#f07935"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#4A3637","color1":"#D17B49","color2":"#7B8748","color3":"#AF865A","color4":"#535C5C","color5":"#775759","color6":"#6D715E","color7":"#C0B18B","color8":"#7e5c5e","color9":"#D17B49","color10":"#7B8748","color11":"#AF865A","color12":"#535C5C","color13":"#775759","color14":"#6D715E","color15":"#C0B18B","color16":"#402E2E","color17":"#AC5D2F"},"special":{"foreground":"#C0B18B","background":"#1F1F1F","cursor":"#AC5D2F"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#2e3436","color1":"#cc0000","color2":"#4e9a06","color3":"#c4a000","color4":"#3465a4","color5":"#75507b","color6":"#06989a","color7":"#d3d7cf","color8":"#555753","color9":"#cc0000","color10":"#4e9a06","color11":"#c4a000","color12":"#3465a4","color13":"#75507b","color14":"#06989a","color15":"#d3d7cf","color16":"#555753","color17":"#ef2929"},"special":{"foreground":"#babdb6","background":"#000000","cursor":"#ef2929"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#202020","color1":"#ff6565","color2":"#93d44f","color3":"#eab93d","color4":"#204a87","color5":"#ce5c00","color6":"#89b6e2","color7":"#cccccc","color8":"#606060","color9":"#ff6565","color10":"#93d44f","color11":"#eab93d","color12":"#204a87","color13":"#ce5c00","color14":"#89b6e2","color15":"#cccccc","color16":"#606060","color17":"#ff8d8d"},"special":{"foreground":"#aaaaaa","background":"#000000","cursor":"#ff8d8d"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#2e3436","color1":"#cc0000","color2":"#4e9a06","color3":"#c4a000","color4":"#3465a4","color5":"#75507b","color6":"#06989a","color7":"#d3d7cf","color8":"#555753","color9":"#cc0000","color10":"#4e9a06","color11":"#c4a000","color12":"#3465a4","color13":"#75507b","color14":"#06989a","color15":"#d3d7cf","color16":"#555753","color17":"#ef2929"},"special":{"foreground":"#dedede","background":"#2b2b2b","cursor":"#ef2929"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#191919","color1":"#eb3d51","color2":"#66b61a","color3":"#d98e1d","color4":"#23ffa8","color5":"#ff00da","color6":"#68a783","color7":"#eaeaea","color8":"#484848","color9":"#eb3d51","color10":"#66b61a","color11":"#d98e1d","color12":"#23ffa8","color13":"#ff00da","color14":"#68a783","color15":"#eaeaea","color16":"#484848","color17":"#be6262"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#be6262"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#202020","color1":"#a07070","color2":"#70a070","color3":"#a0a070","color4":"#7070a0","color5":"#a070a0","color6":"#70a0a0","color7":"#a0a0a0","color8":"#505050","color9":"#a07070","color10":"#70a070","color11":"#a0a070","color12":"#7070a0","color13":"#a070a0","color14":"#70a0a0","color15":"#a0a0a0","color16":"#505050","color17":"#d07070"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#d07070"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#1c1c1c","color1":"#d81860","color2":"#60ff60","color3":"#f9fd75","color4":"#4695c8","color5":"#a78edb","color6":"#43afce","color7":"#f3ebe2","color8":"#4d4d4d","color9":"#d81860","color10":"#60ff60","color11":"#f9fd75","color12":"#4695c8","color13":"#a78edb","color14":"#43afce","color15":"#f3ebe2","color16":"#4d4d4d","color17":"#f00060"},"special":{"foreground":"#66ff66","background":"#101010","cursor":"#f00060"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#0F0E0D","color1":"#845336","color2":"#57553C","color3":"#A17E3E","color4":"#43454F","color5":"#604848","color6":"#5C6652","color7":"#A18B62","color8":"#383332","color9":"#845336","color10":"#57553C","color11":"#A17E3E","color12":"#43454F","color13":"#604848","color14":"#5C6652","color15":"#A18B62","color16":"#383332","color17":"#8C4F4A"},"special":{"foreground":"#DABA8B","background":"#191716","cursor":"#8C4F4A"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#202020","color1":"#bf3f34","color2":"#707d22","color3":"#bf7a29","color4":"#627a92","color5":"#75507b","color6":"#757978","color7":"#b2a191","color8":"#404040","color9":"#bf3f34","color10":"#707d22","color11":"#bf7a29","color12":"#627a92","color13":"#75507b","color14":"#757978","color15":"#b2a191","color16":"#404040","color17":"#ff6c5f"},"special":{"foreground":"#b2a191","background":"#171717","cursor":"#ff6c5f"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#202020","color1":"#b91e2e","color2":"#81957c","color3":"#f9bb80","color4":"#356579","color5":"#2d2031","color6":"#0b3452","color7":"#909090","color8":"#606060","color9":"#b91e2e","color10":"#81957c","color11":"#f9bb80","color12":"#356579","color13":"#2d2031","color14":"#0b3452","color15":"#909090","color16":"#606060","color17":"#d14548"},"special":{"foreground":"#d2c5bc","background":"#101010","cursor":"#d14548"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#666666","color1":"#CC6699","color2":"#99CC66","color3":"#CC9966","color4":"#6699CC","color5":"#9966CC","color6":"#66CC99","color7":"#CCCCCC","color8":"#999999","color9":"#CC6699","color10":"#99CC66","color11":"#CC9966","color12":"#6699CC","color13":"#9966CC","color14":"#66CC99","color15":"#CCCCCC","color16":"#999999","color17":"#FF99CC"},"special":{"foreground":"#CCCCCC","background":"#333333","cursor":"#FF99CC"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#666666","color1":"#cc6666","color2":"#66cc99","color3":"#cc9966","color4":"#6699cc","color5":"#cc6699","color6":"#66cccc","color7":"#cccccc","color8":"#999999","color9":"#cc6666","color10":"#66cc99","color11":"#cc9966","color12":"#6699cc","color13":"#cc6699","color14":"#66cccc","color15":"#cccccc","color16":"#999999","color17":"#ff9999"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#ff9999"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#101010","color1":"#E84F4F","color2":"#B8D68C","color3":"#E1AA5D","color4":"#7DC1CF","color5":"#9B64FB","color6":"#6D878D","color7":"#DDDDDD","color8":"#404040","color9":"#E84F4F","color10":"#B8D68C","color11":"#E1AA5D","color12":"#7DC1CF","color13":"#9B64FB","color14":"#6D878D","color15":"#DDDDDD","color16":"#404040","color17":"#D23D3D"},"special":{"foreground":"#D7D0C7","background":"#151515","cursor":"#D23D3D"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#1e2320","color1":"#705050","color2":"#60b48a","color3":"#dfaf8f","color4":"#506070","color5":"#dc8cc3","color6":"#8cd0d3","color7":"#dcdccc","color8":"#709080","color9":"#705050","color10":"#60b48a","color11":"#dfaf8f","color12":"#506070","color13":"#dc8cc3","color14":"#8cd0d3","color15":"#dcdccc","color16":"#709080","color17":"#dca3a3"},"special":{"foreground":"#ffffff","background":"#000000","cursor":"#dca3a3"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#073642","foreground":"#fdf6e3","cursor":"#dc322f"},"colors":{"color0":"#073642","color1":"#dc322f","color2":"#859900","color3":"#b58900","color4":"#268bd2","color5":"#d33682","color6":"#2aa198","color7":"#eee8d5","color8":"#6c7c80","color9":"#dc322f","color10":"#859900","color11":"#b58900","color12":"#268bd2","color13":"#d33682","color14":"#2aa198","color15":"#eee8d5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#322622","foreground":"#8e8f8d","cursor":"#8e8f8d"},"colors":{"color0":"#322622","color1":"#fc5526","color2":"#83973f","color3":"#9e9022","color4":"#7f8dbf","color5":"#ce7673","color6":"#6e978b","color7":"#8e8f8d","color8":"#919078","color9":"#dc721a","color10":"#609d59","color11":"#b1891a","color12":"#6b8ed6","color13":"#9d80d3","color14":"#229ea0","color15":"#8e8f8d"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1f252d","foreground":"#a2a8ba","cursor":"#a2a8ba"},"colors":{"color0":"#1f252d","color1":"#cb8d56","color2":"#8ba089","color3":"#a79c46","color4":"#8c9abe","color5":"#b190af","color6":"#8e9aba","color7":"#a2a8ba","color8":"#a29899","color9":"#d39d74","color10":"#80b48f","color11":"#bda75a","color12":"#9ca5de","color13":"#c69ac6","color14":"#8caeb6","color15":"#a2a8ba"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#18161d","foreground":"#a4a0ac","cursor":"#a4a0ac"},"colors":{"color0":"#18161d","color1":"#ff7780","color2":"#68b183","color3":"#bda014","color4":"#54a5ff","color5":"#da89b2","color6":"#79a8c3","color7":"#a4a0ac","color8":"#bd9b87","color9":"#ef873d","color10":"#08b885","color11":"#d39710","color12":"#a294fe","color13":"#ec7aca","color14":"#4ab0b9","color15":"#a4a0ac"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#2b353c","foreground":"#abacac","cursor":"#abacac"},"colors":{"color0":"#2b353c","color1":"#be9604","color2":"#0eb40e","color3":"#79aa00","color4":"#00acb3","color5":"#ba964c","color6":"#5fa98f","color7":"#abacac","color8":"#ab9699","color9":"#bdae13","color10":"#3ac53a","color11":"#9ab800","color12":"#20bdce","color13":"#cca57a","color14":"#6fb9ae","color15":"#abacac"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#34403c","foreground":"#a5a8a7","cursor":"#a5a8a7"},"colors":{"color0":"#34403c","color1":"#ff855a","color2":"#6ab78a","color3":"#b6aa1a","color4":"#5daeee","color5":"#d495b4","color6":"#6eb2bc","color7":"#a5a8a7","color8":"#96aca7","color9":"#df993a","color10":"#4abb88","color11":"#99b22a","color12":"#3caffe","color13":"#d091db","color14":"#4ab4d3","color15":"#a5a8a7"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#293345","foreground":"#9b999e","cursor":"#9b999e"},"colors":{"color0":"#293345","color1":"#fe6d32","color2":"#6ba86d","color3":"#af9a0a","color4":"#679ed7","color5":"#bc8ab6","color6":"#6ea590","color7":"#9b999e","color8":"#a39799","color9":"#df8251","color10":"#7aa747","color11":"#ba953a","color12":"#3ba1e8","color13":"#c97ed7","color14":"#52a6b1","color15":"#9b999e"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#141a19","foreground":"#928f90","cursor":"#928f90"},"colors":{"color0":"#141a19","color1":"#ff1414","color2":"#009600","color3":"#928100","color4":"#4f76ff","color5":"#dd38bc","color6":"#358aaa","color7":"#928f90","color8":"#927b80","color9":"#ff5500","color10":"#3aa43a","color11":"#b38a00","color12":"#8082ff","color13":"#d159fd","color14":"#1da190","color15":"#928f90"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#202427","foreground":"#798ba5","cursor":"#798ba5"},"colors":{"color0":"#202427","color1":"#ca7162","color2":"#589584","color3":"#988b21","color4":"#2b92c8","color5":"#b572b6","color6":"#4f91b5","color7":"#798ba5","color8":"#888a8a","color9":"#c47818","color10":"#2c9a81","color11":"#a2864b","color12":"#6987d7","color13":"#987dc2","color14":"#1f96b0","color15":"#798ba5"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#1e1e1e","foreground":"#d4d4d4","cursor":"#f44747"},"colors":{"color0":"#1e1e1e","color1":"#f44747","color2":"#d7ba7d","color3":"#608b4e","color4":"#569cd6","color5":"#4ec9b0","color6":"#c586c0","color7":"#d4d4d4","color8":"#808080","color9":"#f44747","color10":"#d7ba7d","color11":"#608b4e","color12":"#569cd6","color13":"#4ec9b0","color14":"#c586c0","color15":"#d4d4d4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#3f3f3f","foreground":"#dcdccc","cursor":"#cc9393"},"colors":{"color0":"#3f3f3f","color1":"#cc9393","color2":"#7f9f7f","color3":"#d0bf8f","color4":"#6ca0a3","color5":"#dc8cc3","color6":"#93e0e3","color7":"#dcdccc","color8":"#828282","color9":"#cc9393","color10":"#7f9f7f","color11":"#d0bf8f","color12":"#6ca0a3","color13":"#dc8cc3","color14":"#93e0e3","color15":"#dcdccc"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f7f7f7","foreground":"#090300","cursor":"#db2d20"},"colors":{"color0":"#f7f7f7","color1":"#db2d20","color2":"#01a252","color3":"#fded02","color4":"#01a0e4","color5":"#a16a94","color6":"#b5e4f4","color7":"#090300","color8":"#5c5855","color9":"#db2d20","color10":"#01a252","color11":"#fded02","color12":"#01a0e4","color13":"#a16a94","color14":"#b5e4f4","color15":"#090300"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f3f4f5","foreground":"#565e65","cursor":"#c7ae95"},"colors":{"color0":"#f3f4f5","color1":"#c7ae95","color2":"#95c7ae","color3":"#aec795","color4":"#ae95c7","color5":"#c795ae","color6":"#95aec7","color7":"#1c2023","color8":"#747c84","color9":"#c7ae95","color10":"#95c7ae","color11":"#aec795","color12":"#ae95c7","color13":"#c795ae","color14":"#95aec7","color15":"#1c2023"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#efecf4","foreground":"#585260","cursor":"#585260"},"colors":{"color0":"#efecf4","color1":"#be4678","color2":"#2a9292","color3":"#a06e3b","color4":"#576ddb","color5":"#955ae7","color6":"#398bc6","color7":"#585260","color8":"#7e7887","color9":"#be4678","color10":"#2a9292","color11":"#a06e3b","color12":"#576ddb","color13":"#955ae7","color14":"#398bc6","color15":"#19171c"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#fefbec","foreground":"#6e6b5e","cursor":"#6e6b5e"},"colors":{"color0":"#fefbec","color1":"#d73737","color2":"#60ac39","color3":"#ae9513","color4":"#6684e1","color5":"#b854d4","color6":"#1fad83","color7":"#6e6b5e","color8":"#999580","color9":"#d73737","color10":"#60ac39","color11":"#ae9513","color12":"#6684e1","color13":"#b854d4","color14":"#1fad83","color15":"#20201d"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f4f3ec","foreground":"#5f5e4e","cursor":"#5f5e4e"},"colors":{"color0":"#f4f3ec","color1":"#ba6236","color2":"#7d9726","color3":"#a5980d","color4":"#36a166","color5":"#5f9182","color6":"#5b9d48","color7":"#5f5e4e","color8":"#878573","color9":"#ba6236","color10":"#7d9726","color11":"#a5980d","color12":"#36a166","color13":"#5f9182","color14":"#5b9d48","color15":"#22221b"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f1efee","foreground":"#68615e","cursor":"#68615e"},"colors":{"color0":"#f1efee","color1":"#f22c40","color2":"#7b9726","color3":"#c38418","color4":"#407ee7","color5":"#6666ea","color6":"#3d97b8","color7":"#68615e","color8":"#9c9491","color9":"#f22c40","color10":"#7b9726","color11":"#c38418","color12":"#407ee7","color13":"#6666ea","color14":"#3d97b8","color15":"#1b1918"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f7f3f7","foreground":"#695d69","cursor":"#695d69"},"colors":{"color0":"#f7f3f7","color1":"#ca402b","color2":"#918b3b","color3":"#bb8a35","color4":"#516aec","color5":"#7b59c0","color6":"#159393","color7":"#695d69","color8":"#9e8f9e","color9":"#ca402b","color10":"#918b3b","color11":"#bb8a35","color12":"#516aec","color13":"#7b59c0","color14":"#159393","color15":"#1b181b"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#ebf8ff","foreground":"#516d7b","cursor":"#516d7b"},"colors":{"color0":"#ebf8ff","color1":"#d22d72","color2":"#568c3b","color3":"#8a8a0f","color4":"#257fad","color5":"#6b6bb8","color6":"#2d8f6f","color7":"#516d7b","color8":"#7195a8","color9":"#d22d72","color10":"#568c3b","color11":"#8a8a0f","color12":"#257fad","color13":"#6b6bb8","color14":"#2d8f6f","color15":"#161b1d"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f4ecec","foreground":"#585050","cursor":"#585050"},"colors":{"color0":"#f4ecec","color1":"#ca4949","color2":"#4b8b8b","color3":"#a06e3b","color4":"#7272ca","color5":"#8464c4","color6":"#5485b6","color7":"#585050","color8":"#7e7777","color9":"#ca4949","color10":"#4b8b8b","color11":"#a06e3b","color12":"#7272ca","color13":"#8464c4","color14":"#5485b6","color15":"#1b1818"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#ecf4ee","foreground":"#526057","cursor":"#526057"},"colors":{"color0":"#ecf4ee","color1":"#b16139","color2":"#489963","color3":"#a07e3b","color4":"#478c90","color5":"#55859b","color6":"#1c9aa0","color7":"#526057","color8":"#78877d","color9":"#b16139","color10":"#489963","color11":"#a07e3b","color12":"#478c90","color13":"#55859b","color14":"#1c9aa0","color15":"#171c19"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f4fbf4","foreground":"#5e6e5e","cursor":"#5e6e5e"},"colors":{"color0":"#f4fbf4","color1":"#e6193c","color2":"#29a329","color3":"#98981b","color4":"#3d62f5","color5":"#ad2bee","color6":"#1999b3","color7":"#5e6e5e","color8":"#809980","color9":"#e6193c","color10":"#29a329","color11":"#98981b","color12":"#3d62f5","color13":"#ad2bee","color14":"#1999b3","color15":"#131513"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f5f7ff","foreground":"#5e6687","cursor":"#5e6687"},"colors":{"color0":"#f5f7ff","color1":"#c94922","color2":"#ac9739","color3":"#c08b30","color4":"#3d8fd1","color5":"#6679cc","color6":"#22a2c9","color7":"#5e6687","color8":"#898ea4","color9":"#c94922","color10":"#ac9739","color11":"#c08b30","color12":"#3d8fd1","color13":"#6679cc","color14":"#22a2c9","color15":"#202746"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#F5F5F5","foreground":"#303030","cursor":"#303030"},"colors":{"color0":"#F5F5F5","color1":"#AC4142","color2":"#90A959","color3":"#F4BF75","color4":"#6A9FB5","color5":"#AA759F","color6":"#75B5AA","color7":"#303030","color8":"#B0B0B0","color9":"#AC4142","color10":"#90A959","color11":"#F4BF75","color12":"#6A9FB5","color13":"#AA759F","color14":"#75B5AA","color15":"#151515"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#fbf1f2","foreground":"#8b8198","cursor":"#8b8198"},"colors":{"color0":"#fbf1f2","color1":"#D57E85","color2":"#A3B367","color3":"#DCB16C","color4":"#7297B9","color5":"#BB99B4","color6":"#69A9A7","color7":"#8b8198","color8":"#bfb9c6","color9":"#D57E85","color10":"#A3B367","color11":"#DCB16C","color12":"#7297B9","color13":"#BB99B4","color14":"#69A9A7","color15":"#585062"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#ffffff","foreground":"#404040","cursor":"#404040"},"colors":{"color0":"#ffffff","color1":"#c41a15","color2":"#007400","color3":"#826b28","color4":"#0000ff","color5":"#a90d91","color6":"#318495","color7":"#404040","color8":"#808080","color9":"#c41a15","color10":"#007400","color11":"#826b28","color12":"#0000ff","color13":"#a90d91","color14":"#318495","color15":"#5e5e5e"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f8f8f8","foreground":"#383838","cursor":"#383838"},"colors":{"color0":"#f8f8f8","color1":"#ab4642","color2":"#a1b56c","color3":"#f7ca88","color4":"#7cafc2","color5":"#ba8baf","color6":"#86c1b9","color7":"#383838","color8":"#b8b8b8","color9":"#ab4642","color10":"#a1b56c","color11":"#f7ca88","color12":"#7cafc2","color13":"#ba8baf","color14":"#86c1b9","color15":"#181818"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#ffffff","foreground":"#333333","cursor":"#333333"},"colors":{"color0":"#ffffff","color1":"#ed6a43","color2":"#183691","color3":"#795da3","color4":"#795da3","color5":"#a71d5d","color6":"#183691","color7":"#333333","color8":"#969896","color9":"#ed6a43","color10":"#183691","color11":"#795da3","color12":"#795da3","color13":"#a71d5d","color14":"#183691","color15":"#333333"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#ffffff","foreground":"#373b41","cursor":"#373b41"},"colors":{"color0":"#ffffff","color1":"#CC342B","color2":"#198844","color3":"#FBA922","color4":"#3971ED","color5":"#A36AC7","color6":"#3971ED","color7":"#373b41","color8":"#b4b7b4","color9":"#CC342B","color10":"#198844","color11":"#FBA922","color12":"#3971ED","color13":"#A36AC7","color14":"#3971ED","color15":"#1d1f21"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f7f7f7","foreground":"#464646","cursor":"#464646"},"colors":{"color0":"#f7f7f7","color1":"#7c7c7c","color2":"#8e8e8e","color3":"#a0a0a0","color4":"#686868","color5":"#747474","color6":"#868686","color7":"#464646","color8":"#ababab","color9":"#7c7c7c","color10":"#8e8e8e","color11":"#a0a0a0","color12":"#686868","color13":"#747474","color14":"#868686","color15":"#101010"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f9f5d7","foreground":"#504945","cursor":"#504945"},"colors":{"color0":"#f9f5d7","color1":"#9d0006","color2":"#79740e","color3":"#b57614","color4":"#076678","color5":"#8f3f71","color6":"#427b58","color7":"#504945","color8":"#bdae93","color9":"#9d0006","color10":"#79740e","color11":"#b57614","color12":"#076678","color13":"#8f3f71","color14":"#427b58","color15":"#282828"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#fbf1c7","foreground":"#504945","cursor":"#504945"},"colors":{"color0":"#fbf1c7","color1":"#9d0006","color2":"#79740e","color3":"#b57614","color4":"#076678","color5":"#8f3f71","color6":"#427b58","color7":"#504945","color8":"#bdae93","color9":"#9d0006","color10":"#79740e","color11":"#b57614","color12":"#076678","color13":"#8f3f71","color14":"#427b58","color15":"#282828"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f2e5bc","foreground":"#504945","cursor":"#504945"},"colors":{"color0":"#f2e5bc","color1":"#9d0006","color2":"#79740e","color3":"#b57614","color4":"#076678","color5":"#8f3f71","color6":"#427b58","color7":"#504945","color8":"#bdae93","color9":"#9d0006","color10":"#79740e","color11":"#b57614","color12":"#076678","color13":"#8f3f71","color14":"#427b58","color15":"#282828"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f7f9fb","foreground":"#405c79","cursor":"#405c79"},"colors":{"color0":"#f7f9fb","color1":"#bf8b56","color2":"#56bf8b","color3":"#8bbf56","color4":"#8b56bf","color5":"#bf568b","color6":"#568bbf","color7":"#405c79","color8":"#aabcce","color9":"#bf8b56","color10":"#56bf8b","color11":"#8bbf56","color12":"#8b56bf","color13":"#bf568b","color14":"#568bbf","color15":"#0b1c2c"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#FAFAFA","foreground":"#80CBC4","cursor":"#80CBC4"},"colors":{"color0":"#FAFAFA","color1":"#FF5370","color2":"#91B859","color3":"#FFB62C","color4":"#6182B8","color5":"#7C4DFF","color6":"#39ADB5","color7":"#80CBC4","color8":"#CCD7DA","color9":"#FF5370","color10":"#91B859","color11":"#FFB62C","color12":"#6182B8","color13":"#7C4DFF","color14":"#39ADB5","color15":"#80CBC4"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f8f8f8","foreground":"#383838","cursor":"#383838"},"colors":{"color0":"#f8f8f8","color1":"#ab4642","color2":"#538947","color3":"#f79a0e","color4":"#7cafc2","color5":"#96609e","color6":"#4b8093","color7":"#383838","color8":"#b8b8b8","color9":"#ab4642","color10":"#538947","color11":"#f79a0e","color12":"#7cafc2","color13":"#96609e","color14":"#4b8093","color15":"#181818"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#fafafa","foreground":"#383a42","cursor":"#383a42"},"colors":{"color0":"#fafafa","color1":"#ca1243","color2":"#50a14f","color3":"#c18401","color4":"#4078f2","color5":"#a626a4","color6":"#0184bc","color7":"#383a42","color8":"#a0a1a7","color9":"#ca1243","color10":"#50a14f","color11":"#c18401","color12":"#4078f2","color13":"#a626a4","color14":"#0184bc","color15":"#090a0b"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f9f9f9","foreground":"#102015","cursor":"#102015"},"colors":{"color0":"#f9f9f9","color1":"#e92f2f","color2":"#0ed839","color3":"#dddd13","color4":"#3b48e3","color5":"#f996e2","color6":"#23edda","color7":"#102015","color8":"#555555","color9":"#e92f2f","color10":"#0ed839","color11":"#dddd13","color12":"#3b48e3","color13":"#f996e2","color14":"#23edda","color15":"#000000"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#fdf6e3","foreground":"#586e75","cursor":"#586e75"},"colors":{"color0":"#fdf6e3","color1":"#dc322f","color2":"#859900","color3":"#b58900","color4":"#268bd2","color5":"#6c71c4","color6":"#2aa198","color7":"#586e75","color8":"#839496","color9":"#dc322f","color10":"#859900","color11":"#b58900","color12":"#268bd2","color13":"#6c71c4","color14":"#2aa198","color15":"#002b36"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#FFFFFF","foreground":"#101010","cursor":"#101010"},"colors":{"color0":"#FFFFFF","color1":"#FF0086","color2":"#00C918","color3":"#ABA800","color4":"#3777E6","color5":"#AD00A1","color6":"#1FAAAA","color7":"#101010","color8":"#B0B0B0","color9":"#FF0086","color10":"#00C918","color11":"#ABA800","color12":"#3777E6","color13":"#AD00A1","color14":"#1FAAAA","color15":"#202020"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#ffffff","foreground":"#4d4d4c","cursor":"#4d4d4c"},"colors":{"color0":"#ffffff","color1":"#c82829","color2":"#718c00","color3":"#eab700","color4":"#4271ae","color5":"#8959a8","color6":"#3e999f","color7":"#4d4d4c","color8":"#8e908c","color9":"#c82829","color10":"#718c00","color11":"#eab700","color12":"#4271ae","color13":"#8959a8","color14":"#3e999f","color15":"#1d1f21"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#ffffff","foreground":"#6c696e","cursor":"#6c696e"},"colors":{"color0":"#ffffff","color1":"#d8137f","color2":"#17ad98","color3":"#dc8a0e","color4":"#775dff","color5":"#aa17e6","color6":"#149bda","color7":"#6c696e","color8":"#a7a5a8","color9":"#d8137f","color10":"#17ad98","color11":"#dc8a0e","color12":"#775dff","color13":"#aa17e6","color14":"#149bda","color15":"#322d34"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f4f4f4","foreground":"#3e3e3e","cursor":"#970b16"},"colors":{"color0":"#ffffff","color1":"#970b16","color2":"#07962a","color3":"#f8eec7","color4":"#003e8a","color5":"#e94691","color6":"#89d1ec","color7":"#3e3e3e","color8":"#666666","color9":"#970b16","color10":"#07962a","color11":"#f8eec7","color12":"#003e8a","color13":"#e94691","color14":"#89d1ec","color15":"#3e3e3e"}}
\ No newline at end of file
+++ /dev/null
-{"colors":{"color0":"#D3D3D3","color1":"#EF6B7B","color2":"#A1D569","color3":"#F59335","color4":"#4EC2E8","color5":"#FEC7CD","color6":"#95C1C0","color7":"#707070","color8":"#B3B3B3","color9":"#EF6B7B","color10":"#A1D569","color11":"#F59335","color12":"#4EC2E8","color13":"#FEC7CD","color14":"#95C1C0","color15":"#707070","color16":"#B3B3B3","color17":"#ED5466"},"special":{"foreground":"#707070","background":"#F3F3F3","cursor":"#ED5466"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#eee8d5","foreground":"#002b36","cursor":"#dc322f"},"colors":{"color0":"#eee8d5","color1":"#dc322f","color2":"#859900","color3":"#b58900","color4":"#268bd2","color5":"#d33682","color6":"#2aa198","color7":"#073642","color8":"#6c7c80","color9":"#dc322f","color10":"#859900","color11":"#b58900","color12":"#268bd2","color13":"#d33682","color14":"#2aa198","color15":"#073642"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f3f1f5","foreground":"#53575a","cursor":"#53575a"},"colors":{"color0":"#f3f1f5","color1":"#9b3132","color2":"#306130","color3":"#73500a","color4":"#4c547e","color5":"#883c64","color6":"#186060","color7":"#53575a","color8":"#735e3f","color9":"#9b474d","color10":"#4e6938","color11":"#8e5319","color12":"#5c5d8c","color13":"#a24055","color14":"#2d6978","color15":"#53575a"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#fff5f3","foreground":"#4d696f","cursor":"#4d696f"},"colors":{"color0":"#fff5f3","color1":"#df2014","color2":"#587d0a","color3":"#8a6f00","color4":"#196bec","color5":"#c83884","color6":"#2a79a2","color7":"#4d696f","color8":"#8b6781","color9":"#9a511a","color10":"#11742f","color11":"#8d590a","color12":"#004fff","color13":"#9536c0","color14":"#046c92","color15":"#4d696f"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#dadce8","foreground":"#63606b","cursor":"#63606b"},"colors":{"color0":"#dadce8","color1":"#c01c10","color2":"#2a7000","color3":"#825a0a","color4":"#025ccd","color5":"#a43878","color6":"#49628d","color7":"#63606b","color8":"#80565d","color9":"#b43036","color10":"#007214","color11":"#91520a","color12":"#5046eb","color13":"#ba166b","color14":"#076c76","color15":"#63606b"}}
\ No newline at end of file
+++ /dev/null
-{"special":{"background":"#f4f1f0","foreground":"#52505e","cursor":"#52505e"},"colors":{"color0":"#f4f1f0","color1":"#a01c10","color2":"#0b5d46","color3":"#545422","color4":"#1c4f9f","color5":"#942166","color6":"#185870","color7":"#52505e","color8":"#575050","color9":"#913210","color10":"#2a5d08","color11":"#774611","color12":"#5440a7","color13":"#8d0e9b","color14":"#0e577b","color15":"#52505e"}}
\ No newline at end of file
+++ /dev/null
-"""
-Export colors in various formats.
-"""
-import logging
-import os
-
-from .settings import CACHE_DIR, MODULE_DIR, CONF_DIR
-from . import util
-
-
-def template(colors, input_file, output_file=None):
- """Read template file, substitute markers and
- save the file elsewhere."""
- template_data = util.read_file_raw(input_file)
- template_data = "".join(template_data).format(**colors)
-
- util.save_file(template_data, output_file)
-
-
-def flatten_colors(colors):
- """Prepare colors to be exported.
- Flatten dicts and convert colors to util.Color()"""
- all_colors = {"wallpaper": colors["wallpaper"],
- "alpha": colors["alpha"],
- **colors["special"],
- **colors["colors"]}
- return {k: util.Color(v) for k, v in all_colors.items()}
-
-
-def get_export_type(export_type):
- """Convert template type to the right filename."""
- return {
- "css": "colors.css",
- "dmenu": "colors-wal-dmenu.h",
- "dwm": "colors-wal-dwm.h",
- "st": "colors-wal-st.h",
- "tabbed": "colors-wal-tabbed.h",
- "gtk2": "colors-gtk2.rc",
- "json": "colors.json",
- "konsole": "colors-konsole.colorscheme",
- "kitty": "colors-kitty.conf",
- "plain": "colors",
- "putty": "colors-putty.reg",
- "rofi": "colors-rofi.Xresources",
- "scss": "colors.scss",
- "shell": "colors.sh",
- "speedcrunch": "colors-speedcrunch.json",
- "sway": "colors-sway",
- "tty": "colors-tty.sh",
- "waybar": "colors-waybar.css",
- "xresources": "colors.Xresources",
- "xmonad": "colors.hs",
- "yaml": "colors.yml",
- }.get(export_type, export_type)
-
-
-def every(colors, output_dir=CACHE_DIR):
- """Export all template files."""
- colors = flatten_colors(colors)
- template_dir = os.path.join(MODULE_DIR, "templates")
- template_dir_user = os.path.join(CONF_DIR, "templates")
- util.create_dir(template_dir_user)
-
- join = os.path.join # Minor optimization.
- for file in [*os.scandir(template_dir),
- *os.scandir(template_dir_user)]:
- if file.name != ".DS_Store":
- template(colors, file.path, join(output_dir, file.name))
-
- logging.info("Exported all files.")
- logging.info("Exported all user files.")
-
-
-def color(colors, export_type, output_file=None):
- """Export a single template file."""
- all_colors = flatten_colors(colors)
-
- template_name = get_export_type(export_type)
- template_file = os.path.join(MODULE_DIR, "templates", template_name)
- output_file = output_file or os.path.join(CACHE_DIR, template_name)
-
- if os.path.isfile(template_file):
- template(all_colors, template_file, output_file)
- logging.info("Exported %s.", export_type)
- else:
- logging.warning("Template '%s' doesn't exist.", export_type)
+++ /dev/null
-"""
-Get the image file.
-"""
-import logging
-import os
-import random
-import re
-import sys
-
-from .settings import CACHE_DIR
-from . import util
-from . import wallpaper
-
-
-def get_image_dir(img_dir):
- """Get all images in a directory."""
- current_wall = wallpaper.get()
- current_wall = os.path.basename(current_wall)
-
- file_types = (".png", ".jpg", ".jpeg", ".jpe", ".gif")
-
- return [img.name for img in os.scandir(img_dir)
- if img.name.lower().endswith(file_types)], current_wall
-
-
-def get_random_image(img_dir):
- """Pick a random image file from a directory."""
- images, current_wall = get_image_dir(img_dir)
-
- if len(images) > 2 and current_wall in images:
- images.remove(current_wall)
-
- elif not images:
- logging.error("No images found in directory.")
- sys.exit(1)
-
- random.shuffle(images)
- return os.path.join(img_dir, images[0])
-
-
-def get_next_image(img_dir):
- """Get the next image in a dir."""
- images, current_wall = get_image_dir(img_dir)
- images.sort(key=lambda img: [int(x) if x.isdigit() else x
- for x in re.split('([0-9]+)', img)])
-
- try:
- next_index = images.index(current_wall) + 1
-
- except ValueError:
- next_index = 0
-
- try:
- image = images[next_index]
-
- except IndexError:
- image = images[0]
-
- return os.path.join(img_dir, image)
-
-
-def get(img, cache_dir=CACHE_DIR, iterative=False):
- """Validate image input."""
- if os.path.isfile(img):
- wal_img = img
-
- elif os.path.isdir(img):
- if iterative:
- wal_img = get_next_image(img)
-
- else:
- wal_img = get_random_image(img)
-
- else:
- logging.error("No valid image file found.")
- sys.exit(1)
-
- wal_img = os.path.abspath(wal_img)
-
- # Cache the image file path.
- util.save_file(wal_img, os.path.join(cache_dir, "wal"))
-
- logging.info("Using image \033[1;37m%s\033[0m.", os.path.basename(wal_img))
- return wal_img
+++ /dev/null
-"""
-Reload programs.
-"""
-import logging
-import os
-import shutil
-import subprocess
-
-from .settings import CACHE_DIR, MODULE_DIR, OS
-from . import util
-
-
-def tty(tty_reload):
- """Load colors in tty."""
- tty_script = os.path.join(CACHE_DIR, "colors-tty.sh")
- term = os.environ.get("TERM")
-
- if tty_reload and term == "linux":
- subprocess.Popen(["sh", tty_script])
-
-
-def xrdb(xrdb_files=None):
- """Merge the colors into the X db so new terminals use them."""
- xrdb_files = xrdb_files or \
- [os.path.join(CACHE_DIR, "colors.Xresources")]
-
- if shutil.which("xrdb") and OS != "Darwin":
- for file in xrdb_files:
- subprocess.run(["xrdb", "-merge", "-quiet", file])
-
-
-def gtk():
- """Reload GTK theme on the fly."""
- # Here we call a Python 2 script to reload the GTK themes.
- # This is done because the Python 3 GTK/Gdk libraries don't
- # provide a way of doing this.
- if shutil.which("python2"):
- gtk_reload = os.path.join(MODULE_DIR, "scripts", "gtk_reload.py")
- util.disown(["python2", gtk_reload])
-
- else:
- logging.warning("GTK2 reload support requires Python 2.")
-
-
-def i3():
- """Reload i3 colors."""
- if shutil.which("i3-msg") and util.get_pid("i3"):
- util.disown(["i3-msg", "reload"])
-
-
-def kitty():
- """ Reload kitty colors. """
- if shutil.which("kitty") and util.get_pid("kitty"):
- util.disown(["kitty", "@", "set-colors", "--all"])
-
-
-def polybar():
- """Reload polybar colors."""
- if shutil.which("polybar") and util.get_pid("polybar"):
- util.disown(["pkill", "-USR1", "polybar"])
-
-
-def sway():
- """Reload sway colors."""
- if shutil.which("swaymsg") and util.get_pid("sway"):
- util.disown(["swaymsg", "reload"])
-
-
-def colors(cache_dir=CACHE_DIR):
- """Reload colors. (Deprecated)"""
- sequences = os.path.join(cache_dir, "sequences")
-
- logging.error("'wal -r' is deprecated: "
- "Use 'cat %s' instead.", sequences)
-
- if os.path.isfile(sequences):
- print("".join(util.read_file(sequences)), end="")
-
-
-def env(xrdb_file=None, tty_reload=True):
- """Reload environment."""
- xrdb(xrdb_file)
- i3()
- kitty()
- sway()
- polybar()
- logging.info("Reloaded environment.")
- tty(tty_reload)
+++ /dev/null
-#!/usr/bin/env python2
-"""
-Small Python 2 script to reload GTK2 themes.
-
-This uses Python2 since this requires 'send_clientmessage_toall()'
-which isn't available in Python 3.
-
-Original source: https://crunchbang.org/forums/viewtopic.php?id=39646
-"""
-try:
- import gtk
-except ImportError:
- print("[ERROR] gtk_reload: GTK reload requires PyGTK.")
- exit(1)
-
-
-def gtk_reload():
- """Reload GTK2 themes."""
- events = gtk.gdk.Event(gtk.gdk.CLIENT_EVENT)
- data = gtk.gdk.atom_intern("_GTK_READ_RCFILES", False)
- events.data_format = 8
- events.send_event = True
- events.message_type = data
- events.send_clientmessage_toall()
-
-
-gtk_reload()
+++ /dev/null
-"""
-Send sequences to all open terminals.
-"""
-import glob
-import logging
-import os
-
-from .settings import CACHE_DIR, OS
-from . import util
-
-
-def set_special(index, color, iterm_name="h", alpha=100):
- """Convert a hex color to a special sequence."""
- if OS == "Darwin":
- return "\033]P%s%s\033\\" % (iterm_name, color.strip("#"))
-
- if index in [11, 708] and alpha != "100":
- return "\033]%s;[%s]%s\033\\" % (index, alpha, color)
-
- return "\033]%s;%s\033\\" % (index, color)
-
-
-def set_color(index, color):
- """Convert a hex color to a text color sequence."""
- if OS == "Darwin" and index < 20:
- return "\033]P%1x%s\033\\" % (index, color.strip("#"))
-
- return "\033]4;%s;%s\033\\" % (index, color)
-
-
-def set_iterm_tab_color(color):
- """Set iTerm2 tab/window color"""
- return ("\033]6;1;bg;red;brightness;%s\a"
- "\033]6;1;bg;green;brightness;%s\a"
- "\033]6;1;bg;blue;brightness;%s\a") % (*util.hex_to_rgb(color),)
-
-
-def create_sequences(colors, vte_fix=False):
- """Create the escape sequences."""
- alpha = colors["alpha"]
-
- # Colors 0-15.
- sequences = [set_color(index, colors["colors"]["color%s" % index])
- for index in range(16)]
-
- # Special colors.
- # Source: https://goo.gl/KcoQgP
- # 10 = foreground, 11 = background, 12 = cursor foregound
- # 13 = mouse foreground, 708 = background border color.
- sequences.extend([
- set_special(10, colors["special"]["foreground"], "g"),
- set_special(11, colors["special"]["background"], "h", alpha),
- set_special(12, colors["special"]["cursor"], "l"),
- set_special(13, colors["special"]["foreground"], "l"),
- set_special(17, colors["special"]["foreground"], "l"),
- set_special(19, colors["special"]["background"], "l"),
- set_color(232, colors["special"]["background"]),
- set_color(256, colors["special"]["foreground"])
- ])
-
- if not vte_fix:
- sequences.extend(
- set_special(708, colors["special"]["background"], "l", alpha)
- )
-
- if OS == "Darwin":
- sequences += set_iterm_tab_color(colors["special"]["background"])
-
- return "".join(sequences)
-
-
-def send(colors, cache_dir=CACHE_DIR, to_send=True, vte_fix=False):
- """Send colors to all open terminals."""
- if OS == "Darwin":
- tty_pattern = "/dev/ttys00[0-9]*"
-
- else:
- tty_pattern = "/dev/pts/[0-9]*"
-
- sequences = create_sequences(colors, vte_fix)
-
- # Writing to "/dev/pts/[0-9] lets you send data to open terminals.
- if to_send:
- for term in glob.glob(tty_pattern):
- util.save_file(sequences, term)
-
- util.save_file(sequences, os.path.join(cache_dir, "sequences"))
- logging.info("Set terminal colors.")
+++ /dev/null
-"""
- '||
-... ... .... ... ... ... ... .... ||
- ||' || '|. | || || | '' .|| ||
- || | '|.| ||| ||| .|' || ||
- ||...' '| | | '|..'|' .||.
- || .. |
-'''' ''
-Created by Dylan Araps.
-"""
-
-import os
-import platform
-
-
-__version__ = "3.3.0"
-__cache_version__ = "1.1.0"
-
-
-HOME = os.getenv("HOME", os.getenv("USERPROFILE"))
-CACHE_DIR = os.getenv("PYWAL_CACHE_DIR", os.path.join(HOME, ".cache", "wal"))
-MODULE_DIR = os.path.dirname(__file__)
-CONF_DIR = os.path.join(HOME, ".config", "wal")
-OS = platform.uname()[0]
+++ /dev/null
-{color0}
-{color1}
-{color2}
-{color3}
-{color4}
-{color5}
-{color6}
-{color7}
-{color8}
-{color9}
-{color10}
-{color11}
-{color12}
-{color13}
-{color14}
-{color15}
+++ /dev/null
-foreground {foreground}
-background {background}
-cursor {cursor}
-
-color0 {color0}
-color8 {color8}
-color1 {color1}
-color9 {color9}
-color2 {color2}
-color10 {color10}
-color3 {color3}
-color11 {color11}
-color4 {color4}
-color12 {color12}
-color5 {color5}
-color13 {color13}
-color6 {color6}
-color14 {color14}
-color7 {color7}
-color15 {color15}
+++ /dev/null
-[Background]
-Color={background.rgb}
-
-[BackgroundIntense]
-Color={background.rgb}
-
-[Color0]
-Color={color0.rgb}
-
-[Color0Intense]
-Color={color8.rgb}
-
-[Color1]
-Color={color1.rgb}
-
-[Color1Intense]
-Color={color9.rgb}
-
-[Color2]
-Color={color2.rgb}
-
-[Color2Intense]
-Color={color10.rgb}
-
-[Color3]
-Color={color3.rgb}
-
-[Color3Intense]
-Color={color11.rgb}
-
-[Color4]
-Color={color4.rgb}
-
-[Color4Intense]
-Color={color12.rgb}
-
-[Color5]
-Color={color5.rgb}
-
-[Color5Intense]
-Color={color13.rgb}
-
-[Color6]
-Color={color6.rgb}
-
-[Color6Intense]
-Color={color14.rgb}
-
-[Color7]
-Color={color7.rgb}
-
-[Color7Intense]
-Color={color15.rgb}
-
-[Foreground]
-Color={foreground.rgb}
-
-[ForegroundIntense]
-Color={foreground.rgb}
-
-[General]
-Description=Colorscheme generated by wal
-Opacity=1
+++ /dev/null
-NAME=wal
-BG={color0.strip}
-FG={color15.strip}
-MENU_BG={color0.strip}
-MENU_FG={color15.strip}
-SEL_BG={color1.strip}
-SEL_FG={color0.strip}
-TXT_BG={color0.strip}
-TXT_FG={color15.strip}
-BTN_BG={color2.strip}
-BTN_FG={color15.strip}
-HDR_BTN_BG={color3.strip}
-HDR_BTN_FG={color15.strip}
-GTK3_GENERATE_DARK=True
-ROUNDNESS=0
-SPACING=3
-GRADIENT=0.0
+++ /dev/null
-Windows Registry Editor Version 5.00
-
-[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\wal]
-"Colour0"="{foreground.rgb}" ; Default Foreground
-"Colour1"="{foreground.rgb}" ; Default Bold Foreground
-"Colour2"="{background.rgb}" ; Default Background
-"Colour3"="{background.rgb}" ; Default Bold Background
-"Colour4"="{background.rgb}" ; Cursor Text
-"Colour5"="{cursor.rgb}" ; Cursor Color
-"Colour6"="{color0.rgb}" ; ANSI Black
-"Colour7"="{color8.rgb}" ; ANSI Black Bold
-"Colour8"="{color1.rgb}" ; ANSI Red
-"Colour9"="{color9.rgb}" ; ANSI Red Bold
-"Colour10"="{color2.rgb}" ; ANSI Green
-"Colour11"="{color10.rgb}" ; ANSI Green Bold
-"Colour12"="{color3.rgb}" ; ANSI Yellow
-"Colour13"="{color11.rgb}" ; ANSI Yellow Bold
-"Colour14"="{color4.rgb}" ; ANSI Blue
-"Colour15"="{color12.rgb}" ; ANSI Blue Bold
-"Colour16"="{color5.rgb}" ; ANSI Magenta
-"Colour17"="{color13.rgb}" ; ANSI Magenta Bold
-"Colour18"="{color6.rgb}" ; ANSI Cyan
-"Colour19"="{color14.rgb}" ; ANSI Cyan Bold
-"Colour20"="{color7.rgb}" ; ANSI White
-"Colour21"="{color15.rgb}" ; ANSI White Bold
-
+++ /dev/null
-* {{
- active-background: {color2};
- active-foreground: @foreground;
- normal-background: @background;
- normal-foreground: @foreground;
- urgent-background: {color1};
- urgent-foreground: @foreground;
-
- alternate-active-background: @background;
- alternate-active-foreground: @foreground;
- alternate-normal-background: @background;
- alternate-normal-foreground: @foreground;
- alternate-urgent-background: @background;
- alternate-urgent-foreground: @foreground;
-
- selected-active-background: {color1};
- selected-active-foreground: @foreground;
- selected-normal-background: {color2};
- selected-normal-foreground: @foreground;
- selected-urgent-background: {color3};
- selected-urgent-foreground: @foreground;
-
- background-color: @background;
- background: {background};
- foreground: {foreground};
- border-color: @background;
- spacing: 2;
-}}
-
-#window {{
- background-color: @background;
- border: 0;
- padding: 2.5ch;
-}}
-
-#mainbox {{
- border: 0;
- padding: 0;
-}}
-
-#message {{
- border: 2px 0px 0px;
- border-color: @border-color;
- padding: 1px;
-}}
-
-#textbox {{
- text-color: @foreground;
-}}
-
-#inputbar {{
- children: [ prompt,textbox-prompt-colon,entry,case-indicator ];
-}}
-
-#textbox-prompt-colon {{
- expand: false;
- str: ":";
- margin: 0px 0.3em 0em 0em;
- text-color: @normal-foreground;
-}}
-
-#listview {{
- fixed-height: 0;
- border: 2px 0px 0px;
- border-color: @border-color;
- spacing: 2px;
- scrollbar: true;
- padding: 2px 0px 0px;
-}}
-
-#element {{
- border: 0;
- padding: 1px;
-}}
-
-#element.normal.normal {{
- background-color: @normal-background;
- text-color: @normal-foreground;
-}}
-
-#element.normal.urgent {{
- background-color: @urgent-background;
- text-color: @urgent-foreground;
-}}
-
-#element.normal.active {{
- background-color: @active-background;
- text-color: @active-foreground;
-}}
-
-#element.selected.normal {{
- background-color: @selected-normal-background;
- text-color: @selected-normal-foreground;
-}}
-
-#element.selected.urgent {{
- background-color: @selected-urgent-background;
- text-color: @selected-urgent-foreground;
-}}
-
-#element.selected.active {{
- background-color: @selected-active-background;
- text-color: @selected-active-foreground;
-}}
-
-#element.alternate.normal {{
- background-color: @alternate-normal-background;
- text-color: @alternate-normal-foreground;
-}}
-
-#element.alternate.urgent {{
- background-color: @alternate-urgent-background;
- text-color: @alternate-urgent-foreground;
-}}
-
-#element.alternate.active {{
- background-color: @alternate-active-background;
- text-color: @alternate-active-foreground;
-}}
-
-#scrollbar {{
- width: 4px;
- border: 0;
- handle-width: 8px;
- padding: 0;
-}}
-
-#sidebar {{
- border: 2px 0px 0px;
- border-color: @border-color;
-}}
-
-#button {{
- text-color: @normal-foreground;
-}}
-
-#button.selected {{
- background-color: @selected-normal-background;
- text-color: @selected-normal-foreground;
-}}
-
-#inputbar {{
- spacing: 0;
- text-color: @normal-foreground;
- padding: 1px;
-}}
-
-#case-indicator {{
- spacing: 0;
- text-color: @normal-foreground;
-}}
-
-#entry {{
- spacing: 0;
- text-color: @normal-foreground;
-}}
-
-#prompt {{
- spacing: 0;
- text-color: @normal-foreground;
-}}
+++ /dev/null
-* {{
- active-background: {color2};
- active-foreground: @foreground;
- normal-background: @background;
- normal-foreground: @foreground;
- urgent-background: {color1};
- urgent-foreground: @foreground;
-
- alternate-active-background: @background;
- alternate-active-foreground: @foreground;
- alternate-normal-background: @background;
- alternate-normal-foreground: @foreground;
- alternate-urgent-background: @background;
- alternate-urgent-foreground: @foreground;
-
- selected-active-background: {color1};
- selected-active-foreground: @foreground;
- selected-normal-background: {color2};
- selected-normal-foreground: @foreground;
- selected-urgent-background: {color3};
- selected-urgent-foreground: @foreground;
-
- background-color: @background;
- background: {foreground};
- foreground: {background};
- border-color: @background;
- spacing: 2;
-}}
-
-#window {{
- background-color: @background;
- border: 0;
- padding: 2.5ch;
-}}
-
-#mainbox {{
- border: 0;
- padding: 0;
-}}
-
-#message {{
- border: 2px 0px 0px;
- border-color: @border-color;
- padding: 1px;
-}}
-
-#textbox {{
- text-color: @foreground;
-}}
-
-#inputbar {{
- children: [ prompt,textbox-prompt-colon,entry,case-indicator ];
-}}
-
-#textbox-prompt-colon {{
- expand: false;
- str: ":";
- margin: 0px 0.3em 0em 0em;
- text-color: @normal-foreground;
-}}
-
-#listview {{
- fixed-height: 0;
- border: 2px 0px 0px;
- border-color: @border-color;
- spacing: 2px;
- scrollbar: true;
- padding: 2px 0px 0px;
-}}
-
-#element {{
- border: 0;
- padding: 1px;
-}}
-
-#element.normal.normal {{
- background-color: @normal-background;
- text-color: @normal-foreground;
-}}
-
-#element.normal.urgent {{
- background-color: @urgent-background;
- text-color: @urgent-foreground;
-}}
-
-#element.normal.active {{
- background-color: @active-background;
- text-color: @active-foreground;
-}}
-
-#element.selected.normal {{
- background-color: @selected-normal-background;
- text-color: @selected-normal-foreground;
-}}
-
-#element.selected.urgent {{
- background-color: @selected-urgent-background;
- text-color: @selected-urgent-foreground;
-}}
-
-#element.selected.active {{
- background-color: @selected-active-background;
- text-color: @selected-active-foreground;
-}}
-
-#element.alternate.normal {{
- background-color: @alternate-normal-background;
- text-color: @alternate-normal-foreground;
-}}
-
-#element.alternate.urgent {{
- background-color: @alternate-urgent-background;
- text-color: @alternate-urgent-foreground;
-}}
-
-#element.alternate.active {{
- background-color: @alternate-active-background;
- text-color: @alternate-active-foreground;
-}}
-
-#scrollbar {{
- width: 4px;
- border: 0;
- handle-width: 8px;
- padding: 0;
-}}
-
-#sidebar {{
- border: 2px 0px 0px;
- border-color: @border-color;
-}}
-
-#button {{
- text-color: @normal-foreground;
-}}
-
-#button.selected {{
- background-color: @selected-normal-background;
- text-color: @selected-normal-foreground;
-}}
-
-#inputbar {{
- spacing: 0;
- text-color: @normal-foreground;
- padding: 1px;
-}}
-
-#case-indicator {{
- spacing: 0;
- text-color: @normal-foreground;
-}}
-
-#entry {{
- spacing: 0;
- text-color: @normal-foreground;
-}}
-
-#prompt {{
- spacing: 0;
- text-color: @normal-foreground;
-}}
+++ /dev/null
-{{
- "cursor": "{cursor}",
- "number": "{foreground}",
- "parens": "{color13}",
- "result": "{color12}",
- "comment": "{color8}",
- "matched": "{color4}",
- "function": "{color1}",
- "operator": "{color3}",
- "variable": "{color2}",
- "scrollbar": "{color3}",
- "separator": "{color3}",
- "background": "{background}",
- "editorbackground": "{background}"
-}}
+++ /dev/null
-set $wallpaper {wallpaper}
-
-set $background {background}
-set $foreground {foreground}
-
-set $color0 {color0}
-set $color1 {color1}
-set $color2 {color2}
-set $color3 {color3}
-set $color4 {color4}
-set $color5 {color5}
-set $color6 {color6}
-set $color7 {color7}
-set $color8 {color8}
-set $color9 {color9}
-set $color10 {color10}
-set $color11 {color11}
-set $color12 {color12}
-set $color13 {color13}
-set $color14 {color14}
-set $color15 {color15}
+++ /dev/null
-#!/bin/sh
-[ "${{TERM:-none}}" = "linux" ] && \
- printf '%b' '\e]P0{color0.strip}
- \e]P1{color1.strip}
- \e]P2{color2.strip}
- \e]P3{color3.strip}
- \e]P4{color4.strip}
- \e]P5{color5.strip}
- \e]P6{color6.strip}
- \e]P7{color7.strip}
- \e]P8{color8.strip}
- \e]P9{color9.strip}
- \e]PA{color10.strip}
- \e]PB{color11.strip}
- \e]PC{color12.strip}
- \e]PD{color13.strip}
- \e]PE{color14.strip}
- \e]PF{color15.strip}
- \ec'
+++ /dev/null
-static const char *colors[SchemeLast][2] = {{
- /* fg bg */
- [SchemeNorm] = {{ "{color15}", "{color0}" }},
- [SchemeSel] = {{ "{color15}", "{color1}" }},
- [SchemeOut] = {{ "{color15}", "{color14}" }},
-}};
+++ /dev/null
-static const char norm_fg[] = "{color15}";
-static const char norm_bg[] = "{color0}";
-static const char norm_border[] = "{color8}";
-
-static const char sel_fg[] = "{color15}";
-static const char sel_bg[] = "{color2}";
-static const char sel_border[] = "{color15}";
-
-static const char urg_fg[] = "{color15}";
-static const char urg_bg[] = "{color1}";
-static const char urg_border[] = "{color1}";
-
-static const char *colors[][3] = {{
- /* fg bg border */
- [SchemeNorm] = {{ norm_fg, norm_bg, norm_border }}, // unfocused wins
- [SchemeSel] = {{ sel_fg, sel_bg, sel_border }}, // the focused win
- [SchemeUrg] = {{ urg_fg, urg_bg, urg_border }},
-}};
+++ /dev/null
-const char *colorname[] = {{
-
- /* 8 normal colors */
- [0] = "{color0}", /* black */
- [1] = "{color1}", /* red */
- [2] = "{color2}", /* green */
- [3] = "{color3}", /* yellow */
- [4] = "{color4}", /* blue */
- [5] = "{color5}", /* magenta */
- [6] = "{color6}", /* cyan */
- [7] = "{color7}", /* white */
-
- /* 8 bright colors */
- [8] = "{color8}", /* black */
- [9] = "{color9}", /* red */
- [10] = "{color10}", /* green */
- [11] = "{color11}", /* yellow */
- [12] = "{color12}", /* blue */
- [13] = "{color13}", /* magenta */
- [14] = "{color14}", /* cyan */
- [15] = "{color15}", /* white */
-
- /* special colors */
- [256] = "{background}", /* background */
- [257] = "{foreground}", /* foreground */
- [258] = "{cursor}", /* cursor */
-}};
-
-/* Default colors (colorname index)
- * foreground, background, cursor */
- unsigned int defaultbg = 0;
- unsigned int defaultfg = 257;
- unsigned int defaultcs = 258;
- unsigned int defaultrcs= 258;
+++ /dev/null
-static const char* selbgcolor = "{color0}";
-static const char* selfgcolor = "{color15}";
-static const char* normbgcolor = "{color2}";
-static const char* normfgcolor = "{color15}";
-static const char* urgbgcolor = "{color1}";
-static const char* urgfgcolor = "{color15}";
+++ /dev/null
-" Special
-let wallpaper = "{wallpaper}"
-let background = "{background}"
-let foreground = "{foreground}"
-let cursor = "{cursor}"
-
-" Colors
-let color0 = "{color0}"
-let color1 = "{color1}"
-let color2 = "{color2}"
-let color3 = "{color3}"
-let color4 = "{color4}"
-let color5 = "{color5}"
-let color6 = "{color6}"
-let color7 = "{color7}"
-let color8 = "{color8}"
-let color9 = "{color9}"
-let color10 = "{color10}"
-let color11 = "{color11}"
-let color12 = "{color12}"
-let color13 = "{color13}"
-let color14 = "{color14}"
-let color15 = "{color15}"
+++ /dev/null
-@define-color foreground {foreground};
-@define-color background {background};
-@define-color cursor {cursor};
-
-@define-color color0 {color0};
-@define-color color1 {color1};
-@define-color color2 {color2};
-@define-color color3 {color3};
-@define-color color4 {color4};
-@define-color color5 {color5};
-@define-color color6 {color6};
-@define-color color7 {color7};
-@define-color color8 {color8};
-@define-color color9 {color9};
-@define-color color10 {color10};
-@define-color color11 {color11};
-@define-color color12 {color12};
-@define-color color13 {color13};
-@define-color color14 {color14};
-@define-color color15 {color15};
+++ /dev/null
-! X colors.
-! Generated by 'wal'
-*foreground: {foreground}
-*background: {background}
-*.foreground: {foreground}
-*.background: {background}
-emacs*foreground: {foreground}
-emacs*background: {background}
-URxvt*foreground: {foreground}
-XTerm*foreground: {foreground}
-UXTerm*foreground: {foreground}
-URxvt*background: {background.alpha}
-XTerm*background: {background}
-UXTerm*background: {background}
-URxvt*cursorColor: {cursor}
-XTerm*cursorColor: {cursor}
-UXTerm*cursorColor: {cursor}
-URxvt*borderColor: {background.alpha}
-
-! Colors 0-15.
-*.color0: {color0}
-*color0: {color0}
-*.color1: {color1}
-*color1: {color1}
-*.color2: {color2}
-*color2: {color2}
-*.color3: {color3}
-*color3: {color3}
-*.color4: {color4}
-*color4: {color4}
-*.color5: {color5}
-*color5: {color5}
-*.color6: {color6}
-*color6: {color6}
-*.color7: {color7}
-*color7: {color7}
-*.color8: {color8}
-*color8: {color8}
-*.color9: {color9}
-*color9: {color9}
-*.color10: {color10}
-*color10: {color10}
-*.color11: {color11}
-*color11: {color11}
-*.color12: {color12}
-*color12: {color12}
-*.color13: {color13}
-*color13: {color13}
-*.color14: {color14}
-*color14: {color14}
-*.color15: {color15}
-*color15: {color15}
-
-! Black color that will not be affected by bold highlighting.
-*.color66: {color0}
-*color66: {color0}
-
-! Xclock colors.
-XClock*foreground: {foreground}
-XClock*background: {background}
-XClock*majorColor: rgba:{color15.xrgba}
-XClock*minorColor: rgba:{color15.xrgba}
-XClock*hourColor: rgba:{color15.xrgba}
-XClock*minuteColor: rgba:{color15.xrgba}
-XClock*secondColor: rgba:{color15.xrgba}
-
-! Set depth to make transparency work.
-URxvt*depth: 32
+++ /dev/null
-/* CSS variables
- Generated by 'wal' */
-:root {{
- --wallpaper: url("{wallpaper}");
-
- /* Special */
- --background: {background};
- --foreground: {foreground};
- --cursor: {cursor};
-
- /* Colors */
- --color0: {color0};
- --color1: {color1};
- --color2: {color2};
- --color3: {color3};
- --color4: {color4};
- --color5: {color5};
- --color6: {color6};
- --color7: {color7};
- --color8: {color8};
- --color9: {color9};
- --color10: {color10};
- --color11: {color11};
- --color12: {color12};
- --color13: {color13};
- --color14: {color14};
- --color15: {color15};
-}}
+++ /dev/null
---Place this file in your .xmonad/lib directory and import module Colors into .xmonad/xmonad.hs config
---The easy way is to create a soft link from this file to the file in .xmonad/lib using ln -s
---Then recompile and restart xmonad.
-
-module Colors
- ( wallpaper
- , background, foreground, cursor
- , color0, color1, color2, color3, color4, color5, color6, color7
- , color8, color9, color10, color11, color12, color13, color14, color15
- ) where
-
--- Shell variables
--- Generated by 'wal'
-wallpaper="{wallpaper}"
-
--- Special
-background="{background}"
-foreground="{foreground}"
-cursor="{cursor}"
-
--- Colors
-color0="{color0}"
-color1="{color1}"
-color2="{color2}"
-color3="{color3}"
-color4="{color4}"
-color5="{color5}"
-color6="{color6}"
-color7="{color7}"
-color8="{color8}"
-color9="{color9}"
-color10="{color10}"
-color11="{color11}"
-color12="{color12}"
-color13="{color13}"
-color14="{color14}"
-color15="{color15}"
+++ /dev/null
-{{
- "wallpaper": "{wallpaper}",
- "alpha": "{alpha}",
-
- "special": {{
- "background": "{background}",
- "foreground": "{foreground}",
- "cursor": "{cursor}"
- }},
- "colors": {{
- "color0": "{color0}",
- "color1": "{color1}",
- "color2": "{color2}",
- "color3": "{color3}",
- "color4": "{color4}",
- "color5": "{color5}",
- "color6": "{color6}",
- "color7": "{color7}",
- "color8": "{color8}",
- "color9": "{color9}",
- "color10": "{color10}",
- "color11": "{color11}",
- "color12": "{color12}",
- "color13": "{color13}",
- "color14": "{color14}",
- "color15": "{color15}"
- }}
-}}
+++ /dev/null
-// SCSS Variables
-// Generated by 'wal'
-$wallpaper: "{wallpaper}";
-
-// Special
-$background: {background};
-$foreground: {foreground};
-$cursor: {cursor};
-
-// Colors
-$color0: {color0};
-$color1: {color1};
-$color2: {color2};
-$color3: {color3};
-$color4: {color4};
-$color5: {color5};
-$color6: {color6};
-$color7: {color7};
-$color8: {color8};
-$color9: {color9};
-$color10: {color10};
-$color11: {color11};
-$color12: {color12};
-$color13: {color13};
-$color14: {color14};
-$color15: {color15};
+++ /dev/null
-# Shell variables
-# Generated by 'wal'
-wallpaper='{wallpaper}'
-
-# Special
-background='{background}'
-foreground='{foreground}'
-cursor='{cursor}'
-
-# Colors
-color0='{color0}'
-color1='{color1}'
-color2='{color2}'
-color3='{color3}'
-color4='{color4}'
-color5='{color5}'
-color6='{color6}'
-color7='{color7}'
-color8='{color8}'
-color9='{color9}'
-color10='{color10}'
-color11='{color11}'
-color12='{color12}'
-color13='{color13}'
-color14='{color14}'
-color15='{color15}'
-
-# FZF colors
-export FZF_DEFAULT_OPTS="
- $FZF_DEFAULT_OPTS
- --color fg:7,bg:0,hl:1,fg+:232,bg+:1,hl+:255
- --color info:7,prompt:2,spinner:1,pointer:232,marker:1
-"
-
-# Fix LS_COLORS being unreadable.
-export LS_COLORS="${{LS_COLORS}}:su=30;41:ow=30;42:st=30;44:"
+++ /dev/null
-wallpaper: "{wallpaper}"
-
-special:
- background: "{background}"
- foreground: "{foreground}"
- cursor: "{cursor}"
-
-colors:
- color0: "{color0}"
- color1: "{color1}"
- color2: "{color2}"
- color3: "{color3}"
- color4: "{color4}"
- color5: "{color5}"
- color6: "{color6}"
- color7: "{color7}"
- color8: "{color8}"
- color9: "{color9}"
- color10: "{color10}"
- color11: "{color11}"
- color12: "{color12}"
- color13: "{color13}"
- color14: "{color14}"
- color15: "{color15}"
+++ /dev/null
-"""
-Theme file handling.
-"""
-import logging
-import os
-import random
-import sys
-
-from .settings import CONF_DIR, MODULE_DIR
-from . import util
-
-
-def list_out():
- """List all themes in a pretty format."""
- dark_themes = [theme.name.replace(".json", "")
- for theme in list_themes()]
- ligh_themes = [theme.name.replace(".json", "")
- for theme in list_themes(dark=False)]
- user_themes = [theme.name.replace(".json", "")
- for theme in list_themes_user()]
-
- if user_themes:
- print("\033[1;32mUser Themes\033[0m:")
- print(" -", "\n - ".join(sorted(user_themes)))
-
- print("\033[1;32mDark Themes\033[0m:")
- print(" -", "\n - ".join(sorted(dark_themes)))
-
- print("\033[1;32mLight Themes\033[0m:")
- print(" -", "\n - ".join(sorted(ligh_themes)))
-
- print("\033[1;32mExtra\033[0m:")
- print(" - random (select a random dark theme)")
- print(" - random_dark (select a random dark theme)")
- print(" - random_light (select a random light theme)")
-
-
-def list_themes(dark=True):
- """List all installed theme files."""
- dark = "dark" if dark else "light"
- themes = os.scandir(os.path.join(MODULE_DIR, "colorschemes", dark))
- return [t for t in themes if os.path.isfile(t.path)]
-
-
-def list_themes_user():
- """List user theme files."""
- themes = [*os.scandir(os.path.join(CONF_DIR, "colorschemes/dark/")),
- *os.scandir(os.path.join(CONF_DIR, "colorschemes/light/"))]
- return [t for t in themes if os.path.isfile(t.path)]
-
-
-def terminal_sexy_to_wal(data):
- """Convert terminal.sexy json schema to wal."""
- data["colors"] = {}
- data["special"] = {
- "foreground": data["foreground"],
- "background": data["background"],
- "cursor": data["color"][9]
- }
-
- for i, color in enumerate(data["color"]):
- data["colors"]["color%s" % i] = color
-
- return data
-
-
-def parse(theme_file):
- """Parse the theme file."""
- data = util.read_file_json(theme_file)
-
- if "wallpaper" not in data:
- data["wallpaper"] = "None"
-
- if "alpha" not in data:
- data["alpha"] = util.Color.alpha_num
-
- # Terminal.sexy format.
- if "color" in data:
- data = terminal_sexy_to_wal(data)
-
- return data
-
-
-def get_random_theme(dark=True):
- """Get a random theme file."""
- themes = [theme.path for theme in list_themes(dark)]
- random.shuffle(themes)
- return themes[0]
-
-
-def file(input_file, light=False):
- """Import colorscheme from json file."""
- util.create_dir(os.path.join(CONF_DIR, "colorschemes/light/"))
- util.create_dir(os.path.join(CONF_DIR, "colorschemes/dark/"))
-
- theme_name = ".".join((input_file, "json"))
- bri = "light" if light else "dark"
-
- user_theme_file = os.path.join(CONF_DIR, "colorschemes", bri, theme_name)
- theme_file = os.path.join(MODULE_DIR, "colorschemes", bri, theme_name)
-
- # Find the theme file.
- if input_file in ("random", "random_dark"):
- theme_file = get_random_theme()
-
- elif input_file == "random_light":
- theme_file = get_random_theme(light)
-
- elif os.path.isfile(user_theme_file):
- theme_file = user_theme_file
-
- elif os.path.isfile(input_file):
- theme_file = input_file
-
- # Parse the theme file.
- if os.path.isfile(theme_file):
- logging.info("Set theme to \033[1;37m%s\033[0m.",
- os.path.basename(theme_file))
- return parse(theme_file)
-
- logging.error("No %s colorscheme file found.", bri)
- logging.error("Try adding '-l' to set light themes.")
- logging.error("Try removing '-l' to set dark themes.")
- sys.exit(1)
+++ /dev/null
-"""
-Misc helper functions.
-"""
-import colorsys
-import json
-import logging
-import os
-import subprocess
-import sys
-
-
-class Color:
- """Color formats."""
- alpha_num = "100"
-
- def __init__(self, hex_color):
- self.hex_color = hex_color
-
- def __str__(self):
- return self.hex_color
-
- @property
- def rgb(self):
- """Convert a hex color to rgb."""
- return "%s,%s,%s" % (*hex_to_rgb(self.hex_color),)
-
- @property
- def xrgba(self):
- """Convert a hex color to xrdb rgba."""
- return hex_to_xrgba(self.hex_color)
-
- @property
- def rgba(self):
- """Convert a hex color to rgba."""
- return "rgba(%s,%s,%s,%s)" % (*hex_to_rgb(self.hex_color),
- int(self.alpha_num)/100)
-
- @property
- def alpha(self):
- """Add URxvt alpha value to color."""
- return "[%s]%s" % (self.alpha_num, self.hex_color)
-
- @property
- def octal(self):
- """Export color in octal"""
- return "%s%s" % ("#", oct(int(self.hex_color[1:], 16))[2:])
-
- @property
- def octal_strip(self):
- """Strip '#' from octal color."""
- return oct(int(self.hex_color[1:], 16))[2:]
-
- @property
- def strip(self):
- """Strip '#' from color."""
- return self.hex_color[1:]
-
-
-def read_file(input_file):
- """Read data from a file and trim newlines."""
- with open(input_file, "r") as file:
- return file.read().splitlines()
-
-
-def read_file_json(input_file):
- """Read data from a json file."""
- with open(input_file, "r") as json_file:
- return json.load(json_file)
-
-
-def read_file_raw(input_file):
- """Read data from a file as is, don't strip
- newlines or other special characters.."""
- with open(input_file, "r") as file:
- return file.readlines()
-
-
-def save_file(data, export_file):
- """Write data to a file."""
- create_dir(os.path.dirname(export_file))
-
- try:
- with open(export_file, "w") as file:
- file.write(data)
- except PermissionError:
- logging.warning("Couldn't write to %s.", export_file)
-
-
-def save_file_json(data, export_file):
- """Write data to a json file."""
- create_dir(os.path.dirname(export_file))
-
- with open(export_file, "w") as file:
- json.dump(data, file, indent=4)
-
-
-def create_dir(directory):
- """Alias to create the cache dir."""
- os.makedirs(directory, exist_ok=True)
-
-
-def setup_logging():
- """Logging config."""
- logging.basicConfig(format=("[%(levelname)s\033[0m] "
- "\033[1;31m%(module)s\033[0m: "
- "%(message)s"),
- level=logging.INFO,
- stream=sys.stdout)
- logging.addLevelName(logging.ERROR, '\033[1;31mE')
- logging.addLevelName(logging.INFO, '\033[1;32mI')
- logging.addLevelName(logging.WARNING, '\033[1;33mW')
-
-
-def hex_to_rgb(color):
- """Convert a hex color to rgb."""
- return tuple(bytes.fromhex(color.strip("#")))
-
-
-def hex_to_xrgba(color):
- """Convert a hex color to xrdb rgba."""
- col = color.lower().strip("#")
- return "%s%s/%s%s/%s%s/ff" % (*col,)
-
-
-def rgb_to_hex(color):
- """Convert an rgb color to hex."""
- return "#%02x%02x%02x" % (*color,)
-
-
-def darken_color(color, amount):
- """Darken a hex color."""
- color = [int(col * (1 - amount)) for col in hex_to_rgb(color)]
- return rgb_to_hex(color)
-
-
-def lighten_color(color, amount):
- """Lighten a hex color."""
- color = [int(col + (255 - col) * amount) for col in hex_to_rgb(color)]
- return rgb_to_hex(color)
-
-
-def blend_color(color, color2):
- """Blend two colors together."""
- r1, g1, b1 = hex_to_rgb(color)
- r2, g2, b2 = hex_to_rgb(color2)
-
- r3 = int(0.5 * r1 + 0.5 * r2)
- g3 = int(0.5 * g1 + 0.5 * g2)
- b3 = int(0.5 * b1 + 0.5 * b2)
-
- return rgb_to_hex((r3, g3, b3))
-
-
-def saturate_color(color, amount):
- """Saturate a hex color."""
- r, g, b = hex_to_rgb(color)
- r, g, b = [x/255.0 for x in (r, g, b)]
- h, l, s = colorsys.rgb_to_hls(r, g, b)
- s = amount
- r, g, b = colorsys.hls_to_rgb(h, l, s)
- r, g, b = [x*255.0 for x in (r, g, b)]
-
- return rgb_to_hex((int(r), int(g), int(b)))
-
-
-def rgb_to_yiq(color):
- """Sort a list of colors."""
- return colorsys.rgb_to_yiq(*hex_to_rgb(color))
-
-
-def disown(cmd):
- """Call a system command in the background,
- disown it and hide it's output."""
- subprocess.Popen(cmd,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
-
-
-def get_pid(name):
- """Check if process is running by name."""
- try:
- subprocess.check_output(["pidof", "-s", name])
- except subprocess.CalledProcessError:
- return False
-
- return True
+++ /dev/null
-"""Set the wallpaper."""
-import ctypes
-import logging
-import os
-import shutil
-import subprocess
-import urllib.parse
-
-from .settings import CACHE_DIR, HOME, OS
-from . import util
-
-
-def get_desktop_env():
- """Identify the current running desktop environment."""
- desktop = os.environ.get("XDG_CURRENT_DESKTOP")
- if desktop:
- return desktop
-
- desktop = os.environ.get("DESKTOP_SESSION")
- if desktop:
- return desktop
-
- desktop = os.environ.get("GNOME_DESKTOP_SESSION_ID")
- if desktop:
- return "GNOME"
-
- desktop = os.environ.get("MATE_DESKTOP_SESSION_ID")
- if desktop:
- return "MATE"
-
- desktop = os.environ.get("SWAYSOCK")
- if desktop:
- return "SWAY"
-
- desktop = os.environ.get("DESKTOP_STARTUP_ID")
- if desktop and "awesome" in desktop:
- return "AWESOME"
-
- return None
-
-
-def xfconf(path, img):
- """Call xfconf to set the wallpaper on XFCE."""
- util.disown(["xfconf-query", "--channel", "xfce4-desktop",
- "--property", path, "--set", img])
-
-
-def set_wm_wallpaper(img):
- """Set the wallpaper for non desktop environments."""
- if shutil.which("feh"):
- util.disown(["feh", "--bg-fill", img])
-
- elif shutil.which("nitrogen"):
- util.disown(["nitrogen", "--set-zoom-fill", img])
-
- elif shutil.which("bgs"):
- util.disown(["bgs", "-z", img])
-
- elif shutil.which("hsetroot"):
- util.disown(["hsetroot", "-fill", img])
-
- elif shutil.which("habak"):
- util.disown(["habak", "-mS", img])
-
- elif shutil.which("display"):
- util.disown(["display", "-backdrop", "-window", "root", img])
-
- else:
- logging.error("No wallpaper setter found.")
- return
-
-
-def set_desktop_wallpaper(desktop, img):
- """Set the wallpaper for the desktop environment."""
- desktop = str(desktop).lower()
-
- if "xfce" in desktop or "xubuntu" in desktop:
- # XFCE requires two commands since they differ between versions.
- xfconf("/backdrop/screen0/monitor0/image-path", img)
- xfconf("/backdrop/screen0/monitor0/workspace0/last-image", img)
-
- elif "muffin" in desktop or "cinnamon" in desktop:
- util.disown(["gsettings", "set",
- "org.cinnamon.desktop.background",
- "picture-uri", "file://" + urllib.parse.quote(img)])
-
- elif "gnome" in desktop or "unity" in desktop:
- util.disown(["gsettings", "set",
- "org.gnome.desktop.background",
- "picture-uri", "file://" + urllib.parse.quote(img)])
-
- elif "mate" in desktop:
- util.disown(["gsettings", "set", "org.mate.background",
- "picture-filename", img])
-
- elif "sway" in desktop:
- util.disown(["swaymsg", "output", "*", "bg", img, "fill"])
-
- elif "awesome" in desktop:
- util.disown(["awesome-client", "gears.wallpaper.maximized(", img, ")"])
-
- else:
- set_wm_wallpaper(img)
-
-
-def set_mac_wallpaper(img):
- """Set the wallpaper on macOS."""
- db_file = "Library/Application Support/Dock/desktoppicture.db"
- db_path = os.path.join(HOME, db_file)
- subprocess.call(["sqlite3", db_path, "update data set value = '%s'" % img])
-
- # Kill the dock to fix issues with cached wallpapers.
- # macOS caches wallpapers and if a wallpaper is set that shares
- # the filename with a cached wallpaper, the cached wallpaper is
- # used instead.
- subprocess.call(["killall", "Dock"])
-
-
-def set_win_wallpaper(img):
- """Set the wallpaper on Windows."""
- # There's a different command depending on the architecture
- # of Windows. We check the PROGRAMFILES envar since using
- # platform is unreliable.
- if "x86" in os.environ["PROGRAMFILES"]:
- ctypes.windll.user32.SystemParametersInfoW(20, 0, img, 3)
- else:
- ctypes.windll.user32.SystemParametersInfoA(20, 0, img, 3)
-
-
-def change(img):
- """Set the wallpaper."""
- if not os.path.isfile(img):
- return
-
- desktop = get_desktop_env()
-
- if OS == "Darwin":
- set_mac_wallpaper(img)
-
- elif OS == "Windows":
- set_win_wallpaper(img)
-
- else:
- set_desktop_wallpaper(desktop, img)
-
- logging.info("Set the new wallpaper.")
-
-
-def get(cache_dir=CACHE_DIR):
- """Get the current wallpaper."""
- current_wall = os.path.join(cache_dir, "wal")
-
- if os.path.isfile(current_wall):
- return util.read_file(current_wall)[0]
-
- return "None"