Python module for custom MakeHuman plugin not found - python

I installed a plugin for MakeHuman in it's Plugin folder (in usr/share/makehuman-community).
However, the plugin cannot load, since it doesn't find it's own, custom module. I tried out a few different things to fix it:
The original line in the __init__.py was:
from standardize import *
and the folder structure was like this:
└── plugin-folder
├── __init__.py
└── standardize.py
So, since it was in the same folder, I tried just replacing the line with:
import standardize
But that didn't work. So I moved back to the first line and changed the folderstructure to the following:
└── plugin-folder
├── __init__.py
└── standardize
├── __init__.py
└── standardize.py
But still, not working. I have absolutely no experience with python, so I am pretty lost on this one. Any ideas, what's wrong? I think the plugin was written with a relatively old python version originally. Also had to upgrade it from PyQt4 to PyQt5 (in another plugin, but this works just fine. This one here isn't even using PyQt).

Related

Python packages/modules in different subdirs

I'm relatively new to Python, and I'm struggling to understand if what I'm trying to do is just not possible, or if I am just doing it wrong. I admit that I come from Perl - where the rules for where you put your packages, and how the directories should look like is a bit looser, so my point of view my be not so pythonic.
Also, this is a different version of a question I've asked a couple of times here and here and I keep getting answers (that I am grateful for) that say I should not, but never "it's impossible" or "here's how you do it, though you should not". If something is possible, but not advisable, I would rather be able to find out why by trying and seeing and if it is impossible by design, I'd like to know (and stop banging my head against a wall).
Apologies in advance for the long intro - here's the question, finally.
I have this nice module - svgpathtools - that contains methods, classes and sits in an install-specific directory (inside the Python install that comes with Blender), directory that looks like this:
/home/simone/blender/blender-2.92.0-linux64/2.92/python/lib/python3.7/site-packages/svgpathtools
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-37.pyc
│   ├── bezier.cpython-37.pyc
│   ├── document.cpython-37.pyc
│   ├── misctools.cpython-37.pyc
│   ├── parser.cpython-37.pyc
│   ├── path.cpython-37.pyc
│   ├── paths2svg.cpython-37.pyc
│   ├── polytools.cpython-37.pyc
│   ├── smoothing.cpython-37.pyc
│   ├── svg_io_sax.cpython-37.pyc
│   └── svg_to_paths.cpython-37.pyc
├── bezier.py
├── document.py
├── misctools.py
├── parser.py
├── path.py
├── paths2svg.py
├── polytools.py
├── smoothing.py
├── svg_io_sax.py
└── svg_to_paths.py
1 directory, 22 files
I want to add functionality to it without messing with that directory and without subclassing. The first for obvious reasons, the second because for now I am only adding a couple of methods max, so it's not worth maintaining a whole subclass (for now at least). So my idea is to have a directory that looks like this:
/home/simone/blender_learning/mesh-20210920
└── svgpathtools
├── __init__.py
└── distance.py
Now: if I keep svgpathtools/__init__.py, python (3.8.10) won't find the original svgpathtools in the Blender install subdirectory, so all its functionality is gone
and if I remove svgpathtools/__init__.py, python won't find svgpathtools/distance.py so import svgpathtools.distance throws an error.
Which one is it then:
it's impossible: because of the way python looks for packages, you can't have sub-packages in a different place than the main package
I am doing it wrong in some way (please tell me why)
Pretty please: don't just tell me I should not do it without having told me which one it is. I know that doable <> advisable (playing with explosives? petting hungry leopards? eating fugu?)
When you import a module import <module> python looks through the paths for the first match
import sys
print(sys.path)
So having a module with the same name ends up shadowing it, rather than what you want which is keep looking and merge them. So you'll have to name your extensions package something else to not conflict with it.
You can probably get the behaviour you want by rolling your own import method with importlib and a wrapper around the module to fallback to the other but it seems hardly worth it.
Use e.g. sys.path.append("..") to add the directory above the script to the python modules path.
It's not impossible but yes: it's explosive. And that's because of the way python stores its references to the imported modules. If you do:
import sys
print(sys.modules)
you'll see that those references are stored in a dictionnary, and that the keys are the modules names.
Although you could find a messy way to overthrow it, the simplest way would probably using a new name for your own lib, something like svgpathtools_ or svgpathtools_extended for example.

Trying to run python code from repo without instructions

