Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotation and docstring edits #127

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
317 changes: 200 additions & 117 deletions ebmlite/core.py

Large diffs are not rendered by default.

81 changes: 41 additions & 40 deletions ebmlite/decoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from datetime import datetime, timedelta
import struct
from typing import BinaryIO, Optional, Tuple
import warnings

# ==============================================================================
Expand Down Expand Up @@ -42,10 +43,10 @@
# --- Reading and Decoding
# ==============================================================================

def decodeIntLength(byte):
def decodeIntLength(byte: int) -> Tuple[int, int]:
""" Extract the encoded size from an initial byte.

@return: The size, and the byte with the size removed (it is the first
:return: The size, and the byte with the size removed (it is the first
byte of the value).
"""
# An inelegant implementation, but it's fast.
Expand All @@ -67,11 +68,11 @@ def decodeIntLength(byte):
return 8, 0


def decodeIDLength(byte):
def decodeIDLength(byte: int) -> Tuple[int, int]:
""" Extract the encoded ID size from an initial byte.

@return: The size and the original byte (it is part of the ID).
@raise IOError: raise if the length of an ID is invalid.
:return: The size and the original byte (it is part of the ID).
:raise IOError: raise if the length of an ID is invalid.
"""
if byte >= 128:
return 1, byte
Expand All @@ -86,12 +87,12 @@ def decodeIDLength(byte):
raise IOError('Invalid length for ID: %d' % length)


def readElementID(stream):
def readElementID(stream: BinaryIO) -> Tuple[int, int]:
""" Read an element ID from a file (or file-like stream).

@param stream: The source file-like object.
@return: The decoded element ID and its length in bytes.
@raise IOError: raised if the length of the ID of an element is greater than 4 bytes.
:param stream: The source file-like object.
:return: The decoded element ID and its length in bytes.
:raise IOError: raised if the length of the ID of an element is greater than 4 bytes.
"""
ch = stream.read(1)
length, eid = decodeIDLength(ord(ch))
Expand All @@ -104,11 +105,11 @@ def readElementID(stream):
return eid, length


def readElementSize(stream):
def readElementSize(stream: BinaryIO) -> Tuple[Optional[int], int]:
""" Read an element size from a file (or file-like stream).

@param stream: The source file-like object.
@return: The decoded size (or `None`) and the length of the
:param stream: The source file-like object.
:return: The decoded size (or `None`) and the length of the
descriptor in bytes.
"""
ch = stream.read(1)
Expand All @@ -126,12 +127,12 @@ def readElementSize(stream):
return size, length


def readUInt(stream, size):
def readUInt(stream: BinaryIO, size: int) -> int:
""" Read an unsigned integer from a file (or file-like stream).

@param stream: The source file-like object.
@param size: The number of bytes to read from the stream.
@return: The decoded value.
:param stream: The source file-like object.
:param size: The number of bytes to read from the stream.
:return: The decoded value.
"""

if size == 0:
Expand All @@ -141,12 +142,12 @@ def readUInt(stream, size):
return _struct_uint64_unpack_from(data.rjust(8, b'\x00'))[0]


def readInt(stream, size):
def readInt(stream: BinaryIO, size: int) -> int:
""" Read a signed integer from a file (or file-like stream).

@param stream: The source file-like object.
@param size: The number of bytes to read from the stream.
@return: The decoded value.
:param stream: The source file-like object.
:param size: The number of bytes to read from the stream.
:return: The decoded value.
"""

if size == 0:
Expand All @@ -160,13 +161,13 @@ def readInt(stream, size):
return _struct_int64_unpack_from(data.rjust(8, pad))[0]


def readFloat(stream, size):
""" Read an floating point value from a file (or file-like stream).
def readFloat(stream: BinaryIO, size: int) -> float:
""" Read a floating point value from a file (or file-like stream).

@param stream: The source file-like object.
@param size: The number of bytes to read from the stream.
@return: The decoded value.
@raise IOError: raised if the length of this floating point number is not
:param stream: The source file-like object.
:param size: The number of bytes to read from the stream.
:return: The decoded value.
:raise IOError: raised if the length of this floating point number is not
valid (0, 4, 8 bytes)
"""
if size == 4:
Expand All @@ -180,12 +181,12 @@ def readFloat(stream, size):
"only lengths of 0, 4, or 8 bytes supported." % size)


def readString(stream, size):
def readString(stream: BinaryIO, size: int) -> str:
""" Read an ASCII string from a file (or file-like stream).

