Howto Develop for Multiple Platforms

Python Syntax Version

The pythonids provides a 16bit bitmask for Python releases, for alternatives refer to sys.hexversion of the various Python implementation and syntax variants.

  • pythonids.PYV35Plus

    The flag for the supported Python Syntax versions [pythonids]:

    1
    2
    3
    4
    pythonids.PYV35Plus = (
        True,   # Python3.5+
        False   # Python2.7
    )
    

    For example:

    1
    2
    3
    4
    5
    6
    7
    from pythonids import PYV35Plus  # raises exception when not in 2.7 or 3.5+
    
    if PYV35Plus == True:
        # do sth. special for Python3...
    
     else:
        # do sth. else for Python2.7...
    
  • pythonids.PYVxyz

    The combined bit-mask-flag of the Python Syntax version PythonX.Y and release PythonX.Y(Z) is provided by the variable Vxyz [PYVxyz]:

    1
    2
    3
    4
    5
    PYVxyz := 0bxxxyyyyyzzzzzzzz
    
    xxx:     3 bits / 0-7   for major version, e.g. 3       for 3.6.5  or e.g. future 4.0.2
    yyyyy:   5 bits / 0-31  for minor version, e.g. 6       for 3.6.5  or e.g. future 3.14.3
    zzzzzz:  8 bits / 0-255 for the release build, e.g. 14  for 2.7.14 or e.g. future 2.7.23
    

    See also [encode_pysyntax_to_16bit].

  • pythonids.encode_pysyntax_to_16bit()

    Dynamic version evaluation by compressed bitmasks as single integer values by the slim and fast function interface [encode_pysyntax_to_16bit].

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    PYV32 = encode_pysyntax_to_16bit(3, 2)        # integer
    myPYVxyz = encode_pysyntax_to_16bit(3, 6, 5)  # integer
    
    for x in range(1000000000):
    
       if PYVxyz & myPYVxyz:   # pure integer comparison - is the version 3.6.5
          callFunction0(x)
    
       elif PYV32 > myPYVxyz:  # pure integer comparison - is higher than version 3.2.0
          callFunction1(x)
    
       else:                   # is lower or equal version 3.2.0
          callFunction2(x)
    

See also Python Syntax Versions.

Python Distribution

The pythonids provides a 32bit bitmask for ‘Python Distribution’ releases , which identify the actual current implementation of the execution framework including the major and minor version of the Pyhton Syntax.

  • pythonids.pythondist.PYDIST

    The combined bit-mask-flag of the Python Distribution version Python-Variant-X.Y with the major and minor syntax compatibility to PythonX.Y [PYDIST]:

    1
    2
    3
    4
    5
    6
    PYDIST := 0bnxxxxxxxxyyyyyyzzzzzzzzzzzzzzzzzz
    
    n:                   1 bits    ignored, optional set as category Python
    xxxxxxxx:            8 bits    for major and minor version of the Python Syntax
    yyyyyy:              6 bits    enum value for the Python Distribution
    zzzzzzzzzzzzzzzzzz:  18 bits   release version of the Python Distribution
    

    See also [encode_pydist_to_32bit].

  • pythonids.encode_pydist_to_32bit()

    Dynamic version evaluation by compressed bitmasks as single integer values by the slim and fast function interface [encode_pydist_to_32bit].

    The following example demonstrates the detection of Cython [Cython] and the specific release of Cython itself. This enables the appropriate selection of the special optimization for the best performance of the current application. The required overhead is basically negligible, in particular when multiple code segments require the same or similar environment dependent processing decisions.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
      from pythonids.pythondist import PYDIST, PYE_DIST, PYE_CPYTHON, PYE_PYPY, PYE_JYTHON, \
         encode_pydist_to_32bit
    
      CPYPY580PYV27 = encode_pydist_to_32bit(PYE_PYPY, 5, 8, 0, 2, 7)     # Syntax Python-2.7.13
      CPYPY5100PYV27 = encode_pydist_to_32bit(PYE_PYPY, 5, 10, 0, 2, 7)   # Syntax Python-2.7.13
      CPYPY5101PYV35 = encode_pydist_to_32bit(PYE_PYPY, 5, 10, 1, 3, 5)   # Syntax Python-3.5.3
    
      if PYDIST & PYE_DIST == PYE_PYPY:  # check by single integer value
         #
         # for PyPy
         #
    
         if PYDIST == CPYPY580PYV27:
            for x in range(1000000000):
               callFunctionOptimized0(x)
    
         elif PYDIST > CPYPY5100PYV27 and PYDIST < CPYPY5101PYV35:
            for x in range(1000000000):
               callFunctionOptimized1(x)
    
         elif PYDIST > CPYPY5101PYV35:
            for x in range(1000000000):
               callFunctionOptimized(x)
    
         else:
            for x in range(1000000000):
               callFunctionStillWorks(x)
    
      elif PYDIST & PYE_DIST == PYE_JYTHON:  # check by single integer value Jython
         #
         # for Jython
         #
         callFunctionJython(x)
    
      else:
         #
         # generic
         #
         callFunctionGeneric(x)
    

See also Python Distribution Categorization.

Integer Type Comparison

The Python type int is common for values and in particular for enumerations and pseudo-const variables in Python. Therefore commonly used in conditional clauses including checks on the type. This causes some difficulties on Jython, because Jython uses the type long. Thus the following if clause delivers different results on Jython and else.

ix = 123123123123

if type(ix) == int:
   res = True
else:
   res = False

The results are different on implementations:

  • on CPython, IPython, IronPython, and PyPy:

    res = True
    
  • on Jython:

    res = False
    

The module pythonids.pythondist supports the constant ISINT:

if (PYDIST & PYE_DIST) == PYE_JYTHON:
    # Jython knows the type long - and casts to it from 32bit on
    isJython = True
    ISINT = (int, long,)

else:
    isJython = False
    ISINT = (int,)

thus the conditional clause:

from pythonids.pythondist import ISINT

ix = 123123123123

if type(ix) in ISINT:
   res = True
else:
   res = False

delivers now the same result on all implementations:

res = True

See also Bit Masks for Numeric Vectors.

Basic Unicode

The implementation of Python code for the versions Python2 and Python3 has to handle numerous changes. The probably most frequent compatibility issue arises for the change of the string representation. Here the most common comparison and basic transformation could be handled by the following patch. See also [ISSUE32078].

  • pythonids.ISSTR and pythonids.unicode

    The simplified portability of encodings for Python2 and Python3 is supported by the adapted type set ISSTR and the conditional unicode alias [pythonids]:

    1
    2
    3
    4
    5
    6
    if PYV35Plus:
       unicode = str           # applicable for basic compatibility only
       ISSTR = (str, bytes,)
    
    else:
       ISSTR = (str, unicode,)
    

See also Python2 and Python3 Encoding and Decoding.

  • ISSTR: string and unicode for type comparison:

    if PYV35Plus:
       ISSTR = (str, bytes,)
    else:
       ISSTR = (str, unicode,)
    
  • unicode: for Python3, remaps unicode to str:

    if PYV35Plus:
       unicode = str
    

    Works due to a design flaw for simple cases only.