I am trying to run a code from this repo without success. There are no instructions on how to run it. I suspect I should run FactcheckingRANLP/Factchecking_clean/classification/lstm_train.py and then run .../lstm_test.py.
The problem is that this code uses import statements as a module, referencing to folders and files that are in different directories, for example, in lstm_train.py:
File "lstm_train.py", line 3, in <module>
from classification.lstm_utils import *
ModuleNotFoundError: No module named 'classification'
This is the tree structure of the classification folder:
.
├── classification
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── lstm_repres.py
│   ├── lstm_test.py
│   ├── lstm_train.py
│   ├── lstm_train.pyc
│   ├── lstm_utils.py
│   ├── lstm_utils.pyc
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   ├── lstm_train.cpython-36.pyc
│   │   └── lstm_utils.cpython-36.pyc
│   └── svm_run.py
I would like to know how can I make python run lsmt_train/test.py files in such a manner that the import statements contained within them are compiled correctly. I prefer not to modify the code as this could possibly generate a lot of errors..
You could add the path pointing to the classification folder to your python path variable.
I suggest using the sys package:
import sys
sys.path.append('<<<PathToRepo>>>/FactcheckingRANLP/Factchecking_clean')
With the repo classification directory added to your python path, the import statements should work.
EDIT:
Correction; in the initial post I suggested adding the path to .../classification to your path variable, instead the parent folder .../Factchecking_clean is required as the file imports the module 'classification'.
Also, in Lucas Azevedo's answer, the parent directory path is added in the repository lstm_train file itself. While this definitely works, I still think it should be possible without editing the original repository.
I took a look at the repo in question and files like lstm_train.py are scripts which should be executed with the python working directory set as '<<<PathToRepo>>>/FactcheckingRANLP/Factchecking_clean'.
There are a few ways to do so:
You could open the project in a python IDE and configure your execution to use the directory .../Factchecking_clean as the working directory. In pycharm for example this could be done by importing the repo directory .../Factchecking_clean as a project. The following image shows how to set a working directory for execution in pycharm:
I think the repository was developed with this execution configuration set up.
Another possibility is to execute the python script from within another python file. This seems to be rather inconvenient to me, regardless you could do so by creating a separate python file with:
import sys
import os
sys.path.append('<<<PathToRepo>>>/FactcheckingRANLP/Factchecking_clean')
os.chdir('<<<PathToRepo>>>/FactcheckingRANLP/Factchecking_clean')
exec(open('./classification/lstm_train.py').read())
This adds the Factchecking_clean directory to the python path (using sys.path.append()) to be able to import stuff like classification.utils. The working directory is set by os.chdir() and finally exec(open('<<<filepath>>>')).read() executes the lstm_train file with the correct working directory and path variable set up.
Executing the new python file with the code above works for me (without editing the original repository).
However, as scripts like lstm_train.py actually are used to execute specific parts of the code provided in the rest of the repository modules, I think editing these files for experimental purposes is fine. In general, when working with repositories like this I recommend using an IDE (like pycharm) with a correctly set up configuration (method 1).
Ended up having to modify the repository's code, following the suggestion of Jeff.
import sys,os
parent_dir_path = os.path.abspath(__file__+"/../..")
sys.path.append(parent_dir_path)
adding the path until classification doesnt work, as the import is done mentioning the classification folder. The parent directory is the one that has to be added.
__file__ gives the current file name and os.path.abspath resolves the path navigation done with /../..

Proper ways to set the path of my app in Python

