├── .coveragerc ├── .github └── workflows │ └── python.yml ├── .gitignore ├── CHANGELOG.rst ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── TODO.rst ├── docs ├── Makefile ├── api.rst ├── changelog.rst ├── conf.py ├── index.rst └── overview.rst ├── examples ├── .gitignore ├── Makefile ├── __init__.py ├── ping.thrift ├── ping_client_requests.py ├── ping_client_thrift.py └── ping_server_tornado.py ├── hooks └── pre-commit ├── requirements-dev.txt ├── requirements-test.txt ├── requirements.txt ├── scripts └── install-hooks.sh ├── setup.cfg ├── setup.py ├── tests ├── __init__.py ├── compile │ ├── __init__.py │ ├── test_compiler.py │ ├── test_includes.py │ └── test_spec.py ├── conftest.py ├── idl │ ├── __init__.py │ └── test_parser.py ├── protocol │ ├── __init__.py │ └── test_binary.py ├── spec │ ├── __init__.py │ ├── conftest.py │ ├── test_common.py │ ├── test_const.py │ ├── test_enum.py │ ├── test_exc.py │ ├── test_hashable.py │ ├── test_list.py │ ├── test_map.py │ ├── test_primitive.py │ ├── test_service.py │ ├── test_set.py │ ├── test_struct.py │ ├── test_typedef.py │ └── test_union.py ├── test_benchmark.py ├── test_buffer.py ├── test_loader.py ├── test_names_match_type.py ├── test_runtime.py ├── util │ ├── __init__.py │ ├── spec.py │ └── value.py └── wire │ ├── __init__.py │ └── test_value.py ├── thriftrw ├── __init__.py ├── _buffer.pxd ├── _buffer.pyx ├── _cython.pxd ├── _cython.pyx ├── _runtime.pxd ├── _runtime.pyx ├── compile │ ├── __init__.py │ ├── compiler.py │ ├── generate.py │ ├── link.py │ └── scope.py ├── errors.py ├── idl │ ├── __init__.py │ ├── ast.py │ ├── lexer.py │ └── parser.py ├── loader.py ├── protocol │ ├── __init__.py │ ├── _endian.h │ ├── _endian.pxd │ ├── binary.pxd │ ├── binary.pyx │ ├── core.pxd │ └── core.pyx ├── spec │ ├── __init__.py │ ├── base.pxd │ ├── base.pyx │ ├── check.pxd │ ├── check.pyx │ ├── common.pyx │ ├── const.py │ ├── enum.pxd │ ├── enum.pyx │ ├── exc.pxd │ ├── exc.pyx │ ├── field.pxd │ ├── field.pyx │ ├── list.pxd │ ├── list.pyx │ ├── map.pxd │ ├── map.pyx │ ├── primitive.pxd │ ├── primitive.pyx │ ├── reference.pxd │ ├── reference.pyx │ ├── service.pxd │ ├── service.pyx │ ├── set.pxd │ ├── set.pyx │ ├── spec_mapper.pyx │ ├── struct.pxd │ ├── struct.pyx │ ├── typedef.pxd │ ├── typedef.pyx │ ├── union.pxd │ └── union.pyx └── wire │ ├── __init__.py │ ├── message.pxd │ ├── message.pyx │ ├── mtype.pxd │ ├── mtype.pyx │ ├── ttype.pxd │ ├── ttype.pyx │ ├── value.pxd │ └── value.pyx └── tox.ini /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = true 3 | plugins = Cython.Coverage 4 | 5 | [report] 6 | exclude_lines = 7 | pragma: no cover 8 | raise NotImplementedError 9 | def __repr__ 10 | def __str__ 11 | pass 12 | omit = examples/* 13 | 14 | [xml] 15 | output = coverage.xml 16 | -------------------------------------------------------------------------------- /.github/workflows/python.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: ['*'] 6 | tags: ['*'] 7 | pull_request: 8 | branches: ['*'] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | name: Test (Python ${{ matrix.python-version }}) 14 | strategy: 15 | matrix: 16 | python-version: 17 | - '3.7' 18 | - '3.8' 19 | - '3.9' 20 | - '3.10' 21 | - '3.11' 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Set up Python ${{ matrix.python-version }} 25 | uses: actions/setup-python@v2 26 | with: 27 | python-version: ${{ matrix.python-version }} 28 | - name: Install 29 | run: | 30 | pip install tox 31 | pip install -r requirements.txt 32 | cython -Xlanguage_level=2 $(find thriftrw -name '*.pyx') 33 | - name: Test 34 | run: | 35 | tox -e ${{ matrix.python-version }} 36 | utilities: 37 | runs-on: ubuntu-latest 38 | name: Build utility functions 39 | steps: 40 | - name: Install 41 | run: | 42 | pip install tox 43 | - name: Run utility functions 44 | run: | 45 | tox -e cover 46 | tox -e flake8 47 | tox -e docs 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.pyc 3 | .tox 4 | build/ 5 | dist/ 6 | *.egg 7 | *.egg-info 8 | env/ 9 | _build 10 | *.swp 11 | node_modules 12 | *.c 13 | *.so 14 | .benchmarks/ 15 | .coverage 16 | .idea/ 17 | coverage.xml 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to thriftrw 2 | ======================== 3 | 4 | We are happy to accept third-party pull requests. Please try to follow these 5 | guidelines when making changes: 6 | 7 | - If the change you are making is a new feature or introduces significant new 8 | APIs, make sure that the design has been discussed with us. Open a GitHub 9 | Issue if one does not already exist and start the discussion there with an 10 | API proposal. This is not necessary for small changes or bugfixes. Use 11 | your judgement. 12 | 13 | - Avoid making changes to the Thrift IDL syntax. We want to maintain 14 | compatibility with Apache Thrift. 15 | 16 | - Ensure new files have the copyright notice at the top of the file. Run the 17 | `scripts/install-hooks.sh` script to install a pre-commit hook that will 18 | automate this for you. 19 | 20 | - `flake8` must not throw any warnings. 21 | 22 | - Changes should be self-contained and must have tests and documentation to 23 | accompany them. 24 | 25 | - Commit messages must follow the format: 26 | 27 | Short one line description 28 | 29 | More detailed description if necessary. 30 | 31 | References to related GitHub issues if any. 32 | 33 | Making changes 34 | ============== 35 | 36 | - Clone the GitHub repo (or your fork of it). 37 | 38 | $ git clone https://github.com/thriftrw/thriftrw-python.git thriftrw 39 | $ cd thriftrw 40 | 41 | - Create a virtualenv and install the dependencies. 42 | 43 | $ virtualenv env 44 | $ source env/bin/activate 45 | $ pip install -r requirements.txt 46 | $ pip install -r requirements-test.txt 47 | 48 | - Make your change, build it, and test it. 49 | 50 | $ python setup.py develop 51 | 52 | To test the change with the version of Python used by the virtualenv, 53 | simply run, 54 | 55 | $ make test 56 | 57 | If you have multiple versions of Python installed, you can use `tox` to 58 | test against them. For example, 59 | 60 | $ tox -e 3.7 61 | 62 | - Create a Pull Request with a meaningful title and description to get your 63 | changes reviewed and merged. Reference any relevant GitHub issues in 64 | the PR. Address review feedback, if any. 65 | 66 | 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include LICENSE 3 | recursive-include thriftrw *.py 4 | recursive-include thriftrw *.c 5 | recursive-include thriftrw *.h 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test lint docs docsopen clean install 2 | 3 | test_args := \ 4 | --cov thriftrw \ 5 | --cov-config .coveragerc \ 6 | --cov-report term-missing \ 7 | tests 8 | 9 | test: 10 | PYTHONDONTWRITEBYTECODE=1 py.test $(test_args) 11 | 12 | lint: 13 | flake8 thriftrw tests 14 | 15 | docs: 16 | PYTHONDONTWRITEBYTECODE=1 make -C docs html SPHINXOPTS=-W 17 | 18 | docszip: docs 19 | cd docs/_build/html; zip -r ../html.zip . 20 | 21 | docsopen: docs 22 | open docs/_build/html/index.html 23 | 24 | clean: 25 | rm -rf thriftrw.egg-info 26 | rm -rf dist 27 | rm -rf build 28 | find tests thriftrw -name \*.pyc -delete 29 | find tests thriftrw -name \*.c -delete 30 | find tests thriftrw -name \*.so -delete 31 | make -C docs clean 32 | 33 | install: 34 | pip install -r requirements.txt 35 | pip install -r requirements-dev.txt 36 | pip install -r requirements-test.txt 37 | pip install -e . 38 | -------------------------------------------------------------------------------- /TODO.rst: -------------------------------------------------------------------------------- 1 | * Identifier renaming hooks to convert ``camelCase`` to ``snake_case``. 2 | * Compiler option to change the base class of generated classes. 3 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | ``thriftrw`` 5 | ------------ 6 | 7 | .. automodule:: thriftrw 8 | 9 | ``thriftrw.loader`` 10 | ------------------- 11 | 12 | .. automodule:: thriftrw.loader 13 | :members: Loader 14 | 15 | ``thriftrw.compile`` 16 | -------------------- 17 | 18 | .. automodule:: thriftrw.compile 19 | 20 | ``thriftrw.protocol`` 21 | --------------------- 22 | 23 | .. automodule:: thriftrw.protocol 24 | 25 | ``thriftrw.spec`` 26 | ----------------- 27 | 28 | .. automodule:: thriftrw.spec 29 | 30 | ``thriftrw.wire`` 31 | ----------------- 32 | 33 | .. automodule:: thriftrw.wire 34 | 35 | ``thriftrw.idl`` 36 | ---------------- 37 | 38 | .. automodule:: thriftrw.idl 39 | 40 | ``thriftrw.errors`` 41 | ------------------- 42 | 43 | .. automodule:: thriftrw.errors 44 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CHANGELOG.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. thriftrw documentation master file, created by 2 | sphinx-quickstart on Tue Aug 4 17:48:29 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to thriftrw's documentation! 7 | ==================================== 8 | 9 | thriftrw is a Python library to serialize and deserialize Thrift types. 10 | 11 | GitHub 12 | https://github.com/thriftrw/thriftrw-python 13 | 14 | PyPI 15 | https://pypi.python.org/pypi/thriftrw 16 | 17 | Contents: 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | 22 | overview 23 | api 24 | changelog 25 | 26 | 27 | Indices and tables 28 | ================== 29 | 30 | * :ref:`genindex` 31 | * :ref:`modindex` 32 | * :ref:`search` 33 | 34 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | ping/ 2 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: gen 2 | 3 | gen: 4 | thrift -out . --gen py ping.thrift 5 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/examples/__init__.py -------------------------------------------------------------------------------- /examples/ping.thrift: -------------------------------------------------------------------------------- 1 | struct Pong { 2 | 1: required double timestamp 3 | } 4 | 5 | service Ping { 6 | Pong ping(1: string name); 7 | } 8 | -------------------------------------------------------------------------------- /examples/ping_client_requests.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals, print_function 2 | 3 | import os.path 4 | import requests 5 | 6 | import thriftrw 7 | 8 | ping = thriftrw.load( 9 | os.path.join(os.path.dirname(__file__), 'ping.thrift'), 10 | ) 11 | 12 | 13 | def main(): 14 | req = ping.Ping.ping.request('world') 15 | 16 | response = requests.post( 17 | 'http://127.0.0.1:8888/thrift', 18 | data=ping.dumps.message(req, seqid=42), 19 | ) 20 | reply = ping.loads.message(ping.Ping, response.content) 21 | assert reply.name == 'ping' 22 | assert reply.seqid == 42 23 | 24 | resp = reply.body 25 | print(resp) 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /examples/ping_client_thrift.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import print_function 3 | 4 | from thrift.transport.THttpClient import THttpClient 5 | from thrift.protocol.TBinaryProtocol import TBinaryProtocolAccelerated 6 | 7 | from ping import Ping 8 | 9 | 10 | trans = THttpClient('http://localhost:8888/thrift') 11 | proto = TBinaryProtocolAccelerated(trans) 12 | client = Ping.Client(proto) 13 | 14 | print(client.ping('world')) 15 | -------------------------------------------------------------------------------- /examples/ping_server_tornado.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals, print_function 2 | 3 | import time 4 | import os.path 5 | 6 | from tornado import web 7 | from tornado.ioloop import IOLoop 8 | from tornado.httpserver import HTTPServer 9 | 10 | import thriftrw 11 | 12 | ping = thriftrw.load( 13 | os.path.join(os.path.dirname(__file__), 'ping.thrift'), 14 | ) 15 | 16 | 17 | class ThriftRequestHandler(web.RequestHandler): 18 | 19 | def post(self): 20 | assert self.request.body 21 | 22 | message = ping.loads.message(ping.Ping, self.request.body) 23 | method, handler = self._METHODS[message.name] 24 | 25 | args = message.body 26 | resp = method.response(success=handler(self, args)) 27 | 28 | reply = ping.dumps.message(resp, seqid=message.seqid) 29 | self.write(reply) 30 | 31 | def handle_ping(self, args): 32 | print('Hello, %s' % args.name) 33 | return ping.Pong(time.time()) 34 | 35 | _METHODS = {'ping': (ping.Ping.ping, handle_ping)} 36 | 37 | 38 | if __name__ == "__main__": 39 | app = web.Application([ 40 | (r'/thrift', ThriftRequestHandler), 41 | ]) 42 | HTTPServer(app).listen(8888) 43 | print('Listening on http://127.0.0.1:8888/thrift') 44 | IOLoop.current().start() 45 | -------------------------------------------------------------------------------- /hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Ensures that the license blurb is added to all source code. 4 | 5 | findup() { 6 | if [[ -f "$1/$2" ]]; then 7 | echo "$1" 8 | else 9 | findUp "$1/.." "$2" 10 | fi 11 | } 12 | 13 | ROOT=$(realpath "$(findup "." "setup.py")") 14 | LICENSE_EXEC="$ROOT/node_modules/.bin/uber-licence" 15 | 16 | ensure_license() { 17 | cwd="$(pwd)" 18 | # This is ugly but it basically executes the uber-license tool, parses the 19 | # output to figure out which files were changed, and stages them into the 20 | # commit. 21 | ("$LICENSE_EXEC" --file '*.{py,pyx,pxd}' || exit 1) \ 22 | | grep '^fixed file ' | perl -F"'" -ane 'print "$F[1]\n"' \ 23 | | while read fileName; do 24 | echo "License added to $cwd/$fileName" 25 | done 26 | } 27 | 28 | unset GIT_DIR 29 | 30 | # Ensure uber-licence is installed. 31 | if [[ ! -x "$LICENSE_EXEC" ]]; then 32 | echo "uber-licence is not installed. Installing." 33 | pushd "$ROOT" &>/dev/null 34 | npm i uber-licence 35 | popd &>/dev/null 36 | fi 37 | 38 | for d in thriftrw tests; do 39 | pushd "$ROOT/$d" &>/dev/null 40 | ensure_license 41 | popd &>/dev/null 42 | done 43 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | flake8 2 | zest.releaser 3 | wheel 4 | -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | pytest==7.2.1 2 | pytest-cov==4.0.0 3 | pytest-benchmark[histogram]==4.0.0 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cython>=0.29.29 2 | ply 3 | -------------------------------------------------------------------------------- /scripts/install-hooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This installs all hooks inside ./hooks into .git/hooks, skipping anything 4 | # that's already there. 5 | 6 | set -e 7 | 8 | ROOT=$(pwd) 9 | 10 | if [[ ! -d "$ROOT/.git" ]]; then 11 | echo "Please run this from the project root." 12 | exit 1 13 | fi 14 | 15 | find "$ROOT/hooks" -type file | while read hook; do 16 | name=$(basename "$hook") 17 | dest="$ROOT/.git/hooks/$name" 18 | if [[ -f "$dest" ]]; then 19 | echo "Skipping hook $name because it's already installed." 20 | else 21 | ln -s "$hook" "$dest" 22 | echo "Installed hook $name." 23 | fi 24 | done 25 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [zest.releaser] 2 | create-wheel = yes 3 | python-file-with-version = thriftrw/__init__.py 4 | 5 | [tool:pytest] 6 | addopts = --tb short --benchmark-autosave --benchmark-save-data 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import re 5 | 6 | from setuptools import setup 7 | from setuptools import find_packages 8 | from setuptools.command.sdist import sdist as _sdist 9 | from setuptools.extension import Extension as _Extension 10 | 11 | cmdclass = {} 12 | ext_modules = [] 13 | 14 | cython_modules = [ 15 | 'thriftrw._buffer', 16 | 'thriftrw._cython', 17 | 'thriftrw._runtime', 18 | 'thriftrw.protocol.core', 19 | 'thriftrw.protocol.binary', 20 | 'thriftrw.spec.base', 21 | 'thriftrw.spec.check', 22 | 'thriftrw.spec.common', 23 | 'thriftrw.spec.enum', 24 | 'thriftrw.spec.exc', 25 | 'thriftrw.spec.field', 26 | 'thriftrw.spec.list', 27 | 'thriftrw.spec.map', 28 | 'thriftrw.spec.reference', 29 | 'thriftrw.spec.primitive', 30 | 'thriftrw.spec.service', 31 | 'thriftrw.spec.set', 32 | 'thriftrw.spec.spec_mapper', 33 | 'thriftrw.spec.struct', 34 | 'thriftrw.spec.typedef', 35 | 'thriftrw.spec.union', 36 | 'thriftrw.wire.message', 37 | 'thriftrw.wire.mtype', 38 | 'thriftrw.wire.ttype', 39 | 'thriftrw.wire.value', 40 | ] 41 | 42 | extension_extras = {} 43 | 44 | # If Cython is available we will re-cythonize the pyx files, otherwise we just 45 | # compile the packaged C files. 46 | extension_filetype = '.c' 47 | 48 | Extension = None 49 | try: 50 | import Cython.Distutils 51 | 52 | cmdclass.update(build_ext=Cython.Distutils.build_ext) 53 | 54 | # Check if we forgot to add something to cython_modules. 55 | for root, _, files in os.walk('thriftrw'): 56 | for name in files: 57 | if not name.endswith('.pyx'): 58 | continue 59 | path = os.path.join(root, name) 60 | module = path.replace('/', '.')[:-4] 61 | if module not in cython_modules: 62 | raise Exception( 63 | 'Module "%s" (%s) is not present in the ' 64 | '"cython_modules" list.' 65 | % (module, path) 66 | ) 67 | 68 | Extension = Cython.Distutils.Extension 69 | extension_filetype = '.pyx' 70 | 71 | cython_directives = { 72 | 'embedsignature': True, 73 | } 74 | 75 | if os.getenv('THRIFTRW_PROFILE'): 76 | # Add hooks for the profiler in the generated C code. 77 | cython_directives['profile'] = True 78 | 79 | if os.getenv('THRIFTRW_COVERAGE'): 80 | # Add line tracing hooks to the generated C code. The hooks aren't 81 | # actually enabled unless the CYTHON_TRACE macre is also set. This 82 | # affects performance negatively and should only be used during 83 | # testing. 84 | extension_extras['define_macros'] = [('CYTHON_TRACE', '1')] 85 | cython_directives['linetrace'] = True 86 | 87 | if cython_directives: 88 | extension_extras['cython_directives'] = cython_directives 89 | except ImportError: 90 | pass 91 | 92 | if Extension is None: 93 | Extension = _Extension 94 | 95 | 96 | for module in cython_modules: 97 | ext_modules.append( 98 | Extension( 99 | module, 100 | [module.replace('.', '/') + extension_filetype], 101 | **extension_extras 102 | ) 103 | ) 104 | 105 | 106 | class sdist(_sdist): 107 | """This forces us to always re-compile extensions before releasing.""" 108 | 109 | def run(self): 110 | try: 111 | from Cython.Build import cythonize 112 | 113 | cythonize([ 114 | module.replace('.', '/') + '.pyx' for module in cython_modules 115 | ]) 116 | except ImportError: 117 | pass 118 | _sdist.run(self) 119 | 120 | 121 | cmdclass['sdist'] = sdist 122 | 123 | 124 | version = None 125 | with open('thriftrw/__init__.py', 'r') as f: 126 | for line in f: 127 | m = re.match(r'^__version__\s*=\s*(["\'])([^"\']+)\1', line) 128 | if m: 129 | version = m.group(2) 130 | break 131 | 132 | if not version: 133 | raise Exception( 134 | 'Could not determine version number from thriftrw/__init__.py' 135 | ) 136 | 137 | 138 | with open('README.rst') as f: 139 | long_description = f.read() 140 | 141 | setup( 142 | name='thriftrw', 143 | version=version, 144 | description=( 145 | 'A library to serialize and deserialize Thrift values.' 146 | ), 147 | long_description=long_description, 148 | author='Abhinav Gupta', 149 | author_email='abg@uber.com', 150 | url='https://github.com/thriftrw/thriftrw-python', 151 | packages=find_packages(exclude=('tests', 'tests.*')), 152 | license='MIT', 153 | install_requires=['ply'], 154 | tests_require=['pytest', 'mock'], 155 | classifiers=[ 156 | 'Development Status :: 5 - Production/Stable', 157 | 'Intended Audience :: Developers', 158 | 'License :: OSI Approved :: MIT License', 159 | 'Programming Language :: Python :: 3', 160 | 'Topic :: Software Development :: Libraries :: Python Modules', 161 | ], 162 | ext_modules=ext_modules, 163 | cmdclass=cmdclass, 164 | ) 165 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/tests/__init__.py -------------------------------------------------------------------------------- /tests/compile/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/tests/compile/__init__.py -------------------------------------------------------------------------------- /tests/compile/test_compiler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.errors import ThriftCompilerError 26 | 27 | 28 | @pytest.fixture 29 | def test_unknown_type(loads): 30 | with pytest.raises(ThriftCompilerError) as exc_info: 31 | loads(''' 32 | struct Foo { 1: optional Bar bar } 33 | struct Bar { 1: optional Baz baz } 34 | ''') 35 | 36 | assert 'Unknown type "Baz"' in str(exc_info) 37 | 38 | 39 | def test_duplicate_type_names(loads): 40 | with pytest.raises(ThriftCompilerError) as exc_info: 41 | loads(''' 42 | typedef string foo 43 | 44 | struct foo { 1: required string bar } 45 | ''') 46 | 47 | assert 'Cannot define type "foo"' in str(exc_info) 48 | assert 'type with that name already exists' in str(exc_info) 49 | 50 | 51 | def test_constant_type_conflict(loads): 52 | with pytest.raises(ThriftCompilerError) as exc_info: 53 | loads(''' 54 | const string foo = "foo" 55 | 56 | struct foo { 1: required string bar } 57 | ''') 58 | 59 | assert 'Cannot define "foo"' in str(exc_info) 60 | assert 'name has already been used' in str(exc_info) 61 | 62 | 63 | def test_service_type_conflict(loads): 64 | with pytest.raises(ThriftCompilerError) as exc_info: 65 | loads(''' 66 | struct foo { 1: required string bar } 67 | service foo {} 68 | ''') 69 | 70 | assert 'Cannot define "foo"' in str(exc_info) 71 | assert 'name has already been used' in str(exc_info) 72 | 73 | 74 | def test_services_and_types(loads): 75 | s = ''' 76 | struct Foo {} 77 | union Bar {} 78 | 79 | service A {} 80 | service B {} 81 | 82 | const list z = [x, y]; 83 | const i32 x = 42; 84 | const i32 y = 123; 85 | ''' 86 | m = loads(s) 87 | 88 | assert { 89 | 'z': [m.x, m.y], 90 | 'x': 42, 91 | 'y': 123, 92 | } == m.__constants__ 93 | 94 | assert ( 95 | m.__types__ == (m.Foo, m.Bar) or 96 | m.__types__ == (m.Bar, m.Foo) 97 | ) 98 | 99 | assert ( 100 | m.__services__ == (m.A, m.B) or 101 | m.__services__ == (m.B, m.A) 102 | ) 103 | 104 | assert m.__thrift_source__ == s 105 | -------------------------------------------------------------------------------- /tests/compile/test_spec.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # Copyright (c) 2016 Uber Technologies, Inc. 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | from __future__ import absolute_import, unicode_literals, print_function 23 | 24 | import pytest 25 | from decimal import Decimal 26 | from fractions import Fraction 27 | from itertools import permutations 28 | 29 | from thriftrw import spec 30 | from thriftrw.wire import ttype 31 | 32 | from ..util.value import ( 33 | vbool, vbyte, vi16, vi32, vi64, vdouble, vbinary, vlist, vmap, vset, 34 | ) 35 | 36 | 37 | @pytest.mark.parametrize('t_spec, value, obj', [ 38 | (spec.BoolTypeSpec, vbool(True), True), 39 | (spec.BoolTypeSpec, vbool(False), False), 40 | 41 | (spec.ByteTypeSpec, vbyte(42), 42), 42 | (spec.DoubleTypeSpec, vdouble(1.0138910), 1.0138910), 43 | (spec.I16TypeSpec, vi16(13907), 13907), 44 | (spec.I32TypeSpec, vi32(198314), 198314), 45 | (spec.I64TypeSpec, vi64(13814081), 13814081), 46 | 47 | (spec.BinaryTypeSpec, vbinary(b''), b''), 48 | (spec.BinaryTypeSpec, vbinary(b'hello'), b'hello'), 49 | 50 | (spec.TextTypeSpec, vbinary(b'\xe2\x98\x83'), u'☃'), 51 | 52 | (spec.ListTypeSpec(spec.I16TypeSpec), vlist(ttype.I16), []), 53 | (spec.ListTypeSpec(spec.ByteTypeSpec), 54 | vlist(ttype.BYTE, vbyte(1), vbyte(2), vbyte(3)), 55 | [1, 2, 3]), 56 | ]) 57 | def test_primitive_wire_conversion(t_spec, value, obj): 58 | t_spec.validate(obj) 59 | assert value == t_spec.to_wire(obj) 60 | assert obj == t_spec.from_wire(value) 61 | 62 | 63 | @pytest.mark.parametrize('t_spec, value, input, output', [ 64 | ( 65 | spec.DoubleTypeSpec, 66 | vdouble(1.391874431876), 67 | Decimal(1.391874431876), 68 | 1.391874431876, 69 | ), 70 | ( 71 | spec.DoubleTypeSpec, 72 | vdouble(1.713294871420987), 73 | Fraction(1.713294871420987), 74 | 1.713294871420987, 75 | ), 76 | ]) 77 | def test_primitive_to_wire(t_spec, value, input, output): 78 | t_spec.validate(input) 79 | assert value == t_spec.to_wire(input) 80 | assert output == t_spec.from_wire(value) 81 | 82 | 83 | @pytest.mark.parametrize('t_spec, value', [ 84 | (spec.BoolTypeSpec, vbyte(1)), 85 | (spec.ByteTypeSpec, vbool(True)), 86 | (spec.ListTypeSpec(spec.I32TypeSpec), vset(ttype.I32, vi32(42))), 87 | ]) 88 | def test_ttype_mismatch(t_spec, value): 89 | with pytest.raises(ValueError): 90 | t_spec.from_wire(value) 91 | 92 | 93 | @pytest.mark.parametrize('t_spec, pairs, obj', [ 94 | (spec.MapTypeSpec(spec.TextTypeSpec, spec.I32TypeSpec), [], {}), 95 | ( 96 | spec.MapTypeSpec(spec.TextTypeSpec, spec.I32TypeSpec), 97 | [ 98 | (vbinary(b'a'), vi32(1)), 99 | (vbinary(b'b'), vi32(2)), 100 | (vbinary(b'c'), vi32(3)), 101 | (vbinary(b'\xe2\x98\x83'), vi32(4)), 102 | ], 103 | { 104 | u'a': 1, 105 | u'b': 2, 106 | u'c': 3, 107 | u'☃': 4, 108 | } 109 | ) 110 | 111 | ]) 112 | def test_map_wire_conversion(t_spec, pairs, obj): 113 | ktype = t_spec.kspec.ttype_code 114 | vtype = t_spec.vspec.ttype_code 115 | 116 | assert t_spec.from_wire(vmap(ktype, vtype, *pairs)) == obj 117 | 118 | value = t_spec.to_wire(obj) 119 | assert ktype == value.key_ttype 120 | assert vtype == value.value_ttype 121 | assert any( 122 | left == right 123 | for left in permutations(pairs) 124 | for right in permutations(pairs) 125 | ) 126 | 127 | 128 | def test_map_from_wire_duplicate_keys(): 129 | mspec = spec.MapTypeSpec(spec.I16TypeSpec, spec.I32TypeSpec) 130 | result = mspec.from_wire(vmap( 131 | ttype.I16, ttype.I32, 132 | (vi16(0), vi32(1)), 133 | (vi16(2), vi32(3)), 134 | (vi16(4), vi32(5)), 135 | (vi16(0), vi32(6)), 136 | )) 137 | 138 | assert {0: 6, 2: 3, 4: 5} == result 139 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from functools import partial 24 | import sys 25 | 26 | import pytest 27 | 28 | from thriftrw.loader import Loader 29 | from thriftrw.protocol import BinaryProtocol 30 | 31 | 32 | def pytest_configure(config): 33 | config.addinivalue_line( 34 | "markers", "unimport: unimport module for test" 35 | ) 36 | 37 | 38 | def unimport(*names): 39 | """Removes imported modules from ``sys.modules``. 40 | 41 | The given modules and all their parents will be removed from 42 | ``sys.modules``. For example, if ``unimport('os.path')`` is called, both 43 | ``os.path`` and ``os`` will be removed from ``sys.modules``. 44 | 45 | The intented use case for this is to tell the system to forget about 46 | modules created during tests to ensure that other tests that create 47 | similarly named modules don't conflict with existing modules. 48 | 49 | :param names: 50 | List of modules to be removed. The given modules and all their parents 51 | will be removed. 52 | """ 53 | modules = set() 54 | for name in names: 55 | parts = name.split('.') 56 | while parts: 57 | modules.add('.'.join(parts)) 58 | parts = parts[:-1] 59 | 60 | for module in modules: 61 | sys.modules.pop(module, None) 62 | 63 | 64 | def pytest_runtest_teardown(item, nextitem): 65 | """Teardown hook for unimport. 66 | 67 | Can be used like so, 68 | 69 | .. code-block:: python 70 | 71 | @pytest.mark.unimport('foo.bar', 'foo.qux') 72 | def test_something(): 73 | from foo.bar import Bar 74 | 75 | # ... 76 | """ 77 | for marker in item.iter_markers('unimport'): 78 | unimport(*marker.args) 79 | 80 | 81 | @pytest.fixture 82 | def loads(request): 83 | return partial(Loader(BinaryProtocol()).loads, request.node.name) 84 | -------------------------------------------------------------------------------- /tests/idl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/tests/idl/__init__.py -------------------------------------------------------------------------------- /tests/idl/test_parser.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.idl import ast 26 | from thriftrw.idl.parser import Parser 27 | from thriftrw.errors import ThriftParserError 28 | 29 | 30 | @pytest.mark.parametrize('s', [ 31 | # we disallow 0 as a field ID at the parser level 32 | 'struct Foo { 0: string foo }', 33 | 'service Bar {', 34 | 'service { }', 35 | 'typedef i64 foo (bar = )', 36 | ]) 37 | def test_parse_errors(s): 38 | with pytest.raises(ThriftParserError): 39 | Parser().parse(s) 40 | 41 | 42 | @pytest.mark.parametrize('start, expected, s', [ 43 | # type annotations 44 | ('annotations', [], ''), 45 | ('annotations', [], '()'), 46 | ('annotations', [ 47 | ast.Annotation('foo', True, 1), 48 | ast.Annotation('bar', 'baz', 1), 49 | ast.Annotation('qux', True, 1), 50 | ], "(foo, bar = 'baz', qux)"), 51 | 52 | # constants 53 | ( 54 | 'const_value', 55 | ast.ConstReference('SomeEnum.someItem', 1), 56 | 'SomeEnum.someItem', 57 | ), 58 | ( 59 | 'const_value', 60 | ast.ConstList( 61 | values=[ 62 | ast.ConstPrimitiveValue(1, 1), 63 | ast.ConstPrimitiveValue(2, 1), 64 | ast.ConstPrimitiveValue(3, 1), 65 | ], 66 | lineno=1, 67 | ), 68 | '[1, 2, 3]', 69 | ), 70 | ( 71 | 'const_value', 72 | ast.ConstMap( 73 | pairs={ 74 | ast.ConstPrimitiveValue('x', 1): ast.ConstReference('y', 1), 75 | ast.ConstPrimitiveValue('baz', 1): ast.ConstReference(42, 1), 76 | }, 77 | lineno=1, 78 | ), 79 | '{"x": y, "baz": 42}', 80 | ), 81 | 82 | # field types 83 | ('field_type', ast.PrimitiveType('byte', []), 'byte'), 84 | ('field_type', ast.PrimitiveType('byte', []), 'i8'), # i8 == byte 85 | ('field_type', ast.PrimitiveType('i16', []), 'i16'), 86 | ( 87 | 'field_type', 88 | ast.PrimitiveType('i32', [ 89 | ast.Annotation('foo', 'bar', 1), 90 | ast.Annotation('baz', 'qux', 1), 91 | ]), 92 | 'i32 (foo = "bar", baz = "qux")', 93 | ), 94 | 95 | ( 96 | # typedef with annotations on both, the typedef and the arguments. 97 | 'typedef', 98 | ast.Typedef( 99 | name='Integer', 100 | target_type=ast.PrimitiveType('i32', [ 101 | ast.Annotation('foo', 'bar', 3), 102 | ast.Annotation('baz', 'qux', 4), 103 | ]), 104 | annotations=[ 105 | ast.Annotation('boxed', 'true', 5), 106 | ast.Annotation('bounded', True, 5), 107 | ], 108 | lineno=5, 109 | ), 110 | """ 111 | typedef i32 ( 112 | foo = "bar"; 113 | baz = "qux"; 114 | ) Integer (boxed = "true", bounded) 115 | """, 116 | ), 117 | ]) 118 | def test_parse_ast(start, expected, s): 119 | assert expected == Parser(start=start, silent=True).parse(s) 120 | -------------------------------------------------------------------------------- /tests/protocol/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/tests/protocol/__init__.py -------------------------------------------------------------------------------- /tests/spec/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/tests/spec/__init__.py -------------------------------------------------------------------------------- /tests/spec/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.compile.scope import Scope 26 | 27 | 28 | @pytest.fixture 29 | def scope(request): 30 | return Scope(request.node.name) 31 | -------------------------------------------------------------------------------- /tests/spec/test_common.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from collections import namedtuple 24 | 25 | from thriftrw.spec import common 26 | 27 | 28 | def test_fields_str(): 29 | Foo = namedtuple('Foo', 'bar') 30 | to_str = common.fields_str('Foo', ('bar',)) 31 | 32 | assert to_str(Foo(42)) == ('Foo({%r: 42})' % 'bar') 33 | assert to_str(Foo(None)) == ('Foo({%r: None})' % 'bar') 34 | 35 | 36 | def test_fields_str_ignore_none(): 37 | Foo = namedtuple('Foo', 'bar') 38 | to_str = common.fields_str('Foo', ('bar',), False) 39 | 40 | assert to_str(Foo(42)) == ('Foo({%r: 42})' % 'bar') 41 | assert to_str(Foo(None)) == 'Foo({})' 42 | -------------------------------------------------------------------------------- /tests/spec/test_exc.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.idl import Parser 26 | from thriftrw.spec.exc import ExceptionTypeSpec 27 | from thriftrw.spec.field import FieldSpec 28 | from thriftrw.spec import primitive as prim_spec 29 | 30 | 31 | @pytest.fixture 32 | def parse(): 33 | return Parser(start='exception', silent=True).parse 34 | 35 | 36 | def test_compile(parse): 37 | spec = ExceptionTypeSpec.compile(parse('''exception MyException { 38 | 1: required string message 39 | }''')) 40 | 41 | assert spec.name == 'MyException' 42 | assert spec.fields == [ 43 | FieldSpec(1, 'message', prim_spec.TextTypeSpec, True) 44 | ] 45 | 46 | 47 | def test_load(loads): 48 | MyException = loads(''' 49 | exception MyException { 50 | 1: required string message 51 | } 52 | ''').MyException 53 | 54 | assert issubclass(MyException, Exception) 55 | 56 | with pytest.raises(MyException): 57 | # Must be raise-able 58 | raise MyException('hello world') 59 | -------------------------------------------------------------------------------- /tests/spec/test_hashable.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | from __future__ import absolute_import, unicode_literals, print_function 21 | 22 | import pytest 23 | 24 | 25 | @pytest.mark.parametrize('name, src, kwargs', [ 26 | ( 27 | 'Foo', ''' 28 | struct Foo { 29 | 1: required string a 30 | } 31 | ''', 32 | {'a': 'zzz'} 33 | ), 34 | ( 35 | 'Bar', ''' 36 | union Bar{ 37 | 1: binary b 38 | 2: string s 39 | } 40 | ''', 41 | {'s': 'bar'}, 42 | ), 43 | ( 44 | 'Baz', ''' 45 | enum Enum { A = 1, B = 2 } 46 | struct Baz { 47 | 1: optional Enum e 48 | } 49 | ''', 50 | {'e': 1}, 51 | ), 52 | ]) 53 | def test_hashable(loads, name, src, kwargs): 54 | module = loads(src) 55 | klass = getattr(module, name) 56 | obj1 = klass(**kwargs) 57 | obj2 = klass(**kwargs) 58 | assert hash(obj1) == hash(obj2) 59 | assert hash(obj1) == hash(obj1) 60 | 61 | 62 | @pytest.mark.parametrize('name, src, kwargs1, kwargs2', [ 63 | ( 64 | 'Foo', ''' 65 | struct Foo { 66 | 1: required string a 67 | } 68 | ''', 69 | {'a': 'zzz'}, 70 | {'a': 'aaa'}, 71 | ), 72 | ( 73 | 'Bar', ''' 74 | union Bar{ 75 | 1: binary b 76 | 2: string s 77 | } 78 | ''', 79 | {'s': 'bar'}, 80 | {'b': '0b111'}, 81 | ), 82 | ( 83 | 'Baz', ''' 84 | enum Enum { A = 1, B = 2 } 85 | struct Baz { 86 | 1: optional Enum e 87 | } 88 | ''', 89 | {'e': 1}, 90 | {'e': 2}, 91 | ), 92 | ]) 93 | def test_hash_inequality(loads, name, src, kwargs1, kwargs2): 94 | module = loads(src) 95 | klass = getattr(module, name) 96 | obj1 = klass(**kwargs1) 97 | obj2 = klass(**kwargs2) 98 | assert hash(obj1) != hash(obj2) 99 | 100 | 101 | @pytest.mark.parametrize('name, src, kwargs', [ 102 | ( 103 | 'Foo', ''' 104 | struct Foo { 105 | 1: required string a 106 | 2: required list b 107 | 3: required map c = {} 108 | } 109 | ''', 110 | {'a': 'zzz', 'b': ['bar']}, 111 | ), 112 | ( 113 | 'Bar', ''' 114 | union Bar { 115 | 1: binary b 116 | 2: string s 117 | 3: list ls 118 | } 119 | ''', 120 | {'s': 'bar'}, 121 | ), 122 | ]) 123 | def test_nonhashable(loads, name, src, kwargs): 124 | module = loads(src) 125 | klass = getattr(module, name) 126 | obj = klass(**kwargs) 127 | with pytest.raises(TypeError): 128 | hash(obj) 129 | -------------------------------------------------------------------------------- /tests/spec/test_list.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.idl import Parser 26 | from thriftrw.spec import primitive as prim_spec 27 | from thriftrw.spec.list import ListTypeSpec 28 | from thriftrw.spec.typedef import TypedefTypeSpec 29 | from thriftrw.spec.spec_mapper import type_spec_or_ref 30 | from thriftrw.wire import ttype 31 | 32 | from ..util.value import vbinary, vlist 33 | 34 | 35 | @pytest.fixture 36 | def parse(): 37 | return Parser(start='list_type', silent=True).parse 38 | 39 | 40 | def test_mapper(parse): 41 | ast = parse('list') 42 | spec = type_spec_or_ref(ast) 43 | assert spec == ListTypeSpec(prim_spec.BinaryTypeSpec) 44 | 45 | 46 | def test_link(parse, scope): 47 | ast = parse('list') 48 | spec = type_spec_or_ref(ast) 49 | 50 | scope.add_type_spec( 51 | 'Foo', TypedefTypeSpec('Foo', prim_spec.TextTypeSpec), 1 52 | ) 53 | 54 | spec = spec.link(scope) 55 | assert spec.vspec == prim_spec.TextTypeSpec 56 | 57 | value = [u'foo', u'bar'] 58 | assert spec.to_wire(value) == vlist( 59 | ttype.BINARY, vbinary(b'foo'), vbinary(b'bar') 60 | ) 61 | assert value == spec.from_wire(spec.to_wire(value)) 62 | 63 | 64 | def test_primitive(parse, scope, loads): 65 | Foo = loads('struct Foo { 1: required i64 i }').Foo 66 | scope.add_type_spec('Foo', Foo.type_spec, 1) 67 | 68 | spec = type_spec_or_ref(parse('list')).link(scope) 69 | 70 | value = [ 71 | Foo(1234), 72 | Foo(1234567890), 73 | Foo(1234567890123456789), 74 | ] 75 | 76 | prim_value = [ 77 | {'i': 1234}, 78 | {'i': 1234567890}, 79 | {'i': 1234567890123456789}, 80 | ] 81 | 82 | assert spec.to_primitive(value) == prim_value 83 | assert spec.from_primitive(prim_value) == value 84 | 85 | 86 | def test_from_primitive_invalid(parse, scope): 87 | spec = type_spec_or_ref(parse('list')).link(scope) 88 | 89 | with pytest.raises(ValueError): 90 | spec.from_primitive(['a', 'b', 'c']) 91 | 92 | 93 | def test_validate(): 94 | spec = ListTypeSpec(prim_spec.BinaryTypeSpec) 95 | spec.validate([b'a']) 96 | spec.validate([u'a']) 97 | 98 | with pytest.raises(TypeError): 99 | spec.validate(42) 100 | -------------------------------------------------------------------------------- /tests/spec/test_map.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.idl import Parser 26 | from thriftrw.spec import primitive as prim_spec 27 | from thriftrw.spec.map import MapTypeSpec 28 | from thriftrw.spec.typedef import TypedefTypeSpec 29 | from thriftrw.spec.spec_mapper import type_spec_or_ref 30 | from thriftrw.wire import ttype 31 | 32 | from ..util.value import vi32, vmap, vbinary 33 | 34 | 35 | @pytest.fixture 36 | def parse(): 37 | return Parser(start='map_type', silent=True).parse 38 | 39 | 40 | def test_mapper(parse): 41 | ast = parse('map') 42 | spec = type_spec_or_ref(ast) 43 | assert spec == MapTypeSpec(prim_spec.TextTypeSpec, prim_spec.I32TypeSpec) 44 | 45 | 46 | def test_link(parse, scope): 47 | ast = parse('map') 48 | spec = type_spec_or_ref(ast) 49 | 50 | scope.add_type_spec( 51 | 'Foo', TypedefTypeSpec('Foo', prim_spec.I32TypeSpec), 1 52 | ) 53 | 54 | spec = spec.link(scope) 55 | assert spec.vspec == prim_spec.I32TypeSpec 56 | 57 | value = {u'foo': 1, u'bar': 2} 58 | assert ( 59 | spec.to_wire(value) == vmap( 60 | ttype.BINARY, ttype.I32, 61 | (vbinary(b'foo'), vi32(1)), 62 | (vbinary(b'bar'), vi32(2)), 63 | ) 64 | ) or ( 65 | spec.to_wire(value) == vmap( 66 | ttype.BINARY, ttype.I32, 67 | (vbinary(b'bar'), vi32(2)), 68 | (vbinary(b'foo'), vi32(1)), 69 | ) 70 | ) 71 | assert value == spec.from_wire(spec.to_wire(value)) 72 | 73 | 74 | def test_primitive(parse, scope, loads): 75 | Foo = loads('struct Foo { 1: required string bar }').Foo 76 | scope.add_type_spec('Foo', Foo.type_spec, 1) 77 | 78 | spec = type_spec_or_ref(parse('map')).link(scope) 79 | 80 | value = { 81 | 'a': Foo('1'), 82 | 'b': Foo('2'), 83 | 'c': Foo('3'), 84 | } 85 | 86 | prim_value = { 87 | 'a': {'bar': '1'}, 88 | 'b': {'bar': '2'}, 89 | 'c': {'bar': '3'}, 90 | } 91 | 92 | assert spec.to_primitive(value) == prim_value 93 | assert spec.from_primitive(prim_value) == value 94 | -------------------------------------------------------------------------------- /tests/spec/test_primitive.py: -------------------------------------------------------------------------------- 1 | # encoding=utf8 2 | # Copyright (c) 2016 Uber Technologies, Inc. 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | from __future__ import absolute_import, unicode_literals, print_function 23 | 24 | import pytest 25 | 26 | from thriftrw.spec.primitive import ByteTypeSpec 27 | from thriftrw.spec.primitive import I16TypeSpec 28 | from thriftrw.spec.primitive import I32TypeSpec 29 | from thriftrw.spec.primitive import I64TypeSpec 30 | from thriftrw.spec.primitive import TextTypeSpec 31 | from thriftrw.wire.value import BinaryValue 32 | 33 | 34 | @pytest.mark.parametrize('args', [ 35 | (u'☃', b'\xe2\x98\x83', None), 36 | (b'\xe2\x98\x83', b'\xe2\x98\x83', u'☃'), 37 | (b'foo', b'foo', u'foo'), 38 | ]) 39 | def test_text_round_trip(args): 40 | # workaround for pytest-dev/pytest#1086 until pytest 2.8.2 is released. 41 | s, val, out = args 42 | if out is None: 43 | out = s 44 | 45 | wire_val = TextTypeSpec.to_wire(s) 46 | assert wire_val == BinaryValue(val) 47 | assert TextTypeSpec.from_wire(wire_val) == out 48 | 49 | 50 | @pytest.mark.parametrize('args', [ 51 | (u'☃', u'☃', None), 52 | (b'\xe2\x98\x83', u'☃', u'☃'), 53 | ]) 54 | def test_text_primitive(args): 55 | # workaround for pytest-dev/pytest#1086 until pytest 2.8.2 is released. 56 | s, prim_s, out_s = args 57 | if out_s is None: 58 | out_s = s 59 | 60 | assert TextTypeSpec.to_primitive(s) == prim_s 61 | assert TextTypeSpec.from_primitive(prim_s) == out_s 62 | 63 | 64 | def test_validate(): 65 | spec = TextTypeSpec 66 | spec.validate('foo') 67 | 68 | with pytest.raises(TypeError): 69 | spec.validate(1) 70 | 71 | 72 | def test_validate_byte(): 73 | ByteTypeSpec.validate(127) 74 | ByteTypeSpec.validate(-128) 75 | with pytest.raises(ValueError): 76 | ByteTypeSpec.validate(128) 77 | with pytest.raises(ValueError): 78 | ByteTypeSpec.validate(-129) 79 | 80 | 81 | def test_validate_i16(): 82 | I16TypeSpec.validate(32767) 83 | I16TypeSpec.validate(-32768) 84 | with pytest.raises(ValueError): 85 | I16TypeSpec.validate(32768) 86 | with pytest.raises(ValueError): 87 | I16TypeSpec.validate(-32769) 88 | 89 | 90 | def test_validate_i32(): 91 | I32TypeSpec.validate(2147483647) 92 | I32TypeSpec.validate(-2147483648) 93 | with pytest.raises(ValueError): 94 | I32TypeSpec.validate(2147483648) 95 | with pytest.raises(ValueError): 96 | I32TypeSpec.validate(-2147483649) 97 | 98 | 99 | def test_validate_i64(): 100 | I64TypeSpec.validate(9223372036854775807) 101 | I64TypeSpec.validate(-9223372036854775808) 102 | with pytest.raises(ValueError): 103 | I64TypeSpec.validate(9223372036854775808) 104 | with pytest.raises(ValueError): 105 | I64TypeSpec.validate(-9223372036854775809) 106 | -------------------------------------------------------------------------------- /tests/spec/test_set.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | from itertools import permutations 25 | 26 | from thriftrw.idl import Parser 27 | from thriftrw.spec import primitive as prim_spec 28 | from thriftrw.spec.set import SetTypeSpec 29 | from thriftrw.spec.typedef import TypedefTypeSpec 30 | from thriftrw.spec.spec_mapper import type_spec_or_ref 31 | from thriftrw.wire import ttype 32 | 33 | from ..util.value import vbinary, vset 34 | 35 | 36 | @pytest.fixture 37 | def parse(): 38 | return Parser(start='set_type', silent=True).parse 39 | 40 | 41 | def test_mapper(parse): 42 | ast = parse('set') 43 | spec = type_spec_or_ref(ast) 44 | assert spec == SetTypeSpec(prim_spec.BinaryTypeSpec) 45 | 46 | 47 | def test_link(parse, scope): 48 | ast = parse('set') 49 | spec = type_spec_or_ref(ast) 50 | 51 | scope.add_type_spec( 52 | 'Foo', TypedefTypeSpec('Foo', prim_spec.TextTypeSpec), 1 53 | ) 54 | 55 | spec = spec.link(scope) 56 | assert spec.vspec == prim_spec.TextTypeSpec 57 | 58 | value = set([u'foo', u'bar']) 59 | assert ( 60 | spec.to_wire(value) == vset( 61 | ttype.BINARY, vbinary(b'foo'), vbinary(b'bar') 62 | ) 63 | ) or ( 64 | spec.to_wire(value) == vset( 65 | ttype.BINARY, vbinary(b'bar'), vbinary(b'foo') 66 | ) 67 | ) 68 | assert value == spec.from_wire(spec.to_wire(value)) 69 | 70 | 71 | def test_primitive(parse, scope): 72 | ast = parse('set') 73 | spec = type_spec_or_ref(ast).link(scope) 74 | 75 | prim_value = spec.to_primitive(set([1, 2, 3])) 76 | assert any(prim_value == list(xs) for xs in permutations([1, 2, 3])) 77 | assert spec.from_primitive(prim_value) == set([1, 2, 3]) 78 | 79 | 80 | def test_validate(): 81 | spec = SetTypeSpec(prim_spec.TextTypeSpec) 82 | 83 | spec.validate(set(['a'])) 84 | 85 | with pytest.raises(TypeError): 86 | spec.validate(set([1])) 87 | 88 | with pytest.raises(TypeError): 89 | spec.validate(1) 90 | -------------------------------------------------------------------------------- /tests/spec/test_typedef.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.spec.reference import TypeReference 26 | from thriftrw.spec.typedef import TypedefTypeSpec 27 | from thriftrw.spec import primitive as prim_spec 28 | from thriftrw.idl import Parser 29 | 30 | 31 | @pytest.fixture 32 | def parse(): 33 | """Parser for enum definitions.""" 34 | return Parser(start='typedef', silent=True).parse 35 | 36 | 37 | def test_compile(parse): 38 | assert TypedefTypeSpec.compile(parse('typedef i32 ID')) == ( 39 | TypedefTypeSpec('ID', prim_spec.I32TypeSpec) 40 | ) 41 | 42 | assert TypedefTypeSpec.compile(parse('typedef Custom Foo')) == ( 43 | TypedefTypeSpec('Foo', TypeReference('Custom', 1)) 44 | ) 45 | 46 | 47 | def test_link(loads): 48 | mod = loads(''' 49 | typedef Bar Foo 50 | typedef Baz Bar 51 | typedef Qux Baz 52 | 53 | struct Qux { 54 | 1: required i32 x 55 | } 56 | ''') 57 | 58 | assert mod.Foo is mod.Bar 59 | assert mod.Bar is mod.Baz 60 | assert mod.Baz is mod.Qux 61 | -------------------------------------------------------------------------------- /tests/test_benchmark.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | import pytest 22 | 23 | import thriftrw 24 | 25 | 26 | @pytest.fixture(scope='session') 27 | def module(request): 28 | return thriftrw.loader.Loader().loads('benchmark', ''' 29 | struct PrimitiveContainers { 30 | 1: required list strings; 31 | 2: required set ints; 32 | 3: required map mapped; 33 | } 34 | 35 | struct Point { 36 | 1: required double x; 37 | 2: required double y; 38 | } 39 | 40 | struct Edge { 41 | 1: required Point start; 42 | 2: required Point end; 43 | } 44 | 45 | struct Graph { 1: required list edges } 46 | ''') 47 | 48 | 49 | @pytest.fixture(params=[ 50 | 'primitive_containers', 51 | 'nested_structs', 52 | ]) 53 | def value(module, request): 54 | if request.param == 'primitive_containers': 55 | return module.PrimitiveContainers( 56 | strings=['foo'] * 100000, 57 | ints=set(range(100000)), 58 | mapped={n: 'bar' for n in range(100000)}, 59 | ) 60 | elif request.param == 'nested_structs': 61 | return module.Graph(edges=[ 62 | module.Edge( 63 | start=module.Point(1.23, 4.56), 64 | end=module.Point(1.23, 4.56), 65 | ) for i in range(1000) 66 | ]) 67 | else: 68 | raise NotImplementedError 69 | 70 | 71 | def test_binary_dumps(benchmark, module, value): 72 | benchmark(module.dumps, value) 73 | 74 | 75 | def test_binary_loads(benchmark, module, value): 76 | serialized = module.dumps(value) 77 | benchmark(module.loads, value.__class__, serialized) 78 | 79 | 80 | def test_to_primitive(benchmark, value): 81 | benchmark(value.to_primitive) 82 | 83 | 84 | def test_from_primitive(benchmark, value): 85 | primitive = value.to_primitive() 86 | benchmark(value.type_spec.from_primitive, primitive) 87 | -------------------------------------------------------------------------------- /tests/test_buffer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw._buffer import ReadBuffer 26 | from thriftrw._buffer import WriteBuffer 27 | from thriftrw.errors import EndOfInputError 28 | 29 | 30 | def test_empty_write_buffer(): 31 | buff = WriteBuffer(10) 32 | assert buff.length == 0 33 | assert buff.capacity == 10 34 | assert buff.value == b'' 35 | 36 | 37 | def test_empty_read_buffer(): 38 | buff = ReadBuffer(b'') 39 | assert buff.take(0) == b'' 40 | 41 | with pytest.raises(EndOfInputError): 42 | buff.take(1) 43 | 44 | 45 | def test_simple_write(): 46 | buff = WriteBuffer(10) 47 | buff.write_bytes(b'hello ') 48 | buff.write_bytes(b'world') 49 | 50 | assert buff.value == b'hello world' 51 | assert buff.length == 11 52 | 53 | 54 | def test_simple_read(): 55 | buff = ReadBuffer(b'abcd') 56 | 57 | assert buff.take(1) == b'a' 58 | assert buff.take(2) == b'bc' 59 | 60 | with pytest.raises(EndOfInputError): 61 | buff.take(2) 62 | 63 | assert buff.take(1) == b'd' 64 | 65 | 66 | def test_write_clear(): 67 | buff = WriteBuffer(10) 68 | buff.write_bytes(b'foo') 69 | buff.clear() 70 | 71 | assert buff.value == b'' 72 | assert buff.capacity == 10 73 | assert buff.length == 0 74 | -------------------------------------------------------------------------------- /tests/test_loader.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from textwrap import dedent 24 | 25 | import pytest 26 | 27 | from thriftrw.errors import ThriftCompilerError 28 | from thriftrw.loader import Loader 29 | 30 | 31 | def test_load_from_file(tmpdir): 32 | tmpdir.join('my_service.thrift').write(''' 33 | struct Foo { 34 | 1: required string a 35 | 2: optional string b 36 | } 37 | ''') 38 | 39 | my_service = Loader().load(str(tmpdir.join('my_service.thrift'))) 40 | my_service.Foo(b='b', a='a') 41 | 42 | 43 | def test_load_from_file_missing_requiredness(tmpdir): 44 | tmpdir.join('my_service.thrift').write(''' 45 | struct Foo { 46 | 1: required string a 47 | 2: string b 48 | } 49 | ''') 50 | 51 | with pytest.raises(ThriftCompilerError) as exc_info: 52 | Loader().load(str(tmpdir.join('my_service.thrift'))) 53 | 54 | assert ( 55 | '"b" of "Foo" on line 4 does not explicitly specify requiredness.' 56 | in str(exc_info) 57 | ) 58 | 59 | 60 | def test_load_from_file_non_strict_missing_requiredness(tmpdir): 61 | tmpdir.join('my_service.thrift').write(''' 62 | struct Foo { 63 | 1: required string a 64 | 2: string b 65 | } 66 | 67 | exception Bar { 68 | 1: string message 69 | } 70 | ''') 71 | 72 | loader = Loader(strict=False) 73 | m = loader.load(str(tmpdir.join('my_service.thrift'))) 74 | m.Foo(b='b', a='a') 75 | 76 | m.Bar(message='foo') 77 | m.Bar() 78 | 79 | 80 | def test_caching(tmpdir, monkeypatch): 81 | tmpdir.join('my_service.thrift').write(''' 82 | struct Foo { 83 | 1: required string a 84 | 2: optional string b 85 | } 86 | ''') 87 | 88 | path = str(tmpdir.join('my_service.thrift')) 89 | loader = Loader() 90 | 91 | mod1 = loader.load(path) 92 | mod2 = loader.load(path) 93 | assert mod1 is mod2 94 | 95 | 96 | @pytest.mark.unimport('foo.bar.svc') 97 | def test_install_absolute(tmpdir, monkeypatch): 98 | module_root = tmpdir.mkdir('foo') 99 | module_root.join('__init__.py').ensure() 100 | 101 | thrift_file = module_root.join('service.thrift') 102 | thrift_file.write( 103 | 'struct Foo { 1: required string a; 2: optional string b }' 104 | ) 105 | 106 | py_file = module_root.join('bar.py') 107 | py_file.write( 108 | dedent(''' 109 | import thriftrw 110 | 111 | thriftrw.install(%r, name='svc') 112 | ''' % str(thrift_file)) 113 | ) 114 | 115 | monkeypatch.syspath_prepend(str(tmpdir)) 116 | 117 | from foo.bar.svc import Foo 118 | 119 | assert Foo(a='bar') == Foo(a='bar') 120 | 121 | 122 | @pytest.mark.unimport('foo.service', 'foo.bar') 123 | def test_install_relative(tmpdir, monkeypatch): 124 | module_root = tmpdir.mkdir('foo') 125 | module_root.join('service.thrift').write('struct Bar {}') 126 | 127 | module_root.join('bar.py').write(dedent(''' 128 | from __future__ import absolute_import 129 | from .service import Bar 130 | ''')) 131 | 132 | module_root.join('__init__.py').write(dedent(''' 133 | import thriftrw 134 | 135 | thriftrw.install('service.thrift') 136 | ''')) 137 | 138 | monkeypatch.syspath_prepend(str(tmpdir)) 139 | 140 | from foo.bar import Bar 141 | 142 | assert Bar() == Bar() 143 | 144 | 145 | @pytest.mark.unimport('foo.service') 146 | def test_install_twice(tmpdir, monkeypatch): 147 | module_root = tmpdir.mkdir('foo') 148 | module_root.join('__init__.py').write(dedent(''' 149 | import thriftrw 150 | 151 | def go(): 152 | return thriftrw.install('service.thrift') 153 | ''')) 154 | 155 | module_root.join('service.thrift').write( 156 | 'struct Foo { 1: required string a 2: optional string b }' 157 | ) 158 | 159 | monkeypatch.syspath_prepend(str(tmpdir)) 160 | 161 | from foo import go 162 | 163 | with pytest.raises(ImportError): 164 | from foo.service import Foo 165 | Foo() 166 | 167 | assert go() is go() 168 | 169 | from foo.service import Foo 170 | assert go().Foo is Foo 171 | -------------------------------------------------------------------------------- /tests/test_names_match_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | Tests in this file just make sure that the names for functions and types are 23 | valid for use in ``type()`` calls and assignable to ``__name__``. 24 | """ 25 | 26 | from __future__ import absolute_import, print_function 27 | # We intentionally don't add unicode_literals here because we want the system 28 | # to use whatever the default is for that version of Python. 29 | 30 | import pytest 31 | 32 | 33 | @pytest.fixture 34 | def service(loads): 35 | return loads(''' 36 | struct Item {} 37 | 38 | service Service { void someMethod() } 39 | ''') 40 | 41 | 42 | def test_function_spec_name(service): 43 | func_spec = service.Service.someMethod.spec 44 | 45 | def some_func(): 46 | pass 47 | 48 | some_func.__name__ = func_spec.name 49 | 50 | 51 | def test_type_spec_name(service): 52 | type_spec = service.Item.type_spec 53 | type(type_spec.name, (), {}) 54 | -------------------------------------------------------------------------------- /tests/test_runtime.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.loader import Loader 26 | from thriftrw.protocol import BinaryProtocol 27 | from thriftrw.wire import mtype 28 | 29 | 30 | service = Loader(BinaryProtocol()).loads( 31 | 'runtime_service', 32 | ''' 33 | exception GreatSadness { 34 | 1: optional string message 35 | } 36 | 37 | service Service { 38 | oneway void write(1: binary data) 39 | 40 | i32 read() 41 | throws (1: GreatSadness sadness) 42 | 43 | } 44 | ''' 45 | ) 46 | Service = service.Service 47 | 48 | 49 | @pytest.mark.parametrize('name, seqid, typ, obj, bs', [ 50 | (b'write', 42, mtype.ONEWAY, Service.write.request(b'hello'), [ 51 | 0x00, 0x00, 0x00, 0x05, # length:4 = 5 52 | 0x77, 0x72, 0x69, 0x74, 0x65, # 'write' 53 | 0x04, # mtype:1 = ONEWAY 54 | 0x00, 0x00, 0x00, 0x2a, # seqid:4 = 42 55 | 56 | 0x0B, # ttype:1 = BINARY 57 | 0x00, 0x01, # id:2 = 1 58 | 0x00, 0x00, 0x00, 0x05, # length:4 = 5 59 | 0x68, 0x65, 0x6c, 0x6c, 0x6f, # 'hello' 60 | 61 | 0x00, # STOP 62 | ]), 63 | (b'read', 127, mtype.CALL, Service.read.request(), [ 64 | 0x00, 0x00, 0x00, 0x04, # length:4 = 5 65 | 0x72, 0x65, 0x61, 0x64, # 'read' 66 | 0x01, # CALL 67 | 0x00, 0x00, 0x00, 0x7f, # seqid:4 = 127 68 | 0x00, # STOP 69 | ]), 70 | (b'read', 127, mtype.REPLY, Service.read.response(success=42), [ 71 | 0x00, 0x00, 0x00, 0x04, # length:4 = 5 72 | 0x72, 0x65, 0x61, 0x64, # 'read' 73 | 0x02, # REPLY 74 | 0x00, 0x00, 0x00, 0x7f, # seqid:4 = 127 75 | 76 | 0x08, # ttype:1 = i32 77 | 0x00, 0x00, # id:2 = 0 78 | 0x00, 0x00, 0x00, 0x2a, # value = 42 79 | 80 | 0x00, # STOP 81 | ]), 82 | ( 83 | b'read', 84 | 42, 85 | mtype.REPLY, 86 | Service.read.response(sadness=service.GreatSadness()), 87 | [ 88 | 0x00, 0x00, 0x00, 0x04, # length:4 = 5 89 | 0x72, 0x65, 0x61, 0x64, # 'read' 90 | 0x02, # REPLY 91 | 0x00, 0x00, 0x00, 0x2a, # seqid:4 = 42 92 | 93 | 0x0C, # ttype:1 = struct 94 | 0x00, 0x01, # id:2 = 1 95 | 0x00, # STOP 96 | 97 | 0x00, # STOP 98 | ], 99 | ), 100 | ]) 101 | def test_message_round_trips(name, seqid, typ, obj, bs): 102 | bs = bytes(bytearray(bs)) 103 | 104 | assert service.dumps.message(obj, seqid) == bs 105 | 106 | message = service.loads.message(Service, bs) 107 | assert message.seqid == seqid 108 | assert message.message_type == typ 109 | assert message.name == name 110 | assert message.body == obj 111 | -------------------------------------------------------------------------------- /tests/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/tests/util/__init__.py -------------------------------------------------------------------------------- /tests/util/spec.py: -------------------------------------------------------------------------------- 1 | from thriftrw.spec.list import ListTypeSpec 2 | from thriftrw.spec.map import MapTypeSpec 3 | from thriftrw.spec.struct import StructTypeSpec 4 | from thriftrw.spec.set import SetTypeSpec 5 | from thriftrw.idl import Parser 6 | from thriftrw.compile.scope import Scope 7 | 8 | 9 | parse_struct = Parser(start='struct', silent=True).parse 10 | 11 | 12 | def sstruct(fields=""): 13 | """This helper creates a mock spec for sstruct """ 14 | struct_ast = parse_struct('struct RefStruct { %s }' % fields) 15 | spec = StructTypeSpec.compile(struct_ast) 16 | spec.link(Scope("test")) 17 | return spec 18 | 19 | 20 | def smap(key, value): 21 | return MapTypeSpec(key, value) 22 | 23 | 24 | def sset(value): 25 | return SetTypeSpec(value) 26 | 27 | 28 | def slist(value): 29 | return ListTypeSpec(value) 30 | -------------------------------------------------------------------------------- /tests/util/value.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | This module provides helpers to construct Value objects for tests. 23 | """ 24 | from __future__ import absolute_import, unicode_literals, print_function 25 | 26 | from thriftrw.wire import value 27 | 28 | 29 | vbool = value.BoolValue 30 | vbyte = value.ByteValue 31 | vi16 = value.I16Value 32 | vi32 = value.I32Value 33 | vi64 = value.I64Value 34 | vdouble = value.DoubleValue 35 | 36 | 37 | def vbinary(s): 38 | return value.BinaryValue(s) 39 | 40 | 41 | def vstruct(*fields): 42 | return value.StructValue([value.FieldValue(*args) for args in fields]) 43 | 44 | 45 | def vlist(typ, *items): 46 | return value.ListValue(typ, list(items)) 47 | 48 | 49 | def vmap(ktype, vtype, *items): 50 | return value.MapValue( 51 | ktype, vtype, [value.MapItem(k, v) for k, v in items] 52 | ) 53 | 54 | 55 | def vset(vtype, *items): 56 | return value.SetValue(vtype, list(items)) 57 | 58 | 59 | __all__ = [ 60 | 'vbool', 'vbyte', 'vi16', 'vi32', 'vi64', 'vdouble', 'vbinary', 'vstruct', 61 | 'vlist', 'vmap', 'vset' 62 | ] 63 | -------------------------------------------------------------------------------- /tests/wire/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thriftrw/thriftrw-python/7afc446a3f474912e79bd1679b6440640c8d4dcf/tests/wire/__init__.py -------------------------------------------------------------------------------- /tests/wire/test_value.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | import pytest 24 | 25 | from thriftrw.wire import value 26 | from thriftrw.wire import ttype 27 | from thriftrw.wire.value import _ValueVisitorArgs 28 | 29 | 30 | @pytest.mark.parametrize('value, visit_name, visit_args', [ 31 | # Primitives 32 | (value.BoolValue(True), 'visit_bool', (True,)), 33 | (value.ByteValue(42), 'visit_byte', (42,)), 34 | (value.DoubleValue(12.34), 'visit_double', (12.34,)), 35 | (value.I16Value(1234), 'visit_i16', (1234,)), 36 | (value.I32Value(39813), 'visit_i32', (39813,)), 37 | (value.I64Value(198735315), 'visit_i64', (198735315,)), 38 | (value.BinaryValue(b'hello world'), 'visit_binary', (b'hello world',)), 39 | 40 | # Struct 41 | (value.StructValue([ 42 | value.FieldValue(1, ttype.BOOL, value.BoolValue(True)), 43 | value.FieldValue(2, ttype.BYTE, value.ByteValue(42)), 44 | ]), 'visit_struct', ([ 45 | value.FieldValue(1, ttype.BOOL, value.BoolValue(True)), 46 | value.FieldValue(2, ttype.BYTE, value.ByteValue(42)), 47 | ],)), 48 | 49 | # Map 50 | (value.MapValue(ttype.BINARY, ttype.I16, [ 51 | value.MapItem(value.BinaryValue(b'Hello'), value.I16Value(1)), 52 | value.MapItem(value.BinaryValue(b'World'), value.I16Value(2)), 53 | ]), 'visit_map', (ttype.BINARY, ttype.I16, [ 54 | value.MapItem(value.BinaryValue(b'Hello'), value.I16Value(1)), 55 | value.MapItem(value.BinaryValue(b'World'), value.I16Value(2)), 56 | ])), 57 | 58 | # Set 59 | (value.SetValue(ttype.I32, [ 60 | value.I32Value(1234), 61 | value.I32Value(4567), 62 | ]), 'visit_set', (ttype.I32, [ 63 | value.I32Value(1234), 64 | value.I32Value(4567), 65 | ])), 66 | 67 | # List 68 | (value.ListValue(ttype.I64, [ 69 | value.I64Value(1380), 70 | value.I64Value(1479), 71 | ]), 'visit_list', (ttype.I64, [ 72 | value.I64Value(1380), 73 | value.I64Value(1479), 74 | ])), 75 | ]) 76 | def test_visitors(value, visit_name, visit_args): 77 | """Checks that for each value type, the correct visitor is called.""" 78 | 79 | visitor = _ValueVisitorArgs() 80 | result = value.apply(visitor) 81 | name = result[0] 82 | args = result[1:] 83 | 84 | assert visit_name == name 85 | assert visit_args == args 86 | 87 | 88 | def test_struct_get(): 89 | struct = value.StructValue([ 90 | value.FieldValue(1, ttype.BOOL, value.BoolValue(True)), 91 | value.FieldValue(2, ttype.BYTE, value.ByteValue(42)), 92 | value.FieldValue(3, ttype.LIST, value.ListValue( 93 | ttype.BINARY, 94 | [ 95 | value.BinaryValue(b'Hello'), 96 | value.BinaryValue(b'World'), 97 | ] 98 | )), 99 | ]) 100 | 101 | assert struct.get(1, ttype.BOOL).value 102 | assert value.ByteValue(42) == struct.get(2, ttype.BYTE).value 103 | assert value.ListValue(ttype.BINARY, [ 104 | value.BinaryValue(b'Hello'), 105 | value.BinaryValue(b'World'), 106 | ]) == struct.get(3, ttype.LIST).value 107 | 108 | assert not struct.get(1, ttype.BINARY) 109 | -------------------------------------------------------------------------------- /thriftrw/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | .. autofunction:: load 23 | 24 | .. autofunction:: install 25 | """ 26 | from __future__ import absolute_import, unicode_literals, print_function 27 | 28 | from .loader import load 29 | from .loader import install 30 | 31 | __version__ = '1.9.0' 32 | 33 | __all__ = ['load', 'install'] 34 | -------------------------------------------------------------------------------- /thriftrw/_buffer.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | 24 | cdef class ReadBuffer(object): 25 | cdef char* data 26 | cdef int offset, length 27 | 28 | cdef bytes _data 29 | # a reference to the original PyObject is required to ensure that the 30 | # underlying char* doesn't go away. 31 | 32 | cpdef void read(self, char* dest, int count) except * 33 | 34 | cpdef bytes take(self, int count) 35 | 36 | cpdef void skip(self, int count) except * 37 | 38 | 39 | cdef class WriteBuffer(object): 40 | cdef char* data 41 | cdef readonly int length, capacity 42 | 43 | cpdef void clear(self) 44 | 45 | cpdef void write_bytes(self, bytes data) 46 | 47 | cdef void write(self, char* data, int count) 48 | 49 | cdef void ensure_capacity(self, int min_bytes) 50 | -------------------------------------------------------------------------------- /thriftrw/_cython.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | 24 | cdef bint richcompare_op(int op, int compare) 25 | 26 | cdef bint richcompare(int op, list pairs) 27 | -------------------------------------------------------------------------------- /thriftrw/_cython.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | 24 | cdef bint richcompare_op(int op, int compare): 25 | # op operation 26 | # 0 < 27 | # 1 <= 28 | # 2 == 29 | # 3 != 30 | # 4 > 31 | # 5 >= 32 | 33 | if op == 2: 34 | return compare == 0 35 | elif op == 3: 36 | return compare != 0 37 | elif op == 4: 38 | return compare > 0 39 | elif op == 5: 40 | return compare >= 0 41 | elif op == 0: 42 | return compare < 0 43 | elif op == 1: 44 | return compare <= 0 45 | else: 46 | assert False, 'Invalid comparison operator "%d"' % (op,) 47 | 48 | 49 | cdef bint richcompare(int op, list pairs): 50 | """Utility function to make ``richcmp`` easier to write. 51 | 52 | It takes a list of attribute pairs. Attributes are compared in the order 53 | they appear and the result is returned based on the ``op``. 54 | 55 | .. code-block:: python 56 | 57 | def __richcmp__(self, other, op): 58 | return richcompare( 59 | op, 60 | [ 61 | (self.attr1, other.attr1), 62 | (self.attr2, other.attr2), 63 | # ... 64 | ] 65 | ) 66 | """ 67 | 68 | cdef int compare = 0 69 | 70 | for (left, right) in pairs: 71 | if left > right: 72 | compare = 1 73 | break 74 | elif left < right: 75 | compare = -1 76 | break 77 | 78 | return richcompare_op(op, compare) 79 | -------------------------------------------------------------------------------- /thriftrw/_runtime.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport int32_t 24 | 25 | from thriftrw.wire.message cimport Message 26 | from thriftrw.protocol.core cimport Protocol 27 | 28 | 29 | cdef class Serializer(object): 30 | cdef readonly Protocol protocol 31 | 32 | cpdef bytes dumps(self, obj) 33 | 34 | cpdef bytes message(self, obj, int32_t seqid=*) 35 | 36 | 37 | cdef class Deserializer(object): 38 | cdef readonly Protocol protocol 39 | 40 | cpdef object loads(self, obj_cls, bytes s) 41 | 42 | cpdef Message message(self, service, bytes s) 43 | -------------------------------------------------------------------------------- /thriftrw/compile/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | .. autoclass:: thriftrw.compile.Compiler 23 | :members: 24 | """ 25 | from __future__ import absolute_import, unicode_literals, print_function 26 | 27 | from .compiler import Compiler 28 | from .scope import Scope 29 | 30 | 31 | __all__ = ['Compiler', 'Scope'] 32 | -------------------------------------------------------------------------------- /thriftrw/compile/generate.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from thriftrw import spec 24 | from thriftrw.spec.const import ConstValuePrimitive 25 | 26 | __all__ = ['Generator'] 27 | 28 | 29 | class Generator(object): 30 | """Implements the Generate step of the compiler. 31 | 32 | During the Generate step, the system goes through the Thrift AST and 33 | collects all constants, and builds up type specs and classes with 34 | references to each other. 35 | """ 36 | 37 | __slots__ = ('scope', 'type_mapper', 'strict') 38 | 39 | def __init__(self, scope, strict=True): 40 | """Initialize the generator. 41 | 42 | :param thriftrw.compile.scope.Scope scope: 43 | Scope maintaining the current compilation state. 44 | """ 45 | self.scope = scope 46 | self.strict = strict 47 | 48 | def process(self, definition): 49 | """Process the given definition from the AST. 50 | 51 | :param definition: 52 | A definition from the AST. 53 | """ 54 | definition.apply(self) 55 | 56 | def visit_const(self, const): 57 | const_spec = spec.ConstSpec.compile(const) 58 | self.scope.add_const_spec(const_spec) 59 | 60 | def visit_typedef(self, typedef): 61 | self.scope.add_type_spec( 62 | typedef.name, 63 | spec.TypedefTypeSpec.compile(typedef), 64 | typedef.lineno, 65 | ) 66 | 67 | def visit_enum(self, enum): 68 | enum_spec = spec.EnumTypeSpec.compile(enum) 69 | for key, value in enum_spec.items.items(): 70 | self.scope.add_const_spec( 71 | spec.ConstSpec( 72 | name=enum_spec.name + '.' + key, 73 | value_spec=ConstValuePrimitive(value), 74 | type_spec=spec.I32TypeSpec, 75 | save=False, 76 | ) 77 | ) 78 | self.scope.add_type_spec(enum.name, enum_spec, enum.lineno) 79 | 80 | def visit_struct(self, struct): 81 | struct_spec = spec.StructTypeSpec.compile( 82 | struct, 83 | require_requiredness=self.strict, 84 | ) 85 | self.scope.add_type_spec(struct_spec.name, struct_spec, struct.lineno) 86 | 87 | def visit_union(self, union): 88 | union_spec = spec.UnionTypeSpec.compile(union) 89 | self.scope.add_type_spec(union_spec.name, union_spec, union.lineno) 90 | 91 | def visit_exc(self, exc): 92 | exc_spec = spec.ExceptionTypeSpec.compile( 93 | exc, 94 | require_requiredness=self.strict, 95 | ) 96 | self.scope.add_type_spec(exc_spec.name, exc_spec, exc.lineno) 97 | 98 | def visit_service(self, svc): 99 | service_spec = spec.ServiceSpec.compile(svc) 100 | self.scope.add_service_spec(service_spec) 101 | -------------------------------------------------------------------------------- /thriftrw/compile/link.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | 24 | __all__ = ['TypeSpecLinker', 'ServiceSpecLinker'] 25 | 26 | 27 | class TypeSpecLinker(object): 28 | """Links together references in TypeSpecs.""" 29 | 30 | __slots__ = ('scope',) 31 | 32 | def __init__(self, scope): 33 | self.scope = scope 34 | 35 | def link(self): 36 | """Resolve and link all types in the scope.""" 37 | 38 | type_specs = {} 39 | types = [] 40 | 41 | for name, type_spec in self.scope.type_specs.items(): 42 | type_spec = type_spec.link(self.scope) 43 | type_specs[name] = type_spec 44 | 45 | if type_spec.surface is not None: 46 | self.scope.add_surface(name, type_spec.surface) 47 | types.append(type_spec.surface) 48 | 49 | self.scope.type_specs = type_specs 50 | self.scope.add_surface('__types__', tuple(types)) 51 | 52 | 53 | class ServiceSpecLinker(object): 54 | """Links references to type in service specs.""" 55 | 56 | __slots__ = ('scope',) 57 | 58 | def __init__(self, scope): 59 | self.scope = scope 60 | 61 | def link(self): 62 | service_specs = {} 63 | services = [] 64 | 65 | for name, service_spec in self.scope.service_specs.items(): 66 | service_spec = service_spec.link(self.scope) 67 | service_specs[name] = service_spec 68 | 69 | if service_spec.surface is not None: 70 | self.scope.add_surface( 71 | service_spec.name, service_spec.surface 72 | ) 73 | services.append(service_spec.surface) 74 | 75 | self.scope.service_specs = service_specs 76 | self.scope.add_surface('__services__', tuple(services)) 77 | 78 | 79 | class ConstSpecLinker(object): 80 | """Links references to top-level constants.""" 81 | 82 | __slots__ = ('scope',) 83 | 84 | def __init__(self, scope): 85 | self.scope = scope 86 | 87 | def link(self): 88 | const_specs = {} 89 | constants = {} 90 | 91 | for name, const_spec in self.scope.const_specs.items(): 92 | const_spec = const_spec.link(self.scope) 93 | const_specs[name] = const_spec 94 | 95 | if const_spec.surface is not None and const_spec.save: 96 | self.scope.add_surface( 97 | const_spec.name, const_spec.surface 98 | ) 99 | constants[const_spec.name] = const_spec.surface 100 | 101 | self.scope.const_specs = const_specs 102 | self.scope.add_surface('__constants__', constants) 103 | -------------------------------------------------------------------------------- /thriftrw/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | .. autoclass:: ThriftError 23 | :members: 24 | 25 | .. autoclass:: ThriftParserError 26 | :members: 27 | 28 | .. autoclass:: ThriftCompilerError 29 | :members: 30 | 31 | .. autoclass:: ThriftProtocolError 32 | :members: 33 | 34 | .. autoclass:: EndOfInputError 35 | :members: 36 | 37 | .. autoclass:: UnknownExceptionError 38 | :members: 39 | """ 40 | from __future__ import absolute_import, unicode_literals, print_function 41 | 42 | 43 | class ThriftError(Exception): 44 | """Base class for all exceptions raised by thriftrw.""" 45 | 46 | 47 | class ThriftParserError(ThriftError): 48 | """Exception raised by the parser or lexer in case of errors.""" 49 | 50 | 51 | class ThriftCompilerError(ThriftError): 52 | """Exception raised during IDL compilation.""" 53 | 54 | 55 | class ThriftProtocolError(ThriftError): 56 | """Exceptions raised by Protocol implementations for errors encountered 57 | during serialization or deserialization. 58 | """ 59 | 60 | 61 | class EndOfInputError(ThriftProtocolError): 62 | """The input was shorter than expected.""" 63 | 64 | 65 | class UnknownExceptionError(ThriftError): 66 | """We parsed an unknown exception in a function response.""" 67 | 68 | def __init__(self, message, thrift_response=None): 69 | super(UnknownExceptionError, self).__init__(message) 70 | self.thrift_response = thrift_response 71 | 72 | def __str__(self): 73 | return 'UnknownExceptionError(%s, thrift_response=%r)' % ( 74 | super(UnknownExceptionError, self).__str__(), 75 | self.thrift_response, 76 | ) 77 | 78 | __repr__ = __str__ 79 | -------------------------------------------------------------------------------- /thriftrw/idl/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | A parser for Thrift IDL files. 23 | 24 | Parser 25 | ------ 26 | 27 | Adapted from ``thriftpy.parser``. 28 | 29 | .. autoclass:: Parser 30 | :members: 31 | 32 | AST 33 | --- 34 | 35 | .. autoclass:: Program 36 | 37 | Headers 38 | ~~~~~~~ 39 | 40 | .. autoclass:: Include 41 | 42 | .. autoclass:: Namespace 43 | 44 | Definitions 45 | ~~~~~~~~~~~ 46 | 47 | .. autoclass:: Const 48 | 49 | .. autoclass:: Typedef 50 | 51 | .. autoclass:: Enum 52 | 53 | .. autoclass:: EnumItem 54 | 55 | .. autoclass:: Struct 56 | 57 | .. autoclass:: Union 58 | 59 | .. autoclass:: Exc 60 | 61 | .. autoclass:: Service 62 | 63 | .. autoclass:: ServiceReference 64 | 65 | .. autoclass:: Function 66 | 67 | .. autoclass:: Field 68 | 69 | Types 70 | ~~~~~ 71 | 72 | .. autoclass:: PrimitiveType 73 | 74 | .. autoclass:: MapType 75 | 76 | .. autoclass:: SetType 77 | 78 | .. autoclass:: ListType 79 | 80 | .. autoclass:: DefinedType 81 | 82 | Constants 83 | ~~~~~~~~~ 84 | 85 | .. autoclass:: ConstPrimitiveValue 86 | 87 | .. autoclass:: ConstReference 88 | 89 | Annotations 90 | ~~~~~~~~~~~ 91 | 92 | .. autoclass:: Annotation 93 | """ 94 | from __future__ import absolute_import, unicode_literals, print_function 95 | 96 | from .parser import Parser 97 | from .ast import ( 98 | Program, 99 | Include, 100 | Namespace, 101 | Const, 102 | Typedef, 103 | Enum, 104 | EnumItem, 105 | Struct, 106 | Union, 107 | Exc, 108 | Service, 109 | ServiceReference, 110 | Function, 111 | Field, 112 | PrimitiveType, 113 | MapType, 114 | SetType, 115 | ListType, 116 | DefinedType, 117 | ConstValue, 118 | ConstPrimitiveValue, 119 | ConstReference, 120 | Annotation, 121 | ) 122 | 123 | 124 | __all__ = [ 125 | # Parser 126 | 'Parser', 127 | 128 | # AST 129 | 'Program', 130 | 'Include', 131 | 'Namespace', 132 | 'Const', 133 | 'Typedef', 134 | 'Enum', 135 | 'EnumItem', 136 | 'Struct', 137 | 'Union', 138 | 'Exc', 139 | 'Service', 140 | 'ServiceReference', 141 | 'Function', 142 | 'Field', 143 | 'PrimitiveType', 144 | 'MapType', 145 | 'SetType', 146 | 'ListType', 147 | 'DefinedType', 148 | 'ConstValue', 149 | 'ConstPrimitiveValue', 150 | 'ConstReference', 151 | 'Annotation', 152 | ] 153 | -------------------------------------------------------------------------------- /thriftrw/idl/lexer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from ply import lex 24 | 25 | from ..errors import ThriftParserError 26 | 27 | 28 | __all__ = ['Lexer'] 29 | 30 | 31 | THRIFT_KEYWORDS = ( 32 | 'namespace', 33 | 'include', 34 | 'void', 35 | 'bool', 36 | 'byte', 37 | 'i8', 38 | 'i16', 39 | 'i32', 40 | 'i64', 41 | 'double', 42 | 'string', 43 | 'binary', 44 | 'map', 45 | 'list', 46 | 'set', 47 | 'oneway', 48 | 'typedef', 49 | 'struct', 50 | 'union', 51 | 'exception', 52 | 'extends', 53 | 'throws', 54 | 'service', 55 | 'enum', 56 | 'const', 57 | 'required', 58 | 'optional', 59 | 'true', 60 | 'false', 61 | ) 62 | 63 | 64 | class LexerSpec(object): 65 | """Lexer specification for Thrift IDL files. 66 | 67 | Adapted from thriftpy.parser.lexer.""" 68 | 69 | literals = ':;,=*{}()<>[]' 70 | 71 | tokens = ( 72 | 'INTCONSTANT', 73 | 'DUBCONSTANT', 74 | 'LITERAL', 75 | 'IDENTIFIER', 76 | ) + tuple(map(str.upper, THRIFT_KEYWORDS)) 77 | 78 | t_ignore = ' \t\r' # whitespace 79 | 80 | def t_error(self, t): 81 | raise ThriftParserError( 82 | 'Illegal characher %r at line %d' % (t.value[0], t.lexer.lineno) 83 | ) 84 | 85 | def t_newline(self, t): 86 | r'\n+' 87 | t.lexer.lineno += len(t.value) 88 | 89 | def t_ignore_SILLYCOMM(self, t): 90 | r'\/\*\**\*\/' 91 | t.lexer.lineno += t.value.count('\n') 92 | 93 | def t_ignore_MULTICOMM(self, t): 94 | r'\/\*[^*]\/*([^*/]|[^*]\/|\*[^/])*\**\*\/' 95 | t.lexer.lineno += t.value.count('\n') 96 | 97 | def t_ignore_DOCTEXT(self, t): 98 | r'\/\*\*([^*/]|[^*]\/|\*[^/])*\**\*\/' 99 | t.lexer.lineno += t.value.count('\n') 100 | 101 | def t_ignore_UNIXCOMMENT(self, t): 102 | r'\#[^\n]*' 103 | 104 | def t_ignore_COMMENT(self, t): 105 | r'\/\/[^\n]*' 106 | 107 | def t_DUBCONSTANT(self, t): 108 | r'-?\d+\.\d*(e-?\d+)?' 109 | t.value = float(t.value) 110 | return t 111 | 112 | def t_HEXCONSTANT(self, t): 113 | r'0x[0-9A-Fa-f]+' 114 | t.value = int(t.value, 16) 115 | t.type = 'INTCONSTANT' 116 | return t 117 | 118 | def t_INTCONSTANT(self, t): 119 | r'[+-]?[0-9]+' 120 | t.value = int(t.value) 121 | return t 122 | 123 | def t_LITERAL(self, t): 124 | r'(\"([^\\\n]|(\\.))*?\")|\'([^\\\n]|(\\.))*?\'' 125 | s = t.value[1:-1] 126 | maps = { 127 | 't': '\t', 128 | 'r': '\r', 129 | 'n': '\n', 130 | '\\': '\\', 131 | '\'': '\'', 132 | '"': '\"' 133 | } 134 | i = 0 135 | length = len(s) 136 | val = '' 137 | while i < length: 138 | if s[i] == '\\': 139 | i += 1 140 | if s[i] in maps: 141 | val += maps[s[i]] 142 | else: 143 | msg = 'Cannot escape character: %s' % s[i] 144 | raise ThriftParserError(msg) 145 | else: 146 | val += s[i] 147 | i += 1 148 | 149 | t.value = val 150 | return t 151 | 152 | def t_IDENTIFIER(self, t): 153 | r'[a-zA-Z_](\.[a-zA-Z_0-9]|[a-zA-Z_0-9])*' 154 | 155 | if t.value in THRIFT_KEYWORDS: 156 | # Not an identifier after all. 157 | t.type = t.value.upper() 158 | 159 | return t 160 | 161 | 162 | class Lexer(LexerSpec): 163 | """Lexer for Thrift IDL files.""" 164 | 165 | def __init__(self, **kwargs): 166 | self._lexer = lex.lex(module=self, **kwargs) 167 | 168 | def input(self, data): 169 | """Reset the lexer and feed in new input. 170 | 171 | :param data: 172 | String of input data. 173 | """ 174 | # input(..) doesn't reset the lineno. We have to do that manually. 175 | self._lexer.lineno = 1 176 | return self._lexer.input(data) 177 | 178 | def token(self): 179 | """Return the next token. 180 | 181 | Returns None when the end of the input is reached. 182 | """ 183 | return self._lexer.token() 184 | -------------------------------------------------------------------------------- /thriftrw/protocol/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | Protocols 23 | --------- 24 | 25 | .. autoclass:: thriftrw.protocol.Protocol 26 | :members: 27 | 28 | .. autoclass:: thriftrw.protocol.BinaryProtocol 29 | :members: 30 | """ 31 | from __future__ import absolute_import, unicode_literals, print_function 32 | 33 | from .binary import BinaryProtocol 34 | from .core import Protocol 35 | 36 | 37 | __all__ = [ 38 | # Protocol 39 | 'Protocol', 40 | 'BinaryProtocol', 41 | ] 42 | -------------------------------------------------------------------------------- /thriftrw/protocol/_endian.h: -------------------------------------------------------------------------------- 1 | /* Borrowed from thriftpy. */ 2 | 3 | #if defined(__APPLE__) 4 | 5 | #include 6 | 7 | #define htobe16(x) OSSwapHostToBigInt16(x) 8 | #define htobe32(x) OSSwapHostToBigInt32(x) 9 | #define htobe64(x) OSSwapHostToBigInt64(x) 10 | #define be16toh(x) OSSwapBigToHostInt16(x) 11 | #define be32toh(x) OSSwapBigToHostInt32(x) 12 | #define be64toh(x) OSSwapBigToHostInt64(x) 13 | 14 | #else 15 | 16 | #include 17 | #include 18 | 19 | #ifndef htobe16 20 | #define htobe16(x) bswap_16(x) 21 | #endif 22 | 23 | #ifndef htobe32 24 | #define htobe32(x) bswap_32(x) 25 | #endif 26 | 27 | #ifndef htobe64 28 | #define htobe64(x) bswap_64(x) 29 | #endif 30 | 31 | #ifndef be16toh 32 | #define be16toh(x) bswap_16(x) 33 | #endif 34 | 35 | #ifndef be32toh 36 | #define be32toh(x) bswap_32(x) 37 | #endif 38 | 39 | #ifndef be64toh 40 | #define be64toh(x) bswap_64(x) 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /thriftrw/protocol/_endian.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | 24 | from libc.stdint cimport ( 25 | int16_t, 26 | int32_t, 27 | int64_t, 28 | ) 29 | 30 | cdef extern from "_endian.h": 31 | int16_t htobe16(int16_t n) 32 | int32_t htobe32(int32_t n) 33 | int64_t htobe64(int64_t n) 34 | int16_t be16toh(int16_t n) 35 | int32_t be32toh(int32_t n) 36 | int64_t be64toh(int64_t n) 37 | -------------------------------------------------------------------------------- /thriftrw/protocol/binary.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport ( 24 | int8_t, 25 | int16_t, 26 | int32_t, 27 | int64_t, 28 | ) 29 | 30 | from .core cimport ( 31 | Protocol, 32 | ProtocolWriter, 33 | ProtocolReader, 34 | FieldHeader, 35 | MapHeader, 36 | SetHeader, 37 | ListHeader, 38 | MessageHeader, 39 | ) 40 | from thriftrw.wire.message cimport Message 41 | from thriftrw._buffer cimport ReadBuffer, WriteBuffer 42 | from thriftrw.wire.value cimport ( 43 | ValueVisitor, 44 | Value, 45 | BoolValue, 46 | ByteValue, 47 | DoubleValue, 48 | I16Value, 49 | I32Value, 50 | I64Value, 51 | BinaryValue, 52 | FieldValue, 53 | StructValue, 54 | MapValue, 55 | MapItem, 56 | SetValue, 57 | ListValue, 58 | ) 59 | 60 | 61 | cdef class BinaryProtocol(Protocol): 62 | pass 63 | 64 | cdef class BinaryProtocolReader(ProtocolReader): 65 | cdef ReadBuffer reader 66 | 67 | cdef void _read(self, char* data, int count) except * 68 | cdef int8_t _byte(self) except * 69 | cdef int16_t _i16(self) except * 70 | cdef int32_t _i32(self) except * 71 | cdef int64_t _i64(self) except * 72 | cdef double _double(self) except * 73 | 74 | 75 | cdef class BinaryProtocolWriter(ProtocolWriter): 76 | cdef WriteBuffer writer 77 | 78 | cdef void _write(BinaryProtocolWriter self, char* data, int length) 79 | 80 | 81 | cdef class _OldBinaryProtocolReader(object): 82 | cdef ReadBuffer reader 83 | 84 | cdef object _reader(self, int8_t typ) 85 | 86 | cpdef object read(self, int8_t typ) 87 | 88 | cdef void _read(self, char* data, int count) except * 89 | 90 | cdef int8_t _byte(self) except * 91 | 92 | cdef int16_t _i16(self) except * 93 | 94 | cdef int32_t _i32(self) except * 95 | 96 | cdef int64_t _i64(self) except * 97 | 98 | cdef double _double(self) except * 99 | 100 | cdef Message read_message(self) 101 | 102 | cdef BoolValue read_bool(self) 103 | 104 | cdef ByteValue read_byte(self) 105 | 106 | cdef DoubleValue read_double(self) 107 | 108 | cdef I16Value read_i16(self) 109 | 110 | cdef I32Value read_i32(self) 111 | 112 | cdef I64Value read_i64(self) 113 | 114 | cdef BinaryValue read_binary(self) 115 | 116 | cdef StructValue read_struct(self) 117 | 118 | cdef MapValue read_map(self) 119 | 120 | cdef SetValue read_set(self) 121 | 122 | cdef ListValue read_list(self) 123 | -------------------------------------------------------------------------------- /thriftrw/protocol/core.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport ( 24 | int8_t, 25 | int16_t, 26 | int32_t, 27 | int64_t, 28 | ) 29 | 30 | from thriftrw.wire cimport ttype 31 | from thriftrw.wire.value cimport Value, ValueVisitor 32 | from thriftrw.wire.message cimport Message 33 | from thriftrw._buffer cimport WriteBuffer, ReadBuffer 34 | 35 | 36 | cdef struct FieldHeader: 37 | int8_t type 38 | int16_t id 39 | 40 | 41 | cdef struct MapHeader: 42 | int8_t ktype 43 | int8_t vtype 44 | int32_t size 45 | 46 | 47 | cdef struct SetHeader: 48 | int8_t type 49 | int32_t size 50 | 51 | 52 | cdef struct ListHeader: 53 | int8_t type 54 | int32_t size 55 | 56 | 57 | cdef class MessageHeader(object): 58 | cdef readonly bytes name 59 | cdef readonly int8_t type 60 | cdef readonly int32_t seqid 61 | 62 | 63 | cdef class ProtocolWriter(object): 64 | 65 | cdef void write_value(self, Value value) except * 66 | 67 | # Primitives 68 | 69 | cdef void write_bool(self, bint value) except * 70 | cdef void write_byte(self, int8_t value) except * 71 | cdef void write_double(self, double value) except * 72 | cdef void write_i16(self, int16_t value) except * 73 | cdef void write_i32(self, int32_t value) except * 74 | cdef void write_i64(self, int64_t value) except * 75 | cdef void write_binary(self, char* value, int32_t length) except * 76 | 77 | # Structs 78 | 79 | cdef void write_struct_begin(self) except * 80 | cdef void write_field_begin(self, FieldHeader header) except * 81 | cdef void write_field_end(self) except * 82 | cdef void write_struct_end(self) except * 83 | 84 | # Containers 85 | 86 | cdef void write_map_begin(self, MapHeader header) except * 87 | cdef void write_map_end(self) except * 88 | 89 | cdef void write_set_begin(self, SetHeader header) except * 90 | cdef void write_set_end(self) except * 91 | 92 | cdef void write_list_begin(self, ListHeader header) except * 93 | cdef void write_list_end(self) except * 94 | 95 | # Messages 96 | 97 | cdef void write_message_begin(self, MessageHeader header) except * 98 | cdef void write_message_end(self) except * 99 | 100 | 101 | cdef class ProtocolReader: 102 | 103 | # Skip 104 | 105 | cdef void skip(self, int typ) except * 106 | cdef void skip_binary(self) except * 107 | cdef void skip_map(self) except * 108 | cdef void skip_list(self) except * 109 | cdef void skip_set(self) except * 110 | cdef void skip_struct(self) except * 111 | 112 | # Primitives 113 | 114 | cdef bint read_bool(self) except * 115 | cdef int8_t read_byte(self) except * 116 | cdef double read_double(self) except * 117 | cdef int16_t read_i16(self) except * 118 | cdef int32_t read_i32(self) except * 119 | cdef int64_t read_i64(self) except * 120 | cdef bytes read_binary(self) 121 | 122 | # Structs 123 | 124 | cdef void read_struct_begin(self) except * 125 | cdef FieldHeader read_field_begin(self) except * 126 | cdef void read_field_end(self) except * 127 | cdef void read_struct_end(self) except * 128 | 129 | # Containers 130 | 131 | cdef MapHeader read_map_begin(self) except * 132 | cdef void read_map_end(self) except * 133 | 134 | cdef SetHeader read_set_begin(self) except * 135 | cdef void read_set_end(self) except * 136 | 137 | cdef ListHeader read_list_begin(self) except * 138 | cdef void read_list_end(self) except * 139 | 140 | # Messages 141 | 142 | cdef MessageHeader read_message_begin(self) 143 | cdef void read_message_end(self) except * 144 | 145 | 146 | cdef class Protocol(object): 147 | cpdef ProtocolWriter writer(self, WriteBuffer buff) 148 | 149 | cpdef ProtocolReader reader(self, ReadBuffer buff) 150 | 151 | cpdef bytes serialize_value(self, Value value) 152 | 153 | cpdef Value deserialize_value(self, int typ, bytes s) 154 | 155 | cpdef bytes serialize_message(self, Message message) 156 | 157 | cpdef Message deserialize_message(self, bytes s) 158 | 159 | 160 | cdef class _ValueWriter(ValueVisitor): 161 | cdef ProtocolWriter writer 162 | -------------------------------------------------------------------------------- /thriftrw/spec/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | Specs 23 | ----- 24 | 25 | Specs represent compiled ASTs and act as the *specification* of behavior for 26 | the types or values they represent. All specs have a ``name`` and may have a 27 | ``surface`` attribute which, if not None, is exposed in the generated module 28 | at the top-level. 29 | 30 | .. autoclass:: thriftrw.spec.TypeSpec 31 | :members: 32 | 33 | Native types 34 | ~~~~~~~~~~~~ 35 | 36 | .. data:: thriftrw.spec.BoolTypeSpec 37 | 38 | TypeSpec for boolean values. 39 | 40 | .. data:: thriftrw.spec.ByteTypeSpec 41 | 42 | TypeSpec for single-byte integers. 43 | 44 | .. data:: thriftrw.spec.DoubleTypeSpec 45 | 46 | TypeSpec for floating point numbers with 64 bits of precision. 47 | 48 | .. data:: thriftrw.spec.I16TypeSpec 49 | 50 | TypeSpec for 16-bit integers. 51 | 52 | .. data:: thriftrw.spec.I32TypeSpec 53 | 54 | TypeSpec for 32-bit integers. 55 | 56 | .. data:: thriftrw.spec.I64TypeSpec 57 | 58 | TypeSpec for 64-bit integers. 59 | 60 | .. data:: thriftrw.spec.BinaryTypeSpec 61 | 62 | TypeSpec for binary blobs. 63 | 64 | .. versionchanged:: 0.4.0 65 | 66 | Automatically coerces text values into binary. 67 | 68 | .. data:: thriftrw.spec.TextTypeSpec 69 | 70 | TypeSpec for unicode data. 71 | 72 | Values will be decoded/encoded using UTF-8 encoding before/after being 73 | serialized/deserialized. 74 | 75 | .. versionchanged:: 0.3.1 76 | 77 | Allows passing binary values directly. 78 | 79 | .. autoclass:: thriftrw.spec.ListTypeSpec 80 | :members: 81 | 82 | .. autoclass:: thriftrw.spec.MapTypeSpec 83 | :members: 84 | 85 | .. autoclass:: thriftrw.spec.SetTypeSpec 86 | :members: 87 | 88 | Custom Types 89 | ~~~~~~~~~~~~ 90 | 91 | .. autoclass:: thriftrw.spec.EnumTypeSpec 92 | :members: 93 | 94 | .. autoclass:: thriftrw.spec.StructTypeSpec 95 | :members: 96 | 97 | .. autoclass:: thriftrw.spec.ExceptionTypeSpec 98 | :members: 99 | 100 | .. autoclass:: thriftrw.spec.UnionTypeSpec 101 | :members: 102 | 103 | .. autoclass:: thriftrw.spec.FieldSpec 104 | :members: 105 | 106 | .. autoclass:: thriftrw.spec.TypedefTypeSpec 107 | :members: 108 | 109 | Services 110 | ~~~~~~~~ 111 | 112 | .. autoclass:: thriftrw.spec.ServiceSpec 113 | :members: 114 | 115 | .. autoclass:: thriftrw.spec.ServiceFunction 116 | :members: 117 | 118 | .. autoclass:: thriftrw.spec.FunctionSpec 119 | :members: 120 | 121 | .. autoclass:: thriftrw.spec.FunctionArgsSpec 122 | :members: 123 | 124 | .. autoclass:: thriftrw.spec.FunctionResultSpec 125 | :members: 126 | 127 | Constants 128 | ~~~~~~~~~ 129 | 130 | .. autoclass:: thriftrw.spec.ConstSpec 131 | :members: 132 | """ 133 | from __future__ import absolute_import, unicode_literals, print_function 134 | 135 | from .base import TypeSpec 136 | from .const import ConstSpec 137 | from .enum import EnumTypeSpec 138 | from .field import FieldSpec 139 | from .list import ListTypeSpec 140 | from .map import MapTypeSpec 141 | from .set import SetTypeSpec 142 | from .struct import StructTypeSpec 143 | from .exc import ExceptionTypeSpec 144 | from .union import UnionTypeSpec 145 | from .typedef import TypedefTypeSpec 146 | from .service import ( 147 | ServiceSpec, 148 | FunctionSpec, 149 | FunctionArgsSpec, 150 | FunctionResultSpec, 151 | ServiceFunction, 152 | ) 153 | from .primitive import ( 154 | BoolTypeSpec, 155 | ByteTypeSpec, 156 | DoubleTypeSpec, 157 | I16TypeSpec, 158 | I32TypeSpec, 159 | I64TypeSpec, 160 | BinaryTypeSpec, 161 | TextTypeSpec, 162 | ) 163 | 164 | 165 | __all__ = [ 166 | # Types 167 | 'TypeSpec', 168 | 169 | # Primitives 170 | 'BoolTypeSpec', 171 | 'ByteTypeSpec', 172 | 'DoubleTypeSpec', 173 | 'I16TypeSpec', 174 | 'I32TypeSpec', 175 | 'I64TypeSpec', 176 | 'BinaryTypeSpec', 177 | 'TextTypeSpec', 178 | 179 | # Containers 180 | 'ListTypeSpec', 181 | 'MapTypeSpec', 182 | 'SetTypeSpec', 183 | 184 | # Custom types 185 | 'EnumTypeSpec', 186 | 187 | 'ExceptionTypeSpec', 188 | 'StructTypeSpec', 189 | 'UnionTypeSpec', 190 | 'FieldSpec', 191 | 192 | 'TypedefTypeSpec', 193 | 194 | # Services 195 | 'ServiceSpec', 196 | 'FunctionSpec', 197 | 'FunctionArgsSpec', 198 | 'FunctionResultSpec', 199 | 'ServiceFunction', 200 | 201 | # Constants 202 | 'ConstSpec', 203 | ] 204 | -------------------------------------------------------------------------------- /thriftrw/spec/base.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from thriftrw.wire.value cimport Value 24 | from thriftrw.protocol.core cimport ProtocolWriter, ProtocolReader 25 | 26 | from libc.stdint cimport int8_t 27 | 28 | 29 | cdef class TypeSpec(object): 30 | 31 | cdef public int8_t ttype_code 32 | 33 | cdef public bint hashable 34 | 35 | cpdef Value to_wire(TypeSpec self, object value) 36 | 37 | cpdef object from_wire(TypeSpec self, Value wire_value) 38 | 39 | cpdef object read_from(TypeSpec self, ProtocolReader reader) 40 | 41 | cpdef void write_to(TypeSpec self, ProtocolWriter writer, 42 | object value) except * 43 | 44 | cpdef TypeSpec link(self, scope) 45 | 46 | cpdef object to_primitive(TypeSpec self, object value) 47 | 48 | cpdef object from_primitive(TypeSpec self, object prim_value) 49 | 50 | cpdef void validate(TypeSpec self, object instance) except * 51 | -------------------------------------------------------------------------------- /thriftrw/spec/base.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from thriftrw.wire.value cimport Value 24 | from thriftrw.protocol.core cimport ProtocolWriter, ProtocolReader 25 | 26 | __all__ = ['TypeSpec'] 27 | 28 | 29 | cdef class TypeSpec: 30 | """Base class for classes representing TypeSpecs. 31 | 32 | A TypeSpec knows how to convert values of the corresponding type to and 33 | from :py:class:`thriftrw.wire.Value` objects. 34 | """ 35 | __slots__ = () 36 | 37 | property name: 38 | """Name of the type referenced by this type spec.""" 39 | 40 | def __get__(self): 41 | raise NotImplementedError 42 | 43 | property surface: 44 | """The surface of a type spec. 45 | 46 | The surface of a type spec, if non-None is the value associated with 47 | its name at the top-level in the generated module. 48 | """ 49 | 50 | def __get__(self): 51 | raise NotImplementedError 52 | 53 | cpdef object read_from(TypeSpec self, ProtocolReader reader): 54 | """Read a primitive value of this type from :py:class:`thriftrw.protocol.ProtocolReader`.""" 55 | raise NotImplementedError 56 | 57 | cpdef void write_to(TypeSpec self, ProtocolWriter writer, 58 | object value) except *: 59 | """Writes a value directly to :py:class:`thriftrw.protocol.ProtocolWriter`.""" 60 | writer.write_value(self.to_wire(value)) 61 | 62 | cpdef Value to_wire(TypeSpec self, object value): 63 | """Converts the given value into a :py:class:`thriftrw.wire.Value` 64 | object. 65 | 66 | :returns thriftrw.wire.Value: 67 | Wire representation of the value. 68 | """ 69 | raise NotImplementedError( 70 | 'to_wire called on unlinked type reference: %r', self 71 | ) 72 | 73 | cpdef object from_wire(TypeSpec self, Value wire_value): 74 | """Converts the given :py:class:`thriftrw.wire.Value` back into the 75 | original type. 76 | 77 | :param thriftr.wire.Value wire_value: 78 | Value to convert. 79 | :raises ValueError: 80 | If the type of the wire value does not have the correct Thrift 81 | type for this type spec. 82 | """ 83 | raise NotImplementedError( 84 | 'from_wire called on unlinked type reference: %r', self 85 | ) 86 | 87 | cpdef TypeSpec link(self, scope): 88 | raise NotImplementedError 89 | 90 | cpdef object to_primitive(TypeSpec self, object value): 91 | """Converts a value matching this type spec into a primitive value. 92 | 93 | A primitive value is a text, binary, integer, or float value, or a 94 | list or dict of other primitive values. 95 | 96 | .. versionadded:: 0.4 97 | 98 | :param value: 99 | Value matching this TypeSpec. 100 | :returns: 101 | A representation of that value using only primitive types, lists, 102 | and maps. 103 | """ 104 | raise NotImplementedError( 105 | 'to_primitive called on unlinked type reference: %r', self 106 | ) 107 | 108 | cpdef object from_primitive(TypeSpec self, object prim_value): 109 | """Converts a primitive value into a value of this type. 110 | 111 | A primitive value is a text, binary, integer, or float value, or a 112 | list or dict of other primitive values. 113 | 114 | .. versionadded:: 0.4 115 | 116 | :param prim_value: 117 | A primitive value as produced by ``to_primitive``. 118 | :returns: 119 | A value matching this TypeSpec. 120 | """ 121 | raise NotImplementedError( 122 | 'from_primitive called on unlinked type reference: %r', self 123 | ) 124 | 125 | cpdef void validate(TypeSpec self, object o) except *: 126 | """Whether an instance of this spec is valid. 127 | 128 | :param instance: 129 | An instance of the type described by this spec. 130 | 131 | :raises TypeError: 132 | If the value did not match the type expected by this TypeSpec. 133 | :raises ValueError: 134 | If the value matched the type but did not hold the correct set of 135 | acceptable values. 136 | """ 137 | raise NotImplementedError( 138 | 'validate called on unlinked type reference: %r', self 139 | ) 140 | -------------------------------------------------------------------------------- /thriftrw/spec/check.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | from thriftrw.wire.value cimport Value 26 | 27 | cpdef type_code_matches(TypeSpec type_spec, Value wire_value) 28 | 29 | cpdef instanceof_surface(TypeSpec type_spec, object value) 30 | 31 | cpdef instanceof_class(TypeSpec type_spec, cls, object value) 32 | 33 | cpdef isiterable(TypeSpec type_spec, object value) 34 | 35 | cpdef ismapping(TypeSpec type_spec, object value) 36 | -------------------------------------------------------------------------------- /thriftrw/spec/check.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | from thriftrw.wire.value cimport Value 26 | 27 | __all__ = ['type_code_matches', 'instanceof_surface'] 28 | 29 | 30 | cpdef type_code_matches(TypeSpec type_spec, Value wire_value): 31 | """Verifies that the ttype_code for the TypeSpec and the Value matches. 32 | 33 | Raises ``ValueError`` if not. 34 | 35 | :param thriftrw.spec.base.TypeSpec type_spec: 36 | TypeSpec against which the value is being checked. 37 | :param thriftrw.idl.Value wire_value: 38 | Wire value being checked. 39 | """ 40 | if type_spec.ttype_code != wire_value.ttype_code: 41 | raise ValueError( 42 | 'Cannot read a "%s" (type %d) from %r (type %d)' % 43 | (type_spec.name, type_spec.ttype_code, wire_value, 44 | wire_value.ttype_code) 45 | ) 46 | 47 | 48 | cpdef instanceof_surface(TypeSpec type_spec, object value): 49 | """Verifies that the value is an instance of the type's surface. 50 | 51 | Raises ``TypeError`` if not. 52 | 53 | :param thriftrw.spec.base.TypeSpec type_spec: 54 | TypeSpec against which the value is being checked. 55 | :param value: 56 | Value being validated. 57 | """ 58 | instanceof_class(type_spec, type_spec.surface, value) 59 | 60 | 61 | cpdef instanceof_class(TypeSpec type_spec, cls, object value): 62 | if not isinstance(value, cls): 63 | raise TypeError( 64 | 'Cannot serialize %r into a "%s".' % (value, type_spec.name) 65 | ) 66 | 67 | cpdef isiterable(TypeSpec type_spec, object value): 68 | """Checks if the given value is iterable.""" 69 | if not hasattr(value, '__iter__'): 70 | raise TypeError( 71 | 'Cannot serialize %r into a "%s".' % (value, type_spec.name) 72 | ) 73 | 74 | cpdef ismapping(TypeSpec type_spec, object value): 75 | """Checks if the given value is iterable.""" 76 | if not hasattr(value, '__getitem__') or not hasattr(value, 'items'): 77 | raise TypeError( 78 | 'Cannot serialize %r into a "%s".' % (value, type_spec.name) 79 | ) 80 | -------------------------------------------------------------------------------- /thriftrw/spec/common.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | 24 | def fields_eq(fields): 25 | """Generates an ``__eq__`` method. 26 | 27 | :param list fields: 28 | List of fields of the object to be compared. 29 | """ 30 | def __eq__(self, other): 31 | return isinstance(other, self.__class__) and all( 32 | getattr(self, name) == getattr(other, name) for name in fields 33 | ) 34 | return __eq__ 35 | 36 | 37 | def fields_str(cls_name, field_list, include_none=True): 38 | """Generates a ``__str__`` method. 39 | 40 | :param cls_name: 41 | Name of the class for which the method is being generated. 42 | :param list field_list: 43 | List of field_list of the class to be included in the output. 44 | :param bool include_none: 45 | Whether None attributes should be included in the output. 46 | """ 47 | def __str__(self): 48 | fields = {} 49 | 50 | for name in field_list: 51 | # TODO use to_primitive? 52 | value = getattr(self, name) 53 | if include_none or value is not None: 54 | fields[name] = value 55 | 56 | return "%s(%r)" % (cls_name, fields) 57 | return __str__ 58 | 59 | 60 | def to_primitive_method(type_spec): 61 | """Generates the ``to_primitive`` method for types given the TypeSpec.""" 62 | 63 | def to_primitive(self): 64 | return type_spec.to_primitive(self) 65 | 66 | return to_primitive 67 | 68 | 69 | def from_primitive_classmethod(): 70 | """Generates the ``from_primitive`` classmethod for types.""" 71 | 72 | @classmethod 73 | def from_primitive(cls, prim_value): 74 | return cls.type_spec.from_primitive(prim_value) 75 | 76 | return from_primitive 77 | 78 | 79 | def struct_hasher(spec): 80 | """Generates a ``__hash__`` method. 81 | 82 | :param list fields: 83 | List of fields of the object to be hashed. 84 | """ 85 | def __hash__(self): 86 | return hash( 87 | tuple( 88 | getattr(self, field.name) for field in spec.fields 89 | ) 90 | ) 91 | return __hash__ 92 | -------------------------------------------------------------------------------- /thriftrw/spec/enum.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | 26 | cdef class EnumTypeSpec(TypeSpec): 27 | cdef readonly str name 28 | cdef readonly dict items 29 | cdef readonly values_to_names 30 | cdef public bint linked 31 | cdef public object surface 32 | -------------------------------------------------------------------------------- /thriftrw/spec/exc.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .struct cimport StructTypeSpec 24 | 25 | 26 | cdef class ExceptionTypeSpec(StructTypeSpec): 27 | pass 28 | -------------------------------------------------------------------------------- /thriftrw/spec/exc.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .struct cimport StructTypeSpec 24 | 25 | 26 | __all__ = ['ExceptionTypeSpec'] 27 | 28 | 29 | cdef class ExceptionTypeSpec(StructTypeSpec): 30 | """Spec for ``exception`` types defined in the Thrift file. 31 | 32 | This is exactly the same as :py:class:`thriftrw.spec.StructTypeSpec` 33 | except that the generated class inherits the ``Exception`` class. 34 | """ 35 | 36 | def __init__(self, *args, **kwargs): 37 | kwargs['base_cls'] = Exception 38 | super(ExceptionTypeSpec, self).__init__(*args, **kwargs) 39 | -------------------------------------------------------------------------------- /thriftrw/spec/field.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport int16_t 24 | 25 | from .base cimport TypeSpec 26 | 27 | 28 | cdef class FieldSpec(object): 29 | cdef readonly int16_t id 30 | cdef readonly str name 31 | cdef readonly bint required 32 | cdef readonly bint hashable 33 | 34 | cdef public TypeSpec spec 35 | cdef public object default_value 36 | cdef public bint linked 37 | -------------------------------------------------------------------------------- /thriftrw/spec/list.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | 26 | cdef class ListTypeSpec(TypeSpec): 27 | cdef public TypeSpec vspec 28 | cdef public bint linked 29 | 30 | -------------------------------------------------------------------------------- /thriftrw/spec/list.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from . cimport check 24 | from .base cimport TypeSpec 25 | from thriftrw.wire cimport ttype 26 | from thriftrw._cython cimport richcompare 27 | from thriftrw.wire.value cimport ListValue 28 | from thriftrw.wire.value cimport Value 29 | from thriftrw.protocol.core cimport ListHeader, ProtocolWriter, ProtocolReader 30 | 31 | __all__ = ['ListTypeSpec'] 32 | 33 | 34 | cdef class ListTypeSpec(TypeSpec): 35 | """Spec for list types. 36 | 37 | .. py:attribute:: vspec 38 | 39 | TypeSpec for the kind of values lists conforming to this spec must 40 | contain. 41 | """ 42 | 43 | surface = list 44 | 45 | def __init__(self, vspec): 46 | """ 47 | :param TypeSpec vspec: 48 | TypeSpec of values stored in the list. 49 | """ 50 | self.ttype_code = ttype.LIST 51 | self.vspec = vspec 52 | self.linked = False 53 | 54 | cpdef TypeSpec link(self, scope): 55 | if not self.linked: 56 | self.linked = True 57 | self.vspec = self.vspec.link(scope) 58 | return self 59 | 60 | @property 61 | def name(self): 62 | return 'list<%s>' % self.vspec.name 63 | 64 | cpdef object read_from(ListTypeSpec self, ProtocolReader reader): 65 | cdef ListHeader header = reader.read_list_begin() 66 | cdef list output = [] 67 | for i in range(header.size): 68 | output.append(self.vspec.read_from(reader)) 69 | 70 | reader.read_list_end() 71 | return output 72 | 73 | cpdef Value to_wire(ListTypeSpec self, object value): 74 | return ListValue( 75 | value_ttype=self.vspec.ttype_code, 76 | values=[self.vspec.to_wire(v) for v in value], 77 | ) 78 | 79 | cpdef object to_primitive(ListTypeSpec self, object value): 80 | return [self.vspec.to_primitive(x) for x in value] 81 | 82 | cpdef void write_to(ListTypeSpec self, ProtocolWriter writer, 83 | object value) except *: 84 | cdef ListHeader header = ListHeader(self.vspec.ttype_code, len(value)) 85 | writer.write_list_begin(header) 86 | for v in value: 87 | self.vspec.write_to(writer, v) 88 | writer.write_list_end() 89 | 90 | cpdef object from_wire(ListTypeSpec self, Value wire_value): 91 | check.type_code_matches(self, wire_value) 92 | return [self.vspec.from_wire(v) for v in wire_value.values] 93 | 94 | cpdef object from_primitive(ListTypeSpec self, object prim_value): 95 | return [self.vspec.from_primitive(v) for v in prim_value] 96 | 97 | cpdef void validate(ListTypeSpec self, object instance) except *: 98 | check.isiterable(self, instance) 99 | for v in instance: 100 | self.vspec.validate(v) 101 | 102 | def __str__(self): 103 | return 'ListTypeSpec(vspec=%r)' % self.vspec 104 | 105 | def __repr__(self): 106 | return str(self) 107 | 108 | def __richcmp__(ListTypeSpec self, ListTypeSpec other not None, int op): 109 | return richcompare(op, [ 110 | (self.vspec, other.vspec), 111 | ]) 112 | 113 | -------------------------------------------------------------------------------- /thriftrw/spec/map.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | 26 | cdef class MapTypeSpec(TypeSpec): 27 | cdef public TypeSpec kspec 28 | cdef public TypeSpec vspec 29 | cdef public bint linked 30 | 31 | -------------------------------------------------------------------------------- /thriftrw/spec/map.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from . cimport check 24 | from .base cimport TypeSpec 25 | from thriftrw.wire cimport ttype 26 | from thriftrw._cython cimport richcompare 27 | from thriftrw.wire.value cimport MapItem, MapValue, Value 28 | from thriftrw.protocol.core cimport MapHeader, ProtocolWriter, ProtocolReader 29 | 30 | __all__ = ['MapTypeSpec'] 31 | 32 | 33 | cdef class MapTypeSpec(TypeSpec): 34 | """Spec for map types. 35 | 36 | .. py:attribute:: kspec 37 | 38 | TypeSpec for the kind of keys matching maps must contain. 39 | 40 | .. py:attribute:: vspec 41 | 42 | TypeSpec for the kind of values matching maps must contain. 43 | """ 44 | 45 | surface = dict 46 | 47 | def __init__(self, kspec, vspec): 48 | """ 49 | :param TypeSpec kspec: 50 | TypeSpec of the keys in the map. 51 | :param TypeSpec vspec: 52 | TypeSpec of the values in the map. 53 | """ 54 | self.ttype_code = ttype.MAP 55 | self.kspec = kspec 56 | self.vspec = vspec 57 | self.linked = False 58 | 59 | @property 60 | def name(self): 61 | return 'map<%s, %s>' % (self.kspec.name, self.vspec.name) 62 | 63 | cpdef TypeSpec link(self, scope): 64 | if not self.linked: 65 | self.linked = True 66 | self.kspec = self.kspec.link(scope) 67 | self.vspec = self.vspec.link(scope) 68 | return self 69 | 70 | cpdef Value to_wire(MapTypeSpec self, object value): 71 | return MapValue( 72 | key_ttype=self.kspec.ttype_code, 73 | value_ttype=self.vspec.ttype_code, 74 | pairs=[ 75 | MapItem(self.kspec.to_wire(k), self.vspec.to_wire(v)) 76 | for k, v in value.items() 77 | ] 78 | ) 79 | 80 | cpdef object to_primitive(MapTypeSpec self, object value): 81 | return { 82 | self.kspec.to_primitive(k): self.vspec.to_primitive(v) 83 | for k, v in value.items() 84 | } 85 | 86 | cpdef object read_from(MapTypeSpec self, ProtocolReader reader): 87 | cdef MapHeader header = reader.read_map_begin() 88 | cdef dict output = { 89 | self.kspec.read_from(reader): self.vspec.read_from(reader) 90 | for i in range(header.size) 91 | } 92 | reader.read_map_end() 93 | return output 94 | 95 | cpdef void write_to(MapTypeSpec self, ProtocolWriter writer, 96 | object value) except *: 97 | cdef MapHeader header = MapHeader( 98 | self.kspec.ttype_code, self.vspec.ttype_code, len(value) 99 | ) 100 | writer.write_map_begin(header) 101 | for k, v in value.items(): 102 | self.kspec.write_to(writer, k) 103 | self.vspec.write_to(writer, v) 104 | writer.write_map_end() 105 | 106 | cpdef object from_wire(MapTypeSpec self, Value wire_value): 107 | check.type_code_matches(self, wire_value) 108 | return { 109 | self.kspec.from_wire(i.key): self.vspec.from_wire(i.value) 110 | for i in wire_value.pairs 111 | } 112 | 113 | cpdef object from_primitive(MapTypeSpec self, object prim_value): 114 | return { 115 | self.kspec.from_primitive(k): self.vspec.from_primitive(v) 116 | for k, v in prim_value.items() 117 | } 118 | 119 | cpdef void validate(MapTypeSpec self, object instance) except *: 120 | check.ismapping(self, instance) 121 | for k, v in instance.items(): 122 | self.kspec.validate(k) 123 | self.vspec.validate(v) 124 | 125 | def __str__(self): 126 | return 'MapTypeSpec(kspec=%r, vspec=%r)' % (self.kspec, self.vspec) 127 | 128 | def __repr__(self): 129 | return str(self) 130 | 131 | def __richcmp__(MapTypeSpec self, MapTypeSpec other not None, int op): 132 | return richcompare(op, [ 133 | (self.kspec, other.kspec), 134 | (self.vspec, other.vspec), 135 | ]) 136 | 137 | -------------------------------------------------------------------------------- /thriftrw/spec/primitive.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport int8_t 24 | 25 | from .base cimport TypeSpec 26 | 27 | 28 | cdef class PrimitiveTypeSpec(TypeSpec): 29 | cdef readonly str name 30 | cdef readonly int8_t code 31 | cdef readonly object value_cls 32 | cdef readonly object surface 33 | cdef readonly object cast 34 | cdef readonly object validate_extra 35 | 36 | 37 | cdef class _TextualTypeSpec(TypeSpec): 38 | pass 39 | 40 | 41 | cdef class _TextTypeSpec(_TextualTypeSpec): 42 | pass 43 | 44 | 45 | cdef class _BinaryTypeSpec(_TextualTypeSpec): 46 | pass 47 | 48 | 49 | cdef class _BoolTypeSpec(TypeSpec): 50 | pass 51 | -------------------------------------------------------------------------------- /thriftrw/spec/reference.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | 26 | cdef class TypeReference(TypeSpec): 27 | cdef readonly str name 28 | cdef readonly int lineno 29 | -------------------------------------------------------------------------------- /thriftrw/spec/reference.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from thriftrw._cython cimport richcompare 24 | from thriftrw.wire.value cimport Value 25 | 26 | from .base cimport TypeSpec 27 | 28 | __all__ = ['TypeReference'] 29 | 30 | 31 | cdef class TypeReference(TypeSpec): 32 | """A reference to another type.""" 33 | 34 | __slots__ = ('name', 'lineno') 35 | 36 | def __init__(self, name, lineno): 37 | self.name = str(name) 38 | self.lineno = lineno 39 | 40 | cpdef TypeSpec link(self, scope): 41 | return scope.resolve_type_spec(self.name, self.lineno) 42 | 43 | # It may be worth making this implement the TypeSpec interface and raise 44 | # exceptions complaining about unresolved type references, since that's 45 | # probably a bug. 46 | 47 | def __str__(self): 48 | return 'TypeReference(%s, lineno=%d)' % ( 49 | self.name, self.lineno 50 | ) 51 | 52 | def __repr__(self): 53 | return str(self) 54 | 55 | def __richcmp__(TypeReference self, TypeReference other not None, int op): 56 | return richcompare(op, [ 57 | (self.name, other.name), 58 | (self.lineno, other.lineno), 59 | ]) 60 | -------------------------------------------------------------------------------- /thriftrw/spec/service.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .struct cimport StructTypeSpec 24 | from .union cimport UnionTypeSpec 25 | from .base cimport TypeSpec 26 | 27 | 28 | cdef class FunctionArgsSpec(StructTypeSpec): 29 | cdef public FunctionSpec function 30 | 31 | 32 | cdef class FunctionResultSpec(UnionTypeSpec): 33 | cdef public TypeSpec return_spec 34 | cdef public list exception_specs 35 | cdef public FunctionSpec function 36 | cdef public object exception_ids 37 | 38 | 39 | cdef class FunctionSpec(object): 40 | cdef readonly str name 41 | cdef public FunctionArgsSpec args_spec 42 | cdef public FunctionResultSpec result_spec 43 | cdef readonly bint oneway 44 | cdef public bint linked 45 | cdef public object surface 46 | cdef public ServiceSpec service 47 | 48 | cpdef FunctionSpec link(self, scope, ServiceSpec service) 49 | 50 | 51 | cdef class ServiceSpec(object): 52 | cdef readonly str name 53 | cdef public list functions 54 | cdef public object parent 55 | cdef public dict _functions 56 | cdef public bint linked 57 | cdef public object surface 58 | 59 | cpdef ServiceSpec link(self, scope) 60 | -------------------------------------------------------------------------------- /thriftrw/spec/set.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | 26 | cdef class SetTypeSpec(TypeSpec): 27 | cdef public TypeSpec vspec 28 | cdef public bint linked 29 | -------------------------------------------------------------------------------- /thriftrw/spec/set.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | from thriftrw.wire cimport ttype 25 | from thriftrw._cython cimport richcompare 26 | from thriftrw.wire.value cimport SetValue 27 | from thriftrw.wire.value cimport Value 28 | from thriftrw.protocol.core cimport SetHeader, ProtocolWriter, ProtocolReader 29 | from . cimport check 30 | 31 | __all__ = ['SetTypeSpec'] 32 | 33 | 34 | cdef class SetTypeSpec(TypeSpec): 35 | """ 36 | :param TypeSpec vspec: 37 | TypeSpec of values stored in the set. 38 | """ 39 | 40 | 41 | def __init__(self, vspec): 42 | self.ttype_code = ttype.SET 43 | self.vspec = vspec 44 | self.linked = False 45 | 46 | cpdef TypeSpec link(self, scope): 47 | if not self.linked: 48 | self.linked = True 49 | self.vspec = self.vspec.link(scope) 50 | return self 51 | 52 | @property 53 | def name(self): 54 | return 'set<%s>' % self.vspec.name 55 | 56 | cpdef object read_from(SetTypeSpec self, ProtocolReader reader): 57 | cdef SetHeader header = reader.read_set_begin() 58 | cdef set output = set() 59 | for _ in range(header.size): 60 | output.add(self.vspec.read_from(reader)) 61 | 62 | reader.read_set_end() 63 | 64 | return output 65 | 66 | cpdef Value to_wire(self, object value): 67 | items = [] 68 | for v in value: 69 | items.append(self.vspec.to_wire(v)) 70 | return SetValue( 71 | value_ttype=self.vspec.ttype_code, 72 | values=items, 73 | ) 74 | 75 | cpdef object to_primitive(self, object value): 76 | items = [] 77 | for x in value: 78 | items.append(self.vspec.to_primitive(x)) 79 | return items 80 | 81 | cpdef void write_to(SetTypeSpec self, ProtocolWriter writer, 82 | object value) except *: 83 | cdef SetHeader header = SetHeader(self.vspec.ttype_code, len(value)) 84 | writer.write_set_begin(header) 85 | for v in value: 86 | self.vspec.write_to(writer, v) 87 | writer.write_set_end() 88 | 89 | cpdef object from_wire(self, Value wire_value): 90 | check.type_code_matches(self, wire_value) 91 | result = set() 92 | for v in wire_value.values: 93 | result.add(self.vspec.from_wire(v)) 94 | return result 95 | 96 | cpdef object from_primitive(self, object prim_value): 97 | result = set() 98 | for v in prim_value: 99 | result.add(self.vspec.from_primitive(v)) 100 | return result 101 | 102 | cpdef void validate(self, object instance) except *: 103 | check.isiterable(self, instance) 104 | for v in instance: 105 | self.vspec.validate(v) 106 | 107 | def __str__(self): 108 | return 'SetTypeSpec(vspec=%r)' % self.vspec 109 | 110 | def __repr__(self): 111 | return str(self) 112 | 113 | def __richcmp__(SetTypeSpec self, SetTypeSpec other not None, int op): 114 | return richcompare(op, [ 115 | (self.vspec, other.vspec), 116 | ]) 117 | 118 | -------------------------------------------------------------------------------- /thriftrw/spec/spec_mapper.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .reference cimport TypeReference 24 | from .map cimport MapTypeSpec 25 | from .set cimport SetTypeSpec 26 | from .list cimport ListTypeSpec 27 | 28 | from .primitive import ( 29 | BoolTypeSpec, 30 | ByteTypeSpec, 31 | DoubleTypeSpec, 32 | I16TypeSpec, 33 | I32TypeSpec, 34 | I64TypeSpec, 35 | BinaryTypeSpec, 36 | TextTypeSpec, 37 | ) 38 | 39 | 40 | __slots__ = ['type_spec_or_ref'] 41 | 42 | 43 | #: Mapping of Thrift primitive type names to corresponding type specs. 44 | PRIMITIVE_TYPES = { 45 | 'bool': BoolTypeSpec, 46 | 'byte': ByteTypeSpec, 47 | 'double': DoubleTypeSpec, 48 | 'i16': I16TypeSpec, 49 | 'i32': I32TypeSpec, 50 | 'i64': I64TypeSpec, 51 | 'string': TextTypeSpec, 52 | 'binary': BinaryTypeSpec, 53 | } 54 | 55 | 56 | class TypeSpecMapper(object): 57 | """Maps AST types to type specifications. 58 | 59 | For references to defined types, return ``TypeReference`` objects instead. 60 | These will be replaced during the linking stage. 61 | """ 62 | 63 | __slots__ = () 64 | 65 | def get(self, typ): 66 | """Get the TypeSpec for the given AST type. 67 | 68 | If the type being referenced is a custom defined type, a TypeReference 69 | is returned instead. 70 | """ 71 | return typ.apply(self) 72 | 73 | def visit_defined(self, typ): 74 | return TypeReference(typ.name, typ.lineno) 75 | 76 | def visit_primitive(self, typ): 77 | assert typ.name in PRIMITIVE_TYPES 78 | return PRIMITIVE_TYPES[typ.name] 79 | 80 | def visit_map(self, mtype): 81 | kspec = self.get(mtype.key_type) 82 | vspec = self.get(mtype.value_type) 83 | return MapTypeSpec(kspec, vspec) 84 | 85 | def visit_set(self, stype): 86 | vspec = self.get(stype.value_type) 87 | return SetTypeSpec(vspec) 88 | 89 | def visit_list(self, ltype): 90 | vspec = self.get(ltype.value_type) 91 | return ListTypeSpec(vspec) 92 | 93 | 94 | #: Gets a TypeSpec for the given type if it's a native Thrift type or a 95 | #: TypeReference if it's a custom defined type. 96 | type_spec_or_ref = TypeSpecMapper().get 97 | -------------------------------------------------------------------------------- /thriftrw/spec/struct.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | 26 | cdef class StructTypeSpec(TypeSpec): 27 | cdef readonly str name 28 | cdef readonly list fields 29 | cdef readonly object base_cls 30 | 31 | cdef public bint linked 32 | cdef public object surface 33 | 34 | cdef dict _index 35 | -------------------------------------------------------------------------------- /thriftrw/spec/typedef.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | 25 | 26 | cdef class TypedefTypeSpec(TypeSpec): 27 | cdef readonly str name 28 | cdef public TypeSpec target_spec 29 | -------------------------------------------------------------------------------- /thriftrw/spec/typedef.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from thriftrw._cython cimport richcompare 24 | from thriftrw.wire.value cimport Value 25 | from .base cimport TypeSpec 26 | 27 | from .spec_mapper import type_spec_or_ref 28 | 29 | 30 | cdef class TypedefTypeSpec(TypeSpec): 31 | """Typedefs are aliases for other types. 32 | 33 | Typedefs resolve themselves to the target type at link time and eliminate 34 | themselves from the tree. 35 | """ 36 | 37 | def __init__(self, name, target_spec): 38 | self.name = str(name) 39 | self.target_spec = target_spec 40 | 41 | @classmethod 42 | def compile(cls, typedef): 43 | target_spec = type_spec_or_ref(typedef.target_type) 44 | return cls(typedef.name, target_spec) 45 | 46 | cpdef TypeSpec link(self, scope): 47 | return self.target_spec.link(scope) 48 | 49 | def __str__(self): 50 | return 'TypedefTypeSpec(%r, %r)' % (self.name, self.target_spec) 51 | 52 | def __repr__(self): 53 | return str(self) 54 | 55 | def __richcmp__(TypedefTypeSpec self, TypedefTypeSpec other not None, int op): 56 | return richcompare(op, [ 57 | (self.name, other.name), 58 | (self.target_spec, other.target_spec), 59 | ]) 60 | -------------------------------------------------------------------------------- /thriftrw/spec/union.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from .base cimport TypeSpec 24 | from thriftrw.protocol.core cimport ProtocolReader 25 | 26 | 27 | cdef class UnionTypeSpec(TypeSpec): 28 | cdef readonly str name 29 | cdef readonly list fields 30 | cdef readonly bint allow_empty 31 | 32 | cdef public bint linked 33 | cdef public object surface 34 | 35 | cdef dict _index 36 | -------------------------------------------------------------------------------- /thriftrw/wire/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | Types 23 | ----- 24 | 25 | .. automodule:: thriftrw.wire.ttype 26 | 27 | Value 28 | ----- 29 | 30 | .. autoclass:: thriftrw.wire.Value 31 | :members: 32 | 33 | .. autoclass:: thriftrw.wire.ValueVisitor 34 | :members: 35 | 36 | Value Types 37 | ~~~~~~~~~~~ 38 | 39 | .. autoclass:: thriftrw.wire.BoolValue 40 | 41 | .. autoclass:: thriftrw.wire.ByteValue 42 | 43 | .. autoclass:: thriftrw.wire.DoubleValue 44 | 45 | .. autoclass:: thriftrw.wire.I16Value 46 | 47 | .. autoclass:: thriftrw.wire.I32Value 48 | 49 | .. autoclass:: thriftrw.wire.I64Value 50 | 51 | .. autoclass:: thriftrw.wire.BinaryValue 52 | 53 | .. autoclass:: thriftrw.wire.FieldValue 54 | 55 | .. autoclass:: thriftrw.wire.StructValue 56 | 57 | .. autoclass:: thriftrw.wire.MapValue 58 | 59 | .. autoclass:: thriftrw.wire.MapItem 60 | 61 | .. autoclass:: thriftrw.wire.SetValue 62 | 63 | .. autoclass:: thriftrw.wire.ListValue 64 | 65 | Message 66 | ------- 67 | 68 | .. autoclass:: thriftrw.wire.Message 69 | 70 | .. automodule:: thriftrw.wire.mtype 71 | """ 72 | from __future__ import absolute_import, unicode_literals, print_function 73 | 74 | from .value import ( 75 | Value, 76 | BoolValue, 77 | ByteValue, 78 | DoubleValue, 79 | I16Value, 80 | I32Value, 81 | I64Value, 82 | BinaryValue, 83 | FieldValue, 84 | StructValue, 85 | MapValue, 86 | MapItem, 87 | SetValue, 88 | ListValue, 89 | ValueVisitor, 90 | ) 91 | from .message import Message 92 | 93 | __all__ = [ 94 | 'ttype', 95 | 96 | # Value 97 | 'Value', 98 | 'BoolValue', 99 | 'ByteValue', 100 | 'DoubleValue', 101 | 'I16Value', 102 | 'I32Value', 103 | 'I64Value', 104 | 'BinaryValue', 105 | 'FieldValue', 106 | 'StructValue', 107 | 'MapValue', 108 | 'MapItem', 109 | 'SetValue', 110 | 'ListValue', 111 | 'ValueVisitor', 112 | 113 | # Message 114 | 'mtype', 115 | 'Message', 116 | ] 117 | -------------------------------------------------------------------------------- /thriftrw/wire/message.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport int32_t 24 | 25 | 26 | cdef class Message(object): 27 | cdef public bytes name 28 | cdef public int32_t seqid 29 | cdef public int message_type 30 | cdef public object body 31 | -------------------------------------------------------------------------------- /thriftrw/wire/message.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport int32_t 24 | 25 | from . cimport mtype 26 | 27 | from thriftrw._cython cimport richcompare 28 | 29 | __all__ = ['Message'] 30 | 31 | 32 | cdef class Message(object): 33 | """A Message envelope for Thrift requests and responses. 34 | 35 | .. py:attribute:: name 36 | 37 | Name of the method being called. 38 | 39 | .. py:attribute:: seqid 40 | 41 | ID of the message used by the client to match responses to requests. 42 | The server's contract is to return the same ``seqid`` in the response 43 | that it received in the request. 44 | 45 | .. py:attribute:: message_type 46 | 47 | Message type of the message. See :py:mod:`thriftrw.wire.ttype`. 48 | 49 | .. py:attribute:: body 50 | 51 | Message payload. The value here depends on the message type. 52 | 53 | 54 | Requests and responses **must** be wrapped in a ``Message`` if you are 55 | making requests to Apache Thrift services or receiving requests from 56 | clients generated by Apache Thrift. 57 | 58 | See :ref:`calling-apache-thrift` for more information. 59 | 60 | .. versionadded:: 1.0 61 | """ 62 | 63 | def __cinit__(self, name, int32_t seqid, int message_type, body): 64 | if not isinstance(name, bytes): 65 | self.name = name.encode('utf-8') 66 | else: 67 | self.name = name 68 | self.seqid = seqid 69 | self.message_type = message_type 70 | self.body = body 71 | 72 | def __richcmp__(Message self, Message other not None, int op): 73 | return richcompare(op, [ 74 | (self.name, other.name), 75 | (self.seqid, other.seqid), 76 | (self.body, other.body), 77 | (self.message_type, other.message_type), 78 | ]) 79 | 80 | def __str__(self): 81 | return 'Message(%r, %r, %r, %r)' % ( 82 | self.name, self.seqid, mtype.name_of(self.message_type), self.body 83 | ) 84 | 85 | def __repr__(self): 86 | return str(self) 87 | -------------------------------------------------------------------------------- /thriftrw/wire/mtype.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | cpdef enum MessageType: 24 | CALL = 1 25 | REPLY = 2 26 | EXCEPTION = 3 27 | ONEWAY = 4 28 | 29 | 30 | cpdef str name_of(int value) 31 | -------------------------------------------------------------------------------- /thriftrw/wire/mtype.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | The types of messages envelopes supported by Thrift. 23 | 24 | .. py:data:: CALL 25 | :annotation: = 1 26 | 27 | An outgoing call to a specific method. 28 | 29 | ``Message.body`` is a struct containing the request arguments. 30 | 31 | .. py:data:: REPLY 32 | :annotation: = 2 33 | 34 | A response to a ``CALL`` message. 35 | 36 | ``Message.body`` is a union of the return value (with field ID 0) and the 37 | application exceptions that the message can raise. 38 | 39 | .. py:data:: EXCEPTION 40 | :annotation: = 3 41 | 42 | An unexpected exception in response to a ``CALL`` message. 43 | 44 | ``Message.body`` is a struct representing the exception. 45 | 46 | Note that exceptions that are defined in the IDL are returned as part of 47 | the ``REPLY`` message. This message type is used for unexpected exceptions 48 | that were not defined in the IDL but which the server and client have 49 | agreed upon as standard exceptions that they both recognize. 50 | 51 | .. py:data:: ONEWAY 52 | :annotation: = 4 53 | 54 | An outgoing request to a specific ``oneway`` method. 55 | 56 | ``Message.body`` is the same as a ``CALL`` message but no ``REPLY`` or 57 | ``EXCEPTION`` is expected in response. 58 | 59 | .. versionadded:: 1.0 60 | """ 61 | 62 | from __future__ import absolute_import, unicode_literals, print_function 63 | 64 | MESSAGE_TYPES = (CALL, REPLY, EXCEPTION, ONEWAY) 65 | 66 | 67 | cpdef str name_of(int value): 68 | """Returns the name of the message type with the given value. 69 | 70 | Returns None if no such message type exists. 71 | """ 72 | if value == CALL: 73 | return str('CALL') 74 | elif value == REPLY: 75 | return str('REPLY') 76 | elif value == EXCEPTION: 77 | return str('EXCEPTION') 78 | elif value == ONEWAY: 79 | return str('ONEWAY') 80 | else: 81 | return None 82 | -------------------------------------------------------------------------------- /thriftrw/wire/ttype.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | 24 | cpdef enum TType: 25 | BOOL = 2 26 | BYTE = 3 27 | DOUBLE = 4 28 | I16 = 6 29 | I32 = 8 30 | I64 = 10 31 | BINARY = 11 32 | STRUCT = 12 33 | MAP = 13 34 | SET = 14 35 | LIST = 15 36 | 37 | 38 | cpdef str name_of(int value) 39 | -------------------------------------------------------------------------------- /thriftrw/wire/ttype.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """ 22 | Different TType codes supported by Thrift. 23 | 24 | .. py:data:: BOOL 25 | :annotation: = 2 26 | 27 | .. py:data:: BYTE 28 | :annotation: = 3 29 | 30 | .. py:data:: DOUBLE 31 | :annotation: = 4 32 | 33 | .. py:data:: I16 34 | :annotation: = 6 35 | 36 | .. py:data:: I32 37 | :annotation: = 8 38 | 39 | .. py:data:: I64 40 | :annotation: = 10 41 | 42 | .. py:data:: BINARY 43 | :annotation: = 11 44 | 45 | .. py:data:: STRUCT 46 | :annotation: = 12 47 | 48 | .. py:data:: MAP 49 | :annotation: = 13 50 | 51 | .. py:data:: SET 52 | :annotation: = 14 53 | 54 | .. py:data:: LIST 55 | :annotation: = 15 56 | 57 | """ 58 | 59 | from __future__ import absolute_import, unicode_literals, print_function 60 | 61 | 62 | cpdef str name_of(int value): 63 | """Returns the name of the TType with the given value. 64 | 65 | Returns None if no such TType exists. 66 | """ 67 | if value == TType.BOOL: 68 | return str('BOOL') 69 | elif value == TType.BYTE: 70 | return str('BYTE') 71 | elif value == TType.DOUBLE: 72 | return str('DOUBLE') 73 | elif value == TType.I16: 74 | return str('I16') 75 | elif value == TType.I32: 76 | return str('I32') 77 | elif value == TType.I64: 78 | return str('I64') 79 | elif value == TType.BINARY: 80 | return str('BINARY') 81 | elif value == TType.STRUCT: 82 | return str('STRUCT') 83 | elif value == TType.MAP: 84 | return str('MAP') 85 | elif value == TType.SET: 86 | return str('SET') 87 | elif value == TType.LIST: 88 | return str('LIST') 89 | else: 90 | return None 91 | -------------------------------------------------------------------------------- /thriftrw/wire/value.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import, unicode_literals, print_function 22 | 23 | from libc.stdint cimport ( 24 | int8_t, 25 | int16_t, 26 | int32_t, 27 | int64_t, 28 | ) 29 | 30 | 31 | cdef class ValueVisitor(object): 32 | 33 | cdef object visit_bool(self, bint value) 34 | 35 | cdef object visit_byte(self, int8_t value) 36 | 37 | cdef object visit_double(self, double value) 38 | 39 | cdef object visit_i16(self, int16_t value) 40 | 41 | cdef object visit_i32(self, int32_t value) 42 | 43 | cdef object visit_i64(self, int64_t value) 44 | 45 | cdef object visit_binary(self, bytes value) 46 | 47 | cdef object visit_struct(self, list fields) 48 | 49 | cdef object visit_map(self, int8_t key_ttype, int8_t value_ttype, list pairs) 50 | 51 | cdef object visit_set(self, int8_t value_ttype, list values) 52 | 53 | cdef object visit_list(self, int8_t value_ttype, list values) 54 | 55 | 56 | cdef class _ValueVisitorArgs(ValueVisitor): 57 | pass 58 | 59 | 60 | cdef class Value(object): 61 | 62 | cpdef object apply(Value self, ValueVisitor visitor) 63 | 64 | 65 | cdef class BoolValue(Value): 66 | cdef readonly bint value 67 | 68 | 69 | cdef class ByteValue(Value): 70 | cdef readonly int8_t value 71 | 72 | 73 | cdef class DoubleValue(Value): 74 | cdef readonly double value 75 | 76 | 77 | cdef class I16Value(Value): 78 | cdef readonly int16_t value 79 | 80 | 81 | cdef class I32Value(Value): 82 | cdef readonly int32_t value 83 | 84 | 85 | cdef class I64Value(Value): 86 | cdef readonly int64_t value 87 | 88 | 89 | cdef class BinaryValue(Value): 90 | cdef readonly bytes value 91 | # TODO change to char* once BinaryProtocol knows how to write that. 92 | 93 | 94 | cdef class FieldValue(object): 95 | cdef readonly int16_t id 96 | cdef readonly int8_t ttype 97 | cdef readonly object value 98 | 99 | 100 | cdef class StructValue(Value): 101 | cdef readonly list fields 102 | cdef readonly dict _index 103 | 104 | 105 | cdef class MapItem(object): 106 | cdef readonly object key 107 | cdef readonly object value 108 | 109 | 110 | cdef class MapValue(Value): 111 | cdef readonly int8_t key_ttype 112 | cdef readonly int8_t value_ttype 113 | cdef readonly list pairs 114 | 115 | 116 | cdef class SetValue(Value): 117 | cdef readonly int8_t value_ttype 118 | cdef readonly list values 119 | 120 | 121 | cdef class ListValue(Value): 122 | cdef readonly int8_t value_ttype 123 | cdef readonly list values 124 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3.7,3.8,3.9,3.10,3.11,cover,flake8,docs 3 | usedevelop = true 4 | 5 | [testenv] 6 | commands = 7 | python setup.py clean --all build_ext --force --inplace 8 | py.test -svv tests 9 | basepython = 10 | 3.7: python3.7 11 | 3.8: python3.8 12 | 3.9: python3.9 13 | 3.10: python3.10 14 | 3.11: python3.11 15 | deps = -rrequirements-test.txt 16 | 17 | [testenv:cover] 18 | basepython = python 19 | setenv = 20 | THRIFTRW_COVERAGE=1 21 | deps = 22 | -rrequirements-test.txt 23 | coveralls 24 | cython 25 | commands = 26 | python setup.py clean --all build_ext --force --inplace 27 | py.test --cov thriftrw --cov-config .coveragerc --cov-report=xml --cov-report=term-missing tests 28 | coveralls -v 29 | 30 | [testenv:flake8] 31 | basepython = python 32 | deps = flake8 33 | commands = flake8 thriftrw tests 34 | 35 | [testenv:docs] 36 | basepython = python 37 | changedir = docs 38 | deps = 39 | sphinx 40 | ply 41 | commands = make html 42 | --------------------------------------------------------------------------------