Category Archives: Python

A number of spools containing sewing thread.

Trying free-threading in Python 3.14

With the release of Python 3.14, support for running multiple threads, in parallel, without each thread having to wait for the Global Interpreter Lock (GIL) is now supported.

I was keen to try this out, if only in a ‘hello world’ sense but it took me a little while to sort out what was necessary. In 3.14, and for some (perhaps “a lot of”) releases to come the GIL is enabled by default and if you wish to try out the new “GIL-less” world you have to compile an instance of Python while using the “disable-gil” flag.

Well it’s been some time since I’ve done anything other than installed canned versions of Python so I had remind myself how to do this.

The following describes my experience of a Linux/Bash environment but it should throw some light on other supported environments.

Although interested to 3.14 in action I certainly did want a freshly minted release to be my primary python so I needed a mean to install 3.14 alongside a more established version. Because I’d used it before I decided to use pyenv , a python version management tool that allows you to easily switch between different versions of python. If you don’t have it installed the instructions to do so are quite clear, don’t miss the changes to the environment variables after the install.

Once pyenv is in the place the rest is very straightforward, the key point is ensuring that the “–disable-gil” flag being used when compiling your new install.

rshea@jobabo:~/dev$ env PYTHON_CONFIGURE_OPTS="--enable-optimizations --with-threads --enable-shared --disable-gil" pyenv install 3.14
Downloading Python-3.14.0.tar.xz...
-> https://www.python.org/ftp/python/3.14.0/Python-3.14.0.tar.xz
Installing Python-3.14.0...
Installed Python-3.14.0 to /home/rshea/.pyenv/versions/3.14.0

Now make 3.14 the active python.

rshea@jobabo:~/dev$ pyenv shell 3.14.0

And start python with the argument which ensures the GIL is not used.

rshea@jobabo:~/dev$ python -X gil-0

And within the REPL you can then check that the GIL is indeed disabled.

Python 3.14.0 free-threading build (main, Oct 12 2025, 16:11:53) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sysconfig
>>> status = sysconfig.get_config_var("Py_GIL_DISABLED")
>>> status
1

If you should find that the value of status is 0 then it’s worth checking the arguments you used to compile python with, you should be able to see ‘–disable-gil’ in the arguments displayed.

>>> import sysconfig
>>> print(sysconfig.get_config_var('CONFIG_ARGS'))
'--prefix=/home/rshea/.pyenv/versions/3.14.0' '--libdir=/home/rshea/.pyenv/versions/3.14.0/lib' '--enable-optimizations' '--with-threads' '--enable-shared' '--disable-gil' 'LDFLAGS=-L/home/rshea/.pyenv/versions/3.14.0/lib -Wl,-rpath,/home/rshea/.pyenv/versions/3.14.0/lib' 'LIBS=-L/home/rshea/.pyenv/versions/3.14.0/lib -Wl,-rpath,/home/rshea/.pyenv/versions/3.14.0/lib' 'CPPFLAGS=-I/home/rshea/.pyenv/versions/3.14.0/include'
>>> import sys

That’s all for now, my next step is to try Asyncio introspection capabilities but will have to wait for another day.

The image of wooden spools of thread is courtesy of : W.carter, and is used under CC BY-SA 4.0, via Wikimedia Commons.

Django Rest Framework Authentication Packages

What is this ?

I’ve found the official documentation of Django Rest Framework third-party authentication packages difficult to parse, and lacking some information I would like, so I’ve produced my own version, extending the original. I will revise this blog post until I’m satisfied and then I will submit my version as a pull request to the Django Rest Framework project for consideration as a replacement for the existing version.

DRF – Third Party Authentication Packages

Categorisation

In addition to the main table, there are extra tables showing packages grouped by :

Main Table

NameDescriptionLast Update to Repos
Django-rest-knox
[docs]

Django-rest-knox library provides models and views to handle token-based authentication in a more secure and extensible way than the built-in TokenAuthentication scheme – with Single Page Applications and Mobile clients in mind.

It provides per-client tokens, and views:

  • to generate them when provided some other authentication (usually basic authentication),
  • to delete the token (providing a server enforced logout) and
  • to delete all tokens (logs out all clients that a user is logged into).
2025-01-28
Django OAuth Toolkit
[docs]

The Django OAuth Toolkit package provides OAuth 2.0 support and works with Python 3.4+.

