diff --git a/setup.py b/setup.py index 37f180acde1773e24ac737952cf240c6ba6dc544..a0285365836273c28e0c655c9c935d85138d7ee2 100755 --- a/setup.py +++ b/setup.py @@ -138,7 +138,6 @@ def install_weboob(): 'Pillow', 'mechanize; python_version < "3.0"', 'futures; python_version < "3.2"', - 'enum34; python_version < "3.4"', ] if not options.deps: diff --git a/weboob/applications/flatboob/flatboob.py b/weboob/applications/flatboob/flatboob.py index ad02687e15c40a8a87c745fa32e8344886bdd40c..4e9635ac082242f61e3f54cdd1bc4b1daabae572 100644 --- a/weboob/applications/flatboob/flatboob.py +++ b/weboob/applications/flatboob/flatboob.py @@ -174,7 +174,7 @@ def do_search(self, line): query.house_types.append(value) _type = None - posts_types = sorted(POSTS_TYPES, key=lambda e: e.value) + posts_types = sorted(POSTS_TYPES) while _type not in range(len(posts_types)): for i, t in enumerate(posts_types): print(' %s%2d)%s %s' % (self.BOLD, diff --git a/weboob/capabilities/bank.py b/weboob/capabilities/bank.py index d3e9a91daf5dac88d962c9e8036e8474d2b80408..16e7bc24738853c08652b3b4e8e1271d92f52d29 100644 --- a/weboob/capabilities/bank.py +++ b/weboob/capabilities/bank.py @@ -29,7 +29,7 @@ from weboob.tools.compat import unicode from .base import BaseObject, Field, StringField, DecimalField, IntField, \ - UserError, Currency, NotAvailable, EnumField, IntEnum + UserError, Currency, NotAvailable, EnumField, Enum from .date import DateField from .collection import CapCollection @@ -190,7 +190,7 @@ class Recipient(BaseAccount): iban = StringField('International Bank Account Number') -class AccountType(IntEnum): +class AccountType(Enum): UNKNOWN = 0 CHECKING = 1 "Transaction, everyday transactions" @@ -312,7 +312,7 @@ class Loan(Account): next_payment_date = DateField('Date of the next payment') -class TransactionType(IntEnum): +class TransactionType(Enum): UNKNOWN = 0 TRANSFER = 1 ORDER = 2 @@ -436,7 +436,7 @@ def __repr__(self): return '' % (self.label, self.code, self.valuation) -class PocketCondition(IntEnum): +class PocketCondition(Enum): UNKNOWN = 0 DATE = 1 AVAILABLE = 2 diff --git a/weboob/capabilities/base.py b/weboob/capabilities/base.py index 5e84851f35e0dc1586d0f0de6df0b64df795c2cf..369f76f186b8f00d9b15aab9d9f44e0bf4e1a4b4 100644 --- a/weboob/capabilities/base.py +++ b/weboob/capabilities/base.py @@ -18,7 +18,6 @@ # along with weboob. If not, see . from collections import OrderedDict -from enum import Enum as _Enum import warnings import re from decimal import Decimal @@ -32,27 +31,65 @@ __all__ = ['UserError', 'FieldNotFound', 'NotAvailable', 'FetchError', 'NotLoaded', 'Capability', 'Field', 'IntField', 'DecimalField', 'FloatField', 'StringField', 'BytesField', 'BoolField', - 'Enum', 'IntEnum', 'StrEnum', 'EnumField', + 'Enum', 'EnumField', 'empty', 'BaseObject'] -class Enum(_Enum): - pass +class EnumMeta(type): + @classmethod + def __prepare__(mcs, name, bases, **kwargs): + # in python3.6, default namespace keeps declaration order + # in python>=3 but <3.6, force ordered namespace + # doesn't work in python2 + return OrderedDict() + + def __init__(cls, name, bases, attrs, *args, **kwargs): + super(EnumMeta, cls).__init__(name, bases, attrs, *args, **kwargs) + attrs = [(k, v) for k, v in attrs.items() if not callable(v) and not k.startswith('__')] + if sys.version_info.major < 3: + # can't have original declaration order, at least sort by value + attrs.sort(key=lambda kv: kv[1]) + cls.__members__ = OrderedDict(attrs) + + def __setattr__(cls, name, value): + super(EnumMeta, cls).__setattr__(name, value) + if not callable(value) and not name.startswith('__'): + cls.__members__[name] = value + + def __call__(cls, *args, **kwargs): + raise ValueError("Enum type can't be instanciated") + + @property + def _items(cls): + return cls.__members__.items() + + @property + def _keys(cls): + return cls.__members__.keys() + + @property + def _values(cls): + return cls.__members__.values() + + @property + def _types(cls): + return set(map(type, cls._values)) + def __iter__(cls): + return iter(cls.__members__.values()) -class StrEnum(unicode, Enum): - if sys.version_info.major < 3: - # cannot use StrConv helper, else for some reason it will error like: - # TypeError: cannot be pickled - def __str__(self): - return unicode(self.value).encode('utf-8') - else: - def __str__(self): - return str(self.value) + def __len__(cls): + return len(cls.__members__) + def __contains__(cls, value): + return value in cls.__members__.values() -class IntEnum(int, Enum): - __str__ = int.__str__ + def __getitem__(cls, k): + return cls.__members__[k] + + +class Enum(with_metaclass(EnumMeta, object)): + pass def empty(value): @@ -306,13 +343,15 @@ def convert(self, value): class EnumField(Field): def __init__(self, doc, enum, **kwargs): - super(EnumField, self).__init__(doc, enum, **kwargs) - if not issubclass(enum, _Enum): + if not issubclass(enum, Enum): raise TypeError('invalid enum type: %r' % enum) + super(EnumField, self).__init__(doc, *enum._types, **kwargs) self.enum = enum def convert(self, value): - return self.enum(value) + if value not in self.enum._values: + raise ValueError('value %r does not belong to enum %s' % (value, self.enum)) + return value class _BaseObjectMeta(type): diff --git a/weboob/capabilities/bugtracker.py b/weboob/capabilities/bugtracker.py index 9f43e1390da7bbbd07fcef5b2d709dfb27c81b34..c846f259cff4271a0a65079f76e2a43d76d69aa3 100644 --- a/weboob/capabilities/bugtracker.py +++ b/weboob/capabilities/bugtracker.py @@ -20,7 +20,7 @@ from weboob.tools.compat import unicode from .base import Capability, BaseObject, Field, StringField,\ - IntField, UserError, IntEnum + IntField, UserError, Enum from .date import DateField, DeltaField @@ -135,7 +135,7 @@ def __repr__(self): return '' % self.name -class StatusType(IntEnum): +class StatusType(Enum): NEW = 0 PROGRESS = 1 RESOLVED = 2 diff --git a/weboob/capabilities/calendar.py b/weboob/capabilities/calendar.py index 59d2576177ecb140189ec75772a27a6b4b4a8f82..a5cb44ab88b7ba637cdd4a0fbcbb161b3863e5f1 100644 --- a/weboob/capabilities/calendar.py +++ b/weboob/capabilities/calendar.py @@ -19,7 +19,7 @@ from .base import ( BaseObject, StringField, IntField, FloatField, Field, EnumField, - StrEnum, + Enum, ) from .collection import CapCollection, CollectionNotFound, Collection from .date import DateField @@ -30,7 +30,7 @@ __all__ = ['BaseCalendarEvent', 'CapCalendarEvent'] -class CATEGORIES(StrEnum): +class CATEGORIES(Enum): CONCERT = u'Concert' CINE = u'Cinema' THEATRE = u'Theatre' @@ -45,18 +45,18 @@ class CATEGORIES(StrEnum): #the following elements deal with ICalendar stantdards #see http://fr.wikipedia.org/wiki/ICalendar#Ev.C3.A9nements_.28VEVENT.29 -class TRANSP(StrEnum): +class TRANSP(Enum): OPAQUE = u'OPAQUE' TRANSPARENT = u'TRANSPARENT' -class STATUS(StrEnum): +class STATUS(Enum): TENTATIVE = u'TENTATIVE' CONFIRMED = u'CONFIRMED' CANCELLED = u'CANCELLED' -class TICKET(StrEnum): +class TICKET(Enum): AVAILABLE = u'Available' NOTAVAILABLE = u'Not available' CLOSED = u'Closed' diff --git a/weboob/capabilities/file.py b/weboob/capabilities/file.py index 0f4d519ac4849503e107c5dbbd410c888cb92cc4..1822bae3e8e970a4da0a2d83ce69d201778c6d03 100644 --- a/weboob/capabilities/file.py +++ b/weboob/capabilities/file.py @@ -19,14 +19,14 @@ from weboob.tools.compat import long -from .base import Capability, BaseObject, NotAvailable, Field, StringField, IntField, StrEnum, IntEnum +from .base import Capability, BaseObject, NotAvailable, Field, StringField, IntField, Enum from .date import DateField __all__ = ['BaseFile', 'CapFile'] -class LICENSES(StrEnum): +class LICENSES(Enum): OTHER = u'Other license' PD = u'Public Domain' COPYRIGHT = u'All rights reserved' @@ -74,7 +74,7 @@ def page_url(self): return self.id2url(self.id) -class SearchSort(IntEnum): +class SearchSort(Enum): RELEVANCE = 0 RATING = 1 VIEWS = 2 diff --git a/weboob/capabilities/gallery.py b/weboob/capabilities/gallery.py index f0b7be5394070d30a0bb5dca5aebfb7d87ce145a..ff05740347889387ac4fa8d865192cf41f91110a 100644 --- a/weboob/capabilities/gallery.py +++ b/weboob/capabilities/gallery.py @@ -21,7 +21,7 @@ from weboob.capabilities.image import BaseImage as CIBaseImage, Thumbnail from weboob.tools.compat import unicode from .base import Capability, BaseObject, NotLoaded, Field, StringField, \ - IntField, FloatField, IntEnum + IntField, FloatField, Enum from .date import DateField @@ -98,7 +98,7 @@ def __iscomplete__(self): return self.data is not NotLoaded -class SearchSort(IntEnum): +class SearchSort(Enum): RELEVANCE = 0 RATING = 1 VIEWS = 2 diff --git a/weboob/capabilities/housing.py b/weboob/capabilities/housing.py index 364faf4307c80ab027c01cf516bfcfabeefbea2e..60ad763950fc5cbf19d1e301af5334443a1e3e2d 100644 --- a/weboob/capabilities/housing.py +++ b/weboob/capabilities/housing.py @@ -19,7 +19,7 @@ from .base import Capability, BaseObject, Field, IntField, DecimalField, \ - StringField, BytesField, StrEnum, EnumField, UserError + StringField, BytesField, Enum, EnumField, UserError from .date import DateField __all__ = [ @@ -58,13 +58,13 @@ def __repr__(self): return '' % (self.id, len(self.data) if self.data else 0, self.url) -class UTILITIES(StrEnum): +class UTILITIES(Enum): INCLUDED = u'C.C.' EXCLUDED = u'H.C.' UNKNOWN = u'' -class ENERGY_CLASS(StrEnum): +class ENERGY_CLASS(Enum): A = u'A' B = u'B' C = u'C' @@ -74,7 +74,7 @@ class ENERGY_CLASS(StrEnum): G = u'G' -class POSTS_TYPES(StrEnum): +class POSTS_TYPES(Enum): RENT=u'RENT' SALE = u'SALE' SHARING = u'SHARING' @@ -82,12 +82,12 @@ class POSTS_TYPES(StrEnum): VIAGER = u'VIAGER' -class ADVERT_TYPES(StrEnum): +class ADVERT_TYPES(Enum): PROFESSIONAL = u'Professional' PERSONAL = u'Personal' -class HOUSE_TYPES(StrEnum): +class HOUSE_TYPES(Enum): APART = u'Apartment' HOUSE = u'House' PARKING = u'Parking' diff --git a/weboob/capabilities/parcel.py b/weboob/capabilities/parcel.py index e8a8863c28ddf261a27e0a2d4b0b15a9011be904..319ef5751df7920e0c20e6258f6e751539db7eb3 100644 --- a/weboob/capabilities/parcel.py +++ b/weboob/capabilities/parcel.py @@ -18,7 +18,7 @@ # along with weboob. If not, see . -from .base import Capability, BaseObject, Field, StringField, UserError, IntEnum +from .base import Capability, BaseObject, Field, StringField, UserError, Enum from .date import DateField @@ -31,7 +31,7 @@ def __repr__(self): return '' % (self.date, self.activity, self.location) -class ParcelState(IntEnum): +class ParcelState(Enum): UNKNOWN = 0 PLANNED = 1 IN_TRANSIT = 2