Change session variable value fails - python

EDIT: actually, I can see the value of the session variable changed, but in the next call to the function the value is set back to 0
I am a Flask beginner and I have problems in changing the value of a session variable. Here is an excerpt of my code:
EDIT after first round of comments
0) I set the SECRET_KEY variable in my config.py.
1) when a user logs in I set a session variable:
#app.route('/login', methods=['GET', 'POST'])
def login():
session['info_released'] = 0
app.logger.debug('info_released session value: {}'.format(session['info_released'])
...
Checking the log, the value of the session variable is correctly set to 0.
2) I have a counter variable passed via request.json that is incremented from time to time. Between one counter increment and the following one I check the following condition several times (via an ajax call):
#app.route('/get_actual_demand', methods=['GET', 'POST'])
def get_actual_demand():
app.logger.info('> SESSION: {}'.format(session['info_released']))
if request.json['counter'] == 10 and session['info_released'] == 0:
#code
session['info_released'] = 1
app.logger.info('> SESSION VAR. AFTER CHANGE: {}'.format(session['info_released']))
return jsonify(released=1)
else:
return jsonify(released=0)
That is, when counter == 10 I check the condition many times but I want to run the #code only once (the first time the counter == 10 and the session variable is 0).
EDIT: Checking the log, the session['info_released'] is changed to 1 when counter == 10, but in the next call the value is set back to 0: indeed, the #code is run many times until the counter gets incremented.
I can't understand what I am doing wrong. I may also have the program flow better organized, but I don't think it matters with the problem I am having.
EDIT: it seems that everything I do on the session variables inside the get_actual_demand() view function are only "local". I changed the code as follows, removing the session['info_released'] = 0 from the login() function:
#app.route('/get_actual_demand', methods=['GET', 'POST'])
def get_actual_demand():
# the variable session['info_released'] is no more
# defined in the login() function
if request.json['counter'] == 10:
try:
# The first time I get here, raise a KeyError exception
if session['info_released'] == 1:
return jsonify(released=0)
except KeyError:
# Use `session['info_released']` as a flag,
# defined here
session['info_released'] = 1
return jsonify(released=1)
else:
return jsonify(released=0)
Checking the log (removed from the code) I can see the session variable defined when it first hits the exception, but then hits again the exception as if the session variable is still not present.
I think there is something missing in my configuration, but I can't find hints in the documentation. My config.py is as follows:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
DEBUG = False
TESTING = False
CSRF_ENABLED = True
WTF_CSRF_ENABLED = True
SECRET_KEY = 'oqEr[]*woi+145##11!&$fsa%(Mn21eq'
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
class DevelopmentConfig(Config):
DEVELOPMENT = True
DEBUG = True
SQLALCHEMY_DATABASE_URI ='postgresql+psycopg2://libra:password#localhost/mydb'

I had the same problem and I solved it using Flask-Session extension which adds support for Server-side Session to your application.
Here is the URL:
http://pythonhosted.org/Flask-Session/
I added the next lines to my app:
from flask import Flask, session
from flask.ext.session import Session
app = Flask(__name__)
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
and that's all. No need secret keys.
Hope this helps.

Related

Testing a POST method unit test which inserts data to mongodb database

