@staticmethod, backward compatibility?

N

Neal Becker

How can I write code to take advantage of new decorator syntax, while
allowing backward compatibility?

I almost want a preprocessor.

#if PYTHON_VERSION >= 2.4
@staticmethod
....


Since python < 2.4 will just choke on @staticmethod, how can I do this?
 
P

Peter Hansen

Neal said:
How can I write code to take advantage of new decorator syntax, while
allowing backward compatibility?

I almost want a preprocessor.

#if PYTHON_VERSION >= 2.4
@staticmethod
...

Since python < 2.4 will just choke on @staticmethod, how can I do this?

It seems to me that no matter what you do, if it's not done with an
external processing tool which requires no changes in the source code,
the result will be much uglier than if you just used the pre-2.4
decorator syntax:

def meth():
pass
meth = staticmethod(meth)


-Peter
 
D

Duncan Booth

Neal said:
How can I write code to take advantage of new decorator syntax, while
allowing backward compatibility?

I almost want a preprocessor.

#if PYTHON_VERSION >= 2.4
@staticmethod
...


Since python < 2.4 will just choke on @staticmethod, how can I do this?
Here's one way to do it. The restrictions are:

it only works on modules, so you can't use decorators in the
main script;
it only handles one decorate per function (but shouldn't be
too hard to extend);
decorators are assumed to only occupy a single line.

Example of use:

----- example.py --------
import decorate23
import test

test.C().fred('it', 'works')
----- end example.py ----

----- test.py -----------
class C:
@staticmethod
def fred(a, b):
print a, b
return None

@classmethod
def freda(cls, a, b):
print a, b
return None
----- end test.py -------

The contents of decorate23 are, of course, left as an exercise
for the reader.









































Only kidding:

----- decorate23.py -----
# Automatically apply decorators for pre-2.4 code
import sys
import re


if sys.version_info < (2,4):
from imputil import _compile, _suffix_char
import imp, sys, marshal, struct, __builtin__
import imputil

PATTERN = re.compile('^(?P<indent>[\\s]*)@(?P<decorator>.*)\n'
'(?P<body>\\1def (?P<id>[a-zA-Z_0-9]+)\\(.*(?:\n\\1.*)*)',
re.MULTILINE)
def autodecorate(source):
def replace(match):
decorator = match.group('decorator')
indent = match.group('indent')
id = match.group('id')
body = match.group('body')

return "%(body)s\n%(indent)s%(id)s = %(decorator)s(%(id)s)\n" % locals()

return PATTERN.sub(replace, source)

def hook_compile(pathname, timestamp):
"""Compile (and cache) a Python source file.

The file specified by <pathname> is compiled to a code object and
returned.

Presuming the appropriate privileges exist, the bytecodes will be
saved back to the filesystem for future imports. The source file's
modification timestamp must be provided as a Long value.
"""
codestring = open(pathname, 'rU').read()

if codestring and codestring[-1] != '\n':
codestring = codestring + '\n'
codestring = autodecorate(codestring)

code = __builtin__.compile(codestring, pathname, 'exec')

# try to cache the compiled code
try:
f = open(pathname + _suffix_char, 'wb')
except IOError:
pass
else:
f.write('\0\0\0\0')
f.write(struct.pack('<I', timestamp))
marshal.dump(code, f)
f.flush()
f.seek(0, 0)
f.write(imp.get_magic())
f.close()

return code

imputil._compile = hook_compile
imputil.ImportManager().install()
----- end decorate23.py -

The overhead shouldn't be too bad as the hook will only kick in when
the code needs recompiling, but the line numbers in tracebacks
refer to the modified code so they'll be slightly out.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top