Make sure two Python classes have properties of the same name

I am looking to create a class interface in Python, but have discovered that Python has no interface constructs.

I need that if a programmer tries to add new properties to one class without adding properties with the same name in another class, an exception must be raised (at compile time or at runtime)

Example:

class MongoCompany:
    company_name = MongoField()

class ESCompany:
    company_name = ESField()

an exception occurs if the programmer tries to add a field to MongoCompanywithout changing ESCompany.

class MongoCompany:
    company_name = MongoField()
    company_phone = MongoField()

class ESCompany:
    company_name = ESField()

MongoCompany.init()

Edit:

Background This should prevent programmers from modifying the MongoDB schema declared in the Mongoengine class Documentwithout adding the corresponding modification to the Elasticsearch schema declared in another file with the elasticsearch-dsl class DocType.

+4
1

! , ! , , . , , , .

class RequiredFieldsMeta(type):
    _interface = {'company_name', 'num_employees'}

    def __new__(cls, clsname, bases, attrs):
        for field in RequiredFieldsMeta._interface:
            if field not in attrs:
                raise AttributeError(
                   'Class %s missing required property %s'
                    % (clsname, field))
        for name in attrs:
            if not isdunder(name) and name not in RequiredFieldsMeta._interface:
                raise AttributeError(
                    'Class %s has extra property %s'
                    % (clsname, name))
        return super(RequiredFieldsMeta, cls).__new__(cls, clsname, bases, attrs)

# Works fine:
class MongoCompany(metaclass=RequiredFieldsMeta):
    company_name = 'Mongo Inc.'
    num_employees = 100

# Throws AttributeError:
class ESyCompany(metaclass=RequiredFieldsMeta):
    extra_prop = 'foobar'

, : , .

EDIT: is_dunder. , name.startswith('__') , , python, , .


EDIT 2: , , "" ( ) :

def __new__(cls, clsname, bases, attrs):
    attr_names = {a for a in attrs if not is_dunder(a)}

    if attr_names.difference(RequiredFieldsMeta._interface):
        raise AttributeError('Class %s has extra properties' % clsname)
    if RequiredFieldsMeta._interface.difference(attr_names):
        raise AttributeError('Class %s missing required properties' % clsname)

    return super(RequiredFieldsMeta, cls).__new__(cls, clsname, bases, attrs)

:

def __new__(cls, clsname, bases, attrs):
    attr_names = {a for a in attrs if not is_dunder(a)}
    if attr_names != RequiredFieldsMeta._interface:
        raise AttributeError(
            'Class %s does not match the required interface' % clsname)
    return super(RequiredFieldsMeta, cls).__new__(cls, clsname, bases, attrs)
+6

Source: https://habr.com/ru/post/1682281/


All Articles