SPARQL-Anything / PySPARQL-Anything

The SPARQL Anything Python library
Apache License 2.0
11 stars 1 forks source link

should `sa.SparqlAnything()` be idempotent? #22

Open justin2004 opened 3 months ago

justin2004 commented 3 months ago

say you are at the REPL and you instantiate the sa engine but you forgot to assign it to a variable....

maybe subsequent invocations should return the same reference?

Python 3.12.4 (main, Jun  7 2024, 19:06:40) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pysparql_anything as sa
sa>>> sa.SparqlAnything()
<pysparql_anything.sparql_anything.SparqlAnything object at 0x77d81fc9bb90>
>>> engine=sa.SparqlAnything()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.12/site-packages/pysparql_anything/sparql_anything.py", line 25, in __init__
    self.receiver = SPARQLAnythingReflection(jvm_options)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/pysparql_anything/sparql_anything_reflection.py", line 43, in __init__
    jnius_config.set_classpath(get_path2jar())
  File "/usr/local/lib/python3.12/site-packages/jnius_config.py", line 47, in set_classpath
    check_vm_running()
  File "/usr/local/lib/python3.12/site-packages/jnius_config.py", line 20, in check_vm_running
    raise ValueError("VM is already running, can't set classpath/options; VM started at" + vm_started_at)
ValueError: VM is already running, can't set classpath/options; VM started at  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.12/site-packages/pysparql_anything/sparql_anything.py", line 25, in __init__
    self.receiver = SPARQLAnythingReflection(jvm_options)
  File "/usr/local/lib/python3.12/site-packages/pysparql_anything/sparql_anything_reflection.py", line 45, in __init__
    from jnius import autoclass
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 995, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/usr/local/lib/python3.12/site-packages/jnius/__init__.py", line 45, in <module>
    from .reflect import *  # noqa
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 995, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/usr/local/lib/python3.12/site-packages/jnius/reflect.py", line 19, in <module>
    class Class(JavaClass, metaclass=MetaJavaClass):
MarcoR1791 commented 3 weeks ago

Hi Justin,

I've been looking into this. The closest thing that I can implement (and I've tested it) is a singleton construction that returns the same reference whenever the constructor is called again. To use your same example, we now have this:

Python 3.11.9 (tags/v3.11.9:de54cf5, Apr  2 2024, 10:12:12) [MSC v.1938 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pysparql_anything as sa
>>> sa.SparqlAnything()
<pysparql_anything.sparql_anything.SparqlAnything object at 0x00000192AE485010>
>>> e = sa.SparqlAnything()
>>> e
<pysparql_anything.sparql_anything.SparqlAnything object at 0x00000192AE485010>
>>> e2 = sa.SparqlAnything("-Xrs", "-Xmx6g")
>>> e2
<pysparql_anything.sparql_anything.SparqlAnything object at 0x00000192AE485010>
>>>

The last example has been added to show that due to limitations with the JNI that first call to the SparqlAnything constructor is final, as the JVM cannot be shutdown and restarted with new options unless the underlying process is shut down and restarted.

@enridaga, as you gave this a thumbs up wdyt?

justin2004 commented 3 weeks ago

thanks @MarcoR1791 , looks good to me. i think as long as there is something like an sa.shutdown() that last example doesn't bother me since one could shutdown and invoke again with different args.

MarcoR1791 commented 3 weeks ago

No probs! Actually finally learnt how Python really creates classes and their instances.

As for the the sa.shutdown() method, I'm not sure if it can even be done at the moment. See the last comment in issue #6 with links to further related discussions about the JVM and JNI. Obviously if anyone has an idea on the matter I'm very open to hearing about it.

I'm also curious whether there is a specific use case that you have for running PySPARQL in the Python shell rather than using the provided CLI?

justin2004 commented 3 weeks ago

As for the the sa.shutdown() method, I'm not sure if it can even be done at the moment.

ah, no worries.

i mostly use the shell to invoke sparql anything. once i did do a deployment using python to invoke sparql anything but i used subprocess.run(). i was trying out this project a few weeks ago using python and it was more convenient than subprocess.run().