@param stream: The source file-like object.
@param size: The number of bytes to read from the stream.
@return: The decoded value.
:param stream: The source file-like object.
:param size: The number of bytes to read from the stream.
:return: The decoded value.
"""
if size == 0:
return u''
Expand All @@ -200,12 +201,12 @@ def readString(stream, size):
return str(value, 'ascii', 'replace')


def readUnicode(stream, size):
""" Read an UTF-8 encoded string from a file (or file-like stream).
def readUnicode(stream: BinaryIO, size: int) -> str:
""" Read a UTF-8 encoded string from a file (or file-like stream).

@param stream: The source file-like object.
@param size: The number of bytes to read from the stream.
@return: The decoded value.
:param stream: The source file-like object.
:param size: The number of bytes to read from the stream.
:return: The decoded value.
"""

if size == 0:
Expand All @@ -216,14 +217,14 @@ def readUnicode(stream, size):
return str(data, 'utf_8')


def readDate(stream, size=8):
def readDate(stream: BinaryIO, size: int = 8) -> datetime:
""" Read an EBML encoded date (nanoseconds since UTC 2001-01-01T00:00:00)
from a file (or file-like stream).

@param stream: The source file-like object.
@param size: The number of bytes to read from the stream.
@return: The decoded value (as `datetime.datetime`).
@raise IOError: raised if the length of the date is not 8 bytes.
:param stream: The source file-like object.
:param size: The number of bytes to read from the stream.
:return: The decoded value (as `datetime.datetime`).
:raise IOError: raised if the length of the date is not 8 bytes.
"""
if size != 8:
raise IOError("Cannot read date value of length %d, only 8." % size)
Expand Down
95 changes: 48 additions & 47 deletions ebmlite/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import datetime
import struct
import sys
from typing import AnyStr, Optional
import warnings

from .decoding import _struct_uint64, _struct_int64
Expand Down Expand Up @@ -45,11 +46,11 @@
# ==============================================================================


def getLength(val):
def getLength(val: int) -> int:
""" Calculate the encoded length of a value.
@param val: A value to be encoded, generally either an ID or a size for
:param val: A value to be encoded, generally either an ID or a size for
an EBML element
@return The minimum length, in bytes, that can be used to represent val
:return The minimum length, in bytes, that can be used to represent val
"""
# Brute force it. Ugly but faster than calculating it.
if val <= 126:
Expand All @@ -70,15 +71,15 @@ def getLength(val):
return 8


def encodeSize(val, length=None):
def encodeSize(val: Optional[int], length: Optional[int] = None) -> bytes:
""" Encode an element size.

@param val: The size to encode. If `None`, the EBML 'unknown' size
:param val: The size to encode. If `None`, the EBML 'unknown' size
will be returned (1 or `length` bytes, all bits 1).
@keyword length: An explicit length for the encoded size. If `None`,
:param length: An explicit length for the encoded size. If `None`,
the size will be encoded at the minimum length required.
@return: an encoded size for an EBML element.
@raise ValueError: raised if the length is invalid, or the length cannot
:return: an encoded size for an EBML element.
:raise ValueError: raised if the length is invalid, or the length cannot
be encoded.
"""
if val is None:
Expand All @@ -98,16 +99,16 @@ def encodeSize(val, length=None):
# --- Encoding
# ==============================================================================

def encodeId(eid, length=None):
def encodeId(eid: int, length: Optional[int] = None) -> bytes:
""" Encode an element ID.

@param eid: The EBML ID to encode.
@keyword length: An explicit length for the encoded data. A `ValueError`
:param eid: The EBML ID to encode.
:param length: An explicit length for the encoded data. A `ValueError`
will be raised if the length is too short to encode the value.
@return: The binary representation of ID, left-padded with ``0x00`` if
:return: The binary representation of ID, left-padded with ``0x00`` if
`length` is not `None`.
@return: The encoded version of the ID.
@raise ValueError: raised if length is less than one or more than 4.
:return: The encoded version of the ID.
:raise ValueError: raised if length is less than one or more than 4.
"""
if length is not None:
if length < 1 or length > 4:
Expand All @@ -119,15 +120,15 @@ def encodeId(eid, length=None):
raise TypeError('Cannot encode {} {!r} as ID'.format(type(eid).__name__, eid))


def encodeUInt(val, length=None):
def encodeUInt(val: int, length: Optional[int] = None) -> bytes:
""" Encode an unsigned integer.

@param val: The unsigned integer value to encode.
@keyword length: An explicit length for the encoded data. A `ValueError`
:param val: The unsigned integer value to encode.
:param length: An explicit length for the encoded data. A `ValueError`
will be raised if the length is too short to encode the value.
@return: The binary representation of val as an unsigned integer,
:return: The binary representation of val as an unsigned integer,
left-padded with ``0x00`` if `length` is not `None`.
@raise ValueError: raised if val is longer than length.
:raise ValueError: raised if val is longer than length.
"""
if isinstance(val, float):
fval, val = val, int(val)
Expand Down Expand Up @@ -155,16 +156,16 @@ def encodeUInt(val, length=None):
return packed.rjust(length, pad)


