Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Plug-in architectures for Python web applications
Search
Raphael Michel
October 25, 2017
Programming
78
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Plug-in architectures for Python web applications
Raphael Michel
October 25, 2017
More Decks by Raphael Michel
See All by Raphael Michel
Automatic Screenshots of your Django web application with py.test and Selenium
raphaelm
1
260
Data Internationalization in Django
raphaelm
2
550
Other Decks in Programming
See All in Programming
AI時代の仕事技芸論〜ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ(スクフェス仙台 2026バージョン)
kuranuki
0
560
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
190
鹿野さんに聞く!『TypeScriptコードレシピ集』で磨く実践力
tonkotsuboy_com
4
1k
はてなアカウント基盤 State of the Union
cockscomb
1
1.3k
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
460
えっ!!コードを読まずに開発を!?
hananouchi
0
170
Creating Composable Callables in Contemporary C++
rollbear
0
200
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1.2k
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
140
act1-costs.pdf
sumedhbala
0
200
OS アップデート対応の取り組み方がもっと共有されてほしい
andpad
0
110
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
240
Featured
See All Featured
Writing Fast Ruby
sferik
630
63k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.5k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
190
Amusing Abliteration
ianozsvald
1
220
Java REST API Framework Comparison - PWX 2021
mraible
34
9.4k
Statistics for Hackers
jakevdp
799
230k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
230
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
Embracing the Ebb and Flow
colly
88
5.1k
Transcript
PLUG IN ECOSYSTEMS FOR PYTHON WEB APPLICATIONS
None
Source: w3techs.com WordPress is used by 59.6% of all the
websites whose content management system we know. This is 28.7% of all websites.
None
Open Source event ticket shop Python/Django stack Key design goal:
Be extensible. Don't make people patch or fork it.
IDEAS FOR PLUGINS Payment methods Export formats, ticket layouts Additional
features
OUR PLAN 1. Establish a way that plugins can hook
into your application 2. Provide many of these hooks 3. Document them well 4. There is no step four!
LET'S WRITE SOME PYTHON!
SIMPLE SIGNAL SYSTEM class Signal: def __init__(self): self.receivers = []
def register(self, func): self.receivers.append(func) return func def send(self, *args, **kwargs) return [ func(*args, **kwargs) for func in self.receivers ] user_created = Signal() @user_created.register def plugin_listener(): send_mail()
DJANGO.DISPATCH.SIGNAL Similar API Handles thread-safety for you Caching, weak references,
… → If you're on Django, use this one.
1 PLUGIN = 1 DJANGO APP Plugins can have their
own models Plugins can have their own templates Plugins can have their own static files …
HOW TO INSTALL A PLUGIN Like a django app! Install
package with source code Add to INSTALLED_APPS in settings.py Add url include to urls.py Too many steps! And we don't want to touch code…
ALL WE WANT IST $ pip install pretix-xyz (+ migrations,
maybe)
PLUGIN: __INIT__.PY from django.apps import AppConfig class PluginApp(AppConfig): name =
'xyz' verbose_name = 'XYZ plugin' class PretixPluginMeta: name = 'XYZ plugin' def ready(self): from . import signals default_app_config = 'pretix_xyz.PluginApp'
PLUGIN: SETUP.PY setup( name='pretix-xyz', install_requires=[], packages=find_packages(exclude=['tests', 'tests.*']), include_package_data=True, entry_points={ 'pretix.plugin':
[ 'pretix_xyz=pretix_xyz:PretixPluginMeta' ] } )
APP: SETTINGS.PY from pkg_resources import iter_entry_points for entry_point in iter_entry_points(
group='pretix.plugin', name=None): INSTALLED_APPS.append(entry_point.module_name)
PLUGIN: URLS.PY urlpatterns = [ url(…), … ]
APP: URLS.PY plugin_patterns = [] for app in apps.get_app_configs(): if
hasattr(app, 'PretixPluginMeta'): if importlib.util.find_spec(app.name + '.urls'): urlmod = importlib.import_module( app.name + '.urls') plugin_patterns.append( url('', include((singlurlmod.urlpatterns, app.label))) ) urlpatterns = [ ..., url('', include((plugin_patterns, 'plugins'))) ] {% url "plugins:pretix_xyz:my.url.name" %}
THAT'S OUR PLUGIN SYSTEM!
BONUS: PLUGINS PER CLIENT/USER Custom Signal() subclass Store list of
enabled plugins per client More URL magic (if wanted)
MAKE IT EASY {% load signal %} … {% signal
"pretix.control.signals.order_info" order=order %} @register.simple_tag def signal(signame: str, **kwargs): sigmodule, signame = signame.rsplit('.', 1) sigmodule = importlib.import_module(sigmodule) signal = getattr(sigmodule, signame) html_result = [] for receiver, response in signal.send(event, **kwargs): if response: html_result.append(response) return mark_safe("".join(html_result))
WRITE DOCUMENTATION No, seriously.
PROVIDE A COOKIECUTTER TEMPLATE $ cookiecutter \ https://github.com/pretix/pretix- plugin-cookiecutter
AUTO-INSTALL Naah, better don't.
THANK YOU! ANY QUESTIONS? Raphael Michel
[email protected]
@_rami_ raphaelm pretix.eu
[email protected]
@pretixeu pretix
MAY 23-27TH, 2018 HEIDELBERG, GERMANY 2018.DJANGOCON.EU