Importing a class and calling a method - python

I am using Eclipse for Python programming.
In my project, I have a file: main.py. This file is located in the root of the project files hierarchy. In the root itself, I created a folder with the name Classes in which I have a class file named: PositionWindow.py. This file contains a class PositionWindow and the class itself contains a function named: Center().
In main.py, I want to import this class [PositionWindow] and later call that function Center in the appropriate place.
I am not able to import that class correctly in main.py and not following how to call that function later.

You seem to be programming in java, still. I understand that you used java for a long time, but this is no longer java. This is python...
Python doesn't have directories. It has packages
Python doesn't have class files. It has modules.
You can have multiple classes in a module.
You can have multiple modules in a package.
I suggest you read at least the python basic tutorial (specially the part about packages and modules) so you can learn python, instead of trying to guess the language.
About the structure of your project, there's this article which is pretty good, and shows you how to do it.
shameless copy paste:
Filesystem structure of a Python project
by Jp Calderone
Do:
name the directory something related to your project. For example, if your
project is named "Twisted", name the
top-level directory for its source
files Twisted. When you do releases,
you should include a version number
suffix: Twisted-2.5.
create a directory Twisted/bin and put your executables there, if you
have any. Don't give them a .py
extension, even if they are Python
source files. Don't put any code in
them except an import of and call to a
main function defined somewhere else
in your projects.
If your project is expressable as a single Python source file, then put it
into the directory and name it
something related to your project. For
example, Twisted/twisted.py. If you
need multiple source files, create a
package instead (Twisted/twisted/,
with an empty
Twisted/twisted/__init__.py) and place
your source files in it. For example,
Twisted/twisted/internet.py.
put your unit tests in a sub-package of your package (note - this means
that the single Python source file
option above was a trick - you always
need at least one other file for your
unit tests). For example,
Twisted/twisted/test/. Of course, make
it a package with
Twisted/twisted/test/__init__.py.
Place tests in files like
Twisted/twisted/test/test_internet.py.
add Twisted/README and Twisted/setup.py to explain and
install your software, respectively,
if you're feeling nice.
Don't:
put your source in a directory called src or lib. This makes it hard
to run without installing.
put your tests outside of your Python package. This makes it hard to
run the tests against an installed
version.
create a package that only has a __init__.py and then put all your code into __init__.py. Just make a module
instead of a package, it's simpler.
try to come up with magical hacks to make Python able to import your module
or package without having the user add
the directory containing it to their
import path (either via PYTHONPATH or
some other mechanism). You will not
correctly handle all cases and users
will get angry at you when your
software doesn't work in their
environment.

Instead of creating "folder" in the root of your project, create a "package". Simply create a blank file called __init__.py and you should be able to import your module in main.py.
import Classes.PositionWindow
p = Classes.PositionWindow.PositionWindow()
p.Center()
However, you should read up on modules and packages, because your structure indicates that your approach may be flawed. First, a class doesn't have to be in a separate .py file like it does in Java. Further, your packages/modules/functions/methods should all be in lower case. Only class names should be in Upper case.

So you have this file layout:
/main.py
/Classes/PositionWindow.py (with Center inside it)
You have two choices:
Add "Classes" to your Python Path, allowing you to import PositionWindow.py directly.
Make "Classes" a package (possibly with a better name).
To add the Classes folder to your Python Path, set PYTHONPATH as an environment variable to include it. This works like your shell's PATH -- when you import PositionWindow, it will look through all the directories in your Python Path to find it.
Alternatively, if you add a blank file:
Classes/__init__.py
You can import the package and its contents like so in main.py:
import Classes.PositionWindow
x = Classes.PositionWindow.Center()

Related

Importing modules from adjacent folders in Python

