Skip to content

Commit

Permalink
PYCBC-103: Pure C API Rewrite
Browse files Browse the repository at this point in the history
Change-Id: Ib71a9cd7bdf28c1d29daa0188ad2d66be38bca66
Reviewed-on: http://review.couchbase.org/26234
Tested-by: Mordechai Nunberg <[email protected]>
Reviewed-by: Pavel Paulau <[email protected]>
Reviewed-by: Mordechai Nunberg <[email protected]>
  • Loading branch information
mnunberg committed May 14, 2013
1 parent 78cb992 commit 6580564
Show file tree
Hide file tree
Showing 53 changed files with 5,560 additions and 2,988 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@ couchbase/libcouchbase.c
couchbase/libcouchbase.h
couchbase/__pycache__
*.pyc
*.pdb
*.swp
*.out
*.log
*.so
*.dylib
*.pyd
*.dll
*.exe
6 changes: 4 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
include *.txt *.py *.md LICENSE
include couchbase/libcouchbase.c couchbase/libcouchbase.h
include *.txt *.md LICENSE
recursive-include couchbase *.py
recursive-include src *.c *.h
recursive-include docs *
recursive-exclude docs/build *
recursive-include tests *.py *.ini
recursive-include examples *.py
exclude MANIFEST.in
40 changes: 19 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ Install libcouchbase.
Building
--------

If you have a source checkout via Git you need to have Cython (>=0.19)
installed in order to generate the `couchbase/libcouchbase.c` file. If you've
downloaded the source package the file is already included.

As the target audience is currently developers, you probably want to install
the module locally. You can run:
In order to build this client, you need to have `libcouchbase` installed. Once
this is done, you can now build the extension.

python setup.py build_ext --inplace

If you have compile libcouchbase yourself at a custom location, you can pass
it in via the `CFLAGS` and `LDFLAGS` environment variables.

