<commit_before># encoding: utf-8

import os
import fcntl
import functools
import select
import collections

from evdev import _input, _uinput, ecodes, util
from evdev.events import InputEvent

class EventIO(object):
    '''
    Class capable of read and write input events.
    
    This is used as as a base class for both device and uinput:
    
    - On ``device``, you read user-generated events (keys pressed, mouse moved, etc) and write feedback events (leds, beeps)
    
    - On ``uinput``, you write user-generated events (keys pressed, mouse moved, etc) and read feedback events (leds, beeps)
    '''

    def fileno(self):
        '''
        Return the file descriptor to the open event device. This makes
        it possible to pass instances directly to :func:`select.select()` and 
        :class:`asyncore.file_dispatcher`.
        '''
        return self.fd

    def read_loop(self):
        '''
        Enter an endless loop that yields input events.
        '''
        while True:
            r, w, x = select.select([self.fd], [], [])
            for event in self.read():
                yield event


    def read_one(self):
        '''
        Read and return a single input event as an instance of
        :class:`InputEvent <evdev.events.InputEvent>`.

        Return ``None`` if there are no pending input events.<commit_msg>Support for new asyncio coroutines<commit_after># encoding: utf-8

import os
import fcntl
import functools
import select
import collections

from evdev import _input, _uinput, ecodes, util
from evdev.events import InputEvent

try:
    import asyncio
except ImportError:
    asyncio = None

class EventIO(object):
    '''
    Class capable of read and write input events.
    
    This is used as as a base class for both device and uinput:
    
    - On ``device``, you read user-generated events (keys pressed, mouse moved, etc) and write feedback events (leds, beeps)
    
    - On ``uinput``, you write user-generated events (keys pressed, mouse moved, etc) and read feedback events (leds, beeps)
    '''

    def fileno(self):
        '''
        Return the file descriptor to the open event device. This makes
        it possible to pass instances directly to :func:`select.select()` and 
        :class:`asyncore.file_dispatcher`.
        '''
        return self.fd

    def read_loop(self):
        '''
        Enter an endless loop that yields input events.
        
        The returned iterator is compatible with `async for` syntax
        '''
        class ReadIterator:
            def __init__(self, device):
                self.current_batch = iter(())
                self.device = device

            # Standard iterator
            def __iter__(self):
                return self

            def next(self):  # Python 2.x
                return self.__next__()

            def __next__(self):  # Python 3.x
                try:
                    # Try to read from previous batch
                    return  next(self.current_batch)
                except StopIteration:
                    # Fetch next batch
                    r, w, x = select.select([self.device.fd], [], [])
                    self.current_batch = self.device.read()
                    return  next(self.current_batch)

            # Async iteration - Python 3.5
            if asyncio is not None:
                @asyncio.coroutine
                def __aiter__(self):
                    return self

                @asyncio.coroutine
                def __anext__(self):
                    future = asyncio.Future()
                    try:
                        # Try to read from previous batch
                        future.set_result(next(self.current_batch))
                    except StopIteration:
                        # Fetch next batch
                        def next_batch_ready(batch):
                            self.current_batch = batch.result()
                            future.set_result(next(self.current_batch))
                        self.device.async_read().add_done_callback(next_batch_ready)
                    return future
        
        return ReadIterator(self)

    if asyncio is not None:
        def _do_when_readable(self, callback):
            loop = asyncio.get_event_loop()
            def ready():
                loop.remove_reader(self.fileno())
                callback()
            loop.add_reader(self.fileno(), ready)

        def async_read_one(self):
            '''
            asyncio coroutine to read and return a single input event as an instance of
            :class:`InputEvent <evdev.events.InputEvent>`.
            '''
            future = asyncio.Future()
            self._do_when_readable(lambda: future.set_result(self.read_one()))
            return future

        def async_read(self):
            '''
            asyncio coroutine to read multiple input events from device. Return a generator object that
            yields :class:`InputEvent <evdev.events.InputEvent>` instances.
            '''
            future = asyncio.Future()
            self._do_when_readable(lambda: future.set_result(self.read()))
            return future


    def read_one(self):
        '''
        Read and return a single input event as an instance of
        :class:`InputEvent <evdev.events.InputEvent>`.

        Return ``None`` if there are no pending input events.
{'fraction_non_alphanumeric': 0.08093558566920364, 'fraction_numerical': 0.0011137924633376648, 'mean_word_length': 1.778751933986591, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5652512', 'n_tokens_mistral': 1391, 'n_tokens_neox': 1339, 'n_words': 466}