diff options
Diffstat (limited to 'src')
33 files changed, 8227 insertions, 5791 deletions
diff --git a/src/zope/interface/README.ru.txt b/src/zope/interface/README.ru.txt deleted file mode 100644 index a284c9a..0000000 --- a/src/zope/interface/README.ru.txt +++ /dev/null @@ -1,803 +0,0 @@ -========== -Интерфейсы -========== - -.. contents:: - -Интерфейсы - это объекты специфицирующие (документирующие) внешнее поведение -объектов которые их "предоставляют". Интерфейсы определяют поведение через -следующие составляющие: - -- Неформальную документацию в строках документации - -- Определения атрибутов - -- Инварианты - условия, которые должны соблюдаться для объектов предоставляющих - интерфейс - -Определения атрибутов описывают конкретные атрибуты. Они определяют -имя атрибута и предоставляют документацию и ограничения для значений -атрибута. Определения атрибутов могут быть заданы несколькими путями -как мы увидим ниже. - -Определение интерфейсов -======================= - -Интерфейсы определяются с использованием ключевого слова class:: - - >>> import zope.interface - >>> class IFoo(zope.interface.Interface): - ... """Foo blah blah""" - ... - ... x = zope.interface.Attribute("""X blah blah""") - ... - ... def bar(q, r=None): - ... """bar blah blah""" - -В примере выше мы создали интерфейс `IFoo`. Мы наследуем его от -класса `zope.interface.Interface`, который является родительским интерфейсом -для всех интерфейсов, как `object` - это родительский класс для всех новых -классов [#create]_. Данный интерфейс не является классом, а является -Интерфейсом, экземпляром `InterfaceClass`:: - - >>> type(IFoo) - <class 'zope.interface.interface.InterfaceClass'> - -Мы можем запросить у интерфейса его документацию:: - - >>> IFoo.__doc__ - 'Foo blah blah' - -и его имя:: - - >>> IFoo.__name__ - 'IFoo' - -и даже модуль в котором он определен:: - - >>> IFoo.__module__ - '__main__' - -Наш интерфейс определяет два атрибута: - -`x` - Это простейшая форма определения атрибутов. Определяются имя - и строка документации. Формально здесь не определяется ничего более. - -`bar` - Это метод. Методы определяются как обычные функции. Метод - это просто - атрибут который должен быть вызываемым с указанием сигнатуры, - предоставляемой определением функции. - - Надо отметить, что аргумент `self` не указывается для `bar`. Интерфейс - документирует как объект *используется*. Когда методы экземпляров классов - вызываются мы не передаем аргумент `self`, таким образом аргумент `self` - не включается и в сигнатуру интерфейса. Аргумент `self` в методах - экземпляров классов на самом деле деталь реализации экземпляров классов - в Python. Другие объекты кроме экземпляров классов могут предоставлять - интерфейсы и их методы могут не быть методами экземпляров классов. Для - примера модули могут предоставлять интерфейсы и их методы обычно просто - функции. Даже экземпляры могут иметь методы не являющиеся методами - экземпляров класса. - -Мы можем получить доступ к атрибутам определенным интерфейсом используя -синтаксис доступа к элементам массива:: - - >>> x = IFoo['x'] - >>> type(x) - <class 'zope.interface.interface.Attribute'> - >>> x.__name__ - 'x' - >>> x.__doc__ - 'X blah blah' - - >>> IFoo.get('x').__name__ - 'x' - - >>> IFoo.get('y') - -Можно использовать `in` для определения содержит ли интерфейс -определенное имя:: - - >>> 'x' in IFoo - True - -Мы можем использовать итератор для интерфейсов что бы получить все имена -которые интерфейсы определяют:: - - >>> names = list(IFoo) - >>> names.sort() - >>> names - ['bar', 'x'] - -Надо помнить, что интерфейсы не являются классами. Мы не можем получить -доступ к определениям атрибутов через доступ к атрибутам интерфейсов:: - - >>> IFoo.x - Traceback (most recent call last): - File "<stdin>", line 1, in ? - AttributeError: 'InterfaceClass' object has no attribute 'x' - -Методы также предоставляют доступ к сигнатуре метода:: - - >>> bar = IFoo['bar'] - >>> bar.getSignatureString() - '(q, r=None)' - -Объявление интерфейсов -====================== - -Определив интерфейс мы можем теперь *объявить*, что объекты предоставляют их. -Перед описанием деталей определим некоторые термины: - -*предоставлять* - Мы говорим, что объекты *предоставляют* интерфейсы. Если объект - предоставляет интерфейс, тогда интерфейс специфицирует поведение объекта. - Другими словами, интерфейсы специфицируют поведение объектов которые - предоставляют их. - -*реализовать* - Мы обычно говорим что классы *реализуют* интерфейсы. Если класс - реализует интерфейс, тогда экземпляры этого класса предоставляют - данный интерфейс. Объекты предоставляют интерфейсы которые их классы - реализуют [#factory]_. (Объекты также могут предоставлять интерфейсы напрямую - плюс к тем которые реализуют их классы.) - - Важно помнить, что классы обычно не предоставляют интерфейсы которые - они реализуют. - - Мы можем обобщить это до фабрик. Для любого вызываемого объекта мы можем - объявить что он производит объекты которые предоставляют какие-либо - интерфейсы сказав, что фабрика реализует данные интерфейсы. - -Теперь после того как мы определили эти термины мы можем поговорить об -API для объявления интерфейсов. - -Объявление реализуемых интерфейсов ----------------------------------- - -Наиболее часто используемый путь для объявления интерфейсов - это использование -функции implements в определении класса:: - - >>> class Foo: - ... zope.interface.implements(IFoo) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - -В этом примере мы объявили, что `Foo` реализует `IFoo`. Это значит, что -экземпляры `Foo` предоставляют `IFoo`. После данного объявления есть -несколько путей для анализа объявлений. Во-первых мы можем спросить -что интерфейс реализован классом:: - - >>> IFoo.implementedBy(Foo) - True - -Также мы можем спросить если интерфейс предоставляется объектами класса:: - - >>> foo = Foo() - >>> IFoo.providedBy(foo) - True - -Конечно `Foo` не предоставляет `IFoo`, он реализует его:: - - >>> IFoo.providedBy(Foo) - False - -Мы можем также узнать какие интерфейсы реализуются объектами:: - - >>> list(zope.interface.implementedBy(Foo)) - [<InterfaceClass __main__.IFoo>] - -Это ошибка спрашивать про интерфейсы реализуемые не вызываемым объектом:: - - >>> IFoo.implementedBy(foo) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - - >>> list(zope.interface.implementedBy(foo)) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - -Также можно узнать какие интерфейсы предоставляются объектами:: - - >>> list(zope.interface.providedBy(foo)) - [<InterfaceClass __main__.IFoo>] - >>> list(zope.interface.providedBy(Foo)) - [] - -Мы можем объявить интерфейсы реализуемые другими фабриками (кроме классов). -Это можно сделать используя декоратор `implementer` (в стиле Python 2.4). -Для версий Python ниже 2.4 это будет выглядеть следующим образом:: - - >>> def yfoo(y): - ... foo = Foo() - ... foo.y = y - ... return foo - >>> yfoo = zope.interface.implementer(IFoo)(yfoo) - - >>> list(zope.interface.implementedBy(yfoo)) - [<InterfaceClass __main__.IFoo>] - -Надо заметить, что декоратор implementer может модифицировать свои аргументы. -Вызывающая сторона не должна предполагать, что всегда будет создаваться -новый объект. - -XXX: Double check and update these version numbers, and translate to russian: - -In zope.interface 3.5.1 and lower, the implementer decorator can not -be used for classes, but in 3.5.2 and higher it can: - - >>> Foo = zope.interface.implementer(IFoo)(Foo) - >>> list(zope.interface.providedBy(Foo())) - [<InterfaceClass __main__.IFoo>] - -Note that class decorators using the @implementer(IFoo) syntax are only -supported in Python 2.6 and later. - - -Объявление предоставляемых интерфейсов --------------------------------------- - -Мы можем объявлять интерфейсы напрямую предоставляемые объектами. Предположим -что мы хотим документировать что делает метод `__init__` класса `Foo`. Это -*точно* не часть `IFoo`. Обычно мы не должны напрямую вызывать метод `__init__` -для экземпляров Foo. Скорее метод `__init__` является частью метода `__call__` -класса `Foo`:: - - >>> class IFooFactory(zope.interface.Interface): - ... """Create foos""" - ... - ... def __call__(x=None): - ... """Create a foo - ... - ... The argument provides the initial value for x ... - ... """ - -У нас есть класс предоставляющий данный интерфейс, таким образом мы можем -объявить интерфейс класса:: - - >>> zope.interface.directlyProvides(Foo, IFooFactory) - -Теперь мы видим, что Foo уже предоставляет интерфейсы:: - - >>> list(zope.interface.providedBy(Foo)) - [<InterfaceClass __main__.IFooFactory>] - >>> IFooFactory.providedBy(Foo) - True - -Объявление интерфейсов класса достаточно частая операция и для нее есть -специальная функция объявления `classProvides`, которая позволяет объявлять -интерфейсы при определении класса:: - - >>> class Foo2: - ... zope.interface.implements(IFoo) - ... zope.interface.classProvides(IFooFactory) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - - >>> list(zope.interface.providedBy(Foo2)) - [<InterfaceClass __main__.IFooFactory>] - >>> IFooFactory.providedBy(Foo2) - True - -Похожая функция `moduleProvides` поддерживает объявление интерфейсов при -определении модуля. Для примера смотрите использование вызова -`moduleProvides` в `zope.interface.__init__`, который объявляет, что -пакет `zope.interface` предоставляет `IInterfaceDeclaration`. - -Иногда мы хотим объявить интерфейсы экземпляров, даже если эти экземпляры -уже берут интерфейсы от своих классов. Предположим, что мы создаем новый -интерфейс `ISpecial`:: - - >>> class ISpecial(zope.interface.Interface): - ... reason = zope.interface.Attribute("Reason why we're special") - ... def brag(): - ... "Brag about being special" - -Мы можем сделать созданный экземпляр foo специальным предоставив атрибуты -`reason` и `brag`:: - - >>> foo.reason = 'I just am' - >>> def brag(): - ... return "I'm special!" - >>> foo.brag = brag - >>> foo.reason - 'I just am' - >>> foo.brag() - "I'm special!" - -и объявив интерфейс:: - - >>> zope.interface.directlyProvides(foo, ISpecial) - -таким образом новый интерфейс включается в список предоставляемых интерфейсов:: - - >>> ISpecial.providedBy(foo) - True - >>> list(zope.interface.providedBy(foo)) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] - -Мы также можем определить, что интерфейсы напрямую предоставляются -объектами:: - - >>> list(zope.interface.directlyProvidedBy(foo)) - [<InterfaceClass __main__.ISpecial>] - - >>> newfoo = Foo() - >>> list(zope.interface.directlyProvidedBy(newfoo)) - [] - -Наследуемые объявления ----------------------- - -Обычно объявления наследуются:: - - >>> class SpecialFoo(Foo): - ... zope.interface.implements(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(SpecialFoo)) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] - - >>> list(zope.interface.providedBy(SpecialFoo())) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] - -Иногда мы не хотим наследовать объявления. В этом случае мы можем -использовать `implementsOnly` вместо `implements`:: - - >>> class Special(Foo): - ... zope.interface.implementsOnly(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(Special)) - [<InterfaceClass __main__.ISpecial>] - - >>> list(zope.interface.providedBy(Special())) - [<InterfaceClass __main__.ISpecial>] - -Внешние объявления ------------------- - -Обычно мы создаем объявления реализации как часть объявления класса. Иногда -мы можем захотеть создать объявления вне объявления класса. Для примера, -мы можем хотеть объявить интерфейсы для классов которые писали не мы. -Для этого может использоваться функция `classImplements`:: - - >>> class C: - ... pass - - >>> zope.interface.classImplements(C, IFoo) - >>> list(zope.interface.implementedBy(C)) - [<InterfaceClass __main__.IFoo>] - -Мы можем использовать `classImplementsOnly` для исключения наследуемых -интерфейсов:: - - >>> class C(Foo): - ... pass - - >>> zope.interface.classImplementsOnly(C, ISpecial) - >>> list(zope.interface.implementedBy(C)) - [<InterfaceClass __main__.ISpecial>] - -Объекты объявлений ------------------- - -Когда мы объявляем интерфейсы мы создаем объект *объявления*. Когда мы -запрашиваем объявления возвращается объект объявления:: - - >>> type(zope.interface.implementedBy(Special)) - <class 'zope.interface.declarations.Implements'> - -Объекты объявления и объекты интерфейсов во многом похожи друг на друга. -На самом деле они даже имеют общий базовый класс. Важно понять, что они могут -использоваться там где в объявлениях ожидаются интерфейсы. Вот простой -пример:: - - >>> class Special2(Foo): - ... zope.interface.implementsOnly( - ... zope.interface.implementedBy(Foo), - ... ISpecial, - ... ) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - -Объявление здесь практически такое же как -``zope.interface.implements(ISpecial)``, отличие только в порядке -интерфейсов в итоговом объявления:: - - >>> list(zope.interface.implementedBy(Special2)) - [<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.ISpecial>] - -Наследование интерфейсов -======================== - -Интерфейсы могут расширять другие интерфейсы. Они делают это просто -показывая эти интерфейсы как базовые:: - - >>> class IBlat(zope.interface.Interface): - ... """Blat blah blah""" - ... - ... y = zope.interface.Attribute("y blah blah") - ... def eek(): - ... """eek blah blah""" - - >>> IBlat.__bases__ - (<InterfaceClass zope.interface.Interface>,) - - >>> class IBaz(IFoo, IBlat): - ... """Baz blah""" - ... def eek(a=1): - ... """eek in baz blah""" - ... - - >>> IBaz.__bases__ - (<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.IBlat>) - - >>> names = list(IBaz) - >>> names.sort() - >>> names - ['bar', 'eek', 'x', 'y'] - -Заметим, что `IBaz` переопределяет eek:: - - >>> IBlat['eek'].__doc__ - 'eek blah blah' - >>> IBaz['eek'].__doc__ - 'eek in baz blah' - -Мы были осторожны переопределяя eek совместимым путем. Когда интерфейс -расширяется, расширенный интерфейс должен быть совместимым [#compat]_ с -расширяемыми интерфейсами. - -Мы можем запросить расширяет ли один из интерфейсов другой:: - - >>> IBaz.extends(IFoo) - True - >>> IBlat.extends(IFoo) - False - -Заметим, что интерфейсы не расширяют сами себя:: - - >>> IBaz.extends(IBaz) - False - -Иногда мы можем хотеть что бы они расширяли сами себя, но вместо этого -мы можем использовать `isOrExtends`:: - - >>> IBaz.isOrExtends(IBaz) - True - >>> IBaz.isOrExtends(IFoo) - True - >>> IFoo.isOrExtends(IBaz) - False - -Когда мы применяем итерацию к интерфейсу мы получаем все имена которые он -определяет включая имена определенные для базовых интерфейсов. Иногда -мы хотим получить *только* имена определенные интерфейсом напрямую. -Для этого мы используем метод `names`:: - - >>> list(IBaz.names()) - ['eek'] - -Наследование в случае определения атрибутов --------------------------------------------- - -Интерфейс может переопределять определения атрибутов из базовых интерфейсов. -Если два базовых интерфейса определяют один и тот же атрибут атрибут -наследуется от более специфичного интерфейса. Для примера:: - - >>> class IBase(zope.interface.Interface): - ... - ... def foo(): - ... "base foo doc" - - >>> class IBase1(IBase): - ... pass - - >>> class IBase2(IBase): - ... - ... def foo(): - ... "base2 foo doc" - - >>> class ISub(IBase1, IBase2): - ... pass - -Определение ISub для foo будет из IBase2 т.к. IBase2 более специфичен для -IBase:: - - >>> ISub['foo'].__doc__ - 'base2 foo doc' - -Заметим, что это отличается от поиска в глубину. - -Иногда полезно узнать, что интерфейс определяет атрибут напрямую. Мы можем -использовать метод direct для получения напрямую определенных атрибутов:: - - >>> IBase.direct('foo').__doc__ - 'base foo doc' - - >>> ISub.direct('foo') - -Спецификации ------------- - -Интерфейсы и объявления - это специальные случаи спецификаций. Описание -выше для наследования интерфейсов можно применить и к объявлениям и -к спецификациям. Объявления фактически расширяют интерфейсы которые они -объявляют:: - - >>> class Baz(object): - ... zope.interface.implements(IBaz) - - >>> baz_implements = zope.interface.implementedBy(Baz) - >>> baz_implements.__bases__ - (<InterfaceClass __main__.IBaz>, <implementedBy ...object>) - - >>> baz_implements.extends(IFoo) - True - - >>> baz_implements.isOrExtends(IFoo) - True - >>> baz_implements.isOrExtends(baz_implements) - True - -Спецификации (интерфейсы и объявления) предоставляют атрибут `__sro__` -который описывает спецификацию и всех ее предков:: - - >>> baz_implements.__sro__ - (<implementedBy __main__.Baz>, - <InterfaceClass __main__.IBaz>, - <InterfaceClass __main__.IFoo>, - <InterfaceClass __main__.IBlat>, - <InterfaceClass zope.interface.Interface>, - <implementedBy ...object>) - -Помеченные значения -=================== - -Интерфейсы и описания атрибутов поддерживают механизм расширения -заимствованный из UML и называемый "помеченные значения" который позволяет -сохранять дополнительные данные:: - - >>> IFoo.setTaggedValue('date-modified', '2004-04-01') - >>> IFoo.setTaggedValue('author', 'Jim Fulton') - >>> IFoo.getTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('datemodified') - >>> tags = list(IFoo.getTaggedValueTags()) - >>> tags.sort() - >>> tags - ['author', 'date-modified'] - -Атрибуты функций конвертируются в помеченные значения когда создаются -определения атрибутов метода:: - - >>> class IBazFactory(zope.interface.Interface): - ... def __call__(): - ... "create one" - ... __call__.return_type = IBaz - - >>> IBazFactory['__call__'].getTaggedValue('return_type') - <InterfaceClass __main__.IBaz> - -Помеченные значения также могут быть определены внутри определения -интерфейса:: - - >>> class IWithTaggedValues(zope.interface.Interface): - ... zope.interface.taggedValue('squish', 'squash') - >>> IWithTaggedValues.getTaggedValue('squish') - 'squash' - -Инварианты -========== - -Интерфейсы могут описывать условия которые должны быть соблюдены для объектов -которые их предоставляют. Эти условия описываются используя один или более -инвариантов. Инварианты - это вызываемые объекты которые будут вызваны -с объектом предоставляющим интерфейс в качестве параметра. Инвариант -должен выкинуть исключение `Invalid` если условие не соблюдено. Например:: - - >>> class RangeError(zope.interface.Invalid): - ... """A range has invalid limits""" - ... def __repr__(self): - ... return "RangeError(%r)" % self.args - - >>> def range_invariant(ob): - ... if ob.max < ob.min: - ... raise RangeError(ob) - -Определив этот инвариант мы можем использовать его в определении интерфейсов:: - - >>> class IRange(zope.interface.Interface): - ... min = zope.interface.Attribute("Lower bound") - ... max = zope.interface.Attribute("Upper bound") - ... - ... zope.interface.invariant(range_invariant) - -Интерфейсы имеют метод для проверки своих инвариантов:: - - >>> class Range(object): - ... zope.interface.implements(IRange) - ... - ... def __init__(self, min, max): - ... self.min, self.max = min, max - ... - ... def __repr__(self): - ... return "Range(%s, %s)" % (self.min, self.max) - - >>> IRange.validateInvariants(Range(1,2)) - >>> IRange.validateInvariants(Range(1,1)) - >>> IRange.validateInvariants(Range(2,1)) - Traceback (most recent call last): - ... - RangeError: Range(2, 1) - -В случае нескольких инвариантов мы можем захотеть остановить проверку после -первой ошибки. Если мы передадим в `validateInvariants` пустой список тогда -будет выкинуто единственное исключение `Invalid` со списком исключений -как аргументом:: - - >>> from zope.interface.exceptions import Invalid - >>> errors = [] - >>> try: - ... IRange.validateInvariants(Range(2,1), errors) - ... except Invalid, e: - ... str(e) - '[RangeError(Range(2, 1))]' - -И список будет заполнен индивидуальными исключениями:: - - >>> errors - [RangeError(Range(2, 1))] - - >>> del errors[:] - -Адаптация -========= - -Интерфейсы могут быть вызваны для осуществления адаптации. Эта семантика -основана на функции adapt из PEP 246. Если объект не может быть адаптирован -будет выкинут TypeError:: - - >>> class I(zope.interface.Interface): - ... pass - - >>> I(0) - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>) - -только если альтернативное значение не передано как второй аргумент:: - - >>> I(0, 'bob') - 'bob' - -Если объект уже реализует нужный интерфейс он будет возвращен:: - - >>> class C(object): - ... zope.interface.implements(I) - - >>> obj = C() - >>> I(obj) is obj - True - -Если объект реализует __conform__, тогда она будет использована:: - - >>> class C(object): - ... zope.interface.implements(I) - ... def __conform__(self, proto): - ... return 0 - - >>> I(C()) - 0 - -Также если присутствуют функции для вызова адаптации (см. __adapt__) они будут -использованы:: - - >>> from zope.interface.interface import adapter_hooks - >>> def adapt_0_to_42(iface, obj): - ... if obj == 0: - ... return 42 - - >>> adapter_hooks.append(adapt_0_to_42) - >>> I(0) - 42 - - >>> adapter_hooks.remove(adapt_0_to_42) - >>> I(0) - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>) - - -__adapt__ ---------- - - >>> class I(zope.interface.Interface): - ... pass - -Интерфейсы реализуют метод __adapt__ из PEP 246. Этот метод обычно не -вызывается напрямую. Он вызывается архитектурой адаптации из PEP 246 и методом -__call__ интерфейсов. Метод адаптации отвечает за адаптацию объекта к -получателю. Версия по умолчанию возвращает None:: - - >>> I.__adapt__(0) - -если только переданный объект не предоставляет нужный интерфейс:: - - >>> class C(object): - ... zope.interface.implements(I) - - >>> obj = C() - >>> I.__adapt__(obj) is obj - True - -Функции для вызова адаптации могут быть добавлены (или удалены) для -предоставления адаптации "на заказ". Мы установим глупую функцию которая -адаптирует 0 к 42. Мы устанавливаем функцию просто добавляя ее к списку -adapter_hooks:: - - >>> from zope.interface.interface import adapter_hooks - >>> def adapt_0_to_42(iface, obj): - ... if obj == 0: - ... return 42 - - >>> adapter_hooks.append(adapt_0_to_42) - >>> I.__adapt__(0) - 42 - -Функции должны возвращать либо адаптер, либо None если адаптер не найден. -Функции могут быть удалены удалением их из списка:: - - >>> adapter_hooks.remove(adapt_0_to_42) - >>> I.__adapt__(0) - - -.. [#create] Основная причина по которой мы наследуемся от `Interface` - это - что бы быть уверенными в том, что ключевое слово class будет - создавать интерфейс, а не класс. - - Есть возможность создать интерфейсы вызвав специальный - класс интерфейса напрямую. Делая это, возможно (и в редких - случаях полезно) создать интерфейсы которые не наследуются - от `Interface`. Однако использование этой техники выходит - за рамки данного документа. - -.. [#factory] Классы - это фабрики. Они могут быть вызваны для создания - своих экземпляров. Мы ожидаем что в итоге мы расширим - концепцию реализации на другие типы фабрик, таким образом - мы сможем объявлять интерфейсы предоставляемые созданными - фабриками объектами. - -.. [#compat] Цель - заменяемость. Объект который предоставляет расширенный - интерфейс должен быть заменяем в качестве объектов которые - предоставляют расширяемый интерфейс. В нашем примере объект - который предоставляет IBaz должен быть используемым и - в случае если ожидается объект который предоставляет IBlat. - - Реализация интерфейса не требует этого. Но возможно в дальнейшем - она должна будет делать какие-либо проверки. diff --git a/src/zope/interface/README.txt b/src/zope/interface/README.txt deleted file mode 100644 index 253d1ed..0000000 --- a/src/zope/interface/README.txt +++ /dev/null @@ -1,829 +0,0 @@ -========== -Interfaces -========== - -Interfaces are objects that specify (document) the external behavior -of objects that "provide" them. An interface specifies behavior -through: - -- Informal documentation in a doc string - -- Attribute definitions - -- Invariants, which are conditions that must hold for objects that - provide the interface - -Attribute definitions specify specific attributes. They define the -attribute name and provide documentation and constraints of attribute -values. Attribute definitions can take a number of forms, as we'll -see below. - -Defining interfaces -=================== - -Interfaces are defined using Python class statements:: - - >>> import zope.interface - >>> class IFoo(zope.interface.Interface): - ... """Foo blah blah""" - ... - ... x = zope.interface.Attribute("""X blah blah""") - ... - ... def bar(q, r=None): - ... """bar blah blah""" - -In the example above, we've created an interface, `IFoo`. We -subclassed `zope.interface.Interface`, which is an ancestor interface for -all interfaces, much as `object` is an ancestor of all new-style -classes [#create]_. The interface is not a class, it's an Interface, -an instance of `InterfaceClass`:: - - >>> type(IFoo) - <class 'zope.interface.interface.InterfaceClass'> - -We can ask for the interface's documentation:: - - >>> IFoo.__doc__ - 'Foo blah blah' - -and its name:: - - >>> IFoo.__name__ - 'IFoo' - -and even its module:: - - >>> IFoo.__module__ - '__main__' - -The interface defined two attributes: - -`x` - This is the simplest form of attribute definition. It has a name - and a doc string. It doesn't formally specify anything else. - -`bar` - This is a method. A method is defined via a function definition. A - method is simply an attribute constrained to be a callable with a - particular signature, as provided by the function definition. - - Note that `bar` doesn't take a `self` argument. Interfaces document - how an object is *used*. When calling instance methods, you don't - pass a `self` argument, so a `self` argument isn't included in the - interface signature. The `self` argument in instance methods is - really an implementation detail of Python instances. Other objects, - besides instances can provide interfaces and their methods might not - be instance methods. For example, modules can provide interfaces and - their methods are usually just functions. Even instances can have - methods that are not instance methods. - -You can access the attributes defined by an interface using mapping -syntax:: - - >>> x = IFoo['x'] - >>> type(x) - <class 'zope.interface.interface.Attribute'> - >>> x.__name__ - 'x' - >>> x.__doc__ - 'X blah blah' - - >>> IFoo.get('x').__name__ - 'x' - - >>> IFoo.get('y') - -You can use `in` to determine if an interface defines a name:: - - >>> 'x' in IFoo - True - -You can iterate over interfaces to get the names they define:: - - >>> names = list(IFoo) - >>> names.sort() - >>> names - ['bar', 'x'] - -Remember that interfaces aren't classes. You can't access attribute -definitions as attributes of interfaces:: - - >>> IFoo.x - Traceback (most recent call last): - File "<stdin>", line 1, in ? - AttributeError: 'InterfaceClass' object has no attribute 'x' - -Methods provide access to the method signature:: - - >>> bar = IFoo['bar'] - >>> bar.getSignatureString() - '(q, r=None)' - -TODO - Methods really should have a better API. This is something that - needs to be improved. - -Declaring interfaces -==================== - -Having defined interfaces, we can *declare* that objects provide -them. Before we describe the details, lets define some terms: - -*provide* - We say that objects *provide* interfaces. If an object provides an - interface, then the interface specifies the behavior of the - object. In other words, interfaces specify the behavior of the - objects that provide them. - -*implement* - We normally say that classes *implement* interfaces. If a class - implements an interface, then the instances of the class provide - the interface. Objects provide interfaces that their classes - implement [#factory]_. (Objects can provide interfaces directly, - in addition to what their classes implement.) - - It is important to note that classes don't usually provide the - interfaces that they implement. - - We can generalize this to factories. For any callable object we - can declare that it produces objects that provide some interfaces - by saying that the factory implements the interfaces. - -Now that we've defined these terms, we can talk about the API for -declaring interfaces. - -Declaring implemented interfaces --------------------------------- - -The most common way to declare interfaces is using the implements -function in a class statement:: - - >>> class Foo: - ... zope.interface.implements(IFoo) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - - -In this example, we declared that `Foo` implements `IFoo`. This means -that instances of `Foo` provide `IFoo`. Having made this declaration, -there are several ways we can introspect the declarations. First, we -can ask an interface whether it is implemented by a class:: - - >>> IFoo.implementedBy(Foo) - True - -And we can ask whether an interface is provided by an object:: - - >>> foo = Foo() - >>> IFoo.providedBy(foo) - True - -Of course, `Foo` doesn't provide `IFoo`, it implements it:: - - >>> IFoo.providedBy(Foo) - False - -We can also ask what interfaces are implemented by an object:: - - >>> list(zope.interface.implementedBy(Foo)) - [<InterfaceClass __main__.IFoo>] - -It's an error to ask for interfaces implemented by a non-callable -object:: - - >>> IFoo.implementedBy(foo) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - - >>> list(zope.interface.implementedBy(foo)) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - -Similarly, we can ask what interfaces are provided by an object:: - - >>> list(zope.interface.providedBy(foo)) - [<InterfaceClass __main__.IFoo>] - >>> list(zope.interface.providedBy(Foo)) - [] - -We can declare interfaces implemented by other factories (besides -classes). We do this using a Python-2.4-style decorator named -`implementer`. In versions of Python before 2.4, this looks like:: - - >>> def yfoo(y): - ... foo = Foo() - ... foo.y = y - ... return foo - >>> yfoo = zope.interface.implementer(IFoo)(yfoo) - - >>> list(zope.interface.implementedBy(yfoo)) - [<InterfaceClass __main__.IFoo>] - -Note that the implementer decorator may modify it's argument. Callers -should not assume that a new object is created. - -Using implementer also works on callable objects. This is used by -zope.formlib, as an example. - - >>> class yfactory: - ... def __call__(self, y): - ... foo = Foo() - ... foo.y = y - ... return foo - >>> yfoo = yfactory() - >>> yfoo = zope.interface.implementer(IFoo)(yfoo) - - >>> list(zope.interface.implementedBy(yfoo)) - [<InterfaceClass __main__.IFoo>] - -XXX: Double check and update these version numbers: - -In zope.interface 3.5.2 and lower, the implementer decorator can not -be used for classes, but in 3.6.0 and higher it can: - - >>> Foo = zope.interface.implementer(IFoo)(Foo) - >>> list(zope.interface.providedBy(Foo())) - [<InterfaceClass __main__.IFoo>] - -Note that class decorators using the @implementer(IFoo) syntax are only -supported in Python 2.6 and later. - - -Declaring provided interfaces ------------------------------ - -We can declare interfaces directly provided by objects. Suppose that -we want to document what the `__init__` method of the `Foo` class -does. It's not *really* part of `IFoo`. You wouldn't normally call -the `__init__` method on Foo instances. Rather, the `__init__` method -is part of the `Foo`'s `__call__` method:: - - >>> class IFooFactory(zope.interface.Interface): - ... """Create foos""" - ... - ... def __call__(x=None): - ... """Create a foo - ... - ... The argument provides the initial value for x ... - ... """ - -It's the class that provides this interface, so we declare the -interface on the class:: - - >>> zope.interface.directlyProvides(Foo, IFooFactory) - -And then, we'll see that Foo provides some interfaces:: - - >>> list(zope.interface.providedBy(Foo)) - [<InterfaceClass __main__.IFooFactory>] - >>> IFooFactory.providedBy(Foo) - True - -Declaring class interfaces is common enough that there's a special -declaration function for it, `classProvides`, that allows the -declaration from within a class statement:: - - >>> class Foo2: - ... zope.interface.implements(IFoo) - ... zope.interface.classProvides(IFooFactory) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - - >>> list(zope.interface.providedBy(Foo2)) - [<InterfaceClass __main__.IFooFactory>] - >>> IFooFactory.providedBy(Foo2) - True - -There's a similar function, `moduleProvides`, that supports interface -declarations from within module definitions. For example, see the use -of `moduleProvides` call in `zope.interface.__init__`, which declares that -the package `zope.interface` provides `IInterfaceDeclaration`. - -Sometimes, we want to declare interfaces on instances, even though -those instances get interfaces from their classes. Suppose we create -a new interface, `ISpecial`:: - - >>> class ISpecial(zope.interface.Interface): - ... reason = zope.interface.Attribute("Reason why we're special") - ... def brag(): - ... "Brag about being special" - -We can make an existing foo instance special by providing `reason` -and `brag` attributes:: - - >>> foo.reason = 'I just am' - >>> def brag(): - ... return "I'm special!" - >>> foo.brag = brag - >>> foo.reason - 'I just am' - >>> foo.brag() - "I'm special!" - -and by declaring the interface:: - - >>> zope.interface.directlyProvides(foo, ISpecial) - -then the new interface is included in the provided interfaces:: - - >>> ISpecial.providedBy(foo) - True - >>> list(zope.interface.providedBy(foo)) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] - -We can find out what interfaces are directly provided by an object:: - - >>> list(zope.interface.directlyProvidedBy(foo)) - [<InterfaceClass __main__.ISpecial>] - - >>> newfoo = Foo() - >>> list(zope.interface.directlyProvidedBy(newfoo)) - [] - -Inherited declarations ----------------------- - -Normally, declarations are inherited:: - - >>> class SpecialFoo(Foo): - ... zope.interface.implements(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(SpecialFoo)) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] - - >>> list(zope.interface.providedBy(SpecialFoo())) - [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>] - -Sometimes, you don't want to inherit declarations. In that case, you -can use `implementsOnly`, instead of `implements`:: - - >>> class Special(Foo): - ... zope.interface.implementsOnly(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(Special)) - [<InterfaceClass __main__.ISpecial>] - - >>> list(zope.interface.providedBy(Special())) - [<InterfaceClass __main__.ISpecial>] - -External declarations ---------------------- - -Normally, we make implementation declarations as part of a class -definition. Sometimes, we may want to make declarations from outside -the class definition. For example, we might want to declare interfaces -for classes that we didn't write. The function `classImplements` can -be used for this purpose:: - - >>> class C: - ... pass - - >>> zope.interface.classImplements(C, IFoo) - >>> list(zope.interface.implementedBy(C)) - [<InterfaceClass __main__.IFoo>] - -We can use `classImplementsOnly` to exclude inherited interfaces:: - - >>> class C(Foo): - ... pass - - >>> zope.interface.classImplementsOnly(C, ISpecial) - >>> list(zope.interface.implementedBy(C)) - [<InterfaceClass __main__.ISpecial>] - - - -Declaration Objects -------------------- - -When we declare interfaces, we create *declaration* objects. When we -query declarations, declaration objects are returned:: - - >>> type(zope.interface.implementedBy(Special)) - <class 'zope.interface.declarations.Implements'> - -Declaration objects and interface objects are similar in many ways. In -fact, they share a common base class. The important thing to realize -about them is that they can be used where interfaces are expected in -declarations. Here's a silly example:: - - >>> class Special2(Foo): - ... zope.interface.implementsOnly( - ... zope.interface.implementedBy(Foo), - ... ISpecial, - ... ) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - -The declaration here is almost the same as -``zope.interface.implements(ISpecial)``, except that the order of -interfaces in the resulting declaration is different:: - - >>> list(zope.interface.implementedBy(Special2)) - [<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.ISpecial>] - - -Interface Inheritance -===================== - -Interfaces can extend other interfaces. They do this simply by listing -the other interfaces as base interfaces:: - - >>> class IBlat(zope.interface.Interface): - ... """Blat blah blah""" - ... - ... y = zope.interface.Attribute("y blah blah") - ... def eek(): - ... """eek blah blah""" - - >>> IBlat.__bases__ - (<InterfaceClass zope.interface.Interface>,) - - >>> class IBaz(IFoo, IBlat): - ... """Baz blah""" - ... def eek(a=1): - ... """eek in baz blah""" - ... - - >>> IBaz.__bases__ - (<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.IBlat>) - - >>> names = list(IBaz) - >>> names.sort() - >>> names - ['bar', 'eek', 'x', 'y'] - -Note that `IBaz` overrides eek:: - - >>> IBlat['eek'].__doc__ - 'eek blah blah' - >>> IBaz['eek'].__doc__ - 'eek in baz blah' - -We were careful to override eek in a compatible way. When extending -an interface, the extending interface should be compatible [#compat]_ -with the extended interfaces. - -We can ask whether one interface extends another:: - - >>> IBaz.extends(IFoo) - True - >>> IBlat.extends(IFoo) - False - -Note that interfaces don't extend themselves:: - - >>> IBaz.extends(IBaz) - False - -Sometimes we wish they did, but we can, instead use `isOrExtends`:: - - >>> IBaz.isOrExtends(IBaz) - True - >>> IBaz.isOrExtends(IFoo) - True - >>> IFoo.isOrExtends(IBaz) - False - -When we iterate over an interface, we get all of the names it defines, -including names defined by base interfaces. Sometimes, we want *just* -the names defined by the interface directly. We bane use the `names` -method for that:: - - >>> list(IBaz.names()) - ['eek'] - -Inheritance of attribute specifications ---------------------------------------- - -An interface may override attribute definitions from base interfaces. -If two base interfaces define the same attribute, the attribute is -inherited from the most specific interface. For example, with:: - - >>> class IBase(zope.interface.Interface): - ... - ... def foo(): - ... "base foo doc" - - >>> class IBase1(IBase): - ... pass - - >>> class IBase2(IBase): - ... - ... def foo(): - ... "base2 foo doc" - - >>> class ISub(IBase1, IBase2): - ... pass - -ISub's definition of foo is the one from IBase2, since IBase2 is more -specific that IBase:: - - >>> ISub['foo'].__doc__ - 'base2 foo doc' - -Note that this differs from a depth-first search. - -Sometimes, it's useful to ask whether an interface defines an -attribute directly. You can use the direct method to get a directly -defined definitions:: - - >>> IBase.direct('foo').__doc__ - 'base foo doc' - - >>> ISub.direct('foo') - -Specifications --------------- - -Interfaces and declarations are both special cases of specifications. -What we described above for interface inheritance applies to both -declarations and specifications. Declarations actually extend the -interfaces that they declare:: - - >>> class Baz(object): - ... zope.interface.implements(IBaz) - - >>> baz_implements = zope.interface.implementedBy(Baz) - >>> baz_implements.__bases__ - (<InterfaceClass __main__.IBaz>, <implementedBy ...object>) - - >>> baz_implements.extends(IFoo) - True - - >>> baz_implements.isOrExtends(IFoo) - True - >>> baz_implements.isOrExtends(baz_implements) - True - -Specifications (interfaces and declarations) provide an `__sro__` -that lists the specification and all of it's ancestors:: - - >>> baz_implements.__sro__ - (<implementedBy __main__.Baz>, - <InterfaceClass __main__.IBaz>, - <InterfaceClass __main__.IFoo>, - <InterfaceClass __main__.IBlat>, - <InterfaceClass zope.interface.Interface>, - <implementedBy ...object>) - - -Tagged Values -============= - -Interfaces and attribute descriptions support an extension mechanism, -borrowed from UML, called "tagged values" that lets us store extra -data:: - - >>> IFoo.setTaggedValue('date-modified', '2004-04-01') - >>> IFoo.setTaggedValue('author', 'Jim Fulton') - >>> IFoo.getTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('datemodified') - >>> tags = list(IFoo.getTaggedValueTags()) - >>> tags.sort() - >>> tags - ['author', 'date-modified'] - -Function attributes are converted to tagged values when method -attribute definitions are created:: - - >>> class IBazFactory(zope.interface.Interface): - ... def __call__(): - ... "create one" - ... __call__.return_type = IBaz - - >>> IBazFactory['__call__'].getTaggedValue('return_type') - <InterfaceClass __main__.IBaz> - -Tagged values can also be defined from within an interface definition:: - - >>> class IWithTaggedValues(zope.interface.Interface): - ... zope.interface.taggedValue('squish', 'squash') - >>> IWithTaggedValues.getTaggedValue('squish') - 'squash' - -Invariants -========== - -Interfaces can express conditions that must hold for objects that -provide them. These conditions are expressed using one or more -invariants. Invariants are callable objects that will be called with -an object that provides an interface. An invariant raises an `Invalid` -exception if the condition doesn't hold. Here's an example:: - - >>> class RangeError(zope.interface.Invalid): - ... """A range has invalid limits""" - ... def __repr__(self): - ... return "RangeError(%r)" % self.args - - >>> def range_invariant(ob): - ... if ob.max < ob.min: - ... raise RangeError(ob) - -Given this invariant, we can use it in an interface definition:: - - >>> class IRange(zope.interface.Interface): - ... min = zope.interface.Attribute("Lower bound") - ... max = zope.interface.Attribute("Upper bound") - ... - ... zope.interface.invariant(range_invariant) - -Interfaces have a method for checking their invariants:: - - >>> class Range(object): - ... zope.interface.implements(IRange) - ... - ... def __init__(self, min, max): - ... self.min, self.max = min, max - ... - ... def __repr__(self): - ... return "Range(%s, %s)" % (self.min, self.max) - - >>> IRange.validateInvariants(Range(1,2)) - >>> IRange.validateInvariants(Range(1,1)) - >>> IRange.validateInvariants(Range(2,1)) - Traceback (most recent call last): - ... - RangeError: Range(2, 1) - -If you have multiple invariants, you may not want to stop checking -after the first error. If you pass a list to `validateInvariants`, -then a single `Invalid` exception will be raised with the list of -exceptions as it's argument:: - - >>> from zope.interface.exceptions import Invalid - >>> errors = [] - >>> try: - ... IRange.validateInvariants(Range(2,1), errors) - ... except Invalid, e: - ... str(e) - '[RangeError(Range(2, 1))]' - -And the list will be filled with the individual exceptions:: - - >>> errors - [RangeError(Range(2, 1))] - - - >>> del errors[:] - -Adaptation -========== - -Interfaces can be called to perform adaptation. - -The semantics are based on those of the PEP 246 adapt function. - -If an object cannot be adapted, then a TypeError is raised:: - - >>> class I(zope.interface.Interface): - ... pass - - >>> I(0) - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>) - - - -unless an alternate value is provided as a second positional argument:: - - >>> I(0, 'bob') - 'bob' - -If an object already implements the interface, then it will be returned:: - - >>> class C(object): - ... zope.interface.implements(I) - - >>> obj = C() - >>> I(obj) is obj - True - -If an object implements __conform__, then it will be used:: - - >>> class C(object): - ... zope.interface.implements(I) - ... def __conform__(self, proto): - ... return 0 - - >>> I(C()) - 0 - -Adapter hooks (see __adapt__) will also be used, if present:: - - >>> from zope.interface.interface import adapter_hooks - >>> def adapt_0_to_42(iface, obj): - ... if obj == 0: - ... return 42 - - >>> adapter_hooks.append(adapt_0_to_42) - >>> I(0) - 42 - - >>> adapter_hooks.remove(adapt_0_to_42) - >>> I(0) - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>) - -__adapt__ ---------- - - >>> class I(zope.interface.Interface): - ... pass - -Interfaces implement the PEP 246 __adapt__ method. - -This method is normally not called directly. It is called by the PEP -246 adapt framework and by the interface __call__ operator. - -The adapt method is responsible for adapting an object to the -reciever. - -The default version returns None:: - - >>> I.__adapt__(0) - -unless the object given provides the interface:: - - >>> class C(object): - ... zope.interface.implements(I) - - >>> obj = C() - >>> I.__adapt__(obj) is obj - True - -Adapter hooks can be provided (or removed) to provide custom -adaptation. We'll install a silly hook that adapts 0 to 42. -We install a hook by simply adding it to the adapter_hooks -list:: - - >>> from zope.interface.interface import adapter_hooks - >>> def adapt_0_to_42(iface, obj): - ... if obj == 0: - ... return 42 - - >>> adapter_hooks.append(adapt_0_to_42) - >>> I.__adapt__(0) - 42 - -Hooks must either return an adapter, or None if no adapter can -be found. - -Hooks can be uninstalled by removing them from the list:: - - >>> adapter_hooks.remove(adapt_0_to_42) - >>> I.__adapt__(0) - - -.. [#create] The main reason we subclass `Interface` is to cause the - Python class statement to create an interface, rather - than a class. - - It's possible to create interfaces by calling a special - interface class directly. Doing this, it's possible - (and, on rare occasions, useful) to create interfaces - that don't descend from `Interface`. Using this - technique is beyond the scope of this document. - -.. [#factory] Classes are factories. They can be called to create - their instances. We expect that we will eventually - extend the concept of implementation to other kinds of - factories, so that we can declare the interfaces - provided by the objects created. - -.. [#compat] The goal is substitutability. An object that provides an - extending interface should be substitutable for an object - that provides the extended interface. In our example, an - object that provides IBaz should be usable whereever an - object that provides IBlat is expected. - - The interface implementation doesn't enforce this. - but maybe it should do some checks. diff --git a/src/zope/interface/__init__.py b/src/zope/interface/__init__.py index 8b05f6b..ad0a766 100644 --- a/src/zope/interface/__init__.py +++ b/src/zope/interface/__init__.py @@ -50,23 +50,33 @@ See the module doc strings for more information. """ __docformat__ = 'restructuredtext' -from zope.interface.interface import Interface, _wire +from zope.interface.interface import Interface +from zope.interface.interface import _wire # Need to actually get the interface elements to implement the right interfaces _wire() del _wire -from zope.interface.interface import Attribute, invariant, taggedValue - -from zope.interface.declarations import providedBy, implementedBy -from zope.interface.declarations import classImplements, classImplementsOnly -from zope.interface.declarations import directlyProvidedBy, directlyProvides -from zope.interface.declarations import alsoProvides, provider -from zope.interface.declarations import implementer, implementer_only -from zope.interface.declarations import implements, implementsOnly -from zope.interface.declarations import classProvides, moduleProvides -from zope.interface.declarations import noLongerProvides, Declaration +from zope.interface.declarations import Declaration +from zope.interface.declarations import alsoProvides +from zope.interface.declarations import classImplements +from zope.interface.declarations import classImplementsOnly +from zope.interface.declarations import classProvides +from zope.interface.declarations import directlyProvidedBy +from zope.interface.declarations import directlyProvides +from zope.interface.declarations import implementedBy +from zope.interface.declarations import implementer +from zope.interface.declarations import implementer_only +from zope.interface.declarations import implements +from zope.interface.declarations import implementsOnly +from zope.interface.declarations import moduleProvides +from zope.interface.declarations import noLongerProvides +from zope.interface.declarations import providedBy +from zope.interface.declarations import provider from zope.interface.exceptions import Invalid +from zope.interface.interface import Attribute +from zope.interface.interface import invariant +from zope.interface.interface import taggedValue # The following are to make spec pickles cleaner from zope.interface.declarations import Provides diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 7b0f816..b2088ee 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -979,7 +979,13 @@ _lookup1(lookup *self, Py_DECREF(tup); } else - Py_INCREF(result); + { + if (result == Py_None && default_ != NULL) + { + result = default_; + } + Py_INCREF(result); + } return result; } diff --git a/src/zope/interface/adapter.py b/src/zope/interface/adapter.py index 2ad145b..31c1d85 100644 --- a/src/zope/interface/adapter.py +++ b/src/zope/interface/adapter.py @@ -13,11 +13,12 @@ ############################################################################## """Adapter management """ - import weakref -from zope.interface import providedBy, Interface, ro -_marker = object +from zope.interface import providedBy +from zope.interface import Interface +from zope.interface import ro + class BaseAdapterRegistry(object): # List of methods copied from lookup sub-objects: @@ -62,7 +63,7 @@ class BaseAdapterRegistry(object): # Invalidating registries have caches that are invalidated # when they or their base registies change. An invalidating # registry can only have invalidating registries as bases. - # See LookupBasePy below for the pertinent logic. + # See LookupBaseFallback below for the pertinent logic. # Verifying registies can't rely on getting invalidation messages, # so have to check the generations of base registries to determine @@ -245,7 +246,8 @@ class BaseAdapterRegistry(object): old = components.get(u'') if not old: - return + # this is belt-and-suspenders against the failure of cleanup below + return #pragma NO COVERAGE if value is None: new = () @@ -285,14 +287,14 @@ class BaseAdapterRegistry(object): # XXX hack to fake out twisted's use of a private api. We need to get them # to use the new registed method. - def get(self, _): + def get(self, _): #pragma NO COVER class XXXTwistedFakeOut: selfImplied = {} return XXXTwistedFakeOut _not_in_mapping = object() -class LookupBasePy(object): +class LookupBaseFallback(object): def __init__(self): self._cache = {} @@ -393,12 +395,22 @@ class LookupBasePy(object): return result -LookupBase = LookupBasePy +LookupBasePy = LookupBaseFallback # BBB + +try: + from _zope_interface_coptimizations import LookupBase +except ImportError: #pragma NO COVER + LookupBase = LookupBaseFallback -class VerifyingBasePy(LookupBasePy): + +class VerifyingBaseFallback(LookupBaseFallback): + # Mixin for lookups against registries which "chain" upwards, and + # whose lookups invalidate their own caches whenever a parent registry + # bumps its own '_generation' counter. E.g., used by + # zope.component.persistentregistry def changed(self, originally_changed): - LookupBasePy.changed(self, originally_changed) + LookupBaseFallback.changed(self, originally_changed) self._verify_ro = self._registry.ro[1:] self._verify_generations = [r._generation for r in self._verify_ro] @@ -409,25 +421,23 @@ class VerifyingBasePy(LookupBasePy): def _getcache(self, provided, name): self._verify() - return LookupBasePy._getcache(self, provided, name) + return LookupBaseFallback._getcache(self, provided, name) def lookupAll(self, required, provided): self._verify() - return LookupBasePy.lookupAll(self, required, provided) + return LookupBaseFallback.lookupAll(self, required, provided) def subscriptions(self, required, provided): self._verify() - return LookupBasePy.subscriptions(self, required, provided) - -VerifyingBase = VerifyingBasePy + return LookupBaseFallback.subscriptions(self, required, provided) +VerifyingBasePy = VerifyingBaseFallback #BBB try: - import _zope_interface_coptimizations -except ImportError: - pass -else: - from _zope_interface_coptimizations import LookupBase, VerifyingBase + from _zope_interface_coptimizations import VerifyingBase +except ImportError: #pragma NO COVER + VerifyingBase = VerifyingBaseFallback + class AdapterLookupBase(object): diff --git a/src/zope/interface/adapter.ru.txt b/src/zope/interface/adapter.ru.txt deleted file mode 100644 index 30c2782..0000000 --- a/src/zope/interface/adapter.ru.txt +++ /dev/null @@ -1,540 +0,0 @@ -================ -Реестр адаптеров -================ - -.. contents:: - -Реестры адаптеров предоставляют возможность для регистрации объектов которые -зависят от одной, или нескольких спецификаций интерфейсов и предоставляют -(возможно не напрямую) какой-либо интерфейс. В дополнение, регистрации имеют -имена. (Можно думать об именах как о спецификаторах предоставляемого -интерфейса.) - -Термин "спецификация интерфейса" ссылается и на интерфейсы и на определения -интерфейсов, такие как определения интерфейсов реализованных некоторым классом. - -Одиночные адаптеры -================== - -Давайте рассмотрим простой пример использующий единственную требуемую -спецификацию:: - - >>> from zope.interface.adapter import AdapterRegistry - >>> import zope.interface - - >>> class IR1(zope.interface.Interface): - ... pass - >>> class IP1(zope.interface.Interface): - ... pass - >>> class IP2(IP1): - ... pass - - >>> registry = AdapterRegistry() - -Мы зарегистрируем объект который зависит от IR1 и "предоставляет" IP2:: - - >>> registry.register([IR1], IP2, '', 12) - -После регистрации мы можем запросить объект снова:: - - >>> registry.lookup([IR1], IP2, '') - 12 - -Заметьте, что мы используем целое в этом примере. В реальных приложениях вы -можете использовать объекты которые на самом деле зависят или предоставляют -интерфейсы. Реестр не заботиться о том, что регистрируется и таким образом мы -можем использовать целые, или строки что бы упростить наши примеры. Здесь есть -одно исключение. Регистрация значения None удаляет регистрацию для любого -зарегистрированного прежде значения. - -Если объект зависит от спецификации он может быть запрошен с помощью -спецификации которая расширяет спецификацию от которой он зависит:: - - >>> class IR2(IR1): - ... pass - >>> registry.lookup([IR2], IP2, '') - 12 - -Мы можем использовать класс реализующий спецификацию для запроса объекта:: - - >>> class C2: - ... zope.interface.implements(IR2) - - >>> registry.lookup([zope.interface.implementedBy(C2)], IP2, '') - 12 - -и объект может быть запрошен для интерфейсов которые предоставляемый объектом -интерфейс расширяет:: - - >>> registry.lookup([IR1], IP1, '') - 12 - >>> registry.lookup([IR2], IP1, '') - 12 - -Но если вы требуете спецификацию которая не расширяет спецификацию от которой -зависит объект, вы не получите ничего:: - - >>> registry.lookup([zope.interface.Interface], IP1, '') - -Между прочим, вы можете передать значение по умолчанию при запросе:: - - >>> registry.lookup([zope.interface.Interface], IP1, '', 42) - 42 - -Если вы пробуете получить интерфейс который объект не предоставляет вы также -не получите ничего:: - - >>> class IP3(IP2): - ... pass - >>> registry.lookup([IR1], IP3, '') - -Вы также не получите ничего если вы используете неверное имя:: - - >>> registry.lookup([IR1], IP1, 'bob') - >>> registry.register([IR1], IP2, 'bob', "Bob's 12") - >>> registry.lookup([IR1], IP1, 'bob') - "Bob's 12" - -Вы можете не использовать имя при запросе:: - - >>> registry.lookup([IR1], IP1) - 12 - -Если мы регистрируем объект который предоставляет IP1:: - - >>> registry.register([IR1], IP1, '', 11) - -тогда этот объект будет иметь преимущество перед O(12):: - - >>> registry.lookup([IR1], IP1, '') - 11 - -Также, если мы регистрируем объект для IR2 тогда он будет иметь преимущество -когда используется IR2:: - - >>> registry.register([IR2], IP1, '', 21) - >>> registry.lookup([IR2], IP1, '') - 21 - -Поиск того, что (если вообще что-то) зарегистрировано ------------------------------------------------------ - -Мы можем спросить есть-ли адаптер зарегистрированный для набора интерфейсов. -Это отличается от обычного запроса так как здесь мы ищем точное совпадение:: - - >>> print registry.registered([IR1], IP1) - 11 - - >>> print registry.registered([IR1], IP2) - 12 - - >>> print registry.registered([IR1], IP2, 'bob') - Bob's 12 - - - >>> print registry.registered([IR2], IP1) - 21 - - >>> print registry.registered([IR2], IP2) - None - -В последнем примере, None был возвращен потому, что для данного интерфейса -ничего не было зарегистрировано. - -lookup1 -------- - -Запрос одиночного адаптера - это наиболее частая операция и для нее есть -специализированная версия запроса которая получает на вход единственный -требуемый интерфейс:: - - >>> registry.lookup1(IR2, IP1, '') - 21 - >>> registry.lookup1(IR2, IP1) - 21 - -Адаптация на практике ---------------------- - -Реестр адаптеров предназначен для поддержки адаптации когда один объект -реализующий интерфейс адаптируется к другому объекту который поддерживает -другой интерфейс. Реестр адаптеров также поддерживает вычисление адаптеров. В -этом случае мы должны регистрировать фабрики для адаптеров:: - - >>> class IR(zope.interface.Interface): - ... pass - - >>> class X: - ... zope.interface.implements(IR) - - >>> class Y: - ... zope.interface.implements(IP1) - ... def __init__(self, context): - ... self.context = context - - >>> registry.register([IR], IP1, '', Y) - -В этом случае мы регистрируем класс как фабрику. Теперь мы можем вызвать -`queryAdapter` для получения адаптированного объекта:: - - >>> x = X() - >>> y = registry.queryAdapter(x, IP1) - >>> y.__class__.__name__ - 'Y' - >>> y.context is x - True - -Мы также можем регистрировать и запрашивать по имени:: - - >>> class Y2(Y): - ... pass - - >>> registry.register([IR], IP1, 'bob', Y2) - >>> y = registry.queryAdapter(x, IP1, 'bob') - >>> y.__class__.__name__ - 'Y2' - >>> y.context is x - True - -Когда фабрика для адаптера возвращает `None` - это рассматривается как если бы -адаптер не был найден. Это позволяет нам избежать адаптации (по желанию) и дает -возможность фабрике адаптера определить возможна ли адаптация основываясь на -состоянии объекта который адаптируется:: - - >>> def factory(context): - ... if context.name == 'object': - ... return 'adapter' - ... return None - - >>> class Object(object): - ... zope.interface.implements(IR) - ... name = 'object' - - >>> registry.register([IR], IP1, 'conditional', factory) - >>> obj = Object() - >>> registry.queryAdapter(obj, IP1, 'conditional') - 'adapter' - >>> obj.name = 'no object' - >>> registry.queryAdapter(obj, IP1, 'conditional') is None - True - >>> registry.queryAdapter(obj, IP1, 'conditional', 'default') - 'default' - -Альтернативный метод для предоставления такой же функциональности как и -`queryAdapter()` - это `adapter_hook()`:: - - >>> y = registry.adapter_hook(IP1, x) - >>> y.__class__.__name__ - 'Y' - >>> y.context is x - True - >>> y = registry.adapter_hook(IP1, x, 'bob') - >>> y.__class__.__name__ - 'Y2' - >>> y.context is x - True - -`adapter_hook()` просто меняет порядок аргументов для объекта и интерфейса. Это -используется для встраивания в механизм вызовов интерфейсов. - -Адаптеры по умолчанию ---------------------- - -Иногда вы можете захотеть предоставить адаптер который не будет ничего -адаптировать. Для этого нужно передать None как требуемый интерфейс:: - - >>> registry.register([None], IP1, '', 1) - -после этого вы можете использовать этот адаптер для интерфейсов для которых у -вас нет конкретного адаптера:: - - >>> class IQ(zope.interface.Interface): - ... pass - >>> registry.lookup([IQ], IP1, '') - 1 - -Конечно, конкретные адаптеры все еще используются когда необходимо:: - - >>> registry.lookup([IR2], IP1, '') - 21 - -Адаптеры классов ----------------- - -Вы можете регистрировать адаптеры для определений классов, что будет похоже на -регистрацию их для классов:: - - >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21') - >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') - 'C21' - -Адаптеры для словарей ---------------------- - -В какой-то момент было невозможно регистрировать адаптеры основанные на -словарях из-за ошибки. Давайте удостоверимся что это теперь работает:: - - >>> adapter = {} - >>> registry.register((), IQ, '', adapter) - >>> registry.lookup((), IQ, '') is adapter - True - -Удаление регистрации --------------------- - -Вы можете удалить регистрацию регистрируя None вместо объекта:: - - >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None) - >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') - 21 - -Конечно это значит, что None не может быть зарегистрирован. Это исключение к -утверждению выше о том, что реестр не заботиться о том, что регистрируется. - -Мульти-адаптеры -=============== - -Вы можете адаптировать несколько спецификаций:: - - >>> registry.register([IR1, IQ], IP2, '', '1q2') - >>> registry.lookup([IR1, IQ], IP2, '') - '1q2' - >>> registry.lookup([IR2, IQ], IP1, '') - '1q2' - - >>> class IS(zope.interface.Interface): - ... pass - >>> registry.lookup([IR2, IS], IP1, '') - - >>> class IQ2(IQ): - ... pass - - >>> registry.lookup([IR2, IQ2], IP1, '') - '1q2' - - >>> registry.register([IR1, IQ2], IP2, '', '1q22') - >>> registry.lookup([IR2, IQ2], IP1, '') - '1q22' - -Мульти-адаптация ----------------- - -Вы можете адаптировать несколько объектов:: - - >>> class Q: - ... zope.interface.implements(IQ) - -Как и с одиночными адаптерами, мы регистрируем фабрику которая возвращает -класс:: - - >>> class IM(zope.interface.Interface): - ... pass - >>> class M: - ... zope.interface.implements(IM) - ... def __init__(self, x, q): - ... self.x, self.q = x, q - >>> registry.register([IR, IQ], IM, '', M) - -И затем мы можем вызвать `queryMultiAdapter` для вычисления адаптера:: - - >>> q = Q() - >>> m = registry.queryMultiAdapter((x, q), IM) - >>> m.__class__.__name__ - 'M' - >>> m.x is x and m.q is q - True - -и, конечно, мы можем использовать имена:: - - >>> class M2(M): - ... pass - >>> registry.register([IR, IQ], IM, 'bob', M2) - >>> m = registry.queryMultiAdapter((x, q), IM, 'bob') - >>> m.__class__.__name__ - 'M2' - >>> m.x is x and m.q is q - True - -Адаптеры по умолчанию ---------------------- - -Как и для одиночных адаптеров вы можете определить адаптер по умолчанию передав -None вместо *первой* спецификации:: - - >>> registry.register([None, IQ], IP2, '', 'q2') - >>> registry.lookup([IS, IQ], IP2, '') - 'q2' - -Нулевые адаптеры -================ - -Вы можете также адаптировать без спецификации:: - - >>> registry.register([], IP2, '', 2) - >>> registry.lookup([], IP2, '') - 2 - >>> registry.lookup([], IP1, '') - 2 - -Перечисление именованных адаптеров ----------------------------------- - -Адаптеры имеют имена. Иногда это полезно для получения всех именованных -адаптеров для заданного интерфейса:: - - >>> adapters = list(registry.lookupAll([IR1], IP1)) - >>> adapters.sort() - >>> assert adapters == [(u'', 11), (u'bob', "Bob's 12")] - -Это работает также и для мульти-адаптеров:: - - >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob') - >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1)) - >>> adapters.sort() - >>> assert adapters == [(u'', '1q22'), (u'bob', '1q2 for bob')] - -И даже для нулевых адаптеров:: - - >>> registry.register([], IP2, 'bob', 3) - >>> adapters = list(registry.lookupAll([], IP1)) - >>> adapters.sort() - >>> assert adapters == [(u'', 2), (u'bob', 3)] - -Подписки -======== - -Обычно мы хотим запросить объект который наиболее близко соответствует -спецификации. Иногда мы хотим получить все объекты которые соответствуют -какой-либо спецификации. Мы используем подписки для этого. Мы подписываем -объекты для спецификаций и затем позже находим все подписанные объекты:: - - >>> registry.subscribe([IR1], IP2, 'sub12 1') - >>> registry.subscriptions([IR1], IP2) - ['sub12 1'] - -Заметьте, что в отличие от обычных адаптеров подписки не имеют имен. - -Вы можете иметь несколько подписчиков для одной спецификации:: - - >>> registry.subscribe([IR1], IP2, 'sub12 2') - >>> registry.subscriptions([IR1], IP2) - ['sub12 1', 'sub12 2'] - -Если подписчики зарегистрированы для одних и тех же требуемых интерфейсов, они -возвращаются в порядке определения. - -Вы можете зарегистрировать подписчики для всех спецификаций используя None:: - - >>> registry.subscribe([None], IP1, 'sub_1') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - -Заметьте, что новый подписчик возвращается первым. Подписчики определенные -для менее общих требуемых интерфейсов возвращаются перед подписчиками -для более общих интерфейсов. - -Подписки могут смешиваться между несколькими совместимыми спецификациями:: - - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - >>> registry.subscribe([IR1], IP1, 'sub11') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2', 'sub11'] - >>> registry.subscribe([IR2], IP2, 'sub22') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2', 'sub11', 'sub22'] - >>> registry.subscriptions([IR2], IP2) - ['sub12 1', 'sub12 2', 'sub22'] - -Подписки могут существовать для нескольких спецификаций:: - - >>> registry.subscribe([IR1, IQ], IP2, 'sub1q2') - >>> registry.subscriptions([IR1, IQ], IP2) - ['sub1q2'] - -Как и с одиночными подписчиками и адаптерами без подписок, вы можете определить -None для первого требуемого интерфейса, что бы задать значение по умолчанию:: - - >>> registry.subscribe([None, IQ], IP2, 'sub_q2') - >>> registry.subscriptions([IS, IQ], IP2) - ['sub_q2'] - >>> registry.subscriptions([IR1, IQ], IP2) - ['sub_q2', 'sub1q2'] - -Вы можете создать подписки которые независимы от любых спецификаций:: - - >>> list(registry.subscriptions([], IP1)) - [] - - >>> registry.subscribe([], IP2, 'sub2') - >>> registry.subscriptions([], IP1) - ['sub2'] - >>> registry.subscribe([], IP1, 'sub1') - >>> registry.subscriptions([], IP1) - ['sub2', 'sub1'] - >>> registry.subscriptions([], IP2) - ['sub2'] - -Удаление регистрации подписчиков --------------------------------- - -Мы можем удалять регистрацию подписчиков. При удалении регистрации подписчика -мы можем удалить регистрацию заданного адаптера:: - - >>> registry.unsubscribe([IR1], IP1, 'sub11') - >>> registry.subscriptions([IR1], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - -Если мы не задаем никакого значения тогда подписки будут удалены для всех -подписчиков совпадающих с заданным интерфейсом:: - - >>> registry.unsubscribe([IR1], IP2) - >>> registry.subscriptions([IR1], IP1) - ['sub_1'] - -Адаптеры подписки ------------------ - -Обычно мы регистрируем фабрики для адаптеров которые затем позволяют нам -вычислять адаптеры, но с подписками мы получаем несколько адаптеров. Это пример -подписчика для нескольких объектов:: - - >>> registry.subscribe([IR, IQ], IM, M) - >>> registry.subscribe([IR, IQ], IM, M2) - - >>> subscribers = registry.subscribers((x, q), IM) - >>> len(subscribers) - 2 - >>> class_names = [s.__class__.__name__ for s in subscribers] - >>> class_names.sort() - >>> class_names - ['M', 'M2'] - >>> [(s.x is x and s.q is q) for s in subscribers] - [True, True] - -подписчики фабрик адаптеров не могут возвращать None:: - - >>> def M3(x, y): - ... return None - - >>> registry.subscribe([IR, IQ], IM, M3) - >>> subscribers = registry.subscribers((x, q), IM) - >>> len(subscribers) - 2 - -Обработчики ------------ - -Обработчик - это подписанная фабрика которая не возвращает нормального -значения. Она возвращает None. Обработчик отличается от адаптеров тем, что он -делает всю работу когда вызывается фабрика. - -Для регистрации обработчика надо просто передать None как предоставляемый -интерфейс:: - - >>> def handler(event): - ... print 'handler', event - - >>> registry.subscribe([IR1], None, handler) - >>> registry.subscriptions([IR1], None) == [handler] - True diff --git a/src/zope/interface/adapter.txt b/src/zope/interface/adapter.txt deleted file mode 100644 index 298a862..0000000 --- a/src/zope/interface/adapter.txt +++ /dev/null @@ -1,543 +0,0 @@ -================ -Adapter Registry -================ - -Adapter registries provide a way to register objects that depend on -one or more interface specifications and provide (perhaps indirectly) -some interface. In addition, the registrations have names. (You can -think of the names as qualifiers of the provided interfaces.) - -The term "interface specification" refers both to interfaces and to -interface declarations, such as declarations of interfaces implemented -by a class. - - -Single Adapters -=============== - -Let's look at a simple example, using a single required specification:: - - >>> from zope.interface.adapter import AdapterRegistry - >>> import zope.interface - - >>> class IR1(zope.interface.Interface): - ... pass - >>> class IP1(zope.interface.Interface): - ... pass - >>> class IP2(IP1): - ... pass - - >>> registry = AdapterRegistry() - -We'll register an object that depends on IR1 and "provides" IP2:: - - >>> registry.register([IR1], IP2, '', 12) - -Given the registration, we can look it up again:: - - >>> registry.lookup([IR1], IP2, '') - 12 - -Note that we used an integer in the example. In real applications, -one would use some objects that actually depend on or provide -interfaces. The registry doesn't care about what gets registered, so -we'll use integers and strings to keep the examples simple. There is -one exception. Registering a value of None unregisters any -previously-registered value. - -If an object depends on a specification, it can be looked up with a -specification that extends the specification that it depends on:: - - >>> class IR2(IR1): - ... pass - >>> registry.lookup([IR2], IP2, '') - 12 - -We can use a class implementation specification to look up the object:: - - >>> class C2: - ... zope.interface.implements(IR2) - - >>> registry.lookup([zope.interface.implementedBy(C2)], IP2, '') - 12 - - -and it can be looked up for interfaces that its provided interface -extends:: - - >>> registry.lookup([IR1], IP1, '') - 12 - >>> registry.lookup([IR2], IP1, '') - 12 - -But if you require a specification that doesn't extend the specification the -object depends on, you won't get anything:: - - >>> registry.lookup([zope.interface.Interface], IP1, '') - -By the way, you can pass a default value to lookup:: - - >>> registry.lookup([zope.interface.Interface], IP1, '', 42) - 42 - -If you try to get an interface the object doesn't provide, you also -won't get anything:: - - >>> class IP3(IP2): - ... pass - >>> registry.lookup([IR1], IP3, '') - -You also won't get anything if you use the wrong name:: - - >>> registry.lookup([IR1], IP1, 'bob') - >>> registry.register([IR1], IP2, 'bob', "Bob's 12") - >>> registry.lookup([IR1], IP1, 'bob') - "Bob's 12" - -You can leave the name off when doing a lookup:: - - >>> registry.lookup([IR1], IP1) - 12 - -If we register an object that provides IP1:: - - >>> registry.register([IR1], IP1, '', 11) - -then that object will be prefered over O(12):: - - >>> registry.lookup([IR1], IP1, '') - 11 - -Also, if we register an object for IR2, then that will be prefered -when using IR2:: - - >>> registry.register([IR2], IP1, '', 21) - >>> registry.lookup([IR2], IP1, '') - 21 - -Finding out what, if anything, is registered --------------------------------------------- - -We can ask if there is an adapter registered for a collection of -interfaces. This is different than lookup, because it looks for an -exact match. - - >>> print registry.registered([IR1], IP1) - 11 - - >>> print registry.registered([IR1], IP2) - 12 - - >>> print registry.registered([IR1], IP2, 'bob') - Bob's 12 - - - >>> print registry.registered([IR2], IP1) - 21 - - >>> print registry.registered([IR2], IP2) - None - -In the last example, None was returned because nothing was registered -exactly for the given interfaces. - -lookup1 -------- - -Lookup of single adapters is common enough that there is a specialized -version of lookup that takes a single required interface:: - - >>> registry.lookup1(IR2, IP1, '') - 21 - >>> registry.lookup1(IR2, IP1) - 21 - -Actual Adaptation ------------------ - -The adapter registry is intended to support adaptation, where one -object that implements an interface is adapted to another object that -supports a different interface. The adapter registry supports the -computation of adapters. In this case, we have to register adapter -factories:: - - >>> class IR(zope.interface.Interface): - ... pass - - >>> class X: - ... zope.interface.implements(IR) - - >>> class Y: - ... zope.interface.implements(IP1) - ... def __init__(self, context): - ... self.context = context - - >>> registry.register([IR], IP1, '', Y) - -In this case, we registered a class as the factory. Now we can call -`queryAdapter` to get the adapted object:: - - >>> x = X() - >>> y = registry.queryAdapter(x, IP1) - >>> y.__class__.__name__ - 'Y' - >>> y.context is x - True - -We can register and lookup by name too:: - - >>> class Y2(Y): - ... pass - - >>> registry.register([IR], IP1, 'bob', Y2) - >>> y = registry.queryAdapter(x, IP1, 'bob') - >>> y.__class__.__name__ - 'Y2' - >>> y.context is x - True - -When the adapter factory produces `None`, then this is treated as if no -adapter has been found. This allows us to prevent adaptation (when desired) -and let the adapter factory determine whether adaptation is possible based on -the state of the object being adapted. - - >>> def factory(context): - ... if context.name == 'object': - ... return 'adapter' - ... return None - - >>> class Object(object): - ... zope.interface.implements(IR) - ... name = 'object' - - >>> registry.register([IR], IP1, 'conditional', factory) - >>> obj = Object() - >>> registry.queryAdapter(obj, IP1, 'conditional') - 'adapter' - >>> obj.name = 'no object' - >>> registry.queryAdapter(obj, IP1, 'conditional') is None - True - >>> registry.queryAdapter(obj, IP1, 'conditional', 'default') - 'default' - -An alternate method that provides the same function as `queryAdapter()` is -`adapter_hook()`:: - - >>> y = registry.adapter_hook(IP1, x) - >>> y.__class__.__name__ - 'Y' - >>> y.context is x - True - >>> y = registry.adapter_hook(IP1, x, 'bob') - >>> y.__class__.__name__ - 'Y2' - >>> y.context is x - True - -The `adapter_hook()` simply switches the order of the object and -interface arguments. It is used to hook into the interface call -mechanism. - - -Default Adapters ----------------- - -Sometimes, you want to provide an adapter that will adapt anything. -For that, provide None as the required interface:: - - >>> registry.register([None], IP1, '', 1) - -then we can use that adapter for interfaces we don't have specific -adapters for:: - - >>> class IQ(zope.interface.Interface): - ... pass - >>> registry.lookup([IQ], IP1, '') - 1 - -Of course, specific adapters are still used when applicable:: - - >>> registry.lookup([IR2], IP1, '') - 21 - -Class adapters --------------- - -You can register adapters for class declarations, which is almost the -same as registering them for a class:: - - >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21') - >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') - 'C21' - -Dict adapters -------------- - -At some point it was impossible to register dictionary-based adapters due a -bug. Let's make sure this works now: - - >>> adapter = {} - >>> registry.register((), IQ, '', adapter) - >>> registry.lookup((), IQ, '') is adapter - True - -Unregistering -------------- - -You can unregister by registering None, rather than an object:: - - >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None) - >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') - 21 - -Of course, this means that None can't be registered. This is an -exception to the statement, made earlier, that the registry doesn't -care what gets registered. - -Multi-adapters -============== - -You can adapt multiple specifications:: - - >>> registry.register([IR1, IQ], IP2, '', '1q2') - >>> registry.lookup([IR1, IQ], IP2, '') - '1q2' - >>> registry.lookup([IR2, IQ], IP1, '') - '1q2' - - >>> class IS(zope.interface.Interface): - ... pass - >>> registry.lookup([IR2, IS], IP1, '') - - >>> class IQ2(IQ): - ... pass - - >>> registry.lookup([IR2, IQ2], IP1, '') - '1q2' - - >>> registry.register([IR1, IQ2], IP2, '', '1q22') - >>> registry.lookup([IR2, IQ2], IP1, '') - '1q22' - -Multi-adaptation ----------------- - -You can adapt multiple objects:: - - >>> class Q: - ... zope.interface.implements(IQ) - -As with single adapters, we register a factory, which is often a class:: - - >>> class IM(zope.interface.Interface): - ... pass - >>> class M: - ... zope.interface.implements(IM) - ... def __init__(self, x, q): - ... self.x, self.q = x, q - >>> registry.register([IR, IQ], IM, '', M) - -And then we can call `queryMultiAdapter` to compute an adapter:: - - >>> q = Q() - >>> m = registry.queryMultiAdapter((x, q), IM) - >>> m.__class__.__name__ - 'M' - >>> m.x is x and m.q is q - True - -and, of course, we can use names:: - - >>> class M2(M): - ... pass - >>> registry.register([IR, IQ], IM, 'bob', M2) - >>> m = registry.queryMultiAdapter((x, q), IM, 'bob') - >>> m.__class__.__name__ - 'M2' - >>> m.x is x and m.q is q - True - -Default Adapters ----------------- - -As with single adapters, you can define default adapters by specifying -None for the *first* specification:: - - >>> registry.register([None, IQ], IP2, '', 'q2') - >>> registry.lookup([IS, IQ], IP2, '') - 'q2' - -Null Adapters -============= - -You can also adapt no specification:: - - >>> registry.register([], IP2, '', 2) - >>> registry.lookup([], IP2, '') - 2 - >>> registry.lookup([], IP1, '') - 2 - -Listing named adapters ----------------------- - -Adapters are named. Sometimes, it's useful to get all of the named -adapters for given interfaces:: - - >>> adapters = list(registry.lookupAll([IR1], IP1)) - >>> adapters.sort() - >>> assert adapters == [(u'', 11), (u'bob', "Bob's 12")] - -This works for multi-adapters too:: - - >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob') - >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1)) - >>> adapters.sort() - >>> assert adapters == [(u'', '1q22'), (u'bob', '1q2 for bob')] - -And even null adapters:: - - >>> registry.register([], IP2, 'bob', 3) - >>> adapters = list(registry.lookupAll([], IP1)) - >>> adapters.sort() - >>> assert adapters == [(u'', 2), (u'bob', 3)] - -Subscriptions -============= - -Normally, we want to look up an object that most-closely matches a -specification. Sometimes, we want to get all of the objects that -match some specification. We use subscriptions for this. We -subscribe objects against specifications and then later find all of -the subscribed objects:: - - >>> registry.subscribe([IR1], IP2, 'sub12 1') - >>> registry.subscriptions([IR1], IP2) - ['sub12 1'] - -Note that, unlike regular adapters, subscriptions are unnamed. - -You can have multiple subscribers for the same specification:: - - >>> registry.subscribe([IR1], IP2, 'sub12 2') - >>> registry.subscriptions([IR1], IP2) - ['sub12 1', 'sub12 2'] - -If subscribers are registered for the same required interfaces, they -are returned in the order of definition. - -You can register subscribers for all specifications using None:: - - >>> registry.subscribe([None], IP1, 'sub_1') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - -Note that the new subscriber is returned first. Subscribers defined -for less general required interfaces are returned before subscribers -for more general interfaces. - -Subscriptions may be combined over multiple compatible specifications:: - - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - >>> registry.subscribe([IR1], IP1, 'sub11') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2', 'sub11'] - >>> registry.subscribe([IR2], IP2, 'sub22') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2', 'sub11', 'sub22'] - >>> registry.subscriptions([IR2], IP2) - ['sub12 1', 'sub12 2', 'sub22'] - -Subscriptions can be on multiple specifications:: - - >>> registry.subscribe([IR1, IQ], IP2, 'sub1q2') - >>> registry.subscriptions([IR1, IQ], IP2) - ['sub1q2'] - -As with single subscriptions and non-subscription adapters, you can -specify None for the first required interface, to specify a default:: - - >>> registry.subscribe([None, IQ], IP2, 'sub_q2') - >>> registry.subscriptions([IS, IQ], IP2) - ['sub_q2'] - >>> registry.subscriptions([IR1, IQ], IP2) - ['sub_q2', 'sub1q2'] - -You can have subscriptions that are indepenent of any specifications:: - - >>> list(registry.subscriptions([], IP1)) - [] - - >>> registry.subscribe([], IP2, 'sub2') - >>> registry.subscriptions([], IP1) - ['sub2'] - >>> registry.subscribe([], IP1, 'sub1') - >>> registry.subscriptions([], IP1) - ['sub2', 'sub1'] - >>> registry.subscriptions([], IP2) - ['sub2'] - -Unregistering subscribers -------------------------- - -We can unregister subscribers. When unregistering a subscriber, we -can unregister a specific subscriber:: - - >>> registry.unsubscribe([IR1], IP1, 'sub11') - >>> registry.subscriptions([IR1], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - -If we don't specify a value, then all subscribers matching the given -interfaces will be unsubscribed: - - >>> registry.unsubscribe([IR1], IP2) - >>> registry.subscriptions([IR1], IP1) - ['sub_1'] - - -Subscription adapters ---------------------- - -We normally register adapter factories, which then allow us to compute -adapters, but with subscriptions, we get multiple adapters. Here's an -example of multiple-object subscribers:: - - >>> registry.subscribe([IR, IQ], IM, M) - >>> registry.subscribe([IR, IQ], IM, M2) - - >>> subscribers = registry.subscribers((x, q), IM) - >>> len(subscribers) - 2 - >>> class_names = [s.__class__.__name__ for s in subscribers] - >>> class_names.sort() - >>> class_names - ['M', 'M2'] - >>> [(s.x is x and s.q is q) for s in subscribers] - [True, True] - -adapter factory subcribers can't return None values:: - - >>> def M3(x, y): - ... return None - - >>> registry.subscribe([IR, IQ], IM, M3) - >>> subscribers = registry.subscribers((x, q), IM) - >>> len(subscribers) - 2 - -Handlers --------- - -A handler is a subscriber factory that doesn't produce any normal -output. It returns None. A handler is unlike adapters in that it does -all of its work when the factory is called. - -To register a handler, simply provide None as the provided interface:: - - >>> def handler(event): - ... print 'handler', event - - >>> registry.subscribe([IR1], None, handler) - >>> registry.subscriptions([IR1], None) == [handler] - True diff --git a/src/zope/interface/advice.py b/src/zope/interface/advice.py index d23818e..28f4805 100644 --- a/src/zope/interface/advice.py +++ b/src/zope/interface/advice.py @@ -29,7 +29,7 @@ from types import FunctionType try: from types import ClassType __python3 = False -except ImportError: +except ImportError: #pragma NO COVER __python3 = True import sys @@ -63,7 +63,7 @@ def getFrameInfo(frame): kind = "class" elif not sameNamespace: kind = "function call" - else: + else: # pragma NO COVER # How can you have f_locals is f_globals, and have '__module__' set? # This is probably module-level code, but with a '__module__' variable. kind = "unknown" @@ -106,7 +106,7 @@ def addClassAdvisor(callback, depth=2): # ) previousMetaclass = caller_locals.get('__metaclass__') - if __python3: + if __python3: # pragma NO COVER defaultMetaclass = caller_globals.get('__metaclass__', type) else: defaultMetaclass = caller_globals.get('__metaclass__', ClassType) @@ -167,7 +167,7 @@ def determineMetaclass(bases, explicit_mc=None): candidates = minimalBases(meta) # minimal set of metaclasses - if not candidates: + if not candidates: #pragma NO COVER # they're all "classic" classes assert(not __python3) # This should not happen under Python 3 return ClassType diff --git a/src/zope/interface/common/interfaces.py b/src/zope/interface/common/interfaces.py index 47e9de7..6274e6d 100644 --- a/src/zope/interface/common/interfaces.py +++ b/src/zope/interface/common/interfaces.py @@ -77,14 +77,14 @@ classImplements(OSError, IOSError) classImplements(OverflowError, IOverflowError) try: classImplements(OverflowWarning, IOverflowWarning) -except NameError: +except NameError: #pragma NO COVER pass # OverflowWarning was removed in Python 2.5 classImplements(ReferenceError, IReferenceError) classImplements(RuntimeError, IRuntimeError) classImplements(RuntimeWarning, IRuntimeWarning) try: classImplements(StandardError, IStandardError) -except NameError: +except NameError: #pragma NO COVER pass # StandardError does not exist in Python 3 classImplements(StopIteration, IStopIteration) classImplements(SyntaxError, ISyntaxError) diff --git a/src/zope/interface/declarations.py b/src/zope/interface/declarations.py index bafe399..00daa7f 100644 --- a/src/zope/interface/declarations.py +++ b/src/zope/interface/declarations.py @@ -27,11 +27,15 @@ There are three flavors of declarations: __docformat__ = 'restructuredtext' import sys +from types import FunctionType +from types import MethodType +from types import ModuleType import weakref -from zope.interface.interface import InterfaceClass, Specification -from zope.interface.interface import SpecificationBase -from types import ModuleType, MethodType, FunctionType + from zope.interface.advice import addClassAdvisor +from zope.interface.interface import InterfaceClass +from zope.interface.interface import SpecificationBase +from zope.interface.interface import Specification # Registry of class-implementation specifications BuiltinImplementationSpecifications = {} @@ -760,7 +764,7 @@ Provides.__safe_for_unpickling__ = True try: from types import ClassType DescriptorAwareMetaClasses = ClassType, type -except ImportError: # Python 3 +except ImportError: #pragma NO COVERAGE (Python 3) DescriptorAwareMetaClasses = (type,) def directlyProvides(object, *interfaces): @@ -973,7 +977,7 @@ def noLongerProvides(object, interface): if interface.providedBy(object): raise ValueError("Can only remove directly provided interfaces.") -class ClassProvidesBasePy(object): +class ClassProvidesBaseFallback(object): def __get__(self, inst, cls): if cls is self._cls: @@ -988,14 +992,15 @@ class ClassProvidesBasePy(object): raise AttributeError('__provides__') -ClassProvidesBase = ClassProvidesBasePy +ClassProvidesBasePy = ClassProvidesBaseFallback # BBB +ClassProvidesBase = ClassProvidesBaseFallback # Try to get C base: try: import _zope_interface_coptimizations -except ImportError: +except ImportError: #pragma NO COVERAGE pass -else: +else: #pragma NO COVERAGE from _zope_interface_coptimizations import ClassProvidesBase @@ -1185,6 +1190,8 @@ def moduleProvides(*interfaces): # # Declaration querying support +# XXX: is this a fossil? Nobody calls it, no unit tests exercise it, no +# doctests import it, and the package __init__ doesn't import it. def ObjectSpecification(direct, cls): """Provide object specifications @@ -1251,9 +1258,9 @@ def ObjectSpecification(direct, cls): 1 """ - return Provides(cls, direct) + return Provides(cls, direct) #pragma NO COVER fossil -def getObjectSpecification(ob): +def getObjectSpecificationFallback(ob): provides = getattr(ob, '__provides__', None) if provides is not None: @@ -1268,7 +1275,9 @@ def getObjectSpecification(ob): return implementedBy(cls) -def providedBy(ob): +getObjectSpecification = getObjectSpecificationFallback + +def providedByFallback(ob): # Here we have either a special object, an old-style declaration # or a descriptor @@ -1317,8 +1326,9 @@ def providedBy(ob): return implementedBy(ob.__class__) return r +providedBy = providedByFallback -class ObjectSpecificationDescriptorPy(object): +class ObjectSpecificationDescriptorFallback(object): """Implement the `__providedBy__` attribute The `__providedBy__` attribute computes the interfaces peovided by @@ -1357,7 +1367,7 @@ class ObjectSpecificationDescriptorPy(object): return implementedBy(cls) -ObjectSpecificationDescriptor = ObjectSpecificationDescriptorPy +ObjectSpecificationDescriptor = ObjectSpecificationDescriptorFallback ############################################################################## @@ -1385,10 +1395,11 @@ _empty = Declaration() try: import _zope_interface_coptimizations -except ImportError: +except ImportError: #pragma NO COVER pass else: - from _zope_interface_coptimizations import implementedBy, providedBy + from _zope_interface_coptimizations import implementedBy + from _zope_interface_coptimizations import providedBy from _zope_interface_coptimizations import getObjectSpecification from _zope_interface_coptimizations import ObjectSpecificationDescriptor diff --git a/src/zope/interface/human.ru.txt b/src/zope/interface/human.ru.txt deleted file mode 100644 index a149072..0000000 --- a/src/zope/interface/human.ru.txt +++ /dev/null @@ -1,156 +0,0 @@ -=============================== -Использование реестра адаптеров -=============================== - -Данный документ содержит небольшую демонстрацию пакета ``zope.interface`` и его -реестра адаптеров. Документ рассчитывался как конкретный, но более узкий пример -того как использовать интерфейсы и адаптеры вне Zope 3. - -Сначала нам необходимо импортировать пакет для работы с интерфейсами:: - - >>> import zope.interface - -Теперь мы разработаем интерфейс для нашего объекта - простого файла. Наш файл -будет содержать всего один атрибут - body, в котором фактически будет сохранено -содержимое файла:: - - >>> class IFile(zope.interface.Interface): - ... - ... body = zope.interface.Attribute(u'Содержимое файла.') - ... - -Для статистики нам часто необходимо знать размер файла. Но было бы несколько -топорно реализовывать определение размера прямо для объекта файла, т.к. размер -больше относится к мета-данным. Таким образом мы создаем еще один интерфейс для -представления размера какого-либо объекта:: - - >>> class ISize(zope.interface.Interface): - ... - ... def getSize(): - ... 'Return the size of an object.' - ... - -Теперь мы должны создать класс реализующий наш файл. Необходимо что бы наш -объект хранил информацию о том, что он реализует интерфейс `IFile`. Мы также -создаем атрибут с содержимым файла по умолчанию (для упрощения нашего -примера):: - - >>> class File(object): - ... - ... zope.interface.implements(IFile) - ... body = 'foo bar' - ... - -Дальше мы создаем адаптер, который будет предоставлять интерфейс `ISize` -получая любой объект предоставляющий интерфейс `IFile`. По соглашению мы -используем атрибут `__used_for__` для указания интерфейса который как мы -ожидаем предоставляет адаптируемый объект, `IFile` в нашем случае. На самом -деле этот атрибут используется только для документирования. В случае если -адаптер используется для нескольких интерфейсов можно указать их все в виде -кортежа. - -Опять же по соглашению конструктор адаптера получает один аргумент - context -(контекст). В нашем случае контекст - это экземпляр `IFile` (объект, -предоставляющий `IFile`) который используется для получения из него размера. -Так же по соглашению контекст сохраняется а адаптере в атрибуте с именем -`context`. Twisted комьюнити ссылается на контекст как на объект `original`. -Таким образом можно также дать аргументу любое подходящее имя, например -`file`:: - - >>> class FileSize(object): - ... - ... zope.interface.implements(ISize) - ... __used_for__ = IFile - ... - ... def __init__(self, context): - ... self.context = context - ... - ... def getSize(self): - ... return len(self.context.body) - ... - -Теперь когда мы написали наш адаптер мы должны зарегистрировать его в реестре -адаптеров, что бы его можно было запросить когда он понадобится. Здесь нет -какого-либо глобального реестра адаптеров, таким образом мы должны -самостоятельно создать для нашего примера реестр:: - - >>> from zope.interface.adapter import AdapterRegistry - >>> registry = AdapterRegistry() - -Реестр содержит отображение того, что адаптер реализует на основе другого -интерфейса который предоставляет объект. Поэтому дальше мы регистрируем адаптер -который адаптирует интерфейс `IFile` к интерфейсу `ISize`. Первый аргумент к -методу `register()` реестра - это список адаптируемых интерфейсов. В нашем -случае мы имеем только один адаптируемый интерфейс - `IFile`. Список -интерфейсов имеет смысл для использования концепции мульти-адаптеров, которые -требуют нескольких оригинальных объектов для адаптации к новому интерфейсу. В -этой ситуации конструктор адаптера будет требовать новый аргумент для каждого -оригинального интерфейса. - -Второй аргумент метода `register()` - это интерфейс который предоставляет -адаптер, в нашем случае `ISize`. Третий аргумент - имя адаптера. Сейчас нам не -важно имя адаптера и мы передаем его как пустую строку. Обычно имена полезны -если используются адаптеры для одинакового набора интерфейсов, но в различных -ситуациях. Последний аргумент - это класс адаптера:: - - >>> registry.register([IFile], ISize, '', FileSize) - -Теперь мы можем использовать реестр для запроса адаптера:: - - >>> registry.lookup1(IFile, ISize, '') - <class '__main__.FileSize'> - -Попробуем более практичный пример. Создадим экземпляр `File` и создадим адаптер -использующий запрос реестра. Затем мы увидим возвращает ли адаптер корректный -размер при вызове `getSize()`:: - - >>> file = File() - >>> size = registry.lookup1(IFile, ISize, '')(file) - >>> size.getSize() - 7 - -На самом деле это не очень практично, т.к. нам нужно самим передавать все -аргументы методу запроса. Существует некоторый синтаксический леденец который -позволяет нам получить экземпляр адаптера просто вызвав `ISize(file)`. Что бы -использовать эту функциональность нам понадобится добавить наш реестр к списку -adapter_hooks, который находится в модуле с адаптерами. Этот список хранит -коллекцию вызываемых объектов которые вызываются автоматически когда вызывается -IFoo(obj); их предназначение - найти адаптеры которые реализуют интерфейс для -определенного экземпляра контекста. - -Необходимо реализовать свою собственную функцию для поиска адаптера; данный -пример описывает одну из простейших функций для использования с реестром, но -также можно реализовать поисковые функции которые, например, используют -кэширование, или адаптеры сохраняемые в базе. Функция поиска должна принимать -желаемый на выходе интерфейс (в нашем случае `ISize`) как первый аргумент и -контекст для адаптации (`file`) как второй. Функция должна вернуть адаптер, -т.е. экземпляр `FileSize`:: - - >>> def hook(provided, object): - ... adapter = registry.lookup1(zope.interface.providedBy(object), - ... provided, '') - ... return adapter(object) - ... - -Теперь мы просто добавляем нашу функцию к списку `adapter_hooks`:: - - >>> from zope.interface.interface import adapter_hooks - >>> adapter_hooks.append(hook) - -Как только функция зарегистрирована мы можем использовать желаемый синтаксис:: - - >>> size = ISize(file) - >>> size.getSize() - 7 - -После нам нужно прибраться за собой, что бы другие получили чистый список -`adaper_hooks` после нас:: - - >>> adapter_hooks.remove(hook) - -Это все. Здесь намеренно отложена дискуссия об именованных и мульти-адаптерах, -т.к. данный текст рассчитан как практическое и простое введение в интерфейсы и -адаптеры Zope 3. Для более подробной информации имеет смысл прочитать -`adapter.txt` из пакета `zope.interface`, что бы получить более формальное, -справочное и полное трактование пакета. Внимание: многие жаловались, что -`adapter.txt` приводит их мозг к расплавленному состоянию! diff --git a/src/zope/interface/human.txt b/src/zope/interface/human.txt deleted file mode 100644 index 749b87d..0000000 --- a/src/zope/interface/human.txt +++ /dev/null @@ -1,152 +0,0 @@ -========================== -Using the Adapter Registry -========================== - -This is a small demonstration of the ``zope.interface`` package including its -adapter registry. It is intended to provide a concrete but narrow example on -how to use interfaces and adapters outside of Zope 3. - -First we have to import the interface package:: - - >>> import zope.interface - -We now develop an interface for our object, which is a simple file in this -case. For now we simply support one attribute, the body, which contains the -actual file contents:: - - >>> class IFile(zope.interface.Interface): - ... - ... body = zope.interface.Attribute('Contents of the file.') - ... - -For statistical reasons we often want to know the size of a file. However, it -would be clumsy to implement the size directly in the file object, since the -size really represents meta-data. Thus we create another interface that -provides the size of something:: - - >>> class ISize(zope.interface.Interface): - ... - ... def getSize(): - ... 'Return the size of an object.' - ... - -Now we need to implement the file. It is essential that the object states -that it implements the `IFile` interface. We also provide a default body -value (just to make things simpler for this example):: - - >>> class File(object): - ... - ... zope.interface.implements(IFile) - ... body = 'foo bar' - ... - -Next we implement an adapter that can provide the `ISize` interface given any -object providing `IFile`. By convention we use `__used_for__` to specify the -interface that we expect the adapted object to provide, in our case -`IFile`. However, this attribute is not used for anything. If you have -multiple interfaces for which an adapter is used, just specify the interfaces -via a tuple. - -Again by convention, the constructor of an adapter takes one argument, the -context. The context in this case is an instance of `File` (providing `IFile`) -that is used to extract the size from. Also by convention the context is -stored in an attribute named `context` on the adapter. The twisted community -refers to the context as the `original` object. However, you may feel free to -use a specific argument name, such as `file`:: - - >>> class FileSize(object): - ... - ... zope.interface.implements(ISize) - ... __used_for__ = IFile - ... - ... def __init__(self, context): - ... self.context = context - ... - ... def getSize(self): - ... return len(self.context.body) - ... - -Now that we have written our adapter, we have to register it with an adapter -registry, so that it can be looked up when needed. There is no such thing as a -global registry; thus we have to instantiate one for our example manually:: - - >>> from zope.interface.adapter import AdapterRegistry - >>> registry = AdapterRegistry() - - -The registry keeps a map of what adapters implement based on another -interface, the object already provides. Therefore, we next have to register an -adapter that adapts from `IFile` to `ISize`. The first argument to -the registry's `register()` method is a list of original interfaces.In our -cause we have only one original interface, `IFile`. A list makes sense, since -the interface package has the concept of multi-adapters, which are adapters -that require multiple objects to adapt to a new interface. In these -situations, your adapter constructor will require an argument for each -specified interface. - -The second argument is the interface the adapter provides, in our case -`ISize`. The third argument is the name of the adapter. Since we do not care -about names, we simply leave it as an empty string. Names are commonly useful, -if you have adapters for the same set of interfaces, but they are useful in -different situations. The last argument is simply the adapter class:: - - >>> registry.register([IFile], ISize, '', FileSize) - -You can now use the the registry to lookup the adapter:: - - >>> registry.lookup1(IFile, ISize, '') - <class '__main__.FileSize'> - -Let's get a little bit more practical. Let's create a `File` instance and -create the adapter using a registry lookup. Then we see whether the adapter -returns the correct size by calling `getSize()`:: - - >>> file = File() - >>> size = registry.lookup1(IFile, ISize, '')(file) - >>> size.getSize() - 7 - -However, this is not very practical, since I have to manually pass in the -arguments to the lookup method. There is some syntactic candy that will allow -us to get an adapter instance by simply calling `ISize(file)`. To make use of -this functionality, we need to add our registry to the adapter_hooks list, -which is a member of the adapters module. This list stores a collection of -callables that are automatically invoked when IFoo(obj) is called; their -purpose is to locate adapters that implement an interface for a certain -context instance. - -You are required to implement your own adapter hook; this example covers one -of the simplest hooks that use the registry, but you could implement one that -used an adapter cache or persistent adapters, for instance. The helper hook is -required to expect as first argument the desired output interface (for us -`ISize`) and as the second argument the context of the adapter (here -`file`). The function returns an adapter, i.e. a `FileSize` instance:: - - >>> def hook(provided, object): - ... adapter = registry.lookup1(zope.interface.providedBy(object), - ... provided, '') - ... return adapter(object) - ... - -We now just add the hook to an `adapter_hooks` list:: - - >>> from zope.interface.interface import adapter_hooks - >>> adapter_hooks.append(hook) - -Once the hook is registered, you can use the desired syntax:: - - >>> size = ISize(file) - >>> size.getSize() - 7 - -Now we have to cleanup after ourselves, so that others after us have a clean -`adapter_hooks` list:: - - >>> adapter_hooks.remove(hook) - -That's it. I have intentionally left out a discussion of named adapters and -multi-adapters, since this text is intended as a practical and simple -introduction to Zope 3 interfaces and adapters. You might want to read the -`adapter.txt` in the `zope.interface` package for a more formal, referencial -and complete treatment of the package. Warning: People have reported that -`adapter.txt` makes their brain feel soft! diff --git a/src/zope/interface/index.txt b/src/zope/interface/index.txt deleted file mode 100644 index 3c499b5..0000000 --- a/src/zope/interface/index.txt +++ /dev/null @@ -1,29 +0,0 @@ -Welcome to zope.interface's documentation! -========================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - README - adapter - human - verify - -По-русски -========= - -.. toctree:: - :maxdepth: 2 - - README.ru - adapter.ru - human.ru - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/src/zope/interface/interface.py b/src/zope/interface/interface.py index aec7d85..e7ca1e1 100644 --- a/src/zope/interface/interface.py +++ b/src/zope/interface/interface.py @@ -163,7 +163,7 @@ class SpecificationBasePy(object): SpecificationBase = SpecificationBasePy try: from _zope_interface_coptimizations import SpecificationBase -except ImportError: +except ImportError: #pragma NO COVER pass _marker = object() @@ -204,14 +204,14 @@ class InterfaceBasePy(object): InterfaceBase = InterfaceBasePy try: from _zope_interface_coptimizations import InterfaceBase -except ImportError: +except ImportError: #pragma NO COVER pass adapter_hooks = [] try: from _zope_interface_coptimizations import adapter_hooks -except ImportError: +except ImportError: #pragma NO COVER pass @@ -224,7 +224,7 @@ class Specification(SpecificationBase): This class is a base class for both interfaces themselves and for interface specifications (declarations). - Specifications are mutable. If you reassign their cases, their + Specifications are mutable. If you reassign their bases, their relations with other specifications are adjusted accordingly. For example: @@ -450,7 +450,7 @@ class InterfaceClass(Element, InterfaceBase, Specification): # This is how cPython figures out the module of # a class, but of course it does it in C. :-/ __module__ = sys._getframe(1).f_globals['__name__'] - except (AttributeError, KeyError): + except (AttributeError, KeyError): #pragma NO COVERAGE pass self.__module__ = __module__ @@ -605,9 +605,10 @@ class InterfaceClass(Element, InterfaceBase, Specification): if errors: raise Invalid(errors) - def _getInterface(self, ob, name): - """Retrieve a named interface.""" - return None + #XXX I believe this is a fossil: nobody calls it anywhere. + #def _getInterface(self, ob, name): + # """Retrieve a named interface.""" + # return None def __d(self, klass): for k, v in self.__attrs.items(): @@ -632,7 +633,7 @@ class InterfaceClass(Element, InterfaceBase, Specification): def _call_conform(self, conform): try: return conform(self) - except TypeError: + except TypeError: #pragma NO COVER # We got a TypeError. It might be an error raised by # the __conform__ implementation, or *we* may have # made the TypeError by calling an unbound method @@ -646,12 +647,12 @@ class InterfaceClass(Element, InterfaceBase, Specification): raise # This clever trick is from Phillip Eby - return None + return None #pragma NO COVER def __reduce__(self): return self.__name__ - def __cmp(self, o1, o2): + def __cmp(self, other): # Yes, I did mean to name this __cmp, rather than __cmp__. # It is a private method used by __lt__ and __gt__. # I don't want to override __eq__ because I want the default @@ -673,46 +674,44 @@ class InterfaceClass(Element, InterfaceBase, Specification): sort before None. """ - if o1 is None: - return 1 - if o2 is None: + if other is None: return -1 - n1 = (getattr(o1, '__name__', ''), getattr(o1, '__module__', '')) - n2 = (getattr(o2, '__name__', ''), getattr(o2, '__module__', '')) + n1 = (getattr(self, '__name__', ''), getattr(self, '__module__', '')) + n2 = (getattr(other, '__name__', ''), getattr(other, '__module__', '')) # This spelling works under Python3, which doesn't have cmp(). return (n1 > n2) - (n1 < n2) def __hash__(self): d = self.__dict__ - if '__module__' not in d or '__name__' not in d: + if '__module__' not in d or '__name__' not in d: #pragma NO COVER warnings.warn('Hashing uninitialized InterfaceClass instance') return 1 return hash((self.__name__, self.__module__)) def __eq__(self, other): - c = self.__cmp(self, other) + c = self.__cmp(other) return c == 0 def __ne__(self, other): - c = self.__cmp(self, other) + c = self.__cmp(other) return c != 0 def __lt__(self, other): - c = self.__cmp(self, other) + c = self.__cmp(other) return c < 0 def __le__(self, other): - c = self.__cmp(self, other) + c = self.__cmp(other) return c <= 0 def __gt__(self, other): - c = self.__cmp(self, other) + c = self.__cmp(other) return c > 0 def __ge__(self, other): - c = self.__cmp(self, other) + c = self.__cmp(other) return c >= 0 @@ -742,6 +741,18 @@ class Method(Attribute): # # implements(IMethod) + positional = required = () + _optional = varargs = kwargs = None + def _get_optional(self): + if self._optional is None: + return {} + return self._optional + def _set_optional(self, opt): + self._optional = opt + def _del_optional(self): + self._optional = None + optional = property(_get_optional, _set_optional, _del_optional) + def __call__(self, *args, **kw): raise BrokenImplementation(self.interface, self.__name__) @@ -758,7 +769,7 @@ class Method(Attribute): for v in self.positional: sig.append(v) if v in self.optional.keys(): - sig[-1] += "=" + `self.optional[v]` + sig[-1] += "=" + repr(self.optional[v]) if self.varargs: sig.append("*" + self.varargs) if self.kwargs: diff --git a/src/zope/interface/registry.py b/src/zope/interface/registry.py index 6310686..c5009d3 100644 --- a/src/zope/interface/registry.py +++ b/src/zope/interface/registry.py @@ -18,7 +18,7 @@ import types try: from zope.event import notify -except ImportError: +except ImportError: #pragma NO COVER def notify(*arg, **kw): pass from zope.interface.interfaces import ISpecification @@ -40,7 +40,7 @@ from zope.interface.declarations import implementer # required by py3k fixers from zope.interface.declarations import implementer_only # req by py3k fixers from zope.interface.adapter import AdapterRegistry -if sys.version_info[0] == 3: +if sys.version_info[0] == 3: #pragma NO COVER def _u(s): return s class_types = type diff --git a/src/zope/interface/ro.py b/src/zope/interface/ro.py index 47a7ea2..ab47a4c 100644 --- a/src/zope/interface/ro.py +++ b/src/zope/interface/ro.py @@ -30,7 +30,7 @@ def mergeOrderings(orderings, seen=None): For example: - >>> _mergeOrderings([ + >>> mergeOrderings([ ... ['x', 'y', 'z'], ... ['q', 'z'], ... [1, 3, 5], diff --git a/src/zope/interface/tests/advisory_testing.py b/src/zope/interface/tests/advisory_testing.py new file mode 100644 index 0000000..f78a550 --- /dev/null +++ b/src/zope/interface/tests/advisory_testing.py @@ -0,0 +1,42 @@ +############################################################################## +# +# Copyright (c) 2003 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +import sys + +from zope.interface.advice import addClassAdvisor +from zope.interface.advice import getFrameInfo + +my_globals = globals() + +def ping(log, value): + + def pong(klass): + log.append((value,klass)) + return [klass] + + addClassAdvisor(pong) + +try: + from types import ClassType + + class ClassicClass: + __metaclass__ = ClassType + classLevelFrameInfo = getFrameInfo(sys._getframe()) +except ImportError: + ClassicClass = None + +class NewStyleClass: + __metaclass__ = type + classLevelFrameInfo = getFrameInfo(sys._getframe()) + +moduleLevelFrameInfo = getFrameInfo(sys._getframe()) diff --git a/src/zope/interface/tests/dummy.py b/src/zope/interface/tests/dummy.py index f5564da..9057d73 100644 --- a/src/zope/interface/tests/dummy.py +++ b/src/zope/interface/tests/dummy.py @@ -11,12 +11,13 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -"""Dummy Module +""" Dummy Module """ from zope.interface import moduleProvides -from zope.interface.tests.ifoo import IFoo +from zope.interface.tests.idummy import IDummyModule -moduleProvides(IFoo) +moduleProvides(IDummyModule) def bar(baz): + # Note: no 'self', because the module provides the interface directly. pass diff --git a/src/zope/interface/tests/foodforthought.txt b/src/zope/interface/tests/foodforthought.txt deleted file mode 100644 index 45d961b..0000000 --- a/src/zope/interface/tests/foodforthought.txt +++ /dev/null @@ -1,61 +0,0 @@ -================================ -Food-based subscription examples -================================ - - -This file gives more subscription examples using a cooking-based example:: - - >>> from zope.interface.adapter import AdapterRegistry - >>> registry = AdapterRegistry() - - >>> import zope.interface - >>> class IAnimal(zope.interface.Interface): - ... pass - >>> class IPoultry(IAnimal): - ... pass - >>> class IChicken(IPoultry): - ... pass - >>> class ISeafood(IAnimal): - ... pass - -Adapting to some other interface for which there is no -subscription adapter returns an empty sequence:: - - >>> class IRecipe(zope.interface.Interface): - ... pass - >>> class ISausages(IRecipe): - ... pass - >>> class INoodles(IRecipe): - ... pass - >>> class IKFC(IRecipe): - ... pass - - >>> list(registry.subscriptions([IPoultry], IRecipe)) - [] - -unless we define a subscription:: - - >>> registry.subscribe([IAnimal], ISausages, 'sausages') - >>> list(registry.subscriptions([IPoultry], ISausages)) - ['sausages'] - -And define another subscription adapter:: - - >>> registry.subscribe([IPoultry], INoodles, 'noodles') - >>> meals = list(registry.subscriptions([IPoultry], IRecipe)) - >>> meals.sort() - >>> meals - ['noodles', 'sausages'] - - >>> registry.subscribe([IChicken], IKFC, 'kfc') - >>> meals = list(registry.subscriptions([IChicken], IRecipe)) - >>> meals.sort() - >>> meals - ['kfc', 'noodles', 'sausages'] - -And the answer for poultry hasn't changed:: - - >>> meals = list(registry.subscriptions([IPoultry], IRecipe)) - >>> meals.sort() - >>> meals - ['noodles', 'sausages'] diff --git a/src/zope/interface/tests/idummy.py b/src/zope/interface/tests/idummy.py new file mode 100644 index 0000000..1e34fe0 --- /dev/null +++ b/src/zope/interface/tests/idummy.py @@ -0,0 +1,23 @@ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" Interface describing API of zope.interface.tests.dummy test module +""" +from zope.interface import Interface + +class IDummyModule(Interface): + """ Dummy interface for unit tests. + """ + def bar(baz): + """ Just a note. + """ diff --git a/src/zope/interface/tests/test_adapter.py b/src/zope/interface/tests/test_adapter.py index 30a8598..8322f74 100644 --- a/src/zope/interface/tests/test_adapter.py +++ b/src/zope/interface/tests/test_adapter.py @@ -13,400 +13,1260 @@ ############################################################################## """Adapter registry tests """ -import doctest import unittest -import zope.interface -from zope.interface.adapter import AdapterRegistry - - -class IF0(zope.interface.Interface): - pass -class IF1(IF0): - pass - -class IB0(zope.interface.Interface): - pass -class IB1(IB0): - pass - -class IR0(zope.interface.Interface): - pass -class IR1(IR0): - pass - -def test_multi_adapter_get_best_match(): - """ - >>> registry = AdapterRegistry() - - >>> class IB2(IB0): - ... pass - >>> class IB3(IB2, IB1): - ... pass - >>> class IB4(IB1, IB2): - ... pass - - >>> registry.register([None, IB1], IR0, '', 'A1') - >>> registry.register([None, IB0], IR0, '', 'A0') - >>> registry.register([None, IB2], IR0, '', 'A2') - - >>> registry.lookup((IF1, IB1), IR0, '') - 'A1' - >>> registry.lookup((IF1, IB2), IR0, '') - 'A2' - >>> registry.lookup((IF1, IB0), IR0, '') - 'A0' - >>> registry.lookup((IF1, IB3), IR0, '') - 'A2' - >>> registry.lookup((IF1, IB4), IR0, '') - 'A1' - """ - -def test_multi_adapter_lookupAll_get_best_matches(): - """ - >>> registry = AdapterRegistry() - - >>> class IB2(IB0): - ... pass - >>> class IB3(IB2, IB1): - ... pass - >>> class IB4(IB1, IB2): - ... pass - - >>> registry.register([None, IB1], IR0, '', 'A1') - >>> registry.register([None, IB0], IR0, '', 'A0') - >>> registry.register([None, IB2], IR0, '', 'A2') - - >>> tuple(registry.lookupAll((IF1, IB1), IR0))[0][1] - 'A1' - >>> tuple(registry.lookupAll((IF1, IB2), IR0))[0][1] - 'A2' - >>> tuple(registry.lookupAll((IF1, IB0), IR0))[0][1] - 'A0' - >>> tuple(registry.lookupAll((IF1, IB3), IR0))[0][1] - 'A2' - >>> tuple(registry.lookupAll((IF1, IB4), IR0))[0][1] - 'A1' - """ - - -def test_multi_adapter_w_default(): - """ - >>> registry = AdapterRegistry() - - >>> registry.register([None, None], IB1, 'bob', 'A0') - - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A0' - - >>> registry.register([None, IR0], IB1, 'bob', 'A1') - - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A1' - - >>> registry.lookup((IF1, IR1), IB0, 'bruce') - - >>> registry.register([None, IR1], IB1, 'bob', 'A2') - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A2' - """ - -def test_multi_adapter_w_inherited_and_multiple_registrations(): - """ - >>> registry = AdapterRegistry() - - >>> class IX(zope.interface.Interface): - ... pass - - >>> registry.register([IF0, IR0], IB1, 'bob', 'A1') - >>> registry.register([IF1, IX], IB1, 'bob', 'AX') - - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A1' - """ - -def test_named_adapter_with_default(): - """Query a named simple adapter - - >>> registry = AdapterRegistry() - - If we ask for a named adapter, we won't get a result unless there - is a named adapter, even if the object implements the interface: - - >>> registry.lookup([IF1], IF0, 'bob') - - >>> registry.register([None], IB1, 'bob', 'A1') - >>> registry.lookup([IF1], IB0, 'bob') - 'A1' - - >>> registry.lookup([IF1], IB0, 'bruce') - - >>> registry.register([None], IB0, 'bob', 'A2') - >>> registry.lookup([IF1], IB0, 'bob') - 'A2' - """ - -def test_multi_adapter_gets_closest_provided(): - """ - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR0], IB0, 'bob', 'A1') - >>> registry.register((IF1, IR0), IB1, 'bob', 'A2') - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A1' - - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR0], IB1, 'bob', 'A2') - >>> registry.register([IF1, IR0], IB0, 'bob', 'A1') - >>> registry.lookup([IF1, IR0], IB0, 'bob') - 'A1' - - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR0], IB0, 'bob', 'A1') - >>> registry.register([IF1, IR1], IB1, 'bob', 'A2') - >>> registry.lookup([IF1, IR1], IB0, 'bob') - 'A2' - - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR1], IB1, 'bob', 2) - >>> registry.register([IF1, IR0], IB0, 'bob', 1) - >>> registry.lookup([IF1, IR1], IB0, 'bob') - 2 - """ -def test_multi_adapter_check_non_default_dont_hide_default(): - """ - >>> registry = AdapterRegistry() - - >>> class IX(zope.interface.Interface): - ... pass - - - >>> registry.register([None, IR0], IB0, 'bob', 1) - >>> registry.register([IF1, IX], IB0, 'bob', 2) - >>> registry.lookup([IF1, IR1], IB0, 'bob') - 1 - """ - -def test_adapter_hook_with_factory_producing_None(): - """ - >>> registry = AdapterRegistry() - >>> default = object() - - >>> class Object1(object): - ... zope.interface.implements(IF0) - >>> class Object2(object): - ... zope.interface.implements(IF0) - - >>> def factory(context): - ... if isinstance(context, Object1): - ... return 'adapter' - ... return None - - >>> registry.register([IF0], IB0, '', factory) - - >>> registry.adapter_hook(IB0, Object1()) - 'adapter' - >>> registry.adapter_hook(IB0, Object2()) is None - True - >>> registry.adapter_hook(IB0, Object2(), default=default) is default - True - """ - -def test_adapter_registry_update_upon_interface_bases_change(): - """ - Let's first create a adapter registry and a simple adaptation hook: - - >>> globalRegistry = AdapterRegistry() - - >>> def _hook(iface, ob, lookup=globalRegistry.lookup1): - ... factory = lookup(zope.interface.providedBy(ob), iface) - ... if factory is None: - ... return None - ... else: - ... return factory(ob) - - >>> zope.interface.interface.adapter_hooks.append(_hook) - - Now we create some interfaces and an implementation: - - >>> class IX(zope.interface.Interface): - ... pass - - >>> class IY(zope.interface.Interface): - ... pass - - >>> class X(object): - ... pass - - >>> class Y(object): - ... zope.interface.implements(IY) - ... def __init__(self, original): - ... self.original=original - - and register an adapter: - - >>> globalRegistry.register((IX,), IY, '', Y) - - at first, we still expect the adapter lookup from `X` to `IY` to fail: - - >>> IY(X()) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', - <zope.interface.tests.test_adapter.X object at ...>, - <InterfaceClass zope.interface.tests.test_adapter.IY>) - - But after we declare an interface on the class `X`, it should pass: - - >>> zope.interface.classImplementsOnly(X, IX) - - >>> IY(X()) #doctest: +ELLIPSIS - <zope.interface.tests.test_adapter.Y object at ...> - - >>> hook = zope.interface.interface.adapter_hooks.pop() - """ - - -def test_changing_declarations(): - """ - - If we change declarations for a class, those adapter lookup should - eflect the changes: - - >>> class I1(zope.interface.Interface): - ... pass - >>> class I2(zope.interface.Interface): - ... pass - - >>> registry = AdapterRegistry() - >>> registry.register([I1], I2, '', 42) - - >>> class C: - ... pass - - >>> registry.lookup([zope.interface.implementedBy(C)], I2, '') - - >>> zope.interface.classImplements(C, I1) - - >>> registry.lookup([zope.interface.implementedBy(C)], I2, '') - 42 - """ - -def test_correct_multi_adapter_lookup(): - """ - >>> registry = AdapterRegistry() - >>> registry.register([IF0, IB1], IR0, '', 'A01') - >>> registry.register([IF1, IB0], IR0, '', 'A10') - >>> registry.lookup((IF1, IB1), IR0, '') - 'A10' - """ - -def test_duplicate_bases(): - """ -There was a bug that caused problems if a spec had multiple bases: - - >>> class I(zope.interface.Interface): - ... pass - >>> class I2(I, I): - ... pass - >>> registry = AdapterRegistry() - >>> registry.register([I2], IR0, 'x', 'X') - >>> registry.lookup((I2, ), IR0, 'x') - 'X' - >>> registry.register([I2], IR0, 'y', 'Y') - >>> registry.lookup((I2, ), IR0, 'x') - 'X' - >>> registry.lookup((I2, ), IR0, 'y') - 'Y' -""" - -def test_register_objects_with_cmp(): - """ - The registry should never use == as that will tend to fail when - objects are picky about what they are compared with: - - >>> class Picky: - ... def __cmp__(self, other): - ... raise TypeError("I\'m too picky for comparison!") - >>> class I(zope.interface.Interface): - ... pass - >>> class I2(I, I): - ... pass - - >>> registry = AdapterRegistry() - >>> picky = Picky() - >>> registry.register([I2], IR0, '', picky) - >>> registry.unregister([I2], IR0, '', picky) - - >>> registry.subscribe([I2], IR0, picky) - >>> registry.unsubscribe([I2], IR0, picky) - - """ - -def test_unregister_cleans_up_empties(): - """ - >>> class I(zope.interface.Interface): - ... pass - >>> class IP(zope.interface.Interface): - ... pass - >>> class C(object): - ... pass - - >>> registry = AdapterRegistry() - - >>> registry.register([], IP, '', C) - >>> registry.register([I], IP, '', C) - >>> registry.register([I], IP, 'name', C) - >>> registry.register([I, I], IP, '', C) - >>> len(registry._adapters) - 3 - >>> map(len, registry._adapters) - [1, 1, 1] - - >>> registry.unregister([], IP, '', C) - >>> registry.unregister([I], IP, '', C) - >>> registry.unregister([I], IP, 'name', C) - >>> registry.unregister([I, I], IP, '', C) - >>> registry._adapters - [] - - """ - -def test_unsubscribe_cleans_up_empties(): - """ - >>> class I1(zope.interface.Interface): - ... pass - >>> class I2(zope.interface.Interface): - ... pass - >>> class IP(zope.interface.Interface): - ... pass - - >>> registry = AdapterRegistry() - >>> def handler(event): - ... pass - - >>> registry.subscribe([I1], I1, handler) - >>> registry.subscribe([I2], I1, handler) - >>> len(registry._subscribers) - 2 - >>> map(len, registry._subscribers) - [0, 2] - - >>> registry.unsubscribe([I1], I1, handler) - >>> registry.unsubscribe([I2], I1, handler) - >>> registry._subscribers - [] - - """ +class _SilencePy3Deprecations(unittest.TestCase): + # silence deprecation warnings under py3 + + def failUnless(self, expr): + # St00pid speling. + return self.assertTrue(expr) + + def failIf(self, expr): + # St00pid speling. + return self.assertFalse(expr) + + +def _makeInterfaces(): + from zope.interface import Interface + + class IB0(Interface): pass + class IB1(IB0): pass + class IB2(IB0): pass + class IB3(IB2, IB1): pass + class IB4(IB1, IB2): pass + + class IF0(Interface): pass + class IF1(IF0): pass + + class IR0(Interface): pass + class IR1(IR0): pass + + return IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 + + +class BaseAdapterRegistryTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.adapter import BaseAdapterRegistry + class _CUT(BaseAdapterRegistry): + class LookupClass(object): + _changed = _extendors = () + def __init__(self, reg): + pass + def changed(self, orig): + self._changed += (orig,) + def add_extendor(self, provided): + self._extendors += (provided,) + def remove_extendor(self, provided): + self._extendors = tuple([x for x in self._extendors + if x != provided]) + for name in BaseAdapterRegistry._delegated: + setattr(_CUT.LookupClass, name, object()) + return _CUT + + def _makeOne(self): + return self._getTargetClass()() + + def test_lookup_delegation(self): + CUT = self._getTargetClass() + registry = CUT() + for name in CUT._delegated: + self.failUnless( + getattr(registry, name) is getattr(registry._v_lookup, name)) + + def test__generation_on_first_creation(self): + registry = self._makeOne() + # Bumped to 1 in BaseAdapterRegistry.__init__ + self.assertEqual(registry._generation, 1) + + def test__generation_after_calling_changed(self): + registry = self._makeOne() + orig = object() + registry.changed(orig) + # Bumped to 1 in BaseAdapterRegistry.__init__ + self.assertEqual(registry._generation, 2) + self.assertEqual(registry._v_lookup._changed, (registry, orig,)) + + def test__generation_after_changing___bases__(self): + class _Base(object): pass + registry = self._makeOne() + registry.__bases__ = (_Base,) + self.assertEqual(registry._generation, 2) + + def test_register(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + registry.register([IB0], IR0, '', 'A1') + self.assertEqual(registry.registered([IB0], IR0, ''), 'A1') + self.assertEqual(len(registry._adapters), 2) #order 0 and order 1 + self.assertEqual(registry._generation, 2) + + def test_register_with_value_None_unregisters(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + registry.register([None], IR0, '', 'A1') + registry.register([None], IR0, '', None) + self.assertEqual(len(registry._adapters), 0) + + def test_register_with_same_value(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + _value = object() + registry.register([None], IR0, '', _value) + _before = registry._generation + registry.register([None], IR0, '', _value) + self.assertEqual(registry._generation, _before) # skipped changed() + + def test_registered_empty(self): + registry = self._makeOne() + self.assertEqual(registry.registered([None], None, ''), None) + + def test_registered_non_empty_miss(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + registry.register([IB1], None, '', 'A1') + self.assertEqual(registry.registered([IB2], None, ''), None) + + def test_registered_non_empty_hit(self): + registry = self._makeOne() + registry.register([None], None, '', 'A1') + self.assertEqual(registry.registered([None], None, ''), 'A1') + + def test_unregister_empty(self): + registry = self._makeOne() + registry.unregister([None], None, '') #doesn't raise + self.assertEqual(registry.registered([None], None, ''), None) + + def test_unregister_non_empty_miss_on_required(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + registry.register([IB1], None, '', 'A1') + registry.unregister([IB2], None, '') #doesn't raise + self.assertEqual(registry.registered([IB1], None, ''), 'A1') + + def test_unregister_non_empty_miss_on_name(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + registry.register([IB1], None, '', 'A1') + registry.unregister([IB1], None, 'nonesuch') #doesn't raise + self.assertEqual(registry.registered([IB1], None, ''), 'A1') + + def test_unregister_with_value_not_None_miss(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + orig = object() + nomatch = object() + registry.register([IB1], None, '', orig) + registry.unregister([IB1], None, '', nomatch) #doesn't raise + self.failUnless(registry.registered([IB1], None, '') is orig) + + def test_unregister_hit_clears_empty_subcomponents(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + one = object() + another = object() + registry.register([IB1, IB2], None, '', one) + registry.register([IB1, IB3], None, '', another) + self.failUnless(IB2 in registry._adapters[2][IB1]) + self.failUnless(IB3 in registry._adapters[2][IB1]) + registry.unregister([IB1, IB3], None, '', another) + self.failUnless(IB2 in registry._adapters[2][IB1]) + self.failIf(IB3 in registry._adapters[2][IB1]) + + def test_unsubscribe_empty(self): + registry = self._makeOne() + registry.unsubscribe([None], None, '') #doesn't raise + self.assertEqual(registry.registered([None], None, ''), None) + + def test_unsubscribe_hit(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + orig = object() + registry.subscribe([IB1], None, orig) + registry.unsubscribe([IB1], None, orig) #doesn't raise + self.assertEqual(len(registry._subscribers), 0) + + def test_unsubscribe_after_multiple(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + first = object() + second = object() + third = object() + registry.subscribe([IB1], None, first) + registry.subscribe([IB1], None, second) + registry.subscribe([IB1], IR0, third) + registry.unsubscribe([IB1], IR0, third) + registry.unsubscribe([IB1], None, second) + registry.unsubscribe([IB1], None, first) + self.assertEqual(len(registry._subscribers), 0) + + def test_unsubscribe_w_None_after_multiple(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + first = object() + second = object() + third = object() + registry.subscribe([IB1], None, first) + registry.subscribe([IB1], None, second) + registry.unsubscribe([IB1], None) + self.assertEqual(len(registry._subscribers), 0) + + def test_unsubscribe_non_empty_miss_on_required(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + registry.subscribe([IB1], None, 'A1') + self.assertEqual(len(registry._subscribers), 2) + registry.unsubscribe([IB2], None, '') #doesn't raise + self.assertEqual(len(registry._subscribers), 2) + + def test_unsubscribe_non_empty_miss_on_value(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + registry.subscribe([IB1], None, 'A1') + self.assertEqual(len(registry._subscribers), 2) + registry.unsubscribe([IB1], None, 'A2') #doesn't raise + self.assertEqual(len(registry._subscribers), 2) + + def test_unsubscribe_with_value_not_None_miss(self): + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() + registry = self._makeOne() + orig = object() + nomatch = object() + registry.subscribe([IB1], None, orig) + registry.unsubscribe([IB1], None, nomatch) #doesn't raise + self.assertEqual(len(registry._subscribers), 2) + + +class LookupBaseFallbackTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.adapter import LookupBaseFallback + return LookupBaseFallback + + def _makeOne(self, uc_lookup=None, uc_lookupAll=None, + uc_subscriptions=None): + if uc_lookup is None: + def uc_lookup(self, required, provided, name): + pass + if uc_lookupAll is None: + def uc_lookupAll(self, required, provided): + pass + if uc_subscriptions is None: + def uc_subscriptions(self, required, provided): + pass + class Derived(self._getTargetClass()): + _uncached_lookup = uc_lookup + _uncached_lookupAll = uc_lookupAll + _uncached_subscriptions = uc_subscriptions + return Derived() + + def test_lookup_miss_no_default(self): + _called_with = [] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return None + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup(('A',), 'B', 'C') + self.failUnless(found is None) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + + def test_lookup_miss_w_default(self): + _called_with = [] + _default = object() + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return None + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup(('A',), 'B', 'C', _default) + self.failUnless(found is _default) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + + def test_lookup_not_cached(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup(('A',), 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + + def test_lookup_cached(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup(('A',), 'B', 'C') + found = lb.lookup(('A',), 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + + def test_lookup_not_cached_multi_required(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup(('A', 'D'), 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A', 'D'), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + + def test_lookup_cached_multi_required(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup(('A', 'D'), 'B', 'C') + found = lb.lookup(('A', 'D'), 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A', 'D'), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + + def test_lookup_not_cached_after_changed(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup(('A',), 'B', 'C') + lb.changed(lb) + found = lb.lookup(('A',), 'B', 'C') + self.failUnless(found is b) + self.assertEqual(_called_with, + [(('A',), 'B', 'C'), (('A',), 'B', 'C')]) + self.assertEqual(_results, [c]) + + def test_lookup1_miss_no_default(self): + _called_with = [] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return None + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup1('A', 'B', 'C') + self.failUnless(found is None) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + + def test_lookup1_miss_w_default(self): + _called_with = [] + _default = object() + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return None + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup1('A', 'B', 'C', _default) + self.failUnless(found is _default) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + + def test_lookup1_miss_w_default_negative_cache(self): + _called_with = [] + _default = object() + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return None + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup1('A', 'B', 'C', _default) + self.failUnless(found is _default) + found = lb.lookup1('A', 'B', 'C', _default) + self.failUnless(found is _default) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + + def test_lookup1_not_cached(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup1('A', 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + + def test_lookup1_cached(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup1('A', 'B', 'C') + found = lb.lookup1('A', 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + + def test_lookup1_not_cached_after_changed(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) + found = lb.lookup1('A', 'B', 'C') + lb.changed(lb) + found = lb.lookup1('A', 'B', 'C') + self.failUnless(found is b) + self.assertEqual(_called_with, + [(('A',), 'B', 'C'), (('A',), 'B', 'C')]) + self.assertEqual(_results, [c]) + + def test_adapter_hook_miss_no_default(self): + req, prv = object(), object() + lb = self._makeOne() + found = lb.adapter_hook(prv, req, '') + self.failUnless(found is None) + + def test_adapter_hook_miss_w_default(self): + req, prv, _default = object(), object(), object() + lb = self._makeOne() + found = lb.adapter_hook(prv, req, '', _default) + self.failUnless(found is _default) + + def test_adapter_hook_hit_factory_returns_None(self): + _f_called_with = [] + def _factory(context): + _f_called_with.append(context) + return None + def _lookup(self, required, provided, name): + return _factory + req, prv, _default = object(), object(), object() + lb = self._makeOne(uc_lookup=_lookup) + adapted = lb.adapter_hook(prv, req, 'C', _default) + self.failUnless(adapted is _default) + self.assertEqual(_f_called_with, [req]) + + def test_adapter_hook_hit_factory_returns_adapter(self): + _f_called_with = [] + _adapter = object() + def _factory(context): + _f_called_with.append(context) + return _adapter + def _lookup(self, required, provided, name): + return _factory + req, prv, _default = object(), object(), object() + lb = self._makeOne(uc_lookup=_lookup) + adapted = lb.adapter_hook(prv, req, 'C', _default) + self.failUnless(adapted is _adapter) + self.assertEqual(_f_called_with, [req]) + + def test_queryAdapter(self): + _f_called_with = [] + _adapter = object() + def _factory(context): + _f_called_with.append(context) + return _adapter + def _lookup(self, required, provided, name): + return _factory + req, prv, _default = object(), object(), object() + lb = self._makeOne(uc_lookup=_lookup) + adapted = lb.queryAdapter(req, prv, 'C', _default) + self.failUnless(adapted is _adapter) + self.assertEqual(_f_called_with, [req]) + + def test_lookupAll_uncached(self): + _called_with = [] + _results = [object(), object(), object()] + def _lookupAll(self, required, provided): + _called_with.append((required, provided)) + return tuple(_results) + lb = self._makeOne(uc_lookupAll=_lookupAll) + found = lb.lookupAll('A', 'B') + self.assertEqual(found, tuple(_results)) + self.assertEqual(_called_with, [(('A',), 'B')]) + + def test_lookupAll_cached(self): + _called_with = [] + _results = [object(), object(), object()] + def _lookupAll(self, required, provided): + _called_with.append((required, provided)) + return tuple(_results) + lb = self._makeOne(uc_lookupAll=_lookupAll) + found = lb.lookupAll('A', 'B') + found = lb.lookupAll('A', 'B') + self.assertEqual(found, tuple(_results)) + self.assertEqual(_called_with, [(('A',), 'B')]) + + def test_subscriptions_uncached(self): + _called_with = [] + _results = [object(), object(), object()] + def _subscriptions(self, required, provided): + _called_with.append((required, provided)) + return tuple(_results) + lb = self._makeOne(uc_subscriptions=_subscriptions) + found = lb.subscriptions('A', 'B') + self.assertEqual(found, tuple(_results)) + self.assertEqual(_called_with, [(('A',), 'B')]) + + def test_subscriptions_cached(self): + _called_with = [] + _results = [object(), object(), object()] + def _subscriptions(self, required, provided): + _called_with.append((required, provided)) + return tuple(_results) + lb = self._makeOne(uc_subscriptions=_subscriptions) + found = lb.subscriptions('A', 'B') + found = lb.subscriptions('A', 'B') + self.assertEqual(found, tuple(_results)) + self.assertEqual(_called_with, [(('A',), 'B')]) + + +class LookupBaseTests(LookupBaseFallbackTests): + + def _getTargetClass(self): + from zope.interface.adapter import LookupBase + return LookupBase + + +class VerifyingBaseFallbackTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.adapter import VerifyingBaseFallback + return VerifyingBaseFallback + + def _makeOne(self, registry, uc_lookup=None, uc_lookupAll=None, + uc_subscriptions=None): + if uc_lookup is None: + def uc_lookup(self, required, provided, name): + pass + if uc_lookupAll is None: + def uc_lookupAll(self, required, provided): + pass + if uc_subscriptions is None: + def uc_subscriptions(self, required, provided): + pass + class Derived(self._getTargetClass()): + _uncached_lookup = uc_lookup + _uncached_lookupAll = uc_lookupAll + _uncached_subscriptions = uc_subscriptions + def __init__(self, registry): + super(Derived, self).__init__() + self._registry = registry + derived = Derived(registry) + derived.changed(derived) # init. '_verify_ro' / '_verify_generations' + return derived + + def _makeRegistry(self, depth): + class WithGeneration(object): + _generation = 1 + class Registry: + def __init__(self, depth): + self.ro = [WithGeneration() for i in range(depth)] + return Registry(depth) + + def test_lookup(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + reg = self._makeRegistry(3) + lb = self._makeOne(reg, uc_lookup=_lookup) + found = lb.lookup(('A',), 'B', 'C') + found = lb.lookup(('A',), 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + reg.ro[1]._generation += 1 + found = lb.lookup(('A',), 'B', 'C') + self.failUnless(found is b) + self.assertEqual(_called_with, + [(('A',), 'B', 'C'), (('A',), 'B', 'C')]) + self.assertEqual(_results, [c]) + + def test_lookup1(self): + _called_with = [] + a, b, c = object(), object(), object() + _results = [a, b, c] + def _lookup(self, required, provided, name): + _called_with.append((required, provided, name)) + return _results.pop(0) + reg = self._makeRegistry(3) + lb = self._makeOne(reg, uc_lookup=_lookup) + found = lb.lookup1('A', 'B', 'C') + found = lb.lookup1('A', 'B', 'C') + self.failUnless(found is a) + self.assertEqual(_called_with, [(('A',), 'B', 'C')]) + self.assertEqual(_results, [b, c]) + reg.ro[1]._generation += 1 + found = lb.lookup1('A', 'B', 'C') + self.failUnless(found is b) + self.assertEqual(_called_with, + [(('A',), 'B', 'C'), (('A',), 'B', 'C')]) + self.assertEqual(_results, [c]) + + def test_adapter_hook(self): + a, b, c = [object(), object(), object()] + def _factory1(context): + return a + def _factory2(context): + return b + def _factory3(context): + return c + _factories = [_factory1, _factory2, _factory3] + def _lookup(self, required, provided, name): + return _factories.pop(0) + req, prv, _default = object(), object(), object() + reg = self._makeRegistry(3) + lb = self._makeOne(reg, uc_lookup=_lookup) + adapted = lb.adapter_hook(prv, req, 'C', _default) + self.failUnless(adapted is a) + adapted = lb.adapter_hook(prv, req, 'C', _default) + self.failUnless(adapted is a) + reg.ro[1]._generation += 1 + adapted = lb.adapter_hook(prv, req, 'C', _default) + self.failUnless(adapted is b) + + def test_queryAdapter(self): + a, b, c = [object(), object(), object()] + def _factory1(context): + return a + def _factory2(context): + return b + def _factory3(context): + return c + _factories = [_factory1, _factory2, _factory3] + def _lookup(self, required, provided, name): + return _factories.pop(0) + req, prv, _default = object(), object(), object() + reg = self._makeRegistry(3) + lb = self._makeOne(reg, uc_lookup=_lookup) + adapted = lb.queryAdapter(req, prv, 'C', _default) + self.failUnless(adapted is a) + adapted = lb.queryAdapter(req, prv, 'C', _default) + self.failUnless(adapted is a) + reg.ro[1]._generation += 1 + adapted = lb.adapter_hook(prv, req, 'C', _default) + self.failUnless(adapted is b) + + def test_lookupAll(self): + _results_1 = [object(), object(), object()] + _results_2 = [object(), object(), object()] + _results = [_results_1, _results_2] + def _lookupAll(self, required, provided): + return tuple(_results.pop(0)) + reg = self._makeRegistry(3) + lb = self._makeOne(reg, uc_lookupAll=_lookupAll) + found = lb.lookupAll('A', 'B') + self.assertEqual(found, tuple(_results_1)) + found = lb.lookupAll('A', 'B') + self.assertEqual(found, tuple(_results_1)) + reg.ro[1]._generation += 1 + found = lb.lookupAll('A', 'B') + self.assertEqual(found, tuple(_results_2)) + + def test_subscriptions(self): + _results_1 = [object(), object(), object()] + _results_2 = [object(), object(), object()] + _results = [_results_1, _results_2] + def _subscriptions(self, required, provided): + return tuple(_results.pop(0)) + reg = self._makeRegistry(3) + lb = self._makeOne(reg, uc_subscriptions=_subscriptions) + found = lb.subscriptions('A', 'B') + self.assertEqual(found, tuple(_results_1)) + found = lb.subscriptions('A', 'B') + self.assertEqual(found, tuple(_results_1)) + reg.ro[1]._generation += 1 + found = lb.subscriptions('A', 'B') + self.assertEqual(found, tuple(_results_2)) + + +class VerifyingBaseTests(VerifyingBaseFallbackTests): + + def _getTargetClass(self): + from zope.interface.adapter import VerifyingBase + return VerifyingBase + + +class AdapterLookupBaseTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.adapter import AdapterLookupBase + return AdapterLookupBase + + def _makeOne(self, registry): + return self._getTargetClass()(registry) + + def _makeSubregistry(self, *provided): + class Subregistry: + def __init__(self): + self._adapters = [] + self._subscribers = [] + return Subregistry() + + def _makeRegistry(self, *provided): + class Registry: + def __init__(self, provided): + self._provided = provided + self.ro = [] + return Registry(provided) + + def test_ctor_empty_registry(self): + registry = self._makeRegistry() + alb = self._makeOne(registry) + self.assertEqual(alb._extendors, {}) + + def test_ctor_w_registry_provided(self): + from zope.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + alb = self._makeOne(registry) + self.assertEqual(sorted(alb._extendors.keys()), + sorted([IBar, IFoo, Interface])) + self.assertEqual(alb._extendors[IFoo], [IFoo]) + self.assertEqual(alb._extendors[IBar], [IBar]) + self.assertEqual(sorted(alb._extendors[Interface]), + sorted([IFoo, IBar])) + + def test_changed_empty_required(self): + # ALB.changed expects to call a mixed in changed. + class Mixin(object): + def changed(self, *other): + pass + class Derived(self._getTargetClass(), Mixin): + pass + registry = self._makeRegistry() + alb = Derived(registry) + alb.changed(alb) + + def test_changed_w_required(self): + # ALB.changed expects to call a mixed in changed. + class Mixin(object): + def changed(self, *other): + pass + class Derived(self._getTargetClass(), Mixin): + pass + class FauxWeakref(object): + _unsub = None + def __init__(self, here): + self._here = here + def __call__(self): + if self._here: + return self + def unsubscribe(self, target): + self._unsub = target + gone = FauxWeakref(False) + here = FauxWeakref(True) + registry = self._makeRegistry() + alb = Derived(registry) + alb._required[gone] = 1 + alb._required[here] = 1 + alb.changed(alb) + self.assertEqual(len(alb._required), 0) + self.assertEqual(gone._unsub, None) + self.assertEqual(here._unsub, alb) + + def test_init_extendors_after_registry_update(self): + from zope.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + alb = self._makeOne(registry) + registry._provided = [IFoo, IBar] + alb.init_extendors() + self.assertEqual(sorted(alb._extendors.keys()), + sorted([IBar, IFoo, Interface])) + self.assertEqual(alb._extendors[IFoo], [IFoo]) + self.assertEqual(alb._extendors[IBar], [IBar]) + self.assertEqual(sorted(alb._extendors[Interface]), + sorted([IFoo, IBar])) + + def test_add_extendor(self): + from zope.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + alb = self._makeOne(registry) + alb.add_extendor(IFoo) + alb.add_extendor(IBar) + self.assertEqual(sorted(alb._extendors.keys()), + sorted([IBar, IFoo, Interface])) + self.assertEqual(alb._extendors[IFoo], [IFoo]) + self.assertEqual(alb._extendors[IBar], [IBar]) + self.assertEqual(sorted(alb._extendors[Interface]), + sorted([IFoo, IBar])) + + def test_remove_extendor(self): + from zope.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + alb = self._makeOne(registry) + alb.remove_extendor(IFoo) + self.assertEqual(sorted(alb._extendors.keys()), + sorted([IFoo, IBar, Interface])) + self.assertEqual(alb._extendors[IFoo], []) + self.assertEqual(alb._extendors[IBar], [IBar]) + self.assertEqual(sorted(alb._extendors[Interface]), + sorted([IBar])) + + # test '_subscribe' via its callers, '_uncached_lookup', etc. + + def test__uncached_lookup_empty_ro(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + alb = self._makeOne(registry) + result = alb._uncached_lookup((IFoo,), IBar) + self.assertEqual(result, None) + self.assertEqual(len(alb._required), 1) + self.failUnless(IFoo.weakref() in alb._required) + + def test__uncached_lookup_order_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + registry.ro.append(subr) + alb = self._makeOne(registry) + result = alb._uncached_lookup((IFoo,), IBar) + self.assertEqual(result, None) + + def test__uncached_lookup_extendors_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + subr = self._makeSubregistry() + subr._adapters = [{}, {}] #utilities, single adapters + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_lookup((IFoo,), IBar) + self.assertEqual(result, None) + + def test__uncached_lookup_components_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + subr._adapters = [{}, {}] #utilities, single adapters + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_lookup((IFoo,), IBar) + self.assertEqual(result, None) + + def test__uncached_lookup_simple_hit(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _expected = object() + subr._adapters = [ #utilities, single adapters + {}, + {IFoo: {IBar: {'': _expected}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_lookup((IFoo,), IBar) + self.failUnless(result is _expected) + + def test_queryMultiAdaptor_lookup_miss(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + class Foo(object): + implements(IFoo) + foo = Foo() + registry = self._makeRegistry() + subr = self._makeSubregistry() + subr._adapters = [ #utilities, single adapters + {}, + {}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + alb.lookup = alb._uncached_lookup # provided by derived + subr._v_lookup = alb + _default = object() + result = alb.queryMultiAdapter((foo,), IBar, default=_default) + self.failUnless(result is _default) + + def test_queryMultiAdaptor_factory_miss(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + class Foo(object): + implements(IFoo) + foo = Foo() + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _expected = object() + _called_with = [] + def _factory(context): + _called_with.append(context) + return None + subr._adapters = [ #utilities, single adapters + {}, + {IFoo: {IBar: {'': _factory}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + alb.lookup = alb._uncached_lookup # provided by derived + subr._v_lookup = alb + _default = object() + result = alb.queryMultiAdapter((foo,), IBar, default=_default) + self.failUnless(result is _default) + self.assertEqual(_called_with, [foo]) + + def test_queryMultiAdaptor_factory_hit(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + class Foo(object): + implements(IFoo) + foo = Foo() + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _expected = object() + _called_with = [] + def _factory(context): + _called_with.append(context) + return _expected + subr._adapters = [ #utilities, single adapters + {}, + {IFoo: {IBar: {'': _factory}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + alb.lookup = alb._uncached_lookup # provided by derived + subr._v_lookup = alb + _default = object() + result = alb.queryMultiAdapter((foo,), IBar, default=_default) + self.failUnless(result is _expected) + self.assertEqual(_called_with, [foo]) + + def test__uncached_lookupAll_empty_ro(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + alb = self._makeOne(registry) + result = alb._uncached_lookupAll((IFoo,), IBar) + self.assertEqual(result, ()) + self.assertEqual(len(alb._required), 1) + self.failUnless(IFoo.weakref() in alb._required) + + def test__uncached_lookupAll_order_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_lookupAll((IFoo,), IBar) + self.assertEqual(result, ()) + + def test__uncached_lookupAll_extendors_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + subr = self._makeSubregistry() + subr._adapters = [{}, {}] #utilities, single adapters + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_lookupAll((IFoo,), IBar) + self.assertEqual(result, ()) + + def test__uncached_lookupAll_components_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + subr._adapters = [{}, {}] #utilities, single adapters + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_lookupAll((IFoo,), IBar) + self.assertEqual(result, ()) + + def test__uncached_lookupAll_simple_hit(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _expected = object() + _named = object() + subr._adapters = [ #utilities, single adapters + {}, + {IFoo: {IBar: {'': _expected, 'named': _named}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_lookupAll((IFoo,), IBar) + self.assertEqual(sorted(result), [('', _expected), ('named', _named)]) + + def test_names(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _expected = object() + _named = object() + subr._adapters = [ #utilities, single adapters + {}, + {IFoo: {IBar: {'': _expected, 'named': _named}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + alb.lookupAll = alb._uncached_lookupAll + subr._v_lookup = alb + result = alb.names((IFoo,), IBar) + self.assertEqual(sorted(result), ['', 'named']) + + def test__uncached_subscriptions_empty_ro(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + alb = self._makeOne(registry) + result = alb._uncached_subscriptions((IFoo,), IBar) + self.assertEqual(result, []) + self.assertEqual(len(alb._required), 1) + self.failUnless(IFoo.weakref() in alb._required) + + def test__uncached_subscriptions_order_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_subscriptions((IFoo,), IBar) + self.assertEqual(result, []) + + def test__uncached_subscriptions_extendors_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry() + subr = self._makeSubregistry() + subr._subscribers = [{}, {}] #utilities, single adapters + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_subscriptions((IFoo,), IBar) + self.assertEqual(result, []) + + def test__uncached_subscriptions_components_miss(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + subr._subscribers = [{}, {}] #utilities, single adapters + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_subscriptions((IFoo,), IBar) + self.assertEqual(result, []) + + def test__uncached_subscriptions_simple_hit(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _exp1, _exp2 = object(), object() + subr._subscribers = [ #utilities, single adapters + {}, + {IFoo: {IBar: {'': (_exp1, _exp2)}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + subr._v_lookup = alb + result = alb._uncached_subscriptions((IFoo,), IBar) + self.assertEqual(sorted(result), sorted([_exp1, _exp2])) + + def test_subscribers_wo_provided(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + class Foo(object): + implements(IFoo) + foo = Foo() + registry = self._makeRegistry(IFoo, IBar) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _called = {} + def _factory1(context): + _called.setdefault('_factory1', []).append(context) + def _factory2(context): + _called.setdefault('_factory2', []).append(context) + subr._subscribers = [ #utilities, single adapters + {}, + {IFoo: {None: {'': (_factory1, _factory2)}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + alb.subscriptions = alb._uncached_subscriptions + subr._v_lookup = alb + result = alb.subscribers((foo,), None) + self.assertEqual(result, ()) + self.assertEqual(_called, {'_factory1': [foo], '_factory2': [foo]}) + + def test_subscribers_w_provided(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', IFoo) + class Foo(object): + implements(IFoo) + foo = Foo() + registry = self._makeRegistry(IFoo, IBar) + registry = self._makeRegistry(IFoo, IBar) + subr = self._makeSubregistry() + _called = {} + _exp1, _exp2 = object(), object() + def _factory1(context): + _called.setdefault('_factory1', []).append(context) + return _exp1 + def _factory2(context): + _called.setdefault('_factory2', []).append(context) + return _exp2 + subr._subscribers = [ #utilities, single adapters + {}, + {IFoo: {IBar: {'': (_factory1, _factory2)}}}, + ] + registry.ro.append(subr) + alb = self._makeOne(registry) + alb.subscriptions = alb._uncached_subscriptions + subr._v_lookup = alb + result = alb.subscribers((foo,), IBar) + self.assertEqual(result, [_exp1, _exp2]) + self.assertEqual(_called, {'_factory1': [foo], '_factory2': [foo]}) + + +class AdapterRegistryTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.adapter import AdapterRegistry + return AdapterRegistry + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_ctor_no_bases(self): + ar = self._makeOne() + self.assertEqual(len(ar._v_subregistries), 0) + + def test_ctor_w_bases(self): + base = self._makeOne() + sub = self._makeOne([base]) + self.assertEqual(len(sub._v_subregistries), 0) + self.assertEqual(len(base._v_subregistries), 1) + self.failUnless(sub in base._v_subregistries) + + # test _addSubregistry / _removeSubregistry via only caller, _setBases + + def test__setBases_removing_existing_subregistry(self): + before = self._makeOne() + after = self._makeOne() + sub = self._makeOne([before]) + sub.__bases__ = [after] + self.assertEqual(len(before._v_subregistries), 0) + self.assertEqual(len(after._v_subregistries), 1) + self.failUnless(sub in after._v_subregistries) + + def test_changed_w_subregistries(self): + base = self._makeOne() + class Derived(object): + _changed = None + def changed(self, originally_changed): + self._changed = originally_changed + derived1, derived2 = Derived(), Derived() + base._addSubregistry(derived1) + base._addSubregistry(derived2) + orig = object() + base.changed(orig) + self.failUnless(derived1._changed is orig) + self.failUnless(derived2._changed is orig) + + +class Test_utils(unittest.TestCase): + + def test__convert_None_to_Interface_w_None(self): + from zope.interface.adapter import _convert_None_to_Interface + from zope.interface.interface import Interface + self.failUnless(_convert_None_to_Interface(None) is Interface) + + def test__convert_None_to_Interface_w_other(self): + from zope.interface.adapter import _convert_None_to_Interface + other = object() + self.failUnless(_convert_None_to_Interface(other) is other) + + def test__normalize_name_str(self): + from zope.interface.adapter import _normalize_name + STR = 'str' + self.assertEqual(_normalize_name(STR), unicode(STR)) + + def test__normalize_name_unicode(self): + from zope.interface.adapter import _normalize_name + USTR = u'ustr' + self.assertEqual(_normalize_name(USTR), USTR) + + def test__normalize_name_other(self): + from zope.interface.adapter import _normalize_name + for other in 1, 1.0, (), [], {}, object(): + self.assertRaises(TypeError, _normalize_name, other) + + # _lookup, _lookupAll, and _subscriptions tested via their callers + # (AdapterLookupBase.{lookup,lookupAll,subscriptions}). def test_suite(): return unittest.TestSuite(( - doctest.DocFileSuite('../adapter.txt', '../adapter.ru.txt', - '../human.txt', '../human.ru.txt', - 'foodforthought.txt', - globs={'__name__': '__main__'}), - doctest.DocTestSuite(), + unittest.makeSuite(BaseAdapterRegistryTests), + unittest.makeSuite(LookupBaseFallbackTests), + unittest.makeSuite(LookupBaseTests), + unittest.makeSuite(VerifyingBaseFallbackTests), + unittest.makeSuite(VerifyingBaseTests), + unittest.makeSuite(AdapterLookupBaseTests), + unittest.makeSuite(AdapterRegistryTests), + unittest.makeSuite(Test_utils), )) - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/zope/interface/tests/test_advice.py b/src/zope/interface/tests/test_advice.py index f21252e..b7e4dd0 100644 --- a/src/zope/interface/tests/test_advice.py +++ b/src/zope/interface/tests/test_advice.py @@ -1,4 +1,3 @@ - ############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. @@ -27,70 +26,71 @@ Visit the PEAK home page at http://peak.telecommunity.com for more information. """ import unittest -from unittest import TestCase, makeSuite, TestSuite -from zope.interface.advice import addClassAdvisor, determineMetaclass -from zope.interface.advice import getFrameInfo import sys -def ping(log, value): - - def pong(klass): - log.append((value,klass)) - return [klass] - - addClassAdvisor(pong) - -try: - from types import ClassType - - class ClassicClass: - __metaclass__ = ClassType - classLevelFrameInfo = getFrameInfo(sys._getframe()) -except ImportError: - pass - -class NewStyleClass: - __metaclass__ = type - classLevelFrameInfo = getFrameInfo(sys._getframe()) - -moduleLevelFrameInfo = getFrameInfo(sys._getframe()) - -class FrameInfoTest(TestCase): +class FrameInfoTest(unittest.TestCase): - classLevelFrameInfo = getFrameInfo(sys._getframe()) - - def checkModuleInfo(self): - kind, module, f_locals, f_globals = moduleLevelFrameInfo + def test_w_module(self): + from zope.interface.tests import advisory_testing + (kind, module, + f_locals, f_globals) = advisory_testing.moduleLevelFrameInfo self.assertEquals(kind, "module") for d in module.__dict__, f_locals, f_globals: - self.assert_(d is globals()) - - def checkClassicClassInfo(self): - kind, module, f_locals, f_globals = ClassicClass.classLevelFrameInfo + self.assert_(d is advisory_testing.my_globals) + + def test_w_ClassicClass(self): + from zope.interface.tests import advisory_testing + if advisory_testing.ClassicClass is None: + return + (kind, + module, + f_locals, + f_globals) = advisory_testing.ClassicClass.classLevelFrameInfo self.assertEquals(kind, "class") - self.assert_(f_locals is ClassicClass.__dict__) # ??? + self.assert_(f_locals is advisory_testing.ClassicClass.__dict__) # ??? for d in module.__dict__, f_globals: - self.assert_(d is globals()) - - def checkNewStyleClassInfo(self): - kind, module, f_locals, f_globals = NewStyleClass.classLevelFrameInfo + self.assert_(d is advisory_testing.my_globals) + + def test_w_NewStyleClass(self): + from zope.interface.tests import advisory_testing + (kind, + module, + f_locals, + f_globals) = advisory_testing.NewStyleClass.classLevelFrameInfo self.assertEquals(kind, "class") for d in module.__dict__, f_globals: - self.assert_(d is globals()) + self.assert_(d is advisory_testing.my_globals) - def checkCallInfo(self): + def test_inside_function_call(self): + from zope.interface.advice import getFrameInfo kind, module, f_locals, f_globals = getFrameInfo(sys._getframe()) self.assertEquals(kind, "function call") self.assert_(f_locals is locals()) # ??? for d in module.__dict__, f_globals: self.assert_(d is globals()) + def test_inside_exec(self): + from zope.interface.advice import getFrameInfo + _globals = {'getFrameInfo': getFrameInfo} + _locals = {} + exec _FUNKY_EXEC in _globals, _locals + self.assertEquals(_locals['kind'], "exec") + self.assert_(_locals['f_locals'] is _locals) + self.assert_(_locals['module'] is None) + self.assert_(_locals['f_globals'] is _globals) + -class AdviceTests(TestCase): +_FUNKY_EXEC = """\ +import sys +kind, module, f_locals, f_globals = getFrameInfo(sys._getframe()) +""" - def checkOrder(self): +class AdviceTests(unittest.TestCase): + + def test_order(self): + from zope.interface.tests.advisory_testing import ping log = [] class Foo(object): ping(log, 1) @@ -98,13 +98,14 @@ class AdviceTests(TestCase): ping(log, 3) # Strip the list nesting - for i in 1,2,3: + for i in 1, 2, 3: self.assert_(isinstance(Foo, list)) Foo, = Foo self.assertEquals(log, [(1, Foo), (2, [Foo]), (3, [[Foo]])]) - def TODOcheckOutside(self): + def TODOtest_outside(self): + from zope.interface.tests.advisory_testing import ping # Disabled because the check does not work with doctest tests. try: ping([], 1) @@ -115,71 +116,73 @@ class AdviceTests(TestCase): "Should have detected advice outside class body" ) - def checkDoubleType(self): - if sys.hexversion >= 0x02030000: - return # you can't duplicate bases in 2.3 - class aType(type,type): - ping([],1) - aType, = aType - self.assert_(aType.__class__ is type) + def test_single_explicit_meta(self): + from zope.interface.tests.advisory_testing import ping - def checkSingleExplicitMeta(self): - - class M(type): + class Metaclass(type): pass - class C(M): - __metaclass__ = M + class Concrete(Metaclass): + __metaclass__ = Metaclass ping([],1) - C, = C - self.assert_(C.__class__ is M) + Concrete, = Concrete + self.assert_(Concrete.__class__ is Metaclass) + + + def test_mixed_metas(self): + from zope.interface.tests.advisory_testing import ping + class Metaclass1(type): + pass - def checkMixedMetas(self): + class Metaclass2(type): + pass - class M1(type): pass - class M2(type): pass + class Base1: + __metaclass__ = Metaclass1 - class B1: __metaclass__ = M1 - class B2: __metaclass__ = M2 + class Base2: + __metaclass__ = Metaclass2 try: - class C(B1,B2): - ping([],1) + class Derived(Base1, Base2): + ping([], 1) + except TypeError: pass else: raise AssertionError("Should have gotten incompatibility error") - class M3(M1,M2): pass + class Metaclass3(Metaclass1, Metaclass2): + pass - class C(B1,B2): - __metaclass__ = M3 - ping([],1) + class Derived(Base1, Base2): + __metaclass__ = Metaclass3 + ping([], 1) - self.assert_(isinstance(C,list)) - C, = C - self.assert_(isinstance(C,M3)) + self.assert_(isinstance(Derived, list)) + Derived, = Derived + self.assert_(isinstance(Derived, Metaclass3)) - def checkMetaOfClass(self): + def test_meta_of_class(self): + from zope.interface.advice import determineMetaclass - class metameta(type): + class Metameta(type): pass - class meta(type): - __metaclass__ = metameta + class Meta(type): + __metaclass__ = Metameta - self.assertEquals(determineMetaclass((meta, type)), metameta) + self.assertEquals(determineMetaclass((Meta, type)), Metameta) -TestClasses = (AdviceTests, FrameInfoTest) def test_suite(): if sys.version[0] == '2': - return TestSuite([makeSuite(t,'check') for t in TestClasses]) + return unittest.TestSuite(( + unittest.makeSuite(FrameInfoTest), + unittest.makeSuite(AdviceTests), + )) else: # Advise metaclasses doesn't work in Python 3 return TestSuite([]) - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py index e6f2e14..5d111a6 100644 --- a/src/zope/interface/tests/test_declarations.py +++ b/src/zope/interface/tests/test_declarations.py @@ -13,422 +13,1464 @@ ############################################################################## """Test the new API for making and checking interface declarations """ -import doctest import unittest -from zope.interface import Interface, implements -from zope.interface import directlyProvides, providedBy -from zope.interface import classImplements, implementedBy, implementsOnly - -class I1(Interface): pass -class I2(Interface): pass -class I3(Interface): pass -class I4(Interface): pass -class I5(Interface): pass - -class A(object): - implements(I1) -class B(object): - implements(I2) -class C(A, B): - implements(I3) - -class COnly(A, B): - implementsOnly(I3) - -class COnly_old(A, B): - __implemented__ = I3 - -class D(COnly): - implements(I5) - -def test_ObjectSpecification_Simple(): - """ - >>> c = C() - >>> directlyProvides(c, I4) - >>> [i.__name__ for i in providedBy(c)] - ['I4', 'I3', 'I1', 'I2'] - """ - -def test_ObjectSpecification_Simple_w_only(): - """ - >>> c = COnly() - >>> directlyProvides(c, I4) - >>> [i.__name__ for i in providedBy(c)] - ['I4', 'I3'] - """ - -def test_ObjectSpecification_Simple_old_style(): - """ - >>> c = COnly_old() - >>> directlyProvides(c, I4) - >>> [i.__name__ for i in providedBy(c)] - ['I4', 'I3'] - """ - - -class Test(unittest.TestCase): - - # Note that most of the tests are in the doc strings of the - # declarations module. - - def failUnless(self, expr): # silence deprecation warnings under py3 - return self.assertTrue(expr) - - def failIf(self, expr): # silence deprecation warnings under py3 - return self.assertFalse(expr) - - def test_backward_compat(self): - - class C1(object): __implemented__ = I1 - class C2(C1): __implemented__ = I2, I5 - class C3(C2): __implemented__ = I3, C2.__implemented__ - - self.failUnless(C3.__implemented__.__class__ is tuple) - - self.assertEqual( - [i.getName() for i in providedBy(C3())], - ['I3', 'I2', 'I5'], - ) - - class C4(C3): - implements(I4) - - self.assertEqual( - [i.getName() for i in providedBy(C4())], - ['I4', 'I3', 'I2', 'I5'], - ) - - self.assertEqual( - [i.getName() for i in C4.__implemented__], - ['I4', 'I3', 'I2', 'I5'], - ) - - # Note that C3.__implemented__ should now be a sequence of interfaces - self.assertEqual( - [i.getName() for i in C3.__implemented__], - ['I3', 'I2', 'I5'], - ) - self.failIf(C3.__implemented__.__class__ is tuple) - - def test_module(self): - from zope.interface.tests import m1, m2 - #import zope.interface.tests.m2 - directlyProvides(m2, - m1.I1, - m1.I2, - ) - self.assertEqual(list(providedBy(m1)), - list(providedBy(m2)), - ) - - def test_builtins(self): - # Setup - - intspec = implementedBy(int) - olddeclared = intspec.declared - - classImplements(int, I1) - class myint(int): - implements(I2) - - x = 42 - self.assertEqual([i.getName() for i in providedBy(x)], - ['I1']) - - x = myint(42) - directlyProvides(x, I3) - self.assertEqual([i.getName() for i in providedBy(x)], - ['I3', 'I2', 'I1']) - - # cleanup - intspec.declared = olddeclared - classImplements(int) - - x = 42 - self.assertEqual([i.getName() for i in providedBy(x)], - []) - - -def test_signature_w_no_class_interfaces(): - """ - >>> from zope.interface import * - >>> class C(object): - ... pass - >>> c = C() - >>> list(providedBy(c)) - [] - - >>> class I(Interface): - ... pass - >>> directlyProvides(c, I) - >>> list(providedBy(c)) == list(directlyProvidedBy(c)) - 1 - """ - -def test_classImplement_on_deeply_nested_classes(): - """This test is in response to a bug found, which is why it's a bit - contrived - - >>> from zope.interface import * - >>> class B1(object): - ... pass - >>> class B2(B1): - ... pass - >>> class B3(B2): - ... pass - >>> class D(object): - ... implements() - >>> class S(B3, D): - ... implements() - - This failed due to a bug in the code for finding __providedBy__ - descriptors for old-style classes. - - """ - -def test_pickle_provides_specs(): - """ - >>> from pickle import dumps, loads - >>> a = A() - >>> I2.providedBy(a) - 0 - >>> directlyProvides(a, I2) - >>> I2.providedBy(a) - 1 - >>> a2 = loads(dumps(a)) - >>> I2.providedBy(a2) - 1 - - """ - -def test_that_we_dont_inherit_class_provides(): - """ - >>> from zope.interface import classProvides - >>> class X(object): - ... classProvides(I1) - >>> class Y(X): - ... pass - >>> [i.__name__ for i in X.__provides__] - ['I1'] - >>> Y.__provides__ - Traceback (most recent call last): - ... - AttributeError: __provides__ - - """ - -def test_that_we_dont_inherit_provides_optimizations(): - """ - - When we make a declaration for a class, we install a __provides__ - descriptors that provides a default for instances that don't have - instance-specific declarations: - - >>> class A(object): - ... implements(I1) - - >>> class B(object): - ... implements(I2) - - >>> [i.__name__ for i in A().__provides__] - ['I1'] - >>> [i.__name__ for i in B().__provides__] - ['I2'] - - But it's important that we don't use this for subclasses without - declarations. This would cause incorrect results: - - >>> class X(A, B): - ... pass - - >>> X().__provides__ - Traceback (most recent call last): - ... - AttributeError: __provides__ - - However, if we "induce" a declaration, by calling implementedBy - (even indirectly through providedBy): - - >>> [i.__name__ for i in providedBy(X())] - ['I1', 'I2'] - - - then the optimization will work: - - >>> [i.__name__ for i in X().__provides__] - ['I1', 'I2'] - - """ - -def test_classProvides_before_implements(): - """Special descriptor for class __provides__ - - The descriptor caches the implementedBy info, so that - we can get declarations for objects without instance-specific - interfaces a bit quicker. - - For example:: - - >>> from zope.interface import Interface, classProvides - >>> class IFooFactory(Interface): - ... pass - >>> class IFoo(Interface): - ... pass - >>> class C(object): - ... classProvides(IFooFactory) - ... implements(IFoo) - >>> [i.getName() for i in C.__provides__] - ['IFooFactory'] - - >>> [i.getName() for i in C().__provides__] - ['IFoo'] - """ - -def test_getting_spec_for_proxied_builtin_class(): - """ - - In general, we should be able to get a spec - for a proxied class if someone has declared or - asked for a spec before. - - We don't want to depend on proxies in this (zope.interface) - package, but we do want to work with proxies. Proxies have the - effect that a class's __dict__ cannot be gotten. Further, for - built-in classes, we can't save, and thus, cannot get, any class - attributes. We'll emulate this by treating a plain object as a class: - - >>> cls = object() - - We'll create an implements specification: - - >>> import zope.interface.declarations - >>> impl = zope.interface.declarations.Implements(I1, I2) - - Now, we'll emulate a declaration for a built-in type by putting - it in BuiltinImplementationSpecifications: - - >>> zope.interface.declarations.BuiltinImplementationSpecifications[ - ... cls] = impl - - Now, we should be able to get it back: - - >>> implementedBy(cls) is impl - True - - Of course, we don't want to leave it there. :) - - >>> del zope.interface.declarations.BuiltinImplementationSpecifications[ - ... cls] - - """ -def test_declaration_get(): - """ - We can get definitions from a declaration: +class _SilencePy3Deprecations(unittest.TestCase): + # silence deprecation warnings under py3 - >>> import zope.interface - >>> class I1(zope.interface.Interface): - ... a11 = zope.interface.Attribute('a11') - ... a12 = zope.interface.Attribute('a12') - >>> class I2(zope.interface.Interface): - ... a21 = zope.interface.Attribute('a21') - ... a22 = zope.interface.Attribute('a22') - ... a12 = zope.interface.Attribute('a212') - >>> class I11(I1): - ... a11 = zope.interface.Attribute('a111') - - >>> decl = zope.interface.Declaration(I11, I2) - >>> decl.get('a11') is I11.get('a11') - True - >>> decl.get('a12') is I1.get('a12') - True - >>> decl.get('a21') is I2.get('a21') - True - >>> decl.get('a22') is I2.get('a22') - True - >>> decl.get('a') - >>> decl.get('a', 42) - 42 - - We get None even with no interfaces: - - >>> decl = zope.interface.Declaration() - >>> decl.get('a11') - >>> decl.get('a11', 42) - 42 - - We get new data if e change interface bases: - - >>> decl.__bases__ = I11, I2 - >>> decl.get('a11') is I11.get('a11') - True - """ - -def test_classImplements_after_classImplementsOnly_issue_402(): - """http://www.zope.org/Collectors/Zope3-dev/402 - ->>> from zope.interface import * ->>> class I1(Interface): -... pass ->>> class I2(Interface): -... pass ->>> class C: -... implements(I1) ->>> class C2: -... implementsOnly(I2) ->>> class I3(Interface): -... pass - ->>> [i.__name__ for i in providedBy(C2()).__iro__] -['I2', 'Interface'] - ->>> classImplements(C2, I3) ->>> [i.__name__ for i in providedBy(C2()).__iro__] -['I2', 'I3', 'Interface'] - ->>> class I4(Interface): -... pass ->>> classImplements(C2, I4) ->>> [i.__name__ for i in providedBy(C2()).__iro__] -['I2', 'I3', 'I4', 'Interface'] - - -""" - -def test_picklability_of_implements_specifications(): - """ - - Sometimes, we need to pickle implements specs. We should be able - to do so as long as the class is picklable. - - >>> import pickle - >>> pickle.loads(pickle.dumps(implementedBy(C))) is implementedBy(C) - True - - - """ - -def test_provided_by_with_slots(): - """ - - This is an edge case: if the __slots__ of a class contain '__provides__', - using providedBy() on that class should still work (this occurs, for - example, when providing an adapter for a concrete class.) + def failUnless(self, expr): + # St00pid speling. + return self.assertTrue(expr) - >>> import zope.interface - >>> class Slotted(object): - ... __slots__ = ('__provides__') - >>> class IFoo(zope.interface.Interface): - ... pass - >>> IFoo.providedBy(Slotted) - False + def failIf(self, expr): + # St00pid speling. + return self.assertFalse(expr) + + +class DeclarationTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import Declaration + return Declaration + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_ctor_no_bases(self): + decl = self._makeOne() + self.assertEqual(list(decl.__bases__), []) + + def test_ctor_w_interface_in_bases(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decl = self._makeOne(IFoo) + self.assertEqual(list(decl.__bases__), [IFoo]) + + def test_ctor_w_implements_in_bases(self): + from zope.interface.declarations import Implements + impl = Implements() + decl = self._makeOne(impl) + self.assertEqual(list(decl.__bases__), [impl]) + + def test_changed_wo_existing__v_attrs(self): + decl = self._makeOne() + decl.changed(decl) # doesn't raise + self.failIf('_v_attrs' in decl.__dict__) + + def test_changed_w_existing__v_attrs(self): + decl = self._makeOne() + decl._v_attrs = object() + decl.changed(decl) + self.failIf('_v_attrs' in decl.__dict__) + + def test___contains__w_self(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decl = self._makeOne() + self.failIf(decl in decl) + + def test___contains__w_unrelated_iface(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decl = self._makeOne() + self.failIf(IFoo in decl) + + def test___contains__w_base_interface(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decl = self._makeOne(IFoo) + self.failUnless(IFoo in decl) + + def test___iter___empty(self): + decl = self._makeOne() + self.assertEqual(list(decl), []) + + def test___iter___single_base(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decl = self._makeOne(IFoo) + self.assertEqual(list(decl), [IFoo]) + + def test___iter___multiple_bases(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + decl = self._makeOne(IFoo, IBar) + self.assertEqual(list(decl), [IFoo, IBar]) + + def test___iter___inheritance(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', (IFoo,)) + decl = self._makeOne(IBar) + self.assertEqual(list(decl), [IBar]) #IBar.interfaces() omits bases + + def test___iter___w_nested_sequence_overlap(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + decl = self._makeOne(IBar, (IFoo, IBar)) + self.assertEqual(list(decl), [IBar, IFoo]) + + def test_flattened_empty(self): + from zope.interface.interface import Interface + decl = self._makeOne() + self.assertEqual(list(decl.flattened()), [Interface]) + + def test_flattened_single_base(self): + from zope.interface.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decl = self._makeOne(IFoo) + self.assertEqual(list(decl.flattened()), [IFoo, Interface]) + + def test_flattened_multiple_bases(self): + from zope.interface.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + decl = self._makeOne(IFoo, IBar) + self.assertEqual(list(decl.flattened()), [IFoo, IBar, Interface]) + + def test_flattened_inheritance(self): + from zope.interface.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', (IFoo,)) + decl = self._makeOne(IBar) + self.assertEqual(list(decl.flattened()), [IBar, IFoo, Interface]) + + def test_flattened_w_nested_sequence_overlap(self): + from zope.interface.interface import Interface + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + decl = self._makeOne(IBar, (IFoo, IBar)) + # Note that decl.__iro__ has IFoo first. + self.assertEqual(list(decl.flattened()), [IFoo, IBar, Interface]) + + def test___sub___unrelated_interface(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + before = self._makeOne(IFoo) + after = before - IBar + self.failUnless(isinstance(after, self._getTargetClass())) + self.assertEqual(list(after), [IFoo]) + + def test___sub___related_interface(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + before = self._makeOne(IFoo) + after = before - IFoo + self.assertEqual(list(after), []) + + def test___sub___related_interface_by_inheritance(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar', (IFoo,)) + before = self._makeOne(IBar) + after = before - IBar + self.assertEqual(list(after), []) + + def test___add___unrelated_interface(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + before = self._makeOne(IFoo) + after = before + IBar + self.failUnless(isinstance(after, self._getTargetClass())) + self.assertEqual(list(after), [IFoo, IBar]) + + def test___add___related_interface(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + IBaz = InterfaceClass('IBaz') + before = self._makeOne(IFoo, IBar) + other = self._makeOne(IBar, IBaz) + after = before + other + self.assertEqual(list(after), [IFoo, IBar, IBaz]) + + +class ImplementsTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import Implements + return Implements + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_ctor_no_bases(self): + impl = self._makeOne() + self.assertEqual(impl.inherit, None) + self.assertEqual(impl.declared, ()) + self.assertEqual(impl.__name__, '?') + self.assertEqual(list(impl.__bases__), []) + + def test___repr__(self): + impl = self._makeOne() + impl.__name__ = 'Testing' + self.assertEqual(repr(impl), '<implementedBy Testing>') + + def test___reduce__(self): + from zope.interface.declarations import implementedBy + impl = self._makeOne() + self.assertEqual(impl.__reduce__(), (implementedBy, (None,))) + + +class Test_implementedByFallback(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import implementedByFallback + return implementedByFallback(*args, **kw) + + def test_dictless_wo_existing_Implements_wo_registrations(self): + class Foo(object): + __slots__ = ('__implemented__',) + foo = Foo() + foo.__implemented__ = None + self.assertEqual(list(self._callFUT(foo)), []) + + def test_dictless_wo_existing_Implements_cant_assign___implemented__(self): + class Foo(object): + def _get_impl(self): return None + def _set_impl(self, val): raise TypeError + __implemented__ = property(_get_impl, _set_impl) + def __call__(self): pass #act like a factory + foo = Foo() + self.assertRaises(TypeError, self._callFUT, foo) + + def test_dictless_wo_existing_Implements_w_registrations(self): + from zope.interface import declarations + class Foo(object): + __slots__ = ('__implemented__',) + foo = Foo() + foo.__implemented__ = None + reg = object() + specs = {foo: reg} + with _Monkey(declarations, BuiltinImplementationSpecifications=specs): + self.failUnless(self._callFUT(foo) is reg) + + def test_dictless_w_existing_Implements(self): + from zope.interface.declarations import Implements + impl = Implements() + class Foo(object): + __slots__ = ('__implemented__',) + foo = Foo() + foo.__implemented__ = impl + self.failUnless(self._callFUT(foo) is impl) + + def test_dictless_w_existing_not_Implements(self): + from zope.interface.interface import InterfaceClass + class Foo(object): + __slots__ = ('__implemented__',) + foo = Foo() + IFoo = InterfaceClass('IFoo') + foo.__implemented__ = (IFoo,) + self.assertEqual(list(self._callFUT(foo)), [IFoo]) + + def test_w_existing_attr_as_Implements(self): + from zope.interface.declarations import Implements + impl = Implements() + class Foo(object): + __implemented__ = impl + self.failUnless(self._callFUT(Foo) is impl) + + def test_builtins_added_to_cache(self): + from zope.interface import declarations + from zope.interface.declarations import Implements + specs = {} + with _Monkey(declarations, BuiltinImplementationSpecifications=specs): + self.assertEqual(list(self._callFUT(tuple)), []) + self.assertEqual(list(self._callFUT(list)), []) + self.assertEqual(list(self._callFUT(dict)), []) + for typ in (tuple, list, dict): + spec = specs[typ] + self.failUnless(isinstance(spec, Implements)) + self.assertEqual(repr(spec), + '<implementedBy __builtin__.%s>' % typ.__name__) + + def test_builtins_w_existing_cache(self): + from zope.interface import declarations + t_spec, l_spec, d_spec = object(), object(), object() + specs = {tuple: t_spec, list: l_spec, dict: d_spec} + with _Monkey(declarations, BuiltinImplementationSpecifications=specs): + self.failUnless(self._callFUT(tuple) is t_spec) + self.failUnless(self._callFUT(list) is l_spec) + self.failUnless(self._callFUT(dict) is d_spec) + + def test_oldstyle_class_no_assertions(self): + # TODO: Figure out P3 story + class Foo: + pass + self.assertEqual(list(self._callFUT(Foo)), []) + + def test_no_assertions(self): + # TODO: Figure out P3 story + class Foo(object): + pass + self.assertEqual(list(self._callFUT(Foo)), []) + + def test_w_None_no_bases_not_factory(self): + class Foo(object): + __implemented__ = None + foo = Foo() + self.assertRaises(TypeError, self._callFUT, foo) + + def test_w_None_no_bases_w_factory(self): + from zope.interface.declarations import objectSpecificationDescriptor + class Foo(object): + __implemented__ = None + def __call__(self): + pass + foo = Foo() + foo.__name__ = 'foo' + spec = self._callFUT(foo) + self.assertEqual(spec.__name__, + 'zope.interface.tests.test_declarations.foo') + self.failUnless(spec.inherit is foo) + self.failUnless(foo.__implemented__ is spec) + self.failUnless(foo.__providedBy__ is objectSpecificationDescriptor) + self.failIf('__provides__' in foo.__dict__) + + def test_w_None_no_bases_w_class(self): + from zope.interface.declarations import ClassProvides + class Foo(object): + __implemented__ = None + spec = self._callFUT(Foo) + self.assertEqual(spec.__name__, + 'zope.interface.tests.test_declarations.Foo') + self.failUnless(spec.inherit is Foo) + self.failUnless(Foo.__implemented__ is spec) + self.failUnless(isinstance(Foo.__providedBy__, ClassProvides)) + self.failUnless(isinstance(Foo.__provides__, ClassProvides)) + self.assertEqual(Foo.__provides__, Foo.__providedBy__) + + def test_w_existing_Implements(self): + from zope.interface.declarations import Implements + impl = Implements() + class Foo(object): + __implemented__ = impl + self.failUnless(self._callFUT(Foo) is impl) + + +class Test_implementedBy(Test_implementedByFallback): + # Repeat tests for C optimizations + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import implementedBy + return implementedBy(*args, **kw) + + +class Test_classImplementsOnly(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import classImplementsOnly + return classImplementsOnly(*args, **kw) + + def test_no_existing(self): + from zope.interface.declarations import ClassProvides + from zope.interface.interface import InterfaceClass + class Foo(object): + pass + ifoo = InterfaceClass('IFoo') + self._callFUT(Foo, ifoo) + spec = Foo.__implemented__ + self.assertEqual(spec.__name__, + 'zope.interface.tests.test_declarations.Foo') + self.failUnless(spec.inherit is None) + self.failUnless(Foo.__implemented__ is spec) + self.failUnless(isinstance(Foo.__providedBy__, ClassProvides)) + self.failUnless(isinstance(Foo.__provides__, ClassProvides)) + self.assertEqual(Foo.__provides__, Foo.__providedBy__) + + def test_w_existing_Implements(self): + from zope.interface.declarations import Implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + impl = Implements(IFoo) + impl.declared = (IFoo,) + class Foo(object): + __implemented__ = impl + impl.inherit = Foo + self._callFUT(Foo, IBar) + # Same spec, now different values + self.failUnless(Foo.__implemented__ is impl) + self.assertEqual(impl.inherit, None) + self.assertEqual(impl.declared, (IBar,)) + + +class Test_classImplements(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import classImplements + return classImplements(*args, **kw) + + def test_no_existing(self): + from zope.interface.declarations import ClassProvides + from zope.interface.interface import InterfaceClass + class Foo(object): + pass + IFoo = InterfaceClass('IFoo') + self._callFUT(Foo, IFoo) + spec = Foo.__implemented__ + self.assertEqual(spec.__name__, + 'zope.interface.tests.test_declarations.Foo') + self.failUnless(spec.inherit is Foo) + self.failUnless(Foo.__implemented__ is spec) + self.failUnless(isinstance(Foo.__providedBy__, ClassProvides)) + self.failUnless(isinstance(Foo.__provides__, ClassProvides)) + self.assertEqual(Foo.__provides__, Foo.__providedBy__) + + def test_w_existing_Implements(self): + from zope.interface.declarations import Implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + impl = Implements(IFoo) + impl.declared = (IFoo,) + class Foo(object): + __implemented__ = impl + impl.inherit = Foo + self._callFUT(Foo, IBar) + # Same spec, now different values + self.failUnless(Foo.__implemented__ is impl) + self.assertEqual(impl.inherit, Foo) + self.assertEqual(impl.declared, (IFoo, IBar,)) + + def test_w_existing_Implements_w_bases(self): + from zope.interface.declarations import Implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + IBaz = InterfaceClass('IBar') + b_impl = Implements(IBaz) + impl = Implements(IFoo) + impl.declared = (IFoo,) + class Base(object): + __implemented__ = b_impl + class Foo(Base): + __implemented__ = impl + impl.inherit = Foo + self._callFUT(Foo, IBar) + # Same spec, now different values + self.failUnless(Foo.__implemented__ is impl) + self.assertEqual(impl.inherit, Foo) + self.assertEqual(impl.declared, (IFoo, IBar,)) + self.assertEqual(impl.__bases__, (IFoo, IBar, b_impl)) + + +class Test__implements_advice(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import _implements_advice + return _implements_advice(*args, **kw) + + def test_no_existing_implements(self): + from zope.interface.declarations import classImplements + from zope.interface.declarations import Implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + class Foo(object): + __implements_advice_data__ = ((IFoo,), classImplements) + self._callFUT(Foo) + self.failIf('__implements_advice_data__' in Foo.__dict__) + self.failUnless(isinstance(Foo.__implemented__, Implements)) + self.assertEqual(list(Foo.__implemented__), [IFoo]) + + +class Test_implementer(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import implementer + return implementer + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_oldstyle_class(self): + # TODO Py3 story + from zope.interface.declarations import ClassProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + class Foo: + pass + decorator = self._makeOne(IFoo) + returned = decorator(Foo) + self.failUnless(returned is Foo) + spec = Foo.__implemented__ + self.assertEqual(spec.__name__, + 'zope.interface.tests.test_declarations.Foo') + self.failUnless(spec.inherit is Foo) + self.failUnless(Foo.__implemented__ is spec) + self.failUnless(isinstance(Foo.__providedBy__, ClassProvides)) + self.failUnless(isinstance(Foo.__provides__, ClassProvides)) + self.assertEqual(Foo.__provides__, Foo.__providedBy__) + + def test_newstyle_class(self): + from zope.interface.declarations import ClassProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + class Foo(object): + pass + decorator = self._makeOne(IFoo) + returned = decorator(Foo) + self.failUnless(returned is Foo) + spec = Foo.__implemented__ + self.assertEqual(spec.__name__, + 'zope.interface.tests.test_declarations.Foo') + self.failUnless(spec.inherit is Foo) + self.failUnless(Foo.__implemented__ is spec) + self.failUnless(isinstance(Foo.__providedBy__, ClassProvides)) + self.failUnless(isinstance(Foo.__provides__, ClassProvides)) + self.assertEqual(Foo.__provides__, Foo.__providedBy__) + + def test_nonclass_cannot_assign_attr(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decorator = self._makeOne(IFoo) + self.assertRaises(TypeError, decorator, object()) + + def test_nonclass_can_assign_attr(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + class Foo(object): + pass + foo = Foo() + decorator = self._makeOne(IFoo) + returned = decorator(foo) + self.failUnless(returned is foo) + spec = foo.__implemented__ + self.assertEqual(spec.__name__, '?') + self.failUnless(spec.inherit is None) + self.failUnless(foo.__implemented__ is spec) + + +class Test_implementer_only(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import implementer_only + return implementer_only + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_function(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decorator = self._makeOne(IFoo) + def _function(): pass + self.assertRaises(ValueError, decorator, _function) + + def test_method(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + decorator = self._makeOne(IFoo) + class Bar: + def _method(): pass + self.assertRaises(ValueError, decorator, Bar._method) + + def test_oldstyle_class(self): + # TODO Py3 story + from zope.interface.declarations import Implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + old_spec = Implements(IBar) + class Foo: + __implemented__ = old_spec + decorator = self._makeOne(IFoo) + returned = decorator(Foo) + self.failUnless(returned is Foo) + spec = Foo.__implemented__ + self.assertEqual(spec.__name__, '?') + self.failUnless(spec.inherit is None) + self.failUnless(Foo.__implemented__ is spec) + + def test_newstyle_class(self): + from zope.interface.declarations import Implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') + IBar = InterfaceClass('IBar') + old_spec = Implements(IBar) + class Foo(object): + __implemented__ = old_spec + decorator = self._makeOne(IFoo) + returned = decorator(Foo) + self.failUnless(returned is Foo) + spec = Foo.__implemented__ + self.assertEqual(spec.__name__, '?') + self.failUnless(spec.inherit is None) + self.failUnless(Foo.__implemented__ is spec) + + +# Test '_implements' by way of 'implements{,Only}', its only callers. + +class Test_implementsOnly(_SilencePy3Deprecations): + + def _getFUT(self): + from zope.interface.declarations import implementsOnly + return implementsOnly + + def test_called_once_from_class_w_bases(self): + from zope.interface.declarations import implements + from zope.interface.declarations import implementsOnly + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + globs = {'implements': implements, + 'implementsOnly': implementsOnly, + 'IFoo': IFoo, + 'IBar': IBar, + } + locs = {} + CODE = "\n".join([ + 'class Foo(object):', + ' implements(IFoo)', + 'class Bar(Foo):' + ' implementsOnly(IBar)', + ]) + # XXX need six-ish majyk here :( + exec CODE in globs, locs + Bar = locs['Bar'] + spec = Bar.__implemented__ + self.assertEqual(list(spec), [IBar]) + +class Test_implements(_SilencePy3Deprecations): + + def _getFUT(self): + from zope.interface.declarations import implements + return implements + + def test_called_from_function(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'implements': implements, 'IFoo': IFoo} + locs = {} + CODE = "\n".join([ + 'def foo():', + ' implements(IFoo)' + ]) + # XXX need six-ish majyk here :( + exec CODE in globs, locs + foo = locs['foo'] + self.assertRaises(TypeError, foo) + + def test_called_twice_from_class(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + globs = {'implements': implements, 'IFoo': IFoo, 'IBar': IBar} + locs = {} + CODE = "\n".join([ + 'class Foo(object):', + ' implements(IFoo)', + ' implements(IBar)', + ]) + # XXX need six-ish majyk here :( + try: + exec CODE in globs, locs + except TypeError: + pass + else: + self.fail("Didn't raise TypeError") + + def test_called_once_from_class(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'implements': implements, 'IFoo': IFoo} + locs = {} + CODE = "\n".join([ + 'class Foo(object):', + ' implements(IFoo)', + ]) + # XXX need six-ish majyk here :( + exec CODE in globs, locs + Foo = locs['Foo'] + spec = Foo.__implemented__ + self.assertEqual(list(spec), [IFoo]) + + +class ProvidesClassTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import ProvidesClass + return ProvidesClass + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_simple_class_one_interface(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + spec = self._makeOne(Foo, IFoo) + self.assertEqual(list(spec), [IFoo]) + + def test___reduce__(self): + from zope.interface.declarations import Provides # the function + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + spec = self._makeOne(Foo, IFoo) + klass, args = spec.__reduce__() + self.failUnless(klass is Provides) + self.assertEqual(args, (Foo, IFoo)) + + def test___get___class(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + spec = self._makeOne(Foo, IFoo) + Foo.__provides__ = spec + self.failUnless(Foo.__provides__ is spec) + + def test___get___instance(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + spec = self._makeOne(Foo, IFoo) + Foo.__provides__ = spec + def _test(): + foo = Foo() + return foo.__provides__ + self.assertRaises(AttributeError, _test) + + +class Test_Provides(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import Provides + return Provides(*args, **kw) + + def test_no_cached_spec(self): + from zope.interface import declarations + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + cache = {} + class Foo(object): + pass + with _Monkey(declarations, InstanceDeclarations=cache): + spec = self._callFUT(Foo, IFoo) + self.assertEqual(list(spec), [IFoo]) + self.failUnless(cache[(Foo, IFoo)] is spec) + + def test_w_cached_spec(self): + from zope.interface import declarations + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + prior = object() + class Foo(object): + pass + cache = {(Foo, IFoo): prior} + with _Monkey(declarations, InstanceDeclarations=cache): + spec = self._callFUT(Foo, IFoo) + self.failUnless(spec is prior) + + +class Test_directlyProvides(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import directlyProvides + return directlyProvides(*args, **kw) + + def test_w_normal_object(self): + from zope.interface.declarations import ProvidesClass + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + obj = Foo() + self._callFUT(obj, IFoo) + self.failUnless(isinstance(obj.__provides__, ProvidesClass)) + self.assertEqual(list(obj.__provides__), [IFoo]) + + def test_w_class(self): + from zope.interface.declarations import ClassProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + self._callFUT(Foo, IFoo) + self.failUnless(isinstance(Foo.__provides__, ClassProvides)) + self.assertEqual(list(Foo.__provides__), [IFoo]) + + def test_w_non_descriptor_aware_metaclass(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class MetaClass(type): + def __getattribute__(self, name): + # Emulate metaclass whose base is not the type object. + if name == '__class__': + return self + return type.__getattribute__(self, name) + class Foo(object): + __metaclass__ = MetaClass + obj = Foo() + self.assertRaises(TypeError, self._callFUT, obj, IFoo) + + def test_w_classless_object(self): + from zope.interface.declarations import ProvidesClass + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + the_dict = {} + class Foo(object): + def __getattribute__(self, name): + # Emulate object w/o any class + if name == '__class__': + return None + try: + return the_dict[name] + except KeyError: + raise AttributeError(name) + def __setattr__(self, name, value): + the_dict[name] = value + obj = Foo() + self._callFUT(obj, IFoo) + self.failUnless(isinstance(the_dict['__provides__'], ProvidesClass)) + self.assertEqual(list(the_dict['__provides__']), [IFoo]) + + +class Test_alsoProvides(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import alsoProvides + return alsoProvides(*args, **kw) + + def test_wo_existing_provides(self): + from zope.interface.declarations import ProvidesClass + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + obj = Foo() + self._callFUT(obj, IFoo) + self.failUnless(isinstance(obj.__provides__, ProvidesClass)) + self.assertEqual(list(obj.__provides__), [IFoo]) + + def test_w_existing_provides(self): + from zope.interface.declarations import directlyProvides + from zope.interface.declarations import ProvidesClass + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + class Foo(object): + pass + obj = Foo() + directlyProvides(obj, IFoo) + self._callFUT(obj, IBar) + self.failUnless(isinstance(obj.__provides__, ProvidesClass)) + self.assertEqual(list(obj.__provides__), [IFoo, IBar]) + + +class Test_noLongerProvides(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import noLongerProvides + return noLongerProvides(*args, **kw) + + def test_wo_existing_provides(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + obj = Foo() + self._callFUT(obj, IFoo) + self.assertEqual(list(obj.__provides__), []) + + def test_w_existing_provides_hit(self): + from zope.interface.declarations import directlyProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + obj = Foo() + directlyProvides(obj, IFoo) + self._callFUT(obj, IFoo) + self.assertEqual(list(obj.__provides__), []) + + def test_w_existing_provides_miss(self): + from zope.interface.declarations import directlyProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + class Foo(object): + pass + obj = Foo() + directlyProvides(obj, IFoo) + self._callFUT(obj, IBar) + self.assertEqual(list(obj.__provides__), [IFoo]) + + def test_w_iface_implemented_by_class(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + implements(IFoo) + obj = Foo() + self.assertRaises(ValueError, self._callFUT, obj, IFoo) + + +class ClassProvidesBaseFallbackTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import ClassProvidesBaseFallback + return ClassProvidesBaseFallback + + def _makeOne(self, klass, implements): + # Don't instantiate directly: the C version can't have attributes + # assigned. + class Derived(self._getTargetClass()): + def __init__(self, k, i): + self._cls = k + self._implements = i + return Derived(klass, implements) + + def test_w_same_class_via_class(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + cpbp = Foo.__provides__ = self._makeOne(Foo, IFoo) + self.failUnless(Foo.__provides__ is cpbp) + + def test_w_same_class_via_instance(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + foo = Foo() + cpbp = Foo.__provides__ = self._makeOne(Foo, IFoo) + self.failUnless(foo.__provides__ is IFoo) + + def test_w_different_class(self): + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + class Bar(Foo): + pass + bar = Bar() + cpbp = Foo.__provides__ = self._makeOne(Foo, IFoo) + self.assertRaises(AttributeError, getattr, Bar, '__provides__') + self.assertRaises(AttributeError, getattr, bar, '__provides__') + + +class ClassProvidesBaseTests(ClassProvidesBaseFallbackTests): + # Repeat tests for C optimizations + + def _getTargetClass(self): + from zope.interface.declarations import ClassProvidesBase + return ClassProvidesBase + + +class ClassProvidesTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import ClassProvides + return ClassProvides + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_w_simple_metaclass(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + class Foo(object): + implements(IFoo) + cp = Foo.__provides__ = self._makeOne(Foo, type(Foo), IBar) + self.failUnless(Foo.__provides__ is cp) + self.assertEqual(list(Foo().__provides__), [IFoo]) + + def test___reduce__(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + class Foo(object): + implements(IFoo) + cp = Foo.__provides__ = self._makeOne(Foo, type(Foo), IBar) + self.assertEqual(cp.__reduce__(), + (self._getTargetClass(), (Foo, type(Foo), IBar))) + + +class Test_directlyProvidedBy(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import directlyProvidedBy + return directlyProvidedBy(*args, **kw) + + def test_wo_declarations_in_class_or_instance(self): + class Foo(object): + pass + foo = Foo() + self.assertEqual(list(self._callFUT(foo)), []) + + def test_w_declarations_in_class_but_not_instance(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + implements(IFoo) + foo = Foo() + self.assertEqual(list(self._callFUT(foo)), []) + + def test_w_declarations_in_instance_but_not_class(self): + from zope.interface.declarations import directlyProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + foo = Foo() + directlyProvides(foo, IFoo) + self.assertEqual(list(self._callFUT(foo)), [IFoo]) + + def test_w_declarations_in_instance_and_class(self): + from zope.interface.declarations import directlyProvides + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + class Foo(object): + implements(IFoo) + foo = Foo() + directlyProvides(foo, IBar) + self.assertEqual(list(self._callFUT(foo)), [IBar]) + + +class Test_classProvides(_SilencePy3Deprecations): + + def _getFUT(self): + from zope.interface.declarations import classProvides + return classProvides + + def test_called_from_function(self): + from zope.interface.declarations import classProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'classProvides': classProvides, 'IFoo': IFoo} + locs = {} + CODE = "\n".join([ + 'def foo():', + ' classProvides(IFoo)' + ]) + # XXX need six-ish majyk here :( + exec CODE in globs, locs + foo = locs['foo'] + self.assertRaises(TypeError, foo) + + def test_called_twice_from_class(self): + from zope.interface.declarations import classProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + globs = {'classProvides': classProvides, 'IFoo': IFoo, 'IBar': IBar} + locs = {} + CODE = "\n".join([ + 'class Foo(object):', + ' classProvides(IFoo)', + ' classProvides(IBar)', + ]) + # XXX need six-ish majyk here :( + try: + exec CODE in globs, locs + except TypeError: + pass + else: + self.fail("Didn't raise TypeError") + + def test_called_once_from_class(self): + from zope.interface.declarations import classProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'classProvides': classProvides, 'IFoo': IFoo} + locs = {} + CODE = "\n".join([ + 'class Foo(object):', + ' classProvides(IFoo)', + ]) + # XXX need six-ish majyk here :( + exec CODE in globs, locs + Foo = locs['Foo'] + spec = Foo.__providedBy__ + self.assertEqual(list(spec), [IFoo]) + + +# Test _classProvides_advice through classProvides, its only caller. + + +class Test_provider(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations import provider + return provider + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_w_class(self): + from zope.interface.declarations import ClassProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + @self._makeOne(IFoo) + class Foo(object): + pass + self.failUnless(isinstance(Foo.__provides__, ClassProvides)) + self.assertEqual(list(Foo.__provides__), [IFoo]) + + +class Test_moduleProvides(_SilencePy3Deprecations): + + def _getFUT(self): + from zope.interface.declarations import moduleProvides + return moduleProvides + + def test_called_from_function(self): + from zope.interface.declarations import moduleProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'__name__': 'zope.interface.tests.foo', + 'moduleProvides': moduleProvides, 'IFoo': IFoo} + locs = {} + CODE = "\n".join([ + 'def foo():', + ' moduleProvides(IFoo)' + ]) + # XXX need six-ish majyk here :( + exec CODE in globs, locs + foo = locs['foo'] + self.assertRaises(TypeError, foo) + + def test_called_from_class(self): + from zope.interface.declarations import moduleProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'__name__': 'zope.interface.tests.foo', + 'moduleProvides': moduleProvides, 'IFoo': IFoo} + CODE = "\n".join([ + 'class Foo(object):', + ' moduleProvides(IFoo)', + ]) + try: + # XXX need six-ish majyk here :( + exec CODE in globs + except TypeError: + pass + else: + assert False, 'TypeError not raised' + + def test_called_once_from_module_scope(self): + from zope.interface.declarations import moduleProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'__name__': 'zope.interface.tests.foo', + 'moduleProvides': moduleProvides, 'IFoo': IFoo} + CODE = "\n".join([ + 'moduleProvides(IFoo)', + ]) + # XXX need six-ish majyk here :( + exec CODE in globs + spec = globs['__provides__'] + self.assertEqual(list(spec), [IFoo]) + + def test_called_twice_from_module_scope(self): + from zope.interface.declarations import moduleProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + globs = {'__name__': 'zope.interface.tests.foo', + 'moduleProvides': moduleProvides, 'IFoo': IFoo} + CODE = "\n".join([ + 'moduleProvides(IFoo)', + 'moduleProvides(IFoo)', + ]) + try: + # XXX need six-ish majyk here :( + exec CODE in globs + except TypeError: + pass + else: + assert False, 'TypeError not raised' + + +class Test_getObjectSpecificationFallback(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import getObjectSpecificationFallback + return getObjectSpecificationFallback(*args, **kw) + + def test_wo_existing_provides_classless(self): + the_dict = {} + class Foo(object): + def __getattribute__(self, name): + # Emulate object w/o any class + if name == '__class__': + raise AttributeError(name) + try: + return the_dict[name] + except KeyError: + raise AttributeError(name) + def __setattr__(self, name, value): + the_dict[name] = value + foo = Foo() + spec = self._callFUT(foo) + self.assertEqual(list(spec), []) + + def test_existing_provides_is_spec(self): + from zope.interface.declarations import directlyProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + def foo(): + pass + directlyProvides(foo, IFoo) + spec = self._callFUT(foo) + self.failUnless(spec is foo.__provides__) + + def test_existing_provides_is_not_spec(self): + def foo(): + pass + foo.__provides__ = object() # not a valid spec + spec = self._callFUT(foo) + self.assertEqual(list(spec), []) + + def test_existing_provides(self): + from zope.interface.declarations import directlyProvides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + foo = Foo() + directlyProvides(foo, IFoo) + spec = self._callFUT(foo) + self.assertEqual(list(spec), [IFoo]) + + def test_wo_provides_on_class_w_implements(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + implements(IFoo) + foo = Foo() + spec = self._callFUT(foo) + self.assertEqual(list(spec), [IFoo]) + + def test_wo_provides_on_class_wo_implements(self): + class Foo(object): + pass + foo = Foo() + spec = self._callFUT(foo) + self.assertEqual(list(spec), []) + + +class Test_getObjectSpecification(Test_getObjectSpecificationFallback): + # Repeat tests for C optimizations + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import getObjectSpecification + return getObjectSpecification(*args, **kw) + + +class Test_providedByFallback(_SilencePy3Deprecations): + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import providedByFallback + return providedByFallback(*args, **kw) + + def test_wo_providedBy_on_class_wo_implements(self): + class Foo(object): + pass + foo = Foo() + spec = self._callFUT(foo) + self.assertEqual(list(spec), []) + + def test_w_providedBy_valid_spec(self): + from zope.interface.declarations import Provides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + foo = Foo() + foo.__providedBy__ = Provides(Foo, IFoo) + spec = self._callFUT(foo) + self.assertEqual(list(spec), [IFoo]) + + def test_w_providedBy_invalid_spec(self): + class Foo(object): + pass + foo = Foo() + foo.__providedBy__ = object() + spec = self._callFUT(foo) + self.assertEqual(list(spec), []) + + def test_w_providedBy_invalid_spec_class_w_implements(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + implements(IFoo) + foo = Foo() + foo.__providedBy__ = object() + spec = self._callFUT(foo) + self.assertEqual(list(spec), [IFoo]) + + def test_w_providedBy_invalid_spec_w_provides_no_provides_on_class(self): + class Foo(object): + pass + foo = Foo() + foo.__providedBy__ = object() + expected = foo.__provides__ = object() + spec = self._callFUT(foo) + self.failUnless(spec is expected) + + def test_w_providedBy_invalid_spec_w_provides_diff_provides_on_class(self): + class Foo(object): + pass + foo = Foo() + foo.__providedBy__ = object() + expected = foo.__provides__ = object() + Foo.__provides__ = object() + spec = self._callFUT(foo) + self.failUnless(spec is expected) + + def test_w_providedBy_invalid_spec_w_provides_same_provides_on_class(self): + from zope.interface.declarations import implements + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + implements(IFoo) + foo = Foo() + foo.__providedBy__ = object() + foo.__provides__ = Foo.__provides__ = object() + spec = self._callFUT(foo) + self.assertEqual(list(spec), [IFoo]) + + +class Test_providedBy(Test_providedByFallback): + # Repeat tests for C optimizations + + def _callFUT(self, *args, **kw): + from zope.interface.declarations import providedBy + return providedBy(*args, **kw) + + +class ObjectSpecificationDescriptorFallbackTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.declarations \ + import ObjectSpecificationDescriptorFallback + return ObjectSpecificationDescriptorFallback + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_accessed_via_class(self): + from zope.interface.declarations import Provides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + class Foo(object): + pass + Foo.__provides__ = Provides(Foo, IFoo) + Foo.__providedBy__ = self._makeOne() + self.assertEqual(list(Foo.__providedBy__), [IFoo]) + + def test_accessed_via_inst_wo_provides(self): + from zope.interface.declarations import implements + from zope.interface.declarations import Provides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + class Foo(object): + implements(IFoo) + Foo.__provides__ = Provides(Foo, IBar) + Foo.__providedBy__ = self._makeOne() + foo = Foo() + self.assertEqual(list(foo.__providedBy__), [IFoo]) + + def test_accessed_via_inst_w_provides(self): + from zope.interface.declarations import directlyProvides + from zope.interface.declarations import implements + from zope.interface.declarations import Provides + from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass("IFoo") + IBar = InterfaceClass("IBar") + IBaz = InterfaceClass("IBaz") + class Foo(object): + implements(IFoo) + Foo.__provides__ = Provides(Foo, IBar) + Foo.__providedBy__ = self._makeOne() + foo = Foo() + directlyProvides(foo, IBaz) + self.assertEqual(list(foo.__providedBy__), [IBaz, IFoo]) + + +class ObjectSpecificationDescriptorTests( + ObjectSpecificationDescriptorFallbackTests): + # Repeat tests for C optimizations + + def _getTargetClass(self): + from zope.interface.declarations import ObjectSpecificationDescriptor + return ObjectSpecificationDescriptor + + +# Test _normalizeargs through its callers. + + +class _Monkey(object): + # context-manager for replacing module names in the scope of a test. + def __init__(self, module, **kw): + self.module = module + self.to_restore = dict([(key, getattr(module, key)) for key in kw]) + for key, value in kw.items(): + setattr(module, key, value) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + for key, value in self.to_restore.items(): + setattr(self.module, key, value) - """ def test_suite(): return unittest.TestSuite(( - unittest.makeSuite(Test), - doctest.DocTestSuite("zope.interface.declarations"), - doctest.DocTestSuite(), + unittest.makeSuite(DeclarationTests), + unittest.makeSuite(ImplementsTests), + unittest.makeSuite(Test_implementedByFallback), + unittest.makeSuite(Test_implementedBy), + unittest.makeSuite(Test_classImplementsOnly), + unittest.makeSuite(Test_classImplements), + unittest.makeSuite(Test__implements_advice), + unittest.makeSuite(Test_implementer), + unittest.makeSuite(Test_implementer_only), + unittest.makeSuite(Test_implements), + unittest.makeSuite(Test_implementsOnly), + unittest.makeSuite(ProvidesClassTests), + unittest.makeSuite(Test_Provides), + unittest.makeSuite(Test_directlyProvides), + unittest.makeSuite(Test_alsoProvides), + unittest.makeSuite(Test_noLongerProvides), + unittest.makeSuite(ClassProvidesBaseFallbackTests), + unittest.makeSuite(ClassProvidesTests), + unittest.makeSuite(Test_directlyProvidedBy), + unittest.makeSuite(Test_classProvides), + unittest.makeSuite(Test_provider), + unittest.makeSuite(Test_moduleProvides), + unittest.makeSuite(Test_getObjectSpecificationFallback), + unittest.makeSuite(Test_getObjectSpecification), + unittest.makeSuite(Test_providedByFallback), + unittest.makeSuite(Test_providedBy), + unittest.makeSuite(ObjectSpecificationDescriptorFallbackTests), + unittest.makeSuite(ObjectSpecificationDescriptorTests), )) diff --git a/src/zope/interface/tests/test_document.py b/src/zope/interface/tests/test_document.py index a2653b3..6a1b0b2 100644 --- a/src/zope/interface/tests/test_document.py +++ b/src/zope/interface/tests/test_document.py @@ -13,57 +13,274 @@ ############################################################################## """Documentation tests. """ -from unittest import TestCase, main, makeSuite +import unittest -from zope.interface import Interface, Attribute -class Test(TestCase): +class Test_asStructuredText(unittest.TestCase): - def testBlech(self): + def _callFUT(self, iface): from zope.interface.document import asStructuredText + return asStructuredText(iface) - self.assertEqual(asStructuredText(I2), '''\ -I2 + def test_asStructuredText_no_docstring(self): + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "INoDocstring", + " Attributes:", + " Methods:", + "" + ]) + class INoDocstring(Interface): + pass + self.assertEqual(self._callFUT(INoDocstring), EXPECTED) - I2 doc + def test_asStructuredText_empty_with_docstring(self): + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IEmpty", + " This is an empty interface.", + " Attributes:", + " Methods:", + "" + ]) + class IEmpty(Interface): + """ This is an empty interface. + """ + self.assertEqual(self._callFUT(IEmpty), EXPECTED) - This interface extends: + def test_asStructuredText_empty_with_multiline_docstring(self): + from zope.interface import Interface + EXPECTED = '\n'.join([ + "IEmpty", + "", + " This is an empty interface.", + " ", + (" It can be used to annotate any class or object, " + "because it promises"), + " nothing.", + "", + " Attributes:", + "", + " Methods:", + "", + "" + ]) + class IEmpty(Interface): + """ This is an empty interface. - o _I1 + It can be used to annotate any class or object, because it promises + nothing. + """ + self.assertEqual(self._callFUT(IEmpty), EXPECTED) - Attributes: + def test_asStructuredText_with_attribute_no_docstring(self): + from zope.interface import Attribute + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IHasAttribute", + " This interface has an attribute.", + " Attributes:", + " an_attribute -- no documentation", + " Methods:", + "" + ]) + class IHasAttribute(Interface): + """ This interface has an attribute. + """ + an_attribute = Attribute('an_attribute') - a1 -- no documentation + self.assertEqual(self._callFUT(IHasAttribute), EXPECTED) - a2 -- a2 doc + def test_asStructuredText_with_attribute_with_docstring(self): + from zope.interface import Attribute + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IHasAttribute", + " This interface has an attribute.", + " Attributes:", + " an_attribute -- This attribute is documented.", + " Methods:", + "" + ]) + class IHasAttribute(Interface): + """ This interface has an attribute. + """ + an_attribute = Attribute('an_attribute', + 'This attribute is documented.') - Methods: + self.assertEqual(self._callFUT(IHasAttribute), EXPECTED) - f21() -- f21 doc + def test_asStructuredText_with_method_no_args_no_docstring(self): + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IHasMethod", + " This interface has a method.", + " Attributes:", + " Methods:", + " aMethod() -- no documentation", + "" + ]) + class IHasMethod(Interface): + """ This interface has a method. + """ + def aMethod(): + pass - f22() -- no documentation + self.assertEqual(self._callFUT(IHasMethod), EXPECTED) - f23() -- f23 doc + def test_asStructuredText_with_method_positional_args_no_docstring(self): + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IHasMethod", + " This interface has a method.", + " Attributes:", + " Methods:", + " aMethod(first, second) -- no documentation", + "" + ]) + class IHasMethod(Interface): + """ This interface has a method. + """ + def aMethod(first, second): + pass -''') + self.assertEqual(self._callFUT(IHasMethod), EXPECTED) + def test_asStructuredText_with_method_starargs_no_docstring(self): + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IHasMethod", + " This interface has a method.", + " Attributes:", + " Methods:", + " aMethod(first, second, *rest) -- no documentation", + "" + ]) + class IHasMethod(Interface): + """ This interface has a method. + """ + def aMethod(first, second, *rest): + pass -def test_suite(): - return makeSuite(Test) + self.assertEqual(self._callFUT(IHasMethod), EXPECTED) + + def test_asStructuredText_with_method_kwargs_no_docstring(self): + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IHasMethod", + " This interface has a method.", + " Attributes:", + " Methods:", + " aMethod(first, second, **kw) -- no documentation", + "" + ]) + class IHasMethod(Interface): + """ This interface has a method. + """ + def aMethod(first, second, **kw): + pass + + self.assertEqual(self._callFUT(IHasMethod), EXPECTED) + + def test_asStructuredText_with_method_with_docstring(self): + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IHasMethod", + " This interface has a method.", + " Attributes:", + " Methods:", + " aMethod() -- This method is documented.", + "" + ]) + class IHasMethod(Interface): + """ This interface has a method. + """ + def aMethod(): + """This method is documented. + """ + + self.assertEqual(self._callFUT(IHasMethod), EXPECTED) + + def test_asStructuredText_derived_ignores_base(self): + from zope.interface import Attribute + from zope.interface import Interface + EXPECTED = '\n\n'.join([ + "IDerived", + " IDerived doc", + " This interface extends:", + " o IBase", + " Attributes:", + " attr1 -- no documentation", + " attr2 -- attr2 doc", + " Methods:", + " method3() -- method3 doc", + " method4() -- no documentation", + " method5() -- method5 doc", + "", + ]) + + class IBase(Interface): + def method1(): + pass + def method2(): + pass -class _I1(Interface): - def f11(): pass - def f12(): pass + class IDerived(IBase): + "IDerived doc" + attr1 = Attribute('attr1') + attr2 = Attribute('attr2', 'attr2 doc') -class I2(_I1): - "I2 doc" + def method3(): + "method3 doc" + def method4(): + pass + def method5(): + "method5 doc" - a1 = Attribute('a1') - a2 = Attribute('a2', 'a2 doc') + self.assertEqual(self._callFUT(IDerived), EXPECTED) - def f21(): "f21 doc" - def f22(): pass - def f23(): "f23 doc" +class Test__justify_and_indent(unittest.TestCase): -if __name__=='__main__': - main(defaultTest='test_suite') + def _callFUT(self, text, level, **kw): + from zope.interface.document import _justify_and_indent + return _justify_and_indent(text, level, **kw) + + def test_simple_level_0(self): + LINES = ['Three blind mice', 'See how they run'] + text = '\n'.join(LINES) + self.assertEqual(self._callFUT(text, 0), text) + + def test_simple_level_1(self): + LINES = ['Three blind mice', 'See how they run'] + text = '\n'.join(LINES) + self.assertEqual(self._callFUT(text, 1), + '\n'.join([' ' + line for line in LINES])) + + def test_simple_level_2(self): + LINES = ['Three blind mice', 'See how they run'] + text = '\n'.join(LINES) + self.assertEqual(self._callFUT(text, 1), + '\n'.join([' ' + line for line in LINES])) + + def test_simple_w_CRLF(self): + LINES = ['Three blind mice', 'See how they run'] + text = '\r\n'.join(LINES) + self.assertEqual(self._callFUT(text, 1), + '\n'.join([' ' + line for line in LINES])) + + def test_with_munge(self): + TEXT = ("This is a piece of text longer than 15 characters, \n" + "and split across multiple lines.") + EXPECTED = (" This is a piece\n" + " of text longer\n" + " than 15 characters,\n" + " and split across\n" + " multiple lines.\n" + " ") + self.assertEqual(self._callFUT(TEXT, 1, munge=1, width=15), EXPECTED) + +def test_suite(): + return unittest.TestSuite(( + unittest.makeSuite(Test_asStructuredText), + unittest.makeSuite(Test__justify_and_indent), + )) diff --git a/src/zope/interface/tests/test_exceptions.py b/src/zope/interface/tests/test_exceptions.py new file mode 100644 index 0000000..94009f6 --- /dev/null +++ b/src/zope/interface/tests/test_exceptions.py @@ -0,0 +1,75 @@ +############################################################################## +# +# Copyright (c) 2010 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" zope.interface.exceptions unit tests +""" +import unittest + +def _makeIface(): + from zope.interface import Interface + class IDummy(Interface): + pass + return IDummy + +class DoesNotImplementTests(unittest.TestCase): + + def _getTargetClass(self): + from zope.interface.exceptions import DoesNotImplement + return DoesNotImplement + + def _makeOne(self, iface=None): + if iface is None: + iface = _makeIface() + return self._getTargetClass()(iface) + + def test___str__(self): + dni = self._makeOne() + # XXX The trailing newlines and blank spaces are a stupid artifact. + self.assertEqual(str(dni), + 'An object does not implement interface <InterfaceClass ' + 'zope.interface.tests.test_exceptions.IDummy>\n\n ') + +class BrokenImplementationTests(unittest.TestCase): + + def _getTargetClass(self): + from zope.interface.exceptions import BrokenImplementation + return BrokenImplementation + + def _makeOne(self, iface=None, name='missing'): + if iface is None: + iface = _makeIface() + return self._getTargetClass()(iface, name) + + def test___str__(self): + dni = self._makeOne() + # XXX The trailing newlines and blank spaces are a stupid artifact. + self.assertEqual(str(dni), + 'An object has failed to implement interface <InterfaceClass ' + 'zope.interface.tests.test_exceptions.IDummy>\n\n' + ' The missing attribute was not provided.\n ') + +class BrokenMethodImplementationTests(unittest.TestCase): + + def _getTargetClass(self): + from zope.interface.exceptions import BrokenMethodImplementation + return BrokenMethodImplementation + + def _makeOne(self, method='aMethod', mess='I said so'): + return self._getTargetClass()(method, mess) + + def test___str__(self): + dni = self._makeOne() + self.assertEqual(str(dni), + 'The implementation of aMethod violates its contract\n' + ' because I said so.\n ') + diff --git a/src/zope/interface/tests/test_interface.py b/src/zope/interface/tests/test_interface.py index 78398a1..458c011 100644 --- a/src/zope/interface/tests/test_interface.py +++ b/src/zope/interface/tests/test_interface.py @@ -13,316 +13,1597 @@ ############################################################################## """Test Interface implementation """ -from __future__ import with_statement - -import doctest import unittest -import sys -class InterfaceTests(unittest.TestCase): +_marker = object() + +class _SilencePy3Deprecations(unittest.TestCase): + # silence deprecation warnings under py3 - def failUnless(self, expr): # silence deprecation warnings under py3 + def failUnless(self, expr): + # St00pid speling. return self.assertTrue(expr) - def failIf(self, expr): # silence deprecation warnings under py3 + def failIf(self, expr): + # St00pid speling. return self.assertFalse(expr) - def _makeDerivedInterface(self): + +class Test_invariant(unittest.TestCase): + + def test_w_single(self): + from zope.interface.interface import invariant + from zope.interface.interface import TAGGED_DATA + + def _check(*args, **kw): + pass + + class Foo(object): + invariant(_check) + + self.assertEqual(getattr(Foo, TAGGED_DATA, None), + {'invariants': [_check]}) + + def test_w_multiple(self): + from zope.interface.interface import invariant + from zope.interface.interface import TAGGED_DATA + + def _check(*args, **kw): + pass + + def _another_check(*args, **kw): + pass + + class Foo(object): + invariant(_check) + invariant(_another_check) + + self.assertEqual(getattr(Foo, TAGGED_DATA, None), + {'invariants': [_check, _another_check]}) + + +class Test_taggedValue(unittest.TestCase): + + def test_w_single(self): + from zope.interface.interface import taggedValue + from zope.interface.interface import TAGGED_DATA + + class Foo(object): + taggedValue('bar', ['baz']) + + self.assertEqual(getattr(Foo, TAGGED_DATA, None), + {'bar': ['baz']}) + + def test_w_multiple(self): + from zope.interface.interface import taggedValue + from zope.interface.interface import TAGGED_DATA + + class Foo(object): + taggedValue('bar', ['baz']) + taggedValue('qux', 'spam') + + self.assertEqual(getattr(Foo, TAGGED_DATA, None), + {'bar': ['baz'], 'qux': 'spam'}) + + def test_w_multiple_overwriting(self): + from zope.interface.interface import taggedValue + from zope.interface.interface import TAGGED_DATA + + class Foo(object): + taggedValue('bar', ['baz']) + taggedValue('qux', 'spam') + taggedValue('bar', 'frob') + + self.assertEqual(getattr(Foo, TAGGED_DATA, None), + {'bar': 'frob', 'qux': 'spam'}) + + +class ElementTests(unittest.TestCase): + + DEFAULT_NAME = 'AnElement' + + def _getTargetClass(self): + from zope.interface.interface import Element + return Element + + def _makeOne(self, name=None, __doc__=_marker): + if name is None: + name = self.DEFAULT_NAME + if __doc__ is _marker: + return self._getTargetClass()(name) + return self._getTargetClass()(name, __doc__) + + def test_ctor_defaults(self): + element = self._makeOne() + self.assertEqual(element.__name__, self.DEFAULT_NAME) + self.assertEqual(element.getName(), self.DEFAULT_NAME) + self.assertEqual(element.__doc__, '') + self.assertEqual(element.getDoc(), '') + self.assertEqual(element.getTaggedValueTags(), []) + + def test_ctor_no_doc_space_in_name(self): + element = self._makeOne('An Element') + self.assertEqual(element.__name__, None) + self.assertEqual(element.__doc__, 'An Element') + + def test_getTaggedValue_miss(self): + element = self._makeOne() + self.assertRaises(KeyError, element.getTaggedValue, 'nonesuch') + + def test_queryTaggedValue_miss(self): + element = self._makeOne() + self.assertEqual(element.queryTaggedValue('nonesuch'), None) + + def test_queryTaggedValue_miss_w_default(self): + element = self._makeOne() + self.assertEqual(element.queryTaggedValue('nonesuch', 'bar'), 'bar') + + def test_setTaggedValue(self): + element = self._makeOne() + element.setTaggedValue('foo', 'bar') + self.assertEqual(element.getTaggedValueTags(), ['foo']) + self.assertEqual(element.getTaggedValue('foo'), 'bar') + self.assertEqual(element.queryTaggedValue('foo'), 'bar') + + +class SpecificationBasePyTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.interface import SpecificationBasePy + return SpecificationBasePy + + def _makeOne(self): + return self._getTargetClass()() + + def test_providedBy_miss(self): + from zope.interface import interface + from zope.interface.declarations import _empty + sb = self._makeOne() + def _providedBy(obj): + return _empty + with _Monkey(interface, providedBy=_providedBy): + self.failIf(sb.providedBy(object())) + + def test_providedBy_hit(self): + from zope.interface import interface + sb = self._makeOne() + class _Decl(object): + _implied = {sb: {},} + def _providedBy(obj): + return _Decl() + with _Monkey(interface, providedBy=_providedBy): + self.failUnless(sb.providedBy(object())) + + def test_implementedBy_miss(self): + from zope.interface import interface + from zope.interface.declarations import _empty + sb = self._makeOne() + def _implementedBy(obj): + return _empty + with _Monkey(interface, implementedBy=_implementedBy): + self.failIf(sb.implementedBy(object())) + + def test_implementedBy_hit(self): + from zope.interface import interface + sb = self._makeOne() + class _Decl(object): + _implied = {sb: {},} + def _implementedBy(obj): + return _Decl() + with _Monkey(interface, implementedBy=_implementedBy): + self.failUnless(sb.implementedBy(object())) + + def test_isOrExtends_miss(self): + sb = self._makeOne() + sb._implied = {} # not defined by SpecificationBasePy + self.failIf(sb.isOrExtends(object())) + + def test_isOrExtends_hit(self): + sb = self._makeOne() + testing = object() + sb._implied = {testing: {}} # not defined by SpecificationBasePy + self.failUnless(sb(testing)) + + def test___call___miss(self): + sb = self._makeOne() + sb._implied = {} # not defined by SpecificationBasePy + self.failIf(sb.isOrExtends(object())) + + def test___call___hit(self): + sb = self._makeOne() + testing = object() + sb._implied = {testing: {}} # not defined by SpecificationBasePy + self.failUnless(sb(testing)) + + +class InterfaceBasePyTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.interface import InterfaceBasePy + return InterfaceBasePy + + def _makeOne(self, object_should_provide): + class IB(self._getTargetClass()): + def _call_conform(self, conform): + return conform(self) + def providedBy(self, obj): + return object_should_provide + return IB() + + def test___call___w___conform___returning_value(self): + ib = self._makeOne(False) + conformed = object() + class _Adapted(object): + def __conform__(self, iface): + return conformed + self.failUnless(ib(_Adapted()) is conformed) + + def test___call___w___conform___miss_ob_provides(self): + ib = self._makeOne(True) + class _Adapted(object): + def __conform__(self, iface): + return None + adapted = _Adapted() + self.failUnless(ib(adapted) is adapted) + + def test___call___wo___conform___ob_no_provides_w_alternate(self): + ib = self._makeOne(False) + adapted = object() + alternate = object() + self.failUnless(ib(adapted, alternate) is alternate) + + def test___call___w___conform___ob_no_provides_wo_alternate(self): + ib = self._makeOne(False) + adapted = object() + self.assertRaises(TypeError, ib, adapted) + + def test___adapt___ob_provides(self): + ib = self._makeOne(True) + adapted = object() + self.failUnless(ib.__adapt__(adapted) is adapted) + + def test___adapt___ob_no_provides_uses_hooks(self): + from zope.interface import interface + ib = self._makeOne(False) + adapted = object() + _missed = [] + def _hook_miss(iface, obj): + _missed.append((iface, obj)) + return None + def _hook_hit(iface, obj): + return obj + with _Monkey(interface, adapter_hooks=[_hook_miss, _hook_hit]): + self.failUnless(ib.__adapt__(adapted) is adapted) + self.assertEqual(_missed, [(ib, adapted)]) + + +class SpecificationTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.interface import Specification + return Specification + + def _makeOne(self, bases=_marker): + if bases is _marker: + return self._getTargetClass()() + return self._getTargetClass()(bases) + + def test_ctor(self): + from zope.interface.interface import Interface + spec = self._makeOne() + self.assertEqual(spec.__bases__, ()) + self.assertEqual(len(spec._implied), 2) + self.failUnless(spec in spec._implied) + self.failUnless(Interface in spec._implied) + self.assertEqual(len(spec.dependents), 0) + + def test_subscribe_first_time(self): + spec = self._makeOne() + dep = DummyDependent() + spec.subscribe(dep) + self.assertEqual(len(spec.dependents), 1) + self.assertEqual(spec.dependents[dep], 1) + + def test_subscribe_again(self): + spec = self._makeOne() + dep = DummyDependent() + spec.subscribe(dep) + spec.subscribe(dep) + self.assertEqual(spec.dependents[dep], 2) + + def test_unsubscribe_miss(self): + spec = self._makeOne() + dep = DummyDependent() + self.assertRaises(KeyError, spec.unsubscribe, dep) + + def test_unsubscribe(self): + spec = self._makeOne() + dep = DummyDependent() + spec.subscribe(dep) + spec.subscribe(dep) + spec.unsubscribe(dep) + self.assertEqual(spec.dependents[dep], 1) + spec.unsubscribe(dep) + self.failIf(dep in spec.dependents) + + def test___setBases_subscribes_bases_and_notifies_dependents(self): + from zope.interface.interface import Interface + spec = self._makeOne() + dep = DummyDependent() + spec.subscribe(dep) + class I(Interface): + pass + class J(Interface): + pass + spec.__bases__ = (I,) + self.assertEqual(dep._changed, [spec]) + self.assertEqual(I.dependents[spec], 1) + spec.__bases__ = (J,) + self.assertEqual(I.dependents.get(spec), None) + self.assertEqual(J.dependents[spec], 1) + + def test_changed_clears_volatiles_and_implied(self): + from zope.interface.interface import Interface + class I(Interface): + pass + spec = self._makeOne() + spec._v_attrs = 'Foo' + spec._implied[I] = () + spec.changed(spec) + self.assert_(getattr(spec, '_v_attrs', self) is self) + self.failIf(I in spec._implied) + + +class InterfaceClassTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.interface import InterfaceClass + return InterfaceClass + + def _makeOne(self, name='ITest', bases=(), attrs=None, __doc__=None, + __module__=None): + return self._getTargetClass()(name, bases, attrs, __doc__, __module__) + + def test_ctor_defaults(self): + klass = self._getTargetClass() + inst = klass('ITesting') + self.assertEqual(inst.__name__, 'ITesting') + self.assertEqual(inst.__doc__, '') + self.assertEqual(inst.__bases__, ()) + self.assertEqual(inst.getBases(), ()) + + def test_ctor_bad_bases(self): + klass = self._getTargetClass() + self.assertRaises(TypeError, klass, 'ITesting', (object(),)) + + def test_ctor_w_attrs_attrib_methods(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + klass = self._getTargetClass() + inst = klass('ITesting', attrs=ATTRS) + self.assertEqual(inst.__name__, 'ITesting') + self.assertEqual(inst.__doc__, '') + self.assertEqual(inst.__bases__, ()) + self.assertEqual(inst.names(), ATTRS.keys()) + + def test_ctor_attrs_w___locals__(self): + ATTRS = {'__locals__': {}} + klass = self._getTargetClass() + inst = klass('ITesting', attrs=ATTRS) + self.assertEqual(inst.__name__, 'ITesting') + self.assertEqual(inst.__doc__, '') + self.assertEqual(inst.__bases__, ()) + self.assertEqual(inst.names(), ATTRS.keys()) + + def test_ctor_attrs_w__decorator_non_return(self): + from zope.interface.interface import _decorator_non_return + ATTRS = {'dropme': _decorator_non_return} + klass = self._getTargetClass() + inst = klass('ITesting', attrs=ATTRS) + self.assertEqual(inst.__name__, 'ITesting') + self.assertEqual(inst.__doc__, '') + self.assertEqual(inst.__bases__, ()) + self.assertEqual(inst.names(), []) + + def test_ctor_attrs_w_invalide_attr_type(self): + from zope.interface.exceptions import InvalidInterface + ATTRS = {'invalid': object()} + klass = self._getTargetClass() + self.assertRaises(InvalidInterface, klass, 'ITesting', attrs=ATTRS) + + def test_interfaces(self): + iface = self._makeOne() + self.assertEqual(list(iface.interfaces()), [iface]) + + def test_getBases(self): + iface = self._makeOne() + sub = self._makeOne('ISub', bases=(iface,)) + self.assertEqual(sub.getBases(), (iface,)) + + def test_isEqualOrExtendedBy_identity(self): + iface = self._makeOne() + self.failUnless(iface.isEqualOrExtendedBy(iface)) + + def test_isEqualOrExtendedBy_subiface(self): + iface = self._makeOne() + sub = self._makeOne('ISub', bases=(iface,)) + self.failUnless(iface.isEqualOrExtendedBy(sub)) + self.failIf(sub.isEqualOrExtendedBy(iface)) + + def test_isEqualOrExtendedBy_unrelated(self): + one = self._makeOne('One') + another = self._makeOne('Another') + self.failIf(one.isEqualOrExtendedBy(another)) + self.failIf(another.isEqualOrExtendedBy(one)) + + def test_names_w_all_False_ignores_bases(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(sorted(derived.names(all=False)), ['baz']) + + def test_names_w_all_True_no_bases(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + one = self._makeOne(attrs=ATTRS) + self.assertEqual(sorted(one.names(all=True)), ['bar', 'foo']) + + def test_names_w_all_True_w_bases_simple(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(sorted(derived.names(all=True)), ['bar', 'baz', 'foo']) + + def test_names_w_all_True_bases_w_same_names(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + def _foo(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(sorted(derived.names(all=True)), ['bar', 'baz', 'foo']) + + def test___iter__(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + def _foo(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(sorted(derived), ['bar', 'baz', 'foo']) + + def test_namesAndDescriptions_w_all_False_ignores_bases(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(sorted(derived.namesAndDescriptions(all=False)), + [('baz', DERIVED_ATTRS['baz']), + ]) + + def test_namesAndDescriptions_w_all_True_no_bases(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + one = self._makeOne(attrs=ATTRS) + self.assertEqual(sorted(one.namesAndDescriptions(all=False)), + [('bar', ATTRS['bar']), + ('foo', ATTRS['foo']), + ]) + + def test_namesAndDescriptions_w_all_True_simple(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(sorted(derived.namesAndDescriptions(all=True)), + [('bar', BASE_ATTRS['bar']), + ('baz', DERIVED_ATTRS['baz']), + ('foo', BASE_ATTRS['foo']), + ]) + + def test_namesAndDescriptions_w_all_True_bases_w_same_names(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + def _foo(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(sorted(derived.namesAndDescriptions(all=True)), + [('bar', BASE_ATTRS['bar']), + ('baz', DERIVED_ATTRS['baz']), + ('foo', DERIVED_ATTRS['foo']), + ]) + + def test_getDescriptionFor_miss(self): + one = self._makeOne() + self.assertRaises(KeyError, one.getDescriptionFor, 'nonesuch') + + def test_getDescriptionFor_hit(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + one = self._makeOne(attrs=ATTRS) + self.assertEqual(one.getDescriptionFor('foo'), ATTRS['foo']) + self.assertEqual(one.getDescriptionFor('bar'), ATTRS['bar']) + + def test___getitem___miss(self): + one = self._makeOne() + def _test(): + return one['nonesuch'] + self.assertRaises(KeyError, _test) + + def test___getitem___hit(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + one = self._makeOne(attrs=ATTRS) + self.assertEqual(one['foo'], ATTRS['foo']) + self.assertEqual(one['bar'], ATTRS['bar']) + + def test___contains___miss(self): + one = self._makeOne() + self.failIf('nonesuch' in one) + + def test___contains___hit(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + one = self._makeOne(attrs=ATTRS) + self.failUnless('foo' in one) + self.failUnless('bar' in one) + + def test_direct_miss(self): + one = self._makeOne() + self.assertEqual(one.direct('nonesuch'), None) + + def test_direct_hit_local_miss_bases(self): + from zope.interface.interface import Attribute + from zope.interface.interface import fromFunction + def _bar(): + """DOCSTRING""" + def _foo(): + """DOCSTRING""" + BASE_ATTRS = {'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = {'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } + base = self._makeOne('IBase', attrs=BASE_ATTRS) + derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) + self.assertEqual(derived.direct('foo'), DERIVED_ATTRS['foo']) + self.assertEqual(derived.direct('baz'), DERIVED_ATTRS['baz']) + self.assertEqual(derived.direct('bar'), None) + + def test_queryDescriptionFor_miss(self): + iface = self._makeOne() + self.assertEqual(iface.queryDescriptionFor('nonesuch'), None) + + def test_queryDescriptionFor_hit(self): + from zope.interface import Attribute + ATTRS = {'attr': Attribute('Title', 'Description')} + iface = self._makeOne(attrs=ATTRS) + self.assertEqual(iface.queryDescriptionFor('attr'), ATTRS['attr']) + + + #TODO (or not: 'deferred' looks like a fossil to me. + #def test_deferred_cache_hit(self): + #def test_deferred_cache_miss(self): + #def test_deferred_cache_miss_w_bases(self): + + def test_validateInvariants_pass(self): + _called_with = [] + def _passable(*args, **kw): + _called_with.append((args, kw)) + return True + iface = self._makeOne() + obj = object() + iface.setTaggedValue('invariants', [_passable]) + self.assertEqual(iface.validateInvariants(obj), None) + self.assertEqual(_called_with, [((obj,), {})]) + + def test_validateInvariants_fail_wo_errors_passed(self): + from zope.interface.exceptions import Invalid + _passable_called_with = [] + def _passable(*args, **kw): + _passable_called_with.append((args, kw)) + return True + _fail_called_with = [] + def _fail(*args, **kw): + _fail_called_with.append((args, kw)) + raise Invalid + iface = self._makeOne() + obj = object() + iface.setTaggedValue('invariants', [_passable, _fail]) + self.assertRaises(Invalid, iface.validateInvariants, obj) + self.assertEqual(_passable_called_with, [((obj,), {})]) + self.assertEqual(_fail_called_with, [((obj,), {})]) + + def test_validateInvariants_fail_w_errors_passed(self): + from zope.interface.exceptions import Invalid + _errors = [] + _fail_called_with = [] + def _fail(*args, **kw): + _fail_called_with.append((args, kw)) + raise Invalid + iface = self._makeOne() + obj = object() + iface.setTaggedValue('invariants', [_fail]) + self.assertRaises(Invalid, iface.validateInvariants, obj, _errors) + self.assertEqual(_fail_called_with, [((obj,), {})]) + self.assertEqual(len(_errors), 1) + self.failUnless(isinstance(_errors[0], Invalid)) + + def test_validateInvariants_fail_in_base_wo_errors_passed(self): + from zope.interface.exceptions import Invalid + _passable_called_with = [] + def _passable(*args, **kw): + _passable_called_with.append((args, kw)) + return True + _fail_called_with = [] + def _fail(*args, **kw): + _fail_called_with.append((args, kw)) + raise Invalid + base = self._makeOne('IBase') + derived = self._makeOne('IDerived', (base,)) + obj = object() + base.setTaggedValue('invariants', [_fail]) + derived.setTaggedValue('invariants', [_passable]) + self.assertRaises(Invalid, derived.validateInvariants, obj) + self.assertEqual(_passable_called_with, [((obj,), {})]) + self.assertEqual(_fail_called_with, [((obj,), {})]) + + #TODO + def test_validateInvariants_fail_in_base_w_errors_passed(self): + from zope.interface.exceptions import Invalid + _errors = [] + _passable_called_with = [] + def _passable(*args, **kw): + _passable_called_with.append((args, kw)) + return True + _fail_called_with = [] + def _fail(*args, **kw): + _fail_called_with.append((args, kw)) + raise Invalid + base = self._makeOne('IBase') + derived = self._makeOne('IDerived', (base,)) + obj = object() + base.setTaggedValue('invariants', [_fail]) + derived.setTaggedValue('invariants', [_passable]) + self.assertRaises(Invalid, derived.validateInvariants, obj, _errors) + self.assertEqual(_passable_called_with, [((obj,), {})]) + self.assertEqual(_fail_called_with, [((obj,), {})]) + self.assertEqual(len(_errors), 1) + self.failUnless(isinstance(_errors[0], Invalid)) + + def test___reduce__(self): + iface = self._makeOne('PickleMe') + self.assertEqual(iface.__reduce__(), 'PickleMe') + + def test___hash___normal(self): + iface = self._makeOne('HashMe') + self.assertEqual(hash(iface), + hash((('HashMe', + 'zope.interface.tests.test_interface')))) + + def test___hash___missing_required_attrs(self): + import warnings + try: + from warnings import catch_warnings + except ImportError: # Python 2.5 + return + class Derived(self._getTargetClass()): + def __init__(self): + pass # Don't call base class. + derived = Derived() + with catch_warnings(record=True) as warned: + warnings.simplefilter('always') # see LP #825249 + self.assertEqual(hash(derived), 1) + self.assertEqual(len(warned), 1) + self.failUnless(warned[0].category is UserWarning) + self.assertEqual(str(warned[0].message), + 'Hashing uninitialized InterfaceClass instance') + + def test_comparison_with_None(self): + iface = self._makeOne() + self.failUnless(iface < None) + self.failUnless(iface <= None) + self.failIf(iface == None) + self.failUnless(iface != None) + self.failIf(iface >= None) + self.failIf(iface > None) + + self.failIf(None < iface) + self.failIf(None <= iface) + self.failIf(None == iface) + self.failUnless(None != iface) + self.failUnless(None >= iface) + self.failUnless(None > iface) + + def test_comparison_with_same_instance(self): + iface = self._makeOne() + + self.failIf(iface < iface) + self.failUnless(iface <= iface) + self.failUnless(iface == iface) + self.failIf(iface != iface) + self.failUnless(iface >= iface) + self.failIf(iface > iface) + + def test_comparison_with_same_named_instance_in_other_module(self): + + one = self._makeOne('IName', __module__='zope.interface.tests.one') + other = self._makeOne('IName', __module__='zope.interface.tests.other') + + self.failUnless(one < other) + self.failIf(other < one) + self.failUnless(one <= other) + self.failIf(other <= one) + self.failIf(one == other) + self.failIf(other == one) + self.failUnless(one != other) + self.failUnless(other != one) + self.failIf(one >= other) + self.failUnless(other >= one) + self.failIf(one > other) + self.failUnless(other > one) + + +class InterfaceTests(_SilencePy3Deprecations): + + def test_attributes_link_to_interface(self): from zope.interface import Interface from zope.interface import Attribute - class _I1(Interface): - a1 = Attribute("This is an attribute") + class I1(Interface): + attr = Attribute("My attr") + + self.failUnless(I1['attr'].interface is I1) + + def test_methods_link_to_interface(self): + from zope.interface import Interface - def f11(): + class I1(Interface): + + def method(foo, bar, bingo): pass - def f12(): + + self.failUnless(I1['method'].interface is I1) + + def test_classImplements_simple(self): + from zope.interface import Interface + from zope.interface import implementedBy + from zope.interface import providedBy + + class ICurrent(Interface): + def method1(a, b): pass - f12.optional = 1 + def method2(a, b): + pass + + class IOther(Interface): + pass + + class Current(object): + __implemented__ = ICurrent + def method1(self, a, b): + return 1 + def method2(self, a, b): + return 2 + + current = Current() + + self.failUnless(ICurrent.implementedBy(Current)) + self.failIf(IOther.implementedBy(Current)) + self.failUnless(ICurrent in implementedBy(Current)) + self.failIf(IOther in implementedBy(Current)) + self.failUnless(ICurrent in providedBy(current)) + self.failIf(IOther in providedBy(current)) - class _I1_(_I1): + def test_classImplements_base_not_derived(self): + from zope.interface import Interface + from zope.interface import implementedBy + from zope.interface import providedBy + class IBase(Interface): + def method(): + pass + class IDerived(IBase): pass + class Current(): + __implemented__ = IBase + def method(self): + pass + current = Current() + + self.failUnless(IBase.implementedBy(Current)) + self.failIf(IDerived.implementedBy(Current)) + self.failUnless(IBase in implementedBy(Current)) + self.failIf(IDerived in implementedBy(Current)) + self.failUnless(IBase in providedBy(current)) + self.failIf(IDerived in providedBy(current)) + + def test_classImplements_base_and_derived(self): + from zope.interface import Interface + from zope.interface import implementedBy + from zope.interface import providedBy + + class IBase(Interface): + def method(): + pass - class _I1__(_I1_): + class IDerived(IBase): pass - class _I2(_I1__): - def f21(): + class Current(object): + __implemented__ = IDerived + def method(self): pass - def f22(): + + current = Current() + + self.failUnless(IBase.implementedBy(Current)) + self.failUnless(IDerived.implementedBy(Current)) + self.failIf(IBase in implementedBy(Current)) + self.failUnless(IBase in implementedBy(Current).flattened()) + self.failUnless(IDerived in implementedBy(Current)) + self.failIf(IBase in providedBy(current)) + self.failUnless(IBase in providedBy(current).flattened()) + self.failUnless(IDerived in providedBy(current)) + + def test_classImplements_multiple(self): + from zope.interface import Interface + from zope.interface import implementedBy + from zope.interface import providedBy + + class ILeft(Interface): + def method(): + pass + + class IRight(ILeft): + pass + + class Left(object): + __implemented__ = ILeft + + def method(self): pass - f23 = f22 - - return _I2 - - def testInterfaceSetOnAttributes(self): - from zope.interface.tests.unitfixtures import FooInterface - self.assertEqual(FooInterface['foobar'].interface, - FooInterface) - self.assertEqual(FooInterface['aMethod'].interface, - FooInterface) - - def testClassImplements(self): - from zope.interface.tests.unitfixtures import A - from zope.interface.tests.unitfixtures import B - from zope.interface.tests.unitfixtures import C - from zope.interface.tests.unitfixtures import D - from zope.interface.tests.unitfixtures import E - from zope.interface.tests.unitfixtures import I1 - from zope.interface.tests.unitfixtures import I2 - from zope.interface.tests.unitfixtures import IC - self.failUnless(IC.implementedBy(C)) - - self.failUnless(I1.implementedBy(A)) - self.failUnless(I1.implementedBy(B)) - self.failUnless(not I1.implementedBy(C)) - self.failUnless(I1.implementedBy(D)) - self.failUnless(I1.implementedBy(E)) - - self.failUnless(not I2.implementedBy(A)) - self.failUnless(I2.implementedBy(B)) - self.failUnless(not I2.implementedBy(C)) - - # No longer after interfacegeddon - # self.failUnless(not I2.implementedBy(D)) - - self.failUnless(not I2.implementedBy(E)) - - def testUtil(self): + + class Right(object): + __implemented__ = IRight + + class Ambi(Left, Right): + pass + + ambi = Ambi() + + self.failUnless(ILeft.implementedBy(Ambi)) + self.failUnless(IRight.implementedBy(Ambi)) + self.failUnless(ILeft in implementedBy(Ambi)) + self.failUnless(IRight in implementedBy(Ambi)) + self.failUnless(ILeft in providedBy(ambi)) + self.failUnless(IRight in providedBy(ambi)) + + def test_classImplements_multiple_w_explict_implements(self): + from zope.interface import Interface from zope.interface import implementedBy from zope.interface import providedBy - from zope.interface.tests.unitfixtures import A - from zope.interface.tests.unitfixtures import B - from zope.interface.tests.unitfixtures import C - from zope.interface.tests.unitfixtures import I1 - from zope.interface.tests.unitfixtures import I2 - from zope.interface.tests.unitfixtures import IC - self.failUnless(IC in implementedBy(C)) - self.failUnless(I1 in implementedBy(A)) - self.failUnless(not I1 in implementedBy(C)) - self.failUnless(I2 in implementedBy(B)) - self.failUnless(not I2 in implementedBy(C)) - - self.failUnless(IC in providedBy(C())) - self.failUnless(I1 in providedBy(A())) - self.failUnless(not I1 in providedBy(C())) - self.failUnless(I2 in providedBy(B())) - self.failUnless(not I2 in providedBy(C())) - - - def testObjectImplements(self): - from zope.interface.tests.unitfixtures import A - from zope.interface.tests.unitfixtures import B - from zope.interface.tests.unitfixtures import C - from zope.interface.tests.unitfixtures import D - from zope.interface.tests.unitfixtures import E - from zope.interface.tests.unitfixtures import I1 - from zope.interface.tests.unitfixtures import I2 - from zope.interface.tests.unitfixtures import IC - self.failUnless(IC.providedBy(C())) - - self.failUnless(I1.providedBy(A())) - self.failUnless(I1.providedBy(B())) - self.failUnless(not I1.providedBy(C())) - self.failUnless(I1.providedBy(D())) - self.failUnless(I1.providedBy(E())) - - self.failUnless(not I2.providedBy(A())) - self.failUnless(I2.providedBy(B())) - self.failUnless(not I2.providedBy(C())) - - # Not after interface geddon - # self.failUnless(not I2.providedBy(D())) - - self.failUnless(not I2.providedBy(E())) - - def testDeferredClass(self): - from zope.interface.tests.unitfixtures import A + + class ILeft(Interface): + + def method(): + pass + + class IRight(ILeft): + pass + + class IOther(Interface): + pass + + class Left(): + __implemented__ = ILeft + + def method(self): + pass + + class Right(object): + __implemented__ = IRight + + class Other(object): + __implemented__ = IOther + + class Mixed(Left, Right): + __implemented__ = Left.__implemented__, Other.__implemented__ + + mixed = Mixed() + + self.failUnless(ILeft.implementedBy(Mixed)) + self.failIf(IRight.implementedBy(Mixed)) + self.failUnless(IOther.implementedBy(Mixed)) + self.failUnless(ILeft in implementedBy(Mixed)) + self.failIf(IRight in implementedBy(Mixed)) + self.failUnless(IOther in implementedBy(Mixed)) + self.failUnless(ILeft in providedBy(mixed)) + self.failIf(IRight in providedBy(mixed)) + self.failUnless(IOther in providedBy(mixed)) + + def test_interface_deferred_class_method_broken(self): + from zope.interface import Interface from zope.interface.exceptions import BrokenImplementation - a = A() - self.assertRaises(BrokenImplementation, a.ma) + class IDeferring(Interface): + def method(): + pass + + class Deferring(IDeferring.deferred()): + __implemented__ = IDeferring + + deferring = Deferring() + + self.assertRaises(BrokenImplementation, deferring.method) def testInterfaceExtendsInterface(self): - from zope.interface.tests.unitfixtures import BazInterface - from zope.interface.tests.unitfixtures import BarInterface - from zope.interface.tests.unitfixtures import BobInterface - from zope.interface.tests.unitfixtures import FunInterface + from zope.interface import Interface + + new = Interface.__class__ + FunInterface = new('FunInterface') + BarInterface = new('BarInterface', [FunInterface]) + BobInterface = new('BobInterface') + BazInterface = new('BazInterface', [BobInterface, BarInterface]) + self.failUnless(BazInterface.extends(BobInterface)) self.failUnless(BazInterface.extends(BarInterface)) self.failUnless(BazInterface.extends(FunInterface)) - self.failUnless(not BobInterface.extends(FunInterface)) - self.failUnless(not BobInterface.extends(BarInterface)) + self.failIf(BobInterface.extends(FunInterface)) + self.failIf(BobInterface.extends(BarInterface)) self.failUnless(BarInterface.extends(FunInterface)) - self.failUnless(not BarInterface.extends(BazInterface)) + self.failIf(BarInterface.extends(BazInterface)) - def testVerifyImplementation(self): + def test_verifyClass(self): + from zope.interface import Attribute + from zope.interface import Interface from zope.interface.verify import verifyClass + + class ICheckMe(Interface): + attr = Attribute(u'My attr') + + def method(): + pass + + class CheckMe(object): + __implemented__ = ICheckMe + attr = 'value' + + def method(self): + pass + + self.failUnless(verifyClass(ICheckMe, CheckMe)) + + def test_verifyObject(self): + from zope.interface import Attribute from zope.interface import Interface - from zope.interface.tests.unitfixtures import Foo - from zope.interface.tests.unitfixtures import FooInterface - from zope.interface.tests.unitfixtures import I1 - self.failUnless(verifyClass(FooInterface, Foo)) - self.failUnless(Interface.providedBy(I1)) - - def test_names(self): - iface = self._makeDerivedInterface() - names = list(iface.names()) - names.sort() - self.assertEqual(names, ['f21', 'f22', 'f23']) - all = list(iface.names(all=True)) - all.sort() - self.assertEqual(all, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23']) - - def test_namesAndDescriptions(self): - iface = self._makeDerivedInterface() - names = [nd[0] for nd in iface.namesAndDescriptions()] - names.sort() - self.assertEqual(names, ['f21', 'f22', 'f23']) - names = [nd[0] for nd in iface.namesAndDescriptions(1)] - names.sort() - self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23']) - - for name, d in iface.namesAndDescriptions(1): - self.assertEqual(name, d.__name__) - - def test_getDescriptionFor(self): - iface = self._makeDerivedInterface() - self.assertEqual(iface.getDescriptionFor('f11').__name__, 'f11') - self.assertEqual(iface.getDescriptionFor('f22').__name__, 'f22') - self.assertEqual(iface.queryDescriptionFor('f33', self), self) - self.assertRaises(KeyError, iface.getDescriptionFor, 'f33') - - def test___getitem__(self): - iface = self._makeDerivedInterface() - self.assertEqual(iface['f11'].__name__, 'f11') - self.assertEqual(iface['f22'].__name__, 'f22') - self.assertEqual(iface.get('f33', self), self) - self.assertRaises(KeyError, iface.__getitem__, 'f33') - - def test___contains__(self): - iface = self._makeDerivedInterface() - self.failUnless('f11' in iface) - self.failIf('f33' in iface) + from zope.interface.verify import verifyObject - def test___iter__(self): - iface = self._makeDerivedInterface() - names = list(iter(iface)) - names.sort() - self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23']) + class ICheckMe(Interface): + attr = Attribute(u'My attr') + + def method(): + pass + + class CheckMe(object): + __implemented__ = ICheckMe + attr = 'value' + + def method(self): + pass + + check_me = CheckMe() + + self.failUnless(verifyObject(ICheckMe, check_me)) - def testAttr(self): - iface = self._makeDerivedInterface() - description = iface.getDescriptionFor('a1') - self.assertEqual(description.__name__, 'a1') - self.assertEqual(description.__doc__, 'This is an attribute') + def test_interface_object_provides_Interface(self): + from zope.interface import Interface + + class AnInterface(Interface): + pass + + self.assert_(Interface.providedBy(AnInterface)) - def testFunctionAttributes(self): - # Make sure function attributes become tagged values. + def test_names_simple(self): + from zope.interface import Attribute from zope.interface import Interface - class ITest(Interface): + + class ISimple(Interface): + attr = Attribute(u'My attr') + + def method(): + pass + + self.assertEqual(sorted(ISimple.names()), ['attr', 'method']) + + def test_names_derived(self): + from zope.interface import Attribute + from zope.interface import Interface + + class IBase(Interface): + attr = Attribute(u'My attr') + + def method(): + pass + + class IDerived(IBase): + attr2 = Attribute(u'My attr') + + def method(): + pass + + def method2(): + pass + + self.assertEqual(sorted(IDerived.names()), + ['attr2', 'method', 'method2']) + self.assertEqual(sorted(IDerived.names(all=True)), + ['attr', 'attr2', 'method', 'method2']) + + def test_namesAndDescriptions_simple(self): + from zope.interface import Attribute + from zope.interface.interface import Method + from zope.interface import Interface + + class ISimple(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + name_values = sorted(ISimple.namesAndDescriptions()) + + self.assertEqual(len(name_values), 2) + self.assertEqual(name_values[0][0], 'attr') + self.failUnless(isinstance(name_values[0][1], Attribute)) + self.assertEqual(name_values[0][1].__name__, 'attr') + self.assertEqual(name_values[0][1].__doc__, 'My attr') + self.assertEqual(name_values[1][0], 'method') + self.failUnless(isinstance(name_values[1][1], Method)) + self.assertEqual(name_values[1][1].__name__, 'method') + self.assertEqual(name_values[1][1].__doc__, 'My method') + + def test_namesAndDescriptions_derived(self): + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface.interface import Method + + class IBase(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + class IDerived(IBase): + attr2 = Attribute(u'My attr2') + + def method(): + "My method, overridden" + + def method2(): + "My method2" + + name_values = sorted(IDerived.namesAndDescriptions()) + + self.assertEqual(len(name_values), 3) + self.assertEqual(name_values[0][0], 'attr2') + self.failUnless(isinstance(name_values[0][1], Attribute)) + self.assertEqual(name_values[0][1].__name__, 'attr2') + self.assertEqual(name_values[0][1].__doc__, 'My attr2') + self.assertEqual(name_values[1][0], 'method') + self.failUnless(isinstance(name_values[1][1], Method)) + self.assertEqual(name_values[1][1].__name__, 'method') + self.assertEqual(name_values[1][1].__doc__, 'My method, overridden') + self.assertEqual(name_values[2][0], 'method2') + self.failUnless(isinstance(name_values[2][1], Method)) + self.assertEqual(name_values[2][1].__name__, 'method2') + self.assertEqual(name_values[2][1].__doc__, 'My method2') + + name_values = sorted(IDerived.namesAndDescriptions(all=True)) + + self.assertEqual(len(name_values), 4) + self.assertEqual(name_values[0][0], 'attr') + self.failUnless(isinstance(name_values[0][1], Attribute)) + self.assertEqual(name_values[0][1].__name__, 'attr') + self.assertEqual(name_values[0][1].__doc__, 'My attr') + self.assertEqual(name_values[1][0], 'attr2') + self.failUnless(isinstance(name_values[1][1], Attribute)) + self.assertEqual(name_values[1][1].__name__, 'attr2') + self.assertEqual(name_values[1][1].__doc__, 'My attr2') + self.assertEqual(name_values[2][0], 'method') + self.failUnless(isinstance(name_values[2][1], Method)) + self.assertEqual(name_values[2][1].__name__, 'method') + self.assertEqual(name_values[2][1].__doc__, 'My method, overridden') + self.assertEqual(name_values[3][0], 'method2') + self.failUnless(isinstance(name_values[3][1], Method)) + self.assertEqual(name_values[3][1].__name__, 'method2') + self.assertEqual(name_values[3][1].__doc__, 'My method2') + + def test_getDescriptionFor_nonesuch_no_default(self): + from zope.interface import Interface + + class IEmpty(Interface): + pass + + self.assertRaises(KeyError, IEmpty.getDescriptionFor, 'nonesuch') + + def test_getDescriptionFor_simple(self): + from zope.interface import Attribute + from zope.interface.interface import Method + from zope.interface import Interface + + class ISimple(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + a_desc = ISimple.getDescriptionFor('attr') + self.failUnless(isinstance(a_desc, Attribute)) + self.assertEqual(a_desc.__name__, 'attr') + self.assertEqual(a_desc.__doc__, 'My attr') + + m_desc = ISimple.getDescriptionFor('method') + self.failUnless(isinstance(m_desc, Method)) + self.assertEqual(m_desc.__name__, 'method') + self.assertEqual(m_desc.__doc__, 'My method') + + def test_getDescriptionFor_derived(self): + from zope.interface import Attribute + from zope.interface.interface import Method + from zope.interface import Interface + + class IBase(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + class IDerived(IBase): + attr2 = Attribute(u'My attr2') + + def method(): + "My method, overridden" + + def method2(): + "My method2" + + a_desc = IDerived.getDescriptionFor('attr') + self.failUnless(isinstance(a_desc, Attribute)) + self.assertEqual(a_desc.__name__, 'attr') + self.assertEqual(a_desc.__doc__, 'My attr') + + m_desc = IDerived.getDescriptionFor('method') + self.failUnless(isinstance(m_desc, Method)) + self.assertEqual(m_desc.__name__, 'method') + self.assertEqual(m_desc.__doc__, 'My method, overridden') + + a2_desc = IDerived.getDescriptionFor('attr2') + self.failUnless(isinstance(a2_desc, Attribute)) + self.assertEqual(a2_desc.__name__, 'attr2') + self.assertEqual(a2_desc.__doc__, 'My attr2') + + m2_desc = IDerived.getDescriptionFor('method2') + self.failUnless(isinstance(m2_desc, Method)) + self.assertEqual(m2_desc.__name__, 'method2') + self.assertEqual(m2_desc.__doc__, 'My method2') + + def test___getitem__nonesuch(self): + from zope.interface import Interface + + class IEmpty(Interface): + pass + + self.assertRaises(KeyError, IEmpty.__getitem__, 'nonesuch') + + def test___getitem__simple(self): + from zope.interface import Attribute + from zope.interface.interface import Method + from zope.interface import Interface + + class ISimple(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + a_desc = ISimple['attr'] + self.failUnless(isinstance(a_desc, Attribute)) + self.assertEqual(a_desc.__name__, 'attr') + self.assertEqual(a_desc.__doc__, 'My attr') + + m_desc = ISimple['method'] + self.failUnless(isinstance(m_desc, Method)) + self.assertEqual(m_desc.__name__, 'method') + self.assertEqual(m_desc.__doc__, 'My method') + + def test___getitem___derived(self): + from zope.interface import Attribute + from zope.interface.interface import Method + from zope.interface import Interface + + class IBase(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + class IDerived(IBase): + attr2 = Attribute(u'My attr2') + + def method(): + "My method, overridden" + + def method2(): + "My method2" + + a_desc = IDerived['attr'] + self.failUnless(isinstance(a_desc, Attribute)) + self.assertEqual(a_desc.__name__, 'attr') + self.assertEqual(a_desc.__doc__, 'My attr') + + m_desc = IDerived['method'] + self.failUnless(isinstance(m_desc, Method)) + self.assertEqual(m_desc.__name__, 'method') + self.assertEqual(m_desc.__doc__, 'My method, overridden') + + a2_desc = IDerived['attr2'] + self.failUnless(isinstance(a2_desc, Attribute)) + self.assertEqual(a2_desc.__name__, 'attr2') + self.assertEqual(a2_desc.__doc__, 'My attr2') + + m2_desc = IDerived['method2'] + self.failUnless(isinstance(m2_desc, Method)) + self.assertEqual(m2_desc.__name__, 'method2') + self.assertEqual(m2_desc.__doc__, 'My method2') + + def test___contains__nonesuch(self): + from zope.interface import Interface + + class IEmpty(Interface): + pass + + self.failIf('nonesuch' in IEmpty) + + def test___contains__simple(self): + from zope.interface import Attribute + from zope.interface import Interface + + class ISimple(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + self.failUnless('attr' in ISimple) + self.failUnless('method' in ISimple) + + def test___contains__derived(self): + from zope.interface import Attribute + from zope.interface import Interface + + class IBase(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + class IDerived(IBase): + attr2 = Attribute(u'My attr2') + + def method(): + "My method, overridden" + + def method2(): + "My method2" + + self.failUnless('attr' in IDerived) + self.failUnless('method' in IDerived) + self.failUnless('attr2' in IDerived) + self.failUnless('method2' in IDerived) + + def test___iter__empty(self): + from zope.interface import Interface + + class IEmpty(Interface): + pass + + self.assertEqual(list(IEmpty), []) + + def test___iter__simple(self): + from zope.interface import Attribute + from zope.interface import Interface + + class ISimple(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + self.assertEqual(sorted(list(ISimple)), ['attr', 'method']) + + def test___iter__derived(self): + from zope.interface import Attribute + from zope.interface import Interface + + class IBase(Interface): + attr = Attribute(u'My attr') + + def method(): + "My method" + + class IDerived(IBase): + attr2 = Attribute(u'My attr2') + + def method(): + "My method, overridden" + + def method2(): + "My method2" + + self.assertEqual(sorted(list(IDerived)), + ['attr', 'attr2', 'method', 'method2']) + + def test_function_attributes_become_tagged_values(self): + from zope.interface import Interface + + class ITagMe(Interface): def method(): pass method.optional = 1 - method = ITest['method'] + method = ITagMe['method'] self.assertEqual(method.getTaggedValue('optional'), 1) - def testInvariant(self): + def test___doc___non_element(self): + from zope.interface import Interface + + class IHaveADocString(Interface): + "xxx" + + self.assertEqual(IHaveADocString.__doc__, "xxx") + self.assertEqual(list(IHaveADocString), []) + + def test___doc___as_element(self): + from zope.interface import Attribute + from zope.interface import Interface + + class IHaveADocString(Interface): + "xxx" + __doc__ = Attribute('the doc') + + self.assertEqual(IHaveADocString.__doc__, "") + self.assertEqual(list(IHaveADocString), ['__doc__']) + + def _errorsEqual(self, has_invariant, error_len, error_msgs, iface): from zope.interface.exceptions import Invalid + self.assertRaises(Invalid, iface.validateInvariants, has_invariant) + e = [] + try: + iface.validateInvariants(has_invariant, e) + except Invalid, error: + self.assertEquals(error.args[0], e) + else: + self._assert(0) # validateInvariants should always raise + # Invalid + self.assertEquals(len(e), error_len) + msgs = [error.args[0] for error in e] + msgs.sort() + for msg in msgs: + self.assertEquals(msg, error_msgs.pop(0)) + + def test_invariant_simple(self): + from zope.interface import Attribute + from zope.interface import Interface from zope.interface import directlyProvides - from zope.interface.tests.unitfixtures import BarGreaterThanFoo - from zope.interface.tests.unitfixtures import ifFooThenBar - from zope.interface.tests.unitfixtures import IInvariant - from zope.interface.tests.unitfixtures import InvariantC - from zope.interface.tests.unitfixtures import ISubInvariant + from zope.interface import invariant + + class IInvariant(Interface): + foo = Attribute('foo') + bar = Attribute('bar; must eval to Boolean True if foo does') + invariant(_ifFooThenBar) + + class HasInvariant(object): + pass + # set up - o = InvariantC() - directlyProvides(o, IInvariant) - # a helper - def errorsEqual(self, o, error_len, error_msgs, iface=None): - if iface is None: - iface = IInvariant - self.assertRaises(Invalid, iface.validateInvariants, o) - e = [] - try: - iface.validateInvariants(o, e) - except Invalid, error: - self.assertEqual(error.args[0], e) - else: - self._assert(0) # validateInvariants should always raise - # Invalid - self.assertEqual(len(e), error_len) - msgs = [error.args[0] for error in e] - msgs.sort() - for msg in msgs: - self.assertEqual(msg, error_msgs.pop(0)) + has_invariant = HasInvariant() + directlyProvides(has_invariant, IInvariant) + # the tests self.assertEqual(IInvariant.getTaggedValue('invariants'), - [ifFooThenBar]) - self.assertEqual(IInvariant.validateInvariants(o), None) - o.bar = 27 - self.assertEqual(IInvariant.validateInvariants(o), None) - o.foo = 42 - self.assertEqual(IInvariant.validateInvariants(o), None) - del o.bar - errorsEqual(self, o, 1, ['If Foo, then Bar!']) + [_ifFooThenBar]) + self.assertEqual(IInvariant.validateInvariants(has_invariant), None) + has_invariant.bar = 27 + self.assertEqual(IInvariant.validateInvariants(has_invariant), None) + has_invariant.foo = 42 + self.assertEqual(IInvariant.validateInvariants(has_invariant), None) + del has_invariant.bar + self._errorsEqual(has_invariant, 1, ['If Foo, then Bar!'], + IInvariant) + + def test_invariant_nested(self): + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface import directlyProvides + from zope.interface import invariant + + class IInvariant(Interface): + foo = Attribute('foo') + bar = Attribute('bar; must eval to Boolean True if foo does') + invariant(_ifFooThenBar) + + class ISubInvariant(IInvariant): + invariant(_barGreaterThanFoo) + + class HasInvariant(object): + pass + # nested interfaces with invariants: self.assertEqual(ISubInvariant.getTaggedValue('invariants'), - [BarGreaterThanFoo]) - o = InvariantC() - directlyProvides(o, ISubInvariant) - o.foo = 42 + [_barGreaterThanFoo]) + has_invariant = HasInvariant() + directlyProvides(has_invariant, ISubInvariant) + has_invariant.foo = 42 # even though the interface has changed, we should still only have one # error. - errorsEqual(self, o, 1, ['If Foo, then Bar!'], ISubInvariant) + self._errorsEqual(has_invariant, 1, ['If Foo, then Bar!'], + ISubInvariant) # however, if we set foo to 0 (Boolean False) and bar to a negative # number then we'll get the new error - o.foo = 2 - o.bar = 1 - errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'], - ISubInvariant) + has_invariant.foo = 2 + has_invariant.bar = 1 + self._errorsEqual(has_invariant, 1, + ['Please, Boo MUST be greater than Foo!'], + ISubInvariant) # and if we set foo to a positive number and boo to 0, we'll # get both errors! - o.foo = 1 - o.bar = 0 - errorsEqual(self, o, 2, ['If Foo, then Bar!', - 'Please, Boo MUST be greater than Foo!'], - ISubInvariant) + has_invariant.foo = 1 + has_invariant.bar = 0 + self._errorsEqual(has_invariant, 2, + ['If Foo, then Bar!', + 'Please, Boo MUST be greater than Foo!'], + ISubInvariant) # for a happy ending, we'll make the invariants happy - o.foo = 1 - o.bar = 2 - self.assertEqual(IInvariant.validateInvariants(o), None) # woohoo + has_invariant.foo = 1 + has_invariant.bar = 2 + self.assertEquals(IInvariant.validateInvariants(has_invariant), None) + + def test_invariant_mutandis(self): + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface import directlyProvides + from zope.interface import invariant + + class IInvariant(Interface): + foo = Attribute('foo') + bar = Attribute('bar; must eval to Boolean True if foo does') + invariant(_ifFooThenBar) + + class HasInvariant(object): + pass + # now we'll do two invariants on the same interface, # just to make sure that a small # multi-invariant interface is at least minimally tested. - o = InvariantC() - directlyProvides(o, IInvariant) - o.foo = 42 + has_invariant = HasInvariant() + directlyProvides(has_invariant, IInvariant) + has_invariant.foo = 42 + + # if you really need to mutate, then this would be the way to do it. + # Probably a bad idea, though. :-) old_invariants = IInvariant.getTaggedValue('invariants') invariants = old_invariants[:] - invariants.append(BarGreaterThanFoo) # if you really need to mutate, - # then this would be the way to do it. Probably a bad idea, though. :-) + invariants.append(_barGreaterThanFoo) IInvariant.setTaggedValue('invariants', invariants) - # + # even though the interface has changed, we should still only have one # error. - errorsEqual(self, o, 1, ['If Foo, then Bar!']) + self._errorsEqual(has_invariant, 1, ['If Foo, then Bar!'], + IInvariant) # however, if we set foo to 0 (Boolean False) and bar to a negative # number then we'll get the new error - o.foo = 2 - o.bar = 1 - errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!']) + has_invariant.foo = 2 + has_invariant.bar = 1 + self._errorsEqual(has_invariant, 1, + ['Please, Boo MUST be greater than Foo!'], IInvariant) # and if we set foo to a positive number and boo to 0, we'll # get both errors! - o.foo = 1 - o.bar = 0 - errorsEqual(self, o, 2, ['If Foo, then Bar!', - 'Please, Boo MUST be greater than Foo!']) + has_invariant.foo = 1 + has_invariant.bar = 0 + self._errorsEqual(has_invariant, 2, + ['If Foo, then Bar!', + 'Please, Boo MUST be greater than Foo!'], + IInvariant) # for another happy ending, we'll make the invariants happy again - o.foo = 1 - o.bar = 2 - self.assertEqual(IInvariant.validateInvariants(o), None) # bliss + has_invariant.foo = 1 + has_invariant.bar = 2 + self.assertEquals(IInvariant.validateInvariants(has_invariant), None) # clean up IInvariant.setTaggedValue('invariants', old_invariants) @@ -344,164 +1625,431 @@ class InterfaceTests(unittest.TestCase): self.assertEqual(list(I), ['__doc__']) def testIssue228(self): - from zope.interface import Interface # Test for http://collector.zope.org/Zope3-dev/228 - if sys.version[0] == '3': + # Old style classes don't have a '__class__' attribute + import sys + if sys.version[0] < '3': # No old style classes in Python 3, so the test becomes moot. - return + from zope.interface import Interface + + class I(Interface): + "xxx" + + class OldStyle: + __providedBy__ = None + + self.assertRaises(AttributeError, I.providedBy, OldStyle) + + def test_invariant_as_decorator(self): + from zope.interface import Interface + from zope.interface import Attribute + from zope.interface import implements + from zope.interface import invariant + from zope.interface.exceptions import Invalid + + class IRange(Interface): + min = Attribute("Lower bound") + max = Attribute("Upper bound") + + @invariant + def range_invariant(ob): + if ob.max < ob.min: + raise Invalid('max < min') + + class Range(object): + implements(IRange) + + def __init__(self, min, max): + self.min, self.max = min, max + + IRange.validateInvariants(Range(1,2)) + IRange.validateInvariants(Range(1,1)) + try: + IRange.validateInvariants(Range(2,1)) + except Invalid, e: + self.assertEqual(str(e), 'max < min') + + def test_taggedValue(self): + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface import taggedValue + + class ITagged(Interface): + foo = Attribute('foo') + bar = Attribute('bar; must eval to Boolean True if foo does') + taggedValue('qux', 'Spam') + + class HasInvariant(object): + pass + + self.assertEquals(ITagged.getTaggedValue('qux'), 'Spam') + self.assert_('qux' in ITagged.getTaggedValueTags()) + + def test_description_cache_management(self): + # See https://bugs.launchpad.net/zope.interface/+bug/185974 + # There was a bug where the cache used by Specification.get() was not + # cleared when the bases were changed. + from zope.interface import Interface + from zope.interface import Attribute + + class I1(Interface): + a = Attribute('a') + + class I2(I1): + pass + + class I3(I2): + pass + + self.failUnless(I3.get('a') is I1.get('a')) + + I2.__bases__ = (Interface,) + self.failUnless(I3.get('a') is None) + + def test___call___defers_to___conform___(self): + from zope.interface import Interface + from zope.interface import implements + class I(Interface): - "xxx" - class Bad: - __providedBy__ = None - # Old style classes don't have a '__class__' attribute - self.failUnlessRaises(AttributeError, I.providedBy, Bad) + pass - def test_comparison_with_None(self): + class C(object): + implements(I) + def __conform__(self, proto): + return 0 + + self.assertEqual(I(C()), 0) + + def test___call___object_implements(self): from zope.interface import Interface + from zope.interface import implements - class IEmpty(Interface): + class I(Interface): pass - self.failUnless(IEmpty < None) - self.failUnless(IEmpty <= None) - self.failIf(IEmpty == None) - self.failUnless(IEmpty != None) - self.failIf(IEmpty >= None) - self.failIf(IEmpty > None) + class C(object): + implements(I) - self.failIf(None < IEmpty) - self.failIf(None <= IEmpty) - self.failIf(None == IEmpty) - self.failUnless(None != IEmpty) - self.failUnless(None >= IEmpty) - self.failUnless(None > IEmpty) + c = C() + self.assert_(I(c) is c) - def test_comparison_with_same_instance(self): + def test___call___miss_wo_alternate(self): from zope.interface import Interface - class IEmpty(Interface): + class I(Interface): pass - self.failIf(IEmpty < IEmpty) - self.failUnless(IEmpty <= IEmpty) - self.failUnless(IEmpty == IEmpty) - self.failIf(IEmpty != IEmpty) - self.failUnless(IEmpty >= IEmpty) - self.failIf(IEmpty > IEmpty) + class C(object): + pass - def test_comparison_with_same_named_instance_in_other_module(self): - from zope.interface.tests.ifoo import IFoo as IFoo1 - from zope.interface.tests.ifoo_other import IFoo as IFoo2 - - self.failUnless(IFoo1 < IFoo2) - self.failUnless(IFoo1 <= IFoo2) - self.failIf(IFoo1 == IFoo2) - self.failUnless(IFoo1 != IFoo2) - self.failIf(IFoo1 >= IFoo2) - self.failIf(IFoo1 > IFoo2) - - def test_hash_normal(self): - from zope.interface.tests.ifoo import IFoo - self.assertEqual(hash(IFoo), - hash((('IFoo', 'zope.interface.tests.ifoo')))) - - def test_hash_missing_required_attrs(self): - import warnings - try: - from warnings import catch_warnings - except ImportError: # Python 2.5 - return - from zope.interface.interface import InterfaceClass - class Derived(InterfaceClass): - def __init__(self): - pass # Don't call base class. - derived = Derived() - with catch_warnings(record=True) as warned: - warnings.simplefilter('always') # see LP #825249 - self.assertEqual(hash(derived), 1) - self.assertEqual(len(warned), 1) - self.failUnless(warned[0].category is UserWarning) - self.assertEqual(str(warned[0].message), - 'Hashing uninitialized InterfaceClass instance') + c = C() + self.assertRaises(TypeError, I, c) + + def test___call___miss_w_alternate(self): + from zope.interface import Interface + + class I(Interface): + pass + + class C(object): + pass + c = C() + self.assert_(I(c, self) is self) -if sys.version_info >= (2, 4): + def test___call___w_adapter_hook(self): + from zope.interface import Interface + from zope.interface.interface import adapter_hooks + old_hooks = adapter_hooks[:] - def test_invariant_as_decorator(): - """Invaiants can be deined in line + def _miss(iface, obj): + pass - >>> from zope.interface.exceptions import Invalid - >>> from zope.interface import Interface - >>> from zope.interface import Attribute - >>> from zope.interface import implements - >>> from zope.interface import invariant - >>> class IRange(Interface): - ... min = Attribute("Lower bound") - ... max = Attribute("Upper bound") - ... - ... @invariant - ... def range_invariant(ob): - ... if ob.max < ob.min: - ... raise Invalid('max < min') + def _hit(iface, obj): + return self + adapter_hooks[:] = [_miss, _hit] - >>> class Range(object): - ... implements(IRange) - ... - ... def __init__(self, min, max): - ... self.min, self.max = min, max + class I(Interface): + pass + + class C(object): + pass - >>> from zope.interface.exceptions import Invalid - >>> IRange.validateInvariants(Range(1,2)) - >>> IRange.validateInvariants(Range(1,1)) - >>> try: - ... IRange.validateInvariants(Range(2,1)) - ... except Invalid, e: - ... str(e) - 'max < min' + c = C() + self.assert_(I(c) is self) - """ +class AttributeTests(ElementTests): + DEFAULT_NAME = 'TestAttribute' -def test_description_cache_management(): - """ See https://bugs.launchpad.net/zope.interface/+bug/185974 + def _getTargetClass(self): + from zope.interface.interface import Attribute + return Attribute -There was a bug where the cache used by Specification.get() was not -cleared when the bases were changed. - >>> from zope.interface import Interface - >>> from zope.interface import Attribute - >>> class I1(Interface): - ... a = Attribute('a') +class MethodTests(AttributeTests): - >>> class I2(I1): - ... pass + DEFAULT_NAME = 'TestMethod' - >>> class I3(I2): - ... pass + def _getTargetClass(self): + from zope.interface.interface import Method + return Method - >>> I3.get('a') is I1.get('a') - True - >>> I2.__bases__ = (Interface,) - >>> I3.get('a') is None - True - """ + def test_optional_as_property(self): + method = self._makeOne() + self.assertEqual(method.optional, {}) + method.optional = {'foo': 'bar'} + self.assertEqual(method.optional, {'foo': 'bar'}) + del method.optional + self.assertEqual(method.optional, {}) + + def test___call___raises_BrokenImplementation(self): + from zope.interface.exceptions import BrokenImplementation + method = self._makeOne() + try: + method() + except BrokenImplementation, e: + self.assertEqual(e.interface, None) + self.assertEqual(e.name, self.DEFAULT_NAME) + else: + self.fail('__call__ should raise BrokenImplementation') + + def test_getSignatureInfo_bare(self): + method = self._makeOne() + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), []) + self.assertEqual(list(info['required']), []) + self.assertEqual(info['optional'], {}) + self.assertEqual(info['varargs'], None) + self.assertEqual(info['kwargs'], None) + + def test_getSignatureString_bare(self): + method = self._makeOne() + self.assertEqual(method.getSignatureString(), '()') + + def test_getSignatureString_w_only_required(self): + method = self._makeOne() + method.positional = method.required = ['foo'] + self.assertEqual(method.getSignatureString(), '(foo)') + + def test_getSignatureString_w_optional(self): + method = self._makeOne() + method.positional = method.required = ['foo'] + method.optional = {'foo': 'bar'} + self.assertEqual(method.getSignatureString(), "(foo='bar')") + + def test_getSignatureString_w_varargs(self): + method = self._makeOne() + method.varargs = 'args' + self.assertEqual(method.getSignatureString(), "(*args)") + + def test_getSignatureString_w_kwargs(self): + method = self._makeOne() + method.kwargs = 'kw' + self.assertEqual(method.getSignatureString(), "(**kw)") + + +class Test_fromFunction(unittest.TestCase): + + def _callFUT(self, *args, **kw): + from zope.interface.interface import fromFunction + return fromFunction(*args, **kw) + + def test_bare(self): + def _func(): + "DOCSTRING" + method = self._callFUT(_func) + self.assertEqual(method.getName(), '_func') + self.assertEqual(method.getDoc(), 'DOCSTRING') + self.assertEqual(method.interface, None) + self.assertEqual(method.getTaggedValueTags(), []) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), []) + self.assertEqual(list(info['required']), []) + self.assertEqual(info['optional'], {}) + self.assertEqual(info['varargs'], None) + self.assertEqual(info['kwargs'], None) + + def test_w_interface(self): + from zope.interface.interface import InterfaceClass + class IFoo(InterfaceClass): + pass + def _func(): + "DOCSTRING" + method = self._callFUT(_func, interface=IFoo) + self.assertEqual(method.interface, IFoo) + + def test_w_name(self): + def _func(): + "DOCSTRING" + method = self._callFUT(_func, name='anotherName') + self.assertEqual(method.getName(), 'anotherName') + + def test_w_only_required(self): + def _func(foo): + "DOCSTRING" + method = self._callFUT(_func) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), ['foo']) + self.assertEqual(list(info['required']), ['foo']) + self.assertEqual(info['optional'], {}) + self.assertEqual(info['varargs'], None) + self.assertEqual(info['kwargs'], None) + + def test_w_optional(self): + def _func(foo='bar'): + "DOCSTRING" + method = self._callFUT(_func) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), ['foo']) + self.assertEqual(list(info['required']), []) + self.assertEqual(info['optional'], {'foo': 'bar'}) + self.assertEqual(info['varargs'], None) + self.assertEqual(info['kwargs'], None) + + def test_w_optional_self(self): + # XXX This is a weird case, trying to cover the following code in + # FUT:: + # + # nr = na-len(defaults) + # if nr < 0: + # defaults=defaults[-nr:] + # nr = 0 + def _func(self='bar'): + "DOCSTRING" + method = self._callFUT(_func, imlevel=1) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), []) + self.assertEqual(list(info['required']), []) + self.assertEqual(info['optional'], {}) + self.assertEqual(info['varargs'], None) + self.assertEqual(info['kwargs'], None) + + def test_w_varargs(self): + def _func(*args): + "DOCSTRING" + method = self._callFUT(_func) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), []) + self.assertEqual(list(info['required']), []) + self.assertEqual(info['optional'], {}) + self.assertEqual(info['varargs'], 'args') + self.assertEqual(info['kwargs'], None) + + def test_w_kwargs(self): + def _func(**kw): + "DOCSTRING" + method = self._callFUT(_func) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), []) + self.assertEqual(list(info['required']), []) + self.assertEqual(info['optional'], {}) + self.assertEqual(info['varargs'], None) + self.assertEqual(info['kwargs'], 'kw') + + def test_full_spectrum(self): + def _func(foo, bar='baz', *args, **kw): + "DOCSTRING" + method = self._callFUT(_func) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), ['foo', 'bar']) + self.assertEqual(list(info['required']), ['foo']) + self.assertEqual(info['optional'], {'bar': 'baz'}) + self.assertEqual(info['varargs'], 'args') + self.assertEqual(info['kwargs'], 'kw') + + +class Test_fromMethod(unittest.TestCase): + + def _callFUT(self, *args, **kw): + from zope.interface.interface import fromMethod + return fromMethod(*args, **kw) + + def test_no_args(self): + class Foo(object): + def bar(self): + "DOCSTRING" + method = self._callFUT(Foo.bar) + self.assertEqual(method.getName(), 'bar') + self.assertEqual(method.getDoc(), 'DOCSTRING') + self.assertEqual(method.interface, None) + self.assertEqual(method.getTaggedValueTags(), []) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), []) + self.assertEqual(list(info['required']), []) + self.assertEqual(info['optional'], {}) + self.assertEqual(info['varargs'], None) + self.assertEqual(info['kwargs'], None) + + def test_full_spectrum(self): + class Foo(object): + def bar(self, foo, bar='baz', *args, **kw): + "DOCSTRING" + method = self._callFUT(Foo.bar) + info = method.getSignatureInfo() + self.assertEqual(list(info['positional']), ['foo', 'bar']) + self.assertEqual(list(info['required']), ['foo']) + self.assertEqual(info['optional'], {'bar': 'baz'}) + self.assertEqual(info['varargs'], 'args') + self.assertEqual(info['kwargs'], 'kw') + +class DummyDependent(object): + + def __init__(self): + self._changed = [] + + def changed(self, originally_changed): + self._changed.append(originally_changed) + + +def _barGreaterThanFoo(obj): + from zope.interface.exceptions import Invalid + foo = getattr(obj, 'foo', None) + bar = getattr(obj, 'bar', None) + if foo is not None and isinstance(foo, type(bar)): + # type checking should be handled elsewhere (like, say, + # schema); these invariants should be intra-interface + # constraints. This is a hacky way to do it, maybe, but you + # get the idea + if not bar > foo: + raise Invalid('Please, Boo MUST be greater than Foo!') + +def _ifFooThenBar(obj): + from zope.interface.exceptions import Invalid + if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None): + raise Invalid('If Foo, then Bar!') + + +class _Monkey(object): + # context-manager for replacing module names in the scope of a test. + def __init__(self, module, **kw): + self.module = module + self.to_restore = dict([(key, getattr(module, key)) for key in kw]) + for key, value in kw.items(): + setattr(module, key, value) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + for key, value in self.to_restore.items(): + setattr(self.module, key, value) def test_suite(): - suite = unittest.makeSuite(InterfaceTests) - suite.addTest(doctest.DocTestSuite("zope.interface.interface")) - if sys.version_info >= (2, 4): - suite.addTest(doctest.DocTestSuite()) - suite.addTest(doctest.DocFileSuite( - '../README.txt', - globs={'__name__': '__main__'}, - optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS, - )) - suite.addTest(doctest.DocFileSuite( - '../README.ru.txt', - globs={'__name__': '__main__'}, - optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS, - )) - return suite + import doctest + return unittest.TestSuite(( + unittest.makeSuite(ElementTests), + unittest.makeSuite(SpecificationBasePyTests), + unittest.makeSuite(InterfaceBasePyTests), + unittest.makeSuite(SpecificationTests), + unittest.makeSuite(InterfaceTests), + unittest.makeSuite(AttributeTests), + unittest.makeSuite(MethodTests), + unittest.makeSuite(Test_fromFunction), + #unittest.makeSuite(Test_fromMethod), + doctest.DocTestSuite(), + doctest.DocTestSuite("zope.interface.interface"), + )) diff --git a/src/zope/interface/tests/test_interfaces.py b/src/zope/interface/tests/test_interfaces.py new file mode 100644 index 0000000..7bc5807 --- /dev/null +++ b/src/zope/interface/tests/test_interfaces.py @@ -0,0 +1,115 @@ +import unittest + +class _SilencePy3Deprecations(unittest.TestCase): + # silence deprecation warnings under py3 + + def failUnless(self, expr): + # St00pid speling. + return self.assertTrue(expr) + + def failIf(self, expr): + # St00pid speling. + return self.assertFalse(expr) + + +class _ConformsToIObjectEvent(object): + + def _makeOne(self, target=None): + if target is None: + target = object() + return self._getTargetClass()(target) + + def test_class_conforms_to_IObjectEvent(self): + from zope.interface.interfaces import IObjectEvent + from zope.interface.verify import verifyClass + verifyClass(IObjectEvent, self._getTargetClass()) + + def test_instance_conforms_to_IObjectEvent(self): + from zope.interface.interfaces import IObjectEvent + from zope.interface.verify import verifyObject + verifyObject(IObjectEvent, self._makeOne()) + + +class _ConformsToIRegistrationEvent(_ConformsToIObjectEvent): + + def test_class_conforms_to_IRegistrationEvent(self): + from zope.interface.interfaces import IRegistrationEvent + from zope.interface.verify import verifyClass + verifyClass(IRegistrationEvent, self._getTargetClass()) + + def test_instance_conforms_to_IRegistrationEvent(self): + from zope.interface.interfaces import IRegistrationEvent + from zope.interface.verify import verifyObject + verifyObject(IRegistrationEvent, self._makeOne()) + + +class ObjectEventTests(_SilencePy3Deprecations, _ConformsToIObjectEvent): + + def _getTargetClass(self): + from zope.interface.interfaces import ObjectEvent + return ObjectEvent + + def test_ctor(self): + target = object() + event = self._makeOne(target) + self.failUnless(event.object is target) + + +class RegistrationEventTests(_SilencePy3Deprecations, + _ConformsToIRegistrationEvent): + + def _getTargetClass(self): + from zope.interface.interfaces import RegistrationEvent + return RegistrationEvent + + def test___repr__(self): + target = object() + event = self._makeOne(target) + r = repr(event) + self.assertEqual(r.splitlines(), + ['RegistrationEvent event:', repr(target)]) + + +class RegisteredTests(_SilencePy3Deprecations, + _ConformsToIRegistrationEvent): + + def _getTargetClass(self): + from zope.interface.interfaces import Registered + return Registered + + def test_class_conforms_to_IRegistered(self): + from zope.interface.interfaces import IRegistered + from zope.interface.verify import verifyClass + verifyClass(IRegistered, self._getTargetClass()) + + def test_instance_conforms_to_IRegistered(self): + from zope.interface.interfaces import IRegistered + from zope.interface.verify import verifyObject + verifyObject(IRegistered, self._makeOne()) + + +class UnregisteredTests(_SilencePy3Deprecations, + _ConformsToIRegistrationEvent): + + def _getTargetClass(self): + from zope.interface.interfaces import Unregistered + return Unregistered + + def test_class_conforms_to_IUnregistered(self): + from zope.interface.interfaces import IUnregistered + from zope.interface.verify import verifyClass + verifyClass(IUnregistered, self._getTargetClass()) + + def test_instance_conforms_to_IUnregistered(self): + from zope.interface.interfaces import IUnregistered + from zope.interface.verify import verifyObject + verifyObject(IUnregistered, self._makeOne()) + + +def test_suite(): + return unittest.TestSuite(( + unittest.makeSuite(ObjectEventTests), + unittest.makeSuite(RegistrationEventTests), + unittest.makeSuite(RegisteredTests), + unittest.makeSuite(UnregisteredTests), + )) diff --git a/src/zope/interface/tests/test_odd_declarations.py b/src/zope/interface/tests/test_odd_declarations.py index cbafa22..e8ebe47 100644 --- a/src/zope/interface/tests/test_odd_declarations.py +++ b/src/zope/interface/tests/test_odd_declarations.py @@ -16,13 +16,17 @@ These tests are to make sure we do something sane in the presence of classic ExtensionClass classes and instances. """ -import doctest import unittest from zope.interface.tests import odd -from zope.interface import Interface, implements, classProvides -from zope.interface import directlyProvides, providedBy, directlyProvidedBy -from zope.interface import classImplements, classImplementsOnly, implementedBy +from zope.interface import Interface +from zope.interface import implements +from zope.interface import directlyProvides +from zope.interface import providedBy +from zope.interface import directlyProvidedBy +from zope.interface import classImplements +from zope.interface import classImplementsOnly +from zope.interface import implementedBy class I1(Interface): pass class I2(Interface): pass @@ -184,15 +188,15 @@ class Test(unittest.TestCase): self.assertRaises(TypeError, directlyProvides, C, I5) # see above - def TODO_test_classProvides_fails_for_odd_class(self): - try: - class A(Odd): - classProvides(I1) - except TypeError: - pass # Sucess - self.failUnless(False, - "Shouldn't be able to use directlyProvides on odd class." - ) + #def TODO_test_classProvides_fails_for_odd_class(self): + # try: + # class A(Odd): + # classProvides(I1) + # except TypeError: + # pass # Sucess + # self.assert_(False, + # "Shouldn't be able to use directlyProvides on odd class." + # ) def test_implementedBy(self): class I2(I1): pass @@ -208,15 +212,9 @@ class Test(unittest.TestCase): self.assertEqual([i.getName() for i in implementedBy(C2)], ['I3', 'I2']) - - - def test_suite(): + import doctest suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(Test)) suite.addTest(doctest.DocTestSuite(odd)) return suite - - -if __name__ == '__main__': - unittest.main() diff --git a/src/zope/interface/tests/test_registry.py b/src/zope/interface/tests/test_registry.py index a151001..e132e77 100644 --- a/src/zope/interface/tests/test_registry.py +++ b/src/zope/interface/tests/test_registry.py @@ -12,939 +12,2438 @@ # ############################################################################## """Component Registry Tests""" - -import types import unittest -from zope import interface -from zope.interface import implementedBy -from zope.interface.interfaces import ComponentLookupError -from zope.interface.registry import Components - -import sys - -# fixtures - -if sys.version_info[0] == 3: - _class_types = type -else: - _class_types = (type, types.ClassType) - -class adapter: - - def __init__(self, *interfaces): - self.interfaces = interfaces - - def __call__(self, ob): - if isinstance(ob, _class_types): - ob.__component_adapts__ = _adapts_descr(self.interfaces) - else: - ob.__component_adapts__ = self.interfaces - - return ob - - -def adapts(*interfaces): - frame = sys._getframe(1) - locals = frame.f_locals - - # Try to make sure we were called from a class def. In 2.2.0 we can't - # check for __module__ since it doesn't seem to be added to the locals - # until later on. - if (locals is frame.f_globals) or ( - ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)): - raise TypeError("adapts can be used only from a class definition.") - - if '__component_adapts__' in locals: - raise TypeError("adapts can be used only once in a class definition.") - - locals['__component_adapts__'] = _adapts_descr(interfaces) - -class _adapts_descr(object): - def __init__(self, interfaces): - self.interfaces = interfaces - - def __get__(self, inst, cls): - if inst is None: - return self.interfaces - raise AttributeError('__component_adapts__') - -class I1(interface.Interface): - pass -class I2(interface.Interface): - pass -class I2e(I2): - pass -class I3(interface.Interface): - pass -class IC(interface.Interface): - pass - -class ITestType(interface.interfaces.IInterface): - pass - -class U: - - def __init__(self, name): - self.__name__ = name - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, self.__name__) - -class U1(U): - interface.implements(I1) - -class U12(U): - interface.implements(I1, I2) - -class IA1(interface.Interface): - pass - -class IA2(interface.Interface): - pass - -class IA3(interface.Interface): - pass - -class A: - - def __init__(self, *context): - self.context = context - - def __repr__(self): - return "%s%r" % (self.__class__.__name__, self.context) - -class A12_1(A): - adapts(I1, I2) - interface.implements(IA1) - -class A12_(A): - adapts(I1, I2) - -class A_2(A): - interface.implements(IA2) - -class A_3(A): - interface.implements(IA3) - -class A1_12(U): - adapts(I1) - interface.implements(IA1, IA2) - -class A1_2(U): - adapts(I1) - interface.implements(IA2) - -class A1_23(U): - adapts(I1) - interface.implements(IA1, IA3) - -def noop(*args): - pass - - -# tests - -class TestAdapter(unittest.TestCase): - - def setUp(self): - self.components = Components('comps') - - def test_register_and_unregister_adapter(self): - self.components.registerAdapter(A12_1) - - multi_adapter = self.components.getMultiAdapter( - (U1(1), U12(2)), IA1) - self.assertEqual(multi_adapter.__class__, A12_1) - self.assertEqual(repr(multi_adapter), 'A12_1(U1(1), U12(2))') - - self.assertTrue(self.components.unregisterAdapter(A12_1)) - self.assertRaises( - ComponentLookupError, - self.components.getMultiAdapter, - (U1(1), U12(2)), - IA1 - ) - - def test_register_and_unregister_adapter_with_two_interfaces(self): - self.assertRaises(TypeError, self.components.registerAdapter, - A1_12) - self.components.registerAdapter(A1_12, - provided=IA2) +class _SilencePy3Deprecations(unittest.TestCase): + # silence deprecation warnings under py3 + + def failUnless(self, expr): + # St00pid speling. + return self.assertTrue(expr) + + def failIf(self, expr): + # St00pid speling. + return self.assertFalse(expr) + +class ComponentsTests(_SilencePy3Deprecations): + + def _getTargetClass(self): + from zope.interface.registry import Components + return Components + + def _makeOne(self, name='test', *args, **kw): + return self._getTargetClass()(name, *args, **kw) + + def _wrapEvents(self): + from zope.interface import registry + _events = [] + def _notify(*args, **kw): + _events.append((args, kw)) + _monkey = _Monkey(registry, notify=_notify) + return _monkey, _events + + def test_ctor_no_bases(self): + from zope.interface.adapter import AdapterRegistry + comp = self._makeOne('testing') + self.assertEqual(comp.__name__, 'testing') + self.assertEqual(comp.__bases__, ()) + self.failUnless(isinstance(comp.adapters, AdapterRegistry)) + self.failUnless(isinstance(comp.utilities, AdapterRegistry)) + self.assertEqual(comp.adapters.__bases__, ()) + self.assertEqual(comp.utilities.__bases__, ()) + self.assertEqual(comp._utility_registrations, {}) + self.assertEqual(comp._adapter_registrations, {}) + self.assertEqual(comp._subscription_registrations, []) + self.assertEqual(comp._handler_registrations, []) + + def test_ctor_w_base(self): + base = self._makeOne('base') + comp = self._makeOne('testing', (base,)) + self.assertEqual(comp.__name__, 'testing') + self.assertEqual(comp.__bases__, (base,)) + self.assertEqual(comp.adapters.__bases__, (base.adapters,)) + self.assertEqual(comp.utilities.__bases__, (base.utilities,)) + + def test___repr__(self): + comp = self._makeOne('testing') + self.assertEqual(repr(comp), '<Components testing>') + + # test _init_registries / _init_registrations via only caller, __init__. + + def test_assign_to___bases__(self): + base1 = self._makeOne('base1') + base2 = self._makeOne('base2') + comp = self._makeOne() + comp.__bases__ = (base1, base2) + self.assertEqual(comp.__bases__, (base1, base2)) + self.assertEqual(comp.adapters.__bases__, + (base1.adapters, base2.adapters)) + self.assertEqual(comp.utilities.__bases__, + (base1.utilities, base2.utilities)) + + def test_registerUtility_both_factory_and_component(self): + def _factory(): + pass + _to_reg = object() + comp = self._makeOne() + self.assertRaises(TypeError, comp.registerUtility, + component=_to_reg, factory=_factory) + + def test_registerUtility_w_component(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = object() + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerUtility(_to_reg, ifoo, _name, _info) + self.failUnless(comp.utilities._adapters[0][ifoo][_name] is _to_reg) + self.assertEqual(comp._utility_registrations[ifoo, _name], + (_to_reg, _info, None)) + self.assertEqual(comp.utilities._subscribers[0][ifoo][''], (_to_reg,)) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _to_reg) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is None) + + def test_registerUtility_w_factory(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = object() + def _factory(): + return _to_reg + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerUtility(None, ifoo, _name, _info, factory=_factory) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _to_reg) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _factory) + + def test_registerUtility_no_provided_available(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + class Foo(object): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = Foo() + comp = self._makeOne() + self.assertRaises(TypeError, + comp.registerUtility, _to_reg, None, _name, _info) + + def test_registerUtility_wo_provided(self): + from zope.interface.declarations import directlyProvides + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + class Foo(object): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = Foo() + directlyProvides(_to_reg, ifoo) + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerUtility(_to_reg, None, _name, _info) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _to_reg) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is None) + + def test_registerUtility_duplicates_existing_reg(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, _name, _info) + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerUtility(_to_reg, ifoo, _name, _info) + self.assertEqual(len(_events), 0) + + def test_registerUtility_replaces_existing_reg(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.interfaces import Registered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _before, _after = object(), object() + comp = self._makeOne() + comp.registerUtility(_before, ifoo, _name, _info) + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerUtility(_after, ifoo, _name, _info) + self.assertEqual(len(_events), 2) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _before) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is None) + args, kw = _events[1] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _after) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is None) + + def test_registerUtility_w_existing_subscr(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name1 = _u('name1') + _name2 = _u('name2') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, _name1, _info) + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerUtility(_to_reg, ifoo, _name2, _info) + self.assertEqual(comp.utilities._subscribers[0][ifoo][''], (_to_reg,)) + + def test_registerUtility_wo_event(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = object() + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerUtility(_to_reg, ifoo, _name, _info, False) + self.assertEqual(len(_events), 0) + + def test_unregisterUtility_neither_factory_nor_component_nor_provided(self): + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterUtility, + component=None, provided=None, factory=None) + + def test_unregisterUtility_both_factory_and_component(self): + def _factory(): + pass + _to_reg = object() + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterUtility, + component=_to_reg, factory=_factory) + + def test_unregisterUtility_w_component_miss(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _name = _u('name') + _to_reg = object() + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterUtility(_to_reg, ifoo, _name) + self.failIf(unreg) + self.failIf(_events) + + def test_unregisterUtility_w_component(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _name = _u('name') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, _name) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterUtility(_to_reg, ifoo, _name) + self.failUnless(unreg) + self.failIf(comp.utilities._adapters) # all erased + self.failIf((ifoo, _name) in comp._utility_registrations) + self.failIf(comp.utilities._subscribers) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _to_reg) + self.failUnless(event.object.factory is None) + + def test_unregisterUtility_w_factory(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = object() + def _factory(): + return _to_reg + comp = self._makeOne() + comp.registerUtility(None, ifoo, _name, _info, factory=_factory) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterUtility(None, ifoo, _name, factory=_factory) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _to_reg) + self.failUnless(event.object.factory is _factory) + + def test_unregisterUtility_wo_explicit_provided(self): + from zope.interface.declarations import directlyProvides + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + class Foo(object): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = Foo() + directlyProvides(_to_reg, ifoo) + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, _name, _info) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterUtility(_to_reg, None, _name) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _to_reg) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is None) + + def test_unregisterUtility_wo_component_or_factory(self): + from zope.interface.declarations import directlyProvides + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import UtilityRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + class Foo(object): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + _to_reg = Foo() + directlyProvides(_to_reg, ifoo) + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, _name, _info) + _monkey, _events = self._wrapEvents() + with _monkey: + # Just pass the interface / name + unreg = comp.unregisterUtility(provided=ifoo, name=_name) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, UtilityRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.component is _to_reg) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is None) + + def test_unregisterUtility_w_existing_subscr(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name1 = _u('name1') + _name2 = _u('name2') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, _name1, _info) + comp.registerUtility(_to_reg, ifoo, _name2, _info) + _monkey, _events = self._wrapEvents() + with _monkey: + comp.unregisterUtility(_to_reg, ifoo, _name2) + self.assertEqual(comp.utilities._subscribers[0][ifoo][''], (_to_reg,)) + + def test_registeredUtilities_empty(self): + comp = self._makeOne() + self.assertEqual(list(comp.registeredUtilities()), []) + + def test_registeredUtilities_notempty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + from zope.interface.registry import UtilityRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name1 = _u('name1') + _name2 = _u('name2') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, _name1, _info) + comp.registerUtility(_to_reg, ifoo, _name2, _info) + reg = list(comp.registeredUtilities()) + self.assertEqual(len(reg), 2) + self.failUnless(isinstance(reg[0], UtilityRegistration)) + self.failUnless(reg[0].registry is comp) + self.failUnless(reg[0].provided is ifoo) + self.failUnless(reg[0].name is _name1) + self.failUnless(reg[0].component is _to_reg) + self.failUnless(reg[0].info is _info) + self.failUnless(reg[0].factory is None) + self.failUnless(isinstance(reg[1], UtilityRegistration)) + self.failUnless(reg[1].registry is comp) + self.failUnless(reg[1].provided is ifoo) + self.failUnless(reg[1].name is _name2) + self.failUnless(reg[1].component is _to_reg) + self.failUnless(reg[1].info is _info) + self.failUnless(reg[1].factory is None) + + def test_queryUtility_miss_no_default(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + self.failUnless(comp.queryUtility(ifoo) is None) - multi_adapter = self.components.getMultiAdapter((U1(1),), IA2) - self.assertEqual(multi_adapter.__class__, A1_12) - self.assertEqual(repr(multi_adapter), 'A1_12(U1(1))') + def test_queryUtility_miss_w_default(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + _default = object() + self.failUnless(comp.queryUtility(ifoo, default=_default) is _default) + + def test_queryUtility_hit(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo) + self.failUnless(comp.queryUtility(ifoo) is _to_reg) + + def test_getUtility_miss(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import ComponentLookupError + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + self.assertRaises(ComponentLookupError, comp.getUtility, ifoo) - self.assertRaises(TypeError, self.components.unregisterAdapter, A1_12) - self.assertTrue(self.components.unregisterAdapter(A1_12, provided=IA2)) + def test_getUtility_hit(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo) + self.failUnless(comp.getUtility(ifoo) is _to_reg) + + def test_getUtilitiesFor_miss(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + self.assertEqual(list(comp.getUtilitiesFor(ifoo)), []) + + def test_getUtilitiesFor_hit(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _name1 = _u('name1') + _name2 = _u('name2') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, name=_name1) + comp.registerUtility(_to_reg, ifoo, name=_name2) + self.assertEqual(sorted(comp.getUtilitiesFor(ifoo)), + [(_name1, _to_reg), (_name2, _to_reg)]) + + def test_getAllUtilitiesRegisteredFor_miss(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + self.assertEqual(list(comp.getAllUtilitiesRegisteredFor(ifoo)), []) + + def test_getAllUtilitiesRegisteredFor_hit(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _name1 = _u('name1') + _name2 = _u('name2') + _to_reg = object() + comp = self._makeOne() + comp.registerUtility(_to_reg, ifoo, name=_name1) + comp.registerUtility(_to_reg, ifoo, name=_name2) + self.assertEqual(list(comp.getAllUtilitiesRegisteredFor(ifoo)), + [_to_reg]) + + def test_registerAdapter_w_explicit_provided_and_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import AdapterRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerAdapter(_factory, (ibar,), ifoo, _name, _info) + self.failUnless(comp.adapters._adapters[1][ibar][ifoo][_name] + is _factory) + self.assertEqual(comp._adapter_registrations[(ibar,), ifoo, _name], + (_factory, _info)) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _factory) + + def test_registerAdapter_no_provided_available(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + _to_reg = object() + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + self.assertRaises(TypeError, comp.registerAdapter, _Factory, (ibar,), + name=_name, info=_info) + + def test_registerAdapter_wo_explicit_provided(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + from zope.interface.interfaces import Registered + from zope.interface.registry import AdapterRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + _to_reg = object() + @implementer(ifoo) + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerAdapter(_Factory, (ibar,), name=_name, info=_info) + self.failUnless(comp.adapters._adapters[1][ibar][ifoo][_name] + is _Factory) + self.assertEqual(comp._adapter_registrations[(ibar,), ifoo, _name], + (_Factory, _info)) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _Factory) + + def test_registerAdapter_no_required_available(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + self.assertRaises(TypeError, comp.registerAdapter, _Factory, + provided=ifoo, name=_name, info=_info) + + def test_registerAdapter_w_invalid_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + self.assertRaises(TypeError, comp.registerAdapter, _Factory, + ibar, provided=ifoo, name=_name, info=_info) + + def test_registerAdapter_w_required_containing_None(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interface import Interface + from zope.interface.interfaces import Registered + from zope.interface.registry import AdapterRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _name = _u('name') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerAdapter(_Factory, [None], provided=ifoo, + name=_name, info=_info) + self.failUnless(comp.adapters._adapters[1][Interface][ifoo][_name] + is _Factory) + self.assertEqual(comp._adapter_registrations[(Interface,), ifoo, _name], + (_Factory, _info)) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (Interface,)) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _Factory) + + def test_registerAdapter_w_required_containing_class(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implements + from zope.interface.declarations import implementedBy + from zope.interface.interfaces import Registered + from zope.interface.registry import AdapterRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + class _Factory(object): + def __init__(self, context): + self._context = context + class _Context(object): + implements(ibar) + _ctx_impl = implementedBy(_Context) + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerAdapter(_Factory, [_Context], provided=ifoo, + name=_name, info=_info) + self.failUnless(comp.adapters._adapters[1][_ctx_impl][ifoo][_name] + is _Factory) + self.assertEqual(comp._adapter_registrations[(_ctx_impl,), ifoo, _name], + (_Factory, _info)) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (_ctx_impl,)) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _Factory) + + def test_registerAdapter_w_required_containing_junk(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + self.assertRaises(TypeError, comp.registerAdapter, _Factory, [object()], + provided=ifoo, name=_name, info=_info) + + def test_registerAdapter_wo_explicit_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import AdapterRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + class _Factory(object): + __component_adapts__ = (ibar,) + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerAdapter(_Factory, provided=ifoo, name=_name, + info=_info) + self.failUnless(comp.adapters._adapters[1][ibar][ifoo][_name] + is _Factory) + self.assertEqual(comp._adapter_registrations[(ibar,), ifoo, _name], + (_Factory, _info)) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.failUnless(event.object.name is _name) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _Factory) + + def test_registerAdapter_wo_event(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _name = _u('name') + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerAdapter(_factory, (ibar,), ifoo, _name, _info, + event=False) + self.assertEqual(len(_events), 0) + + def test_unregisterAdapter_neither_factory_nor_provided(self): + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterAdapter, + factory=None, provided=None) + + def test_unregisterAdapter_neither_factory_nor_required(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterAdapter, + factory=None, provided=ifoo, required=None) + + def test_unregisterAdapter_miss(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterAdapter(_Factory, (ibar,), ifoo) + self.failIf(unreg) + + def test_unregisterAdapter_hit_w_explicit_provided_and_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar,), ifoo) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterAdapter(_Factory, (ibar,), ifoo) + self.failUnless(unreg) + self.failIf(comp.adapters._adapters) + self.failIf(comp._adapter_registrations) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is _Factory) + + def test_unregisterAdapter_wo_explicit_provided(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + from zope.interface.interfaces import Unregistered + from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + @implementer(ifoo) + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar,), ifoo) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterAdapter(_Factory, (ibar,)) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is _Factory) + + def test_unregisterAdapter_wo_explicit_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + __component_adapts__ = (ibar,) + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar,), ifoo) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterAdapter(_Factory, provided=ifoo) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, AdapterRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is _Factory) + + def test_registeredAdapters_empty(self): + comp = self._makeOne() + self.assertEqual(list(comp.registeredAdapters()), []) + + def test_registeredAdapters_notempty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IFoo') + _info = _u('info') + _name1 = _u('name1') + _name2 = _u('name2') + class _Factory(object): + def __init__(self, context): + pass + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar,), ifoo, _name1, _info) + comp.registerAdapter(_Factory, (ibar,), ifoo, _name2, _info) + reg = list(comp.registeredAdapters()) + self.assertEqual(len(reg), 2) + self.failUnless(isinstance(reg[0], AdapterRegistration)) + self.failUnless(reg[0].registry is comp) + self.failUnless(reg[0].provided is ifoo) + self.assertEqual(reg[0].required, (ibar,)) + self.failUnless(reg[0].name is _name1) + self.failUnless(reg[0].info is _info) + self.failUnless(reg[0].factory is _Factory) + self.failUnless(isinstance(reg[1], AdapterRegistration)) + self.failUnless(reg[1].registry is comp) + self.failUnless(reg[1].provided is ifoo) + self.assertEqual(reg[1].required, (ibar,)) + self.failUnless(reg[1].name is _name2) + self.failUnless(reg[1].info is _info) + self.failUnless(reg[1].factory is _Factory) + + def test_queryAdapter_miss_no_default(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + _context = object() + self.failUnless(comp.queryAdapter(_context, ifoo) is None) + + def test_queryAdapter_miss_w_default(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + _context = object() + _default = object() + self.failUnless( + comp.queryAdapter(_context, ifoo, default=_default) is _default) + + def test_queryAdapter_hit(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + def __init__(self, context): + self.context = context + @implementer(ibar) + class _Context(object): + pass + _context = _Context() + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar,), ifoo) + adapter = comp.queryAdapter(_context, ifoo) + self.failUnless(isinstance(adapter, _Factory)) + self.failUnless(adapter.context is _context) + + def test_getAdapter_miss(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + from zope.interface.interfaces import ComponentLookupError + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + @implementer(ibar) + class _Context(object): + pass + _context = _Context() + comp = self._makeOne() self.assertRaises(ComponentLookupError, - self.components.getMultiAdapter, (U1(1),), IA2) - - def test_register_and_unregister_adapter_with_no_interfaces(self): - self.assertRaises(TypeError, self.components.registerAdapter, A12_) + comp.getAdapter, _context, ifoo) - self.components.registerAdapter(A12_, provided=IA2) - multi_adapter = self.components.getMultiAdapter((U1(1), U12(2)), IA2) - self.assertEqual(multi_adapter.__class__, A12_) - self.assertEqual(repr(multi_adapter), 'A12_(U1(1), U12(2))') - - self.assertRaises(TypeError, self.components.unregisterAdapter, A12_) - self.assertTrue(self.components.unregisterAdapter(A12_, provided=IA2)) - self.assertRaises(ComponentLookupError, - self.components.getMultiAdapter, (U1(1), U12(2)), IA2) - - def test_reg_and_unreg_adp_with_no___component_adapts___attribute(self): - self.assertRaises(TypeError, self.components.registerAdapter, A_2) - self.components.registerAdapter(A_2, required=[I3]) - self.assertTrue(self.components.unregisterAdapter(A_2, required=[I3])) - - def test_register_and_unregister_class_specific(self): - self.components.registerAdapter(A_3, required=[U], - info=u'Really class specific') - self.assertTrue(self.components.unregisterAdapter(required=[U], - provided=IA3)) - - def test_registered_adapters_and_sorting(self): - self.components.registerAdapter(A12_1) - self.components.registerAdapter(A1_12, provided=IA2) - self.components.registerAdapter(A12_, provided=IA2) - self.components.registerAdapter(A_2, required=[I3]) - self.components.registerAdapter(A_3, required=[U], - info=u'Really class specific') - - sorted_adapters = sorted(self.components.registeredAdapters()) - sorted_adapters_name = map(lambda x: getattr(x, 'name'), - sorted_adapters) - sorted_adapters_provided = map(lambda x: getattr(x, 'provided'), - sorted_adapters) - sorted_adapters_required = map(lambda x: getattr(x, 'required'), - sorted_adapters) - sorted_adapters_info = map(lambda x: getattr(x, 'info'), - sorted_adapters) - - self.assertEqual(len(sorted_adapters), 5) - self.assertEqual(sorted_adapters_name, [u'', u'', u'', u'', u'']) - self.assertEqual(sorted_adapters_provided, [IA1, - IA2, - IA2, - IA2, - IA3]) - - self.assertEqual(sorted_adapters_required, [(I1, I2), - (I1, I2), - (I1,), - (I3,), - (implementedBy(U),)]) - self.assertEqual(sorted_adapters_info, - [u'', u'', u'', u'', u'Really class specific']) - - def test_get_none_existing_adapter(self): + def test_getAdapter_hit(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + def __init__(self, context): + self.context = context + @implementer(ibar) + class _Context(object): + pass + _context = _Context() + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar,), ifoo) + adapter = comp.getAdapter(_context, ifoo) + self.failUnless(isinstance(adapter, _Factory)) + self.failUnless(adapter.context is _context) + + def test_queryMultiAdapter_miss(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + ibaz = IFoo('IBaz') + @implementer(ibar) + class _Context1(object): + pass + @implementer(ibaz) + class _Context2(object): + pass + _context1 = _Context1() + _context2 = _Context2() + comp = self._makeOne() + self.assertEqual(comp.queryMultiAdapter((_context1, _context2), ifoo), + None) + + def test_queryMultiAdapter_miss_w_default(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + ibaz = IFoo('IBaz') + @implementer(ibar) + class _Context1(object): + pass + @implementer(ibaz) + class _Context2(object): + pass + _context1 = _Context1() + _context2 = _Context2() + _default = object() + comp = self._makeOne() + self.failUnless( + comp.queryMultiAdapter((_context1, _context2), ifoo, + default=_default) is _default) + + def test_queryMultiAdapter_hit(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + ibaz = IFoo('IBaz') + @implementer(ibar) + class _Context1(object): + pass + @implementer(ibaz) + class _Context2(object): + pass + _context1 = _Context1() + _context2 = _Context2() + class _Factory(object): + def __init__(self, context1, context2): + self.context = context1, context2 + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar, ibaz), ifoo) + adapter = comp.queryMultiAdapter((_context1, _context2), ifoo) + self.failUnless(isinstance(adapter, _Factory)) + self.assertEqual(adapter.context, (_context1, _context2)) + + def test_getMultiAdapter_miss(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + from zope.interface.interfaces import ComponentLookupError + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + ibaz = IFoo('IBaz') + @implementer(ibar) + class _Context1(object): + pass + @implementer(ibaz) + class _Context2(object): + pass + _context1 = _Context1() + _context2 = _Context2() + comp = self._makeOne() self.assertRaises(ComponentLookupError, - self.components.getMultiAdapter, (U(1),), IA1) - - def test_query_none_existing_adapter(self): - self.assertTrue(self.components.queryMultiAdapter((U(1),), IA1) is None) - self.assertEqual(self.components.queryMultiAdapter((U(1),), IA1, - default=42), 42) - - def test_unregister_none_existing_adapter(self): - self.assertFalse(self.components.unregisterAdapter(A_2, required=[I3])) - self.assertFalse(self.components.unregisterAdapter(A12_1, required=[U])) - - def test_unregister_adapter(self): - self.components.registerAdapter(A12_1) - self.components.registerAdapter(A1_12, provided=IA2) - self.components.registerAdapter(A12_, provided=IA2) - self.components.registerAdapter(A_2, required=[I3]) - self.components.registerAdapter(A_3, required=[U], - info=u'Really class specific') - - self.assertTrue(self.components.unregisterAdapter(A12_1)) - self.assertTrue(self.components.unregisterAdapter( - required=[U], provided=IA3)) - - sorted_adapters = sorted(self.components.registeredAdapters()) - sorted_adapters_name = map(lambda x: getattr(x, 'name'), - sorted_adapters) - sorted_adapters_provided = map(lambda x: getattr(x, 'provided'), - sorted_adapters) - sorted_adapters_required = map(lambda x: getattr(x, 'required'), - sorted_adapters) - sorted_adapters_info = map(lambda x: getattr(x, 'info'), - sorted_adapters) - - self.assertEqual(len(sorted_adapters), 3) - self.assertEqual(sorted_adapters_name, [u'', u'', u'']) - self.assertEqual(sorted_adapters_provided, [IA2, - IA2, - IA2]) - self.assertEqual(sorted_adapters_required, [(I1, I2), - (I1,), - (I3,)]) - self.assertEqual(sorted_adapters_info, [u'', u'', u'']) - - def test_register_named_adapter(self): - self.components.registerAdapter(A1_12, provided=IA2, name=u'test') - self.assertTrue( - self.components.queryMultiAdapter((U1(1),), IA2) is None) - self.assertEqual( - repr(self.components.queryMultiAdapter((U1(1),),IA2,name=u'test')), - 'A1_12(U1(1))') - - self.assertTrue(self.components.queryAdapter(U1(1), IA2) is None) - self.assertEqual( - repr(self.components.queryAdapter(U1(1), IA2, name=u'test')), - 'A1_12(U1(1))') - self.assertEqual( - repr(self.components.getAdapter(U1(1), IA2, name=u'test')), - 'A1_12(U1(1))') - - def test_get_adapters(self): - self.components.registerAdapter(A1_12, provided=IA1, name=u'test 1') - self.components.registerAdapter(A1_23, provided=IA2, name=u'test 2') - self.components.registerAdapter(A1_12, provided=IA2) - self.components.registerAdapter(A1_12, provided=IA2) - - adapters = list(self.components.getAdapters((U1(1),), IA2)) - self.assertEqual(len(adapters), 2) - self.assertEqual(adapters[0][0], u'test 2') - self.assertEqual(adapters[1][0], u'') - self.assertEqual(repr(adapters[0][1]), 'A1_23(U1(1))') - self.assertEqual(repr(adapters[1][1]), 'A1_12(U1(1))') - - def test_register_no_factory(self): - self.components.registerAdapter(A1_12, provided=IA2) - self.components.registerAdapter(noop, - required=[IA1], provided=IA2, - name=u'test noop') - - self.assertTrue( - self.components.queryAdapter(U1(9), IA2, name=u'test noop') is None) - adapters = list(self.components.getAdapters((U1(1),), IA2)) - self.assertEqual(len(adapters), 1) - self.assertEqual(adapters[0][0], u'') - self.assertEqual(repr(adapters[0][1]), 'A1_12(U1(1))') - - self.assertTrue(self.components.unregisterAdapter(A1_12, provided=IA2)) - - sorted_adapters = sorted(self.components.registeredAdapters()) - sorted_adapters_name = map(lambda x: getattr(x, 'name'), - sorted_adapters) - sorted_adapters_provided = map(lambda x: getattr(x, 'provided'), - sorted_adapters) - sorted_adapters_required = map(lambda x: getattr(x, 'required'), - sorted_adapters) - sorted_adapters_info = map(lambda x: getattr(x, 'info'), - sorted_adapters) - - self.assertEqual(len(sorted_adapters), 1) - self.assertEqual(sorted_adapters_name, [u'test noop']) - self.assertEqual(sorted_adapters_provided, [IA2]) - self.assertEqual(sorted_adapters_required, [(IA1,)]) - self.assertEqual(sorted_adapters_info, [u'']) - - -class TestExtending(unittest.TestCase): - - def test_extendning(self): - c1 = Components('1') - self.assertEqual(c1.__bases__, ()) - - c2 = Components('2', (c1, )) - self.assertTrue(c2.__bases__ == (c1, )) - - test_object1 = U1(1) - test_object2 = U1(2) - test_object3 = U12(1) - test_object4 = U12(3) - - self.assertEqual(len(list(c1.registeredUtilities())), 0) - self.assertEqual(len(list(c2.registeredUtilities())), 0) - - c1.registerUtility(test_object1) - self.assertEqual(len(list(c1.registeredUtilities())), 1) - self.assertEqual(len(list(c2.registeredUtilities())), 0) - self.assertEqual(c1.queryUtility(I1), test_object1) - self.assertEqual(c2.queryUtility(I1), test_object1) - - c1.registerUtility(test_object2) - self.assertEqual(len(list(c1.registeredUtilities())), 1) - self.assertEqual(len(list(c2.registeredUtilities())), 0) - self.assertEqual(c1.queryUtility(I1), test_object2) - self.assertEqual(c2.queryUtility(I1), test_object2) - - - c3 = Components('3', (c1, )) - c4 = Components('4', (c2, c3)) - self.assertEqual(c4.queryUtility(I1), test_object2) - - c1.registerUtility(test_object3, I2) - self.assertEqual(c4.queryUtility(I2), test_object3) - - c3.registerUtility(test_object4, I2) - self.assertEqual(c4.queryUtility(I2), test_object4) - - @adapter(I1) - def handle1(x): - self.assertEqual(x, test_object1) - - def handle(*objects): - self.assertEqual(objects, (test_object1,)) - - @adapter(I1) - def handle3(x): - self.assertEqual(x, test_object1) - - @adapter(I1) - def handle4(x): - self.assertEqual(x, test_object1) - - c1.registerHandler(handle1, info=u'First handler') - c2.registerHandler(handle, required=[U]) - c3.registerHandler(handle3) - c4.registerHandler(handle4) - - c4.handle(test_object1) - -class TestHandler(unittest.TestCase): - - def setUp(self): - self.components = Components('comps') - - def test_register_handler(self): - test_object1 = U1(1) - test_object2 = U12(2) - - @adapter(I1) - def handle1(x): - self.assertEqual(x, test_object1) - - self.components.registerHandler(handle1, info=u'First handler') - self.components.handle(test_object1) - - @adapter(I1, I2) - def handle12(x, y): - self.assertEqual(x, test_object1) - self.assertEqual(y, test_object2) - - self.components.registerHandler(handle12) - self.components.handle(test_object1, test_object2) - - def test_register_noncompliant_handler(self): - handle_calls = [] - def handle(*objects): - handle_calls.append(objects) - - self.assertRaises(TypeError, self.components.registerHandler, handle) - self.components.registerHandler( - handle, required=[I1], info=u'a comment') - self.components.registerHandler( - handle, required=[U], info=u'handle a class') - - test_object = U1(1) - self.components.handle(test_object) - self.assertEqual(len(handle_calls), 2) - map(self.assertEqual, handle_calls, [(test_object,), (test_object,)]) - - def test_list_handlers(self): - test_object1 = U1(1) - test_object2 = U12(2) - - @adapter(I1) - def handle1(x): - self.assertEqual(x, test_object1) - - @adapter(I1, I2) - def handle12(x, y): - self.assertEqual(x, test_object1) - self.assertEqual(y, test_object2) - - handle_calls = [] - def handle(*objects): - handle_calls.append(objects) - - self.components.registerHandler(handle1, info=u'First handler') - self.components.registerHandler(handle12) - self.components.registerHandler( - handle, required=[I1], info=u'a comment') - self.components.registerHandler( - handle, required=[U], info=u'handle a class') - - handlers = list(self.components.registeredHandlers()) - handlers_required = map(lambda x: getattr(x, 'required'), handlers) - handlers_handler = map(lambda x: getattr(x, 'handler'), handlers) - handlers_info = map(lambda x: getattr(x, 'info'), handlers) - - self.assertEqual(len(handlers), 4) - self.assertEqual(handlers_required, - [(I1,), (I1, I2), (I1,), (implementedBy(U),)]) - self.assertEqual(handlers_handler, - [handle1, handle12, handle, handle]) - self.assertEqual( - handlers_info, - [u'First handler', u'', u'a comment', u'handle a class']) - - def test_unregister_handler(self): - test_object1 = U1(1) - test_object2 = U12(2) - - @adapter(I1) - def handle1(x): - self.assertEqual(x, test_object1) - - @adapter(I1, I2) - def handle12(x, y): - self.assertEqual(x, test_object1) - self.assertEqual(y, test_object2) - - handle_calls = [] - def handle(*objects): - handle_calls.append(objects) - - self.components.registerHandler(handle1, info=u'First handler') - self.components.registerHandler(handle12) - self.components.registerHandler( - handle, required=[I1], info=u'a comment') - self.components.registerHandler( - handle, required=[U], info=u'handle a class') - - self.assertEqual(len(list(self.components.registeredHandlers())), 4) - self.assertTrue(self.components.unregisterHandler(handle12)) - self.assertEqual(len(list(self.components.registeredHandlers())), 3) - self.assertFalse(self.components.unregisterHandler(handle12)) - self.assertEqual(len(list(self.components.registeredHandlers())), 3) - self.assertRaises(TypeError, self.components.unregisterHandler) - self.assertEqual(len(list(self.components.registeredHandlers())), 3) - self.assertTrue( - self.components.unregisterHandler(handle, required=[I1])) - self.assertEqual(len(list(self.components.registeredHandlers())), 2) - self.assertTrue(self.components.unregisterHandler(handle, required=[U])) - self.assertEqual(len(list(self.components.registeredHandlers())), 1) - - def test_multi_handler_unregistration(self): - """ - There was a bug where multiple handlers for the same required - specification would all be removed when one of them was - unregistered. - - """ - from zope import interface - - calls = [] - - class I(interface.Interface): - pass - - def factory1(event): - calls.append(2) - - def factory2(event): - calls.append(3) - - class Event(object): - interface.implements(I) - - self.components.registerHandler(factory1, [I,]) - self.components.registerHandler(factory2, [I,]) - self.components.handle(Event()) - self.assertEqual(sum(calls), 5) - self.assertTrue(self.components.unregisterHandler(factory1, [I,])) - calls = [] - self.components.handle(Event()) - self.assertEqual(sum(calls), 3) - -class TestSubscriber(unittest.TestCase): - - def setUp(self): - self.components = Components('comps') - - def test_register_subscriber(self): - self.components.registerSubscriptionAdapter(A1_2) - self.components.registerSubscriptionAdapter(A1_12, provided=IA2) - self.components.registerSubscriptionAdapter( - A, [I1], IA2, info='a sample comment') - subscribers = self.components.subscribers((U1(1),), IA2) - self.assertEqual(len(subscribers), 3) - self.assertEqual(repr(subscribers[0]), 'A1_2(U1(1))') - self.assertEqual(repr(subscribers[1]), 'A1_12(U1(1))') - self.assertEqual(repr(subscribers[2]), 'A(U1(1),)') - - def test_register_noncompliant_subscriber(self): - self.assertRaises(TypeError, - self.components.registerSubscriptionAdapter, A1_12) - self.assertRaises(TypeError, - self.components.registerSubscriptionAdapter, A) - self.assertRaises( - TypeError, - self.components.registerSubscriptionAdapter, A, required=[IA1]) - - def test_register_named_subscriber(self): - self.components.registerSubscriptionAdapter( - A, [I1], IA2, u'', u'a sample comment') - self.assertRaises(TypeError, - self.components.registerSubscriptionAdapter, - A, [I1], IA2, u'oops', u'a sample comment') - subscribers = self.components.subscribers((U1(1),), IA2) - self.assertEqual(len(subscribers), 1) - self.assertEqual(repr(subscribers[0]), 'A(U1(1),)') - - def test_register_no_factory(self): - self.components.registerSubscriptionAdapter(noop, [I1], IA2) - subscribers = self.components.subscribers((U1(1),), IA2) - self.assertEqual(len(subscribers), 0) - - def test_sorting_registered_subscription_adapters(self): - self.components.registerSubscriptionAdapter(A1_2) - self.components.registerSubscriptionAdapter(A1_12, provided=IA2) - self.components.registerSubscriptionAdapter( - A, [I1], IA2, info=u'a sample comment') - self.components.registerSubscriptionAdapter( - A, [I1], IA2, u'', u'a sample comment') - self.components.registerSubscriptionAdapter(noop, [I1], IA2) - - sorted_subscribers = sorted( - self.components.registeredSubscriptionAdapters()) - sorted_subscribers_name = map(lambda x: getattr(x, 'name'), - sorted_subscribers) - sorted_subscribers_provided = map(lambda x: getattr(x, 'provided'), - sorted_subscribers) - sorted_subscribers_required = map(lambda x: getattr(x, 'required'), - sorted_subscribers) - sorted_subscribers_factory = map(lambda x: getattr(x, 'factory'), - sorted_subscribers) - sorted_subscribers_info = map(lambda x: getattr(x, 'info'), - sorted_subscribers) - - self.assertEqual(len(sorted_subscribers), 5) - self.assertEqual(sorted_subscribers_name, [u'', u'', u'', u'', u'']) - self.assertEqual(sorted_subscribers_provided, - [IA2, IA2, IA2, IA2, IA2]) - self.assertEqual(sorted_subscribers_required, - [(I1,), (I1,), (I1,),(I1,), (I1,)]) - self.assertEqual(sorted_subscribers_factory, - [A, A, A1_12, A1_2, noop]) - self.assertEqual( - sorted_subscribers_info, - [u'a sample comment', u'a sample comment', u'', u'', u'']) - - def test_unregister(self): - self.components.registerSubscriptionAdapter(A1_2) - self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 1) - self.assertTrue(self.components.unregisterSubscriptionAdapter(A1_2)) - self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 0) - - def test_unregister_multiple(self): - self.components.registerSubscriptionAdapter(A1_2) - self.components.registerSubscriptionAdapter(A1_12, provided=IA2) - self.components.registerSubscriptionAdapter( - A, [I1], IA2, info=u'a sample comment') - self.components.registerSubscriptionAdapter( - A, [I1], IA2, u'', u'a sample comment') - self.components.registerSubscriptionAdapter(noop, [I1], IA2) - self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 4) - self.assertEqual( - len(list(self.components.registeredSubscriptionAdapters())), 5) - - self.assertTrue( - self.components.unregisterSubscriptionAdapter(A, [I1], IA2)) - self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 2) - self.assertEqual( - len(list(self.components.registeredSubscriptionAdapters())), 3) + comp.getMultiAdapter, (_context1, _context2), ifoo) - def test_unregister_no_factory(self): - self.components.registerSubscriptionAdapter(A1_2) - self.components.registerSubscriptionAdapter(A1_12, provided=IA2) - self.components.registerSubscriptionAdapter(noop, [I1], IA2) - self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 2) - self.assertEqual( - len(list(self.components.registeredSubscriptionAdapters())), 3) - - self.assertRaises( - TypeError, - self.components.unregisterSubscriptionAdapter, required=[I1]) - self.assertRaises( - TypeError, - self.components.unregisterSubscriptionAdapter, provided=IA2) - self.assertTrue( - self.components.unregisterSubscriptionAdapter( - required=[I1], provided=IA2)) - self.assertEqual(len(self.components.subscribers((U1(1),), IA2)), 0) - self.assertEqual( - len(list(self.components.registeredSubscriptionAdapters())), 0) - - def test_unregister_noncompliant_subscriber(self): - self.assertRaises( - TypeError, - self.components.unregisterSubscriptionAdapter, A1_12) - self.assertRaises( - TypeError, - self.components.unregisterSubscriptionAdapter, A) - self.assertRaises( - TypeError, - self.components.unregisterSubscriptionAdapter, A, required=[IA1]) - - def test_unregister_nonexistent_subscriber(self): - self.assertFalse( - self.components.unregisterSubscriptionAdapter(required=[I1], - provided=IA2)) - -class TestUtility(unittest.TestCase): - - def setUp(self): - self.components = Components('comps') - - def test_register_utility(self): - test_object = U1(1) - self.components.registerUtility(test_object) - self.assertEqual(self.components.getUtility(I1), test_object) - - def test_register_utility_with_factory(self): - test_object = U1(1) - def factory(): - return test_object - self.components.registerUtility(factory=factory) - self.assertEqual(self.components.getUtility(I1), test_object) - self.assertTrue(self.components.unregisterUtility(factory=factory)) - - def test_register_utility_with_component_and_factory(self): - def factory(): - return U1(1) - self.assertRaises( - TypeError, - self.components.registerUtility, U1(1), factory=factory) - - def test_unregister_utility_with_and_without_component_and_factory(self): - def factory(): - return U1(1) - self.assertRaises( - TypeError, - self.components.unregisterUtility, U1(1), factory=factory) - self.assertRaises(TypeError, self.components.unregisterUtility) - - def test_register_utility_with_no_interfaces(self): - self.assertRaises(TypeError, self.components.registerUtility, A) - - def test_register_utility_with_two_interfaces(self): - self.assertRaises(TypeError, self.components.registerUtility, U12(1)) - - def test_register_utility_with_arguments(self): - test_object1 = U12(1) - test_object2 = U12(2) - self.components.registerUtility(test_object1, I2) - self.components.registerUtility(test_object2, I2, 'name') - self.assertEqual(self.components.getUtility(I2), test_object1) - self.assertEqual(self.components.getUtility(I2, 'name'), test_object2) - - def test_get_none_existing_utility(self): - from zope.interface.interfaces import ComponentLookupError - self.assertRaises(ComponentLookupError, self.components.getUtility, I3) - - def test_query_none_existing_utility(self): - self.assertTrue(self.components.queryUtility(I3) is None) - self.assertEqual(self.components.queryUtility(I3, default=42), 42) - - def test_registered_utilities_and_sorting(self): - test_object1 = U1(1) - test_object2 = U12(2) - test_object3 = U12(3) - self.components.registerUtility(test_object1) - self.components.registerUtility(test_object3, I2, u'name') - self.components.registerUtility(test_object2, I2) - - sorted_utilities = sorted(self.components.registeredUtilities()) - sorted_utilities_name = map(lambda x: getattr(x, 'name'), - sorted_utilities) - sorted_utilities_component = map(lambda x: getattr(x, 'component'), - sorted_utilities) - sorted_utilities_provided = map(lambda x: getattr(x, 'provided'), - sorted_utilities) - - self.assertEqual(len(sorted_utilities), 3) - self.assertEqual(sorted_utilities_name, [u'', u'', u'name']) + def test_getMultiAdapter_hit(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + ibaz = IFoo('IBaz') + @implementer(ibar) + class _Context1(object): + pass + @implementer(ibaz) + class _Context2(object): + pass + _context1 = _Context1() + _context2 = _Context2() + class _Factory(object): + def __init__(self, context1, context2): + self.context = context1, context2 + comp = self._makeOne() + comp.registerAdapter(_Factory, (ibar, ibaz), ifoo) + adapter = comp.getMultiAdapter((_context1, _context2), ifoo) + self.failUnless(isinstance(adapter, _Factory)) + self.assertEqual(adapter.context, (_context1, _context2)) + + def test_getAdapters_empty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + ibaz = IFoo('IBaz') + @implementer(ibar) + class _Context1(object): + pass + @implementer(ibaz) + class _Context2(object): + pass + _context1 = _Context1() + _context2 = _Context2() + comp = self._makeOne() self.assertEqual( - sorted_utilities_component, - [test_object1, test_object2, test_object3]) - self.assertEqual(sorted_utilities_provided, [I1, I2, I2]) - - def test_duplicate_utility(self): - test_object1 = U1(1) - test_object2 = U12(2) - test_object3 = U12(3) - test_object4 = U1(4) - self.components.registerUtility(test_object1) - self.components.registerUtility(test_object2, I2) - self.components.registerUtility(test_object3, I2, u'name') - self.assertEqual(self.components.getUtility(I1), test_object1) - - self.components.registerUtility(test_object4, info=u'use 4 now') - self.assertEqual(self.components.getUtility(I1), test_object4) - - def test_unregister_utility(self): - test_object = U1(1) - self.components.registerUtility(test_object) - self.assertEqual(self.components.getUtility(I1), test_object) - self.assertTrue(self.components.unregisterUtility(provided=I1)) - self.assertFalse(self.components.unregisterUtility(provided=I1)) - - def test_unregister_utility_extended(self): - test_object = U1(1) - self.components.registerUtility(test_object) - self.assertFalse(self.components.unregisterUtility(U1(1))) - self.assertEqual(self.components.queryUtility(I1), test_object) - self.assertTrue(self.components.unregisterUtility(test_object)) - self.assertTrue(self.components.queryUtility(I1) is None) - - def test_get_utilities_for(self): - test_object1 = U1(1) - test_object2 = U12(2) - test_object3 = U12(3) - self.components.registerUtility(test_object1) - self.components.registerUtility(test_object2, I2) - self.components.registerUtility(test_object3, I2, u'name') - - sorted_utilities = sorted(self.components.getUtilitiesFor(I2)) - self.assertEqual(len(sorted_utilities), 2) - self.assertEqual(sorted_utilities[0], (u'', test_object2)) - self.assertEqual(sorted_utilities[1], (u'name', test_object3)) - - def test_get_all_utilities_registered_for(self): - test_object1 = U1(1) - test_object2 = U12(2) - test_object3 = U12(3) - test_object4 = U('ext') - self.components.registerUtility(test_object1) - self.components.registerUtility(test_object2, I2) - self.components.registerUtility(test_object3, I2, u'name') - self.components.registerUtility(test_object4, I2e) - - sorted_utilities = sorted(self.components.getUtilitiesFor(I2)) - self.assertEqual(len(sorted_utilities), 2) - self.assertEqual(sorted_utilities[0], (u'', test_object2)) - self.assertEqual(sorted_utilities[1], (u'name', test_object3)) - - all_utilities = self.components.getAllUtilitiesRegisteredFor(I2) - self.assertEqual(len(all_utilities), 3) - self.assertTrue(test_object2 in all_utilities) - self.assertTrue(test_object3 in all_utilities) - self.assertTrue(test_object4 in all_utilities) - - self.assertTrue(self.components.unregisterUtility(test_object4, I2e)) - self.assertEqual(self.components.getAllUtilitiesRegisteredFor(I2e), []) - - def test_utility_events(self): - from zope.event import subscribers - old_subscribers = subscribers[:] - subscribers[:] = [] - - test_object = U1(1) - def log_event(event): - self.assertEqual(event.object.component, test_object) - subscribers.append(log_event) - self.components.registerUtility(test_object) - - subscribers[:] = old_subscribers - - def test_dont_leak_utility_registrations_in__subscribers(self): - """ - We've observed utilities getting left in _subscribers when they - get unregistered. - - """ - class C: - def __init__(self, name): - self.name = name - def __repr__(self): - return "C(%s)" % self.name - - c1 = C(1) - c2 = C(2) - - self.components.registerUtility(c1, I1) - self.components.registerUtility(c1, I1) - utilities = list(self.components.getAllUtilitiesRegisteredFor(I1)) - self.assertEqual(len(utilities), 1) - self.assertEqual(utilities[0], c1) - - self.assertTrue(self.components.unregisterUtility(provided=I1)) - utilities = list(self.components.getAllUtilitiesRegisteredFor(I1)) - self.assertEqual(len(utilities), 0) - - self.components.registerUtility(c1, I1) - self.components.registerUtility(c2, I1) - - utilities = list(self.components.getAllUtilitiesRegisteredFor(I1)) - self.assertEqual(len(utilities), 1) - self.assertEqual(utilities[0], c2) - - -class TestExtending(unittest.TestCase): - - def test_extendning(self): - c1 = Components('1') - self.assertEqual(c1.__bases__, ()) - - c2 = Components('2', (c1, )) - self.assertTrue(c2.__bases__ == (c1, )) - - test_object1 = U1(1) - test_object2 = U1(2) - test_object3 = U12(1) - test_object4 = U12(3) - - self.assertEqual(len(list(c1.registeredUtilities())), 0) - self.assertEqual(len(list(c2.registeredUtilities())), 0) - - c1.registerUtility(test_object1) - self.assertEqual(len(list(c1.registeredUtilities())), 1) - self.assertEqual(len(list(c2.registeredUtilities())), 0) - self.assertEqual(c1.queryUtility(I1), test_object1) - self.assertEqual(c2.queryUtility(I1), test_object1) - - c1.registerUtility(test_object2) - self.assertEqual(len(list(c1.registeredUtilities())), 1) - self.assertEqual(len(list(c2.registeredUtilities())), 0) - self.assertEqual(c1.queryUtility(I1), test_object2) - self.assertEqual(c2.queryUtility(I1), test_object2) - - - c3 = Components('3', (c1, )) - c4 = Components('4', (c2, c3)) - self.assertEqual(c4.queryUtility(I1), test_object2) - - c1.registerUtility(test_object3, I2) - self.assertEqual(c4.queryUtility(I2), test_object3) + list(comp.getAdapters((_context1, _context2), ifoo)), []) - c3.registerUtility(test_object4, I2) - self.assertEqual(c4.queryUtility(I2), test_object4) + def test_getAdapters_non_empty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + ibaz = IFoo('IBaz') + @implementer(ibar) + class _Context1(object): + pass + @implementer(ibaz) + class _Context2(object): + pass + _context1 = _Context1() + _context2 = _Context2() + class _Factory1(object): + def __init__(self, context1, context2): + self.context = context1, context2 + class _Factory2(object): + def __init__(self, context1, context2): + self.context = context1, context2 + _name1 = _u('name1') + _name2 = _u('name2') + comp = self._makeOne() + comp.registerAdapter(_Factory1, (ibar, ibaz), ifoo, name=_name1) + comp.registerAdapter(_Factory2, (ibar, ibaz), ifoo, name=_name2) + found = sorted(comp.getAdapters((_context1, _context2), ifoo)) + self.assertEqual(len(found), 2) + self.assertEqual(found[0][0], _name1) + self.failUnless(isinstance(found[0][1], _Factory1)) + self.assertEqual(found[1][0], _name2) + self.failUnless(isinstance(found[1][1], _Factory2)) + + def test_registerSubscriptionAdapter_w_nonblank_name(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _name = _u('name') + _info = _u('info') + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + self.assertRaises(TypeError, comp.registerSubscriptionAdapter, + _factory, (ibar,), ifoo, _name, _info) + + def test_registerSubscriptionAdapter_w_explicit_provided_and_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import SubscriptionRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _blank = _u('') + _info = _u('info') + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerSubscriptionAdapter(_factory, (ibar,), ifoo, + info=_info) + reg = comp.adapters._subscribers[1][ibar][ifoo][_blank] + self.assertEqual(len(reg), 1) + self.failUnless(reg[0] is _factory) + self.assertEqual(comp._subscription_registrations, + [((ibar,), ifoo, _blank, _factory, _info)]) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, SubscriptionRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, _blank) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _factory) + + def test_registerSubscriptionAdapter_wo_explicit_provided(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + from zope.interface.interfaces import Registered + from zope.interface.registry import SubscriptionRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _blank = _u('') + _to_reg = object() + @implementer(ifoo) + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerSubscriptionAdapter(_Factory, (ibar,), info=_info) + reg = comp.adapters._subscribers[1][ibar][ifoo][_blank] + self.assertEqual(len(reg), 1) + self.failUnless(reg[0] is _Factory) + self.assertEqual(comp._subscription_registrations, + [((ibar,), ifoo, _blank, _Factory, _info)]) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, SubscriptionRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, _blank) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _Factory) + + def test_registerSubscriptionAdapter_wo_explicit_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import SubscriptionRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _info = _u('info') + _blank = _u('') + class _Factory(object): + __component_adapts__ = (ibar,) + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerSubscriptionAdapter( + _Factory, provided=ifoo, info=_info) + reg = comp.adapters._subscribers[1][ibar][ifoo][_blank] + self.assertEqual(len(reg), 1) + self.failUnless(reg[0] is _Factory) + self.assertEqual(comp._subscription_registrations, + [((ibar,), ifoo, _blank, _Factory, _info)]) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, SubscriptionRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, _blank) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _Factory) + + def test_registerSubscriptionAdapter_wo_event(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _blank = _u('') + _info = _u('info') + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerSubscriptionAdapter(_factory, (ibar,), ifoo, + info=_info, event=False) + self.assertEqual(len(_events), 0) + + def test_registeredSubscriptionAdapters_empty(self): + comp = self._makeOne() + self.assertEqual(list(comp.registeredSubscriptionAdapters()), []) + + def test_registeredSubscriptionAdapters_notempty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IFoo') + _info = _u('info') + _blank = _u('') + class _Factory(object): + def __init__(self, context): + pass + comp = self._makeOne() + comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo, info=_info) + comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo, info=_info) + reg = list(comp.registeredSubscriptionAdapters()) + self.assertEqual(len(reg), 2) + self.failUnless(isinstance(reg[0], SubscriptionRegistration)) + self.failUnless(reg[0].registry is comp) + self.failUnless(reg[0].provided is ifoo) + self.assertEqual(reg[0].required, (ibar,)) + self.assertEqual(reg[0].name, _blank) + self.failUnless(reg[0].info is _info) + self.failUnless(reg[0].factory is _Factory) + self.failUnless(isinstance(reg[1], SubscriptionRegistration)) + self.failUnless(reg[1].registry is comp) + self.failUnless(reg[1].provided is ifoo) + self.assertEqual(reg[1].required, (ibar,)) + self.assertEqual(reg[1].name, _blank) + self.failUnless(reg[1].info is _info) + self.failUnless(reg[1].factory is _Factory) + + def test_unregisterSubscriptionAdapter_w_nonblank_name(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + _nonblank = _u('nonblank') + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterSubscriptionAdapter, + required=ifoo, provided=ibar, name=_nonblank) + + def test_unregisterSubscriptionAdapter_neither_factory_nor_provided(self): + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterSubscriptionAdapter, + factory=None, provided=None) + + def test_unregisterSubscriptionAdapter_neither_factory_nor_required(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterSubscriptionAdapter, + factory=None, provided=ifoo, required=None) + + def test_unregisterSubscriptionAdapter_miss(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterSubscriptionAdapter(_Factory, (ibar,), ifoo) + self.failIf(unreg) + self.failIf(_events) + + def test_unregisterSubscriptionAdapter_hit_wo_factory(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterSubscriptionAdapter(None, (ibar,), ifoo) + self.failUnless(unreg) + self.failIf(comp.adapters._subscribers) + self.failIf(comp._subscription_registrations) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, SubscriptionRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is None) + + def test_unregisterSubscriptionAdapter_hit_w_factory(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterSubscriptionAdapter(_Factory, (ibar,), ifoo) + self.failUnless(unreg) + self.failIf(comp.adapters._subscribers) + self.failIf(comp._subscription_registrations) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, SubscriptionRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is _Factory) + + def test_unregisterSubscriptionAdapter_wo_explicit_provided(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implementer + from zope.interface.interfaces import Unregistered + from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + @implementer(ifoo) + class _Factory(object): + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterSubscriptionAdapter(_Factory, (ibar,)) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, SubscriptionRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is _Factory) + + def test_unregisterSubscriptionAdapter_wo_explicit_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + __component_adapts__ = (ibar,) + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterSubscriptionAdapter(_Factory, provided=ifoo) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, SubscriptionRegistration)) + self.failUnless(event.object.registry is comp) + self.failUnless(event.object.provided is ifoo) + self.assertEqual(event.object.required, (ibar,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is _Factory) + + def test_subscribers_empty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implements + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + comp = self._makeOne() + class Bar(object): + implements(ibar) + bar = Bar() + self.assertEqual(list(comp.subscribers((bar,), ifoo)), []) + + def test_subscribers_non_empty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implements + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Factory(object): + __component_adapts__ = (ibar,) + def __init__(self, context): + self._context = context + class _Derived(_Factory): + pass + comp = self._makeOne() + comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo) + comp.registerSubscriptionAdapter(_Derived, (ibar,), ifoo) + class Bar(object): + implements(ibar) + bar = Bar() + subscribers = comp.subscribers((bar,), ifoo) + def _klassname(x): + return x.__class__.__name__ + subscribers = sorted(subscribers, key=_klassname) + self.assertEqual(len(subscribers), 2) + self.failUnless(isinstance(subscribers[0], _Derived)) + self.failUnless(isinstance(subscribers[1], _Factory)) + + def test_registerHandler_w_nonblank_name(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _nonblank = _u('nonblank') + comp = self._makeOne() + def _factory(context): + pass + self.assertRaises(TypeError, comp.registerHandler, _factory, + required=ifoo, name=_nonblank) + + def test_registerHandler_w_explicit_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import HandlerRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _blank = _u('') + _info = _u('info') + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerHandler(_factory, (ifoo,), info=_info) + reg = comp.adapters._subscribers[1][ifoo][None][_blank] + self.assertEqual(len(reg), 1) + self.failUnless(reg[0] is _factory) + self.assertEqual(comp._handler_registrations, + [((ifoo,), _blank, _factory, _info)]) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, HandlerRegistration)) + self.failUnless(event.object.registry is comp) + self.assertEqual(event.object.required, (ifoo,)) + self.assertEqual(event.object.name, _blank) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _factory) + + def test_registerHandler_wo_explicit_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Registered + from zope.interface.registry import HandlerRegistration + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _info = _u('info') + _blank = _u('') + class _Factory(object): + __component_adapts__ = (ifoo,) + def __init__(self, context): + self._context = context + comp = self._makeOne() + _monkey, _events = self._wrapEvents() + with _monkey: + comp.registerHandler(_Factory, info=_info) + reg = comp.adapters._subscribers[1][ifoo][None][_blank] + self.assertEqual(len(reg), 1) + self.failUnless(reg[0] is _Factory) + self.assertEqual(comp._handler_registrations, + [((ifoo,), _blank, _Factory, _info)]) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Registered)) + self.failUnless(isinstance(event.object, HandlerRegistration)) + self.failUnless(event.object.registry is comp) + self.assertEqual(event.object.required, (ifoo,)) + self.assertEqual(event.object.name, _blank) + self.failUnless(event.object.info is _info) + self.failUnless(event.object.factory is _Factory) + + def test_registeredHandlers_empty(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + comp = self._makeOne() + self.failIf(list(comp.registeredHandlers())) - @adapter(I1) - def handle1(x): - self.assertEqual(x, test_object1) + def test_registeredHandlers_non_empty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + def _factory1(context): + pass + def _factory2(context): + pass + comp = self._makeOne() + comp.registerHandler(_factory1, (ifoo,)) + comp.registerHandler(_factory2, (ifoo,)) + def _factory_name(x): + return x.factory.func_code.co_name + subscribers = sorted(comp.registeredHandlers(), key=_factory_name) + self.assertEqual(len(subscribers), 2) + self.failUnless(isinstance(subscribers[0], HandlerRegistration)) + self.assertEqual(subscribers[0].required, (ifoo,)) + self.assertEqual(subscribers[0].name, '') + self.assertEqual(subscribers[0].factory, _factory1) + self.assertEqual(subscribers[0].info, '') + self.failUnless(isinstance(subscribers[1], HandlerRegistration)) + self.assertEqual(subscribers[1].required, (ifoo,)) + self.assertEqual(subscribers[1].name, '') + self.assertEqual(subscribers[1].factory, _factory2) + self.assertEqual(subscribers[1].info, '') + + def test_unregisterHandler_w_nonblank_name(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _nonblank = _u('nonblank') + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterHandler, + required=(ifoo,), name=_nonblank) + + def test_unregisterHandler_neither_factory_nor_required(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + self.assertRaises(TypeError, comp.unregisterHandler) - def handle(*objects): - self.assertEqual(objects, (test_object1,)) + def test_unregisterHandler_miss(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + unreg = comp.unregisterHandler(required=(ifoo,)) + self.failIf(unreg) + + def test_unregisterHandler_hit_w_factory_and_explicit_provided(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + comp.registerHandler(_factory, (ifoo,)) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterHandler(_factory, (ifoo,)) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, HandlerRegistration)) + self.failUnless(event.object.registry is comp) + self.assertEqual(event.object.required, (ifoo,)) + self.assertEqual(event.object.name, '') + self.failUnless(event.object.factory is _factory) + + def test_unregisterHandler_hit_w_only_explicit_provided(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + _to_reg = object() + def _factory(context): + return _to_reg + comp = self._makeOne() + comp.registerHandler(_factory, (ifoo,)) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterHandler(required=(ifoo,)) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, HandlerRegistration)) + self.failUnless(event.object.registry is comp) + self.assertEqual(event.object.required, (ifoo,)) + self.assertEqual(event.object.name, '') + self.failUnless(event.object.factory is None) + + def test_unregisterHandler_wo_explicit_required(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.interfaces import Unregistered + from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + class _Factory(object): + __component_adapts__ = (ifoo,) + def __init__(self, context): + self._context = context + comp = self._makeOne() + comp.registerHandler(_Factory) + _monkey, _events = self._wrapEvents() + with _monkey: + unreg = comp.unregisterHandler(_Factory) + self.failUnless(unreg) + self.assertEqual(len(_events), 1) + args, kw = _events[0] + event, = args + self.assertEqual(kw, {}) + self.failUnless(isinstance(event, Unregistered)) + self.failUnless(isinstance(event.object, HandlerRegistration)) + self.failUnless(event.object.registry is comp) + self.assertEqual(event.object.required, (ifoo,)) + self.assertEqual(event.object.name, '') + self.assertEqual(event.object.info, '') + self.failUnless(event.object.factory is _Factory) + + def test_handle_empty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implements + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + comp = self._makeOne() + class Bar(object): + implements(ifoo) + bar = Bar() + comp.handle((bar,)) # doesn't raise + + def test_handle_non_empty(self): + from zope.interface.declarations import InterfaceClass + from zope.interface.declarations import implements + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + _called_1 = [] + def _factory_1(context): + _called_1.append(context) + _called_2 = [] + def _factory_2(context): + _called_2.append(context) + comp = self._makeOne() + comp.registerHandler(_factory_1, (ifoo,)) + comp.registerHandler(_factory_2, (ifoo,)) + class Bar(object): + implements(ifoo) + bar = Bar() + comp.handle(bar) + self.assertEqual(_called_1, [bar]) + self.assertEqual(_called_2, [bar]) + + +# Test _getUtilityProvided, _getAdapterProvided, _getAdapterRequired via their +# callers (Component.registerUtility, Component.registerAdapter). + + +class UtilityRegistrationTests(unittest.TestCase): + + def _getTargetClass(self): + from zope.interface.registry import UtilityRegistration + return UtilityRegistration + + def _makeOne(self, component=None, factory=None): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + class _Registry(object): + def __repr__(self): + return '_REGISTRY' + registry = _Registry() + name = _u('name') + doc = 'DOCSTRING' + klass = self._getTargetClass() + return (klass(registry, ifoo, name, component, doc, factory), + registry, + name, + ) + + def test_class_conforms_to_IUtilityRegistration(self): + from zope.interface.verify import verifyClass + from zope.interface.interfaces import IUtilityRegistration + verifyClass(IUtilityRegistration, self._getTargetClass()) + + def test_instance_conforms_to_IUtilityRegistration(self): + from zope.interface.verify import verifyObject + from zope.interface.interfaces import IUtilityRegistration + ur, _, _ = self._makeOne() + verifyObject(IUtilityRegistration, ur) + + def test___repr__(self): + class _Component(object): + __name__ = 'TEST' + _component = _Component() + ur, _registry, _name = self._makeOne(_component) + self.assertEqual(repr(ur), + "UtilityRegistration(_REGISTRY, IFoo, %r, TEST, None, 'DOCSTRING')" + % (_name)) + + def test___repr___provided_wo_name(self): + class _Component(object): + def __repr__(self): + return 'TEST' + _component = _Component() + ur, _registry, _name = self._makeOne(_component) + ur.provided = object() + self.assertEqual(repr(ur), + "UtilityRegistration(_REGISTRY, None, %r, TEST, None, 'DOCSTRING')" + % (_name)) + + def test___repr___component_wo_name(self): + class _Component(object): + def __repr__(self): + return 'TEST' + _component = _Component() + ur, _registry, _name = self._makeOne(_component) + ur.provided = object() + self.assertEqual(repr(ur), + "UtilityRegistration(_REGISTRY, None, %r, TEST, None, 'DOCSTRING')" + % (_name)) + + def test___hash__(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + self.assertEqual(hash(ur), id(ur)) + + def test___eq___identity(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + self.failUnless(ur == ur) + + def test___eq___hit(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component) + self.failUnless(ur == ur2) + + def test___eq___miss(self): + _component = object() + _component2 = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component2) + self.failIf(ur == ur2) + + def test___ne___identity(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + self.failIf(ur != ur) + + def test___ne___hit(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component) + self.failIf(ur != ur2) + + def test___ne___miss(self): + _component = object() + _component2 = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component2) + self.failUnless(ur != ur2) + + def test___lt___identity(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + self.failIf(ur < ur) + + def test___lt___hit(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component) + self.failIf(ur < ur2) + + def test___lt___miss(self): + _component = object() + _component2 = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component2) + ur2.name = _name + '2' + self.failUnless(ur < ur2) + + def test___le___identity(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + self.failUnless(ur <= ur) + + def test___le___hit(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component) + self.failUnless(ur <= ur2) + + def test___le___miss(self): + _component = object() + _component2 = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component2) + ur2.name = _name + '2' + self.failUnless(ur <= ur2) + + def test___gt___identity(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + self.failIf(ur > ur) + + def test___gt___hit(self): + _component = object() + _component2 = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component2) + ur2.name = _name + '2' + self.failUnless(ur2 > ur) + + def test___gt___miss(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component) + self.failIf(ur2 > ur) + + def test___ge___identity(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + self.failUnless(ur >= ur) + + def test___ge___miss(self): + _component = object() + _component2 = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component2) + ur2.name = _name + '2' + self.failIf(ur >= ur2) + + def test___ge___hit(self): + _component = object() + ur, _registry, _name = self._makeOne(_component) + ur2, _, _ = self._makeOne(_component) + ur2.name = _name + '2' + self.failUnless(ur2 >= ur) + + +class AdapterRegistrationTests(unittest.TestCase): + + def _getTargetClass(self): + from zope.interface.registry import AdapterRegistration + return AdapterRegistration + + def _makeOne(self, component=None): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Registry(object): + def __repr__(self): + return '_REGISTRY' + registry = _Registry() + name = _u('name') + doc = 'DOCSTRING' + klass = self._getTargetClass() + return (klass(registry, (ibar,), ifoo, name, component, doc), + registry, + name, + ) + + def test_class_conforms_to_IAdapterRegistration(self): + from zope.interface.verify import verifyClass + from zope.interface.interfaces import IAdapterRegistration + verifyClass(IAdapterRegistration, self._getTargetClass()) + + def test_instance_conforms_to_IAdapterRegistration(self): + from zope.interface.verify import verifyObject + from zope.interface.interfaces import IAdapterRegistration + ar, _, _ = self._makeOne() + verifyObject(IAdapterRegistration, ar) + + def test___repr__(self): + class _Component(object): + __name__ = 'TEST' + _component = _Component() + ar, _registry, _name = self._makeOne(_component) + self.assertEqual(repr(ar), + ("AdapterRegistration(_REGISTRY, [IBar], IFoo, %r, TEST, " + + "'DOCSTRING')") % (_name)) + + def test___repr___provided_wo_name(self): + class _Component(object): + def __repr__(self): + return 'TEST' + _component = _Component() + ar, _registry, _name = self._makeOne(_component) + ar.provided = object() + self.assertEqual(repr(ar), + ("AdapterRegistration(_REGISTRY, [IBar], None, %r, TEST, " + + "'DOCSTRING')") % (_name)) + + def test___repr___component_wo_name(self): + class _Component(object): + def __repr__(self): + return 'TEST' + _component = _Component() + ar, _registry, _name = self._makeOne(_component) + ar.provided = object() + self.assertEqual(repr(ar), + ("AdapterRegistration(_REGISTRY, [IBar], None, %r, TEST, " + + "'DOCSTRING')") % (_name)) + + def test___hash__(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + self.assertEqual(hash(ar), id(ar)) + + def test___eq___identity(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + self.failUnless(ar == ar) + + def test___eq___hit(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component) + self.failUnless(ar == ar2) + + def test___eq___miss(self): + _component = object() + _component2 = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component2) + self.failIf(ar == ar2) + + def test___ne___identity(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + self.failIf(ar != ar) + + def test___ne___miss(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component) + self.failIf(ar != ar2) + + def test___ne___hit_component(self): + _component = object() + _component2 = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component2) + self.failUnless(ar != ar2) + + def test___ne___hit_provided(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ibaz = IFoo('IBaz') + _component = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component) + ar2.provided = ibaz + self.failUnless(ar != ar2) + + def test___ne___hit_required(self): + from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): + pass + ibaz = IFoo('IBaz') + _component = object() + _component2 = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component2) + ar2.required = (ibaz,) + self.failUnless(ar != ar2) + + def test___lt___identity(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + self.failIf(ar < ar) + + def test___lt___hit(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component) + self.failIf(ar < ar2) + + def test___lt___miss(self): + _component = object() + _component2 = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component2) + ar2.name = _name + '2' + self.failUnless(ar < ar2) + + def test___le___identity(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + self.failUnless(ar <= ar) + + def test___le___hit(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component) + self.failUnless(ar <= ar2) + + def test___le___miss(self): + _component = object() + _component2 = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component2) + ar2.name = _name + '2' + self.failUnless(ar <= ar2) + + def test___gt___identity(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + self.failIf(ar > ar) + + def test___gt___hit(self): + _component = object() + _component2 = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component2) + ar2.name = _name + '2' + self.failUnless(ar2 > ar) + + def test___gt___miss(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component) + self.failIf(ar2 > ar) + + def test___ge___identity(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + self.failUnless(ar >= ar) + + def test___ge___miss(self): + _component = object() + _component2 = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component2) + ar2.name = _name + '2' + self.failIf(ar >= ar2) + + def test___ge___hit(self): + _component = object() + ar, _registry, _name = self._makeOne(_component) + ar2, _, _ = self._makeOne(_component) + ar2.name = _name + '2' + self.failUnless(ar2 >= ar) + + +class SubscriptionRegistrationTests(unittest.TestCase): + + def _getTargetClass(self): + from zope.interface.registry import SubscriptionRegistration + return SubscriptionRegistration + + def _makeOne(self, component=None): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + ibar = IFoo('IBar') + class _Registry(object): + def __repr__(self): + return '_REGISTRY' + registry = _Registry() + name = _u('name') + doc = 'DOCSTRING' + klass = self._getTargetClass() + return (klass(registry, (ibar,), ifoo, name, component, doc), + registry, + name, + ) + + def test_class_conforms_to_ISubscriptionAdapterRegistration(self): + from zope.interface.verify import verifyClass + from zope.interface.interfaces import ISubscriptionAdapterRegistration + verifyClass(ISubscriptionAdapterRegistration, self._getTargetClass()) + + def test_instance_conforms_to_ISubscriptionAdapterRegistration(self): + from zope.interface.verify import verifyObject + from zope.interface.interfaces import ISubscriptionAdapterRegistration + sar, _, _ = self._makeOne() + verifyObject(ISubscriptionAdapterRegistration, sar) + + +class HandlerRegistrationTests(unittest.TestCase): + + def _getTargetClass(self): + from zope.interface.registry import HandlerRegistration + return HandlerRegistration + + def _makeOne(self, component=None): + from zope.interface.declarations import InterfaceClass + from zope.interface.registry import _u + class IFoo(InterfaceClass): + pass + ifoo = IFoo('IFoo') + class _Registry(object): + def __repr__(self): + return '_REGISTRY' + registry = _Registry() + name = _u('name') + doc = 'DOCSTRING' + klass = self._getTargetClass() + return (klass(registry, (ifoo,), name, component, doc), + registry, + name, + ) + + def test_class_conforms_to_IHandlerRegistration(self): + from zope.interface.verify import verifyClass + from zope.interface.interfaces import IHandlerRegistration + verifyClass(IHandlerRegistration, self._getTargetClass()) + + def test_instance_conforms_to_IHandlerRegistration(self): + from zope.interface.verify import verifyObject + from zope.interface.interfaces import IHandlerRegistration + hr, _, _ = self._makeOne() + verifyObject(IHandlerRegistration, hr) + + def test_properties(self): + def _factory(context): + pass + hr, _, _ = self._makeOne(_factory) + self.failUnless(hr.handler is _factory) + self.failUnless(hr.factory is hr.handler) + self.failUnless(hr.provided is None) + + def test___repr___factory_w_name(self): + class _Factory(object): + __name__ = 'TEST' + hr, _registry, _name = self._makeOne(_Factory()) + self.assertEqual(repr(hr), + ("HandlerRegistration(_REGISTRY, [IFoo], %r, TEST, " + + "'DOCSTRING')") % (_name)) + + def test___repr___factory_wo_name(self): + class _Factory(object): + def __repr__(self): + return 'TEST' + hr, _registry, _name = self._makeOne(_Factory()) + self.assertEqual(repr(hr), + ("HandlerRegistration(_REGISTRY, [IFoo], %r, TEST, " + + "'DOCSTRING')") % (_name)) - @adapter(I1) - def handle3(x): - self.assertEqual(x, test_object1) - @adapter(I1) - def handle4(x): - self.assertEqual(x, test_object1) +class _Monkey(object): + # context-manager for replacing module names in the scope of a test. + def __init__(self, module, **kw): + self.module = module + self.to_restore = dict([(key, getattr(module, key)) for key in kw]) + for key, value in kw.items(): + setattr(module, key, value) - c1.registerHandler(handle1, info=u'First handler') - c2.registerHandler(handle, required=[U]) - c3.registerHandler(handle3) - c4.registerHandler(handle4) + def __enter__(self): + return self - c4.handle(test_object1) + def __exit__(self, exc_type, exc_val, exc_tb): + for key, value in self.to_restore.items(): + setattr(self.module, key, value) def test_suite(): return unittest.TestSuite(( - unittest.makeSuite(TestUtility), - unittest.makeSuite(TestAdapter), - unittest.makeSuite(TestSubscriber), - unittest.makeSuite(TestHandler), - unittest.makeSuite(TestExtending) + unittest.makeSuite(ComponentsTests), + unittest.makeSuite(UtilityRegistrationTests), + unittest.makeSuite(AdapterRegistrationTests), + unittest.makeSuite(SubscriptionRegistrationTests), + unittest.makeSuite(AdapterRegistrationTests), )) diff --git a/src/zope/interface/tests/test_verify.py b/src/zope/interface/tests/test_verify.py index 1e2282f..5585f43 100644 --- a/src/zope/interface/tests/test_verify.py +++ b/src/zope/interface/tests/test_verify.py @@ -11,190 +11,534 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -"""Interface Verify tests +""" zope.interface.verify unit tests """ -import doctest import unittest -from zope.interface import Interface, implements, classImplements, Attribute -from zope.interface.verify import verifyClass, verifyObject -from zope.interface.exceptions import DoesNotImplement, BrokenImplementation -from zope.interface.exceptions import BrokenMethodImplementation -class Test(unittest.TestCase): +class Test_verifyClass(unittest.TestCase): - def testNotImplemented(self): + def _callFUT(self, iface, klass): + from zope.interface.verify import verifyClass + return verifyClass(iface, klass) - class C(object): pass + def test_class_doesnt_implement(self): + from zope.interface import Interface + from zope.interface.exceptions import DoesNotImplement - class I(Interface): pass + class ICurrent(Interface): + pass + + class Current(object): + pass + + self.assertRaises(DoesNotImplement, self._callFUT, ICurrent, Current) + + def test_class_doesnt_implement_but_classImplements_later(self): + from zope.interface import Interface + from zope.interface import classImplements + + class ICurrent(Interface): + pass + + class Current(object): + pass - self.assertRaises(DoesNotImplement, verifyClass, I, C) + classImplements(Current, ICurrent) - classImplements(C, I) + self._callFUT(ICurrent, Current) - verifyClass(I, C) + def test_class_doesnt_have_required_method_simple(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenImplementation - def testMissingAttr(self): + class ICurrent(Interface): + def method(): pass - class I(Interface): - def f(): pass + class Current(object): + implements(ICurrent) - class C(object): - implements(I) + self.assertRaises(BrokenImplementation, + self._callFUT, ICurrent, Current) - self.assertRaises(BrokenImplementation, verifyClass, I, C) + def test_class_has_required_method_simple(self): + from zope.interface import Interface + from zope.interface import implements - C.f=lambda self: None + class ICurrent(Interface): + def method(): pass - verifyClass(I, C) + class Current(object): + implements(ICurrent) - def testMissingAttr_with_Extended_Interface(self): + def method(self): + pass + + self._callFUT(ICurrent, Current) + + def test_class_doesnt_have_required_method_derived(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenImplementation - class II(Interface): - def f(): + class IBase(Interface): + def method(): pass - class I(II): + class IDerived(IBase): pass - class C(object): - implements(I) + class Current(object): + implements(IDerived) - self.assertRaises(BrokenImplementation, verifyClass, I, C) + self.assertRaises(BrokenImplementation, + self._callFUT, IDerived, Current) - C.f=lambda self: None + def test_class_has_required_method_derived(self): + from zope.interface import Interface + from zope.interface import implements - verifyClass(I, C) + class IBase(Interface): + def method(): + pass - def testWrongArgs(self): + class IDerived(IBase): + pass - class I(Interface): - def f(a): pass + class Current(object): + implements(IDerived) - class C(object): - def f(self, b): pass + def method(self): + pass - implements(I) + self._callFUT(IDerived, Current) + def test_method_takes_wrong_arg_names_but_OK(self): # We no longer require names to match. - #self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + + def method(a): + pass - C.f=lambda self, a: None + class Current(object): + implements(ICurrent) - verifyClass(I, C) + def method(self, b): + pass + + self._callFUT(ICurrent, Current) - C.f=lambda self, **kw: None + def test_method_takes_not_enough_args(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) + class ICurrent(Interface): - C.f=lambda self, a, *args: None + def method(a): + pass - verifyClass(I, C) + class Current(object): + implements(ICurrent) + + def method(self): + pass - C.f=lambda self, a, *args, **kw: None + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) - verifyClass(I, C) + def test_method_doesnt_take_required_starargs(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation - C.f=lambda self, *args: None + class ICurrent(Interface): - verifyClass(I, C) + def method(*args): + pass + + class Current(object): + implements(ICurrent) + + def method(self): + pass - def testExtraArgs(self): + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) - class I(Interface): - def f(a): pass + def test_method_doesnt_take_required_only_kwargs(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation - class C(object): - def f(self, a, b): pass + class ICurrent(Interface): - implements(I) + def method(**kw): + pass - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) + class Current(object): + implements(ICurrent) - C.f=lambda self, a: None + def method(self): + pass - verifyClass(I, C) + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) - C.f=lambda self, a, b=None: None + def test_method_takes_extra_arg(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation - verifyClass(I, C) + class ICurrent(Interface): - def testNoVar(self): + def method(a): + pass - class I(Interface): - def f(a, *args): pass + class Current(object): + implements(ICurrent) - class C(object): - def f(self, a): pass + def method(self, a, b): + pass - implements(I) + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) + def test_method_takes_extra_arg_with_default(self): + from zope.interface import Interface + from zope.interface import implements - C.f=lambda self, a, *foo: None + class ICurrent(Interface): - verifyClass(I, C) + def method(a): + pass - def testNoKW(self): + class Current(object): + implements(ICurrent) - class I(Interface): - def f(a, **args): pass + def method(self, a, b=None): + pass - class C(object): - def f(self, a): pass + self._callFUT(ICurrent, Current) - implements(I) + def test_method_takes_only_positional_args(self): + from zope.interface import Interface + from zope.interface import implements - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) + class ICurrent(Interface): - C.f=lambda self, a, **foo: None + def method(a): + pass - verifyClass(I, C) + class Current(object): + implements(ICurrent) - def testModule(self): + def method(self, *args): + pass - from zope.interface.tests.ifoo import IFoo - from zope.interface.tests import dummy + self._callFUT(ICurrent, Current) + + def test_method_takes_only_kwargs(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation + + class ICurrent(Interface): + + def method(a): + pass + + class Current(object): + implements(ICurrent) + + def method(self, **kw): + pass + + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) + + def test_method_takes_extra_starargs(self): + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + + def method(a): + pass + + class Current(object): + implements(ICurrent) + + def method(self, a, *args): + pass + + self._callFUT(ICurrent, Current) + + def test_method_takes_extra_starargs_and_kwargs(self): + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + + def method(a): + pass + + class Current(object): + implements(ICurrent) + + def method(self, a, *args, **kw): + pass + + self._callFUT(ICurrent, Current) + + def test_method_doesnt_take_required_positional_and_starargs(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation + + class ICurrent(Interface): + + def method(a, *args): + pass + + class Current(object): + implements(ICurrent) + + def method(self, a): + pass + + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) + + def test_method_takes_required_positional_and_starargs(self): + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + + def method(a, *args): + pass + + class Current(object): + implements(ICurrent) + + def method(self, a, *args): + pass + + self._callFUT(ICurrent, Current) + + def test_method_takes_only_starargs(self): + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + + def method(a, *args): + pass + + class Current(object): + implements(ICurrent) + + def method(self, *args): + pass + + self._callFUT(ICurrent, Current) + + def test_method_takes_required_kwargs(self): + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + + def method(**kwargs): + pass + + class Current(object): + implements(ICurrent) - verifyObject(IFoo, dummy) + def method(self, **kw): + pass + + self._callFUT(ICurrent, Current) + + def test_method_takes_positional_plus_required_starargs(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation + + class ICurrent(Interface): + + def method(*args): + pass + + class Current(object): + implements(ICurrent) + + def method(self, a, *args): + pass - def testMethodForAttr(self): - - class IFoo(Interface): - foo = Attribute("The foo Attribute") + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) - class Foo: - implements(IFoo) + def test_method_doesnt_take_required_kwargs(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation - def foo(self): - pass + class ICurrent(Interface): - verifyClass(IFoo, Foo) + def method(**kwargs): + pass + + class Current(object): + implements(ICurrent) + + def method(self, a): + pass + + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) - def testNonMethodForMethod(self): - class IBar(Interface): - def foo(): - pass + def test_class_has_method_for_iface_attr(self): + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + attr = Attribute("The foo Attribute") + + class Current: + implements(ICurrent) + + def attr(self): + pass - class Bar: - implements(IBar) + self._callFUT(ICurrent, Current) + + def test_class_has_nonmethod_for_method(self): + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenMethodImplementation + + class ICurrent(Interface): + def method(): + pass + + class Current: + implements(ICurrent) + method = 1 + + self.assertRaises(BrokenMethodImplementation, + self._callFUT, ICurrent, Current) + + def test_class_has_attribute_for_attribute(self): + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + attr = Attribute("The foo Attribute") + + class Current: + implements(ICurrent) + + attr = 1 + + self._callFUT(ICurrent, Current) + + def test_class_misses_attribute_for_attribute(self): + # This check *passes* for verifyClass + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface import implements + + class ICurrent(Interface): + attr = Attribute("The foo Attribute") + + class Current: + implements(ICurrent) + + self._callFUT(ICurrent, Current) + + def test_w_callable_non_func_method(self): + from zope.interface.interface import Method + from zope.interface import Interface + from zope.interface import implements + + class QuasiMethod(Method): + def __call__(self, *args, **kw): + pass + + class QuasiCallable(object): + def __call__(self, *args, **kw): + pass + + class ICurrent(Interface): + attr = QuasiMethod('This is callable') + + class Current: + implements(ICurrent) + attr = QuasiCallable() + + self._callFUT(ICurrent, Current) + +class Test_verifyObject(Test_verifyClass): + + def _callFUT(self, iface, target): + from zope.interface.verify import verifyObject + if isinstance(target, (type, type(OldSkool))): + target = target() + return verifyObject(iface, target) + + def test_class_misses_attribute_for_attribute(self): + # This check *fails* for verifyObject + from zope.interface import Attribute + from zope.interface import Interface + from zope.interface import implements + from zope.interface.exceptions import BrokenImplementation + + class ICurrent(Interface): + attr = Attribute("The foo Attribute") + + class Current: + implements(ICurrent) + + self.assertRaises(BrokenImplementation, + self._callFUT, ICurrent, Current) + + def test_module_hit(self): + from zope.interface.tests.idummy import IDummyModule + from zope.interface.tests import dummy + + self._callFUT(IDummyModule, dummy) + + def test_module_miss(self): + from zope.interface import Interface + from zope.interface.tests import dummy + from zope.interface.exceptions import DoesNotImplement + + # same name, different object + class IDummyModule(Interface): + pass - foo = 1 + self.assertRaises(DoesNotImplement, + self._callFUT, IDummyModule, dummy) - self.assertRaises(BrokenMethodImplementation, verifyClass, IBar, Bar) - +class OldSkool: + pass def test_suite(): - loader=unittest.TestLoader() + #import doctest return unittest.TestSuite(( - doctest.DocFileSuite( - '../verify.txt', - optionflags=doctest.NORMALIZE_WHITESPACE), - loader.loadTestsFromTestCase(Test), - )) - -if __name__=='__main__': - unittest.TextTestRunner().run(test_suite()) + unittest.makeSuite(Test_verifyClass), + unittest.makeSuite(Test_verifyObject), + # This one needs to turn into just docs. + #doctest.DocFileSuite('../verify.txt', + # optionflags=doctest.NORMALIZE_WHITESPACE), + )) diff --git a/src/zope/interface/tests/unitfixtures.py b/src/zope/interface/tests/unitfixtures.py deleted file mode 100644 index c47eaf0..0000000 --- a/src/zope/interface/tests/unitfixtures.py +++ /dev/null @@ -1,140 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Foundation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Unit Test Fixtures -""" -from zope.interface import Interface, invariant -from zope.interface.interface import Attribute -from zope.interface.exceptions import Invalid - -class mytest(Interface): - pass - -class C(object): - def m1(self, a, b): - "return 1" - return 1 - - def m2(self, a, b): - "return 2" - return 2 - -# testInstancesOfClassImplements - -# YAGNI IC=Interface.impliedInterface(C) -class IC(Interface): - def m1(a, b): - "return 1" - - def m2(a, b): - "return 2" - - - -C.__implemented__=IC - -class I1(Interface): - def ma(): - "blah" - -class I2(I1): pass - -class I3(Interface): pass - -class I4(Interface): pass - -class A(I1.deferred()): - __implemented__=I1 - -class B(object): - __implemented__=I2, I3 - -class D(A, B): pass - -class E(A, B): - __implemented__ = A.__implemented__, C.__implemented__ - - -class FooInterface(Interface): - """ This is an Abstract Base Class """ - - foobar = Attribute("fuzzed over beyond all recognition") - - def aMethod(foo, bar, bingo): - """ This is aMethod """ - - def anotherMethod(foo=6, bar="where you get sloshed", bingo=(1,3,)): - """ This is anotherMethod """ - - def wammy(zip, *argues): - """ yadda yadda """ - - def useless(**keywords): - """ useless code is fun! """ - -class Foo(object): - """ A concrete class """ - - __implemented__ = FooInterface, - - foobar = "yeah" - - def aMethod(self, foo, bar, bingo): - """ This is aMethod """ - return "barf!" - - def anotherMethod(self, foo=6, bar="where you get sloshed", bingo=(1,3,)): - """ This is anotherMethod """ - return "barf!" - - def wammy(self, zip, *argues): - """ yadda yadda """ - return "barf!" - - def useless(self, **keywords): - """ useless code is fun! """ - return "barf!" - -foo_instance = Foo() - -class Blah(object): - pass - -new = Interface.__class__ -FunInterface = new('FunInterface') -BarInterface = new('BarInterface', [FunInterface]) -BobInterface = new('BobInterface') -BazInterface = new('BazInterface', [BobInterface, BarInterface]) - -# fixtures for invariant tests -def ifFooThenBar(obj): - if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None): - raise Invalid('If Foo, then Bar!') -class IInvariant(Interface): - foo = Attribute('foo') - bar = Attribute('bar; must eval to Boolean True if foo does') - invariant(ifFooThenBar) -def BarGreaterThanFoo(obj): - foo = getattr(obj, 'foo', None) - bar = getattr(obj, 'bar', None) - if foo is not None and isinstance(foo, type(bar)): - # type checking should be handled elsewhere (like, say, - # schema); these invariants should be intra-interface - # constraints. This is a hacky way to do it, maybe, but you - # get the idea - if not bar > foo: - raise Invalid('Please, Boo MUST be greater than Foo!') -class ISubInvariant(IInvariant): - invariant(BarGreaterThanFoo) -class InvariantC(object): - pass diff --git a/src/zope/interface/verify.py b/src/zope/interface/verify.py index da60b6e..0c9369c 100644 --- a/src/zope/interface/verify.py +++ b/src/zope/interface/verify.py @@ -68,7 +68,8 @@ def _verify(iface, candidate, tentative=0, vtype=None): if isinstance(attr, FunctionType): if sys.version[0] == '3' and isinstance(candidate, type): # This is an "unbound method" in Python 3. - meth = fromFunction(attr, iface, name=name, imlevel=1) + meth = fromFunction(attr, iface, name=name, + imlevel=1) #pragma NO COVERAGE else: # Nope, just a normal function meth = fromFunction(attr, iface, name=name) @@ -78,9 +79,9 @@ def _verify(iface, candidate, tentative=0, vtype=None): else: if not callable(attr): raise BrokenMethodImplementation(name, "Not a method") - # sigh, it's callable, but we don't know how to intrspect it, so + # sigh, it's callable, but we don't know how to introspect it, so # we have to give it a pass. - continue + continue #pragma NO COVERAGE # Make sure that the required and implemented method signatures are # the same. diff --git a/src/zope/interface/verify.txt b/src/zope/interface/verify.txt deleted file mode 100644 index 7eec6d2..0000000 --- a/src/zope/interface/verify.txt +++ /dev/null @@ -1,127 +0,0 @@ -=================================== -Verifying interface implementations -=================================== - -The ``zope.interface.verify`` module provides functions that test whether a -given interface is implemented by a class or provided by an object, resp. - - -Verifying classes -================= - -This is covered by unit tests defined in ``zope.interface.tests.test_verify``. - - -Verifying objects -================= - -An object provides an interface if - -- either its class declares that it implements the interfaces, or the object - declares that it directly provides the interface - -- the object defines all the methods required by the interface - -- all the methods have the correct signature - -- the object defines all non-method attributes required by the interface - -This doctest currently covers only the latter item. - -Testing for attributes ----------------------- - -Attributes of the object, be they defined by its class or added by its -``__init__`` method, will be recognized: - ->>> from zope.interface import Interface, Attribute, implements ->>> from zope.interface.exceptions import BrokenImplementation ->>> class IFoo(Interface): -... x = Attribute("The X attribute") -... y = Attribute("The Y attribute") - ->>> class Foo(object): -... implements(IFoo) -... x = 1 -... def __init__(self): -... self.y = 2 - ->>> from zope.interface.verify import verifyObject ->>> verifyObject(IFoo, Foo()) -True - -If either attribute is missing, verification will fail: - ->>> class Foo(object): -... implements(IFoo) -... x = 1 - ->>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS -... verifyObject(IFoo, Foo()) -... except BrokenImplementation, e: -... print str(e) -An object has failed to implement interface <InterfaceClass ...IFoo> -<BLANKLINE> - The y attribute was not provided. -<BLANKLINE> - ->>> class Foo(object): -... implements(IFoo) -... def __init__(self): -... self.y = 2 - ->>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS -... verifyObject(IFoo, Foo()) -... except BrokenImplementation, e: -... print str(e) -An object has failed to implement interface <InterfaceClass ...IFoo> -<BLANKLINE> - The x attribute was not provided. -<BLANKLINE> - -If an attribute is implemented as a property that raises an AttributeError -when trying to get its value, the attribute is considered missing: - ->>> class IFoo(Interface): -... x = Attribute('The X attribute') - ->>> class Foo(object): -... implements(IFoo) -... @property -... def x(self): -... raise AttributeError - ->>> try: #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS -... verifyObject(IFoo, Foo()) -... except BrokenImplementation, e: -... print str(e) -An object has failed to implement interface <InterfaceClass ...IFoo> -<BLANKLINE> - The x attribute was not provided. -<BLANKLINE> - -Any other exception raised by a property will propagate to the caller of -``verifyObject``: - ->>> class Foo(object): -... implements(IFoo) -... @property -... def x(self): -... raise Exception - ->>> verifyObject(IFoo, Foo()) -Traceback (most recent call last): -Exception - -Of course, broken properties that are not required by the interface don't do -any harm: - ->>> class Foo(object): -... implements(IFoo) -... x = 1 -... @property -... def y(self): -... raise Exception - ->>> verifyObject(IFoo, Foo()) -True |
