Edgewall Software
Modify

Opened 13 years ago

Closed 13 years ago

Last modified 9 years ago

#8419 closed defect (worksforme)

self.env.components not concurrent with self.env.is_component_enabled

Reported by: Jeff Hammel <jhammel@…> Owned by:
Priority: normal Milestone:
Component: general Version: 0.11.4
Severity: normal Keywords:
Cc: Branch:
Release Notes:
API Changes:
Internal Changes:

Description

I've encountered this bug building several plugins, and I don't know what exactly the problem is. Even if a component is enabled and self.env.is_component_enabled confirms this, a KeyError is thrown looking up the component in self.env.components (where self is a Component):

(Pdb) self.env.components[TicketSystem]
*** KeyError: <class 'trac.ticket.api.TicketSystem'>
(Pdb) self.env.is_component_enabled(TicketSystem)
True
(Pdb) TicketSystem(self.env)
<trac.ticket.api.TicketSystem object at 0x85c9f8c>
(Pdb) 

I won't include my code, because I've encountered this in several different places, apparently unrelated. The bug also seems intermittent.

Attachments (0)

Change History (8)

comment:1 by Christian Boos, 13 years ago

Milestone: 0.11.6

I've seen something similar once. I'm not sure it was the exact same issue (can't find the backtrace right now), but it was likely a race in the Component system which is what I think your problem could be as well.

in reply to:  1 comment:2 by Jeff Hammel <jhammel@…>, 13 years ago

Replying to cboos:

I've seen something similar once. I'm not sure it was the exact same issue (can't find the backtrace right now), but it was likely a race in the Component system which is what I think your problem could be as well.

I've seen this several times, in completely different code bases. Because it seems unpredictable, a race condition seems likely

comment:3 by osimons, 13 years ago

They are answers to different questsion. env.is_component_enabled() checks the config settings and other Trac rules (like all trac.* is enabled by default unless explicitly disabled) and returns boolean used by ComponentManager to actually enable or disable.

However, a component isn't added to env.components dictionary before actually being instantiated with the specific env instance - and thereby tagged on to the environment. This usually gets done on first access by a fresh env to various contributors. However, an env that hasn't yet been involved in an Admin page, won't have active pure admin provider components (example for illustration).

The book-keeping is done by env.__metaclass__._registry - it will list all classes loaded (even those disabled), and when requesting the various classes that extend a given ExtensionPoint you will get back those enabled - and then they will stay attached in env.components for the life of the environment.

So, for your special need you should check if it is enabled, and then if so instantiate it and use it (it can be instantiated as many times as you like, you just get the same instance returned anyway).

Illustration showing a plain environment that has not yet 'touched' any classes:

>>> from trac.env import Environment
>>> myenv = Environment('/some/project')
>>> print myenv.components
{<class 'trac.env.Environment'>: <trac.env.Environment object at 0x11c20d0>}
>>> print myenv.__metaclass__._registry
{... 'a really long list' ...}

in reply to:  1 ; comment:4 by Christian Boos, 13 years ago

Replying to cboos:

… I'm not sure it was the exact same issue (can't find the backtrace right now), but it was likely a race in the Component system

Ok, I remember what it was: a method of a Component was used before the __init__ method of that component was called. So it has nothing to do with the current issue, which is more an API misuse as Simon explained.

Jeff, do you agree on wontfix here?

in reply to:  4 ; comment:5 by Jeff Hammel <jhammel@…>, 13 years ago

Replying to cboos:

Replying to cboos:

… I'm not sure it was the exact same issue (can't find the backtrace right now), but it was likely a race in the Component system

Ok, I remember what it was: a method of a Component was used before the __init__ method of that component was called. So it has nothing to do with the current issue, which is more an API misuse as Simon explained.

Jeff, do you agree on wontfix here?

Makes sense, I think. So just to make sure I understand, env.components should not be used to fetch components; instead, the component should be instantiated with the environment and that should be used.

in reply to:  5 ; comment:6 by osimons, 13 years ago

Milestone: 0.11.6
Resolution: worksforme
Status: newclosed

Replying to Jeff Hammel <jhammel@…>:

Makes sense, I think. So just to make sure I understand, env.components should not be used to fetch components; instead, the component should be instantiated with the environment and that should be used.

Correct.

in reply to:  6 comment:7 by Jeff Hammel <jhammel@…>, 13 years ago

Replying to osimons:

Replying to Jeff Hammel <jhammel@…>:

Makes sense, I think. So just to make sure I understand, env.components should not be used to fetch components; instead, the component should be instantiated with the environment and that should be used.

Correct.

Good to know. I was under the opposite assumption.

comment:8 by Christian Boos, 13 years ago

… another Invalid action "resolve" for me ;-)

Just wanted to add that, indeed, outside of trac/core.py, the ComponentManager.components field is never used in the Trac code base.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The ticket will remain with no owner.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from (none) to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.