Skip to content

Commit d90fb5c

Browse files
committed
Add example project showing how to use BrotliCFFI
1 parent 31f57cf commit d90fb5c

File tree

4 files changed

+177
-0
lines changed

4 files changed

+177
-0
lines changed

README.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ More information can be found `in the documentation`_.
1717
.. _available here: https://github.com/google/brotli
1818
.. _in the documentation: https://brotlipy.readthedocs.org
1919

20+
Using BrotliCFFI in Projects
21+
----------------------------
22+
23+
The API is 100% compatible with the `Brotli Python C bindings`_.
24+
We recommend installing the C bindings on CPython and the CFFI
25+
bindings everywhere else (PyPy, etc)
26+
27+
We provide an `example project`_ that shows how to use both
28+
libraries together to support Brotli with multiple Python implementations.
29+
30+
.. _Brotli Python C bindings: https://pypi.org/project/Brotli
31+
.. _example project: https://github.com/python-hyper/brotlipy/tree/master/example
32+
2033
License
2134
-------
2235

example/README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Example Project using C and CFFI Brotli Bindings
2+
3+
This simple example project shows how to include
4+
`brotlicffi` into projects supporting both CPython
5+
and other Python implementations like PyPy.
6+
7+
Basically it boils down to these two steps:
8+
9+
Include the two dependencies in your `install_requires`/`requirements.txt`:
10+
11+
```python
12+
# install_requires:
13+
from setuptools import setup
14+
15+
setup(
16+
...,
17+
install_requires=[
18+
"brotli; implementation_name == 'cpython'",
19+
"brotlicffi; implementation_name != 'cpython'"
20+
]
21+
)
22+
```
23+
24+
```
25+
# requirements.txt:
26+
brotli; implementation_name == 'cpython'
27+
brotlicffi; implementation_name != 'cpython'
28+
```
29+
30+
...then you can import the bindings in your project like so:
31+
32+
```python
33+
try:
34+
import brotlicffi as brotli
35+
except ImportError:
36+
import brotli
37+
```
38+
39+
It should be that simple! Now let's see our example project in action:
40+
41+
## Installing on CPython and PyPy
42+
43+
Build the project sdist locally
44+
45+
```
46+
$ cd example/
47+
$ python setup.py sdist
48+
$ ls dist/
49+
example-brotli-project-0.1.0.tar.gz
50+
```
51+
52+
### Installing on CPython
53+
54+
Run `python:3.7-slim` Docker image to test against CPython
55+
56+
```
57+
$ docker run --rm -it -v $(pwd)/dist:/dist python:3.7-slim /bin/bash
58+
```
59+
60+
Install the example project
61+
62+
```
63+
$ python -m pip install /dist/example-brotli-project-0.1.0.tar.gz
64+
Processing /dist/example-brotli-project-0.1.0.tar.gz
65+
Collecting brotli
66+
Downloading Brotli-1.0.9-cp37-cp37-manylinux1_x86_64.whl (357 kB)
67+
|████████████████████████████████| 357 kB 1.9 MB/s
68+
Building wheels for collected packages: example-brotli-project
69+
Building wheel for example-brotli-project (setup.py) ... done
70+
Created wheel for example-brotli-project: filename=example_brotli_project-0.1.0-py3-none-any.whl size=1976 sha256=b94975444c08cf82f395c8277e29b5b6f3b3270dd4f7d224482e4493be89c6bd
71+
Stored in directory: /root/.cache/pip/wheels/be/67/36/911a88789436560de345984e6c4c3785098e98b92dcbab5980
72+
Successfully built example-brotli-project
73+
Installing collected packages: brotli, example-brotli-project
74+
Successfully installed brotli-1.0.9 example-brotli-project-0.1.0
75+
```
76+
77+
Notice that `Brotli` is installed from PyPI instead of `brotlicffi` on CPython.
78+
79+
Now run the program and see the output:
80+
81+
```
82+
$ example-brotli-project "Hello, world!"
83+
Compressing data: b'Hello, world!'
84+
Compressed data: b'\x0b\x06\x80Hello, world!\x03'
85+
Decompressed data: b'Hello, world!'
86+
```
87+
88+
### Installing on PyPy
89+
90+
Run `pypy:3.7-slim` Docker image to test against PyPy
91+
92+
```
93+
$ docker run --rm -it -v $(pwd)/dist:/dist pypy:3.7-slim /bin/bash
94+
$ pypy -m pip install /dist/example-brotli-project-0.1.0.tar.gz
95+
Processing /dist/example-brotli-project-0.1.0.tar.gz
96+
Collecting brotlicffi
97+
Downloading brotlicffi-0.8.0-pp37-pypy37_pp73-manylinux1_x86_64.whl (341 kB)
98+
|████████████████████████████████| 341 kB 2.8 MB/s
99+
Requirement already satisfied: cffi>=1.0.0 in /opt/pypy/lib_pypy (from brotlicffi->example-brotli-project==0.1.0) (1.14.2)
100+
Building wheels for collected packages: example-brotli-project
101+
Building wheel for example-brotli-project (setup.py) ... done
102+
Created wheel for example-brotli-project: filename=example_brotli_project-0.1.0-py3-none-any.whl size=1976 sha256=566f5bfb3a0d74d11485b02b929a09d6e6cc8bab7c409cf30ff50f2067692356
103+
Stored in directory: /root/.cache/pip/wheels/cb/e1/0f/337346ea74252e5b652824bb0f2fc82e81208f9f8e3de42465
104+
Successfully built example-brotli-project
105+
Installing collected packages: brotlicffi, example-brotli-project
106+
Successfully installed brotlicffi-0.8.0 example-brotli-project-0.1.0
107+
```
108+
109+
Notice now that `brotlicffi` is installed from PyPI instead of `Brotli` on CPython.
110+
111+
Now run the program and see the output:
112+
113+
```
114+
$ example-brotli-project "Hello, world!"
115+
Compressing data: b'Hello, world!'
116+
Compressed data: b'\x0b\x06\x80Hello, world!\x03'
117+
Decompressed data: b'Hello, world!'
118+
```
119+
120+
Identical output compared to CPython! :tada:

example/example_brotli_project.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""A simple project that is compatible with both
2+
'brotli' C bindings and 'brotlicffi' CFFI bindings
3+
"""
4+
5+
import sys
6+
7+
try:
8+
import brotlicffi as brotli
9+
except ImportError:
10+
import brotli
11+
12+
13+
def main():
14+
data = sys.argv[1].encode("utf-8")
15+
print(f"Compressing data: {data}")
16+
17+
compressor = brotli.Compressor(mode=brotli.MODE_TEXT)
18+
compressed = compressor.process(data) + compressor.finish()
19+
print(f"Compressed data: {compressed}")
20+
21+
decompressor = brotli.Decompressor()
22+
decompressed = decompressor.process(compressed) + decompressor.finish()
23+
print(f"Decompressed data: {decompressed}")
24+
25+
26+
if __name__ == "__main__":
27+
main()

example/setup.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from setuptools import setup
2+
3+
4+
setup(
5+
name="example-brotli-project",
6+
version="0.1.0",
7+
py_modules=["example_brotli_project"],
8+
install_requires=[
9+
"brotli; implementation_name == 'cpython'",
10+
"brotlicffi; implementation_name != 'cpython'"
11+
],
12+
entry_points={
13+
"console_scripts": [
14+
"example-brotli-project=example_brotli_project:main"
15+
]
16+
}
17+
)

0 commit comments

Comments
 (0)