Såvidt begynt på nytt kommandolinjegrensesnitt.
* Kopiert inn noe dokumentasjon (filformat og kommandolinjeargumenter) fra forrige forsøk (som var i python-katalogen). * Kopiert implementajonen av filformatet fra forrige forsøk. * Kopiert nyttige ting fra mdboh, samt noe fra forrige inkarnasjon av kommandolinjegrensesnittet her, til util.py * Skrevet litt testkode i worblehat.py.
This commit is contained in:
parent
e490174661
commit
e0aa1d53d2
|
@ -0,0 +1,67 @@
|
||||||
|
# Forslag til kommandolinjeargumenter og deres betydning.
|
||||||
|
|
||||||
|
# søk etter bøker som inneholder «computer programming» og «knuth» (i
|
||||||
|
# tittel, undertittel eller forfatternavn):
|
||||||
|
worlbehat search 'computer programming' knuth
|
||||||
|
# søk i beskrivelse også:
|
||||||
|
worblehat --search-description search tex
|
||||||
|
|
||||||
|
# list opp alle bøkene:
|
||||||
|
worblehat list book
|
||||||
|
# vis boken med en gitt ISBN:
|
||||||
|
worblehat show 5467237485472
|
||||||
|
# vis bok, med kart:
|
||||||
|
worblehat --with-map show 5467237485472
|
||||||
|
|
||||||
|
# list opp alle personer:
|
||||||
|
worblehat list person
|
||||||
|
# søk etter person:
|
||||||
|
worblehat search-person donald knuth
|
||||||
|
# vis en person:
|
||||||
|
worblehat show dek
|
||||||
|
|
||||||
|
# skriv ut informasjon i samme format som commit forventer:
|
||||||
|
worblehat --commit-format show 5467237485472
|
||||||
|
worblehat --commit-format show dek
|
||||||
|
# samme, til en ny fil i /tmp:
|
||||||
|
worblehat --commit-format --tmp-file show 5467237485472
|
||||||
|
worblehat --commit-format --tmp-file show dek
|
||||||
|
# kan vise flere ting samtidig:
|
||||||
|
worblehat --commit-format --tmp-file show 5467237485472 432175437253 dek rms mlh
|
||||||
|
|
||||||
|
# lagre informasjon fra en fil i databasen (filen kan inneholde både
|
||||||
|
# nye og endrede personer og bøker):
|
||||||
|
worblehat commit # leser fra stdin
|
||||||
|
worblehat commit fjas.txt
|
||||||
|
|
||||||
|
# endre en bok/person
|
||||||
|
# (kombinerer `wh --commit-format --tmp-file show ...`,
|
||||||
|
# `$EDITOR /tmp/...`
|
||||||
|
# og `wh commit /tmp/...`)
|
||||||
|
worblehat edit 5467237485472
|
||||||
|
worblehat edit 5467237485472 432175437253 dek rms mlh
|
||||||
|
|
||||||
|
# foreslå informasjon om nye bøker (leser ISBN-numre fra stdin, søker
|
||||||
|
# i Google Books eller lignende, skriver info i commit-format til
|
||||||
|
# stdout (eller tmp-fil)):
|
||||||
|
worblehat suggest-book-data
|
||||||
|
worblehat --tmp-file suggest-book-data
|
||||||
|
# registrer nye bøker
|
||||||
|
# (kombinerer `wh --tmp-file suggest-book-data`,
|
||||||
|
# `$EDITOR /tmp/...`
|
||||||
|
# og `wh commit /tmp/...`)
|
||||||
|
worblehat register-books
|
||||||
|
|
||||||
|
# list opp alle kategoriene (med id, navn, muligens noe mer):
|
||||||
|
worblehat list category
|
||||||
|
# vis en kategori (vis informasjon om kategorien, samt liste over bøkene):
|
||||||
|
worblehat show matematikk
|
||||||
|
# vis en kategori, med plassering på kart:
|
||||||
|
worblehat --with-map show matematikk
|
||||||
|
|
||||||
|
# vis kart over bokhyllene:
|
||||||
|
worblehat map
|
||||||
|
# vis kart over hyllen som heter 'A':
|
||||||
|
worblehat map A
|
||||||
|
# vis kart over hyllen som heter 'A', og uthev hyllene med matematikk i:
|
||||||
|
worblehat map A matematikk
|
|
@ -0,0 +1,70 @@
|
||||||
|
Filformatet som forventes av 'commit'-kommandoen, og som skrives ut av
|
||||||
|
kommandoen 'suggest-book-data', samt av andre kommandoer når man gir
|
||||||
|
opsjonen --commit-format
|
||||||
|
|
||||||
|
En linje som starter med '#' er en kommentar.
|
||||||
|
|
||||||
|
Filen består av ett eller flere avsnitt. En blank linje indikerer
|
||||||
|
nytt avsnitt. Hvert avsnitt beskriver én ting som skal gjøres. De
|
||||||
|
mulige tingene å gjøre er: legge inn ny bok eller forfatter, endre en
|
||||||
|
eksisterende bok eller forfatter, slette en bok eller forfatter.
|
||||||
|
|
||||||
|
Hvert avsnitt har en samling felter med tilhørende verdier. Et felt
|
||||||
|
skrives med feltnavn, kolon, verdi, newline. Hvis verdien skal bestå
|
||||||
|
av flere linjer, brukes whitespace (minst ett mellomrom eller en tab)
|
||||||
|
på begynnelsen av hver ekstra linje. Whitespace (inkludert newline)
|
||||||
|
mellom kolonet og verdien ignoreres. Whitespace på slutten av linjer
|
||||||
|
ignoreres. Whitespace på begynnelsen av fortsettelseslinjer fjernes i
|
||||||
|
verdien som lagres, men newline-ene beholdes.
|
||||||
|
|
||||||
|
Eksempler på felter:
|
||||||
|
|
||||||
|
title: Foo Bar
|
||||||
|
description:
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
In ut est ac ante aliquam dictum. Nulla facilisi. Cras vel
|
||||||
|
lectus mauris. In nec convallis mauris.
|
||||||
|
|
||||||
|
Hvert avsnitt må inneholde feltet 'action', som beskriver hva som skal
|
||||||
|
gjøres. De mulige verdiene for action-feltet er:
|
||||||
|
|
||||||
|
new-book
|
||||||
|
edit-book
|
||||||
|
delete-book
|
||||||
|
new-person
|
||||||
|
edit-person
|
||||||
|
delete-person
|
||||||
|
new-category
|
||||||
|
edit-category
|
||||||
|
delete-category
|
||||||
|
|
||||||
|
Eksempler:
|
||||||
|
|
||||||
|
action: new-book
|
||||||
|
isbn: 4325463287546
|
||||||
|
title: Foo Bar
|
||||||
|
subtitle: Baaaz
|
||||||
|
category: matematikk
|
||||||
|
persons:
|
||||||
|
author rjh
|
||||||
|
author oo
|
||||||
|
illustrator ko
|
||||||
|
publisher: Foo Publishing
|
||||||
|
published_year: 2010
|
||||||
|
edition: 1
|
||||||
|
num_pages: 420
|
||||||
|
series:
|
||||||
|
description:
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
In ut est ac ante aliquam dictum. Nulla facilisi. Cras vel
|
||||||
|
lectus mauris. In nec convallis mauris.
|
||||||
|
picture:
|
||||||
|
thumbnail:
|
||||||
|
references:
|
||||||
|
url http://example.org/
|
||||||
|
wikipedia http://en.wikipedia.org/wiki/FooBar
|
||||||
|
|
||||||
|
action: edit-category
|
||||||
|
id: matematikk
|
||||||
|
name: Matematikk
|
||||||
|
placement: T10 T11 T12
|
|
@ -0,0 +1,180 @@
|
||||||
|
import types
|
||||||
|
|
||||||
|
# The possible fields for each type of object.
|
||||||
|
#
|
||||||
|
# Each field is a tuple (fieldname, fieldtype). Fieldtype is either
|
||||||
|
# 's' (string), 'd' (dictionary, where the values are lists of
|
||||||
|
# strings), 'l' (list of strings).
|
||||||
|
fields = {
|
||||||
|
'book':
|
||||||
|
[('isbn', 's'), ('title', 's'), ('category', 's'),
|
||||||
|
('subtitle', 's'), ('persons', 'd'), ('publisher', 's'),
|
||||||
|
('published_year', 'i'), ('edition', 'i'), ('num_pages', 'i'),
|
||||||
|
('series', 's'), ('description', 's'), # TODO picture, thumbnail
|
||||||
|
('references', 'd')],
|
||||||
|
'person':
|
||||||
|
[('id', 's'), ('first_name', 's'), ('last_name', 's')],
|
||||||
|
'category':
|
||||||
|
[('id', 's'), ('name', 's'), ('placement', 'l')] }
|
||||||
|
|
||||||
|
# Fields associated with each action.
|
||||||
|
#
|
||||||
|
# The 'type' is a key in the fields dictionary, indicating the set of
|
||||||
|
# fields which can be used with the action. The 'required' list is a
|
||||||
|
# list of fields which must be present for the action to be accepted.
|
||||||
|
action_fields = {
|
||||||
|
'new-book':
|
||||||
|
{ 'type': 'book',
|
||||||
|
'required': ['isbn', 'title', 'category'] },
|
||||||
|
'edit-book':
|
||||||
|
{ 'type': 'book',
|
||||||
|
'required': ['isbn'] },
|
||||||
|
'delete-book':
|
||||||
|
{ 'type': 'book',
|
||||||
|
'required': ['isbn'] },
|
||||||
|
'new-person':
|
||||||
|
{ 'type': 'person',
|
||||||
|
'required': ['id', 'first_name', 'last_name'] },
|
||||||
|
'edit-person':
|
||||||
|
{ 'type': 'person',
|
||||||
|
'required': ['id'] },
|
||||||
|
'delete-person':
|
||||||
|
{ 'type': 'person',
|
||||||
|
'required': ['id'] },
|
||||||
|
'new-category':
|
||||||
|
{ 'type': 'category',
|
||||||
|
'required': ['id', 'name'] },
|
||||||
|
'edit-category':
|
||||||
|
{ 'type': 'category',
|
||||||
|
'required': ['id'] },
|
||||||
|
'delete-category':
|
||||||
|
{ 'type': 'category',
|
||||||
|
'required': ['id'] } }
|
||||||
|
|
||||||
|
class CommitFormatSyntaxError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def read_field_value_str(val):
|
||||||
|
return '\n'.join(map(lambda x: x.strip(), val.split('\n'))).strip()
|
||||||
|
|
||||||
|
def read_field_value_int(val):
|
||||||
|
if val.strip() == '':
|
||||||
|
return None
|
||||||
|
return int(val.strip())
|
||||||
|
|
||||||
|
def read_field_value_dict(val):
|
||||||
|
d = {}
|
||||||
|
if val.strip() == '':
|
||||||
|
return d
|
||||||
|
for line in val.strip().split('\n'):
|
||||||
|
key, value = line.strip().split(' ', 1)
|
||||||
|
if key in d:
|
||||||
|
d[key].append(value)
|
||||||
|
else:
|
||||||
|
d[key] = [value]
|
||||||
|
return d
|
||||||
|
|
||||||
|
def read_field_value_list(val):
|
||||||
|
return val.strip().split(' ')
|
||||||
|
|
||||||
|
def read_action(text):
|
||||||
|
'''
|
||||||
|
Parse text as an action, returning a dictionary.
|
||||||
|
'''
|
||||||
|
lines = text.split('\n')
|
||||||
|
print 'reading action'
|
||||||
|
print 'lines:'
|
||||||
|
print lines
|
||||||
|
d = {}
|
||||||
|
lastfield = None
|
||||||
|
for line in lines:
|
||||||
|
if len(line) == 0:
|
||||||
|
raise CommitFormatSyntaxError('Empty line in action')
|
||||||
|
if line[0] in [' ', '\t']: # continuation line
|
||||||
|
if not lastfield:
|
||||||
|
raise CommitFormatSyntaxError('First line is continuation line: ' + line)
|
||||||
|
d[lastfield] = d[lastfield] + '\n' + line.strip()
|
||||||
|
else:
|
||||||
|
field, value = line.split(':', 1)
|
||||||
|
d[field] = value.strip()
|
||||||
|
lastfield = field
|
||||||
|
|
||||||
|
if 'action' not in d:
|
||||||
|
raise CommitFormatSyntaxError('Missing \'action\' field')
|
||||||
|
action = d['action']
|
||||||
|
|
||||||
|
print 'dict:'
|
||||||
|
print d
|
||||||
|
|
||||||
|
for field in action_fields[action]['required']:
|
||||||
|
if field not in d:
|
||||||
|
raise CommitFormatSyntaxError('Missing required field \'%s\' in \'%s\' action' % (field, action))
|
||||||
|
data_type = action_fields[action]['type']
|
||||||
|
result = { 'action': action }
|
||||||
|
for field, ftype in fields[data_type]:
|
||||||
|
if field in d:
|
||||||
|
reader = { 's': read_field_value_str,
|
||||||
|
'i': read_field_value_int,
|
||||||
|
'd': read_field_value_dict,
|
||||||
|
'l': read_field_value_list }[ftype]
|
||||||
|
result[field] = reader(d[field])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def read_actionlist(text):
|
||||||
|
'''
|
||||||
|
Parse text as a list of actions.
|
||||||
|
|
||||||
|
The result is a list of dictionaries.
|
||||||
|
'''
|
||||||
|
return map(lambda x: read_action(x.strip()),
|
||||||
|
text.split('\n\n'))
|
||||||
|
|
||||||
|
def write_field_value_str(val):
|
||||||
|
lines = ''
|
||||||
|
if not val:
|
||||||
|
val = ''
|
||||||
|
val = unicode(val)
|
||||||
|
value_lines = val.split('\n')
|
||||||
|
for l in value_lines:
|
||||||
|
lines += ' ' + l + '\n'
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def write_field_value_dict(val):
|
||||||
|
lines = '\n'
|
||||||
|
for (key,values) in val.items():
|
||||||
|
for single_value in values:
|
||||||
|
lines += ' ' + key + ' ' + unicode(single_value) + '\n'
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def write_field_value_list(val):
|
||||||
|
lines = ''
|
||||||
|
for single_value in val:
|
||||||
|
lines += ' ' + unicode(single_value)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def make_comment(s):
|
||||||
|
return '\n'.join(map(lambda x: '# ' + x,
|
||||||
|
s.split('\n'))) + '\n'
|
||||||
|
|
||||||
|
def write_action(d):
|
||||||
|
if type(d) in types.StringTypes:
|
||||||
|
return make_comment(d)
|
||||||
|
lines = ''
|
||||||
|
if 'comment' in d:
|
||||||
|
lines += make_comment(d['comment'])
|
||||||
|
action = d['action']
|
||||||
|
lines += 'action: ' + action + '\n'
|
||||||
|
data_type = action_fields[action]['type']
|
||||||
|
for field, ftype in fields[data_type]:
|
||||||
|
if field in d:
|
||||||
|
value_writer = {'s': write_field_value_str,
|
||||||
|
'i': write_field_value_str,
|
||||||
|
'd': write_field_value_dict,
|
||||||
|
'l': write_field_value_list}[ftype]
|
||||||
|
lines += field + ':' + value_writer(d[field])
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def write_actionlist(actions):
|
||||||
|
return '\n'.join(map(write_action, actions))
|
||||||
|
|
||||||
|
# test: print write_actionlist([{'comment':'Foo!\nBar!','action':'new-book','isbn':'434545'},{'action':'edit-book','isbn':'654654745','persons':{'author':['ab','foo'],'illustrator':['moo']}},'This\nis\na\ncomment.',{'action':'edit-category','id':'matematikk','name':'Matematikk','placement':['T10','T11']}])
|
|
@ -0,0 +1,65 @@
|
||||||
|
def make_result_dict(cursor, row):
|
||||||
|
d = {}
|
||||||
|
for i in xrange(len(row)):
|
||||||
|
d[cursor.description[i][0]] = row[i]
|
||||||
|
return d
|
||||||
|
|
||||||
|
def fetchone_dict(cursor):
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row != None:
|
||||||
|
return make_result_dict(cursor, row)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def fetchall_dict(cursor):
|
||||||
|
return map(lambda r: make_result_dict(cursor, r),
|
||||||
|
cursor.fetchall())
|
||||||
|
|
||||||
|
def first(lst):
|
||||||
|
return lst[0]
|
||||||
|
|
||||||
|
def second(lst):
|
||||||
|
return lst[1]
|
||||||
|
|
||||||
|
def count(predicate, lst):
|
||||||
|
c = 0
|
||||||
|
for elem in lst:
|
||||||
|
if predicate(elem):
|
||||||
|
c = c+1
|
||||||
|
return c
|
||||||
|
|
||||||
|
def find(predicate, lst):
|
||||||
|
for elem in lst:
|
||||||
|
if predicate(elem):
|
||||||
|
return elem
|
||||||
|
return None
|
||||||
|
|
||||||
|
def unique(lst):
|
||||||
|
newlst = []
|
||||||
|
for elem in lst:
|
||||||
|
if elem not in newlst:
|
||||||
|
newlst.append(elem)
|
||||||
|
return newlst
|
||||||
|
|
||||||
|
def mapcond(fun, predicate, lst):
|
||||||
|
def mapfun(x):
|
||||||
|
if predicate(x):
|
||||||
|
return fun(x)
|
||||||
|
return x
|
||||||
|
return map(mapfun, lst)
|
||||||
|
|
||||||
|
def maptup(fun, lst):
|
||||||
|
return tuple(map(fun, lst))
|
||||||
|
|
||||||
|
def translate(value, translations):
|
||||||
|
return translations.get(value, value)
|
||||||
|
|
||||||
|
def p(s):
|
||||||
|
encoded = s
|
||||||
|
if isinstance(s, unicode):
|
||||||
|
encoded = s.encode('utf8')
|
||||||
|
print encoded
|
||||||
|
|
||||||
|
def cut_str(string, length, ellipsis='...'):
|
||||||
|
if len(string) < length:
|
||||||
|
return string
|
||||||
|
return string[0:length-len(ellipsis)]+ellipsis
|
|
@ -0,0 +1,12 @@
|
||||||
|
import pgdb
|
||||||
|
from fileformat import read_actionlist, write_actionlist
|
||||||
|
from util import *
|
||||||
|
|
||||||
|
connection = pgdb.connect(database='oysteini_pbb2',
|
||||||
|
user='oysteini_pbb',
|
||||||
|
password='lio5Aide',
|
||||||
|
host='postgres.pvv.ntnu.no');
|
||||||
|
|
||||||
|
c = connection.cursor()
|
||||||
|
c.execute('SELECT * from bok')
|
||||||
|
print fetchall_dict(c)
|
Reference in New Issue