mirror of
https://github.com/nasa/fprime-tools.git
synced 2025-12-10 20:07:42 -06:00
mstarch: fixing up Fw UTs for refactored types
This commit is contained in:
parent
3be5da734b
commit
35879444ef
7
setup.py
7
setup.py
@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
####
|
||||
# fprime Python Package:
|
||||
#
|
||||
@ -17,12 +16,8 @@
|
||||
# pip install -e ./Fw/Python
|
||||
# ```
|
||||
###
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
# Setup a python package using setup-tools. This is a newer (and more recommended) technology
|
||||
# then distutils.
|
||||
|
||||
@ -2,8 +2,12 @@
|
||||
Created on May 29, 2020
|
||||
@author: jishii
|
||||
"""
|
||||
from .type_exceptions import ArrayLengthException, TypeMismatchException
|
||||
from .type_base import ValueType
|
||||
from .type_exceptions import (
|
||||
ArrayLengthException,
|
||||
NotInitializedException,
|
||||
TypeMismatchException,
|
||||
)
|
||||
|
||||
|
||||
class ArrayType(ValueType):
|
||||
@ -47,8 +51,13 @@ class ArrayType(ValueType):
|
||||
"""
|
||||
JSONable type
|
||||
"""
|
||||
members = {"name": self.__typename, "type": self.__typename, "size": self.__arr_size, "format": self.__arr_format,
|
||||
"values": [member.to_jsonable() for member in self.val]}
|
||||
members = {
|
||||
"name": self.__typename,
|
||||
"type": self.__typename,
|
||||
"size": self.__arr_size,
|
||||
"format": self.__arr_format,
|
||||
"values": [member.to_jsonable() for member in self.val],
|
||||
}
|
||||
return members
|
||||
|
||||
def serialize(self):
|
||||
@ -64,7 +73,7 @@ class ArrayType(ValueType):
|
||||
item = self.arr_type()
|
||||
item.deserialize(data, offset + i * item.getSize())
|
||||
values.append(item)
|
||||
self.val = valuess
|
||||
self.val = values
|
||||
|
||||
@property
|
||||
def arr_type(self):
|
||||
@ -84,4 +93,3 @@ class ArrayType(ValueType):
|
||||
def getSize(self):
|
||||
""" Return the size of the array """
|
||||
return sum([item.getSize() for item in self.val])
|
||||
|
||||
|
||||
@ -2,10 +2,15 @@
|
||||
Created on Dec 18, 2014
|
||||
@author: tcanham, reder
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
import struct
|
||||
from .type_exceptions import DeserializeException, NotInitializedException, TypeMismatchException
|
||||
|
||||
from .type_base import ValueType
|
||||
from .type_exceptions import (
|
||||
DeserializeException,
|
||||
NotInitializedException,
|
||||
TypeMismatchException,
|
||||
TypeRangeException
|
||||
)
|
||||
|
||||
|
||||
class BoolType(ValueType):
|
||||
@ -13,26 +18,28 @@ class BoolType(ValueType):
|
||||
Representation of a boolean type that will be stored for F prime. True values are stored as a U8 of 0xFF and False
|
||||
is stored as a U8 of 0x00.
|
||||
"""
|
||||
|
||||
TRUE = 0xFF
|
||||
FALSE = 0x00
|
||||
|
||||
def validate(self, val):
|
||||
""" Validate the given class """
|
||||
if not isinstance(bool, val):
|
||||
if not isinstance(val, bool):
|
||||
raise TypeMismatchException(bool, type(val))
|
||||
|
||||
def serialize(self):
|
||||
""" Serialize a boolean value"""
|
||||
""" Serialize a boolean value """
|
||||
if self.val is None:
|
||||
raise NotInitializedException(type(self))
|
||||
return struct.pack("B", 0xFF if self.val else 0x00)
|
||||
|
||||
def deserialize(self, data, offset):
|
||||
"""
|
||||
Utilize deserialized decorator here...
|
||||
"""
|
||||
""" Deserialize boolean value """
|
||||
try:
|
||||
return struct.unpack_from("B", self.TRUE if self.val else self.FALSE)
|
||||
int_val = struct.unpack_from("B", data, offset)[0]
|
||||
if int_val not in [self.TRUE, self.FALSE]:
|
||||
raise TypeRangeException(int_val)
|
||||
self.val = int_val == self.TRUE
|
||||
except struct.error:
|
||||
raise DeserializeException("Not enough bytes to deserialize bool.")
|
||||
|
||||
|
||||
@ -3,8 +3,15 @@ Created on Dec 18, 2014
|
||||
@author: tcanham, reder
|
||||
"""
|
||||
import struct
|
||||
from .type_exceptions import DeserializeException, EnumMismatchException, NotInitializedException, TypeMismatchException, TypeRangeException
|
||||
|
||||
from .type_base import ValueType
|
||||
from .type_exceptions import (
|
||||
DeserializeException,
|
||||
EnumMismatchException,
|
||||
NotInitializedException,
|
||||
TypeMismatchException,
|
||||
TypeRangeException,
|
||||
)
|
||||
|
||||
|
||||
class EnumType(ValueType):
|
||||
@ -15,6 +22,7 @@ class EnumType(ValueType):
|
||||
and current value as a string. The member values will have to be computed
|
||||
containing code based on C enum rules
|
||||
"""
|
||||
|
||||
def __init__(self, typename="", enum_dict=None, val=None):
|
||||
"""
|
||||
Constructor
|
||||
@ -38,8 +46,8 @@ class EnumType(ValueType):
|
||||
|
||||
def validate(self, val):
|
||||
""" Validate the value passed into the enumeration """
|
||||
if isinstance(self.enum_dict(), dict):
|
||||
raise TypeMismatchException(dict, type(val))
|
||||
if not isinstance(self.enum_dict(), dict):
|
||||
raise TypeMismatchException(dict, type(self.enum_dict()))
|
||||
for member in self.keys():
|
||||
if not isinstance(member, str):
|
||||
raise TypeMismatchException(str, type(member))
|
||||
@ -77,8 +85,11 @@ class EnumType(ValueType):
|
||||
try:
|
||||
int_val = struct.unpack_from(">i", data, offset)[0]
|
||||
except:
|
||||
raise DeserializeException("Could not deserialize enum value. Needed: {} bytes Found: {}"
|
||||
.format(self.getSize(), len(data[offset:])))
|
||||
raise DeserializeException(
|
||||
"Could not deserialize enum value. Needed: {} bytes Found: {}".format(
|
||||
self.getSize(), len(data[offset:])
|
||||
)
|
||||
)
|
||||
for key, val in self.enum_dict().items():
|
||||
if int_val == val:
|
||||
self.val = key
|
||||
@ -89,5 +100,4 @@ class EnumType(ValueType):
|
||||
|
||||
def getSize(self):
|
||||
""" Calculates the size based on the size of an integer used to store it """
|
||||
return struct.calcsize('>i');
|
||||
|
||||
return struct.calcsize(">i")
|
||||
|
||||
@ -1,248 +0,0 @@
|
||||
# ===============================================================================
|
||||
# NAME: filepacket.py
|
||||
#
|
||||
# DESCRIPTION: A python version of Rob Bocchino's filepacket classes
|
||||
# AUTHOR: jdperez
|
||||
# EMAIL: jdperez@jpl.nasa.gov
|
||||
# DATE CREATED: June 17, 2015
|
||||
#
|
||||
# Copyright 2015, California Institute of Technology.
|
||||
# ALL RIGHTS RESERVED. U.S. Government Sponsorship acknowledged.
|
||||
# ===============================================================================
|
||||
#
|
||||
# Python standard modules
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import six
|
||||
from .numerical_types import U8Type, U16Type, U32Type
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
# PacketType = Enum('PacketType', 'START DATA END CANCEL NONE')
|
||||
class PacketType(Enum):
|
||||
START = 0
|
||||
DATA = 1
|
||||
END = 2
|
||||
CANCEL = 3
|
||||
NONE = 255
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class FilePacketAbc(object):
|
||||
@abstractmethod
|
||||
def serialize(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def deserialize(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def getBufSize(self):
|
||||
pass
|
||||
|
||||
|
||||
class Header(FilePacketAbc):
|
||||
def __init__(self, pktType, seqIdx):
|
||||
self.__pktType = U8Type(pktType)
|
||||
self.__seqIdx = U32Type(seqIdx)
|
||||
|
||||
def deserialize(self, buf):
|
||||
ptr = 0
|
||||
|
||||
self.__pktType.deserialize(buf, ptr)
|
||||
ptr += self.__pktType.getSize()
|
||||
|
||||
self.__seqIdx.deserialize(buf, ptr)
|
||||
|
||||
def serialize(self):
|
||||
return self.__pktType.serialize() + self.__seqIdx.serialize()
|
||||
|
||||
def getBufSize(self):
|
||||
return self.__pktType.getSize() + self.__seqIdx.getSize()
|
||||
|
||||
|
||||
class StartPacket(FilePacketAbc):
|
||||
def __init__(self, seqIdx=None, filesize=None, srcPath="", destPath=""):
|
||||
self.__header = Header(PacketType.START.value, seqIdx)
|
||||
self.__filesize = U32Type(filesize)
|
||||
self.__srcPathLen = U8Type(len(srcPath))
|
||||
self.__srcPath = srcPath
|
||||
self.__destPathLen = U8Type(len(destPath))
|
||||
self.__destPath = destPath
|
||||
|
||||
def setSrcPath(self, path):
|
||||
self.__srcPathLen = len(path)
|
||||
self.__srcPath = path
|
||||
|
||||
def setDestPath(self, path):
|
||||
self.__destPathLen = len(path)
|
||||
self.__destPath = path
|
||||
|
||||
def getDestPath(self):
|
||||
return self.__destPath
|
||||
|
||||
def getSrcPath(self):
|
||||
return self.__srcPath
|
||||
|
||||
def getSrcLen(self):
|
||||
return self.__srcPathLen
|
||||
|
||||
def getDestLen(self):
|
||||
return self.__destPathLen
|
||||
|
||||
def getFileSize(self):
|
||||
return self.__filesize
|
||||
|
||||
def serialize(self):
|
||||
return (
|
||||
self.__header.serialize()
|
||||
+ self.__filesize.serialize()
|
||||
+ self.__srcPathLen.serialize()
|
||||
+ self.__srcPath
|
||||
+ self.__destPathLen.serialize()
|
||||
+ self.__destPath
|
||||
)
|
||||
|
||||
def deserialize(self, buf):
|
||||
ptr = 0
|
||||
|
||||
self.__header.deserialize(buf)
|
||||
ptr += self.__header.getBufSize()
|
||||
|
||||
self.__filesize.deserialize(buf, ptr)
|
||||
ptr += self.__filesize.getSize()
|
||||
|
||||
self.__srcPathLen.deserialize(buf, ptr)
|
||||
ptr += self.__srcPathLen.getSize()
|
||||
|
||||
self.__srcPath = buf[ptr : self.__srcPathLen.val]
|
||||
ptr += self.__srcPathLen.val
|
||||
|
||||
self.__destPathLen.deserialize(buf, ptr)
|
||||
ptr += self.__destPathLen.getSize()
|
||||
|
||||
self.__destPath = buf[ptr:]
|
||||
|
||||
def getBufSize(self):
|
||||
return (
|
||||
self.__header.getBufSize()
|
||||
+ self.__filesize.getSize()
|
||||
+ self.__srcPathLen.getSize()
|
||||
+ self.__srcPathLen.val
|
||||
+ self.__destPathLen.getSize()
|
||||
+ self.__destPathLen.val
|
||||
)
|
||||
|
||||
|
||||
class DataPacket:
|
||||
def __init__(self, seqIdx=None, byteOffset=None, dataSize=None, data=None):
|
||||
self.__header = Header(PacketType.DATA.value, seqIdx)
|
||||
self.__byteOffset = U32Type(byteOffset)
|
||||
self.__dataSize = U16Type(dataSize)
|
||||
self.__data = data
|
||||
|
||||
def serialize(self):
|
||||
return (
|
||||
self.__header.serialize()
|
||||
+ self.__byteOffset.serialize()
|
||||
+ self.__dataSize.serialize()
|
||||
+ self.__data
|
||||
)
|
||||
|
||||
def deserialize(self, buf):
|
||||
ptr = 0
|
||||
|
||||
self.__header.deserialize(buf)
|
||||
ptr += self.__header.getBufSize()
|
||||
|
||||
self.__byteOffset.deserialize(buf, ptr)
|
||||
ptr += self.__byteOffset.getSize()
|
||||
|
||||
self.__dataSize.deserialize(buf, ptr)
|
||||
ptr += self.__dataSize.getSize()
|
||||
|
||||
self.__data = buf[ptr:]
|
||||
|
||||
def getBufSize(self):
|
||||
return (
|
||||
self.__header.getBufSize()
|
||||
+ self.__byteOffset.getSize()
|
||||
+ self.__dataSize.getSize()
|
||||
+ self.__dataSize.val
|
||||
)
|
||||
|
||||
def getHeader(self):
|
||||
return self.__header
|
||||
|
||||
def getByteOffset(self):
|
||||
return self.__byteOffset
|
||||
|
||||
def getDataSize(self):
|
||||
return self.__dataSize
|
||||
|
||||
def getData(self):
|
||||
return self.__data
|
||||
|
||||
|
||||
class EndPacket:
|
||||
def __init__(self, seqIdx=None, xSum=None):
|
||||
self.__header = Header(PacketType.END.value, seqIdx)
|
||||
self.__xSum = U32Type(xSum)
|
||||
|
||||
def setChecksum(self, xSum):
|
||||
self.__xSum = xSum
|
||||
|
||||
def getChecksum(self):
|
||||
return self.__xSum
|
||||
|
||||
def serialize(self):
|
||||
return self.__header.serialize() + self.__xSum.serialize()
|
||||
|
||||
def deserialize(self, buf):
|
||||
ptr = 0
|
||||
|
||||
self.__header.deserialize(buf)
|
||||
ptr += self.__header.getBufSize()
|
||||
|
||||
self.__xSum.deserialize(buf, ptr)
|
||||
|
||||
def getBufSize(self):
|
||||
return self.__header.getBufSize() + self.__xSum.getSize()
|
||||
|
||||
|
||||
class CancelPacket:
|
||||
def __init__(self, seqIdx=None):
|
||||
self.__header = Header(PacketType.CANCEL.value, seqIdx)
|
||||
|
||||
|
||||
class FilePacket:
|
||||
def __init__(self, filePacket):
|
||||
self.__filePacket = filePacket
|
||||
|
||||
def serialize(self):
|
||||
# return self.__filePacket.header.pktType.serialize() +\
|
||||
# self.__filePacket.header.seqIdx.serialize() +\
|
||||
# self.__filePacket.serialize()
|
||||
return self.__filePacket.serialize()
|
||||
|
||||
def deserialize(self, buf):
|
||||
ptr = 0
|
||||
|
||||
"""
|
||||
self.__filePacket.header.pktType.deserialize(buf, ptr)
|
||||
ptr += self.__filePacket.header.pktType.getSize()
|
||||
|
||||
self.__filePacket.header.seqIdx.deserialize(buf, ptr)
|
||||
ptr += self.__seqIdx.getSize()
|
||||
|
||||
self.__filePacket.deserialize(buf, ptr)
|
||||
"""
|
||||
self.__filePacket.deserialize(buf, ptr)
|
||||
|
||||
def getBufSize(self):
|
||||
return self.__filePacket.getBufSize()
|
||||
@ -6,28 +6,57 @@ that map to stdint.h integer sizes, that is, 8-bit, 16-bit, 32-bit, and 64-bit s
|
||||
|
||||
@author mstarch
|
||||
"""
|
||||
import re
|
||||
import abc
|
||||
import re
|
||||
import struct
|
||||
|
||||
from .type_base import ValueType
|
||||
from .type_exceptions import DeserializeException, NotInitializedException, TypeMismatchException, TypeRangeException
|
||||
from .type_exceptions import (
|
||||
DeserializeException,
|
||||
NotInitializedException,
|
||||
TypeMismatchException,
|
||||
TypeRangeException,
|
||||
)
|
||||
|
||||
BITS_RE = re.compile(r"[IUF](\d\d?)")
|
||||
|
||||
|
||||
class NumericalType(ValueType, abc.ABC):
|
||||
""" Numerical types that can be serialized using struct and are of some power of 2 byte width """
|
||||
|
||||
@classmethod
|
||||
def __get_bits(cls):
|
||||
def get_bits(cls):
|
||||
""" Gets the integer bits of a given type """
|
||||
match = BITS_RE.match(cls)
|
||||
assert match, "Type {} does not follow format I#Type nor U#Type required of integer types".format(cls)
|
||||
match = BITS_RE.match(cls.__name__)
|
||||
assert (
|
||||
match
|
||||
), "Type {} does not follow format I#Type U#Type nor F#Type required of numerical types".format(
|
||||
cls
|
||||
)
|
||||
return int(match.group(1))
|
||||
|
||||
@classmethod
|
||||
def getSize(cls):
|
||||
""" Gets the size of the integer based on the size specified in the class name """
|
||||
return int(cls.__get_bits()/8)
|
||||
return int(cls.get_bits() / 8)
|
||||
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def get_serialize_format():
|
||||
""" Gets the format serialization string such that the class can be serialized via struct """
|
||||
|
||||
def serialize(self):
|
||||
""" Serializes this type using struct and the val property """
|
||||
if self.val is None:
|
||||
raise NotInitializedException(type(self))
|
||||
return struct.pack(self.get_serialize_format(), self.val)
|
||||
|
||||
def deserialize(self, data, offset):
|
||||
""" Serializes this type using struct and the val property """
|
||||
try:
|
||||
self.val = struct.unpack_from(self.get_serialize_format(), data, offset)[0]
|
||||
except struct.error as err:
|
||||
raise DeserializeException(str(err))
|
||||
|
||||
|
||||
class IntegerType(NumericalType, abc.ABC):
|
||||
@ -38,10 +67,10 @@ class IntegerType(NumericalType, abc.ABC):
|
||||
if not isinstance(val, int):
|
||||
raise TypeMismatchException(int, type(val))
|
||||
min_val = 0
|
||||
max_val = 1 << self.__get_integer_bits()
|
||||
if self.startswith("I"):
|
||||
min_val -= int(max_val/2)
|
||||
max_val -= int(max_val/2)
|
||||
max_val = 1 << self.get_bits()
|
||||
if self.__class__.__name__.startswith("I"):
|
||||
min_val -= int(max_val / 2)
|
||||
max_val -= int(max_val / 2)
|
||||
if val < min_val or val >= max_val:
|
||||
raise TypeRangeException(val)
|
||||
|
||||
@ -66,48 +95,61 @@ class I8Type(IntegerType):
|
||||
|
||||
class I16Type(IntegerType):
|
||||
""" Double byte integer type. Represents C shorts """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
return ">h"
|
||||
|
||||
|
||||
class I32Type(IntegerType):
|
||||
""" Four byte integer type. Represents C int32_t, """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
return ">i"
|
||||
|
||||
|
||||
class I64Type(IntegerType):
|
||||
""" Eight byte integer type. Represents C int64_t, """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
return ">q"
|
||||
|
||||
|
||||
class U8Type(IntegerType):
|
||||
""" Single byte integer type. Represents C chars """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
return "B"
|
||||
|
||||
|
||||
class U16Type(IntegerType):
|
||||
""" Double byte integer type. Represents C shorts """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
return ">H"
|
||||
|
||||
|
||||
class U32Type(IntegerType):
|
||||
""" Four byte integer type. Represents C unt32_t, """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
return ">I"
|
||||
|
||||
|
||||
class U64Type(IntegerType):
|
||||
""" Eight byte integer type. Represents C unt64_t, """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
@ -116,14 +158,16 @@ class U64Type(IntegerType):
|
||||
|
||||
class F32Type(FloatType):
|
||||
""" Eight byte integer type. Represents C unt64_t, """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
return ">f"
|
||||
|
||||
|
||||
class F64Type(IntegerType):
|
||||
class F64Type(FloatType):
|
||||
""" Eight byte integer type. Represents C unt64_t, """
|
||||
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Allows serialization using struct """
|
||||
|
||||
@ -4,12 +4,9 @@ Created on Dec 18, 2014
|
||||
@author: tcanham
|
||||
|
||||
"""
|
||||
import copy
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
from .type_exceptions import TypeMismatchException
|
||||
from .type_exceptions import NotInitializedException
|
||||
|
||||
from .type_base import BaseType, ValueType
|
||||
from .type_exceptions import NotInitializedException, TypeMismatchException
|
||||
|
||||
|
||||
class SerializableType(ValueType):
|
||||
@ -36,10 +33,14 @@ class SerializableType(ValueType):
|
||||
self.__typename = typename
|
||||
# If the member list is defined, stamp in None for any missing descriptions
|
||||
if mem_list:
|
||||
new_mem_list = [entry if len(entry) == 4 else (entry[0], entry[1], entry[2], None) for entry in mem_list]
|
||||
new_mem_list = [
|
||||
entry if len(entry) == 4 else (entry[0], entry[1], entry[2], None)
|
||||
for entry in mem_list
|
||||
]
|
||||
# Set the member list then set the value
|
||||
self.mem_list = new_mem_list
|
||||
self.val = val
|
||||
if val is not None:
|
||||
self.val = val
|
||||
|
||||
def validate(self, val=None):
|
||||
""" Validate this object including member list and values """
|
||||
@ -52,11 +53,11 @@ class SerializableType(ValueType):
|
||||
# Check each of these members for correct types
|
||||
if not isinstance(member_name, str):
|
||||
raise TypeMismatchException(str, type(member_name))
|
||||
elif isinstance(member_val, BaseType):
|
||||
elif not isinstance(member_val, BaseType):
|
||||
raise TypeMismatchException(BaseType, type(member_val))
|
||||
elif not isinstance(format_string, str):
|
||||
raise TypeMismatchException(str, type(format_string))
|
||||
elif not isinstance(description, str):
|
||||
elif description is not None and not isinstance(description, str):
|
||||
raise TypeMismatchException(str, type(description))
|
||||
# When a value is set and is not empty we need to set the member properties
|
||||
if not val:
|
||||
@ -64,7 +65,9 @@ class SerializableType(ValueType):
|
||||
# If a value is supplied then check each value against the member list
|
||||
for val_member, list_entry in zip(val, self.mem_list):
|
||||
_, member_list_val, _, _ = list_entry
|
||||
member_list_val.validate(val_member) # Insure that the the val_member is consistent with the existing member
|
||||
member_list_val.validate(
|
||||
val_member
|
||||
) # Insure that the the val_member is consistent with the existing member
|
||||
|
||||
@property
|
||||
def mem_list(self):
|
||||
@ -84,7 +87,9 @@ class SerializableType(ValueType):
|
||||
""" Serializes the members of the serializable """
|
||||
if self.mem_list is None:
|
||||
raise NotInitializedException(type(self))
|
||||
return b"".join([member_val.serialize() for _, member_val, _, _ in self.mem_list])
|
||||
return b"".join(
|
||||
[member_val.serialize() for _, member_val, _, _ in self.mem_list]
|
||||
)
|
||||
|
||||
def deserialize(self, data, offset):
|
||||
""" Deserialize the values of each of the members """
|
||||
@ -98,16 +103,16 @@ class SerializableType(ValueType):
|
||||
@property
|
||||
def val(self):
|
||||
""" Getter for .val """
|
||||
return super().val
|
||||
return ValueType.val.fget(self)
|
||||
|
||||
@val.setter
|
||||
def val(self, val):
|
||||
""" Setter for .val calls validate internally """
|
||||
super().val = val
|
||||
ValueType.val.fset(self, val)
|
||||
# When a value is set, we need to set the member properties
|
||||
for val_member, list_entry in zip(val, self.mem_list):
|
||||
_, member_list_val, _, _ = list_entry
|
||||
list_entry.val = val_member
|
||||
member_list_val.val = val_member
|
||||
|
||||
def getSize(self):
|
||||
""" The size of a struct is the size of all the members """
|
||||
|
||||
@ -8,11 +8,13 @@ import struct
|
||||
|
||||
from fprime.constants import DATA_ENCODING
|
||||
|
||||
from .type_exceptions import TypeMismatchException
|
||||
from .type_exceptions import NotInitializedException
|
||||
from .type_exceptions import StringSizeException
|
||||
from .type_exceptions import DeserializeException
|
||||
from . import type_base
|
||||
from .type_exceptions import (
|
||||
DeserializeException,
|
||||
NotInitializedException,
|
||||
StringSizeException,
|
||||
TypeMismatchException,
|
||||
)
|
||||
|
||||
|
||||
class StringType(type_base.ValueType):
|
||||
@ -20,6 +22,7 @@ class StringType(type_base.ValueType):
|
||||
String type representation for F prime. This is a value type that stores a half-word first for representing the
|
||||
length of this given string.
|
||||
"""
|
||||
|
||||
def __init__(self, val=None, max_string_len=None):
|
||||
"""
|
||||
Constructor to build a string
|
||||
@ -44,7 +47,9 @@ class StringType(type_base.ValueType):
|
||||
if self.val is None:
|
||||
raise NotInitializedException(type(self))
|
||||
# Check string size before serializing
|
||||
elif self.__max_string_len is not None and len(self.val) > self.__max_string_len:
|
||||
elif (
|
||||
self.__max_string_len is not None and len(self.val) > self.__max_string_len
|
||||
):
|
||||
raise StringSizeException(len(self.val), self.__max_string_len)
|
||||
# Pack the string size first then return the encoded data
|
||||
buff = struct.pack(">H", len(self.val)) + self.val.encode(DATA_ENCODING)
|
||||
@ -57,13 +62,16 @@ class StringType(type_base.ValueType):
|
||||
try:
|
||||
val_size = struct.unpack_from(">H", data, offset)[0]
|
||||
# Deal with not enough data left in the buffer
|
||||
if len(data[offset + 2:]) < val_size:
|
||||
raise DeserializeException("Not enough data to deserialize string data. Needed: {} Left: {}"
|
||||
.format(val_size, len(data[offset + 2:])))
|
||||
if len(data[offset + 2 :]) < val_size:
|
||||
raise DeserializeException(
|
||||
"Not enough data to deserialize string data. Needed: {} Left: {}".format(
|
||||
val_size, len(data[offset + 2 :])
|
||||
)
|
||||
)
|
||||
# Deal with a string that is larger than max string
|
||||
elif self.__max_string_len is not None and val_size > self.__max_string_len:
|
||||
raise StringSizeException(val_size, self.__max_string_len)
|
||||
self.val = data[offset + 2:offset + 2 + val_size].decode(DATA_ENCODING)
|
||||
self.val = data[offset + 2 : offset + 2 + val_size].decode(DATA_ENCODING)
|
||||
except struct.error:
|
||||
raise DeserializeException("Not enough bytes to deserialize string length.")
|
||||
|
||||
@ -71,4 +79,4 @@ class StringType(type_base.ValueType):
|
||||
"""
|
||||
Get the size of this object
|
||||
"""
|
||||
return struct.calcsize(">H") + len(self.val)
|
||||
return struct.calcsize(">H") + len(self.val)
|
||||
|
||||
@ -16,19 +16,18 @@ time tags sent with serialized data in the fprime architecture.
|
||||
|
||||
@bug No known bugs
|
||||
"""
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import datetime
|
||||
|
||||
from enum import Enum
|
||||
import math
|
||||
from enum import Enum
|
||||
|
||||
# Custom Python Modules
|
||||
import fprime.common.models.serialize.numerical_types
|
||||
from fprime.common.models.serialize.type_exceptions import TypeException
|
||||
from fprime.common.models.serialize.type_exceptions import TypeRangeException
|
||||
from fprime.common.models.serialize import type_base
|
||||
from fprime.common.models.serialize.type_exceptions import (
|
||||
TypeException,
|
||||
TypeRangeException,
|
||||
)
|
||||
|
||||
TimeBase = Enum(
|
||||
"TimeBase",
|
||||
@ -55,6 +54,10 @@ class TimeType(type_base.BaseType):
|
||||
|
||||
Used to parse, store, and create human readable versions of the time tags
|
||||
included in serialized output from fprime_gds systems
|
||||
|
||||
Note: comparisons support comparing to numbers or other instances of TimeType. If comparing to
|
||||
another TimeType, these comparisons use the provided compare method. See TimeType.compare for
|
||||
a description of this behavior. See comparison functions at the end.
|
||||
"""
|
||||
|
||||
def __init__(self, time_base=0, time_context=0, seconds=0, useconds=0):
|
||||
@ -82,8 +85,12 @@ class TimeType(type_base.BaseType):
|
||||
self._check_time_base(time_base)
|
||||
self._check_useconds(useconds)
|
||||
|
||||
self.__timeBase = fprime.common.models.serialize.numerical_types.U16Type(time_base)
|
||||
self.__timeContext = fprime.common.models.serialize.numerical_types.U8Type(time_context)
|
||||
self.__timeBase = fprime.common.models.serialize.numerical_types.U16Type(
|
||||
time_base
|
||||
)
|
||||
self.__timeContext = fprime.common.models.serialize.numerical_types.U8Type(
|
||||
time_context
|
||||
)
|
||||
self.__secs = fprime.common.models.serialize.numerical_types.U32Type(seconds)
|
||||
self.__usecs = fprime.common.models.serialize.numerical_types.U32Type(useconds)
|
||||
|
||||
@ -279,7 +286,6 @@ class TimeType(type_base.BaseType):
|
||||
dt = self.get_datetime(time_zone)
|
||||
|
||||
# If we could convert to a valid datetime, use that, otherwise, format
|
||||
# TODO use time_zone arg
|
||||
if dt:
|
||||
return dt.strftime("%Y-%m-%d %H:%M:%S%z")
|
||||
else:
|
||||
@ -329,22 +335,16 @@ class TimeType(type_base.BaseType):
|
||||
self._check_time_base(time_base)
|
||||
self._check_useconds(useconds)
|
||||
|
||||
self.__timeBase = fprime.common.models.serialize.numerical_types.U16Type(time_base)
|
||||
self.__timeBase = fprime.common.models.serialize.numerical_types.U16Type(
|
||||
time_base
|
||||
)
|
||||
self.__secs = fprime.common.models.serialize.numerical_types.U32Type(seconds)
|
||||
self.__usecs = fprime.common.models.serialize.numerical_types.U32Type(useconds)
|
||||
|
||||
def __repr__(self):
|
||||
return "Time"
|
||||
#The following Python special methods add support for rich comparison of TimeTypes to other
|
||||
#TimeTypes and numbers.
|
||||
|
||||
"""
|
||||
The following Python special methods add support for rich comparison of TimeTypes to other
|
||||
TimeTypes and numbers.
|
||||
Note: comparisons support comparing to numbers or other instances of TimeType. If comparing to
|
||||
another TimeType, these comparisons use the provided compare method. See TimeType.compare for
|
||||
a description of this behavior.
|
||||
"""
|
||||
|
||||
def __get_float(self):
|
||||
def get_float(self):
|
||||
"""
|
||||
a helper method that gets the current TimeType as a float where the non-fraction is seconds
|
||||
and the fraction is microseconds. This enables comparisons with numbers.
|
||||
@ -352,46 +352,50 @@ class TimeType(type_base.BaseType):
|
||||
return self.seconds + (self.useconds / 1000000)
|
||||
|
||||
def __lt__(self, other):
|
||||
""" Less than """
|
||||
if isinstance(other, TimeType):
|
||||
return self.compare(self, other) < 0
|
||||
else:
|
||||
return self.__get_float() < other
|
||||
return self.get_float() < other
|
||||
|
||||
def __le__(self, other):
|
||||
""" Less than or equal """
|
||||
if isinstance(other, TimeType):
|
||||
return self.compare(self, other) <= 0
|
||||
else:
|
||||
return self.__get_float() <= other
|
||||
return self.get_float() <= other
|
||||
|
||||
def __eq__(self, other):
|
||||
""" Equal """
|
||||
if isinstance(other, TimeType):
|
||||
return self.compare(self, other) == 0
|
||||
else:
|
||||
return self.__get_float() == other
|
||||
return self.get_float() == other
|
||||
|
||||
def __ne__(self, other):
|
||||
""" Not equal """
|
||||
if isinstance(other, TimeType):
|
||||
return self.compare(self, other) != 0
|
||||
else:
|
||||
return self.__get_float() != other
|
||||
return self.get_float() != other
|
||||
|
||||
def __gt__(self, other):
|
||||
""" Greater than """
|
||||
if isinstance(other, TimeType):
|
||||
return self.compare(self, other) > 0
|
||||
else:
|
||||
return self.__get_float() > other
|
||||
return self.get_float() > other
|
||||
|
||||
def __ge__(self, other):
|
||||
""" Greater than or equal """
|
||||
if isinstance(other, TimeType):
|
||||
return self.compare(self, other) >= 0
|
||||
else:
|
||||
return self.__get_float() >= other
|
||||
return self.get_float() >= other
|
||||
|
||||
"""
|
||||
The following helper methods enable support for arithmetic operations on TimeTypes.
|
||||
"""
|
||||
#The following helper methods enable support for arithmetic operations on TimeTypes.
|
||||
|
||||
def __set_float(self, num):
|
||||
def set_float(self, num):
|
||||
"""
|
||||
a helper method that takes a float and sets a TimeType's seconds and useconds fields.
|
||||
Note: This method is private because it is only used by the _get_type_from_float helper to
|
||||
@ -402,84 +406,89 @@ class TimeType(type_base.BaseType):
|
||||
self.seconds = int(math.floor(num))
|
||||
self.useconds = int(round((num - self.seconds) * 1000000))
|
||||
|
||||
def __get_type_from_float(self, num):
|
||||
def get_type_from_float(self, num):
|
||||
"""
|
||||
a helper method that returns a new instance of TimeType and sets the seconds and useconds
|
||||
fields using the given number. The new TimeType's time_base and time_context will be
|
||||
preserved from the calling object.
|
||||
"""
|
||||
tType = TimeType(self.__timeBase.val, self.__timeContext.val)
|
||||
tType.__set_float(num)
|
||||
tType.set_float(num)
|
||||
return tType
|
||||
|
||||
"""
|
||||
The following Python special methods add support for arithmetic operations on TimeTypes.
|
||||
"""
|
||||
#The following Python special methods add support for arithmetic operations on TimeTypes.
|
||||
|
||||
def __add__(self, other):
|
||||
""" Addition """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = self.__get_float() + other
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = self.get_float() + other
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __sub__(self, other):
|
||||
""" Subtraction """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = self.__get_float() - other
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = self.get_float() - other
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __mul__(self, other):
|
||||
""" Multiplication """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = self.__get_float() * other
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = self.get_float() * other
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __truediv__(self, other):
|
||||
""" True division """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = self.__get_float() / other
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = self.get_float() / other
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
""" Floored divisionv """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = self.__get_float() // other
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = self.get_float() // other
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
"""
|
||||
The following Python special methods add support for reflected arithmetic operations on
|
||||
TimeTypes.
|
||||
"""
|
||||
#The following Python special methods add support for reflected arithmetic operations on TimeTypes.
|
||||
|
||||
def __radd__(self, other):
|
||||
""" Reflected addition """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = other + self.__get_float()
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = other + self.get_float()
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __rsub__(self, other):
|
||||
""" Reflected subtraction """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = other - self.__get_float()
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = other - self.get_float()
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __rmul__(self, other):
|
||||
""" Reflected multiplication """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = other * self.__get_float()
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = other * self.get_float()
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __rtruediv__(self, other):
|
||||
""" Reflected division """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = other / self.__get_float()
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = other / self.get_float()
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
def __rfloordiv__(self, other):
|
||||
""" Reflected floored division """
|
||||
if isinstance(other, TimeType):
|
||||
other = other.__get_float()
|
||||
num = other // self.__get_float()
|
||||
return self.__get_type_from_float(num)
|
||||
other = other.get_float()
|
||||
num = other // self.get_float()
|
||||
return self.get_type_from_float(num)
|
||||
|
||||
|
||||
def ser_deser_test(t_base, t_context, secs, usecs, should_err=False):
|
||||
@ -504,11 +513,11 @@ def ser_deser_test(t_base, t_context, secs, usecs, should_err=False):
|
||||
|
||||
try:
|
||||
val = TimeType(t_base, t_context, secs, usecs)
|
||||
print(("creating: TimeType(%d, %d, %d, %d)" % (t_base, t_context, secs, usecs)))
|
||||
print((str(val)))
|
||||
print("creating: TimeType(%d, %d, %d, %d)" % (t_base, t_context, secs, usecs))
|
||||
print(str(val))
|
||||
|
||||
buff = val.serialize()
|
||||
print(("Serialized: %s" % repr(buff)))
|
||||
print("Serialized: %s" % repr(buff))
|
||||
type_base.showBytes(buff)
|
||||
|
||||
val2 = TimeType()
|
||||
|
||||
@ -6,9 +6,10 @@ Replaced type base class with decorators
|
||||
"""
|
||||
import abc
|
||||
import struct
|
||||
from .type_exceptions import AbstractMethodException
|
||||
from .type_exceptions import DeserializeException
|
||||
from .type_exceptions import NotInitializedException
|
||||
|
||||
from .type_exceptions import (
|
||||
AbstractMethodException
|
||||
)
|
||||
|
||||
|
||||
class BaseType(abc.ABC):
|
||||
@ -21,10 +22,9 @@ class BaseType(abc.ABC):
|
||||
"""
|
||||
Serializes the current object type.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def deserialize(self, offset):
|
||||
def deserialize(self, data, offset):
|
||||
"""
|
||||
AbstractDeserialize interface
|
||||
"""
|
||||
@ -39,14 +39,13 @@ class BaseType(abc.ABC):
|
||||
|
||||
def __repr__(self):
|
||||
""" Produces a string representation of a given type """
|
||||
return type(self).replace("Type", "")
|
||||
return self.__class__.__name__.replace("Type", "")
|
||||
|
||||
@abc.abstractmethod
|
||||
def to_jsonable(self):
|
||||
"""
|
||||
Converts this type to a JSON serializable object
|
||||
"""
|
||||
if hasattr(self, "val"):
|
||||
return {"value": self.val, "type": str(self)}
|
||||
raise AbstractMethodException("to_jsonable")
|
||||
|
||||
|
||||
@ -55,6 +54,7 @@ class ValueType(BaseType, abc.ABC):
|
||||
An abstract base type used to represent a single value. This defines the value property, allowing for setting and
|
||||
reading from the .val member.
|
||||
"""
|
||||
|
||||
def __init__(self, val=None):
|
||||
""" Defines the single value """
|
||||
self.__val = None
|
||||
@ -62,7 +62,6 @@ class ValueType(BaseType, abc.ABC):
|
||||
if val is not None:
|
||||
self.val = val
|
||||
|
||||
|
||||
@abc.abstractmethod
|
||||
def validate(self, val):
|
||||
"""
|
||||
@ -71,7 +70,6 @@ class ValueType(BaseType, abc.ABC):
|
||||
:param val: value to validate
|
||||
:raises TypeMismatchException: value has incorrect type, TypeRangeException: val is out of range
|
||||
"""
|
||||
pass
|
||||
|
||||
@property
|
||||
def val(self):
|
||||
@ -84,66 +82,11 @@ class ValueType(BaseType, abc.ABC):
|
||||
self.validate(val)
|
||||
self.__val = val
|
||||
|
||||
|
||||
@abc.abstractmethod
|
||||
@staticmethod
|
||||
def get_serialize_format():
|
||||
""" Gets the format serialization string such that the class can be serialized via struct """
|
||||
|
||||
def serialize(self):
|
||||
""" Serializes this type using struct and the val property """
|
||||
if self.val is None:
|
||||
raise NotInitializedException(type(self))
|
||||
return struct.pack(self.get_serialize_format(), self.val)
|
||||
|
||||
def deserialize(self, data, offset):
|
||||
""" Serializes this type using struct and the val property """
|
||||
try:
|
||||
self.val = struct.unpack_from(self.get_serialize_format(), data, offset)[0]
|
||||
except struct.error as err:
|
||||
raise DeserializeException(str(err))
|
||||
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
def deserialize(Class):
|
||||
"""
|
||||
Decorator adds common deserialize method
|
||||
"""
|
||||
setattr(Class, "__val", None)
|
||||
|
||||
def _deserialize(self, tformat, data, offset):
|
||||
if offset > (len(data) - len(data[offset:])):
|
||||
raise DeserializeException(
|
||||
"Not enough data to deserialize! Needed: %d Left: %d"
|
||||
% (self.getSize(), offset)
|
||||
)
|
||||
self.val = struct.unpack_from(tformat, data, offset)[0]
|
||||
|
||||
setattr(Class, "_deserialize", _deserialize)
|
||||
|
||||
return Class
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
def serialize(Class):
|
||||
"""
|
||||
Decorator adds common serialize method
|
||||
"""
|
||||
setattr(Class, "__val", None)
|
||||
|
||||
def _serialize(self, tformat, arg=None):
|
||||
if self.val == None:
|
||||
raise NotInitializedException(type(self))
|
||||
if arg == None:
|
||||
return struct.pack(tformat, self.val)
|
||||
else:
|
||||
return struct.pack(tformat, arg)
|
||||
|
||||
setattr(Class, "_serialize", _serialize)
|
||||
return Class
|
||||
def to_jsonable(self):
|
||||
"""
|
||||
Converts this type to a JSON serializable object
|
||||
"""
|
||||
return {"value": self.val, "type": str(self)}
|
||||
|
||||
|
||||
#
|
||||
|
||||
@ -4,14 +4,13 @@ Created on Dec 18, 2014
|
||||
@author: tcanham
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Exception classes for all types
|
||||
|
||||
|
||||
class TypeException(Exception):
|
||||
def __init__(self, val):
|
||||
super().__init__(val)
|
||||
self.except_msg = val
|
||||
|
||||
def getMsg(self):
|
||||
@ -20,33 +19,31 @@ class TypeException(Exception):
|
||||
|
||||
class AbstractMethodException(TypeException):
|
||||
def __init__(self, val):
|
||||
super(AbstractMethodException, self).__init__(
|
||||
"%s must be implemented since it is abstract!" % str(val)
|
||||
)
|
||||
super().__init__("%s must be implemented since it is abstract!" % str(val))
|
||||
|
||||
|
||||
class TypeRangeException(TypeException):
|
||||
def __init__(self, val):
|
||||
super(TypeRangeException, self).__init__("Value %s out of range!" % str(val))
|
||||
super().__init__("Value %s out of range!" % str(val))
|
||||
|
||||
|
||||
class StringSizeException(TypeException):
|
||||
def __init__(self, size, max_size):
|
||||
super(StringSizeException, self).__init__(
|
||||
"String size %s is greater than %s!" % (str(size), str(max_size))
|
||||
super().__init__(
|
||||
"String size {} is greater than {}!".format(str(size), str(max_size))
|
||||
)
|
||||
|
||||
|
||||
class TypeMismatchException(TypeException):
|
||||
def __init__(self, expected_type, actual_type):
|
||||
super(TypeMismatchException, self).__init__(
|
||||
"Type %s expected, type %s found!" % (expected_type, actual_type)
|
||||
super().__init__(
|
||||
"Type {} expected, type {} found!".format(expected_type, actual_type)
|
||||
)
|
||||
|
||||
|
||||
class ArrayLengthException(TypeException):
|
||||
def __init__(self, arr_type, expected_len, actual_len):
|
||||
super(ArrayLengthException, self).__init__(
|
||||
super().__init__(
|
||||
"Array type %s is of length %s, actual length %s found!"
|
||||
% (arr_type, expected_len, actual_len)
|
||||
)
|
||||
@ -54,38 +51,35 @@ class ArrayLengthException(TypeException):
|
||||
|
||||
class EnumMismatchException(TypeException):
|
||||
def __init__(self, enum, bad_member):
|
||||
super(EnumMismatchException, self).__init__(
|
||||
"Invalid enum member %s set in %s enum!" % (bad_member, enum)
|
||||
super().__init__(
|
||||
"Invalid enum member {} set in {} enum!".format(bad_member, enum)
|
||||
)
|
||||
|
||||
|
||||
class DeserializeException(TypeException):
|
||||
def __init__(self, message):
|
||||
super(DeserializeException, self).__init__(message)
|
||||
pass
|
||||
|
||||
|
||||
class ArgNotFoundException(TypeException):
|
||||
def __init__(self, message):
|
||||
super(ArgNotFoundException, self).__init__("Arg %s not found!" % message)
|
||||
super().__init__("Arg %s not found!" % message)
|
||||
|
||||
|
||||
class NotInitializedException(TypeException):
|
||||
def __init__(self, message):
|
||||
super(NotInitializedException, self).__init__(
|
||||
"Instance %s not initialized!" % message
|
||||
)
|
||||
super().__init__("Instance %s not initialized!" % message)
|
||||
|
||||
|
||||
class NotOverridenException(TypeException):
|
||||
def __init__(self, message):
|
||||
super(NotOverridenException, self).__init__(
|
||||
super().__init__(
|
||||
"Required base class method not overrwritten in type %s!" % message
|
||||
)
|
||||
|
||||
|
||||
class ArgLengthMismatchException(TypeException):
|
||||
def __init__(self, arg_length_actual, arg_length_given):
|
||||
super(ArgLengthMismatchException, self).__init__(
|
||||
super().__init__(
|
||||
"%d args provided, but command expects %d args!"
|
||||
% (arg_length_given, arg_length_actual)
|
||||
)
|
||||
@ -93,7 +87,7 @@ class ArgLengthMismatchException(TypeException):
|
||||
|
||||
class CompoundTypeLengthMismatchException(TypeException):
|
||||
def __init__(self, field_length_actual, field_length_given):
|
||||
super(CompoundTypeLengthMismatchException, self).__init__(
|
||||
super().__init__(
|
||||
"%d fields provided, but compound type expects %d fields!"
|
||||
% (field_length_given, field_length_actual)
|
||||
)
|
||||
|
||||
@ -7,28 +7,26 @@ receiver of these delegated functions.
|
||||
|
||||
@author mstarch
|
||||
"""
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import pty
|
||||
import sys
|
||||
import time
|
||||
import shutil
|
||||
import tempfile
|
||||
import subprocess
|
||||
import itertools
|
||||
import functools
|
||||
import collections
|
||||
import selectors
|
||||
|
||||
# Get a cache directory for building CMakeList file, if need and remove at exit
|
||||
import atexit
|
||||
import six
|
||||
import collections
|
||||
import functools
|
||||
import itertools
|
||||
import os
|
||||
import pty
|
||||
import re
|
||||
import selectors
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import fprime.fbuild
|
||||
import fprime.fbuild.settings
|
||||
|
||||
|
||||
class CMakeBuildCache(object):
|
||||
class CMakeBuildCache:
|
||||
"""
|
||||
Builds CMake deployment for the purposes of inspecting that build. This exists because generating a build on every
|
||||
call take a long time. This cache will hold the results to prevent recalculation.
|
||||
@ -64,7 +62,7 @@ class CMakeBuildCache(object):
|
||||
return self.tempdir
|
||||
|
||||
|
||||
class CMakeHandler(object):
|
||||
class CMakeHandler:
|
||||
"""
|
||||
CMake handler interacts with an F prime CMake-based system. This will help us interact with CMake in refined ways.
|
||||
"""
|
||||
@ -156,11 +154,11 @@ class CMakeHandler(object):
|
||||
run_args + fleshed_args, write_override=True, environment=environment
|
||||
)
|
||||
|
||||
def find_hashed_file(self, build_dir, hash):
|
||||
def find_hashed_file(self, build_dir, hash_value):
|
||||
"""
|
||||
Find a file from a hash
|
||||
:param build_dir: build directory to search
|
||||
:param hash: hash number
|
||||
:param hash_value: hash number
|
||||
:return: filename
|
||||
"""
|
||||
hashes_file = os.path.join(build_dir, "hashes.txt")
|
||||
@ -168,9 +166,9 @@ class CMakeHandler(object):
|
||||
raise CMakeException(
|
||||
"Failed to find {}, was the build generated.".format(hashes_file)
|
||||
)
|
||||
with open(hashes_file, "r") as file_handle:
|
||||
with open(hashes_file) as file_handle:
|
||||
lines = filter(
|
||||
lambda line: "{:x}".format(hash) in line, file_handle.readlines()
|
||||
lambda line: "{:x}".format(hash_value) in line, file_handle.readlines()
|
||||
)
|
||||
return list(lines)
|
||||
|
||||
@ -289,7 +287,7 @@ class CMakeHandler(object):
|
||||
:param cmake_dir: a cmake directory (project or build) to used. default: None, use existing temp cached build.
|
||||
:return: list of values, or Nones
|
||||
"""
|
||||
if isinstance(fields, six.string_types):
|
||||
if isinstance(fields, str):
|
||||
fields = [fields]
|
||||
# Setup the build_dir if it can be detected. Without a cache or specified value, we can crash
|
||||
build_dir = self._build_directory_from_cmake_dir(cmake_dir)
|
||||
@ -407,7 +405,7 @@ class CMakeHandler(object):
|
||||
if not os.path.isfile(cmake_file):
|
||||
raise CMakeProjectException(source_dir, "No CMakeLists.txt is defined")
|
||||
# Test the cmake_file for project(
|
||||
with open(cmake_file, "r") as file_handle:
|
||||
with open(cmake_file) as file_handle:
|
||||
project_lines = list(
|
||||
filter(lambda line: "project(" in line, file_handle.readlines())
|
||||
)
|
||||
@ -491,10 +489,7 @@ class CMakeHandler(object):
|
||||
os.close(pty_out_w)
|
||||
os.close(pty_err_w)
|
||||
ret, stdout, stderr = self._communicate(
|
||||
proc,
|
||||
io.open(pty_out_r, mode="rb"),
|
||||
io.open(pty_err_r, mode="rb"),
|
||||
print_output,
|
||||
proc, open(pty_out_r, mode="rb"), open(pty_err_r, mode="rb"), print_output,
|
||||
)
|
||||
# Raising an exception when the return code is non-zero allows us to handle the exception internally if it is
|
||||
# needed. Thus we do not just exit.
|
||||
@ -540,7 +535,7 @@ class CMakeHandler(object):
|
||||
line = key.fileobj.readline().decode().replace("\r\n", "\n")
|
||||
# Some systems (like running inside Docker) raise an io error instead of returning "" when the device
|
||||
# is ended. Not sure why this is, but the effect is the same, on IOError assume end-of-input
|
||||
except IOError:
|
||||
except OSError:
|
||||
line = ""
|
||||
appendable.append(line)
|
||||
# Streams are EOF when the line returned is empty. Once this occurs, we are responsible for closing the
|
||||
@ -568,7 +563,7 @@ class CMakeInconsistencyException(CMakeException):
|
||||
|
||||
def __init__(self, project_cmake, build_dir):
|
||||
""" Force an appropriate message """
|
||||
super(CMakeInconsistencyException, self).__init__(
|
||||
super().__init__(
|
||||
"{} is inconsistent with build {}. Regenerate the build".format(
|
||||
project_cmake, build_dir
|
||||
)
|
||||
@ -580,9 +575,7 @@ class CMakeOrphanException(CMakeException):
|
||||
|
||||
def __init__(self, file_dir):
|
||||
""" Force an appropriate message """
|
||||
super(CMakeOrphanException, self).__init__(
|
||||
"{} is outside the F prime project".format(file_dir)
|
||||
)
|
||||
super().__init__("{} is outside the F prime project".format(file_dir))
|
||||
|
||||
|
||||
class CMakeProjectException(CMakeException):
|
||||
@ -590,7 +583,7 @@ class CMakeProjectException(CMakeException):
|
||||
|
||||
def __init__(self, project_dir, error):
|
||||
""" Force an appropriate message """
|
||||
super(CMakeProjectException, self).__init__(
|
||||
super().__init__(
|
||||
"{} is an invalid F prime deployment. {}".format(project_dir, error)
|
||||
)
|
||||
|
||||
@ -600,7 +593,7 @@ class CMakeInvalidBuildException(CMakeException):
|
||||
|
||||
def __init__(self, build_dir):
|
||||
""" Force an appropriate message """
|
||||
super(CMakeInvalidBuildException, self).__init__(
|
||||
super().__init__(
|
||||
"{} is not a CMake build directory. Please setup using 'fprime-util generate'".format(
|
||||
build_dir
|
||||
)
|
||||
@ -612,7 +605,7 @@ class CMakeExecutionException(CMakeException):
|
||||
|
||||
def __init__(self, message, stderr, printed):
|
||||
""" The error data should be stored """
|
||||
super(CMakeExecutionException, self).__init__(message)
|
||||
super().__init__(message)
|
||||
self.stderr = stderr
|
||||
self.need = not printed
|
||||
|
||||
@ -636,6 +629,4 @@ class CMakeNoSuchTargetException(CMakeException):
|
||||
|
||||
def __init__(self, build_dir, target):
|
||||
""" Better messaging for this exception """
|
||||
super(CMakeNoSuchTargetException, self).__init__(
|
||||
"{} does not support target {}".format(build_dir, target)
|
||||
)
|
||||
super().__init__("{} does not support target {}".format(build_dir, target))
|
||||
|
||||
@ -6,8 +6,8 @@ settings from the settings.default file that is part of the F prime deployment d
|
||||
|
||||
@author mstarch
|
||||
"""
|
||||
import os
|
||||
import configparser # Written after PY2 eol
|
||||
import os
|
||||
|
||||
|
||||
class IniSettings:
|
||||
@ -104,7 +104,7 @@ class IniSettings:
|
||||
config_dir = IniSettings.read_safe_path(
|
||||
confparse, "fprime", "config_directory", settings_file
|
||||
)
|
||||
config_dir = None if not config_dir else ac_consts[0]
|
||||
config_dir = None if not config_dir else config_dir[0]
|
||||
|
||||
# Read separate environment file if necessary
|
||||
env_file = IniSettings.read_safe_path(
|
||||
@ -158,10 +158,6 @@ class IniSettings:
|
||||
class FprimeLocationUnknownException(Exception):
|
||||
""" Fprime location could not be determined """
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class FprimeSettingsException(Exception):
|
||||
""" An exception for handling F prime settings misconfiguration """
|
||||
|
||||
pass
|
||||
|
||||
@ -5,6 +5,7 @@ This acts as the main entry point for the fprime.util module. This allows users
|
||||
This will include the build_helper scripts and run them.
|
||||
"""
|
||||
import sys
|
||||
|
||||
import fprime.util.build_helper
|
||||
|
||||
|
||||
|
||||
@ -13,15 +13,13 @@ are supported herein:
|
||||
|
||||
@author mstarch
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import fprime.fbuild
|
||||
|
||||
|
||||
UT_SUFFIX = "-ut"
|
||||
ACTION_MAP = {
|
||||
"generate": {
|
||||
@ -248,6 +246,7 @@ def parse_args(args):
|
||||
cmake_args, make_args = validate(parsed)
|
||||
return parsed, cmake_args, make_args, automatic_build_dir
|
||||
|
||||
|
||||
def confirm():
|
||||
"""
|
||||
Confirms the removal of the file with a yes or no input.
|
||||
@ -255,18 +254,12 @@ def confirm():
|
||||
"""
|
||||
# Loop "forever"
|
||||
while True:
|
||||
# Py 2/3
|
||||
prompter = input
|
||||
try:
|
||||
prompter = raw_input
|
||||
except NameError:
|
||||
pass
|
||||
confirm = prompter("Purge this directory (yes/no)?")
|
||||
if confirm.lower() in ["y", "yes"]:
|
||||
confirm_input = input("Purge this directory (yes/no)?")
|
||||
if confirm_input.lower() in ["y", "yes"]:
|
||||
return True
|
||||
elif confirm.lower() in ["n", "no"]:
|
||||
elif confirm_input.lower() in ["n", "no"]:
|
||||
return False
|
||||
print("{} is invalid. Please use 'yes' or 'no'".format(confirm))
|
||||
print("{} is invalid. Please use 'yes' or 'no'".format(confirm_input))
|
||||
|
||||
|
||||
def purge_functionality(build_dir, force=False):
|
||||
@ -323,7 +316,7 @@ def utility_entry(args=None):
|
||||
.format("automatic" if automatic_build_dir else "specified", parsed.build_dir + UT_SUFFIX))
|
||||
fprime.fbuild.builder().generate_build(parsed.path, parsed.build_dir + UT_SUFFIX, cmake_args)
|
||||
except Exception as exc:
|
||||
print("[INFO] Error detected, automatically cleaning up failed-generation")
|
||||
print("[INFO] Error detected, automatically cleaning up failed-generation. Error: {}".format(exc))
|
||||
purge_functionality(parsed.build_dir, True)
|
||||
raise
|
||||
else:
|
||||
|
||||
@ -5,20 +5,26 @@ Created on Jun 25, 2020
|
||||
@author: hpaulson
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import pytest
|
||||
|
||||
from fprime.common.models.serialize import type_base
|
||||
from fprime.common.models.serialize.bool_type import BoolType
|
||||
from fprime.common.models.serialize.enum_type import EnumType
|
||||
from fprime.common.models.serialize.numerical_types import I8Type, I16Type, I32Type, I64Type, U8Type, U16Type, U32Type, \
|
||||
U64Type, F32Type, F64Type
|
||||
from fprime.common.models.serialize.numerical_types import (
|
||||
F32Type,
|
||||
F64Type,
|
||||
I8Type,
|
||||
I16Type,
|
||||
I32Type,
|
||||
I64Type,
|
||||
U8Type,
|
||||
U16Type,
|
||||
U32Type,
|
||||
U64Type,
|
||||
)
|
||||
from fprime.common.models.serialize.serializable_type import SerializableType
|
||||
from fprime.common.models.serialize.string_type import StringType
|
||||
from fprime.common.models.serialize.time_type import TimeType
|
||||
from fprime.common.models.serialize.time_type import TimeBase
|
||||
from fprime.common.models.serialize.time_type import ser_deser_test
|
||||
from fprime.common.models.serialize.time_type import TimeBase, TimeType, ser_deser_test
|
||||
|
||||
|
||||
def test_bool_type():
|
||||
|
||||
@ -2,11 +2,12 @@ import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from fprime.common.models.serialize.time_type import TimeType
|
||||
|
||||
filename = os.path.dirname(__file__)
|
||||
fprime_path = os.path.join(filename, "../../../../../src")
|
||||
sys.path.insert(0, fprime_path)
|
||||
|
||||
from fprime.common.models.serialize.time_type import TimeType
|
||||
|
||||
class TimeTypeTestCases(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
||||
@ -7,10 +7,11 @@ that they function as expected.
|
||||
@author mstarch
|
||||
"""
|
||||
import os
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
import fprime.fbuild
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user