bendudson/py4cl

Doing "from _ import _" in py4cl

brandflake11 opened this issue · 11 comments

Hello,
I am not a python expert at all, but I was using this lisp package to convert some python code into a lisp project I am working on. How would one go about using py4cl to do this kind of python code:

from SigMFUtils import SigMFUtil

I have attempted to do this with PYTHON-EVAL like this:
(py4cl:python-eval "from SigMFUtils import SigMFUtil")

but this doesn't work and results in a python syntax error. Is there a way to from _ import _ with IMPORT-MODULE?

Thank you very much for your time and any help you can offer.

Python like most non-lisp languages makes a distinction between expressions and non-expression-statements; so you'd rather need to use (py4cl:python-exec "from SigMFUtils import SigMFUtil") instead of python-eval.

Thank you very much for your help @digikar99. I wanted to also ask you, which is related to this: How do I also change the directory where the python process for py4cl loads? The SigMFUtils I'm trying to load is in a specific folder, and I need to be in that directory in order for the python process to find SigMFUtils.

I know how to do this if I am just using python in a shell (cd directory && python .), but when it comes to py4cl, I'm not quite sure how that works.

There's also another way to change the process directory once the process has started: in the case of python, it is import os; os.chdir("directory/you/want"); so you could just call (python-exec "import os; os.chdir('directory/you/want')")

@digikar99 Thanks so much for your help. As you can tell, I am not very good with python. :D I'll go ahead and close this.

I apologize for reopening this issue. I'm actually having trouble with reading the .py file using the above code we talked about. Here is an example I'm having trouble with:

(ql:quickload :py4cl)

(py4cl:import-module "sigmf")
(py4cl:import-module "types")
(py4cl:import-module "json")
(py4cl:import-module "matplotlib.pyplot" :as "plt")
(py4cl:import-module "os")

(os:chdir "/home/brandon/my-dir/")
(os:getcwd)

(py4cl:python-exec "from SigMFUtils import SigMFUtil")

The above gives an error, even though the output of OS:GETCWD is the correct directory:


Python error: "No module named 'SigMFUtils'"
   [Condition of type py4cl:python-error]

Restarts:
 0: [retry] Retry SLIME interactive evaluation request.
 1: [*abort] Return to SLIME's top level.
 2: [abort] abort thread (#<thread "worker" running {10169097D3}>)

Backtrace:
  0: (py4cl::dispatch-messages #<uiop/launch-program::process-info {1009DEE2D3}>)
  1: (sb-int:simple-eval-in-lexenv (py4cl:python-exec "from SigMFUtils import SigMFUtil") #<NULL-LEXENV>)
  2: (eval (py4cl:python-exec "from SigMFUtils import SigMFUtil"))
  3: ((lambda nil :in swank:interactive-eval))
 --more--

However, if I run the same code using python 3.9.6 in my shell:

import sigmf
import types
import json
import matplotlib.pyplot as plt
import os

os.chdir("/home/brandon/my-dir")
from SigMFUtils import SigMFUtil

I don't get any error and SigMFUtil gets imported correctly. SigMFUtils is a .py file (named SigMFUtils.py) in the directory that I chdir to. Is this a bug, or am I missing something?

Thank you very much for your time!

Erm... Check for:

(python-exec "import sys")
(python-eval "sys.path") ; EDIT: corrected, thanks brandflake11!

Okay, I wasn't exactly clear about this, but the first item of this list, sys.path[0], is the directory containing the script that was used to invoke the Python interpreter; I had assumed it already contains the current-directory of the program, but turns out that isn't exactly the case. So, the current working directory would need to be added manually; hopefully that does it for you:

(python-exec "sys.path.append('./')") ; EDIT: corrected

Okay, I looked at this and tried some of it. A couple of things:

  1. I was able to import sys. However, in order to see the sys.path I had to change your code to this:
    (python-eval "sys.path")

This needed to be a string in order for lisp to print out the paths from python. It just returned a symbol :sys.path otherwise.

  1. Then, to run the sys.append, I looked it up and the command should actually be:
    (python-exec "sys.path.append('./')")

It seems that sys.append is not a command you can run, but after a quick search sys.path.append was the right answer.

I sys.path.appended the directory that contains the SigMFUtils.py file I'm trying to import.

After appending the path to the directory I am working in, I am getting this error now:

Python error: "cannot import name 'SigMFFile' from 'sigmf' (/home/brandon/.local/lib/python3.9/site-packages/sigmf/__init__.py)"
   [Condition of type py4cl:python-error]

Restarts:
 0: [retry] Retry SLIME interactive evaluation request.
 1: [*abort] Return to SLIME's top level.
 2: [abort] abort thread (#<thread "worker" running {101A739C33}>)

Backtrace:
  0: (py4cl::dispatch-messages #<uiop/launch-program::process-info {101447E383}>)
  1: (sb-int:simple-eval-in-lexenv (py4cl:python-exec "from SigMFUtils import SigMFUtil") #<NULL-LEXENV>)
  2: (eval (py4cl:python-exec "from SigMFUtils import SigMFUtil"))
  3: ((lambda nil :in swank:interactive-eval))
 --more--

Everything looks normal as if I was running python from the shell. I just can't seem to import this. Let me know if you have any more ideas, and if not, that's fine too! Thanks again for your help!

My bad at several places! Apologies, and corrected.

cannot import name 'SigMFFile' from 'sigmf'

Okay... the value in sys.path while running as a script includes the absolute path to the directory-containing-script instead of the relative; does appending the absolute path instead of the relative path './' work?

May be the value of sys.path could be set from the py4cl/2 end in the future.

No problem @digikar99! I actually have tried to add the ./ and absolute path to the sys.path. Does the order of sys.path matter? Do I need to start sbcl in the same directory as the .py file I'm trying to load? I run sbcl from slime if that matters.

I don't think I know if the order matters; so your best bet (as usual in programming) would be to try and see, and/or consult stackoverflow. For a simple sample file I created on my system to test this, it worked as expected; but for anything more complex, I don't know python enough or have a module to test this with.

You could also try changing the path of the lisp program to the relevant directory using uiop:chdir (or starting sbcl in the relevant directory itself) before starting the python process; but I'm unsure if that'd work.

Thanks so much @digikar99 for all of your help. I'll keep experimenting and see if I can find a solution. I appreciate your help.