The package is maintained by jazzband and uses the excellent OAuthLib.

The package is well documented, and well supported and is currently the DRF project  recommended package for OAuth 2.0 support.

2025-02-25
Django REST framework OAuth
[docs]

The Django REST framework OAuth package provides both OAuth1 and OAuth2 support for DRF.

This package was previously included directly in the REST framework but is now supported and maintained as a third-party package.

2019-04-13
JSON Web Token Authentication
[docs]

JSON Web Token is a fairly new standard which can be used for token-based authentication.

Unlike the built-in TokenAuthentication scheme, JWT Authentication doesn’t need to use a database to validate a token.

A package for JWT authentication is djangorestframework-simplejwt which provides some features as well as a pluggable token blacklist app.

2025-02-21
Hawk HTTP Authentication
[docs]

The HawkREST library builds on the Mohawk library to let you work with Hawk signed requests and responses in your API.

Hawk lets two parties securely communicate with each other using messages signed by a shared key.

It is based on HTTP MAC access authentication (which was based on parts of OAuth 1.0).

2018-10-07
HTTP Signature Authentication

HTTP Signature provides a way to achieve origin authentication and message integrity for HTTP messages.


Similar to Amazon’s HTTP Signature scheme, used by many of its services, it permits stateless, per-request authentication.


Elvio Toccalino maintains the djangorestframework-httpsignature (outdated) package which provides an easy-to-use HTTP Signature Authentication mechanism. You can use the updated fork version of djangorestframework-httpsignature, which is drf-httpsig.



2018-03-29
Djoser
[docs]

Djoser library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation.

The package works with a custom user model and uses token-based authentication.

This is a ready to use REST implementation of the Django authentication system.

2024-11-11
django-rest-auth / dj-rest-auth
[docs]

This library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc.

By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management.

2024-12-02
drf-social-oauth2
[docs]

Drf-social-oauth2 is a framework that helps you authenticate with major social oauth2 vendors, such as Facebook, Google, Twitter, Orcid, etc.

It generates tokens in a JWTed way with an easy setup.

2024-07-19
drfpasswordless
[docs]

drfpasswordless adds (Medium, Square Cash inspired) passwordless support to Django REST Framework’s TokenAuthentication scheme.

Users log in and sign up with a token sent to a contact point like an email address or a mobile number.

2023-10-23
django-rest-authemail
[docs]

django-rest-authemail provides a RESTful API interface for user signup and authentication.

Email addresses are used for authentication, rather than usernames.

API endpoints are available for signup, signup email verification, login,

2023-04-10
Django-Rest-Durin
[docs]

Django-Rest-Durin is built with the idea to have one library that does token auth for multiple Web/CLI/Mobile API clients via one interface but allows different token configuration for each API Client that consumes the API.

It provides support for multiple tokens per user via custom models, views, permissions that work with Django-Rest-Framework.

The token expiration time can be different per API client and is customizable via the Django Admin Interface.

2023-05-04

Note1: ‘Last Update to Repos’ column values are as of 26 Feb 2024.

Note2: As of 26 Feb 2024 the table above does not differ a great deal from the official document. I believe that it is easier to read but otherwise the content is very similar. In the future I will update it to include other information to make selecting a third-party DRF authentication package easier.

Packages providing support for Social Identities

  • django-rest-auth / dj-rest-auth
  • drf-social-oauth2

Packages providing OAuth capability

  • Django OAuth Toolkit
  • Django REST framework OAuth
  • drf-social-auth2

Packages by date of last update

Last UpdatePackage
2025Django-rest-knox
Django OAuth Toolkit
JSON Web Token Authentication
2024Djoser
django-rest-auth / dj-rest-auth
drf-social-oauth2
2023drfpasswordless
django-rest-authemail
Django-Rest-Durin
2019Django REST framework OAuth
2018Hawk HTTP Authentication
HTTP Signature Authentication

A note about licensing

As mentioned, the above text is based on part of the official documentation. The license under which django-rest-framework is made available doesn’t make it very clear how the documentation should be treated when re-distributed as it’s neither source code, nor binary so I hope that it’s enough to point out that : this is the license of of the django rest framework project; and the documentation is Copyright © 2011-present, Encode OSS Ltd .

Django and htmx

The 'Django' and the 'htmx' logo beside each other.

I gave a talk last night at the Auckland chapter meetup of Python New Zealand. The subject was the use of htmx with Django .