I want to know how am I supposed to test my code and see whether it works properly. I want to make sure that it stores the received data to the database. Can you please tell me how am I supposed to do that? While I was searching the forum I found this post but I did not really understand what is going on. here is the code I want to test.
client = MongoClient(os.environ.get("MONGODB_URI"))
app.db = client.securify
app.secret_key = str(os.environ.get("APP_SECRET"))
#app.route("/", methods=["GET", "POST"])
def home():
if request.method == "POST":
ip_address = request.remote_addr
entry_content = request.form.get("content")
formatted_date = datetime.datetime.today().strftime("%Y-%m-%d/%H:%M")
app.db.entries.insert({"content": entry_content, "date": formatted_date, "IP": ip_address})
return render_template("home.html")
and here is the mock test I wrote:
import os
from unittest import TestCase
from app import app
class AppTest(TestCase):
# executed prior to each test
def setUp(self):
# you can change your application configuration
app.config['TESTING'] = True
# you can recover a "test cient" of your defined application
self.app = app.test_client()
# then in your test method you can use self.app.[get, post, etc.] to make the request
def test_home(self):
url_path = '/'
response = self.app.get(url_path)
self.assertEqual(response.status_code, 200)
def test_post(self):
url_path = '/'
response = self.app.post(url_path,data={"content": "this is a test"})
self.assertEqual(response.status_code, 200)
The test_post gets stuck and after some seconds gives an error when reaches app.db.entries.insert({"content": entry_content, "date": formatted_date, "IP": ip_address}) part. Please tell me also how can I retrieve the saved data in order to make sure it is saved in the expected way
This is what I do using NodeJS, not tested at all in python but the idea is the same.
First of all, find a in-memory DB, there are options like pymongo-inmemory or mongomock
Then in your code you have to do the connection according to you environment (production/development/whatever)
Something like this:
env = os.environ.get("ENV")
if env == "TESTING":
# connect to mock db
elif env == "DEVELOMPENT":
# for example if you want to test against a real DB but not the production one
# then do the connection here
else:
# connect to production DB
I don't know if it is the proper way to do it but I found a solution. After creating a test client self.app = app.test_client() the db gets set to localhost:27017 so I changed it manually as follows and it worked:
self.app = app.test_client()
client = MongoClient(os.environ.get("MONGODB_URI"))

Testing Flask Sessions with Pytest

Currently I'm working on a Flask project and need to make some tests.
The test I'm struggling is about Flask Sessions.
I have this view:
#blue_blueprint.route('/dashboard')
"""Invoke dashboard view."""
if 'expires' in session:
if session['expires'] > time.time():
pass
else:
refresh_token()
pass
total_day = revenues_day()
total_month = revenues_month()
total_year = revenues_year()
total_stock_size = stock_size()
total_stock_value = stock_value()
mean_cost = total_stock_value/total_stock_size
return render_template('dashboard.html.j2', total_day=total_day, <br> total_month=total_month, total_year=total_year, total_stock_size=total_stock_size, total_stock_value=total_stock_value, mean_cost=mean_cost)
else:
return redirect(url_for('blue._authorization'))
And have this test:
def test_dashboard(client):
with client.session_transaction(subdomain='blue') as session:
session['expires'] = time.time() + 10000
response = client.get('/dashboard', subdomain='blue')
assert response.status_code == 200
My currently conftest.py is:
#pytest.fixture
def app():
app = create_app('config_testing.py')
yield app
#pytest.fixture
def client(app):
return app.test_client(allow_subdomain_redirects=True)
#pytest.fixture
def runner(app):
return app.test_cli_runner(allow_subdomain_redirects=True)
However, when I execute the test, I'm getting a 302 status code instead of the expected 200 status code.
So my question is how I can pass properly the session value?
OBS: Running normally the application the if statement for session is working properly.
I find the solution and I want to share with you the answer.
In the API documentation Test Client says:
When used in combination with a with statement this opens a session transaction. This can be used to modify the session that the test client uses. Once the with block is left the session is stored back.
We should put the assert after with statement not in, for this work, so the code should be:
def test_dashboard(client):
with client.session_transaction(subdomain='blue') as session:
session['expires'] = time.time() + 10000
response = client.get('/dashboard', subdomain='blue')
assert response.status_code == 200
This simple indent solves my problem.

How do I separate sessions between app users in Twilio using Flask sessions?

