• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hivesolutions / netius / #620889944

23 Apr 2024 08:09PM UTC coverage: 45.051%. First build
#620889944

Pull #26

travis-ci

Pull Request #26: Server support for protocols

110 of 405 new or added lines in 21 files covered. (27.16%)

7733 of 17165 relevant lines covered (45.05%)

0.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.67
/src/netius/base/async_old.py
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3

4
# Hive Netius System
5
# Copyright (c) 2008-2024 Hive Solutions Lda.
6
#
7
# This file is part of Hive Netius System.
8
#
9
# Hive Netius System is free software: you can redistribute it and/or modify
10
# it under the terms of the Apache License as published by the Apache
11
# Foundation, either version 2.0 of the License, or (at your option) any
12
# later version.
13
#
14
# Hive Netius System is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# Apache License for more details.
18
#
19
# You should have received a copy of the Apache License along with
20
# Hive Netius System. If not, see <http://www.apache.org/licenses/>.
21

22
__author__ = "João Magalhães <joamag@hive.pt>"
1✔
23
""" The author(s) of the module """
24

25
__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
1✔
26
""" The copyright for the module """
27

28
__license__ = "Apache License, Version 2.0"
1✔
29
""" The license for the module """
30

31
import sys
1✔
32

33
import inspect
34
import functools
1✔
35

36
from . import errors
37
from . import legacy
1✔
38

39

40
class Future(object):
1✔
41
    """
42
    The base future object that represents a promise that a
1✔
43
    certain operation is going to be accomplished.
1✔
44

45
    It should be used as a placeholder for the callbacks for error
1✔
46
    and success and for the final result of the execution.
1✔
47

48
    Most of the implementation takes inspiration from the
1✔
49
    reference Python implementation on futures.
50

51
    :see: https://en.wikipedia.org/wiki/Futures_and_promises
52
    """
53

54
    _asyncio_future_blocking = True
55

56
    def __init__(self, loop=None):
57
        self.status = 0
58
        self._loop = loop
59
        self._blocking = False
60
        self._result = None
61
        self._exception = None
62
        self.cleanup()
1✔
63

64
    def __iter__(self):
1✔
65
        while not self.done():
1✔
66
            yield self
1✔
67
        if self.cancelled():
1✔
68
            raise errors.RuntimeError("Future canceled")
1✔
69
        if self.exception():
1✔
70
            raise self.exception()
1✔
71

72
    def cleanup(self):
1✔
73
        self.done_callbacks = []
×
74
        self.partial_callbacks = []
×
75
        self.ready_callbacks = []
×
76
        self.closed_callbacks = []
×
77

×
78
    def running(self):
79
        return self.status == 0
1✔
80

1✔
81
    def done(self):
1✔
82
        return self.status in (1, 2)
1✔
83

1✔
84
    def cancelled(self):
85
        return self.status == 2
1✔
86

1✔
87
    def finished(self):
88
        return self.done()
1✔
89

1✔
90
    def result(self):
91
        if self.cancelled():
1✔
92
            raise errors.RuntimeError("Already canceled")
1✔
93
        return self._result
94

1✔
95
    def exception(self, timeout=None):
1✔
96
        return self._exception
97

1✔
98
    def partial(self, value):
1✔
99
        self._partial_callbacks(value)
×
100

1✔
101
    def add_done_callback(self, function):
102
        self.done_callbacks.append(function)
1✔
103
        if not self.finished():
1✔
104
            return
105
        self._done_callbacks()
1✔
106

×
107
    def add_partial_callback(self, function):
108
        self.partial_callbacks.append(function)
1✔
109

1✔
110
    def add_ready_callback(self, function):
1✔
111
        self.ready_callbacks.append(function)
×
112

113
    def add_closed_callback(self, function):
1✔
114
        self.closed_callbacks.append(function)
×
115

116
    def remove_done_callback(self, function):
1✔
117
        self.done_callbacks.remove(function)
×
118

119
    def remove_partial_callback(self, function):
1✔
120
        self.partial_callbacks.remove(function)
×
121

122
    def remove_ready_callback(self, function):
1✔
NEW
123
        self.ready_callbacks.remove(function)
×
124

125
    def remove_closed_callback(self, function):
1✔
NEW
126
        self.closed_callbacks.remove(function)
×
127

128
    def approve(self, cleanup=True):
