docs/GenMetadataModelMD.py
#!/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.""")