Skip to content

Commit

Permalink
Add ruff linter
Browse files Browse the repository at this point in the history
  • Loading branch information
Lxstr committed Jan 10, 2024
1 parent f07e28f commit 3ccb16a
Show file tree
Hide file tree
Showing 12 changed files with 226 additions and 149 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/ruff.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: Ruff
on: [push, pull_request]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: chartboost/ruff-action@v1
25 changes: 17 additions & 8 deletions examples/hello.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,32 @@
from flask_session import Session


SESSION_TYPE = 'redis'


app = Flask(__name__)
app.config.from_object(__name__)
app.config.update(
{
"SESSION_TYPE": "sqlalchemy",
"SQLALCHEMY_DATABASE_URI": "sqlite:////tmp/test.db",
"SQLALCHEMY_USE_SIGNER": True,
}
)
Session(app)


@app.route('/set/')
@app.route("/set/")
def set():
session['key'] = 'value'
return 'ok'
session["key"] = "value"
return "ok"


@app.route('/get/')
@app.route("/get/")
def get():
return session.get('key', 'not set')
import time

start_time = time.time()
result = session.get("key", "not set")
print("get", (time.time() - start_time) * 1000)
return result


if __name__ == "__main__":
Expand Down
3 changes: 3 additions & 0 deletions requirements/pytest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
flask>=2.2
cachelib

# Linting
ruff

# Testing
pytest
pytest-cov
Expand Down
113 changes: 72 additions & 41 deletions src/flask_session/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import os

from .sessions import NullSessionInterface, RedisSessionInterface, \
MemcachedSessionInterface, FileSystemSessionInterface, \
MongoDBSessionInterface, SqlAlchemySessionInterface
from .sessions import (
NullSessionInterface,
RedisSessionInterface,
MemcachedSessionInterface,
FileSystemSessionInterface,
MongoDBSessionInterface,
SqlAlchemySessionInterface,
)

__version__ = '0.5.1'
__version__ = "0.5.1"


class Session(object):
Expand Down Expand Up @@ -51,48 +56,74 @@ def init_app(self, app):

def _get_interface(self, app):
config = app.config.copy()
config.setdefault('SESSION_TYPE', 'null')
config.setdefault('SESSION_PERMANENT', True)
config.setdefault('SESSION_USE_SIGNER', False)
config.setdefault('SESSION_KEY_PREFIX', 'session:')
config.setdefault('SESSION_ID_LENGTH', 32)
config.setdefault('SESSION_REDIS', None)
config.setdefault('SESSION_MEMCACHED', None)
config.setdefault('SESSION_FILE_DIR',
os.path.join(os.getcwd(), 'flask_session'))
config.setdefault('SESSION_FILE_THRESHOLD', 500)
config.setdefault('SESSION_FILE_MODE', 384)
config.setdefault('SESSION_MONGODB', None)
config.setdefault('SESSION_MONGODB_DB', 'flask_session')
config.setdefault('SESSION_MONGODB_COLLECT', 'sessions')
config.setdefault('SESSION_SQLALCHEMY', None)
config.setdefault('SESSION_SQLALCHEMY_TABLE', 'sessions')

if config['SESSION_TYPE'] == 'redis':
config.setdefault("SESSION_TYPE", "null")
config.setdefault("SESSION_PERMANENT", True)
config.setdefault("SESSION_USE_SIGNER", False)
config.setdefault("SESSION_KEY_PREFIX", "session:")
config.setdefault("SESSION_ID_LENGTH", 32)
config.setdefault("SESSION_REDIS", None)
config.setdefault("SESSION_MEMCACHED", None)

# Filesystem settings
config.setdefault(
"SESSION_FILE_DIR", os.path.join(os.getcwd(), "flask_session")
)
config.setdefault("SESSION_FILE_THRESHOLD", 500)
config.setdefault("SESSION_FILE_MODE", 384)

# MongoDB settings
config.setdefault("SESSION_MONGODB", None)
config.setdefault("SESSION_MONGODB_DB", "flask_session")
config.setdefault("SESSION_MONGODB_COLLECT", "sessions")
config.setdefault("SESSION_MONGODB_TZ_AWARE", False)

# SQLAlchemy settings
config.setdefault("SESSION_SQLALCHEMY", None)
config.setdefault("SESSION_SQLALCHEMY_TABLE", "sessions")
config.setdefault("SESSION_SQLALCHEMY_SEQUENCE", None)
config.setdefault("SESSION_SQLALCHEMY_SCHEMA", None)
config.setdefault("SESSION_SQLALCHEMY_BIND_KEY", None)

