co6co.web-session 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.2
2
+ Name: co6co.web_session
3
+ Version: 0.0.1
4
+ Summary: web session 扩展
5
+ Home-page: http://github.com/co6co
6
+ Author: co6co
7
+ Author-email: co6co@qq.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.6
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: co6co
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: classifier
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: home-page
18
+ Dynamic: requires-dist
19
+ Dynamic: summary
20
+
21
+ # web session header
22
+
23
+ ```
24
+ 0.0.1 未经严谨测试
25
+ ```
@@ -0,0 +1,5 @@
1
+ # web session header
2
+
3
+ ```
4
+ 0.0.1 未经严谨测试
5
+ ```
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.2
2
+ Name: co6co.web_session
3
+ Version: 0.0.1
4
+ Summary: web session 扩展
5
+ Home-page: http://github.com/co6co
6
+ Author: co6co
7
+ Author-email: co6co@qq.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.6
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: co6co
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: classifier
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: home-page
18
+ Dynamic: requires-dist
19
+ Dynamic: summary
20
+
21
+ # web session header
22
+
23
+ ```
24
+ 0.0.1 未经严谨测试
25
+ ```
@@ -0,0 +1,18 @@
1
+ README.md
2
+ setup.py
3
+ co6co.web_session.egg-info/PKG-INFO
4
+ co6co.web_session.egg-info/SOURCES.txt
5
+ co6co.web_session.egg-info/dependency_links.txt
6
+ co6co.web_session.egg-info/requires.txt
7
+ co6co.web_session.egg-info/top_level.txt
8
+ co6co.web_session.egg-info/zip-safe
9
+ co6co_web_session/__init__.py
10
+ co6co_web_session/aioredis.py
11
+ co6co_web_session/base.py
12
+ co6co_web_session/memcache.py
13
+ co6co_web_session/memory.py
14
+ co6co_web_session/mongodb.py
15
+ co6co_web_session/redis.py
16
+ co6co_web_session/session.py
17
+ co6co_web_session/utils.py
18
+ co6co_web_session/versions.py
@@ -0,0 +1 @@
1
+ co6co_web_session
@@ -0,0 +1,17 @@
1
+ from .memcache import MemcacheSessionImp
2
+ from .redis import RedisSessionImp
3
+ from .memory import MemorySessionImp
4
+ from .mongodb import MongoDBSessionImp
5
+ from .aioredis import AIORedisSessionImp
6
+ from .session import Session
7
+ from .base import IBaseSession
8
+
9
+ __all__ = (
10
+ "IBaseSession",
11
+ "Session",
12
+ "MemcacheSessionImp",
13
+ "RedisSessionImp",
14
+ "MemorySessionImp",
15
+ "MongoDBSessionImp",
16
+ "AIORedisSessionImp",
17
+ )
@@ -0,0 +1,77 @@
1
+ from .base import IBaseSession
2
+
3
+ try:
4
+ import aioredis
5
+ except ImportError:
6
+ aioredis = None
7
+
8
+
9
+ class AIORedisSessionImp(IBaseSession):
10
+ def __init__(
11
+ self,
12
+ redis,
13
+ expiry: int = 2592000,
14
+ head_name: str = "session",
15
+ prefix: str = "session:",
16
+ samesite: str = None,
17
+ session_name: str = "Session",
18
+ secure: bool = False,
19
+ ):
20
+ """Initializes a session interface backed by Redis.
21
+
22
+ Args:
23
+ redis (Callable):
24
+ aioredis connection or connection pool instance.
25
+ domain (str, optional):
26
+ Optional domain which will be attached to the cookie.
27
+ expiry (int, optional):
28
+ Seconds until the session should expire.
29
+ httponly (bool, optional):
30
+ Adds the `httponly` flag to the session cookie.
31
+ cookie_name (str, optional):
32
+ Name used for the client cookie.
33
+ prefix (str, optional):
34
+ Memcache keys will take the format of `prefix+session_id`;
35
+ specify the prefix here.
36
+ sessioncookie (bool, optional):
37
+ Specifies if the sent cookie should be a 'session cookie', i.e
38
+ no Expires or Max-age headers are included. Expiry is still
39
+ fully tracked on the server side. Default setting is False.
40
+ samesite (str, optional):
41
+ Will prevent the cookie from being sent by the browser to the target
42
+ site in all cross-site browsing context, even when following a regular link.
43
+ One of ('lax', 'strict')
44
+ Default: None
45
+ session_name (str, optional):
46
+ Name of the session that will be accessible through the request.
47
+ e.g. If ``session_name`` is ``alt_session``, it should be
48
+ accessed like that: ``request.ctx.alt_session``
49
+ e.g. And if ``session_name`` is left to default, it should be
50
+ accessed like that: ``request.ctx.session``
51
+ Default: 'session'
52
+ secure (bool, optional):
53
+ Adds the `Secure` flag to the session cookie.
54
+ """
55
+ if aioredis is None:
56
+ raise RuntimeError("Please install aioredis: pip install sanic_session[aioredis]")
57
+
58
+ self.redis = redis
59
+
60
+ super().__init__(
61
+ expiry=expiry,
62
+ prefix=prefix,
63
+ head_name=head_name,
64
+
65
+ samesite=samesite,
66
+ session_name=session_name,
67
+ secure=secure,
68
+ )
69
+
70
+ async def _get_value(self, prefix, sid):
71
+ return await self.redis.get(self.prefix + sid)
72
+
73
+ async def _delete_key(self, key):
74
+ await self.redis.delete(key)
75
+
76
+ async def _set_value(self, key, data):
77
+ await self.redis.setex(key, self.expiry, data)
@@ -0,0 +1,143 @@
1
+ import time
2
+ import datetime
3
+ import abc
4
+ import uuid
5
+ from co6co.utils import log
6
+ from co6co.storage.Dict import CallbackDict
7
+ try:
8
+ import ujson
9
+ except ImportError:
10
+ import json as ujson
11
+
12
+
13
+ def get_request_container(request):
14
+ """
15
+ 用于获取请求的容器对象
16
+ """
17
+ return request.ctx.__dict__ if hasattr(request, "ctx") else request
18
+
19
+
20
+ class SessionDict(CallbackDict):
21
+ def __init__(self, initial=None, sid=None):
22
+ def on_update(self):
23
+ self.modified = True
24
+
25
+ super().__init__(initial, on_update)
26
+
27
+ self.sid = sid
28
+ self.modified = False
29
+
30
+
31
+ class IBaseSession(metaclass=abc.ABCMeta):
32
+ # this flag show does this Interface need request/response middleware hooks
33
+
34
+ def __init__(
35
+ # 会话的过期时间,单位为秒
36
+ self, expiry: int,
37
+ # 存储会话数据时使用的键前缀
38
+ prefix: str,
39
+ # 头部名称,可能用于自定义请求头或响应头
40
+ head_name: str,
41
+ # 用于设置 Cookie 的 SameSite 属性
42
+ samesite,
43
+ # 会话对象在请求容器中的名称
44
+ session_name,
45
+ # 是否使用安全的 Cookie(仅通过 HTTPS 传输)
46
+ secure,
47
+ ):
48
+
49
+ self.expiry = expiry
50
+ self.prefix = prefix
51
+ self.head_name = head_name
52
+ self.samesite = samesite
53
+ self.session_name = session_name
54
+ self.secure = secure
55
+
56
+ @staticmethod
57
+ def _calculate_expires(expiry):
58
+ expires = time.time() + expiry
59
+ return datetime.datetime.fromtimestamp(expires)
60
+
61
+ @abc.abstractmethod
62
+ async def _get_value(self, prefix: str, sid: str):
63
+ """
64
+ Get value from datastore. Specific implementation for each datastore.
65
+
66
+ Args:
67
+ prefix:
68
+ A prefix for the key, useful to namespace keys.
69
+ sid:
70
+ a uuid in hex string
71
+ """
72
+ raise NotImplementedError
73
+
74
+ @abc.abstractmethod
75
+ async def _delete_key(self, key: str):
76
+ """Delete key from datastore"""
77
+ raise NotImplementedError
78
+
79
+ @abc.abstractmethod
80
+ async def _set_value(self, key: str, data: SessionDict):
81
+ """Set value for datastore"""
82
+ raise NotImplementedError
83
+
84
+ def getSid(self, request):
85
+ sid = request.headers.get(self.head_name)
86
+ return sid
87
+
88
+ async def open(self, request) -> SessionDict:
89
+ """
90
+ Opens a session onto the request. Restores the client's session
91
+ from the datastore if one exists.The session data will be available on
92
+ `request.session`.
93
+ Args:
94
+ request (sanic.request.Request):
95
+ The request, which a sessionwill be opened onto.
96
+
97
+ Returns:
98
+ SessionDict:
99
+ the client's session data,
100
+ attached as well to `request.session`.
101
+ """
102
+
103
+ sid = self. getSid(request)
104
+ if not sid:
105
+ sid = uuid.uuid4().hex
106
+ session_dict = SessionDict(sid=sid)
107
+ else:
108
+ val = await self._get_value(self.prefix, sid)
109
+
110
+ if val is not None:
111
+ data = ujson.loads(val)
112
+ session_dict = SessionDict(data, sid=sid)
113
+ else:
114
+ session_dict = SessionDict(sid=sid)
115
+
116
+ # attach the session data to the request, return it for convenience
117
+ req = get_request_container(request)
118
+ req[self.session_name] = session_dict
119
+ return session_dict
120
+
121
+ async def save(self, request, response) -> None:
122
+ """Saves the session to the datastore.
123
+
124
+ Args:
125
+ request (sanic.request.Request):
126
+ The sanic request which has an attached session.
127
+ response (sanic.response.Response):
128
+ The Sanic response. Cookies with the appropriate expiration
129
+ will be added onto this response.
130
+
131
+ Returns:
132
+ None
133
+ """
134
+ req = get_request_container(request)
135
+ if self.session_name not in req:
136
+ return
137
+
138
+ key = self.prefix + req[self.session_name].sid
139
+ if not req[self.session_name]:
140
+ await self._delete_key(key)
141
+
142
+ val = ujson.dumps(dict(req[self.session_name]))
143
+ await self._set_value(key, val)
@@ -0,0 +1,92 @@
1
+ import warnings
2
+
3
+ from .base import IBaseSession
4
+
5
+ try:
6
+ import aiomcache
7
+ except ImportError: # pragma: no cover
8
+ aiomcache = None
9
+
10
+
11
+ class MemcacheSessionImp(IBaseSession):
12
+ def __init__(
13
+ self,
14
+ memcache_connection,
15
+ domain: str = None,
16
+ expiry: int = 2592000,
17
+ httponly: bool = True,
18
+ cookie_name: str = "session",
19
+ prefix: str = "session:",
20
+ sessioncookie: bool = False,
21
+ samesite: str = None,
22
+ session_name: str = "Session",
23
+ secure: bool = False,
24
+ ):
25
+ """Initializes the interface for storing client sessions in memcache.
26
+ Requires a client object establised with `asyncio_memcache`.
27
+
28
+ Args:
29
+ memcache_connection (aiomccache.Client):
30
+ The memcache client used for interfacing with memcache.
31
+ domain (str, optional):
32
+ Optional domain which will be attached to the cookie.
33
+ expiry (int, optional):
34
+ Seconds until the session should expire.
35
+ httponly (bool, optional):
36
+ Adds the `httponly` flag to the session cookie.
37
+ cookie_name (str, optional):
38
+ Name used for the client cookie.
39
+ prefix (str, optional):
40
+ Memcache keys will take the format of `prefix+session_id`;
41
+ specify the prefix here.
42
+ sessioncookie (bool, optional):
43
+ Specifies if the sent cookie should be a 'session cookie', i.e
44
+ no Expires or Max-age headers are included. Expiry is still
45
+ fully tracked on the server side. Default setting is False.
46
+ samesite (str, optional):
47
+ Will prevent the cookie from being sent by the browser to
48
+ the target site in all cross-site browsing context, even when
49
+ following a regular link. One of ('lax', 'strict')
50
+ Default: None
51
+ session_name (str, optional):
52
+ Name of the session that will be accessible through the
53
+ request.
54
+ e.g. If ``session_name`` is ``alt_session``, it should be
55
+ accessed like that: ``request.ctx.alt_session``
56
+ e.g. And if ``session_name`` is left to default, it should be
57
+ accessed like that: ``request.ctx.session``
58
+ Default: 'session'
59
+ secure (bool, optional):
60
+ Adds the `Secure` flag to the session cookie.
61
+ """
62
+ if aiomcache is None:
63
+ raise RuntimeError("Please install aiomcache: pip install " "sanic_session[aiomcache]")
64
+
65
+ self.memcache_connection = memcache_connection
66
+
67
+ if expiry > 2592000:
68
+ warnings.warn("Memcache has a maximum 30-day cache limit")
69
+ expiry = 0
70
+
71
+ super().__init__(
72
+ expiry=expiry,
73
+ prefix=prefix,
74
+ cookie_name=cookie_name,
75
+ domain=domain,
76
+ httponly=httponly,
77
+ sessioncookie=sessioncookie,
78
+ samesite=samesite,
79
+ session_name=session_name,
80
+ secure=secure,
81
+ )
82
+
83
+ async def _get_value(self, prefix, sid):
84
+ key = (self.prefix + sid).encode()
85
+ value = await self.memcache_connection.get(key)
86
+ return value.decode() if value else None
87
+
88
+ async def _delete_key(self, key):
89
+ return await self.memcache_connection.delete(key.encode())
90
+
91
+ async def _set_value(self, key, data):
92
+ return await self.memcache_connection.set(key.encode(), data.encode(), exptime=self.expiry)
@@ -0,0 +1,34 @@
1
+ from .base import IBaseSession
2
+ from co6co.storage.Dict import ExpiringDict
3
+
4
+
5
+ class MemorySessionImp(IBaseSession):
6
+ def __init__(
7
+ self,
8
+ expiry: int = 2592000,
9
+ head_name: str = "session",
10
+ prefix: str = "session:",
11
+ samesite: str = None,
12
+ session_name="Session",
13
+ secure: bool = False,
14
+ ):
15
+
16
+ super().__init__(
17
+ expiry=expiry,
18
+ prefix=prefix,
19
+ head_name=head_name,
20
+ samesite=samesite,
21
+ session_name=session_name,
22
+ secure=secure,
23
+ )
24
+ self.session_store = ExpiringDict()
25
+
26
+ async def _get_value(self, prefix, sid):
27
+ return self.session_store.get(self.prefix + sid)
28
+
29
+ async def _delete_key(self, key):
30
+ if key in self.session_store:
31
+ self.session_store.delete(key)
32
+
33
+ async def _set_value(self, key, data):
34
+ self.session_store.set(key, data, self.expiry)
@@ -0,0 +1,129 @@
1
+ from datetime import datetime, timedelta
2
+ import warnings
3
+ from .base import IBaseSession
4
+
5
+ try:
6
+ from sanic_motor import BaseModel
7
+
8
+ class _SessionModel(BaseModel):
9
+ """Collection for session storing.
10
+
11
+ Collection name (default session)
12
+
13
+ Fields:
14
+ sid
15
+ expiry
16
+ data:
17
+ User's session data
18
+ """
19
+
20
+ pass
21
+
22
+
23
+ except ImportError: # pragma: no cover
24
+ _SessionModel = None
25
+
26
+
27
+ class MongoDBSessionImp(IBaseSession):
28
+ def __init__(
29
+ self,
30
+ app,
31
+ coll: str = "session",
32
+ domain: str = None,
33
+ expiry: int = 30 * 24 * 60 * 60,
34
+ httponly: bool = True,
35
+ hand_name: str = "session",
36
+ sessioncookie: bool = False,
37
+ samesite: str = None,
38
+ session_name: str = "Session",
39
+ secure: bool = False,
40
+ ):
41
+ """Initializes the interface for storing client sessions in MongoDB.
42
+
43
+ Args:
44
+ app (sanic.Sanic):
45
+ Sanic instance to register listener('after_server_start')
46
+ coll (str, optional):
47
+ MongoDB collection name for session
48
+ domain (str, optional):
49
+ Optional domain which will be attached to the cookie.
50
+ expiry (int, optional):
51
+ Seconds until the session should expire.
52
+ httponly (bool, optional):
53
+ Adds the `httponly` flag to the session cookie.
54
+ cookie_name (str, optional):
55
+ Name used for the client cookie.
56
+ sessioncookie (bool, optional):
57
+ Specifies if the sent cookie should be a 'session cookie', i.e
58
+ no Expires or Max-age headers are included. Expiry is still
59
+ fully tracked on the server side. Default setting is False.
60
+ samesite (str, optional):
61
+ Will prevent the cookie from being sent by the browser to
62
+ the target site in all cross-site browsing context, even when
63
+ following a regular link.
64
+ One of ('lax', 'strict')
65
+ Default: None
66
+ session_name (str, optional):
67
+ Name of the session that will be accessible through the
68
+ request.
69
+ e.g. If ``session_name`` is ``alt_session``, it should be
70
+ accessed like that: ``request.ctx.alt_session``
71
+ e.g. And if ``session_name`` is left to default, it should be
72
+ accessed like that: ``request.ctx.session``
73
+ Default: 'session'
74
+ secure (bool, optional):
75
+ Adds the `Secure` flag to the session cookie.
76
+ """
77
+ if _SessionModel is None:
78
+ raise RuntimeError("Please install Mongo dependencies: " "pip install sanic_session[mongo]")
79
+
80
+ # prefix not needed for mongodb as mongodb uses uuid4 natively
81
+ prefix = ""
82
+
83
+ if httponly is not True:
84
+ warnings.warn(
85
+ """
86
+ httponly default arg has changed.
87
+ To spare you some debugging time, httponly is currently
88
+ hardcoded as True. This message will be removed with the
89
+ next release. And ``httponly`` will no longer be hardcoded
90
+ """,
91
+ DeprecationWarning,
92
+ )
93
+
94
+ super().__init__(
95
+ expiry=expiry,
96
+ prefix=prefix,
97
+ hand_name=hand_name,
98
+ samesite=samesite,
99
+ session_name=session_name,
100
+ secure=secure,
101
+ )
102
+
103
+ # set collection name
104
+ _SessionModel.__coll__ = coll
105
+
106
+ @app.listener("after_server_start")
107
+ async def apply_session_indexes(app, loop):
108
+ """Create indexes in session collection
109
+ if doesn't exist.
110
+
111
+ Indexes:
112
+ sid:
113
+ For faster lookup.
114
+ expiry:
115
+ For document expiration.
116
+ """
117
+ await _SessionModel.create_index("sid")
118
+ await _SessionModel.create_index("expiry", expireAfterSeconds=0)
119
+
120
+ async def _get_value(self, prefix, key):
121
+ value = await _SessionModel.find_one({"sid": key}, as_raw=True)
122
+ return value["data"] if value else None
123
+
124
+ async def _delete_key(self, key):
125
+ await _SessionModel.delete_one({"sid": key})
126
+
127
+ async def _set_value(self, key, data):
128
+ expiry = datetime.utcnow() + timedelta(seconds=self.expiry)
129
+ await _SessionModel.replace_one({"sid": key}, {"sid": key, "expiry": expiry, "data": data}, upsert=True)
@@ -0,0 +1,86 @@
1
+ from typing import Callable
2
+ from co6co_web_session.base import IBaseSession
3
+
4
+ try:
5
+ import asyncio_redis
6
+ except ImportError:
7
+ asyncio_redis = None
8
+
9
+
10
+ class RedisSessionImp(IBaseSession):
11
+ def __init__(
12
+ self,
13
+ redis_getter: Callable,
14
+ domain: str = None,
15
+ expiry: int = 2592000,
16
+ httponly: bool = True,
17
+ head_anme: str = "session",
18
+ prefix: str = "session:",
19
+ sessioncookie: bool = False,
20
+ samesite: str = None,
21
+ session_name: str = "Session",
22
+ secure: bool = False,
23
+ ):
24
+ """Initializes a session interface backed by Redis.
25
+
26
+ Args:
27
+ redis_getter (Callable):
28
+ Coroutine which should return an asyncio_redis connection pool
29
+ (suggested) or an asyncio_redis Redis connection.
30
+ domain (str, optional):
31
+ Optional domain which will be attached to the cookie.
32
+ expiry (int, optional):
33
+ Seconds until the session should expire.
34
+ httponly (bool, optional):
35
+ Adds the `httponly` flag to the session cookie.
36
+ cookie_name (str, optional):
37
+ Name used for the client cookie.
38
+ prefix (str, optional):
39
+ Memcache keys will take the format of `prefix+session_id`;
40
+ specify the prefix here.
41
+ sessioncookie (bool, optional):
42
+ Specifies if the sent cookie should be a 'session cookie', i.e
43
+ no Expires or Max-age headers are included. Expiry is still
44
+ fully tracked on the server side. Default setting is False.
45
+ samesite (str, optional):
46
+ Will prevent the cookie from being sent by the browser to the
47
+ target site in all cross-site browsing context, even when
48
+ following a regular link.
49
+ One of ('lax', 'strict')
50
+ Default: None
51
+ session_name (str, optional):
52
+ Name of the session that will be accessible through the
53
+ request.
54
+ e.g. If ``session_name`` is ``alt_session``, it should be
55
+ accessed like that: ``request.ctx.alt_session``
56
+ e.g. And if ``session_name`` is left to default, it should be
57
+ accessed like that: ``request.ctx.session``
58
+ Default: 'session'
59
+ secure (bool, optional):
60
+ Adds the `Secure` flag to the session cookie.
61
+ """
62
+ if asyncio_redis is None:
63
+ raise RuntimeError("Please install asyncio_redis: pip install sanic_session[redis]")
64
+
65
+ self.redis_getter = redis_getter
66
+
67
+ super().__init__(
68
+ expiry=expiry,
69
+ prefix=prefix,
70
+ head_anme=head_anme,
71
+ samesite=samesite,
72
+ session_name=session_name,
73
+ secure=secure,
74
+ )
75
+
76
+ async def _get_value(self, prefix, key):
77
+ redis_connection = await self.redis_getter()
78
+ return await redis_connection.get(prefix + key)
79
+
80
+ async def _delete_key(self, key):
81
+ redis_connection = await self.redis_getter()
82
+ await redis_connection.delete([key])
83
+
84
+ async def _set_value(self, key, data):
85
+ redis_connection = await self.redis_getter()
86
+ await redis_connection.setex(key, self.expiry, data)
@@ -0,0 +1,41 @@
1
+
2
+ from .memory import MemorySessionImp
3
+ from .base import IBaseSession
4
+
5
+
6
+ class Session:
7
+
8
+ def __init__(self, app=None, interface: IBaseSession = None):
9
+ self.interface = None
10
+ if app:
11
+ self.init_app(app, interface)
12
+
13
+ @property
14
+ def expiry(self):
15
+ """
16
+ session 过期时间
17
+ """
18
+ return self.interface.expiry if self.interface else None
19
+
20
+ def init_app(self, app, interface: IBaseSession):
21
+ self.interface = interface or MemorySessionImp()
22
+ if not hasattr(app.ctx, "extensions"):
23
+ app.ctx.extensions = {}
24
+
25
+ app.ctx.extensions[self.interface.session_name] = self # session_name defaults to 'session'
26
+
27
+ # @app.middleware('request')
28
+ async def add_session_to_request(request):
29
+ """Before each request initialize a session
30
+ using the client's request."""
31
+ await self.interface.open(request)
32
+
33
+ # @app.middleware('response')
34
+ async def save_session(request, response):
35
+ """After each request save the session, pass
36
+ the response to set client cookies.
37
+ """
38
+ await self.interface.save(request, response)
39
+
40
+ app.request_middleware.appendleft(add_session_to_request)
41
+ app.response_middleware.append(save_session)
@@ -0,0 +1,17 @@
1
+ import datetime
2
+ from .base import get_request_container
3
+
4
+ # 只做一些备份 没作用
5
+
6
+
7
+ def _delete_cookie(self, request, response):
8
+ req = get_request_container(request)
9
+ response.cookies[self.cookie_name] = req[self.session_name].sid
10
+
11
+ # We set expires/max-age even for session cookies to force expiration
12
+ response.cookies[self.cookie_name]["expires"] = datetime.datetime.utcnow()
13
+ response.cookies[self.cookie_name]["max-age"] = 0
14
+
15
+
16
+ def getSid(self, request):
17
+ return request.cookies.get(self.cookie_name)
@@ -0,0 +1,2 @@
1
+ __version_info = (0, 0, 1)
2
+ __version__ = ".".join([str(x) for x in __version_info])
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,51 @@
1
+ from os import path
2
+ from setuptools import setup, find_packages
3
+
4
+
5
+ packages = find_packages()
6
+ packageName = packages[0]
7
+
8
+
9
+ def get_version():
10
+ package_dir = path.abspath(path.dirname(__file__))
11
+ version_file = path.join(package_dir, packageName, 'versions.py')
12
+ with open(version_file, "rb") as f:
13
+ source_code = f.read()
14
+ exec_code = compile(source_code, version_file, "exec")
15
+ scope = {}
16
+ exec(exec_code, scope)
17
+ version = scope.get("__version__", None)
18
+ if version:
19
+ return version
20
+ raise RuntimeError("Unable to find version string.")
21
+
22
+
23
+ # read readmeFile contents
24
+ currentDir = path.abspath(path.dirname(__file__))
25
+ with open(path.join(currentDir, 'README.md'), encoding='utf-8') as f:
26
+ long_description = f.read()
27
+
28
+ setup(
29
+ name=packageName.replace('_', '.', 1),
30
+ version=get_version(),
31
+ description="web session 扩展",
32
+ packages=packages,
33
+ long_description=long_description,
34
+ long_description_content_type='text/markdown',
35
+ classifiers=["Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6"],
36
+ include_package_data=True, zip_safe=True,
37
+ # 依赖哪些模块
38
+ install_requires=["co6co"],
39
+ # package_dir= {'utils':'src/log','main_package':'main'},#告诉Distutils哪些目录下的文件被映射到哪个源码
40
+ author='co6co',
41
+ author_email='co6co@qq.com',
42
+ url="http://github.com/co6co",
43
+ data_file={
44
+ ('', "*.txt"),
45
+ ('', "*.md"),
46
+ },
47
+ package_data={
48
+ '': ['*.txt', '*.md'],
49
+ 'bandwidth_reporter': ['*.txt']
50
+ }
51
+ )