The JavaScript library htmx allows ‘native app like’ user experience for a Django project. Instead of refreshing the entire page, only the parts of the screen that actually need updating are refreshed. This eliminates those pesky flashes and reloads you get with conventional page refreshes. The result? A much smoother interface..

Now, normally, achieving this level of interactivity would require a full-fledged JavaScript-based frontend, along with the corresponding deep dive into React, Vue, or whichever framework is trending this month. But with htmx, you can get similar results by making relatively minor changes to your existing Django templates and views. No new framework, no need to sell your soul to JavaScript (at least not entirely) and you do away with large amounts of code serializing and de-serializing data.

In a Django context this is all made easier with the help of the django-htmx add-on (written by Adam Johnson). It provides the tools you need to integrate htmx into your Django project. In my presentation, I shared an overview of htmx and how combining it with django-htmx can deliver a smooth, engaging user experience—without the need to build a full-on JavaScript frontend or expose a mountain of API endpoints to service it.

That said, I’m not suggesting htmx is a silver bullet. There are plenty of scenarios where a “proper” JavaScript framework—be it React/Next.js, Vue, or Svelte—makes more sense. But I’m excited to explore more about where htmx fits into the Django ecosystem and how it can simplify things in the right contexts

Here are my slides from last night.

Using pipenv to install from github

Summary

I’ve taken to using pipenv (“Python Development Workflow for Humans”) recently and so I frequently come across things I haven’t done previously and need to figure out how to. Todays’s is using pipenv to install a package from a github repository.

How do you do that ?

So, short and sweet, here’s how. In my case I have forked the repos ‘behave-web-api‘ and I want to install my forked version into my current project.

$ pipenv install -e git+ssh://git@github.com/shearichard/behave-web-api.git#egg=behave-web-api

Notice the git+ssh is used as the scheme of the url. Also notice that the egg=behave-web-api (with the value after the equals sign changed to whatever package you’re dealing with) is necessary .

References

References

The pipenv doco for this is comprehensive but because it’s so comprehensive is a little more than you might need in a lot of cases. I also found the note written to himself by Koen Woortman a useful pointer.

Don’t forget when starting with django-sockpuppet

Today I’ve started my first django-sockpuppet project ( https://pypi.org/project/django-sockpuppet/ ).

If you’re using pipenv the first thing you need to do is

pipenv install django-sockpuppet

but I found that command failed when it came to installing the dependency on Twisted https://pypi.org/project/Twisted/ .

The problem was that I had started using a new virtual machine for development and it was lacking libraries which Twisted depends on. To be clear this is an Ubuntu 20.x machine and this problem may be specific to that environment.

So if you’re using django-sockpuppet and you have problems installing it try executing the following.

sudo apt-get install python3-dev
sudo apt-get install libevent-dev

This is pretty standard stuff for a new machine but easy to forget if you don’t change very often.

Using Python’s argparse for a “turn on”/”turn off” argument

What’s argparse ?

Argparse is a Python standard module and “makes it easy to write user-friendly command-line interfaces”. The 2.x doco is here, the 3.x doco is here. Before 2.7 there was the optparse module supplied as part of Python but that’s been deprecated and replaced with argparse.

“turn off” / “turn off” type arguments

I was working on some code yesterday and I wanted an argument of the “turn on” / “turn off” type. So for instance you might want the output to be verbose or not, it’s not uncommon to see this implemented by means of a

--verbose

argument. When ‘–verbose’ is present the programmer provides verbose output, when it’s absent they don’t.

How then ?

A nice neat way to do this is to make use of the `action` (2.x and 3.x) argument of the `add_argument` method and to combine that with use of the `set_defaults` method so that a value is set in the case when the argument is not used by the user.

Here’s an example taken from my django-row-count project :

parser.add_argument('--echotostdout', dest='echotostdout', action='store_true')
parser.set_defaults(echotostdout=False)
args = parser.parse_args()

In this case a command line argument …

--echotostdout

… sets an attribute

args.echotostdout

… to True if it’s present as an argument on the command line and to False if it’s absent.

Django and Heroku – getting it working

Django and Heroku – getting it working

What follows is based on a short talk I gave to the New Zealand Python User Group in Feb 2015. This blog post provides some specifics on areas I was only able to hand wave over during the talk.

Motivation

I recently tried to deploy a Django side project to Heroku.

I’d previously used Heroku for a Ruby on Rails project and remembered it being very straightforward so I was surprised to find it wasn’t that great an experience. The documentation is fragmentary and seems to have been only partially updated to reflect changes in Django and the Heroku environment.

“Simplest Possible”

In the end I decided to suspend my original project and try to make the simplest possible Django project work on Heroku. For “simplest possible” I chose the “Polls” project from the Django Tutorial . I got it working and the code is available in my github account:  https://github.com/shearichard/polls17/tree/v2.0 . If you’re interested the version of the Project which works locally and before I made any changes to support use on Heroku is here : https://github.com/shearichard/polls17/tree/v1.0 .

What needed to be done

To complement the Heroku documentation I’m going to record here the changes that were made to the Project between v1.0 (working locally) and v2.0 (working on Heroku).

The files to which changes were applied to support use in Heroku are as follows :

mysite/mysite/settings.py (before and after)
mysite/mysite/settings_heroku.py (after – there was no ‘before’ for this file !)
mysite/mysite/wsgi.py (before and after)
requirements.txt (before and after)

settings.py

diff --git a/mysite/mysite/settings.py b/mysite/mysite/settings.py
index cb992c1..b2082ba 100644
--- a/mysite/mysite/settings.py
+++ b/mysite/mysite/settings.py
@@ -87,4 +87,5 @@ USE_TZ = True
# https://docs.djangoproject.com/en/1.7/howto/static-files/

STATIC_URL = '/static/'
STATIC_ROOT = 'staticfiles'
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]

 

