Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
zodburi
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
zodburi
Commits
28ae352e
Commit
28ae352e
authored
May 27, 2012
by
Georges Dubus
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added support for postgres:// uri.
Support for mysql and oracle should be easy to add from here.
parent
87be3603
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
289 additions
and
5 deletions
+289
-5
CONTRIBUTORS.txt
CONTRIBUTORS.txt
+1
-0
docs/index.rst
docs/index.rst
+108
-3
setup.py
setup.py
+2
-1
zodburi/resolvers.py
zodburi/resolvers.py
+69
-1
zodburi/tests/test_resolvers.py
zodburi/tests/test_resolvers.py
+109
-0
No files found.
CONTRIBUTORS.txt
View file @
28ae352e
...
...
@@ -97,3 +97,4 @@ Contributors
------------
- Chris McDonough, 2011/08/18
- Georges Dubus 2012/05/27
docs/index.rst
View file @
28ae352e
...
...
@@ -43,9 +43,10 @@ passing to the ``ZODB.DB.DB`` constructor. For example:
URI Schemes
-----------
The URI schemes currently recognized in the ``zodbconn.uri`` setting are
``file://``, ``zeo://``, ``zconfig://`` and ``memory://``. Documentation for
these URI scheme syntaxes are below.
The URI schemes currently recognized in the ``zodbconn.uri`` setting
are ``file://``, ``zeo://``, ``zconfig://``, ``memory://``
``postgres://``. Documentation for these URI scheme syntaxes are
below.
``file://`` URI scheme
~~~~~~~~~~~~~~~~~~~~~~
...
...
@@ -286,6 +287,110 @@ An example that combines a dbname with a query string::
memory://storagename?connection_cache_size=100&database_name=fleeb
``postgres://`` URI scheme
~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``postgres://`` URI scheme can be passed as ``zodbconn.uri`` to
create a RelStorage PostgresSQL database factory. The uri should
contain the user, the password, the host, the port and the db name
e.g.::
postgres://someuser:somepass@somehost:5432/somedb?connection_cache_size=20000
The URI scheme also accepts query string arguments. The query string
arguments honored by this scheme are as follows.
RelStorage-constructor related
++++++++++++++++++++++++++++++
These arguments generally inform the RelStorage constructor about
values of the same names.
poll_interval
int
cache_local_mb
int
commit_lock_timeout
int
commit_lock_id
int
read_only
boolean
shared_blob_dir
boolean
keep_history
boolean
pack_gc
boolean
pack_dry_run
boolean
strict_tpc
boolean
create
boolean
blob_cache_size
bytesize
blob_cache_size_check
bytesize
blob_cache_chunk_size
bytesize
replica_timeout
float
pack_batch_timeout
float
pack_duty_cycle
float
pack_max_delay
float
name
string
blob_dir
string
replica_conf
string
cache_module_name
string
cache_prefix
string
cache_delta_size_limit
string
cache_servers
string of the for "first,second,third"
Misc
++++
demostorage
boolean (if true, wrap RelStorage in a DemoStorage)
Connection-related
++++++++++++++++++
These arguments relate to connections created from the database.
connection_cache_size
integer (default 10000)
connection_pool_size
integer (default 7)
Database-related
++++++++++++++++
These arguments relate to the database (as opposed to storage)
settings.
database_name
string
Example
+++++++
An example that combines a path with a query string::
postgres://someuser:somepass@somehost:5432/somedb?connection_cache_size=20000
More Information
----------------
...
...
setup.py
View file @
28ae352e
...
...
@@ -12,7 +12,7 @@ except:
README
=
''
CHANGES
=
''
requires
=
[
'ZODB3'
]
requires
=
[
'ZODB3'
,
'RelStorage'
,
]
tests_require
=
requires
+
[
'mock'
]
setup
(
name
=
'zodburi'
,
...
...
@@ -40,5 +40,6 @@ setup(name='zodburi',
file = zodburi.resolvers:file_storage_resolver
zconfig = zodburi.resolvers:zconfig_resolver
memory = zodburi.resolvers:mapping_storage_resolver
postgres = zodburi.resolvers:postgresql_resolver
"""
)
zodburi/resolvers.py
View file @
28ae352e
...
...
@@ -10,6 +10,9 @@ from ZODB.DemoStorage import DemoStorage
from
ZODB.MappingStorage
import
MappingStorage
from
ZODB.blob
import
BlobStorage
import
ZConfig
from
relstorage.adapters.postgresql
import
PostgreSQLAdapter
from
relstorage.options
import
Options
from
relstorage.storage
import
RelStorage
from
zodburi.datatypes
import
convert_bytesize
from
zodburi.datatypes
import
convert_int
...
...
@@ -19,6 +22,8 @@ class Resolver(object):
_int_args
=
()
_string_args
=
()
_bytesize_args
=
()
_float_args
=
()
_tuple_args
=
()
def
interpret_kwargs
(
self
,
kw
):
unused
=
kw
.
copy
()
...
...
@@ -197,7 +202,70 @@ class ZConfigURIResolver(object):
return
factory
.
open
,
dbkw
# Not a real resolver, but we use interpret_kwargs
class
PostgreSQLAdapterHelper
(
Resolver
):
_int_args
=
(
'connect_timeout'
,
)
_string_args
=
(
'ssl_mode'
,
)
def
__call__
(
self
,
parsed_uri
,
kw
):
dsn_args
=
[
(
'dbname'
,
parsed_uri
.
path
[
1
:]),
(
'user'
,
parsed_uri
.
username
),
(
'password'
,
parsed_uri
.
password
),
(
'host'
,
parsed_uri
.
hostname
),
(
'port'
,
parsed_uri
.
port
)
]
kw
,
unused
=
self
.
interpret_kwargs
(
kw
)
dsn_args
.
extend
(
kw
.
items
())
dsn
=
' '
.
join
(
"%s='%s'"
%
arg
for
arg
in
dsn_args
)
def
factory
(
options
):
return
PostgreSQLAdapter
(
dsn
=
dsn
,
options
=
options
)
return
factory
,
unused
# The relstorage support is inspired by django-zodb.
# Oracle and mysql should be easily implementable from here
class
RelStorageURIResolver
(
Resolver
):
_int_args
=
(
'poll_interval'
,
'cache_local_mb'
,
'commit_lock_timeout'
,
'commit_lock_id'
,
'read_only'
,
'shared_blob_dir'
,
'keep_history'
,
'pack_gc'
,
'pack_dry_run'
,
'strict_tpc'
,
'create'
,
'demostorage'
,)
_string_args
=
(
'name'
,
'blob_dir'
,
'replica_conf'
,
'cache_module_name'
,
'cache_prefix'
,
'cache_delta_size_limit'
)
_bytesize_args
=
(
'blob_cache_size'
,
'blob_cache_size_check'
,
'blob_cache_chunk_size'
)
_float_args
=
(
'replica_timeout'
,
'pack_batch_timeout'
,
'pack_duty_cycle'
,
'pack_max_delay'
)
_tuple_args
=
(
'cache_servers'
,)
def
__init__
(
self
,
adapter_helper
):
self
.
adapter_helper
=
adapter_helper
def
__call__
(
self
,
uri
):
uri
=
uri
.
replace
(
'postgres://'
,
'http://'
,
1
)
parsed_uri
=
urlparse
.
urlsplit
(
uri
)
kw
=
dict
(
cgi
.
parse_qsl
(
parsed_uri
.
query
))
adapter_factory
,
kw
=
self
.
adapter_helper
(
parsed_uri
,
kw
)
kw
,
unused
=
self
.
interpret_kwargs
(
kw
)
demostorage
=
kw
.
pop
(
'demostorage'
,
False
)
options
=
Options
(
**
kw
)
def
factory
():
adapter
=
adapter_factory
(
options
)
storage
=
RelStorage
(
adapter
=
adapter
,
options
=
options
)
if
demostorage
:
storage
=
DemoStorage
(
base
=
storage
)
return
storage
return
factory
,
unused
client_storage_resolver
=
ClientStorageURIResolver
()
file_storage_resolver
=
FileStorageURIResolver
()
zconfig_resolver
=
ZConfigURIResolver
()
mapping_storage_resolver
=
MappingStorageURIResolver
()
\ No newline at end of file
mapping_storage_resolver
=
MappingStorageURIResolver
()
postgresql_resolver
=
RelStorageURIResolver
(
PostgreSQLAdapterHelper
())
\ No newline at end of file
zodburi/tests/test_resolvers.py
View file @
28ae352e
...
...
@@ -47,6 +47,32 @@ class Base:
for
name
,
value
in
args
.
items
():
self
.
assertEqual
(
value
,
'string'
)
def
test_float_args
(
self
):
resolver
=
self
.
_makeOne
()
names
=
list
(
resolver
.
_float_args
)
kwargs
=
{}
for
name
in
names
:
kwargs
[
name
]
=
'3.14'
args
=
resolver
.
interpret_kwargs
(
kwargs
)[
0
]
keys
=
args
.
keys
()
keys
.
sort
()
self
.
assertEqual
(
keys
,
names
)
for
name
,
value
in
args
.
items
():
self
.
assertEqual
(
value
,
3.14
)
def
test_tuple_args
(
self
):
resolver
=
self
.
_makeOne
()
names
=
list
(
resolver
.
_tuple_args
)
kwargs
=
{}
for
name
in
names
:
kwargs
[
name
]
=
'first,second,third'
args
=
resolver
.
interpret_kwargs
(
kwargs
)[
0
]
keys
=
args
.
keys
()
keys
.
sort
()
self
.
assertEqual
(
keys
,
names
)
for
name
,
value
in
args
.
items
():
self
.
assertEqual
(
value
,
(
'first'
,
'second'
,
'third'
))
class
TestFileStorageURIResolver
(
Base
,
unittest
.
TestCase
):
def
_getTargetClass
(
self
):
...
...
@@ -387,6 +413,88 @@ class TestMappingStorageURIResolver(Base, unittest.TestCase):
self
.
assertEqual
(
storage
.
__name__
,
'storagename'
)
class
TestPostgreSQLURIResolver
(
unittest
.
TestCase
):
def
_getTargetClass
(
self
):
from
zodburi.resolvers
import
RelStorageURIResolver
return
RelStorageURIResolver
def
_makeOne
(
self
):
from
zodburi.resolvers
import
PostgreSQLAdapterHelper
klass
=
self
.
_getTargetClass
()
return
klass
(
PostgreSQLAdapterHelper
())
def
setUp
(
self
):
# relstorage.options.Options is little more than a dict.
# We make it comparable to simplify the tests.
from
relstorage.options
import
Options
Options
.
__eq__
=
lambda
s
,
o
:
vars
(
s
)
==
vars
(
o
)
def
test_bool_args
(
self
):
resolver
=
self
.
_makeOne
()
f
=
resolver
.
interpret_kwargs
kwargs
=
f
({
'read_only'
:
'1'
})
self
.
assertEqual
(
kwargs
[
0
],
{
'read_only'
:
1
})
kwargs
=
f
({
'read_only'
:
'true'
})
self
.
assertEqual
(
kwargs
[
0
],
{
'read_only'
:
1
})
kwargs
=
f
({
'read_only'
:
'on'
})
self
.
assertEqual
(
kwargs
[
0
],
{
'read_only'
:
1
})
kwargs
=
f
({
'read_only'
:
'off'
})
self
.
assertEqual
(
kwargs
[
0
],
{
'read_only'
:
0
})
kwargs
=
f
({
'read_only'
:
'no'
})
self
.
assertEqual
(
kwargs
[
0
],
{
'read_only'
:
0
})
kwargs
=
f
({
'read_only'
:
'false'
})
self
.
assertEqual
(
kwargs
[
0
],
{
'read_only'
:
0
})
@
mock
.
patch
(
'zodburi.resolvers.PostgreSQLAdapter'
)
@
mock
.
patch
(
'zodburi.resolvers.RelStorage'
)
def
test_call
(
self
,
RelStorage
,
PostgreSQLAdapter
):
from
relstorage.options
import
Options
resolver
=
self
.
_makeOne
()
factory
,
dbkw
=
resolver
(
'postgres://someuser:somepass@somehost:5432/somedb?read_only=1'
)
factory
()
expected_options
=
Options
(
read_only
=
1
)
PostgreSQLAdapter
.
assert_called_once_with
(
dsn
=
"dbname='somedb' user='someuser' password='somepass' "
"host='somehost' port='5432'"
,
options
=
expected_options
)
RelStorage
.
assert_called_once_with
(
adapter
=
PostgreSQLAdapter
(),
options
=
expected_options
)
@
mock
.
patch
(
'zodburi.resolvers.PostgreSQLAdapter'
)
@
mock
.
patch
(
'zodburi.resolvers.RelStorage'
)
def
test_call_adapter_options
(
self
,
RelStorage
,
PostgreSQLAdapter
):
from
relstorage.options
import
Options
resolver
=
self
.
_makeOne
()
factory
,
dbkw
=
resolver
(
'postgres://someuser:somepass@somehost:5432/somedb?read_only=1'
'&connect_timeout=10'
)
factory
()
expected_options
=
Options
(
read_only
=
1
)
PostgreSQLAdapter
.
assert_called_once_with
(
dsn
=
"dbname='somedb' user='someuser' password='somepass' "
"host='somehost' port='5432' connect_timeout='10'"
,
options
=
expected_options
)
RelStorage
.
assert_called_once_with
(
adapter
=
PostgreSQLAdapter
(),
options
=
expected_options
)
@
mock
.
patch
(
'zodburi.resolvers.PostgreSQLAdapter'
)
@
mock
.
patch
(
'zodburi.resolvers.RelStorage'
)
def
test_invoke_factory_demostorage
(
self
,
RelStorage
,
PostgreSQLAdapter
):
from
ZODB.DemoStorage
import
DemoStorage
resolver
=
self
.
_makeOne
()
factory
,
dbkw
=
resolver
(
'postgres://someuser:somepass@somehost:5432/somedb?read_only=1'
'&demostorage=true'
)
self
.
assertTrue
(
isinstance
(
factory
(),
DemoStorage
))
def
test_dbargs
(
self
):
resolver
=
self
.
_makeOne
()
factory
,
dbkw
=
resolver
(
'postgres://someuser:somepass@somehost:5432/somedb?read_only=1&'
'connection_pool_size=1&'
'connection_cache_size=1&'
'database_name=dbname'
)
self
.
assertEqual
(
dbkw
,
{
'connection_pool_size'
:
'1'
,
'connection_cache_size'
:
'1'
,
'database_name'
:
'dbname'
})
class
TestEntryPoints
(
unittest
.
TestCase
):
def
test_it
(
self
):
...
...
@@ -397,6 +505,7 @@ class TestEntryPoints(unittest.TestCase):
(
'zeo'
,
resolvers
.
ClientStorageURIResolver
),
(
'file'
,
resolvers
.
FileStorageURIResolver
),
(
'zconfig'
,
resolvers
.
ZConfigURIResolver
),
(
'postgres'
,
resolvers
.
RelStorageURIResolver
),
]
for
name
,
cls
in
expected
:
target
=
load_entry_point
(
'zodburi'
,
'zodburi.resolvers'
,
name
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment