diff --git a/test-requirements.txt b/test-requirements.txt index 2164df74e8..78b5c6ff7c 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,3 +4,5 @@ ipython # for the IPython traceback integration tests pyOpenSSL # for the ssl tests trustme # for the ssl tests pytest-faulthandler +pylint # for pylint finding all symbols tests +jedi # for jedi code completion tests diff --git a/trio/__init__.py b/trio/__init__.py index 5f84226570..8372c35920 100644 --- a/trio/__init__.py +++ b/trio/__init__.py @@ -15,52 +15,52 @@ from ._version import __version__ -__all__ = [] +from ._core import ( + TrioInternalError, RunFinishedError, WouldBlock, Cancelled, + ResourceBusyError, ClosedResourceError, MultiError, run, open_nursery, + open_cancel_scope, current_effective_deadline, TASK_STATUS_IGNORED, + current_time +) -from ._toplevel_core_reexports import * -__all__ += _toplevel_core_reexports.__all__ +from ._timeouts import ( + move_on_at, move_on_after, sleep_forever, sleep_until, sleep, fail_at, + fail_after, TooSlowError +) -from ._timeouts import * -__all__ += _timeouts.__all__ +from ._sync import ( + Event, CapacityLimiter, Semaphore, Lock, StrictFIFOLock, Condition, Queue +) -from ._sync import * -__all__ += _sync.__all__ +from ._threads import ( + run_sync_in_worker_thread, current_default_worker_thread_limiter, + BlockingTrioPortal +) -from ._threads import * -__all__ += _threads.__all__ +from ._highlevel_generic import ( + aclose_forcefully, BrokenStreamError, StapledStream +) -from ._highlevel_generic import * -__all__ += _highlevel_generic.__all__ +from ._signals import catch_signals, open_signal_receiver -from ._signals import * -__all__ += _signals.__all__ +from ._highlevel_socket import SocketStream, SocketListener -from ._highlevel_socket import * -__all__ += _highlevel_socket.__all__ +from ._file_io import open_file, wrap_file -from ._file_io import * -__all__ += _file_io.__all__ +from ._path import Path -from ._path import * -__all__ += _path.__all__ +from ._highlevel_serve_listeners import serve_listeners -from ._highlevel_serve_listeners import * -__all__ += _highlevel_serve_listeners.__all__ +from ._highlevel_open_tcp_stream import open_tcp_stream -from ._highlevel_open_tcp_stream import * -__all__ += _highlevel_open_tcp_stream.__all__ +from ._highlevel_open_tcp_listeners import open_tcp_listeners, serve_tcp -from ._highlevel_open_tcp_listeners import * -__all__ += _highlevel_open_tcp_listeners.__all__ +from ._highlevel_open_unix_stream import open_unix_socket -from ._highlevel_open_unix_stream import * -__all__ += _highlevel_open_unix_stream.__all__ +from ._highlevel_ssl_helpers import ( + open_ssl_over_tcp_stream, open_ssl_over_tcp_listeners, serve_ssl_over_tcp +) -from ._highlevel_ssl_helpers import * -__all__ += _highlevel_ssl_helpers.__all__ - -from ._deprecate import * -__all__ += _deprecate.__all__ +from ._deprecate import TrioDeprecationWarning # Imported by default from . import hazmat @@ -68,6 +68,8 @@ from . import abc from . import ssl # Not imported by default: testing +if False: + from . import testing _deprecate.enable_attribute_deprecations(__name__) __deprecated_attributes__ = { diff --git a/trio/_deprecate.py b/trio/_deprecate.py index 7812623e73..e7323b3057 100644 --- a/trio/_deprecate.py +++ b/trio/_deprecate.py @@ -5,8 +5,6 @@ import attr -__all__ = ["TrioDeprecationWarning"] - # We want our warnings to be visible by default (at least for now), but we # also want it to be possible to override that using the -W switch. AFAICT diff --git a/trio/_toplevel_core_reexports.py b/trio/_toplevel_core_reexports.py deleted file mode 100644 index 08fb93f7f1..0000000000 --- a/trio/_toplevel_core_reexports.py +++ /dev/null @@ -1,33 +0,0 @@ -# PyCharm tries to statically trio's attributes, so that it can offer -# completions. (Other IDEs probably do similar things.) -# -# _core's exports use all sorts of wacky runtime tricks to set up their -# exports, and then they get divided between trio, trio.hazmat, and -# trio.testing. In an attempt to make this easier to understand for static -# analysis, this file lists all the _core symbols that are re-exported at the -# top-level (trio.whatever), with a simple static __all__. This turns out to -# be important -- PyCharm at least gives up on analyzing __all__ entirely if -# it sees __all__ += , see: -# https://github.com/python-trio/trio/issues/314#issuecomment-327824200 -# -# trio/hazmat.py and trio/testing/__init__.py have similar tricks, and we have -# a test to make sure that every _core export does get re-exported in one of -# these places or another. -__all__ = [ - "TrioInternalError", - "RunFinishedError", - "WouldBlock", - "Cancelled", - "ResourceBusyError", - "ClosedResourceError", - "MultiError", - "run", - "open_nursery", - "open_cancel_scope", - "current_effective_deadline", - "TASK_STATUS_IGNORED", - "current_time", -] - -from . import _core -globals().update({sym: getattr(_core, sym) for sym in __all__}) diff --git a/trio/_util.py b/trio/_util.py index 55d9c1976f..486360c3bf 100644 --- a/trio/_util.py +++ b/trio/_util.py @@ -177,9 +177,9 @@ def fix_one(obj): for attr_value in obj.__dict__.values(): fix_one(attr_value) - for objname in namespace["__all__"]: - obj = namespace[objname] - fix_one(obj) + for objname, obj in namespace.items(): + if not objname.startswith("_"): # ignore private attributes + fix_one(obj) # os.fspath is defined on Python 3.6+ but we need to support Python 3.5 too diff --git a/trio/tests/test_exports.py b/trio/tests/test_exports.py index d5ad1b3381..9c28715d35 100644 --- a/trio/tests/test_exports.py +++ b/trio/tests/test_exports.py @@ -1,6 +1,13 @@ import trio import trio.testing +import jedi +import os +import pytest +import sys + +from pylint.lint import PyLinter + from .. import _core @@ -8,13 +15,36 @@ def test_core_is_properly_reexported(): # Each export from _core should be re-exported by exactly one of these # three modules: sources = [trio, trio.hazmat, trio.testing] - for symbol in _core.__all__: + for symbol in dir(_core): + if symbol.startswith('_') or symbol == 'tests': + continue found = 0 for source in sources: if ( - symbol in source.__all__ + symbol in dir(source) and getattr(source, symbol) is getattr(_core, symbol) ): found += 1 print(symbol, found) assert found == 1 + + +def test_pylint_sees_all_non_underscore_symbols_in_namespace(): + # Test pylints ast to contain the same content as dir(trio) + linter = PyLinter() + ast_set = set(linter.get_ast(trio.__file__, 'trio')) + trio_set = set([symbol for symbol in dir(trio) if symbol[0] != '_']) + trio_set.remove('tests') + assert trio_set - ast_set == set([]) + + +def test_jedi_sees_all_completions(): + # Test the jedi completion library get all in dir(trio) + try: + script = jedi.Script("import trio; trio.") + completions = script.completions() + trio_set = set([symbol for symbol in dir(trio) if symbol[:2] != '__']) + jedi_set = set([cmp.name for cmp in completions]) + assert trio_set - jedi_set == set([]) + except NotImplementedError: + pytest.skip("jedi does not yet support {}".format(sys.version))