diff --git a/.travis.yml b/.travis.yml index b23556f8cc9c71bce651c8df9f72d937fa8ac617..cccc0858164fe9902d7ee1e31ccd1a6aabc284e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -117,11 +117,12 @@ matrix: os: osx # PyPy - # These are known to be broken. - python: "pypy" + dist: xenial env: LIBRARY=ffmpeg-4.0 os: linux - python: "pypy3" + dist: xenial env: LIBRARY=ffmpeg-4.0 os: linux @@ -144,14 +145,11 @@ matrix: allow_failures: - - python: "pypy" - env: LIBRARY=ffmpeg-4.0 - os: linux - python: "pypy3" + dist: xenial env: LIBRARY=ffmpeg-4.0 os: linux - before_install: - scripts/build-deps diff --git a/av/codec/context.pyx b/av/codec/context.pyx index ad812049f0a68cbaf01c214dd60cefe8c21468cb..f5c9066d406a388795d5d3ce8711add32b4f8be2 100644 --- a/av/codec/context.pyx +++ b/av/codec/context.pyx @@ -9,7 +9,7 @@ from av.bytesource cimport ByteSource, bytesource from av.codec.codec cimport Codec, wrap_codec from av.dictionary cimport _Dictionary from av.dictionary import Dictionary -from av.enums cimport EnumType, define_enum +from av.enums cimport define_enum from av.packet cimport Packet from av.utils cimport err_check, avdict_to_dict, avrational_to_fraction, to_avrational @@ -41,15 +41,14 @@ cdef CodecContext wrap_codec_context(lib.AVCodecContext *c_ctx, const lib.AVCode return py_ctx -cdef EnumType _ThreadType = define_enum('ThreadType', ( +ThreadType = define_enum('ThreadType', ( ('NONE', 0), ('FRAME', lib.FF_THREAD_FRAME), ('SLICE', lib.FF_THREAD_SLICE), ('AUTO', lib.FF_THREAD_SLICE | lib.FF_THREAD_FRAME), ), is_flags=True) -ThreadType = _ThreadType -cdef EnumType _SkipType = define_enum('SkipType', ( +SkipType = define_enum('SkipType', ( ('NONE', lib.AVDISCARD_NONE), ('DEFAULT', lib.AVDISCARD_DEFAULT), ('NONREF', lib.AVDISCARD_NONREF), @@ -58,7 +57,6 @@ cdef EnumType _SkipType = define_enum('SkipType', ( ('NONKEY', lib.AVDISCARD_NONKEY), ('ALL', lib.AVDISCARD_ALL), )) -SkipType = _SkipType cdef class CodecContext(object): @@ -426,17 +424,17 @@ cdef class CodecContext(object): property thread_type: """One of :class:`.ThreadType`.""" def __get__(self): - return _ThreadType.get(self.ptr.thread_type, create=True) + return ThreadType.get(self.ptr.thread_type, create=True) def __set__(self, value): if lib.avcodec_is_open(self.ptr): raise RuntimeError("Cannot change thread_type after codec is open.") - self.ptr.thread_type = _ThreadType[value].value + self.ptr.thread_type = ThreadType[value].value property skip_frame: """One of :class:`.SkipType`.""" def __get__(self): - return _SkipType._get(self.ptr.skip_frame, create=True) + return SkipType._get(self.ptr.skip_frame, create=True) def __set__(self, value): - self.ptr.skip_frame = _SkipType[value].value + self.ptr.skip_frame = SkipType[value].value diff --git a/av/enums.pxd b/av/enums.pxd index d03fd37f693834332f92b5926fc371a2ca47cd0d..77e1ca75d791166dfd0ca414453e36cc675229d9 100644 --- a/av/enums.pxd +++ b/av/enums.pxd @@ -1,30 +1,4 @@ - -cdef class EnumType(type): - - cdef readonly str name - cdef readonly tuple names - cdef readonly tuple values - - cdef readonly bint is_flags - cdef readonly bint allow_multi_flags - cdef readonly bint allow_user_create - - cdef _by_name - cdef _by_value - cdef _all - - cdef _init( - self, name, items, - bint is_flags, - bint allow_multi_flags, - bint allow_user_create, - ) - cdef _create(self, name, value, by_value_only=*) - cdef _get_multi_flags(self, long value) - cdef _get(self, long value, bint create=*) - - -cpdef EnumType define_enum( +cpdef define_enum( name, items, bint is_flags=*, bint allow_multi_flags=*, diff --git a/av/enums.pyx b/av/enums.pyx index 0dd00454b381894b8f659cb23667ec05a0174a53..5ef75433ed8f1b9f11b04b2fc27b9733fd7204c3 100644 --- a/av/enums.pyx +++ b/av/enums.pyx @@ -1,3 +1,4 @@ +from collections import OrderedDict try: import copyreg @@ -8,26 +9,23 @@ except ImportError: cdef sentinel = object() -cdef class EnumType(type): +class EnumType(type): + def __new__(cls, name, bases, attrs): + enum_class = type.__new__(cls, name, bases, {}) - cdef _init(self, name, items, bint is_flags, bint allow_multi_flags, bint allow_user_create): + enum_class._by_name = {} + enum_class._by_value = {} + enum_class._all = [] - self.name = name - - self.names = () - self.values = () - self._by_name = {} - self._by_value = {} - self._all = [] + enum_class._allow_multi_flags = False + enum_class._allow_user_create = False - self.is_flags = bool(is_flags) - self.allow_multi_flags = allow_multi_flags - self.allow_user_create = allow_user_create + for name, value in attrs.items(): + enum_class._create(name, value) - for name, value in items: - self._create(name, value) + return enum_class - cdef _create(self, name, value, by_value_only=False): + def _create(self, name, value, by_value_only=False): # We only have one instance per value. try: @@ -40,8 +38,6 @@ cdef class EnumType(type): setattr(self, name, item) self._all.append(item) self._by_name[name] = item - self.names += (name, ) - self.values += (value, ) return item @@ -58,7 +54,7 @@ cdef class EnumType(type): try: return self._by_value[key] except KeyError: - if not self.allow_multi_flags: + if not self._allow_multi_flags: raise try: return self._get_multi_flags(key) @@ -66,9 +62,9 @@ cdef class EnumType(type): raise KeyError(key) if isinstance(key, self): return key - raise TypeError("Uncomparable to {}.".format(self.name), key) + raise TypeError("Uncomparable to {}.".format(self.__name__), key) - cdef _get(self, long value, bint create=False): + def _get(self, long value, bint create=False): try: return self._by_value[value] @@ -78,16 +74,16 @@ cdef class EnumType(type): if not create: return - return self._create('{}_{}'.format(self.name.upper(), value), value, by_value_only=True) + return self._create('{}_{}'.format(self.__name__.upper(), value), value, by_value_only=True) - cdef _get_multi_flags(self, long value): + def _get_multi_flags(self, long value): try: return self._by_value[value] except KeyError: pass - if not self.allow_multi_flags: + if not self._allow_multi_flags: raise ValueError("Missing flag in {}.".format(self.__name__), value) flags = [] @@ -99,7 +95,7 @@ cdef class EnumType(type): if not to_find: break if to_find: - raise ValueError("Could not build combo in {}.".format(self.__name__, value)) + raise ValueError("Could not build combo in {}.".format(self.__name__), value) name = '|'.join(f.name for f in flags) cdef EnumFlag combo = self._create(name, value, by_value_only=True) @@ -112,8 +108,8 @@ cdef class EnumType(type): return self[key] except KeyError: if create: - if not self.allow_user_create: - raise ValueError("Cannot create {}.".format(self.name)) + if not self._allow_user_create: + raise ValueError("Cannot create {}.".format(self.__name__)) return self._get(key, create=True) return default @@ -173,7 +169,7 @@ cdef class EnumItem(object): return True try: - other_inst = (<EnumType>self.__class__)._by_name[other] + other_inst = self.__class__._by_name[other] except KeyError: raise ValueError("Name not in {}.".format(self.__class__.__name__), other) else: @@ -182,7 +178,7 @@ cdef class EnumItem(object): if isinstance(other, int): if self.value == other: return True - if other in (<EnumType>self.__class__)._by_value: + if other in self.__class__._by_value: return False raise ValueError("Value not in {}.".format(self.__class__.__name__), other) @@ -206,38 +202,33 @@ cdef class EnumFlag(EnumItem): if not isinstance(other, int): other = self.__class__[other].value value = self.value & other - return (<EnumType>self.__class__)._get_multi_flags(value) + return self.__class__._get_multi_flags(value) def __or__(self, other): if not isinstance(other, int): other = self.__class__[other].value value = self.value | other - return (<EnumType>self.__class__)._get_multi_flags(value) + return self.__class__._get_multi_flags(value) def __xor__(self, other): if not isinstance(other, int): other = self.__class__[other].value value = self.value ^ other - return (<EnumType>self.__class__)._get_multi_flags(value) + return self.__class__._get_multi_flags(value) def __invert__(self): # This can't result in a flag, but is helpful. return ~self.value -cpdef EnumType define_enum(name, items, bint is_flags=False, bint allow_multi_flags=False, bint allow_user_create=False): +cpdef define_enum(name, items, bint is_flags=False, bint allow_multi_flags=False, bint allow_user_create=False): if is_flags: base_cls = EnumFlag else: base_cls = EnumItem - cdef EnumType cls = EnumType(name, (base_cls, ), {}) - cls._init( - name, items, - is_flags=is_flags, - allow_multi_flags=allow_multi_flags, - allow_user_create=allow_user_create, - ) - + cls = EnumType(name, (base_cls, ), OrderedDict(items)) + cls._allow_multi_flags = allow_multi_flags + cls._allow_user_create = allow_user_create return cls diff --git a/av/option.pyx b/av/option.pyx index 4c74d530173a8c3771d7b238f1d12938a5934b7e..61f0ee774b5914098e982f6b538d584299b9a9f3 100644 --- a/av/option.pyx +++ b/av/option.pyx @@ -1,7 +1,7 @@ cimport libav as lib from av.utils cimport flag_in_bitfield -from av.enums cimport EnumType, define_enum +from av.enums cimport define_enum cdef object _cinit_sentinel = object() @@ -15,7 +15,7 @@ cdef Option wrap_option(tuple choices, const lib.AVOption *ptr): return obj -cdef EnumType _OptionType = define_enum('OptionType', ( +OptionType = define_enum('OptionType', ( ('FLAGS', lib.AV_OPT_TYPE_FLAGS), ('INT', lib.AV_OPT_TYPE_INT), ('INT64', lib.AV_OPT_TYPE_INT64), @@ -36,7 +36,6 @@ cdef EnumType _OptionType = define_enum('OptionType', ( ('CHANNEL_LAYOUT', lib.AV_OPT_TYPE_CHANNEL_LAYOUT), ('BOOL', lib.AV_OPT_TYPE_BOOL), )) -OptionType = _OptionType cdef tuple _INT_TYPES = ( lib.AV_OPT_TYPE_FLAGS, @@ -49,7 +48,7 @@ cdef tuple _INT_TYPES = ( lib.AV_OPT_TYPE_BOOL, ) -cdef EnumType _OptionFlags = define_enum('OptionFlags', ( +OptionFlags = define_enum('OptionFlags', ( ('ENCODING_PARAM', lib.AV_OPT_FLAG_ENCODING_PARAM), ('DECODING_PARAM', lib.AV_OPT_FLAG_DECODING_PARAM), ('AUDIO_PARAM', lib.AV_OPT_FLAG_AUDIO_PARAM), @@ -59,7 +58,6 @@ cdef EnumType _OptionFlags = define_enum('OptionFlags', ( ('READONLY', lib.AV_OPT_FLAG_READONLY), ('FILTERING_PARAM', lib.AV_OPT_FLAG_FILTERING_PARAM), ), is_flags=True) -OptionFlags = _OptionFlags cdef class BaseOption(object): @@ -110,7 +108,7 @@ cdef class Option(BaseOption): property type: def __get__(self): - return _OptionType._get(self.ptr.type, create=True) + return OptionType._get(self.ptr.type, create=True) property offset: """ diff --git a/av/video/frame.pyx b/av/video/frame.pyx index f5428413a9e74821e321f55a11789a81b267c222..50257e9c5bb2b8ccb43240f4660b6923b508339a 100644 --- a/av/video/frame.pyx +++ b/av/video/frame.pyx @@ -1,7 +1,7 @@ from libc.stdint cimport uint8_t from av.deprecation import renamed_attr -from av.enums cimport EnumType, define_enum +from av.enums cimport define_enum from av.utils cimport err_check from av.video.format cimport get_video_format, VideoFormat from av.video.plane cimport VideoPlane @@ -19,7 +19,7 @@ cdef VideoFrame alloc_video_frame(): return VideoFrame.__new__(VideoFrame, _cinit_bypass_sentinel) -cdef EnumType PictureType = define_enum('PictureType', ( +PictureType = define_enum('PictureType', ( ('NONE', lib.AV_PICTURE_TYPE_NONE), ('I', lib.AV_PICTURE_TYPE_I), ('P', lib.AV_PICTURE_TYPE_P), diff --git a/tests/test_enums.py b/tests/test_enums.py index c46ff3476ea22968cb23d572a62900e41ea05a3f..f966afdfe5cacf6581418382720c6893ddc59b4a 100644 --- a/tests/test_enums.py +++ b/tests/test_enums.py @@ -29,6 +29,8 @@ class TestEnums(TestCase): self.assertEqual(foo.name, 'FOO') self.assertEqual(foo.value, 1) + self.assertNotIsInstance(foo, PickleableFooBar) + def test_access(self): cls = self.define_foobar()