Edgewall Software

Ticket #4190 (closed enhancement: wontfix)

Opened 2 years ago

Last modified 10 months ago

CORE - Provde an ICoreInit Extension Point with an post_init method

Reported by: ilias@… Owned by: jonas
Priority: normal Milestone:
Component: general Version: devel
Severity: normal Keywords:
Cc:

Description

It seems that within the __init__ method of a trac-component there is not yet every resource available (e.g. self.log.debug).

It would be nice to have something like an "ICoreInit" interface, which would provide several otpional methods.

Of main interest would be the "post_init" one (which would be called after all components are instantiated).

Attachments

Change History

in reply to: ↑ description ; follow-up: ↓ 3   Changed 2 years ago by cmlenz

  • status changed from new to closed
  • resolution set to worksforme

Replying to ilias@lazaridis.com:

It seems that within the __init__ method of a trac-component there is not yet every resource available (e.g. self.log.debug).

Incorrect, you can access self.env, self.log, and self.config. See Component member variables.

follow-up: ↓ 4   Changed 2 years ago by Noah Kantrowitz (coderanger) <coderanger@…>

Also, not all components are created at once. The system waits until they are needed.

in reply to: ↑ 1   Changed 2 years ago by ilias@…

  • status changed from closed to reopened
  • resolution worksforme deleted

Replying to cmlenz:

Incorrect, you can access self.env, self.log, and self.config. See Component member variables.

class ComponentInitParticipantTest(Component):

    #implements(INavigationContributor)       

    def get_active_navigation_item(self, req):
        return 'dummy'
    def get_navigation_items(self, req):
        yield 'dummynav', 'dummy', 'dummy'

    def __init__(self):
        self.log.debug('from init')
        pass

init is not called, exept an when you enable the line "Implements", thus the component get's instantiated when navigation-items are collected. see the full context of the workaround.

If I like to participate at the initialization, an "ICoreInit" or similar would be needed, which provides a "post_init" and eventually an "pre_init" method (called before and after the component-initialization sequence).

class ComponentInitParticipantTest(Component):

    implements(ICoreInit)       

    def post_init(self):
        # do init stuff, as component is instantiated after initialization of core
        self.log.debug('from core-init')

    def __init__(self):
        self.log.debug('from init')
        pass

in reply to: ↑ 2   Changed 2 years ago by ilias@…

Replying to Noah Kantrowitz (coderanger) <coderanger@yahoo.com>:

Also, not all components are created at once. The system waits until they are needed.

I understand. I had assumed that "self.log" is not available within "init", but then realized that "init" was not called (= component not instantiated).

That's one more reason for a construct like "ICoreInit".

follow-up: ↓ 6   Changed 2 years ago by cmlenz

As this would add initialization overhead, can you provide a reasonable use case why you'd need something like this?

in reply to: ↑ 5 ; follow-up: ↓ 8   Changed 2 years ago by ilias@…

Replying to cmlenz:

As this would add initialization overhead, can you provide a reasonable use case why you'd need something like this?

Any use-case in which a core-user likes to take an action right after the core-initialization.

(btw: this is nothing special within component-models.)

the overhead would be minimal, as only components which register to the ICoreInit would introduce overhead.

A concrete use-case is this one, where I provide custom-navigation-orders (requested in #3695). Here I would simply implement the ICoreInit interface instead of using the workaround.

(In a first implementation, ICoreInit could be without any function. Any compomenent which implements ICoreInit would be instantiated immediately.)

I can provide a patch for this.

  Changed 2 years ago by Noah Kantrowitz (coderanger) <coderanger@…>

A simple work-around that is quite easy: implement IRequestFilter, and provide a null implementation. Filters are loaded (and initialized) as soon as the first request hits.

in reply to: ↑ 6   Changed 2 years ago by anonymous

Replying to ilias@lazaridis.com:

Replying to cmlenz:

As this would add initialization overhead, can you provide a reasonable use case why you'd need something like this?

Any use-case in which a core-user likes to take an action right after the core-initialization.

Have you seen the IEnvironmentSetupParticipant interface, in source:trunk/trac/env.py? The environment_needs_upgrade method could be used to perform one time initializations once at environment startup.

  Changed 2 years ago by ilias@…

There are many possible workarounds, including dyna-patches etc. I use already an workaround which triggers on the first request (although the "environment_needs_upgrade" one would be more elegant).

But: my interested in this ticket is not to find a workaround.

My interest is that the trac core is extended, thus a workaround is not needed anymore.

follow-up: ↓ 11   Changed 21 months ago by cboos

  • status changed from reopened to closed
  • resolution set to duplicate

See #5010.

in reply to: ↑ 10   Changed 10 months ago by ilias@…

  • status changed from closed to reopened
  • resolution duplicate deleted

Replying to cboos:

See #5010.

#5010 deals with the environment level.

The currect issue affect the lower level, trac.core, independent of environments

See an implementation based on a workaround:

http://dev.lazaridis.com/base/browser/infra/tracx/tracx/core.py?rev=383

follow-up: ↓ 13   Changed 10 months ago by cboos

  • status changed from reopened to closed
  • resolution set to duplicate

I think the environment level is the right level for talking about "initialization".

What's the initialization at the core level anyway? The component instances are only created on first use, nothing more is done in core.py, there's no global initialization phase at that point.

Look rather at the Environment.__init__ method in env.py, here's where the initial load_components call is made and that's for the initialization phase. You can see that the IEnvironmentSetupParticipant components are then called. Further enhancements to this interface should be discussed in #5010. We can indeed imagine an environment_loaded method to complement the environment_created one. From there, you can load further components using load_components on the directory you want, or any other mean.

in reply to: ↑ 12 ; follow-up: ↓ 14   Changed 10 months ago by ilias@…

  • status changed from closed to reopened
  • resolution duplicate deleted

Replying to cboos:

I think the environment level is the right level for talking about "initialization". What's the initialization at the core level anyway? The component instances are only created on first use, nothing more is done in core.py, there's no global initialization phase at that point.

And that's the topic of this ticket. Essentially this is a design defect.

Look rather at the `Environment.init

No need, as that's another layer, and thus another topic.

This ticket subject the core-level (or component-tlevel), not environment level

You can await some comments of other developers (which are external to trac), thus you understand the seperation ot those 2 layers.

Otherwise, you can of course close as "wontfix".

But: this is not a duplicate.

in reply to: ↑ 13   Changed 10 months ago by cboos

  • status changed from reopened to closed
  • resolution set to wontfix

Replying to ilias@lazaridis.com:

Replying to cboos:

What's the initialization at the core level anyway? The component instances are only created on first use, nothing more is done in core.py, there's no global initialization phase at that point.

And that's the topic of this ticket. Essentially this is a design defect.

Great, so you're welcome to reopen this ticket once you show us:

  • an alternative design (defect free, of course)
  • and a patch implementing the above design

Otherwise, you can of course close as "wontfix".

Sure. Thanks!

But: this is not a duplicate.

[Off-topic] Not in the strict sense, but we also use "duplicate" as a way to consolidate loosely related tickets when the envisioned fix for one will also take care of the others (#5010 - environment life cycle => deals with both shutdown and initialization of components).

Add/Change #4190 (CORE - Provde an ICoreInit Extension Point with an post_init method)

Author



Change Properties
<Author field>
Action
as closed
Next status will be 'reopened'
to The owner will change from jonas. Next status will be 'closed'
 
Note: See TracTickets for help on using tickets.