If your libcouchbase install is in an alternate location (for example,
`/opt/local/libcouchbase'), you may add extra directives, like so:

python setup.py build_ext --inplace \
--library-dir /opt/local/libcouchbase/lib \
--include-dir /opt/local/libcouchbase/include

Or you can modify the environment `CFLAGS` and `LDFLAGS` variables.


Running sample application
Expand Down Expand Up @@ -66,31 +69,27 @@ configuration file. To create them, run:

python tests/setup_tests.py

If the buckets already exist, they will be recreated.

Now you can run the test. If you have Python >=2.7 or >=3.2 you can run:

python -m unittest discover -s tests

Or if you have `nose` installed, you can also run:
To run the tests:

nosetests


Tested platforms
----------------

So far the code has been tested on the following platforms/environments.

Linux 64-bit (with GCC):

- Python 2.7.3
- Python 3.2.3
- PyPy 1.9
- Python 2.6.6

OSX (with clang):
Mac OS X 10.6.8
- Python 2.6.1
- Python 3.3.1

- Python 2.7
Microsoft Windows 2008 R2 (MSVC 2008/VC9)
- Python 2.7.3 (x86)
- Python 2.7.4 (x64)


If you ran it on a different platform and it worked, please let me know and
Expand All @@ -105,4 +104,3 @@ pylibcouchbase is licensed under the Apache License 2.0.


[1]: https://github.com/couchbase/libcouchbase
[2]: https://github.com/geggo/cwrap
63 changes: 52 additions & 11 deletions couchbase/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import couchbase

# Import a few things into the root of the module
from couchbase.libcouchbase import FMT_JSON, FMT_PICKLE, FMT_PLAIN

import couchbase.libcouchbase
from couchbase.libcouchbase import (
FMT_UTF8, FMT_BYTES, FMT_JSON, FMT_PICKLE, FMT_MASK)

class Couchbase:
"""The base class for interacting with Couchbase"""
@staticmethod
def connect(host='localhost', port=8091, username=None, password=None,
bucket=None, quiet=False, conncache=None):
def connect(bucket=None,
host='localhost',
port=8091,
username=None,
password=None,
quiet=False,
conncache=None,
unlock_gil=True,
timeout=2.5,
transcoder=None,
**kwargs):
"""Connect to a bucket.
If `username` is not given but `password` is specified,
Expand All @@ -22,25 +29,52 @@ def connect(host='localhost', port=8091, username=None, password=None,
be simple strings, or (host, port) tuples (in which case the `port`
parameter from the method arguments is ignored).
:type host: string or list
:param number port: port of the management API
:param string username: the user name to connect to the cluster.
It's the username of the management API.
The username could be skipped for
protected buckets, the bucket name will
be used instead.
:param string password: the password of the user or bucket
:param string bucket: the bucket name
:param boolean quiet: the flag controlling whether to raise an
exception when the client executes operations on non-existent
keys. If it is `False` it will raise
:exc:`couchbase.exceptions.NotFoundError` exceptions. When set
to `True` the operations will return `None` silently.
:param string conncache: If set, this will refer to a path on the
filesystem where cached "bootstrap" information may be stored. This
path may be shared among multiple instance of the Couchbase client.
Using this option may reduce overhead when using many short-lived
instances of the client.
:param boolean unlock_gil: If set (which is the default), the connection
object will release the python GIL when possible, allowing other
(Python) threads to function in the background. This should be set to
true if you are using threads in your application (and is the default),
as otherwise all threads will be blocked while couchbase functions
execute.
You may turn this off for some performance boost and you are certain
your application is not using threads
:param float timeout:
Set the timeout in seconds. If an operation takes longer than this
many seconds, the method will return with an error. You may set this
higher if you have slow network conditions.
:param transcoder:
(*EXPERIMENTAL*)
Set the transcoder object to use. This should conform to the interface
in the documentation (it need not actually be a subclass)
:type transcoder: :class:`couchbase.transcoder.Transcoder`
:raise: :exc:`couchbase.exceptions.BucketNotFoundError` if there
is no such bucket to connect to
Expand All @@ -65,10 +99,17 @@ def connect(host='localhost', port=8091, username=None, password=None,
Connect to a different server on the default port 8091::
cb = Couchbase.connect('example.com', username='admin',
cb = Couchbase.connect(host='example.com', username='admin',
password='secret', bucket='mybucket')
"""
return couchbase.libcouchbase.Connection(host, port, username,
password, bucket,
conncache=conncache)
return couchbase.libcouchbase.Connection(host=host,
port=port,
username=username,
password=password,
bucket=bucket,
conncache=conncache,
unlock_gil=unlock_gil,
timeout=timeout,
transcoder=transcoder,
**kwargs)
51 changes: 51 additions & 0 deletions couchbase/_bootstrap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
This module contains the core functionality of '_libcouchbase'. In short,
this contains the convergence between the C module and code written in Python.
While the _libcouchbase module should never be used directly, in the off chance
that this does happen, ensure this module is loaded as well before anything is
done, otherwise Bad Things May Happen.
Additionally, this
module contains python functions used exclusively from C. They are here
because it was quicker to write them in Python than it was in C. Do not touch
this file at all. You have been warned
"""
import json
import pickle

import couchbase.exceptions as E
import couchbase._libcouchbase as C

def _result__repr__(self):
"""
This is used as the `__repr__` function for the :class:`Result`
"""
errdesc = ""

if self.rc != 0:
errdesc = "[{0}]".format(self.errstr)

return ("{cls}<"
"RC=0x{rc:x}{errdesc}, "
"Value={val}, "
"Flags=0x{flags:x}, "
"CAS=0x{cas:x}"
">").format(rc = self.rc,
val = self.value,
flags = self.flags,
cas = self.cas,
errdesc = errdesc,
cls=self.__class__.__name__)

C._init_helpers(
result_reprfunc = _result__repr__,
fmt_utf8_flags = C.FMT_UTF8,
fmt_bytes_flags = C.FMT_BYTES,
pickle_encode = pickle.dumps,
pickle_decode = pickle.loads,
json_encode = json.dumps,
json_decode = json.loads,
lcb_errno_map = E._LCB_ERRNO_MAP,
misc_errno_map = E._EXCTYPE_MAP,
default_exception = E.CouchbaseError)
Loading

0 comments on commit 6580564

Please sign in to comment.