python Import Error: no module named app - python

First, I created __init__.py in my app folder
from flask import Flask
app = Flask(__name__)
from app import views
and then, I created views.py in the same app folder
from app import app
#app.route('/')
#app.route('/index')
def index():
return "Hello, World!
and lastly, I created run.py in a different folder
#!flask/bin/python
from app import app
app.run()
so, my flask tree is like
/microblog
/app
/__init__.py
/views.py
/flask
/tmp
/run.py
But, when I try to run run.py, I get an error
Traceback (most recent call last):
File "/home/shubham/Microblog/tmp/run.py", line 2, in <module>
from app import app
ImportError: No module named app
[Finished in 0.2s with exit code 1]
[shell_cmd: python -u "/home/shubham/Microblog/tmp/run.py"]
[dir: /home/shubham/Microblog/tmp]
[path: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games]

Your problem is that you don't have a clear understanding about the differences between imports, variable names, and packages. And how imports work.
When you're structuring a Python package, you'll typically have your toplevel folder with a setup.py, README and other assorted files in it, then your package folder. You might want something that looks like this:
├── microblog
│   ├── __init__.py
│   ├── server.py
│   └── views.py
├── README
├── MANIFEST.in
└── setup.py
If you really didn't want to put your URL handlers in the same place as your app, you've got it a little backwards though. You should do it like this:
server.py
from flask import Flask
from . import views
app = Flask(__name__)
app.register_blueprint(views.microblog)
def run():
app.run(debug=True)
views.py
from flask import Blueprint
microblog = Blueprint('microblog', __name__)
#microblog.route('/')
#microblog.route('/index')
def index():
return 'Hello, world!'
setup.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import setup
setup(
name='microblog',
version='0.1.0',
description='My microblog',
author='Me',
author_email='me#example.com',
url='http://my.cool.example.com',
packages=[
'microblog',
],
entry_points={
'console_scripts': [
'start-my-blog = microblog.server:run'
],
},
package_dir={'microblog': 'microblog'},
include_package_data=True,
install_requires=['flask',
],
license="BSD",
zip_safe=False,
keywords='',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Natural Language :: English',
'Programming Language :: Python :: 3.4',
],
)
Now you can create yourself a virtualenv, install your app, and then run it:
$ mkvirtualenv microblog
$ workon microblog
(microblog) $ python -m pip install -e .
# a bunch of install happens here, flask & what-not
$ start-my-blog
If you want to change the name of the command to run, you'll do that in your setup.py. Starting out with a structure like this will save you a lot of headaches down the road.

Related

Python package: Stylesheet not loaded when launching script [duplicate]

This question already has answers here:
How to read a (static) file from inside a Python package?
(6 answers)
Closed 2 years ago.
I have a package with the following structure:
package
├── LICENSE
├── README.md
├── MANIFEST.in
├── my_pkg
│ └── __init__.py
│ └── main.py
│ └── style.qss
├── setup.py
When I install it from github using pip, the stylesheet file style.qss is cloned, but when I launch the script typing foopkg it is not loaded. This is my setup.py file:
setup.py
import setuptools
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="my_pkg",
version="0.0.1",
author="foo",
author_email="foo#mail.com",
description="A small gui",
long_description=long_description,
long_description_content_type="text/markdown",
# url="https://github.com/foo/pkg",
include_package_data=True,
packages=setuptools.find_packages(),
install_requires=[
'PyQt5',
],
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.7',
entry_points={
"gui_scripts": [
"foopkg = my_pkg.main:main",
]
}
)
And this is my MANIFEST.in file:
MANIFEST.in
recursive-include my_pkg *.qss
The main.py is
main.py
import sys
...
def main():
app = QApplication(sys.argv)
style_path = sys.path[0] + '/style.qss'
file = QFile(style_path)
file.open(QFile.ReadOnly)
stream = QTextStream(file.readAll())
app.setStyleSheet(stream.readAll())
gui = GuiWindow()
gui.show()
app.exec_()
if __name__ == '__main__':
main()
What am I missing? What should I modify to be able to call my script using stylesheet?
When you build routes you must take into account what information each part contains, for example sys.path[0] contains the information from where the application is launched, for example when launching the entrypoint in Linux in my case it is /usr/bin. Instead you should use the __file__ attribute:
import os
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
def main():
app = QApplication(sys.argv)
style_path = os.path.join(CURRENT_DIR, 'style.qss')
file = QFile(style_path)
# ...

How to Import python package from another directory?