I have a question in how to properly create a path in Python (Python 3.x).
I developed a small scraping app in Python with the following directory structure.
root
├── Dockerfile
├── README.md
├── tox.ini
├── src
│   └── myapp
│   ├── __init__.py
│   ├── do_something.py
│   └── do_something_else.py
└── tests
├── __init__.py
├── test_do_something.py
└── test_do_something_else.py
When I want to run my code, I can go to the src directory and do with
python do_something.py
But, because do_something.py has an import statement from do_something_else.py, it fails like:
Traceback (most recent call last):
File "src/myapp/do_something.py", line 1, in <module>
from src.myapp.do_something_else import do_it
ModuleNotFoundError: No module named 'src'
So, I eventually decided to use the following command to specify the python path:
PYTHONPATH=../../ python do_something.py
to make sure that the path is seen.
But, what are the better ways to feed the path so that my app can run?
I want to know this because when I run pytest via tox, the directory that I would run the command tox would be at the root so that tox.ini is seen by tox package. If I do that, then I most likely run into a similar problem due to the Python path not properly set.
Questions I want to ask specifically are:
where should I run my main code when creating my own project like this? root as like python src/myapp/do_something.py? Or, go to the src/myapp directory and run like python do_something.py?
once, the directory where I should execute my program is determined, what is the correct way to import modules from other py file? Is it ok to use from src.myapp.do_something_else import do_it (this means I must add path from src directory)? Or, different way to import?
What are ways I can have my Python recognize the path? I am aware there are several ways to make the pass accessible as below:
a. write export PYTHONPATH=<path_of_my_choice>:$PYTHONPATH to make the
path accessible temporarily, or write that line in my .bashrc to make it permanent (but it's hard to reproduce when I want to automate creating Python environment via ansible or other automation tools)
b. write import sys; sys.path.append(<root>) to have the root as an accessible path
c. use pytest-pythonpath package (but this is not really a generic answer)
Thank you so much for your inputs!
my environment
OS: MacOS and Amazon Linux 2
Python Version: 3.7
Dependency in Python: pytest, tox
I would suggest to use setup.py to make this a python package. Then you can install it in development mode python setup.py develop. This way it will be available in your python environment w/o needing to specify the PYTHONPATH.
For testing, you can simply install the package python setup.py install.
Hope that helps.
Two simple steps should make it happen. Python experts can comment if this is a good way to do it (especially going by the concluding caution raised towards the end of this post).
I would have done it like below.
First I would have put a "__init__.py" in root so that hierarchy looks like below. This way python will treat the folder as a package.
root
├── Dockerfile
├── README.md
├── tox.ini
├── __init__.py
├── src
│ └── myapp
│ ├── __init__.py
│ ├── do_something.py
│ └── do_something_else.py
└── tests
├── __init__.py
├── test_do_something.py
└── test_do_something_else.py
Then in "do_something.py", I would have added these lines at the top. In the second line please put the full path to the "root" directory.
import sys
sys.path += ['/home/SomeUserName/SomeFolderPath/root']
from src.myapp.do_something_else import do_it
Please note that the second line will essentially modify the sys.path by adding the root folder path (I guess until the interpreter quits). If this is not what you can afford then I am sorry.

Python3 'ModuleNotFoundError' when running the code through the terminal, but everything works as intended in a python virtual environment

I am having problems with importing modules/packages with Python. I noticed this problem when I ran it in my terminal (CMD),
rather than my IDE (I use PyCharm). In PyCharm, I use a virtual enviroment setting with Python 3.7 and everything works as a charm
and as intended.
For reference this is how the imports were done in test_suite.py:
...
from tests.scenarios.test_scenario_01 import TestScenario # They work perfectly fine
from tests.scenarios.test_scenario_02 import TestScenario2 # written like this in PyCharm venv Python 3.7, but why?
...
This is a simplified version of my directory (without the unneccesary files):
QA System/
├── locators/
│ ├── locators.py
│ ├── __init__.py
├── pages/
│ ├── pages.py
│ └── __init__.py
└── tests/
├── reports
├── test_scenarios
├── test_scenario_01.py
├── test_scenario_02.py
├── __init__.py
|── test_suite.py
|── __init__.py
However when running the file test_suite.py manually through my CMD (because I want to integrate it with Jenkins
eventually), I get this error (py -3 test_suite.py):
ModuleNotFoundError: No module named 'tests'
Note: I am using the newest Python 3.7
From what I know about Python imports, for a directory to be treated like a python module, there needs to be a '__init__.py' file
included in the same directory.
After a bit of research I found out that it is possible to do a different type of imports in Python 3 and tried it out (putting a .
before the name of the imports). Like this:
from .scenarios.test_scenario_01 import TestScenario
from .scenarios.test_scenario_02 import TestScenario2
But still, it didn't run successfully and this was the error I've gotten:
ModuleNotFoundError: No module named '__main__.scenarios'; '__main__' is not a package
Could you please help me out on this one?
TLDR: Imports work in a Python3.7 venv, but not outside it
I fixed the issue by setting up a PYTHONPATH in system environment variables with the path to the project. As a value, I put the dir to the project. Thanks for the tips.
In case of directory It is mandate to use init.py. In modules it does not require to include init.py. Please, check what is your main directory and which is your modules..Hope this helps....

unit test structure and import

I want to know how to properly import file in my test file without using __init__.py in test root folder. Last sentence of this artice states, that test directory should not have init file.
I don't know much about python so I would like to know:
1) Why not
2) How to import file tested.py to the test_main.py in order to test its functionality without using init file as a script that insert paths to PYTHONPATHS?
My project has a following structure
.
├── __init__.py
├── my
│   ├── __init__.py
│   ├── main.py
│   └── my_sub
│   ├── __init__.py
│   └── tested.py
└── test
└── test_main.py
Files contains following code
#/Python_test/__init__.py
import my.main
#/Python_test/my/__init__.py
#empty
#/Python_test/my/main.py
from .my_sub.tested import inc
print(inc(5))
#/Python_test/my/my_sub/__init__.py
#empty
#/Python_test/my/my_sub/tested.py
def inc(x):
return x+1
#/Python_test/test/test_main.py
from Python_pytest.my.my_sub.tested import func
def test_answer():
assert func(3) == 3
When I run the code from command line python __init__.py it prints 6, which is correct.
I would like to test the function inc() in tested.py file.
1. I installed pytest package as a testing framework,
2. created test file similar to the one from tutorial here called test_main.py.
3. Added __init__.py with a code that finds path of the root directory and adds it to sys.path
It worked well but then I read that this shouldn't be done this way. But how should it be done? I have hard time reading some unit tested code from some github repositories that are tested and don't use the init file. (one of them is boto3) I can't find any clue that suggest how to properly use it.
I also tried to use relative imports this way
from ..my.main import func
but it throws ValueError: attempted relative import beyond top-level package. Which is ok. But I tried it anyway.
Now I don't know how to do that. Tutorials concerning importing usually states that we should add paths of imported modules to sys.path (if they are not present already) but how should I do that when there shouldn't be the init file which can hold the functionality?

Categories