2
0
mirror of https://github.com/openkmip/pykmip synced 2026-01-02 00:23:15 +00:00

Updating support for the Enumeration primitive

This change updates the Enumeration primitive, adding a fresh
implementation and documentation. An updated unit test suite for the
primitive is included. Numerous changes to Enumeration usage across the
library are also included to comply with the updated implementation.
This commit is contained in:
Peter Hamilton
2015-09-29 13:23:44 -04:00
parent 55b35b0353
commit 20dbad5055
36 changed files with 732 additions and 529 deletions

View File

@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import enum as enumeration
import logging
import six
import struct
@@ -20,13 +21,10 @@ import sys
import time
from struct import pack, unpack
from enum import Enum
from kmip.core.enums import Types
from kmip.core.enums import Tags
from kmip.core.errors import ErrorStrings
from kmip.core import enums
from kmip.core import errors
from kmip.core import exceptions
from kmip.core import utils
@@ -37,7 +35,7 @@ class Base(object):
TYPE_SIZE = 1
LENGTH_SIZE = 4
def __init__(self, tag=Tags.DEFAULT, type=Types.DEFAULT):
def __init__(self, tag=enums.Tags.DEFAULT, type=enums.Types.DEFAULT):
self.tag = tag
self.type = type
self.length = None
@@ -54,7 +52,7 @@ class Base(object):
tts = istream.read(self.TAG_SIZE)
tag = unpack('!I', b'\x00' + tts[0:self.TAG_SIZE])[0]
enum_tag = Tags(tag)
enum_tag = enums.Tags(tag)
# Verify that the tag matches for the current object
if enum_tag is not self.tag:
@@ -71,7 +69,7 @@ class Base(object):
'{0} bytes'.format(num_bytes))
typ = unpack('!B', tts)[0]
enum_typ = Types(typ)
enum_typ = enums.Types(typ)
if enum_typ is not self.type:
raise errors.ReadValueError(Base.__name__, 'type',
@@ -100,10 +98,10 @@ class Base(object):
ostream.write(pack('!I', self.tag.value)[1:])
def write_type(self, ostream):
if type(self.type) is not Types:
if type(self.type) is not enums.Types:
msg = ErrorStrings.BAD_EXP_RECV
raise TypeError(msg.format(Base.__name__, 'type',
Types, type(self.type)))
enums.Types, type(self.type)))
ostream.write(pack('!B', self.type.value))
def write_length(self, ostream):
@@ -157,8 +155,8 @@ class Base(object):
class Struct(Base):
def __init__(self, tag=Tags.DEFAULT):
super(Struct, self).__init__(tag, type=Types.STRUCTURE)
def __init__(self, tag=enums.Tags.DEFAULT):
super(Struct, self).__init__(tag, type=enums.Types.STRUCTURE)
# NOTE (peter-hamilton) If seen, should indicate repr needs to be defined
def __repr__(self):
@@ -172,8 +170,8 @@ class Integer(Base):
MIN = -2147483648
MAX = 2147483647
def __init__(self, value=None, tag=Tags.DEFAULT, signed=True):
super(Integer, self).__init__(tag, type=Types.INTEGER)
def __init__(self, value=None, tag=enums.Tags.DEFAULT, signed=True):
super(Integer, self).__init__(tag, type=enums.Types.INTEGER)
self.value = value
if self.value is None:
@@ -266,7 +264,7 @@ class LongInteger(Base):
MIN = -9223372036854775808
MAX = 9223372036854775807
def __init__(self, value=0, tag=Tags.DEFAULT):
def __init__(self, value=0, tag=enums.Tags.DEFAULT):
"""
Create a LongInteger.
@@ -275,7 +273,7 @@ class LongInteger(Base):
tag (Tags): An enumeration defining the tag of the LongInteger.
Optional, defaults to Tags.DEFAULT.
"""
super(LongInteger, self).__init__(tag, type=Types.LONG_INTEGER)
super(LongInteger, self).__init__(tag, type=enums.Types.LONG_INTEGER)
self.value = value
self.length = LongInteger.LENGTH
@@ -367,9 +365,10 @@ class BigInteger(Base):
Section 9.1 of the KMIP 1.1 specification.
"""
def __init__(self, value=0, tag=Tags.DEFAULT):
super(BigInteger, self).__init__(tag, type=Types.BIG_INTEGER)
def __init__(self, value=0, tag=enums.Tags.DEFAULT):
super(BigInteger, self).__init__(tag, type=enums.Types.BIG_INTEGER)
self.value = value
self.validate()
def read(self, istream):
@@ -486,41 +485,132 @@ class BigInteger(Base):
return NotImplemented
class Enumeration(Integer):
ENUM_TYPE = None
class Enumeration(Base):
"""
An encodeable object representing an enumeration.
An Enumeration is one of the KMIP primitive object types. It is encoded as
an unsigned, big-endian, 32-bit integer. For more information, see Section
9.1 of the KMIP 1.1 specification.
"""
LENGTH = 4
# Bounds for unsigned 32-bit integers
MIN = 0
MAX = 4294967296
def __init__(self, enum, value=None, tag=enums.Tags.DEFAULT):
"""
Create an Enumeration.
Args:
enum (class): The enumeration class of which value is a member
(e.g., Tags). Required.
value (int): The value of the Enumeration, must be an integer
(e.g., Tags.DEFAULT). Optional, defaults to None.
tag (Tags): An enumeration defining the tag of the Enumeration.
Optional, defaults to Tags.DEFAULT.
"""
super(Enumeration, self).__init__(tag, enums.Types.ENUMERATION)
self.value = value
self.enum = enum
self.length = Enumeration.LENGTH
def __init__(self, value=None, tag=Tags.DEFAULT):
self.enum = value
self.validate()
if self.enum is None:
super(Enumeration, self).__init__(None, tag, False)
else:
super(Enumeration, self).__init__(self.enum.value, tag, False)
self.type = Types.ENUMERATION
def read(self, istream):
"""
Read the encoding of the Enumeration from the input stream.
Args:
istream (stream): A buffer containing the encoded bytes of an
Enumeration. Usually a BytearrayStream object. Required.
Raises:
InvalidPrimitiveLength: if the Enumeration encoding read in has an
invalid encoded length.
InvalidPaddingBytes: if the Enumeration encoding read in does not
use zeroes for its padding bytes.
"""
super(Enumeration, self).read(istream)
self.enum = self.ENUM_TYPE(self.value)
# Check for a valid length before even trying to parse the value.
if self.length != Enumeration.LENGTH:
raise exceptions.InvalidPrimitiveLength(
"enumeration length must be {0}".format(Enumeration.LENGTH))
# Decode the Enumeration value and the padding bytes.
value = unpack('!I', istream.read(Enumeration.LENGTH))[0]
self.value = self.enum(value)
pad = unpack('!I', istream.read(Enumeration.LENGTH))[0]
# Verify that the padding bytes are zero bytes.
if pad is not 0:
raise exceptions.InvalidPaddingBytes("padding bytes must be zero")
self.validate()
def write(self, ostream):
"""
Write the encoding of the Enumeration to the output stream.
Args:
ostream (stream): A buffer to contain the encoded bytes of an
Enumeration. Usually a BytearrayStream object. Required.
"""
super(Enumeration, self).write(ostream)
ostream.write(pack('!I', self.value.value))
ostream.write(pack('!I', 0))
def validate(self):
self.__validate()
"""
Verify that the value of the Enumeration is valid.
def __validate(self):
if self.enum is not None:
if not isinstance(self.enum, Enum):
raise TypeError("expected {0}, observed {1}".format(
type(self.enum), Enum))
Raises:
TypeError: if the enum is not of type Enum
ValueError: if the value is not of the expected Enum subtype or if
the value cannot be represented by an unsigned 32-bit integer
"""
if not isinstance(self.enum, enumeration.EnumMeta):
raise TypeError(
'enumeration type {0} must be of type EnumMeta'.format(
self.enum))
if self.value is not None:
if not isinstance(self.value, self.enum):
raise TypeError(
'enumeration {0} must be of type {1}'.format(
self.value, self.enum))
if type(self.value.value) not in six.integer_types:
raise TypeError('enumeration value must be an int')
else:
if self.value.value > Enumeration.MAX:
raise ValueError(
'enumeration value greater than accepted max')
elif self.value.value < Enumeration.MIN:
raise ValueError(
'enumeration value less than accepted min')
def __repr__(self):
return "{0}(value={1})".format(type(self).__name__, self.enum)
enum = "enum={0}".format(self.enum.__name__)
value = "value={0}".format(self.value)
tag = "tag={0}".format(self.tag)
return "Enumeration({0}, {1}, {2})".format(enum, value, tag)
def __str__(self):
return "{0}.{1}".format(type(self.enum).__name__, self.enum.name)
return str(self.value)
def __eq__(self, other):
if isinstance(other, Enumeration):
return ((self.enum == other.enum) and (self.value == other.value))
else:
return NotImplemented
def __ne__(self, other):
if isinstance(other, Enumeration):
return not self.__eq__(other)
else:
return NotImplemented
class Boolean(Base):
@@ -534,7 +624,7 @@ class Boolean(Base):
"""
LENGTH = 8
def __init__(self, value=True, tag=Tags.DEFAULT):
def __init__(self, value=True, tag=enums.Tags.DEFAULT):
"""
Create a Boolean object.
@@ -543,7 +633,7 @@ class Boolean(Base):
tag (Tags): An enumeration defining the tag of the Boolean object.
Optional, defaults to Tags.DEFAULT.
"""
super(Boolean, self).__init__(tag, type=Types.BOOLEAN)
super(Boolean, self).__init__(tag, type=enums.Types.BOOLEAN)
self.logger = logging.getLogger(__name__)
self.value = value
self.length = self.LENGTH
@@ -649,8 +739,8 @@ class TextString(Base):
PADDING_SIZE = 8
BYTE_FORMAT = '!c'
def __init__(self, value=None, tag=Tags.DEFAULT):
super(TextString, self).__init__(tag, type=Types.TEXT_STRING)
def __init__(self, value=None, tag=enums.Tags.DEFAULT):
super(TextString, self).__init__(tag, type=enums.Types.TEXT_STRING)
if value is None:
self.value = ''
@@ -744,8 +834,8 @@ class ByteString(Base):
PADDING_SIZE = 8
BYTE_FORMAT = '!B'
def __init__(self, value=None, tag=Tags.DEFAULT):
super(ByteString, self).__init__(tag, type=Types.BYTE_STRING)
def __init__(self, value=None, tag=enums.Tags.DEFAULT):
super(ByteString, self).__init__(tag, type=enums.Types.BYTE_STRING)
if value is None:
self.value = bytes()
@@ -843,7 +933,7 @@ class DateTime(LongInteger):
more information, see Section 9.1 of the KMIP 1.1 specification.
"""
def __init__(self, value=None, tag=Tags.DEFAULT):
def __init__(self, value=None, tag=enums.Tags.DEFAULT):
"""
Create a DateTime.
@@ -857,7 +947,7 @@ class DateTime(LongInteger):
if value is None:
value = int(time.time())
super(DateTime, self).__init__(value, tag)
self.type = Types.DATE_TIME
self.type = enums.Types.DATE_TIME
def __repr__(self):
return "DateTime(value={0}, tag={1})".format(self.value, self.tag)
@@ -881,8 +971,8 @@ class Interval(Base):
MIN = 0
MAX = 4294967296
def __init__(self, value=0, tag=Tags.DEFAULT):
super(Interval, self).__init__(tag, type=Types.INTERVAL)
def __init__(self, value=0, tag=enums.Tags.DEFAULT):
super(Interval, self).__init__(tag, type=enums.Types.INTERVAL)
self.value = value
self.length = Interval.LENGTH