I have a project that is structured as follows:
project
├── api
│ ├── __init__.py
│ └── api.py
├── instance
│ ├── __init__.py
│ └── config.py
├── package
│ ├── __init__.py
│ └── app.py
├── requirements.txt
└── tests
└── __init__.py
I am trying to call the config.py file from the package/app.py as shown below:
# package/app.py
from instance import config
# I've also tried
import instance.config
import ..instance.config
from ..instance import config
But I always get the following error:
Traceback (most recent call last):
File "/home/csymvoul/projects/project/package/app.py", line 1, in <module>
from instance import config
ModuleNotFoundError: No module named 'instance'
Modifying the sys.path is not something I want to do.
I know that this question is very much answered but the answers that were given, did not work for me.
EDIT: When moving the app.py to the root folder it works just fine. But I need to have it under the package folder.
You can add the parent directory to PYTHONPATH, in order to achieve that, you can use OS depending path in the "module search path" which is listed in sys.path. So you can easily add the parent directory like following:
import sys
sys.path.insert(0, '..')
from instance import config
Note that the previous code uses a relative path, so you must launch the file inside the same location or it will likely not work. To launch from anywhere, you can use the pathlib module.
from pathlib import Path
import sys
path = str(Path(Path(__file__).parent.absolute()).parent.absolute())
sys.path.insert(0, path)
from instance import config
However, the previous approach is more a hack than anything, in order to do things right, you'll first need to reshape your project structure according to this very detailed blog post python packaging, going for the recommended way with a src folder.
Your directory layout must look like this:
project
├── CHANGELOG.rst
├── README.rst
├── requirements.txt
├── setup.py
├── src
│   ├── api
│   │   ├── api.py
│   │   └── __init__.py
│   ├── instance
│   │   ├── config.py
│   │   └── __init__.py
│   └── package
│   ├── app.py
│   └── __init__.py
└── tests
└── __init__.py
Note that you don't really need the requirements.txt because you can declare the dependencies inside your setup.py.
A sample setup.py (adapted from here):
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
import io
import re
from glob import glob
from os.path import basename
from os.path import dirname
from os.path import join
from os.path import splitext
from setuptools import find_packages
from setuptools import setup
def read(*names, **kwargs):
with io.open(
join(dirname(__file__), *names),
encoding=kwargs.get('encoding', 'utf8')
) as fh:
return fh.read()
setup(
name='nameless',
version='1.644.11',
license='BSD-2-Clause',
description='An example package. Generated with cookiecutter-pylibrary.',
author='mpr',
author_email='contact#ionelmc.ro',
packages=find_packages('src'),
package_dir={'': 'src'},
include_package_data=True,
zip_safe=False,
classifiers=[
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: Unix',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
# uncomment if you test on these interpreters:
# 'Programming Language :: Python :: Implementation :: IronPython',
# 'Programming Language :: Python :: Implementation :: Jython',
# 'Programming Language :: Python :: Implementation :: Stackless',
'Topic :: Utilities',
],
keywords=[
# eg: 'keyword1', 'keyword2', 'keyword3',
],
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
install_requires=[
# eg: 'aspectlib==1.1.1', 'six>=1.7',
],
extras_require={
# eg:
# 'rst': ['docutils>=0.11'],
# ':python_version=="2.6"': ['argparse'],
},
setup_requires=[
# 'pytest-runner',
],
entry_points={
'console_scripts': [
'api = api.api:main',
]
},
)
The content of my api.py:
from instance import config
def main():
print("imported")
config.config()
The content of my config.py:
def config():
print("config imported successfully")
You can find all the previous here
Optional but recommended: create a virtual environment, I use venv (Python 3.3 <=) for that, inside the root of the project:
python -m venv .
And to activate:
source bin/activate
Now I can install the package:
Using pip install -e . (with the dot) command inside the root of the project
Your import from instance import config works now, to confirm you can run api.py with:
python src/api/api.py
In Python 3.3 onwards you don't need __init__.py files in your subdirectories for the purpose of imports. Having them can actually be misleading as it causes the creation of package namespaces in each folder containing an init file, as described here.
By removing all those __init__.py files you will be able to import files in the namespace package (including subdirectories) when running app.py, but that's still not want we want.
The Python interpreter still doesn't know how to reach your instance namespace. In order to do that you can use the PYTHONPATH environment variable, including a path that is parent to config.py. You can do that as suggested in #RMPR's answer with sys.path, or by directly setting the environment variable, for instance:
PYTHONPATH=/home/csymvoul/projects/project python3 /home/csymvoul/projects/project/package/app.py
Then importing the dependency like from instance import config.

New to creating a Python Package

