I have the following main.py:
...
app = FastAPI(docs_url="/jopapi/documentation", redoc_url=None)
password_encryptor = PasswordEncryptor(
os.environ.get("JUPYTERHUB_COOKIE_SECRET"), fernet=Fernet
)
...
I already tried to use a custom fixture like this:
#mock.patch.dict(os.environ, {"JUPYTERHUB_COOKIE_SECRET": "471bAcmHjbIdu3KLWphYpgXSW1HNC8q7"}, clear=True)
#pytest.fixture(name="client")
def client_fixture():
client = TestClient(app)
yield client
But the following test:
def test_generic(client: TestClient):
response = client.get("/jobapi/generic")
assert response.status_code == 200
still fails, since the environment variable seems not to get set, which results in None
from src.app.main import app
src\app\main.py:38: in <module>
password_encryptor = PasswordEncryptor(
src\app\auth.py:33: in __init__
self.fernet = fernet(self._generate_fernet_key(self.secret))
src\app\auth.py:36: in _generate_fernet_key
bytestring = secret.encode()
E AttributeError: 'NoneType' object has no attribute 'encode'
When I set the env variable in the main.py file per hand, it works. How can I fix this?
I think you need to create a .env at the root of your project and then read that file using python's dotenv, so finally you can easily use it with os.environ.get() later in your main.py file,
.env
JUPYTERHUB_COOKIE_SECRET=471bAcmHjbIdu3KLWphYpgXSW1HNC8q7
main.py
import os
basedir = path.abspath(path.dirname(__file__))
load_dotenv(path.join(basedir, ".env"))
app = FastAPI(docs_url="/jopapi/documentation", redoc_url=None)
password_encryptor = PasswordEncryptor(
os.environ.get("JUPYTERHUB_COOKIE_SECRET"), fernet=Fernet
)
Related
Objective : To Create UnitTestCases for main.py
How can we import another python file which will dynamically return result
File : main.py
import os
_ENV = os.popen("echo ${RPM_ENVIRONMENT}").read().split('\n')[0]
_HOST = os.popen("echo $(hostname)").read().split('\n')[0]
_JOB_TYPE=os.popen("echo ${JOB_TYPE}").read().split('\n')[0]
SERVER_URL = {
'DEV':{'ENV_URL':'https://dev.net'},
'UAT':{'ENV_URL':'https://uat.net'},
'PROD':{'ENV_URL':'https://prod.net'}
}[_ENV]
Import another python file to our testing script
when i import main.py , i will receive error on SERVER_URL = { KeyError '${RPM_ENVIRONMENT}'
I believe the only reason why its returning error is because it does not recognize RPM_ENVIRONMENT, how can we mock _ENV variables in our main file and print server url as https://dev.net
After i have succesfully import main.py in my test case file, then i will create my unitTest cases as the ENV variable is required for me.
Testing : test_main.py
import unittest, sys
from unittest import mock
# --> Error
sys.path.insert(1, 'C:/home/src')
import main.py as conf
# For an example : we should be able to print https://dev.net when we include this in our line
URL = conf.SERVER_URL.get('ENV_URL')
ENV = conf._ENV
#URL should return https://dev.net & ENV should return DEV
class test_tbrp_case(unittest.TestCase):
def test_port(self):
#function yet to be created
pass
if __name__=='__main__':
unittest.main()
There's little reason to shell out of Python. You can read an environment variable with os.environ. os.environ['RPM_ENVIRONMENT'].
import os
_ENV = os.environ['RPM_ENVIRONMENT']
SERVER_URL = {
'DEV':{'ENV_URL':'https://dev.net'},
'UAT':{'ENV_URL':'https://uat.net'},
'PROD':{'ENV_URL':'https://prod.net'}
}[_ENV]
Now your test can set RPM_ENVIRONMENT before importing main.py.
os.environ['RPM_ENVIRONMENT'] = 'UAT'
sys.path.insert(1, 'C:/home/src')
import main.py as conf
EDIT: I added the following lines to config.py:
print(type(SECRET_KEY), SECRET_KEY)
print(type(SQLALCHEMY_DATABASE_URI), SQLALCHEMY_DATABASE_URI)
print(SQLALCHEMY_DATABASE_URI == "sqlite:///site.db")
And then when I start the flask app with python run.py, I get the output
<class 'str'> secret
<class 'str'> sqlite:///site.db
True
Now in the python terminal when I run the following command
>>> from main import create_app, db
I'm getting output
<class 'NoneType'> None
<class 'NoneType'> None
False
So it seems like the values are not getting loaded from the .env file. Am I missing any imports? Because if hardcode the value of the SQLALCHEMY_DATABASE_URI to sqlite:///site.db the output becomes:
<class 'NoneType'> None
<class 'str'> sqlite:///site.db
True
I'm working on a Flask application and I restructured it using Blueprints. After this change when I try to interact with tables in my database the following error gets thrown:
'NoneType' object has no attribute 'drivername'
I'm loading any secret values or database URI's from a .env file using the dotenv package. In fact, in the front end the application is working because when I make changes they are saved and being rendered on the page. However, I want to work with tables through the table to create dummy data quickly, but for some reason I'm not.
__ init __.py
This file is part of the main package called main
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from main.config import Config
db = SQLAlchemy()
bcrypt = Bcrypt()
login = LoginManager()
login.login_view = 'users.login'
def create_app(config_class=Config):
# Create app and setup config
app = Flask(__name__)
app.config.from_object(Config)
# Link extensions to the app
db.init_app(app)
bcrypt.init_app(app)
login.init_app(app)
# Add route imports
from main.users.routes import users
from main.decks.routes import decks
from main.cards.routes import cards
from main.errors.handlers import errors
# Register blueprints
app.register_blueprint(users)
app.register_blueprint(decks)
app.register_blueprint(cards)
app.register_blueprint(errors)
return app
config.py
from dotenv import load_dotenv
import os
load_dotenv()
class Config():
SECRET_KEY = os.getenv('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI')
.env
SECRET_KEY="secret"
SQLALCHEMY_DATABASE_URI="sqlite:///site.db"
This is how I'm trying to interact with tables from the python terminal
>> from main import db, create_app
>> from main.models import Card
>> app = create_app()
>> with app.app_context():
Card.query.first()
AttributeError: 'NoneType' object has no attribute 'drivername'
This is quite a generic error, because all it means is that somewhere along the line you have an object with type NoneType, and None has no attributes as far as I know, so it will raise an AttributeError. Looking at the question context, I think the most likely error is referring to a database query that is returning None.
So look for a point in your code when you do something like this:
x = Card.query.get(65) # let's say there are only 52 cards, so this is None
return x.drivername
This will cause an AttributeError and has clearly crashed your code. So it will be in any file that is imported by the create_app, and any files they import themselves (if this is quite a lot, think about where you use database queries the most).
Yeah all I had to do in the python terminal was the load the .env file using the load_dotenv() and find_dotenv() functions. In essence, before you call create_app you need to load your environment variables in, which I wasn't entering as a command in my Python terminal, but was automatically getting ran in my script.
I tried to test my code using unittest, where a variable is stored somewhere in a file and accessed using os.getenv
settings.py
import os
TARGET_VAR = os.getenv('TARGET_VAR_VALUE')
some apiclass
from settings import TARGET_VAR
class someApi:
def __init__(self):
print(TARGET_VAR) // good if running normally
....rest of func
test
def test_extreme_devices(self):
app = Flask(__name__)
app.config["LOGIN_DISABLED"] = True
api = flask_restful.Api(app)
api.add_resource('someApi', '/devices/')
with app.test_client() as client:
res = client.get('/devices/')
self.assertEqual(res.status_code, 200)
.env
TARGET_VAR_VALUE='some target value'
This is running good but not when running test
I am confused when running test for testing the someApi class, I got the error
TypeError: int() argument must be a string, a bytes-like object or a number, not
'NoneType'
obviously for the TARGET_VAR is NoneType, even if its value is set in .env
It will work if I add the actual value directly to it
TARGET_VAR = 'actual value'
This issue is only on unittest, but not when flask is running and accessing the route(like postman)
It could be that when you are running the flask app locally the environment already has TARGET_VAR_VALUE loading into the os environment.
If you use something like python-dotenv when running your unittests, you can ensure there's a consistent environment. Just by specifying the correct .env file to use and ensuring it overrides any other env vars:
from dotenv import load_dotenv
load_dotenv("tests/test.env", override=True)
tests/test.env
TARGET_VAR_VALUE='some target value'
I have a flask app that is giving me 500 when I import a file using sys.path.append('path/to/file.py)
Here is my file located in /var/www/html/ip.py which flask is calling:
import sys
sys.path.append('/auto/conf/')
from config import config
server_username = config['server_username']
server_password = config['server_prod_password']
def check_ip(ip_addr):
return "test"
Here is my /auto/conf/config.py:
import os
import ConfigParser
# Define names of dir and file
CRED_DIR = 'cred'
FILE_NAME = 'cred.conf'
# Path to cred file
my_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
cred_dir = os.path.join(my_dir, CRED_DIR)
file_path = os.path.join(cred_dir, FILE_NAME)
# Load the conf file with ConfigParser
config = ConfigParser.SafeConfigParser()
config.read(file_path)
# Build a config dictionary
config = {
'server_username': config.get('server', 'username'),
'server_password': config.get('server', 'password'),
}
and cred.conf is located in /auto/cred/cred.conf and contains server info.
Now, here is the issue. If I run python ip.py, it runs fine. I added print statement and it was fetching proper server username and password. But when I run it via Flask, it gives me 500 error.
Here are some of the things I tried:
-- If I comment out "from config import config" from ip.py, Flask runs returns "test" meaning it worked. It will not get server un and pw but atleast it does not 500.
-- If I move cred.conf and config.py to same directory as ip.py and comment out "sys.path.append('/auto/conf/')" and uncomment "from config import config", Flask works.
Any ideas why its happening? I am thinking Flask does not like sys.path.append. Is there any alternative I can use so Flask works?
Edit:
I changed ip.py to this:
import sys
sys.path.append('/auto/conf/')
import config
and removed all code in config.py and it is still gving me error. If I comment out "import config", Flask works. Definitely it does not like importing in this fashion..
I am working with a python script, and i face importing problem when i try to import a class from another python script. Here is how my python project folder looks:
Mysql_Main/
checks.py
Analyzer/
config.py
ip.py
op.py
__init__.py
Now i want to import two classes named: Config() and Sqlite() from config.py into the checks.py script.How do i do it?
This is what i tried, but its resulting in an error!
inside checks.py:
from Analyzer import config
config = config.Config()
sqlite = config.Sqlite()
The problem is that Config class is imported properly, but Sqlite class is not getting imported.It is showing error - Config instance has no attribute 'Sqlite'
When you do:
config = config.Config()
You write over the variable config and it no longer points to the module config. It stores the new Config instance.
Try:
from Analyzer import config
config_instance = config.Config()
sqlite_instance = config.Sqlite()