├── .dockerignore ├── .editorconfig ├── .flake8 ├── .github ├── issue_template.md └── workflows │ ├── build.yml │ └── pre-commit.yml ├── .gitignore ├── .isort.cfg ├── .pre-commit-config.yaml ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── data └── py_mini_racer.png ├── docs ├── Makefile ├── api.rst ├── authors.rst ├── conf.py ├── contributing.rst ├── history.rst ├── index.rst ├── make.bat └── readme.rst ├── helpers ├── babel.py ├── build_package.py ├── v8_build.py └── wheel_pymalloc.py ├── py_mini_racer ├── __about__.py ├── __init__.py ├── extension │ ├── .editorconfig │ ├── .gitignore │ ├── .gn │ ├── BUILD.gn │ ├── __init__.py │ └── mini_racer_extension.cc └── py_mini_racer.py ├── setup.py ├── tests ├── add.wasm ├── fixtures │ └── babel.js ├── test_babel.py ├── test_call.py ├── test_eval.py ├── test_heap.py ├── test_strict.py ├── test_types.py └── test_wasm.py └── tox.ini /.dockerignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | py_mini_racer/extension/v8/ 3 | vendor/depot_tools/ 4 | Dockerfile 5 | Makefile 6 | wheelhouse 7 | dist 8 | build 9 | docker 10 | Dockerfile.build 11 | docker-compose.yml 12 | Makefile 13 | *.whl 14 | **/*.so 15 | .git 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = 3 | E203, 4 | E501, 5 | W503 6 | exclude = 7 | .tox, 8 | docs/conf.py, 9 | build, 10 | py_mini_racer/extension 11 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Steps to reproduce 2 | 3 | ### Expected behavior 4 | Tell us what should happen 5 | 6 | ### Actual behavior 7 | Tell us what happens instead 8 | 9 | ### System configuration 10 | **PyMiniRacer version**: 11 | 12 | **Python version**: 13 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: [master] 5 | pull_request: 6 | branches: [master] 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | build: 14 | name: ${{ matrix.config.plat_name }} 15 | strategy: 16 | matrix: 17 | config: 18 | - os: ubuntu-16.04 19 | plat_name: manylinux1_x86_64 20 | - os: macos-10.15 21 | plat_name: macosx_10_10_x86_64 22 | - os: windows-2019 23 | plat_name: win_amd64 24 | fail-fast: true 25 | runs-on: ${{ matrix.config.os }} 26 | timeout-minutes: 180 27 | steps: 28 | - name: Configure git 29 | run: git config --global core.symlinks true 30 | 31 | - name: Clone repository 32 | uses: actions/checkout@v1 33 | 34 | - name: Install python 3.6 35 | uses: actions/setup-python@v1 36 | with: 37 | python-version: 3.6.x 38 | architecture: x64 39 | 40 | - name: Install python 2.7 41 | uses: actions/setup-python@v1 42 | with: 43 | python-version: 2.7.x 44 | architecture: x64 45 | 46 | - name: Build wheelhouse 47 | run: | 48 | python3 -m pip install setuptools wheel 49 | mkdir wheelhouse 50 | python3 helpers/build_package.py wheel wheelhouse 51 | shell: bash 52 | 53 | - name: Archive wheelhouse 54 | uses: actions/upload-artifact@v2 55 | with: 56 | name: package-${{ matrix.config.plat_name }} 57 | path: wheelhouse 58 | 59 | - name: Check the wheel 60 | if: matrix.config.plat_name == 'manylinux1_x86_64' 61 | run: | 62 | python3 -m pip install auditwheel twine readme_renderer[md] 63 | auditwheel show wheelhouse/*.whl 64 | twine check wheelhouse/*.whl 65 | 66 | - name: Test 67 | run: | 68 | python3 -m pip install pytest wheelhouse/*.whl 69 | pytest tests 70 | shell: bash 71 | 72 | build-on-alpine: 73 | name: alpine_x86_64 74 | runs-on: ubuntu-latest 75 | container: 76 | image: nicolassqreen/azure-pipelines-container-alpine-python:3.12 77 | timeout-minutes: 180 78 | steps: 79 | - name: Clone repository 80 | uses: actions/checkout@v1 81 | 82 | - name: Download V8 sources 83 | uses: docker://python:2 84 | with: 85 | args: python helpers/v8_build.py --no-build --no-sysroot 86 | 87 | - name: Prepare Aline Linux build environment 88 | run: | 89 | sudo apk -U add samurai llvm lld linux-headers binutils-gold 90 | cp -f /usr/local/bin/gn py_mini_racer/extension/v8/buildtools/linux64/gn 91 | rm -f py_mini_racer/extension/depot_tools/ninja 92 | 93 | - name: Build the extension 94 | run: | 95 | python helpers/v8_build.py --no-update --no-sysroot --target py_mini_racer_shared_lib 96 | cp py_mini_racer/extension/out/libmini_racer.so py_mini_racer/libmini_racer.muslc.so 97 | 98 | - name: Build the wheelhouse 99 | run: | 100 | sudo apk add py3-pip py3-wheel 101 | mkdir wheelhouse 102 | python3 setup.py sdist --dist-dir wheelhouse 103 | 104 | - name: Archive wheelhouse 105 | uses: actions/upload-artifact@v2 106 | with: 107 | name: package-alpine_x86_64 108 | path: wheelhouse 109 | 110 | - name: Test 111 | run: | 112 | python3 -m pip install pytest wheelhouse/*.tar.gz 113 | pytest tests 114 | 115 | release: 116 | if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') 117 | runs-on: ubuntu-latest 118 | needs: [build-on-alpine, build] 119 | steps: 120 | - name: Download packages 121 | uses: actions/download-artifact@v2 122 | with: 123 | path: tmp 124 | 125 | - name: Move packages to the wheelhouse 126 | run: | 127 | mkdir wheelhouse 128 | find tmp -name '*.whl' -exec mv {} wheelhouse \; 129 | find tmp -name '*.tar.gz' -exec mv {} wheelhouse \; 130 | shell: bash 131 | 132 | - name: Publish 📦 to PyPI 133 | uses: pypa/gh-action-pypi-publish@v1.4.2 134 | with: 135 | user: __token__ 136 | password: ${{ secrets.PYPI_TOKEN }} 137 | packages_dir: wheelhouse/ 138 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: Linter Checks 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | pre-commit: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: actions/setup-python@v1 11 | with: 12 | python-version: 3.8 13 | - uses: actions/cache@v1 14 | with: 15 | path: ~/.cache/pre-commit 16 | key: pre-commit|${{ hashFiles('.pre-commit-config.yaml') }} 17 | - uses: pre-commit/action@v1.0.1 18 | with: 19 | token: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | *.dylib 9 | *.dll 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | venv/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *,cover 49 | .hypothesis/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | 58 | # Sphinx documentation 59 | docs/_build/ 60 | 61 | # PyBuilder 62 | target/ 63 | 64 | # V8 vendor 65 | py_mini_racer/extension/.cipd 66 | py_mini_racer/extension/.gclient* 67 | py_mini_racer/extension/v8 68 | py_mini_racer/extension/out 69 | py_mini_racer/extension/depot_tools 70 | py_mini_racer/extension/build 71 | py_mini_racer/extension/build_overrides 72 | py_mini_racer/extension/buildtools 73 | py_mini_racer/extension/testing 74 | py_mini_racer/extension/third_party 75 | py_mini_racer/extension/tools 76 | 77 | *.iml 78 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | combine_as_imports = True 3 | default_section = THIRDPARTY 4 | force_grid_wrap = 0 5 | include_trailing_comma = True 6 | known_first_party = py_mini_racer 7 | multi_line_output = 3 8 | skip_glob = 9 | .venv.* 10 | skip = 11 | .asv, 12 | .tox, 13 | docs, 14 | py_mini_racer/extension 15 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | - repo: https://github.com/PyCQA/flake8 5 | rev: 3.7.9 6 | hooks: 7 | - id: flake8 8 | - repo: https://github.com/timothycrosley/isort 9 | rev: 5.6.4 10 | hooks: 11 | - id: isort 12 | - repo: https://github.com/pre-commit/pre-commit-hooks 13 | rev: v2.4.0 14 | hooks: 15 | - id: trailing-whitespace 16 | exclude: \.patch$ 17 | - id: end-of-file-fixer 18 | exclude: \.patch$ 19 | - id: check-yaml 20 | - id: check-added-large-files 21 | - repo: local 22 | hooks: 23 | - id: clang-format 24 | name: Check C++ format 25 | entry: clang-format 26 | language: system 27 | files: py_mini_racer/extension/mini_racer_extension.cc 28 | args: ['-style=Chromium', '-i'] 29 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Authors 6 | ------- 7 | 8 | * Jean-Baptiste AVIAT 9 | * Boris FELD 10 | * Selim MENOUAR 11 | * Nicolas VIVET 12 | 13 | Contributors 14 | ------------ 15 | 16 | * messense https://github.com/messense 17 | 18 | Why not add your name to the list? 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | You can contribute in many ways: 9 | 10 | Types of Contributions 11 | ---------------------- 12 | 13 | Report Bugs 14 | ~~~~~~~~~~~ 15 | 16 | Report bugs at https://github.com/sqreen/PyMiniRacer/issues. 17 | 18 | If you are reporting a bug, please include: 19 | 20 | * Your operating system name and version. 21 | * Any details about your local setup that might be helpful in troubleshooting. 22 | * Detailed steps to reproduce the bug. 23 | 24 | Fix Bugs 25 | ~~~~~~~~ 26 | 27 | Look through the GitHub issues for bugs. Anything tagged with "bug" 28 | is open to whoever wants to implement it. 29 | 30 | Implement Features 31 | ~~~~~~~~~~~~~~~~~~ 32 | 33 | Look through the GitHub issues for features. Anything tagged with "feature" 34 | is open to whoever wants to implement it. 35 | 36 | Write Documentation 37 | ~~~~~~~~~~~~~~~~~~~ 38 | 39 | Python Mini Racer could always use more documentation, whether as part of the 40 | official Python Mini Racer docs, in docstrings, or even on the web in blog posts, 41 | articles, and such. 42 | 43 | Submit Feedback 44 | ~~~~~~~~~~~~~~~ 45 | 46 | The best way to send feedback is to file an issue at https://github.com/sqreen/PyMiniRacer/issues. 47 | 48 | If you are proposing a feature: 49 | 50 | * Explain in detail how it would work. 51 | * Keep the scope as narrow as possible, to make it easier to implement. 52 | * Remember that this is a volunteer-driven project, and that contributions 53 | are welcome :) 54 | 55 | Get Started! 56 | ------------ 57 | 58 | Ready to contribute? Here's how to set up `PyMiniRacer` for local development. 59 | 60 | 1. Fork the `PyMiniRacer` repo on GitHub. 61 | 2. Clone your fork locally:: 62 | 63 | $ git clone git@github.com:your_name_here/PyMiniRacer.git 64 | 65 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 66 | 67 | $ mkvirtualenv PyMiniRacer 68 | $ cd PyMiniRacer/ 69 | $ python helpers/v8_build.py 70 | $ python setup.py develop 71 | 72 | **Warning**: building this package from source takes several GB of disk space and takes ~60 minutes. 73 | 74 | 4. Create a branch for local development:: 75 | 76 | $ git checkout -b name-of-your-bugfix-or-feature 77 | 78 | Now you can make your changes locally. 79 | 80 | 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: 81 | 82 | $ flake8 py_mini_racer tests 83 | $ python setup.py test 84 | $ tox 85 | 86 | To get flake8 and tox, just pip install them into your virtualenv. 87 | 88 | 6. Commit your changes and push your branch to GitHub:: 89 | 90 | $ git add . 91 | $ git commit -m "Your detailed description of your changes." 92 | $ git push origin name-of-your-bugfix-or-feature 93 | 94 | 7. Submit a pull request through the GitHub website. 95 | 96 | Pull Request Guidelines 97 | ----------------------- 98 | 99 | Before you submit a pull request, check that it meets these guidelines: 100 | 101 | 1. The pull request should include tests. 102 | 2. If the pull request adds functionality, the docs should be updated. Put 103 | your new functionality into a function with a docstring, and add the 104 | feature to the list in README.rst. 105 | 3. The pull request should work for Python 2.7, at least 3.5 and for PyPy. 106 | 107 | Tips 108 | ---- 109 | 110 | To run a subset of tests:: 111 | 112 | $ python -m unittest tests.test_eval 113 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | .. :changelog: 2 | 3 | History 4 | ------- 5 | 6 | 0.6.0 (2020-04-20) 7 | ''''''''''''''''''' 8 | * Update V8 to 8.9 9 | * Optimize function calls without arguments 10 | * Switch V8 to single threaded mode to avoid crashes after fork 11 | * Switch to strict mode by default 12 | * Revamp documentation 13 | 14 | 0.5.0 (2020-02-25) 15 | ''''''''''''''''''' 16 | * Update V8 to 8.8 17 | 18 | 0.4.0 (2020-09-22) 19 | ''''''''''''''''''' 20 | * Universal wheels for Linux, Mac and Windows 21 | * Fallback to source package for Alpine Linux 22 | 23 | 0.3.0 (2020-06-29) 24 | ''''''''''''''''''' 25 | * Introduce a strict mode 26 | * Fix array conversion when size changes dynamically (CVE-2020-25489) 27 | 28 | 0.2.0 (2020-03-11) 29 | ''''''''''''''''''' 30 | * Support for Alpine Linux 31 | * Avoid pip private modules in setup.py 32 | 33 | 0.2.0b1 (2020-01-09) 34 | ''''''''''''''''''''' 35 | * Support for Windows 64 bits 36 | * Support for Python 3.8 37 | * Upgrade V8 to 7.8 38 | * Support soft memory limits 39 | 40 | 0.1.18 (2019-01-04) 41 | '''''''''''''''''''' 42 | * Support memory and time limits 43 | 44 | 0.1.17 (2018-19-12) 45 | '''''''''''''''''''' 46 | * Upgrade libv8 47 | * Fix a memory leak 48 | 49 | 0.1.16 (2018-07-11) 50 | '''''''''''''''''''' 51 | * Add wheel for Python without PyMalloc 52 | 53 | 0.1.15 (2018-06-18) 54 | '''''''''''''''''''' 55 | * Add wheel for Python 3.7 56 | 57 | 58 | 0.1.14 (2018-05-25) 59 | '''''''''''''''''''' 60 | * Add support for pip 10 61 | * Update package metadata 62 | 63 | 0.1.13 (2018-03-15) 64 | '''''''''''''''''''' 65 | * Add heap_stats function 66 | * Fix issue with returned strings containing null bytes 67 | 68 | 0.1.12 (2018-17-04) 69 | '''''''''''''''''''' 70 | * Remove dependency to enum 71 | 72 | 0.1.11 (2017-07-11) 73 | '''''''''''''''''''' 74 | * Add compatibility for centos6 75 | 76 | 0.1.10 (2017-03-31) 77 | '''''''''''''''''''' 78 | * Add the possibility to pass a custom JSON encoder in call. 79 | 80 | 0.1.9 (2017-03-24) 81 | ''''''''''''''''''' 82 | * Fix the compilation for Ubuntu 12.04 and glibc < 2.17. 83 | 84 | 0.1.8 (2017-03-02) 85 | ''''''''''''''''''' 86 | * Update targets build for better compatibility with old Mac OS X and linux platforms. 87 | 88 | 0.1.7 (2016-10-04) 89 | ''''''''''''''''''' 90 | * Improve general performances of the JS execution. 91 | * Add the possibility to build a different version of V8 (for example with debug symbols). 92 | * Fix a conflict that could happens between statically linked libraries and dynamic ones. 93 | 94 | 0.1.6 (2016-08-12) 95 | ''''''''''''''''''' 96 | * Add error message when py_mini_racer sdist fails to build asking to update pip in order to download the pre-compiled wheel instead of the source distribution. 97 | 98 | 0.1.5 (2016-08-04) 99 | ''''''''''''''''''' 100 | * Build py_mini_racer against a static Python. When built against a shared library python, it doesn't work with a static Python. 101 | 102 | 0.1.4 (2016-08-04) 103 | ''''''''''''''''''' 104 | * Ensure JSEvalException message is converted to unicode 105 | 106 | 0.1.3 (2016-08-04) 107 | ''''''''''''''''''' 108 | * Fix extension loading for python3 109 | * Add a make target for building distributions (sdist + wheels) 110 | * Fix eval conversion for python 3 111 | 112 | 0.1.2 (2016-08-03) 113 | ''''''''''''''''''' 114 | * Fix date support 115 | * Fix Dockerfile for generating python3 wheels 116 | 117 | 118 | 0.1.1 (2016-08-02) 119 | ''''''''''''''''''' 120 | * Fix sdist distribution. 121 | 122 | 123 | 0.1.0 (2016-08-01) 124 | ''''''''''''''''''' 125 | * First release on PyPI. 126 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Sqreen 2 | All rights reserved. 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any 5 | purpose with or without fee is hereby granted, provided that the above 6 | copyright notice and this permission notice appear in all copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | 7 | include py_mini_racer/libmini_racer.glibc.so py_mini_racer/libmini_racer.muslc.so 8 | include py_mini_racer/libmini_racer.dylib 9 | include py_mini_racer/mini_racer.dll 10 | 11 | recursive-include tests * 12 | recursive-exclude * __pycache__ 13 | recursive-exclude * *.py[co] 14 | 15 | recursive-include docs *.rst conf.py 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-build docs clean 2 | define BROWSER_PYSCRIPT 3 | import os, webbrowser, sys 4 | try: 5 | from urllib import pathname2url 6 | except: 7 | from urllib.request import pathname2url 8 | 9 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 10 | endef 11 | export BROWSER_PYSCRIPT 12 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 13 | 14 | help: 15 | @echo "clean - remove all build, test, coverage and Python artifacts" 16 | @echo "clean-build - remove build artifacts" 17 | @echo "clean-pyc - remove Python file artifacts" 18 | @echo "clean-test - remove test and coverage artifacts" 19 | @echo "lint - check style with flake8" 20 | @echo "test - run tests quickly with the default Python" 21 | @echo "test-all - run tests on every Python version with tox" 22 | @echo "coverage - check code coverage quickly with the default Python" 23 | @echo "docs - generate Sphinx HTML documentation, including API docs" 24 | @echo "release - package and upload a release" 25 | @echo "dist - package" 26 | @echo "install - install the package to the active Python's site-packages" 27 | 28 | clean: clean-build clean-pyc clean-test 29 | 30 | clean-build: 31 | rm -fr build/ 32 | rm -fr dist/ 33 | rm -fr .eggs/ 34 | rm -fr venv* 35 | rm -Rf py_mini_racer/*.so 36 | find . -name '*.egg-info' -exec rm -fr {} + 37 | find . -name '*.egg' -exec rm -f {} + 38 | 39 | clean-pyc: 40 | find . -name '*.pyc' -exec rm -f {} + 41 | find . -name '*.pyo' -exec rm -f {} + 42 | find . -name '*~' -exec rm -f {} + 43 | find . -name '__pycache__' -exec rm -fr {} + 44 | 45 | clean-test: 46 | rm -fr .tox/ 47 | rm -f .coverage 48 | rm -fr htmlcov/ 49 | 50 | lint: 51 | flake8 py_mini_racer tests 52 | 53 | test: 54 | python setup.py test 55 | 56 | test-all: 57 | tox 58 | 59 | coverage: 60 | coverage run --source py_mini_racer setup.py test 61 | coverage report -m 62 | coverage html 63 | $(BROWSER) htmlcov/index.html 64 | 65 | docs: 66 | rm -f docs/py_mini_racer.rst 67 | rm -f docs/modules.rst 68 | sphinx-apidoc -o docs/ py_mini_racer 69 | $(MAKE) -C docs clean 70 | $(MAKE) -C docs html 71 | $(BROWSER) docs/_build/html/index.html 72 | 73 | servedocs: docs 74 | watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . 75 | 76 | release: clean 77 | python setup.py sdist upload 78 | python setup.py bdist_wheel upload 79 | 80 | dist: clean 81 | python setup.py sdist 82 | python setup.py bdist_wheel 83 | ls -l dist 84 | 85 | upload: dist 86 | twine upload dist/* 87 | 88 | install: clean 89 | python setup.py install 90 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | **This package is now deprecated. Go to https://github.com/bpcreech/PyMiniRacer for an up-to-date version.** 2 | 3 | .. image:: https://img.shields.io/pypi/v/py_mini_racer.svg 4 | :target: https://pypi.python.org/pypi/py_mini_racer 5 | 6 | .. image:: https://github.com/sqreen/PyMiniRacer/actions/workflows/build.yml/badge.svg 7 | :target: https://github.com/sqreen/PyMiniRacer/actions/workflows/build.yml 8 | 9 | .. image:: https://img.shields.io/badge/License-ISC-blue.svg 10 | :target: https://opensource.org/licenses/ISC 11 | 12 | Minimal, modern embedded V8 for Python. 13 | 14 | Features 15 | -------- 16 | 17 | * Latest ECMAScript support 18 | * Web Assembly support 19 | * Unicode support 20 | * Thread safe 21 | * Re-usable contexts 22 | 23 | MiniRacer can be easily used by Django or Flask projects to minify assets, run 24 | babel or WASM modules. 25 | 26 | Examples 27 | -------- 28 | 29 | MiniRacer is straightforward to use: 30 | 31 | .. code-block:: python 32 | 33 | >>> from py_mini_racer import MiniRacer 34 | >>> ctx = MiniRacer() 35 | >>> ctx.eval("1+1") 36 | 2 37 | >>> ctx.eval("var x = {company: 'Sqreen'}; x.company") 38 | 'Sqreen' 39 | >>> print(ctx.eval("'\N{HEAVY BLACK HEART}'")) 40 | ❤ 41 | >>> ctx.eval("var fun = () => ({ foo: 1 });") 42 | 43 | Variables are kept inside of a context: 44 | 45 | .. code-block:: python 46 | 47 | >>> ctx.eval("x.company") 48 | 'Sqreen' 49 | 50 | 51 | While ``eval`` only supports returning primitive data types such as 52 | strings, ``call`` supports returning composite types such as objects: 53 | 54 | .. code-block:: python 55 | 56 | >>> ctx.call("fun") 57 | {'foo': 1} 58 | 59 | 60 | Composite values are serialized using JSON. 61 | Use a custom JSON encoder when sending non-JSON encodable parameters: 62 | 63 | .. code-block:: python 64 | 65 | import json 66 | 67 | from datetime import datetime 68 | 69 | class CustomEncoder(json.JSONEncoder): 70 | 71 | def default(self, obj): 72 | if isinstance(obj, datetime): 73 | return obj.isoformat() 74 | 75 | return json.JSONEncoder.default(self, obj) 76 | 77 | 78 | .. code-block:: python 79 | 80 | >>> ctx.eval("var f = function(args) { return args; }") 81 | >>> ctx.call("f", datetime.now(), encoder=CustomEncoder) 82 | '2017-03-31T16:51:02.474118' 83 | 84 | 85 | MiniRacer is ES6 capable: 86 | 87 | .. code-block:: python 88 | 89 | >>> ctx.execute("[1,2,3].includes(5)") 90 | False 91 | 92 | V8 heap information can be retrieved: 93 | 94 | .. code-block:: python 95 | 96 | >>> ctx.heap_stats() 97 | {'total_physical_size': 1613896, 98 | 'used_heap_size': 1512520, 99 | 'total_heap_size': 3997696, 100 | 'total_heap_size_executable': 3145728, 101 | 'heap_size_limit': 1501560832} 102 | 103 | 104 | A WASM example is available in the `tests`_. 105 | 106 | .. _`tests`: https://github.com/sqreen/PyMiniRacer/blob/master/tests/test_wasm.py 107 | 108 | 109 | Compatibility 110 | ------------- 111 | 112 | PyMiniRacer is compatible with Python 2 & 3 and based on ctypes. 113 | 114 | The binary builds have been tested on x86_64 with: 115 | 116 | * macOS >= 10.13 117 | * Ubuntu >= 16.04 118 | * Debian >= 9 119 | * CentOS >= 7 120 | * Alpine >= 3.11 121 | * Windows 10 122 | 123 | It should work on any Linux with a libc >= 2.12 and a wheel compatible pip (>= 8.1). 124 | 125 | If you're running Alpine Linux, you may need to install required dependencies manually using the following command: 126 | 127 | .. code-block:: bash 128 | 129 | $ apk add libgcc libstdc++ 130 | 131 | If you have a up-to-date pip and it doesn't use a wheel, you might have an environment for which no wheel is built. Please open an issue. 132 | 133 | Installation 134 | ------------ 135 | 136 | We built Python wheels (prebuilt binaries) for macOS 64 bits, Linux 64 bits and Windows 64 bits. 137 | 138 | .. code:: bash 139 | 140 | $ pip install py-mini-racer 141 | 142 | Build 143 | ----- 144 | 145 | **Warning**: building this package from source takes several GB of disk space and takes ~60 minutes. 146 | 147 | First check that your current Python executable is version 2.7. This is required 148 | by the V8 build system. 149 | 150 | .. code:: bash 151 | 152 | $ python --version 153 | Python 2.7.16 154 | 155 | You can build the extension with the following command: 156 | 157 | .. code:: bash 158 | 159 | $ python helpers/v8_build.py 160 | 161 | You can generate a wheel for whatever Python version with the command: 162 | 163 | .. code:: bash 164 | 165 | $ python3 helpers/build_package.py wheel dist 166 | 167 | It will then build V8, the extension, and generates a wheel for your current 168 | Python version. The V8 builds are cached in the ``py_mini_racer/extension/v8/`` 169 | directory. 170 | 171 | Notes for building on macOS 172 | ''''''''''''''''''''''''''' 173 | 174 | The legacy Python binary builds (OSX 10.6) need to be downloaded from: 175 | https://www.python.org/downloads/ 176 | 177 | They will allow to build a wheel compatible with former OSX versions. 178 | 179 | Tests 180 | ----- 181 | 182 | If you want to run the tests, you need to build the extension first, first install pytest: 183 | 184 | .. code-block:: bash 185 | 186 | $ python -m pip install pytest 187 | 188 | Then launch: 189 | 190 | .. code:: bash 191 | 192 | $ python -m pytest tests 193 | 194 | Credits 195 | ------- 196 | 197 | Built with love by Sqreen_. 198 | 199 | .. _Sqreen: https://www.sqreen.com 200 | 201 | PyMiniRacer launch was described in `this blog post`_. 202 | 203 | .. _`this blog post`: https://blog.sqreen.com/embedding-javascript-into-python/ 204 | 205 | PyMiniRacer is inspired by mini_racer_, built for the Ruby world by Sam Saffron. 206 | 207 | .. _`mini_racer`: https://github.com/SamSaffron/mini_racer 208 | 209 | `Cookiecutter-pypackage`_ was used as this package skeleton. 210 | 211 | .. _`Cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage 212 | -------------------------------------------------------------------------------- /data/py_mini_racer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/PyMiniRacer/6eb2dc5e5d7dc772b5edfa01c4b163230d6491c4/data/py_mini_racer.png -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/py_mini_racer.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/py_mini_racer.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/py_mini_racer" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/py_mini_racer" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ------------- 3 | 4 | .. autoclass:: py_mini_racer.MiniRacer 5 | :members: eval, execute, call, set_soft_memory_limit, was_soft_memory_limit_reached, low_memory_notification, heap_stats, v8_version 6 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # py_mini_racer documentation build configuration file, created by 5 | # sphinx-quickstart on Tue Jul 9 22:26:36 2013. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import sys 17 | import os 18 | 19 | # If extensions (or modules to document with autodoc) are in another 20 | # directory, add these directories to sys.path here. If the directory is 21 | # relative to the documentation root, use os.path.abspath to make it 22 | # absolute, like shown here. 23 | #sys.path.insert(0, os.path.abspath('.')) 24 | 25 | # Get the project root dir, which is the parent dir of this 26 | cwd = os.getcwd() 27 | project_root = os.path.dirname(cwd) 28 | 29 | # Insert the project root dir as the first element in the PYTHONPATH. 30 | # This lets us ensure that the source package is imported, and that its 31 | # version is used. 32 | sys.path.insert(0, project_root) 33 | 34 | from py_mini_racer import __about__ 35 | 36 | # -- General configuration --------------------------------------------- 37 | 38 | # If your documentation needs a minimal Sphinx version, state it here. 39 | #needs_sphinx = '1.0' 40 | 41 | # Add any Sphinx extension module names here, as strings. They can be 42 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 43 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] 44 | 45 | autodoc_member_order = 'bysource' 46 | 47 | # Add any paths that contain templates here, relative to this directory. 48 | templates_path = ['_templates'] 49 | 50 | # The suffix of source filenames. 51 | source_suffix = '.rst' 52 | 53 | # The encoding of source files. 54 | #source_encoding = 'utf-8-sig' 55 | 56 | # The master toctree document. 57 | master_doc = 'index' 58 | 59 | # General information about the project. 60 | project = u'PyMiniRacer' 61 | copyright = u'2019, Sqreen' 62 | 63 | # The version info for the project you're documenting, acts as replacement 64 | # for |version| and |release|, also used in various other places throughout 65 | # the built documents. 66 | # 67 | # The short X.Y version. 68 | version = __about__.__version__ 69 | # The full version, including alpha/beta/rc tags. 70 | release = __about__.__version__ 71 | 72 | # The language for content autogenerated by Sphinx. Refer to documentation 73 | # for a list of supported languages. 74 | #language = None 75 | 76 | # There are two options for replacing |today|: either, you set today to 77 | # some non-false value, then it is used: 78 | #today = '' 79 | # Else, today_fmt is used as the format for a strftime call. 80 | #today_fmt = '%B %d, %Y' 81 | 82 | # List of patterns, relative to source directory, that match files and 83 | # directories to ignore when looking for source files. 84 | exclude_patterns = ['_build'] 85 | 86 | # The reST default role (used for this markup: `text`) to use for all 87 | # documents. 88 | #default_role = None 89 | 90 | # If true, '()' will be appended to :func: etc. cross-reference text. 91 | #add_function_parentheses = True 92 | 93 | # If true, the current module name will be prepended to all description 94 | # unit titles (such as .. function::). 95 | #add_module_names = True 96 | 97 | # If true, sectionauthor and moduleauthor directives will be shown in the 98 | # output. They are ignored by default. 99 | #show_authors = False 100 | 101 | # The name of the Pygments (syntax highlighting) style to use. 102 | pygments_style = 'sphinx' 103 | 104 | # A list of ignored prefixes for module index sorting. 105 | #modindex_common_prefix = [] 106 | 107 | # If true, keep warnings as "system message" paragraphs in the built 108 | # documents. 109 | #keep_warnings = False 110 | 111 | 112 | # -- Options for HTML output ------------------------------------------- 113 | 114 | # The theme to use for HTML and HTML Help pages. See the documentation for 115 | # a list of builtin themes. 116 | html_theme = 'alabaster' 117 | 118 | # Theme options are theme-specific and customize the look and feel of a 119 | # theme further. For a list of options available for each theme, see the 120 | # documentation. 121 | html_theme_options = { 122 | 'logo_name': False, 123 | 'github_user': 'sqreen', 124 | 'github_repo': 'PyMiniRacer', 125 | 'github_button': True, 126 | } 127 | 128 | # Add any paths that contain custom themes here, relative to this directory. 129 | #html_theme_path = [] 130 | 131 | # The name for this set of Sphinx documents. If None, it defaults to 132 | # " v documentation". 133 | #html_title = None 134 | 135 | # A shorter title for the navigation bar. Default is the same as 136 | # html_title. 137 | #html_short_title = None 138 | 139 | # The name of an image file (relative to this directory) to place at the 140 | # top of the sidebar. 141 | html_logo = 'data/py_mini_racer.png' 142 | 143 | # The name of an image file (within the static path) to use as favicon 144 | # of the docs. This file should be a Windows icon file (.ico) being 145 | # 16x16 or 32x32 pixels large. 146 | #html_favicon = None 147 | 148 | # Add any paths that contain custom static files (such as style sheets) 149 | # here, relative to this directory. They are copied after the builtin 150 | # static files, so a file named "default.css" will overwrite the builtin 151 | # "default.css". 152 | html_static_path = ['data'] 153 | 154 | # If not '', a 'Last updated on:' timestamp is inserted at every page 155 | # bottom, using the given strftime format. 156 | #html_last_updated_fmt = '%b %d, %Y' 157 | 158 | # If true, SmartyPants will be used to convert quotes and dashes to 159 | # typographically correct entities. 160 | #html_use_smartypants = True 161 | 162 | # Custom sidebar templates, maps document names to template names. 163 | #html_sidebars = {} 164 | 165 | 166 | # Additional templates that should be rendered to pages, maps page names 167 | # to template names. 168 | #html_additional_pages = {} 169 | 170 | # If false, no module index is generated. 171 | #html_domain_indices = True 172 | 173 | # If false, no index is generated. 174 | #html_use_index = True 175 | 176 | # If true, the index is split into individual pages for each letter. 177 | #html_split_index = False 178 | 179 | # If true, links to the reST sources are added to the pages. 180 | #html_show_sourcelink = True 181 | 182 | # If true, "Created using Sphinx" is shown in the HTML footer. 183 | # Default is True. 184 | #html_show_sphinx = True 185 | 186 | # If true, "(C) Copyright ..." is shown in the HTML footer. 187 | # Default is True. 188 | #html_show_copyright = True 189 | 190 | # If true, an OpenSearch description file will be output, and all pages 191 | # will contain a tag referring to it. The value of this option 192 | # must be the base URL from which the finished HTML is served. 193 | #html_use_opensearch = '' 194 | 195 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 196 | #html_file_suffix = None 197 | 198 | # Output file base name for HTML help builder. 199 | htmlhelp_basename = 'py_mini_racerdoc' 200 | 201 | 202 | # -- Options for LaTeX output ------------------------------------------ 203 | 204 | latex_elements = { 205 | # The paper size ('letterpaper' or 'a4paper'). 206 | #'papersize': 'letterpaper', 207 | 208 | # The font size ('10pt', '11pt' or '12pt'). 209 | #'pointsize': '10pt', 210 | 211 | # Additional stuff for the LaTeX preamble. 212 | #'preamble': '', 213 | } 214 | 215 | # Grouping the document tree into LaTeX files. List of tuples 216 | # (source start file, target name, title, author, documentclass 217 | # [howto/manual]). 218 | latex_documents = [ 219 | ('index', 'py_mini_racer.tex', 220 | u'PyMiniRacer Documentation', 221 | u'Boris FELD', 'manual'), 222 | ] 223 | 224 | # The name of an image file (relative to this directory) to place at 225 | # the top of the title page. 226 | #latex_logo = None 227 | 228 | # For "manual" documents, if this is true, then toplevel headings 229 | # are parts, not chapters. 230 | #latex_use_parts = False 231 | 232 | # If true, show page references after internal links. 233 | #latex_show_pagerefs = False 234 | 235 | # If true, show URL addresses after external links. 236 | #latex_show_urls = False 237 | 238 | # Documents to append as an appendix to all manuals. 239 | #latex_appendices = [] 240 | 241 | # If false, no module index is generated. 242 | #latex_domain_indices = True 243 | 244 | 245 | # -- Options for manual page output ------------------------------------ 246 | 247 | # One entry per manual page. List of tuples 248 | # (source start file, name, description, authors, manual section). 249 | man_pages = [ 250 | ('index', 'py_mini_racer', 251 | u'PyMiniRacer Documentation', 252 | [u'Sqreen'], 1) 253 | ] 254 | 255 | # If true, show URL addresses after external links. 256 | #man_show_urls = False 257 | 258 | 259 | # -- Options for Texinfo output ---------------------------------------- 260 | 261 | # Grouping the document tree into Texinfo files. List of tuples 262 | # (source start file, target name, title, author, 263 | # dir menu entry, description, category) 264 | texinfo_documents = [ 265 | ('index', 'py_mini_racer', 266 | u'PyMiniRacer Documentation', 267 | u'Sqreen', 268 | 'py_mini_racer', 269 | 'One line description of project.', 270 | 'Miscellaneous'), 271 | ] 272 | 273 | # Documents to append as an appendix to all manuals. 274 | #texinfo_appendices = [] 275 | 276 | # If false, no module index is generated. 277 | #texinfo_domain_indices = True 278 | 279 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 280 | #texinfo_show_urls = 'footnote' 281 | 282 | # If true, do not generate a @detailmenu in the "Top" node's menu. 283 | #texinfo_no_detailmenu = False 284 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: readme.rst 2 | 3 | API Reference 4 | ------------- 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | api 10 | 11 | Additional Information 12 | ---------------------- 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | 17 | contributing 18 | authors 19 | history 20 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\py_mini_racer.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\py_mini_racer.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | :start-after: center 3 | :end-before: Credits 4 | -------------------------------------------------------------------------------- /helpers/babel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ Transform the input stream using babel.transform """ 3 | import os 4 | import sys 5 | 6 | from py_mini_racer import py_mini_racer 7 | 8 | 9 | def babel_transform(es_string): 10 | """ Transform the provided string using babel.transform """ 11 | 12 | path_to_babel = os.path.join(os.path.dirname(__file__), '..', 'tests', 13 | 'fixtures', 'babel.js') 14 | 15 | babel_source = open(path_to_babel, "r").read() 16 | 17 | # Initializes PyMiniRacer 18 | ctx = py_mini_racer.MiniRacer() 19 | 20 | # Parse babel 21 | ctx.eval("""var self = this; %s """ % babel_source) 22 | 23 | # Transform stuff :) 24 | val = "babel.transform(`%s`)['code']" % es_string 25 | res = ctx.eval(val) 26 | return res 27 | 28 | 29 | if __name__ == '__main__': 30 | 31 | if len(sys.argv) != 1: 32 | name = sys.argv[0] 33 | sys.stderr.write("Usage: cat es6file.js | %s\n" % name) 34 | sys.stderr.write("Example: echo [1,2,3].map(n => n + 1); | %s\n" % name) 35 | sys.exit(-1) 36 | 37 | es6_data = sys.stdin.read() 38 | 39 | res = babel_transform(es6_data) 40 | 41 | print(res) 42 | -------------------------------------------------------------------------------- /helpers/build_package.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | import shutil 4 | import sys 5 | 6 | from setuptools.build_meta import ( 7 | build_sdist as setuptools_build_sdist, 8 | build_wheel as setuptools_build_wheel, 9 | get_requires_for_build_sdist, 10 | get_requires_for_build_wheel, 11 | prepare_metadata_for_build_wheel, 12 | ) 13 | from v8_build import build_v8 14 | 15 | 16 | def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): 17 | config_settings = config_settings or {} 18 | # Our wheel is compatible both with python 2 & python 3 19 | config_settings["--global-option"] = options = ["--python-tag", "py2.py3"] 20 | # Clean previous version of the lib 21 | for pattern in ("py_mini_racer/*.so", "py_mini_racer/*.dylib", "py_mini_racer/*.dll"): 22 | for filename in glob.glob(pattern): 23 | print("removing {}".format(filename)) 24 | os.unlink(filename) 25 | # Build V8 26 | build_v8("py_mini_racer_shared_lib") 27 | # Build the wheel 28 | if os.name == "posix" and sys.platform == "darwin": 29 | shutil.copyfile("py_mini_racer/extension/out/libmini_racer.dylib", "py_mini_racer/libmini_racer.dylib") 30 | options.extend(["--plat-name", "macosx_10_10_x86_64"]) 31 | elif sys.platform == "win32": 32 | shutil.copyfile("py_mini_racer/extension/out/mini_racer.dll", "py_mini_racer/mini_racer.dll") 33 | options.extend(["--plat-name", "win_amd64"]) 34 | else: 35 | shutil.copyfile("py_mini_racer/extension/out/libmini_racer.so", "py_mini_racer/libmini_racer.glibc.so") 36 | options.extend(["--plat-name", "manylinux1_x86_64"]) 37 | return setuptools_build_wheel(wheel_directory, config_settings=config_settings, metadata_directory=metadata_directory) 38 | 39 | 40 | def build_sdist(sdist_directory, config_settings=None): 41 | return setuptools_build_sdist(sdist_directory) 42 | 43 | 44 | __all__ = [ 45 | "get_requires_for_build_wheel", 46 | "get_requires_for_build_sdist", 47 | "prepare_metadata_for_build_wheel", 48 | "build_wheel", 49 | "build_sdist", 50 | ] 51 | 52 | if __name__ == "__main__": 53 | if sys.argv[1] == "wheel": 54 | build_wheel(sys.argv[2]) 55 | else: 56 | build_sdist(sys.argv[2]) 57 | -------------------------------------------------------------------------------- /helpers/v8_build.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*-" 2 | import argparse 3 | import errno 4 | import glob 5 | import json 6 | import logging 7 | import os 8 | import os.path 9 | import subprocess 10 | import sys 11 | from contextlib import contextmanager 12 | 13 | logging.basicConfig() 14 | LOGGER = logging.getLogger(__name__) 15 | LOGGER.setLevel(logging.DEBUG) 16 | ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) 17 | V8_VERSION = "branch-heads/8.9" 18 | 19 | 20 | def local_path(path="."): 21 | """ Return path relative to this file 22 | """ 23 | return os.path.abspath(os.path.join(ROOT_DIR, path)) 24 | 25 | 26 | PATCHES_PATH = local_path('../patches') 27 | 28 | 29 | def call(cmd): 30 | LOGGER.debug("Calling: '%s' from working directory %s", cmd, os.getcwd()) 31 | current_env = os.environ 32 | depot_tools_env = os.pathsep.join([local_path("../py_mini_racer/extension/depot_tools"), os.environ['PATH']]) 33 | current_env['PATH'] = depot_tools_env 34 | current_env['DEPOT_TOOLS_WIN_TOOLCHAIN'] = '0' 35 | return subprocess.check_call(cmd, shell=True, env=current_env) 36 | 37 | 38 | @contextmanager 39 | def chdir(new_path, make=False): 40 | old_path = os.getcwd() 41 | 42 | if make is True: 43 | try: 44 | os.mkdir(new_path) 45 | except OSError: 46 | pass 47 | 48 | try: 49 | yield os.chdir(new_path) 50 | finally: 51 | os.chdir(old_path) 52 | 53 | 54 | def install_depot_tools(): 55 | if not os.path.isdir(local_path("../py_mini_racer/extension/depot_tools")): 56 | LOGGER.debug("Cloning depot tools") 57 | call("git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git {}".format(local_path("../py_mini_racer/extension/depot_tools"))) 58 | else: 59 | LOGGER.debug("Using already cloned depot tools") 60 | 61 | 62 | def prepare_workdir(): 63 | directories = ["build", "build_overrides", "buildtools", "testing", 64 | "third_party", "tools"] 65 | with chdir(local_path("../py_mini_racer/extension")): 66 | for item in directories: 67 | if not os.path.exists(item): 68 | symlink_force(os.path.join("v8", item), item) 69 | 70 | 71 | def ensure_v8_src(revision): 72 | """ Ensure that v8 src are presents and up-to-date 73 | """ 74 | path = local_path("../py_mini_racer/extension") 75 | 76 | if not os.path.isfile(local_path("../py_mini_racer/extension/.gclient")): 77 | fetch_v8(path) 78 | else: 79 | update_v8(path) 80 | 81 | checkout_v8_version(local_path("../py_mini_racer/extension/v8"), revision) 82 | dependencies_sync(path) 83 | 84 | 85 | def fetch_v8(path): 86 | """ Fetch v8 87 | """ 88 | with chdir(os.path.abspath(path), make=True): 89 | call("fetch --nohooks v8") 90 | 91 | 92 | def update_v8(path): 93 | """ Update v8 repository 94 | """ 95 | with chdir(path): 96 | call("gclient fetch") 97 | 98 | 99 | def checkout_v8_version(path, revision): 100 | """ Ensure that we have the right version 101 | """ 102 | with chdir(path): 103 | call("git checkout {} -- .".format(revision)) 104 | 105 | 106 | def dependencies_sync(path): 107 | """ Sync v8 build dependencies 108 | """ 109 | with chdir(path): 110 | call("gclient sync") 111 | 112 | 113 | def run_hooks(path): 114 | """ Run v8 build hooks 115 | """ 116 | with chdir(path): 117 | call("gclient runhooks") 118 | 119 | 120 | def gen_makefiles(build_path, no_sysroot=False): 121 | with chdir(local_path("../py_mini_racer/extension")): 122 | build_path = local_path(build_path) 123 | if not os.path.exists(build_path): 124 | os.makedirs(build_path) 125 | LOGGER.debug("Writing args.gn in %s", build_path) 126 | with open(os.path.join(build_path, "args.gn"), "w") as f: 127 | opts = { 128 | "proprietary_codecs": "false", 129 | "toolkit_views": "false", 130 | "use_aura": "false", 131 | "use_dbus": "false", 132 | "use_gio": "false", 133 | "use_glib": "false", 134 | "use_ozone": "false", 135 | "use_udev": "false", 136 | "is_desktop_linux": "false", 137 | 138 | "is_cfi": "false", 139 | "is_debug": "false", 140 | "is_component_build": "false", 141 | 142 | "symbol_level": "0", 143 | "strip_debug_info": "true", 144 | "treat_warnings_as_errors": "true", 145 | 146 | "v8_monolithic": "false", 147 | "v8_use_external_startup_data": "false", 148 | "v8_enable_i18n_support": "false", 149 | 150 | "v8_untrusted_code_mitigations": "false", 151 | # See https://v8.dev/docs/untrusted-code-mitigations 152 | 153 | # See cc_wrapper 154 | "clang_use_chrome_plugins": "false", 155 | } 156 | if no_sysroot: 157 | opts.update({ 158 | "treat_warnings_as_errors": "false", 159 | "use_sysroot": "false", 160 | "clang_use_chrome_plugins": "false", 161 | "clang_base_path": "\"/usr\"", 162 | "use_custom_libcxx": "false", 163 | "use_gold": "true", 164 | "use_lld": "false", 165 | }) 166 | sccache = os.environ.get('SCCACHE') 167 | if sccache is not None: 168 | opts["cc_wrapper"] = json.dumps(sccache) 169 | f.write("# This file is auto generated by v8_build.py") 170 | f.write("\n".join("{}={}".format(a, b) for (a, b) in opts.items())) 171 | f.write("\n") 172 | extra_args = os.getenv("GN_ARGS") 173 | if extra_args: 174 | f.write("\n".join(extra_args.split())) 175 | f.write("\n") 176 | call("gn gen {}".format(local_path(build_path))) 177 | 178 | 179 | def make(build_path, target, cmd_prefix=""): 180 | """ Create a release of v8 181 | """ 182 | with chdir(local_path("../py_mini_racer/extension")): 183 | call("{} ninja -vv -C {} {}".format(cmd_prefix, local_path(build_path), target)) 184 | 185 | 186 | def patch_v8(): 187 | """ Apply patch on v8 188 | """ 189 | path = local_path("../py_mini_racer/extension/v8") 190 | patches_paths = PATCHES_PATH 191 | apply_patches(path, patches_paths) 192 | 193 | 194 | def symlink_force(target, link_name): 195 | LOGGER.debug("Creating symlink to %s on %s", target, link_name) 196 | if sys.platform == "win32": 197 | call(["mklink", "/d", os.path.abspath(link_name), os.path.abspath(target)]) 198 | else: 199 | try: 200 | os.symlink(target, link_name) 201 | except OSError as e: 202 | if e.errno == errno.EEXIST: 203 | os.remove(link_name) 204 | os.symlink(target, link_name) 205 | else: 206 | raise e 207 | 208 | 209 | def fixup_libtinfo(dir): 210 | dirs = ['/lib64', '/usr/lib64', '/lib', '/usr/lib'] 211 | 212 | v5_locs = ["{}/libtinfo.so.5".format(d) for d in dirs] 213 | found_v5 = next((f for f in v5_locs if os.path.isfile(f)), None) 214 | if found_v5 and os.stat(found_v5).st_size > 100: 215 | return '' 216 | 217 | v6_locs = ["{}/libtinfo.so.6".format(d) for d in dirs] 218 | found_v6 = next((f for f in v6_locs if os.path.isfile(f)), None) 219 | if not found_v6: 220 | return '' 221 | 222 | symlink_force(found_v6, os.path.join(dir, 'libtinfo.so.5')) 223 | return "LD_LIBRARY_PATH='{}:{}'"\ 224 | .format(dir, os.getenv('LD_LIBRARY_PATH', '')) 225 | 226 | 227 | def apply_patches(path, patches_path): 228 | with chdir(path): 229 | 230 | if not os.path.isfile('.applied_patches'): 231 | open('.applied_patches', 'w').close() 232 | 233 | with open('.applied_patches', 'r+') as applied_patches_file: 234 | applied_patches = set(applied_patches_file.read().splitlines()) 235 | 236 | for patch in glob.glob(os.path.join(patches_path, '*.patch')): 237 | if patch not in applied_patches: 238 | call("patch -p1 -N < {}".format(patch)) 239 | applied_patches_file.write(patch + "\n") 240 | 241 | 242 | def patch_sysroot(): 243 | with chdir(local_path("../py_mini_racer/extension/v8/build/linux/debian_sid_amd64-sysroot")): 244 | with open("usr/include/glob.h", "r") as f: 245 | header = f.read() 246 | s, e = header.split("sysroot-creator.sh.", 1) 247 | LOGGER.debug("Patching sysroot /usr/include/glob.h") 248 | with open("usr/include/glob.h", "w") as f: 249 | f.write(s) 250 | f.write("sysroot-creator.sh.") 251 | f.write(""" 252 | __asm__(".symver glob, glob@GLIBC_2.2.5"); 253 | __asm__(".symver glob64, glob64@GLIBC_2.2.5"); 254 | """) 255 | LOGGER.debug("Patching sysroot /usr/include/string.h") 256 | with open("usr/include/string.h", "a") as f: 257 | f.write(""" 258 | __asm__(".symver _sys_errlist, _sys_errlist@GLIBC_2.4"); 259 | __asm__(".symver _sys_nerr, _sys_nerr@GLIBC_2.4"); 260 | __asm__(".symver fmemopen, fmemopen@GLIBC_2.2.5"); 261 | __asm__(".symver memcpy, memcpy@GLIBC_2.2.5"); 262 | __asm__(".symver posix_spawn, posix_spawn@GLIBC_2.2.5"); 263 | __asm__(".symver posix_spawnp, posix_spawnp@GLIBC_2.2.5"); 264 | __asm__(".symver sys_errlist, sys_errlist@GLIBC_2.4"); 265 | __asm__(".symver sys_nerr, sys_nerr@GLIBC_2.4"); 266 | """) 267 | with open("usr/include/math.h", "r") as f: 268 | header = f.read() 269 | s, e = header.split("sysroot-creator.sh.", 1) 270 | LOGGER.debug("Patching sysroot /usr/include/math.h") 271 | with open("usr/include/math.h", "w") as f: 272 | f.write(s) 273 | f.write("sysroot-creator.sh.") 274 | f.write(""" 275 | __asm__(".symver exp2f, exp2f@GLIBC_2.2.5"); 276 | __asm__(".symver expf, expf@GLIBC_2.2.5"); 277 | __asm__(".symver lgamma, lgamma@GLIBC_2.2.5"); 278 | __asm__(".symver lgammaf, lgammaf@GLIBC_2.2.5"); 279 | __asm__(".symver lgammal, lgammal@GLIBC_2.2.5"); 280 | __asm__(".symver log2f, log2f@GLIBC_2.2.5"); 281 | __asm__(".symver logf, logf@GLIBC_2.2.5"); 282 | __asm__(".symver powf, powf@GLIBC_2.2.5"); 283 | """) 284 | 285 | 286 | def build_v8(target=None, build_path=None, revision=None, no_build=False, 287 | no_sysroot=False, no_update=False): 288 | if target is None: 289 | target = "v8" 290 | if build_path is None: 291 | # Must be relative to local_path() 292 | build_path = "../py_mini_racer/extension/out" 293 | if revision is None: 294 | revision = V8_VERSION 295 | install_depot_tools() 296 | if not no_update: 297 | ensure_v8_src(revision) 298 | patch_v8() 299 | if not no_sysroot and sys.platform.startswith("linux"): 300 | patch_sysroot() 301 | prepare_workdir() 302 | if not no_build: 303 | checkout_path = local_path("../py_mini_racer/extension/v8") 304 | cmd_prefix = fixup_libtinfo(checkout_path) 305 | gen_makefiles(build_path, no_sysroot=no_sysroot) 306 | make(build_path, target, cmd_prefix) 307 | 308 | 309 | if __name__ == '__main__': 310 | parser = argparse.ArgumentParser() 311 | parser.add_argument("--target", default="v8", help="Ninja target") 312 | parser.add_argument("--build-path", default="../py_mini_racer/extension/out", help="Build destination directory (relative to the current path)") 313 | parser.add_argument("--v8-revision", default=V8_VERSION) 314 | parser.add_argument("--no-build", action="store_true", help="Only prepare workdir") 315 | parser.add_argument("--no-update", action="store_true", help="Do not update the workdir") 316 | parser.add_argument("--no-sysroot", action="store_true", help="Do not use the V8 build sysroot") 317 | args = parser.parse_args() 318 | build_v8(target=args.target, build_path=args.build_path, revision=args.v8_revision, 319 | no_build=args.no_build, no_update=args.no_update, no_sysroot=args.no_sysroot) 320 | -------------------------------------------------------------------------------- /helpers/wheel_pymalloc.py: -------------------------------------------------------------------------------- 1 | """Script to add without pymalloc version of the wheel""" 2 | 3 | import os 4 | import re 5 | import sys 6 | 7 | from auditwheel.wheeltools import InWheelCtx, _dist_info_dir 8 | from wheel import pkginfo 9 | 10 | 11 | def get_filenames(directory): 12 | """Get all the file to copy""" 13 | for filename in os.listdir(directory): 14 | if re.search(r"cp\d{2}mu?-manylinux1_\S+\.whl", filename): 15 | yield filename 16 | 17 | 18 | def copy_file(filename, destination): 19 | """Copy the file and put the correct tag""" 20 | 21 | print("Updating file %s" % filename) 22 | out_dir = os.path.abspath(destination) 23 | 24 | tags = filename[:-4].split("-") 25 | 26 | tags[-2] = tags[-2].replace("m", "") 27 | 28 | new_name = "-".join(tags) + ".whl" 29 | wheel_flag = "-".join(tags[2:]) 30 | 31 | with InWheelCtx(os.path.join(destination, filename)) as ctx: 32 | info_fname = os.path.join(_dist_info_dir(ctx.path), 'WHEEL') 33 | infos = pkginfo.read_pkg_info(info_fname) 34 | print("Current Tags: ", ", ".join([v for k, v in infos.items() 35 | if k == "Tag"])) 36 | print("Adding Tag", wheel_flag) 37 | del infos['Tag'] 38 | infos.add_header('Tag', wheel_flag) 39 | pkginfo.write_pkg_info(info_fname, infos) 40 | 41 | ctx.out_wheel = os.path.join(out_dir, new_name) 42 | 43 | print("Saving new wheel into %s" % ctx.out_wheel) 44 | 45 | 46 | def main(): 47 | if len(sys.argv) == 2: 48 | directory = sys.argv[1] 49 | else: 50 | directory = "dist" 51 | for filename in get_filenames(directory): 52 | copy_file(filename, directory) 53 | 54 | 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /py_mini_racer/__about__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Sqreen' 2 | __email__ = 'support@sqreen.com' 3 | __version__ = '0.6.0' 4 | -------------------------------------------------------------------------------- /py_mini_racer/__init__.py: -------------------------------------------------------------------------------- 1 | from . import py_mini_racer 2 | 3 | MiniRacer = py_mini_racer.MiniRacer 4 | 5 | __all__ = ['py_mini_racer', 'MiniRacer'] 6 | -------------------------------------------------------------------------------- /py_mini_racer/extension/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /py_mini_racer/extension/.gitignore: -------------------------------------------------------------------------------- 1 | /py_mini_racer.config 2 | /py_mini_racer.creator 3 | /py_mini_racer.creator.user 4 | /py_mini_racer.files 5 | /py_mini_racer.includes 6 | -------------------------------------------------------------------------------- /py_mini_racer/extension/.gn: -------------------------------------------------------------------------------- 1 | buildconfig = "//build/config/BUILDCONFIG.gn" 2 | -------------------------------------------------------------------------------- /py_mini_racer/extension/BUILD.gn: -------------------------------------------------------------------------------- 1 | config("py_mini_racer_config") { 2 | configs = [ "//v8:external_config", "//v8:toolchain", "//v8:features" ] 3 | include_dirs = [ "v8", "$target_gen_dir/v8" ] 4 | cflags = [] 5 | } 6 | 7 | static_library("py_mini_racer_static_lib") { 8 | complete_static_lib = true 9 | output_name = "mini_racer" 10 | sources = [ 11 | "mini_racer_extension.cc", 12 | ] 13 | deps = [ 14 | "//build/config:shared_library_deps", 15 | "//v8:v8", 16 | "//v8:v8_libbase", 17 | "//v8:v8_libplatform", 18 | "//v8:v8_libsampler", 19 | ] 20 | configs += [ ":py_mini_racer_config" ] 21 | } 22 | 23 | shared_library("py_mini_racer_shared_lib") { 24 | output_name = "mini_racer" 25 | sources = [ 26 | "mini_racer_extension.cc", 27 | ] 28 | deps = [ 29 | "//build/config:shared_library_deps", 30 | "//v8:v8", 31 | "//v8:v8_libbase", 32 | "//v8:v8_libplatform", 33 | "//v8:v8_libsampler", 34 | ] 35 | configs += [ ":py_mini_racer_config" ] 36 | } 37 | -------------------------------------------------------------------------------- /py_mini_racer/extension/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqreen/PyMiniRacer/6eb2dc5e5d7dc772b5edfa01c4b163230d6491c4/py_mini_racer/extension/__init__.py -------------------------------------------------------------------------------- /py_mini_racer/extension/mini_racer_extension.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef V8_OS_WIN 15 | #define LIB_EXPORT __declspec(dllexport) 16 | #else // V8_OS_WIN 17 | #define LIB_EXPORT __attribute__((visibility("default"))) 18 | #endif 19 | 20 | template 21 | static inline T* xalloc(T*& ptr, size_t x = sizeof(T)) { 22 | void* tmp = malloc(x); 23 | if (tmp == NULL) { 24 | fprintf(stderr, "malloc failed. Aborting"); 25 | abort(); 26 | } 27 | ptr = static_cast(tmp); 28 | return static_cast(ptr); 29 | } 30 | 31 | using namespace v8; 32 | 33 | class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { 34 | public: 35 | virtual void* Allocate(size_t length) { 36 | void* data = AllocateUninitialized(length); 37 | return data == NULL ? data : memset(data, 0, length); 38 | } 39 | virtual void* AllocateUninitialized(size_t length) { return malloc(length); } 40 | virtual void Free(void* data, size_t) { free(data); } 41 | }; 42 | 43 | struct ContextInfo { 44 | Isolate* isolate; 45 | Persistent* context; 46 | ArrayBufferAllocator* allocator; 47 | std::map> backing_stores; 48 | bool interrupted; 49 | size_t soft_memory_limit; 50 | bool soft_memory_limit_reached; 51 | size_t hard_memory_limit; 52 | bool hard_memory_limit_reached; 53 | }; 54 | 55 | struct EvalResult { 56 | bool parsed; 57 | bool executed; 58 | bool terminated; 59 | bool timed_out; 60 | Persistent* value; 61 | Persistent* message; 62 | Persistent* backtrace; 63 | 64 | ~EvalResult() { 65 | kill_value(value); 66 | kill_value(message); 67 | kill_value(backtrace); 68 | } 69 | 70 | private: 71 | static void kill_value(Persistent* val) { 72 | if (!val) { 73 | return; 74 | } 75 | val->Reset(); 76 | delete val; 77 | } 78 | }; 79 | 80 | typedef struct { 81 | ContextInfo* context_info; 82 | const char* eval; 83 | int eval_len; 84 | unsigned long timeout; 85 | EvalResult* result; 86 | size_t max_memory; 87 | } EvalParams; 88 | 89 | enum BinaryTypes { 90 | type_invalid = 0, 91 | type_null = 1, 92 | type_bool = 2, 93 | type_integer = 3, 94 | type_double = 4, 95 | type_str_utf8 = 5, 96 | // type_array = 6, // deprecated 97 | // type_hash = 7, // deprecated 98 | type_date = 8, 99 | type_symbol = 9, 100 | type_object = 10, 101 | 102 | type_function = 100, 103 | type_shared_array_buffer = 101, 104 | type_array_buffer = 102, 105 | 106 | type_execute_exception = 200, 107 | type_parse_exception = 201, 108 | type_oom_exception = 202, 109 | type_timeout_exception = 203, 110 | }; 111 | 112 | struct BinaryValue { 113 | union { 114 | void* ptr_val; 115 | char* str_val; 116 | uint32_t int_val; 117 | double double_val; 118 | }; 119 | enum BinaryTypes type = type_invalid; 120 | size_t len; 121 | }; 122 | 123 | void BinaryValueFree(ContextInfo* context_info, BinaryValue* v) { 124 | if (!v) { 125 | return; 126 | } 127 | switch (v->type) { 128 | case type_execute_exception: 129 | case type_parse_exception: 130 | case type_oom_exception: 131 | case type_timeout_exception: 132 | case type_str_utf8: 133 | free(v->str_val); 134 | break; 135 | case type_bool: 136 | case type_double: 137 | case type_date: 138 | case type_null: 139 | case type_integer: 140 | case type_function: // no value implemented 141 | case type_symbol: 142 | case type_object: 143 | case type_invalid: 144 | // the other types are scalar values 145 | break; 146 | case type_shared_array_buffer: 147 | case type_array_buffer: 148 | context_info->backing_stores.erase(v); 149 | break; 150 | } 151 | free(v); 152 | } 153 | 154 | enum IsolateData { 155 | CONTEXT_INFO, 156 | }; 157 | 158 | static std::unique_ptr current_platform = NULL; 159 | static std::mutex platform_lock; 160 | 161 | static void gc_callback(Isolate* isolate, GCType type, GCCallbackFlags flags) { 162 | ContextInfo* context_info = (ContextInfo*)isolate->GetData(CONTEXT_INFO); 163 | 164 | if (context_info == nullptr) { 165 | return; 166 | } 167 | 168 | HeapStatistics stats; 169 | isolate->GetHeapStatistics(&stats); 170 | size_t used = stats.used_heap_size(); 171 | 172 | context_info->soft_memory_limit_reached = 173 | (used > context_info->soft_memory_limit); 174 | isolate->MemoryPressureNotification((context_info->soft_memory_limit_reached) 175 | ? v8::MemoryPressureLevel::kModerate 176 | : v8::MemoryPressureLevel::kNone); 177 | if (used > context_info->hard_memory_limit) { 178 | context_info->hard_memory_limit_reached = true; 179 | isolate->TerminateExecution(); 180 | } 181 | } 182 | 183 | static void init_v8(char const* flags) { 184 | // no need to wait for the lock if already initialized 185 | if (current_platform != NULL) 186 | return; 187 | 188 | platform_lock.lock(); 189 | 190 | if (current_platform == NULL) { 191 | V8::InitializeICU(); 192 | if (flags != NULL) { 193 | V8::SetFlagsFromString(flags); 194 | } 195 | if (flags != NULL && strstr(flags, "--single-threaded") != NULL) { 196 | current_platform = platform::NewSingleThreadedDefaultPlatform(); 197 | } else { 198 | current_platform = platform::NewDefaultPlatform(); 199 | } 200 | V8::InitializePlatform(current_platform.get()); 201 | V8::Initialize(); 202 | } 203 | 204 | platform_lock.unlock(); 205 | } 206 | 207 | static void breaker(std::timed_mutex& breaker_mutex, void* d) { 208 | EvalParams* data = (EvalParams*)d; 209 | 210 | if (!breaker_mutex.try_lock_for(std::chrono::milliseconds(data->timeout))) { 211 | data->result->timed_out = true; 212 | data->context_info->isolate->TerminateExecution(); 213 | } 214 | } 215 | 216 | static void set_hard_memory_limit(ContextInfo* context_info, size_t limit) { 217 | context_info->hard_memory_limit = limit; 218 | context_info->hard_memory_limit_reached = false; 219 | } 220 | 221 | static bool maybe_fast_call(const char* eval, int eval_len) { 222 | // Does the eval string ends with '()'? 223 | // TODO check if the string is an identifier 224 | return (eval_len > 2 && eval[eval_len - 2] == '(' && 225 | eval[eval_len - 1] == ')'); 226 | } 227 | 228 | static void* nogvl_context_eval(void* arg) { 229 | EvalParams* eval_params = (EvalParams*)arg; 230 | EvalResult* result = eval_params->result; 231 | Isolate* isolate = eval_params->context_info->isolate; 232 | Isolate::Scope isolate_scope(isolate); 233 | HandleScope handle_scope(isolate); 234 | 235 | TryCatch trycatch(isolate); 236 | 237 | Local context = eval_params->context_info->context->Get(isolate); 238 | 239 | Context::Scope context_scope(context); 240 | 241 | set_hard_memory_limit(eval_params->context_info, eval_params->max_memory); 242 | 243 | result->parsed = false; 244 | result->executed = false; 245 | result->terminated = false; 246 | result->timed_out = false; 247 | result->value = NULL; 248 | 249 | std::timed_mutex breaker_mutex; 250 | std::thread breaker_thread; 251 | 252 | // timeout limit 253 | auto timeout = eval_params->timeout; 254 | if (timeout > 0) { 255 | breaker_mutex.lock(); 256 | breaker_thread = 257 | std::thread(&breaker, std::ref(breaker_mutex), (void*)eval_params); 258 | } 259 | // memory limit 260 | if (eval_params->max_memory > 0) { 261 | isolate->AddGCEpilogueCallback(gc_callback); 262 | } 263 | 264 | MaybeLocal maybe_value; 265 | 266 | // Is it a single function call? 267 | if (maybe_fast_call(eval_params->eval, eval_params->eval_len)) { 268 | Local identifier; 269 | Local func; 270 | 271 | // Let's check if the value is a callable identifier 272 | result->parsed = 273 | String::NewFromUtf8(isolate, eval_params->eval, NewStringType::kNormal, 274 | eval_params->eval_len - 2) 275 | .ToLocal(&identifier) && 276 | context->Global()->Get(context, identifier).ToLocal(&func) && 277 | func->IsFunction(); 278 | 279 | if (result->parsed) { 280 | // Call the identifier 281 | maybe_value = Local::Cast(func)->Call( 282 | context, v8::Undefined(isolate), 0, {}); 283 | result->executed = !maybe_value.IsEmpty(); 284 | } 285 | } 286 | 287 | // Fallback on a slower full eval 288 | if (!result->executed) { 289 | Local eval; 290 | Local