public
Last active

This is a toy one-file application to manage persistent key-value string data. The file is *both* the application and its data. When you run any of the commands described in `escher.py --help`, the file will be executed and, after data change, it will rewrite itself with updated data. You can copy the file with whatever name to create multiple datasets. Remember that the data will be copied with the file. Each file must be readable, writable, and executable.

  • Download Gist
escher.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#! /usr/bin/env python
 
"""{escher} -- one-file key-value storage.
 
What?
This is a toy application to manage persistent key-value string data.
The file {escher} is *both* the application and its data.
When you run any of the commands below, the file will be executed and,
after data change, it will rewrite itself with updated data.
You can copy the file with whatever name to create multiple datasets.
Remember that the data will be copied with the file. Each file must
be readable, writable, and executable.
 
Why?
I don't know; this is probably useless.
 
Usage:
Listing current keys:
$ {escher}
 
Getting the value of the foo key:
$ {escher} foo
(NOTE: If foo is not in the dataset, exit code will be 1.)
 
Setting the value of foo to bar:
$ {escher} foo bar
 
Removing the key foo:
$ {escher} foo ""
(NOTE: If foo is not in the dataset, exit code will be 1.)
 
Removing everything:
$ {escher} --clean
 
Printing this help message:
$ {escher} --help
"""
 
from __future__ import print_function
 
import sys
import os
import pickle
import zlib
import base64
 
__doc__ = __doc__.format(escher=os.path.basename(__file__))
 
sep = "--//--"
 
f = open(__file__, "r")
esc, her = f.read().split(repr(sep), 1)
f.close()
 
data = pickle.loads(zlib.decompress(base64.b64decode(her[1:].strip())))
 
args = sys.argv[1:]
print([
lambda : "\n".join(sorted(data.keys())) if data else
sys.exit(),
lambda key : __doc__ if key == "--help" else
not data.clear() and "X *" if key == "--clean" else
data.get(key, False) or
sys.exit("Error: key not found."),
lambda key, value : not data.update([(key, value)]) and
" ".join([key, "<-", value]) if value else
data.pop(key, True) and "X " + key if key in data else
sys.exit("Error: key not found."),
lambda fu, ti, le : print("Error: invalid argument list.") or sys.exit(2)
][min(len(args), 3)](*args[:3]))
 
her = base64.b64encode(zlib.compress(pickle.dumps(data, 2))).decode('ascii')
 
out = repr(sep).join([esc, "\n#" + her + "\n"])
with open(__file__, "w") as f: f.write(out)
 
'--//--'
#eJxrYKotZNADAAaFAZ8=

There seems to be some issue when running with some concurrency. I did a quick test run with: seq 5000 | xargs -P100 -I% python escher.py foo% % and the file got corrupt.

I conclude that this, sir, is not in fact, web scale.

Clearly it needs more node.js and eventloop/reactor style programming to make it webscale. Also while we're at it, chuck redis in and mongodb or something. Then it'll be webscale.

One thing I found when using this to replace my MongoDB installation is that it doesn't like '}' characters in the values (or keys). Pity. I don't see how this can get to be webscale without javascript compatibility.

I thought you were just supposed to say "Hadoop" three times and drop your wallet on the floor?

@chewxy

, chuck redis in and mongodb or something.

Chuck Norris in and mongodb or something.

I can see why you are programmers and not comedians.

Haha, I wrote one of these myself, several years ago:

https://gist.github.com/477550

@mdda
I couldn't reproduce any problem with '}' characters. Perhaps your shell uses then for substitution? Did you try enclosing the arguments in quotes? Can you show an example that doesn't work so I can try to fix it?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.