├── .activate ├── .codecov.yml ├── .github ├── pull-request-template.md └── workflows │ └── python-package.yml ├── .gitignore ├── .pre-commit-config.yaml ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── Makefile ├── NOTICE ├── Pipfile_3_10 ├── Pipfile_3_10.lock ├── Pipfile_3_7 ├── Pipfile_3_7.lock ├── Pipfile_3_8 ├── Pipfile_3_8.lock ├── Pipfile_3_9 ├── Pipfile_3_9.lock ├── README.md ├── docs ├── .gitignore ├── Makefile ├── conf.py ├── contributing.md ├── doc_requirements.txt ├── index.rst ├── installation.md ├── intro_2.md └── introduction.md ├── install_and_test.sh ├── pyproject.toml ├── requirements.txt ├── setup.py ├── tox.ini ├── typed_python ├── AllTypes.hpp ├── AlternativeMatcherType.hpp ├── AlternativeType.cpp ├── AlternativeType.hpp ├── BoundMethodType.hpp ├── BytesType.cpp ├── BytesType.hpp ├── ClassType.cpp ├── ClassType.hpp ├── Codebase.py ├── Codebase_test.py ├── CompilerVisibleObjectVisitor.hpp ├── CompositeType.cpp ├── CompositeType.hpp ├── ConcreteAlternativeType.cpp ├── ConcreteAlternativeType.hpp ├── ConstDictType.cpp ├── ConstDictType.hpp ├── ConversionLevel.hpp ├── DeepcopyContext.hpp ├── DeserializationBuffer.cpp ├── DeserializationBuffer.hpp ├── DictType.cpp ├── DictType.hpp ├── EmbeddedMessageType.hpp ├── Format.hpp ├── ForwardType.hpp ├── FunctionCallArgMapping.hpp ├── FunctionType.cpp ├── FunctionType.hpp ├── HashAccumulator.hpp ├── HeldClassType.cpp ├── HeldClassType.hpp ├── Instance.cpp ├── Instance.hpp ├── Memory.cpp ├── Memory.hpp ├── ModuleRepresentation.hpp ├── ModuleRepresentationCopyContext.hpp ├── MutuallyRecursiveTypeGroup.cpp ├── MutuallyRecursiveTypeGroup.hpp ├── NoneType.hpp ├── NullSerializationContext.hpp ├── OneOfType.cpp ├── OneOfType.hpp ├── PointerToType.hpp ├── PromotesTo.hpp ├── PyAlternativeInstance.cpp ├── PyAlternativeInstance.hpp ├── PyAlternativeMatcherInstance.hpp ├── PyBoundMethodInstance.cpp ├── PyBoundMethodInstance.hpp ├── PyBytesInstance.hpp ├── PyCellType.hpp ├── PyClassInstance.cpp ├── PyClassInstance.hpp ├── PyCompositeTypeInstance.cpp ├── PyCompositeTypeInstance.hpp ├── PyConstDictInstance.cpp ├── PyConstDictInstance.hpp ├── PyDictInstance.cpp ├── PyDictInstance.hpp ├── PyEmbeddedMessageInstance.hpp ├── PyForwardInstance.hpp ├── PyFunctionInstance.cpp ├── PyFunctionInstance.hpp ├── PyGilState.cpp ├── PyGilState.hpp ├── PyHeldClassInstance.hpp ├── PyInstance.cpp ├── PyInstance.hpp ├── PyModuleRepresentation.cpp ├── PyModuleRepresentation.hpp ├── PyNoneInstance.hpp ├── PyObjectHandle.hpp ├── PyOneOfInstance.hpp ├── PyPointerToInstance.cpp ├── PyPointerToInstance.hpp ├── PyPyCellInstance.hpp ├── PyPythonObjectOfTypeInstance.hpp ├── PyPythonSubclassInstance.hpp ├── PyRefToInstance.cpp ├── PyRefToInstance.hpp ├── PyRegisterTypeInstance.hpp ├── PySetInstance.cpp ├── PySetInstance.hpp ├── PySlab.cpp ├── PySlab.hpp ├── PyStringInstance.hpp ├── PySubclassOfInstance.hpp ├── PyTemporaryReferenceTracer.cpp ├── PyTemporaryReferenceTracer.hpp ├── PyTupleOrListOfInstance.cpp ├── PyTupleOrListOfInstance.hpp ├── PyTypedCellInstance.hpp ├── PyValueInstance.hpp ├── PythonObjectOfTypeType.cpp ├── PythonObjectOfTypeType.hpp ├── PythonSerializationContext.cpp ├── PythonSerializationContext.hpp ├── PythonSerializationContext_deserialization.cpp ├── PythonSerializationContext_serialization.cpp ├── PythonSubclassType.cpp ├── PythonSubclassType.hpp ├── RefToType.hpp ├── RegisterTypes.hpp ├── ReprAccumulator.hpp ├── ScopedIndenter.hpp ├── SerializationBuffer.cpp ├── SerializationBuffer.hpp ├── SerializationContext.hpp ├── SerializationContext.py ├── SetType.cpp ├── SetType.hpp ├── Sha1.cpp ├── Sha1.hpp ├── ShaHash.hpp ├── Slab.cpp ├── Slab.hpp ├── SpecialModuleNames.hpp ├── StringType.cpp ├── StringType.hpp ├── SubclassOfType.cpp ├── SubclassOfType.hpp ├── TupleOrListOfType.cpp ├── TupleOrListOfType.hpp ├── Type.cpp ├── Type.hpp ├── TypeDetails.hpp ├── TypeOrPyobj.cpp ├── TypeOrPyobj.hpp ├── TypedCellType.hpp ├── TypedClosureBuilder.hpp ├── Unicode.hpp ├── UnicodeProps.hpp ├── UnicodeProps_3.6.7.hpp ├── UnicodeProps_3.7.4.hpp ├── ValueType.cpp ├── ValueType.hpp ├── WireType.hpp ├── __init__.py ├── _runtime.cpp ├── _runtime.h ├── _types.cpp ├── _types.hpp ├── all.cpp ├── array │ ├── __init__.py │ ├── array.py │ ├── array_test.py │ └── fortran.py ├── class_types_test.py ├── compiler │ ├── __init__.py │ ├── codegen_helpers.py │ ├── conversion_exception.py │ ├── conversion_level.py │ ├── converter_utils.py │ ├── directed_graph.py │ ├── expression_conversion_context.py │ ├── for_loop_codegen.py │ ├── function_conversion_context.py │ ├── function_dependency_graph.py │ ├── function_metadata.py │ ├── function_stack_state.py │ ├── generator_codegen.py │ ├── merge_type_wrappers.py │ ├── merge_type_wrappers_test.py │ ├── native_compiler │ │ ├── __init__.py │ │ ├── binary_shared_object.py │ │ ├── compiler_cache.py │ │ ├── compiler_cache_test.py │ │ ├── global_variable_definition.py │ │ ├── llvm_execution_engine.py │ │ ├── loaded_module.py │ │ ├── module_definition.py │ │ ├── native_ast.py │ │ ├── native_ast_analysis.py │ │ ├── native_ast_to_llvm.py │ │ ├── native_ast_to_llvm_function_converter.py │ │ ├── native_ast_to_llvm_test.py │ │ ├── native_compiler.py │ │ ├── native_compiler_test.py │ │ ├── native_function_pointer.py │ │ ├── typed_call_target.py │ │ └── typed_llvm_value.py │ ├── native_function_conversion_context.py │ ├── python_ast_analysis.py │ ├── python_ast_analysis_test.py │ ├── python_ast_util.py │ ├── python_object_representation.py │ ├── python_to_native_converter.py │ ├── runtime.py │ ├── runtime_lock.py │ ├── tests │ │ ├── __init__.py │ │ ├── alternative_compilation_test.py │ │ ├── any_all_compilation_test.py │ │ ├── arithmetic_compilation_test.py │ │ ├── builtin_compilation_test.py │ │ ├── bytes_compilation_test.py │ │ ├── class_compilation_test.py │ │ ├── closures_test.py │ │ ├── compilable_builtin_test.py │ │ ├── compiler_typed_python_comparison_test.py │ │ ├── compiling_type_operations_test.py │ │ ├── const_dict_compilation_test.py │ │ ├── conversion_test.py │ │ ├── dict_compilation_test.py │ │ ├── entrypoint_test.py │ │ ├── exception_handling_test.py │ │ ├── exceptions_from_c_code_test.py │ │ ├── function_signature_calculator_test.py │ │ ├── generators_test.py │ │ ├── hash_compilation_test.py │ │ ├── held_class_compilation_test.py │ │ ├── held_class_interpreter_semantics_test.py │ │ ├── isinstance_compilation_test.py │ │ ├── list_of_compilation_test.py │ │ ├── masquerade_test.py │ │ ├── math_functions_compilation_test.py │ │ ├── multithreading_test.py │ │ ├── named_tuple_subclass_compilation_test.py │ │ ├── numpy_interaction_test.py │ │ ├── one_of_compilation_test.py │ │ ├── operator_is_compilation_test.py │ │ ├── pointer_to_compilation_test.py │ │ ├── python_object_of_type_compilation_test.py │ │ ├── range_compilation_test.py │ │ ├── serialization_compilation_test.py │ │ ├── set_compilation_test.py │ │ ├── string_compilation_test.py │ │ ├── subclass_of_test.py │ │ ├── time_compilation_test.py │ │ ├── tuple_compilation_test.py │ │ ├── tuple_of_compilation_test.py │ │ ├── type_conversion_test.py │ │ ├── type_function_compilation_test.py │ │ ├── type_inference_test.py │ │ ├── type_of_instances_compilation_test.py │ │ ├── typed_function_compilation_test.py │ │ └── vectorization_test.py │ ├── type_wrappers │ │ ├── __init__.py │ │ ├── abs_wrapper.py │ │ ├── all_any_wrapper.py │ │ ├── alternative_wrapper.py │ │ ├── arithmetic_wrapper.py │ │ ├── bound_method_wrapper.py │ │ ├── builtin_wrappers.py │ │ ├── bytecount_wrapper.py │ │ ├── bytes_wrapper.py │ │ ├── class_or_alternative_wrapper_mixin.py │ │ ├── class_wrapper.py │ │ ├── compilable_builtin.py │ │ ├── compiler_introspection_wrappers.py │ │ ├── compiler_type.py │ │ ├── const_dict_wrapper.py │ │ ├── deserialize_wrapper.py │ │ ├── dict_wrapper.py │ │ ├── function_signature_calculator.py │ │ ├── hasattr_wrapper.py │ │ ├── hash_table_implementation.py │ │ ├── hash_wrapper.py │ │ ├── held_class_wrapper.py │ │ ├── isinstance_wrapper.py │ │ ├── issubclass_wrapper.py │ │ ├── len_wrapper.py │ │ ├── list_of_wrapper.py │ │ ├── make_named_tuple_wrapper.py │ │ ├── masquerade_wrapper.py │ │ ├── math_wrappers.py │ │ ├── method_descriptor_wrapper.py │ │ ├── min_max_wrapper.py │ │ ├── module_wrapper.py │ │ ├── named_tuple_masquerading_as_dict_wrapper.py │ │ ├── named_tuple_masquerading_as_slice.py │ │ ├── none_wrapper.py │ │ ├── one_of_wrapper.py │ │ ├── pointer_to_wrapper.py │ │ ├── print_wrapper.py │ │ ├── python_free_function_wrapper.py │ │ ├── python_free_object_wrapper.py │ │ ├── python_object_of_type_wrapper.py │ │ ├── python_type_object_wrapper.py │ │ ├── python_typed_function_wrapper.py │ │ ├── range_wrapper.py │ │ ├── ref_to_wrapper.py │ │ ├── refcounted_wrapper.py │ │ ├── repr_wrapper.py │ │ ├── runtime_functions.py │ │ ├── serialize_wrapper.py │ │ ├── set_wrapper.py │ │ ├── slice_type_object_wrapper.py │ │ ├── string_wrapper.py │ │ ├── subclass_of_wrapper.py │ │ ├── super_wrapper.py │ │ ├── time_wrapper.py │ │ ├── tuple_of_wrapper.py │ │ ├── tuple_wrapper.py │ │ ├── type_sets.py │ │ ├── typed_cell_wrapper.py │ │ ├── typed_dict_masquerading_as_dict_wrapper.py │ │ ├── typed_list_masquerading_as_list_wrapper.py │ │ ├── typed_set_masquerading_as_set_wrapper.py │ │ ├── typed_tuple_masquerading_as_tuple_wrapper.py │ │ ├── unresolved_forward_type_wrapper.py │ │ ├── util.py │ │ ├── value_wrapper.py │ │ └── wrapper.py │ ├── typed_expression.py │ ├── typeof.py │ └── withblock_codegen.py ├── deep_bytecount_test.py ├── deepcopy_test.py ├── direct_types │ └── Bytes.hpp ├── dummy_test_module │ └── __init__.py ├── forward_types_test.py ├── function_signature_test.py ├── function_types_test.py ├── generator.py ├── hash.py ├── hash_table_layout.hpp ├── internals.py ├── iterator_adaptor.py ├── lib │ ├── __init__.py │ ├── datetime │ │ ├── __init__.py │ │ ├── chrono.py │ │ ├── chrono_test.py │ │ ├── date_formatter.py │ │ ├── date_formatter_test.py │ │ ├── date_parser.py │ │ ├── date_parser_test.py │ │ ├── date_time.py │ │ ├── date_time_test.py │ │ ├── date_time_util.py │ │ └── date_time_util_test.py │ ├── foo.py │ ├── map.py │ ├── map_test.py │ ├── pmap.py │ ├── pmap_test.py │ ├── reduce.py │ ├── reduce_test.py │ ├── sorted_dict.py │ ├── sorted_dict_test.py │ ├── sorting.py │ ├── sorting_test.py │ ├── timestamp.py │ └── timestamp_test.py ├── lz4 │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── dll │ │ └── example │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── fullbench-dll.sln │ │ │ └── fullbench-dll.vcxproj │ ├── liblz4-dll.rc.in │ ├── liblz4.pc.in │ ├── lz4.c │ ├── lz4.h │ ├── lz4file.c │ ├── lz4file.h │ ├── lz4frame.c │ ├── lz4frame.h │ ├── lz4frame_static.h │ ├── lz4hc.c │ ├── lz4hc.h │ ├── xxhash.c │ └── xxhash.h ├── macro.py ├── macro_test.py ├── module.py ├── module_representation_test.py ├── module_test.py ├── python_ast.py ├── python_ast_test.py ├── string_util.py ├── test_util.py ├── type_filter.py ├── type_function.py ├── type_function_test.py ├── type_identity_test.py ├── type_promotion.py ├── typed_queue.py ├── typed_queue_test.py ├── types_metadata_test.py ├── types_named_tuple_test.py ├── types_serialization_format_test.py ├── types_serialization_test.py ├── types_test.py ├── util.cpp └── util.hpp └── unicodeprops.py /.activate: -------------------------------------------------------------------------------- 1 | # brief shell script to activate the python-version-specific 2 | # virtual environments that are built by the makefile. 3 | # 4 | # usage: in a bash shell, type 5 | # 6 | # make install # if you havn't already done so 7 | # . .activate 8 | # 9 | # and you'll get popped into a virtualenv appropriate for your installed version of python 10 | 11 | PYTHON_VERSION=`python3 -c 'import sys; print("3_" + str(sys.version_info.minor))'` 12 | 13 | echo "Using python environment .venv_$PYTHON_VERSION" 14 | 15 | . .venv_$PYTHON_VERSION/bin/activate 16 | . .env_$PYTHON_VERSION 17 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | range: 50..70 3 | round: down 4 | precision: 0 5 | status: 6 | project: 7 | default: 8 | base: auto 9 | threshold: 0.5 10 | informational: true 11 | ignore: 12 | - "typed_python/compiler/type_wrappers/native_hash.py" 13 | -------------------------------------------------------------------------------- /.github/pull-request-template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Motivation and Context 4 | 5 | 6 | 7 | 8 | ## Approach 9 | 10 | 11 | ## How Has This Been Tested? 12 | 13 | 14 | 15 | 16 | ## Screenshots or console output (if appropriate) 17 | 18 | 19 | ## Types of changes 20 | 21 | - [ ] Bug fix (non-breaking change which fixes an issue) 22 | - [ ] New feature (non-breaking change which adds functionality) 23 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 24 | 25 | ## Checklist: 26 | 27 | 28 | - [ ] My code follows the code style of this project. 29 | - [ ] My change requires a change to the documentation. 30 | - [ ] I have updated the documentation accordingly. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.log 3 | *.so 4 | __pycache__ 5 | build/ 6 | typed_python.egg-info 7 | 8 | # Ignore node modules 9 | # and evironments EVERYWHERE 10 | nodeenv 11 | .nodeenv 12 | node_modules 13 | object_database/web/content/dist 14 | 15 | # Emacs 16 | \#* 17 | \.#* 18 | 19 | # leading slash means only match at repo-root level 20 | /.python-version 21 | /.venv* 22 | /.eggs 23 | /.coverage* 24 | /.tox 25 | /.env* 26 | /.test_venv 27 | /dist/ 28 | /pip-wheel-metadata/ 29 | /testcert.cert 30 | /testcert.key 31 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | # - repo: https://github.com/ambv/black 5 | # rev: 19.3b0 6 | # hooks: 7 | # - id: black 8 | 9 | - repo: https://github.com/pre-commit/pre-commit-hooks 10 | rev: v3.3.0 11 | hooks: 12 | - id: trailing-whitespace 13 | - id: end-of-file-fixer 14 | - id: check-yaml 15 | - id: check-toml 16 | - id: check-json 17 | - id: check-added-large-files 18 | 19 | - repo: https://github.com/pycqa/flake8 20 | rev: 3.8.4 21 | hooks: 22 | - id: flake8 23 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This file lists individuals who have contributed to the repository. 2 | # typed_python is generously sponsored by A Priori Investments 3 | 4 | Braxton McKee 5 | Alexandros Tzannes 6 | Jeff Rubidge 7 | Daniel Krasner 8 | Eric Gade 9 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include typed_python/*.hpp 2 | include typed_python/*.h 3 | include typed_python/*.cpp 4 | include typed_python/direct_types/*.hpp 5 | include typed_python/direct_types/*.cpp 6 | include typed_python/lz4/*.h 7 | include typed_python/lz4/*.c 8 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Braxton Mckee 2 | 3 | Copyright 2017 Braxton Mckee 4 | 5 | This product includes software developed by Braxton Mckee 6 | -------------------------------------------------------------------------------- /Pipfile_3_10: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | autopep8 = "*" 8 | beautifulsoup4 = "*" 9 | flake8 = "*" 10 | pytest = "*" 11 | pre-commit = "*" 12 | flaky = "*" 13 | pytest-cov = "*" 14 | 15 | [packages] 16 | sortedcontainers = "*" 17 | scipy = "*" 18 | llvmlite = "*" 19 | numpy = "*" 20 | psutil = "*" 21 | pytz = "*" 22 | typed_python = {editable = true, path = "."} 23 | -------------------------------------------------------------------------------- /Pipfile_3_7: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | autopep8 = "*" 8 | beautifulsoup4 = "*" 9 | flake8 = "*" 10 | pytest = "*" 11 | pre-commit = "*" 12 | flaky = "*" 13 | pytest-cov = "*" 14 | 15 | [packages] 16 | sortedcontainers = "*" 17 | llvmlite = "*" 18 | numpy = "*" 19 | psutil = "*" 20 | pytz = "*" 21 | typed_python = {editable = true, path = "."} 22 | -------------------------------------------------------------------------------- /Pipfile_3_8: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | autopep8 = "*" 8 | beautifulsoup4 = "*" 9 | flake8 = "*" 10 | pytest = "*" 11 | pre-commit = "*" 12 | flaky = "*" 13 | pytest-cov = "*" 14 | 15 | [packages] 16 | sortedcontainers = "*" 17 | scipy = "*" 18 | llvmlite = "*" 19 | numpy = "*" 20 | psutil = "*" 21 | pytz = "*" 22 | typed_python = {editable = true, path = "."} 23 | -------------------------------------------------------------------------------- /Pipfile_3_9: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | autopep8 = "*" 8 | beautifulsoup4 = "*" 9 | flake8 = "*" 10 | pytest = "*" 11 | pre-commit = "*" 12 | flaky = "*" 13 | pytest-cov = "*" 14 | 15 | [packages] 16 | sortedcontainers = "*" 17 | scipy = "*" 18 | llvmlite = "*" 19 | numpy = "*" 20 | psutil = "*" 21 | pytz = "*" 22 | typed_python = {editable = true, path = "."} 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/APrioriInvestments/typed_python.svg?branch=dev)](https://travis-ci.com/APrioriInvestments/typed_python.svg?branch=dev) 2 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 3 | 4 | 5 | # `typed_python` 6 | 7 | The `typed_python` module provides strong runtime types to Python and a compiler 8 | that can take advantage of them. 9 | 10 | It gives you new types you can use to build strongly- and semi-strongly-typed 11 | datastructures, so that your program is easier to understand, and a compiler toolchain 12 | that can take advantage of those datastructures to generate machine code that's 13 | fast, and that doesn't need the GIL. 14 | 15 | `typed_python` is a standard modules that run on Python 3.6 and higher. You can use it 16 | incrementally throughout your project - add a few type constraints here and 17 | there, or compile a couple of small but performance-critical functions. As you 18 | add more type information, more of your program can be compiled. Everything 19 | can still run in interpreter without compilation if you want. 20 | 21 | `typed_python` is generously supported by [A Priori Investments](www.aprioriinvestments.com), a quantitative 22 | hedge fund in New York. If you're interested in working with us, drop us a line at info@aprioriinvestments.com. 23 | 24 | ## Getting started 25 | 26 | You can read the [introductory tutorial](docs/introduction.md) for using `typed_python` or 27 | check out the documentation [typed_python](docs/typed_python.md). 28 | 29 | ## Where did this come from? 30 | 31 | Every time I (Braxton) find myself writing a lot of Python code, I eventually 32 | start to miss C++. As my program gets bigger, I find myself losing track of 33 | what types are supposed to go where. My code gets littered with 'isinstance' 34 | assertions trying to catch mistakes early and provide information about what 35 | kinds of types I expect in certain parts of the code. Compilers solve these 36 | kinds of problems because the type information is out front directly in the code, 37 | and they can find bugs without having to run the program. And of course, I 38 | miss the performance you get out of C++ - every time I write some overly complicated 39 | numpy code, I think to myself how much easier to understand this code would be 40 | if I could only write a loop. 41 | 42 | On the other hand, whenever I write a lot of C++, I find myself missing the 43 | expressiveness of Python, the ability to iterate without a painful compile 44 | cycle, the safety you get from having bad code throw an exception instead of 45 | producing a segfault. And of course, nobody likes looking through a ten page 46 | error log just to find out that a template parameter is missing. 47 | 48 | I developed `typed_python` to try to have the best of both worlds. `typed_python` 49 | lets me have a single codebase, written entirely in Python, where I can 50 | choose, depending on the context, which style of code I want, from totally 51 | free-form Python with total type chaos, to statically typed, highly performant 52 | code, and anything in between. 53 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | api/ 3 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | 3 | 4 | 5 | # You can set these variables from the command line, and also 6 | # from the environment for the first two. 7 | SPHINXOPTS ?= 8 | SPHINXBUILD ?= sphinx-build 9 | SOURCEDIR = . 10 | BUILDDIR = _build 11 | APIBUILDDIR = api 12 | MODULEDIR = ../typed_python 13 | 14 | # Put it first so that "make" without argument is like "make help". 15 | help: 16 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 17 | 18 | .PHONY: help clean apidocs Makefile 19 | 20 | apidocs: 21 | @sphinx-apidoc -fo "$(APIBUILDDIR)" "$(MODULEDIR)" 22 | 23 | clean: 24 | -rm -rf "$(BUILDDIR)"/* 25 | -rm -rf "$(APIBUILDDIR)"/* 26 | 27 | show: 28 | @echo "Showing generated html" 29 | @python -c "import webbrowser; webbrowser.open_new_tab('file://$(PWD)/$(BUILDDIR)/html/index.html')" 30 | 31 | # Catch-all target: route all unknown targets to Sphinx using the new 32 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 33 | %: Makefile 34 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 35 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | import os 9 | import sys 10 | 11 | project = 'typed_python' 12 | copyright = '2022, Braxton McKee' 13 | author = 'Braxton McKee' 14 | release = '0.2.6' 15 | 16 | # -- General configuration --------------------------------------------------- 17 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 18 | 19 | extensions = ['myst_parser', 20 | 'sphinx.ext.autodoc', 21 | 'sphinx.ext.napoleon', 22 | 'sphinx.ext.viewcode' 23 | ] 24 | 25 | templates_path = ['_templates'] 26 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 27 | 28 | # -- Options for HTML output ------------------------------------------------- 29 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 30 | 31 | html_theme = 'sphinx_book_theme' 32 | html_static_path = ['_static'] 33 | 34 | sys.path.insert(0, os.path.abspath('..')) 35 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please do! 4 | -------------------------------------------------------------------------------- /docs/doc_requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==4.5.0 2 | myst-parser==0.18.0 3 | sphinx-book-theme==0.3.3 4 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. typed_python documentation master file, created by 2 | 3 | sphinx-quickstart on Tue Sep 20 12:56:07 2022. 4 | You can adapt this file completely to your liking, but it should at least 5 | contain the root `toctree` directive. 6 | typed_python 7 | ======================================== 8 | Strong typing and an LLVM-based JIT compiler for Python. 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | :caption: For Users 13 | 14 | introduction.md 15 | intro_2.md 16 | 17 | .. toctree:: 18 | :maxdepth: 1 19 | :caption: For Developers 20 | 21 | installation.md 22 | contributing.md 23 | 24 | .. toctree:: 25 | :maxdepth: 3 26 | :caption: API documentation 27 | 28 | api/typed_python 29 | 30 | 31 | Indices and tables 32 | ================== 33 | 34 | * :ref:`genindex` 35 | * :ref:`modindex` 36 | * :ref:`search` 37 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Development 4 | There are several methods for building and setting up a development environment. 5 | 6 | ### Manual Method ### 7 | 1. Create a new virtualenv with Python 3.6 (`virtualenv --python= venv`) and source it 8 | 2. Install requirements via pip. For the moment there are two options: 9 | * Install with plain pip using the `requirements` 10 | * Install using Pipenv (which reads from the Pipfile) 11 | 3. Build nativepython libraries using `python setup.py build` 12 | 4. Append the root of this repository to your `PYTHONPATH` 13 | 14 | ### Pipenv Method ### 15 | This method is simple, and can take care of virtual environment creation and installation for you. 16 | 1. (Optional) Create a new virtualenv with Python 3.6 (`virtualenv --python= venv`) and source it. If you choose to use Pipenv alone, it will create an appropriate virtualenv for you. 17 | 2. Run `pipenv install --dev --deploy` 18 | 19 | ### Makefile Method ### 20 | The included Makefile in this repository contains recipes for building, installing, and testing. For the moment, it is explicitly linked to a specific Python interpreter, so if you are using, say, an interpreter called `python3.6` (as opposed to `python3`), you will need to change the `PYTHON` variable at the top of the Makefile. 21 | 22 | You can also customize the name and location of any built virtual environments with the `VIRTUAL_ENV` variable. 23 | 24 | 25 | ## Installation ## 26 | 27 | ### OSX ### 28 | 29 | #### Prerequisites #### 30 | * Python 3.6 (recommended installed with homebrew) 31 | * Currently build is tested against `clang`, not `gcc`. For more information about installing `clang` and configuring your environment see [here](https://embeddedartistry.com/blog/2017/2/20/installing-clangllvm-on-osx) 32 | * It is recommended you use Pipenv ([see this link](https://pipenv.readthedocs.io/en/latest/install/#installing-pipenv)) to manage the application. 33 | * You can also use virtualenv. 34 | * install Redis (`brew install redis`) 35 | 36 | 37 | 38 | 39 | ### Linux ### 40 | (These instructions are only for Ubuntu for the moment) 41 | 42 | #### Prerequisites #### 43 | Before building the modules in this repository, you will need to make sure that you have the following: 44 | * Python 3.6 with header files (`python3.6-dev python3.6-dbg`) 45 | Note that for development you will also install the debug interpreter. 46 | If you are using **Ubuntu 16** or earlier, you will first need to add the following PPA: 47 | ``` 48 | sudo add-apt-repository ppa:jonathonf/python-3.6 49 | ``` 50 | Then run as normal: 51 | ``` 52 | sudo apt install python3.6-dev python3.6-dbg 53 | ``` 54 | * Pipenv ([see this link](https://pipenv.readthedocs.io/en/latest/install/#installing-pipenv)) 55 | * Redis Server (`redis-server`) 56 | -------------------------------------------------------------------------------- /install_and_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # a little script to install TP directly in a new venv 4 | # and run the array tests. 5 | rm -rf .test_venv; 6 | python3 -c 'import sys; print("python version is ", sys.version_info)'; 7 | python3 -m venv .test_venv; 8 | . .test_venv/bin/activate; 9 | pip install -v -e .; 10 | pip install scipy; 11 | pip install pytest; 12 | pip install flaky; 13 | TP_COMPILER_CACHE= pytest -k array_test -vs; 14 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools", 4 | "wheel", 5 | 'oldest-supported-numpy', 6 | ] 7 | # build-backend = "setuptools.build_meta:__legacy__" 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | llvmlite==0.38 2 | numpy 3 | psutil 4 | pytz 5 | sortedcontainers 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 Nativepython Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pkg_resources 16 | import setuptools 17 | 18 | from distutils.command.build_ext import build_ext 19 | from distutils.extension import Extension 20 | 21 | 22 | class TypedPythonBuildExtension(build_ext): 23 | def run(self): 24 | self.include_dirs.append( 25 | pkg_resources.resource_filename('numpy', 'core/include') 26 | ) 27 | 28 | build_ext.run(self) 29 | 30 | 31 | extra_compile_args = [ 32 | '-O2', 33 | '-fstack-protector-strong', 34 | '-Wformat', 35 | '-Wdate-time', 36 | '-Werror=format-security', 37 | '-std=c++14', 38 | '-Wno-sign-compare', 39 | '-Wno-narrowing', 40 | '-Wno-sign-compare', 41 | '-Wno-terminate', 42 | '-Wno-reorder', 43 | '-Wno-bool-compare', 44 | '-Wno-cpp' 45 | ] 46 | 47 | ext_modules = [ 48 | Extension( 49 | 'typed_python._types', 50 | sources=[ 51 | 'typed_python/all.cpp', 52 | ], 53 | define_macros=[ 54 | ("_FORTIFY_SOURCE", 2) 55 | ], 56 | include_dirs=['typed_python/lz4'], 57 | extra_compile_args=extra_compile_args 58 | ) 59 | ] 60 | 61 | INSTALL_REQUIRES = [line.strip() for line in open('requirements.txt')] 62 | 63 | setuptools.setup( 64 | name='typed_python', 65 | version='0.2.6', 66 | description='opt-in strong typing at runtime for python, plus a compiler.', 67 | author='Braxton Mckee', 68 | author_email='braxton.mckee@gmail.com', 69 | url='https://github.com/aprioriinvestments/typed_python', 70 | packages=setuptools.find_packages(), 71 | cmdclass={'build_ext': TypedPythonBuildExtension}, 72 | ext_modules=ext_modules, 73 | install_requires=INSTALL_REQUIRES, 74 | 75 | # https://pypi.org/classifiers/ 76 | classifiers=[ 77 | "License :: OSI Approved :: Apache Software License", 78 | "Programming Language :: Python :: 3 :: Only", 79 | ], 80 | python_requires='>=3.7', 81 | license="Apache Software License v2.0", 82 | 83 | include_package_data=True, 84 | data_files=[ 85 | ("", ["requirements.txt"]), 86 | ], 87 | zip_safe=False 88 | ) 89 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | requires = 3 | tox-venv 4 | envlist = py36,py37 5 | 6 | 7 | [testenv] 8 | deps = 9 | pytest 10 | 11 | commands = 12 | ./test.py --filter=typed_python 13 | 14 | 15 | [pytest] 16 | testpaths = 17 | typed_python 18 | 19 | log_level = INFO 20 | log_format = [%(asctime)s.%(msecs)03d] %(levelname)8s %(filename)30s:%(lineno)4s | %(threadName)10s | %(message)s 21 | log_date_format = %Y-%m-%d %H:%M:%S 22 | 23 | 24 | # The pycodestyle section is used by autopep8 25 | [pycodestyle] 26 | max-line-length = 99 27 | ignore = 28 | E201, # whitespace after '{', '(', etc 29 | E202, # whitespace before '}', ')', etc 30 | E226, # missing whitespace around arithmetic operator 31 | E227, # missing whitespace around bitwise or shift operator 32 | E228, # missing whitespace around modulo operator 33 | E731, # do not assign a lambda expression, use a def 34 | W503, # line break before binary operator 35 | W504, # line break after binary operator 36 | exclude = 37 | .git, 38 | .eggs, 39 | .venv, 40 | .venv_3_8, 41 | .venv_3_7, 42 | .venv_3_6, 43 | .venv_3_9, 44 | .venv_3_10, 45 | .venv_3_11, 46 | .tox, 47 | build 48 | 49 | 50 | [flake8] 51 | statistics = True 52 | 53 | max-line-length = 139 54 | 55 | ignore = 56 | E201, # whitespace after '{', '(', etc 57 | E202, # whitespace before '}', ')', etc 58 | E226, # missing whitespace around arithmetic operator 59 | E227, # missing whitespace around bitwise or shift operator 60 | E228, # missing whitespace around modulo operator 61 | E731, # do not assign a lambda expression, use a def 62 | E741, # allow ambiguous variable names like 'l' 63 | W503, # line break before binary operator 64 | W504, # line break after binary operator 65 | 66 | per-file-ignores= 67 | __init__.py: F401, 68 | 69 | exclude = 70 | .git, 71 | .eggs, 72 | .venv, 73 | .venv_3_8, 74 | .venv_3_7, 75 | .venv_3_6, 76 | .venv_3_9, 77 | .venv_3_10, 78 | .venv_3_11, 79 | .tox, 80 | .nodeenv, 81 | build 82 | 83 | 84 | [coverage:run] 85 | source = 86 | typed_python 87 | 88 | parallel = True 89 | 90 | 91 | [coverage:report] 92 | omit = 93 | *_test.py 94 | 95 | exclude_lines = 96 | # Have to re-enable the standard pragma 97 | pragma: no cover 98 | 99 | # Don't complain if tests don't hit defensive assertion code: 100 | raise AssertionError 101 | raise NotImplementedError 102 | pass 103 | -------------------------------------------------------------------------------- /typed_python/AllTypes.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | //the pattern of using 'check' to explicitly enumerate all of 20 | //our subclasses by TypeCategory requires that if you include 21 | //want to use any Type, you need to know about all of them. 22 | #include "Type.hpp" 23 | #include "TypeDetails.hpp" 24 | #include "RegisterTypes.hpp" 25 | #include "ForwardType.hpp" 26 | #include "OneOfType.hpp" 27 | #include "CompositeType.hpp" 28 | #include "PointerToType.hpp" 29 | #include "RefToType.hpp" 30 | #include "TupleOrListOfType.hpp" 31 | #include "ConstDictType.hpp" 32 | #include "DictType.hpp" 33 | #include "NoneType.hpp" 34 | #include "Instance.hpp" 35 | #include "StringType.hpp" 36 | #include "BytesType.hpp" 37 | #include "ValueType.hpp" 38 | #include "AlternativeType.hpp" 39 | #include "ConcreteAlternativeType.hpp" 40 | #include "PythonSubclassType.hpp" 41 | #include "PythonObjectOfTypeType.hpp" 42 | #include "FunctionType.hpp" 43 | #include "HeldClassType.hpp" 44 | #include "ClassType.hpp" 45 | #include "BoundMethodType.hpp" 46 | #include "AlternativeMatcherType.hpp" 47 | #include "EmbeddedMessageType.hpp" 48 | #include "SetType.hpp" 49 | #include "PyCellType.hpp" 50 | #include "TypedCellType.hpp" 51 | #include "SubclassOfType.hpp" 52 | #include "direct_types/Bytes.hpp" 53 | -------------------------------------------------------------------------------- /typed_python/Codebase_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest 16 | import typed_python 17 | 18 | from typed_python.Codebase import Codebase 19 | 20 | 21 | class CodebaseTest(unittest.TestCase): 22 | def test_instantiated_codebase(self): 23 | codebase = Codebase.FromFileMap({ 24 | 'codebase_test_test_module/__init__.py': '', 25 | 'codebase_test_test_module/inner.py': 'f = lambda: 10', 26 | }) 27 | codebase.instantiate() 28 | codebase.instantiate() 29 | 30 | self.assertEqual(codebase.getClassByName('codebase_test_test_module.inner.f')(), 10) 31 | 32 | codebase2 = Codebase.FromRootlevelModule(codebase.getModuleByName("codebase_test_test_module")) 33 | 34 | self.assertTrue(codebase2.isInstantiated()) 35 | self.assertEqual(codebase2.getClassByName('codebase_test_test_module.inner.f')(), 10) 36 | 37 | self.assertEqual(codebase.filesToContents, codebase2.filesToContents) 38 | 39 | vals = list(codebase.allModuleLevelValues()) 40 | vals = [v[0] for v in vals if "__" not in v[0]] 41 | self.assertEqual(vals, ['codebase_test_test_module.inner', 'codebase_test_test_module.inner.f']) 42 | 43 | codebaseAlternativeCode = Codebase.FromFileMap( 44 | {'codebase_test_test_module/__init__.py': ""} 45 | ) 46 | with self.assertRaisesRegex(Exception, "Module codebase_test_test_module is"): 47 | codebaseAlternativeCode.instantiate() 48 | 49 | def test_grab_native_codebase(self): 50 | codebase = Codebase.FromRootlevelModule(typed_python) 51 | 52 | assert codebase.isInstantiated() 53 | -------------------------------------------------------------------------------- /typed_python/ConversionLevel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /******* 4 | Describes the different ways in which we can convert objects from one 5 | type to another during execution. 6 | 7 | See conversion_level.py for more. 8 | *******/ 9 | enum class ConversionLevel { 10 | Signature, 11 | Upcast, 12 | UpcastContainers, 13 | Implicit, 14 | ImplicitContainers, 15 | New, 16 | }; 17 | 18 | inline int conversionLevelToInt(ConversionLevel level) { 19 | if (level == ConversionLevel::Signature) { 20 | return 0; 21 | } 22 | if (level == ConversionLevel::Upcast) { 23 | return 1; 24 | } 25 | if (level == ConversionLevel::UpcastContainers) { 26 | return 2; 27 | } 28 | if (level == ConversionLevel::Implicit) { 29 | return 3; 30 | } 31 | if (level == ConversionLevel::ImplicitContainers) { 32 | return 4; 33 | } 34 | if (level == ConversionLevel::New) { 35 | return 5; 36 | } 37 | 38 | throw std::runtime_error("Invalid ConversionLevel"); 39 | } 40 | 41 | inline std::string conversionLevelToString(ConversionLevel level) { 42 | if (level == ConversionLevel::Signature) { 43 | return "Signature"; 44 | } 45 | if (level == ConversionLevel::Upcast) { 46 | return "Upcast"; 47 | } 48 | if (level == ConversionLevel::UpcastContainers) { 49 | return "UpcastContainers"; 50 | } 51 | if (level == ConversionLevel::Implicit) { 52 | return "Implicit"; 53 | } 54 | if (level == ConversionLevel::ImplicitContainers) { 55 | return "ImplicitContainers"; 56 | } 57 | if (level == ConversionLevel::New) { 58 | return "New"; 59 | } 60 | 61 | throw std::runtime_error("Invalid ConversionLevel"); 62 | } 63 | 64 | inline ConversionLevel intToConversionLevel(int level) { 65 | if (level == 0) { 66 | return ConversionLevel::Signature; 67 | } 68 | if (level == 1) { 69 | return ConversionLevel::Upcast; 70 | } 71 | if (level == 2) { 72 | return ConversionLevel::UpcastContainers; 73 | } 74 | if (level == 3) { 75 | return ConversionLevel::Implicit; 76 | } 77 | if (level == 4) { 78 | return ConversionLevel::ImplicitContainers; 79 | } 80 | if (level == 5) { 81 | return ConversionLevel::New; 82 | } 83 | 84 | throw std::runtime_error("Invalid ConversionLevel"); 85 | } 86 | 87 | inline bool operator<(ConversionLevel lhs, ConversionLevel rhs) { 88 | return conversionLevelToInt(lhs) < conversionLevelToInt(rhs); 89 | } 90 | 91 | inline bool operator>(ConversionLevel lhs, ConversionLevel rhs) { 92 | return conversionLevelToInt(lhs) > conversionLevelToInt(rhs); 93 | } 94 | 95 | inline bool operator<=(ConversionLevel lhs, ConversionLevel rhs) { 96 | return conversionLevelToInt(lhs) <= conversionLevelToInt(rhs); 97 | } 98 | 99 | inline bool operator>=(ConversionLevel lhs, ConversionLevel rhs) { 100 | return conversionLevelToInt(lhs) >= conversionLevelToInt(rhs); 101 | } 102 | -------------------------------------------------------------------------------- /typed_python/DeepcopyContext.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Slab.hpp" 5 | 6 | class DeepcopyContext { 7 | public: 8 | DeepcopyContext(Slab* inSlab) : slab(inSlab) { 9 | } 10 | 11 | void memoize(PyObject* source, PyObject* dest) { 12 | pyObjectsToKeepAlive.push_back(PyObjectHolder(source)); 13 | pyObjectsToKeepAlive.push_back(PyObjectHolder(dest)); 14 | alreadyAllocated[(instance_ptr)source] = (instance_ptr)dest; 15 | } 16 | 17 | std::unordered_map alreadyAllocated; 18 | 19 | std::vector pyObjectsToKeepAlive; 20 | 21 | Slab* slab; 22 | 23 | std::unordered_map tpTypeMap; 24 | 25 | std::unordered_map pyTypeMap; 26 | }; 27 | -------------------------------------------------------------------------------- /typed_python/EmbeddedMessageType.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "BytesType.hpp" 20 | #include "NullSerializationContext.hpp" 21 | #include "SerializationBuffer.hpp" 22 | 23 | class EmbeddedMessageType : public BytesType { 24 | public: 25 | EmbeddedMessageType() 26 | { 27 | m_name = "EmbeddedMessage"; 28 | m_is_default_constructible = true; 29 | m_size = sizeof(layout*); 30 | m_typeCategory = TypeCategory::catEmbeddedMessage; 31 | } 32 | 33 | static EmbeddedMessageType* Make() { 34 | static EmbeddedMessageType* res = new EmbeddedMessageType(); 35 | return res; 36 | } 37 | 38 | template 39 | void serialize(instance_ptr self, buf_t& buffer, size_t fieldNumber) { 40 | //by default we're the empty message 41 | if (count(self) == 0) { 42 | buffer.writeEmpty(fieldNumber); 43 | return; 44 | } 45 | 46 | //we represent a message with fieldNumber 0. Our first byte is whatever 47 | //our own wire type is, so we can just add the field number to it 48 | buffer.writeUnsignedVarint((fieldNumber << 3) + *(uint8_t*)eltPtr(self, 0)); 49 | 50 | //then we write the rest of the message 51 | buffer.write_bytes(eltPtr(self, 1), count(self) - 1); 52 | } 53 | 54 | template 55 | void deserialize(instance_ptr self, buf_t& buffer, size_t wireType) { 56 | NullSerializationContext context; 57 | SerializationBuffer outBuffer(context); 58 | 59 | outBuffer.write(wireType); 60 | buffer.copyMessageToOtherBuffer(wireType, outBuffer); 61 | 62 | constructor((instance_ptr)self, outBuffer.size(), (const char*)outBuffer.buffer()); 63 | } 64 | }; 65 | 66 | -------------------------------------------------------------------------------- /typed_python/HashAccumulator.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | 20 | typedef int32_t typed_python_hash_type; 21 | 22 | 23 | class HashAccumulator { 24 | public: 25 | HashAccumulator(typed_python_hash_type init = 0) : 26 | m_state(init) 27 | { 28 | } 29 | 30 | void add(int32_t i) { 31 | m_state = int32_t(m_state * 1000003) ^ i; 32 | } 33 | 34 | void addBytes(uint8_t* bytes, int64_t count) { 35 | while (count >= 4) { 36 | add(*(int32_t*)bytes); 37 | bytes += 4; 38 | count -= 4; 39 | } 40 | while (count) { 41 | add((uint8_t)*bytes); 42 | bytes++; 43 | count--; 44 | } 45 | } 46 | 47 | typed_python_hash_type get() const { 48 | return m_state; 49 | } 50 | 51 | void addRegister(bool i) { add(i ? 1:0); } 52 | void addRegister(uint8_t i) { add(i); } 53 | void addRegister(uint16_t i) { add(i); } 54 | void addRegister(uint32_t i) { add(i); } 55 | void addRegister(uint64_t i) { 56 | add(i >> 32); 57 | add(i & 0xFFFFFFFF); 58 | } 59 | 60 | void addRegister(int8_t i) { add(i); } 61 | void addRegister(int16_t i) { add(i); } 62 | void addRegister(int32_t i) { add(i); } 63 | void addRegister(int64_t i) { 64 | add(i >> 32); 65 | add(i & 0xFFFFFFFF); 66 | } 67 | 68 | void addRegister(float i) { 69 | addRegister((double)i); 70 | } 71 | 72 | void addRegister(double i) { 73 | if (i == int32_t(i)) { 74 | add((int32_t)i); 75 | } else { 76 | addBytes((uint8_t*)&i, sizeof(i)); 77 | } 78 | } 79 | 80 | private: 81 | typed_python_hash_type m_state; 82 | }; 83 | -------------------------------------------------------------------------------- /typed_python/Memory.cpp: -------------------------------------------------------------------------------- 1 | #include "Memory.hpp" 2 | #include "Slab.hpp" 3 | 4 | #include 5 | 6 | static_assert(sizeof(Slab*) <= sizeof(std::max_align_t), "Can't fit a Slab* in the max_align_t?"); 7 | 8 | void* tp_malloc(size_t s) { 9 | if (s == 0) { 10 | return nullptr; 11 | } 12 | 13 | uint8_t* m = (uint8_t*)malloc(s + sizeof(std::max_align_t)); 14 | 15 | ((int64_t*)m)[0] = -(int64_t)s; 16 | 17 | tpBytesAllocatedOnFreeStore() += s + sizeof(std::max_align_t); 18 | 19 | return m + sizeof(std::max_align_t); 20 | } 21 | 22 | void tp_free(void* p) { 23 | if (!p) { 24 | return; 25 | } 26 | 27 | uint8_t* m = (uint8_t*)p - sizeof(std::max_align_t); 28 | 29 | int64_t sizeOrSlab = ((int64_t*)m)[0]; 30 | 31 | if (sizeOrSlab <= 0) { 32 | tpBytesAllocatedOnFreeStore() += sizeOrSlab - sizeof(std::max_align_t); 33 | free(m); 34 | return; 35 | } 36 | 37 | Slab* slab = ((Slab**)m)[0]; 38 | slab->free(p); 39 | } 40 | 41 | void* tp_realloc(void* p, size_t oldSize, size_t newSize) { 42 | if (!p) { 43 | return tp_malloc(newSize); 44 | } 45 | 46 | if (p && !newSize) { 47 | tp_free(p); 48 | return nullptr; 49 | } 50 | 51 | uint8_t* m = (uint8_t*)p - sizeof(std::max_align_t); 52 | 53 | int64_t sizeOrSlab = ((int64_t*)m)[0]; 54 | 55 | if (sizeOrSlab <= 0) { 56 | tpBytesAllocatedOnFreeStore() += (int64_t)newSize - (int64_t)oldSize; 57 | 58 | uint8_t* res = (uint8_t*)realloc(m, newSize + sizeof(std::max_align_t)); 59 | 60 | *(int64_t*)res = -(int64_t)newSize; 61 | 62 | return res + sizeof(std::max_align_t); 63 | } else { 64 | Slab* slab = ((Slab**)m)[0]; 65 | 66 | void* newData = tp_malloc(newSize); 67 | memcpy(newData, m + sizeof(std::max_align_t), std::min(newSize, oldSize)); 68 | slab->free(p); 69 | 70 | return newData; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /typed_python/Memory.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2021 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | /************** 20 | 21 | Memory: 22 | 23 | This file defines the typed-python memory allocation model. In order to 24 | track memory usage and to allow memory to be allocated in slabs (and eventually 25 | maybe to allow explicit arena management for large applications), our 26 | memory management routines pack an extra word at the beginning of every 27 | allocation. 28 | 29 | The word can either be the bytecount of the allocation with the top bit set, 30 | indicating that this is a direct allocation from malloc, or it can be a pointer 31 | to a Slab object which we decref when the allocation is released. 32 | 33 | ***************/ 34 | 35 | #include 36 | #include 37 | 38 | extern "C" { 39 | 40 | void* tp_malloc(size_t bytes); 41 | void* tp_realloc(void* ptr, size_t oldBytes, size_t newBytes); 42 | void tp_free(void* ptr); 43 | 44 | } 45 | 46 | inline std::atomic& tpBytesAllocatedOnFreeStore() { 47 | static std::atomic allocatedCount; 48 | return allocatedCount; 49 | } 50 | 51 | // how many bytes are required to back an allocation of size 's' 52 | // accounts for alignment and extra pointers. 53 | inline size_t bytesRequiredForAllocation(size_t s) { 54 | if (s == 0) { 55 | return 0; 56 | } 57 | 58 | if (s % sizeof(std::max_align_t)) { 59 | s += sizeof(std::max_align_t) - (s % sizeof(std::max_align_t)); 60 | } 61 | 62 | return s + sizeof(std::max_align_t); 63 | } 64 | -------------------------------------------------------------------------------- /typed_python/NullSerializationContext.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "Type.hpp" 20 | #include "SerializationContext.hpp" 21 | 22 | class NullSerializationContext : public SerializationContext { 23 | public: 24 | virtual void serializePythonObject(PyObject* o, SerializationBuffer& b, size_t fieldNumber) const { 25 | throw std::runtime_error("No serialization plugin provided, so we can't serialize arbitrary python objects."); 26 | } 27 | virtual PyObject* deserializePythonObject(DeserializationBuffer& b, size_t wireType) const { 28 | throw std::runtime_error("No serialization plugin provided, so we can't deserialize arbitrary python objects."); 29 | } 30 | 31 | virtual void serializeNativeType(Type* o, SerializationBuffer& b, size_t fieldNumber) const { 32 | throw std::runtime_error("No serialization plugin provided, so we can't serialize arbitrary python objects."); 33 | } 34 | 35 | virtual Type* deserializeNativeType(DeserializationBuffer& b, size_t wireType) const { 36 | throw std::runtime_error("No serialization plugin provided, so we can't serialize arbitrary python objects."); 37 | } 38 | 39 | 40 | virtual bool compressUsingThreads() const { 41 | return false; 42 | } 43 | virtual bool serializePodListsInline() const { 44 | return false; 45 | } 46 | virtual bool isCompressionEnabled() const { 47 | return false; 48 | } 49 | virtual bool isLineInfoSuppressed() const { 50 | return false; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /typed_python/PyAlternativeMatcherInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyAlternativeMatcherInstance : public PyInstance { 22 | public: 23 | typedef AlternativeMatcher modeled_type; 24 | 25 | AlternativeMatcher* type() { 26 | return (AlternativeMatcher*)extractTypeFrom(((PyObject*)this)->ob_type); 27 | } 28 | 29 | Alternative* baseAlternative() { 30 | if (type()->getAlternative()->isAlternative()) { 31 | return (Alternative*)(type()->getAlternative()); 32 | } 33 | 34 | if (type()->getAlternative()->isConcreteAlternative()) { 35 | return ((ConcreteAlternative*)(type()->getAlternative()))->getAlternative(); 36 | } 37 | 38 | throw std::runtime_error("Invalid base alternative in PyAlternativeMatcherInstance"); 39 | } 40 | 41 | static void mirrorTypeInformationIntoPyTypeConcrete(AlternativeMatcher* altMatcherT, PyTypeObject* pyType) { 42 | PyDict_SetItemString(pyType->tp_dict, "Alternative", typePtrToPyTypeRepresentation(altMatcherT->getBaseAlternative())); 43 | } 44 | 45 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 46 | return true; 47 | } 48 | 49 | PyObject* tp_getattr_concrete(PyObject* pyAttrName, const char* attrName) { 50 | Alternative* alt = baseAlternative(); 51 | 52 | bool matches = alt->subtypes()[ 53 | alt->which(dataPtr()) 54 | ].first == attrName; 55 | 56 | return incref(matches ? Py_True : Py_False); 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /typed_python/PyBoundMethodInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyBoundMethodInstance : public PyInstance { 22 | public: 23 | typedef BoundMethod modeled_type; 24 | 25 | BoundMethod* type(); 26 | 27 | PyObject* tp_call_concrete(PyObject* args, PyObject* kwargs); 28 | 29 | int pyInquiryConcrete(const char* op, const char* opErrRep); 30 | 31 | static void mirrorTypeInformationIntoPyTypeConcrete(BoundMethod* methodT, PyTypeObject* pyType); 32 | 33 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 34 | return true; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /typed_python/PyConstDictInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyConstDictInstance : public PyInstance { 22 | public: 23 | typedef ConstDictType modeled_type; 24 | 25 | ConstDictType* type(); 26 | 27 | PyObject* tp_iter_concrete(); 28 | 29 | PyObject* tp_iternext_concrete(); 30 | 31 | Py_ssize_t mp_and_sq_length_concrete(); 32 | 33 | int sq_contains_concrete(PyObject* item); 34 | 35 | PyObject* pyOperatorConcrete(PyObject* rhs, const char* op, const char* opErr); 36 | 37 | int pyInquiryConcrete(const char* op, const char* opErrRep); 38 | 39 | PyObject* mp_subscript_concrete(PyObject* item); 40 | 41 | static PyObject* constDictItems(PyObject *o); 42 | 43 | static PyObject* constDictKeys(PyObject *o); 44 | 45 | static PyObject* constDictValues(PyObject *o); 46 | 47 | static PyObject* constDictGet(PyObject* o, PyObject* args); 48 | 49 | static PyMethodDef* typeMethodsConcrete(Type* t); 50 | 51 | static void mirrorTypeInformationIntoPyTypeConcrete(ConstDictType* constDictT, PyTypeObject* pyType); 52 | 53 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level); 54 | 55 | static bool compare_to_python_concrete(ConstDictType* dictType, instance_ptr self, PyObject* other, bool exact, int pyComparisonOp); 56 | 57 | static void copyConstructFromPythonInstanceConcrete(ConstDictType* dictType, instance_ptr tgt, PyObject* pyRepresentation, ConversionLevel level); 58 | 59 | bool compare_as_iterator_to_python_concrete(PyObject* other, int pyComparisonOp); 60 | 61 | PyObject* tp_repr_concrete(); 62 | 63 | PyObject* tp_str_concrete(); 64 | }; 65 | -------------------------------------------------------------------------------- /typed_python/PyEmbeddedMessageInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyEmbeddedMessageInstance : public PyInstance { 22 | public: 23 | typedef EmbeddedMessageType modeled_type; 24 | 25 | static void copyConstructFromPythonInstanceConcrete( 26 | EmbeddedMessageType* eltType, instance_ptr tgt, PyObject* pyRepresentation, ConversionLevel level 27 | ) { 28 | if (PyBytes_Check(pyRepresentation) && level >= ConversionLevel::Implicit) { 29 | EmbeddedMessageType::Make()->constructor( 30 | tgt, 31 | PyBytes_GET_SIZE(pyRepresentation), 32 | PyBytes_AsString(pyRepresentation) 33 | ); 34 | return; 35 | } 36 | 37 | PyInstance::copyConstructFromPythonInstanceConcrete(eltType, tgt, pyRepresentation, level); 38 | } 39 | 40 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 41 | return PyBytes_Check(pyRepresentation); 42 | } 43 | 44 | static PyObject* extractPythonObjectConcrete(modeled_type* bytesType, instance_ptr data) { 45 | return PyBytes_FromStringAndSize( 46 | (const char*)EmbeddedMessageType::Make()->eltPtr(data, 0), 47 | EmbeddedMessageType::Make()->count(data) 48 | ); 49 | } 50 | 51 | static bool compare_to_python_concrete(modeled_type* t, instance_ptr self, PyObject* other, bool exact, int pyComparisonOp) { 52 | if (!PyBytes_Check(other)) { 53 | return cmpResultToBoolForPyOrdering(pyComparisonOp, -1); 54 | } 55 | 56 | if (PyBytes_GET_SIZE(other) < ((EmbeddedMessageType*)t)->count(self)) { 57 | return cmpResultToBoolForPyOrdering(pyComparisonOp, -1); 58 | } 59 | 60 | if (PyBytes_GET_SIZE(other) > ((EmbeddedMessageType*)t)->count(self)) { 61 | return cmpResultToBoolForPyOrdering(pyComparisonOp, 1); 62 | } 63 | 64 | return cmpResultToBoolForPyOrdering( 65 | pyComparisonOp, 66 | memcmp( 67 | PyBytes_AsString(other), 68 | ((EmbeddedMessageType*)t)->eltPtr(self, 0), 69 | PyBytes_GET_SIZE(other) 70 | ) 71 | ); 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /typed_python/PyGilState.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2020 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | //scoped object to ensure we're not holding the GIL. If we've 22 | //already released it, this is a no-op. Upon destruction, we 23 | //reacquire it. 24 | class PyEnsureGilReleased { 25 | public: 26 | PyEnsureGilReleased(); 27 | 28 | ~PyEnsureGilReleased(); 29 | 30 | static void gilReleaseThreadLoop(); 31 | 32 | static void setGilReleaseThreadLoopSleepMicroseconds(int64_t ms); 33 | 34 | private: 35 | bool m_should_reacquire; 36 | }; 37 | 38 | //scoped object to ensure we're holding the GIL. If 39 | //we released it in a thread above, this should reacquire it. 40 | //if we already hold it, it should be a no-op 41 | class PyEnsureGilAcquired { 42 | public: 43 | PyEnsureGilAcquired(); 44 | 45 | ~PyEnsureGilAcquired(); 46 | 47 | private: 48 | bool m_should_rerelease; 49 | }; 50 | 51 | 52 | void assertHoldingTheGil(); 53 | -------------------------------------------------------------------------------- /typed_python/PyModuleRepresentation.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2021 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "ModuleRepresentation.hpp" 20 | #include 21 | 22 | class PyModuleRepresentation { 23 | public: 24 | PyObject_HEAD 25 | 26 | std::shared_ptr mModuleRepresentation; 27 | 28 | static void dealloc(PyModuleRepresentation *self); 29 | 30 | static PyObject *new_(PyTypeObject *type, PyObject *args, PyObject *kwargs); 31 | 32 | static int init(PyModuleRepresentation *self, PyObject *args, PyObject *kwargs); 33 | 34 | static PyObject* addExternal(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 35 | 36 | static PyObject* getDict(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 37 | 38 | static PyObject* isSetupComplete(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 39 | 40 | static PyObject* update(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 41 | 42 | static PyObject* setupComplete(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 43 | 44 | static PyObject* copyInto(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 45 | 46 | static PyObject* copyIntoAsInactive(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 47 | 48 | static PyObject* oidFor(PyModuleRepresentation* self, PyObject* args, PyObject* kwargs); 49 | }; 50 | 51 | extern PyTypeObject PyType_ModuleRepresentation; 52 | -------------------------------------------------------------------------------- /typed_python/PyNoneInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyNoneInstance : public PyInstance { 22 | public: 23 | typedef NoneType modeled_type; 24 | 25 | static void copyConstructFromPythonInstanceConcrete(NoneType* none, instance_ptr tgt, PyObject* pyRepresentation, ConversionLevel level) { 26 | if (pyRepresentation == Py_None) { 27 | return; 28 | } 29 | 30 | PyInstance::copyConstructFromPythonInstanceConcrete(none, tgt, pyRepresentation, level); 31 | } 32 | 33 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 34 | return pyRepresentation == Py_None; 35 | } 36 | 37 | static PyObject* extractPythonObjectConcrete(NoneType* valueType, instance_ptr data) { 38 | return incref(Py_None); 39 | } 40 | 41 | static bool compare_to_python_concrete(NoneType* t, instance_ptr self, PyObject* other, bool exact, int pyComparisonOp) { 42 | return cmpResultToBoolForPyOrdering( 43 | pyComparisonOp, 44 | other == Py_None ? 0 : 1 45 | ); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /typed_python/PyPointerToInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyPointerToInstance : public PyInstance { 22 | public: 23 | typedef PointerTo modeled_type; 24 | 25 | PointerTo* type(); 26 | 27 | PyObject* mp_subscript_concrete(PyObject* ix); 28 | 29 | static PyObject* pointerInitialize(PyObject* o, PyObject* args); 30 | 31 | static PyObject* pointerDestroy(PyObject* o, PyObject* args); 32 | 33 | static PyObject* pointerSet(PyObject* o, PyObject* args); 34 | 35 | static PyObject* pointerGet(PyObject* o, PyObject* args); 36 | 37 | static PyObject* pointerCast(PyObject* o, PyObject* args); 38 | 39 | PyObject* pyOperatorConcrete(PyObject* rhs, const char* op, const char* opErr); 40 | 41 | static void mirrorTypeInformationIntoPyTypeConcrete(PointerTo* pointerT, PyTypeObject* pyType); 42 | 43 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 44 | return true; 45 | } 46 | 47 | PyObject* pyUnaryOperatorConcrete(const char* op, const char* opErr); 48 | 49 | int mp_ass_subscript_concrete(PyObject* item, PyObject* value); 50 | 51 | PyObject* tp_getattr_concrete(PyObject* pyAttrName, const char* attrName); 52 | 53 | int pyInquiryConcrete(const char* op, const char* opErrRep); 54 | 55 | static PyMethodDef* typeMethodsConcrete(Type* t); 56 | }; 57 | -------------------------------------------------------------------------------- /typed_python/PyPyCellInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | #include "PyCellType.hpp" 21 | 22 | class PyPyCellInstance : public PyInstance { 23 | public: 24 | typedef PyCellType modeled_type; 25 | 26 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 27 | return false; 28 | } 29 | 30 | PyObject* tp_getattr_concrete(PyObject* pyAttrName, const char* attrName) { 31 | if (strcmp(attrName, "contents") == 0) { 32 | PyObject* res = ((PyCellType*)type())->getPyObj(dataPtr()); 33 | if (!res) { 34 | throw std::runtime_error("PyCell is empty"); 35 | } 36 | return incref(res); 37 | } 38 | 39 | return PyInstance::tp_getattr_concrete(pyAttrName, attrName); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /typed_python/PyPythonObjectOfTypeInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyPythonObjectOfTypeInstance : public PyInstance { 22 | public: 23 | typedef PythonObjectOfType modeled_type; 24 | 25 | static void copyConstructFromPythonInstanceConcrete( 26 | PythonObjectOfType* eltType, instance_ptr tgt, PyObject* pyRepresentation, ConversionLevel level 27 | ) { 28 | int isinst = PyObject_IsInstance(pyRepresentation, (PyObject*)eltType->pyType()); 29 | if (isinst == -1) { 30 | isinst = 0; 31 | PyErr_Clear(); 32 | } 33 | 34 | if (!isinst) { 35 | throw std::logic_error("Object of type " + std::string(pyRepresentation->ob_type->tp_name) + 36 | " is not an instance of " + ((PythonObjectOfType*)eltType)->pyType()->tp_name); 37 | } 38 | 39 | eltType->initializeFromPyObject(tgt, pyRepresentation); 40 | return; 41 | } 42 | 43 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 44 | int isinst = PyObject_IsInstance(pyRepresentation, (PyObject*)type->pyType()); 45 | 46 | if (isinst == -1) { 47 | isinst = 0; 48 | PyErr_Clear(); 49 | } 50 | 51 | return isinst > 0; 52 | } 53 | 54 | static PyObject* extractPythonObjectConcrete(PythonObjectOfType* valueType, instance_ptr data) { 55 | return incref(valueType->getPyObj(data)); 56 | } 57 | 58 | static void mirrorTypeInformationIntoPyTypeConcrete(PythonObjectOfType* inType, PyTypeObject* pyType) { 59 | //expose 'ElementType' as a member of the type object 60 | PyDict_SetItemString( 61 | pyType->tp_dict, 62 | "PyType", 63 | (PyObject*)inType->pyType() 64 | ); 65 | } 66 | 67 | static bool compare_to_python_concrete(PythonObjectOfType* oType, instance_ptr self, PyObject* other, bool exact, int pyComparisonOp) { 68 | return PyObject_RichCompareBool(oType->getPyObj(self), other, pyComparisonOp); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /typed_python/PyRefToInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PyRefToInstance : public PyInstance { 22 | public: 23 | typedef RefTo modeled_type; 24 | 25 | RefTo* type(); 26 | 27 | static void mirrorTypeInformationIntoPyTypeConcrete(RefTo* pointerT, PyTypeObject* pyType); 28 | 29 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 30 | return true; 31 | } 32 | 33 | std::pair callMemberFunction(const char* name, PyObject* arg0=nullptr, PyObject* arg1=nullptr, PyObject* arg2=nullptr); 34 | 35 | PyObject* tp_getattr_concrete(PyObject* pyAttrName, const char* attrName); 36 | 37 | int tp_setattr_concrete(PyObject* attrName, PyObject* attrVal); 38 | 39 | int pyInquiryConcrete(const char* op, const char* opErrRep); 40 | 41 | static PyMethodDef* typeMethodsConcrete(Type* t); 42 | }; 43 | -------------------------------------------------------------------------------- /typed_python/PySlab.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2021 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | #include "Slab.hpp" 21 | 22 | class PySlab { 23 | public: 24 | PyObject_HEAD 25 | 26 | Slab* mSlab; 27 | 28 | static void dealloc(PySlab *self); 29 | 30 | static PyObject *new_(PyTypeObject *type, PyObject *args, PyObject *kwargs); 31 | 32 | static PyObject* newPySlab(Slab* s); 33 | 34 | static int init(PySlab *self, PyObject *args, PyObject *kwargs); 35 | 36 | static PyObject* slabPtr(PySlab* self, PyObject* args, PyObject* kwargs); 37 | 38 | static PyObject* refcount(PySlab* self, PyObject* args, PyObject* kwargs); 39 | 40 | static PyObject* bytecount(PySlab* self, PyObject* args, PyObject* kwargs); 41 | 42 | static PyObject* allocCount(PySlab* self, PyObject* args, PyObject* kwargs); 43 | 44 | static PyObject* liveAllocCount(PySlab* self, PyObject* args, PyObject* kwargs); 45 | 46 | static PyObject* extractObject(PySlab* self, PyObject* args, PyObject* kwargs); 47 | 48 | static PyObject* allocIsAlive(PySlab* self, PyObject* args, PyObject* kwargs); 49 | 50 | static PyObject* allocRefcount(PySlab* self, PyObject* args, PyObject* kwargs); 51 | 52 | static PyObject* allocType(PySlab* self, PyObject* args, PyObject* kwargs); 53 | 54 | static PyObject* getTag(PySlab* self, PyObject* args, PyObject* kwargs); 55 | 56 | static PyObject* setTag(PySlab* self, PyObject* args, PyObject* kwargs); 57 | }; 58 | 59 | extern PyTypeObject PyType_Slab; 60 | -------------------------------------------------------------------------------- /typed_python/PySubclassOfInstance.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | 21 | class PySubclassOfInstance : public PyInstance { 22 | public: 23 | typedef SubclassOfType modeled_type; 24 | 25 | static void copyConstructFromPythonInstanceConcrete(SubclassOfType* subclassOf, instance_ptr tgt, PyObject* pyRepresentation, ConversionLevel level) { 26 | Type* t = PyInstance::tryUnwrapPyInstanceToType(pyRepresentation); 27 | 28 | if (t && (t == subclassOf->getSubclassOf() || t->isSubclassOf(subclassOf->getSubclassOf()))) { 29 | *((Type**)tgt) = t; 30 | return; 31 | } 32 | 33 | if (t) { 34 | throw std::logic_error("Cannot construct a " + subclassOf->name() + " from the type " + t->name()); 35 | } 36 | 37 | PyInstance::copyConstructFromPythonInstanceConcrete(subclassOf, tgt, pyRepresentation, level); 38 | } 39 | 40 | static bool pyValCouldBeOfTypeConcrete(modeled_type* type, PyObject* pyRepresentation, ConversionLevel level) { 41 | return true; 42 | } 43 | 44 | static PyObject* extractPythonObjectConcrete(modeled_type* subclassOfT, instance_ptr data) { 45 | return incref(typePtrToPyTypeRepresentation(*((Type**)data))); 46 | } 47 | 48 | static bool compare_to_python_concrete(SubclassOfType* subclassOf, instance_ptr self, PyObject* other, bool exact, int pyComparisonOp) { 49 | Type* t = PyInstance::tryUnwrapPyInstanceToType(other); 50 | 51 | return subclassOf->cmp(self, (instance_ptr)&t, pyComparisonOp, false); 52 | } 53 | 54 | static void mirrorTypeInformationIntoPyTypeConcrete(SubclassOfType* subclassOfT, PyTypeObject* pyType) { 55 | //expose 'ElementType' as a member of the type object 56 | PyDict_SetItemString(pyType->tp_dict, "Type", typePtrToPyTypeRepresentation(subclassOfT->getSubclassOf())); 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /typed_python/PyTemporaryReferenceTracer.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2021 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "PyInstance.hpp" 20 | #include 21 | 22 | enum class TraceAction { 23 | ConvertTemporaryReference, 24 | Decref 25 | }; 26 | 27 | class PyTemporaryReferenceTracer { 28 | public: 29 | PyTemporaryReferenceTracer() : 30 | mostRecentEmptyFrame(nullptr), 31 | priorTraceFunc(nullptr), 32 | priorTraceFuncArg(nullptr) 33 | {} 34 | 35 | // perform an action on the first instruction where a 36 | // frame goes out of scope or where it is no longer on the 37 | // given line number 38 | class FrameAction { 39 | public: 40 | FrameAction(PyObject* inO, TraceAction inA, int inLine) : 41 | obj(inO), 42 | action(inA), 43 | lineNumber(inLine) 44 | { 45 | } 46 | 47 | PyObject* obj; 48 | TraceAction action; 49 | int lineNumber; 50 | }; 51 | 52 | std::unordered_map > frameToActions; 53 | 54 | std::unordered_map > codeObjectToExpressionLines; 55 | 56 | // the most recent frame we touched that has nothing in it 57 | PyFrameObject* mostRecentEmptyFrame; 58 | 59 | Py_tracefunc priorTraceFunc; 60 | 61 | PyObject* priorTraceFuncArg; 62 | 63 | bool isLineNewStatement(PyObject* code, int line); 64 | 65 | static PyTemporaryReferenceTracer globalTracer; 66 | 67 | static int globalTraceFun(PyObject* obj, PyFrameObject* frame, int what, PyObject* arg); 68 | 69 | // the next time we have an instruction in 'frame', trigger 'o' to become 70 | // a non-temporary reference 71 | static void traceObject(PyObject* o, PyFrameObject* frame); 72 | 73 | static void traceObject(PyObject* o); 74 | 75 | static void installGlobalTraceHandlerIfNecessary(); 76 | 77 | static void keepaliveForCurrentInstruction(PyObject* o); 78 | 79 | static void keepaliveForCurrentInstruction(PyObject* o, PyFrameObject* frame); 80 | }; 81 | -------------------------------------------------------------------------------- /typed_python/PythonSerializationContext.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #include "PythonSerializationContext.hpp" 18 | #include "AllTypes.hpp" 19 | #include "PyInstance.hpp" 20 | #include "MutuallyRecursiveTypeGroup.hpp" 21 | 22 | void PythonSerializationContext::setFlags() { 23 | Class* serContext = (Class*)mContextObj.type(); 24 | 25 | auto getBool = [&](const char* name) { 26 | int i = serContext->getMemberIndex(name); 27 | 28 | if (i < 0) { 29 | throw std::runtime_error( 30 | "Somehow this SerializationContext has no member " + std::string(name) 31 | ); 32 | } 33 | 34 | if (!serContext->checkInitializationFlag(mContextObj.data(), i)) { 35 | throw std::runtime_error( 36 | "Somehow this SerializationContext member " + std::string(name) + " is empty" 37 | ); 38 | } 39 | 40 | if (!serContext->getMemberType(i)->isBool()) { 41 | throw std::runtime_error( 42 | "Somehow this SerializationContext member " + std::string(name) + " is not a bool" 43 | ); 44 | } 45 | 46 | return *(bool*)serContext->eltPtr(mContextObj.data(), i); 47 | }; 48 | 49 | mCompressionEnabled = getBool("compressionEnabled"); 50 | mSerializeHashSequence = getBool("serializeHashSequence"); 51 | mSerializePodListsInline = getBool("serializePodListsInline"); 52 | mCompressUsingThreads = getBool("compressUsingThreads"); 53 | mSuppressLineInfo = !getBool("encodeLineInformationForCode"); 54 | } 55 | 56 | std::string PythonSerializationContext::getNameForPyObj(PyObject* o) const { 57 | PyEnsureGilAcquired acquireTheGil; 58 | 59 | PyObjectStealer contextAsPyObj(PyInstance::extractPythonObject(mContextObj)); 60 | 61 | PyObjectStealer nameForObject(PyObject_CallMethod(contextAsPyObj, "nameForObject", "(O)", o)); 62 | 63 | if (!nameForObject) { 64 | throw PythonExceptionSet(); 65 | } 66 | 67 | if (nameForObject != Py_None) { 68 | if (!PyUnicode_Check(nameForObject)) { 69 | decref(nameForObject); 70 | throw std::runtime_error("nameForObject returned something other than None or a string."); 71 | } 72 | 73 | return std::string(PyUnicode_AsUTF8(nameForObject)); 74 | } 75 | 76 | return ""; 77 | } 78 | -------------------------------------------------------------------------------- /typed_python/ReprAccumulator.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | class ReprAccumulator { 23 | public: 24 | ReprAccumulator(std::ostringstream& stream) : 25 | m_stream(stream) 26 | { 27 | } 28 | 29 | //record that we have seen this object, and then return whether it was redundant. 30 | bool pushObject(void* ptr) { 31 | bool hasSeen = m_seen_objects[ptr] > 0; 32 | m_seen_objects[ptr]++; 33 | return !hasSeen; 34 | } 35 | 36 | void popObject(void* ptr) { 37 | m_seen_objects[ptr]--; 38 | } 39 | 40 | template 41 | ReprAccumulator& operator<<(const T& in) { 42 | m_stream << in; 43 | return *this; 44 | } 45 | 46 | //if true, then this was invoked by a 'str' call, not a 'repr'. 47 | bool isStrCall() const { 48 | return m_isStr; 49 | } 50 | 51 | private: 52 | std::ostringstream& m_stream; 53 | 54 | std::map m_seen_objects; 55 | 56 | bool m_isStr; 57 | }; 58 | 59 | class PushReprState { 60 | public: 61 | template 62 | PushReprState(ReprAccumulator& accumulator, T* ptr) : 63 | m_accumulator(accumulator), 64 | m_ptr((void*)ptr), 65 | m_was_new(false) 66 | { 67 | m_was_new = m_accumulator.pushObject(m_ptr); 68 | } 69 | 70 | ~PushReprState() { 71 | m_accumulator.popObject(m_ptr); 72 | } 73 | 74 | operator bool() const { 75 | return m_was_new; 76 | } 77 | 78 | private: 79 | ReprAccumulator& m_accumulator; 80 | void* m_ptr; 81 | bool m_was_new; 82 | }; 83 | -------------------------------------------------------------------------------- /typed_python/ScopedIndenter.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2022 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | // use to print indented log/debug messages. The static thread-local lets you keep track 22 | // of how many stack frames there are above you 23 | 24 | class ScopedIndenter { 25 | public: 26 | ScopedIndenter() { 27 | get()++; 28 | } 29 | ~ScopedIndenter() { 30 | get()--; 31 | } 32 | 33 | int& get() { 34 | static thread_local int i = 0; 35 | return i; 36 | } 37 | 38 | std::string prefix() { 39 | return std::string(get() * 4, ' '); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /typed_python/SerializationContext.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include "WireType.hpp" 21 | 22 | class SerializationBuffer; 23 | class DeserializationBuffer; 24 | class Type; 25 | 26 | 27 | class SerializationContext { 28 | public: 29 | virtual ~SerializationContext() {}; 30 | 31 | virtual void serializePythonObject(PyObject* o, SerializationBuffer& b, size_t fieldNumber) const = 0; 32 | virtual PyObject* deserializePythonObject(DeserializationBuffer& b, size_t wireType) const = 0; 33 | 34 | virtual void serializeNativeType(Type* o, SerializationBuffer& b, size_t fieldNumber) const = 0; 35 | virtual Type* deserializeNativeType(DeserializationBuffer& b, size_t wireType) const = 0; 36 | 37 | virtual bool compressUsingThreads() const = 0; 38 | virtual bool serializePodListsInline() const = 0; 39 | virtual bool isCompressionEnabled() const = 0; 40 | virtual bool isLineInfoSuppressed() const = 0; 41 | }; 42 | -------------------------------------------------------------------------------- /typed_python/Slab.cpp: -------------------------------------------------------------------------------- 1 | #include "Slab.hpp" 2 | #include "Type.hpp" 3 | 4 | 5 | void Slab::free(void* data) { 6 | if (mIsFreeStore) { 7 | ::tp_free(data); 8 | } else { 9 | 10 | if (mTrackAllocTypes) { 11 | std::lock_guard lock(mAllocMutex); 12 | 13 | if (mAllocOrdering.find(data) == mAllocOrdering.end()) { 14 | throw std::runtime_error("Free of unknown alloc."); 15 | } 16 | 17 | if (mAliveAllocs.find(data) == mAliveAllocs.end()) { 18 | if (mAllocTypes.find(data) == mAllocTypes.end()) { 19 | throw std::runtime_error("Double free of alloc of unknown type."); 20 | } else { 21 | throw std::runtime_error("Double free of alloc of type " + mAllocTypes[data]->name()); 22 | } 23 | } 24 | 25 | mAliveAllocs.erase(data); 26 | } 27 | 28 | decref(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /typed_python/TypeDetails.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | class TypeDetails { 5 | public: 6 | static Type* getType() { throw std::runtime_error("specialize me");} 7 | 8 | static const uint64_t bytecount = 0; 9 | }; 10 | 11 | // Specialize this in specific Type files. 12 | 13 | -------------------------------------------------------------------------------- /typed_python/Unicode.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | inline size_t bytesForUtf8Codepoint(size_t codepoint) { 20 | if (codepoint < 0x80) { 21 | return 1; 22 | } 23 | if (codepoint < 0x800) { 24 | return 2; 25 | } 26 | if (codepoint < 0x10000) { 27 | return 3; 28 | } 29 | 30 | return 4; 31 | } 32 | 33 | template 34 | void encodeUtf8(codepoint_type* codepoints, int64_t sz, uint8_t* out) { 35 | for (long k = 0; k < sz; k++) { 36 | if (codepoints[k] < 0x80) { 37 | *(out++) = codepoints[k]; 38 | } else if (codepoints[k] < 0x800) { 39 | *(out++) = ((codepoints[k] & 0b11111000000) >> 6) + 0b11000000; 40 | *(out++) = ((codepoints[k] & 0b00000111111) ) + 0b10000000; 41 | } else if (codepoints[k] < 0x10000) { 42 | *(out++) = ((codepoints[k] & 0b1111000000000000) >> 12) + 0b11100000; 43 | *(out++) = ((codepoints[k] & 0b0000111111000000) >> 6 ) + 0b10000000; 44 | *(out++) = ((codepoints[k] & 0b0000000000111111) ) + 0b10000000; 45 | } else { 46 | *(out++) = ((codepoints[k] & 0b111000000000000000000) >> 18) + 0b11110000; 47 | *(out++) = ((codepoints[k] & 0b000111111000000000000) >> 12) + 0b10000000; 48 | *(out++) = ((codepoints[k] & 0b000000000111111000000) >> 6 ) + 0b10000000; 49 | *(out++) = ((codepoints[k] & 0b000000000000000111111) ) + 0b10000000; 50 | } 51 | } 52 | } 53 | 54 | template 55 | size_t countUtf8BytesRequiredFor(codepoint_type* codepoints, int64_t sz) { 56 | size_t result = 0; 57 | 58 | for (long k = 0; k < sz; k++) { 59 | result += bytesForUtf8Codepoint(codepoints[k]); 60 | } 61 | 62 | return result; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /typed_python/UnicodeProps.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #include 18 | 19 | // Include information about which unicode characters are considered 'alphanumeric' 20 | // etc, so we can match the various string functions. This behavior is dependent on which 21 | // python version we're using, so we have different includes for different versions. These are 22 | // generated by using 'pyenv' to build the relevant version, and then executing 'unicodeprops.py' 23 | // to generate the file. we could do this in setup.py, but that just seems overly complicated 24 | // and brittle. 25 | 26 | #if PY_MINOR_VERSION == 6 27 | # include "UnicodeProps_3.6.7.hpp" 28 | #else 29 | # include "UnicodeProps_3.7.4.hpp" 30 | #endif 31 | -------------------------------------------------------------------------------- /typed_python/ValueType.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2023 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #include "AllTypes.hpp" 18 | 19 | 20 | Value::Value(const Instance& instance) : 21 | Type(TypeCategory::catValue), 22 | mInstance(instance) 23 | { 24 | m_size = 0; 25 | m_is_default_constructible = true; 26 | 27 | if ( 28 | mInstance.type()->isPythonObjectOfType() && 29 | PyType_Check( 30 | PyObjectHandleTypeBase::getPyObj(mInstance.data()) 31 | ) 32 | ) { 33 | PyObject* obj = PyObjectHandleTypeBase::getPyObj(mInstance.data()); 34 | 35 | std::string name(((PyTypeObject*)obj)->tp_name); 36 | 37 | auto ix = name.rfind('.'); 38 | 39 | if (ix == std::string::npos) { 40 | ix = 0; 41 | } else { 42 | ix += 1; 43 | } 44 | 45 | m_name = "Value(" + name.substr(ix) + ")"; 46 | } else { 47 | m_name = mInstance.repr(); 48 | } 49 | 50 | m_doc = Value_doc; 51 | mValueAsPyobj = PyInstance::extractPythonObject(mInstance); 52 | endOfConstructorInitialization(); // finish initializing the type object. 53 | } 54 | -------------------------------------------------------------------------------- /typed_python/WireType.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include "Format.hpp" 21 | 22 | //every message in our serialization format starts with a 3-bit wire type 23 | //plus a field-number or a count (shifted by 3 bits) encoded as a varint. 24 | class WireType { 25 | public: 26 | enum { 27 | EMPTY = 0, //no content 28 | VARINT = 1, //the next value is a single varint 29 | BITS_32 = 2, //the next value is a 32-bit value 30 | BITS_64 = 3, //the next value is a 64-bit value 31 | BYTES = 4, //the next value is a varint encoding bytecount, followed by that many bytes bytes 32 | SINGLE = 5, //the next value is a single submessage (basically, COMPOUND but not needing an extra byte encoding the '1') 33 | BEGIN_COMPOUND = 6, //this value consists of a sequence of messages followed by a matching 'EndCompound' message 34 | END_COMPOUND = 7 //terminate a 'BEGIN_COMPOUND' 35 | }; 36 | }; 37 | 38 | inline void assertWireTypesEqual(size_t found, size_t expected) { 39 | if (found != expected) { 40 | throw std::runtime_error("Invalid wire type encountered: " + format(found) + " != " + format(expected)); 41 | } 42 | } 43 | 44 | inline void assertNonemptyCompoundWireType(size_t found) { 45 | if (found != WireType::BEGIN_COMPOUND && found != WireType::SINGLE) { 46 | throw std::runtime_error("Invalid wire type encountered: " + format(found) + " != 6 or 5"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /typed_python/_runtime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /typed_python/all.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright 2017-2019 typed_python Authors 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ******************************************************************************/ 16 | 17 | /***** 18 | a .cpp file that includes all the other .cpp files associated 19 | with the project implementation. 20 | 21 | So much code overlaps between the various translation units 22 | that there's no point splitting them up - its faster to just 23 | compile the entire group all at once. 24 | ******/ 25 | 26 | #include "_types.cpp" 27 | #include "_runtime.cpp" 28 | #include "Instance.cpp" 29 | #include "util.cpp" 30 | 31 | #include "PyInstance.cpp" 32 | #include "PyConstDictInstance.cpp" 33 | #include "PyDictInstance.cpp" 34 | #include "PyTupleOrListOfInstance.cpp" 35 | #include "PyPointerToInstance.cpp" 36 | #include "PyRefToInstance.cpp" 37 | #include "PyCompositeTypeInstance.cpp" 38 | #include "PyClassInstance.cpp" 39 | #include "PyAlternativeInstance.cpp" 40 | #include "PyFunctionInstance.cpp" 41 | #include "PyBoundMethodInstance.cpp" 42 | #include "PyGilState.cpp" 43 | #include "PySetInstance.cpp" 44 | 45 | #include "SubclassOfType.cpp" 46 | #include "SetType.cpp" 47 | #include "AlternativeType.cpp" 48 | #include "BytesType.cpp" 49 | #include "ClassType.cpp" 50 | #include "CompositeType.cpp" 51 | #include "ConcreteAlternativeType.cpp" 52 | #include "DictType.cpp" 53 | #include "ConstDictType.cpp" 54 | #include "HeldClassType.cpp" 55 | #include "OneOfType.cpp" 56 | #include "PythonObjectOfTypeType.cpp" 57 | #include "PythonSerializationContext.cpp" 58 | #include "PythonSerializationContext_serialization.cpp" 59 | #include "PythonSerializationContext_deserialization.cpp" 60 | #include "PythonSubclassType.cpp" 61 | #include "StringType.cpp" 62 | #include "TupleOrListOfType.cpp" 63 | #include "Type.cpp" 64 | #include "FunctionType.cpp" 65 | #include "ValueType.cpp" 66 | 67 | #include "SerializationBuffer.cpp" 68 | #include "DeserializationBuffer.cpp" 69 | #include "Sha1.cpp" 70 | #include "MutuallyRecursiveTypeGroup.cpp" 71 | #include "TypeOrPyobj.cpp" 72 | #include "Memory.cpp" 73 | #include "PySlab.cpp" 74 | #include "PyModuleRepresentation.cpp" 75 | #include "Slab.cpp" 76 | #include "PyTemporaryReferenceTracer.cpp" 77 | 78 | #include "lz4.c" 79 | #include "lz4frame.c" 80 | #include "lz4hc.c" 81 | #include "xxhash.c" 82 | -------------------------------------------------------------------------------- /typed_python/array/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APrioriInvestments/typed_python/81b856fa7bf3cb5c121b4e725cfbf5f403d60039/typed_python/array/__init__.py -------------------------------------------------------------------------------- /typed_python/compiler/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /typed_python/compiler/conversion_exception.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | class ConversionException(Exception): 17 | pass 18 | -------------------------------------------------------------------------------- /typed_python/compiler/function_metadata.py: -------------------------------------------------------------------------------- 1 | class FunctionMetadata: 2 | def __init__(self): 3 | self._constantReturnValue = () 4 | 5 | def setConstantReturnValue(self, value): 6 | self._constantReturnValue = (value,) 7 | 8 | def hasConstantReturnValue(self): 9 | return self._constantReturnValue 10 | 11 | def getConstantReturnValue(self): 12 | return self._constantReturnValue[0] if self._constantReturnValue else None 13 | -------------------------------------------------------------------------------- /typed_python/compiler/merge_type_wrappers_test.py: -------------------------------------------------------------------------------- 1 | from typed_python.compiler.merge_type_wrappers import mergeTypes 2 | from typed_python import OneOf, Value, Class 3 | 4 | 5 | class Base(Class): 6 | pass 7 | 8 | 9 | class Child(Base): 10 | pass 11 | 12 | 13 | def test_merge_types(): 14 | assert mergeTypes([float, int]) == OneOf(float, int) 15 | assert mergeTypes([float, Value(1)]) == OneOf(1, float) 16 | assert mergeTypes([float, Value(1.5)]) == float 17 | assert mergeTypes([OneOf(1, float), int]) == OneOf(float, int) 18 | assert mergeTypes([OneOf(float, Child), OneOf(int, Base)]) == OneOf(Base, float, int) 19 | assert mergeTypes([object, str]) == object 20 | assert mergeTypes([OneOf(str, None), object]) == object 21 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APrioriInvestments/typed_python/81b856fa7bf3cb5c121b4e725cfbf5f403d60039/typed_python/compiler/native_compiler/__init__.py -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/global_variable_definition.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import Alternative 16 | 17 | 18 | def pad(x): 19 | if len(x) < 100: 20 | return x 21 | return x[:100] + "..." 22 | 23 | 24 | def metadataRepr(self): 25 | kvs = {} 26 | 27 | for name in self.ElementType.ElementNames: 28 | kvs[name] = pad(repr(getattr(self, name))) 29 | 30 | return type(self).__name__ + "(" + ", ".join(f"{k}={v}" for k, v in kvs.items()) + ")" 31 | 32 | 33 | GlobalVariableMetadata = Alternative( 34 | "GlobalVariableMetadata", 35 | StringConstant=dict(value=str), 36 | BytesConstant=dict(value=bytes), 37 | IntegerConstant=dict(value=int), 38 | # a pointer to a PythonObjectOfType (e.g. our version, with 39 | # refcounts that are not in the GIL) 40 | PointerToPyObject=dict(value=object), 41 | # the raw ID of a global python object, like a builtin or 42 | # an exception 43 | IdOfPyObject=dict(value=object), 44 | # a pointer to the Type* in the underlying 45 | RawTypePointer=dict(value=type), 46 | PointerToTypedPythonObject=dict(value=object, type=type), 47 | # a typed python object at module scope (and therefore truly global) 48 | PointerToTypedPythonObjectAsMemberOfDict=dict( 49 | sourceDict=object, name=str, type=type 50 | ), 51 | ClassVtable=dict(value=type), 52 | ClassMethodDispatchSlot=dict( 53 | clsType=object, 54 | methodName=str, 55 | retType=object, 56 | argTupleType=object, 57 | kwargTupleType=object 58 | ), 59 | __repr__=metadataRepr 60 | ) 61 | 62 | 63 | class GlobalVariableDefinition: 64 | """Representation for a single globally defined value. 65 | 66 | Each such value has a formal name (which should be unique across 67 | all possible compiled value sets, so usually its a hash), a type, 68 | and some metadata indicating to the calling context what its for. 69 | """ 70 | def __init__(self, name, typ, metadata): 71 | """Initialize a GlobalVariableDefinition. 72 | 73 | Args: 74 | name - a string uniquely identifying the global variable 75 | typ - a native_ast type 76 | metadata - any 'value-like' python object we can use 77 | to identify the variable. 78 | """ 79 | self.name = name 80 | self.type = typ 81 | self.metadata = metadata 82 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/llvm_execution_engine.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import llvmlite.binding as llvm 16 | import llvmlite.ir 17 | import typed_python.compiler.native_compiler.native_ast_to_llvm_function_converter as \ 18 | native_ast_to_llvm_function_converter 19 | 20 | 21 | import ctypes 22 | from typed_python import _types 23 | 24 | llvm.initialize() 25 | llvm.initialize_native_target() 26 | llvm.initialize_native_asmprinter() # yes, even this one 27 | 28 | features = llvm.get_host_cpu_features() 29 | 30 | 31 | target_triple = llvm.get_process_triple() 32 | target = llvm.Target.from_triple(target_triple) 33 | target_machine = target.create_target_machine(features=features.flatten()) 34 | target_machine_shared_object = target.create_target_machine(reloc='pic', codemodel='default', features=features.flatten()) 35 | 36 | ctypes.CDLL(_types.__file__, mode=ctypes.RTLD_GLOBAL) 37 | 38 | 39 | pointer_size = ( 40 | llvmlite.ir.PointerType(llvmlite.ir.DoubleType()) 41 | .get_abi_size(target_machine.target_data) 42 | ) 43 | 44 | assert pointer_size == native_ast_to_llvm_function_converter.pointer_size 45 | 46 | 47 | def sizeof_native_type(native_type): 48 | if native_type.matches.Void: 49 | return 0 50 | 51 | return ( 52 | native_ast_to_llvm_function_converter.type_to_llvm_type(native_type) 53 | .get_abi_size(target_machine.target_data) 54 | ) 55 | 56 | 57 | # there can be only one llvm engine alive at once. 58 | _engineCache = [] 59 | 60 | 61 | def create_execution_engine(inlineThreshold): 62 | if _engineCache: 63 | return _engineCache[0] 64 | 65 | pmb = llvm.create_pass_manager_builder() 66 | pmb.opt_level = 3 67 | pmb.size_level = 0 68 | pmb.inlining_threshold = inlineThreshold 69 | pmb.loop_vectorize = True 70 | pmb.slp_vectorize = True 71 | 72 | pass_manager = llvm.create_module_pass_manager() 73 | pmb.populate(pass_manager) 74 | 75 | target_machine.add_analysis_passes(pass_manager) 76 | 77 | # And an execution engine with an empty backing module 78 | backing_mod = llvm.parse_assembly("") 79 | engine = llvm.create_mcjit_compiler(backing_mod, target_machine) 80 | 81 | _engineCache.append((engine, pass_manager)) 82 | 83 | return engine, pass_manager 84 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/module_definition.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import sha_hash 16 | 17 | 18 | class ModuleDefinition: 19 | """A single module of compiled llvm code. 20 | 21 | Members: 22 | moduleText - a string containing the llvm IR for the module 23 | functionList - a list of the names of exported functions 24 | globalDefinitions - a dict from name to a GlobalDefinition 25 | usedExternalFunctions - a set of symbols of functions that were compiled 26 | in different modules that we depend on. These will all be in some module. 27 | functionDefinitions - a dict from name to Function 28 | """ 29 | GET_GLOBAL_VARIABLES_NAME = ".get_global_variables" 30 | 31 | def __init__( 32 | self, 33 | moduleText, 34 | functionNameToType, 35 | globalVariableDefinitions, 36 | usedExternalFunctions, 37 | functionDefinitions 38 | ): 39 | self.moduleText = moduleText 40 | self.functionNameToType = functionNameToType 41 | self.globalVariableDefinitions = globalVariableDefinitions 42 | self.hash = sha_hash(moduleText) 43 | self.usedExternalFunctions = usedExternalFunctions 44 | self.functionDefinitions = functionDefinitions 45 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/native_ast_analysis.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | from typed_python import TupleOf, ListOf, Tuple, Dict, ConstDict, NamedTuple 17 | 18 | from typed_python.compiler.native_compiler.native_ast import ( 19 | Constant, 20 | Type, 21 | UnaryOp, 22 | BinaryOp, 23 | NamedCallTarget, 24 | Expression, 25 | Teardown, 26 | ExpressionIntermediate, 27 | CallTarget, 28 | FunctionBody, 29 | Function, 30 | GlobalVariableMetadata 31 | ) 32 | 33 | 34 | def visitAstChildren(node, callback): 35 | if not callback(node): 36 | return 37 | 38 | # don't look in these 39 | if isinstance(node, (UnaryOp, BinaryOp, Constant, Type, NamedCallTarget, GlobalVariableMetadata)): 40 | return 41 | 42 | if isinstance(node, (int, float, str, bytes, bool, type(None))): 43 | return 44 | 45 | if isinstance(node, Function): 46 | visitAstChildren(node.args, callback) 47 | visitAstChildren(node.body, callback) 48 | visitAstChildren(node.output_type, callback) 49 | return 50 | 51 | if isinstance(node, (Expression, Teardown, ExpressionIntermediate, CallTarget, FunctionBody)): 52 | for name in node.ElementType.ElementNames: 53 | visitAstChildren(getattr(node, name), callback) 54 | return 55 | 56 | if isinstance(node, (Dict, ConstDict, dict)): 57 | for k, v in node.items(): 58 | visitAstChildren(k, callback) 59 | visitAstChildren(v, callback) 60 | return 61 | 62 | if isinstance(node, (TupleOf, ListOf, tuple, list, Tuple, NamedTuple)): 63 | for child in node: 64 | visitAstChildren(child, callback) 65 | return 66 | 67 | raise Exception(f"Unexpected AST node of type {type(node).__name__}") 68 | 69 | 70 | def extractNamedCallTargets(ast): 71 | targets = set() 72 | 73 | def check(node): 74 | if isinstance(node, NamedCallTarget): 75 | targets.add(node) 76 | return True 77 | 78 | visitAstChildren(ast, check) 79 | 80 | return targets 81 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/native_ast_to_llvm_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.native_compiler.native_ast import ( 16 | Expression, Void, Int32, nullExpr, Function, FunctionBody, 17 | Teardown, const_int32_expr, CallTarget, NamedCallTarget 18 | ) 19 | import llvmlite.binding as llvm 20 | import typed_python.compiler.native_compiler.native_ast_to_llvm as native_ast_to_llvm 21 | import unittest 22 | 23 | 24 | def externalCallTarget(name, output, *inputs): 25 | return CallTarget.Named( 26 | target=NamedCallTarget( 27 | name=name, 28 | arg_types=inputs, 29 | output_type=output, 30 | external=True, 31 | varargs=False, 32 | intrinsic=False, 33 | can_throw=True 34 | ) 35 | ) 36 | 37 | 38 | class TestNativeAstToLlvm(unittest.TestCase): 39 | def test_teardowns(self): 40 | converter = native_ast_to_llvm.NativeAstToLlvmConverter() 41 | 42 | ct = externalCallTarget("thrower", Void) 43 | 44 | f = Function( 45 | args=[('a', Int32)], 46 | output_type=Void, 47 | body=FunctionBody.Internal( 48 | Expression.Finally( 49 | expr=( 50 | ct.call() >> 51 | Expression.ActivatesTeardown('a1') >> 52 | ct.call() >> 53 | Expression.ActivatesTeardown('a2') >> 54 | nullExpr 55 | ), 56 | teardowns=[ 57 | Teardown.ByTag(tag='a1', expr=Expression.Branch(cond=const_int32_expr(10), true=ct.call(), false=nullExpr)), 58 | Teardown.ByTag(tag='a1', expr=nullExpr) 59 | ] 60 | ) 61 | ) 62 | ) 63 | 64 | moduleDef = converter.add_functions({'f': f}) 65 | mod = llvm.parse_assembly(moduleDef.moduleText) 66 | mod.verify() 67 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/native_function_pointer.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import typed_python.compiler.native_compiler.native_ast as native_ast 3 | from typed_python import PointerTo 4 | 5 | 6 | class NativeFunctionPointer: 7 | def __init__(self, fname, fp, input_types, output_type): 8 | self.fp = fp 9 | self.fname = fname 10 | self.input_types = input_types 11 | self.output_type = output_type 12 | 13 | def __repr__(self): 14 | return "NativeFunctionPointer(name=%s,addr=%x,in=%s,out=%s)" \ 15 | % (self.fname, self.fp, [str(x) for x in self.input_types], str(self.output_type)) 16 | 17 | def __call__(self, *args): 18 | """Attempt to call the function directly from python. 19 | 20 | We only allow very simple transformations and types - PointerTo, ints, and floats. 21 | """ 22 | def mapToCtype(T): 23 | if T == native_ast.Void: 24 | return None 25 | 26 | if T == native_ast.Int64: 27 | return ctypes.c_long 28 | 29 | if T == native_ast.Float64: 30 | return ctypes.c_double 31 | 32 | if T.matches.Pointer: 33 | return ctypes.c_void_p 34 | 35 | raise Exception(f"Can't convert {T} to a ctypes type") 36 | 37 | def mapArg(a): 38 | if isinstance(a, (int, float)): 39 | return a 40 | 41 | if isinstance(a, PointerTo): 42 | return int(a) 43 | 44 | raise Exception(f"Can't convert {a} to a ctypes argument") 45 | 46 | # it should be initialized to zero 47 | func = ctypes.CFUNCTYPE( 48 | mapToCtype(self.output_type), 49 | *[mapToCtype(t) for t in self.input_types] 50 | )(self.fp) 51 | 52 | # get out the pointer table 53 | return func(*[mapArg(a) for a in args]) 54 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/typed_call_target.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import typed_python.compiler.native_compiler.native_ast as native_ast 16 | from typed_python.compiler.function_metadata import FunctionMetadata 17 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 18 | 19 | 20 | class TypedCallTarget: 21 | def __init__(self, named_call_target, input_types, output_type, alwaysRaises=False, functionMetadata=None): 22 | super().__init__() 23 | 24 | assert isinstance(output_type, Wrapper) or output_type is None 25 | assert isinstance(named_call_target, native_ast.NamedCallTarget) 26 | 27 | assert named_call_target.name != "throws" 28 | 29 | # if we know _ahead of time_ that this will always throw an exception 30 | self.alwaysRaises = alwaysRaises 31 | 32 | self.named_call_target = named_call_target 33 | self.input_types = input_types 34 | self.output_type = output_type 35 | self.functionMetadata = functionMetadata or FunctionMetadata() 36 | 37 | def call(self, *args): 38 | return native_ast.CallTarget.Named(target=self.named_call_target).call(*args) 39 | 40 | @property 41 | def name(self): 42 | return self.named_call_target.name 43 | 44 | def __str__(self): 45 | return "TypedCallTarget(name=%s,inputs=%s,outputs=%s)" % ( 46 | self.name, 47 | [str(x) for x in self.input_types], 48 | str(self.output_type) 49 | ) 50 | -------------------------------------------------------------------------------- /typed_python/compiler/native_compiler/typed_llvm_value.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2023 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | 18 | 19 | class TypedLLVMValue: 20 | def __init__(self, llvm_value, native_type): 21 | object.__init__(self) 22 | 23 | assert isinstance(native_type, native_ast.Type) 24 | 25 | if native_type.matches.Void: 26 | assert llvm_value is None 27 | else: 28 | assert llvm_value is not None 29 | 30 | self.llvm_value = llvm_value 31 | self.native_type = native_type 32 | 33 | def __str__(self): 34 | return "TypedLLVMValue(%s)" % self.native_type 35 | 36 | def __repr__(self): 37 | return str(self) 38 | -------------------------------------------------------------------------------- /typed_python/compiler/runtime_lock.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import threading 16 | 17 | runtimeLock = threading.RLock() 18 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APrioriInvestments/typed_python/81b856fa7bf3cb5c121b4e725cfbf5f403d60039/typed_python/compiler/tests/__init__.py -------------------------------------------------------------------------------- /typed_python/compiler/tests/any_all_compilation_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2023 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import Entrypoint, TupleOf 16 | 17 | 18 | def test_compiles_any_and_all(): 19 | @Entrypoint 20 | def callAny(x): 21 | return any(x) 22 | 23 | @Entrypoint 24 | def callAll(x): 25 | return all(x) 26 | 27 | assert callAll.resultTypeFor(list).typeRepresentation is bool 28 | assert callAny.resultTypeFor(list).typeRepresentation is bool 29 | 30 | for T in [list, TupleOf(int)]: 31 | assert callAny(T([1, 2, 3])) == any(T([1, 2, 3])) 32 | assert callAll(T([1, 2, 3])) == all(T([1, 2, 3])) 33 | assert callAny(T([0, 0, 0])) == any(T([0, 0, 0])) 34 | assert callAll(T([0, 0, 0])) == all(T([0, 0, 0])) 35 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/compilable_builtin_test.py: -------------------------------------------------------------------------------- 1 | from typed_python import Entrypoint 2 | from typed_python.compiler.type_wrappers.compilable_builtin import CompilableBuiltin 3 | from typed_python.compiler.type_wrappers.runtime_functions import externalCallTarget, Float64 4 | 5 | 6 | inlineLlvmFunc = externalCallTarget("inlineLlvmFunc", Float64, Float64, inlineLlvmDefinition=""" 7 | define external double @"inlineLlvmFunc"(double %".1") { 8 | entry: 9 | %.4 = fadd double %.1, 1.000000e+00 10 | ret double %.4 11 | } 12 | """) 13 | 14 | 15 | class InlineLlvmFunc(CompilableBuiltin): 16 | def __eq__(self, other): 17 | return isinstance(other, InlineLlvmFunc) 18 | 19 | def __hash__(self): 20 | return hash("InlineLlvmFunc") 21 | 22 | def convert_call(self, context, instance, args, kwargs): 23 | return context.pushPod( 24 | float, 25 | inlineLlvmFunc.call( 26 | args[0], 27 | ) 28 | ) 29 | 30 | 31 | def test_inline_llvm(): 32 | @Entrypoint 33 | def f(x): 34 | return InlineLlvmFunc()(x) 35 | 36 | assert f(2.5) == 3.5 37 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/compiling_type_operations_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import OneOf, ListOf, Int32 16 | from typed_python.compiler.runtime import Entrypoint 17 | import unittest 18 | 19 | 20 | class TestCompilingTypeOperations(unittest.TestCase): 21 | def test_can_make_new_types(self): 22 | @Entrypoint 23 | def f(x): 24 | result = ListOf(OneOf(None, type(x)))() 25 | result.append(x) 26 | return result 27 | 28 | self.assertEqual( 29 | type(f(10)).ElementType, 30 | OneOf(None, int) 31 | ) 32 | 33 | def test_stringification_of_type(self): 34 | @Entrypoint 35 | def f(x): 36 | return str(x) 37 | 38 | def check(T): 39 | self.assertEqual(f(T), str(T)) 40 | 41 | for typ in [ 42 | str, int, Int32, int, float, bool, float, 43 | type(None), ListOf(int), ListOf(OneOf(int, float)) 44 | ]: 45 | check(typ) 46 | 47 | def test_type_of(self): 48 | @Entrypoint 49 | def f(x): 50 | return type(x) 51 | 52 | self.assertEqual(f(10), int) 53 | self.assertEqual(f(10.5), float) 54 | self.assertEqual(f(Int32(10)), Int32) 55 | 56 | def test_type_of_list_of_int(self): 57 | def f(x): 58 | return type(x).ElementType is int 59 | 60 | self.assertTrue(f(ListOf(int)())) 61 | self.assertTrue(Entrypoint(f)(ListOf(int)())) 62 | 63 | def test_type_invalid_member_accesses(self): 64 | @Entrypoint 65 | def f(): 66 | ListOf(int).notAMember 67 | 68 | with self.assertRaisesRegex(AttributeError, "has no attribute 'notAMember'"): 69 | f() 70 | 71 | def test_type_invalid_unbound_member_call(self): 72 | @Entrypoint 73 | def f(): 74 | ListOf(int).append(10) 75 | 76 | with self.assertRaisesRegex(TypeError, "requires a '.*' object but received"): 77 | f() 78 | 79 | def test_type_valid_unbound_member_call(self): 80 | @Entrypoint 81 | def f(x): 82 | ListOf(int).append(x, 10) 83 | 84 | aList = ListOf(int)() 85 | f(aList) 86 | 87 | self.assertEqual(aList, [10]) 88 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/isinstance_compilation_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import OneOf, TupleOf 16 | 17 | from typed_python import Entrypoint 18 | import unittest 19 | 20 | 21 | class TestIsinstanceCompilation(unittest.TestCase): 22 | def test_basic_isinstance(self): 23 | @Entrypoint 24 | def isInt(x): 25 | return isinstance(x, int) 26 | 27 | self.assertTrue(isInt(0)) 28 | self.assertFalse(isInt(1.0)) 29 | self.assertFalse(isInt("hi")) 30 | 31 | def test_isinstance_with_oneof(self): 32 | @Entrypoint 33 | def isIntOneOf(x: OneOf(int, float)): 34 | return isinstance(x, int) 35 | 36 | self.assertTrue(isIntOneOf(0)) 37 | self.assertFalse(isIntOneOf(1.0)) 38 | 39 | def test_isinstance_with_oneof_and_str(self): 40 | @Entrypoint 41 | def isStrOneOf(x: OneOf(int, str)): 42 | return isinstance(x, str) 43 | 44 | self.assertFalse(isStrOneOf(0)) 45 | self.assertTrue(isStrOneOf("1.0")) 46 | 47 | def test_isinstance_with_value(self): 48 | @Entrypoint 49 | def isIntValue(x: OneOf(0, 1.0)): 50 | return isinstance(x, int) 51 | 52 | self.assertTrue(isIntValue(0)) 53 | self.assertFalse(isIntValue(1.0)) 54 | 55 | def test_isinstance_complex(self): 56 | @Entrypoint 57 | def isTupleOfInt(x): 58 | return isinstance(x, TupleOf(int)) 59 | 60 | self.assertFalse(isTupleOfInt(0)) 61 | self.assertFalse(isTupleOfInt((1, 2))) 62 | self.assertTrue(isTupleOfInt(TupleOf(int)((1, 2)))) 63 | 64 | def test_isinstance_typeof_none(self): 65 | @Entrypoint 66 | def isNone(x): 67 | return isinstance(x, type(None)) 68 | 69 | self.assertFalse(isNone(0)) 70 | self.assertTrue(isNone(None)) 71 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/numpy_interaction_test.py: -------------------------------------------------------------------------------- 1 | from typed_python import ListOf, Entrypoint 2 | import numpy 3 | import numpy.linalg 4 | 5 | 6 | def test_convert_list_to_numpy_array(): 7 | aList = ListOf(int)(range(20)) 8 | assert isinstance(aList.toArray(), numpy.ndarray) 9 | 10 | 11 | def test_can_add_numpy_arrays_in_compiled_code(): 12 | @Entrypoint 13 | def add(x): 14 | return x + x 15 | 16 | assert isinstance(add(numpy.ones(10)), numpy.ndarray) 17 | 18 | 19 | def test_can_call_numpy_builtins_from_compiled_code(): 20 | @Entrypoint 21 | def callSin(x): 22 | return numpy.sin(x) 23 | 24 | assert isinstance(callSin(numpy.ones(10).cumsum()), numpy.ndarray) 25 | 26 | @Entrypoint 27 | def callF(f, x): 28 | return f(x) 29 | 30 | assert isinstance(callF(numpy.sin, numpy.ones(10).cumsum()), numpy.ndarray) 31 | 32 | 33 | def test_can_call_numpy_matrix_funs(): 34 | @Entrypoint 35 | def callDiagonal(x): 36 | a = numpy.identity(10) 37 | return numpy.diagonal(a) 38 | 39 | assert callDiagonal(10).tolist() == [1 for _ in range(10)] 40 | 41 | 42 | def test_listof_from_sliced_numpy_array(): 43 | x = numpy.array((0, 1, 2)) 44 | y = x[::2] 45 | 46 | assert ListOf(int)(y) == [0, 2] 47 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/subclass_of_test.py: -------------------------------------------------------------------------------- 1 | from typed_python import Entrypoint, SubclassOf, Class, Final, Function, ListOf 2 | 3 | 4 | class A(Class): 5 | pass 6 | 7 | 8 | class B(A): 9 | pass 10 | 11 | 12 | class C(B, Final): 13 | pass 14 | 15 | 16 | def test_can_cast_subclass_of_correctly(): 17 | @Function 18 | def f(c: SubclassOf(C)): 19 | return "C" 20 | 21 | @f.overload 22 | def f(c: SubclassOf(B)): 23 | return "B" 24 | 25 | @f.overload 26 | def f(c: SubclassOf(A)): 27 | return "A" 28 | 29 | def checkIt(): 30 | assert f(C) == "C", f(C) 31 | assert f(B) == "B", f(B) 32 | assert f(A) == "A", f(A) 33 | 34 | checkIt() 35 | 36 | Entrypoint(checkIt)() 37 | 38 | @Entrypoint 39 | def checkItList(x): 40 | res = ListOf(str)() 41 | 42 | for cls in x: 43 | res.append(f(cls)) 44 | 45 | return res 46 | 47 | assert checkItList(ListOf(SubclassOf(A))([A, B, C])) == ["A", "B", "C"] 48 | assert checkItList(ListOf(SubclassOf(B))([B, C])) == ["B", "C"] 49 | assert checkItList(ListOf(SubclassOf(C))([C])) == ["C"] 50 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/time_compilation_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2023 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import ( 16 | Entrypoint 17 | ) 18 | import time 19 | 20 | 21 | def test_knows_its_a_float(): 22 | @Entrypoint 23 | def callTime(): 24 | return time.time() 25 | 26 | assert callTime.resultTypeFor().typeRepresentation is float 27 | callTime() 28 | 29 | assert abs(callTime() - time.time()) < 0.001 30 | 31 | 32 | def test_call_perf(): 33 | @Entrypoint 34 | def callTimeNTimes(times): 35 | elapsed = 0.0 36 | t0 = time.time() 37 | 38 | for _ in range(times): 39 | t1 = time.time() 40 | 41 | elapsed += t1 - t0 42 | t0 = t1 43 | 44 | return elapsed 45 | 46 | callTimeNTimes(1) 47 | 48 | t0 = time.time() 49 | estElapsed = callTimeNTimes(10000000) 50 | t1 = time.time() 51 | 52 | elapsedAct = t1 - t0 53 | 54 | print(estElapsed, elapsedAct) 55 | 56 | assert .8 < estElapsed / elapsedAct < 1.2 57 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/type_function_compilation_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import TypeFunction, Entrypoint, ListOf, Value, TupleOf 16 | import unittest 17 | 18 | 19 | class CompileTypeFunctionTest(unittest.TestCase): 20 | def test_basic(self): 21 | @TypeFunction 22 | def List(T): 23 | return ListOf(T) 24 | 25 | @Entrypoint 26 | def canInferType(T): 27 | return List(T) 28 | 29 | self.assertEqual( 30 | canInferType.resultTypeFor(Value(int)).typeRepresentation.Value, 31 | ListOf(int) 32 | ) 33 | 34 | def test_pass_type_function_as_value(self): 35 | @TypeFunction 36 | def List(T): 37 | return ListOf(T) 38 | 39 | @Entrypoint 40 | def inferType(TF, T): 41 | return TF(T) 42 | 43 | self.assertEqual( 44 | inferType.resultTypeFor(Value(List), Value(int)).typeRepresentation.Value, 45 | ListOf(int) 46 | ) 47 | 48 | self.assertEqual(inferType(List, int), ListOf(int)) 49 | 50 | def test_instantiating_type_function_value(self): 51 | @TypeFunction 52 | def List(T): 53 | return ListOf(T) 54 | 55 | @Entrypoint 56 | def convertToList(aContainer, TF): 57 | T = type(aContainer).ElementType 58 | MyList = TF(T) 59 | assert MyList == ListOf(T) 60 | return MyList() 61 | 62 | self.assertEqual( 63 | type(convertToList(TupleOf(int)(), List)), 64 | ListOf(int) 65 | ) 66 | 67 | self.assertEqual( 68 | convertToList.resultTypeFor(TupleOf(int), Value(List)).typeRepresentation, 69 | ListOf(int) 70 | ) 71 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/type_of_instances_compilation_test.py: -------------------------------------------------------------------------------- 1 | from typed_python import Entrypoint, Alternative, Class 2 | 3 | 4 | def test_type_of_class_is_specific(): 5 | class C(Class): 6 | pass 7 | 8 | class B(C): 9 | pass 10 | 11 | @Entrypoint 12 | def typeOfArg(x: C): 13 | return type(x) 14 | 15 | assert typeOfArg(B()) is B 16 | 17 | 18 | def test_type_of_alternative_is_specific(): 19 | for members in [{}, {'a': int}]: 20 | A = Alternative("A", A=members) 21 | 22 | @Entrypoint 23 | def typeOfArg(x: A): 24 | return type(x) 25 | 26 | assert typeOfArg(A.A()) is A.A 27 | 28 | 29 | def test_type_of_concrete_alternative_is_specific(): 30 | for members in [{}, {'a': int}]: 31 | A = Alternative("A", A=members) 32 | 33 | @Entrypoint 34 | def typeOfArg(x: A.A): 35 | return type(x) 36 | 37 | assert typeOfArg(A.A()) is A.A 38 | 39 | 40 | def test_type_name(): 41 | A = Alternative("A", X=dict(x=int), Y=dict(y=int)) 42 | 43 | class C(Class): 44 | pass 45 | 46 | class B(C): 47 | pass 48 | 49 | @Entrypoint 50 | def typenameOfAInst(a: A): 51 | return type(a).__name__ 52 | 53 | assert typenameOfAInst(A.X()) == 'X' 54 | assert typenameOfAInst(A.Y()) == 'Y' 55 | assert typenameOfAInst.resultTypeFor(A.X).typeRepresentation is str 56 | 57 | @Entrypoint 58 | def typenameOfCInst(c: C): 59 | return type(c).__name__ 60 | 61 | assert typenameOfCInst(C()) == 'C' 62 | assert typenameOfCInst(B()) == 'B' 63 | assert typenameOfAInst.resultTypeFor(A.X).typeRepresentation is str 64 | -------------------------------------------------------------------------------- /typed_python/compiler/tests/typed_function_compilation_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from typed_python import Function, Entrypoint 3 | 4 | 5 | class TestCompileTypedFunctions(unittest.TestCase): 6 | def test_compile_function_with_no_ret_type(self): 7 | # this function definitely throws, and so it doesn't 8 | # have a return type. 9 | @Function 10 | def f(x: int): 11 | raise Exception("an exception") 12 | 13 | @Entrypoint 14 | def callF(x: object): 15 | return f(x) 16 | 17 | with self.assertRaisesRegex(Exception, "an exception"): 18 | callF(10) 19 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/abs_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | 18 | 19 | class AbsWrapper(Wrapper): 20 | is_pod = True 21 | is_empty = False 22 | is_pass_by_ref = False 23 | 24 | def __init__(self): 25 | super().__init__(abs) 26 | 27 | def getNativeLayoutType(self): 28 | return native_ast.Type.Struct() 29 | 30 | def convert_call(self, context, expr, args, kwargs): 31 | if len(args) == 1 and not kwargs: 32 | return args[0].convert_abs() 33 | 34 | return super().convert_call(context, expr, args, kwargs) 35 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/all_any_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | 18 | 19 | def all(iterable): 20 | for a in iterable: 21 | if not a: 22 | return False 23 | 24 | return True 25 | 26 | 27 | def any(iterable): 28 | for a in iterable: 29 | if a: 30 | return True 31 | 32 | return False 33 | 34 | 35 | class AllWrapper(Wrapper): 36 | is_pod = True 37 | is_empty = False 38 | is_pass_by_ref = False 39 | 40 | def __init__(self): 41 | super().__init__(print) 42 | 43 | def getNativeLayoutType(self): 44 | return native_ast.Type.Struct() 45 | 46 | def convert_call(self, context, expr, args, kwargs): 47 | return context.call_py_function(all, args, kwargs) 48 | 49 | 50 | class AnyWrapper(Wrapper): 51 | is_pod = True 52 | is_empty = False 53 | is_pass_by_ref = False 54 | 55 | def __init__(self): 56 | super().__init__(print) 57 | 58 | def getNativeLayoutType(self): 59 | return native_ast.Type.Struct() 60 | 61 | def convert_call(self, context, expr, args, kwargs): 62 | return context.call_py_function(all, args, kwargs) 63 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/builtin_wrappers.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and:w 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | 18 | from math import trunc, floor, ceil 19 | 20 | 21 | class BuiltinWrapper(Wrapper): 22 | is_pod = True 23 | is_empty = False 24 | is_pass_by_ref = False 25 | 26 | SUPPORTED_FUNCTIONS = (round, trunc, floor, ceil, format, dir, ord, chr) 27 | 28 | def __init__(self, builtin): 29 | assert builtin in self.SUPPORTED_FUNCTIONS 30 | super().__init__(builtin) 31 | 32 | def getNativeLayoutType(self): 33 | return native_ast.Type.Void() 34 | 35 | def convert_call(self, context, expr, args, kwargs): 36 | builtin = self.typeRepresentation 37 | 38 | if len(args) == 1 and not kwargs: 39 | return args[0].convert_builtin(builtin) 40 | 41 | # builtins that optionally have a second parameter: 42 | if builtin in [round, format] and len(args) == 2 and not kwargs: 43 | return args[0].convert_builtin(builtin, args[1]) 44 | 45 | return super().convert_call(context, expr, args, kwargs) 46 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/bytecount_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | from typed_python.compiler.type_wrappers.python_type_object_wrapper import PythonTypeObjectWrapper 17 | import typed_python.compiler.native_compiler.native_ast as native_ast 18 | from typed_python._types import bytecount 19 | 20 | 21 | class BytecountWrapper(Wrapper): 22 | is_pod = True 23 | is_empty = False 24 | is_pass_by_ref = False 25 | 26 | def __init__(self): 27 | super().__init__(bytecount) 28 | 29 | def getNativeLayoutType(self): 30 | return native_ast.Type.Struct() 31 | 32 | def convert_call(self, context, expr, args, kwargs): 33 | if len(args) == 1 and isinstance(args[0].expr_type, PythonTypeObjectWrapper) and not kwargs: 34 | return context.constant(bytecount(args[0].expr_type.typeRepresentation.Value)) 35 | 36 | return super().convert_call(context, expr, args, kwargs) 37 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/compilable_builtin.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | from typed_python.compiler.native_compiler import native_ast 17 | 18 | import typed_python 19 | 20 | 21 | class CompilableBuiltin(Wrapper): 22 | """Base class for Wrappers that expose _themselves_. 23 | 24 | We use this class to easily create constants that can generate code in the 25 | converter. 26 | 27 | For instance, 28 | 29 | class SomeCodeGenerator(CompilableBuiltin): 30 | def convert_call(self, context, instance, args, kwargs): 31 | ... 32 | 33 | def someFunctionThatIsNativeCompiledOnly(x): 34 | 35 | ... 36 | # this will dispatch to the 'convert_call' above. 37 | return SomeCodeGenerator()(x) 38 | """ 39 | is_pod = True 40 | is_empty = True 41 | is_pass_by_ref = False 42 | is_compile_time_constant = True 43 | 44 | def __init__(self): 45 | super().__init__(type(None)) 46 | 47 | def getNativeLayoutType(self): 48 | return native_ast.Type.Struct() 49 | 50 | def getCompileTimeConstant(self): 51 | return self 52 | 53 | def __eq__(self, other): 54 | raise NotImplementedError(self) 55 | 56 | @property 57 | def __name__(self): 58 | return str(self) 59 | 60 | def __hash__(self): 61 | raise NotImplementedError(self) 62 | 63 | def __str__(self): 64 | return type(self).__qualname__ 65 | 66 | def __repr__(self): 67 | return type(self).__qualname__ 68 | 69 | @classmethod 70 | def convert_type_call(cls, context, typeInst, args, kwargs): 71 | if ( 72 | all(a.isConstant for a in args) 73 | and all(v.isConstant for v in kwargs.values()) 74 | ): 75 | tw = cls( 76 | *[a.constantValue for a in args], 77 | **{k: v.constantValue for k, v in kwargs.items()} 78 | ) 79 | 80 | return typed_python.compiler.python_object_representation.pythonObjectRepresentation(context, tw) 81 | 82 | raise Exception( 83 | f"Can't initialize {cls} with args {args} and {kwargs}" 84 | f" because they're not all compile time constants" 85 | ) 86 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/compiler_introspection_wrappers.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.internals import ( 16 | isCompiled, 17 | typeKnownToCompiler, 18 | localVariableTypesKnownToCompiler 19 | ) 20 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 21 | import typed_python.compiler.native_compiler.native_ast as native_ast 22 | import typed_python 23 | 24 | 25 | class IsCompiledWrapper(Wrapper): 26 | is_pod = True 27 | is_empty = False 28 | is_pass_by_ref = False 29 | 30 | def __init__(self): 31 | super().__init__(isCompiled) 32 | 33 | def getNativeLayoutType(self): 34 | return native_ast.Type.Struct() 35 | 36 | def convert_call(self, context, expr, args, kwargs): 37 | if args or kwargs: 38 | context.pushException(TypeError, "isCompiled() accepts no arguments") 39 | 40 | return context.constant(True) 41 | 42 | 43 | class TypeKnownToCompiler(Wrapper): 44 | is_pod = True 45 | is_empty = False 46 | is_pass_by_ref = False 47 | 48 | def __init__(self): 49 | super().__init__(typeKnownToCompiler) 50 | 51 | def getNativeLayoutType(self): 52 | return native_ast.Type.Struct() 53 | 54 | def convert_call(self, context, expr, args, kwargs): 55 | if len(args) != 1 or kwargs: 56 | context.pushException(TypeError, "typeKnownToCompiler() accepts 1 positional argument") 57 | 58 | return typed_python.compiler.python_object_representation.pythonObjectRepresentation( 59 | context, 60 | args[0].expr_type.typeRepresentation 61 | ) 62 | 63 | 64 | class LocalVariableTypesKnownToCompiler(Wrapper): 65 | is_pod = True 66 | is_empty = False 67 | is_pass_by_ref = False 68 | 69 | def __init__(self): 70 | super().__init__(localVariableTypesKnownToCompiler) 71 | 72 | def getNativeLayoutType(self): 73 | return native_ast.Type.Struct() 74 | 75 | def convert_call(self, context, expr, args, kwargs): 76 | if args or kwargs: 77 | context.pushException(TypeError, "localVariableTypesKnownToCompiler() accepts no arguments") 78 | 79 | return context.constant(dict(context.variableStates._types), allowArbitrary=True) 80 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/compiler_type.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.compilable_builtin import CompilableBuiltin 16 | 17 | 18 | class CompilerType(CompilableBuiltin): 19 | """A builtin for determing the type of a variable as known to the compiler.""" 20 | def __eq__(self, other): 21 | return isinstance(other, CompilerType) 22 | 23 | def __hash__(self): 24 | return hash("CompilerType") 25 | 26 | def __call__(self, x): 27 | return "" 28 | 29 | def convert_call(self, context, expr, args, kwargs): 30 | if len(args) != 1 or len(kwargs): 31 | context.pushException(TypeError, "CompilerType takes exactly one unnamed argument") 32 | return 33 | 34 | return context.constant(str(args[0].expr_type)) 35 | 36 | 37 | typeAsKnownToCompiler = CompilerType() 38 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/hasattr_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2023 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import time 15 | 16 | 17 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 18 | import typed_python.compiler.native_compiler.native_ast as native_ast 19 | 20 | 21 | class HasattrWrapper(Wrapper): 22 | is_pod = True 23 | is_empty = False 24 | is_pass_by_ref = False 25 | 26 | def __init__(self): 27 | super().__init__(time.time) 28 | 29 | def getNativeLayoutType(self): 30 | return native_ast.Type.Struct() 31 | 32 | def convert_call(self, context, expr, args, kwargs): 33 | if len(args) == 2 and len(kwargs) == 0: 34 | return args[0].convert_hasattr(args[1]) 35 | 36 | return expr.toPyObj().convert_call(args, kwargs).toBool() 37 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/hash_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | from typed_python import Int32 18 | 19 | 20 | def tp_hash_to_py_hash(hVal): 21 | """Convert a typed-python hash to a regular python hash. 22 | 23 | Python insists that its hash values are never -1, because it uses -1 as an 24 | indicator that the exception flag is set. TypedPython doesn't have this behavior 25 | because it uses c++ exception propagation internally. As a result, it's the 26 | 'hash' wrapper that's responsible for mapping -1 to -2. 27 | """ 28 | if hVal == -1: 29 | return Int32(-2) 30 | return hVal 31 | 32 | 33 | class HashWrapper(Wrapper): 34 | is_pod = True 35 | is_empty = False 36 | is_pass_by_ref = False 37 | 38 | def __init__(self): 39 | super().__init__(hash) 40 | 41 | def getNativeLayoutType(self): 42 | return native_ast.Type.Struct() 43 | 44 | def convert_call(self, context, expr, args, kwargs): 45 | if len(args) == 1 and not kwargs: 46 | hashVal = args[0].convert_hash() 47 | if hashVal is None: 48 | return None 49 | 50 | return context.call_py_function(tp_hash_to_py_hash, (hashVal,), {}) 51 | 52 | return super().convert_call(context, expr, args, kwargs) 53 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/isinstance_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | from typed_python import Class, Type 15 | from typed_python.compiler.native_compiler import native_ast 16 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 17 | 18 | 19 | def cannotBeSubclass(t1, t2): 20 | """Determine if 't1' cannot be a subclass of 't2'. 21 | 22 | In particular, most typed python types do not admit subclassing, and the only way 23 | two types can have a common child is if they are both Class objects and one has 24 | no members. 25 | """ 26 | # if one is a child of the other then this is obviously false 27 | if issubclass(t1, t2) or issubclass(t2, t1): 28 | return False 29 | 30 | # if either is a typed python type, but if neither is a Class object, 31 | # then its impossible for one to be a subclass of the other. 32 | if ( 33 | (issubclass(t1, Type) or issubclass(t2, Type)) 34 | and (not issubclass(t1, Class) or not issubclass(t2, Class)) 35 | ): 36 | return True 37 | 38 | if issubclass(t1, Class) and issubclass(t2, Class) and t1.MemberTypes and t2.MemberTypes: 39 | return True 40 | 41 | return False 42 | 43 | 44 | class IsinstanceWrapper(Wrapper): 45 | is_pod = True 46 | is_empty = False 47 | is_pass_by_ref = False 48 | 49 | def __init__(self): 50 | super().__init__(isinstance) 51 | 52 | def getNativeLayoutType(self): 53 | return native_ast.Type.Struct() 54 | 55 | @Wrapper.unwrapOneOfAndValue 56 | def convert_call(self, context, expr, args, kwargs): 57 | if len(args) == 2 and not kwargs: 58 | instance = args[0] 59 | typeObj = args[1] 60 | instanceType = instance.convert_typeof() 61 | 62 | return instanceType.convert_issubclass(typeObj, False) 63 | 64 | return super().convert_call(context, expr, args, kwargs) 65 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/issubclass_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.native_compiler import native_ast 16 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 17 | 18 | 19 | class IssubclassWrapper(Wrapper): 20 | is_pod = True 21 | is_empty = False 22 | is_pass_by_ref = False 23 | 24 | def __init__(self): 25 | super().__init__(issubclass) 26 | 27 | def getNativeLayoutType(self): 28 | return native_ast.Type.Struct() 29 | 30 | @Wrapper.unwrapOneOfAndValue 31 | def convert_call(self, context, expr, args, kwargs): 32 | if len(args) == 2 and not kwargs: 33 | return args[0].expr_type.convert_issubclass(context, args[0], args[1], True) 34 | 35 | return super().convert_call(context, expr, args, kwargs) 36 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/len_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | 18 | 19 | class LenWrapper(Wrapper): 20 | is_pod = True 21 | is_empty = False 22 | is_pass_by_ref = False 23 | 24 | def __init__(self): 25 | super().__init__(len) 26 | 27 | def getNativeLayoutType(self): 28 | return native_ast.Type.Struct() 29 | 30 | @Wrapper.unwrapOneOfAndValue 31 | def convert_call(self, context, expr, args, kwargs): 32 | if len(args) == 1 and not kwargs: 33 | return args[0].convert_len() 34 | 35 | return super().convert_call(context, expr, args, kwargs) 36 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/make_named_tuple_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import typed_python 16 | 17 | from typed_python import NamedTuple 18 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 19 | import typed_python.compiler.native_compiler.native_ast as native_ast 20 | 21 | 22 | typeWrapper = lambda x: typed_python.compiler.python_object_representation.typedPythonTypeToTypeWrapper(x) 23 | 24 | 25 | class MakeNamedTupleWrapper(Wrapper): 26 | is_pod = True 27 | is_empty = False 28 | is_pass_by_ref = False 29 | 30 | def __init__(self): 31 | super().__init__(len) 32 | 33 | def getNativeLayoutType(self): 34 | return native_ast.Type.Struct() 35 | 36 | def convert_call(self, context, expr, args, kwargs): 37 | if args: 38 | context.pushException(TypeError, f"makeNamedTuple takes 0 positional arguments but {len(args)} were given") 39 | 40 | argTypes = {k: v.expr_type.interpreterTypeRepresentation for k, v in kwargs.items()} 41 | 42 | namedTupleType = NamedTuple(**argTypes) 43 | 44 | return typeWrapper(namedTupleType).convert_type_call(context, expr, args, kwargs) 45 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/method_descriptor_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | import typed_python 18 | 19 | typeWrapper = lambda t: typed_python.compiler.python_object_representation.typedPythonTypeToTypeWrapper(t) 20 | 21 | 22 | class MethodDescriptorWrapper(Wrapper): 23 | is_pod = True 24 | is_empty = True 25 | is_pass_by_ref = False 26 | 27 | def __init__(self, f): 28 | super().__init__(f) 29 | 30 | self.clsType = f.__objclass__ 31 | self.methodName = f.__name__ 32 | 33 | def getNativeLayoutType(self): 34 | return native_ast.Type.Struct() 35 | 36 | def convert_call(self, context, left, args, kwargs): 37 | if not args: 38 | context.pushException( 39 | TypeError, 40 | f"descriptor '{self.methodName}' of '{self.clsType}' object needs an argument" 41 | ) 42 | return 43 | 44 | if args[0].expr_type != typeWrapper(self.clsType): 45 | context.pushException( 46 | TypeError, 47 | f"descriptor '{self.methodName}' requires a '{self.clsType}' object but " 48 | f"received a '{args[0].expr_type.typeRepresentation}'" 49 | ) 50 | return 51 | 52 | return args[0].convert_method_call(self.methodName, args[1:], kwargs) 53 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/module_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | from typed_python import Value 17 | import typed_python.compiler.native_compiler.native_ast as native_ast 18 | import typed_python.compiler 19 | 20 | typeWrapper = lambda t: typed_python.compiler.python_object_representation.typedPythonTypeToTypeWrapper(t) 21 | 22 | 23 | modulesToIgnore = set([ 24 | 'logging', 25 | 'traceback' 26 | ]) 27 | 28 | 29 | class ModuleWrapper(Wrapper): 30 | is_pod = True 31 | is_empty = False 32 | is_pass_by_ref = False 33 | 34 | def __init__(self, f): 35 | super().__init__(Value(f)) 36 | 37 | def getNativeLayoutType(self): 38 | return native_ast.Type.Struct() 39 | 40 | def convert_default_initialize(self, context, target): 41 | return context.constant(None) 42 | 43 | def convert_assign(self, context, target, toStore): 44 | return context.constant(None) 45 | 46 | def convert_copy_initialize(self, context, target, toStore): 47 | return context.constant(None) 48 | 49 | def convert_destroy(self, context, instance): 50 | return context.constant(None) 51 | 52 | def convert_attribute(self, context, instance, attribute): 53 | if not hasattr(self.typeRepresentation.Value, attribute): 54 | return context.pushException( 55 | AttributeError, 56 | "module '%s' has no attribute '%s'" % ( 57 | self.typeRepresentation.Value.__name__, 58 | attribute 59 | ) 60 | ) 61 | 62 | if self.typeRepresentation.Value.__name__ in modulesToIgnore: 63 | return instance.toPyObj().convert_attribute(attribute) 64 | 65 | return typed_python.compiler.python_object_representation.pythonObjectRepresentation( 66 | context, 67 | getattr(self.typeRepresentation.Value, attribute), 68 | ) 69 | 70 | def convert_typeof(self, context, instance): 71 | return typed_python.compiler.python_object_representation.pythonObjectRepresentation( 72 | context, 73 | type(self.typeRepresentation.Value) 74 | ) 75 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/print_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | from typed_python.compiler.type_wrappers.runtime_functions import print_string 18 | 19 | 20 | class PrintWrapper(Wrapper): 21 | is_pod = True 22 | is_empty = False 23 | is_pass_by_ref = False 24 | 25 | def __init__(self): 26 | super().__init__(print) 27 | 28 | def getNativeLayoutType(self): 29 | return native_ast.Type.Struct() 30 | 31 | def convert_call(self, context, expr, args, kwargs): 32 | sep = context.constant(" ") 33 | end = context.constant("\n") 34 | 35 | for kwargName, value in kwargs.items(): 36 | if kwargName == 'sep': 37 | sep = value.toStr() 38 | if sep is None: 39 | return 40 | elif kwargName == 'end': 41 | end = value.toStr() 42 | if end is None: 43 | return 44 | else: 45 | context.pushException(TypeError, f"'{kwargName}' is an invalid keyword argument for this function") 46 | return 47 | 48 | res = None 49 | 50 | # it would be better to use join 51 | for a in args: 52 | converted = a.toStr() 53 | if converted is None: 54 | return None 55 | 56 | if res is None: 57 | res = converted 58 | else: 59 | res = res + sep + converted 60 | 61 | if res is None: 62 | res = end 63 | else: 64 | res = res + end 65 | 66 | context.pushEffect(print_string.call(res.nonref_expr.cast(native_ast.VoidPtr))) 67 | 68 | return context.pushVoid() 69 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/python_free_function_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import Value 16 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 17 | import typed_python.compiler.native_compiler.native_ast as native_ast 18 | 19 | 20 | class PythonFreeFunctionWrapper(Wrapper): 21 | is_pod = True 22 | is_empty = True 23 | is_pass_by_ref = False 24 | 25 | def __init__(self, f): 26 | super().__init__(Value(f)) 27 | 28 | def getNativeLayoutType(self): 29 | return native_ast.Type.Struct() 30 | 31 | def convert_call(self, context, left, args, kwargs): 32 | return context.call_py_function(self.typeRepresentation.Value, args, kwargs) 33 | 34 | def convert_to_type_with_target(self, context, instance, targetVal, conversionLevel, mayThrowOnFailure=False): 35 | if targetVal.expr_type.typeRepresentation is object: 36 | targetVal.convert_copy_initialize( 37 | context.constant(self.typeRepresentation.Value, allowArbitrary=True) 38 | ) 39 | return context.constant(True) 40 | 41 | if conversionLevel.isNewOrHigher() and targetVal.expr_type.typeRepresentation is str: 42 | targetVal.convert_copy_initialize( 43 | context.constant(str(self.typeRepresentation.Value)) 44 | ) 45 | return context.constant(True) 46 | 47 | return super().convert_to_type_with_target(context, instance, targetVal, conversionLevel, mayThrowOnFailure) 48 | 49 | def convert_repr(self, context, instance): 50 | return context.constant(repr(self.typeRepresentation.Value)) 51 | 52 | def convert_typeof(self, context, instance): 53 | return context.constant(type(self.typeRepresentation.Value)) 54 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/range_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import NamedTuple, Class, Final, PointerTo 16 | from typed_python import pointerTo 17 | 18 | 19 | class Range(Class, Final, __name__='range'): 20 | def __repr__(self): 21 | return "" 22 | 23 | def __str__(self): 24 | return "" 25 | 26 | def __call__(self, stop): 27 | return RangeCls(start=0, stop=stop, step=1) 28 | 29 | def __call__(self, start, stop): # noqa 30 | return RangeCls(start=start, stop=stop, step=1) 31 | 32 | def __call__(self, start, stop, step): # noqa 33 | return RangeCls(start=start, stop=stop, step=step) 34 | 35 | 36 | range = Range() 37 | 38 | 39 | class RangeCls(NamedTuple(start=int, stop=int, step=int)): 40 | def __str__(self): 41 | return repr(self) 42 | 43 | def __repr__(self): 44 | if self.step == 1: 45 | return f"range({self.start}, {self.stop})" 46 | 47 | return f"range({self.start}, {self.stop}, {self.step})" 48 | 49 | def __iter__(self): 50 | return RangeIterator(start=self.start - self.step, stop=self.stop, step=self.step) 51 | 52 | def __typed_python_int_iter_size__(self): 53 | if self.step == 1: 54 | return self.stop - self.start 55 | 56 | if self.step > 0: 57 | return ((self.stop - self.start - 1) // self.step) + 1 58 | else: 59 | return ((self.start - self.stop - 1) // (-self.step)) + 1 60 | 61 | def __typed_python_int_iter_value__(self, x): 62 | return self.start + self.step * x 63 | 64 | 65 | class RangeIterator(NamedTuple(start=int, stop=int, step=int)): 66 | def __iter__(self) -> int: 67 | resPtr = self.__fastnext__() 68 | if resPtr: 69 | return resPtr.get() 70 | raise StopIteration() 71 | 72 | def __fastnext__(self) -> PointerTo(int): 73 | startPtr = pointerTo(self).start 74 | stopPtr = pointerTo(self).stop 75 | stepPtr = pointerTo(self).step 76 | 77 | startPtr.set(startPtr.get() + stepPtr.get()) 78 | 79 | if stepPtr.get() > 0: 80 | if startPtr.get() < stopPtr.get(): 81 | return startPtr 82 | else: 83 | if startPtr.get() > stopPtr.get(): 84 | return startPtr 85 | 86 | return PointerTo(int)() 87 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/repr_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 16 | import typed_python.compiler.native_compiler.native_ast as native_ast 17 | 18 | 19 | class ReprWrapper(Wrapper): 20 | is_pod = True 21 | is_empty = False 22 | is_pass_by_ref = False 23 | 24 | def __init__(self): 25 | super().__init__(len) 26 | 27 | def getNativeLayoutType(self): 28 | return native_ast.Type.Struct() 29 | 30 | def convert_call(self, context, expr, args, kwargs): 31 | if len(args) == 1 and not kwargs: 32 | return args[0].convert_repr() 33 | 34 | return super().convert_call(context, expr, args, kwargs) 35 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/slice_type_object_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import typed_python.compiler 16 | from typed_python import NamedTuple 17 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 18 | from typed_python.compiler.type_wrappers.python_type_object_wrapper import PythonTypeObjectWrapper 19 | from typed_python.compiler.type_wrappers.named_tuple_masquerading_as_slice import NamedTupleMasqueradingAsSlice 20 | 21 | typeWrapper = lambda t: typed_python.compiler.python_object_representation.typedPythonTypeToTypeWrapper(t) 22 | 23 | 24 | class SliceWrapper(PythonTypeObjectWrapper): 25 | def __init__(self): 26 | super().__init__(slice) 27 | 28 | def __repr__(self): 29 | return "SliceWrapper()" 30 | 31 | def __str__(self): 32 | return "SliceWrapper()" 33 | 34 | @Wrapper.unwrapOneOfAndValue 35 | def convert_call(self, context, left, args, kwargs): 36 | if kwargs: 37 | return context.pushException(TypeError, "slice() does not take keyword arguments") 38 | 39 | if len(args) > 3: 40 | return context.pushException(TypeError, f"slice() expected at most 3 arguments, got {len(args)}") 41 | 42 | if len(args) == 0: 43 | return context.pushException(TypeError, "slice() expected at least 1 argument, got 0") 44 | 45 | if len(args) == 1: 46 | args = [context.constant(None), args[0], context.constant(None)] 47 | 48 | while len(args) < 3: 49 | args = tuple(args) + (context.constant(None),) 50 | 51 | ntType = NamedTuple( 52 | start=args[0].expr_type.typeRepresentation, 53 | stop=args[1].expr_type.typeRepresentation, 54 | step=args[2].expr_type.typeRepresentation 55 | ) 56 | 57 | return typeWrapper(ntType).convert_type_call( 58 | context, 59 | None, 60 | [], 61 | dict(start=args[0], stop=args[1], step=args[2]) 62 | ).changeType( 63 | NamedTupleMasqueradingAsSlice(ntType) 64 | ) 65 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/time_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2023 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import time 15 | 16 | 17 | from typed_python.compiler.type_wrappers.wrapper import Wrapper 18 | import typed_python.compiler.native_compiler.native_ast as native_ast 19 | from typed_python.compiler.type_wrappers.runtime_functions import secondsSinceEpoch 20 | 21 | 22 | class TimeWrapper(Wrapper): 23 | is_pod = True 24 | is_empty = False 25 | is_pass_by_ref = False 26 | 27 | def __init__(self): 28 | super().__init__(time.time) 29 | 30 | def getNativeLayoutType(self): 31 | return native_ast.Type.Struct() 32 | 33 | def convert_call(self, context, expr, args, kwargs): 34 | return context.pushPod( 35 | float, 36 | secondsSinceEpoch.call() 37 | ) 38 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/type_sets.py: -------------------------------------------------------------------------------- 1 | class SubclassOf: 2 | def __init__(self, T): 3 | self.T = T 4 | 5 | def __getattr__(self, attr): 6 | return getattr(self.T, attr) 7 | 8 | 9 | class Either: 10 | def __init__(self, types): 11 | self.Types = types 12 | 13 | def __getattr__(self, attr): 14 | vals = [getattr(T, attr) for T in self.Types] 15 | 16 | if len(set(vals)) == 1: 17 | return vals[0] 18 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/typed_dict_masquerading_as_dict_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.masquerade_wrapper import MasqueradeWrapper 16 | 17 | 18 | class TypedDictMasqueradingAsDict(MasqueradeWrapper): 19 | def __init__(self, typeRepresentation): 20 | super().__init__(typeRepresentation) 21 | 22 | @property 23 | def interpreterTypeRepresentation(self): 24 | return dict 25 | 26 | def convert_masquerade_to_untyped(self, context, instance): 27 | return context.constant(dict).convert_call( 28 | [instance.convert_masquerade_to_typed()], 29 | {} 30 | ).changeType(dict) 31 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/typed_list_masquerading_as_list_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.masquerade_wrapper import MasqueradeWrapper 16 | 17 | 18 | class TypedListMasqueradingAsList(MasqueradeWrapper): 19 | def __init__(self, typeRepresentation): 20 | super().__init__(typeRepresentation) 21 | 22 | @property 23 | def interpreterTypeRepresentation(self): 24 | return list 25 | 26 | def convert_masquerade_to_untyped(self, context, instance): 27 | return context.constant(list).convert_call( 28 | [instance.convert_masquerade_to_typed()], 29 | {} 30 | ).changeType(list) 31 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/typed_set_masquerading_as_set_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python.compiler.type_wrappers.masquerade_wrapper import MasqueradeWrapper 16 | 17 | 18 | class TypedSetMasqueradingAsSet(MasqueradeWrapper): 19 | def __init__(self, typeRepresentation): 20 | super().__init__(typeRepresentation) 21 | 22 | @property 23 | def interpreterTypeRepresentation(self): 24 | return set 25 | 26 | def convert_masquerade_to_untyped(self, context, instance): 27 | return context.constant(set).convert_call( 28 | [instance.convert_masquerade_to_typed()], 29 | {} 30 | ).changeType(set) 31 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/typed_tuple_masquerading_as_tuple_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import typed_python 16 | 17 | from typed_python.compiler.type_wrappers.masquerade_wrapper import MasqueradeWrapper 18 | 19 | typeWrapper = lambda t: typed_python.compiler.python_object_representation.typedPythonTypeToTypeWrapper(t) 20 | 21 | 22 | class TypedTupleMasqueradingAsTuple(MasqueradeWrapper): 23 | """Models a 'NamedTuple' that's masquerading as a 'dict' for use in **kwargs.""" 24 | 25 | def __init__(self, typeRepresentation, interiorTypeWrappers=None): 26 | super().__init__(typeRepresentation) 27 | self.interiorTypeWrappers = tuple(interiorTypeWrappers) if interiorTypeWrappers is not None else None 28 | 29 | def __hash__(self): 30 | return hash( 31 | (type(self), self.typeRepresentation, self.interiorTypeWrappers) 32 | ) 33 | 34 | def __eq__(self, other): 35 | if type(self) != type(other): 36 | return False 37 | 38 | return ( 39 | self.typeRepresentation == other.typeRepresentation 40 | and self.interiorTypeWrappers == other.interiorTypeWrappers 41 | ) 42 | 43 | @property 44 | def interpreterTypeRepresentation(self): 45 | return tuple 46 | 47 | def convert_getitem(self, context, instance, index): 48 | actualRes = super().convert_getitem(context, instance, index) 49 | 50 | if actualRes is None: 51 | return None 52 | 53 | if ( 54 | index.isConstant 55 | and isinstance(index.constantValue, int) 56 | and self.interiorTypeWrappers is not None 57 | ): 58 | return actualRes.changeType( 59 | self.interiorTypeWrappers[index.constantValue] 60 | ) 61 | 62 | return actualRes 63 | 64 | def convert_masquerade_to_untyped(self, context, instance): 65 | return context.constant(tuple).convert_call( 66 | [instance.convert_masquerade_to_typed()], 67 | {} 68 | ).changeType(tuple) 69 | 70 | def refAs(self, context, instance, which): 71 | return self.convert_masquerade_to_typed(context, instance).refAs(which) 72 | -------------------------------------------------------------------------------- /typed_python/compiler/type_wrappers/util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """util.py 16 | 17 | Simple implementations of functions that we use during codegen. 18 | 19 | These need to be written in python itself, so that we can convert them 20 | when we're converting code in the compiler. 21 | """ 22 | 23 | 24 | def min(x, y): 25 | if x < y: 26 | return x 27 | return y 28 | 29 | 30 | def max(x, y): 31 | if x > y: 32 | return x 33 | return y 34 | -------------------------------------------------------------------------------- /typed_python/compiler/typeof.py: -------------------------------------------------------------------------------- 1 | import typed_python 2 | from typed_python.compiler.type_wrappers.type_sets import SubclassOf, Either 3 | 4 | 5 | typeWrapper = lambda t: typed_python.compiler.python_to_native_converter.typedPythonTypeToTypeWrapper(t) 6 | 7 | 8 | class TypeOf: 9 | """A 'SignatureFunction' that infers the type of an expression. 10 | 11 | Clients can write something like 12 | 13 | def f(self, x) -> Typeof(lambda self, x: self.g(x)): 14 | ... 15 | 16 | to indicate that they want the type of evaluating an expression 17 | on the given types. 18 | """ 19 | def __init__(self, F): 20 | self.F = typed_python.Function(F) 21 | 22 | def mapArg(self, arg): 23 | if isinstance(arg, SubclassOf): 24 | # the compiler assumes that if you pass it 'C', and 'C' 25 | # is not final, then you may have a subclass of C. 26 | return arg.T 27 | 28 | if isinstance(arg, Either): 29 | return typed_python.OneOf(*arg.Types) 30 | 31 | return arg 32 | 33 | def __call__(self, *args, **kwargs): 34 | args = [self.mapArg(a) for a in args] 35 | kwargs = {k: self.mapArg(v) for k, v in kwargs.items()} 36 | 37 | callTarget = self.resultTypeForCall(args, kwargs) 38 | 39 | converter = typed_python.compiler.runtime.Runtime.singleton().converter 40 | 41 | if callTarget is None and converter.isCurrentlyConverting(): 42 | # return the 'empty' OneOf, which can't actually be constructed. 43 | return typed_python.OneOf() 44 | 45 | return callTarget.output_type.interpreterTypeRepresentation 46 | 47 | def resultTypeForCall(self, argTypes, kwargTypes): 48 | funcObj = typed_python._types.prepareArgumentToBePassedToCompiler(self.F) 49 | 50 | argTypes = [typeWrapper(a) for a in argTypes] 51 | kwargTypes = {k: typeWrapper(v) for k, v in kwargTypes.items()} 52 | 53 | overload = funcObj.overloads[0] 54 | 55 | ExpressionConversionContext = typed_python.compiler.expression_conversion_context.ExpressionConversionContext 56 | 57 | argumentSignature = ExpressionConversionContext.computeFunctionArgumentTypeSignature(overload, argTypes, kwargTypes) 58 | 59 | if argumentSignature is None: 60 | return None 61 | 62 | converter = typed_python.compiler.runtime.Runtime.singleton().converter 63 | 64 | callTarget = converter.convertTypedFunctionCall( 65 | type(funcObj), 66 | 0, 67 | argumentSignature, 68 | assertIsRoot=False 69 | ) 70 | 71 | return callTarget 72 | -------------------------------------------------------------------------------- /typed_python/deep_bytecount_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2021 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import deepBytecount 16 | 17 | from typed_python import ( 18 | TupleOf, ListOf, Dict, Class, Member, NamedTuple, ConstDict 19 | ) 20 | 21 | 22 | def test_deep_bytecount_listof(): 23 | l = ListOf(int)() 24 | 25 | for sz in [10, 100, 1000, 10000]: 26 | l.resize(sz) 27 | assert sz * 8 <= deepBytecount(l) <= 8 * sz + 112 28 | 29 | 30 | def test_deep_bytecount_listof_aliasing(): 31 | NT = NamedTuple(a=ListOf(int), b=ListOf(int)) 32 | 33 | l = ListOf(int)() 34 | 35 | x = NT(a=l, b=l) 36 | 37 | l.resize(1000) 38 | 39 | assert 1000 * 8 <= deepBytecount(x) <= 1000 * 8 + 112 40 | 41 | 42 | def test_deep_bytecount_sees_into_basic_python_objects(): 43 | l = ListOf(int)() 44 | l.resize(1000) 45 | 46 | assert deepBytecount(()) < 100 47 | assert deepBytecount((l,)) > 8000 48 | assert deepBytecount([l]) > 8000 49 | assert deepBytecount({TupleOf(int)(l)}) > 8000 50 | assert deepBytecount({10: l}) > 8000 51 | 52 | class C: 53 | def __init__(self, x): 54 | self.x = x 55 | 56 | assert deepBytecount(C(l)) > 8000 57 | 58 | assert deepBytecount((l, l, l)) < 9000 59 | 60 | 61 | def test_deep_bytecount_sees_into_Class_objects(): 62 | class C(Class): 63 | x = Member(ListOf(int)) 64 | 65 | assert deepBytecount(C(x=ListOf(int)(range(1000)))) > 1000 66 | 67 | 68 | def test_deep_bytecount_sees_into_Dict_objects(): 69 | assert deepBytecount(Dict(int, ListOf(int))({1: ListOf(int)(range(1000))})) 70 | 71 | 72 | def test_deep_bytecount_sees_into_ConstDict_objects(): 73 | assert deepBytecount(ConstDict(int, ListOf(int))({1: ListOf(int)(range(1000))})) 74 | 75 | 76 | def test_deep_bytecount_of_empty_constDict(): 77 | assert deepBytecount(ConstDict(int, int)()) == 0 78 | -------------------------------------------------------------------------------- /typed_python/dummy_test_module/__init__.py: -------------------------------------------------------------------------------- 1 | """A dummy module for testing purposes.""" 2 | import pytz 3 | import numpy 4 | 5 | 6 | def testfunction(): 7 | return "testfunction" 8 | -------------------------------------------------------------------------------- /typed_python/generator.py: -------------------------------------------------------------------------------- 1 | import types 2 | from typed_python import Class, TypeFunction, PointerTo, Member, Final, pointerTo 3 | 4 | 5 | @TypeFunction 6 | def Generator(T): 7 | """TypeFunction producing base classes for typed Generator objects.""" 8 | from typed_python import Entrypoint 9 | 10 | class Generator_(Class, __name__=f"Generator({T})"): 11 | IteratorType = T 12 | 13 | @Entrypoint 14 | def __iter__(self) -> Generator(T): 15 | return self 16 | 17 | def __next__(self) -> T: 18 | res = self.__fastnext__() 19 | if res: 20 | return res.get() 21 | else: 22 | raise StopIteration() 23 | 24 | def __fastnext__(self) -> PointerTo(T): 25 | raise NotImplementedError() 26 | 27 | @staticmethod 28 | def __convert_from__(iterator: types.GeneratorType) -> Generator(T): 29 | return GeneratorAdaptor(T)(iterator) 30 | 31 | return Generator_ 32 | 33 | 34 | @TypeFunction 35 | def GeneratorAdaptor(T): 36 | """Adapt an untyped generator to a typed generator.""" 37 | class GeneratorAdaptor_(Generator(T), Final, __name__=f"GeneratorAdaptor({T})"): 38 | IteratorType = T 39 | 40 | _iterator = Member(object) 41 | _result = Member(T) 42 | 43 | def __init__(self, iterator): 44 | self._iterator = iterator 45 | 46 | def __iter__(self) -> Generator(T): 47 | return self 48 | 49 | def __next__(self) -> T: 50 | res = self.__fastnext__() 51 | if res: 52 | return res.get() 53 | else: 54 | raise StopIteration() 55 | 56 | def __fastnext__(self) -> PointerTo(T): 57 | try: 58 | self._result = self._iterator.__next__() 59 | except StopIteration: 60 | return PointerTo(T)() 61 | 62 | return pointerTo(self)._result 63 | 64 | return GeneratorAdaptor_ 65 | -------------------------------------------------------------------------------- /typed_python/iterator_adaptor.py: -------------------------------------------------------------------------------- 1 | from typed_python import Generator, Final, Member, PointerTo, pointerTo 2 | 3 | 4 | class IteratorAdaptor(Generator(object), Final): 5 | """Adapts a regular iterator to a __fastnext__ iterator""" 6 | _iterator = Member(object) 7 | _instance = Member(object) 8 | 9 | def __init__(self, iterator): 10 | self._iterator = iterator 11 | 12 | def __next__(self) -> object: 13 | return self._iterator.__next__() 14 | 15 | def __fastnext__(self) -> PointerTo(object): 16 | try: 17 | self._instance = self._iterator.__next__() 18 | except StopIteration: 19 | return PointerTo(object)() 20 | 21 | return pointerTo(self)._instance 22 | -------------------------------------------------------------------------------- /typed_python/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APrioriInvestments/typed_python/81b856fa7bf3cb5c121b4e725cfbf5f403d60039/typed_python/lib/__init__.py -------------------------------------------------------------------------------- /typed_python/lib/datetime/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APrioriInvestments/typed_python/81b856fa7bf3cb5c121b4e725cfbf5f403d60039/typed_python/lib/datetime/__init__.py -------------------------------------------------------------------------------- /typed_python/lib/datetime/date_time_util.py: -------------------------------------------------------------------------------- 1 | from typed_python import Entrypoint, ListOf 2 | from typed_python.lib.datetime.date_time import Date 3 | 4 | 5 | @Entrypoint 6 | def daterange( 7 | start: Date, end: Date, step: str = "days", stepSize: int = 1, reversed=False 8 | ) -> ListOf(Date): 9 | """ 10 | Build a list of dates between start and end. 11 | 12 | Parameters 13 | ---------- 14 | start : Date 15 | Include this start date. 16 | end : Date 17 | Exclude this end date. 18 | step : OneOf("days", "weeks", "months", "years") 19 | The type of step to take. 20 | stepSize : int 21 | The number of increments in each step. 22 | """ 23 | if step == "days": 24 | 25 | if reversed: 26 | 27 | def iterate(dt: Date) -> Date: 28 | return dt.previous(stepSize) 29 | else: 30 | 31 | def iterate(dt: Date) -> Date: 32 | return dt.next(stepSize) 33 | 34 | elif step == "weeks": 35 | 36 | if reversed: 37 | 38 | def iterate(dt: Date) -> Date: 39 | return dt.previous(stepSize * 7) 40 | else: 41 | 42 | def iterate(dt: Date) -> Date: 43 | return dt.next(stepSize * 7) 44 | 45 | elif step == "months": 46 | 47 | maxDay = start.day 48 | 49 | if reversed: 50 | raise NotImplementedError("We haven't implemented walking backwards by months.") 51 | 52 | else: 53 | 54 | def iterate(dt: Date) -> Date: 55 | return dt.nextMonth(stepSize, maxDay) 56 | 57 | elif step == "years": 58 | 59 | maxDay = start.day 60 | 61 | if reversed: 62 | raise NotImplementedError("We haven't implemented walking backwards by years.") 63 | 64 | else: 65 | 66 | def iterate(dt: Date) -> Date: 67 | return dt.nextYear(stepSize, maxDay) 68 | 69 | else: 70 | raise Exception("step must be 'years', 'months', 'weeks', or 'days'") 71 | 72 | res = ListOf(Date)() 73 | if reversed: 74 | while start < end: 75 | res.append(end) 76 | end = iterate(end) 77 | 78 | else: 79 | while start < end: 80 | res.append(start) 81 | start = iterate(start) 82 | 83 | return res 84 | -------------------------------------------------------------------------------- /typed_python/lib/datetime/date_time_util_test.py: -------------------------------------------------------------------------------- 1 | from typed_python import ListOf 2 | from typed_python.lib.datetime.date_time_util import daterange 3 | from typed_python.lib.datetime.date_time import Date 4 | 5 | 6 | def test_daterange(): 7 | # days by 1 8 | assert daterange(Date(2022, 1, 2), Date(2022, 1, 10)) == ListOf(Date)( 9 | [Date(2022, 1, day) for day in range(2, 10)] 10 | ) 11 | # days by 2 12 | assert daterange(Date(2022, 1, 2), Date(2022, 1, 10), stepSize=2) == ListOf(Date)( 13 | [Date(2022, 1, day) for day in range(2, 10, 2)] 14 | ) 15 | # months by 2 16 | ymd = [ 17 | (2021, 12, 31), 18 | (2022, 2, 28), 19 | (2022, 4, 30), 20 | (2022, 6, 30), 21 | (2022, 8, 31), 22 | (2022, 10, 31), 23 | (2022, 12, 31), 24 | ] 25 | assert daterange( 26 | Date(2021, 12, 31), Date(2023, 1, 31), "months", stepSize=2 27 | ) == ListOf(Date)([Date(y, m, d) for (y, m, d) in ymd]) 28 | # leap year 29 | ymd = [(2020, 2, 29), (2020, 5, 29)] 30 | assert daterange( 31 | Date(2020, 2, 29), Date(2020, 7, 31), "months", stepSize=3 32 | ) == ListOf(Date)([Date(y, m, d) for (y, m, d) in ymd]) 33 | # leap year by year 34 | ymd = [(2020, 2, 29), (2022, 2, 28), (2024, 2, 29), (2026, 2, 28), (2028, 2, 29)] 35 | assert daterange( 36 | Date(2020, 2, 29), Date(2028, 7, 31), "years", stepSize=2 37 | ) == ListOf(Date)([Date(y, m, d) for (y, m, d) in ymd]) 38 | 39 | # in reverse 40 | assert daterange(Date(2022, 1, 2), Date(2022, 1, 10), reversed=True) == ListOf(Date)( 41 | [Date(2022, 1, day) for day in range(10, 2, -1)] 42 | ) 43 | -------------------------------------------------------------------------------- /typed_python/lib/foo.py: -------------------------------------------------------------------------------- 1 | a = "1234567" 2 | 3 | print(a[3:40]) 4 | -------------------------------------------------------------------------------- /typed_python/lib/reduce.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python._types import Tuple, NamedTuple 16 | from typed_python.compiler.type_wrappers.compilable_builtin import CompilableBuiltin 17 | import typed_python.compiler 18 | 19 | typeWrapper = lambda t: typed_python.compiler.python_object_representation.typedPythonTypeToTypeWrapper(t) 20 | 21 | 22 | class Reduce(CompilableBuiltin): 23 | def __eq__(self, other): 24 | return isinstance(other, Reduce) 25 | 26 | def __hash__(self): 27 | return hash("Reduce") 28 | 29 | def __call__(self, reducer, tup): 30 | if isinstance(tup, (Tuple, NamedTuple)): 31 | return self.reduceTuple(reducer, tup) 32 | 33 | raise TypeError("Currently, 'reduce' only works on typed python Tuple or NamedTuple objects") 34 | 35 | def reduceTuple(self, reducer, tup): 36 | isFirst = True 37 | result = None 38 | 39 | for elt in tup: 40 | if isFirst: 41 | result = reducer(elt) 42 | isFirst = False 43 | else: 44 | result = reducer(result, elt) 45 | 46 | return result 47 | 48 | def convert_call(self, context, expr, args, kwargs): 49 | if len(args) != 2 or len(kwargs): 50 | context.pushException(TypeError, "reduce takes two positional arguments: 'f' and 'iterable'") 51 | return 52 | 53 | argT = args[1].expr_type.typeRepresentation 54 | 55 | if isinstance(argT, type) and issubclass(argT, (NamedTuple, Tuple)): 56 | return self.convert_call_on_tuple(context, args[0], args[1]) 57 | 58 | context.pushException(TypeError, "Currently, 'reduce' only works on typed python Tuple or NamedTuple objects") 59 | 60 | def convert_call_on_tuple(self, context, fArg, tupArg): 61 | outputExpr = None 62 | 63 | argT = tupArg.expr_type.typeRepresentation 64 | 65 | for i in range(len(argT.ElementTypes)): 66 | if i == 0: 67 | outputExpr = fArg.convert_call((tupArg.refAs(i),), {}) 68 | else: 69 | outputExpr = fArg.convert_call((outputExpr, tupArg.refAs(i)), {}) 70 | 71 | if outputExpr is None: 72 | return None 73 | 74 | return outputExpr 75 | 76 | 77 | reduce = Reduce() 78 | -------------------------------------------------------------------------------- /typed_python/lib/reduce_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2020 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest 16 | import time 17 | 18 | from flaky import flaky 19 | from typed_python import Tuple, NamedTuple, Entrypoint 20 | 21 | from typed_python import reduce 22 | 23 | 24 | class TestReduce(unittest.TestCase): 25 | def test_reduce(self): 26 | def f(x, y=0.0): 27 | return x + y 28 | 29 | @Entrypoint 30 | def compiledReduce(f, tup): 31 | return reduce(f, tup) 32 | 33 | aTup = Tuple(int, int, float)((1, 2, 3.0)) 34 | 35 | self.assertEqual(reduce(f, aTup), 6.0) 36 | self.assertEqual(compiledReduce(f, aTup), 6.0) 37 | 38 | aNamedTup = NamedTuple(x=int, y=float)((1, 2.5)) 39 | self.assertEqual(reduce(f, aNamedTup), 3.5) 40 | self.assertEqual(compiledReduce(f, aNamedTup), 3.5) 41 | 42 | @flaky(max_runs=3, min_passes=1) 43 | def test_reduce_perf(self): 44 | def doit(tup, times): 45 | res = 0.0 46 | for i in range(times): 47 | res += reduce(lambda x, y=0.0: x + y, tup) 48 | return res 49 | 50 | compiledDoit = Entrypoint(doit) 51 | 52 | aTup = Tuple(int, int, float)((1, 2, 3.0)) 53 | 54 | compiledDoit(aTup, 1) 55 | 56 | t0 = time.time() 57 | compiledDoit(aTup, 100000) 58 | t1 = time.time() 59 | doit(aTup, 100000) 60 | t2 = time.time() 61 | 62 | speedup = (t2 - t1) / (t1 - t0) 63 | 64 | print(f"tp is {speedup} times faster.") 65 | 66 | # I get about 2000, mostly because the python implementation, 67 | # which has to recreate the type object each time, is very slow. 68 | self.assertGreater(speedup, 100) 69 | -------------------------------------------------------------------------------- /typed_python/lz4/.gitignore: -------------------------------------------------------------------------------- 1 | # make install artefact 2 | liblz4.pc 3 | -------------------------------------------------------------------------------- /typed_python/lz4/LICENSE: -------------------------------------------------------------------------------- 1 | LZ4 Library 2 | Copyright (c) 2011-2020, Yann Collet 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /typed_python/lz4/dll/example/Makefile: -------------------------------------------------------------------------------- 1 | # ########################################################################## 2 | # LZ4 programs - Makefile 3 | # Copyright (C) Yann Collet 2016-2020 4 | # 5 | # GPL v2 License 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # You can contact the author at : 22 | # - LZ4 homepage : http://www.lz4.org 23 | # - LZ4 source repository : https://github.com/lz4/lz4 24 | # ########################################################################## 25 | 26 | VOID := /dev/null 27 | LZ4DIR := ../include 28 | LIBDIR := ../static 29 | DLLDIR := ../dll 30 | 31 | CFLAGS ?= -O3 # can select custom flags. For example : CFLAGS="-O2 -g" make 32 | CFLAGS += -Wall -Wextra -Wundef -Wcast-qual -Wcast-align -Wshadow -Wswitch-enum \ 33 | -Wdeclaration-after-statement -Wstrict-prototypes \ 34 | -Wpointer-arith -Wstrict-aliasing=1 35 | CFLAGS += $(MOREFLAGS) 36 | CPPFLAGS:= -I$(LZ4DIR) -DXXH_NAMESPACE=LZ4_ 37 | FLAGS := $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) 38 | 39 | 40 | # Define *.exe as extension for Windows systems 41 | ifneq (,$(filter Windows%,$(OS))) 42 | EXT =.exe 43 | else 44 | EXT = 45 | endif 46 | 47 | .PHONY: default fullbench-dll fullbench-lib 48 | 49 | 50 | default: all 51 | 52 | all: fullbench-dll fullbench-lib 53 | 54 | 55 | fullbench-lib: fullbench.c xxhash.c 56 | $(CC) $(FLAGS) $^ -o $@$(EXT) $(LIBDIR)/liblz4_static.lib 57 | 58 | fullbench-dll: fullbench.c xxhash.c 59 | $(CC) $(FLAGS) $^ -o $@$(EXT) -DLZ4_DLL_IMPORT=1 $(DLLDIR)/liblz4.dll 60 | 61 | clean: 62 | @$(RM) fullbench-dll$(EXT) fullbench-lib$(EXT) \ 63 | @echo Cleaning completed 64 | -------------------------------------------------------------------------------- /typed_python/lz4/dll/example/fullbench-dll.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Express 2012 for Windows Desktop 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench-dll", "fullbench-dll.vcxproj", "{13992FD2-077E-4954-B065-A428198201A9}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Win32 = Debug|Win32 8 | Debug|x64 = Debug|x64 9 | Release|Win32 = Release|Win32 10 | Release|x64 = Release|x64 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.ActiveCfg = Debug|Win32 14 | {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.Build.0 = Debug|Win32 15 | {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.ActiveCfg = Debug|x64 16 | {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.Build.0 = Debug|x64 17 | {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.ActiveCfg = Release|Win32 18 | {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.Build.0 = Release|Win32 19 | {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.ActiveCfg = Release|x64 20 | {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.Build.0 = Release|x64 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /typed_python/lz4/liblz4-dll.rc.in: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // DLL version information. 4 | 1 VERSIONINFO 5 | FILEVERSION @LIBVER_MAJOR@,@LIBVER_MINOR@,@LIBVER_PATCH@,0 6 | PRODUCTVERSION @LIBVER_MAJOR@,@LIBVER_MINOR@,@LIBVER_PATCH@,0 7 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 8 | #ifdef _DEBUG 9 | FILEFLAGS VS_FF_DEBUG | VS_FF_PRERELEASE 10 | #else 11 | FILEFLAGS 0 12 | #endif 13 | FILEOS VOS_NT_WINDOWS32 14 | FILETYPE VFT_DLL 15 | FILESUBTYPE VFT2_UNKNOWN 16 | BEGIN 17 | BLOCK "StringFileInfo" 18 | BEGIN 19 | BLOCK "040904B0" 20 | BEGIN 21 | VALUE "CompanyName", "Yann Collet" 22 | VALUE "FileDescription", "Extremely fast compression" 23 | VALUE "FileVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" 24 | VALUE "InternalName", "@LIBLZ4@" 25 | VALUE "LegalCopyright", "Copyright (C) 2013-2020, Yann Collet" 26 | VALUE "OriginalFilename", "@LIBLZ4@.dll" 27 | VALUE "ProductName", "LZ4" 28 | VALUE "ProductVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" 29 | END 30 | END 31 | BLOCK "VarFileInfo" 32 | BEGIN 33 | VALUE "Translation", 0x0409, 1200 34 | END 35 | END 36 | -------------------------------------------------------------------------------- /typed_python/lz4/liblz4.pc.in: -------------------------------------------------------------------------------- 1 | # LZ4 - Fast LZ compression algorithm 2 | # Copyright (C) 2011-2020, Yann Collet. 3 | # BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 4 | 5 | prefix=@PREFIX@ 6 | libdir=@LIBDIR@ 7 | includedir=@INCLUDEDIR@ 8 | 9 | Name: lz4 10 | Description: extremely fast lossless compression algorithm library 11 | URL: http://www.lz4.org/ 12 | Version: @VERSION@ 13 | Libs: -L${libdir} -llz4 14 | Cflags: -I${includedir} 15 | -------------------------------------------------------------------------------- /typed_python/lz4/lz4frame_static.h: -------------------------------------------------------------------------------- 1 | /* 2 | LZ4 auto-framing library 3 | Header File for static linking only 4 | Copyright (C) 2011-2020, Yann Collet. 5 | 6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | * Redistributions in binary form must reproduce the above 15 | copyright notice, this list of conditions and the following disclaimer 16 | in the documentation and/or other materials provided with the 17 | distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | You can contact the author at : 32 | - LZ4 source repository : https://github.com/lz4/lz4 33 | - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c 34 | */ 35 | 36 | #ifndef LZ4FRAME_STATIC_H_0398209384 37 | #define LZ4FRAME_STATIC_H_0398209384 38 | 39 | /* The declarations that formerly were made here have been merged into 40 | * lz4frame.h, protected by the LZ4F_STATIC_LINKING_ONLY macro. Going forward, 41 | * it is recommended to simply include that header directly. 42 | */ 43 | 44 | #define LZ4F_STATIC_LINKING_ONLY 45 | #include "lz4frame.h" 46 | 47 | #endif /* LZ4FRAME_STATIC_H_0398209384 */ 48 | -------------------------------------------------------------------------------- /typed_python/module_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typed_python import Module, TupleOf, Class, Member, OneOf 16 | import unittest 17 | 18 | 19 | class ModuleTest(unittest.TestCase): 20 | def test_definining_members(self): 21 | m = Module("M") 22 | m.Int = int 23 | 24 | self.assertEqual(m.Int, int) 25 | 26 | m.Y = int 27 | m.T = TupleOf(m.Y) 28 | 29 | self.assertEqual(m.T, TupleOf(int)) 30 | 31 | def test_defining_classes(self): 32 | m = Module("M") 33 | 34 | @m.define 35 | class X(Class): 36 | y = Member(OneOf(None, m.Y)) 37 | 38 | @m.define 39 | class Y(Class): 40 | x = Member(OneOf(None, m.X)) 41 | 42 | x = X(y=Y(x=None)) 43 | y = Y(x=x) 44 | 45 | self.assertTrue(y.x.y.x is None) 46 | 47 | def test_cant_assign_lower_case(self): 48 | m = Module("M") 49 | with self.assertRaises(AttributeError): 50 | m.int = int 51 | 52 | with self.assertRaises(AttributeError): 53 | m._int = int 54 | 55 | def test_freezing_prevents_defining(self): 56 | m = Module("M") 57 | m.Int = int 58 | 59 | m.freeze() 60 | with self.assertRaises(Exception): 61 | m.Float = float 62 | 63 | def test_freezing_fails_if_undefined(self): 64 | m = Module("M") 65 | m.T = TupleOf(m.I) 66 | 67 | with self.assertRaisesRegex(Exception, "M.I is not defined yet"): 68 | m.freeze() 69 | -------------------------------------------------------------------------------- /typed_python/string_util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | def indent(text, amount=4, ch=' '): 17 | padding = amount * ch 18 | return ''.join(padding+line for line in text.splitlines(True)) 19 | 20 | 21 | def distance(s1, s2): 22 | """Compute the edit distance between s1 and s2""" 23 | if len(s1) < len(s2): 24 | return distance(s2, s1) 25 | 26 | if len(s2) == 0: 27 | return len(s1) 28 | 29 | prev = range(len(s2) + 1) 30 | 31 | for i, c1 in enumerate(s1): 32 | cur = [i + 1] 33 | for j, c2 in enumerate(s2): 34 | cur.append(min(prev[j+1]+1, cur[j]+1, prev[j] + (1 if c1 != c2 else 0))) 35 | prev = cur 36 | 37 | return prev[-1] 38 | 39 | 40 | def closest_in(name, names): 41 | return sorted((distance(name, x), x) for x in names)[0][1] 42 | 43 | 44 | def closest_N_in(name, names, count): 45 | return [x[1] for x in sorted((distance(name, x), x) for x in names)[:count]] 46 | -------------------------------------------------------------------------------- /typed_python/type_filter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 typed_python Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | class TypeFilterBase(type): 17 | def __instancecheck__(self, other): 18 | if not isinstance(other, self.base_type): 19 | return False 20 | 21 | try: 22 | if not self.filter_function(other): 23 | return False 24 | except Exception: 25 | return False 26 | 27 | return True 28 | 29 | 30 | def TypeFilter(base_type, filter_function): 31 | """TypeFilter(base_type, filter_function) 32 | 33 | Produce a 'type object' that can be used in typed python to filter objects by 34 | arbitrary criteria. 35 | """ 36 | class TypeFilter(metaclass=TypeFilterBase): 37 | pass 38 | 39 | TypeFilter.base_type = base_type 40 | TypeFilter.filter_function = filter_function 41 | 42 | return TypeFilter 43 | --------------------------------------------------------------------------------