During testing of my app with ngrok, two of my users texted the Twilio number at the same time and they some how landed in the same session so any counters I was using got messed up for their own respective user experiences. How can I ensure that each user texting the number to use the app will have their own separate experience? Is the trick to somehow create a dynamic SECRET_KEY in Flask session?
Some code below
from flask import Flask, request, session
from twilio.twiml.messaging_response import MessagingResponse
SECRET_KEY = 'a secret key'
app = Flask(__name__)
app.config.from_object(__name__)
#app.route("/sms", methods=['GET','POST'])
def sms_logic():
try:
# Increment the counter
counter = session.get('counter',0)
# Initiate conversation + Save the new counter value in the session
body = request.values.get('Body', None)
counter += 1
session['counter'] = counter
# start our TwiML response
resp = MessagingResponse()
if counter == 1 and body.lower() == 'target_string':
resp.message('response 1')
elif counter == 1 and body.lower() != 'target_string':
resp.message('Unknown entry. Please try again.')
session.clear()
else:
resp.message('response 2 ')
session.clear()
#print(counter)
return(str(resp))
except Exception as e:
pass
if __name__ == "__main__":
app.run(debug=True)
I am clearing the session to reset the counter instead of waiting 4 hours for the session to expire especially if the user would like to go through the app again to make another entry.
Thanks in advance!

seems like web.py sessions are in app rather than on client

So the code below is more or less taken from http://webpy.org/cookbook/session
If I run the app it works as it should i.e. counter increments by one upon each refresh, however if I access the app in an incognito window or other web browser, the counter does not reset. To me it seems like the session doesn't initialize with count: 0 as it should. What is it that causes the new session to take the values of session in other client?
import web
web.config.debug = False
urls = (
"/", "count",
"/reset", "reset"
)
app = web.application(urls, locals())
session = web.session.Session(app, web.session.DiskStore('sessions'),
{'count': 0})
session_data = session._initializer
class count:
def GET(self):
session_data['count'] += 1
return str(session_data['count'])
class reset:
def GET(self):
session.kill()
return ""
if __name__ == "__main__":
app.run()
Sessions should be stored on the client but when I execute this code it seems like it is on the server, which would imply that only one user can use the app and I have to rerun the app to reset the counter.
I haven't been able to solve this for almost a week now. Pleeease help.
The example has sessions being created from the initial session variable. For example, session.count += 1 would add 1 to the current session's count. In your code you change session_data for each user. The way the documentation demonstrates creating a session variable with an initializer is:
session = web.session.Session(app, web.session.DiskStore('sessions'), initializer={'count': 0})
So, instead of doing session_data['count'] += 1, the documentation recommends doing session['count'] += 1 or session.count += 1. You would also need to update the return line in your Index.
I tested and confirmed that this works for me.

Django - request.session not being saved

I have a pretty simply utility function that gets an open web order if their is a session key called 'orderId', and will create one if there is no session key, and the parameter 'createIfNotFound' is equal to true in the function. Stepping through it with my debugger I can see that the piece of code that sets the session key after an order has been created does get hit with no exceptions, but when I check the Http request object' session field, it does not have that attribute ?
Utility
def get_open_web_order(request, createIfNotFound=False):
# Check for orderId in session
order_id = request.session.get('orderId')
web_order = None
if None != order_id:
try:
web_order = WebOrder.objects.get(id=order_id, status='O')
logging.info('Found open web order')
except WebOrder.DoesNotExist:
logging.info('Web order not found')
if (None == web_order) and (createIfNotFound == True):
logging.info('Creating new web order')
web_order = WebOrder()
web_order.status = 'O'
web_order.save()
request.session['orderId'] = web_order.id
# Assign logged in user and default billing and shipping
if request.user.is_authenticated() and hasattr(request.user, 'customer'):
customer = request.user.customer
web_order.customer = customer
web_order.set_defaults_from_customer()
web_order.save()
return web_order
In some cases you need to explicitly tell the session that it has been modified.
You can do this by adding request.session.modified = True to your view, after changing something in session
You can read more on this here - https://docs.djangoproject.com/en/1.10/topics/http/sessions/#when-sessions-are-saved
I had a similar issue, turns out I had set SESSION_COOKIE_DOMAIN in settings.py to the incorrect domain so it would not save any of my new session data. If you are using SESSION_COOKIE_DOMAIN, try checking that!
For example, if I am running the server on my localhost but I have in my settings SESSION_COOKIE_DOMAIN = "notlocalhost", then nothing I change in request.session will save.

Categories

Resources