When installing package using Poetry on Python 3.14 we have compilation
errors:
```
copying src/greenlet/platform/setup_switch_x64_masm.cmd -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_aarch64_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_alpha_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_amd64_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_arm32_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_arm32_ios.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_arm64_masm.asm -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_arm64_masm.obj -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_arm64_msvc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_csky_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_loongarch64_linux.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_m68k_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_mips_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_ppc64_aix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_ppc64_linux.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_ppc_aix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_ppc_linux.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_ppc_macosx.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_ppc_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_riscv_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_s390_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_sh_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_sparc_sun_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_x32_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_x64_masm.asm -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_x64_masm.obj -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_x64_msvc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_x86_msvc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/platform/switch_x86_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
| copying src/greenlet/tests/_test_extension.c -> build/lib.linux-x86_64-cpython-314/greenlet/tests
| copying src/greenlet/tests/_test_extension_cpp.cpp -> build/lib.linux-x86_64-cpython-314/greenlet/tests
| running build_ext
| building 'greenlet._greenlet' extension
| creating build/temp.linux-x86_64-cpython-314/src/greenlet
| c++ -pthread -fno-strict-overflow -Wsign-compare -Wunreachable-code -DNDEBUG -g -O3 -Wall -O3 -fPIC -fPIC -I/tmp/tmp55zvtgm3/.venv/include -I/home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14 -c src/greenlet/greenlet.cpp -o build/temp.linux-x86_64-cpython-314/src/greenlet/greenlet.o
| In file included from src/greenlet/greenlet.cpp:31:
| src/greenlet/TGreenlet.cpp: In member function ‘void greenlet::Greenlet::expose_frames()’:
| src/greenlet/TGreenlet.cpp:626:29: error: aggregate ‘_PyInterpreterFrame iframe_copy’ has incomplete type and cannot be defined
| 626 | _PyInterpreterFrame iframe_copy;
| | ^~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:627:65: error: invalid application of ‘sizeof’ to incomplete type ‘_PyInterpreterFrame’
| 627 | this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe));
| | ^~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:628:14: error: ‘_PyFrame_IsIncomplete’ was not declared in this scope
| 628 | if (!_PyFrame_IsIncomplete(&iframe_copy)) {
| | ^~~~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:654:24: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 654 | if (!iframe->frame_obj) {
| | ^~
| In file included from /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/pyframe.h:19,
| from /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/Python.h:113,
| from src/greenlet/greenlet.cpp:16:
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:656:37: error: aggregate ‘_PyInterpreterFrame dummy_iframe’ has incomplete type and cannot be defined
| 656 | _PyInterpreterFrame dummy_iframe;
| | ^~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:661:38: error: ‘FRAME_OWNED_BY_GENERATOR’ was not declared in this scope
| 661 | dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR;
| | ^~~~~~~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:686:45: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 686 | memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:687:45: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 687 | &last_complete_iframe->previous, sizeof(void *));
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:688:37: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 688 | last_complete_iframe->previous = iframe;
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:705:37: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 705 | memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:706:37: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 706 | &last_complete_iframe->previous, sizeof(void *));
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TGreenlet.cpp:707:29: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 707 | last_complete_iframe->previous = nullptr;
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| In file included from src/greenlet/greenlet.cpp:36:
| src/greenlet/TPythonState.cpp: In member function ‘void greenlet::PythonState::operator<<(const PyThreadState*)’:
| src/greenlet/TPythonState.cpp:137:31: error: ‘Py_C_RECURSION_LIMIT’ was not declared in this scope
| 137 | this->c_recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
| | ^~~~~~~~~~~~~~~~~~~~
| src/greenlet/TPythonState.cpp:137:62: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘c_recursion_remaining’; did you mean ‘py_recursion_remaining’?
| 137 | this->c_recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
| | ^~~~~~~~~~~~~~~~~~~~~
| | py_recursion_remaining
| src/greenlet/TPythonState.cpp: In member function ‘void greenlet::PythonState::unexpose_frames()’:
| src/greenlet/TPythonState.cpp:179:51: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 179 | _PyInterpreterFrame *prev_exposed = iframe->previous;
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TPythonState.cpp:181:23: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 181 | memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0],
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TPythonState.cpp:181:42: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 181 | memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0],
| | ^~
| /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
| 25 | struct _PyInterpreterFrame;
| | ^~~~~~~~~~~~~~~~~~~
| src/greenlet/TPythonState.cpp: In member function ‘void greenlet::PythonState::operator>>(PyThreadState*)’:
| src/greenlet/TPythonState.cpp:212:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘c_recursion_remaining’; did you mean ‘py_recursion_remaining’?
| 212 | tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT - this->c_recursion_depth;
| | ^~~~~~~~~~~~~~~~~~~~~
| | py_recursion_remaining
| src/greenlet/TPythonState.cpp:212:37: error: ‘Py_C_RECURSION_LIMIT’ was not declared in this scope
| 212 | tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT - this->c_recursion_depth;
| | ^~~~~~~~~~~~~~~~~~~~
| error: command '/usr/bin/c++' failed with exit code 1
```
This due to the fact we are not installing a recent greenlet version
(3.1.1) due to the Python restriction.
By upgrading the minium Python version to 3.10 (minimum version
supported by the PSF https://devguide.python.org/versions/) the greenlet
module is now 3.3.1, it's the last available release.
Camoufox Python Interface
Lightweight wrapper around the Playwright API to help launch Camoufox.
Note
All the the latest documentation is avaliable here.
What is this?
This Python library wraps around Playwright's API to help automatically generate & inject unique device characteristics (OS, CPU info, navigator, fonts, headers, screen dimensions, viewport size, WebGL, addons, etc.) into Camoufox.
It uses BrowserForge under the hood to generate fingerprints that mimic the statistical distribution of device characteristics in real-world traffic.
In addition, it will also calculate your target geolocation, timezone, and locale to avoid proxy protection (see demo).
Installation
First, install the camoufox package:
pip install -U camoufox[geoip]
The geoip parameter is optional, but heavily recommended if you are using proxies. It will download an extra dataset to determine the user's longitude, latitude, timezone, country, & locale.
Next, download the Camoufox browser:
Windows
camoufox fetch
MacOS & Linux
python3 -m camoufox fetch
To uninstall, run camoufox remove.
CLI options
Usage: python -m camoufox [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
fetch Fetch the latest version of Camoufox
path Display the path to the Camoufox executable
remove Remove all downloaded files
server Launch a Playwright server
test Open the Playwright inspector
version Display the current version
Usage
All of the latest documentation is avaliable at camoufox.com/python.