Today I will tell you about the massive success that is whypy3.com. With hundreds of users a day (on the best day when it reached page two of Hacker News and hundreds actually being 103), it has been a tremendous success in the lucrative Python code snippet market. By presenting small snippets of code displaying cool features of Python 3, I was able to single–handedly convert millions (1e-6 millions to be exact) of Python 2 users to true Python 3 believers.
It all started when I saw a tweet about a cool Python 3 feature I haven’t seen before. This amazing feature automatically resolves any exception in your code by suppressing it. Who needs pesky exceptions anyway? Alternatively, you can use it to cleanly ignore expected exceptions instead of the usual
from contextlib import suppress
There are obviously way better and bigger reasons to finally make that move to Python 3. But what if you can be lured in by some cool cheap tricks? And that’s exactly why I created whypy3.com. It’s a tool that us Python 3 lovers can use to try and slowly wear down on an insistent boss or colleague. It’s also a fun way for me to share all my favorite Python 3 features so I don’t forget them.
I was initially going to to do the usual static S3 website with CloudFront/CloudFlare. But I also wanted it to be easy for other people to contribute snippets. The obvious choice was GitHub, and since I’m already using GitHub, why not give GitHub Pages a try? Getting it up and running was a breeze. To make it easier to contribute without editing HTML, I decided to use the full blown Jekyll setup. I had to fight a little bit with Jekyll to get highlighting working, but overall it took no time to get a solid looking site up and running.
After posting to Hacker News, I even got a few pull requests for more snippets. To this day, I still get some Twitter interactions here and there. I don’t expect this to become a huge project with actual millions of users, but at the end of the day this was pretty fun, I learned some new technologies, and I probably convinced someone to at least start thinking about moving to Python 3.
Do you use Python 3? Please share your favorite feature!
I usually ended up creating my own image containing both Python and Node with:
RUN curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
RUN apt-get install -y nodejs
# ... rest of my stuff
There are two problems with this approach.
- It’s slow. Installing Node takes a while and doing it for every non-cached build is time consuming.
- You lose the Docker way of just pulling a nice prepared image. If Node changes their deployment method, the
Dockerfile has to be updated. It’s much simpler to just
docker pull node:8
The obvious solution is going to Docker Hub and looking for an image that already contains both. There are a bunch of those but they all look sketchy and very old. I don’t feel like I can trust them to have the latest security updates, or any updates at all. When a new version of Python comes out, I can’t trust those images to get new tags with the new version which means I’d have to go looking for a new image.
So I did what any sensible person would do. I created my own (obligatory link to XKCD #927 here). But instead of creating and pushing a one-off image, I used Travis.ci to update the images daily. This was actually a pretty fun exercise that allowed me to learn more about Docker Python API, Docker Hub and Travis.ci. I tried to make it as easily extensible as possible so anyone can submit a PR for a new combo like Node and Ruby, or Python or Ruby, or Python and Java, etc.
The end result allows you to use:
docker run --rm combos/python_node:3_6 python3 -c "print('hello world')"
docker run --rm combos/python_node:3_6 node -e "console.log('hello world')"
You can rest assured you will always get the latest version of Python 3 and the latest version of Node 6. The image is updated daily. And since the build process is completely transparent on Travis.ci you should be able to trust that there is no funny business in the image.
Source code: https://github.com/kichik/docker-combo
Build server: https://travis-ci.org/kichik/docker-combo
Django 1.10 added a new style of middleware with a different interface and a new setting called
MIDDLWARE instead of
MIDDLEWARE_CLASSES. Creating a class that supports both is easy enough with MiddlewareMixin, but that only works with Django 1.10 and above. What if you want to create middleware that can work with all versions of Django so it can be easily shared?
Writing a compatible middleware is not too hard. The trick is having a fallback for when the import fails on any earlier versions of Django. I couldn’t find a full example anywhere and it took me a few attempts to get it just right, so I thought I’d share my results to save you some time.
from django.core.exceptions import MiddlewareNotUsed
from django.shortcuts import redirect
from django.utils.deprecation import MiddlewareMixin
MiddlewareMixin = object
def __init__(self, *args, **kwargs):
raise MiddlewareNotUsed('DISABLE_MIDDLEWARE is set')
super(CompatibleMiddleware, self).__init__(*args, **kwargs)
def process_request(self, request):
if request.path == '/':
def process_response(self, request, response):
CompatibleMiddleware can now be used in both
MIDDLEWARE_CLASSES. It should also work with any version of Django so it’s easier to share.
I created a quick backport patch for Scapy 2.2.0 so it could run on Python 2.4. Nothing too special. Just the usual removal of with, try/except/finally and defaultdict.
So if you’re stuck with Python 2.4 like me but still want to [ab]use Scapy, apply the patch and get your fuzz on.
The original ticket is available on Scapy Trac.
Inspired by our dear friend Ilya, my friend Ron has engineered a little Python script to simulate Russian phone chats with a little help from Microsoft Sam. Ron has slaved over this task for a whole grueling 5 minutes. We proudly named our magnificent product RCS – Russian Conversation Synthesizer.
Not for the faint of heart…
speak = win32com.client.Dispatch('Sapi.SpVoice')
speak.Volume = 100
speak.Rate = 6
speak.Voice = speak.GetVoices('Name=Microsoft Sam').Item(0)
speak.Speak(random.choice(["blat", "huui", "suukkaa"]))
This lovely script would typically generate an authentic conversation such as:
suukkaa blat blat huui blat suukkaa