I tried making one to post on my GitHub and help users download dependencies for the program, but in the end, all it does is generate duplicate files. I was hoping to have (in the end) a package where the user could enter:
>>> import my_package
>>> my_package.main
but that isn't working. I've looked at several different websites and different templates, but seem to be getting nowhere with this.
Directory structure
Kodimer_Project
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── requirements.txt
├── setup.py
└── wav2bin
├── __version__.py
├── imgs
│   ├── App_Icon.gif
│   ├── App_Icon.ico
│   └── __init__.py
└── src
├── DrawGraph.py
├── GraphicInterface.py
├── SplashScreen.py
├── __init__.py
├── __main__.py
└── helper_functions.py
setup.py
From: https://github.com/kennethreitz/setup.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Note: To use the 'upload' functionality of this file, you must:
# $ pip install twine
import io
import os
import sys
from shutil import rmtree
from setuptools import find_packages, setup, Command
# Package meta-data.
NAME = 'wav2bin'
DESCRIPTION = 'GUI graphing tool used concurrently with lab.'
URL = 'https://github.com/jvanderen1/Kodimer_Project'
EMAIL = 'jvanderen1#gmail.com'
AUTHOR = 'Joshua Van Deren'
# What packages are required for this module to be executed?
REQUIRED = [
'matplotlib',
'numpy',
'scipy'
]
# The rest you shouldn't have to touch too much :)
# ------------------------------------------------
# Except, perhaps the License and Trove Classifiers!
# If you do change the License, remember to change the Trove Classifier for that!
here = os.path.abspath(os.path.dirname(__file__))
# Import the README and use it as the long-description.
# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
LONG_DESCRIPTION = '\n' + f.read()
# Load the package's __version__.py module as a dictionary.
about = {}
with open(os.path.join(here, NAME, '__version__.py')) as f:
exec(f.read(), about)
class UploadCommand(Command):
"""Support setup.py upload."""
description = 'Build and publish the package.'
user_options = []
#staticmethod
def status(s):
"""Prints things in bold."""
print('\033[1m{0}\033[0m'.format(s))
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
try:
self.status('Removing previous builds…')
rmtree(os.path.join(here, 'dist'))
except OSError:
pass
self.status('Building Source and Wheel (universal) distribution…')
os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))
self.status('Uploading the package to PyPi via Twine…')
os.system('twine upload dist/*')
sys.exit()
# Where the magic happens:
setup(
name=NAME,
version=about['__version__'],
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
author=AUTHOR,
author_email=EMAIL,
url=URL,
package_dir={'': 'wav2bin'},
packages=find_packages(exclude=('tests', 'docs')),
# If your package is a single module, use this instead of 'packages':
# py_modules=['mypackage'],
entry_points={
'gui_scripts': ['wav2bin = wav2bin.__main__:main'],
},
install_requires=REQUIRED,
python_requires='>=3',
include_package_data=True,
license='MIT',
classifiers=[
# Trove classifiers
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3 :: Only',
'Natural Language :: English',
'Topic :: Scientific/Engineering :: Human Machine Interfaces',
'Topic :: Software Development :: User Interfaces'
],
# $ setup.py publish support.
cmdclass={
'upload': UploadCommand,
},
)
wav2bin/src/__main__.py
Snippet of code:
if __name__ == '__main__':
main()
After you have some experience with various packaging modules what you would usually do is decide how professional you want your packaging to be? Do you want to host it on pypi? Distribute it from github? Pass it along to friends?
That's how you pick your packaging method, but first you should probably get some experience with the existing packaging modules, the two most popular ones are:
setuptools which is what I usually go with and to which I linked a good tutorial
distutils an older api to distribute packages but it's still around and is also very good to know
If then you decide this is an overkill and you want a less professional approach you can always do it manually.
Either installation to the python package folder, which for pip usually means something like entering the packages root folder and entering either
pip install .
If you are certain of your package, or
pip install -e .
For installing in edit mode if you still wish to keep the package malleable
or having the package in your python path in some other manner before import is mandatory.

flask cli can't locate the script manage.py

