Is it dubious practice to reference a global variable in a custom error_handler for python's str() function?

73 views Asked by At

Is it bad/dubious/allowable practice to reference (or change) a global variable in a custom error_handler for the str() function, that is set with codecs.register_error()? (see https://docs.python.org/3.6/library/codecs.html#codecs.register_error.)

I am trying to implement a customized 'backslashreplace' function that, in addition to backslashescaping, also wraps the result in either single quotes (') or double quotes ("), very much like the gnu ls program does with filenames when --quoting-style=shell-escape.

The problem is, the choice between single or double quotes cannot be transmitted to the error handler. The only way to let it know which to use, is for it to reference a global variable that flags whether or not single/double quotes should be used.

(I am using Python version 3.6.9).

Here's an example program:

#!/usr/bin/env python3

import codecs

# in my program, quote varies between these two at runtime
#quote = "'"
quote = '"'


def my_replace( e ):
    global quote        # <-- global variable

    if not isinstance( e, UnicodeDecodeError ):
        raise TypeError( "don't know how to handle %r" % e )

    x = []
    for c in e.object[e.start:e.end]:
        try:
            if c == 0x93 or c == 0x94:
                x.append( quote + ( "$'\\%o'" % c) + quote )
        except KeyError:
            return( None )

    return( "".join(x), e.end )


codecs.register_error( "my_replace", my_replace )

s = b'61. \x93Gleich wie ein Hirsch begehret\x94, P.169_ IV. Variatio 3.flac'
s = str( s, 'utf-8', errors='my_replace' )
print( quote + s + quote )
1

There are 1 answers

3
progmatico On BEST ANSWER

Using a global var just to store and later read a setting from one or more places, looks OK to me. Specially given it is very simple to do.

For a different idea, have you thought of using a closure for your handler, something like below:

def outer(quote):
    settings = dict(quote=quote)
    def inner():
        print(settings['quote'])
    return inner

error_handler = outer("'")

# Then you register your error_handler...
# Later when called it remembers the settings
error_handler() # prints the simple quote

Taking your comment in consideration, use a class instead of a closure:

class QuotedErrorHandler:
    quote = "'"

    def handler(self, error):
        # do your thing
        print("Quote to use: {}".format(QuotedErrorHandler.quote))
        return error.upper()

QuotedErrorHandler.quote = '"'
my_handler = QuotedErrorHandler()
error_handler = my_handler.handler

print(error_handler("Some error"))
print(my_handler.quote)