1
votes

I have a Python web app and I want to define a general class or function for processing web pages and call it from a more specific class for specific page instances.

Error:

metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

I have checked all the StackOverflow questions & answers about that error message and did not understand the explanations given (and I found an article about metaclasses that I didn't understand - OOP is not really my thing). I also looked at all the StackOverflow questions & answers about calling a class method from another class (and didn't understand them either).

Code:

import webapp2
from datetime import datetime, timedelta

from google.appengine.ext import ndb
from google.appengine.api import users

import admin_templates
import authenticate

class myPage(webapp2.RequestHandler):
    def get(pageInstance):
        pageInstance.outputHtml()

    def outputHtml(pageInstance,pageTitle,pageContent):
        adminLink = authenticate.get_adminlink()
        authMessage = authenticate.get_authmessage()
        adminNav = authenticate.get_adminnav()
        pageInstance.response.headers['Content-Type'] = 'text/html'
        html = admin_templates.base
        html = html.replace('#title#', pageTitle)
        html = html.replace('#authmessage#', authMessage)
        html = html.replace('#adminlink#', adminLink)
        html = html.replace('#adminnav#', adminNav)
        html = html.replace('#content#', pageContent)
        pageInstance.response.out.write(html)
        pageInstance.response.out.write(admin_templates.footer)

class AuditorsPage(webapp2.RequestHandler, myPage.outputHtml):
    def get(self):
        self.output_auditors()

    def output_auditors(self):
        self.outputHtml(admin_templates.auditors_title, admin_templates.auditors_content)

How do I call the outputHtml method in the myPage class from the AuditorsPage class without getting a metaclass error?

5
Why is AuditorsPage trying to inherit from a method of myPage? - chepner
no special reason! just me being inept! - Yvonne Aburrow
Thanks for the edit @bruntime, that's an improvement - Yvonne Aburrow

5 Answers

1
votes

The error comes from the fact that you are subclassing your class from a method in the general class, which can't be done. Actually, your code is wrong, and there are at least two ways you can fix it:

1) Inherit from myPage instead: in this case, it won't work and will bring a MRO error because your methods are not part of any instance of the class, as they are not linked to the object using self as the first parameter.

This is the fix for your code in this case:

from google.appengine.ext import ndb
from google.appengine.api import users

import admin_templates
import authenticate

class myPage(webapp2.RequestHandler):
    def get(self, pageInstance):
        pageInstance.outputHtml()

    def outputHtml(self, pageInstance,pageTitle,pageContent):
        adminLink = authenticate.get_adminlink()
        authMessage = authenticate.get_authmessage()
        adminNav = authenticate.get_adminnav()
        pageInstance.response.headers['Content-Type'] = 'text/html'
        html = admin_templates.base
        html = html.replace('#title#', pageTitle)
        html = html.replace('#authmessage#', authMessage)
        html = html.replace('#adminlink#', adminLink)
        html = html.replace('#adminnav#', adminNav)
        html = html.replace('#content#', pageContent)
        pageInstance.response.out.write(html)
        pageInstance.response.out.write(admin_templates.footer)

class AuditorsPage(myPage):
    def get(self):
        self.output_auditors()

2) Just get the two methods in the myPage class as normal methods with no class, and then call them directly from your class. Actually, you just need to create outputHtml() method, and then call it directly (without self.) from the method in your RequestHandler subclass.

1
votes

Try this:

myPage.outputHtml()

instead of:

self.outputHtml()
1
votes

Class AuditorsPage could inherit from myPage

import webapp2
from datetime import datetime, timedelta

from google.appengine.ext import ndb
from google.appengine.api import users

import admin_templates
import authenticate

class myPage(webapp2.RequestHandler):
    def get(pageInstance):
        pageInstance.outputHtml()

    def outputHtml(pageInstance,pageTitle,pageContent):
        adminLink = authenticate.get_adminlink()
        authMessage = authenticate.get_authmessage()
        adminNav = authenticate.get_adminnav()
        pageInstance.response.headers['Content-Type'] = 'text/html'
        html = admin_templates.base
        html = html.replace('#title#', pageTitle)
        html = html.replace('#authmessage#', authMessage)
        html = html.replace('#adminlink#', adminLink)
        html = html.replace('#adminnav#', adminNav)
        html = html.replace('#content#', pageContent)
        pageInstance.response.out.write(html)
        pageInstance.response.out.write(admin_templates.footer)

class AuditorsPage(myPage):
    def get(self):
        self.output_auditors()

Then you can instanciate AuditorsPage() and call directly outputHtml

foo = AuditorsPage()

foo.outputHtml(admin_templates.auditors_title, admin_templates.auditors_content)
1
votes

Ok so you are not calling super for the AuditorsPage:

class myPage():

    def __init__(self):
        pass

    def outputHtml(self):
        print("outputHTML")


class AuditorsPage(myPage):

    def __init__(self):
        super().__init__()

    def output(self):
        print("AuditorsPage")

I am using a very stripped down version of what you have to explain what is going on. As you can see, we have your myClass class. When creating an object from AuditorsPage, we are now able to access the method outputHTML as expected. Hope this helps.

0
votes

Base on your question, I guess you want to inherit methods from myPage. If that is the case, instead of:

class AuditorsPage(webapp2.RequestHandler, myPage.outputHtml):

Try:

class AuditorsPage(webapp2.RequestHandler, myPage):