diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..f57321189e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,39 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: check-merge-conflict + - id: mixed-line-ending + - id: check-case-conflict + - repo: https://github.com/psf/black + rev: 23.7.0 + hooks: + - id: black + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + - repo: https://github.com/pycqa/flake8 + rev: 6.1.0 + hooks: + - id: flake8 + additional_dependencies: + - "flake8-pyproject==1.2.3" + types: [file] + types_or: [python, pyi] + - repo: https://github.com/codespell-project/codespell + rev: v2.2.5 + hooks: + - id: codespell + +ci: + autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" + autofix_prs: true + autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate" + autoupdate_schedule: weekly + skip: [black,isort] + submodules: false diff --git a/docs/Makefile b/docs/Makefile index 4fd0bb58f2..69095d6d90 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -17,4 +17,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/source/local_customization.py b/docs/source/local_customization.py index a970ad6e22..f071b6dfbb 100644 --- a/docs/source/local_customization.py +++ b/docs/source/local_customization.py @@ -1,11 +1,11 @@ -from docutils.parsers.rst import directives +from docutils.parsers.rst import directives as directives # noqa: F401 from sphinx import addnodes from sphinx.domains.python import PyClasslike -from sphinx.ext.autodoc import ( - FunctionDocumenter, - MethodDocumenter, - ClassLevelDocumenter, - Options, +from sphinx.ext.autodoc import ( # noqa: F401 + ClassLevelDocumenter as ClassLevelDocumenter, + FunctionDocumenter as FunctionDocumenter, + MethodDocumenter as MethodDocumenter, + Options as Options, ) """ diff --git a/notes-to-self/afd-lab.py b/notes-to-self/afd-lab.py index ed420dbdbd..600975482c 100644 --- a/notes-to-self/afd-lab.py +++ b/notes-to-self/afd-lab.py @@ -77,22 +77,27 @@ # matter, energy, and life which lie close at hand yet can never be detected # with the senses we have." -import sys import os.path +import sys + sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + r"\..")) import trio + print(trio.__file__) -import trio.testing import socket +import trio.testing +from trio._core._io_windows import _afd_helper_handle, _check, _get_base_socket from trio._core._windows_cffi import ( - ffi, kernel32, AFDPollFlags, IoControlCodes, ErrorCodes -) -from trio._core._io_windows import ( - _get_base_socket, _afd_helper_handle, _check + AFDPollFlags, + ErrorCodes, + IoControlCodes, + ffi, + kernel32, ) + class AFDLab: def __init__(self): self._afd = _afd_helper_handle() @@ -173,4 +178,5 @@ async def main(): await trio.sleep(2) nursery.cancel_scope.cancel() + trio.run(main) diff --git a/notes-to-self/aio-guest-test.py b/notes-to-self/aio-guest-test.py index b64a11bd04..17d4bfb9e0 100644 --- a/notes-to-self/aio-guest-test.py +++ b/notes-to-self/aio-guest-test.py @@ -1,10 +1,13 @@ import asyncio + import trio + async def aio_main(): loop = asyncio.get_running_loop() trio_done_fut = loop.create_future() + def trio_done_callback(main_outcome): print(f"trio_main finished: {main_outcome!r}") trio_done_fut.set_result(main_outcome) @@ -35,6 +38,7 @@ async def trio_main(): if n >= 10: return + async def aio_pingpong(from_trio, to_trio): print("aio_pingpong!") diff --git a/notes-to-self/atomic-local.py b/notes-to-self/atomic-local.py index 212c9eef00..429211eaf6 100644 --- a/notes-to-self/atomic-local.py +++ b/notes-to-self/atomic-local.py @@ -3,9 +3,11 @@ # Has to be a string :-( sentinel = "_unique_name" + def f(): print(locals()) + # code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring, # constants, names, varnames, filename, name, firstlineno, # lnotab[, freevars[, cellvars]]) diff --git a/notes-to-self/blocking-read-hack.py b/notes-to-self/blocking-read-hack.py index b301058e85..f4a73f876d 100644 --- a/notes-to-self/blocking-read-hack.py +++ b/notes-to-self/blocking-read-hack.py @@ -1,13 +1,16 @@ -import trio +import errno import os import socket -import errno + +import trio bad_socket = socket.socket() + class BlockingReadTimeoutError(Exception): pass + async def blocking_read_with_timeout(fd, count, timeout): print("reading from fd", fd) cancel_requested = False @@ -42,4 +45,5 @@ async def kill_it_after_timeout(new_fd): finally: os.close(new_fd) + trio.run(blocking_read_with_timeout, 0, 10, 2) diff --git a/notes-to-self/estimate-task-size.py b/notes-to-self/estimate-task-size.py index 1e8597ba42..0010c7a2b4 100644 --- a/notes-to-self/estimate-task-size.py +++ b/notes-to-self/estimate-task-size.py @@ -1,15 +1,18 @@ # Little script to get a rough estimate of how much memory each task takes import resource + import trio import trio.testing LOW = 1000 HIGH = 10000 + async def tinytask(): await trio.sleep_forever() + async def measure(count): async with trio.open_nursery() as nursery: for _ in range(count): @@ -23,8 +26,8 @@ async def main(): low_usage = await measure(LOW) high_usage = await measure(HIGH + LOW) - print("Memory usage per task:", - (high_usage.ru_maxrss - low_usage.ru_maxrss) / HIGH) + print("Memory usage per task:", (high_usage.ru_maxrss - low_usage.ru_maxrss) / HIGH) print("(kilobytes on Linux, bytes on macOS)") + trio.run(main) diff --git a/notes-to-self/fbsd-pipe-close-notify.py b/notes-to-self/fbsd-pipe-close-notify.py index 7b18f65d6f..ab17f94c3f 100644 --- a/notes-to-self/fbsd-pipe-close-notify.py +++ b/notes-to-self/fbsd-pipe-close-notify.py @@ -4,9 +4,8 @@ # # Upstream bug: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=246350 -import select import os -import threading +import select r, w = os.pipe() diff --git a/notes-to-self/file-read-latency.py b/notes-to-self/file-read-latency.py index 9af1b7222d..132e29dc4f 100644 --- a/notes-to-self/file-read-latency.py +++ b/notes-to-self/file-read-latency.py @@ -8,7 +8,7 @@ # ns per call, instead of ~500 ns/call for the syscall and related overhead. # That's probably more fair -- the BufferedIOBase code can't service random # accesses, even if your working set fits entirely in RAM. -f = open("/etc/passwd", "rb")#, buffering=0) +f = open("/etc/passwd", "rb") # , buffering=0) while True: start = time.perf_counter() @@ -23,5 +23,8 @@ both = (between - start) / COUNT * 1e9 seek = (end - between) / COUNT * 1e9 read = both - seek - print("{:.2f} ns/(seek+read), {:.2f} ns/seek, estimate ~{:.2f} ns/read" - .format(both, seek, read)) + print( + "{:.2f} ns/(seek+read), {:.2f} ns/seek, estimate ~{:.2f} ns/read".format( + both, seek, read + ) + ) diff --git a/notes-to-self/graceful-shutdown-idea.py b/notes-to-self/graceful-shutdown-idea.py index 792344de02..b454d7610a 100644 --- a/notes-to-self/graceful-shutdown-idea.py +++ b/notes-to-self/graceful-shutdown-idea.py @@ -1,5 +1,6 @@ import trio + class GracefulShutdownManager: def __init__(self): self._shutting_down = False @@ -21,6 +22,7 @@ def cancel_on_graceful_shutdown(self): def shutting_down(self): return self._shutting_down + # Code can check gsm.shutting_down occasionally at appropriate points to see # if it should exit. # @@ -31,9 +33,11 @@ async def stream_handler(stream): while True: with gsm.cancel_on_graceful_shutdown(): data = await stream.receive_some() + print(f"{data = }") if gsm.shutting_down: break + # To trigger the shutdown: async def listen_for_shutdown_signals(): with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM) as signal_aiter: diff --git a/notes-to-self/how-does-windows-so-reuseaddr-work.py b/notes-to-self/how-does-windows-so-reuseaddr-work.py index d8d60d1d66..3189d4d594 100644 --- a/notes-to-self/how-does-windows-so-reuseaddr-work.py +++ b/notes-to-self/how-does-windows-so-reuseaddr-work.py @@ -4,8 +4,8 @@ # # See https://github.com/python-trio/trio/issues/928 for details and context -import socket import errno +import socket modes = ["default", "SO_REUSEADDR", "SO_EXCLUSIVEADDRUSE"] bind_types = ["wildcard", "specific"] diff --git a/notes-to-self/loopy.py b/notes-to-self/loopy.py index 9f893590bd..0297a32dd8 100644 --- a/notes-to-self/loopy.py +++ b/notes-to-self/loopy.py @@ -1,6 +1,8 @@ -import trio import time +import trio + + async def loopy(): try: while True: @@ -9,10 +11,12 @@ async def loopy(): except KeyboardInterrupt: print("KI!") + async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(loopy) nursery.start_soon(loopy) nursery.start_soon(loopy) + trio.run(main) diff --git a/notes-to-self/lots-of-tasks.py b/notes-to-self/lots-of-tasks.py index fca2741de9..048c69a7ec 100644 --- a/notes-to-self/lots-of-tasks.py +++ b/notes-to-self/lots-of-tasks.py @@ -1,12 +1,15 @@ import sys + import trio (COUNT_STR,) = sys.argv[1:] COUNT = int(COUNT_STR) + async def main(): async with trio.open_nursery() as nursery: for _ in range(COUNT): nursery.start_soon(trio.sleep, 1) + trio.run(main) diff --git a/notes-to-self/manual-signal-handler.py b/notes-to-self/manual-signal-handler.py index 39ffeb5a4b..e1b5ee3036 100644 --- a/notes-to-self/manual-signal-handler.py +++ b/notes-to-self/manual-signal-handler.py @@ -3,16 +3,20 @@ if os.name == "nt": import cffi + ffi = cffi.FFI() - ffi.cdef(""" + ffi.cdef( + """ void* WINAPI GetProcAddress(void* hModule, char* lpProcName); typedef void (*PyOS_sighandler_t)(int); - """) + """ + ) kernel32 = ffi.dlopen("kernel32.dll") PyOS_getsig_ptr = kernel32.GetProcAddress( - ffi.cast("void*", sys.dllhandle), b"PyOS_getsig") + ffi.cast("void*", sys.dllhandle), b"PyOS_getsig" + ) PyOS_getsig = ffi.cast("PyOS_sighandler_t (*)(int)", PyOS_getsig_ptr) - import signal + PyOS_getsig(signal.SIGINT)(signal.SIGINT) diff --git a/notes-to-self/measure-listen-backlog.py b/notes-to-self/measure-listen-backlog.py index dc32732dfe..b7253b86cc 100644 --- a/notes-to-self/measure-listen-backlog.py +++ b/notes-to-self/measure-listen-backlog.py @@ -1,5 +1,6 @@ import trio + async def run_test(nominal_backlog): print("--\nnominal:", nominal_backlog) @@ -22,5 +23,6 @@ async def run_test(nominal_backlog): for client_sock in client_socks: client_sock.close() + for nominal_backlog in [10, trio.socket.SOMAXCONN, 65535]: trio.run(run_test, nominal_backlog) diff --git a/notes-to-self/ntp-example.py b/notes-to-self/ntp-example.py index 44db8cc873..2bb9f80fb3 100644 --- a/notes-to-self/ntp-example.py +++ b/notes-to-self/ntp-example.py @@ -3,9 +3,11 @@ # - use the hostname "2.pool.ntp.org" # (see: https://news.ntppool.org/2011/06/continuing-ipv6-deployment/) -import trio -import struct import datetime +import struct + +import trio + def make_query_packet(): """Construct a UDP packet suitable for querying an NTP server to ask for @@ -27,6 +29,7 @@ def make_query_packet(): return packet + def extract_transmit_timestamp(ntp_packet): """Given an NTP packet, extract the "transmit timestamp" field, as a Python datetime.""" @@ -49,15 +52,16 @@ def extract_transmit_timestamp(ntp_packet): offset = datetime.timedelta(seconds=seconds + fraction / 2**32) return base_time + offset + async def main(): print("Our clock currently reads (in UTC):", datetime.datetime.utcnow()) # Look up some random NTP servers. # (See www.pool.ntp.org for information about the NTP pool.) servers = await trio.socket.getaddrinfo( - "pool.ntp.org", # host - "ntp", # port - family=trio.socket.AF_INET, # IPv4 + "pool.ntp.org", # host + "ntp", # port + family=trio.socket.AF_INET, # IPv4 type=trio.socket.SOCK_DGRAM, # UDP ) @@ -66,7 +70,7 @@ async def main(): # Create a UDP socket udp_sock = trio.socket.socket( - family=trio.socket.AF_INET, # IPv4 + family=trio.socket.AF_INET, # IPv4 type=trio.socket.SOCK_DGRAM, # UDP ) @@ -88,4 +92,5 @@ async def main(): transmit_timestamp = extract_transmit_timestamp(data) print("Their clock read (in UTC):", transmit_timestamp) + trio.run(main) diff --git a/notes-to-self/proxy-benchmarks.py b/notes-to-self/proxy-benchmarks.py index a45d94d056..ea92e10c6f 100644 --- a/notes-to-self/proxy-benchmarks.py +++ b/notes-to-self/proxy-benchmarks.py @@ -3,6 +3,7 @@ methods = {"fileno"} + class Proxy1: strategy = "__getattr__" works_for = "any attr" @@ -15,8 +16,10 @@ def __getattr__(self, name): return getattr(self._wrapped, name) raise AttributeError(name) + ################################################################ + class Proxy2: strategy = "generated methods (getattr + closure)" works_for = "methods" @@ -24,16 +27,20 @@ class Proxy2: def __init__(self, wrapped): self._wrapped = wrapped + def add_wrapper(cls, method): def wrapper(self, *args, **kwargs): return getattr(self._wrapped, method)(*args, **kwargs) + setattr(cls, method, wrapper) + for method in methods: add_wrapper(Proxy2, method) ################################################################ + class Proxy3: strategy = "generated methods (exec)" works_for = "methods" @@ -41,20 +48,27 @@ class Proxy3: def __init__(self, wrapped): self._wrapped = wrapped + def add_wrapper(cls, method): - code = textwrap.dedent(""" + code = textwrap.dedent( + """ def wrapper(self, *args, **kwargs): return self._wrapped.{}(*args, **kwargs) - """.format(method)) + """.format( + method + ) + ) ns = {} exec(code, ns) setattr(cls, method, ns["wrapper"]) + for method in methods: add_wrapper(Proxy3, method) ################################################################ + class Proxy4: strategy = "generated properties (getattr + closure)" works_for = "any attr" @@ -62,6 +76,7 @@ class Proxy4: def __init__(self, wrapped): self._wrapped = wrapped + def add_wrapper(cls, attr): def getter(self): return getattr(self._wrapped, attr) @@ -74,11 +89,13 @@ def deleter(self): setattr(cls, attr, property(getter, setter, deleter)) + for method in methods: add_wrapper(Proxy4, method) ################################################################ + class Proxy5: strategy = "generated properties (exec)" works_for = "any attr" @@ -86,8 +103,10 @@ class Proxy5: def __init__(self, wrapped): self._wrapped = wrapped + def add_wrapper(cls, attr): - code = textwrap.dedent(""" + code = textwrap.dedent( + """ def getter(self): return self._wrapped.{attr} @@ -96,16 +115,21 @@ def setter(self, newval): def deleter(self): del self._wrapped.{attr} - """.format(attr=attr)) + """.format( + attr=attr + ) + ) ns = {} exec(code, ns) setattr(cls, attr, property(ns["getter"], ns["setter"], ns["deleter"])) + for method in methods: add_wrapper(Proxy5, method) ################################################################ + # methods only class Proxy6: strategy = "copy attrs from wrappee to wrapper" @@ -116,17 +140,19 @@ def __init__(self, wrapper): for method in methods: setattr(self, method, getattr(self._wrapper, method)) - + ################################################################ classes = [Proxy1, Proxy2, Proxy3, Proxy4, Proxy5, Proxy6] + def check(cls): with open("/etc/passwd") as f: p = cls(f) assert p.fileno() == f.fileno() + for cls in classes: check(cls) @@ -135,7 +161,7 @@ def check(cls): COUNT = 1000000 try: - import __pypy__ + import __pypy__ # noqa: F401 # __pypy__ imported but unused except ImportError: pass else: @@ -147,8 +173,7 @@ def check(cls): start = time.perf_counter() for _ in range(COUNT): obj.fileno() - #obj.fileno + # obj.fileno end = time.perf_counter() per_usec = COUNT / (end - start) / 1e6 - print("{:7.2f} / us: {} ({})" - .format(per_usec, obj.strategy, obj.works_for)) + print("{:7.2f} / us: {} ({})".format(per_usec, obj.strategy, obj.works_for)) diff --git a/notes-to-self/reopen-pipe.py b/notes-to-self/reopen-pipe.py index 5e5b31e41f..dbccd567d7 100644 --- a/notes-to-self/reopen-pipe.py +++ b/notes-to-self/reopen-pipe.py @@ -1,7 +1,7 @@ import os +import tempfile import threading import time -import tempfile def check_reopen(r1, w): diff --git a/notes-to-self/schedule-timing.py b/notes-to-self/schedule-timing.py index 176dcf9220..c84ec9a436 100644 --- a/notes-to-self/schedule-timing.py +++ b/notes-to-self/schedule-timing.py @@ -1,6 +1,7 @@ -import trio import time +import trio + LOOPS = 0 RUNNING = True diff --git a/notes-to-self/socket-scaling.py b/notes-to-self/socket-scaling.py index 1571be4d17..bd7e32ef7f 100644 --- a/notes-to-self/socket-scaling.py +++ b/notes-to-self/socket-scaling.py @@ -17,13 +17,16 @@ # # or similar. +import socket import time + import trio import trio.testing -import socket + async def main(): for total in [10, 100, 500, 1_000, 10_000, 20_000, 30_000]: + def pt(desc, *, count=total, item="socket"): nonlocal last_time now = time.perf_counter() @@ -53,4 +56,5 @@ def pt(desc, *, count=total, item="socket"): sock.close() pt("closing sockets") + trio.run(main) diff --git a/notes-to-self/ssl-close-notify/ssl-close-notify.py b/notes-to-self/ssl-close-notify/ssl-close-notify.py index cd4b450de8..32ecbea2f0 100644 --- a/notes-to-self/ssl-close-notify/ssl-close-notify.py +++ b/notes-to-self/ssl-close-notify/ssl-close-notify.py @@ -22,6 +22,7 @@ client_done = threading.Event() + def server_thread_fn(): server_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) server_ctx.load_cert_chain("trio-test-1.pem") @@ -42,13 +43,12 @@ def server_thread_fn(): break server.sendall(data) + server_thread = threading.Thread(target=server_thread_fn) server_thread.start() client_ctx = ssl.create_default_context(cafile="trio-test-CA.pem") -client = client_ctx.wrap_socket( - client_sock, - server_hostname="trio-test-1.example.org") +client = client_ctx.wrap_socket(client_sock, server_hostname="trio-test-1.example.org") # Now we have two SSLSockets that have established an encrypted connection diff --git a/notes-to-self/ssl-close-notify/ssl2.py b/notes-to-self/ssl-close-notify/ssl2.py index 32a68e1495..54ee1fb9b6 100644 --- a/notes-to-self/ssl-close-notify/ssl2.py +++ b/notes-to-self/ssl-close-notify/ssl2.py @@ -5,7 +5,7 @@ import ssl import threading -#client_sock, server_sock = socket.socketpair() +# client_sock, server_sock = socket.socketpair() listen_sock = socket.socket() listen_sock.bind(("127.0.0.1", 0)) listen_sock.listen(1) @@ -52,12 +52,12 @@ server.shutdown(socket.SHUT_WR) # Attempting to read/write to the fd after it's closed should raise EBADF -#os.close(server.fileno()) +# os.close(server.fileno()) # Attempting to read/write to an fd opened with O_DIRECT raises EINVAL in most # cases (unless you're very careful with alignment etc. which openssl isn't) -#os.dup2(os.open("/tmp/blah-example-file", os.O_RDWR | os.O_CREAT | os.O_DIRECT), server.fileno()) +# os.dup2(os.open("/tmp/blah-example-file", os.O_RDWR | os.O_CREAT | os.O_DIRECT), server.fileno()) # Sending or receiving server.sendall(b"hello") -#server.recv(10) +# server.recv(10) diff --git a/notes-to-self/ssl-handshake/ssl-handshake.py b/notes-to-self/ssl-handshake/ssl-handshake.py index 18a0e1a675..e906bc2a87 100644 --- a/notes-to-self/ssl-handshake/ssl-handshake.py +++ b/notes-to-self/ssl-handshake/ssl-handshake.py @@ -1,5 +1,5 @@ -import ssl import socket +import ssl import threading from contextlib import contextmanager diff --git a/notes-to-self/sslobject.py b/notes-to-self/sslobject.py index 0692af319c..a6e7b07a08 100644 --- a/notes-to-self/sslobject.py +++ b/notes-to-self/sslobject.py @@ -1,5 +1,5 @@ -from contextlib import contextmanager import ssl +from contextlib import contextmanager client_ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) client_ctx.check_hostname = False diff --git a/notes-to-self/thread-dispatch-bench.py b/notes-to-self/thread-dispatch-bench.py index 9afb4bbec8..70547a6000 100644 --- a/notes-to-self/thread-dispatch-bench.py +++ b/notes-to-self/thread-dispatch-bench.py @@ -5,8 +5,8 @@ # trio.to_thread.run_sync import threading -from queue import Queue import time +from queue import Queue COUNT = 10000 diff --git a/notes-to-self/time-wait.py b/notes-to-self/time-wait.py index 08c71b0048..772f6c2727 100644 --- a/notes-to-self/time-wait.py +++ b/notes-to-self/time-wait.py @@ -26,8 +26,8 @@ # Also, it must be set on listen2 before calling bind(), or it will conflict # with the lingering server1 socket. -import socket import errno +import socket import attr diff --git a/notes-to-self/trace.py b/notes-to-self/trace.py index c024a36ba5..aa68fac125 100644 --- a/notes-to-self/trace.py +++ b/notes-to-self/trace.py @@ -1,8 +1,9 @@ -import trio -import os import json +import os from itertools import count +import trio + # Experiment with generating Chrome Event Trace format, which can be browsed # through chrome://tracing or other mechanisms. # @@ -29,6 +30,7 @@ # let us also show "task is running", because neither kind of event is # strictly nested inside the other + class Trace(trio.abc.Instrument): def __init__(self, out): self.out = out @@ -108,14 +110,14 @@ def task_scheduled(self, task): def before_io_wait(self, timeout): self._write( - name=f"I/O wait", + name="I/O wait", ph="B", tid=-1, ) def after_io_wait(self, timeout): self._write( - name=f"I/O wait", + name="I/O wait", ph="E", tid=-1, ) @@ -126,11 +128,13 @@ async def child1(): await trio.sleep(1) print(" child1: exiting!") + async def child2(): print(" child2: started! sleeping now...") await trio.sleep(1) print(" child2: exiting!") + async def parent(): print("parent: started!") async with trio.open_nursery() as nursery: @@ -144,5 +148,6 @@ async def parent(): # -- we exit the nursery block here -- print("parent: all done!") + t = Trace(open("/tmp/t.json", "w")) trio.run(parent, instruments=[t]) diff --git a/notes-to-self/trivial-err.py b/notes-to-self/trivial-err.py index ed11ec33e6..6c32617c74 100644 --- a/notes-to-self/trivial-err.py +++ b/notes-to-self/trivial-err.py @@ -1,26 +1,33 @@ import sys + import trio sys.stderr = sys.stdout + async def child1(): raise ValueError + async def child2(): async with trio.open_nursery() as nursery: nursery.start_soon(grandchild1) nursery.start_soon(grandchild2) + async def grandchild1(): raise KeyError + async def grandchild2(): raise NameError("Bob") + async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(child1) nursery.start_soon(child2) - #nursery.start_soon(grandchild1) + # nursery.start_soon(grandchild1) + trio.run(main) diff --git a/notes-to-self/trivial.py b/notes-to-self/trivial.py index 6852d63200..405d92daf5 100644 --- a/notes-to-self/trivial.py +++ b/notes-to-self/trivial.py @@ -1,8 +1,10 @@ import trio + async def foo(): print("in foo!") return 3 + print("running!") print(trio.run(foo)) diff --git a/notes-to-self/wakeup-fd-racer.py b/notes-to-self/wakeup-fd-racer.py index c6ef6caec1..b56cbdc91c 100644 --- a/notes-to-self/wakeup-fd-racer.py +++ b/notes-to-self/wakeup-fd-racer.py @@ -1,19 +1,21 @@ +import itertools import os +import select import signal +import socket import threading import time -import socket -import select -import itertools # Equivalent to the C function raise(), which Python doesn't wrap if os.name == "nt": import cffi + _ffi = cffi.FFI() _ffi.cdef("int raise(int);") _lib = _ffi.dlopen("api-ms-win-crt-runtime-l1-1-0.dll") signal_raise = getattr(_lib, "raise") else: + def signal_raise(signum): # Use pthread_kill to make sure we're actually using the wakeup fd on # Unix @@ -26,7 +28,7 @@ def raise_SIGINT_soon(): # Sending 2 signals becomes reliable, as we'd expect (because we need # set-flags -> write-to-fd, and doing it twice does # write-to-fd -> set-flags -> write-to-fd -> set-flags) - #signal_raise(signal.SIGINT) + # signal_raise(signal.SIGINT) def drain(sock): @@ -87,8 +89,10 @@ def main(): # them. duration = time.perf_counter() - start if duration < 2: - print(f"Attempt {attempt}: OK, trying again " - f"(select_calls = {select_calls}, drained = {drained})") + print( + f"Attempt {attempt}: OK, trying again " + f"(select_calls = {select_calls}, drained = {drained})" + ) else: print(f"Attempt {attempt}: FAILED, took {duration} seconds") print(f"select_calls = {select_calls}, drained = {drained}") @@ -96,5 +100,6 @@ def main(): thread.join() + if __name__ == "__main__": main() diff --git a/notes-to-self/win-waitable-timer.py b/notes-to-self/win-waitable-timer.py index 92bfd7a39a..5309f43867 100644 --- a/notes-to-self/win-waitable-timer.py +++ b/notes-to-self/win-waitable-timer.py @@ -24,12 +24,12 @@ # make this fairly straightforward, but you obviously need to use a separate # time source -import cffi from datetime import datetime, timedelta, timezone -import time + +import cffi import trio -from trio._core._windows_cffi import (ffi, kernel32, raise_winerror) +from trio._core._windows_cffi import ffi, kernel32, raise_winerror try: ffi.cdef( @@ -91,7 +91,7 @@ LPFILETIME lpFileTime ); """, - override=True + override=True, ) ProcessLeapSecondInfo = 8 @@ -106,10 +106,10 @@ def set_leap_seconds_enabled(enabled): plsi.Flags = 0 plsi.Reserved = 0 if not kernel32.SetProcessInformation( - ffi.cast("HANDLE", -1), # current process - ProcessLeapSecondInfo, - plsi, - ffi.sizeof("PROCESS_LEAP_SECOND_INFO"), + ffi.cast("HANDLE", -1), # current process + ProcessLeapSecondInfo, + plsi, + ffi.sizeof("PROCESS_LEAP_SECOND_INFO"), ): raise_winerror() @@ -135,9 +135,7 @@ def now_as_filetime(): # https://www.epochconverter.com/ldap # FILETIME_TICKS_PER_SECOND = 10**7 -FILETIME_EPOCH = datetime.strptime( - '1601-01-01 00:00:00 Z', '%Y-%m-%d %H:%M:%S %z' -) +FILETIME_EPOCH = datetime.strptime("1601-01-01 00:00:00 Z", "%Y-%m-%d %H:%M:%S %z") # XXX THE ABOVE IS WRONG: # # https://techcommunity.microsoft.com/t5/networking-blog/leap-seconds-for-the-appdev-what-you-should-know/ba-p/339813# @@ -159,11 +157,9 @@ def now_as_filetime(): def py_datetime_to_win_filetime(dt): # We'll want to call this on every datetime as it comes in - #dt = dt.astimezone(timezone.utc) + # dt = dt.astimezone(timezone.utc) assert dt.tzinfo is timezone.utc - return round( - (dt - FILETIME_EPOCH).total_seconds() * FILETIME_TICKS_PER_SECOND - ) + return round((dt - FILETIME_EPOCH).total_seconds() * FILETIME_TICKS_PER_SECOND) async def main(): diff --git a/pyproject.toml b/pyproject.toml index 073e2508d1..97970f0ed0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,11 @@ [tool.black] target-version = ['py38'] +force-exclude = ''' +( + ^/docs/source/reference-.* + | ^/docs/source/tutorial +) +''' [tool.codespell] ignore-words-list = 'astroid,crasher,asend' @@ -20,6 +26,10 @@ per-file-ignores = [ combine_as_imports = true profile = "black" skip_gitignore = true +skip_glob = [ + "docs/source/reference-*", + "docs/source/tutorial/*" +] [tool.mypy] python_version = "3.8"