Macros for Python: Quasiquotes, Case Classes, LINQ and more!
MacroPy is an implementation of Syntactic Macros in the Python Programming Language. MacroPy provides a mechanism for user-defined functions (macros) to perform transformations on the abstract syntax tree (AST) of a Python program at import time. This is an easy way to enhance the semantics of a Python program in ways which are otherwise impossible, for example providing an extremely concise way of declaring classes.
Python like you’ve never seen before
MacroPy allows you to create constructs which are impossible to have in normal python code, such as:
with trace: sum([x + 5 for x in range(3)]) # sum([x + 5 for x in range(3)]) # range(3) -> [0, 1, 2] # x + 5 -> 5 # x + 5 -> 6 # x + 5 -> 7 # [x + 5 for x in range(3)] -> [5, 6, 7] # sum([x + 5 for x in range(3)]) -> 18
print(list(map(f[_], ['omg', 'wtf', 'bbq']))) # ['o', 'w', 'b'] print(list(reduce(f[_ + _], ['omg', 'wtf', 'bbq']))) # 'omgwtfbbq
@case class Point(x, y): pass p = Point(1, 2) print str(p) #Point(1, 2) print p.x #1 print p.y #2 print Point(1, 2) == Point(1, 2) # True
and more! See the docs at http://macropy3.readthedocs.io/en/latest/.
Just execute a:
$ pip install macropy3
if you want to use macros that require external libraries in order to work, you can automatically install those dependencies by installing one of the pinq or pyxl extras like this:
$ pip install macropy3[pinq,pyxl]
then have a look at the docs at http://macropy3.readthedocs.io/en/latest/.
How to contribute
We’re open to contributions, so send us your ideas/questions/issues/pull-requests and we’ll do our best to accommodate you! You can ask questions on the Google Group and on the Gitter channel or file bugs on thee issues page.
MacroPy was initially created as a final project for the MIT class 6.945: Adventures in Advanced Symbolic Programming, taught by Gerald Jay Sussman and Pavel Panchekha. Inspiration was taken from project such as Scala Macros, Karnickel and Pyxl.
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Fix readme.
- Fix and re-enable the SaveExporter() class.
- Fix some issues with pattern matching module requiring non obvious imports from user’s side.
- Fix pattern matching macro need to import _matching symbol
- Add an OptionalMatcher to pattern matching macro to support exclusive or conditions.
- Refactor documentation using sphinx.
- Refactor the macro expansion core code. Now the macro expansion order is from inside-out. This allows to use macros inside other macro’s body.
- Added support for Python 3.4.
- Added SELECT * FROM country emulation in pinq macro.
- Update the examples.
- Update tco and pyxl macros.
- Prevent the import hooks from raising errors.
- Add MANIFEST.in;
- Updated the import machinery and macro detection to be compatible with Python 3.5+.
- Removed support for Python 2, supporting it would require a way to manage differences at the ast level, but i don’t use Python2 anymore.
- Added support for Python 3.5+ in the form of new call arguments form and new AsyncFunctionDef.
- Basic scope analysis now available in the form of the @Scoped decorator, to be used in conjunction with @Walker.
- Error messages are now raised at run-time rather than at import time, with other improvements (double stack traces, catchability).
- @enum macro now has much better error messages
- Improved error messages for mis-use of stub functions outside their related macro (e.g. the u, name, ast stubs for the q/hq macros)
- Improved error messages for invalid case class signatures
- Hygienic Quasiquotes now allow lexical capture of module objects
- Removed unit test from PyPI distribution
- Fixed a bug in ast_ctx_fixer
- gen_sym() is now gen_sym(name="sym"), allowing you to override the base name
- Implemented macropy.case_classes.enum macro
- Implemented macropy.quick_lambda.lazy and macropy.quick_lambda.interned macros