Completed
Pull Request — master (#905)
by
unknown
01:32
created

zipline.utils._enum   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 14
Duplicated Lines 0 %
Metric Value
dl 0
loc 14
rs 10
wmc 5
1
#
2
# Copyright 2015 Quantopian, Inc.
3
#
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
from ctypes import (
17
    Structure,
18
    c_ubyte,
19
    c_uint,
20
    c_ulong,
21
    c_ulonglong,
22
    c_ushort,
23
    sizeof,
24
)
25
26
import numpy as np
27
import pandas as pd
28
from six.moves import range
29
30
31
_inttypes_map = {
32
    sizeof(t) - 1: t for t in {
33
        c_ubyte,
34
        c_uint,
35
        c_ulong,
36
        c_ulonglong,
37
        c_ushort
38
    }
39
}
40
_inttypes = list(
41
    pd.Series(_inttypes_map).reindex(
42
        range(max(_inttypes_map.keys())),
43
        method='bfill',
44
    ),
45
)
46
47
48
def enum(option, *options):
49
    """
50
    Construct a new enum object.
51
52
    Parameters
53
    ----------
54
    *options : iterable of str
55
        The names of the fields for the enum.
56
57
    Returns
58
    -------
59
    enum
60
        A new enum collection.
61
62
    Examples
63
    --------
64
    >>> e = enum('a', 'b', 'c')
65
    >>> e
66
    <enum: ('a', 'b', 'c')>
67
    >>> e.a
68
    0
69
    >>> e.b
70
    1
71
    >>> e.a in e
72
    True
73
    >>> tuple(e)
74
    (0, 1, 2)
75
76
    Notes
77
    -----
78
    Identity checking is not guaranteed to work with enum members, instead
79
    equality checks should be used. From CPython's documentation:
80
81
    "The current implementation keeps an array of integer objects for all
82
    integers between -5 and 256, when you create an int in that range you
83
    actually just get back a reference to the existing object. So it should be
84
    possible to change the value of 1. I suspect the behaviour of Python in
85
    this case is undefined. :-)"
86
    """
87
    options = (option,) + options
88
    rangeob = range(len(options))
89
90
    try:
91
        inttype = _inttypes[int(np.log2(len(options) - 1)) // 8]
92
    except IndexError:
93
        raise OverflowError(
94
            'Cannot store enums with more than sys.maxsize elements, got %d' %
95
            len(options),
96
        )
97
98
    class _enum(Structure):
99
        _fields_ = [(o, inttype) for o in options]
100
101
        def __iter__(self):
102
            return iter(rangeob)
103
104
        def __contains__(self, value):
105
            return 0 <= value < len(options)
106
107
        def __repr__(self):
108
            return '<enum: %s>' % (
109
                ('%d fields' % len(options))
110
                if len(options) > 10 else
111
                repr(options)
112
            )
113
114
    return _enum(*rangeob)
115