common_params = {
"key_prefix": config["SESSION_KEY_PREFIX"],
"use_signer": config["SESSION_USE_SIGNER"],
"permanent": config["SESSION_PERMANENT"],
"sid_length": config["SESSION_ID_LENGTH"],
}

if config["SESSION_TYPE"] == "redis":
session_interface = RedisSessionInterface(
config['SESSION_REDIS'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'memcached':
config["SESSION_REDIS"], **common_params
)
elif config["SESSION_TYPE"] == "memcached":
session_interface = MemcachedSessionInterface(
config['SESSION_MEMCACHED'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'filesystem':
config["SESSION_MEMCACHED"], **common_params
)
elif config["SESSION_TYPE"] == "filesystem":
session_interface = FileSystemSessionInterface(
config['SESSION_FILE_DIR'], config['SESSION_FILE_THRESHOLD'],
config['SESSION_FILE_MODE'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'mongodb':
config["SESSION_FILE_DIR"],
config["SESSION_FILE_THRESHOLD"],
config["SESSION_FILE_MODE"],
**common_params,
)
elif config["SESSION_TYPE"] == "mongodb":
session_interface = MongoDBSessionInterface(
config['SESSION_MONGODB'], config['SESSION_MONGODB_DB'],
config['SESSION_MONGODB_COLLECT'],
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'sqlalchemy':
config["SESSION_MONGODB"],
config["SESSION_MONGODB_DB"],
config["SESSION_MONGODB_COLLECT"],
config["SESSION_MONGODB_TZ_AWARE"],
**common_params,
)
elif config["SESSION_TYPE"] == "sqlalchemy":
session_interface = SqlAlchemySessionInterface(
app, config['SESSION_SQLALCHEMY'],
config['SESSION_SQLALCHEMY_TABLE'],
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
config['SESSION_PERMANENT'])
app,
config["SESSION_SQLALCHEMY"],
config["SESSION_SQLALCHEMY_TABLE"],
config["SESSION_SQLALCHEMY_SEQUENCE"],
config["SESSION_SQLALCHEMY_SCHEMA"],
config["SESSION_SQLALCHEMY_BIND_KEY"],
**common_params,
)
else:
session_interface = NullSessionInterface()

Expand Down
75 changes: 43 additions & 32 deletions src/flask_session/sessions.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import sys
import time
from abc import ABC
from datetime import datetime
import secrets

try:
import cPickle as pickle
except ImportError:
Expand All @@ -20,13 +20,14 @@ def total_seconds(td):

class ServerSideSession(CallbackDict, SessionMixin):
"""Baseclass for server-side based sessions."""

def __bool__(self) -> bool:
return bool(dict(self)) and self.keys() != {"_permanent"}

def __init__(self, initial=None, sid=None, permanent=None):
def on_update(self):
self.modified = True

CallbackDict.__init__(self, initial, on_update)
self.sid = sid
if permanent:
Expand Down Expand Up @@ -55,10 +56,9 @@ class SqlAlchemySession(ServerSideSession):


class SessionInterface(FlaskSessionInterface):

def _generate_sid(self, session_id_length):
return secrets.token_urlsafe(session_id_length)

def __get_signer(self, app):
if not hasattr(app, "secret_key") or not app.secret_key:
raise KeyError("SECRET_KEY must be set when SESSION_USE_SIGNER=True")
Expand All @@ -77,16 +77,14 @@ def _sign(self, app, sid):


class NullSessionInterface(SessionInterface):
"""Used to open a :class:`flask.sessions.NullSession` instance.
"""
"""Used to open a :class:`flask.sessions.NullSession` instance."""

def open_session(self, app, request):
return None


class ServerSideSessionInterface(SessionInterface, ABC):
"""Used to open a :class:`flask.sessions.ServerSideSessionInterface` instance.
"""
"""Used to open a :class:`flask.sessions.ServerSideSessionInterface` instance."""

def __init__(self, db, key_prefix, use_signer=False, permanent=True, sid_length=32):
self.db = db
Expand All @@ -97,7 +95,6 @@ def __init__(self, db, key_prefix, use_signer=False, permanent=True, sid_length=
self.has_same_site_capability = hasattr(self, "get_cookie_samesite")

def set_cookie_to_response(self, app, session, response, expires):

if self.use_signer:
session_id = self._sign(app, session.sid)
else:
Expand All @@ -111,10 +108,16 @@ def set_cookie_to_response(self, app, session, response, expires):
if self.has_same_site_capability:
samesite = self.get_cookie_samesite(app)

response.set_cookie(app.config["SESSION_COOKIE_NAME"], session_id,
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure,
samesite=samesite)
response.set_cookie(
app.config["SESSION_COOKIE_NAME"],
session_id,
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)

def open_session(self, app, request):
sid = request.cookies.get(app.config["SESSION_COOKIE_NAME"])
Expand Down Expand Up @@ -149,9 +152,7 @@ class RedisSessionInterface(ServerSideSessionInterface):
serializer = pickle
session_class = RedisSession

def __init__(
self, redis, key_prefix, use_signer, permanent, sid_length
):
def __init__(self, redis, key_prefix, use_signer, permanent, sid_length):
if redis is None:
from redis import Redis

Expand All @@ -161,7 +162,7 @@ def __init__(

def fetch_session_sid(self, sid):
if not isinstance(sid, str):
sid = sid.decode('utf-8', 'strict')
sid = sid.decode("utf-8", "strict")
val = self.redis.get(self.key_prefix + sid)
if val is not None:
try:
Expand All @@ -180,13 +181,18 @@ def save_session(self, app, session, response):
if not session:
if session.modified:
self.redis.delete(self.key_prefix + session.sid)
response.delete_cookie(app.config["SESSION_COOKIE_NAME"],
domain=domain, path=path)
response.delete_cookie(
app.config["SESSION_COOKIE_NAME"], domain=domain, path=path
)
return

expires = self.get_expiration_time(app, session)
val = self.serializer.dumps(dict(session))
self.redis.set(name=self.key_prefix + session.sid, value=val, ex=total_seconds(app.permanent_session_lifetime))
self.redis.set(
name=self.key_prefix + session.sid,
value=val,
ex=total_seconds(app.permanent_session_lifetime),
)

self.set_cookie_to_response(app, session, response, expires)

Expand All @@ -207,18 +213,16 @@ class MemcachedSessionInterface(ServerSideSessionInterface):
serializer = pickle
session_class = MemcachedSession

def __init__(
self, client, key_prefix, use_signer, permanent, sid_length
):
def __init__(self, client, key_prefix, use_signer, permanent, sid_length):
if client is None:
client = self._get_preferred_memcache_client()
if client is None:
raise RuntimeError('no memcache module found')
raise RuntimeError("no memcache module found")
self.client = client
super().__init__(client, key_prefix, use_signer, permanent, sid_length)

def _get_preferred_memcache_client(self):
servers = ['127.0.0.1:11211']
servers = ["127.0.0.1:11211"]
try:
import pylibmc
except ImportError:
Expand Down Expand Up @@ -249,7 +253,6 @@ def _get_memcache_timeout(self, timeout):
return timeout

def fetch_session_sid(self, sid):

full_session_key = self.key_prefix + sid
val = self.client.get(full_session_key)
if val is not None:
Expand All @@ -270,14 +273,18 @@ def save_session(self, app, session, response):
if not session:
if session.modified:
self.client.delete(full_session_key)
response.delete_cookie(app.config["SESSION_COOKIE_NAME"],
domain=domain, path=path)
response.delete_cookie(
app.config["SESSION_COOKIE_NAME"], domain=domain, path=path
)
return

expires = self.get_expiration_time(app, session)
val = self.serializer.dumps(dict(session), 0)
self.client.set(full_session_key, val, self._get_memcache_timeout(
total_seconds(app.permanent_session_lifetime)))
self.client.set(
full_session_key,
val,
self._get_memcache_timeout(total_seconds(app.permanent_session_lifetime)),
)

self.set_cookie_to_response(app, session, response, expires)

Expand Down Expand Up @@ -336,10 +343,14 @@ def save_session(self, app, session, response):

expires = self.get_expiration_time(app, session)
data = dict(session)
self.cache.set(self.key_prefix + session.sid, data,
total_seconds(app.permanent_session_lifetime))
self.cache.set(
self.key_prefix + session.sid,
data,
total_seconds(app.permanent_session_lifetime),
)
self.set_cookie_to_response(app, session, response, expires)


class MongoDBSessionInterface(ServerSideSessionInterface):
"""A Session interface that uses mongodb as backend.
Expand Down
Loading

0 comments on commit 3ccb16a

Please sign in to comment.