This is an automated email from the ASF dual-hosted git repository.
rafsun42 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/master by this push:
new 7fc34483 Add the `load_from_plugins` parameter in the Python driver to
load AGE from the $libdir/plugins directory (#1935)
7fc34483 is described below
commit 7fc34483840596130f11ee0d61b7ac53862eeb10
Author: Daan <[email protected]>
AuthorDate: Thu Jun 27 21:07:28 2024 +0200
Add the `load_from_plugins` parameter in the Python driver to load AGE from
the $libdir/plugins directory (#1935)
This is useful when a non-superuser login is used for the connection.
Additionally, fixed a small bug where a memoryview was not transformed to
bytes before decoding into a UTF-8 string.
Co-authored-by: Daan Wagenaar <[email protected]>
---
drivers/python/README.md | 10 ++++++++++
drivers/python/age/__init__.py | 8 +++++---
drivers/python/age/age.py | 24 +++++++++++++++++-------
3 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/drivers/python/README.md b/drivers/python/README.md
index c729315d..18465227 100644
--- a/drivers/python/README.md
+++ b/drivers/python/README.md
@@ -84,6 +84,16 @@ SET search_path = ag_catalog, "$user", public;
* Simpler way to access Apache AGE [AGE Sample](samples/apache-age-note.ipynb)
in Samples.
* Agtype converting samples: [Agtype Sample](samples/apache-age-agtypes.ipynb)
in Samples.
+### Non-Superuser Usage
+* For non-superuser usage see: [Allow Non-Superusers to Use Apache
Age](https://age.apache.org/age-manual/master/intro/setup.html).
+* Make sure to give your non-superuser db account proper permissions to the
graph schemas and corresponding objects
+* Make sure to initiate the Apache Age python driver with the
```load_from_plugins``` parameter. This parameter tries to
+ load the Apache Age extension from the PostgreSQL plugins directory located
at ```$libdir/plugins/age```. Example:
+ ```python.
+ ag = age.connect(host='localhost', port=5432, user='dbuser',
password='strong_password',
+ dbname=postgres, load_from_plugins=True, graph='graph_name)
+ ```
+
### License
Apache-2.0 License
diff --git a/drivers/python/age/__init__.py b/drivers/python/age/__init__.py
index 63826909..fd50135a 100644
--- a/drivers/python/age/__init__.py
+++ b/drivers/python/age/__init__.py
@@ -24,15 +24,17 @@ def version():
return VERSION.VERSION
-def connect(dsn=None, graph=None, connection_factory=None,
cursor_factory=ClientCursor, **kwargs):
+def connect(dsn=None, graph=None, connection_factory=None,
cursor_factory=ClientCursor, load_from_plugins=False,
+ **kwargs):
dsn = conninfo.make_conninfo('' if dsn is None else dsn, **kwargs)
ag = Age()
- ag.connect(dsn=dsn, graph=graph, connection_factory=connection_factory,
cursor_factory=cursor_factory, **kwargs)
+ ag.connect(dsn=dsn, graph=graph, connection_factory=connection_factory,
cursor_factory=cursor_factory,
+ load_from_plugins=load_from_plugins, **kwargs)
return ag
# Dummy ResultHandler
rawPrinter = DummyResultHandler()
-__name__="age"
\ No newline at end of file
+__name__="age"
diff --git a/drivers/python/age/age.py b/drivers/python/age/age.py
index 2d98e3ff..817cc6e5 100644
--- a/drivers/python/age/age.py
+++ b/drivers/python/age/age.py
@@ -35,20 +35,29 @@ class AgeDumper(psycopg.adapt.Dumper):
class AgeLoader(psycopg.adapt.Loader):
- def load(self, data: bytes | bytearray | memoryview) -> Any | None:
- return parseAgeValue(data.decode('utf-8'))
+ def load(self, data: bytes | bytearray | memoryview) -> Any | None:
+ if isinstance(data, memoryview):
+ data_bytes = data.tobytes()
+ else:
+ data_bytes = data
+ return parseAgeValue(data_bytes.decode('utf-8'))
-def setUpAge(conn:psycopg.connection, graphName:str):
+
+def setUpAge(conn:psycopg.connection, graphName:str,
load_from_plugins:bool=False):
with conn.cursor() as cursor:
- cursor.execute("LOAD 'age';")
+ if load_from_plugins:
+ cursor.execute("LOAD '$libdir/plugins/age';")
+ else:
+ cursor.execute("LOAD 'age';")
+
cursor.execute("SET search_path = ag_catalog, '$user', public;")
ag_info = TypeInfo.fetch(conn, 'agtype')
if not ag_info:
raise AgeNotSet()
-
+
conn.adapters.register_loader(ag_info.oid, AgeLoader)
conn.adapters.register_loader(ag_info.array_oid, AgeLoader)
@@ -184,9 +193,10 @@ class Age:
self.graphName = None
# Connect to PostgreSQL Server and establish session and type extension
environment.
- def connect(self, graph:str=None, dsn:str=None, connection_factory=None,
cursor_factory=ClientCursor, **kwargs):
+ def connect(self, graph:str=None, dsn:str=None, connection_factory=None,
cursor_factory=ClientCursor,
+ load_from_plugins:bool=False, **kwargs):
conn = psycopg.connect(dsn, cursor_factory=cursor_factory, **kwargs)
- setUpAge(conn, graph)
+ setUpAge(conn, graph, load_from_plugins)
self.connection = conn
self.graphName = graph
return self