1✔
NEW
129
        self.set_result(None, cleanup=cleanup)
×
130

131
    def cancel(self, cleanup=True, force=False):
1✔
NEW
132
        if not force and not self.running():
×
133
            return False
134
        self.status = 2
1✔
135
        self._done_callbacks(cleanup=cleanup)
×
136
        return True
137

1✔
138
    def set_result(self, result, cleanup=True, force=False):
×
139
        if not force and not self.running():
×
140
            raise errors.AssertionError("Future not running")
×
141
        self.status = 1
×
142
        self._result = result
143
        self._done_callbacks(cleanup=cleanup)
1✔
144

1✔
145
    def set_exception(self, exception, cleanup=True, force=False):
×
146
        if not force and not self.running():
1✔
147
            raise errors.AssertionError("Future not running")
1✔
148
        self.status = 1
1✔
149
        self._exception = exception
150
        self._done_callbacks(cleanup=cleanup)
1✔
151

×
152
    @property
×
153
    def ready(self):
×
154
        ready = True
×
155
        for callback in self.ready_callbacks:
×
156
            ready &= callback()
157
        return ready
1✔
158

159
    @property
1✔
160
    def closed(self):
1✔
161
        closed = False
1✔
162
        for callback in self.closed_callbacks:
163
            closed |= callback()
1✔
164
        return closed
165

1✔
166
    def _done_callbacks(self, cleanup=True, delayed=True):
1✔
167
        if not self.done_callbacks:
1✔
168
            return
169
        if delayed and self._loop:
1✔
170
            return self._delay(
1✔
171
                lambda: self._done_callbacks(cleanup=cleanup, delayed=False)
1✔
172
            )
1✔
173
        for callback in self.done_callbacks:
174
            callback(self)
175
        if cleanup:
176
            self.cleanup()
177

178
    def _partial_callbacks(self, value, delayed=True):
1✔
179
        if not self.partial_callbacks:
1✔
180
            return
181
        if delayed and self._loop:
1✔
182
            return self._delay(lambda: self._partial_callbacks(value, delayed=False))
×
183
        for callback in self.partial_callbacks:
×
184
            callback(self, value)
185

186
    def _wrap(self, future):
×
187
        self.status = future.status
188
        self.done_callbacks = future.done_callbacks
1✔
189
        self.partial_callbacks = future.partial_callbacks
×
190
        self.ready_callbacks = future.ready_callbacks
×
191
        self.closed_callbacks = future.closed_callbacks
×
192
        self._loop = future._loop
×
193
        self._blocking = future._blocking
×
194
        self._result = future._result
×
195
        self._exception = future._exception
×
196

×
197
    def _delay(self, callable):
×
198
        has_delay = hasattr(self._loop, "delay")
199
        if has_delay:
1✔
200
            return self._loop.delay(callable, immediately=True)
1✔
201
        return self._loop.call_soon(callable)
1✔
202

×
203

204
class Task(Future):
1✔
205

206
    def __init__(self, future=None):
1✔
207
        Future.__init__(self)
×
208
        self._future = future
×
209
        self._source_traceback = None
×
210
        if future:
×
211
            self._wrap(future)
212

1✔
213

214
class Handle(object):
1✔
215

×
216
    def __init__(self, callable_t=None):
217
        self._callable_t = callable_t
1✔
218

×
219
    def cancel(self):
×
220
        if not self._callable_t:
×
221
            return
222
        options = self._callable_t[4]
1✔
223
        options[0] = False
224

1✔
225

×
226
class Executor(object):
227

1✔
228
    def submit(self, callable, *args, **kwargs):
229
        raise errors.NotImplemented("Missing implementation")
1✔
230

1✔
231

232
class ThreadPoolExecutor(Executor):
1✔
233

×
234
    def __init__(self, owner):
×
235
        self.owner = owner
236

237
    def submit(self, callable, *args, **kwargs):
×
238
        future = self.owner.build_future()
239
        callback = lambda result: self.owner.delay_s(lambda: future.set_result(result))
240
        self.owner.texecute(callable, args=args, kwargs=kwargs, callback=callback)
241
        return future
242

243

×
244
def coroutine(function):
245

1✔
246
    if inspect.isgeneratorfunction(function):
247
        routine = function
×
248
    else:
×
249

250
        @functools.wraps(function)
×
251
        def routine(*args, **kwargs):
252
            # calls the underlying function with the expected arguments
253
            # and keyword arguments (proper call propagation)
254
            result = function(*args, **kwargs)
×
255

256
            # verifies the data type of the resulting object so that a
257
            # proper yielding operation or return will take place
258
            is_future_ = is_future(result)
×
259
            is_generator = inspect.isgenerator(result)
×
260

261
            # in case the result is either a future or a generator
262
            # the complete set of values is properly yield
263
            # to the caller method as expected
264
            if is_future_ or is_generator:
×
265
                for value in result:
×
266
                    yield value
267

268
            # otherwise, the single resulting value is yield
269
            # to the caller method (simple propagation)
270
            else:
×
271
                yield result
272

×
273
    routine._is_coroutine = True
×
274
    return routine
275

1✔
276

277
def async_test_all(factory=None, close=True):
1✔
278

279
    def decorator(function):
1✔
280

1✔
281
        from . import common
282
        from . import asynchronous
1✔
283

284
        @functools.wraps(function)
1✔
285
        def wrapper(*args, **kwargs):
1✔
286
            function_c = asynchronous.coroutine(function)
1✔
287
            future = function_c(*args, **kwargs)
1✔
288
            loop = common.get_main(factory=factory)
289
            return loop.run_coroutine(future, close=close)
1✔
290

291
        return wrapper
1✔
292

293
    return decorator
1✔
294

1✔
295

1✔
296
def async_test(function):
297
    decorator = async_test_all()
1✔
298
    return decorator(function)
×
299

×
300

301
def ensure_generator(value):
1✔
302
    if legacy.is_generator(value):
×
303
        return True, value
304
    return False, value
1✔
305

×
306

×
307
def get_asyncio():
308
    return None
1✔
309

×
310

×
311
def is_coroutine(callable):
312
    if hasattr(callable, "_is_coroutine"):
1✔
313
        return True
×
314
    return False
315

1✔
316

×
317
def is_coroutine_object(generator):
×
318
    if legacy.is_generator(generator):
319
        return True
1✔
320
    return False
1✔
321

322

1✔
323
def is_coroutine_native(generator):
1✔
324
    return False
325

1✔
326

×
327
def is_future(future):
328
    if isinstance(future, Future):
1✔
329
        return True
×
330
    return False
×
331

×
332

333
def is_neo():
1✔
334
    return sys.version_info[0] >= 3 and sys.version_info[1] >= 3
×
335

×
336

×
337
def is_asynclib():
×
338
    return sys.version_info[0] >= 3 and sys.version_info[1] >= 4
×
339

340

1✔
341
def is_await():
×
342
    return sys.version_info[0] >= 3 and sys.version_info[1] >= 6
×
343

×
344

345
def wakeup(force=False):
1✔
346
    from .common import get_loop
×
347

×
348
    loop = get_loop()
×
349
    return loop.wakeup(force=force)
350

1✔
351

352
def sleep(timeout, compat=True, future=None):
353
    from .common import get_loop
354

355
    loop = get_loop()
356
    compat &= hasattr(loop, "_sleep")
357
    sleep = loop._sleep if compat else loop.sleep
358
    for value in sleep(timeout, future=future):
359
        yield value
360

361

362
def wait(event, timeout=None, future=None):
363
    from .common import get_loop
364

365
    loop = get_loop()
366
    for value in loop.wait(event, timeout=timeout, future=future):
NEW
367
        yield value
×
NEW
368

×
NEW
369

×
370
def notify(event, data=None):
371
    from .common import get_loop
372

373
    loop = get_loop()
374
    return loop.notify(event, data=data)
375

376

377
def coroutine_return(coroutine):
378
    """
379
    Allows for the abstraction of the return value of a coroutine
380
    object to be the result of the future yielded as the last element
381
    of the generator.
382

383
    This allows the possibility of providing compatibility
384
    with the legacy not return allowed generators.
385

386
    In case no value is yielded then an invalid value is returned as the
387
    result of the async coroutine.
388

389
    :type coroutine: CoroutineObject
390
    :param coroutine: The coroutine object that is going to yield back
391
    and have its last future result returned from the generator.
392
    """
393

394
    for value in coroutine:
395
        if value == None:
396
            continue
397
        yield value
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc