Python: relatively import the containing package - python

I have the following package structure (drastically simplified from a real use case):
mypackage/
├── __init__.py
├── mod1.py
│   ├── def func1(): return 1
│   └── ...
│
├── mod2.py
│   ├── def func2(): return 2
│   └── ...
└── mod3.py
with __init__.py like this
from .mod1 import *
from .mod2 import *
Now, in mod3.py I want to access the packages complete namespace with one alias like res = p.func1() + p.func2() and I want this to achieve this by one relative import statement. Is this possible?
I don't want an absolute import like import mypackage as p (because the code should be indifferent on renaming the package).
Note, this is related to but different from this unanswered question from 2009.

Generally you do not want to use asterisks while doing imports so you can use this while still using relative import:
from . import mod1
You can call the function like this:
mod1.func1()
PS: If you are using Python 3 you are no longer required to use __init__.py to define packages.
Edit:
If you want use common namespace for all those functions you have imported you could create a new module to use as a header file:
mypackage/
├── header.py
│ ├── from .mod1 import *
│ └── from .mod2 import *
├── mod1.py
│ ├── def func1(): return 1
│ └── ...
│
├── mod2.py
│ ├── def func2(): return 2
│ └── ...
└── mod3.py
And in mod3.py you can import header.py and use the functions in various ways:
from .header import *
val1 = func1()
val2 = func2()
from . import header
val1 = header.func1()
val2 = header.func2()
from . import header as p
val1 = p.func1()
val2 = p.func2()

Related

Making a python package, how do I pass object into submodule

I'm making my own python package with submodules to organize things. How can I create an object defined at the top level and pass the object to a lower submodule so that the submodule edits values?
File structure:
packageFolder
├── mypackage
│   ├── resources
│   │   └── MASTERLOOKUP.csv
│   ├── analysis
│   │   ├── __init__.py
│   │   ├── elffileextract.py
│   │   └── apkextraction.py
│   └── __init__.py
├── setup.py
└── README.md
Inside of the top level __init__.py I included quite a bit of code so I didn't have a long string when creating objects, ie x = mypackage.m_file() preferable as opposed to x = mypackage.mymodule.m_file()
####__init__.py
class m_file():
def __init__(self):
self.FilePath = "*"
self.FileSize = "*"
self.FileType = "*"
self.FileDependencies = "*"
def fileoperation(self):
analysis.elffileextract.process(self) #want to pass in 'm_file' object
Inside a submodule file elffileextract.py I'll have something like this
####analysis/elffileextract.py
from . import m_file
def elfextract(mFile:m_file): #take object as argument
filename = mFile.FileName
mFile.FileDependencies = "glibc.so"
return
Inside of the file analysis/__init__.py I have the following
#### analysis/__init__.py
import mypackage.analysis.elffileextract.py
import mypackage.analysis.apkextraction.py
How I want to be able to use the package is as follows:
>>> import mypackage
>>> x = mypackage.m_file()
>>> x.FileDependencies
'*'
>>> x.fileoperation()
>>> x.FileDependencies
'glibc.so'
I'm not sure what the technical term for passing objects into submodules is but any answers to my problem or pointers in the right direction would be appreciated. I've tried various variations of imports in all files, I can't seem to figure it out. I may be trying to overcomplicate this in a non-pythonic way of doing things.

How to dynamically share a package-wide config variable?

I am building a python package, which has a module called "config", in which I have defined different files that contain some global variables that are used as configuration in other modules.
.
└── mypackage
├── base.py
├── config
│   ├── completion.py
│   ├── __init__.py
│   ├── locals.py
│   └── queries.py
├── encoders.py
├── exceptions.py
├── functions
│   ├── actions.py
│   ├── dummy.py
│   ├── __init__.py
│   ├── parsers.py
│   └── seekers.py
├── __init__.py
├── query.py
└── utils
├── dict.py
├── __init__.py
└── retry.py
For example, the file mypackage/config/queries.py has the following content:
INCLUDE_PARENTS = False
Whereas in the main file mypackage/base.py, I have a function which takes this config variable as a default argument:
import mypackage.config.queries as conf
def query(include_parent_=conf.INCLUDE_PARENTS, **kwargs):
# do stuff depending on include_parent_ argument
What I want, and what I haven't been able to find in other similar questions, is to be able to dynamically modify these variables in a Python/Ipython console session. That is, I should be able to do the following on Ipython:
In [1]: import mypackage as mp
In [2]: mp.config.INCLUDE_PARENTS = True # Its default value was False
In [3]: mp.query()
Out[3]: # result with include_parent_ argument set to True
In [4]: mp.config.INCLUDE_PARENTS = False # Now I set the value back to False
In [5]: mp.query()
Out[5]: # result with include_parent_ argument set to False
But I don't understand why I am not able to achieve it. I have tried importing the configuration variables in init.py with their associated namespace, but I never manage to be able to change the global configuration variables dynamically, as Pandas does, for example.
The issue is that you are using conf.INCLUDE_PARENTS as a default parameter of a function. A default parameter is evaluated when the function is created not when it is called. Thus, when you change your code later, the value inside the function does not change. The following should work as you expect.
def query(include_parent_=None, **kwargs):
if include_parent_ is None:
include_parent_ = conf.INCLUDE_PARENTS
# do stuff depending on include_parent_ argument

How to use data obtained from DB as values in add_argument() when the Flask app starts?

I have the following project structure for a Flask app using flask-restx
.
├── app
│   ├── extensions.py
│   ├── __init__.py
│   └── pv_dimensioning
│   ├── controller.py
│   ├── __init__.py
│   ├── models
│   │   ├── dto.py
│   │   ├── __init__.py
│   │   └── vendor_models.py
│   ├── services
│   │   ├── calculator.py
│   │   ├── database.py
│   │   ├── data.py
│   │   ├── db_crud.py
│   │   ├── __init__.py
│   │   └── processor.py
│   └── utils
│   ├── decode_verify_jwt.py
│   ├── decorator.py
│   └── __init__.py
├── config.py
├── main.py
├── package.json
├── package-lock.json
├── Pipfile
├── Pipfile.lock
├── README.md
├── serverless.yml
└── tests
├── __init__.py
├── test_calculator.py
├── test_config.py
└── test_processor.py
In controller.py, I am adding the add_argument() statements and parsing them in the api routes. In one of the add_argument() statement, I would like to add choices for the user. For getting the choices, I am querying from the database and getting a list of values available. I then convert this list to a tuple, assign it to a variable, and pass it as choices parameter in the add_argument()
My codes:
data.py
from ..models.vendor_models import AdminVendor
def data(app):
values = AdminVendor.query.all()
v = [value.name for value in values]
return {'v': tuple(v)}
controller.py
from flask_restx import Resource, reqparse
parser = reqparse.RequestParser()
parser.add_argument(
"vendor",
choices=vendors, # <--- The values of v should be added here
help="Select the vendor"
)
#ns.route("/")
class UserOutput(Resource):
#ns.doc(
"Get calculated response",
responses={
200: "Values returned",
400: "Validation Error",
403: "Not authorized"
},
)
#ns.expect(parser, validation=True)
def get(self):
args = parser.parse_args()
return DimensionCalculator.inputs(**args), 200
where ns is the namespace.
My __init__.py file in the app folder is as follows:
from flask import Flask
from .extensions import cors, db, ma
def create_app(app_config):
app = Flask(__name__)
app.config.from_object(app_config)
register_blueprints(app)
register_extensions(app)
return app
def register_extensions(app):
cors.init_app(app)
db.init_app(app)
ma.init_app(app)
def register_blueprints(app):
from .pv_dimensioning import dimensioning_blueprint
app.register_blueprint(dimensioning_blueprint)
and the entry point to the app is main.py
import os
from app import create_app
from app.extensions import db
from app.pv_dimensioning.services.data import data
from config import config_by_name
config_name = os.getenv("FLASK_CONFIG") or "default"
app_config = config_by_name[config_name]
app = create_app(app_config)
db.create_all(app=app)
with app.app_context():
v = data(app)
print(v)
The output of print(v) is as follows:
{'v': ('Solarmodul Canadian Solar HiKu CS3L-370MS 370Wp', 'Solarmodul Longi LR4-60HIH-370M, 370Wp', 'Solarmodul Solar Fabrik mono S3 - Halfcut 360Wp', 'Solarmodul Energetica e.Classic M HC black - 360Wp', 'Solarmodul Yingli YL280P-29b-YGE 60 Cell Series 2 - poly, 280Wp', 'Solarmodul Suntech Power STP370S-B60/Wnh, 370Wp', 'Solarmodul AXITEC AXIworldpremium X HC AC-340MH/120S, 340Wp', 'Solarmodul Longi LR4-72HIH-440M, 440Wp', 'Solarmodul Seraphim SRP-330-BMB-DG 330Wp', 'Solarmodul Sharp NU-JD 440Wp')}
I want these values of v to be used in controller.py in the 'vendor' argument.
I have tried getting the values of v from main.py by adding from main import v in the controller.py, but it shows the following error
ImportError: cannot import name 'v' from 'main'
What is the mistake that I am doing?
I'm not an expert on flask_restx, but from my understanding, the choices argument takes an iterable so you should simply be able to pass in the return value of your data function.
data.py
from ..models.vendor_models import AdminVendor
def data():
values = AdminVendor.query.all()
v = [value.name for value in values]
return {'v': tuple(v)}
controller.py
from flask_restx import Resource, reqparse
from .services.data import data
parser = reqparse.RequestParser()
parser.add_argument(
"vendor",
choices=data()['v'],
help="Select the vendor")
Regarding the import error, as Mindslave points out that is most likely a circular import error see this question for a bit more detail. Generally these can be avoided by moving the import from the top of the module to within a function/class, e.g:
from flask_restx import Resource, reqparse
def load_parser():
from .services.data import data # avoid circular import
parser = reqparse.RequestParser()
parser.add_argument(
"vendor",
choices=data()['v'],
help="Select the vendor")
return parser
parse = load_parser()
As a side note, be aware that reqparse is scheduled to be removed from flask_restx, so might be worth considering a different option before you get too embedded with it:
Warning The whole request parser part of Flask-RESTX is slated for
removal and will be replaced by documentation on how to integrate with
other packages that do the input/output stuff better (such as
marshmallow). This means that it will be maintained until 2.0 but
consider it deprecated. Don’t worry, if you have code using that now
and wish to continue doing so, it’s not going to go away any time too
soon.
source: https://flask-restx.readthedocs.io/en/latest/parsing.html

Unable to import python module from same package

I'm currently writing a library in python. I have a package called Selectors as a sub-directory of the library. I am trying to implement a new module in the package, but when I try to import it I get the error:
NameError: name '_RaceSelector__ResultSelector' is not defined
My directory looks like this:
Selectors
│ ├── __init__.py
│ ├── __init__.pyc
│ ├── __pycache__
│ │ ├── SeasonSelector.cpython-38.pyc
│ │ ├── Selector.cpython-38.pyc
│ │ ├── __init__.cpython-38.pyc
│ │ ├── race_selector.cpython-38.pyc
│ │ ├── result_selector.cpython-38.pyc
│ │ └── season_selector.cpython-38.pyc
│ ├── race_selector.py
│ ├── race_selector.pyc
│ ├── result_selector.py
│ ├── result_selector.pyc
│ ├── season_selector.py
│ ├── season_selector.pyc
│ ├── selector.py
│ └── selector.pyc
I want to use the modules in race_selector.py, here is that file:
from .selector import __Selector
from .result_selector import __ResultSelector
class RaceSelector(__Selector):
data = []
loaded_races = []
header = []
result_selector = __ResultSelector()
selector.py
import os
import csv
class __Selector:
def __init__(self, file_name):
self.data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../data/' + file_name + '.csv')
self.raw_data = self.load_data()
self.data = self.get_data()
result_selector.py
import os
from .selector import __Selector
class __ResultSelector(__Selector):
def __init__(self):
super().__init__('results')
I am able to import selector just fine and works as intended, but result_selector produces the error.
Thanks
When you do the following:
result_selector = __ResultSelector()
Python searches for _RaceSelector__ResultSelector because there is 2 underscores.
As mentioned in PEP8:
If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores. This invokes Python's name mangling algorithm, where the name of the class is mangled into the attribute name. This helps avoid attribute name collisions should subclasses inadvertently contain attributes with the same name.

Siblimg import with dependencies

I am trying to import a sibling module that itself has imports from another module.
The tree is as follows
├── USA
├── NewYork
│ ├── __init__.py
│ ├── Manhattan.py
│ └── Queens.py
├── Atlanta
│ ├── __init__.py
│ ├── Buckhead.py
The code is as follows
#Queens.py
def myFunction():
print("I am in Queens")
#Manhattan.py
from Queens import myFunction
class Manhattan():
def __init__(self):
myFunction()
print("I am in Manhattan")
Now, I want to instantiate an object of class Manhattan in Buckhead
#Buckhead.py
from NewYork.Manhattan import Manhattan
man = Manhattan()
I am getting a
ModuleNotFoundError: No module named 'Queens'
How do I go about instantiating the Manhttan class that ITSELF imports a function from the Queen module?

Categories