2

Disclaimer: This has nothing to do with django. I have only tagged it Django because django has a very similar object structure, and the knowledge might be exchangeable.

I am using the cement cli framework and am trying to change the usage statement. This is more of a python inheritance question than a cement question. Here is an example of what I have:

class AbstractBaseController(controller.CementBaseController):
    class Meta:
        label = 'base'
        usage = 'foo ' + label + ' [options. .]'

class BarController(AbstractBaseController):
    class Meta:
        label = 'bar'

Now, let me explain what is going on here. I have multiple controllers (more than just the bar controller) and I want them all to inherit the usage attribute from the AbstractBaseController.Meta, however, I want the usage statement to use the new label, not the Abstract label. The main goal here is to get the usage statement to work on every controller without having to copy and paste it into every controller. Right now, the usage is inherited as 'foo base [options. .]' as it does not replace label before making the substitution.

I have tried the following:

class AbstractBaseController(controller.CementBaseController):
    class Meta:
        label = 'base'
        usage = 'foo {cmd} [options. .]'

class BarController(AbstractBaseController):
    class Meta:
        label = 'bar'
        usage = AbstractBaseController.Meta.usage.replace('{cmd}', label)

And this works. However, I still have the copy and paste issue, since I have to copy this usage cmd into every controller.

I have also tried this:

class AbstractBaseController(controller.CementBaseController):
    class Meta:
        label = 'base'
        usage = 'foo {cmd} [options. .]'
        def __init__(self):
            self.usage = 'foo ' + self.label + ' [options]'

class BarController(AbstractBaseController):
    class Meta(AbstractBaseController.Meta):
        label = 'bar'

But that doesnt seem to do anything. Even with the __init__ I still get usage = 'foo {cmd}' and not even usage = 'foo base'

Is there anyway to get the usage statement unique with the label for each controller while having the code reside in only one place? (The abstract controller)

Nick Humrich
  • 14,905
  • 8
  • 62
  • 85
  • Hi Nick, Any success? – Nihar Sawant Nov 17 '15 at 11:36
  • @Nihar no, I never did figure this out, but it's been a while and upon second look, I think xavier's solution should work. I would need to dive a little into cement code to see why it wasn't working, but for non cement stuff, this sounds like it would work. Are you using cement or just trying to override a meta? My guess is cement never intatiates the class, it just does a class look up, `Meta.usage ` instead of `Meta().usage` – Nick Humrich Nov 17 '15 at 13:39
  • Using a class property is probably the right solution. See: http://stackoverflow.com/questions/128573/using-property-on-classmethods – Nick Humrich Nov 17 '15 at 13:57

1 Answers1

0

Why not use a method?

class A : 
    class SubA:
        label = 'base'
        def __init__(self) :
            self.usage = 'foo '+self.label+' [options]'
class B() :
    class SubB(A.SubA) :
        label = 'bar'

a = A().SubA()
b = B().SubB()
print(a.usage) # "foo base [options]"
print(b.usage) # "foo bar [options]"
xavier
  • 877
  • 6
  • 13