[pypy-commit] pypy default: Add translation option --hash=siphash24
Author: Armin Rigo Branch: Changeset: r89776:ccc88590dc02 Date: 2017-01-26 09:30 +0100 http://bitbucket.org/pypy/pypy/changeset/ccc88590dc02/ Log:Add translation option --hash=siphash24 diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -201,6 +201,10 @@ StrOption("icon", "Path to the (Windows) icon to use for the executable"), StrOption("libname", "Windows: name and possibly location of the lib file to create"), +ChoiceOption("hash", + "The hash to use for strings", + ["rpython", "siphash24"], + default="rpython", cmdline="--hash"), OptionDescription("backendopt", "Backend Optimization Options", [ # control inlining @@ -390,6 +394,12 @@ if sys.platform == "darwin" or sys.platform =="win32": raise ConfigError("'asmgcc' not supported on this platform") +def apply_extra_settings(config): +# make the setting of config.hash definitive +from rpython.rlib.objectmodel import set_hash_algorithm +config.translation.hash = config.translation.hash +set_hash_algorithm(config.translation.hash) + # def set_platform(config): diff --git a/rpython/translator/goal/translate.py b/rpython/translator/goal/translate.py --- a/rpython/translator/goal/translate.py +++ b/rpython/translator/goal/translate.py @@ -11,7 +11,8 @@ from rpython.config.config import (to_optparse, OptionDescription, BoolOption, ArbitraryOption, StrOption, IntOption, Config, ChoiceOption, OptHelpFormatter) from rpython.config.translationoption import (get_combined_translation_config, -set_opt_level, OPT_LEVELS, DEFAULT_OPT_LEVEL, set_platform, CACHE_DIR) +set_opt_level, OPT_LEVELS, DEFAULT_OPT_LEVEL, set_platform, CACHE_DIR, +apply_extra_settings) # clean up early rpython/_cache try: @@ -177,6 +178,9 @@ if 'handle_config' in targetspec_dic: targetspec_dic['handle_config'](config, translateconfig) +# apply extra settings +apply_extra_settings(config) + return targetspec_dic, translateconfig, config, args def show_help(translateconfig, opt_parser, targetspec_dic, config): ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy py3.5: hg merge default
Author: Armin Rigo Branch: py3.5 Changeset: r89777:ad1beddd3f43 Date: 2017-01-26 09:34 +0100 http://bitbucket.org/pypy/pypy/changeset/ad1beddd3f43/ Log:hg merge default diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -311,8 +311,8 @@ if config.objspace.usemodules.cpyext: if config.translation.gc not in ('incminimark', 'boehm'): raise Exception("The 'cpyext' module requires the 'incminimark'" -" 'boehm' GC. You need either 'targetpypystandalone.py" -" --withoutmod-cpyext' or '--gc=incminimark'") +" or 'boehm' GC. You need either 'targetpypystandalone.py" +" --withoutmod-cpyext', or use one of these two GCs.") config.translating = True diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -323,17 +323,28 @@ # return self._add_or_sub(w_other, -1) -def getcfield(self, w_attr): -return self.ctype.getcfield(self.space.str_w(w_attr)) +def getcfield(self, w_attr, mode): +space = self.space +attr = space.str_w(w_attr) +try: +cfield = self.ctype.getcfield(attr) +except KeyError: +raise oefmt(space.w_AttributeError, "cdata '%s' has no field '%s'", +self.ctype.name, attr) +if cfield is None: +raise oefmt(space.w_AttributeError, +"cdata '%s' points to an opaque type: cannot %s fields", +self.ctype.name, mode) +return cfield def getattr(self, w_attr): -cfield = self.getcfield(w_attr) +cfield = self.getcfield(w_attr, mode="read") with self as ptr: w_res = cfield.read(ptr, self) return w_res def setattr(self, w_attr, w_value): -cfield = self.getcfield(w_attr) +cfield = self.getcfield(w_attr, mode="write") with self as ptr: cfield.write(ptr, w_value) diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -348,7 +348,10 @@ return result def getcfield(self, attr): -return self.ctitem.getcfield(attr) +from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion +if isinstance(self.ctitem, W_CTypeStructOrUnion): +return self.ctitem.getcfield(attr) +return W_CType.getcfield(self, attr) def typeoffsetof_field(self, fieldname, following): if following == 0: diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py --- a/pypy/module/_cffi_backend/ctypestruct.py +++ b/pypy/module/_cffi_backend/ctypestruct.py @@ -161,18 +161,18 @@ return self._fields_dict[attr] def getcfield(self, attr): -ready = self._fields_dict is not None -if not ready and self.size >= 0: +# Returns a W_CField. Error cases: returns None if we are an +# opaque struct; or raises KeyError if the particular field +# 'attr' does not exist. The point of not directly building the +# error here is to get the exact ctype in the error message: it +# might be of the kind 'struct foo' or 'struct foo *'. +if self._fields_dict is None: +if self.size < 0: +return None self.force_lazy_struct() -ready = True -if ready: -self = jit.promote(self) -attr = jit.promote_string(attr) -try: -return self._getcfield_const(attr) -except KeyError: -pass -return W_CType.getcfield(self, attr) +self = jit.promote(self) +attr = jit.promote_string(attr) +return self._getcfield_const(attr)# <= KeyError here def cdata_dir(self): if self.size < 0: diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -737,8 +737,14 @@ BInt = new_primitive_type("int") BStruct = new_struct_type("struct foo") BStructPtr = new_pointer_type(BStruct) -p = cast(BStructPtr, 0) -py.test.raises(AttributeError, "p.a1")# opaque +p = cast(BStructPtr, 42) +e = py.test.raises(AttributeError, "p.a1")# opaque +assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: " +"cannot read fields") +e = py.test.raises(AttributeError, "p.a1 = 10")# opaque +
[pypy-commit] pypy py3.5: change the default for the --hash option in py3.5
Author: Armin Rigo Branch: py3.5 Changeset: r89778:45239e9d6953 Date: 2017-01-26 09:42 +0100 http://bitbucket.org/pypy/pypy/changeset/45239e9d6953/ Log:change the default for the --hash option in py3.5 diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -229,6 +229,10 @@ raise Exception("You have to specify the --opt level.\n" "Try --opt=2 or --opt=jit, or equivalently -O2 or -Ojit .") self.translateconfig = translateconfig + +# change the default for this option +config.translation.suggest(hash="siphash24") + # set up the objspace optimizations based on the --opt argument from pypy.config.pypyoption import set_pypy_opt_level set_pypy_opt_level(config, translateconfig.opt) ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy py3.5: revert to the default of --hash=rpython
Author: Armin Rigo Branch: py3.5 Changeset: r89780:1921e9b65a21 Date: 2017-01-26 09:52 +0100 http://bitbucket.org/pypy/pypy/changeset/1921e9b65a21/ Log:revert to the default of --hash=rpython diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -231,7 +231,9 @@ self.translateconfig = translateconfig # change the default for this option -config.translation.suggest(hash="siphash24") +# XXX disabled until we fix the real problem: a per-translation +# seed for siphash is bad +#config.translation.suggest(hash="siphash24") # set up the objspace optimizations based on the --opt argument from pypy.config.pypyoption import set_pypy_opt_level ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: Document the problem (thanks njs)
Author: Armin Rigo Branch: Changeset: r89779:1042ceb32763 Date: 2017-01-26 09:51 +0100 http://bitbucket.org/pypy/pypy/changeset/1042ceb32763/ Log:Document the problem (thanks njs) diff --git a/rpython/rlib/rsiphash.py b/rpython/rlib/rsiphash.py --- a/rpython/rlib/rsiphash.py +++ b/rpython/rlib/rsiphash.py @@ -21,6 +21,9 @@ # that as easily because many details may rely on getting the same hash # value before and after translation. We can, however, pick a random # seed once per translation, which should already be quite good. +# +# XXX no, it is not: e.g. all Ubuntu installations of the same Ubuntu +# would get the same seed. That's not good enough. @not_rpython def select_random_seed(): ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: fix test
Author: Armin Rigo Branch: Changeset: r89781:8ecc4591e7ec Date: 2017-01-26 10:02 +0100 http://bitbucket.org/pypy/pypy/changeset/8ecc4591e7ec/ Log:fix test diff --git a/pypy/interpreter/test/test_appinterp.py b/pypy/interpreter/test/test_appinterp.py --- a/pypy/interpreter/test/test_appinterp.py +++ b/pypy/interpreter/test/test_appinterp.py @@ -23,7 +23,9 @@ (): y y """) -assert str(excinfo.value.errorstr(space)).find('y y') != -1 +# NOTE: the following test only works because excinfo.value is not +# normalized so far +assert str(excinfo.value.get_w_value(space)).find('y y') != -1 def test_simple_applevel(space): app = appdef("""app(x,y): ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: Fix
Author: Armin Rigo Branch: Changeset: r89782:9eb7c2912413 Date: 2017-01-26 10:13 +0100 http://bitbucket.org/pypy/pypy/changeset/9eb7c2912413/ Log:Fix diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -71,7 +71,8 @@ def errorstr(self, space, use_repr=False): "The exception class and value, as a string." -self.normalize_exception(space) +if not use_repr:# see write_unraisable() +self.normalize_exception(space) w_value = self.get_w_value(space) if space is None: # this part NOT_RPYTHON @@ -262,6 +263,11 @@ traceback.print_exception(t, v, tb) """) else: +# Note that like CPython, we don't normalize the +# exception here. So from `'foo'.index('bar')` you get +# "Exception ValueError: 'substring not found' in x ignored" +# but from `raise ValueError('foo')` you get +# "Exception ValueError: ValueError('foo',) in x ignored" msg = 'Exception %s in %s%s ignored\n' % ( self.errorstr(space, use_repr=True), where, objrepr) space.call_method(space.sys.get('stderr'), 'write', ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: complain clearly if set_source() is given a /-separated name
Author: Armin Rigo Branch: Changeset: r2875:510280ce4cc4 Date: 2017-01-26 11:14 +0100 http://bitbucket.org/cffi/cffi/changeset/510280ce4cc4/ Log:complain clearly if set_source() is given a /-separated name diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -593,11 +593,15 @@ ensure('extra_link_args', '/MANIFEST') def set_source(self, module_name, source, source_extension='.c', **kwds): +import os if hasattr(self, '_assigned_source'): raise ValueError("set_source() cannot be called several times " "per ffi object") if not isinstance(module_name, basestring): raise TypeError("'module_name' must be a string") +if os.sep in module_name or (os.altsep and os.altsep in module_name): +raise ValueError("'module_name' must not contain '/': use a dotted " + "name to make a 'package.module' location") self._assigned_source = (str(module_name), source, source_extension, kwds) diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -36,6 +36,11 @@ ['-Werror']) return recompiler._verify(ffi, module_name, source, *args, **kwds) +def test_set_source_no_slashes(): +ffi = FFI() +py.test.raises(ValueError, ffi.set_source, "abc/def", None) +py.test.raises(ValueError, ffi.set_source, "abc/def", "C code") + def test_type_table_func(): check_type_table("double sin(double);", ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy rpython-hash: A quick disable of the hash-preservation logic, fix a few tests
Author: Armin Rigo Branch: rpython-hash Changeset: r89784:11355355dff6 Date: 2017-01-26 12:26 +0100 http://bitbucket.org/pypy/pypy/changeset/11355355dff6/ Log:A quick disable of the hash-preservation logic, fix a few tests diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py --- a/rpython/memory/gctransform/boehm.py +++ b/rpython/memory/gctransform/boehm.py @@ -11,7 +11,7 @@ class BoehmGCTransformer(GCTransformer): malloc_zero_filled = True FINALIZER_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Void)) -HDR = lltype.Struct("header", ("hash", lltype.Signed)) +HDR = lltype.Struct("header") def __init__(self, translator, inline=False): super(BoehmGCTransformer, self).__init__(translator, inline=inline) @@ -33,9 +33,7 @@ def ll_identityhash(addr): obj = llmemory.cast_adr_to_ptr(addr, HDRPTR) -h = obj.hash -if h == 0: -obj.hash = h = ~llmemory.cast_adr_to_int(addr) +h = ~llmemory.cast_adr_to_int(addr) return h if self.translator: @@ -196,7 +194,7 @@ def gcheader_initdata(self, obj): hdr = lltype.malloc(self.HDR, immortal=True) -hdr.hash = lltype.identityhash_nocache(obj._as_ptr()) +#hdr.hash = lltype.identityhash_nocache(obj._as_ptr()) return hdr._obj diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -1518,7 +1518,7 @@ hdr = self.gc_header_for(o, needs_hash) return hdr._obj -def get_prebuilt_hash(self, obj): +def DISABLED_get_prebuilt_hash(self, obj): # for prebuilt objects that need to have their hash stored and # restored. Note that only structures that are StructNodes all # the way have their hash stored (and not e.g. structs with var- diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py --- a/rpython/translator/c/node.py +++ b/rpython/translator/c/node.py @@ -663,6 +663,7 @@ def gcstructnode_factory(db, T, obj): if (db.gctransformer and db.gctransformer.get_prebuilt_hash(obj) is not None): +DISABLED cls = GcStructNodeWithHash else: cls = StructNode diff --git a/rpython/translator/c/test/test_boehm.py b/rpython/translator/c/test/test_boehm.py --- a/rpython/translator/c/test/test_boehm.py +++ b/rpython/translator/c/test/test_boehm.py @@ -381,7 +381,7 @@ current_object_addr_as_int(d2), compute_hash(c), compute_hash(d), -compute_hash(("Hi", None, (7.5, 2, d) +compute_hash(("Hi", None, (7.5, 2) f = self.getcompiled(fn) res = f() @@ -390,8 +390,10 @@ # xxx the next line is too precise, checking the exact implementation assert res[0] == ~res[1] assert res[2] != compute_hash(c) # likely -assert res[3] == compute_hash(d) -assert res[4] == compute_hash(("Hi", None, (7.5, 2, d))) +assert res[3] != compute_hash(d) # likely *not* preserved +assert res[4] == compute_hash(("Hi", None, (7.5, 2))) +# ^^ true as long as we're using the 'rpython' hash for strings +#and not e.g. siphash24 def test_finalizer_queue(self): class A(object): diff --git a/rpython/translator/c/test/test_newgc.py b/rpython/translator/c/test/test_newgc.py --- a/rpython/translator/c/test/test_newgc.py +++ b/rpython/translator/c/test/test_newgc.py @@ -780,7 +780,7 @@ c = C() d = D() h_d = compute_hash(d) # force to be cached on 'd', but not on 'c' -h_t = compute_hash(("Hi", None, (7.5, 2, d))) +h_t = compute_hash(("Hi", None, (7.5, 2))) S = lltype.GcStruct('S', ('x', lltype.Signed), ('a', lltype.Array(lltype.Signed))) s = lltype.malloc(S, 15, zero=True) @@ -789,10 +789,10 @@ def f(): if compute_hash(c) != compute_identity_hash(c): return 12 -if compute_hash(d) != h_d: +if compute_hash(d) == h_d: # likely *not* preserved return 13 -if compute_hash(("Hi", None, (7.5, 2, d))) != h_t: -return 14 +if compute_hash(("Hi", None, (7.5, 2))) != h_t: +return 14 # ^^ true as long as we're not using e.g. siphash24 c2 = C() h_c2 = compute_hash(c2) if compute_hash(c2) != h_c2: diff --git a/rpython/translator/c/test/test_typed.py b/rpython/translator/c/test/test_typed.py --- a/rpython/translator/c/test/test_typed.py +++ b/rpython/translator/c/test/test_typed.py @@ -588,7 +588,7 @@ current_object_addr_as_int(d2),
[pypy-commit] pypy rpython-hash: A branch to try and remove the guarantee: "the rpython hash of any object doesn't change before and after translation"
Author: Armin Rigo Branch: rpython-hash Changeset: r89783:533fd2120ac6 Date: 2017-01-26 12:12 +0100 http://bitbucket.org/pypy/pypy/changeset/533fd2120ac6/ Log:A branch to try and remove the guarantee: "the rpython hash of any object doesn't change before and after translation" ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy rpython-hash: Disable support for explicitly non-ordered, non-empty prebuilt dicts
Author: Armin Rigo Branch: rpython-hash Changeset: r89785:ab8402f0c677 Date: 2017-01-26 12:35 +0100 http://bitbucket.org/pypy/pypy/changeset/ab8402f0c677/ Log:Disable support for explicitly non-ordered, non-empty prebuilt dicts diff --git a/rpython/rtyper/lltypesystem/rdict.py b/rpython/rtyper/lltypesystem/rdict.py --- a/rpython/rtyper/lltypesystem/rdict.py +++ b/rpython/rtyper/lltypesystem/rdict.py @@ -236,21 +236,14 @@ if self.r_rdict_hashfn.lowleveltype != lltype.Void: l_fn = self.r_rdict_hashfn.convert_const(dictobj.key_hash) l_dict.fnkeyhash = l_fn - -for dictkeycontainer, dictvalue in dictobj._dict.items(): -llkey = r_key.convert_const(dictkeycontainer.key) -llvalue = r_value.convert_const(dictvalue) -ll_dict_insertclean(l_dict, llkey, llvalue, -dictkeycontainer.hash) -return l_dict - +any_items = dictobj._dict.items() else: -for dictkey, dictvalue in dictobj.items(): -llkey = r_key.convert_const(dictkey) -llvalue = r_value.convert_const(dictvalue) -ll_dict_insertclean(l_dict, llkey, llvalue, -l_dict.keyhash(llkey)) -return l_dict +any_items = dictobj.items() +if any_items: +raise TyperError("found a prebuilt, explicitly non-ordered, " + "non-empty dict. it would require additional" + " support to rehash it at program start-up") +return l_dict def rtype_len(self, hop): v_dict, = hop.inputargs(self) ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy rpython-hash: in-progress: support dicts with no indexes
Author: Armin Rigo Branch: rpython-hash Changeset: r89786:73f39f5b582e Date: 2017-01-26 14:19 +0100 http://bitbucket.org/pypy/pypy/changeset/73f39f5b582e/ Log:in-progress: support dicts with no indexes diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -46,20 +46,25 @@ @jit.look_inside_iff(lambda d, key, hash, flag: jit.isvirtual(d)) @jit.oopspec('ordereddict.lookup(d, key, hash, flag)') def ll_call_lookup_function(d, key, hash, flag): -fun = d.lookup_function_no & FUNC_MASK -# This likely() here forces gcc to compile the check for fun == FUNC_BYTE -# first. Otherwise, this is a regular switch and gcc (at least 4.7) -# compiles this as a series of checks, with the FUNC_BYTE case last. -# It sounds minor, but it is worth 6-7% on a PyPy microbenchmark. -if likely(fun == FUNC_BYTE): -return ll_dict_lookup(d, key, hash, flag, TYPE_BYTE) -elif fun == FUNC_SHORT: -return ll_dict_lookup(d, key, hash, flag, TYPE_SHORT) -elif IS_64BIT and fun == FUNC_INT: -return ll_dict_lookup(d, key, hash, flag, TYPE_INT) -elif fun == FUNC_LONG: -return ll_dict_lookup(d, key, hash, flag, TYPE_LONG) -assert False +while True: +fun = d.lookup_function_no & FUNC_MASK +# This likely() here forces gcc to compile the check for fun==FUNC_BYTE +# first. Otherwise, this is a regular switch and gcc (at least 4.7) +# compiles this as a series of checks, with the FUNC_BYTE case last. +# It sounds minor, but it is worth 6-7% on a PyPy microbenchmark. +if likely(fun == FUNC_BYTE): +return ll_dict_lookup(d, key, hash, flag, TYPE_BYTE) +elif fun == FUNC_SHORT: +return ll_dict_lookup(d, key, hash, flag, TYPE_SHORT) +elif IS_64BIT and fun == FUNC_INT: +return ll_dict_lookup(d, key, hash, flag, TYPE_INT) +elif fun == FUNC_LONG: +return ll_dict_lookup(d, key, hash, flag, TYPE_LONG) +elif fun == FUNC_NO_INDEX: +ll_dict_create_index(d) +# then, retry +else: +assert False def get_ll_dict(DICTKEY, DICTVALUE, get_custom_eq_hash=None, DICT=None, ll_fasthash_function=None, ll_hash_function=None, @@ -254,7 +259,6 @@ llvalue = r_value.convert_const(dictvalue) _ll_dict_insertclean(l_dict, llkey, llvalue, dictkeycontainer.hash) -return l_dict else: for dictkey, dictvalue in dictobj.items(): @@ -262,7 +266,9 @@ llvalue = r_value.convert_const(dictvalue) _ll_dict_insertclean(l_dict, llkey, llvalue, l_dict.keyhash(llkey)) -return l_dict + +ll_remove_index(l_dict) +return l_dict def rtype_len(self, hop): v_dict, = hop.inputargs(self) @@ -458,17 +464,27 @@ IS_64BIT = sys.maxint != 2 ** 31 - 1 -FUNC_SHIFT = 2 -FUNC_MASK = 0x03 # two bits if IS_64BIT: -FUNC_BYTE, FUNC_SHORT, FUNC_INT, FUNC_LONG = range(4) +FUNC_SHIFT = 3 +FUNC_MASK = 0x07 # three bits +FUNC_NO_INDEX, FUNC_BYTE, FUNC_SHORT, FUNC_INT, FUNC_LONG = range(5) else: -FUNC_BYTE, FUNC_SHORT, FUNC_LONG = range(3) +FUNC_SHIFT = 2 +FUNC_MASK = 0x03 # two bits +FUNC_NO_INDEX, FUNC_BYTE, FUNC_SHORT, FUNC_LONG = range(4) TYPE_BYTE = rffi.UCHAR TYPE_SHORT = rffi.USHORT TYPE_INT = rffi.UINT TYPE_LONG = lltype.Unsigned +NULL = lltype.nullptr(llmemory.GCREF.TO) + +def ll_remove_index(d): +# Used in MemoryError situation, or when translating prebuilt dicts. +# Remove the index completely. +d.indexes = NULL +d.lookup_function_no = FUNC_NO_INDEX + def ll_malloc_indexes_and_choose_lookup(d, n): # keep in sync with ll_clear_indexes() below if n <= 256: @@ -503,22 +519,30 @@ rgc.ll_arrayclear(lltype.cast_opaque_ptr(DICTINDEX_INT, d.indexes)) elif fun == FUNC_LONG: rgc.ll_arrayclear(lltype.cast_opaque_ptr(DICTINDEX_LONG, d.indexes)) +elif fun == FUNC_NO_INDEX: +# nothing to clear in this case +ll_assert(not d.indexes, + "ll_clear_indexes: FUNC_NO_INDEX but d.indexes != NULL") else: assert False @jit.dont_look_inside def ll_call_insert_clean_function(d, hash, i): -fun = d.lookup_function_no & FUNC_MASK -if fun == FUNC_BYTE: -ll_dict_store_clean(d, hash, i, TYPE_BYTE) -elif fun == FUNC_SHORT: -ll_dict_store_clean(d, hash, i, TYPE_SHORT) -elif IS_64BIT and fun == FUNC_INT: -ll_dict_store_clean(d, hash, i, TYPE_INT) -elif fun == FUNC_LONG: -ll_dict_store_clean(d, hash, i, TYPE_LONG) -else: -assert False +while T
[pypy-commit] pypy rpython-hash: Fix test_memoryerror by using the most tight estimate in
Author: Armin Rigo Branch: rpython-hash Changeset: r89787:9a1928019d6b Date: 2017-01-26 14:54 +0100 http://bitbucket.org/pypy/pypy/changeset/9a1928019d6b/ Log:Fix test_memoryerror by using the most tight estimate in ll_dict_create_index. This value should have the same guarantee in real program: if we get out of memory inserting a new item, then the recreated index is still of the smaller size instead of being bigger (and then likely not fitting in memory either) diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -879,9 +879,15 @@ if d.num_live_items == 0: new_size = DICT_INITSIZE # fast path else: -new_estimate = d.num_live_items * 2 +# Use a more conservative estimate than _ll_dict_resize_to() here. +# This function is called when initially creating the index (so, +# for prebuilt dicts, the chance is that it will never grow); +# after we got a MemoryError; and when throwing the index away +# because of heavy shrinking of the dict. The minimum value +# here is such that 'new_estimate * 2 - num_live_items * 3 > 0'. +new_estimate = (d.num_live_items * 3) // 2 + 1 new_size = DICT_INITSIZE -while new_size <= new_estimate: +while new_size < new_estimate: new_size *= 2 ll_dict_reindex(d, new_size) ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy rpython-hash: better fast path
Author: Armin Rigo Branch: rpython-hash Changeset: r89788:b24fe8a08009 Date: 2017-01-26 15:00 +0100 http://bitbucket.org/pypy/pypy/changeset/b24fe8a08009/ Log:better fast path diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -876,7 +876,7 @@ ll_dict_reindex(d, new_size) def ll_dict_create_index(d): -if d.num_live_items == 0: +if d.num_live_items < DICT_INITSIZE * 2 // 3: new_size = DICT_INITSIZE # fast path else: # Use a more conservative estimate than _ll_dict_resize_to() here. ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy rpython-hash: Check popitem() in the hypothesis test
Author: Armin Rigo Branch: rpython-hash Changeset: r89789:90dc3abfc8f2 Date: 2017-01-26 16:55 +0100 http://bitbucket.org/pypy/pypy/changeset/90dc3abfc8f2/ Log:Check popitem() in the hypothesis test diff --git a/rpython/rtyper/test/test_rdict.py b/rpython/rtyper/test/test_rdict.py --- a/rpython/rtyper/test/test_rdict.py +++ b/rpython/rtyper/test/test_rdict.py @@ -1155,6 +1155,8 @@ class MappingSpace(object): def __init__(self, s_key, s_value): +from rpython.rtyper.rtuple import TupleRepr + self.s_key = s_key self.s_value = s_value rtyper = PseudoRTyper() @@ -1168,6 +1170,8 @@ self.reference = self.new_reference() self.ll_key = r_key.convert_const self.ll_value = r_value.convert_const +r_tuple = TupleRepr(rtyper, [r_key, r_value]) +self.TUPLE = r_tuple.lowleveltype def setitem(self, key, value): ll_key = self.ll_key(key) @@ -1191,6 +1195,22 @@ self.reference.clear() assert self.ll_len(self.l_dict) == 0 +def popitem(self): +try: +ll_tuple = self.ll_popitem(self.TUPLE, self.l_dict) +except KeyError: +assert len(self.reference) == 0 +else: +ll_key = ll_tuple.item0 +ll_value = ll_tuple.item1 +for key, value in self.reference.iteritems(): +if self.ll_key(key) == ll_key: +assert self.ll_value(value) == ll_value +del self.reference[key] +break +else: +raise AssertionError("popitem() returned unexpected key") + def fullcheck(self): assert self.ll_len(self.l_dict) == len(self.reference) for key, value in self.reference.iteritems(): @@ -1217,7 +1237,8 @@ def steps(self): if not self.space: return builds(Action, just('setup'), tuples(st_keys, st_values)) -global_actions = [Action('copydict', ()), Action('cleardict', ())] +global_actions = [Action('copydict', ()), Action('cleardict', ()), + Action('popitem', ())] if self.space.reference: return ( self.st_setitem() | sampled_from(global_actions) | @@ -1249,6 +1270,7 @@ ll_contains = staticmethod(rdict.ll_contains) ll_copy = staticmethod(rdict.ll_copy) ll_clear = staticmethod(rdict.ll_clear) +ll_popitem = staticmethod(rdict.ll_popitem) def newdict(self, repr): return rdict.ll_newdict(repr.DICT) diff --git a/rpython/rtyper/test/test_rordereddict.py b/rpython/rtyper/test/test_rordereddict.py --- a/rpython/rtyper/test/test_rordereddict.py +++ b/rpython/rtyper/test/test_rordereddict.py @@ -345,6 +345,7 @@ ll_contains = staticmethod(rodct.ll_dict_contains) ll_copy = staticmethod(rodct.ll_dict_copy) ll_clear = staticmethod(rodct.ll_dict_clear) +ll_popitem = staticmethod(rodct.ll_dict_popitem) def newdict(self, repr): return rodct.ll_newdict(repr.DICT) @@ -363,6 +364,20 @@ break return keys_ll +def popitem(self): +# overridden to check that we're getting the most recent key, +# not a random one +try: +ll_tuple = self.ll_popitem(self.TUPLE, self.l_dict) +except KeyError: +assert len(self.reference) == 0 +else: +ll_key = ll_tuple.item0 +ll_value = ll_tuple.item1 +key, value = self.reference.popitem() +assert self.ll_key(key) == ll_key +assert self.ll_value(value) == ll_value + def fullcheck(self): # overridden to also check key order assert self.ll_len(self.l_dict) == len(self.reference) @@ -379,4 +394,4 @@ def test_hypothesis(): run_state_machine_as_test( -ODictSM, settings(max_examples=500, stateful_step_count=100)) +ODictSM, settings(max_examples=5, stateful_step_count=100)) ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: Cleanup: don't pass the whole CConfig to places that only need an ECI
Author: Ronan Lamy Branch: Changeset: r89790:ae071d58c03a Date: 2017-01-26 17:01 + http://bitbucket.org/pypy/pypy/changeset/ae071d58c03a/ Log:Cleanup: don't pass the whole CConfig to places that only need an ECI diff --git a/rpython/rtyper/tool/rffi_platform.py b/rpython/rtyper/tool/rffi_platform.py --- a/rpython/rtyper/tool/rffi_platform.py +++ b/rpython/rtyper/tool/rffi_platform.py @@ -131,8 +131,8 @@ # General interface class ConfigResult: -def __init__(self, CConfig, info, entries): -self.CConfig = CConfig +def __init__(self, eci, info, entries): +self.eci = eci self.result = {} self.info = info self.entries = entries @@ -154,15 +154,14 @@ class _CWriter(object): """ A simple class which aggregates config parts """ -def __init__(self, CConfig): +def __init__(self, eci): self.path = uniquefilepath() self.f = self.path.open("w") -self.config = CConfig +self.eci = eci def write_header(self): f = self.f -CConfig = self.config -CConfig._compilation_info_.write_c_header(f) +self.eci.write_c_header(f) print >> f, C_HEADER print >> f @@ -194,8 +193,7 @@ self.start_main() self.f.write(question + "\n") self.close() -eci = self.config._compilation_info_ -try_compile_cache([self.path], eci) +try_compile_cache([self.path], self.eci) def configure(CConfig, ignore_errors=False): """Examine the local system by running the C compiler. @@ -208,6 +206,7 @@ assert not hasattr(CConfig, attr), \ "Found legacy attribute %s on CConfig" % attr +eci = CConfig._compilation_info_ entries = [] for key in dir(CConfig): value = getattr(CConfig, key) @@ -215,7 +214,7 @@ entries.append((key, value)) if entries: # can be empty if there are only CConfigSingleEntries -writer = _CWriter(CConfig) +writer = _CWriter(eci) writer.write_header() for key, entry in entries: writer.write_entry(key, entry) @@ -225,7 +224,6 @@ writer.write_entry_main(key) writer.close() -eci = CConfig._compilation_info_ infolist = list(run_example_code(writer.path, eci, ignore_errors=ignore_errors)) assert len(infolist) == len(entries) @@ -236,7 +234,7 @@ resultinfo[key] = info resultentries[entry] = key -result = ConfigResult(CConfig, resultinfo, resultentries) +result = ConfigResult(eci, resultinfo, resultentries) for name, entry in entries: result.get_entry_result(entry) res = result.get_result() @@ -246,7 +244,7 @@ for key in dir(CConfig): value = getattr(CConfig, key) if isinstance(value, CConfigSingleEntry): -writer = _CWriter(CConfig) +writer = _CWriter(eci) writer.write_header() res[key] = value.question(writer.ask_gcc) @@ -344,7 +342,7 @@ allfields = tuple(['c_' + name for name, _ in fields]) padfields = tuple(padfields) name = self.name -eci = config_result.CConfig._compilation_info_ +eci = config_result.eci padding_drop = PaddingDrop(name, allfields, padfields, eci) hints = {'align': info['align'], 'size': info['size'], ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: Extract configure_entries() from configure()
Author: Ronan Lamy Branch: Changeset: r89791:5cf849b8cd32 Date: 2017-01-26 17:29 + http://bitbucket.org/pypy/pypy/changeset/5cf849b8cd32/ Log:Extract configure_entries() from configure() diff --git a/rpython/rtyper/tool/rffi_platform.py b/rpython/rtyper/tool/rffi_platform.py --- a/rpython/rtyper/tool/rffi_platform.py +++ b/rpython/rtyper/tool/rffi_platform.py @@ -214,30 +214,7 @@ entries.append((key, value)) if entries: # can be empty if there are only CConfigSingleEntries -writer = _CWriter(eci) -writer.write_header() -for key, entry in entries: -writer.write_entry(key, entry) - -writer.start_main() -for key, entry in entries: -writer.write_entry_main(key) -writer.close() - -infolist = list(run_example_code(writer.path, eci, - ignore_errors=ignore_errors)) -assert len(infolist) == len(entries) - -resultinfo = {} -resultentries = {} -for info, (key, entry) in zip(infolist, entries): -resultinfo[key] = info -resultentries[entry] = key - -result = ConfigResult(eci, resultinfo, resultentries) -for name, entry in entries: -result.get_entry_result(entry) -res = result.get_result() +res = configure_entries(entries, eci, ignore_errors=ignore_errors) else: res = {} @@ -250,6 +227,33 @@ return res + +def configure_entries(entries, eci, ignore_errors=False): +writer = _CWriter(eci) +writer.write_header() +for key, entry in entries: +writer.write_entry(key, entry) + +writer.start_main() +for key, entry in entries: +writer.write_entry_main(key) +writer.close() + +infolist = list(run_example_code( +writer.path, eci, ignore_errors=ignore_errors)) +assert len(infolist) == len(entries) + +resultinfo = {} +resultentries = {} +for info, (key, entry) in zip(infolist, entries): +resultinfo[key] = info +resultentries[entry] = key + +result = ConfigResult(eci, resultinfo, resultentries) +for name, entry in entries: +result.get_entry_result(entry) +return result.get_result() + # ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: Use rffi_platform.configure_entries() in cparser
Author: Ronan Lamy Branch: Changeset: r89792:75fb54ed4989 Date: 2017-01-26 17:46 + http://bitbucket.org/pypy/pypy/changeset/75fb54ed4989/ Log:Use rffi_platform.configure_entries() in cparser diff --git a/pypy/module/cpyext/cparser.py b/pypy/module/cpyext/cparser.py --- a/pypy/module/cpyext/cparser.py +++ b/pypy/module/cpyext/cparser.py @@ -699,7 +699,7 @@ self.headers = headers if headers is not None else ['sys/types.h'] self.parsed_headers = [] self.sources = [] -self._Config = type('Config', (object,), {}) +self._config_entries = [] self._TYPES = {} self.includes = [] self.struct_typedefs = {} @@ -759,8 +759,9 @@ def realize_struct(self, struct): type_name = struct.get_type_name() configname = type_name.replace(' ', '__') -setattr(self._Config, configname, -rffi_platform.Struct(type_name, struct.fields)) +assert not any(x[0] == configname for x in self._config_entries) +self._config_entries.append( +(configname, rffi_platform.Struct(type_name, struct.fields))) self._TYPES[configname] = struct.TYPE return struct.TYPE @@ -795,13 +796,17 @@ elif name.startswith('macro '): name = name[6:] self.add_macro(name, obj) -self._Config._compilation_info_ = self.build_eci() -for name, TYPE in rffi_platform.configure(self._Config).iteritems(): +if not self._config_entries: +return +eci = self.build_eci() +result = rffi_platform.configure_entries(self._config_entries, eci) +for name, TYPE in result.iteritems(): # hack: prevent the source from being pasted into common_header.h del TYPE._hints['eci'] if name in self._TYPES: self._TYPES[name].become(TYPE) del self._TYPES[name] +self._config_entries[:] = [] def convert_type(self, obj, quals=0): if isinstance(obj, model.DefinedType): ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: Preserve the order of entries in configure_entries() which now takes a list instead of a dict
Author: Ronan Lamy Branch: Changeset: r89793:e484cf6b06b6 Date: 2017-01-26 19:54 + http://bitbucket.org/pypy/pypy/changeset/e484cf6b06b6/ Log:Preserve the order of entries in configure_entries() which now takes a list instead of a dict diff --git a/pypy/module/cpyext/cparser.py b/pypy/module/cpyext/cparser.py --- a/pypy/module/cpyext/cparser.py +++ b/pypy/module/cpyext/cparser.py @@ -699,8 +699,7 @@ self.headers = headers if headers is not None else ['sys/types.h'] self.parsed_headers = [] self.sources = [] -self._config_entries = [] -self._TYPES = {} +self._config_entries = OrderedDict() self.includes = [] self.struct_typedefs = {} self._handled = set() @@ -758,11 +757,8 @@ def realize_struct(self, struct): type_name = struct.get_type_name() -configname = type_name.replace(' ', '__') -assert not any(x[0] == configname for x in self._config_entries) -self._config_entries.append( -(configname, rffi_platform.Struct(type_name, struct.fields))) -self._TYPES[configname] = struct.TYPE +entry = rffi_platform.Struct(type_name, struct.fields) +self._config_entries[entry] = struct.TYPE return struct.TYPE def build_eci(self): @@ -799,14 +795,12 @@ if not self._config_entries: return eci = self.build_eci() -result = rffi_platform.configure_entries(self._config_entries, eci) -for name, TYPE in result.iteritems(): +result = rffi_platform.configure_entries(list(self._config_entries), eci) +for entry, TYPE in zip(self._config_entries, result): # hack: prevent the source from being pasted into common_header.h del TYPE._hints['eci'] -if name in self._TYPES: -self._TYPES[name].become(TYPE) -del self._TYPES[name] -self._config_entries[:] = [] +self._config_entries[entry].become(TYPE) +self._config_entries.clear() def convert_type(self, obj, quals=0): if isinstance(obj, model.DefinedType): diff --git a/rpython/rtyper/tool/rffi_platform.py b/rpython/rtyper/tool/rffi_platform.py --- a/rpython/rtyper/tool/rffi_platform.py +++ b/rpython/rtyper/tool/rffi_platform.py @@ -131,25 +131,20 @@ # General interface class ConfigResult: -def __init__(self, eci, info, entries): +def __init__(self, eci, info): self.eci = eci +self.info = info self.result = {} -self.info = info -self.entries = entries def get_entry_result(self, entry): try: return self.result[entry] except KeyError: pass -name = self.entries[entry] -info = self.info[name] +info = self.info[entry] self.result[entry] = entry.build_result(info, self) return self.result[entry] -def get_result(self): -return dict([(name, self.result[entry]) - for entry, name in self.entries.iteritems()]) class _CWriter(object): """ A simple class which aggregates config parts @@ -207,16 +202,18 @@ "Found legacy attribute %s on CConfig" % attr eci = CConfig._compilation_info_ -entries = [] +entries = {} for key in dir(CConfig): value = getattr(CConfig, key) if isinstance(value, CConfigEntry): -entries.append((key, value)) +entries[key] = value +res = {} if entries: # can be empty if there are only CConfigSingleEntries -res = configure_entries(entries, eci, ignore_errors=ignore_errors) -else: -res = {} +results = configure_entries( +entries.values(), eci, ignore_errors=ignore_errors) +for name, result in zip(entries, results): +res[name] = result for key in dir(CConfig): value = getattr(CConfig, key) @@ -231,12 +228,12 @@ def configure_entries(entries, eci, ignore_errors=False): writer = _CWriter(eci) writer.write_header() -for key, entry in entries: -writer.write_entry(key, entry) +for i, entry in enumerate(entries): +writer.write_entry(str(i), entry) writer.start_main() -for key, entry in entries: -writer.write_entry_main(key) +for i, entry in enumerate(entries): +writer.write_entry_main(str(i)) writer.close() infolist = list(run_example_code( @@ -244,15 +241,11 @@ assert len(infolist) == len(entries) resultinfo = {} -resultentries = {} -for info, (key, entry) in zip(infolist, entries): -resultinfo[key] = info -resultentries[entry] = key +for info, entry in zip(infolist, entries): +resultinfo[entry] = info -result = ConfigResult(eci, resultinfo, resultentries) -for name, entry in entries: -result.get_entry_result(entry) -return result.get_result(
[pypy-commit] pypy rpython-hash: Tweaks, possibly fix a bug
Author: Armin Rigo Branch: rpython-hash Changeset: r89794:eaa33d328249 Date: 2017-01-26 22:05 +0100 http://bitbucket.org/pypy/pypy/changeset/eaa33d328249/ Log:Tweaks, possibly fix a bug diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -642,19 +642,17 @@ except: ll_remove_index(d) raise -rc = d.resize_counter - 3 -if rc <= 0: +if d.resize_counter <= 3: try: ll_dict_resize(d) reindexed = True except: ll_remove_index(d) raise -rc = d.resize_counter - 3 -ll_assert(rc > 0, "ll_dict_resize failed?") if reindexed: ll_call_insert_clean_function(d, hash, d.num_ever_used_items) -# +rc = d.resize_counter - 3 +ll_assert(rc > 0, "ll_dict_resize failed?") d.resize_counter = rc entry = d.entries[d.num_ever_used_items] entry.key = key @@ -799,7 +797,7 @@ # then maybe it is a better idea to keep it instead of reallocating # an identical index very soon. In this case we update the index now. if bool(d.indexes): -new_estimate = d.num_live_items * 2 +new_estimate = d.num_live_items * 2 new_size = DICT_INITSIZE while new_size <= new_estimate: new_size *= 2 @@ -842,12 +840,13 @@ # also possible that there are more dead items immediately behind the # last one, we reclaim all the dead items at the end of the ordereditem # at the same point. -i = d.num_ever_used_items - 2 -while i >= 0 and not d.entries.valid(i): +i = index +while True: i -= 1 -j = i + 1 -assert j >= 0 -d.num_ever_used_items = j +assert i >= 0 +if d.entries.valid(i):# must be at least one +break +d.num_ever_used_items = i + 1 # If the dictionary is more than 75% dead items, then clean up the # deleted items and remove the index. @@ -1065,7 +1064,6 @@ ll_remove_index(d) d.num_live_items = 0 d.num_ever_used_items = 0 -d.resize_counter = DICT_INITSIZE * 2 return d OrderedDictRepr.ll_newdict = staticmethod(ll_newdict) @@ -1232,7 +1230,6 @@ ll_remove_index(d) d.num_live_items = 0 d.num_ever_used_items = 0 -d.resize_counter = DICT_INITSIZE * 2 # old_entries.delete() XXX ll_dict_clear.oopspec = 'odict.clear(d)' diff --git a/rpython/rtyper/test/test_rdict.py b/rpython/rtyper/test/test_rdict.py --- a/rpython/rtyper/test/test_rdict.py +++ b/rpython/rtyper/test/test_rdict.py @@ -1170,6 +1170,7 @@ self.reference = self.new_reference() self.ll_key = r_key.convert_const self.ll_value = r_value.convert_const +self.removed_keys = [] r_tuple = TupleRepr(rtyper, [r_key, r_value]) self.TUPLE = r_tuple.lowleveltype @@ -1185,6 +1186,7 @@ self.ll_delitem(self.l_dict, ll_key) del self.reference[key] assert not self.ll_contains(self.l_dict, ll_key) +self.removed_keys.append(key) def copydict(self): self.l_dict = self.ll_copy(self.l_dict) @@ -1192,6 +1194,8 @@ def cleardict(self): self.ll_clear(self.l_dict) +for key in self.reference: +self.removed_keys.append(key) self.reference.clear() assert self.ll_len(self.l_dict) == 0 @@ -1207,15 +1211,27 @@ if self.ll_key(key) == ll_key: assert self.ll_value(value) == ll_value del self.reference[key] +self.removed_keys.append(key) break else: raise AssertionError("popitem() returned unexpected key") +def removeindex(self): +pass # overridden in test_rordereddict + def fullcheck(self): assert self.ll_len(self.l_dict) == len(self.reference) for key, value in self.reference.iteritems(): assert (self.ll_getitem(self.l_dict, self.ll_key(key)) == self.ll_value(value)) +for key in self.removed_keys: +if key not in self.reference: +try: +self.ll_getitem(self.l_dict, self.ll_key(key)) +except KeyError: +pass +else: +raise AssertionError("removed key still shows up") class MappingSM(GenericStateMachine): def __init__(self): @@ -1238,7 +1254,7 @@ if not self.space: return builds(Action, just('setup'), tuples(st_keys, st_values)) global_actions = [Action('copydict', ()), Action('cleardict', ()), - Action('popitem', ())] +