overhaul warning use so that we can parameterize warnings

Issue #3178 resolved
Mike Bayer repo owner created an issue

took 5 minutes to actually look at the warnings registry. Let's change our long standing approach of parameterized warnings, e.g. for unicode and other things where it really helps to see the value, and just go for no registry for these. We will augment warn() to accept *args that can be interpolated; if these are present, we skip the registry.

Also, if we just re-implement warnings.warn(), we can do the stack frame stuff they are doing there anyway and express it in terms of the application outside of sqlalchemy without guessing on stacklevel.

this applies to #2992 as well as we want to warn for textual strings and I'd really like to put the string in the warning.

Comments (3)

  1. Mike Bayer reporter

    looking to do it like this, will commit soon

    class _hash_limit_string(compat.text_type):
        """A string subclass that can only be hashed on a maximum amount
        of unique values.
    
        This is used for warnings so that we can send out parameterized warnings
        without the __warningregistry__ of the module,  or the non-overridable
        "once" registry within warnings.py, overloading memory,
    
    
        """
        def __new__(cls, value, args, num):
            interpolated = value % args + \
                (" (max %d of this warning will be registered)" % num)
            self = super(_hash_limit_string, cls).__new__(cls, interpolated)
            self._hash = hash("%s_%d" % (value, hash(interpolated) % num))
            return self
    
        def __hash__(self):
            return self._hash
    
        def __eq__(self, other):
            return hash(self) == hash(other)
    

    if someone uses the "once" filter, there's a global dictionary out of our reach. so this is the only way to go.

    there's not really any performant solution to the stack trace part of this, just going to leave that.

  2. Mike Bayer reporter
    • A new style of warning can be emitted which will "filter" up to N occurrences of a parameterized string. This allows parameterized warnings that can refer to their arguments to be delivered a fixed number of times until allowing Python warning filters to squelch them, and prevents memory from growing unbounded within Python's warning registries. fixes #3178

    → <<cset 3c60d3b1ca49>>

  3. Mike Bayer reporter
    • fix a regression from ref #3178, where dialects that don't actually support sane multi rowcount (e.g. pyodbc) would fail on multirow update. add a test that mocks this breakage into plain dialects

    → <<cset f49c367ef712>>

  4. Log in to comment