Merge branch 'master' into peter

This commit is contained in:
brian m. carlson 2015-01-20 03:05:30 +00:00
commit 474bab8c4c
No known key found for this signature in database
GPG key ID: BF535D811F52F68B
5 changed files with 118 additions and 23 deletions

View file

@ -12,6 +12,18 @@ Requirements
In Debian, installing the +python3-urwid+ package will generally satisfy the
dependencies.
If you want to build the documentation as well, you'll need
* Asciidoctor
* Apache FOP
* DocBook XSL-NS stylesheets (the DocBook 5 ones)
* xsltproc
Development requirements include
* pep8
* pyflakes3
newfol is generally developed with the latest version of Python 3, but should be
compatible with earlier versions. Please file an issue on GitHub if something
is broken.

View file

@ -3,8 +3,9 @@ OBJ := $(SRC:.adoc=.pdf) $(SRC:.adoc=.html) $(SRC:.adoc=.ps)
EXTRA_OBJ := $(SRC:.adoc=.xhtml)
EXTRA_OBJ += $(SRC:.adoc=.xml) $(SRC:.adoc=.fo)
ASCIIDOC := asciidoctor
XSLTPROC := xsltproc
FOP := fop
XSLTPROC := xsltproc
XSLT_PARAMS ?=
DOCBOOK_XSL := /usr/share/xml/docbook/stylesheet/docbook-xsl-ns
DOCBOOK_FO := $(DOCBOOK_XSL)/fo/docbook.xsl
@ -24,7 +25,7 @@ clean:
$(ASCIIDOC) -b docbook5 -o $@ $<
%.fo: %.xml
$(XSLTPROC) -o $@ $(DOCBOOK_FO) $<
$(XSLTPROC) $(XSLT_PARAMS) -o $@ $(DOCBOOK_FO) $<
%.pdf: %.fo
$(FOP) -fo $< -pdf $@

View file

@ -142,3 +142,38 @@ settings, colors, and keybindings.
The default location is +_$XDG_CONFIG_HOME_/newfol/defaults+. If
`$XDG_CONFIG_HOME` is not defined, it defaults to +_$HOME_/.config+.
== Key Bindings
Below are the default key bindings. These can be customized with the schema
file and configuration file.
[options="header"]
|===
|Key | Shortcut Name | Meaning
|F1 | previous | Go back one screen
|F2 | sync-database | Save
|F3 | add | Display the Add Record screen
|F4 | search | Display the Search Records screen
|F5 | next | Continue to the next screen
|F6 | next-secondary | Continue; display results in editor read-only
|F7 | menu | Display the menu
|F9 | next-tertiary | Continue; display results in editor read-write
|Ctrl-F5 | invert-selection | Toggle the current item
|Ctrl-F | browse-all | Browse all records
|Ctrl-B | browse | List the tables which have records to browse
|Ctrl-X | about | Display the About screen
|Alt-D | right | Go right
|Alt-G | delete | Delete the character in front of the cursor
|Alt-H | backspace | Delete the character behind the cursor
|Alt-I | up | Go up
|Alt-K | left | Go left
|Alt-N | down | Go down
|Alt-U | home | As if the Home key were pressed
|Alt-Y | remove | Toggle whether the current record is deleted
|Alt-; | end | As if the End key were pressed
|Enter | select | Select a button
|Tab | next-field | Go to the next field
|Shift-Tab | previous-field | Go to the previous field
|Shift-Q | quit | Quit the program
|===

View file

@ -546,11 +546,7 @@ class RawFile(FileFormat):
class FileStorage:
"""A file (or file-like object) in a certain format."""
DEFAULT_TRANSACTION_TYPES = ('hash',)
def __init__(self, fmt, filename, txnformat=None, options=None):
txnformat = self._canonicalize_transaction_types(txnformat)
self._txn = self._make_transaction_store(txnformat, options)
backends = {
BACKENDS = {
"csv": CSVFile,
"qddb": QDDBFile,
"pickle": PickleFile,
@ -558,11 +554,44 @@ class FileStorage:
"yaml": YAMLFile,
"raw": RawFile
}
HOOKS = {
"git": GitHook,
"sha256": lambda *a, **k: HashHook("sha256", *a, **k),
"sha384": lambda *a, **k: HashHook("sha384", *a, **k),
"sha512": lambda *a, **k: HashHook("sha512", *a, **k),
"hash": lambda *a, **k: HashHook(None, *a, **k),
}
def __init__(self, fmt, filename, txnformat=None, options=None):
txnformat = self._canonicalize_transaction_types(txnformat)
self._txn = self._make_transaction_store(txnformat, options)
try:
self._backend = backends[fmt](filename, self._txn, options)
self._backend = self.BACKENDS[fmt](filename, self._txn, options)
except KeyError:
raise ValueError("{0}: not a supported backend".format(fmt))
@classmethod
def register_backend(klass, name, obj):
klass.BACKENDS[name] = obj
@classmethod
def unregister_backend(klass, name):
try:
del klass.BACKENDS[name]
except KeyError:
pass
@classmethod
def register_hook(klass, name, obj):
klass.HOOKS[name] = obj
@classmethod
def unregister_hook(klass, name):
try:
del klass.HOOKS[name]
except KeyError:
pass
@staticmethod
def _canonicalize_transaction_types(types):
if types is None:
@ -575,23 +604,13 @@ class FileStorage:
stypes.discard("hash")
return list(filter(lambda x: x in stypes, types))
@staticmethod
def _get_transaction_types():
return {
"git": GitHook,
"sha256": lambda *a, **k: HashHook("sha256", *a, **k),
"sha384": lambda *a, **k: HashHook("sha384", *a, **k),
"sha512": lambda *a, **k: HashHook("sha512", *a, **k),
"hash": lambda *a, **k: HashHook(None, *a, **k),
}
@staticmethod
def transaction_types():
return list(sorted(FileStorage._get_transaction_types().keys()))
return list(sorted(FileStorage.HOOKS.keys()))
@staticmethod
def _make_transaction_store(items, options):
txntypes = FileStorage._get_transaction_types()
txntypes = FileStorage.HOOKS
if items is None or items == "":
return Hook()
elif isinstance(items, str):

View file

@ -241,5 +241,33 @@ class SHA256TransactionTest(unittest.TestCase):
None)
class ExampleFile(newfol.filemanip.FileFormat):
def __init__(self, filename, txn, options):
self.inited = True
def store(self, records):
self.stored = True
pass
def load(self):
return [Record(['a', 'b'])]
class PluggableBackendsTest(unittest.TestCase):
def test_adding_backend(self):
FileStorage.register_backend('example', ExampleFile)
self.assertEqual(FileStorage.BACKENDS['example'], ExampleFile)
fs = FileStorage('example', 'filename')
recs = fs.load()
self.assertEqual(len(recs), 1)
self.assertEqual(recs[0].fields, ['a', 'b'])
def test_removing_backend(self):
FileStorage.register_backend('example', ExampleFile)
self.assertEqual(FileStorage.BACKENDS['example'], ExampleFile)
FileStorage.unregister_backend('example')
with self.assertRaises(KeyError):
FileStorage.BACKENDS['example']
if __name__ == '__main__':
unittest.main()