Created
May 13, 2015 00:47
-
-
Save metaperl/9cf7b7106a856710bd71 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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