def encodeInt(val, length=None):
def encodeInt(val: int, length: Optional[int] = None) -> bytes:
""" Encode a signed integer.

@param val: The signed integer value to encode.
@keyword length: An explicit length for the encoded data. A `ValueError`
:param val: The signed integer value to encode.
:param length: An explicit length for the encoded data. A `ValueError`
will be raised if the length is too short to encode the value.
@return: The binary representation of val as a signed integer,
:return: The binary representation of val as a signed integer,
left-padded with either ```0x00`` (for positive values) or ``0xFF``
(for negative) if `length` is not `None`.
@raise ValueError: raised if val is longer than length.
:raise ValueError: raised if val is longer than length.
"""
if isinstance(val, float):
fval, val = val, int(val)
Expand Down Expand Up @@ -194,15 +195,15 @@ def encodeInt(val, length=None):
raise TypeError('Cannot encode {} {!r} as integer'.format(type(val).__name__, val))


def encodeFloat(val, length=None):
def encodeFloat(val: float, length: Optional[int] = None) -> bytes:
""" Encode a floating point value.

@param val: The floating point value to encode.
@keyword length: An explicit length for the encoded data. Must be
:param val: The floating point value to encode.
:param length: An explicit length for the encoded data. Must be
`None`, 0, 4, or 8; otherwise, a `ValueError` will be raised.
@return: The binary representation of val as a float, left-padded with
:return: The binary representation of val as a float, left-padded with
``0x00`` if `length` is not `None`.
@raise ValueError: raised if val not length 0, 4, or 8
:raise ValueError: raised if val not length 0, 4, or 8
"""
if length is None:
if val is None or val == 0.0:
Expand All @@ -224,16 +225,16 @@ def encodeFloat(val, length=None):
raise TypeError('Cannot encode {} {!r} as float'.format(type(val).__name__, val))


def encodeBinary(val, length=None):
def encodeBinary(val: AnyStr, length: Optional[int] = None) -> bytes:
""" Encode binary data.

@param val: A string, bytes, or bytearray containing the data to encode.
@keyword length: An explicit length for the encoded data. A
:param val: A string, bytes, or bytearray containing the data to encode.
:param length: An explicit length for the encoded data. A
`ValueError` will be raised if `length` is shorter than the
actual length of the binary data.
@return: The binary representation of value as binary data, left-padded
:return: The binary representation of value as binary data, left-padded
with ``0x00`` if `length` is not `None`.
@raise ValueError: raised if val is longer than length.
:raise ValueError: raised if val is longer than length.
"""
if val is None:
val = b''
Expand All @@ -251,13 +252,13 @@ def encodeBinary(val, length=None):
(len(val), length))


def encodeString(val, length=None):
def encodeString(val: AnyStr, length: Optional[int] = None) -> bytes:
""" Encode an ASCII string.

@param val: The string (or bytearray) to encode.
@keyword length: An explicit length for the encoded data. The result
:param val: The string (or bytearray) to encode.
:param length: An explicit length for the encoded data. The result
will be truncated if the original string is longer.
@return: The binary representation of val as a string, truncated or
:return: The binary representation of val as a string, truncated or
left-padded with ``0x00`` if `length` is not `None`.
"""
if isinstance(val, str):
Expand All @@ -271,13 +272,13 @@ def encodeString(val, length=None):
return encodeBinary(val.translate(STRING_CHARACTERS), length)


def encodeUnicode(val, length=None):
def encodeUnicode(val: str, length: Optional[int] = None) -> bytes:
""" Encode a Unicode string.

@param val: The Unicode string to encode.
@keyword length: An explicit length for the encoded data. The result
:param val: The Unicode string to encode.
:param length: An explicit length for the encoded data. The result
will be truncated if the original string is longer.
@return: The binary representation of val as a string, truncated or
:return: The binary representation of val as a string, truncated or
left-padded with ``0x00`` if `length` is not `None`.
"""
if not isinstance(val, (bytearray, bytes, str)):
Expand All @@ -291,15 +292,15 @@ def encodeUnicode(val, length=None):
return encodeBinary(val, length)


def encodeDate(val, length=None):
def encodeDate(val: datetime.datetime, length: Optional[int] = None) -> bytes:
""" Encode a `datetime` object as an EBML date (i.e. nanoseconds since
2001-01-01T00:00:00).

@param val: The `datetime.datetime` object value to encode.
@keyword length: An explicit length for the encoded data. Must be
:param val: The `datetime.datetime` object value to encode.
:param length: An explicit length for the encoded data. Must be
`None` or 8; otherwise, a `ValueError` will be raised.
@return: The binary representation of val as an 8-byte dateTime.
@raise ValueError: raised if the length of the input is not 8 bytes.
:return: The binary representation of val as an 8-byte dateTime.
:raise ValueError: raised if the length of the input is not 8 bytes.
"""
if length is None:
length = 8
Expand Down
Loading