Skip to content

Commit 1a4e2c6

Browse files
authored
update to pyramid 2.0 (#6969)
* update to pyramid 2.0 sqlalchemy 1.4 optimisation * python 3.10 * randint -> sample for generating unique sequences * force mark `obj.randomNumber` as modified
1 parent 2cc1821 commit 1a4e2c6

18 files changed

+228
-278
lines changed

frameworks/Python/pyramid/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ review the [documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wi
88
Also note that there is additional information that's provided in
99
the [Python README](../).
1010

11-
[Pyramid](http://www.pylonsproject.org/) is a flexible Python 2/3 framework.
11+
[Pyramid](http://www.pylonsproject.org/) is a flexible Python 3 framework.
1212
This test uses [SQLAlchemy](http://www.sqlalchemy.org/) as its ORM, the default
1313
[Chameleon](http://www.pylonsproject.org/) for its templating, and
1414
[Gunicorn](https://github.com/benoitc/gunicorn) for the application server.
@@ -28,5 +28,5 @@ This test uses [SQLAlchemy](http://www.sqlalchemy.org/) as its ORM, the default
2828

2929
### Community
3030

31-
* `#pyramid` IRC Channel ([irc.freenode.net](https://freenode.net/))
31+
* `#pyramid` IRC Channel ([irc.libera.chat](https://libera.chat))
3232
* [Pyramid (pylons-discuss) Google Group](https://groups.google.com/forum/#!forum/pylons-discuss)

frameworks/Python/pyramid/benchmark_config.json

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,6 @@
2323
"display_name": "Pyramid",
2424
"notes": "",
2525
"versus": "wsgi"
26-
},
27-
"py2": {
28-
"json_url": "/json",
29-
"db_url": "/db",
30-
"query_url": "/queries?queries=",
31-
"fortune_url": "/fortunes",
32-
"update_url": "/updates?queries=",
33-
"plaintext_url": "/plaintext",
34-
"port": 8080,
35-
"approach": "Realistic",
36-
"classification": "Fullstack",
37-
"database": "Postgres",
38-
"framework": "pyramid",
39-
"language": "Python",
40-
"flavor": "Python2",
41-
"orm": "Full",
42-
"platform": "None",
43-
"webserver": "Meinheld",
44-
"os": "Linux",
45-
"database_os": "Linux",
46-
"display_name": "Pyramid",
47-
"notes": "",
48-
"versus": "wsgi"
4926
}
5027
}]
5128
}

frameworks/Python/pyramid/config.toml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,3 @@ orm = "Full"
1717
platform = "None"
1818
webserver = "Meinheld"
1919
versus = "wsgi"
20-
21-
[py2]
22-
urls.plaintext = "/plaintext"
23-
urls.json = "/json"
24-
urls.db = "/db"
25-
urls.query = "/queries?queries="
26-
urls.update = "/updates?queries="
27-
urls.fortune = "/fortunes"
28-
approach = "Realistic"
29-
classification = "Fullstack"
30-
database = "Postgres"
31-
database_os = "Linux"
32-
os = "Linux"
33-
orm = "Full"
34-
platform = "None"
35-
webserver = "Meinheld"
36-
versus = "wsgi"

frameworks/Python/pyramid/create_database.py

Lines changed: 0 additions & 18 deletions
This file was deleted.

frameworks/Python/pyramid/development.ini

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@ pyramid.debug_authorization = false
1111
pyramid.debug_notfound = false
1212
pyramid.debug_routematch = false
1313
pyramid.default_locale_name = en
14+
pyramid.includes = pyramid_debugtoolbar
15+
debugtoolbar.active_panels = performance
16+
sqlalchemy.url = postgresql:///frameworkbenchmarks
1417

1518
###
1619
# wsgi server configuration
1720
###
1821

1922
[server:main]
20-
use = egg:gunicorn#main
23+
use = egg:waitress#main
2124
host = 0.0.0.0
22-
port = 6543
25+
port = 8080
2326

2427
###
2528
# logging configuration

frameworks/Python/pyramid/frameworkbenchmarks/__init__.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,39 @@
22
App config and initialization.
33
"""
44

5+
import orjson
56
from pyramid.config import Configurator
7+
from pyramid.renderers import JSON
8+
from .models import get_engine, get_session_factory
9+
10+
11+
def dbsession(request):
12+
sess = request.registry.dbsession_factory()
13+
14+
def cleanup(request):
15+
sess.close()
16+
17+
request.add_finished_callback(cleanup)
18+
return sess
619

720

821
def main(global_config, **settings):
9-
""" This function returns a Pyramid WSGI application.
10-
"""
11-
config = Configurator(settings=settings)
12-
config.include('pyramid_chameleon')
13-
config.add_route('test_1', '/json')
14-
config.add_route('test_2', '/db')
15-
config.add_route('test_3', '/queries')
16-
config.add_route('test_4', '/fortunes')
17-
config.add_route('test_5', '/updates')
18-
config.add_route('test_6', '/plaintext')
19-
config.scan()
22+
"""This function returns a Pyramid WSGI application."""
23+
json_renderer = JSON(serializer=orjson.dumps)
24+
with Configurator(settings=settings) as config:
25+
config.include("pyramid_chameleon")
26+
config.add_renderer("json", json_renderer)
27+
config.add_route("test_1", "/json")
28+
config.add_route("test_2", "/db")
29+
config.add_route("test_3", "/queries")
30+
config.add_route("test_4", "/fortunes")
31+
config.add_route("test_5", "/updates")
32+
config.add_route("test_6", "/plaintext")
33+
config.set_default_csrf_options(require_csrf=False)
34+
35+
engine = get_engine(settings)
36+
config.registry.dbsession_factory = get_session_factory(engine)
37+
config.add_request_method(dbsession, reify=True)
38+
39+
config.scan()
2040
return config.make_wsgi_app()

frameworks/Python/pyramid/frameworkbenchmarks/models.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,48 @@
22
Benchmark models.
33
"""
44

5-
import json
6-
import os
7-
import psycopg2
8-
from collections import Iterable
9-
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String
10-
from sqlalchemy.orm import sessionmaker
5+
6+
from sqlalchemy import Column, Integer, MetaData, String, create_engine
7+
from sqlalchemy.orm import declarative_base, sessionmaker
118
from sqlalchemy.pool import QueuePool
12-
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
139

1410

15-
def get_conn():
16-
return psycopg2.connect(
17-
user='benchmarkdbuser',
18-
password='benchmarkdbpass',
19-
host='tfb-database',
20-
port='5432',
21-
database='hello_world')
11+
def get_engine(settings):
12+
return create_engine(
13+
settings["sqlalchemy.url"],
14+
poolclass=QueuePool,
15+
pool_size=100,
16+
max_overflow=25,
17+
enable_from_linting=False,
18+
future=True,
19+
)
20+
2221

22+
def get_session_factory(engine):
23+
Session = sessionmaker(bind=engine, autoflush=False, future=True)
24+
return Session
2325

24-
conn_pool = QueuePool(get_conn, pool_size=100, max_overflow=25, echo=False)
2526

26-
pg = create_engine('postgresql://', pool=conn_pool)
27-
DBSession = sessionmaker(bind=pg)()
2827
metadata = MetaData()
2928

30-
DatabaseBase = declarative_base()
29+
Base = declarative_base()
3130

3231

33-
class World(DatabaseBase):
34-
__tablename__ = 'world'
32+
class World(Base):
33+
__tablename__ = "world"
3534

36-
id = Column('id', Integer, primary_key=True)
37-
randomNumber = Column(
38-
'randomnumber', Integer, nullable=False, server_default='0')
35+
id = Column("id", Integer, primary_key=True)
36+
randomNumber = Column("randomnumber", Integer, nullable=False, server_default="0")
3937

4038
def __json__(self, request=None):
41-
return {'id': self.id, 'randomNumber': self.randomNumber}
39+
return {"id": self.id, "randomNumber": self.randomNumber}
4240

4341

44-
class Fortune(DatabaseBase):
45-
__tablename__ = 'fortune'
42+
class Fortune(Base):
43+
__tablename__ = "fortune"
4644

47-
id = Column('id', Integer, primary_key=True)
48-
message = Column('message', String, nullable=False)
45+
id = Column("id", Integer, primary_key=True)
46+
message = Column("message", String, nullable=False)
4947

5048
def __json__(self):
51-
return {'id': self.id, 'message': self.message}
49+
return {"id": self.id, "message": self.message}

frameworks/Python/pyramid/frameworkbenchmarks/tests.py

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,77 @@
1-
# encoding: utf-8
2-
31
import unittest
42
import json
5-
import sys
3+
64

75
class FunctionalTests(unittest.TestCase):
86
def setUp(self):
97
from frameworkbenchmarks import main
10-
app = main({})
118
from webtest import TestApp
9+
10+
app = main({}, **{"sqlalchemy.url": "postgresql:///frameworkbenchmarks"})
11+
1212
self.testapp = TestApp(app)
13-
self.py3k = sys.version_info >= (3, 0)
1413

15-
def _get(self, url, content_type='application/json'):
14+
def _get(self, url, content_type="application/json"):
1615
res = self.testapp.get(url, status=200)
17-
self.assertTrue('Content-Length' in res.headers)
16+
self.assertTrue("Content-Length" in res.headers)
1817
return res
1918

20-
def _str_compat(self, obj):
21-
if self.py3k:
22-
return obj.decode('utf-8')
23-
return obj
24-
2519
def _test_obj(self, obj):
26-
self.assertTrue('id' in obj)
27-
self.assertTrue('randomNumber' in obj)
28-
self.assertTrue(1 <= obj['randomNumber'] <= 10000)
20+
self.assertTrue("id" in obj)
21+
self.assertTrue("randomNumber" in obj)
22+
self.assertTrue(1 <= obj["randomNumber"] <= 10000)
2923

3024
def test_json(self):
3125
"""
3226
/json
3327
"""
34-
res = self._get('/json')
35-
self.assertEqual(self._str_compat(res.body), """{"message": "Hello, World!"}""")
28+
res = self._get("/json")
29+
self.assertEqual(res.body, b"""{"message":"Hello, World!"}""")
3630

3731
def test_db(self):
3832
"""
3933
/db
4034
"""
41-
res = self._get('/db')
42-
obj = json.loads(self._str_compat(res.body))
35+
res = self._get("/db")
36+
obj = json.loads(res.body)
4337
self._test_obj(obj)
4438

4539
def test_queries_0(self):
4640
"""
4741
/queries?queries=0
4842
"""
49-
res = self._get('/queries?queries=0')
50-
self.assertEqual(len(json.loads(self._str_compat(res.body))), 1)
43+
res = self._get("/queries?queries=0")
44+
self.assertEqual(len(json.loads(res.body)), 1)
5145

5246
def test_queries_999(self):
5347
"""
5448
/queries?queries=999
5549
"""
56-
res = self._get('/queries?queries=999')
57-
self.assertEqual(len(json.loads(self._str_compat(res.body))), 500)
50+
res = self._get("/queries?queries=999")
51+
self.assertEqual(len(json.loads(res.body)), 500)
5852

5953
def test_queries_10(self):
6054
"""
6155
/queries?queries=10 objects
6256
"""
63-
res = self._get('/queries?queries=10')
64-
objset = json.loads(self._str_compat(res.body))
57+
res = self._get("/queries?queries=10")
58+
objset = json.loads(res.body)
6559
for obj in objset:
6660
self._test_obj(obj)
6761

6862
def test_fortunes(self):
6963
"""
7064
/fortunes
7165
"""
72-
res = self._get('/fortunes')
73-
self.assertEqual(self._str_compat(res.body).strip(), fortunes.strip())
66+
res = self._get("/fortunes")
67+
self.assertEqual(res.body.decode('utf-8').strip(), fortunes.strip())
7468

7569
def test_updates(self):
7670
"""
7771
/updates?queries=10
7872
"""
79-
res = self._get('/updates?queries=10')
80-
objset = json.loads(self._str_compat(res.body))
73+
res = self._get("/updates?queries=10")
74+
objset = json.loads(res.body)
8175
# don't bother with more...
8276
for obj in objset:
8377
self._test_obj(obj)
@@ -86,8 +80,8 @@ def test_plaintext(self):
8680
"""
8781
/plaintext
8882
"""
89-
res = self._get('/plaintext', content_type='text/plain')
90-
self.assertEqual(self._str_compat(res.body), "Hello, World!")
83+
res = self._get("/plaintext", content_type="text/plain")
84+
self.assertEqual(res.body, b"Hello, World!")
9185

9286

9387
fortunes = """

0 commit comments

Comments
 (0)