Python 2.7 compatibility

This commit is contained in:
Pavel Kirienko 2014-06-16 00:48:47 +04:00
parent 7dbba5887a
commit ff7481334a
7 changed files with 61 additions and 24 deletions

View File

@ -4,10 +4,17 @@
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
from __future__ import division, absolute_import, print_function, unicode_literals
import sys, os, logging, errno
from mako.template import Template
from pyuavcan import dsdl
# Python 2.7 compatibility
try:
str = unicode
except NameError:
pass
OUTPUT_FILE_EXTENSION = 'hpp'
OUTPUT_FILE_PERMISSIONS = 0o444 # Read only for all
TEMPLATE_FILENAME = os.path.join(os.path.dirname(__file__), 'data_type_template.tmpl')
@ -22,7 +29,7 @@ logger = logging.getLogger(__name__)
def run(source_dirs, include_dirs, output_dir):
assert isinstance(source_dirs, list)
assert isinstance(include_dirs, list)
assert isinstance(output_dir, str)
output_dir = str(output_dir)
types = run_parser(source_dirs, include_dirs + source_dirs)
if not types:
@ -44,7 +51,10 @@ def type_output_filename(t):
def makedirs(path):
try:
os.makedirs(path, exist_ok=True) # May throw "File exists" when executed as root, which is wrong
try:
os.makedirs(path, exist_ok=True) # May throw "File exists" when executed as root, which is wrong
except TypeError:
os.makedirs(path) # Python 2.7 compatibility
except OSError as ex:
if ex.errno != errno.EEXIST: # http://stackoverflow.com/questions/12468022
raise

View File

@ -1,10 +1,12 @@
#!/usr/bin/env python3
#!/usr/bin/env python
#
# UAVCAN DSDL compiler for libuavcan
# Written in Python 3, compatible with Python 2.7
#
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
from __future__ import division, absolute_import, print_function, unicode_literals
import os, sys, logging, argparse
RUNNING_FROM_SRC_DIR = os.path.abspath(__file__).endswith(os.path.join('libuavcan', 'dsdl_compiler', 'libuavcan_dsdlc'))

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from distutils.core import setup

View File

@ -2,20 +2,21 @@
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
from __future__ import division, absolute_import, print_function, unicode_literals
import os
class DsdlException(Exception):
def __init__(self, text, file=None, line=None):
super().__init__(text)
Exception.__init__(self, text)
self.file = file
self.line = line
def __str__(self):
if self.file and self.line:
return '%s:%d: %s' % (pretty_filename(self.file), self.line, super().__str__())
return '%s:%d: %s' % (pretty_filename(self.file), self.line, Exception.__str__(self))
if self.file:
return '%s: %s' % (pretty_filename(self.file), super().__str__())
return super().__str__()
return '%s: %s' % (pretty_filename(self.file), Exception.__str__(self))
return Exception.__str__(self)
def pretty_filename(filename):

View File