I wanted to ask if there is a way to import modules/functions from a folder in a project that is adjacent to another folder.
For example lets say I have two files:
project/src/training.py
project/lib/functions.py
Now both these folders have the __init__.py file in them. If I wanted to import functions.py into training.py, it doesn't seem to detect. I'm trying to use from lib.functions import * .I know this works from the upper level of the folder structure, where I can call both files from a script, but is there a way to do it files in above/sideways folders?
Fundamentally, the best way of doing this depends on exactly how the two modules are related. There's two possibilities:
The modules are part of one cohesive unit that is intended to be used as a single whole, rather than as separate pieces. (This is the most common situation, and it should be your default if you're not sure.)
The functions.py module is a dependency for training.py but is intended to be used separately.
Cohesive unit
If the modules are one cohesive unit, this is not the standard way of structuring a project in Python.
If you need multiple modules in the same project, the standard way of structuring the folders is to include all the modules in a single package, like so:
project/
trainingproject/
__init__.py
training.py
functions.py
other/
...
project/
...
folders/
...
The __init__.py file causes Python to recognize the trainproject/ directory as a single unit called a package. Using a package enables to use of relative imports:
training.py
from . import functions
# The rest of training.py code
Assuming your current directory is project, you can then invoke training.py as a module:
python -m trainingproject.training
Separate units
If your modules are actually separate packages, then the simplest idiomatic solutions during development is to modify the PYTHONPATH environment variable:
sh-derviative syntax:
# All the extra PYTHONPATH references on the right are to append if it already has values
# Using $PWD ensures that the path in the environment variable is absolute.
PYTHONPATH=$PYTHONPATH${PYTHONPATH:+:}$PWD/lib/
python ./src/training.py
PowerShell syntax:
$env:PYTHONPATH = $(if($env:PYTHONPATH) {$env:PYTHONPATH + ';'}) + (Resolve-Path ./lib)
python ./src/training.py
(This is possible in Command Prompt, too, but I'm omitting that since PowerShell is preferred.)
In your module, you would just do a normal import statement:
training.py
import functions
# Rest of training.py code
Doing this will work when you deploy your code to production as well if you copy all the files over and set up the correct paths, but you might want to consider putting functions.py in a wheel and then installing it with pip. That will eliminate the need to set up PYTHONPATH by installing functions.py to site-packages, which will make the import statement just work out of the box. That will also make it easier to distribute functions.py for use with other scripts independent of training.py. I'm not going to cover how to create a wheel here since that is beyond the scope of this question, but here's an introduction.
Yes, it’s as simple as writing the entire path from the working directory:
from project.src.training import *
Or
from project.lib.functions import *
I agree with what polymath stated above. If you were also wondering how to run these specific scripts or functions once they are imported, use: your_function_name(parameters), and to run a script that you have imported from the same directory, etc, use: exec(‘script_name.py). I would recommend making functions instead of using the exec command however, because it can be a bit hard to use correctly.

Creating Modules with PyCharm

I am working with PyCharm and am trying to create a module from code I've created so that I can import it into new files. In IntelliJ you can start the module creator but in PyCharm this option does not seem to exist.
Without a module when I type:
import my_code
I receive a warning saying "No module named my_code".
I've tried creating packages to replace the module but this does not work.
How do you repackage code in PyCharm so you can import it into a new file?
The project structure is quite simple. I have a number of files I've created as part of a tutorial. I want to make one of the files, "Importing_Files" a module so that I can import it into another file, i.e., "Import_Tester". I've added a picture below to show the tree.
Here's what I would suggest. It looks like you've already tried to set things up correctly, but you need to organize things in Pycharm a bit differently. I ran into a similar problem, which is why I think having an answer to this question is useful.
Your .idea directory is within the package, which makes things awkward. Try this:
Create a new Pycharm project based on the top level of the project.
Make src and test directories within that project, and set them as source root and test root, respectively.
Move the HelloWorld package into src (make sure it's still recognized as a package).
Create new files in src with main sections for any functions you need to run from the command line, add imports for your package, and move your main code into it.
For any main functions that define tests, do the same thing -- create files with main logic in the tests directory. Unit tests are a better way to do that, but this directory structure should work.
Remove the old project (delete the .idea directory in HelloWorld).
The final project layout should look something like this:
CompletePythonMasterClassUdemy
.idea
src
command_line_main.py
HelloWorld
__init__.py
...
test
test_account.py
This is a better way to organize things that should work both within and outside of Pycharm. Unlike the Java world, Python doesn't have as many common conventions for correctly setting up projects. There are very likely better ways to do things, but this works well for me. It should work well for people getting started with Python library development.

How do I structure my Python project to allow named modules to be imported from sub directories

This is my directory structure:
Projects
+ Project_1
+ Project_2
- Project_3
- Lib1
__init__.py # empty
moduleA.py
- Tests
__init__.py # empty
foo_tests.py
bar_tests.py
setpath.py
__init__.py # empty
foo.py
bar.py
Goals:
Have an organized project structure
Be able to independently run each .py file when necessary
Be able to reference/import both sibling and cousin modules
Keep all import/from statements at the beginning of each file.
I Achieved #1 by using the above structure
I've mostly achieved 2, 3, and 4 by doing the following (as recommended by this excellent guide)
In any package that needs to access parent or cousin modules (such as the Tests directory above) I include a file called setpath.py which has the following code:
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('...'))
Then, in each module that needs parent/cousin access, such as foo_tests.py, I can write a nice clean list of imports like so:
import setpath # Annoyingly, PyCharm warns me that this is an unused import statement
import foo.py
Inside setpath.py, the second and third inserts are not strictly necessary for this example, but are included as a troubleshooting step.
My problem is that this only works for imports that reference the module name directly, and not for imports that reference the package. For example, inside bar_tests.py, neither of the two statements below work when running bar_tests.py directly.
import setpath
import Project_3.foo.py # Error
from Project_3 import foo # Error
I receive the error "ImportError: No module named 'Project_3'".
What is odd is that I can run the file directly from within PyCharm and it works fine. I know that PyCharm is doing some behind the scenes magic with the Python Path variable to make everything work, but I can't figure out what it is. As PyCharm simply runs python.exe and sets some environmental variables, it should be possible to clone this behavior from within a Python script itself.
For reasons not really germane to this question, I have to reference bar using the Project_3 qualifier.
I'm open to any solution that accomplishes the above while still meeting my earlier goals. I'm also open to an alternate directory structure if there is one that works better. I've read the Python doc on imports and packages but am still at a loss. I think one possible avenue might be manually setting the __path__ variable, but I'm not sure which one needs to be changed or what to set it to.
Those types of questions qualify as "primarily opinion based", so let me share my opinion how I would do it.
First "be able to independently run each .py file when necessary": either the file is an module, so it should not be called directly, or it is standalone executable, then it should import its dependencies starting from top level (you may avoid it in code or rather move it to common place, by using setup.py entry_points, but then your former executable effectively converts to a module). And yes, it is one of weak points of Python modules model, that causes misunderstandings.
Second, use virtualenv (or venv in Python3) and put each of your Project_x into separate one. This way project's name won't be part of Python module's path.
Third, link you've provided mentions setup.py – you may make use of it. Put your custom code into Project_x/src/mylib1, create src/mylib1/setup.py and finally your modules into src/mylib1/mylib1/module.py. Then you may install your code by pip as any other package (or pip -e so you may work on the code directly without reinstalling it, though it unfortunately has some limitations).
And finally, as you've confirmed in comment already ;). Problem with your current model was that in sys.path.insert(0, os.path.abspath('...')) you'd mistakenly used Python module's notation, which in incorrect for system paths and should be replaced with '../..' to work as expected.
I think your goals are not reasonable. Specifically, goal number 2 is a problem:
Be able to independently run each .py file when neccessary
This doesn't work well for modules in a package. At least, not if you're running the .py files naively (e.g. with python foo_tests.py on the command line). When you run the files that way, Python can't tell where the package hierarchy should start.
There are two alternatives that can work. The first option is to run your scripts from the top level folder (e.g. projects) using the -m flag to the interpreter to give it a dotted path to the main module, and using explicit relative imports to get the sibling and cousin modules. So rather than running python foo_tests.py directly, run python -m project_3.tests.foo_tests from the projects folder (or python -m tests.foo_tests from within project_3 perhaps), and have have foo_tests.py use from .. import foo.
The other (less good) option is to add a top-level folder to your Python installation's module search path on a system wide basis (e.g. add the projects folder to the PYTHON_PATH environment variable), and then use absolute imports for all your modules (e.g. import project3.foo). This is effectively what your setpath module does, but doing it system wide as part of your system's configuration, rather than at run time, it's much cleaner. It also avoids the multiple names that setpath will allow to you use to import a module (e.g. try import foo_tests, tests.foo_tests and you'll get two separate copies of the same module).

What is the proper way to construct a Python package/module referencing a .PYD?

I am a rookie to the Python world, and now I find myself trying to learn how to properly create a Python package or module. I also have several requirements that must be met.
I have a core native DLL (we'll name it MyCore.dll) compiled from C++. This DLL must be deployed to a particular install location, as it's a core component of a product (we'll say ProgramFiles\MyProduct).
I have used SWIG to generate Python bindings for MyCore.dll. It has generated 2 files: _MyCoreBindings.pyd (essentially a DLL that references MyCore.dll) and MyCoreBindings.py (which loads _MyCoreBindings.pyd and provides a Python API to it).
Finally, I have a Python script (MyProduct.py) containing only an import, as my product must be imported in Python under the name MyProduct.SDK :
import MyCoreBindings as SDK
Thus, I want a user's Python script to be able to access it like so:
import MyProduct.SDK
File summary in order of dependency:
ProgramFiles\MyProduct\MyCore.dll
_MyCoreBindings.pyd
MyCoreBindings.py
MyProduct.py (I'm not sure I need this)
I've also read that the format of a Python package involves some directory structure mimicking the import path, and the possible inclusion of setup.py and __init__.py, but all materials I've read have not made it clear what must go in each of these files, and in what cases they are required. I am definitely not clear where this directory structure may be placed.
If you want Python to be able to import your module, then you have a couple of choices:
install the module to Python's site-packages folder.
modify the paths that Python searches for modules/packages to import. You can do that via a *.pth file or by modifying the path using Python's sys module (i.e. sys.path.append(/some/path) )
You use setup.py for installing your package and/or creating eggs/wheels etc. See the following for helpful hints:
https://docs.python.org/2/distutils/setupscript.html
https://pythonhosted.org/an_example_pypi_project/setuptools.html
You can create a package by using _init__.py inside a folder alongside your modules:
- MyProduct
- __init__.py
- MyCoreBindings.py
- _MyCoreBindings.pyd
The _init__.py file can be empty. This basically allows you to import the folder as MyProduct:
import MyProduct
MyProduct.MyCoreBindings
or
from MyProduct import MyCoreBindings as SDK
You won't need a MyProduct.py if you go with the __init__.py in the root folder. I hope that all made sense.

Best practice for handling path/executables in project scripts in Python (e.g. something like Django's manage.py, or fabric)

I do a lot of work on different projects (I'm a scientist) in a fairly standardised directory structure. e.g.:
project
/analyses/
/lib
/doc
/results
/bin
I put all my various utility scripts in /bin/ because cleanliness is next to godliness. However, I have to hard code paths (e.g. ../../x/y/z) and then I have to run things within ./bin/ or they break.
I've used Django and that has /manage.py which runs various django-things and automatically handles the path. I've also used fabric to run various user defined functions.
Question: How do I do something similar? and what's the best way? I can easily write something in /manage.py to inject the root dir into sys.path etc, but then I'd like to be able to do "./manage.py foo" which would run /bin/foo.py. Or is it possible to get fabric to call executables from a certain directory?
Basically - I want something easy and low maintenance. I want to be able to drop an executable script/file/whatever into ./bin/ and not have to deal with path issues or import issues.
What is the best way to do this?
Keep Execution at TLD
In general, try to keep your runtime at top-level. This will straighten out your imports tremendously.
If you have to do a lot of import addressing with relative imports, there's probably a
better way.
Modifying The Path
Other poster's have mentioned the PYTHONPATH. That's a great way to do it permanently in your shell.
If you don't want to/aren't able to manipulate the PYTHONPATH project path directly you can use sys.path to get yourself out of relative import hell.
Using sys.path.append
sys.path is just a list internally. You can append to it to add stuff to into your path.
Say I'm in /bin and there's a library markdown in lib/. You can append a relative paths with sys.path to import what you want.
import sys
sys.path.append('../lib')
import markdown
print markdown.markdown("""
Hello world!
------------
""")
Word to the wise: Don't get too crazy with your sys.path additions. Keep your schema simple to avoid yourself a lot confusion.
Overly eager imports can sometimes lead to cases where a python module needs to import itself, at which point execution will halt!
Using Packages and __init__.py
Another great trick is creating python packages by adding __init__.py files. __init__.py gets loaded before any other modules in the directory, so it's a great way to add imports across the entire directory. This makes it an ideal spot to add sys.path hackery.
You don't even need to necessarily add anything to the file. It's sufficient to just do touch __init__.py at the console to make a directory a package.
See this SO post for a more concrete example.
In a shell script that you source (not run) in your current shell you set the following environment variables:
PATH=$PATH:$PROJECTDIR/bin
PYTHONPATH=$PROJECTDIR/lib
Then you put your Python modules and package tree in your projects ./lib directory. Python automatically adds the PYTHONPATH environment variable to sys.path.
Then you can run any top-level script from the shell without specifying the path, and any imports from your library modules are looked for in the lib directory.
I recommend very simple top-level scripts, such as:
#!/usr/bin/python
import sys
import mytool
mytool.main(sys.argv)
Then you never have to change that, you just edit the module code, and also benefit from the byte-code caching.
You can easily achieve your goals by creating a mini package that hosts each one of your projects. Use paste scripts to create a simple project skeleton. And to make it executable, just install it via setup.py develop. Now your bin scripts just need to import the entry point to this package and execute it.

Categories

Resources