Skip to content

Instantly share code, notes, and snippets.

@metaperl
Created May 13, 2015 00:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save metaperl/9cf7b7106a856710bd71 to your computer and use it in GitHub Desktop.
Save metaperl/9cf7b7106a856710bd71 to your computer and use it in GitHub Desktop.
# core
import copy
from inspect import stack, getframeinfo
import itertools
import os
# 3rd party
from nagare import component, database, editor, presentation, util, validator, var
from nagare.namespaces import xhtml
import sqlalchemy
# local
import models
def tp(m):
frame,filename,line_number,function_name,lines,index = stack()[1]
print "[ {0} {1} ]\n\t{2}".format(filename, line_number, m)
tp("models: {0}".format(models))
class Menu:
def __init__(self, menu):
self.menu = menu
self.selected = var.Var(0)
def display(self, i, comp):
comp.answer(i)
@presentation.render_for(Menu)
def render(self, h, comp, *args):
with h.ul(class_='menu'):
for index, entry in enumerate(self.menu):
h << h.li(
h.a(entry).action(
lambda index=index: self.display(index, comp)),
class_='selected-entry' if self.selected() == index else '')
return h.root
class TabNav:
tab_factories = [
(
'Parser List',
lambda: component.Component(ParserList())
),
(
'New Parser',
lambda: component.Component(AddParserEditor(AddParser()))
),
(
'New Content',
lambda: component.Component(NewContent())
),
]
def __init__(self):
self.menu = component.Component(
Menu([label for label, factory in self.tab_factories]))
self.menu.on_answer(self.select_tab)
self.content = component.Component(None)
self.select_tab(0)
def select_tab(self, index):
self.content.becomes(self.tab_factories[index][1]())
self.menu().selected(index)
@presentation.render_for(TabNav)
def render(self, h, *args):
h.head.css_url('menu.css')
h << self.menu
with h.div(class_='content'):
h << self.content
return h.root
# --- MENU ITEM 1: Parser List
class ParserList(object):
def __init__(self):
pass
def data(self):
return database.session.query(models.OBFL_Parser).order_by(
models.OBFL_Parser.ID.desc())
def toggle(self, row_id):
r = database.session.query(models.OBFL_Parser).filter_by(
ID=row_id).one()
r.isEnabled=yn_toggle(r.isEnabled)
@presentation.render_for(ParserList)
def render(self, h, comp, *args):
for row in self.data():
with h.div:
with h.form:
h << h.input(value=row.Parser_Alias, disabled=True)
h << h.a(row.isEnabled).action(
lambda m=row.ID : self.toggle(m))
h << h.input(type='hidden', value=row.ID)
#h << h.input(type="Submit", value="Update")
return h.root
# --- MENU ITEM: New Content
class NewContent(object):
def __init__(self):
pass
def data(self):
return database.session.query(
models.OBFL_Log_ParsingErrors).filter(
models.OBFL_Log_ParsingErrors.Type_Of_Record == 'Error')
def config(self, comp, dbrow):
print "Calling config"
comp.becomes(ConfigureContent(dbrow))
#r = comp.call(util.Ask("does she love me?"))
#r = comp.becomes(util.Ask("does she love me?"))
def delete(self, comp, dbrow):
row = database.session.query(models.OBFL_Log_ParsingErrors).get(
[dbrow.File_ID, dbrow.Line_Start])
database.session.delete(row)
comp.becomes(NewContent())
@presentation.render_for(NewContent)
def render(self, h, comp, *args):
for le in self.data()[:100]:
#print "rowdict={0}".format(row)
with h.div:
with h.form.post_action(self.config, comp, le):
h << h.a('Delete this row.').action(self.delete, comp, le)
h << h.input(value=le.File_ID, disabled=True)
h << h.input(value=le.File_Name, disabled=True)
h << h.input(value=le.Line_Start, disabled=True)
h << h.input(value=le.Content, disabled=True)
h << h.a('Configure ignore of this row.').action(self.config, comp, le)
return h.root
class ConfigureContent(object):
"""Ask the user to enter a line of text
The text entered is answered
"""
def __init__(self, database_row):
"""Initialization
In:
- ``msg`` -- message to display
"""
self.dbrow = database_row
print "Config init complete"
@staticmethod
def cleancheck():
print "Dirty check {0}".format(database.session.dirty)
def answer(self, comp, r):
row = database.session.query(models.OBFL_Log_ParsingErrors).get(
[self.dbrow.File_ID, self.dbrow.Line_Start])
row.Content = r()
comp.becomes(NewContent())
@presentation.render_for(ConfigureContent)
def render(self, h, comp, *args):
"""The view is a simple form with a text input control
In:
- ``h`` -- the renderer
- ``comp`` -- the component
- ``model`` -- the name of the view
Return:
- a tree
"""
print "rendering"
r = var.Var(self.dbrow.Content)
print "rendering2: {0}".format(self.dbrow.Content)
with h.form.post_action(self.answer, comp, r):
h << h.textarea(r(),rows=40,cols=80).action(r)
h << h.input(type='submit', value='Send')
print "DONE RENDER"
return h.root
# --- MENU ITEM: Add New Parser
#
# Mixins for Add New Parser classes
#
class Keyed(object):
def __init__(self):
super(Keyed, self).__init__()
self.key = ''
class RowDelimited(object):
def __init__(self):
super(RowDelimited , self).__init__()
self.row_delimiter = ''
class ValueTyped(object):
def __init__(self):
super(ValueTyped, self).__init__()
self.value_type = ''
def valuetyped_render(self, h, e):
id_type = {
'666': 'None',
'25': 'Timestamp with Jiffies',
'26': 'Timestamp',
'27': 'nums',
'28': 'alphanums',
'29': 'Any',
'30': 'Single Word',
'31': 'Time',
'32': 'Date'
}
with h.select.action(e.value_type):
with h.optgroup(label='Make a choice'):
for id,type in sorted(id_type.iteritems(),
key=lambda x: x[1]):
h << h.option(type, value=type)
class Tagged(object):
def __init__(self):
super(Tagged, self).__init__()
self.tag_name = ''
#
# Base class for Adding New Parsers
#
class AddParser(object):
def __init__(self):
super(AddParser, self).__init__()
self.name = ''
self.parser_type = ''
self.config_records = list()
def add_config_record(self, r):
print "add_config_record: {0}".format(r.__dict__)
self.config_records.append(r)
def commit_to_database(self, new_parser):
print "Write config records to database."
for i, config_record in enumerate(self.config_records, start=1):
new_detail = models.OBFL_Parser_Details()
new_detail.ParserSection = self.parser_section
new_detail.OrderNum = i
self.bind_attributes(new_detail, config_record)
new_parser.details.append(new_detail)
def bind_attributes(self, parser_detail, config_record):
pass
def append_deep_copy(t):
deep_copy = copy.deepcopy(t)
del(deep_copy.config_records)
t.add_config_record(deep_copy)
def bool_to_yn(b):
if b:
return 'Y'
else:
return 'N'
def yn_to_bool(yn):
if yn == 'Y':
return True
elif yn == 'N':
return False
else:
raise Exception("Invalid value passed.")
def yn_toggle(yn):
if yn == 'Y':
return 'N'
elif yn == 'N':
return 'Y'
else:
raise Exception("Invalid value passed.")
# EOL is a string in the database. It is either Y or N.
class BodyText(AddParser, Keyed, Tagged):
"""A BodyText parser has a key and a tag. It is the most basic in
its inheritance hierarchy."""
def __init__(self):
super(BodyText, self).__init__()
def bind_attributes(self, parser_detail, config_record):
parser_detail.KeySignature=config_record.key
parser_detail.TagName=config_record.tag_name
class BodyTextEditor(editor.Editor):
fields = 'name parser_type key tag_name'.split()
def __init__(self, target):
super(BodyTextEditor, self).__init__(target, self.fields)
self.target=target
def reset_values(self):
self.key('')
self.tag_name('')
def commit_formdata(self):
super(BodyTextEditor, self).commit(self.fields)
def append_formdata(self):
self.commit_formdata()
append_deep_copy(self.target)
self.reset_values()
def update_formdata(self, i):
tp("Updating this formdata: {0} from this target {1}.".format(
i, self.target.__dict__))
self.target.config_records.pop(i)
def remove_formdata(self, i):
tp("Removing this formdata: {0} from this target {1}.".format(
i, self.target.__dict__))
self.target.config_records.pop(i)
@presentation.render_for(BodyTextEditor)
def render(self, h, comp, *args):
with h.form.pre_action(self.reset_values).post_action(self.append_formdata):
with h.div:
h << "Key: " << h.input(
value=self.key()).action(self.key).error(self.key.error)
with h.div:
h << "Tag Name" << h.input(value=self.tag_name()).action(
self.tag_name).error(self.tag_name.error)
h << h.br << h.input(type='submit', value='Add')
h << h.hr
for i, r in enumerate(self.target.config_records):
with h.div:
with h.form:
h << "Key: " << h.input(value=r.key)
h << "Tag Name" << h.input(value=r.tag_name)
h << h.input(type='submit', value='Delete').action(
self.remove_formdata, i)
return h.root
@presentation.render_for(BodyTextEditor)
def render(self, h, comp, *args):
with h.form.pre_action(self.reset_values).post_action(self.append_formdata):
with h.div:
h << "Key: " << h.input(
value=self.key()).action(self.key).error(self.key.error)
with h.div:
h << "Tag Name" << h.input(value=self.tag_name()).action(
self.tag_name).error(self.tag_name.error)
h << h.br << h.input(type='submit', value='Add')
h << h.hr
for i, r in enumerate(self.target.config_records):
r._i=i
c = component.Component(BodyTextEditor(r), model='edit')
h << c
return h.root
@presentation.render_for(BodyTextEditor, model='edit')
def render(self, h, comp, *args):
with h.div:
with h.form:
h << "Key: " << h.input(value=self.key())
h << "Tag Name" << h.input(value=r.tag_name())
h << h.input(type='submit', value='Update').action(
self.commit_formdata)
h << h.input(type='submit', value='Delete').action(
self.remove_formdata, self.target._i)
return h.root
class BodyKeyValue(BodyText, RowDelimited, ValueTyped):
"""A KeyValue parser is a BodyText parser that has row delimiters
and value typing."""
def __init__(self):
super(BodyKeyValue, self).__init__()
def bind_attributes(self, parser_detail, config_record):
super(BodyKeyValue, self).bind_attributes(parser_detail, config_record)
if config_record.value_type == 'None':
parser_detail.ValueType=None
else:
parser_detail.ValueType=config_record.value_type
parser_detail.Delimiter=config_record.row_delimiter
class BodyKeyValueEditor(BodyTextEditor):
fields = BodyTextEditor.fields + 'row_delimiter value_type'.split()
def reset_values(self):
super(BodyKeyValueEditor, self).reset_values()
self.row_delimiter('')
@presentation.render_for(BodyKeyValueEditor)
def render(self, h, comp, *args):
# super(HeaderOnly, self).render(h, comp, args)
with h.form.pre_action(self.reset_values).post_action(self.append_formdata):
with h.div:
h << "Key: " << h.input(
value=self.key()).action(self.key).error(self.key.error)
with h.div:
h << "Delimiter" << h.input(value=self.row_delimiter()).action(
self.row_delimiter).error(self.row_delimiter.error)
with h.div:
h << "Value Type: "
self.target.valuetyped_render(h, self)
with h.div:
h << "Tag Name" << h.input(value=self.tag_name()).action(
self.tag_name).error(self.tag_name.error)
h << h.br << h.input(type='submit', value='Add')
h << h.hr
for i, r in enumerate(self.target.config_records):
with h.form:
with h.div:
h << "Key: " << h.input(value=r.key)
h << "Delimeter" << h.input(
value=r.row_delimiter, size='3')
h << "Value Type" << h.input(value=r.value_type)
h << "Tag Name" << h.input(value=r.tag_name)
h << h.input(type='submit', value='Delete').action(
self.remove_formdata, i)
return h.root
class CustomRow(BodyKeyValue):
"""A HeaderOnly class represents custom rows, as well a headers. It
has a key_position and eol field in addition to having what a
BodyKeyValue class does."""
def __init__(self):
super(CustomRow, self).__init__()
self.key_position = ''
self.eol = False
def eol_as_dbms(self):
return bool_to_yn(self.eol)
def bind_attributes(self, parser_detail, config_record):
super(CustomRow, self).bind_attributes(parser_detail, config_record)
parser_detail.KeySignaturePosition=config_record.key_position
print "EOL IN CUSTOMROW = {0}".format(config_record.eol)
parser_detail.EOL=bool_to_yn(config_record.eol)
class CustomRowEditor(BodyKeyValueEditor):
fields = BodyKeyValueEditor.fields + 'key_position eol'.split()
def reset_values(self):
super(CustomRowEditor, self).reset_values()
self.key_position('L')
self.eol(False)
@presentation.render_for(CustomRowEditor)
def render(self, h, comp, *args):
# super(HeaderOnly, self).render(h, comp, args)
with h.form.pre_action(self.reset_values).post_action(self.append_formdata):
with h.div:
h << "Signature: " << h.input(
value=self.key()).action(self.key).error(self.key.error)
with h.div:
h << "Signature Position: "
with h.select.action(self.key_position):
with h.optgroup(label='Signature Position'):
for option in "Left Right".split():
h << h.option(option, value=option).selected(
self.key_position())
with h.div:
h << "Row Delimiter" << h.input(value=self.row_delimiter()).action(
self.row_delimiter).error(self.row_delimiter.error)
with h.div:
h << "Value Type: "
self.target.valuetyped_render(h, self)
with h.div:
h << "Tag Name" << h.input(value=self.tag_name()).action(
self.tag_name).error(self.tag_name.error)
with h.div:
h << "EOL?" << h.input(type='checkbox').selected(
self.eol()).action(self.eol)
h << h.br << h.input(type='submit', value='Add')
h << h.hr
for i, r in enumerate(self.target.config_records):
with h.form:
with h.div:
h << "Signature: " << h.input(value=r.key)
h << 'Signature Position' << h.input(
value=r.key_position, size='3')
h << "Delimeter" << h.input(
value=r.row_delimiter, size='3')
h << "Value Type" << h.input(value=r.value_type)
h << "Tag Name" << h.input(value=r.tag_name)
h << "EOL" << h.input(
value=bool_to_yn(r.eol),
size=3,
disabled=True
)
h << h.input(type='submit', value='Delete').action(
self.remove_formdata, i)
return h.root
class AddParserEditor(editor.Editor):
fields = 'name parser_type'.split()
def __init__(self, target):
super(AddParserEditor, self).__init__(target, self.fields)
self.target=target
#self.name.validate(validator.to_string(strip=True).not_empty())
def commit(self, comp):
print "Commiting..."
super(AddParserEditor, self).commit(self.fields)
c = ParserConfig(self.name(), self.parser_type())
print "Configured Object {0}".format(c.__dict__)
comp.becomes(component.Component(c))
@presentation.render_for(AddParserEditor)
def render(self, h, comp, *args):
parser_types = 'CustomRows HeaderOnly KeyValue Table Text'.split()
with h.form.post_action(self.commit, comp):
h << "Name: " << h.input(
value=self.name()).action(self.name).error(self.name.error)
with h.select.action(self.parser_type):
with h.optgroup(label='Parser Type'):
for parser_type in parser_types:
h << h.option(parser_type, value=parser_type).selected(
self.parser_type())
h << h.input(type='submit')
return h.root
class BodyTableColumnDelimiter(object):
"""A BodyTableColumnDelimiter is a value that spans the parser configuration
records of a BodyTable."""
def __init__(self):
self.column_delimiter = ''
class BodyTableColumnDelimiterEditor(editor.Editor):
fields = ('column_delimiter', )
def __init__(self, target):
super(BodyTableColumnDelimiterEditor, self).__init__(target, self.fields)
def reset_values(self):
self.column_delimiter('')
def commit(self):
super(BodyTableColumnDelimiterEditor, self).commit(self.fields)
print "Committed column delimiter={0}.".format(self.column_delimiter())
tp("column delimiter in target={0}.".format(self.target.column_delimiter))
@presentation.render_for(BodyTableColumnDelimiterEditor)
def render(self, h, comp, *args):
with h.form.post_action(self.commit):
with h.div:
h << "Column Delimiter: " << h.input(
value=self.column_delimiter()).action(
self.column_delimiter).error(self.column_delimiter.error)
h << h.input(value=self.column_delimiter(), disabled=True)
h << h.input(type='submit', value='Set Global Delimiter')
return h.root
class BodyTable(AddParser, ValueTyped, Tagged):
"""A BodyTable parser is the most basic class in its inheritance
hierarchy."""
def __init__(self):
super(BodyTable, self).__init__()
self.column_name = ''
self.column_width = 0
self.column_delimiter_object = BodyTableColumnDelimiter()
self.column_delimiter_editor = BodyTableColumnDelimiterEditor(
self.column_delimiter_object)
self.column_delimiter_comp = component.Component(
self.column_delimiter_editor)
def commit(self, new_parser):
"""Commit the body table to the dbms."""
print "WRITING NEW_PARSER DELIMITER TO DATABASE={0}.".format(
self.column_delimiter_object.column_delimiter)
print "Dict for column_delimiter_object={0}.".format(
self.column_delimiter_object.__dict__)
new_parser.DELIMITER = self.column_delimiter_object.column_delimiter
super(BodyTable, self).commit(new_parser)
def bind_attributes(self, parser_detail, config_record):
parser_detail.ColumnName=config_record.column_name
parser_detail.ColumnWidth=config_record.column_width
parser_detail.ValueType=config_record.value_type
parser_detail.TagName=config_record.tag_name
class BodyTableEditor(editor.Editor):
fields = 'name parser_type column_name column_width value_type tag_name'.split()
def __init__(self, target):
super(BodyTableEditor, self).__init__(target, self.fields)
self.column_width.validate(validator.to_int().greater_than(-1))
def reset_values(self):
self.column_name('')
self.column_width('0')
self.tag_name('')
def append_formdata(self):
super(BodyTableEditor, self).commit(self.fields)
append_deep_copy(self.target)
self.reset_values()
def remove_formdata(self, i):
tp("Removing this formdata: {0} from this target {1}.".format(
i, self.target.__dict__))
self.target.config_records.pop(i)
@presentation.render_for(BodyTableEditor)
def render(self, h, comp, *args):
tp("when rendering BodyTableEditor, column_delimiter={0}.".format(self.target.column_delimiter_object.column_delimiter))
with h.div:
h << self.target.column_delimiter_comp
h << h.hr
with h.form.pre_action(self.reset_values).post_action(self.append_formdata):
with h.div:
h << "Column Name: " << h.input(
value=self.column_name()).action(self.column_name).error(
self.column_name.error)
with h.div:
h << "Column Width: " << h.input(
value=self.column_width()).action(self.column_width).error(
self.column_width.error)
with h.div:
h << "Value Type: "
self.target.valuetyped_render(h, self)
with h.div:
h << "Tag Name" << h.input(value=self.tag_name()).action(
self.tag_name).error(self.tag_name.error)
h << h.br << h.input(type='submit', value='Add')
h << h.hr
for i, r in enumerate(self.target.config_records):
with h.form:
with h.div:
h << "Column Name: " << h.input(value=r.column_name)
h << "Column Width: " << h.input(value=r.column_width)
h << "Value Type" << h.input(value=r.value_type)
h << "Tag Name" << h.input(value=r.tag_name)
h << h.input(type='submit', value='Delete').action(
self.remove_formdata, i)
return h.root
class ParserConfig(object):
def __init__(self, name, parser_type):
self.name = name
self.parser_type = parser_type
o = self.build_from(CustomRow)
o.parser_section = 'header'
c = CustomRowEditor(o)
self.header = component.Component(c)
if self.parser_type == 'HeaderOnly':
self.body = None
else:
o = self.factory()
o.target.parser_section = 'body'
self.body = component.Component(o)
def factory(self):
if self.parser_type == 'HeaderOnly' or self.parser_type == 'CustomRows':
c = CustomRowEditor(self.build_from(CustomRow))
elif self.parser_type == 'Text':
c = BodyTextEditor(self.build_from(BodyText))
elif self.parser_type == 'Table':
c = BodyTableEditor(self.build_from(BodyTable))
elif self.parser_type == 'KeyValue':
c = BodyKeyValueEditor(self.build_from(BodyKeyValue))
else:
raise Exception("NOTFOUND")
return c
def build_from(self, c):
o = c()
o.name = self.name
o.parser_type = self.parser_type
return o
def new_parser(self):
return models.OBFL_Parser(
Parser_Alias=self.name,
Parser_Name=self.name,
ParserType=self.parser_type,
isEnabled='Y',
Multiline_YN='Y',
Application='OBFL',
ProductFamily='["generic"]',
OS='["generic"]'
)
def commit_to_database(self, comp):
with database.session.no_autoflush:
new_parser = self.new_parser()
self.header().target.commit_to_database(new_parser)
if self.parser_type != 'HeaderOnly':
if self.parser_type == 'Table':
tp("BodyTableColumnDelimiter={0}.".format(
self.body().target.column_delimiter_object.__dict__))
self.body().target.commit_to_database(new_parser)
database.session.add(new_parser)
comp.becomes(ParserList())
@presentation.render_for(ParserConfig)
def render(self, h, comp, *args):
h << h.h2("Parser Name: ", self.name)
with h.fieldset:
h << h.legend('Header Config')
h << self.header
if self.parser_type != "HeaderOnly":
with h.fieldset:
h << h.legend('Body Config')
h << self.body
h << h.br
h << h.a('Commit to Database').action(self.commit_to_database, comp)
return h.root
# define app
app = TabNav
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment