Really excited to read
[Speculative Everything]( once it comes in the mail. Thanks to @DenseDiscovery newsletter for the introduction.

A simple method for disabling that horrid new Slack WYSIWYG interface.

open -a /Applications/

Open the console CMD+OPT+i

javascript:(_ => {
const redux = slackDebug[slackDebug.activeTeamId].redux;
const {wysiwyg_composer, wysiwyg_composer_ios, wysiwyg_composer_webapp, …payload} = redux.getState().experiments;
redux.dispatch({ type: ‘[19] Bulk add experiment assignments to redux’, payload });

Needs to be run in each team that you’re a part of.

Converting an image to a PDF in the purest sense of the word is not possible in the most cases. This is because most images are raster bitmaps, i.e. a square with color value set for each pixel, while PDFs are a container format.

What usually happens when you “convert” an image to a PDF not a conversion from one file-format to the other, but rather your image is embeded inside a PDF container document. Conceptually it’s not too different from pasting an image into a Word document.

Acomplishing this with Python only takes a couple lines of code using wither `Wand` or `Pillow` (PIL).

# Code snippet Wand
## Walk through

# Code snippet PIL

## Walk through

### Gotchas

### Improved Versions

### Conclusion

The PDF file format is a ubiquitous file format and the only real way to guarantee document layout and display, no matter the device or operating system used to view it . Python, being a language that excels at data processing and manipulation, naturally has a lot of tools for working with PDF files to generate reports. This post is a brief introduction to the tools that are available and the tasks they work best for.


Wand is a set of Python bindings for do-it-all ImageMagick library. As such it really a Swiss-army knife for PDF (and image) manipulation and generation. In the context of PDF, ImageMagick (and therefore Wand) is mostly a frontend for GhostScript.

Its API is quite Pythonic and can help you split, convert, and even draw on PDF files. Wand is perfect for manipulating existing PDFs and doing light editing on them.


ReportLab is a commercial/open-source PDF generation library. If you’re making complex PDFs from scratch this is the library you should pick. Period.


PikePDF is a PDF manipulation library based on qpdf. As its underpinnings are written in C++ it’s super fast. Unlike other python pdf libraries, PikePDF supports unlocking encrypted / password protected PDFs.

PikePDF also lets you explore the internal structure of a PDF document, which make it a perfect tool for debugging problem PDFs and extracting content/images.

The APIs are very Pythonic, and let you work with manipulate pages / page order like a regular list. PikePDF is also great for repairing and prepping PDF to be manipulated by Wand.


Pillow is a PDF library, but it supports exporting images to PDF, making it a powerful tool in your Python PDF toolbox.

While there’s some overlap of functionality Wand in terms of image editing capabilities, it’s more focused on editing images, rather than transforming and converting images. Pillow is an indispensable tool when working with any user-supplied images in your PDF workflow.


There is no single PDF tool in Python that fits all needs, all the time. These libraries can, and are, often used in conjunction with one another to quickly and easily generate PDFs on demand. However, depending on how you combine them, there can be some issues resulting in large file sizes and slow generation times. I’ll cover these gotchas in future posts.

On a project at work I’ve been learning GraphQL. I’m in charge of both developing the backend ( using the wonderful graphene-django package) and the frontend ( using Typescript / Vue.js / axios ) for this specific feature.

After wrapping my head around GraphQL and getting a basic endpoint working I wanted to write some tests to ensure that filtering and other requirements are working as expected.

For a proper End-to-end test I’d usually setup a client and post a json dictionary or such. With End-to-end GraphQL tests you need to send actual GraphQL queries, which makes sense but it feels a bit like SQL Injection.

Below is how I’ve settled organizing and writing my GraphQL tests.

├── test_myapp/
│   └──

Because the graphql client will be reused across the django site, I added a global fixture that will automatically load mty project’s schema.

# tests/
def graphql_client():
from myproject.schema import schema
from graphene.test import Client
return Client(schema)

In this example I’m testing that I’m filtering data as expected when passing a search parameter.

For setup, first I write a query as its own fixture so I can re-use it throughout the test and it’s clear exactly what is going to be run. Second, I make sure the query uses variables instead of hard-coded values when querying so I can change the input depending on the test. Third, setup a model_bakery fixture for data that I expect to find.

import pytest
from model_bakery import baker

class TestMyModelData:
def query(self):
return """
query testGetMyModel($searchParam: String!){
myModelData(searchParam: $searchParam) {

def my_model(self):
total_count="20", # Decimal field

def test_none_response(self, graphql_client, query, my_model):
executed = graphql_client.execute(query, variables={"searchParam": "skittles"})
assert executed == {"data": {"myModelData": None}}

def test_filters_usage(self, graphql_client, query, my_model):
params = {"searchParam": "skittles"}
executed = graphql_client.execute(query, variables=params)
assert executed == {
"data": {
"myModelData": {
"totalCount": 20

Executing each test I simply pass my query and required variables for the test/query. In this I’m testing the same query twice: once with and one without a searchParameter. My expectation is that I get no results without a search term and data when to my graphql_client fixture.

As the return value from our client is a dictionary, I can simply assert my expecte results with the actual results. If something changes I’ll know immediately.

Using the techniques above I can easily add new tests for my GraphQL endpoint as the available changes or bugs are found.