#!/usr/bin/env python3 """One interpreter start for the whole of 99-python3-constantly. Emits `key=value' lines, one per line, in file order; the suite reads them with grep. A python3 start on this arm is tens of seconds and every measurement here is the construction of a handful of small container classes -- microseconds beside the start -- so taking the start ONCE is the difference between a half-minute suite and a twenty-minute one. THE TRANSPORT RULES. The runner parses its input line by line, so no value may contain a NEWLINE; the suite splits on the FIRST `=', so a value containing `=' is safe and a key containing one is not. Every repr emitted below was checked against those rules on the control: none of them spans a line and none of them carries a memory address. That last point is what makes a repr comparable across two machines at all, and it is not incidental here -- `_Constant.__repr__' is `', built from two names, so a constant's repr is stable by construction while the DEFAULT object repr this class overrides would have carried an address. The one place a raw object repr could still leak through is `_unspecified', the module-level sentinel; it is never emitted. THIS PROBE EXITS 0 EVEN WHEN THE IMPORT FAILS. constantly is pure Python with no compiled half, so an import failure here would be a platform fact about the interpreter rather than about this package -- and turning it into eighty empty-string mismatches would bury that fact rather than report it. The failure is reported as `import_ok=no' with the exception, the suite reds exactly one case for it, and every behavioural case is SKIPPED with that reason attached. WHERE THE EXPECTED VALUES COME FROM. Every value the suite compares against was MEASURED by running THIS FILE on an x86-64 control at the same version -- constantly 23.10.4 from the same PyPI sdist (sha256 aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd, the recipe's own), under CPython 3.12. This package declares no ext_modules, reads no sizeof, packs no struct, opens no device and branches on nothing at all -- `_constants.py' has no `sys.version_info' test and no platform test -- so there is nothing in it that can know the pointer width. Any difference between the two arms is a defect and not a property, which is what makes the control the right shape here and what makes `py_maxsize_bits' load-bearing: it is the one value that says the transcript came from the wasm32 interpreter rather than from a host copy of the module, since every other value would pass either way. THE ORDER COUNTER IS PROCESS-GLOBAL, AND THIS PROBE IS WRITTEN AROUND THAT. `_constantOrder' is `partial(next, count())' at module scope, so every `_Constant' ever built in the process draws from ONE counter, and `_index' is therefore an absolute serial number rather than a per-container position. Nothing below emits an `_index' value: they would be a statement about the order this file happens to define its fixtures in, which is not a property of the package. What IS emitted is the ORDER `iterconstants()' yields, which is what the counter exists to provide and what a consumer relies on. """ import sys emitted = [] def emit(key, value): emitted.append(key) print('%s=%s' % (key, value)) def r(obj): """A repr with any newline collapsed -- see THE TRANSPORT RULES above.""" return repr(obj).replace('\n', ' ') def err(fn, *args, **kw): """The exception TYPE NAME a call raises, or `none' when it returns. The name only: a message carries quoting and, for some builtins, the repr of an argument, neither of which is worth pinning across two arms. """ try: fn(*args, **kw) except BaseException as exc: return type(exc).__name__ return 'none' # ------------------------------------------------------------------ import --- # Pure Python, so this is expected to be uneventful -- but it is the first thing # that runs on this arm and every case below depends on it. try: import constantly emit('import_ok', 'yes') emit('import_error', '') except BaseException as exc: emit('import_ok', 'no') emit('import_error', '%s: %s' % (type(exc).__name__, str(exc).replace('\n', ' ')[:200])) emit('emitted_count', str(len(emitted) + 1)) emit('probe_done', 'yes') sys.exit(0) from constantly import ( # noqa: E402 (after the gate, by design) NamedConstant, Names, ValueConstant, Values, FlagConstant, Flags, ) # ---------------------------------------------------------------- identity --- # WHICH COPY ANSWERED. Without this, every case below would be a statement about # whatever was first on sys.path. `module_file' differs between the control and # the target by construction, so the suite asserts its SHAPE rather than # comparing it against a control value. emit('module_file', getattr(constantly, '__file__', '')) emit('is_package', 'yes' if str(getattr(constantly, '__file__', '')).endswith('__init__.py') else 'no') # THE VERSION IS COMPUTED, NOT WRITTEN. `__init__.py' does # `_version.get_versions()["version"]', and `_version.py' is a file versioneer # GENERATES -- the sdist ships a pre-baked copy, and the build regenerates it. # So `version_attr' agreeing with `dist_version' says the wheel was cut from the # source this module is, and `version_json_version' says the generated file # itself carries the same string rather than a `0+unknown' fallback, which is # what a versioneer that could not work out a version emits instead. _va = getattr(constantly, '__version__', 'MISSING') emit('version_attr', _va) _dv = 'ERR:not-read' try: from importlib.metadata import version as _mv _dv = _mv('constantly') except BaseException as exc: _dv = 'ERR:%s' % type(exc).__name__ emit('dist_version', _dv) emit('version_agrees', 'yes' if _va == _dv else 'no') # THE VERSIONEER PAYLOAD, read through the module rather than off the file. Its # four other keys are as much a part of what the build produced as the version # is: `error' is what versioneer sets when it fell back, and a non-null one with # a `0+unknown' version is the shape of a build that did not know its own # version. try: from constantly import _version as _vmod _vg = _vmod.get_versions() emit('version_json_version', _vg.get('version', 'MISSING')) emit('version_json_error', 'null' if _vg.get('error') is None else str(_vg.get('error')).replace('\n', ' ')[:120]) emit('version_json_dirty', r(_vg.get('dirty'))) emit('version_json_keys', ','.join(sorted(_vg.keys()))) except BaseException as exc: emit('version_json_version', 'ERR:%s' % type(exc).__name__) emit('version_json_error', 'ERR') emit('version_json_dirty', 'ERR') emit('version_json_keys', 'ERR') # `__all__' IS THE PUBLIC SURFACE, a hand-maintained list in `__init__.py'. # Pinned joined so that a name that appeared and a name that went are each one # red rather than a renumbering of six cases. _all = list(getattr(constantly, '__all__', ())) emit('all_count', str(len(_all))) emit('all_names', ','.join(_all)) # Every promised name is bound. `from constantly import *' is what a consumer # writes, and it is the star import -- not the module import above -- that a # broken `__all__' breaks. emit('all_bound', 'yes' if all(hasattr(constantly, n) for n in _all) else 'no') # `_constants.__all__' IS EMPTY, DELIBERATELY. The private module exports # nothing by star import; `__init__.py' names the six explicitly. Asserted so a # release that started populating it is visible, since that would change what # `from constantly._constants import *' does for anyone who writes it. from constantly import _constants as _c # noqa: E402 emit('private_all', r(list(getattr(_c, '__all__', ['MISSING'])))) # The three dunder strings `__init__.py' sets beside the version. `__copyright__' # is FORMATTED from `__author__' at import time, so pinning it asserts that the # format ran rather than that a literal is present. emit('author', getattr(constantly, '__author__', 'MISSING')) emit('license', getattr(constantly, '__license__', 'MISSING')) emit('copyright', getattr(constantly, '__copyright__', 'MISSING')) # ------------------------------------------------------------------- Names --- # THE SIMPLEST CONTAINER: constants that differ only in name and identity. class Colour(Names): RED = NamedConstant() GREEN = NamedConstant() BLUE = NamedConstant() # THE CONTAINER IS THE CLASS OBJECT and is never instantiated -- `__new__' raises # outright. A consumer who writes `Colour()' has misunderstood the API, and # this is where that is stated. emit('names_instantiate', err(Colour)) # `iterconstants()' YIELDS DECLARATION ORDER, which is the package's central # promise: `_index' is drawn from a process-global counter at construction time, # and the sort in `iterconstants' is what turns that into a stable order. Note # the source order here is RED, GREEN, BLUE while `attributes.items()' in the # metaclass is a dict -- so this case would still pass if it were accidentally # insertion-ordered, and `names_iter_reversed' below is the one that would not. emit('names_iter', ','.join(c.name for c in Colour.iterconstants())) emit('names_iter_count', str(len(list(Colour.iterconstants())))) emit('names_iter_repeatable', 'yes' if [c.name for c in Colour.iterconstants()] == [c.name for c in Colour.iterconstants()] else 'no') class Reversed(Names): # Declared out of alphabetical order ON PURPOSE: an implementation that # sorted by NAME rather than by instantiation index would pass `names_iter' # above and fail here. ZULU = NamedConstant() ALPHA = NamedConstant() MIKE = NamedConstant() emit('names_iter_reversed', ','.join(c.name for c in Reversed.iterconstants())) # THE REPR IS `'. It is NOT `Container.name': the ticket text # describes the dotted form and the implementation has never produced it # (`_Constant.__repr__' is `"<%s=%s>" % (self._container.__name__, self.name)'). # Pinned here so the documented form is the measured one. emit('names_repr', r(Colour.RED)) emit('names_repr_str', str(Colour.RED)) emit('names_name_attr', Colour.RED.name) emit('names_container', Colour.RED._container.__name__) emit('names_is_namedconstant', 'yes' if isinstance(Colour.RED, NamedConstant) else 'no') # A NamedConstant HAS NO `value'. `_constantFactory' hands `_realize' a sentinel # and `_Constant._realize' throws it away, so the attribute is absent rather than # None -- which is the difference between `Names' and `Values' stated as a fact # about an instance. emit('names_has_value', 'yes' if hasattr(Colour.RED, 'value') else 'no') # ATTRIBUTE ACCESS RETURNS THE SAME OBJECT EVERY TIME. The constants are plain # class attributes after realization, not descriptors that build on access, so # identity -- not just equality -- is what a consumer may rely on. emit('names_identity', 'yes' if Colour.RED is Colour.RED else 'no') emit('names_lookup', Colour.lookupByName('GREEN').name) emit('names_lookup_is', 'yes' if Colour.lookupByName('GREEN') is Colour.GREEN else 'no') emit('names_lookup_missing', err(Colour.lookupByName, 'PUCE')) # `lookupByName' READS `_enumerants', NOT the class dictionary, so an ordinary # class attribute that is not a constant is NOT reachable through it. This is # the case that says the container knows which of its attributes are constants. emit('names_lookup_nonconstant', err(Colour.lookupByName, 'iterconstants')) # `_enumerants' is the dict the metaclass saved: names to constants, constants # only. emit('names_enumerants_keys', ','.join(sorted(Colour._enumerants.keys()))) emit('names_enumerants_count', str(len(Colour._enumerants))) class WithExtras(Names): ONE = NamedConstant() TWO = NamedConstant() NOT_A_CONSTANT = "just a string" @classmethod def helper(cls): return 'helper' # A CONTAINER MAY CARRY ORDINARY ATTRIBUTES AND METHODS, and they stay ordinary: # reachable as themselves, absent from `iterconstants()' and from `_enumerants'. emit('extras_iter', ','.join(c.name for c in WithExtras.iterconstants())) emit('extras_attr', WithExtras.NOT_A_CONSTANT) emit('extras_method', WithExtras.helper()) emit('extras_enumerants', ','.join(sorted(WithExtras._enumerants.keys()))) # REUSING A REALIZED CONSTANT IN A SECOND CONTAINER IS A ValueError, raised at # CLASS CREATION TIME by the metaclass. A constant remembers its container, and # this is the check that keeps two containers from sharing one identity. _reuse = Colour.RED def _make_reuser(): class Reuser(Names): RED = _reuse return Reuser emit('names_reuse', err(_make_reuser)) # AN UNREALIZED CONSTANT AT MODULE SCOPE IS LEGAL AND STAYS UNREALIZED. Nothing # realizes a `NamedConstant' but a container class body, so one built loose has # `_container' None and no `name' -- and its repr therefore RAISES rather than # returning a string, because `__repr__' reads `self._container.__name__'. That # is upstream's behaviour, not this port's, and it is asserted because a loose # constant is what a consumer produces by accident. _loose = NamedConstant() emit('loose_container', r(_loose._container)) emit('loose_has_name', 'yes' if hasattr(_loose, 'name') else 'no') emit('loose_repr_raises', err(repr, _loose)) # ------------------------------------------------------------------ Values --- class Status(Values): OK = ValueConstant(200) NOT_FOUND = ValueConstant(404) ERROR = ValueConstant(500) emit('values_iter', ','.join(c.name for c in Status.iterconstants())) emit('values_iter_values', ','.join(str(c.value) for c in Status.iterconstants())) emit('values_repr', r(Status.OK)) emit('values_value', str(Status.OK.value)) emit('values_is_valueconstant', 'yes' if isinstance(Status.OK, ValueConstant) else 'no') # `Values' IS A `_ConstantsContainer' LIKE `Names', so everything asserted about # Names holds here too; the two cases below are the ones that would notice if # `Values' had grown its own `lookupByName' that did something else. emit('values_lookup_by_name', Status.lookupByName('ERROR').name) emit('values_lookup_by_name_missing', err(Status.lookupByName, 'TEAPOT')) emit('values_lookup', Status.lookupByValue(404).name) emit('values_lookup_is', 'yes' if Status.lookupByValue(404) is Status.NOT_FOUND else 'no') emit('values_lookup_missing', err(Status.lookupByValue, 418)) class Duplicated(Values): FIRST = ValueConstant('same') SECOND = ValueConstant('same') THIRD = ValueConstant('other') # `lookupByValue' RETURNS THE FIRST BY DECLARATION ORDER, not by dictionary # order and not an error. It walks `iterconstants()' and returns on the first # match, so a duplicated value resolves to the constant declared earliest -- # which is a documented behaviour and the reason the walk is over the sorted # iterator rather than over `_enumerants.values()'. emit('values_dup_first', Duplicated.lookupByValue('same').name) emit('values_dup_is_first', 'yes' if Duplicated.lookupByValue('same') is Duplicated.FIRST else 'no') # THE VALUE MAY BE ANY OBJECT. `_constantFactory' does not touch it and # `lookupByValue' compares with `==', so the container is not restricted to # ints or strings -- and a value that is unhashable is fine too, since nothing # here puts a value in a dict. class Mixed(Values): TEXT = ValueConstant('a string') NUMBER = ValueConstant(7) TUPLE = ValueConstant((1, 2)) LIST = ValueConstant([3, 4]) NOTHING = ValueConstant(None) emit('values_mixed_text', Mixed.lookupByValue('a string').name) emit('values_mixed_tuple', Mixed.lookupByValue((1, 2)).name) emit('values_mixed_list', Mixed.lookupByValue([3, 4]).name) emit('values_mixed_none', Mixed.lookupByValue(None).name) emit('values_mixed_number', Mixed.lookupByValue(7).name) # `==' AND NOT `is': `lookupByValue(7)' finds a constant built with `7', and # `True == 1' in Python -- so a `Values' whose values are 1 and True would be # ambiguous. Emitted as the measured consequence rather than as a warning. emit('values_bool_int', Mixed.lookupByValue(7.0).name) # ------------------------------------------------------------------- Flags --- class Perm(Flags): READ = FlagConstant() WRITE = FlagConstant() EXEC = FlagConstant() # THE VALUES ARE SUCCESSIVE POWERS OF TWO, assigned by `Flags._constantFactory' # from a per-class counter that starts at 1. Nothing in the class body says so. emit('flags_values', ','.join(str(c.value) for c in Perm.iterconstants())) emit('flags_iter', ','.join(c.name for c in Perm.iterconstants())) emit('flags_read_value', str(Perm.READ.value)) emit('flags_exec_value', str(Perm.EXEC.value)) emit('flags_repr', r(Perm.READ)) emit('flags_names_set', ','.join(sorted(Perm.READ.names))) emit('flags_is_flagconstant', 'yes' if isinstance(Perm.READ, FlagConstant) else 'no') # `Flags' SUBCLASSES `Values', which is why a flag has `.value' and why # `lookupByValue' is available on it. emit('flags_is_values_subclass', 'yes' if issubclass(Perm, Values) else 'no') class Explicit(Flags): A = FlagConstant(4) B = FlagConstant() C = FlagConstant() # AN EXPLICIT VALUE RESETS THE COUNTER to twice itself, so the flags declared # after it continue from there rather than from where they would have been. # This is the one branch in `_constantFactory' and it is not obvious from the # class body. emit('flags_explicit_values', ','.join(str(c.value) for c in Explicit.iterconstants())) # ---- the operators ---- _rw = Perm.READ | Perm.WRITE emit('flags_or_value', str(_rw.value)) emit('flags_or_names', ','.join(sorted(_rw.names))) # THE COMPOSITE'S `name' IS A BRACED, SORTED JOIN -- `_realize' builds it when # more than one name applies -- so the repr of a composite is `' # with the names in ALPHABETICAL order, not in declaration order. That is a real # asymmetry with `iterconstants()' and it is asserted rather than assumed. emit('flags_or_name', _rw.name) emit('flags_or_repr', r(_rw)) emit('flags_or_is_flagconstant', 'yes' if isinstance(_rw, FlagConstant) else 'no') emit('flags_or_container', _rw._container.__name__) _all_three = Perm.READ | Perm.WRITE | Perm.EXEC emit('flags_or_three_value', str(_all_three.value)) emit('flags_or_three_name', _all_three.name) _and = _rw & Perm.WRITE emit('flags_and_value', str(_and.value)) emit('flags_and_name', _and.name) # `&' DOWN TO ONE FLAG PRODUCES A SINGLE-NAME COMPOSITE, and its `name' is the # bare name rather than a braced one -- the `len(names) == 1' branch in # `_realize'. It is a NEW object, not the original constant: equal by value, # distinct by identity. emit('flags_and_is_write', 'yes' if _and is Perm.WRITE else 'no') emit('flags_and_repr', r(_and)) _none = Perm.READ & Perm.EXEC emit('flags_and_empty_value', str(_none.value)) emit('flags_and_empty_name', _none.name) emit('flags_and_empty_bool', r(bool(_none))) _xor = _rw ^ Perm.WRITE emit('flags_xor_value', str(_xor.value)) emit('flags_xor_name', _xor.name) _xor2 = Perm.READ ^ Perm.EXEC emit('flags_xor_two_value', str(_xor2.value)) emit('flags_xor_two_name', _xor2.name) _inv = ~Perm.READ emit('flags_invert_value', str(_inv.value)) emit('flags_invert_name', _inv.name) # `~' IS BOUNDED BY THE CONTAINER, not by the machine word: `__invert__' walks # `iterconstants()' and ORs in every flag not set here, so the result can never # carry a bit the container does not define. On a C bitvector this is where a # pointer width would show; here it cannot, and that is the point. _inv_all = ~_all_three emit('flags_invert_all_value', str(_inv_all.value)) emit('flags_invert_all_name', _inv_all.name) emit('flags_invert_all_bool', r(bool(_inv_all))) # ---- membership and iteration over a composite ---- emit('flags_contains_read', r(Perm.READ in _rw)) emit('flags_contains_exec', r(Perm.EXEC in _rw)) emit('flags_contains_self', r(Perm.READ in Perm.READ)) emit('flags_iter_composite', ','.join(sorted(f.name for f in _rw))) emit('flags_iter_composite_count', str(len(list(_rw)))) # ITERATING A COMPOSITE YIELDS THE CONTAINER'S OWN CONSTANTS, resolved by name # through `lookupByName' -- so the objects that come out are identical to the # class attributes rather than copies. emit('flags_iter_identity', 'yes' if all(f is getattr(Perm, f.name) for f in _rw) else 'no') emit('flags_iter_single', ','.join(f.name for f in Perm.READ)) emit('flags_bool_true', r(bool(Perm.READ))) emit('flags_bool_composite', r(bool(_rw))) emit('flags_lookup_by_value', Perm.lookupByValue(2).name) # `lookupByValue' OVER A COMPOSITE VALUE IS A ValueError. The composite is not # in `_enumerants' -- it was never in a class body -- so the walk finds nothing. emit('flags_lookup_composite', err(Perm.lookupByValue, 3)) emit('flags_lookup_by_name', Perm.lookupByName('WRITE').name) # -------------------------------------------------- across two containers --- class Left(Names): ONE = NamedConstant() TWO = NamedConstant() class Right(Names): ONE = NamedConstant() TWO = NamedConstant() # CONSTANTS FROM TWO CONTAINERS NEVER COMPARE EQUAL, even with the same name in # the same position. `_Constant' defines no `__eq__', so equality is identity -- # which is the strongest form this could take and the one a consumer relies on # when two enumerations coexist. emit('cross_eq', r(Left.ONE == Right.ONE)) emit('cross_ne', r(Left.ONE != Right.ONE)) emit('cross_same_name', r(Left.ONE.name == Right.ONE.name)) emit('cross_hash_distinct', 'yes' if len({Left.ONE, Right.ONE, Left.TWO, Right.TWO}) == 4 else 'no') # ORDERING ACROSS CONTAINERS RAISES. `__lt__' and its three siblings return # `NotImplemented' when the containers differ, and Python turns a pair of # NotImplementeds into a TypeError -- so a cross-container `<' is an error rather # than a silent answer drawn from the shared instantiation counter. That counter # would otherwise give a perfectly plausible wrong answer, which is what makes # this the important half of the cross-container contract. emit('cross_lt', err(lambda: Left.ONE < Right.ONE)) emit('cross_gt', err(lambda: Left.ONE > Right.ONE)) emit('cross_le', err(lambda: Left.ONE <= Right.ONE)) emit('cross_ge', err(lambda: Left.ONE >= Right.ONE)) # AGAINST A NON-CONSTANT TOO: the same guard covers `3', which is what a # consumer comparing a constant to a raw value gets. emit('cross_lt_int', err(lambda: Left.ONE < 3)) # WITHIN ONE CONTAINER, ORDER IS DECLARATION ORDER and the four operators agree # with it. `<=' and `>=' are identity-or-index rather than index-or-equal, so # the reflexive cases are asserted separately. emit('within_lt', r(Left.ONE < Left.TWO)) emit('within_gt', r(Left.TWO > Left.ONE)) emit('within_le_self', r(Left.ONE <= Left.ONE)) emit('within_ge_self', r(Left.ONE >= Left.ONE)) emit('within_lt_self', r(Left.ONE < Left.ONE)) emit('within_sorted', ','.join(c.name for c in sorted([Left.TWO, Left.ONE]))) # A CONSTANT IS ITS OWN TYPE, NOT A str OR AN int. `NamedConstant' subclasses # `object' and nothing else, so none of the implicit conversions a consumer # might expect from an enum library exist here. emit('type_not_str', 'yes' if not isinstance(Left.ONE, str) else 'no') emit('type_not_int', 'yes' if not isinstance(Perm.READ, int) else 'no') emit('type_mro', ','.join(k.__name__ for k in type(Colour.RED).__mro__)) emit('flag_type_mro', ','.join(k.__name__ for k in type(Perm.READ).__mro__)) # THE PUBLIC TYPES ARE NOT CONTAINERS AND THE CONTAINERS ARE NOT CONSTANTS. # `Names', `Values' and `Flags' are classes a consumer SUBCLASSES; the base # classes themselves carry no constants, and a bare `Names' has an empty # `_enumerants' rather than no attribute at all. emit('base_names_enumerants', str(len(Names._enumerants))) emit('base_values_enumerants', str(len(Values._enumerants))) emit('base_flags_enumerants', str(len(Flags._enumerants))) emit('base_constant_types', ','.join([Names._constantType.__name__, Values._constantType.__name__, Flags._constantType.__name__])) # --------------------------------------------------- the shipped test suite --- # UPSTREAM SHIPS ITS OWN TESTS INSIDE THE PACKAGE. `constantly/test/' is a # subpackage the wheel carries, and whether it lands on target is a PACKAGING # fact this probe can measure from the inside. Its contents are not run here: # they are a `unittest' suite and running them would be a second measurement of # CPython, not of this port. What is asserted is that the subpackage imports # and that the module the whole package is annotated with # (`test-case-name: constantly.test.test_constants') is reachable. try: import constantly.test as _t emit('test_pkg_import', 'yes') emit('test_pkg_file', getattr(_t, '__file__', '')) except BaseException as exc: emit('test_pkg_import', 'no:%s' % type(exc).__name__) emit('test_pkg_file', '') try: import constantly.test.test_constants as _tc emit('test_mod_import', 'yes') emit('test_mod_classes', str(len([n for n in dir(_tc) if n.endswith('Tests')]))) except BaseException as exc: emit('test_mod_import', 'no:%s' % type(exc).__name__) emit('test_mod_classes', '') # ------------------------------------------------------------- the arm --- # THE ONE VALUE THAT SAYS WHICH INTERPRETER ANSWERED. Everything else above # would read identically from a host copy of the module; `maxsize' is 2**31-1 on # this wasm32 target and 2**63-1 on the x86-64 control, so this is what makes the # transcript attributable. `py_version' is pinned because every expectation # above was measured under CPython 3.12 and a different minor would make them # claims about a version nobody measured. emit('py_version', '%d.%d' % sys.version_info[:2]) emit('py_maxsize_bits', str(sys.maxsize.bit_length() + 1)) emit('py_platform', sys.platform) # The probe emitted every key it intended to. A probe that returned 0 having # skipped a section would otherwise be indistinguishable from one that ran whole. emit('emitted_count', str(len(emitted) + 2)) emit('probe_done', 'yes')