v0.12.2 - Stdlib import chain
Released May 12, 2026.
When you import re in Python, an enormous amount of machinery has
to be in place for that one line to work. The re package itself
is Python code. It imports _sre, which is a C extension. _sre
calls into a regex engine that walks a bytecode the Python-level
re._compiler produces. The compiler itself imports enum,
functools, unicodedata, _thread. Each of those imports pulls
in more modules. By the time the chain settles, your program has
loaded forty files and crossed the Python / C boundary a dozen
times.
For most of gopy's life, we faked our way through this chain. We
shimmed re to a thin wrapper around Go's regexp. We shimmed
functools to a handful of stubs. We shimmed _colorize,
traceback, warnings, and a long tail of others because porting
the real module would have meant porting half of CPython first.
v0.12.2 ends the shim era. Thirty stdlib modules now import
the real CPython sources from Lib/, and those files resolve
against 1:1 Go ports of their C accelerators. The regex engine in
particular is a complete rewrite: gone is the RE2 shim, in is a
real interpreter that walks the CPython opcode stream the way
Modules/_sre/sre_lib.h does.
Phase 1 of the object protocol full port (spec 1704) lands here
too. The Objects/object.c method and getset tables now live on
objectType as real descriptors, and the metatype typeType
inherits from objectType so attribute lookup on a class walks
into object's descriptors the same way it does in CPython.
Highlights
Three pieces of work define this release.
Real regex engine
The Python-level re package now loads from stdlib/re/, byte
identical to CPython 3.14. It imports _sre, which is our 1:1 Go
port of Modules/_sre. Patterns are compiled by the Python-level
re._compiler into the same opcode buffer CPython produces, and
we walk that buffer with a real backtracking match loop ported
from Modules/_sre/sre_lib.h.
The RE2 shim is gone. There's no fallback path. Every re.match,
re.search, re.findall, re.sub, re.split rides the same
engine CPython does.
import re
m = re.match(r'(\d+)-(\d+)', '12-34')
print(m.groups()) # ('12', '34')
print(m.span(1), m.span(2)) # (0, 2) (3, 5)
# Real \b word boundaries, real (?i) case folding, real
# (?P<name>...) named groups, real backreferences.
re.sub(r'\b(\w+)\s+\1\b', r'\1', 'the the cat')
# 'the cat'
Thirty modules cross the line
The headline ports are:
| Module | What it is | Source |
|---|---|---|
_sre | Regex engine | Modules/_sre/* |
_datetime | date, time, datetime, timedelta, timezone | Modules/_datetimemodule.c |
_hashlib | MD5, SHA family, HMAC, PBKDF2 | Modules/_hashopenssl.c |
_struct | pack, unpack, calcsize | Modules/_struct.c |
_random | Mersenne Twister | Modules/_randommodule.c |
_socket | TCP / UDP / Unix sockets, getaddrinfo | Modules/socketmodule.c |
_io | BytesIO, StringIO, FileIO, buffered IO, TextIOWrapper | Modules/_io/* |
_csv | CSV reader / writer | Modules/_csv.c |
_codecs | Codec registry | Modules/_codecsmodule.c |
_collections | deque, defaultdict, OrderedDict, Counter | Modules/_collectionsmodule.c |
_itertools | Twenty-plus iterators | Modules/itertoolsmodule.c |
_functools | reduce, partial, lru_cache | Modules/_functoolsmodule.c |
_operator | C-level operator functions | Modules/_operator.c |
_abc | ABCMeta C accelerator | Modules/_abc.c |
_weakref | ref, proxy, CallableProxyType | Modules/_weakrefmodule.c |
_thread | get_ident, locks, start_new_thread | Modules/_threadmodule.c |
_heapq | Binary heap | Modules/_heapqmodule.c |
_bisect | Bisection algorithms | Modules/_bisectmodule.c |
_stat | S_IF* constants and predicates | Modules/_stat.c |
_json | JSON scanner and encoder fast path | Modules/_json.c |
_uuid | RFC 4122 UUID generation | Modules/_uuidmodule.c |
_posixsubprocess | fork_exec | Modules/_posixsubprocess.c |
_warnings | Warnings filter machinery | Modules/_warnings.c |
_time | Real-time clock surface | Modules/timemodule.c |
math | The full math.__all__ | Modules/mathmodule.c |
On the Python side, the corresponding .py files now resolve to
vendored CPython sources rather than shims: re, datetime,
hashlib, subprocess, threading, json, logging,
warnings, traceback, unittest, abc, functools,
contextlib, operator, reprlib, pprint, difflib,
_colorize, email, urllib, http, base64, configparser,
tarfile, zipfile, tokenize, linecache, textwrap,
codeop, numbers, random, string, shutil, shlex,
selectors, uuid, io, platform. Every one of these used to
be a shim with a sticky note saying "vendor when the import chain
is ready". The chain is ready.
Object protocol Phase 1
If you ask Python "what methods does object have?", CPython's
answer is the list in Objects/object.c object_methods and
Objects/object.c object_getsets. Up through v0.12.0, gopy's
answer was "whatever I happened to wire up when I needed it for a
specific test". That worked until enum needed
object.__subclasshook__, and then abc needed
object.__init_subclass__, and then a Python-level class needed
__dir__ to walk the type chain.
Phase 1 of spec 1704 ports the full table 1:1. Every name in
object_methods and object_getsets is now a real descriptor
sitting on objectType. The metatype typeType inherits from
objectType, so class-level attribute lookup walks the same path
CPython does.
class C:
pass
# These all walk into the same descriptors CPython uses.
print(C.__dir__) # method
print(C.__subclasshook__) # classmethod
print(C.__init_subclass__) # classmethod
print(C.__class__ is type) # True
print(C().__format__('')) # ''
This work unblocks the enum import end to end and clears the
last open piece of issue #544.
What's new
The full feature breakdown, grouped by where it landed.
Test e2e harness
This release closes the gap that v0.12.1 was supposed to close
(but never tagged). The CPython Lib/test/test_*.py suite is now
the gopy regression gate.
test/regrtest/. A 1:1 port ofLib/test/regrtest.py. It walks aMANIFEST.txttriage table, runs each ready entry through gopy, and reports pass / fail / skip per file. The manifest tracks all 434 CPython 3.14 test entry points; we ship the ones that pass and mark stdlib-dependent tests (json,pickle, networking, asyncio) as deferred until those modules land. The triage table lives at~/notes/Spec/1700/1700_gopy_test_e2e.md.test/cpython/. VendoredLib/test/test_*.pyfiles for shipped features, byte identical to upstream. Why byte identical? Because we want future CPython rebases to show zero diff noise. If a test changes between CPython 3.14 and 3.15, we see exactly that change rather than a tangle of our own edits.test/cpython/support/carriesLib/test/support/helpers unchanged for the same reason.imp/pathfinder.go.FileFinderplusSourceFileLoaderported fromLib/importlib/_bootstrap_external.py. The path finder walkssys.path, resolves package__init__.pydirectories, compiles source on demand, and caches the resultingCodeobject on the loader. The cache is invalidated on file mtime change so editing a vendored.pyand rerunning picks up the new version without a restart.stdlibinit/. A port ofModules/config.c.in. Built-in modules used to register themselves in scatteredinit()functions across the tree. Now there's one table, generated the way CPython generatesModules/config.c, so adding a new built-in is one entry rather than a hunt through the codebase.
Regex engine
The big one. v0.12.0 shipped a regex shim that delegated to Go's
regexp package (PCRE-style but RE2-backed). That worked for
maybe 70% of real-world patterns and failed the rest because the
shim couldn't honor backtracking, named groups, (?P=name)
backreferences, lookaround assertions, or several escape classes
that RE2 deliberately omits for performance.
This release replaces the shim with a real interpreter.
objects/sre/_constants.go. A 1:1 port ofLib/re/_constants.py. This is the opcode and flag table the rest of the engine keys off. We chose to port it (rather than reuseLib/re/_constants.pyat runtime) because the values are load-bearing in the Go code path; keeping them as Go constants lets the compiler check that we never reference a non-existent opcode.objects/sre/_casefix.go. The 46-entry case-fold table the C engine consults at compile time when the pattern carries the(?i)flag. CPython generates this table from Unicode data; we copied the table verbatim and added a regen script so Unicode 16 updates land as a one-line bump.objects/sre/engine.go. The real meat. This isModules/_sre/sre_lib.htranslated to Go. Every opcode in the CPython instruction set is here:LITERAL,LITERAL_IGNORE,IN,IN_IGNORE,ANY,ANY_ALL,REPEAT,MAX_UNTIL,MIN_UNTIL,MARK,JUMP,BRANCH,ASSERT,ASSERT_NOT,AT(the anchor family),GROUPREF,GROUPREF_IGNORE,GROUPREF_EXISTS,CHARSET. The match loop is a faithful Go translation including the stack-based backtracking state.objects/sre/pattern.go. ThePatternsurface:match,fullmatch,search,findall,finditer,sub,subn,split.compileruns the source through the Python-levelre._parserandre._compilerto produce the same opcode stream CPython would, then stamps the bytecode onto the Pattern object so subsequent calls don't recompile. No more shim fallback.objects/sre/match.go. TheMatchsurface:group,groups,groupdict,start,end,span,expand,regs,lastgroup,lastindex. These are 1:1 ports ofModules/_sre/sre.c match_*.
The CI now refuses to merge a change that re-introduces the
regexp import to any of the regex code paths. We learned the
hard way during the v0.10 to v0.12 stretch that "small fallback,
we'll remove it later" turns into a load-bearing fallback faster
than anyone expects.
Why we ported Modules/_sre instead of keeping regexp
Three reasons.
The behavior mismatch was bigger than we'd hoped. re.search and
regexp.FindIndex agree on the easy cases and disagree on the
hard ones. Backreferences ((.+)\1), lookbehind assertions
((?<=foo)bar), and possessive quantifiers (a++) all fall out
of RE2's design constraints. Patterns that mixed those features
silently produced wrong matches against a Go regexp engine, and
"silently wrong" is the worst kind of failure for a runtime
trying to be a drop-in.
Performance was a wash. We assumed RE2 would crush a faithful port on pathological patterns and that the win would offset the fidelity cost. Benchmarks said otherwise. For the patterns real Python programs actually compile, the CPython backtracker is faster than RE2 plus the conversion layer we needed on top.
Compatibility with re._compiler matters. The Python-level
compiler emits an opcode stream the C engine consumes. If we keep
the C engine, we get the Python compiler for free, and any future
Python-level features land without engine changes. If we keep a
foreign engine like RE2, every Python-level change has to be
mirrored across the conversion boundary. The accounting cost was
not small.
C-extension ports
Each entry below is a 1:1 port of the named CPython source. Where the C version touches a C-only facility (OpenSSL, raw POSIX syscalls), we substituted the Go equivalent and kept the public-surface behavior identical.
_abc.Modules/_abc.c. TheABCMetaaccelerator:_abc_init,_abc_register,_abc_instancecheck,_abc_subclasscheck,get_cache_token. The Python-levelabc.pynow loads fromstdlib/abc.pyand resolves its C-side hooks through this module._operator.Modules/_operator.c. Every name inoperator.__all__(add,sub,mul,itemgetter,attrgetter,methodcaller, the rich-compare helpers, the in-place arithmetic helpers) backed by the C-level fast path._weakref.Modules/_weakrefmodule.c.ref,proxy,CallableProxyType,getweakrefcount,getweakrefs. The underlying weakref machinery already lived inobjects/weakref.gofrom v0.10.1; this release wires the C module surface on top soweakref.ref(obj, callback)walks through the same call path CPython uses._functools.Modules/_functoolsmodule.c.reduce,partial,partialmethod,lru_cache,cmp_to_key. Thelru_cachedecorator uses the same OrderedDict-backed LRU CPython does, with the samemaxsize=128default and the same cache statistics shape (hits,misses,maxsize,currsize)._itertools.Modules/itertoolsmodule.c. Full 1:1 port covering every iterator:count,cycle,repeat,accumulate,chain,combinations,combinations_with_replacement,compress,dropwhile,filterfalse,groupby,islice,pairwise,permutations,product,starmap,takewhile,tee,zip_longest. Each iterator carries the upstream state layout sopickle.dumpson a partially-consumedcombinationsobject produces bytes that unpickle to an equivalent iterator._collections.Modules/_collectionsmodule.c.deque,defaultdict,OrderedDict,Counteraccelerators.dequein particular is performance critical; we ported the doubly linked list of fixed-size blocks the CPython version uses rather than wrappingcontainer/list, becausecontainer/listallocates per node while the block layout amortizes._thread.Modules/_threadmodule.c.get_ident, lock type,start_new_thread,_count. Locks back onto Gosync.Mutex.start_new_threadlaunches a goroutine but cooperates with our GIL the way CPython's pthread-launched threads cooperate with theirs, sothreading.Threadsemantics hold._heapq.Modules/_heapqmodule.c.heappush,heappop,heappushpop,heapify,heapreplace,nlargest,nsmallest, plus the_heapify_maxfamily used byheapq.merge._bisect.Modules/_bisectmodule.c.bisect_left,bisect_right,insort_left,insort_right. We deliberately did not optimize past a faithful port; the CPython implementation already takes O(log n) compares and the call overhead from Python dominates._stat.Modules/_stat.c. TheS_IF*family of file-mode constants plus theS_IS*predicate helpersposix.stat_resultleans on. Constants are shared withosso a single change propagates._struct.Modules/_struct.c.pack,unpack,pack_into,unpack_from,iter_unpack,calcsize. Format strings honor every byte-order prefix (<,>,=,!,@), native and standard sizes forb,B,h,H,i,I,l,L,q,Q,n,N,e,f,d,s,p,?,x, and the padding rules CPython documents._random.Modules/_randommodule.c. The Mersenne Twister PRNG.getrandbits,random,seed,setstate,getstate. We kept the upstream state layout (624-elementuint32vector plus index) sorandom.getstate()produces tuples that round-trip throughrandom.setstate()identically to CPython._hashlib.Modules/_hashopenssl.c. MD5, SHA1, SHA224, SHA256, SHA384, SHA512, BLAKE2b, BLAKE2s, HMAC, PBKDF2. Where the C version goes through OpenSSL, we go through Go'scrypto/*packages. Output bytes are identical; performance is comparable on amd64 and slightly better on arm64._posixsubprocess.Modules/_posixsubprocess.c. Thefork_execentry pointsubprocess.Popencalls. We dispatch throughos/exec.Cmdand honor the file-descriptor remapping CPython does so file descriptors inherit cleanly across the fork._socket.Modules/socketmodule.c. The full BSD-style socket interface plusgetaddrinfo,gethostname,gethostbyname,getservbyname. The POSIX implementation usessyscallplusnet; a Windows stub publishes the same surface so cross-platform builds compile._io.Modules/_io/*. The full hierarchy:RawIOBase->BufferedIOBase->TextIOBase.BytesIO,StringIO,FileIO,BufferedReader,BufferedWriter,BufferedRandom,TextIOWrapper._io.openhonors mode, buffering, encoding, newline, and errors through the layer stack. The codec layer hooks into_codecsfor encoding / decoding._codecs.Modules/_codecsmodule.c. The codec registry,lookup,encode,decode. Backsstr.encode,bytes.decode, and theio.TextIOWrapperencoding pipeline._csv.Modules/_csv.c.reader,writer, dialect registration, the quoting and lineterminator state machine._json.Modules/_json.c.scanstring,encode_basestring,encode_basestring_ascii. We ported the C scanner verbatim because the upstreamjsonpackage conditionally uses these accelerators when available; if we publish the symbols, Python-leveljson.dumpsandjson.loadsautomatically take the fast path._uuid.Modules/_uuidmodule.c. RFC 4122 UUID generation.generate_time_safeand the random variants are backed bycrypto/rand._datetime.Modules/_datetimemodule.c.date,time,datetime,timedelta,timezone. Arithmetic, formatting, parsing, and timezone handling all match CPython 3.14. We kept the upstreamMINYEAR=1/MAXYEAR=9999bounds and the same representation choices (adatetimeis a tuple of seven small ints plus an optional tzinfo, not a Gotime.Time) sodatetime.utcnow().toordinal()returns identical values to CPython._warnings.Modules/_warnings.c.warn,warn_explicit,_filters_mutated, the filter list, and the per-thread warnings state. Cooperates withstdlib/warnings.pyfor the Python-level surface._time.Modules/timemodule.c. The full time module:time,monotonic,perf_counter,process_time,sleep,gmtime,localtime,mktime,strftime,strptime,tzname.monotonicuses Go'stime.Now()minus a process origin;perf_counteruses the high-resolution counter throughruntime.nanotime.math.Modules/mathmodule.c. Every name inmath.__all__.pow,sqrt,log,log2,log10,exp,expm1,factorial,gcd,lcm,isclose,isnan,isinf,isfinite,comb,perm,dist,fsum,prod,remainder,nextafter,ulp, the trig family (sin,cos,tan,asin,acos,atan,atan2), and the hyperbolic family (sinh,cosh,tanh,asinh,acosh,atanh).
Vendored Python stdlib
stdlib/ carries byte-identical copies of the CPython 3.14
sources. The manifest at stdlib/MANIFEST.txt enumerates every
vendored file so future CPython rebases stay scriptable: a single
sync script reads the manifest, fetches the upstream files at the
pinned commit, and reports diff vs the vendor tree.
Newly vendored in this release: traceback.py, copy.py,
gettext.py, the logging/ package, the unittest/ package,
_collections_abc.py, _weakrefset.py, _py_abc.py, abc.py,
reprlib.py, operator.py, warnings.py, pprint.py,
difflib.py, functools.py, contextlib.py, the re/ package
(__init__.py, _compiler.py, _parser.py), datetime.py,
numbers.py, hashlib.py, struct.py, random.py,
threading.py, subprocess.py, selectors.py, shutil.py,
shlex.py, uuid.py, the json/ package, string.py,
linecache.py, tokenize.py, textwrap.py, codeop.py,
io.py, platform.py, zipfile/, tarfile.py, base64.py,
configparser.py, the email/ package, the urllib/ package,
the http/ package, _colorize.py.
Each landed alongside a shim deletion. The import machinery now resolves the real file rather than a wrapper.
Object protocol Phase 1
Spec 1704 (private design doc) calls for porting every function
in Objects/object.c, Objects/typeobject.c,
Objects/classobject.c, Objects/funcobject.c, and the name
opcodes in Python/ceval.c, in full. The deliverable is "every
function in the C file has a Go counterpart with a citation". Once
this spec lands we never come back to these files looking for a
missing slot.
Phase 1 is the Objects/object.c block: object_methods and
object_getsets.
// objects/object_proto.go
func init() {
SetTypeDescr(objectType, "__init__", ...)
SetTypeDescr(objectType, "__new__", ...)
SetTypeDescr(objectType, "__repr__", ...)
SetTypeDescr(objectType, "__str__", ...)
SetTypeDescr(objectType, "__hash__", ...)
SetTypeDescr(objectType, "__format__", ...)
SetTypeDescr(objectType, "__sizeof__", ...)
SetTypeDescr(objectType, "__dir__", ...)
SetTypeDescr(objectType, "__reduce__", ...)
SetTypeDescr(objectType, "__reduce_ex__", ...)
SetTypeDescr(objectType, "__getstate__", ...)
SetTypeDescr(objectType, "__subclasshook__", asClassMethod(...))
SetTypeDescr(objectType, "__init_subclass__", asClassMethod(...))
SetTypeDescr(objectType, "__class__", NewGetSet(...))
SetTypeDescr(objectType, "__dict__", NewGetSet(...))
// ...plus the six richcompare slots.
}
Two consequences fall out of getting this right.
typeType now inherits from objectType in the bases tuple, the
same way PyType_Type inherits from PyBaseObject_Type in
CPython. Before this change, attribute lookup on a class skipped
right past object's descriptors because the MRO didn't walk
through object. Now cls.__dir__, cls.__subclasshook__, and
cls.__init_subclass__ all resolve the way they should.
NewUserType propagates __module__ from the building frame
into the new class. __build_class__ no longer pre-stamps
__name__ and __qualname__ into the class namespace either,
because that pre-stamp was hiding the descriptor and producing a
plain string where we wanted a getset.
Exception machinery
This was a quiet ship but a big one. Try / except / finally / with / exception groups all compile and execute through real runtime machinery for the first time.
vm/exc_unwind.go. The exception unwinding loop. When code raises, the unwinder walks the per-code-object exception table, finds the matching handler frame, runs PUSH_EXC_INFO / POP_EXCEPT pairing, and chains__context__through the per-thread handled-exception slot. This is the runtime side of whatcompile/codegen.go try_exceptemits.vm/generator.go. Generators save and restore the thread's exception state on__next__,send,throw, andclose. Without this, an exception raised inside a generator body leaked into the calling frame's__context__after the generator yielded.errors/baseexc_getset.go.BaseExceptiongets real getset descriptors forargs,__traceback__,__context__,__cause__,__suppress_context__. Before this release, these were ad-hoc fields read directly off the Go struct, which meante.__traceback__returned the right value butsetattr(e, '__traceback__', tb)silently no-op'd.errors/raise.go.tp_callon every built-in exception type now goes througherrors.Raise.RAISE_VARARGSis one arm rather than per-type special cases, which meansraise OSError(errno.ENOENT, "msg")andraise OSError(errno.ENOENT, "msg", "filename")both produce the right exception with the rightargsshape without an arm-per-exception explosion.
Compile and VM polish
A backlog of compiler and VM fixes shipped alongside the bigger ports. None of these are headline features but several were load-bearing for the stdlib vendoring.
- Closures, decorators, and
*argscalls route through one unified vectorcall dispatcher invm/eval_call.go. Before this, three separate code paths were maintaining their own argument-shuffling logic. - Chained comparisons (
a < b < c) evaluate left to right with short-circuit semantics incompile/compare.go. Each intermediate result lands on the stack as a boolean rather than the v0.11 wrong-side leaks where the chained value occasionally surfaced where the boolean should have been. EXTENDED_ARGaccumulation is correct across consecutive prefixes incompile/assemble.go. The old code dropped one prefix in three when twoEXTENDED_ARGinstructions appeared in a row, which truncated very long jumps in big functions.- Closure tuples for non-inlined comprehensions in
compile/codegen.go. List, dict, and set comprehensions that reference outer-scope cells now get their closure tuple emitted correctly. LOAD_DEREFnames the missing cell in the raised error.END_FORis a no-op so the trailingPOP_TOPpops the iter the way CPython 3.13+ expects.MAKE_CELLruns for every cell variable, not just the ones whose name appeared inco_cellvars. The omission produced subtle "free variable referenced before assignment" errors in deeply nested closures.
Builtins surface
- The
BaseExceptionfamily is exposed as Python-level names soexcept OSError:works against user code. Up through v0.12.0 these were registered on the type but not in the builtins namespace;OSErrorin anexceptclause raisedNameError. - Type construction routes through
tp_newconsistently.int(),float(),str(),bytes(),list(),tuple(),dict(),set(),frozenset()all dispatch through one call slot. This matters because user subclasses (class L(list): pass) inherit the constructor through the same descriptor protocol the built-ins use. sys.pathis exposed sounittest.loadercan discover test files.sys.argvand the config-derived attributes are stamped at module build time.sys.exc_info()reads the handled-exception slot the unwinder maintains.
Why this release took the shape it did
You'll notice this release pulls in a lot of work that was
nominally v0.12.1. That's because v0.12.1 was an attempt to ship
"just the test infrastructure" without the modules the tests
depend on. We got far enough to wire the test runner and realize
the next ten tests we wanted to land all needed re, datetime,
or _io to work. So we pulled the import chain along with them.
The thirty-module batch is intentionally one release rather than thirty. Each module by itself is a small port, but the wiring between them (path finder, stdlibinit, codec layer, codec registry, generic getset machinery, BaseException getsets, the exception unwinder) is shared. Shipping them as a batch made the diff legible: one PR adds the wiring once, then each module ports against the same wiring. Shipping them one-by-one would have meant rebasing the wiring against itself thirty times.
The decision to vendor CPython sources rather than reimplement
the Python-level files in Go-flavored Python deserves a callout.
The rule is simple: if the file ends in .py upstream, we vendor
it byte for byte. If it ends in .c, we port it 1:1 with a
citation. This is annoying to do (CPython's coding style is its
own thing) but it pays dividends: the diff against upstream is
always small, and a fix in CPython 3.14.1 lands as a one-line
manifest bump on our side rather than a multi-day re-implementation
sweep.
Compatibility
A few user-visible changes are worth flagging.
- Regex behavior changes. Patterns that previously worked
against the RE2 backed shim and silently produced wrong
matches now produce CPython-faithful matches. In particular,
(.+)\1, lookbehind assertions, and possessive quantifiers all behave like CPython rather than like RE2. If you had code that compensated for the shim's quirks, that compensation can go. object.__dir__now walks the type chain the same way CPython does. Code that relied on the v0.12.0 short-list behavior may see additional entries indir(obj).BaseExceptionattribute writes now actually take effect. If you had code likee.__traceback__ = tbthat appeared to work but was silently dropped, it now does what you wrote.sys.exc_info()returns the currently-handled exception per CPython semantics. If nothing is being handled, it returns(None, None, None). Old code that called it outside anexceptblock to inspect a stale state will see the empty tuple now.
What's next
The remaining phases of spec 1704 land in v0.12.3.
- Phase 2.
Objects/funcobject.c PyClassMethod_Typeblock. Full port of everycm_*function:cm_init,cm_descr_get,cm_repr,cm_traverse, thecm_memberlistfor__func__and__wrapped__, thecm_getsetlistfor__isabstractmethod__/__dict__/__annotations__/__annotate__.__set_name__forwarding. - Phase 3.
Objects/funcobject.c PyStaticMethod_Typeblock. Mirror of Phase 2 plussm_callsostaticmethod(f)(x)works without.funcindirection. - Phase 4.
Objects/funcobject.c PyFunction_Typeblock. Full audit offunc_*functions for the getset table. - Phase 5.
Objects/classobject.c PyMethod_Type. Full bound-method port includingmethod_richcompare,method_hash,method_repr, the full getset table. - Phase 6.
Objects/typeobject.c type_newpipeline. Every function intype_new_*ported with the slots they wire. - Phase 7.
Objects/typeobject.c inherit_slots. Audit every slot edge so subclasses inherit slots through the same propagation rules CPython uses. - Phase 8.
Python/ceval.cSTORE_NAME / LOAD_NAME / DELETE_NAME. The fast-path-vs-protocol split CPython does for dict subclasses as the class namespace.
Outside spec 1704, the v0.12.3 cut also pulls in:
- The
os,posixpath,ntpathfull ports (issue #518). argparsepolish past the v0.12.2 vendor.- The
iosplit refinements past the v0.12.2 layer stack. - The
fnmatchoption-A delegation tore.compile(translate)(issue #542). enum.FlagBoundaryimport end to end (issue #544).
Networking, multiprocessing, asyncio, sqlite3, ctypes, tk / curses, GUI tests, gdb / dtrace stay out of scope. Those land when their respective porting specs do.
Acknowledgments
This release closes work tracked across roughly forty internal specs. The public-facing pointers are:
- Spec 1700 (test e2e drop) and the manifest at
~/notes/Spec/1700/1700_gopy_test_e2e.md. - Spec 1703 (regex full port). 8 phases, all shipped here.
- Spec 1704 (object protocol full port). Phase 1 shipped here.
- Issue #544 (enum import). Object protocol Phase 1 closes the last open piece.
The pull request that shipped this release is #22. The commit log covering everything since v0.12.0 is at compare v0.12.0..v0.12.2.