...
Your .py
files will now have a series of blocks that look like this, using C preprocessor syntax:
. . .
#ifndef USING_PYTHON2
from logginginterface import *
#else /* USING_PYTHON2 */
from .logginginterface import *
#endif /* USING_PYTHON2 */
NOTE: The sense of the "#ifdef/#ifndef" is backwards from what we really want, but this will be dealt with in a later section below. I've added annotated the lines further to make it clearer which lines are the python2 and which are the python3 code. |
. . .
#ifndef USING_PYTHON2
import urllib from logginginterface import * # python2 code
#else /* USING_PYTHON2 */
import urllib.request, urllib.parse, urllib.error from .logginginterface import * # python3 code
#endif /* USING_PYTHON2 */
. . .
#ifndef USING_PYTHON2 return urllib.quote(str(s), '')
import urllib # python2 code
#else /* USING_PYTHON2 */
return import urllib.request, urllib.parse.quote(str(s), ''), urllib.error # python3 code
#endif /* USING_PYTHON2 */
. . .
#ifndef USING_PYTHON2
os.umask(077)return urllib.quote(str(s), '') # python2 code
#else /* USING_PYTHON2 */
os.umask(0o77)return urllib.parse.quote(str(s), '') # python3 code
#endif /* USING_PYTHON2 */
. . .
#ifndef USING_PYTHON2
if openstack.has_key('custom_configuration'):os.umask(077) # python2 code
#else /* USING_PYTHON2 */
if 'custom_configuration' in openstack:os.umask(0o77) # python3 code
#endif /* USING_PYTHON2 */
. . .
#ifndef USING_PYTHON2
print >>fp, binascii.hexlify(b).decode('utf-8')if openstack.has_key('custom_configuration'): # python2 code
#else /* USING_PYTHON2 */
print(binascii.hexlify(b).decode('utf-8'), file=fp)if 'custom_configuration' in openstack: # python3 code
#endif /* USING_PYTHON2 */
. . .
#ifndef USING_PYTHON2
debug("ctx node has the following Properties: {}".format(i.properties.keys()))print >>fp, binascii.hexlify(b).decode('utf-8') # python2 code
#else /* USING_PYTHON2 */
debug("ctx node has the following Properties: {}".format(list(i.properties.keys())))print(binascii.hexlify(b).decode('utf-8'), file=fp) # python3 code
#endif /* USING_PYTHON2 */
. . .
#ifndef USING_PYTHON2
for k, nv in want.items():debug("ctx node has the following Properties: {}".format(i.properties.keys()))
#else /* USING_PYTHON2 */
for k, nv in list(want.items()):debug("ctx node has the following Properties: {}".format(list(i.properties.keys())))
#endif /* USING_PYTHON2 */
. . .
|
These .py files are currently executable by NEITHER Python2 NOR Python3, so the next step is to deal with the differences to make them runnable by BOTH.
...
#ifndef USING_PYTHON2
for k, nv in want.items(): # python2 code
#else /* USING_PYTHON2 */
for k, nv in list(want.items()): # python3 code
#endif /* USING_PYTHON2 */
. . .
|
These .py files are currently executable by NEITHER Python2 NOR Python3, so the next step is to deal with the differences to make them runnable by BOTH.
- There are some things allowed in Python2.7 that are mandated in Python3.
- There are other things that can be done in just the Python3 form if the right settings are provided.
- Or there are things that can be done in just the Python2 form.
- There are things that must be done differently in the two languages, so a run-time choice is needed.
We will make use of each of these features.
Preparatory Statements
First step is to add these statements to the very top of each .py file:
...
from __future__ import print_function
import sys
USING_PYTHON2 = sys.version_info[0] < 3
If your .py
file starts with a #!
invocation statement, place those lines AFTER the shbang:
...
#!/usr/bin/env python
from __future__ import print_function
import sys
USING_PYTHON2 = sys.version_info[0] < 3
These lines do two things:
...
- form.
- There are things that must be done differently in the two languages, so a run-time choice is needed.
We will make use of each of these features.
Preparatory Statements
First step is to add these statements to the very top of each .py file:
from __future__ import print_function
import sys
USING_PYTHON2 = sys.version_info[0] < 3
|
If your .py
file starts with a #!
invocation statement, place those lines AFTER the shbang:
#!/usr/bin/env python from __future__ import print_function
import sys
USING_PYTHON2 = sys.version_info[0] < 3
|
These lines do two things:
- Allows the function version of the print statements to be used.
- Gives us a value (
USING_PYTHON2
) that can be tested for at run time to determine if we are running Python2 or Python3.
Changing the #ifndef/#else/#endif Statements
You need to change blocks such as this:
#ifndef USING_PYTHON2
some python2 code
#else /* USING_PYTHON2 */
some python3 code
#endif /* USING_PYTHON2 */
#ifdef USING_PYTHON2
some python3 code
#endif /* USING_PYTHON2 */
|
to this. Make CERTAIN that the indentation is adjusted as well.
if USING_PYTHON2:
some python2 code
else:
some python3 code
if not USING_PYTHON2:
some python3 code
|
Yes, there is some cognitive dissonance for changing "#ifndef" to "if", but the rest of the generated code is set up properly to be able to quickly edit the code.
- Search for all instances of "
#ifndef USING_PYTHON2
" and change "#ifndef
" to "if
" and add a trailing ":
". - Search for all instances of "
#else /* USING_PYTHON2 */
" and change that to "else:". - Remove all instances of "
#endif /* USING_PYTHON2 */
" from the code. - Re-indent the lines in between.
You should also search for "#ifdef USING_PYTHON2" and change that to "if not USING_PYTHON2:".
Import Statements
The way that imports of functions found in local files changes in Python3. So change blocks such as this:
#ifndef USING_PYTHON2
from logginginterface import * # python2 code
#else /* USING_PYTHON2 */
from .logginginterface import * # python3 code
#endif /* USING_PYTHON2 */
|
...
#ifndef USING_PYTHON2
import urlliburllib # python2 code
#else /* USING_PYTHON2 */
import urllib.request, urllib.parse, urllib.errorerror # python3 code
#endif /* USING_PYTHON2 */
|
...
if USING_PYTHON2:
from logginginterface import * # python2 code
import urllib
else:
from .logginginterface import *import * # python3 code
import urllib.request, urllib.parse, urllib.error
|
...
#ifndef USING_PYTHON2
return urllib.quote(str(s), '') # python2 code
#else /* USING_PYTHON2 */
return urllib.parse.quote(str(s), '') # python3 code
#endif /* USING_PYTHON2 */
|
...
#ifndef USING_PYTHON2
os.umask(077) # python2 code
#else /* USING_PYTHON2 */
os.umask(0o77) # python3 code
#endif /* USING_PYTHON2 */
|
...
#ifndef USING_PYTHON2
if openstack.has_key('custom_configuration'): # python2 code
#else /* USING_PYTHON2 */
if 'custom_configuration' in openstack: # python3 code
#endif /* USING_PYTHON2 */
|
...
#ifndef USING_PYTHON2
print >>fp, binascii.hexlify(b).decode('utf-8') # python2 code
#else /* USING_PYTHON2 */
print(binascii.hexlify(b).decode('utf-8'), file=fp) # python3 code
#endif /* USING_PYTHON2 */
|
...
#ifndef USING_PYTHON2
debug("ctx node has the following Properties: {}".format(i.properties.keys())) # python2 code
#else /* USING_PYTHON2 */
debug("ctx node has the following Properties: {}".format(list(i.properties.keys()))) # python3 code
#endif /* USING_PYTHON2 */
|
...