Input:
import binascii
import calendar
import six
from datetime import datetime
from datetime import timedelta
from .types import EmbeddedSignatureHeader
from .types import Signature
from ...constants import CompressionAlgorithm
from ...constants import Features as _Features
from ...constants import HashAlgorithm
from ...constants import KeyFlags as _KeyFlags
from ...constants import KeyServerPreferences as _KeyServerPreferences
from ...constants import NotationDataFlags
from ...constants import PubKeyAlgorithm
from ...constants import RevocationKeyClass
from ...constants import RevocationReason
from ...constants import SymmetricKeyAlgorithm
from ...decorators import sdproperty
from ...types import Fingerprint
        from ..packets import SignatureV4
    bits are for future expansion to other kinds of authorizations.  This
    is found on a self-signature.

    If the "sensitive" flag is set, the keyholder feels this subpacket
    contains private trust information that describes a real-world
    sensitive relationship.  If this flag is set, implementations SHOULD
    NOT export this signature to other users except in cases where the
    data needs to be available: when the signature is being sent to the
    designated revoker, or when it is accompanied by a revocation
    signature from that revoker.  Note that it may be appropriate to
    isolate this subpacket within a separate signature so that it is not
    combined with other subpackets that need to be exported.
    """
    __typeid__ = 0x0C

    @sdproperty
    def keyclass(self):
        return self._keyclass

    @keyclass.register(list)
    def keyclass_list(self, val):
        self._keyclass = val

    @keyclass.register(int)
    @keyclass.register(RevocationKeyClass)
    def keyclass_int(self, val):
        self._keyclass += RevocationKeyClass & val

    @keyclass.register(bytearray)
    def keyclass_bytearray(self, val):
        self.keyclass = self.bytes_to_int(val)

    @sdproperty
    def algorithm(self):
        return self._algorithm

    @algorithm.register(int)
    @algorithm.register(PubKeyAlgorithm)
    def algorithm_int(self, val):
        self._algorithm = PubKeyAlgorithm(val)

    @algorithm.register(bytearray)
    def algorithm_bytearray(self, val):
        self.algorithm = self.bytes_to_int(val)

    @sdproperty
    def fingerprint(self):
        return self._fingerprint

    @fingerprint.register(str)
    @fingerprint.register(six.text_type)
    @fingerprint.register(Fingerprint)
    def fingerprint_str(self, val):
        self._fingerprint = Fingerprint(val)

    @fingerprint.register(bytearray)
    def fingerprint_bytearray(self, val):
        self.fingerprint = ''.join('{:02x}'.format(c) for c in val).upper()

    def __init__(self):
        super(RevocationKey, self).__init__()
        self.keyclass = []
        self.algorithm = PubKeyAlgorithm.Invalid
        self._fingerprint = ""

    def __bytearray__(self):
        _bytes = super(RevocationKey, self).__bytearray__()
        _bytes += self.int_to_bytes(sum(self.keyclass))
        _bytes += self.int_to_bytes(self.algorithm.value)
        _bytes += self.fingerprint.__bytes__()
        return _bytes

    def parse(self, packet):
        super(RevocationKey, self).parse(packet)
        self.keyclass = packet[:1]
        del packet[:1]
        self.algorithm = packet[:1]
        del packet[:1]
        self.fingerprint = packet[:20]
        del packet[:20]

class Issuer(Signature):
    __typeid__ = 0x10

    @sdproperty
    def issuer(self):
        return self._issuer

    @issuer.register(bytearray)
    def issuer_bytearray(self, val):
        self._issuer = binascii.hexlify(val).upper().decode('latin-1')

    def __init__(self):
        super(Issuer, self).__init__()
        self.issuer = bytearray()

    def __bytearray__(self):
        _bytes = super(Issuer, self).__bytearray__()
        _bytes += binascii.unhexlify(self._issuer.encode())
        return _bytes

    def parse(self, packet):
        super(Issuer, self).parse(packet)
        self.issuer = packet[:8]
        del packet[:8]

class NotationData(Signature):
    __typeid__ = 0x14

    @sdproperty
    def flags(self):
        return self._flags

    @flags.register(list)
    def flags_list(self, val):
        self._flags = val

    @flags.register(int)

Context:
src/leap/mx/vendor/pgpy/constants.py
class KeyFlags(FlagEnum):
    #: Signifies that a key may be used to certify keys and user ids. Primary keys always have this, even if it is not specified.
    Certify = 0x01
    #: Signifies that a key may be used to sign messages and documents.
    Sign = 0x02
    #: Signifies that a key may be used to encrypt messages.
    EncryptCommunications = 0x04
    #: Signifies that a key may be used to encrypt storage. Currently equivalent to :py:obj:`~pgpy.constants.EncryptCommunications`.
    EncryptStorage = 0x08
    #: Signifies that the private component of a given key may have been split by a secret-sharing mechanism. Split
    #: keys are not currently supported by PGPy.
    Split = 0x10
    #: Signifies that a key may be used for authentication.
    Authentication = 0x20
    #: Signifies that the private component of a key may be in the possession of more than one person.
    MultiPerson = 0x80
src/leap/mx/vendor/pgpy/packet/subpackets/types.py
class EmbeddedSignatureHeader(VersionedHeader):
    def __bytearray__(self):
        return bytearray([self.version])

    def parse(self, packet):
        self.tag = 2
        super(EmbeddedSignatureHeader, self).parse(packet)
src/leap/mx/vendor/pgpy/constants.py
class HashAlgorithm(IntEnum):
    Invalid = 0x00
    MD5 = 0x01
    SHA1 = 0x02
    RIPEMD160 = 0x03
    _reserved_1 = 0x04
    _reserved_2 = 0x05
    _reserved_3 = 0x06
    _reserved_4 = 0x07
    SHA256 = 0x08
    SHA384 = 0x09
    SHA512 = 0x0A
    SHA224 = 0x0B

    def __init__(self, *args):
        super(self.__class__, self).__init__()
        self._tuned_count = 0

    @property
    def hasher(self):
        return hashlib.new(self.name)

    @property
    def digest_size(self):
        return self.hasher.digest_size

    @property
    def tuned_count(self):
        if self._tuned_count == 0:
            self.tune_count()

        return self._tuned_count

    def tune_count(self):
        start = end = 0
        htd = _hashtunedata[:]

        while start == end:
            # potentially do this multiple times in case the resolution of time.time is low enough that
            # hashing 100 KiB isn't enough time to produce a measurable difference
            # (e.g. if the timer for time.time doesn't have enough precision)
            htd = htd + htd
            h = self.hasher

            start = time.time()
            h.update(htd)
            end = time.time()

        # now calculate how many bytes need to be hashed to reach our expected time period
        # GnuPG tunes for about 100ms, so we'll do that as well
        _TIME = 0.100
        ct = int(len(htd) * (_TIME / (end - start)))
        c1 = ((ct >> (ct.bit_length() - 5)) - 16)
        c2 = (ct.bit_length() - 11)
        c = ((c2 << 4) + c1)

        # constrain self._tuned_count to be between 0 and 255
        self._tuned_count = max(min(c, 255), 0)
src/leap/mx/vendor/pgpy/constants.py
class Features(FlagEnum):
    ModificationDetection = 0x01

    @classproperty
    def pgpy_features(cls):
        return Features.ModificationDetection
src/leap/mx/vendor/pgpy/constants.py
class PubKeyAlgorithm(IntEnum):
    Invalid = 0x00
    #: Signifies that a key is an RSA key.
    RSAEncryptOrSign = 0x01
    RSAEncrypt = 0x02  # deprecated
    RSASign = 0x03     # deprecated
    #: Signifies that a key is an ElGamal key.
    ElGamal = 0x10
    #: Signifies that a key is a DSA key.
    DSA = 0x11
    #: Signifies that a key is an ECDH key.
    ECDH = 0x12
    #: Signifies that a key is an ECDSA key.
    ECDSA = 0x13
    FormerlyElGamalEncryptOrSign = 0x14  # deprecated - do not generate
    # DiffieHellman = 0x15  # X9.42

    @property
    def can_gen(self):
        return self in {PubKeyAlgorithm.RSAEncryptOrSign,
                        PubKeyAlgorithm.DSA,
                        PubKeyAlgorithm.ECDSA,
                        PubKeyAlgorithm.ECDH}

    @property
    def can_encrypt(self):  # pragma: no cover
        return self in {PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.ElGamal, PubKeyAlgorithm.ECDH}

    @property
    def can_sign(self):
        return self in {PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.DSA, PubKeyAlgorithm.ECDSA}

    @property
    def deprecated(self):
        return self in {PubKeyAlgorithm.RSAEncrypt,
                        PubKeyAlgorithm.RSASign,
                        PubKeyAlgorithm.FormerlyElGamalEncryptOrSign}
src/leap/mx/vendor/pgpy/types.py
class Fingerprint(str):
    """
    A subclass of ``str``. Can be compared using == and != to ``str``, ``unicode``, and other :py:obj:`Fingerprint` instances.

    Primarily used as a key for internal dictionaries, so it ignores spaces when comparing and hashing
    """
    @property
    def keyid(self):
        return str(self).replace(' ', '')[-16:]

    @property
    def shortid(self):
        return str(self).replace(' ', '')[-8:]

    def __new__(cls, content):
        if isinstance(content, Fingerprint):
            return content

        # validate input before continuing: this should be a string of 40 hex digits
        content = content.upper().replace(' ', '')
        if not bool(re.match(r'^[A-F0-9]{40}$', content)):
            raise ValueError("Expected: String of 40 hex digits")

        # store in the format: "AAAA BBBB CCCC DDDD EEEE  FFFF 0000 1111 2222 3333"
        #                                               ^^ note 2 spaces here
        spaces = [ ' ' if i != 4 else '  ' for i in range(10) ]
        chunks = [ ''.join(g) for g in six.moves.zip_longest(*[iter(content)] * 4) ]
        content = ''.join(j for i in six.moves.zip_longest(chunks, spaces, fillvalue='') for j in i).strip()

        return str.__new__(cls, content)

    def __eq__(self, other):
        if isinstance(other, Fingerprint):
            return str(self) == str(other)

        if isinstance(other, (six.text_type, bytes, bytearray)):
            if isinstance(other, (bytes, bytearray)):  # pragma: no cover
                other = other.decode('latin-1')

            other = str(other).replace(' ', '')
            return any([self.replace(' ', '') == other,
                        self.keyid == other,
                        self.shortid == other])

        return False  # pragma: no cover

    def __ne__(self, other):
        return not (self == other)

    def __hash__(self):
        return hash(str(self.replace(' ', '')))

    def __bytes__(self):
        return binascii.unhexlify(six.b(self.replace(' ', '')))
src/leap/mx/vendor/pgpy/constants.py
class RevocationKeyClass(FlagEnum):
    Sensitive = 0x40
    Normal = 0x80
src/leap/mx/vendor/pgpy/constants.py
class CompressionAlgorithm(IntEnum):
    #: No compression
    Uncompressed = 0x00
    #: ZIP DEFLATE
    ZIP = 0x01
    #: ZIP DEFLATE with zlib headers
    ZLIB = 0x02
    #: Bzip2
    BZ2 = 0x03

    def compress(self, data):
        if self is CompressionAlgorithm.Uncompressed:
            return data

        if self is CompressionAlgorithm.ZIP:
            return zlib.compress(data)[2:-4]

        if self is CompressionAlgorithm.ZLIB:
            return zlib.compress(data)

        if self is CompressionAlgorithm.BZ2:
            return bz2.compress(data)

        raise NotImplementedError(self)

    def decompress(self, data):
        if six.PY2:
            data = bytes(data)

        if self is CompressionAlgorithm.Uncompressed:
            return data

        if self is CompressionAlgorithm.ZIP:
            return zlib.decompress(data, -15)

        if self is CompressionAlgorithm.ZLIB:
            return zlib.decompress(data)

        if self is CompressionAlgorithm.BZ2:
            return bz2.decompress(data)

        raise NotImplementedError(self)
src/leap/mx/vendor/pgpy/decorators.py
def sdproperty(fget):
    def defset(obj, val):  # pragma: no cover
        raise TypeError(str(val.__class__))

    class SDProperty(property):
        def register(self, cls=None, fset=None):
            return self.fset.register(cls, fset)

        def setter(self, fset):
            self.register(object, fset)
            return type(self)(self.fget, self.fset, self.fdel, self.__doc__)

    return SDProperty(fget, sdmethod(defset))
src/leap/mx/vendor/pgpy/constants.py
class NotationDataFlags(FlagEnum):
    HumanReadable = 0x80
src/leap/mx/vendor/pgpy/constants.py
class SymmetricKeyAlgorithm(IntEnum):
    """Supported symmetric key algorithms."""
    Plaintext = 0x00
    #: .. warning::
    #:     IDEA is insecure. PGPy only allows it to be used for decryption, not encryption!
    IDEA = 0x01
    #: Triple-DES with 168-bit key derived from 192
    TripleDES = 0x02
    #: CAST5 (or CAST-128) with 128-bit key
    CAST5 = 0x03
    #: Blowfish with 128-bit key and 16 rounds
    Blowfish = 0x04
    #: AES with 128-bit key
    AES128 = 0x07
    #: AES with 192-bit key
    AES192 = 0x08
    #: AES with 256-bit key
    AES256 = 0x09
    # Twofish with 256-bit key - not currently supported
    Twofish256 = 0x0A
    #: Camellia with 128-bit key
    Camellia128 = 0x0B
    #: Camellia with 192-bit key
    Camellia192 = 0x0C
    #: Camellia with 256-bit key
    Camellia256 = 0x0D

    @property
    def cipher(self):
        bs = {SymmetricKeyAlgorithm.IDEA: algorithms.IDEA,
              SymmetricKeyAlgorithm.TripleDES: algorithms.TripleDES,
              SymmetricKeyAlgorithm.CAST5: algorithms.CAST5,
              SymmetricKeyAlgorithm.Blowfish: algorithms.Blowfish,
              SymmetricKeyAlgorithm.AES128: algorithms.AES,
              SymmetricKeyAlgorithm.AES192: algorithms.AES,
              SymmetricKeyAlgorithm.AES256: algorithms.AES,
              SymmetricKeyAlgorithm.Twofish256: namedtuple('Twofish256', ['block_size'])(block_size=128),
              SymmetricKeyAlgorithm.Camellia128: algorithms.Camellia,
              SymmetricKeyAlgorithm.Camellia192: algorithms.Camellia,
              SymmetricKeyAlgorithm.Camellia256: algorithms.Camellia}

        if self in bs:
            return bs[self]

        raise NotImplementedError(repr(self))

    @property
    def is_insecure(self):
        insecure_ciphers = {SymmetricKeyAlgorithm.IDEA}
        return self in insecure_ciphers

    @property
    def block_size(self):
        return self.cipher.block_size

    @property
    def key_size(self):
        ks = {SymmetricKeyAlgorithm.IDEA: 128,
              SymmetricKeyAlgorithm.TripleDES: 192,
              SymmetricKeyAlgorithm.CAST5: 128,
              SymmetricKeyAlgorithm.Blowfish: 128,
              SymmetricKeyAlgorithm.AES128: 128,
              SymmetricKeyAlgorithm.AES192: 192,
              SymmetricKeyAlgorithm.AES256: 256,
              SymmetricKeyAlgorithm.Twofish256: 256,
              SymmetricKeyAlgorithm.Camellia128: 128,
              SymmetricKeyAlgorithm.Camellia192: 192,
              SymmetricKeyAlgorithm.Camellia256: 256}

        if self in ks:
            return ks[self]

        raise NotImplementedError(repr(self))

    def gen_iv(self):
        return os.urandom(self.block_size // 8)

    def gen_key(self):
        return os.urandom(self.key_size // 8)
src/leap/mx/vendor/pgpy/constants.py
class KeyServerPreferences(IntEnum):
    Unknown = 0x00
    NoModify = 0x80
src/leap/mx/vendor/pgpy/packet/subpackets/types.py
class Signature(SubPacket):
    __typeid__ = -1
src/leap/mx/vendor/pgpy/constants.py
class RevocationReason(IntEnum):
    #: No reason was specified. This is the default reason.
    NotSpecified = 0x00
    #: The key was superseded by a new key. Only meaningful when revoking a key.
    Superseded = 0x01
    #: Key material has been compromised. Only meaningful when revoking a key.
    Compromised = 0x02
    #: Key is retired and no longer used. Only meaningful when revoking a key.
    Retired = 0x03
    #: User ID information is no longer valid. Only meaningful when revoking a certification of a user id.
    UserID = 0x20

Answer: @flags.register(NotationDataFlags)


Input:
import abc
import itertools
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
from cliff.command import Command
from audeep.backend.data.data_set import load, Partition
from audeep.backend.enum_parser import EnumType
from audeep.backend.evaluation import CrossValidatedEvaluation, PartitionedEvaluation
from audeep.backend.formatters import ConfusionMatrixFormatter
from audeep.backend.learners import TensorflowMLPLearner, LearnerBase, LibLINEARLearner
from audeep.backend.log import LoggingMixin
                            action="store_true",
                            help="Balance classes in the training partitions/splits")
        parser.add_argument("--majority-vote",
                            action="store_true",
                            help="Use majority voting to determine the labels of chunked instances")
        parser.add_argument("--repeat",
                            metavar="N",
                            default=1,
                            type=int,
                            help="Repeat evaluation N times and compute the mean accuracy (default 1)")

        return parser

    def plot_confusion_matrix(self, cm, classes,
                              normalize=False,
                              title='Confusion matrix',
                              cmap="Blues"):
        """
        This function plots the confusion matrix.
        Normalization can be applied by setting `normalize=True`.
        """
        cm_norm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        plt.imshow(cm_norm, interpolation='nearest', cmap=cmap)
        plt.title(title)
        plt.colorbar()
        tick_marks = np.arange(len(classes))
        plt.xticks(tick_marks, classes, rotation=90)
        plt.yticks(tick_marks, classes)

        if normalize:
            cm = cm_norm

        thresh = cm.max() / 2.
        for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
            if normalize:
                plt.text(j, i, "%1.2f" % cm[i, j],
                         horizontalalignment="center",
                         color="white" if cm[i, j] > thresh else "black")
            else:
                plt.text(j, i, "%.0f" % cm[i, j],
                         horizontalalignment="center",
                         color="white" if cm[i, j] > thresh else "black")

        plt.tight_layout()
        plt.ylabel('True label')
        plt.xlabel('Predicted label')
        plt.show()

    @abc.abstractmethod
    def _get_learner(self, parsed_args) -> LearnerBase:
        pass

    def take_action(self, parsed_args):
        self._learner = self._get_learner(parsed_args)

        if not parsed_args.input.exists():
            raise IOError("failed to open data file at {}".format(parsed_args.input))

        if parsed_args.train_partitions is None and parsed_args.eval_partitions is None and not parsed_args.cross_validate:
            raise ValueError("must select either cross validated or partitioned evaluation")
        if (parsed_args.train_partitions is not None or parsed_args.eval_partitions is not None) \
                and parsed_args.cross_validate:
            raise ValueError("partitioned evaluation and cross validated evaluation are mutually exclusive")
        if not parsed_args.cross_validate and ((parsed_args.train_partitions is not None)
                                                   ^ (parsed_args.eval_partitions is not None)):
            raise ValueError("at least one train and eval partition required")

        data_set = load(parsed_args.input)

        accuracies = []
        uars = []
        confusion_matrices = []

        if parsed_args.cross_validate:
            accuracy_confidence_intervals = []
            uar_confidence_intervals = []

            for _ in range(parsed_args.repeat):
                evaluation = CrossValidatedEvaluation(learner=self._learner,
                                                      upsample=parsed_args.upsample,
                                                      majority_vote=parsed_args.majority_vote)
                evaluation.run(data_set)

                accuracies.append(evaluation.accuracy)
                uars.append(evaluation.uar)
                accuracy_confidence_intervals.append(evaluation.accuracy_confidence_interval)
                uar_confidence_intervals.append(evaluation.uar_confidence_interval)
                confusion_matrices.append(evaluation.confusion_matrix)

            accuracy = np.mean(accuracies)
            accuracy_confidence_interval = np.mean(accuracy_confidence_intervals)
            uar = np.mean(uars)
            uar_confidence_interval = np.mean(uar_confidence_intervals)

            self.log.info("cross validation accuracy: %2.2f%% (+/- %2.2f%%)", 100 * accuracy,
                          100 * accuracy_confidence_interval)
            self.log.info("cross validation UAR: %2.2f%% (+/- %2.2f%%)", 100 * uar, 100 * uar_confidence_interval)
        else:
            for _ in range(parsed_args.repeat):
                # noinspection PyTypeChecker
                evaluation = PartitionedEvaluation(learner=self._learner,
                                                   train_partitions=parsed_args.train_partitions,
                                                   eval_partitions=parsed_args.eval_partitions,
                                                   upsample=parsed_args.upsample,
                                                   majority_vote=parsed_args.majority_vote)
                evaluation.run(data_set)

                accuracies.append(evaluation.accuracy)
                uars.append(evaluation.uar)
                confusion_matrices.append(evaluation.confusion_matrix)

            accuracy = np.mean(accuracies)
            uar = np.mean(uars)

            # noinspection PyTypeChecker,PyStringFormat
            self.log.info("accuracy on %s: %2.2f%% (UAR %2.2f%%)" % (
                " & ".join([p.name for p in parsed_args.eval_partitions]), 100 * accuracy, 100 * uar))

        confusion_matrix = np.sum(confusion_matrices, axis=0)

Context:
audeep/backend/formatters.py
class ConfusionMatrixFormatter:
    """
    Formatter for printing a confusion matrix with labels to stdout.
    """

    def __init__(self,
                 decimals: int = None,
                 normalize: bool = False,
                 abbrev_labels: int = 3):
        """
        Create a new ConfusionMatrixFormatter.

        Number of decimals can only be specified if normalization is enabled, otherwise it is ignored.

        Parameters
        ----------
        decimals: int, optional
            Number of decimals to print for each confusion matrix entry
        normalize: bool, default False
            Normalize confusion matrix to represent probabilities instead of counts.
        abbrev_labels: int, default 3
            Abbreviate nominal labels to have the specified length
        """
        self._normalize = normalize
        self._abbrev_labels = abbrev_labels

        if normalize:
            if decimals is not None:
                self._decimals = decimals
            else:
                self._decimals = 2

    def format(self,
               confusion_matrix: np.ndarray,
               label_map: Mapping[str, int]) -> str:
        """
        Print the specified confusion matrix using the specified label map.

        The `confusion_matrix` parameter must be a square numpy matrix, and the `label_map` parameter must be a mapping
        of nominal to numeric labels, containing one entry for each confusion matrix row/column.

        Parameters
        ----------
        confusion_matrix: numpy.ndarray
            A confusion matrix
        label_map: map of str to int
            A label map

        Returns
        -------
        str
            A string representation of the confusion matrix
        """
        if len(confusion_matrix.shape) != 2:
            raise ValueError("confusion matrix must be 2D, is: {}".format(len(confusion_matrix.shape)))
        elif confusion_matrix.shape[0] != confusion_matrix.shape[1]:
            raise ValueError("confusion matrix must be square, is {}".format(confusion_matrix.shape))
        elif confusion_matrix.shape[0] != len(label_map):
            raise ValueError("number of labels must match confusion matrix size, expected: {}, got: {}"
                             .format(confusion_matrix.shape[0], len(label_map)))

        # order nominal labels by numeric values
        ordered_labels = sorted(label_map.items(), key=lambda t: t[1])
        ordered_labels = list(zip(*ordered_labels))[0]

        if self._abbrev_labels is not None:
            ordered_labels = [label[:self._abbrev_labels] if len(label) > self._abbrev_labels else label
                              for label in ordered_labels]

        max_label_len = max(map(len, ordered_labels))

        if self._normalize:
            confusion_matrix = confusion_matrix / np.sum(confusion_matrix, axis=1)[:, np.newaxis]

            column_width = max(2 + self._decimals, max_label_len)
            number_pattern = " %%%d.%df" % (column_width, self._decimals)
        else:
            max_digits = int(math.ceil(math.log10(np.max(confusion_matrix))))

            column_width = max(max_digits, max_label_len)
            number_pattern = " %%%dd" % column_width

        result = ""

        label_pattern = "%%%ds" % column_width

        # print header row
        for col in range(confusion_matrix.shape[1] + 1):
            if col == 0:
                result += " " * max_label_len
            else:
                result += " " + label_pattern % ordered_labels[col - 1]

        result += "\n"

        label_pattern = "%%%ds" % max_label_len

        for row in range(confusion_matrix.shape[0]):
            result += label_pattern % ordered_labels[row]

            for col in range(confusion_matrix.shape[1]):
                result += number_pattern % confusion_matrix[row, col]

            result += "\n"

        return result
audeep/backend/learners.py
class TensorflowMLPLearner(LearnerBase):
    """
    A learner using Tensorflow to build an MLP classifier.
    """

    def __init__(self,
                 checkpoint_dir: Path,
                 num_layers: int,
                 num_units: int,
                 learning_rate=0.001,
                 num_epochs=400,
                 keep_prob=0.6,
                 shuffle_training=False):
        """
        Create and initialize a new TensorflowMLPLearner with the specified parameters.

        Due to limitations of Tensorflow (or my inability to find a better solution), this learner has to serialize
        trained model to the hard disk between invocations of the `fit` and `predict` methods.

        Furthermore, the entire training data is copied to GPU memory to increase training performance. Thus, only
        moderately-sized models can be trained using this learner.

        Parameters
        ----------
        checkpoint_dir: pathlib.Path
            A directory in which temporary models can be stored
        num_layers: int
            The number of layers in the MLP
        num_units: int
            The number of units in each layer
        learning_rate: float, default 0.001
            The learning rate for training
        num_epochs: int, default 400
            The number of training epochs
        keep_prob: float, default 0.6
            The probability to keep hidden activations
        shuffle_training: bool, default False
            Shuffle training data between epochs
        """
        self._checkpoint_dir = checkpoint_dir
        self._latest_checkpoint = None
        self._num_labels = None
        self._model = MLPModel(num_layers, num_units)
        self._learning_rate = learning_rate
        self._num_epochs = num_epochs
        self._keep_prob = keep_prob
        self._shuffle_training = shuffle_training

    def fit(self,
            data_set: DataSet):
        # generic parameter checks
        super().fit(data_set)

        self._num_labels = len(data_set.label_map)

        graph = tf.Graph()

        with graph.as_default():
            tf_inputs = tf.Variable(initial_value=data_set.features, trainable=False, dtype=tf.float32)
            tf_labels = tf.Variable(initial_value=data_set.labels_numeric, trainable=False, dtype=tf.int32)

            if self._shuffle_training:
                tf_inputs = tf.random_shuffle(tf_inputs, seed=42)
                tf_labels = tf.random_shuffle(tf_labels, seed=42)

            with tf.variable_scope("mlp"):
                tf_logits = self._model.inference(tf_inputs, self._keep_prob, self._num_labels)
                tf_loss = self._model.loss(tf_logits, tf_labels)
                tf_train_op = self._model.optimize(tf_loss, self._learning_rate)

            tf_init_op = tf.global_variables_initializer()
            tf_saver = tf.train.Saver(tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="mlp"))

        session = tf.Session(graph=graph)
        session.run(tf_init_op)

        for epoch in range(self._num_epochs):
            session.run(tf_train_op)

        # timestamped model file
        self._latest_checkpoint = self._checkpoint_dir / "model_{:%Y%m%d%H%M%S%f}".format(datetime.datetime.now())
        tf_saver.save(session, str(self._latest_checkpoint), write_meta_graph=False)

        session.close()

    def predict(self,
                data_set: DataSet):
        # generic parameter checks
        super().predict(data_set)

        if self._latest_checkpoint is None:
            raise RuntimeError("no model has been built yet. Invoke fit before predict")

        graph = tf.Graph()

        with graph.as_default():
            tf_inputs = tf.placeholder(shape=[None, self.num_features], dtype=tf.float32, name="inputs")

            with tf.variable_scope("mlp"):
                tf_logits = self._model.inference(tf_inputs, 1.0, self._num_labels)
                tf_prediction = self._model.prediction(tf_logits)

            tf_saver = tf.train.Saver(tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="mlp"))

        with tf.Session(graph=graph) as session:
            tf_saver.restore(session, str(self._latest_checkpoint))

            predictions = session.run(tf_prediction, feed_dict={tf_inputs: data_set.features})

        return predictions
audeep/backend/data/data_set.py
def load(path: Path) -> DataSet:
    """
    Loads a data set from the specified NetCDF4 file.

    Parameters
    ----------
    path: pathlib.Path
        Path to the file which should be loaded.

    Returns
    -------
    DataSet
        The data set loaded from the specified file
    """
    log = logging.getLogger(__name__)
    log.info("loading data set from %s", path)

    data = xr.open_dataset(str(path))  # type: xr.Dataset

    # restore data types
    data[_DataVar.FILENAME] = data[_DataVar.FILENAME].astype(np.object).fillna(None)
    data[_DataVar.CHUNK_NR] = data[_DataVar.CHUNK_NR].astype(np.object).fillna(None)
    data[_DataVar.CV_FOLDS] = data[_DataVar.CV_FOLDS].astype(np.object).fillna(None)
    data[_DataVar.PARTITION] = data[_DataVar.PARTITION].astype(np.object).fillna(None)
    data[_DataVar.LABEL_NOMINAL] = data[_DataVar.LABEL_NOMINAL].astype(np.object).fillna(None)
    data[_DataVar.LABEL_NUMERIC] = data[_DataVar.LABEL_NUMERIC].astype(np.object)
    data[_DataVar.FEATURES] = data[_DataVar.FEATURES].astype(np.float32)

    return DataSet(data=data,
                   mutable=False)
audeep/backend/learners.py
class LibLINEARLearner(LearnerBase):
    """
    A learner using LibLINEAR for classification.
    """

    def __init__(self,
                 complexity: float):
        """
        Create and initialize a new LibLINEARLearner with the specified SVM complexity parameter.

        Parameters
        ----------
        complexity: float
            The SVM complexity parameter
        """
        self._model = LinearSVC(C=complexity)

    def fit(self,
            data_set: DataSet):
        # generic parameter checks
        super().fit(data_set)

        self._model.fit(X=data_set.features, y=data_set.labels_numeric)

    def predict(self,
                data_set: DataSet):
        # generic parameter checks
        super().predict(data_set)

        return self._model.predict(data_set.features)
audeep/backend/evaluation.py
class CrossValidatedEvaluation(LoggingMixin):
    """
    Cross-validated evaluation of a learner on some data.

    Given a data set and a learner, this class computes cross-validated accuracy and unweighted average recall, and a
    95% confidence interval for both values. Additionally, a confusion matrix is summed over all cross-validation folds.
    """

    def __init__(self,
                 learner: LearnerBase,
                 upsample: bool,
                 majority_vote: bool):
        """
        Creates and initializes a new cross-validated evaluation of the specified learner.

        The `run` method has to be invoked on some data before results can be retrieved.

        Parameters
        ----------
        learner: LearnerBase
            A learner which should be evaluated
        upsample: bool
            Balance classes in the training splits of each fold by upsampling instances
        """
        super().__init__()

        self._learner = learner
        self._upsample = upsample
        self._majority_vote = majority_vote
        self._accuracy = None
        self._accuracy_confidence_interval = None
        self._uar = None
        self._uar_confidence_interval = None
        self._confusion_matrix = None

    @property
    def accuracy(self) -> float:
        """
        Returns the accuracy of the learner.

        This property returns the accuracy on the last data set on which the `run` method has been invoked. As a
        consequence, this property returns None if the `run` method has not yet been invoked.

        Returns
        -------
        float
            Returns the accuracy of the learner on the last data set passed to the `run` method
        """
        return self._accuracy

    @property
    def accuracy_confidence_interval(self) -> float:
        """
        Returns a 95% confidence interval for the accuracy of the learner.

        This property returns the confidence interval on the last data set on which the `run` method has been invoked.
        As a consequence, this property returns None if the `run` method has not yet been invoked.

        Returns
        -------
        float
            Returns a 95% confidence interval for the accuracy of the learner on the last data set passed to the `run`
            method
        """
        return self._accuracy_confidence_interval

    @property
    def uar(self) -> float:
        """
        Returns the unweighted average recall of the learner.

        This property returns the unweighted average recall on the last data set on which the `run` method has been
        invoked. As a consequence, this property returns None if the `run` method has not yet been invoked.

        Returns
        -------
        float
            Returns the unweighted average recall of the learner on the last data set passed to the `run` method
        """
        return self._uar

    @property
    def uar_confidence_interval(self) -> float:
        """
        Returns a 95% confidence interval for the unweighted average recall of the learner.

        This property returns the confidence interval on the last data set on which the `run` method has been invoked.
        As a consequence, this property returns None if the `run` method has not yet been invoked.

        Returns
        -------
        float
            Returns a 95% confidence interval for the unweighted average recall of the learner on the last data set
            passed to the `run` method
        """
        return self._uar_confidence_interval

    @property
    def confusion_matrix(self) -> np.ndarray:
        """
        Returns the confusion matrix of the learner.

        This property returns the confusion matrix on the last data set on which the `run` method has been invoked.
        As a consequence, this property returns None if the `run` method has not yet been invoked. The confusion matrix
        is computed as the sum of the confusion matrices on the individual cross-validation folds.

        Returns
        -------
        numpy.ndarray
            The confusion matrix of the learner on the last data set passed to the `run` method
        """
        return self._confusion_matrix

    def run(self,
            data_set: DataSet):
        """
        Evaluates the learner on the specified data set using cross-validation.

        Sets the various properties of this instance to the values obtained during evaluation on the specified data set.

        Parameters
        ----------
        data_set: DataSet
            The data set on which the learner should be evaluated

        Raises
        ------
        ValueError
            If the specified data set does not have cross-validation information
        """
        if not data_set.has_cv_info:
            raise ValueError("data set does not have cross validation info")

        accuracies = []
        uars = []
        confusion_matrices = []

        # order numeric labels by nominal value
        ordered_labels = sorted(data_set.label_map.items(), key=lambda t: t[0])
        ordered_labels = list(zip(*ordered_labels))[1]

        for fold in range(data_set.num_folds):
            self.log.info("processing cross validation fold %d...", fold + 1)

            learner_wrapper = PreProcessingWrapper(learner=self._learner,
                                                   upsample=self._upsample,
                                                   majority_vote=self._majority_vote)

            train_split = data_set.split(fold=fold,
                                         split=Split.TRAIN)
            valid_split = data_set.split(fold=fold,
                                         split=Split.VALID)

            learner_wrapper.fit(train_split)

            # IMPORTANT: these methods return maps of filename to label, since order may (or most certainly will) be
            # different
            predictions = learner_wrapper.predict(valid_split)
            true_labels = valid_split.filename_labels_numeric

            # sort labels and predictions by filename
            predictions = np.array([item[1] for item in sorted(predictions.items(), key=lambda item: item[0])])
            true_labels = np.array([item[1] for item in sorted(true_labels.items(), key=lambda item: item[0])])

            accuracy = accuracy_score(true_labels, predictions)
            uar = uar_score(true_labels, predictions)

            accuracies.append(accuracy)
            uars.append(uar)
            confusion_matrices.append(confusion_matrix(y_true=true_labels,
                                                       y_pred=predictions,
                                                       labels=ordered_labels))

            self.log.info("fold %d accuracy is %2.2f%% (UAR %2.2f%%)", fold + 1, 100 * accuracy, 100 * uar)

        self._accuracy = np.mean(accuracies)
        self._accuracy_confidence_interval = 2 * np.std(accuracies)
        self._uar = np.mean(uars)
        self._uar_confidence_interval = 2 * np.std(uars)
        self._confusion_matrix = np.sum(confusion_matrices, axis=0)
audeep/backend/learners.py
class LearnerBase:
    """
    Defines a common interface for all classification algorithms.
    """
    __metaclass__ = ABCMeta

    _num_features = None

    @property
    def num_features(self):
        """
        Returns the number of features for which the learner was trained.

        This property is updated each time the `fit` method is called on some data. Any subsequent calls to the
        `predict` method then expect the same number of features.

        Returns
        -------
        int
            The number of features for which the learner was trained
        """
        return self._num_features

    @abstractmethod
    def fit(self,
            data_set: DataSet):
        """
        Fit the learner to the specified data.

        Parameters
        ----------
        data_set: DataSet
            The data set on which to train the learner. Must be fully labelled.

        Raises
        ------
        ValueError
            If the feature matrix has invalid shape
        """
        if len(data_set.feature_shape) != 1:
            raise ValueError("invalid number of feature dimensions: {}".format(len(data_set.feature_shape)))

        self._num_features = data_set.feature_shape[0]

    @abstractmethod
    def predict(self,
                data_set: DataSet):
        """
        Predict the labels of the specified data set.

        Parameters
        ----------
        data_set: DataSet
            Data set containing instances for which to predict labels.

        Returns
        -------
        numpy.ndarray
            The predicted labels of the specified data

        Raises
        ------
        ValueError
            If the specified feature matrix has invalid shape
        """
        if len(data_set.feature_shape) != 1:
            raise ValueError("invalid number of feature dimensions: {}".format(len(data_set.feature_shape)))
        if data_set.feature_shape[0] != self.num_features:
            raise ValueError("learner was trained with different number of features")
audeep/backend/log.py
class LoggingMixin:
    """
    A logging mixin, which adds a log attribute to a class.
    """

    def __init__(self, *args, **kwargs):
        """
        Create and initialize the LoggingMixin.

        Any parameters passed to this constructor will be passed to the base class unchanged.

        Parameters
        ----------
        args
            Positional arguments
        kwargs
            Keyword arguments
        """
        # noinspection PyArgumentList
        super().__init__(*args, **kwargs)

        self.log = logging.getLogger(self.__class__.__name__)
audeep/backend/data/data_set.py
class Partition(Enum):
    """
    Identifiers for different data partitions.
    """
    TRAIN = 0
    DEVEL = 1
    TEST = 2
audeep/backend/enum_parser.py
class EnumType:
    """
    Performs case-insensitive parsing of string arguments to enum members.

    Consider, for example, an enum type with a member called MEMBER. Then, all string values with lower case
    equivalent "member" will be parsed to the enum member MEMBER.
    """

    def __init__(self,
                 enum_class: Type[Enum]):
        """
        Create and initialize a new EnumParser for the specified Enum type.

        Parameters
        ----------
        enum_class: Type[Enum]
            The enum class for which values should be parsed
        """
        self._enum_class = enum_class
        self._member_map = {x.name.lower(): x.name for x in enum_class}

    def __call__(self, arg: str):
        """
        Try to parse the specified string to an enum member.

        Parameters
        ----------
        arg: str
            The string value which should be parsed

        Returns
        -------
        enum
            A member of the enum type passed to this class which has the specified name

        Raises
        ------
        argparse.ArgumentTypeError
            If the enum does not have a member with the specified name
        """
        arg_lower = arg.lower()

        if not arg_lower in self._member_map:
            raise ArgumentTypeError("invalid choice %s (choose from %s)" % (arg, ", ".join(self._member_map.values())))

        return self._enum_class[self._member_map[arg_lower]]
audeep/backend/evaluation.py
class PartitionedEvaluation(LoggingMixin):
    """
    Partitioned evaluation of a learner on some data set.

    The learner is trained on specific partitions of the data set, and evaluated on some other specific partitions of
    the data set. Typically, a the learner is tuned by training on the train partition and evaluating on the development
    partition of a data set. Once tuning is complete, the learner is trained on the train and development partitions,
    and evaluated on the test partition.
    """

    def __init__(self,
                 learner: LearnerBase,
                 train_partitions: Sequence[Partition],
                 eval_partitions: Sequence[Partition],
                 upsample: bool,
                 majority_vote: bool):
        """
        Create a new partitioned evaluation of the specified learner.

        Evaluation is performed by training the learner on the specified training partitions, and evaluating the
        learner on the specified evaluation partitions.

        Parameters
        ----------
        learner: LearnerBase
            The learner which should be evaluated
        train_partitions: list of Partition
            The partitions on which the learner should be trained
        eval_partitions: list of Partition
            The partitions on which the learner should be evaluted
        upsample: bool
            Balance classes in the training partitions by upsampling instances
        """
        super().__init__()

        self._learner = learner
        self._train_partitions = train_partitions
        self._eval_partitions = eval_partitions
        self._upsample = upsample
        self._majority_vote = majority_vote
        self._accuracy = None
        self._uar = None
        self._confusion_matrix = None

    @property
    def accuracy(self) -> float:
        """
        Returns the accuracy of the learner.

        This property returns the accuracy on the last data set on which the `run` method has been invoked. As a
        consequence, this property returns None if the `run` method has not yet been invoked.

        Returns
        -------
        float
            Returns the accuracy of the learner on the last data set passed to the `run` method
        """
        return self._accuracy

    @property
    def uar(self) -> float:
        """
        Returns the unweighted average recall of the learner.

        This property returns the unweighted average recall on the last data set on which the `run` method has been
        invoked. As a consequence, this property returns None if the `run` method has not yet been invoked.

        Returns
        -------
        float
            Returns the unweighted average recall of the learner on the last data set passed to the `run` method
        """
        return self._uar

    @property
    def confusion_matrix(self) -> np.ndarray:
        """
        Returns the confusion matrix of the learner.

        This property returns the confusion matrix on the last data set on which the `run` method has been invoked.
        As a consequence, this property returns None if the `run` method has not yet been invoked.

        Returns
        -------
        numpy.ndarray
            The confusion matrix of the learner on the last data set passed to the `run` method
        """
        return self._confusion_matrix

    def run(self,
            data_set: DataSet):
        """
        Evaluates the learner on the specified data set.

        Sets the various properties of this instance to the values obtained during evaluation on the specified data set.

        Parameters
        ----------
        data_set: DataSet
            The data set on which the learner should be evaluated

        Raises
        ------
        ValueError
            If the specified data set does not have partition information
        """
        if not data_set.has_partition_info:
            raise ValueError("data set does not have partition info")

        self.log.info("training classifier")

        learner_wrapper = PreProcessingWrapper(learner=self._learner,
                                               upsample=self._upsample,
                                               majority_vote=self._majority_vote)

        train_split = data_set.partitions(self._train_partitions)
        eval_split = data_set.partitions(self._eval_partitions)

        learner_wrapper.fit(train_split)

        # IMPORTANT: these methods return maps of filename to label, since order may (or most certainly will) be
        # different
        predictions = learner_wrapper.predict(eval_split)
        true_labels = eval_split.filename_labels_numeric

        # sort labels and predictions by filename
        predictions = np.array([item[1] for item in sorted(predictions.items(), key=lambda item: item[0])])
        true_labels = np.array([item[1] for item in sorted(true_labels.items(), key=lambda item: item[0])])

        self._accuracy = accuracy_score(true_labels, predictions)
        self._uar = uar_score(true_labels, predictions)

        # order numeric labels by nominal value
        ordered_labels = sorted(data_set.label_map.items(), key=lambda t: t[0])
        ordered_labels = list(zip(*ordered_labels))[1]

        self._confusion_matrix = confusion_matrix(y_true=true_labels,
                                                  y_pred=predictions,
                                                  labels=ordered_labels)

Answer: formatter = ConfusionMatrixFormatter()


Input:
from .property import *
from .exceptions import ReservedWordError
from .declarative import DeclarativeMeta, DeclarativeType
from .vertex import Vertex
from .edge import Edge
from .broker import get_broker
from .query import Query
from .batch import Batch
from .commands import VertexCommand, CreateEdgeCommand
from ..utils import to_unicode
from collections import namedtuple
from os.path import isfile
import pyorient

    def create_vertex(self, vertex_cls, **kwargs):
        result = self.client.command(
            to_unicode(self.create_vertex_command(vertex_cls, **kwargs)))[0]

        props = result.oRecordData
        return vertex_cls.from_graph(self, result._rid,
                                     self.props_from_db[vertex_cls](props))

    def create_vertex_command(self, vertex_cls, **kwargs):
        class_name = vertex_cls.registry_name

        if kwargs:
            db_props = Graph.props_to_db(vertex_cls, kwargs, self.strict)
            set_clause = u' SET {}'.format(
                u','.join(u'{}={}'.format(
                    PropertyEncoder.encode_name(k), PropertyEncoder.encode_value(v))
                    for k, v in db_props.items()))
        else:
            set_clause = u''

        return VertexCommand(
            u'CREATE VERTEX {}{}'.format(class_name, set_clause))

    def delete_vertex(self, vertex, where = None, limit=None, batch=None):
        # TODO FIXME Parse delete result
        result = self.client.command(to_unicode(self.delete_vertex_command(vertex, where, limit, batch)))

    def delete_vertex_command(self, vertex, where=None, limit=None, batch=None):
        vertex_clause = getattr(vertex, 'registry_name', None) or vertex

        delete_clause = ''
        if where is not None:
            where_clause = ''
            if isinstance(where, dict):
                where_clause = u' and '.join(u'{0}={1}'
                    .format(PropertyEncoder.encode_name(k)
                            , PropertyEncoder.encode_value(v))
                    for k,v in where.items())
            else:
                where_clause = Query.filter_string(where)

            delete_clause += ' WHERE {}'.format(where_clause)
        if limit is not None:
            delete_clause += ' LIMIT {}'.format(limit)
        if batch is not None:
            delete_clause += ' BATCH {}'.format(batch)

        return VertexCommand(
            u'DELETE VERTEX {}{}'.format(
                vertex_clause, delete_clause))

    def create_edge(self, edge_cls, from_vertex, to_vertex, **kwargs):
        result = self.client.command(
            to_unicode(self.create_edge_command(edge_cls
                                     , from_vertex
                                     , to_vertex
                                     , **kwargs)))[0]

        return self.edge_from_record(result, edge_cls)

    def create_edge_command(self, edge_cls, from_vertex, to_vertex, **kwargs):
        class_name = edge_cls.registry_name

        if kwargs:
            db_props = Graph.props_to_db(edge_cls, kwargs, self.strict)
            set_clause = u' SET {}'.format(
                u','.join(u'{}={}'.format(
                    PropertyEncoder.encode_name(k), PropertyEncoder.encode_value(v))
                    for k, v in db_props.items()))
        else:
            set_clause = ''

        return CreateEdgeCommand(
            u'CREATE EDGE {} FROM {} TO {}{}'.format(
                class_name, from_vertex._id, to_vertex._id, set_clause))

    def create_function(self, name, code, parameters=None, idempotent=False, language='javascript'):
        parameter_str = ' PARAMETERS [' + ','.join(parameters) + ']' if parameters else ''

        self.client.command(
            u'CREATE FUNCTION {} \'{}\' {} IDEMPOTENT {} LANGUAGE {}'.format(
                name, code, parameter_str, 'true' if idempotent else 'false', language))

    def get_vertex(self, vertex_id):
        record = self.client.command('SELECT FROM {}'.format(vertex_id))
        return self.vertex_from_record(record[0]) if record else None

    def get_edge(self, edge_id):
        record = self.client.command('SELECT FROM {}'.format(edge_id))
        return self.edge_from_record(record[0]) if record else None

    def get_element(self, elem_id):
        record = self.client.command('SELECT FROM {}'.format(elem_id))
        return self.element_from_record(record[0]) if record else None

    def save_element(self, element_class, props, elem_id):
        """:returns: True if successful, False otherwise"""
        if isinstance(element_class, str):
            name = element_class
            element_class = self.registry.get(element_class)
            if not element_class:
                raise KeyError(
                    'Class \'{}\' not registered with graph.'.format(name))

        if props:
            db_props = Graph.props_to_db(element_class, props, self.strict)
            set_clause = u' SET {}'.format(
                u','.join(u'{}={}'.format(
                    PropertyEncoder.encode_name(k), PropertyEncoder.encode_value(v))
                    for k, v in db_props.items()))
        else:
            set_clause = ''

        result = self.client.command(u'UPDATE {}{}'.format(elem_id, set_clause))
        return result and result[0] == b'1'

    def query(self, first_entity, *entities):
        return Query(self, (first_entity,) + entities)

Context:
pyorient/ogm/edge.py
class Edge(GraphElement):
    Broker = EdgeBroker

    def __init__(self, **kwargs):
        super(Edge, self).__init__(**kwargs)

        self._in = None
        self._out = None

    @classmethod
    def from_graph(cls, graph, element_id, in_hash, out_hash, props):
        edge = super(Edge, cls).from_graph(graph, element_id, props);
        edge._in = in_hash
        edge._out = out_hash

        return edge

    def outV(self):
        g = self._graph
        return g.get_vertex(self._out) if g else None

    def inV(self):
        g = self._graph
        return g.get_vertex(self._in) if g else None
pyorient/ogm/vertex.py
class Vertex(GraphElement):
    Broker = VertexBroker

    # TODO
    # Edge information is carried in vertexes retrieved from database,
    # as OrientBinaryObject. Can likely optimise these traversals
    # when we know how to parse these.
    def outE(self, *edge_classes):
        g = self._graph
        return g.outE(self._id, *edge_classes) if g else None

    def inE(self, *edge_classes):
        g = self._graph
        return g.inE(self._id, *edge_classes) if g else None

    def bothE(self, *edge_classes):
        g = self._graph
        return g.bothE(self._id, *edge_classes) if g else None

    def out(self, *edge_classes):
        g = self._graph
        return g.out(self._id, *edge_classes) if g else None

    def in_(self, *edge_classes):
        g = self._graph
        return g.in_(self._id, *edge_classes) if g else None

    def both(self, *edge_classes):
        g = self._graph
        return g.both(self._id, *edge_classes) if g else None

    def __call__(self, edge_or_broker):
        """Provides syntactic sugar for creating edges."""
        if hasattr(edge_or_broker, 'broker'):
            edge_or_broker = edge_or_broker.broker.element_cls
        elif hasattr(edge_or_broker, 'element_cls'):
            edge_or_broker = edge_or_broker.element_cls

        if edge_or_broker.decl_type == 1:
            return VertexVector(self, edge_or_broker.objects)
pyorient/ogm/declarative.py
class DeclarativeType(object):
    """Marker for graph database element types"""
    Vertex = 0
    Edge = 1
pyorient/ogm/exceptions.py
class ReservedWordError(Exception):
    pass
pyorient/ogm/commands.py
class VertexCommand(object):
    def __init__(self, command_text):
        self.command_text = command_text

    def __str__(self):
        return to_str(self.__unicode__())

    def __unicode__(self):
        return u'{}'.format(self.command_text)
pyorient/ogm/broker.py
def get_broker(cls):
    for v in cls.__dict__.values():
        if isinstance(v, Broker):
            return v
    return None
pyorient/ogm/query.py
class Query(object):
    def __init__(self, graph, entities):
        """Query against a class or a selection of its properties.

        :param graph: Graph to query
        :param entities: Vertex/Edge class/a collection of its properties,
        an instance of such a class, or a subquery.
        """
        self._graph = graph
        self._subquery = None

        first_entity = entities[0]

        if isinstance(first_entity, Property):
            self.source_name = first_entity._context.registry_name
            self._class_props = entities
        elif isinstance(first_entity, GraphElement):
            # Vertex or edge instance
            self.source_name = first_entity._id
            self._class_props = tuple()
            pass
        elif isinstance(first_entity, Query):# \
                #or isinstance(first_entity, Traverse):
            # Subquery
            self._subquery = first_entity
            self.source_name = first_entity.source_name
            self._class_props = tuple()
            pass
        elif isinstance(first_entity, QV):
            self.source_name = self.build_what(first_entity)
            self._class_props = tuple()
        else:
            self.source_name = first_entity.registry_name
            self._class_props = tuple(entities[1:])

        self._params = {}

    @classmethod
    def sub(cls, source):
        """Shorthand for defining a sub-query, which does not need a Graph"""
        return cls(None, (source, ))

    def __iter__(self):
        params = self._params

        # TODO Don't ignore initial skip value
        with TempParams(params, skip='#-1:-1', limit=1):
            optional_clauses = self.build_optional_clauses(params, None)

            prop_names = []
            props, lets = self.build_props(params, prop_names, for_iterator=True)
            if len(prop_names) > 1:
                prop_prefix = self.source_name.translate(sanitise_ids)

                selectuple = namedtuple(prop_prefix + '_props',
                    [Query.sanitise_prop_name(name)
                        for name in prop_names])
            wheres = self.build_wheres(params)

            g = self._graph
            while True:
                current_skip = params['skip']
                where = u'WHERE {0}'.format(
                    u' and '.join(
                        [self.rid_lower(current_skip)] + wheres))

                select = self.build_select(props, lets + [where] + optional_clauses)

                response = g.client.command(select)
                if response:
                    response = response[0]

                    if prop_names:
                        next_skip = response.oRecordData.get('rid')
                        if next_skip:
                            self.skip(next_skip)

                            if len(prop_names) > 1:
                                yield selectuple(
                                    *tuple(self.parse_record_prop(
                                            response.oRecordData.get(name))
                                        for name in prop_names))
                            else:
                                yield self.parse_record_prop(
                                        response.oRecordData[prop_names[0]])
                        else:
                            yield g.element_from_record(response)
                            break
                    else:
                        if '-' in response._rid:
                            # Further queries would yield the same
                            # TODO Find out if any single iteration queries
                            #      return multiple values
                            yield next(iter(response.oRecordData.values()))
                            break
                        elif response._rid == current_skip:
                            # OrientDB bug?
                            # expand() makes for strange responses
                            break
                        else:
                            self.skip(response._rid)

                        yield g.element_from_record(response)
                else:
                    break

    def __getitem__(self, key):
        """Set query slice, or just get result by index."""
        if isinstance(key, slice):
            if key.stop is None:
                if key.start is not None:
                    self._params['skip'] = key.start
                return self
            elif key.start is None:
                key.start = 0

            return self.slice(key.start, key.stop)

        with TempParams(self._params, skip=key, limit=1):
            response = self.all()
            return response[0] if response else None

    def __str__(self):
        props, lets, where, optional_clauses = self.prepare()
        return self.build_select(props, lets + where + optional_clauses)

    def __len__(self):
        return self.count()

    def prepare(self, prop_names=None):
        params = self._params
        props, lets = self.build_props(params, prop_names)
        skip = params.get('skip')
        if skip and ':' in str(skip):
            rid_clause = [self.rid_lower(skip)]
            skip = None
        else:
            rid_clause = []
        optional_clauses = self.build_optional_clauses(params, skip)

        wheres = rid_clause + self.build_wheres(params)
        where = [u'WHERE {0}'.format(u' and '.join(wheres))] if wheres else []

        return props, lets, where, optional_clauses

    def all(self):
        prop_names = []
        props, lets, where, optional_clauses = self.prepare(prop_names)
        if len(prop_names) > 1:
            prop_prefix = self.source_name.translate(sanitise_ids)

            selectuple = namedtuple(prop_prefix + '_props',
                [Query.sanitise_prop_name(name)
                    for name in prop_names])
        select = self.build_select(props, lets + where + optional_clauses)

        g = self._graph

        response = g.client.command(select)
        if response:
            # TODO Determine which other queries always take only one iteration
            list_query = 'count' not in self._params

            if list_query:
                if prop_names:
                    if len(prop_names) > 1:
                        return [
                            selectuple(*tuple(
                                self.parse_record_prop(
                                    record.oRecordData.get(name))
                                for name in prop_names))
                            for record in response]
                    else:
                        prop_name = prop_names[0]
                        return [
                            self.parse_record_prop(
                                record.oRecordData[prop_name])
                            for record in response]
                else:
                    if self._params.get('reify', False) and len(response) == 1:
                        # Simplify query for subsequent uses
                        del self._params['kw_filters']
                        self.source_name = response[0]._rid

                    return g.elements_from_records(response)
            else:
                return next(iter(response[0].oRecordData.values()))
        else:
            return []

    def first(self, reify=False):
        with TempParams(self._params, limit=1, reify=reify):
            response = self.all()
            return response[0] if response else None

    def one(self, reify=False):
        with TempParams(self._params, limit=2):
            responses = self.all()
            num_responses = len(responses)
            if num_responses > 1:
                raise MultipleResultsFound(
                    'Expecting one result for query; got more.')
            elif num_responses < 1:
                raise NoResultFound('Expecting one result for query; got none.')
            else:
                return responses[0]

    def scalar(self):
        try:
            response = self.one()
        except NoResultFound:
            return None
        else:
            return response[0] if isinstance(response, tuple) else response

    def count(self, field=None):
        params = self._params

        if not field:
            whats = params.get('what')
            if whats and len(whats) == 1:
                field = self.build_what(whats[0])
            elif len(self._class_props) == 1:
                field = self._class_props[0]
            else:
                field = '*'

        with TempParams(params, count=field):
            return self.all()

    def what(self, *whats):
        self._params['what'] = whats
        return self

    def let(self, **kwargs):
        self._params['let'] = kwargs
        return self

    def filter(self, expression):
        self._params['filter'] = expression
        return self

    def filter_by(self, **kwargs):
        self._params['kw_filters'] = kwargs
        return self

    def group_by(self, *criteria):
        self._params['group_by'] = criteria
        return self

    def order_by(self, *criteria, **kwargs):
        self._params['order_by'] = (criteria, kwargs.get('reverse', False))
        return self

    def unwind(self, field):
        self._params['unwind'] = field
        return self

    def skip(self, skip):
        self._params['skip'] = skip
        return self

    def limit(self, limit):
        self._params['limit'] = limit
        return self

    def slice(self, start, stop):
        """Give bounds on how many records to retrieve

        :param start: If a string, must denote the id of the record _preceding_
        that to be retrieved next, or '#-1:-1'. Otherwise denotes how many
        records to skip.

        :param stop: If 'start' was a string, denotes a limit on how many
        records to retrieve. Otherwise, the index one-past-the-last
        record to retrieve.
        """
        self._params['skip'] = start
        if isinstance(start, str):
            self._params['limit'] = stop
        else:
            self._params['limit'] = stop - start
        return self

    def lock(self):
        self._params['lock'] = True

    @classmethod
    def filter_string(cls, expression_root):
        op = expression_root.operator

        left = expression_root.operands[0]
        right = expression_root.operands[1]
        if isinstance(left, IdentityOperand):
            if isinstance(left, Property):
                left_str = left.context_name()
            elif isinstance(left, ArithmeticOperation):
                left_str = u'({})'.format(cls.arithmetic_string(left))
            elif isinstance(left, ChainableWhat):
                left_str = cls.build_what(left)
            else:
                raise ValueError(
                    'Operator {} not supported as a filter'.format(op))

            if op is Operator.Equal:
                return u'{0} = {1}'.format(
                    left_str, ArgConverter.convert_to(ArgConverter.Vertex
                                                      , right, cls))
            elif op is Operator.GreaterEqual:
                return u'{0} >= {1}'.format(
                    left_str, ArgConverter.convert_to(ArgConverter.Value
                                                      , right, cls))
            elif op is Operator.Greater:
                return u'{0} > {1}'.format(
                    left_str, ArgConverter.convert_to(ArgConverter.Value
                                                      , right, cls))
            elif op is Operator.LessEqual:
                return u'{0} <= {1}'.format(
                    left_str, ArgConverter.convert_to(ArgConverter.Value
                                                      , right, cls))
            elif op is Operator.Less:
                return u'{0} < {1}'.format(
                    left_str, ArgConverter.convert_to(ArgConverter.Value
                                                      , right, cls))
            elif op is Operator.NotEqual:
                return u'{0} <> {1}'.format(
                    left_str, ArgConverter.convert_to(ArgConverter.Vertex
                                                      , right, cls))
            elif op is Operator.Between:
                far_right = PropertyEncoder.encode_value(expression_root.operands[2])
                return u'{0} BETWEEN {1} and {2}'.format(
                    left_str, PropertyEncoder.encode_value(right), far_right)
            elif op is Operator.Contains:
                if isinstance(right, LogicalConnective):
                    return u'{0} contains({1})'.format(
                        left_str, cls.filter_string(right))
                else:
                    return u'{} in {}'.format(
                        PropertyEncoder.encode_value(right), left_str)
            elif op is Operator.EndsWith:
                return u'{0} like {1}'.format(left_str, PropertyEncoder.encode_value('%' + right))
            elif op is Operator.Is:
                if not right: # :)
                    return '{0} is null'.format(left_str)
            elif op is Operator.IsNot:
                if not right:
                    return '{} is not null'.format(left_str)
            elif op is Operator.Like:
                return u'{0} like {1}'.format(
                    left_str, PropertyEncoder.encode_value(right))
            elif op is Operator.Matches:
                return u'{0} matches {1}'.format(
                    left_str, PropertyEncoder.encode_value(right))
            elif op is Operator.StartsWith:
                return u'{0} like {1}'.format(
                    left_str, PropertyEncoder.encode_value(right + '%'))
            elif op is Operator.InstanceOf:
                return u'{0} instanceof {1}'.format(
                    left_str, repr(right.registry_name))
            else:
                raise AssertionError('Unhandled Operator type: {}'.format(op))
        else:
            return u'{0} {1} {2}'.format(
                cls.filter_string(left)
                , 'and' if op is Operator.And else 'or'
                , cls.filter_string(right))

    @classmethod
    def arithmetic_string(cls, operation_root):
        if isinstance(operation_root, ArithmeticOperation):
            op = operation_root.operator
            if operation_root.paren:
                lp = '('
                rp = ')'
            else:
                lp = rp = ''

            left = operation_root.operands[0]
            # Unary operators not yet supported?
            right = operation_root.operands[1]

            if op is Operator.Add:
                exp = '{} + {}'.format(
                        cls.arithmetic_string(left)
                        , cls.arithmetic_string(right))
            elif op is Operator.Sub:
                exp = '{} - {}'.format(
                        cls.arithmetic_string(left)
                        , cls.arithmetic_string(right))
            elif op is Operator.Mul:
                exp = '{} * {}'.format(
                        cls.arithmetic_string(left)
                        , cls.arithmetic_string(right))
            elif op is Operator.Div:
                exp = '{} / {}'.format(
                        cls.arithmetic_string(left)
                        , cls.arithmetic_string(right))
            elif op is Operator.Mod:
                exp = '{} % {}'.format(
                        cls.arithmetic_string(left)
                        , cls.arithmetic_string(right))

            return '{}{}{}'.format(lp,exp,rp)
        elif isinstance(operation_root, Property):
            return operation_root.context_name()
        else:
            return operation_root

    def build_props(self, params, prop_names=None, for_iterator=False):
        let = params.get('let')
        if let:
            lets = ['LET {}'.format(
                ','.join('${} = {}'.format(
                    PropertyEncoder.encode_name(k),
                    u'({})'.format(v) if isinstance(v, Query) else
                    self.build_what(v)) for k,v in let.items()))]
        else:
            lets = []

        count_field = params.get('count')
        if count_field:
            if isinstance(count_field, Property):
                count_field = count_field.context_name()

            # Record response will use the same (lower-)case as the request
            return ['count({})'.format(count_field or '*')], lets

        whats = params.get('what')
        if whats:
            props = [self.build_what(what, prop_names) for what in whats]

            if prop_names is not None:
                # Multiple, distinct what's can alias to the same name
                # Make unique; consistent with what OrientDB assumes
                used_names = {}
                for idx, name in enumerate(prop_names):
                    prop_names[idx] = Query.unique_prop_name(name, used_names)
        else:
            props = [e.context_name() for e in self._class_props]
            if prop_names is not None:
                prop_names.extend(props)

        if props and for_iterator:
            props[0:0] = ['@rid']

        return props, lets

    def build_wheres(self, params):
        kw_filters = params.get('kw_filters')
        kw_where = [u' and '.join(u'{0}={1}'
            .format(PropertyEncoder.encode_name(k), PropertyEncoder.encode_value(v))
                for k,v in kw_filters.items())] if kw_filters else []

        filter_exp = params.get('filter')
        exp_where = [self.filter_string(filter_exp)] if filter_exp else []

        return kw_where + exp_where

    def rid_lower(self, skip):
        return '@rid > {}'.format(skip)

    def build_optional_clauses(self, params, skip):
        '''LET, while being an optional clause, must precede WHERE
        and is therefore handled separately.'''
        optional_clauses = []

        group_by = params.get('group_by')
        if group_by:
            group_clause = 'GROUP BY {}'.format(
                ','.join([by.context_name() for by in group_by]))
            optional_clauses.append(group_clause)

        order_by = params.get('order_by')
        if order_by:
            order_clause = 'ORDER BY {0} {1}'.format(
                ','.join([by.context_name() for by in order_by[0]])
                , 'DESC' if order_by[1] else 'ASC')
            optional_clauses.append(order_clause)

        unwind = params.get('unwind')
        if unwind:
           unwind_clause = 'UNWIND {}'.format(
                    unwind.context_name()
                    if isinstance(unwind, Property) else unwind)
           optional_clauses.append(unwind_clause)

        if skip:
            optional_clauses.append('SKIP {}'.format(skip))

        # TODO Determine other functions for which limit is useless
        if 'count' not in params:
            limit = params.get('limit')
            if limit:
                optional_clauses.append('LIMIT {}'.format(limit))

        lock = params.get('lock')
        if lock:
            optional_clauses.append('LOCK RECORD')

        return optional_clauses

    WhatFunction = namedtuple('what', ['max_args', 'fmt', 'expected'])
    WhatFunctions = {
        # TODO handle GraphElement args
        What.Out: WhatFunction(1, 'out({})', (ArgConverter.Label,))
        , What.In: WhatFunction(1, 'in({})', (ArgConverter.Label,))
        , What.Both: WhatFunction(1, 'both({})', (ArgConverter.Label,))
        , What.OutE: WhatFunction(1, 'outE({})', (ArgConverter.Label,))
        , What.InE: WhatFunction(1, 'inE({})', (ArgConverter.Label,))
        , What.BothE: WhatFunction(1, 'bothE({})', (ArgConverter.Label,))
        , What.OutV: WhatFunction(0, 'outV()', tuple())
        , What.InV: WhatFunction(0, 'inV()', tuple())
        , What.Eval: WhatFunction(1, 'eval({})', (ArgConverter.Expression,))
        , What.Coalesce: WhatFunction(None, 'coalesce({})'
                                      , (ArgConverter.Field,))
        , What.If: WhatFunction(3, 'if({})'
                                , (ArgConverter.Boolean, ArgConverter.Value
                                   , ArgConverter.Value))
        , What.IfNull: WhatFunction(2, 'ifnull({})'
                                    , (ArgConverter.Field, ArgConverter.Value))
        , What.Expand: WhatFunction(1, 'expand({})', (ArgConverter.Field,))
        , What.First: WhatFunction(1, 'first({})', (ArgConverter.Field,))
        , What.Last: WhatFunction(1, 'last({})', (ArgConverter.Field,))
        , What.Count: WhatFunction(1, 'count({})', (ArgConverter.Field,))
        , What.Min: WhatFunction(None, 'min({})', (ArgConverter.Field,))
        , What.Max: WhatFunction(None, 'max({})', (ArgConverter.Field,))
        , What.Avg: WhatFunction(1, 'avg({})', (ArgConverter.Field,))
        , What.Mode: WhatFunction(1, 'mode({})', (ArgConverter.Field,))
        , What.Median: WhatFunction(1, 'median({})', (ArgConverter.Field,))
        , What.Percentile: WhatFunction(None, 'percentile({})'
                                        , (ArgConverter.Field,))
        , What.Variance: WhatFunction(1, 'variance({})', (ArgConverter.Field,))
        , What.StdDev: WhatFunction(1, 'stddev({})', (ArgConverter.Field,))
        , What.Sum: WhatFunction(1, 'sum({})', (ArgConverter.Field,))
        , What.Date: WhatFunction(3, 'date({})'
                                  , (ArgConverter.String, ArgConverter.String
                                     , ArgConverter.String))
        , What.SysDate: WhatFunction(2, 'sysdate({})'
                                     , (ArgConverter.String
                                        , ArgConverter.String))
        , What.Format: WhatFunction(None, 'format({})'
                                    , (ArgConverter.Format, ArgConverter.Field))
        , What.Dijkstra:
            WhatFunction(4, 'dijkstra({})'
                         , (ArgConverter.Vertex, ArgConverter.Vertex
                         , ArgConverter.Label, ArgConverter.Value))
        , What.ShortestPath:
            WhatFunction(4, 'shortestPath({})'
                         , (ArgConverter.Vertex, ArgConverter.Vertex
                            , ArgConverter.Value, ArgConverter.Label))
        , What.Distance:
            WhatFunction(4, 'distance({})'
                         , (ArgConverter.Field, ArgConverter.Field
                            , ArgConverter.Value, ArgConverter.Value))
        , What.Distinct: WhatFunction(1, 'distinct({})', (ArgConverter.Field,))
        , What.UnionAll: WhatFunction(None, 'unionall({})'
                                      , (ArgConverter.Field,))
        , What.Intersect: WhatFunction(None, 'intersect({})'
                                       , (ArgConverter.Field,))
        , What.Difference: WhatFunction(None, 'difference({})'
                                        , (ArgConverter.Field,))
        , What.SymmetricDifference:
            WhatFunction(None, 'symmetricDifference({})', (ArgConverter.Field,))
        # FIXME Don't understand usage of these, yet.
        , What.Set: WhatFunction(1, 'set({})', (ArgConverter.Field,))
        , What.List: WhatFunction(1, 'list({})', (ArgConverter.Field,))
        , What.Map: WhatFunction(2, 'map({})', (ArgConverter.Field
                                                , ArgConverter.Field))
        , What.TraversedElement:
            WhatFunction(2, 'traversedElement({})'
                         , (ArgConverter.Value, ArgConverter.Value))
        , What.TraversedEdge:
            WhatFunction(2, 'traversedEdge({})'
                         , (ArgConverter.Value, ArgConverter.Value))
        , What.TraversedVertex:
            WhatFunction(2, 'traversedVertex({})'
                         , (ArgConverter.Value, ArgConverter.Value))
        , What.Any: WhatFunction(0, 'any()', tuple())
        , What.All: WhatFunction(0, 'all()', tuple())
        # Methods
        , What.Append: WhatFunction(1, 'append({})', (ArgConverter.Value,))
        , What.AsBoolean: WhatFunction(0, 'asBoolean()', tuple())
        , What.AsDate: WhatFunction(0, 'asDate()', tuple())
        , What.AsDatetime: WhatFunction(0, 'asDatetime()', tuple())
        , What.AsDecimal: WhatFunction(0, 'asDecimal()', tuple())
        , What.AsFloat: WhatFunction(0, 'asFloat()', tuple())
        , What.AsInteger: WhatFunction(0, 'asInteger()', tuple())
        , What.AsList: WhatFunction(0, 'asList()', tuple())
        , What.AsLong: WhatFunction(0, 'asLong()', tuple())
        , What.AsMap: WhatFunction(0, 'asMap()', tuple())
        , What.AsSet: WhatFunction(0, 'asSet()', tuple())
        , What.AsString: WhatFunction(0, 'asString()', tuple())
        , What.CharAt: WhatFunction(1, 'charAt({})', (ArgConverter.Field,))
        , What.Convert: WhatFunction(1, 'convert({})', (ArgConverter.Value,))
        , What.Exclude: WhatFunction(None, 'exclude({})', (ArgConverter.Value,))
        , What.FormatMethod: WhatFunction(1, 'format({})', (ArgConverter.Value,))
        , What.Hash: WhatFunction(1, 'hash({})', (ArgConverter.Value,))
        , What.Include: WhatFunction(None, 'include({})', (ArgConverter.Value,))
        , What.IndexOf: WhatFunction(2, 'indexOf({})', (ArgConverter.Value, ArgConverter.Value))
        , What.JavaType: WhatFunction(0, 'javaType()', tuple())
        , What.Keys: WhatFunction(0, 'keys()', tuple())
        , What.Left: WhatFunction(1, 'left({})', (ArgConverter.Value,))
        , What.Length: WhatFunction(0, 'length()', tuple())
        , What.Normalize: WhatFunction(2, 'normalize({})', (ArgConverter.Value, ArgConverter.Value))
        , What.Prefix: WhatFunction(1, 'prefix({})', (ArgConverter.Value,))
        , What.Remove: WhatFunction(None, 'remove({})', (ArgConverter.Value,))
        , What.RemoveAll: WhatFunction(None, 'removeAll({})', (ArgConverter.Value,))
        , What.Replace: WhatFunction(2, 'replace({})', (ArgConverter.Value, ArgConverter.Value))
        , What.Right: WhatFunction(1, 'right({})', (ArgConverter.Value,))
        , What.Size: WhatFunction(0, 'size()', tuple())
        , What.SubString: WhatFunction(2, 'substring({})', (ArgConverter.Value, ArgConverter.Value))
        , What.Trim: WhatFunction(0, 'trim()', tuple())
        , What.ToJSON: WhatFunction(0, 'toJSON()', tuple()) # FIXME TODO Figure out format argument
        , What.ToLowerCase: WhatFunction(0, 'toLowerCase()', tuple())
        , What.ToUpperCase: WhatFunction(0, 'toUpperCase()', tuple())
        , What.Type: WhatFunction(0, 'type()', tuple())
        , What.Values: WhatFunction(0, 'values()', tuple())
        , What.WhatLet: WhatFunction(1, '${}', (ArgConverter.Name, ))
        , What.AtThis: WhatFunction(0, '@this', tuple())
        , What.AtRid: WhatFunction(0, '@rid', tuple())
        , What.AtClass: WhatFunction(0, '@class', tuple())
        , What.AtVersion: WhatFunction(0, '@version', tuple())
        , What.AtSize: WhatFunction(0, '@size', tuple())
        , What.AtType: WhatFunction(0, '@type', tuple())
    }

    @classmethod
    def append_what_function(cls, chain, func_key, func_args):
        what_function = Query.WhatFunctions[func_key]
        max_args = what_function.max_args
        if max_args > 0 or max_args is None:
            chain.append(
                what_function.fmt.format(
                    ','.join(cls.what_args(what_function.expected,
                                            func_args[1]))))
        else:
            chain.append(what_function.fmt)

    @classmethod
    def build_what(cls, what, prop_names=None):
        if isinstance(what, Property):
            prop_name = what.context_name()
            if prop_names is not None:
                prop_names.append(prop_name)
            return prop_name
        elif not isinstance(what, What):
            if isinstance(what, str):
                what_str = json.dumps(what)
            else:
                what_str = str(what)

            if prop_names is not None:
                period = what_str.find('.')
                if period >= 0:
                    prop_names.append(what_str[0:period])
                else:
                    prop_names.append(what_str.replace('"', ''))
            return what_str

        name_override = what.name_override
        as_str = ' AS {}'.format(name_override) if name_override else ''

        if isinstance(what, FunctionWhat):
            func = what.chain[0][0]
            what_function = Query.WhatFunctions[func]

            if prop_names is not None:
                # Projections not allowed with Expand
                counted = func is not What.Expand
                if counted:
                    prop_names.append(
                        cls.parse_prop_name(what_function.fmt, name_override))

            return '{}{}'.format(
                what_function.fmt.format(
                    ','.join(cls.what_args(what_function.expected,
                                            what.chain[0][1]))), as_str)
        elif isinstance(what, ChainableWhat):
            chain = []
            for func_args in what.chain:
                func_key = func_args[0]
                if func_key == What.WhatFilter:
                    filter_exp = func_args[1]
                    chain[-1] += '[{}]'.format(ArgConverter.convert_to(ArgConverter.Filter, filter_exp, cls))
                    continue
                elif func_key == What.WhatCustom:
                    chain.append('{}({})'.format(func_args[1], ','.join(cls.what_args(func_args[2], func_args[3]))))
                    continue

                cls.append_what_function(chain, func_key, func_args)

            for prop in what.props:
                if isinstance(prop, tuple):
                    func_key = prop[0]
                    cls.append_what_function(chain, func_key, prop)
                else:
                    chain.append(prop)

            if prop_names is not None:
                prop_names.append(
                    cls.parse_prop_name(chain[0], name_override))
            return '{}{}'.format('.'.join(chain), as_str)

    @staticmethod
    def unique_prop_name(name, used_names):
        used = used_names.get(name, None)
        if used is None:
            used_names[name] = 1
            return name
        else:
            used_names[name] += 1
            return name + str(used_names[name])

    @staticmethod
    def sanitise_prop_name(name):
        if iskeyword(name):
            return name + '_'
        elif name[0] == '$':
            return 'qv_'+ name[1:]
        else:
            return name

    @staticmethod
    def parse_prop_name(from_str, override):
        if override:
            return override
        else:
            paren_idx = from_str.find('(')
            if paren_idx < 0:
                return from_str
            else:
                return from_str[:paren_idx]

    @classmethod
    def what_args(cls, expected, args):
        if args:
            return [ArgConverter.convert_to(conversion, arg, cls)
                    for arg, conversion in
                        zip_longest(args, expected
                                    , fillvalue=expected[-1])
                        if arg is not None]
        else:
            return []

    def build_select(self, props, optional_clauses):
        # This 'is not None' is important; don't want to implicitly call
        # __len__ (which invokes count()) on subquery.
        if self._subquery is not None:
            src = u'({})'.format(self._subquery)
        else:
            src = self.source_name

        optional_string = ' '.join(optional_clauses)
        if props:
            return u'SELECT {} FROM {} {}'.format(
                ','.join(props), src, optional_string)
        else:
            return u'SELECT FROM {} {}'.format(src, optional_string)

    def parse_record_prop(self, prop):
        if isinstance(prop, list):
            g = self._graph
            return g.elements_from_links(prop) if len(prop) > 0 and isinstance(prop[0], pyorient.OrientRecordLink) else prop
        elif isinstance(prop, pyorient.OrientRecordLink):
            return self._graph.element_from_link(prop)
        return prop
pyorient/ogm/batch.py
class Batch(object):
    READ_COMMITTED = 0
    REPEATABLE_READ = 1

    def __init__(self, graph, isolation_level=READ_COMMITTED):
        self.graph = graph
        self.objects = {}
        self.variables = {}

        if isolation_level == Batch.REPEATABLE_READ:
            self.commands = 'BEGIN ISOLATION REPEATABLE_READ\n'
        else:
            self.commands = 'BEGIN\n'

        for name,cls in graph.registry.items():
            broker = get_broker(cls)
            if broker:
                self.objects[cls] = broker = BatchBroker(broker)
            else:
                self.objects[cls] = broker = BatchBroker(cls.objects)

            broker_name = getattr(cls, 'registry_plural', None)
            if broker_name is not None:
                setattr(self, broker_name, broker)

    def __setitem__(self, key, value):
        command = str(value)
        if isinstance(key, slice):
            self.commands += '{}\n'.format(command)
        else:
            key = Batch.clean_name(key) if Batch.clean_name else key

            self.commands += 'LET {} = {}\n'.format(key, command)

            VarType = BatchVariable
            if isinstance(value, VertexCommand):
                VarType = BatchVertexVariable
            self.variables[key] = VarType('${}'.format(key), value)

    def sleep(self, ms):
        self.commands += 'sleep {}'.format(ms)

    def clear(self):
        self.objects.clear()
        self.variables.clear()

        self.commands = self.commands[:self.commands.index('\n') + 1]

    def __getitem__(self, key):
        """Commit batch with return value, or reference a previously defined
        variable.

        Using a plain string as a key commits and returns the named variable.

        Slicing with only a 'stop' value does not commit - it is the syntax for
        using a variable. Otherwise slicing can give finer control over commits;
        step values give a retry limit, and a start value denotes the returned
        variable.
        """

        returned = None
        if isinstance(key, slice):
            if key.step:
                if key.start:
                    returned = Batch.return_string(key.start)
                    self.commands += \
                        'COMMIT RETRY {}\nRETURN {}'.format(key.step, returned)
                else:
                    self.commands += 'COMMIT RETRY {}'.format(key.step)
            elif key.stop:
                # No commit.

                if Batch.clean_name:
                    return self.variables[Batch.clean_name(key.stop)]
                elif any(c in Batch.INVALID_CHARS for c in key.stop):
                    raise ValueError(
                        'Variable name \'{}\' contains invalid character(s).'
                            .format(key.stop))

                return self.variables[key.stop]
            else:
                if key.start:
                    returned = Batch.return_string(key.start)
                    self.commands += 'COMMIT\nRETURN {}'.format(returned)
                else:
                    self.commands += 'COMMIT'
        else:
            returned = Batch.return_string(key)
            self.commands += 'COMMIT\nRETURN {}'.format(returned)

        g = self.graph
        if returned:
            response = g.client.batch(self.commands)
            self.clear()

            if returned[0] in ('[','{'):
                return g.elements_from_records(response) if response else None
            else:
                return g.element_from_record(response[0]) if response else None
        else:
            g.client.batch(self.commands)
            self.clear()

    def commit(self, retries=None):
        """Commit batch with no return value."""
        self.commands += 'COMMIT' + (' RETRY {}'.format(retries) if retries else '')

        g = self.graph
        g.client.batch(self.commands)
        self.clear()

    @staticmethod
    def return_string(variables):
        cleaned = Batch.clean_name or (lambda s:s)

        if isinstance(variables, (list, tuple)):
            return '[' + ','.join(
                '${}'.format(cleaned(var)) for var in variables) + ']'
        elif isinstance(variables, dict):
            return '{' + ','.join(
                '{}:${}'.format(repr(k),cleaned(v))
                    for k,v in variables.items()) + '}'
        else:
            # Since any value can be returned from a batch,
            # '$' must be used when a variable is referenced
            if isinstance(variables, str):
                if variables[0] == '$':
                    return '{}'.format('$' + cleaned(variables[1:]))
                else:
                    return repr(variables)
            else:
                return '{}'.format(variables)

    INVALID_CHARS = set(string.punctuation + string.whitespace)

    @staticmethod
    def default_name_cleaner(name):
        rx = '[' + re.escape(''.join(Batch.INVALID_CHARS)) + ']'
        return re.sub(rx, '_', name)

    clean_name = None
    @classmethod
    def use_name_cleaner(cls, cleaner=default_name_cleaner):
        cls.clean_name = cleaner
pyorient/ogm/declarative.py
class DeclarativeMeta(type):
    """Metaclass for registering node and relationship types.

    Node and relationship metadata is mostly ignored until their classes are
    created in a Graph. The main benefit is to allow 'self-referencing'
    properties with LinkedClassProperty subclasses.
    """
    def __init__(cls, class_name, bases, attrs):
        if not hasattr(cls, 'registry'):
            cls.registry = OrderedDict()
            cls.decl_root = cls
        else:
            decl_bases = set(
                base.decl_root for base in bases
                    if hasattr(base, 'decl_root') and base is not base.decl_root)
            if len(decl_bases) > 1:
                raise TypeError(
                    'When multiply-inheriting graph elements, they must share '
                    'the same declarative base class. '
                    'Note: Each call to declarative_*() returns a new base class.')

            if cls.decl_type is DeclarativeType.Vertex:
                cls.registry_name = attrs.get('element_type'
                                              , cls.__name__.lower())

                plural = attrs.get('element_plural')
                if plural:
                    cls.registry_plural = plural
            else:
                label = attrs.get('label')
                if label:
                    cls.registry_name = cls.registry_plural = label
                else:
                    cls.registry_name = cls.__name__.lower()

            # See also __setattr__ for properties added after class definition
            for prop in cls.__dict__.values():
                if not isinstance(prop, Property):
                    continue
                prop._context = cls

            # FIXME Only want bases that correspond to vertex/edge classes.
            cls.registry[cls.registry_name] = cls

        return super(DeclarativeMeta, cls).__init__(class_name, bases, attrs)

    def __setattr__(self, name, value):
        if isinstance(value, Property):
            if value.context:
                raise ValueError(
                    'Attempt to add a single Property to multiple classes.')
            value.context = self
        return super(DeclarativeMeta, self).__setattr__(name, value)

    def __format__(self, format_spec):
        """Quoted class-name for specifying class as string argument.

        Use 'registry_name' when it is possible to refer to schema entities
        directly.
        """
        return repr(self.registry_name)
pyorient/ogm/commands.py
class CreateEdgeCommand(object):
    def __init__(self, command_text):
        self.command_text = command_text
        self.retries = None

    def __str__(self):
        return to_str(self.__unicode__())

    def __unicode__(self):
        if self.retries:
            return u'{} RETRY {}'.format(self.command_text, self.retries)
        else:
            return u'{}'.format(self.command_text)

    def retry(self, retries):
        self.retries = retries
        return self

Answer: def batch(self, isolation_level=Batch.READ_COMMITTED):