I was trying to deploy some Google Cloud Functions today and found out about this wonderful project to test the functions locally. I can't thank you enough for this project, since it saves a lot of time (deploying is very time consuming, and being able to test it locally is a big relief).
I've created a minimum viable example that can help to reproduce the error. The same example works wonderfully when deployed as a Google Cloud Function, but it fails with an error when run with functions-framework
. The error is as follows (I'm using python 3.7 to create a virtual env and testing within that):
(venv) .../python/min-eg $ functions-framework --port 5000 --target hello
Traceback (most recent call last):
File "/home/msharma/git/python/min-eg/venv/bin/functions-framework", line 8, in <module>
sys.exit(_cli())
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/functions_framework/_cli.py", line 37, in _cli
app = create_app(target, source, signature_type)
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/functions_framework/__init__.py", line 229, in create_app
spec.loader.exec_module(source_module)
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/msharma/git/python/min-eg/main.py", line 1, in <module>
from app import db
File "/home/msharma/git/python/min-eg/app.py", line 29, in <module>
with app.app_context():
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/home/msharma/git/python/min-eg/venv/lib/python3.7/site-packages/flask/globals.py", line 52, in _find_app
raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
alembic==1.4.2
cffi==1.14.1
click==7.1.2
cloudevents==0.3.0
Flask==1.1.2
Flask-JWT-Extended==3.24.1
Flask-Migrate==2.5.3
Flask-SQLAlchemy==2.4.4
functions-framework==2.0.0
gunicorn==20.0.4
itsdangerous==1.1.0
Jinja2==2.11.2
Mako==1.1.3
MarkupSafe==1.1.1
pathtools==0.1.2
psycopg2==2.8.5
py-bcrypt==0.4
pycparser==2.20
PyJWT==1.7.1
python-dateutil==2.8.1
python-editor==1.0.4
six==1.15.0
SQLAlchemy==1.3.18
watchdog==0.10.3
Werkzeug==1.0.1
import os
from flask import current_app as app
from flask_sqlalchemy import SQLAlchemy, sqlalchemy
def setup_context():
# Set these in the environment variables for the function
db_user = os.environ["DB_USER"]
db_password = os.environ["DB_PASSWORD"]
db_name = os.environ["DB_NAME"]
db_connection_instance_name = os.environ["DB_CONNECTION_INSTANCE_NAME"]
db_host = os.environ["DB_HOST"]
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
driver_name = 'postgresql+psycopg2'
app.config['SQLALCHEMY_DATABASE_URI'] = sqlalchemy.engine.url.URL(
drivername=driver_name,
username=db_user,
password=db_password,
database=db_name,
host=db_host
)
db = SQLAlchemy(app)
return db
with app.app_context():
db = setup_context()
def hello(request):
stmt = 'select * from users;'
try:
result = db.session.execute(stmt)
for rowproxy in result:
print(rowproxy.items())
except Exception as e:
return 'Error: {}'.format(str(e))
return 'ok'
In terms of code, something like this (i'm not sure if I'm doing it correctly, so please bear with me):
app = flask.Flask(target, template_folder=template_folder)
app.config["MAX_CONTENT_LENGTH"] = MAX_CONTENT_LENGTH
with app.app_context():
# Load the source file:
# 1. Extract the module name from the source path
realpath = os.path.realpath(source)
directory, filename = os.path.split(realpath)
name, extension = os.path.splitext(filename)
# 2. Create a new module
spec = importlib.util.spec_from_file_location(name, realpath)
source_module = importlib.util.module_from_spec(spec)
# 3. Add the directory of the source to sys.path to allow the function to
# load modules relative to its location
sys.path.append(directory)
# 4. Add the module to sys.modules
sys.modules[name] = source_module
# 5. Execute the module
spec.loader.exec_module(source_module)