diff -r 50741316dd3a Lib/enum.py --- a/Lib/enum.py Thu Mar 05 20:28:52 2015 +1300 +++ b/Lib/enum.py Thu Mar 05 17:30:02 2015 +0200 @@ -2,7 +2,7 @@ import sys from collections import OrderedDict from types import MappingProxyType, DynamicClassAttribute -__all__ = ['Enum', 'IntEnum', 'unique'] +__all__ = ['Enum', 'IntEnum', 'unique', 'IntFlags'] def _is_descriptor(obj): @@ -312,7 +312,7 @@ class EnumMeta(type): if isinstance(names, str): names = names.replace(',', ' ').split() if isinstance(names, (tuple, list)) and isinstance(names[0], str): - names = [(e, i) for (i, e) in enumerate(names, start)] + names = cls._gen_values_(names, start) # Here, names is either an iterable of (name, value) or a mapping. for item in names: @@ -339,6 +339,9 @@ class EnumMeta(type): return enum_class + def _gen_values_(cls, names, start): + return [(e, i) for (i, e) in enumerate(names, start)] + @staticmethod def _get_mixins_(bases): """Returns the type for creating enum members, and the first inherited @@ -527,3 +530,108 @@ def unique(enumeration): raise ValueError('duplicate values found in %r: %s' % (enumeration, alias_details)) return enumeration + + +class IntFlagsMeta(EnumMeta): + """Metaclass for IntFlags""" + + def __new__(metacls, cls, bases, classdict): + enum_class = EnumMeta.__new__(metacls, cls, bases, classdict) + enum_class.__new__ = enum_class.__new_member__ + return enum_class + + def _gen_values_(cls, names, start): + return [(e, start< 1 or value: + s = '~(%s)' % s + else: + s = '~%s' % s + return s + + def __repr__(self): + invert, names, value = self._decompose() + if not names: + return repr(self._value_) + s = '|'.join('%s' % n for n in names) + if value: + s = '%s|%s' % (s, value) + if invert: + if len(names) > 1 or value: + s = '<%s.~(%s): %r>' % (self.__class__.__name__, s, self._value_) + else: + s = '<%s.~%s: %r>' % (self.__class__.__name__, s, self._value_) + else: + s = '<%s.%s: %r>' % (self.__class__.__name__, s, self._value_) + return s + + def __or__(self, other): + if isinstance(other, self.__class__): + other = other._value_ + elif isinstance(other, IntFlags) or not isinstance(other, int): + return NotImplemented + return self.__class__(self._value_ | other) + + def __ror__(self, other): + if isinstance(other, self.__class__): + other = other._value_ + elif isinstance(other, IntFlags) or not isinstance(other, int): + return NotImplemented + return self.__class__(other | self._value_) + + def __and__(self, other): + if isinstance(other, self.__class__): + other = other._value_ + elif isinstance(other, IntFlags) or not isinstance(other, int): + return NotImplemented + return self.__class__(self._value_ & other) + + def __rand__(self, other): + if isinstance(other, self.__class__): + other = other._value_ + elif isinstance(other, IntFlags) or not isinstance(other, int): + return NotImplemented + return self.__class__(other & self._value_) + + def __invert__(self): + return self.__class__(~self._value_) diff -r 50741316dd3a Lib/os.py --- a/Lib/os.py Thu Mar 05 20:28:52 2015 +1300 +++ b/Lib/os.py Thu Mar 05 17:30:02 2015 +0200 @@ -23,6 +23,7 @@ and opendir), and leave all pathname man #' +import enum import sys, errno import stat as st @@ -115,6 +116,24 @@ from os.path import (curdir, pardir, sep del _names +OpenMode = enum.IntFlags('OpenMode', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith('O_')}) +globals().update(OpenMode.__members__) +StatFlags = enum.IntFlags('StatFlags', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith('ST_')}) +globals().update(StatFlags.__members__) +DLOpenFlags = enum.IntFlags('DLOpenFlags', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith('RTLD_')}) +globals().update(DLOpenFlags.__members__) +DLOpenFlags = enum.IntFlags('AccessMode', + [(name, globals()[name]) + for name in ('R_OK', 'W_OK', 'X_OK', 'F_OK') + if name in globals()]) +globals().update(DLOpenFlags.__members__) + if _exists("_have_functions"): _globals = globals() diff -r 50741316dd3a Lib/re.py --- a/Lib/re.py Thu Mar 05 20:28:52 2015 +1300 +++ b/Lib/re.py Thu Mar 05 17:30:02 2015 +0200 @@ -119,6 +119,7 @@ This module also defines an exception 'e """ +import enum import sys import sre_compile import sre_parse @@ -139,17 +140,20 @@ except ImportError: __version__ = "2.2.1" # flags -A = ASCII = sre_compile.SRE_FLAG_ASCII # assume ascii "locale" -I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE # ignore case -L = LOCALE = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale -U = UNICODE = sre_compile.SRE_FLAG_UNICODE # assume unicode "locale" -M = MULTILINE = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline -S = DOTALL = sre_compile.SRE_FLAG_DOTALL # make dot match newline -X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments +class Flags(enum.IntFlags): + A = ASCII = sre_compile.SRE_FLAG_ASCII # assume ascii "locale" + I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE # ignore case + L = LOCALE = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale + U = UNICODE = sre_compile.SRE_FLAG_UNICODE # assume unicode "locale" + M = MULTILINE = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline + S = DOTALL = sre_compile.SRE_FLAG_DOTALL # make dot match newline + X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments -# sre extensions (experimental, don't rely on these) -T = TEMPLATE = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking -DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation + # sre extensions (experimental, don't rely on these) + T = TEMPLATE = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking + DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation + +globals().update(Flags.__members__) # sre exception error = sre_compile.error diff -r 50741316dd3a Lib/socket.py --- a/Lib/socket.py Thu Mar 05 20:28:52 2015 +1300 +++ b/Lib/socket.py Thu Mar 05 17:30:02 2015 +0200 @@ -50,7 +50,7 @@ import _socket from _socket import * import os, sys, io, selectors -from enum import IntEnum +from enum import IntEnum, IntFlags try: import errno @@ -79,6 +79,16 @@ SocketKind = IntEnum('SocketKind', if name.isupper() and name.startswith('SOCK_')}) globals().update(SocketKind.__members__) +MsgFlags = IntFlags('MsgFlags', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith('MSG_')}) +globals().update(MsgFlags.__members__) + +AddressInfo = IntFlags('AddressInfo', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith('AI_')}) +globals().update(AddressInfo.__members__) + _LOCALHOST = '127.0.0.1' _LOCALHOST_V6 = '::1' diff -r 50741316dd3a Lib/stat.py --- a/Lib/stat.py Thu Mar 05 20:28:52 2015 +1300 +++ b/Lib/stat.py Thu Mar 05 17:30:02 2015 +0200 @@ -2,6 +2,7 @@ Suggested usage: from stat import * """ +import enum # Indices for stat struct members in the tuple returned by os.stat() @@ -176,3 +177,18 @@ try: from _stat import * except ImportError: pass + +Permissions = enum.IntFlags('Permissions', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith('S_') and isinstance(value, int)}) +globals().update(Permissions.__members__) + +FileFlags = enum.IntFlags('FileFlags', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith(('UF_', 'SF_'))}) +globals().update(FileFlags.__members__) + +FileAttributes = enum.IntFlags('FileAttributes', + {name: value for name, value in globals().items() + if name.isupper() and name.startswith('FILE_ATTRIBUTE_')}) +globals().update(FileAttributes.__members__) diff -r 50741316dd3a Lib/test/test_enum.py --- a/Lib/test/test_enum.py Thu Mar 05 20:28:52 2015 +1300 +++ b/Lib/test/test_enum.py Thu Mar 05 17:30:02 2015 +0200 @@ -3,7 +3,7 @@ import inspect import pydoc import unittest from collections import OrderedDict -from enum import Enum, IntEnum, EnumMeta, unique +from enum import Enum, IntEnum, EnumMeta, unique, IntFlags from io import StringIO from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL @@ -1666,5 +1666,228 @@ class TestStdLib(unittest.TestCase): if failed: self.fail("result does not equal expected, see print above") + +class TestIntFlags(unittest.TestCase): + """Tests of the IntFlags.""" + + class Perm(IntFlags): + R = 1 << 0 + W = 1 << 1 + X = 1 << 2 + + class Open(IntFlags): + RO = 0 + WO = 1 + RW = 2 + AC = 3 + CE = 1<<19 + + def test_str(self): + Perm = self.Perm + self.assertEqual(str(Perm.R), 'Perm.R') + self.assertEqual(str(Perm.W), 'Perm.W') + self.assertEqual(str(Perm.X), 'Perm.X') + self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|Perm.W') + self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X') + self.assertEqual(str(Perm.R | 8), 'Perm.R|8') + self.assertEqual(str(Perm(0)), '0') + self.assertEqual(str(Perm(8)), '8') + self.assertEqual(str(~Perm.R), '~Perm.R') + self.assertEqual(str(~Perm.W), '~Perm.W') + self.assertEqual(str(~Perm.X), '~Perm.X') + self.assertEqual(str(~(Perm.R | Perm.W)), '~(Perm.R|Perm.W)') + self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), '~(Perm.R|Perm.W|Perm.X)') + self.assertEqual(str(~(Perm.R | 8)), '~(Perm.R|8)') + self.assertEqual(str(Perm(~0)), '-1') + self.assertEqual(str(Perm(~8)), '-9') + + Open = self.Open + self.assertEqual(str(Open.RO), 'Open.RO') + self.assertEqual(str(Open.WO), 'Open.WO') + self.assertEqual(str(Open.AC), 'Open.AC') + self.assertEqual(str(Open.RO | Open.CE), 'Open.CE') + self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|Open.CE') + self.assertEqual(str(Open(4)), '4') + self.assertEqual(str(~Open.RO), '~Open.RO') + self.assertEqual(str(~Open.WO), '~Open.WO') + self.assertEqual(str(~Open.AC), '~Open.AC') + self.assertEqual(str(~(Open.RO | Open.CE)), '~Open.CE') + self.assertEqual(str(~(Open.WO | Open.CE)), '~(Open.WO|Open.CE)') + self.assertEqual(str(Open(~4)), '-5') + + def test_repr(self): + Perm = self.Perm + self.assertEqual(repr(Perm.R), '') + self.assertEqual(repr(Perm.W), '') + self.assertEqual(repr(Perm.X), '') + self.assertEqual(repr(Perm.R | Perm.W), '') + self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') + self.assertEqual(repr(Perm.R | 8), '') + self.assertEqual(repr(Perm(0)), '0') + self.assertEqual(repr(Perm(8)), '8') + self.assertEqual(repr(~Perm.R), '') + self.assertEqual(repr(~Perm.W), '') + self.assertEqual(repr(~Perm.X), '') + self.assertEqual(repr(~(Perm.R | Perm.W)), '') + self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') + self.assertEqual(repr(~(Perm.R | 8)), '') + self.assertEqual(repr(Perm(~0)), '-1') + self.assertEqual(repr(Perm(~8)), '-9') + + Open = self.Open + self.assertEqual(repr(Open.RO), '') + self.assertEqual(repr(Open.WO), '') + self.assertEqual(repr(Open.AC), '') + self.assertEqual(repr(Open.RO | Open.CE), '') + self.assertEqual(repr(Open.WO | Open.CE), '') + self.assertEqual(repr(Open(4)), '4') + self.assertEqual(repr(~Open.RO), '') + self.assertEqual(repr(~Open.WO), '') + self.assertEqual(repr(~Open.AC), '') + self.assertEqual(repr(~(Open.RO | Open.CE)), '') + self.assertEqual(repr(~(Open.WO | Open.CE)), '') + self.assertEqual(repr(Open(~4)), '-5') + + def test_or(self): + Perm = self.Perm + for i in Perm: + for j in Perm: + self.assertEqual(i | j, i.value | j.value) + self.assertEqual((i | j).value, i.value | j.value) + self.assertIs(type(i | j), Perm) + for j in range(8): + self.assertEqual(i | j, i.value | j) + self.assertEqual((i | j).value, i.value | j) + self.assertIs(type(i | j), Perm) + self.assertEqual(j | i, j | i.value) + self.assertEqual((j | i).value, j | i.value) + self.assertIs(type(j | i), Perm) + for i in Perm: + self.assertIs(i | i, i) + self.assertIs(i | 0, i) + self.assertIs(0 | i, i) + Open = self.Open + self.assertIs(Open.RO | Open.CE, Open.CE) + + def test_and(self): + Perm = self.Perm + RW = Perm.R | Perm.W + RX = Perm.R | Perm.X + WX = Perm.W | Perm.X + RWX = Perm.R | Perm.W | Perm.X + values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] + for i in values: + for j in values: + self.assertEqual(i & j, i.value & j.value) + self.assertEqual((i & j).value, i.value & j.value) + self.assertIs(type(i & j), Perm) + for j in range(8): + self.assertEqual(i & j, i.value & j) + self.assertEqual((i & j).value, i.value & j) + self.assertIs(type(i & j), Perm) + self.assertEqual(j & i, j & i.value) + self.assertEqual((j & i).value, j & i.value) + self.assertIs(type(j & i), Perm) + for i in Perm: + self.assertIs(i & i, i) + self.assertIs(i & 7, i) + self.assertIs(7 & i, i) + + def test_invert(self): + Perm = self.Perm + RW = Perm.R | Perm.W + RX = Perm.R | Perm.X + WX = Perm.W | Perm.X + RWX = Perm.R | Perm.W | Perm.X + values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] + for i in values: + self.assertEqual(~i, ~i.value) + self.assertEqual((~i).value, ~i.value) + self.assertIs(type(~i), Perm) + self.assertEqual(~~i, i) + for i in Perm: + self.assertIs(~~i, i) + + def test_programatic_function_string(self): + Perm = IntFlags('Perm', 'R W X') + lst = list(Perm) + self.assertEqual(len(lst), len(Perm)) + self.assertEqual(len(Perm), 3, Perm) + self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) + for i, n in enumerate('R W X'.split()): + v = 1<