@ -4,12 +4,23 @@
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
from __future__ import division, absolute_import, print_function, unicode_literals
import os, re, logging
from io import StringIO
from .signature import compute_signature
from .common import DsdlException, pretty_filename
from .type_limits import get_unsigned_integer_range, get_signed_integer_range, get_float_range
# Python 2.7 compatibility
try:
str = unicode
except NameError:
pass
try:
long(1)
except NameError:
long = int
MAX_FULL_TYPE_NAME_LEN = 80
DATA_TYPE_ID_MAX = 1023
MAX_DATA_STRUCT_LEN_BYTES = 439
@ -41,7 +52,7 @@ class PrimitiveType(Type):
self.kind = kind
self.bitlen = bitlen
self.cast_mode = cast_mode
super().__init__(self.get_normalized_definition(), Type.CATEGORY_PRIMITIVE)
Type.__init__(self, self.get_normalized_definition(), Type.CATEGORY_PRIMITIVE)
self.value_range = {
PrimitiveType.KIND_BOOLEAN: get_unsigned_integer_range,
PrimitiveType.KIND_UNSIGNED_INT: get_unsigned_integer_range,
@ -75,7 +86,7 @@ class ArrayType(Type):
self.value_type = value_type
self.mode = mode
self.max_size = max_size
super().__init__(self.get_normalized_definition(), Type.CATEGORY_ARRAY)
Type.__init__(self, self.get_normalized_definition(), Type.CATEGORY_ARRAY)
def get_normalized_definition(self):
typedef = self.value_type.get_normalized_definition()
@ -93,7 +104,7 @@ class CompoundType(Type):
KIND_MESSAGE = 1
def __init__(self, full_name, kind, source_file, default_dtid, source_text):
super().__init__(full_name, Type.CATEGORY_COMPOUND)
Type.__init__(self, full_name, Type.CATEGORY_COMPOUND)
self.source_file = source_file
self.default_dtid = default_dtid
self.kind = kind
@ -154,10 +165,12 @@ class Field(Attribute):
class Constant(Attribute):
def __init__(self, type, name, init_expression, value): # @ReservedAssignment
super().__init__(type, name)
Attribute.__init__(self, type, name)
self.init_expression = init_expression
self.value = value
self.string_value = repr(value)
if isinstance(value, long):
self.string_value = self.string_value.replace('L', '')
def get_normalized_definition(self):
return '%s %s = %s' % (self.type.get_normalized_definition(), self.name, self.init_expression)
@ -204,7 +217,8 @@ class Parser:
def _locate_compound_type_definition(self, referencing_filename, typename):
def locate_namespace_directory(namespace):
root_namespace, *sub_namespace_components = namespace.split('.')
namespace_components = namespace.split('.')
root_namespace, sub_namespace_components = namespace_components[0], namespace_components[1:]
for directory in self.search_dirs:
if directory.split(os.path.sep)[-1] == root_namespace:
return os.path.join(directory, *sub_namespace_components)
@ -311,10 +325,10 @@ class Parser:
if isinstance(value, str) and len(value) == 1: # ASCII character
value = ord(value)
elif isinstance(value, (float, int, bool)): # Numeric literal
elif isinstance(value, (float, int, bool, long)): # Numeric literal
value = {
attrtype.KIND_UNSIGNED_INT : int,
attrtype.KIND_SIGNED_INT : int,
attrtype.KIND_UNSIGNED_INT : long,
attrtype.KIND_SIGNED_INT : long,
attrtype.KIND_BOOLEAN : int, # Not bool because we need to check range
attrtype.KIND_FLOAT : float
}[attrtype.kind](value)
@ -328,12 +342,12 @@ class Parser:
def _parse_line(self, filename, tokens):
cast_mode = None
if tokens[0] == 'saturated' or tokens[0] == 'truncated':
cast_mode, *tokens = tokens
cast_mode, tokens = tokens[0], tokens[1:]
if len(tokens) < 2:
error('Invalid attribute definition')
typename, attrname, *tokens = tokens
typename, attrname, tokens = tokens[0], tokens[1], tokens[2:]
validate_attribute_name(attrname)
attrtype = self._parse_type(filename, typename, cast_mode)
@ -384,7 +398,8 @@ class Parser:
ex.line = num
raise ex
except Exception as ex:
raise DsdlException('Internal error: %s' % str(ex), line=num) from ex
self.log.error('Internal error', exc_info=True)
raise DsdlException('Internal error: %s' % str(ex), line=num)
if response_part:
t = CompoundType(full_typename, CompoundType.KIND_SERVICE, filename, default_dtid, source_text)
@ -412,9 +427,10 @@ class Parser:
ex.file = filename
raise ex
except IOError as ex:
raise DsdlException('IO error: %s' % str(ex), file=filename) from ex
raise DsdlException('IO error: %s' % str(ex), file=filename)
except Exception as ex:
raise DsdlException('Internal error: %s' % str(ex), file=filename) from ex
self.log.error('Internal error', exc_info=True)
raise DsdlException('Internal error: %s' % str(ex), file=filename)
def error(fmt, *args):
@ -488,7 +504,7 @@ def parse_namespaces(source_dirs, search_dirs=None):
import fnmatch
from functools import partial
def on_walk_error(directory, ex):
raise DsdlException('OS error in [%s]: %s' % (directory, str(ex))) from ex
raise DsdlException('OS error in [%s]: %s' % (directory, str(ex)))
for source_dir in source_dirs:
walker = os.walk(source_dir, onerror=partial(on_walk_error, source_dir), followlinks=True)
for root, _dirnames, filenames in walker:

View File

@ -4,6 +4,8 @@
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
from __future__ import division, absolute_import, print_function, unicode_literals
#
# CRC-64-WE
# Description: http://reveng.sourceforge.net/crc-catalogue/17plus.htm#crc.cat-bits.64
@ -24,8 +26,13 @@ class Signature:
self._crc = Signature.MASK64
def add(self, data_bytes):
if isinstance(data_bytes, str):
data_bytes = map(ord, data_bytes)
try:
if isinstance(data_bytes, basestring): # Python 2.7 compatibility
data_bytes = map(ord, data_bytes)
except NameError:
if isinstance(data_bytes, str): # This branch will be taken on Python 3
data_bytes = map(ord, data_bytes)
for b in data_bytes:
self._crc ^= (b << 56) & Signature.MASK64
for _ in range(8):

View File

@ -4,6 +4,7 @@
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
from __future__ import division, absolute_import, print_function, unicode_literals
from .common import DsdlException
def get_unsigned_integer_range(bitlen):