Skip to content

Commit

Permalink
Version bump: ran 2to3, changed buffer to memoryview, updated setup a…
Browse files Browse the repository at this point in the history
…nd tox config
  • Loading branch information
kazeka committed Dec 24, 2015
1 parent 4dc1de4 commit b720de2
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
language: python
python:
- "3.4"
- "2.7"
- "2.6"

install: pip install -r test-requirements.txt --use-mirrors
script: sh run-tests
3 changes: 3 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.. image:: https://travis-ci.org/litl/park.svg?branch=master :alt: Build Status
.. image:: https://coveralls.io/repos/litl/park/badge.svg?branch=master :alt: Coverage Status

Park is a persistent key-value API for Python with ordered traversal
of keys. Both keys and values are binary safe. It's similar in use to
LevelDB, but has no dependencies outside the Python standard library.
Expand Down
54 changes: 38 additions & 16 deletions park.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
# coding: utf-8
# Copyright 2012 litl, LLC. All Rights Reserved.

__version__ = "1.0.0"
# Copyright 2012-2015 litl, LLC. All Rights Reserved.

import abc
import itertools
import logging
import os
import sqlite3

__version__ = "1.1.0"

logger = logging.getLogger(__name__)

__all__ = ["SQLiteStore", "KVStore"]

import sys
if sys.version_info < (3,):
def b(x):
return x

def un_b(x):
return x
else:
import codecs

def b(x):
return codecs.latin_1_encode(x)[0]

def un_b(x):
return codecs.latin_1_decode(x)[0]


class KVStore(object):
"""An abstract key-value interface with support for range iteration."""
Expand Down Expand Up @@ -244,7 +260,7 @@ def __init__(self, path):
self.conn = sqlite3.connect(path)

# Don't create unicode objects for retrieved values
self.conn.text_factory = buffer
self.conn.text_factory = memoryview

# Disable the SQLite cache. Its pages tend to get swapped
# out, even if the database file is in buffer cache.
Expand Down Expand Up @@ -284,15 +300,16 @@ def get(self, key, default=None):
q = "SELECT value FROM kv WHERE key = ?"
c = self.conn.cursor()

row = c.execute(q, (sqlite3.Binary(key),)).fetchone()
row = c.execute(q, (sqlite3.Binary(b(key)),)).fetchone()
if not row:
return default

return bytes(row[0])
return un_b(bytes(row[0]))

def put(self, key, value):
q = "INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)"
self.conn.execute(q, (sqlite3.Binary(key), sqlite3.Binary(value)))
self.conn.execute(q,
(sqlite3.Binary(b(key)), sqlite3.Binary(b(value))))
self.conn.commit()

def put_many(self, items):
Expand All @@ -301,14 +318,15 @@ def put_many(self, items):

blob = sqlite3.Binary
for batch in ibatch(items, 30000):
items = ((blob(key), blob(value)) for key, value in batch)
items = ((blob(b(key)), blob(b(value)))
for key, value in batch)

c.executemany(q, items)
self.conn.commit()

def delete(self, key):
q = "DELETE FROM kv WHERE key = ?"
self.conn.execute(q, (sqlite3.Binary(key),))
self.conn.execute(q, (sqlite3.Binary(b(key)),))
self.conn.commit()

def delete_many(self, keys):
Expand All @@ -317,19 +335,23 @@ def delete_many(self, keys):

blob = sqlite3.Binary
for batch in ibatch(keys, 30000):
items = ((blob(key),) for key in batch)
items = ((blob(b(key)),) for key in batch)

c.executemany(q, items)
self.conn.commit()

def _range_where(self, key_from=None, key_to=None):
if key_from is not None and key_to is None:
key_from = b(key_from)
return "WHERE key >= :key_from"

if key_from is None and key_to is not None:
key_to = b(key_to)
return "WHERE key <= :key_to"

if key_from is not None and key_to is not None:
key_from = b(key_from)
key_to = b(key_to)
return "WHERE key BETWEEN :key_from AND :key_to"

return ""
Expand All @@ -339,25 +361,25 @@ def items(self, key_from=None, key_to=None):
% self._range_where(key_from, key_to)

if key_from is not None:
key_from = sqlite3.Binary(key_from)
key_from = sqlite3.Binary(b(key_from))

if key_to is not None:
key_to = sqlite3.Binary(key_to)
key_to = sqlite3.Binary(b(key_to))

c = self.conn.cursor()
for key, value in c.execute(q, dict(key_from=key_from, key_to=key_to)):
yield bytes(key), bytes(value)
yield un_b(bytes(key)), un_b(bytes(value))

def keys(self, key_from=None, key_to=None):
q = "SELECT key FROM kv %s ORDER BY key " \
% self._range_where(key_from, key_to)

if key_from is not None:
key_from = sqlite3.Binary(key_from)
key_from = sqlite3.Binary(b(key_from))

if key_to is not None:
key_to = sqlite3.Binary(key_to)
key_to = sqlite3.Binary(b(key_to))

c = self.conn.cursor()
for key, in c.execute(q, dict(key_from=key_from, key_to=key_to)):
yield bytes(key)
yield un_b(bytes(key))
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Load the test requirements. These are in a separate file so they can
# be accessed from Travis CI and tox.
with open("test-requirements.txt") as fd:
tests_require = list(fd.xreadlines())
tests_require = list(fd)


setup(
Expand All @@ -25,7 +25,7 @@
py_modules=["park"],

setup_requires=[
"unittest2==0.5.1"
"unittest2==1.1.0"
],

test_suite="unittest2.collector",
Expand Down
6 changes: 3 additions & 3 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
coverage==3.5.2
pep8==1.3.3
pyflakes==0.5.0
coverage==4.0
pep8==1.6.2
pyflakes==1.0.0
8 changes: 4 additions & 4 deletions test_park.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# coding: utf-8
# Copyright 2012 litl, LLC. All Rights Reserved.
# Copyright 2012-2015 litl, LLC. All Rights Reserved.

import operator
import os
Expand Down Expand Up @@ -189,12 +189,12 @@ def test_items(self):
("nine", "value9")
])

for key, value in put_items.items():
for key, value in list(put_items.items()):
self.store.put(key, value)

# Sorted order is: eight five four nine one seven six three two
keys = list(self.store.items())
expected = sorted(put_items.items(), key=operator.itemgetter(0))
expected = sorted(list(put_items.items()), key=operator.itemgetter(0))
self.assertEqual(expected, keys)

# Test key_from on keys that are present and missing in the db
Expand Down Expand Up @@ -260,7 +260,7 @@ def test_context_manager(self):

class TestIbatch(unittest.TestCase):
def test_ibatch(self):
items = range(10)
items = list(range(10))

batches = park.ibatch(items, 3)

Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py26, py27
envlist = py27, py34

[testenv]
deps=
Expand Down

0 comments on commit b720de2

Please sign in to comment.