#11684 closed defect (fixed)
Methods decorated with lazy are not included in ApiDocs
Reported by: | Ryan J Ollos | Owned by: | Ryan J Ollos |
---|---|---|---|
Priority: | normal | Milestone: | 1.0.2 |
Component: | general | Version: | |
Severity: | normal | Keywords: | |
Cc: | Branch: | ||
Release Notes: | |||
API Changes: |
The decorators |
||
Internal Changes: |
Description
The following patch seems to fix the issue:
-
trac/util/__init__.py
diff --git a/trac/util/__init__.py b/trac/util/__init__.py index 13676d5..a31a147 100644
a b 20 20 from __future__ import with_statement 21 21 22 22 import errno 23 import functools 23 24 import inspect 24 25 from itertools import izip, tee 25 26 import locale … … class lazy(object): 1109 1110 1110 1111 def __init__(self, fn): 1111 1112 self.fn = fn 1113 functools.update_wrapper(self, fn) 1112 1114 1113 1115 def __get__(self, instance, owner): 1114 1116 if instance is None:
Attachments (0)
Change History (13)
comment:1 by , 10 years ago
API Changes: | modified (diff) |
---|---|
Resolution: | → fixed |
Status: | new → closed |
follow-up: 4 comment:2 by , 10 years ago
The cached
and with_transaction
decorators have the same issue. I'll fix it for cached
, but will ignore with_transaction
since it's deprecated. functools is only available since Python 2.5, which is why I didn't backport to Trac 0.12 (which supports Python 2.4).
comment:3 by , 10 years ago
Proposed fix for cached
decorator:
-
trac/cache.py
diff --git a/trac/cache.py b/trac/cache.py index 711e2b8..2bee647 100644
a b 13 13 14 14 from __future__ import with_statement 15 15 16 import functools 17 16 18 from .core import Component 17 19 from .util import arity 18 20 from .util.concurrency import ThreadLocal, threading … … def cached(fn_or_attr=None): 173 175 supported (but will be removed in version 1.1.1). 174 176 """ 175 177 if hasattr(fn_or_attr, '__call__'): 176 return CachedSingletonProperty(fn_or_attr) 178 property = CachedSingletonProperty(fn_or_attr) 179 functools.update_wrapper(property, fn_or_attr) 180 return property 177 181 def decorator(fn): 178 return CachedProperty(fn, fn_or_attr) 182 property = CachedProperty(fn, fn_or_attr) 183 functools.update_wrapper(property, fn) 184 return property 179 185 return decorator
comment:4 by , 10 years ago
Replying to rjollos:
The
cached
andwith_transaction
decorators have the same issue.
I'm not sure about cached
decorator. The decorator updates __doc__
property from the original function in tags/trac-1.0.1/trac/cache.py@:42#L37.
>>> from trac.ticket.api import TicketSystem >>> TicketSystem.fields <trac.cache.CachedSingletonProperty object at 0x28b99d0> >>> TicketSystem.fields.__doc__ 'Return the list of fields available for tickets.' >>>
follow-up: 6 comment:5 by , 10 years ago
I didn't notice the assignment to __doc__
, but there is still a problem. The command help(TicketSystem)
yields:
... | __init__(self) | | custom_fields = <trac.cache.CachedSingletonProperty object> | eventually_restrict_owner(self, field, ticket=None) | Restrict given owner field to be a list of users having | the TICKET_MODIFY permission (for the given ticket) | | fields = <trac.cache.CachedSingletonProperty object> | format_summary(self, summary, status=None, resolution=None, type=None) ...
With the use of functools.wrapped_function
:
... | | __init__(self) | | custom_fields(...) | Return the list of custom ticket fields available for tickets. | | eventually_restrict_owner(self, field, ticket=None) | Restrict given owner field to be a list of users having | the TICKET_MODIFY permission (for the given ticket) | | fields(...) | Return the list of fields available for tickets. | ...
That's not quite right though because it suggests that fields
and custom_fields
are functions rather than attributes. Methods decorated with lazy
have the same issue.
Using functools.wrapped_function
would fix this issue:
>>> TicketSystem.fields.__module__ 'trac.cache'
—>
>>> TicketSystem.fields.__module__ 'trac.ticket.api'
The __dict__
is different too:
>>> TicketSystem.fields.__dict__ {'__doc__': 'Return the list of fields available for tickets.', 'retriever': <function fields at 0x3165050>}
When using functools.wrapped_function
:
>>> TicketSystem.fields.__dict__ {'__name__': 'fields', '__module__': 'trac.ticket.api', '__doc__': 'Return the list of fields available for tickets.', 'retriever': <function fields at 0x329ee60>}
We could just remove the assignment to __doc__
and use functool.wrapped_function
, unless some issue is found with that approach. The docstring was added in [8071/trunk/trac/cache.py] (or at least the class was moved in that revision). Python 2.4 was supported at that time, so it looks like functools.wrapped_function
could not be used directly from the standard library.
comment:6 by , 10 years ago
Thanks for the details. I understand it.
That's not quite right though because it suggests that
fields
andcustom_fields
are functions rather than attributes. Methods decorated withlazy
have the same issue.
Adding __set__
method, as a result the names would be listed as a attribute.
Also, _
isn't used in message for AttributeError
s. That's intentional. I don't think that messages should be translated because it is lead by programming error and would be logged to trac.log. Users don't see it in users' browser.
-
trac/cache.py
diff --git a/trac/cache.py b/trac/cache.py index 711e2b8..fa2ff79 100644
a b 13 13 14 14 from __future__ import with_statement 15 15 16 import functools 17 16 18 from .core import Component 17 19 from .util import arity 18 20 from .util.concurrency import ThreadLocal, threading … … class CachedPropertyBase(object): 39 41 40 42 def __init__(self, retriever): 41 43 self.retriever = retriever 42 self.__doc__ = retriever.__doc__44 functools.update_wrapper(self, retriever) 43 45 44 46 def make_key(self, cls): 45 47 attr = self.retriever.__name__ … … class CachedPropertyBase(object): 49 51 break 50 52 return '%s.%s.%s' % (cls.__module__, cls.__name__, attr) 51 53 54 def __set__(self, instance, value): 55 raise AttributeError('Setting attribute is not allowed.') 56 52 57 53 58 class CachedSingletonProperty(CachedPropertyBase): 54 59 """Cached property descriptor for classes behaving as singletons
Edit: removed __set__
from lazy
class in the patch. Cannot create TicketSystem
instance with __set__
.
follow-up: 9 comment:7 by , 10 years ago
I'm a bit unsure, but extrapolating on the changes from comment:6, I tried inheriting from property
. Proposed changes in log:rjollos.git:t11684.2.
comment:8 by , 10 years ago
Resolution: | fixed |
---|---|
Status: | closed → reopened |
comment:9 by , 10 years ago
comment:10 by , 10 years ago
Status: | reopened → assigned |
---|
comment:11 by , 10 years ago
I'm fairly confident that [1b87dcef/rjollos.git] is okay. Inheriting from property
adds an AttributeError
-raising __set__
method, which as far as I understand it would be effectively the same as comment:6.
I'm less certain about [008a4635/rjollos.git]. Removing the inheritance from property
, the tests still pass and the documentation displays the property as a data description rather than a method: [0d28fb30/rjollos.git].
We could make lazy
act as a lazily evaluated property: [265d37a8/rjollos.git], however it is probably safer (for backward compatibility) to have it act as an attribute and to add a lazyproperty
class if needed.
I'm leaning towards committing [1b87dcef/rjollos.git] and creating a new ticket for discussion of the other changes in 1.0.3.
comment:12 by , 10 years ago
API Changes: | modified (diff) |
---|---|
Resolution: | → fixed |
Status: | assigned → closed |
[1b87dcef/rjollos.git] committed in [13028], merged in [13029]. #11693 created for changes discussed in comment:11.
comment:13 by , 10 years ago
API Changes: | modified (diff) |
---|
Also, previously we'd see:
Now:
Fixed in [12968], merged to trunk in [12969].