settings_heroku.py

The settings_heroku.py file was completely new for use within the Heroku environment and we can see it referenced below from within wsgi.py when a test is made to see if the code is running within Heroku.

The final form of settings_heroku.py is as follows :

from .settings import *

import dj_database_url
DATABASES['default'] =  dj_database_url.config()

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

Things worthy of note here are :

  • we import the whole of the local settings file (referenced here as ‘.settings’) and then change or add to it as necessary.
  • we make use of the dj-database-url to pick up the database configuration to be used in the Heroku environment
  • `STATIC_ROOT` and `STATICFILES_DIRS` are not needed in the standard version of the ‘Polls’ project but they are needed when we move to Heroku so they’re added here.
  • `STATIC_URL` is already defined in the standard settings file and so doesn’t actually need to be in settings_heroku.py at all.
  • STATICFILES_STORAGE allow for the use of Whitenoise a module which allows wsgi apps (such as this one) to serve their own static files, something which hadn’t previously been possible. There’s other good reasons to use Whitenoise in the areas of file compression and cache-header handling

wsgi.py

The version of wsgi.py before the changes for Heroku is very straightforward and can be seen below.

"""
WSGI config for mysite project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

To make wsgi.py work for Heroku there are essentially three changes:

  • Make the settings file used dependent on the existence of an environmental variable, ‘DYNO’. If it’s present then the code is running on Heroku and the server is started  using the the settings_heroku.py file shown above, otherwise we continue to use the settings.py file.
  • To make use of Whitenoise we take the the output of `get_wsgi_application` and use it as an argument when instantiating a `DjangoWhiteNoise` object.
  • Lastly, and least important, we redirect standard output so to standard error. This isn’t necessary at all and is something I did to make for easier diagnosis of issues while getting the Heroku specific version working.
diff --git a/mysite/mysite/wsgi.py b/mysite/mysite/wsgi.py
index 15c7d49..e5e1e5c 100644
--- a/mysite/mysite/wsgi.py
+++ b/mysite/mysite/wsgi.py
@@ -8,7 +8,20 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""

import os
import sys

#Allows us to see useful stuff in Gunicorn output
sys.stdout = sys.stderr

#Rely upon env var 'DYNO` to determine if we are
#running within Heroku
if 'DYNO' in os.environ:
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings_heroku")
else:
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise

application = get_wsgi_application()
application = DjangoWhiteNoise(application)

 

requirements.txt

The requirements.txt (created as the output from a `pip freeze` command) reflects the libraries installed at any given point.

Here’s the diff of requirements.txt between the local installation and the ‘Heroku’ ready installation.

As can be seen the extra libraries required by the migration to Heroku were :

  • dj-database-url
  • gunicorn
  • whitenoise
diff --git a/requirements.txt b/requirements.txt
index 98b2fd1..4e189d2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,7 @@
Django==1.7.4
Pygments==2.0.2
argparse==1.2.1
dj-database-url==0.3.0
django-extensions==1.5.0
django-pdb==0.4.1
fancycompleter==0.4
gunicorn==19.2.1
@@ -11,5 +12,6 @@ psycopg2==2.6
pyflakes==0.8.1
pyrepl==0.8.4
six==1.9.0
whitenoise==1.0.6
wmctrl==0.1
wsgiref==0.1.2

A general point about Project structure

A good deal of the Heroku documention assumes that your project directory (the one that contains manage.py) is also your root directory . This isn’t how I do things. I prefer my root directory to contain stuff like .gitignore, requirements.txt, README.md etc and to have a directory within the root which is my project directory.

If your project is similarly structured it’s worth bearing in mind that the Procfile required by Heroku should include ” –pythonpath ./mysite” (where ‘mysite’ is the name of your project directory) as an argument to the gunicorn invocation … I had a number of issues before I did this . Here’s an example of the argument in use.

A general point about the Heroku CLI

The Heroku Toolbelt includes the Heroku CLI which allows you to manage Heroku apps from the command line. For instance this :

heroku ps --app foo

Provides a list of running dynos in your ‘foo’ application.

Anyway the strange thing is that it seems to me that almost every command you issue via the Heroku CLI requires the

--app foo

argument, where ‘foo’ is the name of your application, and yet the documentation never mentions that ! You work it out pretty quickly because you don’t do much without without it but it’s strange all the same.

 In conclusion

Using the free levels of Heroku for running a Django project gives you access to a really high quality hosting environment at a very attractive price (free as long as you don’t get too much traffic or data). Once you’ve got over the bumps it works really well and for many people will be a good solution for hobby projects.

Dominate: Manipulate HTML DOM using Python

Dominate: Manipulate HTML DOM using Python

This is a talk I gave in March 2014 which I never got around to doing a blog post for.

Dominate is : “a Python library for creating and manipulating HTML documents using an elegant DOM API” .

There’s a part of me which deep down feels that using templates is “wrong” and that procedural processing is the way to go … it might be a deluded part of me but it is a part of me ! Anyway as a result when I read about Dominate I had to give it a spin.

I gave a talk to the Wellington branch of the New Zealand Python User group and the slides are here : https://s3.amazonaws.com/shearichard/dominate-demo-NZPUG-2014-March.pdf . They are really very simple examples but, I hope, instructive.

As part of that I put my examples up on Bitbucket and they’re available here : https://bitbucket.org/rshea/nzpug201403/src

 

Charting with Django : three approaches

Charting with Django : three approaches

This is a belated (and hasty) post about a talk I gave in October 2013 at the Wellington branch of the New Zealand Python User Group.

Comparing three different charting libraries

In the talk I compared three different approaches to providing charts within a Django project.

The three different approaches used were :

Chartit
Django-Graphos
Chartkick

Sample code and slides

I built a Django project and an application for each of the three approaches and that code is available here : https://bitbucket.org/rshea/django-charts-demo .

The slides for my talk are available here as a PDF : https://s3.amazonaws.com/shearichard/django-with-charts.pdf

Conclusion in brief

If you’re only interested in my conclusion I would suggest Django-Graphos – read the slides for why.

Python you want a string you get a tuple – howzat ?

Python you want a string you get a tuple – howzat ?

Summary

How come you’re getting a tuple when you passed a string ?

Don’t do this at home

This is something that happened to me today. It really perplexed me so maybe this post will help someone else.

My class

I’d got a class a bit like the one below:

class cat(object):
    def __init__(self, name, colour, weight):
        self.name = name
        self.colour = colour,
        self.weight = weight
    def report(self):
        print self.name
        print self.colour
        print self.weight

Using it

But when I tried to use it like this:

mycat = cat('Garfield', 'Marmalade', 10)
mycat.report()

the output looked like this :

Garfield
('Marmalade',)
10

The problem being the attribute `colour` was being stored as a tuple.

The Answer

Looking back on it the problem is quite obvious but I was so busy looking at other parts of the situation (which was significantly more complex than the my cat example I missed it for quite a while.

Within the __init__ method I had inadvertently appended a comma onto the end of the self.colour assignment and Python takes that to mean, in our example, colour is the first element of a tuple.