This is an automated email from the ASF dual-hosted git repository.

jgemignani pushed a commit to branch PG13
in repository https://gitbox.apache.org/repos/asf/age.git


The following commit(s) were added to refs/heads/PG13 by this push:
     new 0c9cb195 Add the `load_from_plugins` parameter in the Python driver to 
load AGE from the $libdir/plugins directory (#1935) (#1947)
0c9cb195 is described below

commit 0c9cb1951e3e963f9db3908566b199d55267d310
Author: Daan <[email protected]>
AuthorDate: Wed Jul 3 19:34:23 2024 +0200

    Add the `load_from_plugins` parameter in the Python driver to load AGE from 
the $libdir/plugins directory (#1935) (#1947)
    
    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]>
    (cherry picked from commit 7fc34483840596130f11ee0d61b7ac53862eeb10)
---
 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 3e246dda..07067c19 100644
--- a/drivers/python/README.md
+++ b/drivers/python/README.md
@@ -75,6 +75,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

Reply via email to