pacifica/pacifica-metadata

View on GitHub
docs/GenMetadataModelMD.py

Summary

Maintainability
A
0 mins
Test Coverage
#!/usr/bin/python
# -*- coding: utf-8 -*-
# pylint: disable=invalid-name
"""
Create the metadatamodel.rst file.

This script is used to generate the metadatamodel.rst file and automatically
walks the metadata orm objects searching for PeeWee attributes and populating
tables...
"""
from __future__ import print_function
from functools import cmp_to_key
from pacifica.metadata.orm import ORM_OBJECTS

print("""Metadata Model
============================

This covers all the objects and their relationships to other
objects in the model.

All The Objects
----------------------
""")

for obj_cls in ORM_OBJECTS:
    print('{0}'.format(obj_cls.__name__))
    print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
    print('')
    col_widths = [27, 22, 33, 23]
    col_titles = ['Column', 'Type', 'Reference', 'Attributes']
    sep_line = '+{}+'.format('+'.join(['-'*col_w for col_w in col_widths]))
    head_line = '+{}+'.format('+'.join(['='*col_w for col_w in col_widths]))
    print(sep_line)
    print('|{}|'.format('|'.join([header.ljust(col_w)
                                  for header, col_w in zip(col_titles, col_widths)])))
    print(head_line)
    column_tuples = []
    # pylint: disable=protected-access
    # pylint: disable=no-member
    for obj_attr_name, obj_cls_attr in obj_cls._meta.fields.items():
        attr_type = type(obj_cls_attr)
        # pylint: disable=too-many-boolean-expressions
        # introspection is hard...
        extended_objs = attr_type.__name__ == 'ExtendDateTimeField' or \
            attr_type.__name__ == 'ExtendDateField'
        peewee_chk = attr_type.__module__ == 'peewee' and \
            obj_cls_attr != '_meta' and \
            attr_type.__name__ != 'ReverseRelationDescriptor' and \
            attr_type.__name__ != 'CompositeKey'
        if extended_objs or peewee_chk:
            column_name = obj_attr_name
            column_type = attr_type.__name__
            points_to = ''
            sql_attrs = []
            if obj_cls_attr.null:
                sql_attrs.append('NULL')
            else:
                sql_attrs.append('NOT NULL')
            if obj_cls_attr.primary_key:
                sql_attrs.append('PRIMARY KEY')
            if obj_cls_attr.sequence:
                sql_attrs.append(
                    'DEFAULT NEXTVAL({0})'.format(obj_cls_attr.sequence))
            sql_attrs = ', '.join(sql_attrs)
            if attr_type.__name__ == 'ForeignKeyField':
                points_to_class = obj_cls_attr.rel_model.__name__
                points_to_column = obj_cls_attr.rel_field.name
                points_to = '{0}.{1}'.format(points_to_class, points_to_column)
                if column_name.endswith('_id'):
                    continue
            column_tuples.append(
                (column_name, column_type, points_to, sql_attrs))
    # pylint: enable=protected-access

    # pylint: disable=invalid-name
    # pylint: disable=too-many-return-statements
    def column_cmp(a, b):
        """
        Custom column compare.

        This is complicated but it needs to be for sorting the attributes...
        the ID field is always first
        then anything else besides 'created', 'deleted', 'updated'
        """
        if a[0] == 'id' and b[0] == 'id':
            return 0
        if a[0] == 'id':
            return -1
        if b[0] == 'id':
            return 1
        common_dates = ['created', 'deleted', 'updated']
        if a[0] == b[0]:
            return 0
        if a[0] in common_dates:
            return 1
        if b[0] in common_dates:
            return -1
        return a[0] < b[0]
    # pylint: enable=too-many-return-statements
    # pylint: enable=invalid-name

    for column in sorted(column_tuples, key=cmp_to_key(column_cmp)):
        print('|{}|'.format('|'.join([col.ljust(col_w)
                                      for col, col_w in zip(column, col_widths)])))
        print(sep_line)
    print('')

print("""
Note
----------

This document is generated by the ``GenMetadataModelMD.py`` script and needs to
be regenerated whenever changes are made to the model.""")