my flask app is a package named app located at /Users/gexinjie/Codes/MyProject/xinnjie_blog
the file tree is like this
xinnjie_blog
├── app
| ├── __init__.py
│   ├── config.py
│   ├── exceptions.py
│   ├── model.py
│   ├── model_sqlalchemy.py
│   ├── static
│   ├── templates
│   ├── util.py
│   └── views
├── manage.py
I export it as PATHONPATH, so manage.py can import app
echo $PATHONPATH
/Users/gexinjie/Codes/MyProject/xinnjie_blog
and export FLASK_APP
echo $FLASK_APP
manage.py
current dir is /Users/gexinjie/Codes/MyProject/xinnjie_blog
pwd
/Users/gexinjie/Codes/MyProject/xinnjie_blog
here is the manage.py
import click
from app import create_app
app = create_app('development')
#app.cli.command()
def initdb():
click.echo('Init the db...')
here is app.__init__.py
from flask import Flask
from .model_sqlalchemy import db
def create_app(config_name='default'):
app = Flask(__name__)
... # init
return app
but then if I execute flask initdb, I get this error:
Usage: flask [OPTIONS] COMMAND [ARGS]...
Error: No such command "initdb".
and if I execute flask run, I get
Usage: flask run [OPTIONS]
Error: The file/path provided (manage) does not appear to exist. Please verify the path is correct. If app is not on PYTHONPATH, ensure the extension is .py
why manage.py is not found? And how can I fix it.
(actually it worked well when manage.py have flask app in itself )
# manage.py
# this work well
app = Flask(__name__) # not app = create_app('development')
Thank you
Thank to #Adam, This problem was solved after I uninstall Anaconda.
Because all the time I tested manage.py on Pycharm command tool, and that flask was installed by Anaconda(python version 3.6), it may lack some extensions(usually I use python3.5 on terminal).So I think the problem occur during importing.
The flask command tool complain about 'can't locate the app', but the real problem is import error.So that is so confusing.
"universal" solution:
So when if you come to this kind of problem like I do, I suggest you first check the location of your app(try both relative path and absolute path), relative path may cause the locate problem when you are not at the right working directory.So absolute path is recommend.
If every thing about path went well, then make sure that all the packages required by your app is installed and can be imported. if you are using some type of virtual environment or something like that (In my case, I use the other version of python lacking some flask extensions), it may be the import error makes flask complain.
Hope this can help you.

Define imports and Python project structure to allow running locally and when installed

I am working on a Python project and started using a setup.py file to install it. I followed some guides on how to structure the project and everything is working great after installing it.
My problem is that I "lost" the ability to run my application from inside the project's directory, locally so to speak without installing it, for testing purposes. Here's how the directory layout looks like:
project_dir/
├── bin
│   └── app.py
├── data
│ └── data.conf
├── app_module
│   └── __init__.py
├── LICENSE
├── README.md
└── setup.py
The problem has to do with the imports. In app.py I have import app_module and it works as intended after it gets installed to the proper directory by running python setup.py install. If I want to run it by doing python bin/app.py it obviously doesn't work.
What am I doing wrong and how could I get this to work? Ideally I want to be able to run it from inside the directory and it should still work when installed with the setup.py script.
if your bin/app.py is only doing:
import app_module
app_module.run() # or whatever you called the main() function
you could (should!) use an entry_points (search for console_scripts).
And while running your uninstalled code, you would do either:
python -m app_module or python app_module/__init__.py (assuming you have a __main__ section inside this file, otherwise look at how json.tool is doing.
Edit
Here is a basic example, assuming your library is named "app_module".
setup.py
import imp
import os
import setuptools
module_name = 'app_module'
module = imp.load_module(
module_name,
*imp.find_module(module_name, [os.path.dirname(__file__)])
)
base = 'data'
data_files = [
(
'/usr/local/share/appdata/' + module_name + root[len(base):],
[os.path.join(root, f) for f in files]
) for root, dirs, files in os.walk(base)
]
setuptools.setup(
name=module_name,
version=module.__version__,
classifiers=(
'Environment :: Console',
'Operating System :: POSIX :: Linux',
),
packages=(
module_name,
),
entry_points={
# the executable will be called 'app' (not 'app.py')
'console_scripts': ['app = ' + module_name + ':main'],
# it does not seems unnecessarily complicated to me, it's just three lines
},
data_files=data_files,
)
app_module/__init__.py
import optparse
import sys
__version__ = '1.2.3'
def main():
parser = optparse.OptionParser(version=__version__)
parser.add_option('-m', '--man', action='store_true')
opt, args = parser.parse_args()
if opt.man:
help(__name__)
sys.exit()
print opt, args
if __name__ == '__main__':
main()
And now...
To run it:
python /full-or-replative/path/to/app_module/__init__.py
# or
export PYTHONPATH=/full-or-replative/path/to/app_module/
python -m app_module
To install and run it:
# test in a virtualenv
workon test
python setup.py install
app -h
What you need to do is either set the python path to include your module (ie run it as PYTHONPATH=project_dir python app.py, or make the app_module be placed in project_dir/bin in order to be included in the builtin path.
Note that not doing this is dangerous as after installed your app.py would otherwise pick up the installed package (app_module) instead of that in your project dir (which can get confusing).

Categories