Compare commits

...

1602 Commits

Author SHA1 Message Date
Windel Bouwman
cc24b73031 Set all versions to 0.1.0 2019-07-07 13:04:12 +02:00
Windel Bouwman
93f70abdf1 Merge pull request #1108 from RustPython/update-docs
Update documentation folder and readme.
2019-07-06 19:09:59 +02:00
Windel Bouwman
bcf470ee52 Merge pull request #1111 from RustPython/sys-version
Add git information in sys and platform modules.
2019-07-06 18:37:42 +02:00
Windel Bouwman
5c39350451 Revert Pipfile back to py36 2019-07-06 18:36:18 +02:00
Windel Bouwman
22c3ed3e1f Merge branch 'master' of github.com:RustPython/RustPython into update-docs 2019-07-06 17:01:33 +02:00
Windel Bouwman
ef649be941 Add git information in sys and platform modules. 2019-07-06 17:00:03 +02:00
Windel Bouwman
69980c23b7 Merge pull request #1109 from RustPython/update-travis-yml
Trial to improve travis config.
2019-07-06 16:02:07 +02:00
coolreader18
f041a0a50f Merge pull request #1110 from palaviv/wasm-warns
Remove wasm warnings
2019-07-06 08:38:59 -05:00
Aviv Palivoda
10cad47b50 Remove wasm warnings 2019-07-06 16:14:29 +03:00
Windel Bouwman
f68b064224 Stick to python3.6 for now. 2019-07-06 13:13:35 +02:00
Windel Bouwman
70c20543f8 Merge pull request #1106 from palaviv/syntex-error
Pass more information in user defined parse error
2019-07-06 13:02:11 +02:00
Windel Bouwman
ef44e7295e Trial to improve travis config. 2019-07-06 12:32:53 +02:00
Aviv Palivoda
0be08fe9f4 Fix wasm syntax error 2019-07-06 13:30:06 +03:00
Windel Bouwman
c64a974bfd Update documentation folder and readme. 2019-07-06 11:42:19 +02:00
Windel Bouwman
a099ba5f8e Merge pull request #1104 from palaviv/remove-importlib-frames
Remove importlib frames from traceback
2019-07-06 10:58:20 +02:00
Aviv Palivoda
0e74d16498 Pass ParseError location to CompileError 2019-07-06 10:23:32 +03:00
Aviv Palivoda
251e33af22 Add TODO on verbose 2019-07-06 09:16:23 +03:00
Aviv Palivoda
c70748fbaa Use filter 2019-07-06 09:15:21 +03:00
Aviv Palivoda
6239fe0fbc Remove importlib frames from traceback 2019-07-06 09:15:21 +03:00
Aviv Palivoda
ef1d5433df Pass more information in user defined parse error 2019-07-05 11:01:49 +03:00
coolreader18
22c0b085ad Merge pull request #1105 from palaviv/skip-modules
Allow skipping of unknown modules in whats_left.sh
2019-07-04 16:35:27 -05:00
Aviv Palivoda
2edba36de7 Allow skipping of unknown modules 2019-07-04 23:58:01 +03:00
coolreader18
f8e8a12ed2 Merge pull request #1102 from palaviv/clean-import
Remove old import
2019-07-04 13:16:50 -05:00
Aviv Palivoda
f740845bab Use vm.class 2019-07-04 17:38:55 +03:00
Aviv Palivoda
bb30d0fce0 Don't install external imports if there is no compiler 2019-07-04 17:36:27 +03:00
Aviv Palivoda
42d17138eb Remove old import 2019-07-04 17:32:17 +03:00
Aviv Palivoda
ee4ee5456f Use vm.import when running with -m 2019-07-04 17:32:17 +03:00
coolreader18
72febb77d0 Merge pull request #1103 from mkurnikov/importerror-attributes
Add name, path, msg attributes to ImportError
2019-07-03 18:17:03 -05:00
Maxim Kurnikov
9ce5240598 add name, path, msg attributes to ImportError 2019-07-03 22:18:49 +03:00
Windel Bouwman
df53d55c82 Merge pull request #1101 from palaviv/wasm-importlib
Use importlib import in WASM
2019-07-03 20:18:59 +02:00
coolreader18
f34f16b2cc Merge pull request #1095 from RustPython/coolreader18/whats_left-modules
Add module listing to whats_left.sh
2019-07-03 12:58:09 -05:00
Aviv Palivoda
090cfed593 Use importlib import in WASM 2019-07-03 18:57:49 +03:00
coolreader18
6b018a0b8b Merge pull request #1096 from RustPython/underscore2hyphen
Underscore2hyphen
2019-07-03 10:16:03 -05:00
coolreader18
96f6646063 Merge pull request #1098 from mkurnikov/pass-if-expression-to-function
Do not pollute stack when if-expression condition evaluated to False
2019-07-03 09:55:39 -05:00
Maxim Kurnikov
8162b87a00 Do not pollute stack when if-expression condition evaluated to False 2019-07-03 16:13:16 +03:00
coolreader18
3668250c12 Show module attributes missing 2019-07-01 14:21:29 -05:00
Windel Bouwman
6a58b76ef7 Change authors to team name. 2019-07-01 21:14:07 +02:00
Windel Bouwman
bedbad284e Change underscore into hyphen 2019-07-01 21:05:29 +02:00
Windel Bouwman
4a108c1ef5 Merge pull request #1059 from RustPython/unicodedata
Add initial unicodedata module.
2019-07-01 20:44:14 +02:00
Windel Bouwman
e05a75c363 Merge pull request #1092 from RustPython/bytecode-crate
Make parser and compiler optional features for vm crate.
2019-07-01 20:43:06 +02:00
coolreader18
92625857ba Allow specifying sections for whats_left.sh 2019-07-01 13:28:55 -05:00
coolreader18
f8cf39ebbb Change sys.path in not_impl_gen.py 2019-07-01 13:20:04 -05:00
coolreader18
982b2f2c14 Add comment to not_impl_gen.py 2019-07-01 13:11:43 -05:00
coolreader18
307990d5de Add module listing to whats_left.sh 2019-07-01 13:06:45 -05:00
coolreader18
dfabd4a2a1 Merge pull request #1093 from RustPython/getrow
Change get_row() into row()
2019-07-01 09:22:35 -05:00
coolreader18
fbd0c599a9 Merge pull request #1074 from JimJeon/feature/rmod
Implement int.__rmod__
2019-06-30 20:33:15 -05:00
JimJeon
2f1d4a8d29 Fix with rustfmt 2019-07-01 09:44:47 +09:00
Windel Bouwman
13be2cf3f4 Merge master branch 2019-06-30 21:22:33 +02:00
Windel Bouwman
5b534ade4d Merge pull request #1091 from palaviv/fix-import
Fix locals and globals in call to __import__
2019-06-30 20:43:52 +02:00
Windel Bouwman
f816a50110 Change get_row() into row() 2019-06-30 20:23:01 +02:00
Windel Bouwman
3954dbe716 Make parser and compiler optional features for vm crate. 2019-06-30 20:11:40 +02:00
Windel Bouwman
36adf45b27 Merge pull request #1086 from RustPython/bytecode-crate
Move bytecode into own crate.
2019-06-30 20:03:54 +02:00
coolreader18
602e4b7edb Merge pull request #1085 from RustPython/travis-configs
Simplify travis config.
2019-06-30 12:14:17 -05:00
Aviv Palivoda
49f3bf7401 Fix locals and globals in call to __import__ 2019-06-30 20:09:26 +03:00
coolreader18
6ba3553fcf Merge pull request #1089 from silmeth/serialization
improve (de)serialization: no crash on BigInts, non-string map keys
2019-06-30 10:10:31 -05:00
silmeth
5dddd02bca improve (de)serialization: no crash on BigInts, non-string map keys 2019-06-30 16:10:58 +02:00
Windel Bouwman
f1d250b10a Merge branch 'master' of https://github.com/RustPython/RustPython into bytecode-crate 2019-06-30 11:42:47 +02:00
Windel Bouwman
e40c844be7 Make bytecode crate independent of parser crate. 2019-06-30 11:42:36 +02:00
Windel Bouwman
183415e64b Move bytecode into own crate. 2019-06-30 11:01:40 +02:00
Windel Bouwman
a332b74ad8 Merge pull request #1064 from RustPython/cryptomods
Add initial hashlib module.
2019-06-30 10:58:49 +02:00
Windel Bouwman
7ab5d53642 update to newer version of DynDigest trait which allows clone. 2019-06-30 10:10:17 +02:00
Windel Bouwman
f0492eefb2 Merge pull request #1084 from silmeth/int-float-comparison
fix float–int cross-type comparisons
2019-06-30 09:25:49 +02:00
Windel Bouwman
598a0a9b79 Simplify travis config further. 2019-06-30 09:13:47 +02:00
Windel Bouwman
f0715fe388 Simplify travis config. 2019-06-30 09:04:57 +02:00
Windel Bouwman
ae684e323e Merge pull request #1065 from RustPython/coolreader18/wasm-test-traceback
Give more information in the error messages for failed wasm tests
2019-06-30 08:57:25 +02:00
coolreader18
4d5b4f5dbe Use new_import_error, fix serve command 2019-06-30 00:52:03 -04:00
Aviv Palivoda
4bf317c3af Merge pull request #1076 from corona10/complex_repr
Fix complex representation for negative imaginary number case.
2019-06-29 21:03:16 +03:00
Aviv Palivoda
546c1c0504 Merge pull request #1083 from palaviv/parse-level
Calculate import level at parsing
2019-06-29 20:49:22 +03:00
Aviv Palivoda
ed737026c3 Merge pull request #1082 from RustPython/xdrlib
Add xdrlib.py
2019-06-29 20:46:42 +03:00
Windel Bouwman
c7004f7b0f Merge pull request #1070 from corona10/ellipsis
Add "Ellipsis" for Ellipsis
2019-06-29 16:58:13 +02:00
silmeth
d0de3be2a9 fix float–int cross-type comparisons
Fixes #1069
2019-06-29 16:50:09 +02:00
Windel Bouwman
e88f7536b3 Improve single arm match. 2019-06-29 16:48:03 +02:00
Windel Bouwman
df31abea98 Merge branch 'master' of https://github.com/RustPython/RustPython into cryptomods 2019-06-29 16:46:00 +02:00
Dong-hee Na
8c318dcd3c Add "Ellipsis" for Ellipsis
Currently, only "..." works for Ellipsis type.
This PR will fix this code to work.
```python
a = Ellipsis
b = ...
a is b
```
2019-06-29 23:34:27 +09:00
Windel Bouwman
d185f53195 Merge pull request #1079 from sanxiyn/os-lstat
Implement os.lstat
2019-06-29 16:19:04 +02:00
Windel Bouwman
c0600860c8 Merge pull request #1081 from RustPython/travis-config
Disable code coverage on all branches except the master branch.
2019-06-29 16:16:16 +02:00
Aviv Palivoda
0d8d2e3beb Calculate import level at parsing 2019-06-29 17:04:31 +03:00
Windel Bouwman
ddc24d67dc Add xdrlib.py 2019-06-29 14:44:39 +02:00
Windel Bouwman
0a242b69a5 Merge pull request #1067 from palaviv/memoryview-slice
Memoryview slice
2019-06-29 14:41:46 +02:00
Windel Bouwman
5f3e5e1602 Disable code coverage on all branches except the master branch. 2019-06-29 14:18:54 +02:00
Windel Bouwman
f4d63c923a Switch to better supported crypto lib. 2019-06-29 14:03:19 +02:00
Windel Bouwman
09823a0a64 Merge pull request #1078 from corona10/sys.byteorder
sys.byteorder: Implement sys.byteorder
2019-06-29 13:24:41 +02:00
Windel Bouwman
18a49d10b5 Merge pull request #1077 from hannut91/add-tuple-rmul
Add tuple.__rmul__
2019-06-29 13:19:13 +02:00
JimJeon
5172a098bf Changed function name to rmod 2019-06-29 17:38:01 +09:00
Seo Sanghyeon
87d866d414 Implement os.lstat 2019-06-29 17:21:11 +09:00
Dong-hee Na
b1aa10d03e Fix complex representation for negative imaginary number case. 2019-06-29 16:30:34 +09:00
Dong-hee Na
103559101e sys.byteorder: Implement sys.byteorder 2019-06-29 16:16:03 +09:00
Aviv Palivoda
32be3bc110 Merge pull request #1071 from hannut91/add-resolve-path
Fix TestWithTempDir test to pass on Mac
2019-06-29 10:15:23 +03:00
Windel Bouwman
57de0ebc05 Merge pull request #1061 from RustPython/xdrlib
Add endianness support to struct module.
2019-06-29 09:05:54 +02:00
hannut91
91d901abdb Add tuple.__rmul__
Add tuple.__rmul__ and uncomment test snippet of __rmul__.
2019-06-29 16:02:42 +09:00
JimJeon
1e568f1044 Implement int.__rmod__
Extracted inner_mod function and used in int.__mod__ and int.__rmod__
and also added test snippets of int.__mod__ and int.__rmod__.
2019-06-29 15:21:28 +09:00
hannut91
1dc5daa4d8 Fix TestWithTempDir test to pass on Mac
Fix TestWithTmpeDir test that comapre os.getcwd() and tmpdir.
os.getcwd() returns the result of resolving the symbolic link. But tmpdir
absolute path. Testing fails on Mac because the /tmp directory is a symbolic
link. Comparing the results of resolving tempdir will pass the test. But
RustPython does not implement lstat, so it does not pass, but in CPython The
test passes.
2019-06-29 14:58:44 +09:00
coolreader18
212522a4bb Merge pull request #1068 from palaviv/imp-_fix_co_filename
Add empty _imp._fix_co_filename
2019-06-28 05:26:24 -05:00
Aviv Palivoda
a3dc98d172 Add empty _imp._fix_co_filename 2019-06-28 10:46:55 +03:00
Aviv Palivoda
5a8613c78a Add tests for memoryview 2019-06-28 10:28:48 +03:00
Aviv Palivoda
7d2c4b6b6e memoryview support __getitem__ 2019-06-28 10:19:44 +03:00
Aviv Palivoda
3c54494132 Merge pull request #1054 from mkurnikov/keyerror-cpython
KeyError should have passed key object as a first element of .args
2019-06-28 09:23:51 +03:00
Aviv Palivoda
da39dde31f Merge pull request #1062 from palaviv/file-io-fd
Improve FileIO
2019-06-28 09:18:54 +03:00
coolreader18
d44350d042 Make vm.import more clear 2019-06-27 13:56:34 -05:00
coolreader18
4959361d29 Give more information in the error messages for failed wasm tests 2019-06-27 13:56:03 -05:00
Windel Bouwman
0a369d821d Add initial hashlib module. 2019-06-27 19:09:35 +02:00
Maxim Kurnikov
848714e18e save passed object into the first .args parameter for dict/mappingproxy KeyError 2019-06-26 23:40:24 +03:00
Windel Bouwman
0642412027 Merge pull request #1057 from RustPython/coolreader18/cpython-libs2
Add CPython library modules needed for unittest
2019-06-26 21:56:34 +02:00
coolreader18
c78c95f03a Add CPython library modules needed for unittest 2019-06-26 11:39:10 -05:00
coolreader18
1f9fa724e0 Merge pull request #1063 from palaviv/eof-error
Add EOFError
2019-06-26 10:42:42 -05:00
Aviv Palivoda
f2dff1cd20 Add EOFError 2019-06-26 18:25:47 +03:00
Aviv Palivoda
8cdf19c5f9 FileIO.write support ByteArray 2019-06-26 18:17:47 +03:00
Windel Bouwman
9e194b3904 Add endianness support to struct module. 2019-06-26 16:38:11 +02:00
Windel Bouwman
4db83aca7f Add initial unicodedata module. 2019-06-26 13:41:58 +02:00
coolreader18
c96680a70c Merge pull request #1050 from palaviv/relative-import
Support relative import
2019-06-25 15:50:26 -05:00
coolreader18
6d5f381d70 Merge pull request #1056 from mkurnikov/args-in-exceptions
Add args attribute to exceptions, make __str__ and __repr__ compatible with CPython
2019-06-25 11:32:07 -05:00
Aviv Palivoda
dc7eb24aab Support fileno as name in FileIO 2019-06-25 19:13:27 +03:00
Aviv Palivoda
725cfcc58d compute_c_flag ignore chars after first 2019-06-25 18:48:30 +03:00
Aviv Palivoda
da4c0bccfa pass local variables to __import__ only if there is a frame 2019-06-25 18:15:28 +03:00
Maxim Kurnikov
8852abc6c3 make exception __repr__ compatible with python3.6 2019-06-24 22:19:59 +03:00
Maxim Kurnikov
1e53e6c168 specify python 3.6 specifically as a Pipfile venv target 2019-06-24 22:19:01 +03:00
Maxim Kurnikov
060cd75783 simplify exception_repr a bit 2019-06-24 18:13:18 +03:00
Maxim Kurnikov
82101d9f1a rename exc_repr -> exc_name to better describe what it refers to 2019-06-24 18:10:27 +03:00
Maxim Kurnikov
ff1049a1eb fix regression in the exception representation in the traceback 2019-06-24 18:09:27 +03:00
Maxim Kurnikov
cd1d7b1a43 add args attribute to exceptions, make __str__ and __repr__ compatible with CPython 2019-06-24 17:30:20 +03:00
coolreader18
3085eadcb5 Merge pull request #1055 from romab1998/feature/ord_bytes_bytearray
add bytearray and bytes input types for ord()
2019-06-23 21:16:54 -05:00
Windel Bouwman
ba88716fbe Merge pull request #1049 from RustPython/coolreader18/fromargs-span-errors
Improve errors messages for derive(FromArgs)
2019-06-23 20:59:11 +02:00
romab
7effca3533 added tests for ord() in tests/snippets 2019-06-23 23:25:12 +05:00
Aviv Palivoda
bb9d697a85 Merge pull request #1053 from RustPython/zen
Added the python zen module.
2019-06-23 18:27:31 +03:00
Aviv Palivoda
e8c0644a04 Test relative import from upper level 2019-06-23 18:21:02 +03:00
Aviv Palivoda
ae5259670c Test relative import 2019-06-23 18:21:02 +03:00
Aviv Palivoda
a5276df980 Support relative import 2019-06-23 18:21:02 +03:00
Windel Bouwman
eeb7551692 Merge pull request #1039 from RustPython/coolreader18/wasm-_js-module
[WASM] Add a JsValue class
2019-06-23 11:39:01 +02:00
Windel Bouwman
fee9c99950 Merge pull request #1026 from rmliddle/BytesIO
String/BytesIO
2019-06-23 11:37:11 +02:00
romab
f2922e3f25 add bytearray and bytes input types for ord() 2019-06-23 11:34:12 +05:00
rmliddle
9bc392ca70 removed duplicate c_flag function 2019-06-23 11:59:21 +10:00
rmliddle
026958a322 Resolved merge conflict 2019-06-23 11:39:46 +10:00
rmliddle
0f0a9369b5 Updated StringIO to use "StringIO" 2019-06-23 11:36:59 +10:00
Windel Bouwman
ed63ebd0a3 Added the python zen module. 2019-06-22 13:13:34 +02:00
Windel Bouwman
2f75562f14 Merge pull request #1045 from RustPython/coolreader18/pyclassmethod-attr
Add #[pyclassmethod] to #[pyimpl]
2019-06-22 12:40:49 +02:00
coolreader18
658b6ca9b9 Fix errors 2019-06-21 20:20:21 -05:00
coolreader18
298b05d56d Don't convert errors from js to python 2019-06-21 20:20:21 -05:00
coolreader18
8cf38f5b25 Move classmethods on JsValue to be normal methods 2019-06-21 20:20:21 -05:00
coolreader18
072c8725fc Fix get_prop on primitives 2019-06-21 20:20:21 -05:00
coolreader18
886f77bdff Add PyJsValue::instanceof 2019-06-21 20:20:20 -05:00
coolreader18
a3735da489 Move confirm and prompt to browser.py 2019-06-21 20:20:20 -05:00
coolreader18
5627ab2345 Add PyJsValue::construct() 2019-06-21 20:20:20 -05:00
coolreader18
93cdd94ab7 Add browser.py module 2019-06-21 20:20:20 -05:00
coolreader18
56bcb02a5e Add _js module and fix imports 2019-06-21 20:20:20 -05:00
coolreader18
61b26878de Add rustpython_vm::__exports module and fix warning 2019-06-21 20:20:19 -05:00
coolreader18
9bb5dcc663 Merge pull request #1051 from michelhe/get-rid-of-debug-print
Remove a mistakenly commited debug print
2019-06-21 13:58:04 -05:00
coolreader18
650139b918 Merge pull request #1048 from RustPython/revert-1037-coolreader18/option-source_path
Revert "Make CodeObject.source_path an Option<String>", just add a parameter to import_codeobj
2019-06-21 11:49:03 -05:00
Michel Heily
c972e7c73e Remove a mistakenly commited debug print 2019-06-21 12:57:58 +03:00
coolreader18
ba8b733139 Merge pull request #1044 from RustPython/coolreader18/ser_de-own-module
Move PyObject de/serialization to its own module
2019-06-20 23:44:13 -05:00
rmliddle
e96a7014c4 Updates BytesIO to use "BufferedIO" 2019-06-21 13:51:51 +10:00
coolreader18
c359c430c2 Add set_file_attr to import_codeobj 2019-06-20 22:43:13 -05:00
coolreader18
aefbae40e4 Revert "Make CodeObject.source_path an Option<String>" 2019-06-20 12:01:20 -05:00
coolreader18
cb832e9aa1 Improve errors messages for derive(FromArgs) 2019-06-20 11:57:59 -05:00
coolreader18
86b8c07581 Update Cargo.lock 2019-06-19 20:03:31 -05:00
coolreader18
0ac42ac9aa Add convenience functions 2019-06-19 17:30:09 -05:00
Windel Bouwman
30979d9f27 Merge pull request #1043 from yanganto/feat/unicode-iterals
support unicode literal
2019-06-19 19:13:13 +02:00
Antonio Yang
974dc683e4 support unicode literal
- support unicode literal \x with 2 digits
- support unicode literal \u with 4 digits
- support unicode literal \U with 8 digits
- avoid to parse \x as unicode literal in bytes
2019-06-20 00:30:38 +08:00
coolreader18
e68b4943ca Add #[pyclassmethod] to #[pyimpl] 2019-06-18 20:37:08 -05:00
coolreader18
7554dfa72e Merge pull request #1042 from palaviv/os-replace
Add os.rename and OSError.errno
2019-06-18 18:56:35 -05:00
coolreader18
9ac854aea5 Use serde_wasm_bindgen for wasm ser/de 2019-06-18 14:32:34 -05:00
coolreader18
a8d80193c7 Move PyObject serialization to its own file 2019-06-18 13:31:58 -05:00
Aviv Palivoda
17cd22b8e8 Test OSError errno 2019-06-18 19:06:41 +03:00
Aviv Palivoda
9ee1ad93e0 Test os.rename 2019-06-18 19:06:41 +03:00
Aviv Palivoda
2f408f2210 Add conversion from io::Error to OSError 2019-06-18 19:06:00 +03:00
Aviv Palivoda
700d7d4b62 Add os.rename 2019-06-18 19:02:04 +03:00
Windel Bouwman
0f73c746db Merge pull request #1032 from michelhe/printf-like-string-formatting
Printf-style formatting
2019-06-17 21:49:33 +02:00
Michel Heily
64af5c43df Add some test snippets for modulo string formatting 2019-06-17 19:35:09 +03:00
Michel Heily
adccfa63cf Fix bugs when parsing format specifiers with key mappings.
* Algorithm used for parsing the key from "%(key)d" format did not
handle multiple parenthesis correctly.

* Second problem is that they way we calculated number of consumed chars
was based on str::find, making the code vulnerable to false-positives.
2019-06-17 19:35:09 +03:00
Michel Heily
6fe2c43bf7 Move lambda to its own function in do_cformat 2019-06-17 19:35:09 +03:00
Michel Heily
fca4178353 Avoid unnecessary allocation in modulo formatting 2019-06-17 19:35:09 +03:00
Michel Heily
5d38b9b624 Simplify error handling for CFormatString::from_str 2019-06-17 19:35:09 +03:00
Michel Heily
8d612f3a36 Add %c formatting 2019-06-17 19:35:09 +03:00
Michel Heily
8e880b9bdd cformat: Fix a bug when formatting unicode strings
String::len() returns number of bytes and not number of chars, so it
doens't work as expected for unicode strings.

Also, added a test that would have triggered the bug.
2019-06-17 19:35:09 +03:00
Michel Heily
e374aff0bc Support '*' for width and precsision for printf-style formatting 2019-06-17 19:35:09 +03:00
Michel Heily
d5ffecea32 objstr: Improve errors for modulo format 2019-06-17 19:35:09 +03:00
Michel Heily
dc77728dbc cformat: Add some unittests.
Also, this commit fixes some bugs that were found using said unittests.
2019-06-17 19:35:09 +03:00
Michel Heily
481b044883 Support modulo formatting of numbers and string types 2019-06-17 19:35:09 +03:00
Michel Heily
fe6c1488d9 Start implementing str.__mod__ 2019-06-17 19:35:09 +03:00
Michel Heily
f27265cf8a Add get_value for objtuple 2019-06-17 19:35:09 +03:00
Michel Heily
d74e126246 Add parser for C printf-style format strings
This commit is a part of a series of future commits that will resolve #1007 .
Code is based on vm/src/format.rs.
2019-06-17 19:35:09 +03:00
Windel Bouwman
73edde66f7 Merge pull request #1037 from RustPython/coolreader18/option-source_path
Make CodeObject.source_path an Option<String>
2019-06-17 16:58:48 +02:00
rmliddle
8faab1f494 Implement String, BytesIO with Cursor<Vec<u8>> 2019-06-17 19:31:42 +10:00
coolreader18
b74b65d37e Make CodeObject.source_path an Option<String> 2019-06-16 19:59:04 -05:00
coolreader18
9b3521904a Update bench.rs to use vm.compile() 2019-06-16 15:47:27 -05:00
Windel Bouwman
8b0089e258 Merge pull request #1036 from RustPython/coolreader18/stdlib-mods-maplit
Use maplit::hashmap! for stdlib::get_module_inits()
2019-06-16 19:21:05 +02:00
coolreader18
b6b8f6ec9c Have stdlib::get_module_inits() use maplit::hashmap! 2019-06-16 10:33:47 -05:00
Windel Bouwman
ffeaf2d06a Merge pull request #1034 from RustPython/coolreader18/comptime-pycompilation
Allow compiling Python code to bytecode at compile-time
2019-06-16 17:28:02 +02:00
coolreader18
743adf10de Merge branch 'master' into coolreader18/comptime-pycompilation 2019-06-16 09:05:34 -05:00
coolreader18
d3927ff30e Merge pull request #1033 from palaviv/open-flags
Support more open flags
2019-06-16 00:34:45 -05:00
coolreader18
1814977c45 Add doc comments 2019-06-15 20:19:59 -05:00
coolreader18
6b9bbf3ea4 Change TODO 2019-06-15 13:23:04 -05:00
coolreader18
75c2e4ae9b Remove lazy_static, just store as a CodeObject 2019-06-15 11:31:30 -05:00
Aviv Palivoda
92ad30ef6a Add mode argument to os.open 2019-06-15 17:02:46 +03:00
Aviv Palivoda
82f83ef345 Support more open flags 2019-06-15 16:22:51 +03:00
coolreader18
241f5190cc Formatting 2019-06-15 00:30:14 -05:00
coolreader18
b5ba62fe94 Add lazy_static argument 2019-06-14 21:17:12 -05:00
coolreader18
48966a76e2 Make py_compile_bytecode!() an expression 2019-06-14 18:20:02 -05:00
coolreader18
7817cecc49 Merge pull request #1031 from palaviv/reversed
Support reversed on sequence
2019-06-14 15:23:35 -05:00
coolreader18
7e68f9924e Make Location's fields private again 2019-06-14 14:52:30 -05:00
coolreader18
4d0eb06724 Default source_path 2019-06-14 12:40:01 -05:00
coolreader18
d2cde9a3bf Use bincode to deserialize into a CodeObject 2019-06-14 12:26:35 -05:00
coolreader18
8143b69165 Change imp_get_frozen_object 2019-06-14 11:31:39 -05:00
coolreader18
9a09a92f31 Merge pull request #1030 from palaviv/import-from-list
Import all from_list in one call
2019-06-14 10:56:01 -05:00
coolreader18
e592f3d888 Add py_compile_bytecode! macro 2019-06-14 10:42:45 -05:00
Aviv Palivoda
60e799727f Support reversed on sequence 2019-06-14 15:25:24 +03:00
Aviv Palivoda
e61fa6dd74 Use Iterator to create from_list 2019-06-14 08:49:20 +03:00
Aviv Palivoda
4938c03d6f Improve compiler import 2019-06-14 08:45:30 +03:00
Aviv Palivoda
12a3028806 Import all from_list in one __import__ call 2019-06-14 08:27:49 +03:00
coolreader18
8b894a11fb Merge pull request #1029 from RustPython/coolreader18/rustpython_compiler
Split off bytecode compilation into a separate crate
2019-06-13 15:48:11 -04:00
coolreader18
bfd6145d5f Use RUSTPYTHONPATH in ouroboros instructions 2019-06-13 12:34:30 -05:00
coolreader18
c2502bf8ef Add doc comments and individual compile functions 2019-06-12 22:04:59 -05:00
coolreader18
45bb2bd263 Split off bytecode compilation into a separate crate 2019-06-12 21:43:43 -05:00
Windel Bouwman
3f343aff6c Merge pull request #1018 from palaviv/imp3
Importlib
2019-06-12 16:21:26 +02:00
coolreader18
02821324b7 Merge pull request #1028 from RustPython/coolreader18/update-deps1
Update cargo dependencies
2019-06-11 18:07:09 -05:00
coolreader18
cb2fe657a9 Merge pull request #1014 from mkurnikov/cleanup-get-method-error-handling
Cleanup get_method() error handling
2019-06-11 17:43:58 -05:00
coolreader18
07c6a90045 Update cargo dependencies 2019-06-11 16:00:35 -05:00
Aviv Palivoda
1de9f73bd0 Optimize already loaded modules 2019-06-11 22:54:54 +03:00
Windel Bouwman
50662c488a Merge pull request #968 from RustPython/walrus
Add walrus operator to lexer and try to make lexer code cleaner.
2019-06-11 15:06:04 +02:00
Aviv Palivoda
ea8e28026b Simplify objmodule 2019-06-11 13:13:32 +03:00
Aviv Palivoda
0e320f9af6 Change comment to XXX 2019-06-10 21:50:37 +03:00
Aviv Palivoda
603ef1ad05 Support from_list 2019-06-10 21:45:05 +03:00
Aviv Palivoda
e1472f2277 Add sys.dont_write_bytecode 2019-06-10 19:18:32 +03:00
Aviv Palivoda
03735a6d26 Add optional parameters to compile 2019-06-10 19:18:32 +03:00
Aviv Palivoda
8dec522f96 compile source may be bytes 2019-06-10 19:18:32 +03:00
Aviv Palivoda
10828e01fb Set sys.pycache_prefix to None 2019-06-10 19:18:32 +03:00
Aviv Palivoda
b567464378 Add ModuleNotFoundError to builtins 2019-06-10 19:18:32 +03:00
Aviv Palivoda
5df05d4f95 Add script dir to sys.path 2019-06-10 19:18:32 +03:00
Aviv Palivoda
d9d0ea1834 Fix os to _os in class 2019-06-10 19:18:32 +03:00
Aviv Palivoda
5584733cda Add sys.path_importer_cache 2019-06-10 19:18:32 +03:00
Aviv Palivoda
c8248c3211 Expose __name__ in __dict__ 2019-06-10 19:18:32 +03:00
Aviv Palivoda
375790e142 objmodule should have a dict 2019-06-10 19:18:32 +03:00
Aviv Palivoda
fe0284aa05 Add new to objmodule and change __name__ to property 2019-06-10 19:18:32 +03:00
Aviv Palivoda
6615e811c0 Collapse concat 2019-06-10 19:18:32 +03:00
Aviv Palivoda
5c53e58547 Print frozen import file name in stacktrace 2019-06-10 19:18:32 +03:00
Aviv Palivoda
0e76dbb749 Add needed methods to _thread 2019-06-10 19:18:32 +03:00
Aviv Palivoda
2817214c88 Remove unused imports 2019-06-10 19:18:32 +03:00
Aviv Palivoda
7f61125866 Use _bootstrap.py __import__ 2019-06-10 19:18:32 +03:00
Aviv Palivoda
58d9d9deeb Add sys.path_hooks 2019-06-10 19:18:32 +03:00
Aviv Palivoda
b0cccf35ad Change os_details 2019-06-10 19:18:32 +03:00
Aviv Palivoda
a57f38b07f Rename builtin io to _io 2019-06-10 19:18:32 +03:00
Aviv Palivoda
fbaff7fd50 Install external importers on init_importlib 2019-06-10 19:18:32 +03:00
Aviv Palivoda
37b40c55da Add frozen _bootstrap_external.py 2019-06-10 19:18:32 +03:00
Aviv Palivoda
0d9a066712 Add sys.meta_path 2019-06-10 19:18:32 +03:00
Aviv Palivoda
f2145880fa Don't set __file__ for frozen modules 2019-06-10 19:18:32 +03:00
Aviv Palivoda
f1af6b1f40 Include _bootstrap.py as str 2019-06-10 19:18:32 +03:00
Aviv Palivoda
698044b128 Add Module.__name__ 2019-06-10 19:18:32 +03:00
Aviv Palivoda
e88d6ac1ef Add init_importlib 2019-06-10 19:18:32 +03:00
Aviv Palivoda
7ff59b27d7 Add _bootsrap.py as frozen module 2019-06-10 19:18:32 +03:00
coolreader18
740e8387b8 Merge pull request #1027 from alanjds/format-bang
Feature: str.format accepting !r, !s and !a
2019-06-10 10:56:00 -05:00
rmliddle
33885a8334 Namespace added for objstr: get_value, PyStringRef 2019-06-10 22:48:28 +10:00
Alan Justino
854bacf452 Fix the Rust tests 2019-06-09 18:45:08 -03:00
Alan Justino
f0a2b4c50b Apply the {!r} on str.format calls
By the Python docs, the `!` forces a conversion of the argument before
applying the normal formating logic described after the `:` marker.

See: https://docs.python.org/3.4/library/string.html#format-string-syntax
2019-06-09 18:11:10 -03:00
Alan Justino
e19b674abf FormatSpec got a preconversor:FormatPreconversor to handle !r, !s and !a 2019-06-09 16:22:22 -03:00
coolreader18
68011df6cb Merge pull request #1024 from yanganto/str_isprintable
str.isprintable
2019-06-09 13:07:47 -05:00
Alan Justino
65d0093822 Dont fail on '{!r}'.format(...) 2019-06-09 13:46:13 -03:00
Antonio Yang
f76be43d26 str.isprintable
- check unicode type by unicode_categories
- rm redundant check of empty string
2019-06-09 23:33:38 +08:00
rmliddle
6542d3586e Optional args on new for Bytes/StringIO 2019-06-10 00:57:17 +10:00
rmliddle
6767b4efb1 BytesIO First Pass 2019-06-09 21:33:16 +10:00
Windel Bouwman
aa6b155e1e Merge branch 'master' of https://github.com/RustPython/RustPython into walrus 2019-06-09 11:49:02 +02:00
Windel Bouwman
1b968e9406 Merge pull request #1022 from RustPython/coolreader18/demo-repl-continuation
Add line continuation for the WASM demo terminal
2019-06-09 11:16:35 +02:00
coolreader18
d45c632f49 Add incompatibility issue template 2019-06-08 18:59:02 -05:00
coolreader18
b0db7c1096 Add RFC issue template
Structure taken from #771
2019-06-08 18:28:18 -05:00
coolreader18
cd61248635 Merge branch 'master' into coolreader18/demo-repl-continuation 2019-06-08 13:17:05 -05:00
Windel Bouwman
9d9fcfc034 Removal of walrus operator. 2019-06-08 16:38:15 +02:00
Windel Bouwman
9592e94920 Isolate determination of indentation into seperate method. 2019-06-08 16:23:51 +02:00
Windel Bouwman
eb234ca3c5 Merge pull request #1021 from mkurnikov/speed-up-file-open
Get io reader/writer classes only when needed
2019-06-08 16:13:42 +02:00
Windel Bouwman
a1e2da6807 Merge pull request #1020 from RustPython/coolreader18/no-pwd-android
Disable the pwd module on android
2019-06-08 16:12:23 +02:00
Maxim Kurnikov
baf62d56d2 get io reader/writer classes only when needed 2019-06-08 02:49:45 +03:00
coolreader18
2b555cb40e Merge pull request #1016 from mkurnikov/fix-io-open-r
Fix io.open("r") case and address some TODOs
2019-06-07 12:07:47 -05:00
coolreader18
50252b4e80 Disable the pwd module on android 2019-06-07 11:57:50 -05:00
coolreader18
d27840c11d Merge pull request #1019 from palaviv/warnings
Add _warnings
2019-06-07 11:45:48 -05:00
Aviv Palivoda
8fccad1e09 Print warning to stderr
Co-Authored-By: coolreader18 <33094578+coolreader18@users.noreply.github.com>
2019-06-07 18:59:41 +03:00
Maxim Kurnikov
c0e1702869 split mode/type for io.open properly, fix open('r') case 2019-06-07 16:34:16 +03:00
Maxim Kurnikov
8a5182a8a1 make get_method_or_type_error() error message lazy 2019-06-07 16:08:37 +03:00
Aviv Palivoda
d2a82b1acd Add _warnings 2019-06-07 15:14:27 +03:00
Windel Bouwman
1b7088c353 Merge pull request #1017 from michelhe/memoryview_obj
Fix memoryview.obj misimplementation.
2019-06-05 13:22:49 +02:00
coolreader18
74d52ee82f Merge pull request #1011 from palaviv/_imp2
More _imp
2019-06-05 00:43:10 -05:00
Michel Heily
b2cdeab0c6 Fix memoryview.obj misimplementation.
The memoryview skeleton did not correctly assign the "obj" attribute;
The "obj" attribute was assigned to the memoryview class and not the memryview object,
leading to a funny bug that can be reproduced as follows:

```python

m1 = memoryview(b'1234')
m2 = memoryview(b'abcd')

print(m1.obj)
```

the result would be the value inside `m2` instead that of `m1`
2019-06-05 02:36:45 +03:00
Windel Bouwman
0c9d3c8918 Merge pull request #1015 from mkurnikov/empty-exception-message
Make empty exception message format compatible with CPython
2019-06-04 15:52:47 +02:00
Maxim Kurnikov
bc33921fdb make empty exception message format compatible with CPython 2019-06-04 14:59:28 +03:00
Maxim Kurnikov
3bfd66bb89 make some exception messages more compatible with CPython, split get_method() into two methods and make raising TypeError more explicit for get_method() errors 2019-06-03 19:46:32 +03:00
Maxim Kurnikov
1b9c054d03 make new exception logs a bit more descriptive 2019-06-03 19:41:30 +03:00
coolreader18
e871ab0673 Merge pull request #1013 from mkurnikov/source-line-in-traceback
Add indented source lines in traceback
2019-06-02 23:05:59 -05:00
coolreader18
7ddfa1c4ce Merge pull request #1012 from mkurnikov/more-refactorings-2
More doc comments, split with_exit() method for __exit__ into two methods
2019-06-02 22:58:11 -05:00
Maxim Kurnikov
58b1f4a8ee add indented source line in traceback 2019-06-02 18:21:52 +03:00
Maxim Kurnikov
3b5cc1ad2f more doc comments, split with_exit() method for context manager __exit__ into two methods 2019-06-02 01:37:25 +03:00
Aviv Palivoda
106f5f7054 Add _imp.is_frozen_package 2019-06-01 15:15:16 +03:00
Aviv Palivoda
0acce07631 Add _imp.init_frozen 2019-06-01 15:11:55 +03:00
Aviv Palivoda
4faaf2d6ca Add _imp.get_frozen_object 2019-06-01 15:03:45 +03:00
Aviv Palivoda
9a168b10d1 Add _imp.exec_builtin that does nothing 2019-06-01 14:49:12 +03:00
Aviv Palivoda
1294b56cbe Add _imp.create_builtin 2019-06-01 14:32:23 +03:00
coolreader18
b6edd19331 Merge pull request #1010 from mkurnikov/fix-clippy-warnings
Fix most of clippy warnings
2019-05-31 20:19:49 -05:00
Maxim Kurnikov
bc35a64e54 fix most of clippy warnings 2019-06-01 03:19:22 +03:00
Windel Bouwman
e0dbfb553f Merge pull request #1009 from mkurnikov/refactorings
Some cleanups and typo fixes
2019-05-31 22:25:52 +02:00
Maxim Kurnikov
1949239592 cleanups, type fixes and renames 2019-05-31 21:56:10 +03:00
Windel Bouwman
849c6eb1ee Merge pull request #995 from stwen77/binascii
add binascii crc32
2019-05-31 09:30:19 +02:00
Windel Bouwman
8a9e6ef0de Merge pull request #1008 from RustPython/coolreader18/cpython-libs1
Update Lib/operator.py and add Lib/heapq.py from cpython
2019-05-31 09:27:16 +02:00
stwen77
e9f3f4b89a Merge branch 'master' into binascii 2019-05-31 14:22:42 +08:00
Shitong Wen
e452d5523e use crate crc to replace crc table 2019-05-31 14:16:31 +08:00
coolreader18
39c63ef139 Update Lib/operator.py and add Lib/heapq.py from cpython 2019-05-30 23:04:09 -05:00
Aviv Palivoda
9e88b808dd Add _imp.is_frozen 2019-05-30 18:50:46 +03:00
Windel Bouwman
15f94679c4 Merge pull request #988 from skinny121/sys_flags
Add sys.flags
2019-05-30 12:24:04 +02:00
ben
d2757a2680 Fix merge issue with PyTuple::fast_getitem 2019-05-30 21:22:30 +12:00
ben
c0c531d550 Merge branch 'master' into sys_flags
# Conflicts:
#	tests/snippets/sysmod.py
#	vm/src/sysmodule.rs
2019-05-30 21:12:57 +12:00
Windel Bouwman
3f5bb517a5 Merge pull request #1001 from RustPython/coolreader18/rustpythonpath
Check RUSTPYTHONPATH as well as PYTHONPATH env variables
2019-05-30 09:53:05 +02:00
Windel Bouwman
22b4894ae6 Merge pull request #1006 from RustPython/coolreader18/weakproxy-setattr
Add __setattr__ to weakproxy
2019-05-30 09:47:01 +02:00
coolreader18
725a1e8434 Merge pull request #979 from youknowone/refactor-set
PySet/PyFrozenSet refactoring
2019-05-29 23:38:56 -05:00
coolreader18
1dc2d09713 Add __setattr__ to weakproxy 2019-05-29 22:46:12 -05:00
coolreader18
7ae33b72cb Merge pull request #1005 from Jongy/lib-reprlib
Lib reprlib
2019-05-29 22:08:57 -05:00
coolreader18
c78dc520ad Don't clone PathBufs 2019-05-29 16:53:13 -05:00
coolreader18
11892816a7 Don't check env variables on wasm 2019-05-29 16:38:04 -05:00
Yonatan Goldschmidt
7ec3cef48e Add Lib/reprlib.py from CPython
Generated with:
`git -C ../cpython show 1bf9cc509326bc42cd8cb1650eb9bf64550d817e:Lib/reprlib.py > Lib/reprlib.py`

Required for `functools`.
2019-05-30 00:15:11 +03:00
coolreader18
1846100e7f Merge pull request #969 from Jongy/itertools-islice
itertools islice
2019-05-29 16:08:48 -05:00
Yonatan Goldschmidt
80b1f545e2 Add itertools.islice 2019-05-29 23:25:49 +03:00
Windel Bouwman
d70caf7dea Merge pull request #960 from youknowone/sys-getfilesystemencode
Add sys.getfilesystemencoding, sys.getfilesystemencodeerrors
2019-05-29 15:21:19 +02:00
Windel Bouwman
121cd43932 Merge pull request #901 from youknowone/str-encode
Add str.encode for utf-8
2019-05-29 15:20:36 +02:00
Jeong YunWon
c349f77207 Add {set,frozenset}.__r*__ 2019-05-29 21:51:20 +09:00
Jeong YunWon
ba4ac902eb PySet/PyFrozenSet doesn't call PyObject::new 2019-05-29 21:51:20 +09:00
Jeong YunWon
979e1253ae Fix set/frozenset comparison 2019-05-29 21:51:20 +09:00
Jeong YunWon
31c88721e6 Refactor PySet with try_set_inner! 2019-05-29 21:51:20 +09:00
Jeong YunWon
89729c3155 PyClassImpl for PySet, PyFrozenSet 2019-05-29 21:51:20 +09:00
coolreader18
5bd36ad9c5 Merge pull request #927 from youknowone/set-collision
Fix set() hash collision
2019-05-29 07:44:31 -05:00
Jeong YunWon
59476c65bb PyBytes::from_string 2019-05-29 21:27:58 +09:00
Jeong YunWon
7f2560c9e1 Add str.encode for utf-8 2019-05-29 21:25:34 +09:00
jgirardet
ad357d08af normalize_encoding 2019-05-29 21:24:51 +09:00
Jeong YunWon
3675ce859a Add sys.getfilesystemencoding, sys.getfilesystemencodeerrors 2019-05-29 21:20:55 +09:00
Windel Bouwman
f113342c0c Merge pull request #1002 from RobertBerglund/bytearray.__setitem__
bytearray.__setitem__
2019-05-29 13:48:58 +02:00
rbrtberglund
eed9c44a74 improved PyByteInner.setitem 2019-05-29 00:02:58 +02:00
coolreader18
d2fdb3258a Merge branch 'master' into coolreader18/rustpythonpath 2019-05-28 16:25:47 -05:00
Windel Bouwman
d9be5aba35 Merge pull request #1004 from DanielShaulov/marshal_support
Add support for marshal with loads and dumps
2019-05-28 12:12:35 +02:00
rbrtberglund
9b4b2d7fa6 fixed SyntaxError: Got unexpected EOF in bytearray.py 2019-05-27 22:48:25 +02:00
rbrtberglund
7be801db2f implemented __setitem__ for bytearray 2019-05-27 22:22:20 +02:00
Daniel Shaulov
bd89c4e32b Reformat with rustfmt 2019-05-27 22:19:07 +03:00
Daniel Shaulov
b2f17a18ea Add support for marshal with loads and dumps 2019-05-27 22:09:47 +03:00
coolreader18
96df472d85 Merge pull request #999 from palaviv/_imp
Add _imp
2019-05-26 13:53:21 -05:00
Aviv Palivoda
042a673ea2 Use contains_key 2019-05-26 21:16:40 +03:00
coolreader18
770f54791e Fix ownership errors 2019-05-25 17:28:25 -05:00
coolreader18
017377061d Check RUSTPYTHONPATH as well as PYTHONPATH env variables 2019-05-25 15:52:44 -05:00
coolreader18
7ce111b16c Merge pull request #997 from ZapAnton/objstr_refactor_mul
objstr: Refactored the 'mul' method
2019-05-25 12:11:44 -05:00
coolreader18
d0d4cb56c5 Merge pull request #998 from palaviv/frozen
Support frozen modules
2019-05-25 12:10:11 -05:00
ZapAnton
a2e64c0425 objstr: Replaced the unwrap_or with the OverflowError 2019-05-25 16:38:51 +03:00
Aviv Palivoda
7a467781e2 Add _imp.is_builtin 2019-05-25 15:34:18 +03:00
Aviv Palivoda
8197b17c14 Add empty _imp locks methods 2019-05-25 15:07:51 +03:00
Aviv Palivoda
2c74d7cc12 Add _imp 2019-05-25 15:02:03 +03:00
Aviv Palivoda
f33d15ab6a Test frozen modules import 2019-05-25 11:15:17 +03:00
Aviv Palivoda
a38f205f0e Add support for frozen modules 2019-05-25 11:13:25 +03:00
ZapAnton
e38c54985e objstr: Replaced the if-else construct with the max function 2019-05-24 20:37:47 +03:00
ZapAnton
fedbd29051 objstr: Refactored the 'mul' method
- Used `str::repeat` instead of manually building the result string
- Rewritten the int type check to return error at the beginning of the
method
- Replaced the `unwrap` calls with the single `unwrap_or`
2019-05-24 13:01:15 +03:00
Windel Bouwman
606a336fdf Merge pull request #996 from palaviv/io-context
RawIOBase inherits IOBase
2019-05-24 11:03:13 +02:00
Aviv Palivoda
8afb6a201c RawIOBase inherits IOBase 2019-05-24 10:23:30 +03:00
Shitong Wen
813c6112e6 add crc32 test 2019-05-23 16:30:19 +08:00
Shitong Wen
21bffc8ffa add crc32 test 2019-05-23 16:11:17 +08:00
Shitong Wen
fdd569cb8b add crc32 2019-05-23 16:08:12 +08:00
stwen77
95ddd55081 Merge pull request #4 from RustPython/master
refresh
2019-05-22 19:20:44 +08:00
Windel Bouwman
61e752e2b0 Merge pull request #994 from mkurnikov/simplify-with-cloned
Simplify PyFuncArgs get_kwarg/get_optional_kwarg with cloned()
2019-05-22 13:02:50 +02:00
Maxim Kurnikov
737ec52365 simplify PyFuncArgs get_kwarg/get_optional_kwarg with cloned() 2019-05-22 12:47:28 +03:00
Windel Bouwman
59fa46d5c3 Merge pull request #977 from adrian17/master
Fix no-arg dir(), convert it to new args style
2019-05-22 11:20:33 +02:00
Windel Bouwman
6b3b132343 Merge pull request #993 from mkurnikov/move-to-indexmap
Move PyFuncArgs.kwargs to IndexMap, implement PEP-468
2019-05-22 11:17:51 +02:00
Maxim Kurnikov
b5352da2c0 fix formatting 2019-05-22 03:30:30 +03:00
Maxim Kurnikov
0098e8485a move PyFuncArgs.kwargs to IndexMap 2019-05-22 03:18:15 +03:00
coolreader18
9ff9404ec8 Merge pull request #992 from sanxiyn/fix-rsplit
Fix rsplit
2019-05-21 09:48:14 -05:00
Seo Sanghyeon
433434a1bb Fix rsplit 2019-05-21 23:01:04 +09:00
Windel Bouwman
5ff766adb6 Merge pull request #976 from sanxiyn/pwd
Implement pwd module
2019-05-21 14:49:30 +02:00
Windel Bouwman
c01a867da5 Merge pull request #974 from stwen77/add_int_to_bytes
Add to_bytes for int
2019-05-21 14:47:31 +02:00
Windel Bouwman
002140ad69 Merge pull request #991 from Jongy/tuple-remove-refcell
Remove RefCell from tuple
2019-05-21 14:46:20 +02:00
Yonatan Goldschmidt
84684e5f7d Don't use RefCell in tuple object 2019-05-19 23:57:32 +03:00
coolreader18
1ea0192ea3 Merge pull request #986 from Jongy/itertools-chain
Add `itertools.chain`
2019-05-19 15:30:07 -05:00
coolreader18
347d9e7510 Merge pull request #985 from RobertBerglund/exit
Add exit/quit builtin function
2019-05-19 15:24:34 -05:00
Yonatan Goldschmidt
802f07980e Remove tuple handling from get_elements_cell
Like my HEAD, this shouldn't be allowed for a tuple (and the
only call-site of this function doesn't run on tuples anyway).
2019-05-19 23:01:10 +03:00
Yonatan Goldschmidt
9ad527c800 Remove tuple handling from get_mut_elements
This function is unused anyway; But even was it used, it makes no sense
to return mutable references to tuple items, when the tuple holding them
is immutable.
2019-05-19 23:01:05 +03:00
Yonatan Goldschmidt
9bf386ea87 Add itertools.chain 2019-05-19 22:33:47 +03:00
coolreader18
bb14858f03 Merge branch 'master' of github.com:RustPython/RustPython 2019-05-19 14:05:23 -05:00
coolreader18
0cb1b73714 Merge branch 'palaviv-move-fspath' 2019-05-19 14:05:13 -05:00
coolreader18
8f8194ae13 Fix os.rs 2019-05-19 14:05:09 -05:00
coolreader18
0c19cf0d25 Merge branch 'move-fspath' of https://github.com/palaviv/RustPython into palaviv-move-fspath 2019-05-19 14:03:20 -05:00
coolreader18
297e507197 Merge pull request #990 from skinny121/simple_namespace
Add SimpleNamespace and sys.implementation
2019-05-19 14:02:24 -05:00
coolreader18
4ada5bf530 Merge pull request #972 from sanxiyn/re-escape
Implement re.escape
2019-05-19 13:20:22 -05:00
Adrian Wielgosik
1e7fa52e0f Fix no-arg dir(), convert it to new args style 2019-05-19 12:27:08 +02:00
Seo Sanghyeon
347d1fd240 Enable pwd module only on Unix 2019-05-19 13:16:37 +09:00
Seo Sanghyeon
36412c57a4 Implement pwd module 2019-05-19 12:52:38 +09:00
coolreader18
a967171ed9 Merge pull request #989 from sanxiyn/update-rustyline
Update rustyline to 4.1.0 to fix nightly build
2019-05-18 22:35:37 -05:00
Ben Lewis
964256439b Update vm/src/obj/objnamespace.rs
Co-Authored-By: coolreader18 <33094578+coolreader18@users.noreply.github.com>
2019-05-19 15:25:52 +12:00
ben
52039845dd Use closure for generated properties in struct sequences. 2019-05-19 15:23:51 +12:00
ben
60c9d5004a Add SimpleNamespace and sys.implementation 2019-05-19 15:01:22 +12:00
Seo Sanghyeon
b9814ce3c7 Update rustyline to 4.1.0 to fix nightly build 2019-05-19 12:00:36 +09:00
rbrtberglund
bb93977a7e applied suggestions to improve exit function implementation 2019-05-19 00:42:55 +02:00
ben
8b657ab81e Add documentation for sys.flags 2019-05-19 10:32:07 +12:00
ben
2ca96c8ae1 Add sys.flags by creating a pystruct_sequence macro 2019-05-19 10:17:21 +12:00
coolreader18
8359c6e031 Merge pull request #983 from ypyf/type_new
improve error message for type_new
2019-05-18 17:12:43 -05:00
coolreader18
b5fa32ec95 Merge pull request #987 from Jongy/itertools-starmap
Add `itertools.starmap`
2019-05-18 16:31:58 -05:00
Yonatan Goldschmidt
7f310bd81f Add itertools.starmap 2019-05-18 23:53:40 +03:00
rbrtberglund
cb0367e708 Add exit/quit builtin function 2019-05-18 16:14:43 +02:00
coolreader18
9ee3bad3c1 Merge pull request #984 from sanxiyn/fix-wasm-test
Avoid timeout in WASM test
2019-05-17 12:12:41 -05:00
Seo Sanghyeon
b76da2ad05 Avoid timeout in WASM test 2019-05-17 18:58:59 +09:00
coolreader18
9888d27e61 Merge pull request #981 from youknowone/frexp
Add math.frexp
2019-05-16 21:37:34 -05:00
coolreader18
23344ddf8a Merge pull request #982 from youknowone/float-fromhex
Add float.fromhex float.hex
2019-05-16 21:33:40 -05:00
coolreader18
8759e7e513 Merge pull request #980 from youknowone/complex-hash
Add complex.__hash__
2019-05-16 21:25:46 -05:00
Jeong YunWon
ca912a168d Add float.to_hex 2019-05-17 03:24:31 +09:00
Jeong YunWon
ceca2ed98e Add float.fromhex 2019-05-17 02:35:39 +09:00
Jeong YunWon
d223af645b Add math.frexp 2019-05-17 01:12:43 +09:00
ypyf
83c5a3d330 improve error message for type_new 2019-05-16 20:35:40 +08:00
Jeong YunWon
87fc4cc470 Add complex.__hash__ 2019-05-16 06:21:33 +09:00
Jeong YunWon
81186ea5b7 Fix set() hash collision based on dictdatatype::Dict 2019-05-16 00:02:39 +09:00
Jeong YunWon
cc9dcbc9f8 Refactor dictdatatype::Dict 2019-05-16 00:01:44 +09:00
Jeong YunWon
13187fad5c Fix dictdatatype::Dict eq to regard __bool__ 2019-05-15 23:25:05 +09:00
coolreader18
54152b877b Merge pull request #970 from sanxiyn/remove-types
Replace types module with pure Python version
2019-05-14 20:46:17 -05:00
Shitong Wen
68a1a9f648 add to_bytes for int 2019-05-14 16:56:50 +08:00
coolreader18
15d2a3d318 Merge pull request #973 from sanxiyn/remove-extern-crate
Remove extern crate unneeded for Rust 2018
2019-05-13 23:51:37 -05:00
Seo Sanghyeon
189bf171ab Remove extern crate unneeded for Rust 2018 2019-05-14 12:24:44 +09:00
Seo Sanghyeon
5cff843782 Implement re.escape 2019-05-13 19:41:06 +09:00
Adam
2c747168de Merge pull request #926 from youknowone/number-hashes
Fix number hashes for small numbers
2019-05-13 09:02:19 +01:00
Windel Bouwman
0e56bb4e8c Merge pull request #965 from Jongy/itertools-takewhile
Itertools takewhile
2019-05-13 08:13:11 +02:00
coolreader18
82e424acaa Merge branch 'master' into move-fspath 2019-05-12 21:46:43 -05:00
Seo Sanghyeon
b76cb680e9 Comment out unsupported code from types.py 2019-05-13 11:44:12 +09:00
Seo Sanghyeon
b048a66bc3 Copy types.py from CPython 2019-05-13 11:42:16 +09:00
Seo Sanghyeon
29fff5ab4d Remove types module 2019-05-13 11:41:46 +09:00
stwen77
0cd1ca5f80 Merge pull request #3 from RustPython/master
pull
2019-05-13 10:41:28 +08:00
coolreader18
b01d7564b8 Merge pull request #964 from youknowone/os-supports-placeholders
Add os.supports_* placeholders
2019-05-12 16:23:38 -05:00
Windel Bouwman
b8c788197e Add walrus operator to lexer and try to make lexer code cleaner. 2019-05-12 22:35:28 +02:00
Yonatan Goldschmidt
98d90c830b Add itertools.takewhile 2019-05-12 23:16:23 +03:00
Jeong YunWon
64afd5ccf8 Add os.supports_* placeholders 2019-05-13 01:15:19 +09:00
Jeong YunWon
7a64f3e797 Fix dict hash impl 2019-05-13 01:10:54 +09:00
Jeong YunWon
c768b25673 Refine hash types and refactor hash impl 2019-05-13 01:10:52 +09:00
Jeong YunWon
3bebe44896 Fix int.__hash__ 2019-05-13 01:09:51 +09:00
Jeong YunWon
2c77dc208f Add float.__hash__ 2019-05-13 01:09:51 +09:00
Jeong YunWon
72043dac99 Fix builtin hash() 2019-05-13 01:09:51 +09:00
Windel Bouwman
95a894a443 Merge pull request #954 from youknowone/property-kwargs
Fix property to take keyword arguments
2019-05-12 16:15:01 +02:00
Windel Bouwman
e1416f5ecc Merge pull request #967 from skinny121/str_xwith_tuple_arg
Accept tuple for first arg in str.startswith and str.endswith
2019-05-12 16:13:25 +02:00
Windel Bouwman
5273bdc836 Merge pull request #955 from youknowone/sys-builtin_module_names
Add sys.builtin_module_names
2019-05-12 15:07:45 +02:00
Windel Bouwman
878cc3b120 Merge pull request #943 from Furyzer0/master
[WIP] implement str.translate and str.maketrans
2019-05-12 15:04:31 +02:00
Windel Bouwman
41f4cdc6f9 Merge pull request #952 from youknowone/fix-exec-locals
Fix exec to populate locals only when globals() is not given
2019-05-12 15:03:01 +02:00
Windel Bouwman
b5140a9924 Merge pull request #953 from youknowone/classmethod-func
Add classmethod.__func__
2019-05-12 12:53:26 +02:00
Jeong YunWon
ddf676569a Add sys.builtin_module_names 2019-05-12 19:18:37 +09:00
Jeong YunWon
e311b4f156 Fix exec to populate locals only when globals() is not given 2019-05-12 19:15:39 +09:00
zer0
04c017d268 unit testing for str.maketrans 2019-05-12 12:47:23 +03:00
Windel Bouwman
0a1399a42b Merge pull request #962 from skinny121/os_stat_time
Add st_{a,m,c}time to os.stat
2019-05-12 11:42:57 +02:00
Windel Bouwman
937704fbd9 Merge pull request #881 from youknowone/globals-builtins
Add __builtins__ to globals()
2019-05-12 11:40:07 +02:00
Windel Bouwman
9f39fa50c8 Merge pull request #949 from Jongy/itertools-repeat
Itertools repeat
2019-05-12 11:36:35 +02:00
Windel Bouwman
2261988648 Merge pull request #948 from Jongy/itertools
Itertools
2019-05-12 11:34:22 +02:00
ben
90711f10a0 Accept tuple for first arg in str.startswith and str.endswith 2019-05-12 13:14:27 +12:00
zer0
764215151d more idiomatic code 2019-05-12 00:40:43 +03:00
zer0
b94923314d removed import warning 2019-05-12 00:00:21 +03:00
zer0
268cb8d217 fix str.maketrans 2 and 3 arguments cases 2019-05-11 23:58:42 +03:00
ben
645c6dec48 Add wait between file modification and access 2019-05-12 08:55:39 +12:00
ben
f2703511b9 Fix dead code warning on windows and disable access time tests
as file access time on windows has quite bad resolution.
2019-05-12 08:26:37 +12:00
ben
4070baa6ac Add fsync and more tests for file times 2019-05-12 07:51:14 +12:00
coolreader18
9dcfacbf3b Merge pull request #963 from palaviv/sys-platform
Add sys.platform
2019-05-11 13:50:46 -05:00
Aviv Palivoda
d96d04f0fd Add os.fspath tests 2019-05-11 18:08:47 +03:00
Aviv Palivoda
b54354860f Move fspath to _os 2019-05-11 18:06:06 +03:00
Aviv Palivoda
d1c95d1c51 Remove patch in posixpath.py 2019-05-11 17:17:00 +03:00
Windel Bouwman
c276357c8e Merge pull request #961 from palaviv/os-cwd
os.{getcwd,chdir}
2019-05-11 14:45:07 +02:00
Windel Bouwman
57e250f9b2 Merge pull request #957 from Jongy/binascii
Binascii
2019-05-11 14:43:08 +02:00
Yonatan Goldschmidt
12e831380d Add itertools.repeat 2019-05-11 15:42:11 +03:00
Windel Bouwman
ad86bd5a37 Merge pull request #951 from youknowone/str-isidentifier
Fix str.isidentifier() and add tests snippets
2019-05-11 14:35:38 +02:00
Yonatan Goldschmidt
322aff70df Add binascii.b2a_hex, binascii.a2b_hex 2019-05-11 12:01:35 +03:00
Yonatan Goldschmidt
070529d8c7 Add binascii.unhexlify 2019-05-11 12:01:35 +03:00
Yonatan Goldschmidt
8dd664ef20 Add binascii.hexlify 2019-05-11 12:01:35 +03:00
Yonatan Goldschmidt
f7531d8b08 Add binascii module skeleton 2019-05-11 11:57:46 +03:00
Yonatan Goldschmidt
ce514d2aa5 Add itertools.count 2019-05-11 11:48:27 +03:00
Yonatan Goldschmidt
7490724b65 Add itertools module skeleton 2019-05-11 11:48:26 +03:00
Aviv Palivoda
152c1654d6 Add sys.platform 2019-05-11 11:43:11 +03:00
ben
b01e960da7 Add st_{a,m,c}time to os.stat 2019-05-11 19:15:54 +12:00
Aviv Palivoda
c7e9bdd464 Add tests for chdir and getcwd 2019-05-11 09:29:24 +03:00
Aviv Palivoda
f0fd371b69 Add os.chdir 2019-05-11 09:29:09 +03:00
Aviv Palivoda
8294ac5451 Add os.getcwd 2019-05-11 09:17:23 +03:00
Jeong YunWon
c0f14eace3 Fix str.isidentifier() and add tests snippets 2019-05-11 14:30:47 +09:00
zer0
6e05795521 added str.maketrans 2019-05-11 01:03:22 +03:00
Jeong YunWon
268164e957 Fix property to take keyword arguments 2019-05-11 06:03:53 +09:00
Jeong YunWon
eab5d42ee6 Adapt PyClassImpl for PyProperty 2019-05-11 06:03:45 +09:00
zer0
b15a584168 added small test to snippets 2019-05-10 23:47:11 +03:00
zer0
2f253ca054 cargo fmt 2019-05-10 23:31:11 +03:00
Jeong YunWon
7564833b6e Add classmethod.__func__ 2019-05-11 05:30:27 +09:00
Jeong YunWon
b720681c7b PyClassImpl for PyClassMethod 2019-05-11 05:30:27 +09:00
Jeong YunWon
509394080b Inject __builtins__ to scope only when it doesn't exist 2019-05-11 03:05:18 +09:00
Jeong YunWon
f69c79bdc7 Add __builtins__ to globals() 2019-05-11 01:17:22 +09:00
coolreader18
0a683f2be6 Merge pull request #946 from stwen77/fix_floor_div
fix floor div for int
2019-05-10 08:25:24 -05:00
coolreader18
385d4851d1 Merge pull request #942 from Jongy/fix-unused-macros-warn
Define `os_unix_stat_inner` only when required
2019-05-10 08:00:20 -05:00
Windel Bouwman
d14fb6edbb Merge pull request #947 from palaviv/file
Support __file__
2019-05-10 14:41:12 +02:00
Aviv Palivoda
fc1a063a2c Add __file__ for file executed from main 2019-05-10 14:06:23 +03:00
Aviv Palivoda
da3df8a0ae Add __file__ for imported modules 2019-05-10 13:58:10 +03:00
Yonatan Goldschmidt
fe37ecf8d3 Define os_unix_stat_inner only when required
Avoids warn when building on Windows.
2019-05-10 11:24:28 +03:00
Shitong Wen
50c119a503 fix floor div for int 2019-05-10 14:21:09 +08:00
Windel Bouwman
352bd85681 Merge pull request #944 from sapir/more-bytearray-methods
More bytearray methods
2019-05-10 07:06:30 +02:00
stwen77
bc6e3eb0c4 Merge pull request #2 from RustPython/master
refresh
2019-05-10 10:37:26 +08:00
Y. Sapir
32950bd0bc Implement bytearray.reverse 2019-05-10 00:33:14 +03:00
Y. Sapir
e5bae56ccb Implement bytearray.remove 2019-05-10 00:33:14 +03:00
Y. Sapir
43cd50270f Implement bytearray.insert 2019-05-10 00:33:14 +03:00
Y. Sapir
485ffa01a2 Implement bytearray.extend 2019-05-10 00:33:14 +03:00
Y. Sapir
04ce9ea185 Implement bytearray.copy 2019-05-10 00:33:12 +03:00
Y. Sapir
87844ff434 Implement bytes.__mul__ and __rmul__ 2019-05-09 23:51:20 +03:00
Y. Sapir
94d1b6585c Implement bytearray.__mul__, __imul__ and __rmul__ 2019-05-09 23:50:20 +03:00
Windel Bouwman
e974e57b4c Merge pull request #941 from stwen77/int_from_bytes
add from_bytes for int
2019-05-09 16:57:36 +02:00
zer0
59ae590771 formatting 2019-05-09 17:09:38 +03:00
zer0
3196b6be73 added str.translate 2019-05-09 16:59:40 +03:00
coolreader18
76a0020e26 Merge pull request #940 from sanxiyn/test-all-any
Test all and any
2019-05-09 07:37:16 -05:00
Shitong Wen
86fcc97730 int_from_bytes 2019-05-09 20:06:28 +08:00
Seo Sanghyeon
d3966af25d Test all and any 2019-05-09 15:54:07 +09:00
Shitong Wen
e9fea281fb add from_bytes for int 2019-05-09 11:02:34 +08:00
Shitong Wen
036b184dd3 add from_bytes for int 2019-05-09 10:52:10 +08:00
stwen77
bdb9445e93 Merge pull request #1 from RustPython/master
pull
2019-05-09 10:34:09 +08:00
coolreader18
252ac4ae26 Merge pull request #938 from sanxiyn/revert-mappingproxy
Revert mappingproxy hack
2019-05-08 21:04:47 -05:00
Seo Sanghyeon
7d0ab6395b Revert mappingproxy hack 2019-05-09 09:45:41 +09:00
coolreader18
80e9bd8ab6 Merge pull request #931 from jgirardet/title
add bytes/byterray title
2019-05-08 12:13:59 -05:00
jgirardet
4c09505865 Merge branch 'master' into title 2019-05-08 18:16:02 +02:00
coolreader18
099b1f4752 Merge pull request #936 from palaviv/os-path
Os path
2019-05-08 10:44:08 -05:00
Aviv Palivoda
f5653cbc68 Use supported raise from 2019-05-08 16:47:49 +03:00
Aviv Palivoda
216f69e635 Use os.path 2019-05-08 16:46:45 +03:00
Aviv Palivoda
ac9ddf7756 Add CPython ntpath.py 2019-05-08 16:32:09 +03:00
Aviv Palivoda
daae7aa998 Add CPython posixpath.py 2019-05-08 16:31:21 +03:00
Aviv Palivoda
6153e2d6ca Add CPython genericpath.py 2019-05-08 16:25:33 +03:00
Windel Bouwman
6f31cf7554 Merge pull request #913 from Jongy/str-preallocate-and-rmul
Preallocate strings in a smarter way + add str.rmul
2019-05-07 21:54:31 +02:00
Windel Bouwman
382e566315 Merge pull request #930 from jgirardet/byteraayfollow
add split, rsplit, partition, rpartition, expandtabs, spitlines, zfill,replace to bytearray
2019-05-07 21:50:39 +02:00
Windel Bouwman
d76e4d5433 Merge pull request #934 from Jongy/range-arg3-zero
Raise an error on `range()` with step=0
2019-05-07 21:30:00 +02:00
Windel Bouwman
c9ba9192f6 Merge pull request #922 from palaviv/os-symlink
Symlinks
2019-05-07 21:28:46 +02:00
Windel Bouwman
aed8e03473 Merge pull request #932 from youknowone/dict-unpacking
Add dict unpacking support for literal
2019-05-07 21:25:39 +02:00
coolreader18
7727d09691 Merge pull request #933 from Jongy/nameerror-on-bad-del
Nameerror on bad del
2019-05-07 13:31:58 -05:00
Yonatan Goldschmidt
d4a3d7eb01 Raise an error on range() with step=0 2019-05-06 23:23:48 +03:00
Jeong YunWon
e12c6813ef Add dict unpacking support for literal 2019-05-07 04:42:58 +09:00
Yonatan Goldschmidt
04bff49ee0 Raise proper NameError on del when name is not defined
Closes #929.
2019-05-06 22:40:00 +03:00
jgirardet
dc18356947 add bytes/byterray title 2019-05-06 21:37:15 +02:00
jgirardet
ed94ddba2d add split, rsplit, partition, rpartition, expandtabs, spitlines, zfill,
replace to bytearray
2019-05-06 21:04:09 +02:00
Yonatan Goldschmidt
e35dec64f9 Add vm.new_name_error helper 2019-05-06 21:47:18 +03:00
Windel Bouwman
abf0a329ee Merge pull request #924 from Jongy/builtin-ord-improvements
Builtin ord improvements
2019-05-06 18:14:23 +02:00
Windel Bouwman
7ae533f860 Merge pull request #911 from sapir/fix-clippy-float-error
Fix clippy error about float comparison
2019-05-06 18:12:25 +02:00
Windel Bouwman
567fc4e94f Merge pull request #916 from jgirardet/bytergevalue
rewrite pybytearray with pybyteinner
2019-05-06 18:09:12 +02:00
Windel Bouwman
68d1fb8957 Merge pull request #915 from jgirardet/split
add  bytes split, expendtab, splitlines, zfil, replace
2019-05-06 17:46:43 +02:00
Windel Bouwman
720f2fed44 Merge pull request #925 from Jongy/builtin-chr-raise-error
Raise error on out-of-range input in `chr()`
2019-05-06 17:38:25 +02:00
Yonatan Goldschmidt
c656c5cc72 Add chr() test snippets 2019-05-06 03:10:53 +03:00
Yonatan Goldschmidt
ea535856b4 Raise error on out-of-range input in chr() 2019-05-06 03:04:19 +03:00
jgirardet
5a95c5af22 remove unittests 2019-05-05 23:29:49 +02:00
Windel Bouwman
51245639ab Merge pull request #923 from youknowone/floatint-format
str(1.0) == '1.0'
2019-05-05 21:18:43 +02:00
Windel Bouwman
e1bdae000c Merge pull request #904 from RustPython/async-stuff
Add async def and async for parsing.
2019-05-05 21:16:29 +02:00
Aviv Palivoda
ecd6e85f3c Fix windows build try 2 2019-05-05 21:32:49 +03:00
Aviv Palivoda
c06b6ccc96 Fix windows build 2019-05-05 21:19:20 +03:00
Yonatan Goldschmidt
6a73790b26 Raise proper error when string of length 0 is given to ord() 2019-05-05 20:24:54 +03:00
Yonatan Goldschmidt
717c96837e Borrow instead of cloning in ord() 2019-05-05 20:24:20 +03:00
Jeong YunWon
6b495eac1e str(1.0) == '1.0' 2019-05-06 02:14:28 +09:00
Aviv Palivoda
2c30e83896 Add follow_symlinks to stat 2019-05-05 20:04:39 +03:00
Aviv Palivoda
260af4d877 Add follow_symlinks to DirEntry.{is_file, is_dir} 2019-05-05 19:40:01 +03:00
Aviv Palivoda
914f32afc3 Add symlink tests 2019-05-05 19:17:30 +03:00
Aviv Palivoda
5bd23b4fb6 is_dir and is_file follow_symlink by default 2019-05-05 19:14:34 +03:00
Windel Bouwman
6228a207e1 Merge pull request #912 from sapir/repl-underscore
Repl underscore
2019-05-05 11:21:20 +02:00
coolreader18
de6bc057fb Merge pull request #919 from sapir/check-parent-equiv
Include reimplemented methods in whats_left.sh, and skip inherited methods
2019-05-04 19:11:48 -05:00
Y. Sapir
c38a3711d0 Include reimplemented methods in whats_left.sh, and skip inherited methods 2019-05-05 00:05:13 +03:00
Y. Sapir
88c3852b73 Don't check for methods on iter - it's a builtin function 2019-05-05 00:02:10 +03:00
Windel Bouwman
ee2b2a82fc Merge pull request #909 from sapir/add-bool-methods
Add bool methods
2019-05-04 22:34:43 +02:00
Windel Bouwman
a36fb77d42 Merge pull request #910 from sapir/print-file-parameter
Print file parameter
2019-05-04 22:33:55 +02:00
Y. Sapir
1a5bddc41b Fix clippy error about float comparison 2019-05-04 23:32:49 +03:00
Aviv Palivoda
6225de3098 Change file attributes to consts 2019-05-04 23:15:22 +03:00
Y. Sapir
bbb8df797f Refactor builtin_print to avoid duplicate loop code 2019-05-04 22:55:20 +03:00
Y. Sapir
ad2499f432 Implement print file parameter 2019-05-04 22:55:20 +03:00
Y. Sapir
4cce44ab31 Add test for print file parameter 2019-05-04 22:55:20 +03:00
Y. Sapir
45d7c383cd Implement bool.__ror__, __rand__ and __rxor__ 2019-05-04 22:27:43 +03:00
Windel Bouwman
c217685eeb Merge pull request #918 from palaviv/except-block
Except block
2019-05-04 18:49:23 +02:00
coolreader18
e91996b4e6 Merge pull request #896 from youknowone/pycomplex
PyComplex extend_class, uniform operand handling, missing methods + Complex64 IntoPyObject
2019-05-04 11:33:21 -05:00
coolreader18
406be20fe0 Merge pull request #914 from palaviv/wasm-import
Add browser.load_module
2019-05-04 10:32:07 -05:00
Aviv Palivoda
6c1dca7cc2 Add DirEntry.is_symlink 2019-05-04 18:14:21 +03:00
Aviv Palivoda
46ad1f5449 Add os.symlink 2019-05-04 18:01:23 +03:00
Aviv Palivoda
810b8ee4d0 Simplify PopException 2019-05-04 17:19:59 +03:00
Aviv Palivoda
32714f889e Remove empty params from ExceptHandler 2019-05-04 17:18:04 +03:00
Windel Bouwman
231343d63b Merge pull request #917 from palaviv/os-stat-2
Extend os.stat
2019-05-04 12:28:16 +02:00
Windel Bouwman
4a43872052 Merge pull request #903 from RustPython/lexer-error-improvements
Improve handling of lexical errors.
2019-05-04 11:56:33 +02:00
Aviv Palivoda
159063bb47 Convert windows file attributes to unix mode 2019-05-04 12:50:28 +03:00
Aviv Palivoda
d803acfdc5 Add yield in except test 2019-05-04 12:32:40 +03:00
Aviv Palivoda
5270da3934 Add ExceptHandler block 2019-05-04 12:32:40 +03:00
Aviv Palivoda
775be3a36a Add stat mode tests 2019-05-04 11:07:56 +03:00
Aviv Palivoda
b96f4a5758 Add CPython stat.py file 2019-05-04 11:00:36 +03:00
Aviv Palivoda
01b245f5df Add stat to DirEntry 2019-05-04 10:59:32 +03:00
jgirardet
5864c6e063 rewrite pybytearray with pybyteinner 2019-05-04 01:14:08 +02:00
Aviv Palivoda
c57fd1b96e Remove closure 2019-05-03 23:52:02 +03:00
Jeong YunWon
88e64adc56 Add complex __pow__ and __rpow__ 2019-05-04 01:05:27 +09:00
Jeong YunWon
930c8eef50 Add complex.{__mod__, __rmod__, __divmod__, __rdivmod__} 2019-05-04 01:05:27 +09:00
Jeong YunWon
9523baf5ac complex [r]truediv, [r]floordiv 2019-05-04 01:05:27 +09:00
Jeong YunWon
7c8880fb4a complex overflow message test 2019-05-04 01:05:27 +09:00
Jeong YunWon
2a2d0e4764 Add complex.__rmul__ 2019-05-04 01:05:27 +09:00
Jeong YunWon
982bbd69d8 complex.__bool__ uses Zero::is_zero instead of zero() 2019-05-04 01:05:27 +09:00
Jeong YunWon
61de5f2efc complex.__eq__ using try_float 2019-05-04 01:05:27 +09:00
Jeong YunWon
9a7fadcb6c Refactor PyComplex using try_complex 2019-05-04 00:59:19 +09:00
Jeong YunWon
7b438d9be8 impl IntoPyObject for Complex64 2019-05-04 00:59:19 +09:00
Jeong YunWon
9448254914 PyComplex uses extend_class for __new__ and __doc__ 2019-05-04 00:59:19 +09:00
Windel Bouwman
e578dcfc46 Merge pull request #899 from youknowone/float-complex
Add numbers.Complex impl to float + extend_class
2019-05-03 17:22:12 +02:00
Windel Bouwman
daf70424d2 Merge pull request #847 from jgirardet/kwargs
add other bytes method
2019-05-03 17:15:09 +02:00
Aviv Palivoda
d121b422b6 Add browser.load_module 2019-05-03 16:15:18 +03:00
Yonatan Goldschmidt
857a7014c2 Enable and extend strings/membership tests 2019-05-03 15:11:14 +03:00
Adam
1d6e8d5aa5 Merge pull request #905 from RustPython/mappingproxy
Mappingproxy
2019-05-03 09:58:37 +01:00
Windel Bouwman
199fce22be Merge pull request #900 from youknowone/int-pow
Fix int.__pow__
2019-05-03 07:30:16 +02:00
Y. Sapir
821959b889 Save REPL return value as _ 2019-05-03 03:10:03 +03:00
Y. Sapir
29ec26917f Return last expression in compile Mode::Single 2019-05-03 03:10:03 +03:00
Yonatan Goldschmidt
d1730a53ad Add basic string multiplication tests 2019-05-03 03:07:15 +03:00
Yonatan Goldschmidt
f12268f79a Implement str.__rmul__ 2019-05-03 03:07:15 +03:00
Yonatan Goldschmidt
a118497a4b Preallocate cloned strings with the minimum expected length
Similar to 620bea78.
2019-05-03 03:07:15 +03:00
coolreader18
18264b2881 Merge pull request #907 from Jongy/str-title-preallocate
Preallocate output string of str.title() with required size
2019-05-02 18:38:15 -05:00
Y. Sapir
6f66e8440d Add tests for return type of bool.__or__ etc. 2019-05-03 01:54:18 +03:00
Y. Sapir
ea347dfdec Implement bool.__or__, __and__ and __xor__ 2019-05-03 01:54:18 +03:00
Y. Sapir
26306b528f Simplify PyInt.rxor to reuse PyInt.xor 2019-05-03 01:42:17 +03:00
Yonatan Goldschmidt
620bea7830 Preallocate output string of str.title() with required size 2019-05-03 01:14:06 +03:00
Adam Kelly
65d602571d Create mappingproxy type with __getitem__ and __contains__. 2019-05-02 16:45:00 +01:00
Adam Kelly
dd0c70f289 Fix typo in objobject. 2019-05-02 16:36:35 +01:00
Windel Bouwman
b3b523ffa9 Add await syntax. 2019-05-02 17:11:51 +02:00
Windel Bouwman
5bc1aa08dc Add async def and async for parsing. 2019-05-02 16:55:33 +02:00
Jeong YunWon
0bf7ff96b8 Special handling for base -1, 0, 1 for big exp 2019-05-02 23:11:00 +09:00
Jeong YunWon
c18615b6e5 Fix __builtins__.pow to perform modpow for 3rd argument 2019-05-02 22:59:08 +09:00
Jeong YunWon
8d4562b0bb Fix __builtins__.pow to reflect __rpow__ 2019-05-02 22:59:06 +09:00
Jeong YunWon
eb9ca06ee7 Add int.__rpow__ 2019-05-02 22:59:05 +09:00
Jeong YunWon
614378d720 Add int.__pow__ negative exp impl 2019-05-02 22:44:28 +09:00
Jeong YunWon
c138dea992 Remove int.__pow__ float handling 2019-05-02 14:23:35 +09:00
coolreader18
8f3b62ba0e Merge pull request #895 from youknowone/pyrange-extend
extend_class for PyRange
2019-05-01 20:15:58 -05:00
coolreader18
3051702a2d Merge branch 'master' into pyrange-extend 2019-05-01 20:15:50 -05:00
coolreader18
fc729fd610 Merge pull request #892 from youknowone/float-round
Add basic float.__round__ without ndigits support
2019-05-01 20:07:02 -05:00
coolreader18
fa148a4aed Merge branch 'master' into float-round 2019-05-01 20:06:52 -05:00
coolreader18
3e7d43e27c Merge pull request #889 from adrian17/iter-class
Convert iterators to pyclass macros
2019-05-01 16:32:46 -05:00
Adrian Wielgosik
c7fd54e809 Convert iterators to pyclass macros 2019-05-01 21:26:37 +02:00
Windel Bouwman
1247a35be9 Improve handling of lexical errors. 2019-05-01 21:05:21 +02:00
Windel Bouwman
1f002e8df3 Merge pull request #887 from youknowone/to_int
objint::to_int to call __int__
2019-05-01 19:08:54 +02:00
Jeong YunWon
4a598d03e2 Add float.imag, float.conjugate 2019-05-01 21:31:02 +09:00
Jeong YunWon
bb878a3402 PyFloat to use extend_class for __new__ and __doc__ 2019-05-01 21:31:02 +09:00
Windel Bouwman
08b716f694 Merge pull request #898 from youknowone/builtins-divmod
Fix __builtins__.divmod to reflect __rdivmod__
2019-05-01 14:23:38 +02:00
Windel Bouwman
eb5cef20ba Merge pull request #897 from youknowone/test-utils
Temporary fix to assertRaises and assert_raises prints errors
2019-05-01 14:11:23 +02:00
Windel Bouwman
7358017671 Merge pull request #902 from lili668668/bytearray_append
Add bytearray.append
2019-05-01 14:10:17 +02:00
Tzu-Yin Hong
4ef65d8ac3 Add bytearray.append 2019-05-01 15:53:28 +08:00
Jeong YunWon
0d891cba2c Temporary fix to assertRaises and assert_raises prints errors 2019-05-01 12:07:01 +09:00
coolreader18
b542b39f5e Merge pull request #893 from youknowone/float-overflow
PyFloat overflow handling + missing methods
2019-04-30 21:36:27 -05:00
Jeong YunWon
14dd85a596 Fix __builtins__.divmod to reflect __rdivmod__ 2019-05-01 05:14:52 +09:00
Jeong YunWon
22a35c9b90 extend_class for PyRangeIterator 2019-05-01 05:13:05 +09:00
jgirardet
0d505adbb5 use PyBytinner as arg 2019-04-30 22:01:45 +02:00
Jeong YunWon
1c814ff2b5 Add float.__rpow__ 2019-05-01 04:02:34 +09:00
Jeong YunWon
09710b5222 Add float.__rdivmod__ and div/mod tests 2019-05-01 03:40:28 +09:00
Jimmy Girardet
fd614b7a75 refactor split options 2019-04-30 20:24:12 +02:00
Jimmy Girardet
cf70323475 add replace 2019-04-30 20:24:12 +02:00
Jimmy Girardet
b60d7413b9 add zfill 2019-04-30 20:24:12 +02:00
jgirardet
29f674fa1d fix split with empty bytes 2019-04-30 20:24:12 +02:00
jgirardet
d89ca3c3e4 add spitlines 2019-04-30 20:24:12 +02:00
jgirardet
434985d6d0 add partition/reparition refactor split/rsplit 2019-04-30 20:24:12 +02:00
jgirardet
0af8ad05eb add expandstab 2019-04-30 20:24:12 +02:00
jgirardet
cfff7cbd63 add split and rsplit 2019-04-30 20:24:12 +02:00
Jeong YunWon
813307f8f9 Refactor PyFloat using try_float() 2019-05-01 01:22:56 +09:00
Jeong YunWon
a0ad4368c6 Add float.pow OverflowError handling 2019-05-01 01:22:52 +09:00
Jeong YunWon
a318e4e09e objfloat.rs try_float for common operand handling 2019-05-01 01:21:14 +09:00
Jimmy Girardet
5d13daef20 remove all try_as_bytes_like 2019-04-30 18:01:40 +02:00
Jeong YunWon
599f1f678f extend_class for PyRange 2019-05-01 00:51:47 +09:00
jgirardet
ece6601851 add PyByteInner as fn argument / use Either 2019-04-30 15:47:41 +02:00
Windel Bouwman
177704f1ea Merge pull request #891 from ntrinquier/add-methods-for-numeric-types
Add methods for the complex type
2019-04-30 08:16:44 +02:00
Jeong YunWon
c951cb3cfd float.__round__ for ndigits == 0 2019-04-30 06:09:48 +09:00
Jeong YunWon
132d34fc67 Add range.__eq__ 2019-04-29 15:10:59 -05:00
coolreader18
9c4a0710f3 Merge pull request #880 from youknowone/fix-range-negative
Fix range() to support negative index + Add range.__eq__
2019-04-29 15:09:20 -05:00
Jeong YunWon
b7c7591639 Fix float.__trunc__ to handle abnormal values 2019-04-30 03:30:35 +09:00
Jeong YunWon
4c8f655d4e float.__round__ inf/nan support 2019-04-30 03:30:30 +09:00
Nicolas Trinquier
490db0a84f Add support for complex type for the to_complex function 2019-04-29 20:13:01 +02:00
Jeong YunWon
68e15a2bd8 Add basic float.__round__ without ndigits support 2019-04-30 03:11:31 +09:00
coolreader18
fd91d26444 Merge pull request #890 from palaviv/exc-stack
Add exceptions stack to VirtualMachine
2019-04-29 13:07:00 -05:00
Aviv Palivoda
56ef6ec5f8 Change to is_some 2019-04-29 20:08:15 +03:00
Nicolas Trinquier
eebdbfe679 Add int and float methods for the complex type 2019-04-29 18:39:10 +02:00
Nicolas Trinquier
f8373aa38a Add mul method for the complex type 2019-04-29 18:34:35 +02:00
Windel Bouwman
e3e2e7f905 Merge pull request #869 from skinny121/isinstance_tuple_arg
Accept a tuple for the second argument of isinstance and issubclass
2019-04-29 13:34:40 +02:00
Adam
63a71d6b50 Merge pull request #855 from RustPython/nonlocal-errors
Add check for nonlocal on top level.
2019-04-29 11:30:39 +01:00
ben
4a4631a622 Use match_class instead of Either in isinstance/issubclass 2019-04-29 19:41:42 +12:00
ben
81dd5faa81 Accept a tuple for the second argument of isinstance and issubclass 2019-04-29 19:41:42 +12:00
Windel Bouwman
2c7f3b5bb1 Merge pull request #888 from youknowone/math-rounding
Add trunc, ceil, floor to math module
2019-04-29 08:05:15 +02:00
coolreader18
9feeee059e Merge pull request #886 from youknowone/pycomplex
Add complex.__bool__, complex.__sub__, OverflowError/float support of complex.__add__
2019-04-28 18:44:21 -05:00
Jeong YunWon
388b62aae2 objint::to_int to call __int__ 2019-04-29 04:39:52 +09:00
Jeong YunWon
6afe78c9a6 Add math.ceil / math.floor 2019-04-29 04:26:10 +09:00
Jeong YunWon
c3714c2eca Add math.trunc 2019-04-29 04:26:10 +09:00
Windel Bouwman
53dea486d2 Merge pull request #878 from sanxiyn/fix-just
Fix justification
2019-04-28 19:13:33 +02:00
Windel Bouwman
bea6b48d1f Merge pull request #885 from youknowone/pyfloat
Add __int__, __float__, __trunc__, __rmod__ to float
2019-04-28 19:08:32 +02:00
Aviv Palivoda
b72fc3bc9d Add test for #867 2019-04-28 19:20:16 +03:00
Aviv Palivoda
af7a89aa99 pop exception on context 2019-04-28 19:06:14 +03:00
Aviv Palivoda
f1551af0f5 Add tests - not working 2019-04-28 18:52:52 +03:00
Jeong YunWon
20b2f64cef Add float.__rmod__ 2019-04-28 22:46:21 +09:00
Jeong YunWon
304cea89b8 objint::get_float_value 2019-04-28 20:31:07 +09:00
Jeong YunWon
8047ab3d3e Add float tests 2019-04-28 20:03:30 +09:00
Jeong YunWon
4810a55c82 Add float.__trunc__ 2019-04-28 12:44:25 +09:00
Jeong YunWon
9dda776e25 Add float.__int__ / float.__float__ 2019-04-28 12:41:59 +09:00
Jeong YunWon
dc05459459 Add float.__sub__, float.__rsub__ 2019-04-28 12:20:45 +09:00
Jeong YunWon
a2625916f5 Fix complex.__add__ to support float 2019-04-28 12:01:54 +09:00
Jeong YunWon
2eae737f3d complex.__add__ can raises OverflowError 2019-04-28 06:52:54 +09:00
Jeong YunWon
15e4e678ca Add complex.__bool__ 2019-04-28 06:19:12 +09:00
Jeong YunWon
ed79ccc6b1 PyComplex uses PyClassImpl 2019-04-28 06:04:21 +09:00
Jeong YunWon
7fb98c91d2 PyFloat uses #[pyclass] #[pyimpl] #[pymethod] 2019-04-28 05:47:29 +09:00
Windel Bouwman
88e52ef842 Merge pull request #884 from adrian17/imul
Support list.__imul__
2019-04-27 21:08:39 +02:00
Windel Bouwman
a2858cee7e Merge pull request #882 from youknowone/add-type-name
Add type.__name__
2019-04-27 21:07:17 +02:00
Aviv Palivoda
60afbb4bf5 Don't pop exeption for context 2019-04-27 21:53:08 +03:00
Jeong YunWon
d87468a1cb Add type.__name__ 2019-04-28 03:21:26 +09:00
Adrian Wielgosik
9d40a4c9d8 Support list.__imul__ 2019-04-27 17:44:21 +02:00
Agent
180ec22d4b Add constants to os module (#883) 2019-04-27 09:41:19 -05:00
Aviv Palivoda
4b9bafc824 Remove in_exc_handler for Raise 2019-04-27 14:33:24 +03:00
Aviv Palivoda
462c8233f3 Add exceptions stack to VirtualMachine 2019-04-27 14:21:01 +03:00
Jeong YunWon
a7091ca88d Add range.__eq__ 2019-04-27 00:54:21 +09:00
Jeong YunWon
16353f4f54 range negative side bound error 2019-04-27 00:13:54 +09:00
Jeong YunWon
16152a1d32 Fix range() to support negative index 2019-04-27 00:06:29 +09:00
Seo Sanghyeon
0e9acdc12b Fix justification 2019-04-26 15:33:37 +09:00
Agent
6e867edb6d Fix json.loads (#876)
* Fix json.loads
2019-04-25 23:17:16 -05:00
coolreader18
13a8bc1c11 Merge pull request #875 from sanxiyn/test-json-dict
Enable dict round trip test for json
2019-04-25 20:41:30 -05:00
coolreader18
1088f7061c Merge pull request #874 from RustPython/coolreader18/os-android
Add a cfg for os.stat for android
2019-04-25 17:59:24 -05:00
coolreader18
e4698987bb Add a cfg for os.stat for android 2019-04-25 16:59:06 -05:00
Seo Sanghyeon
e6f08cf93e Enable dict round trip test for json 2019-04-26 06:29:01 +09:00
Windel Bouwman
950344990a Merge pull request #872 from ypyf/master
Fix os_stat for MacOS
2019-04-25 20:37:45 +02:00
Windel Bouwman
3145d2a8fd Merge pull request #870 from RustPython/dict_fromkeys
Dict fromkeys
2019-04-25 20:35:57 +02:00
coolreader18
b30b446fe2 Merge pull request #871 from sanxiyn/strip-arg
Implement stripping with arguments
2019-04-25 09:17:13 -05:00
Yan Feng
d48b59fd74 Fix os_stat for MacOS 2019-04-25 20:13:04 +08:00
Seo Sanghyeon
f38f263d93 Implement stripping with arguments 2019-04-25 20:33:30 +09:00
Adam Kelly
d3f4c8f6e1 Use unwrap_or_else for OptionalArg in dictionary. 2019-04-25 09:07:17 +01:00
Adam Kelly
4f0b17e84f Add dict.fromkeys. 2019-04-25 09:07:17 +01:00
Adam Kelly
1a48fb17df Add PyContext.new_classmethod 2019-04-25 09:07:17 +01:00
Adam Kelly
cad4a13cf7 Add utility methods for default optional args. 2019-04-25 09:07:17 +01:00
Adam
6f04bebae5 Merge pull request #866 from RustPython/dict_popitem
dict.popitem & dict.setdefault
2019-04-25 09:06:28 +01:00
Adam Kelly
1c43a6bfbe Add dict.setdefault. 2019-04-25 08:04:54 +01:00
Adam Kelly
ceac014a6c Add dict.popitem. 2019-04-25 08:04:24 +01:00
Windel Bouwman
a8b2d1384c Merge pull request #865 from sanxiyn/test-comparison-error
Test error cases of comparisons
2019-04-25 07:18:02 +02:00
coolreader18
291e33af16 Merge pull request #868 from skinny121/rpartition_bug
Fix rpartition bug
2019-04-24 18:28:22 -05:00
ben
d84b8b52a5 Fix the tuple from rpartition being in wrong order when sub isn't
contained within the string
2019-04-25 10:37:59 +12:00
Windel Bouwman
8982f567b0 Add nonlocal binding check. 2019-04-24 15:19:52 +02:00
Seo Sanghyeon
fb62653c5c Test error cases of comparisons 2019-04-24 19:28:21 +09:00
Windel Bouwman
1081ea048a Merge pull request #864 from sanxiyn/test-integer-literal
Test integer literals
2019-04-24 09:28:15 +02:00
Windel Bouwman
86acb7aa3a Merge pull request #860 from palaviv/os-stat
Add os.stat
2019-04-24 09:27:21 +02:00
Windel Bouwman
2b2165f459 Merge pull request #861 from youknowone/main-py
Add __main__.py support
2019-04-24 09:21:32 +02:00
Seo Sanghyeon
f9124f41a8 Test integer literals 2019-04-24 04:00:52 +09:00
Jeong YunWon
29c0d89033 test_run_script for filr/dir 2019-04-24 02:38:26 +09:00
Jeong YunWon
2eb97aa1e8 Add __main__.py support 2019-04-23 20:27:25 +09:00
Windel Bouwman
7f8217472e Merge pull request #859 from youknowone/dict-pop
Add built-in dict.pop
2019-04-23 07:12:00 +02:00
Jeong YunWon
1d5adc4353 Add built-in dict.pop 2019-04-23 10:34:06 +09:00
Aviv Palivoda
55bd00b600 Add stat_result.{st_size} 2019-04-22 18:52:35 +03:00
Aviv Palivoda
56958552f4 Add stat_result.{st_nlink, st_uid, st_gid} 2019-04-22 18:47:10 +03:00
Aviv Palivoda
9a1caa08c3 Add stat_result.{st_ino, st_dev} 2019-04-22 18:35:38 +03:00
Aviv Palivoda
384bf5b545 Add os.stat 2019-04-22 18:27:39 +03:00
coolreader18
b9082b02e0 Merge pull request #858 from youknowone/fix-readme
Fix README not to refer moved file
2019-04-22 07:55:54 -05:00
Jeong YunWon
9f7676589f Fix README not to refer moved file
`cargo run tests/snippets/whats_left_to_implement.py`
-> `./whats_left.sh`
2019-04-22 21:31:22 +09:00
coolreader18
9e54dbef7c Merge pull request #856 from palaviv/socket-new-args
Convert socket to new args style
2019-04-21 19:00:37 -05:00
Aviv Palivoda
cb32201904 Add Address 2019-04-22 00:18:19 +03:00
Windel Bouwman
ce8ea805ae Add check for nonlocal on top level. 2019-04-21 19:40:14 +02:00
Windel Bouwman
adb66322c5 Merge pull request #852 from palaviv/scandir
Add os.scandir
2019-04-21 18:56:29 +02:00
coolreader18
d55d8841ad Merge pull request #854 from sanxiyn/delete-tuple
Implement deleting tuples
2019-04-21 11:47:46 -05:00
coolreader18
801c864645 Bump WASM npm version 2019-04-21 11:30:40 -05:00
Seo Sanghyeon
2aeb0ad59b Assert deleted variables are really deleted 2019-04-22 00:26:30 +09:00
coolreader18
0478358fd9 Merge pull request #853 from palaviv/set-disjoint
Add set.isdisjoint
2019-04-21 09:58:29 -05:00
Seo Sanghyeon
87f9a8e634 Implement deleting tuples 2019-04-21 23:48:13 +09:00
Aviv Palivoda
b61cd6f011 Simplify return values 2019-04-21 17:44:41 +03:00
Aviv Palivoda
1f73393255 Move more socket methods to new arg style 2019-04-21 17:35:20 +03:00
Aviv Palivoda
9954361df9 Move more socket methods to new arg style 2019-04-21 17:28:41 +03:00
Aviv Palivoda
206ba4dbfb Change socket to new args style 2019-04-21 17:20:33 +03:00
Aviv Palivoda
3986e2f87d Add set.isdisjoint 2019-04-21 16:41:36 +03:00
Aviv Palivoda
64e6ea0016 Add DirEntry.{is_file} 2019-04-21 12:06:49 +03:00
Aviv Palivoda
548f3f34c4 Add DirEntry.{is_dir} 2019-04-21 12:04:12 +03:00
Aviv Palivoda
858a6d03b0 Add DirEntry.{name, path} 2019-04-21 11:42:57 +03:00
Aviv Palivoda
3828652da6 Add os.scandir 2019-04-21 11:17:36 +03:00
Windel Bouwman
3afb5d39ed Merge pull request #850 from palaviv/socket-fileno
Socket.fileno
2019-04-20 14:36:05 +02:00
Joey
01f143ec7b Merge pull request #832 from RustPython/joey/proper-titlecase
str: proper titlecase support
2019-04-19 17:05:12 -07:00
coolreader18
de3900bcad Upgrade deps 2019-04-19 15:17:03 -05:00
Windel Bouwman
52a1a95ab0 Merge pull request #846 from LuoZijun/add-benches
Add benches
2019-04-19 22:15:08 +02:00
coolreader18
89aa07720d Merge pull request #851 from RustPython/coolreader18/pycallable
Add PyCallable
2019-04-19 13:34:33 -05:00
luozijun
7822f6d8d8 Add benches 2019-04-20 02:09:06 +08:00
coolreader18
148ef5cd09 Merge pull request #849 from palaviv/os-temp-dir
Use temp directory for os test
2019-04-19 12:39:53 -05:00
coolreader18
a984fd34d9 Update callable test 2019-04-19 12:11:18 -05:00
coolreader18
ac3cfca0fa Fix callable (again) 2019-04-19 12:04:22 -05:00
coolreader18
cf5e106748 Fix is_callable 2019-04-19 11:43:24 -05:00
Joey
ae8ea1d060 Merge remote-tracking branch 'origin/master' into joey/proper-titlecase 2019-04-19 09:27:00 -07:00
Joey
29ea307f4c unicode-casing: specify rev explicitly, add todo comment 2019-04-19 09:26:24 -07:00
coolreader18
a6f3b9a5ff Add PyCallable 2019-04-19 10:14:57 -05:00
coolreader18
2a74e48d98 Add vm.is_callable 2019-04-19 10:10:56 -05:00
Aviv Palivoda
d704a0fcda Rename os test folder 2019-04-19 17:14:14 +03:00
Aviv Palivoda
8215ec0a7c Don't delete test dir 2019-04-19 17:04:04 +03:00
Aviv Palivoda
f42c2a6ba5 Test fileno only on posix 2019-04-19 16:58:43 +03:00
Aviv Palivoda
aef973802c Close open reference to test file 2019-04-19 16:20:44 +03:00
Aviv Palivoda
2bc72dae9f Move fileno logic to Connection impl 2019-04-19 16:10:55 +03:00
Aviv Palivoda
e7b059ed9c Add socket.fileno for windows 2019-04-19 16:00:00 +03:00
Aviv Palivoda
cf0a920743 Add socket.fileno for unix 2019-04-19 15:50:06 +03:00
Aviv Palivoda
08f2a5705b Add prints for windows debug 2019-04-19 14:40:01 +03:00
Aviv Palivoda
00e46b7d72 Try to fix windows test 2019-04-19 13:50:34 +03:00
Aviv Palivoda
abb9cde62c Use temp dir for os test 2019-04-19 12:23:45 +03:00
Aviv Palivoda
a75e7635d5 Add os.sep 2019-04-19 12:09:11 +03:00
jgirardet
61ee15b97b add strip lstrip rstrip 2019-04-19 00:04:39 +02:00
jgirardet
9ea823abf1 add rfind, rindex 2019-04-18 23:06:11 +02:00
jgirardet
8a2ce9e260 add swapcase 2019-04-18 21:58:15 +02:00
jgirardet
a42bfae84d kwargs for translate 2019-04-18 21:41:46 +02:00
jgirardet
03997273ed refactor index/find with ByteInnerOptions 2019-04-18 21:12:45 +02:00
jgirardet
56c5790745 reformat center, ljsut, rjust args 2019-04-18 21:00:33 +02:00
jgirardet
1669d5280f refactor count 2019-04-18 20:41:12 +02:00
jgirardet
8bcdbbf21b use PyInt Ref, add ljust, rjust 2019-04-18 19:52:17 +02:00
coolreader18
19be5c9cf5 Merge pull request #845 from RustPython/coolreader18/proc-macro-span-errors
Target rustpython_derive errors at specific source spans
2019-04-18 12:30:24 -05:00
jgirardet
ba67f3c264 refactore fromhex 2019-04-18 19:25:45 +02:00
jgirardet
4a4d163626 refactor getitem 2019-04-18 19:10:37 +02:00
jgirardet
44d58f63ab refactor contains 2019-04-18 19:03:08 +02:00
jgirardet
473ae24199 use PyStringRef in new 2019-04-18 17:31:58 +02:00
jgirardet
84d61a9212 bytes.new with kwargs 2019-04-18 14:56:47 +02:00
jgirardet
046bd9b6d8 reactor bytes.center 2019-04-18 14:15:13 +02:00
jgirardet
8693adcd61 handle None case for bytes.translate 2019-04-18 14:15:13 +02:00
Jimmy Girardet
0b283102a6 add translate 2019-04-18 14:15:13 +02:00
Jimmy Girardet
ced6f15a59 add bytes.makertans 2019-04-18 14:15:13 +02:00
Jimmy Girardet
bd2166789d add bytes index and find 2019-04-18 14:15:13 +02:00
Jimmy Girardet
8a7c46da7b add endswith startswith 2019-04-18 14:15:13 +02:00
Jimmy Girardet
14658b6236 move is_byte to try_as_byte
move trait IsByte to ByteOr
refactor center
refactor count
fix center with negative value
add test for count(integer)
2019-04-18 14:15:13 +02:00
jgirardet
5f5d5c4278 add bytes.join 2019-04-18 14:15:13 +02:00
jgirardet
e6d6b77698 fix error msg 2019-04-18 14:15:13 +02:00
jgirardet
00cf524814 add slice capability to bytes. add trait IsByte 2019-04-18 14:15:13 +02:00
jgirardet
c550360be5 add is_bytes_like add bytes.count wthout slice 2019-04-18 14:15:13 +02:00
Windel Bouwman
319bb807fb Merge pull request #843 from jgirardet/parsenew
support bytes creation from hex and ascii
2019-04-18 08:35:45 +02:00
jgirardet
eb2d0b01ee refactor lex byte 2019-04-18 08:06:06 +02:00
Windel Bouwman
ae7058ffa8 Merge pull request #842 from RustPython/benchmarking
Add some benchmark scripts.
2019-04-18 07:05:25 +02:00
Windel Bouwman
6cf7f79dd4 Merge pull request #844 from RustPython/improve-syntax-error
Improve syntax error with line information.
2019-04-18 07:03:40 +02:00
coolreader18
48b0a17e4d Merge branch 'master' into coolreader18/proc-macro-span-errors 2019-04-17 20:45:50 -05:00
Windel Bouwman
b34784e9ef Format main.rs 2019-04-17 20:52:53 +02:00
Windel Bouwman
eb16f16566 Improve syntax error with line information. 2019-04-17 20:02:24 +02:00
Adam
615a121200 Merge pull request #841 from RustPython/mutual-import
Support mutual importing modules.
2019-04-17 15:09:23 +01:00
Jimmy Girardet
9c57ae4046 support bytes creation from hex and ascii 2019-04-17 15:28:14 +02:00
Windel Bouwman
84457e6e92 Add some benchmark scripts. 2019-04-17 15:04:50 +02:00
Windel Bouwman
2a8b586622 Fix caching of rust modules. 2019-04-17 14:03:18 +02:00
Windel Bouwman
240c1e42db Merge pull request #839 from RustPython/nonlocal
Add nonlocal support.
2019-04-17 14:02:04 +02:00
Windel Bouwman
6d1b807c77 Improve error message of unwrap operation on nonlocal scope. 2019-04-17 12:59:56 +02:00
Windel Bouwman
06563a36f6 Support mutual importing modules. 2019-04-17 12:33:09 +02:00
Windel Bouwman
75e8f81e77 Merge pull request #767 from skinny121/slice_new
Refactor slice.__new__ to new style function
2019-04-17 12:11:04 +02:00
Windel Bouwman
780ee8a767 Merge pull request #840 from RustPython/coolreader18/fix-unsetenv-test
Fix os.unsetenv test for windows
2019-04-17 12:08:02 +02:00
ben
9b71424d4e Use slice.xxx_index() methods in setslice and delslice 2019-04-17 20:02:08 +12:00
ben
f2873a519d Merge branch 'master' into slice_new
# Conflicts:
#	tests/snippets/builtin_slice.py
#	vm/src/frame.rs
#	vm/src/obj/objrange.rs
#	vm/src/obj/objslice.rs
2019-04-17 19:44:46 +12:00
coolreader18
11bf84e8c1 Fix test again 2019-04-16 22:01:09 -05:00
coolreader18
96d6c518e9 Fix os.unsetenv test for windows 2019-04-16 19:40:01 -05:00
Windel Bouwman
6abf1511e9 Add nonlocal support. 2019-04-16 17:19:57 +02:00
coolreader18
d7275c7712 Merge pull request #837 from skinny121/main_rs_cleanup
Use new_syntax_error in main.rs
2019-04-16 06:58:18 -05:00
coolreader18
827f830d09 Merge pull request #836 from RustPython/coolreader18/no-proc-macro-hack
Remove the __inside_vm hack for procedural macros
2019-04-16 06:51:44 -05:00
ben
224863583b Use new_syntax error in main.rs 2019-04-16 20:53:14 +12:00
coolreader18
dc63fc8ce7 Switch to span-based errors for pyclass and pyimpl 2019-04-15 22:15:20 -05:00
coolreader18
08babef619 Remove the __inside_vm hack for procedural macros 2019-04-15 20:24:16 -05:00
Windel Bouwman
78db5ea311 Merge pull request #835 from RustPython/coolreader18/weakproxy
Add weakproxy
2019-04-15 17:35:04 +02:00
Adam
2c3f4b6de4 Merge pull request #816 from RustPython/dict_changed_during_iteration
Guard for changes in dictionary size during iteration.
2019-04-15 15:53:37 +01:00
Adam Kelly
dfbaf3cdf0 Remove pub from PyDict.entries (easy TODO) 2019-04-15 13:25:04 +01:00
Adam Kelly
c9b479c43b Guard for changes in dictionary size during iteration. 2019-04-15 13:25:04 +01:00
coolreader18
1612c954a1 Add weakproxy test 2019-04-14 20:14:54 -05:00
coolreader18
cc76bf7a1f Add weakproxy class 2019-04-14 20:09:43 -05:00
coolreader18
5855baf4ec Merge pull request #834 from dkaste/rust-2018-macros
Make macros comply fully with Rust 2018
2019-04-14 17:06:45 -05:00
Darren Kaste
a8e064b1c0 Import TypeProtocol before use in type_check! 2019-04-14 17:19:44 -04:00
Darren Kaste
daaeb78831 Prefix helper macro calls with $crate 2019-04-14 17:08:35 -04:00
Joey
79623f4e7a str: proper titlecase support 2019-04-14 12:23:09 -07:00
coolreader18
143e329f79 Merge pull request #831 from palaviv/exception-context
Exception reraise and context
2019-04-14 13:31:10 -05:00
Aviv Palivoda
2ffd1c9484 Fix typo 2019-04-14 20:39:28 +03:00
Aviv Palivoda
4068a36ce8 Use assertRaises 2019-04-14 20:38:34 +03:00
Aviv Palivoda
b6ce407391 Remove else and finally from in_exc_handler 2019-04-14 19:06:21 +03:00
Aviv Palivoda
aec7f84960 Print exception context 2019-04-14 18:55:29 +03:00
Aviv Palivoda
188758929d Add more tests to exception context 2019-04-14 18:54:43 +03:00
Aviv Palivoda
3ec9b01928 Add exception __context__ 2019-04-14 18:54:43 +03:00
Aviv Palivoda
2c2925a684 Support reraise 2019-04-14 18:54:43 +03:00
Windel Bouwman
51aa817a81 Merge pull request #829 from skinny121/unittest_rustpython
RustPython changes for #824
2019-04-14 10:49:21 +02:00
Windel Bouwman
71b6e2abf0 Merge pull request #806 from RustPython/symbol-table
Initial version of symbol table builder.
2019-04-14 10:44:43 +02:00
ben
307689a15e comment out lines that reference mappingproxy as type doesn't yet have a
__dict__
2019-04-14 19:10:10 +12:00
coolreader18
8f3319e01d Merge pull request #827 from RustPython/joey/titlecase
str: improve {is,}title impl and add tests
2019-04-13 22:59:04 -04:00
Joey
762c281dd4 address feedback 2019-04-13 19:07:15 -07:00
ben
a708ce2eb2 Remove needless format! 2019-04-14 12:15:55 +12:00
ben
d24dd170e9 Changes to RustPython to support importing and running unittest 2019-04-14 12:09:54 +12:00
coolreader18
c0d328ad18 Merge pull request #828 from skinny121/rust_1_34_update
Update code format and fix some clippy warnings
2019-04-13 19:20:06 -04:00
ben
6650ad895a Fix a bunch of clippy warnings 2019-04-14 10:07:50 +12:00
ben
1f8181b561 Update formatting to be consistent with rustfmt included in 1.34 2019-04-14 09:40:59 +12:00
Joey
8839461028 str: improve {is,}title impl and add tests 2019-04-13 12:45:09 -07:00
coolreader18
56765681f8 Merge pull request #826 from RustPython/joey/fix-compile
Fix sub-crate compilation
2019-04-13 14:21:26 -05:00
Joey
16644daffa Fix sub-crate compilation 2019-04-13 12:04:37 -07:00
Windel Bouwman
733d3a1d1f Merge master branch 2019-04-13 12:51:55 +02:00
Windel Bouwman
be4e3170af Merge pull request #822 from jgirardet/addbytesm
add capitalize bytes.center + fix str.center
2019-04-13 12:41:35 +02:00
Windel Bouwman
83ea419c63 Add load and store of global to name protocol. 2019-04-13 11:55:10 +02:00
Adam
78ab68a64e Merge pull request #817 from skinny121/function_metadata
Add __name__, __qualname__ and __module__ to functions and classes
2019-04-13 09:44:33 +01:00
jgirardet
73dbcfbe01 Add bytes.center
fix str.center
add some tests
introduce is_byte
2019-04-13 08:23:40 +02:00
jgirardet
bd78f7e12b add capitalize 2019-04-13 08:21:37 +02:00
coolreader18
2c887905a1 Merge pull request #766 from jgirardet/seq
Fix #746: invalid slice with start or stop =-1 when step<0
2019-04-12 16:41:36 -05:00
coolreader18
22203975fa Merge pull request #821 from palaviv/excpetion-cause
Add exception cause
2019-04-12 16:08:54 -05:00
Aviv Palivoda
256abe63b6 Use vm.new_type_error 2019-04-12 23:08:26 +03:00
Aviv Palivoda
20e0cc8bd7 Use assertRaises 2019-04-12 23:06:53 +03:00
coolreader18
a91cfd16bf Fix WASM import error 2019-04-12 14:28:26 -04:00
coolreader18
774b0d8e45 Merge pull request #823 from adrian17/remove-impl
Drop IntoPyNativeFunc impl to fix Nightly/Beta breakages.
2019-04-12 13:27:06 -05:00
Windel Bouwman
76659fd985 Merge pull request #820 from skinny121/gen_throw
Implement generator.throw
2019-04-12 19:38:54 +02:00
Windel Bouwman
456c8a19ce Merge pull request #819 from palaviv/os-env
Add os.environ
2019-04-12 19:33:33 +02:00
Adrian Wielgosik
585e6e5428 Drop IntoPyNativeFunc impl to fix Nightly/Beta breakages. 2019-04-12 19:28:09 +02:00
Windel Bouwman
76c597f2af Add global bytecode and testcase. 2019-04-12 19:24:23 +02:00
Adam
785854ac9e Merge pull request #818 from RustPython/dir_str_bug
Fix dir bug - not including object attributes correctly.
2019-04-12 15:26:49 +01:00
Aviv Palivoda
908f758cbe Print cause on exception 2019-04-12 15:50:17 +03:00
Adam Kelly
80ec464d84 Use dict.update to combine class and object attrs in object_dir. 2019-04-12 12:25:19 +01:00
ben
63643e1fdb Implement generator.throw 2019-04-12 20:30:37 +12:00
Aviv Palivoda
6c4b092641 Support exception __cause__ 2019-04-12 10:50:45 +03:00
Windel Bouwman
28cf4c0010 Symbol role scan fully covered. 2019-04-11 22:18:29 +02:00
Aviv Palivoda
b293956258 Use original _Environ as much as possible 2019-04-11 19:15:37 +03:00
Aviv Palivoda
1272829793 Comment unsupported code from _collections_abc.py 2019-04-11 19:03:08 +03:00
Aviv Palivoda
eb40e08d8a Add _collections_abc.py from CPython 2019-04-11 19:02:04 +03:00
Aviv Palivoda
69e49e6cba Simplify os.py 2019-04-11 18:55:53 +03:00
Aviv Palivoda
4293b11429 Add environ class 2019-04-11 18:55:53 +03:00
Aviv Palivoda
c33593efa9 Remove getenv and add environ 2019-04-11 18:55:53 +03:00
Aviv Palivoda
951659a54d Add os.unsetenv 2019-04-11 18:55:53 +03:00
Aviv Palivoda
9b475a2c41 Add os.putenv 2019-04-11 18:55:53 +03:00
Aviv Palivoda
72467069be Add os.getenv 2019-04-11 18:55:53 +03:00
Adam
42a3b7a75c Merge pull request #815 from RustPython/refactor_ast
Refactor ast.
2019-04-11 16:43:19 +01:00
Adam Kelly
8569145751 Define classes for all the ast types. 2019-04-11 16:41:47 +01:00
Adam Kelly
8a14665575 Ast refactor: Everything can fail. 2019-04-11 16:41:44 +01:00
Adam Kelly
d7e0ceec12 New (PyRef<T>) style types. 2019-04-11 16:40:54 +01:00
Adam Kelly
aa38a1aa51 Start refactor of ast. 2019-04-11 16:40:49 +01:00
Adam Kelly
664554bc5e Fix dir bug - not including object attributes correctly. 2019-04-11 15:35:01 +01:00
Windel Bouwman
7cf3135878 Merge pull request #812 from RustPython/dict_eq
Dict eq
2019-04-11 13:33:18 +02:00
ben
2164cb5e65 Produce correct value for __qualname__ and add attributes to class. 2019-04-11 20:13:23 +12:00
ben
84eff4a7ac Add __name__ and __module__ to functions 2019-04-11 20:13:23 +12:00
Adam Kelly
b70f989952 dict equality - objects always equal themselves. 2019-04-11 08:39:03 +01:00
Adam Kelly
bd5772d914 Implement dict.__eq__ 2019-04-11 08:31:13 +01:00
Adam Kelly
939f109375 Merge branch 'dict_into_iter' 2019-04-11 08:29:13 +01:00
Adam Kelly
aeb84936ff Merge branch 'master' into dict_into_iter 2019-04-11 08:28:12 +01:00
Windel Bouwman
58a393f047 Merge pull request #804 from jgirardet/refactore_bytes
refactor bytes
2019-04-11 08:20:01 +02:00
coolreader18
ef55efb631 Merge pull request #814 from RustPython/coolreader18/pyproperty-attr
Change #[pymethod(property)] to #[pyproperty]
2019-04-10 22:19:00 -05:00
coolreader18
6a190e39f3 Fix __radd__ and __rmul__ 2019-04-10 20:41:06 -05:00
coolreader18
dd4539b1a6 Change to use PyClassImpl::extend_class 2019-04-10 18:02:30 -05:00
coolreader18
c5f4eab142 Change objint to impl style with properties 2019-04-10 17:55:24 -05:00
coolreader18
2bdaa02700 Improve error messages 2019-04-10 17:45:07 -05:00
coolreader18
d099165e3b Rename item_name -> item_ident 2019-04-10 17:41:45 -05:00
coolreader18
47bd9680f9 Change ClassItem to enum 2019-04-10 17:41:25 -05:00
jgirardet
9d25a216de fix some tests, run clippy 2019-04-10 21:39:16 +02:00
Jimmy Girardet
54c7335f1c SyntaxError for non ascii char 2019-04-10 18:05:28 +02:00
jgirardet
751c3d52e2 use vec! for int arg in bytes new 2019-04-10 13:24:31 +02:00
Adam Kelly
e04275b199 Missed get_key_values_pairs removal in wasm. 2019-04-10 09:48:53 +01:00
Adam Kelly
8f840d5376 Pick code review nits. 2019-04-10 09:28:54 +01:00
Adam Kelly
9a92159413 Remove unneeded Cell on DictIter. 2019-04-10 09:26:03 +01:00
Jimmy Girardet
977f56ade1 add bytes.fromhex 2019-04-10 10:08:10 +02:00
coolreader18
cbdab226d9 Change #[pymethod(property)] to #[pyproperty] 2019-04-09 22:07:21 -05:00
Jimmy Girardet
5cc83a35aa hex 2019-04-09 17:08:38 +02:00
Jimmy Girardet
9b763072fe add upper lower 2019-04-09 16:23:56 +02:00
Adam
d84ad431e1 Merge pull request #811 from RustPython/dict_view_len
Add __len__ to dictionary views.
2019-04-09 14:09:49 +01:00
Jimmy Girardet
6c745f68dd fix typo, fix bytesinner.add now return Vec[u8] 2019-04-09 14:43:13 +02:00
Jimmy Girardet
2940c7cc28 add islpaha isalnum isdigit islower isupper isspace istitle 2019-04-09 14:33:29 +02:00
Adam Kelly
ec5fd550de Implement IntoIterator for PyDictRef. 2019-04-09 11:30:52 +01:00
Adam Kelly
25d3f83e4d Add __len__ to dictionary views. 2019-04-09 11:28:25 +01:00
Adam
31fd2936c5 Merge pull request #796 from RustPython/dict_iters
Dict iters
2019-04-09 11:11:14 +01:00
Adam Kelly
f3f3d8a478 Merge branch 'Ryex-ryex-list.__delitem__slice_error' 2019-04-09 10:31:55 +01:00
Adam
39042e6475 Merge pull request #805 from Ryex/ryex-list.__setitem__
implement  list.__setitem__ with slice and int indexing
2019-04-09 10:24:48 +01:00
Adam
958a0a2600 Merge pull request #809 from skinny121/dict_test_cleanup
Cleanup dict test snippet
2019-04-09 10:19:32 +01:00
Adam Kelly
d9216c87f1 Remove done todo. 2019-04-09 10:17:17 +01:00
Adam Kelly
23a4b1e9d8 Additional tests for dictionary iteration. 2019-04-09 10:13:44 +01:00
ben
046e4b3fe3 Cleanup dict test snippet 2019-04-09 20:43:59 +12:00
Windel Bouwman
981c14fb0d Merge pull request #795 from RustPython/coolreader18/wasm-cleanup1
[WASM] Clean up a bit
2019-04-09 07:46:24 +02:00
coolreader18
422ab69b99 Use impl style classes 2019-04-08 21:50:38 -05:00
coolreader18
c581852b5b Merge branch 'master' into coolreader18/wasm-cleanup1 2019-04-08 21:49:04 -05:00
coolreader18
1568637d26 Merge branch 'master' into coolreader18/wasm-cleanup1 2019-04-08 21:41:45 -05:00
Rachel Powers
1101b6571c fix error related to #746 but for list.__delitem__ 2019-04-08 16:17:57 -06:00
Rachel Powers
b2a1f6580b fix error when start or stop of slice is -1 and step != 1 2019-04-08 15:56:06 -06:00
jgirardet
b535958310 add getitem, fix contain error_message 2019-04-08 23:12:40 +02:00
Rachel Powers
4d53ddedb0 test for if iter raises error 2019-04-08 14:45:34 -06:00
Windel Bouwman
8e07719e81 Merge branch 'master' of github.com:RustPython/RustPython into symbol-table 2019-04-08 22:32:00 +02:00
Rachel Powers
4c50defa37 extend PyIterable::try_from_object to work with sequences 2019-04-08 13:46:23 -06:00
jgirardet
8232a4d285 finish contains 2019-04-08 21:27:44 +02:00
Rachel Powers
d0e6d2fa32 add tests for custom iters 2019-04-08 13:18:37 -06:00
Rachel Powers
4e277cfcc2 move to useing PyIterable 2019-04-08 12:41:28 -06:00
coolreader18
e7e126e31d Fix whats_left.sh 2019-04-08 12:30:53 -05:00
Windel Bouwman
21e890daa4 Merge pull request #802 from andrew-ld/master
use a code generator for not implemented tests
2019-04-08 17:05:52 +02:00
Windel Bouwman
b1a95f669f Initial version of symbol table builder. 2019-04-08 17:02:27 +02:00
andrew
3aa110a296 add .gitignore 2019-04-08 16:03:35 +02:00
andrew
2811f27bb5 add a warning 2019-04-08 16:03:24 +02:00
Adam Kelly
29e9753e51 Even newer style class definitions. 2019-04-08 15:02:04 +01:00
Adam Kelly
2d127b9834 Use macro to generate full set of views and iterators. 2019-04-08 12:11:59 +01:00
Adam Kelly
5c4755ffd7 Separate iterators for items/keys/values. 2019-04-08 11:08:45 +01:00
Adam Kelly
9c32de954b Add iterator for dictionary keys. 2019-04-08 10:35:09 +01:00
Jimmy Girardet
86928114fa resolve conflict 2019-04-08 10:33:56 +02:00
jgirardet
c487f12222 Merge branch 'master' into seq 2019-04-08 09:36:37 +02:00
Jimmy Girardet
0e264426c9 fix import 2019-04-08 09:12:22 +02:00
Rachel Powers
a23b5bc470 cleanup and cargo fmt 2019-04-07 19:32:11 -06:00
Joey
7910c95ff0 Merge pull request #785 from palaviv/set-inner
refactor objset using inner
2019-04-07 18:20:37 -07:00
Rachel Powers
118c98ccc7 exhaustive (hopefully) test snippets
I attempted to cover every case with the snippets
 but I easily could of missed some.
2019-04-07 19:12:03 -06:00
Rachel Powers
4d8a56aea1 list.__setitem__ with slice and int indexing
optimisation is uncertain
correctness is uncertain

but it does appear to work
2019-04-07 19:09:44 -06:00
jgirardet
ec65b8480f add contains 2019-04-08 00:45:53 +02:00
jgirardet
3c736c1f94 iter 2019-04-08 00:11:20 +02:00
Aviv Palivoda
abc72e9992 contains return bool 2019-04-07 23:54:42 +03:00
jgirardet
dddf9fee39 gt lt ge le 2019-04-07 22:42:47 +02:00
jgirardet
ec98b4d6bf repr len eq 2019-04-07 22:36:13 +02:00
Aviv Palivoda
5ae921dc57 update function support iterable 2019-04-07 23:26:59 +03:00
Aviv Palivoda
848350d334 ior support only set and frozenset 2019-04-07 23:06:42 +03:00
Aviv Palivoda
3ed8727ee5 symmetric_difference support iterable 2019-04-07 23:01:49 +03:00
coolreader18
53aa57dbbe Merge pull request #803 from RustPython/joey/self-by-ref
int, str, range: take self by shared reference
2019-04-07 14:54:08 -05:00
Aviv Palivoda
e011e3f327 intersection and difference support iterable 2019-04-07 22:36:56 +03:00
Aviv Palivoda
fa369ff779 Limit non-operator versions to set and frozenset 2019-04-07 22:09:37 +03:00
Joey Hain
c2e03ed342 fix int.__float__ 2019-04-07 11:56:59 -07:00
jgirardet
f538a92007 pybytes.__new__ ok 2019-04-07 20:34:27 +02:00
Aviv Palivoda
3bc1e3598c Use PyIterable 2019-04-07 21:26:20 +03:00
Joey Hain
ea61599da4 range: take self by ref 2019-04-07 10:07:36 -07:00
Joey Hain
e70f174eb6 str: take self by ref 2019-04-07 10:07:36 -07:00
Joey Hain
aec33634ca int: take self by ref 2019-04-07 10:07:31 -07:00
Aviv Palivoda
a0aa88d2fb clear return implicit None 2019-04-07 20:02:27 +03:00
jgirardet
2eb8e7bf2b new ok for pybytes 2019-04-07 18:55:35 +02:00
Windel Bouwman
48cca16dd7 Merge pull request #801 from skinny121/dict_copy_update
Implement copy and update dict methods
2019-04-07 12:24:51 +02:00
andrew
f03a164c14 use a code generator for not implemented tests 2019-04-07 12:22:10 +02:00
Windel Bouwman
f4964dafbf Merge pull request #798 from skinny121/keyword_only_args
Implement keyword only argument defaults
2019-04-07 12:11:15 +02:00
Adam
90ded15339 Merge pull request #799 from RustPython/joey/ref-receiver
Allow first argument to be a shared ref to a python value
2019-04-07 10:02:03 +01:00
Adam
8a5d6ca79e Merge pull request #800 from skinny121/warning_classes
Add builtin warning classes
2019-04-07 09:51:23 +01:00
jgirardet
7e965c7cc8 check encoding in new 2019-04-07 10:12:57 +02:00
ben
32051c9d96 Implement copy and update dict methods 2019-04-07 19:19:39 +12:00
ben
02a21cd072 Add builtin warning classes 2019-04-07 17:42:10 +12:00
coolreader18
7ca3b77fcd Just a fn 2019-04-06 23:55:30 -05:00
coolreader18
5afc558564 Add id() method 2019-04-06 23:47:01 -05:00
Joey Hain
c2716040d2 float: take self by shared ref 2019-04-06 19:05:18 -07:00
Joey Hain
be55562457 Allow first argument to be a shared ref to a python value 2019-04-06 18:50:40 -07:00
jgirardet
10cbf2ae74 bytes._new stuff 2019-04-07 01:49:16 +02:00
ben
51732feaed Use get_item_option from ItemProtocol instead of get_item 2019-04-07 07:43:29 +12:00
ben
d5a9d96d62 Expose function.__defaults__ and function.__kwdefaults__(only getters) 2019-04-07 07:38:42 +12:00
ben
5fd3cf2bcd Implemented keyword only defaults 2019-04-07 07:38:42 +12:00
Windel Bouwman
d64554dab2 Merge pull request #797 from palaviv/os-dirs
Add os.{mkdir, mkdirs, rmdir, listdir}
2019-04-06 20:25:00 +02:00
Windel Bouwman
ea95fb2b4e Merge pull request #794 from RustPython/generic_dict
Parameterise dictdatatype::Dict by value type.
2019-04-06 20:18:22 +02:00
Aviv Palivoda
401ca08b65 Use map_err 2019-04-06 21:11:58 +03:00
Aviv Palivoda
a21aa6eac9 Add os.listdir 2019-04-06 19:14:23 +03:00
Aviv Palivoda
bf6b12266a Add os.rmdir 2019-04-06 18:30:40 +03:00
Aviv Palivoda
2ec6afeb11 Add os.mkdirs 2019-04-06 18:24:06 +03:00
Aviv Palivoda
eb9378fe90 Add os.mkdir 2019-04-06 18:20:18 +03:00
coolreader18
3aeaa05f1a Merge branch 'master' into coolreader18/wasm-cleanup1 2019-04-06 10:11:07 -05:00
Adam Kelly
e67d5f3c62 Parameterise dictdatatype::Dict by value type. 2019-04-06 16:06:42 +01:00
Windel Bouwman
d577bb7ac9 Merge pull request #787 from palaviv/os-fd
Add os.{read,write,remove,unlink}
2019-04-06 17:02:31 +02:00
Windel Bouwman
1faa7fa202 Merge pull request #783 from Ryex/ryex-impl-list.__delitem__
Implement list.__delitem__
2019-04-06 16:56:21 +02:00
Windel Bouwman
0f6a25c38e Merge pull request #791 from RustPython/dict_protocols
Dict protocols
2019-04-06 16:48:30 +02:00
Windel Bouwman
a6858befbc Merge pull request #792 from RustPython/docstring-fix
Fix moment when docstring is set.
2019-04-06 16:39:33 +02:00
Aviv Palivoda
04acfe2665 Remove failing line in windows 2019-04-06 17:29:52 +03:00
Aviv Palivoda
1f0fd39722 Change os new funcs to new arg style 2019-04-06 17:29:40 +03:00
Windel Bouwman
bcf94ed8bf Merge pull request #788 from RustPython/syntax-enhancements
Fix syntax for float literals, statements seperated by semicolons and…
2019-04-06 12:31:53 +02:00
Windel Bouwman
afb28bfccb Fix moment when docstring is set. 2019-04-06 11:53:59 +02:00
Adam Kelly
584b707356 Add dict.__missing__ support. 2019-04-06 10:15:34 +01:00
Adam Kelly
b1dd5836af Simpler implementation of ItemProtocol for PyDictRef. 2019-04-06 10:15:34 +01:00
Adam Kelly
e2a4f22be8 Avoid name similarity between ItemProtocol and inner methods. 2019-04-06 10:15:33 +01:00
Adam Kelly
0fe3f7748c Simplify PyDictRef.__repr__. 2019-04-06 10:15:31 +01:00
Adam Kelly
7b2d92f495 Delete DictProtocol. impl ItemProtocol for PyDictRef. 2019-04-06 10:15:29 +01:00
Adam Kelly
ee9066a713 dict.get shouldn't call into __getitem__ 2019-04-06 10:12:16 +01:00
Adam Kelly
3e42edd261 dict.__new__ - support for dict subtypes. 2019-04-06 10:12:16 +01:00
Windel Bouwman
42bb3465c3 Merge pull request #790 from skinny121/decorator_and_defaults
Fix decorator on functions with defaults
2019-04-06 11:08:01 +02:00
Windel Bouwman
b90a1cf6ef Merge pull request #789 from skinny121/dict_literal_order
Fix order of dict literal
2019-04-06 11:07:22 +02:00
coolreader18
157204c61a Clean up the wasm crate 2019-04-05 23:24:26 -05:00
Rachel Powers
909d94ec23 impl and use SequenceIndex for list.__delitem__
- removal of del_item
- all del function impl on PyListRef
- stepped deletion now loops only over the range
  insted of the whole list
2019-04-05 20:25:53 -06:00
ben
7fffc57255 Fix decorator on functions with defaults 2019-04-06 12:46:48 +13:00
jgirardet
a7d5b0e9ac start 2019-04-06 01:44:00 +02:00
Rachel Powers
c3ecf0ef9e Merge branch 'master' into ryex-impl-list.__delitem__ 2019-04-05 17:15:32 -06:00
ben
dda0d561ac Fix order of dict literal 2019-04-06 10:43:39 +13:00
Windel Bouwman
ab3d004c42 Fix syntax for float literals, statements seperated by semicolons and starargs after keyword arguments. 2019-04-05 21:59:20 +02:00
Windel Bouwman
8535ba9a56 Merge pull request #786 from RustPython/dict_cleanup
Dict cleanup
2019-04-05 20:56:58 +02:00
Aviv Palivoda
2a3a88c2f2 Use match_class macro to avoid unwanted clones 2019-04-05 19:59:01 +03:00
Aviv Palivoda
a685216f29 Use new arg style for set and frozenset new 2019-04-05 19:59:01 +03:00
Aviv Palivoda
ed8c1e1a95 Implement set and frozenset with PySetInner 2019-04-05 19:58:17 +03:00
Aviv Palivoda
cdd39bc50e Add tests for os.{read, write} 2019-04-05 19:51:38 +03:00
Aviv Palivoda
1f19951ece Add os.{remove,unlink} 2019-04-05 19:51:38 +03:00
Aviv Palivoda
28c3ef1ae3 Add os.write 2019-04-05 19:50:24 +03:00
Aviv Palivoda
37e7972dcd Add os.read 2019-04-05 19:49:13 +03:00
Adam Kelly
f354f4ce02 Move contains_key to PyDictRef. 2019-04-05 16:18:10 +01:00
Adam Kelly
0dce9bb96a Use item protocol when executing instructions. 2019-04-05 16:16:55 +01:00
Adam Kelly
4212594c5b Prefer key to needle. 2019-04-05 16:16:55 +01:00
Adam Kelly
ec94168a15 Remove objdict::get_key_value_pairs. 2019-04-05 16:16:55 +01:00
Windel Bouwman
59d8612cfa Merge pull request #782 from skinny121/abc_module
Add abc module from CPython
2019-04-05 17:05:45 +02:00
Windel Bouwman
e2293ead70 Merge pull request #780 from RustPython/dict_non_str_keys
Support non-string keys in dictionaries.
2019-04-05 16:56:58 +02:00
coolreader18
916066924e Merge pull request #784 from RustPython/joey/range-index
Add and use a RangeIndex type instead of Either
2019-04-05 09:05:14 -05:00
Adam Kelly
77d5f57df1 Add some additional dictionary tests. 2019-04-05 14:36:19 +01:00
Rachel Powers
a41e8973bd Merge branch 'master' into ryex-impl-list.__delitem__ 2019-04-05 03:59:44 -06:00
Adam Kelly
43347e2d8b Dictionary: KeyError -> ValueError. 2019-04-05 09:50:31 +01:00
Adam Kelly
b943f4a4bb Historic real proper dictionary support. 2019-04-05 09:50:31 +01:00
Adam Kelly
9ed051e3b7 Module Initialisation takes VirtualMachine rather than PyContext. 2019-04-05 09:50:31 +01:00
Adam Kelly
7438b0685c Changes suggested by code review. 2019-04-05 09:50:31 +01:00
Adam Kelly
c8eda3733d Eliminate ctx.set_attr. 2019-04-05 09:50:31 +01:00
Adam Kelly
25c17b4829 Change all the ctx.set_attr in ast. 2019-04-05 09:50:31 +01:00
Adam Kelly
f840bdcd7f Generalise set_attr. 2019-04-05 09:39:59 +01:00
Adam Kelly
bce4f1e483 Simplify/shrink the dict interface. 2019-04-05 09:39:59 +01:00
ben
79caaa5a0b Move PSF-LICENSE and add Lib README.md 2019-04-05 19:19:55 +13:00
jgirardet
d96a5b11f7 add resources to snippets 2019-04-04 21:32:04 +02:00
Windel Bouwman
95cbb530d8 Merge pull request #779 from RustPython/syntax-enhancements
Improve trailing comma situation
2019-04-04 19:45:28 +02:00
Joey
05ede30c51 range index 2019-04-04 07:52:53 -07:00
Joey
1c958c93b1 Merge pull request #774 from RustPython/joey/match-class
Add match_class! macro
2019-04-04 07:13:31 -07:00
Rachel Powers
d0e6c3bd92 convert to PySliceRef as it is the only option 2019-04-04 04:52:33 -06:00
Rachel Powers
e3994010f3 add list.__delitem__ test snippits 2019-04-04 04:04:26 -06:00
Rachel Powers
c97f342ef7 cleanup and rustfmt 2019-04-04 03:18:58 -06:00
Rachel Powers
aba059b81a impl PySliceableSequenceMut & objseqence::del_item
used to impl list.__delitem__
2019-04-04 02:52:51 -06:00
ben
c01dc5310a Add callback parameter to weakref, at the moment this callback isn't yet
implement though.
2019-04-04 20:11:53 +13:00
ben
ea872521d6 Make object by default hashable 2019-04-04 20:11:53 +13:00
ben
0bd08618af Change _py_abc to workaround current issue, and run test with PYTHONPATH
linking to Lib directory.
2019-04-04 20:11:53 +13:00
ben
39d4d64a4c Copy abc and dependent python files over from CPython 3.7 branch 2019-04-04 20:11:53 +13:00
Rachel Powers
fa53d5cd65 impl list.__delitem__ using list.__setitem__ as a guide
while it works as well as __setitem__ currently does this impliments no
support for slice indexing or negative indexing, adtionaly a bad index
panics insted of giving a vm type error!
2019-04-03 21:11:03 -06:00
Joey Hain
88bf2a32c4 address feedback 2019-04-03 17:30:04 -07:00
Windel Bouwman
29a137bf0f Drop testlist2. Also add test cases for trailing comma in for statement and tuple addition example. 2019-04-03 22:24:19 +02:00
coolreader18
c6e875f209 Merge pull request #773 from RustPython/coolreader18/whats_left-overhaul
Redo much of whats_left_to_implement.py
2019-04-03 10:29:33 -05:00
coolreader18
e078614e05 Change to classes and remove unnecesary if 2019-04-03 08:50:55 -05:00
Windel Bouwman
23f57f757c Improve trailing comma situation 2019-04-03 14:08:12 +02:00
Windel Bouwman
a59db050ac Merge pull request #776 from adrian17/comparisons
Support chained comparisons
2019-04-03 09:17:11 +02:00
Joey
1e7ca4cac3 Merge pull request #777 from RustPython/joey/convert-complex
Convert complex to new args style
2019-04-02 22:35:34 -07:00
Adrian Wielgosik
2fb3fc92ec Support chained comparisons 2019-04-02 23:22:54 +02:00
Joey
6863c19fb7 complex: convert to new args style 2019-04-02 09:51:06 -07:00
Joey
75d02a1725 complex: move to impl block 2019-04-02 09:30:18 -07:00
ben
ea2622ee7b Make slice.stop not an option 2019-04-02 17:25:51 +13:00
coolreader18
d81533befa Merge branch 'master' into coolreader18/whats_left-overhaul 2019-04-01 23:20:47 -05:00
coolreader18
a77b3489b7 Merge pull request #764 from RustPython/coolreader18/py_class-proc-macro
Add #[py_class] attribute proc macro
2019-04-01 23:17:38 -05:00
Joey Hain
8549ea22a3 Use match_class! in objint::to_int 2019-04-01 20:22:11 -07:00
Joey Hain
98889d5339 match_class! macro 2019-04-01 20:09:45 -07:00
coolreader18
9ff1e41422 Give values instead of types, list comprehension, remove methods not in CPython 2019-04-01 18:28:15 -05:00
coolreader18
6276241d59 Redo much of whats_left_to_implement.py 2019-04-01 18:12:28 -05:00
Windel Bouwman
0ce15e1ff5 Merge pull request #772 from adrian17/iterables
Refactor iterables, separate types, make behavior more compatible with CPython
2019-04-01 21:45:15 +02:00
Adrian Wielgosik
2f2a8438b5 Add iterable tests 2019-04-01 19:45:20 +02:00
Adrian Wielgosik
de5b1c4055 Support iter() for types with only __getitem__ 2019-04-01 19:45:16 +02:00
Adrian Wielgosik
c918e9d5d3 Split iterators into separate types 2019-04-01 19:45:14 +02:00
Adrian Wielgosik
bbfca26b27 Move PyIteratorValue to objiter.rs 2019-04-01 19:45:10 +02:00
Adrian Wielgosik
cba8aa9be5 Drop iter_type_init, explicitly define __iter__ for iterators 2019-04-01 19:45:07 +02:00
Adrian Wielgosik
016ecf204d Move iterator __contains__ to 'in' implementation 2019-04-01 19:45:00 +02:00
coolreader18
b3ea8155a5 Don't clone 2019-03-31 22:40:57 -05:00
coolreader18
43b0760173 Merge branch 'master' into coolreader18/py_class-proc-macro 2019-03-31 21:16:25 -05:00
coolreader18
51b766089f Allow an enum with #[pyclass] 2019-03-31 19:53:52 -05:00
coolreader18
42768b20e5 Small demo improvements 2019-03-31 17:53:53 -05:00
coolreader18
53b46a7b32 Split some of #[pyclass] off into #[pyimpl] 2019-03-31 17:23:33 -05:00
Windel Bouwman
aede03c1b2 Merge pull request #762 from palaviv/doc
Support class and function __doc__
2019-03-31 20:01:05 +02:00
Aviv Palivoda
4e99350e5c Use StoreAttr for __doc__ 2019-03-31 18:52:27 +03:00
Aviv Palivoda
6d53fe6924 Add more tests for class doc 2019-03-31 18:52:27 +03:00
Aviv Palivoda
ab3cde77b4 Support class __doc__ 2019-03-31 18:52:27 +03:00
Aviv Palivoda
c76b31866d Add more tests for function doc 2019-03-31 18:52:27 +03:00
Aviv Palivoda
f994f8660e Function support __doc__ 2019-03-31 18:51:57 +03:00
Windel Bouwman
69c81730d3 Merge pull request #760 from RustPython/parser-fixes
Add support for trailing comma in function defs. Parser code simplica…
2019-03-31 10:57:51 +02:00
Windel Bouwman
f1a60e1ce5 Merge pull request #769 from RustPython/coolreader18/lalrpop-process-out_dir
Process lalrpop in cargo's target directory
2019-03-31 10:57:31 +02:00
coolreader18
60ad5489f1 Ignore clippy lints in the lalrpop generated file 2019-03-30 22:58:46 -05:00
coolreader18
1b57f07834 Process lalrpop in cargo's target directory 2019-03-30 22:56:37 -05:00
coolreader18
15cffc4d2b Clean up a bit 2019-03-30 22:30:14 -05:00
coolreader18
f11f04da70 Split rustpython_derive into multiple files 2019-03-30 18:43:31 -05:00
ben
e0f7fbb191 Don't derive FromArgs on payload type. 2019-03-31 10:53:45 +13:00
Joey
cb0b6a80c5 Merge pull request #759 from RustPython/joey/convert-bytes
Convert bytes to new args style
2019-03-30 14:48:43 -07:00
ben
a49895ef63 Cleanup slice_new and added more slice tests 2019-03-31 09:58:02 +13:00
ben
5625f7e15e Allow arbitrary in slice, and convert slice.__new__ to new style 2019-03-31 09:58:02 +13:00
jgirardet
7d18a1ce60 Fix #746: invalid slice with start or stop =-1 when step<0 2019-03-30 21:47:20 +01:00
Joey Hain
c2d04f97d8 bytes: add tests for NotImplemented 2019-03-30 13:33:50 -07:00
Joey Hain
83c1d4fe10 Merge remote-tracking branch 'origin/master' into joey/convert-bytes 2019-03-30 13:31:43 -07:00
coolreader18
d9efe4ea37 Require a #[pymethod] for a method to be recognized 2019-03-29 16:16:31 -05:00
coolreader18
8376ec2d98 Use doc comments for python __doc__ 2019-03-29 15:17:58 -05:00
coolreader18
ab6031871c impl PyStringRef using py_class 2019-03-29 14:51:42 -05:00
coolreader18
4222d87e31 Merge branch 'master' into coolreader18/py_class-proc-macro 2019-03-29 13:55:08 -05:00
Joey
c5c91818a5 Merge pull request #755 from skinny121/int_new_args
Use new style args for int.__new__
2019-03-29 09:13:25 -07:00
coolreader18
c724fdaabe Merge pull request #761 from adrian17/re
Convert re to new style args
2019-03-29 10:58:11 -04:00
ben
ce9a909b9d Change kind identifier to fully use python terminology 2019-03-29 19:03:13 +13:00
ben
b5dc5a28e7 Merge branch 'master' into int_new_args
# Conflicts:
#	vm/src/function.rs
2019-03-29 18:51:19 +13:00
coolreader18
ff85838556 Add #[py_class] attribute proc macro 2019-03-29 00:16:34 -05:00
coolreader18
6618def266 Merge pull request #763 from adrian17/more-args
Convert more functions to new args style
2019-03-28 19:10:03 -04:00
Adrian Wielgosik
8f1ec3dd23 Convert slice::{start, stop, stop} to new args style 2019-03-28 23:08:46 +01:00
Adrian Wielgosik
d5e2b3a8b6 Convert iterators next() to new args style
Except objiter, as it'll need to be reworked anyway
2019-03-28 23:08:46 +01:00
Adrian Wielgosik
792c6a103e Convert re to new style args 2019-03-28 21:32:18 +01:00
Windel Bouwman
73cd680d8d Add support for trailing comma in function defs. Parser code simplications. 2019-03-28 17:50:41 +01:00
Joey
149aefe470 Merge pull request #757 from RustPython/joey/convert-bytearray
bytearray: convert to new args style
2019-03-28 08:16:49 -07:00
Joey
da4df08516 Merge pull request #758 from RustPython/joey/convert-builtins
Convert some builtin fns to new args style
2019-03-28 08:16:35 -07:00
coolreader18
e1865fed82 Merge pull request #743 from RustPython/coolreader18/update-deps
Update cargo dependencies
2019-03-28 11:16:21 -04:00
ben
6fd6cc647b Renamed ArgKind, and member to be consistent with python inspect module 2019-03-28 22:00:55 +13:00
ben
c8f4474e7f Implement handling of optional attribute in proc macro 2019-03-28 21:46:26 +13:00
ben
657d025592 Change syntax of attributes in FromArgs proc macro 2019-03-28 21:34:11 +13:00
coolreader18
b621a13415 Merge branch 'master' into coolreader18/update-deps 2019-03-27 22:32:42 -04:00
Joey Hain
e0aca86473 bytes: convert methods to new args style 2019-03-27 19:23:23 -07:00
Joey Hain
e4272126cf bytes: return NotImplemented where appropriate 2019-03-27 19:15:38 -07:00
Joey Hain
b0d7960cc5 bytes: move methods to impl block 2019-03-27 19:14:37 -07:00
Joey Hain
62842e6d19 convert some builtins 2019-03-27 19:01:13 -07:00
Joey
57fa041d08 bytearray: convert to new args style 2019-03-27 18:55:56 -07:00
Joey
e048037146 Merge pull request #756 from adrian17/objobject
Convert objobject.rs to new args style
2019-03-27 17:51:20 -07:00
Adrian Wielgosik
89f63e4c9a Convert objobject.rs to new args style 2019-03-27 23:25:09 +01:00
Windel Bouwman
c2eb6643f3 Merge pull request #754 from adrian17/master
Upgrade lalrpop
2019-03-27 21:09:01 +01:00
Adrian Wielgosik
40dd75d513 Upgrade lalrpop 2019-03-27 18:55:08 +01:00
ben
3ca387b509 Enhance FromArgs derive proc macro to allow positional, and positional
or keyword arguments.
2019-03-28 05:55:15 +13:00
Windel Bouwman
1cda87a239 Merge pull request #752 from RustPython/more_dict_cleanup
More dict cleanup
2019-03-27 15:53:14 +01:00
Adam Kelly
c644176547 Modules have attributes, not items. 2019-03-27 10:53:08 +00:00
Adam Kelly
4cb7f026de Remove unnecessary cast to pyobject in kwarg construction. 2019-03-27 10:53:08 +00:00
Windel Bouwman
14d3aab528 Merge pull request #753 from adrian17/master
Remove .gcno files before a coverage run
2019-03-26 19:34:05 +01:00
Adrian Wielgosik
c5203a4934 Remove .gcno files before a coverage run 2019-03-26 19:00:06 +01:00
Joey
5ef8220d20 Merge pull request #751 from RustPython/scope_holds_dictionaries
Change types inside Scope to PyDictRef.
2019-03-26 09:33:31 -07:00
Adam Kelly
4a5592d461 Change types inside Scope to PyDictRef. 2019-03-26 15:16:49 +00:00
Adam
e68eb9c409 Merge pull request #750 from RustPython/joey/cleanup-type-protocol
Clean up type protocol
2019-03-26 12:00:12 +00:00
Joey Hain
625d2357bd Fix wasm 2019-03-25 19:34:24 -07:00
Joey Hain
8bdc766bed Use name field directly 2019-03-25 19:32:58 -07:00
Joey Hain
6474a4a6ef Remove objtype::get_type_name() 2019-03-25 19:18:07 -07:00
Joey Hain
cc4f3fdb40 Clean up TypeProtocol 2019-03-25 19:18:01 -07:00
coolreader18
e819ca6b87 Merge branch 'master' into coolreader18/update-deps 2019-03-25 21:41:32 -04:00
coolreader18
ac2a5e281c Add comment explaining bytes -> Uint8Array conversion 2019-03-25 19:37:16 -05:00
Adam Kelly
17b816fbf8 Fix objset compilation error caused by merge race. 2019-03-25 20:37:47 +00:00
Adam
cac9da4c35 Merge pull request #748 from RustPython/attributes_and_dictionaries
Attributes and dictionaries
2019-03-25 20:30:46 +00:00
Windel Bouwman
20c09f025a Merge pull request #747 from adrian17/master
Update grcov
2019-03-25 20:41:39 +01:00
Windel Bouwman
6ae10ed938 Fix build and add extend_class macro usage for set and frozenset 2019-03-25 20:23:13 +01:00
Windel Bouwman
983be0f944 Merge pull request #725 from palaviv/frozen-set-2
frozenset
2019-03-25 19:54:52 +01:00
Windel Bouwman
e47032f9e4 Merge pull request #749 from adrian17/tests-cleanup
Tests cleanups
2019-03-25 19:38:11 +01:00
Adrian Wielgosik
2131a8130c Clean up some tests 2019-03-25 17:59:51 +01:00
Adrian Wielgosik
16e04cf298 Run rustpython tests without cargo middleman 2019-03-25 17:54:04 +01:00
Adrian Wielgosik
4ab59a8e4c Do not run benchmarks in the main test suite 2019-03-25 17:53:13 +01:00
Adrian Wielgosik
e44b02b88f Avoid trace log in tests 2019-03-25 17:52:37 +01:00
Adam Kelly
55e0fb1f19 AST class for nodes instead of just using object everywhere. 2019-03-25 16:39:25 +00:00
Adam Kelly
bbb7162472 Various dictionary changes.
* vm.ctx.new_dict returns a PyDictRef
* Special case for module goes away.
* Instances get a real dictionary.
2019-03-25 16:37:20 +00:00
Adrian Wielgosik
602f2a83da Update grcov 2019-03-25 17:35:21 +01:00
Adam Kelly
17c3f9f024 builtin_locals can just return a reference to the locals dict. 2019-03-25 16:34:07 +00:00
Adam Kelly
3562b8f59c Store class attributes inside PyClass struct. 2019-03-25 11:21:01 +00:00
Adam
9989795141 Merge pull request #742 from RustPython/emoji-support
Doing what is needed for all our non-latin friends.
2019-03-25 10:39:09 +00:00
Windel Bouwman
ca11e7dea7 Add support for emoji as name. 2019-03-24 20:16:38 +01:00
Joey
0409e8197b Merge pull request #744 from RustPython/joey/range-new-style
Convert range to new args style
2019-03-24 11:49:34 -07:00
Joey
f2d562a4cc pyint: use as_bigint() everywhere 2019-03-24 10:05:25 -07:00
Joey
9a0113deed range: represent w/ int refs 2019-03-24 09:59:06 -07:00
Joey
c2e1e9b0dc Convert range to new args style 2019-03-24 09:59:06 -07:00
coolreader18
565719dcda Update cargo dependencies 2019-03-24 11:26:41 -05:00
coolreader18
3b582760b4 Merge pull request #733 from RustPython/coolreader18/wasm-browser-dom
[WASM] Add PyDocument and PyElement classes to browser
2019-03-24 10:47:46 -05:00
Joey
9d78fa5df2 Merge pull request #719 from adrian17/type-subclasses
Type __subclasses__()
2019-03-24 08:22:11 -07:00
coolreader18
6450612bdf Merge branch 'master' into coolreader18/wasm-browser-dom 2019-03-24 08:54:51 -05:00
coolreader18
0ac1c1f19c Add line continuation for the WASM demo terminal 2019-03-24 08:42:18 -05:00
Windel Bouwman
d0c4fcb2fa Doing what is needed for all our non-latin friends. 2019-03-24 13:14:38 +01:00
Adrian Wielgosik
e39df6daef Basic implementation of T.__subclasses__().
Ideally, the weak list should be updated whenever a type is removed,
and the list shouldn't be a Vec, but this should be good enough for
starters.
2019-03-24 12:49:04 +01:00
Adrian Wielgosik
a895ab35ae Make PyWeak::downgrade take a reference 2019-03-24 11:56:15 +01:00
Adrian Wielgosik
9a6f7aa8a1 Make PyRef::clone not require T implementing Clone
It seems to be a weird consequence of using PhantomData,
so I just rolled a custom Clone.
2019-03-24 11:56:15 +01:00
Joey
fbd0860f1b Merge pull request #740 from skinny121/into_object_cleanup
Use specific PyRef where possible - code object/type_new_class
2019-03-23 21:28:39 -07:00
coolreader18
12564da369 Rustfmt? 2019-03-23 22:46:21 -05:00
coolreader18
ec433cdbb9 Fix rustfmt again (?) 2019-03-23 22:17:21 -05:00
ben
3f363585e8 Panic if value poped of stack isn't a code object. 2019-03-24 16:08:17 +13:00
Joey
5441f3f89c Merge pull request #739 from RustPython/joey/range-getitem-either
Introduce Either extractor and convert range.__getitem__
2019-03-23 19:10:37 -07:00
coolreader18
946103bca8 Merge branch 'master' into coolreader18/wasm-browser-dom 2019-03-23 20:12:26 -05:00
Joey
84d47d21cf Rename to just Either 2019-03-23 17:51:12 -07:00
ben
6eb93a7000 Move code methods into impl PyCodeRef 2019-03-24 13:50:50 +13:00
coolreader18
0f2889a0e5 Fix weird rustfmt 2019-03-23 19:46:46 -05:00
ben
db8e648646 Make PyFunction.code a PyCodeRef, PyGenerator.frame a FrameRef, and
other improvements to increase use of specific ref types.
2019-03-24 13:41:37 +13:00
ben
dc68101577 Refactor type_new_class to use more specific ref types 2019-03-24 12:08:15 +13:00
Joey
3c15d892c5 Avoid some cloning 2019-03-23 15:57:06 -07:00
Joey
e5066da94e Merge remote-tracking branch 'origin/master' into joey/range-getitem-either 2019-03-23 15:50:12 -07:00
Joey
b6f1ecdb4b Fix example 2019-03-23 15:49:31 -07:00
Joey
a1560103ea Merge pull request #737 from skinny121/object_type_pyclassref
Change PyObject.typ to PyClassRef
2019-03-23 15:41:19 -07:00
Joey
a5558e0e32 Introduce Either extractor and convert range.__getitem__ 2019-03-23 15:05:12 -07:00
ben
faf1925a25 Remove usages of PyClassRef::from_pyobj 2019-03-24 10:51:52 +13:00
ben
00540dec35 Fix wasm, to reflect that PyObject.typ is now a PyClassRef 2019-03-24 10:51:52 +13:00
ben
6fa059fd6c Make PyObject.typ a PyClassRef 2019-03-24 10:51:52 +13:00
Joey
4666a09b20 Merge pull request #735 from RustPython/joey/range-cleanup
Range cleanups
2019-03-23 14:35:18 -07:00
Aviv Palivoda
590b659548 Change validate_set_or_frozenset to a function 2019-03-23 23:24:57 +02:00
Joey
da3dfa6c03 Merge pull request #734 from RustPython/joey/socket-cleanup
Some socket and io cleanups
2019-03-23 14:18:14 -07:00
Joey
3177824474 Fix test- 2019-03-23 12:57:17 -07:00
Joey
18ed00a653 Range cleanups 2019-03-23 12:48:37 -07:00
Joey
e4e7da3d54 Some socket cleanups 2019-03-23 12:21:55 -07:00
coolreader18
cecc2e1835 Merge pull request #732 from palaviv/super-classmethod
Support classmethod super
2019-03-23 14:17:06 -05:00
coolreader18
0aabe88c5d Put browser class methods into impl blocks 2019-03-23 14:04:14 -05:00
coolreader18
9050799cc4 Merge branch 'master' into coolreader18/wasm-browser-dom 2019-03-23 13:22:07 -05:00
Joey
65e00a8f32 Merge pull request #730 from RustPython/joey/remove-frompyobjecterf
Remove FromPyObjectRef, replace with downcast
2019-03-23 11:05:10 -07:00
Aviv Palivoda
1d820a9586 Use payload_is 2019-03-23 20:01:11 +02:00
Aviv Palivoda
2f9a49d077 Support classmethod super 2019-03-23 19:56:00 +02:00
Joey
af0194d51e Merge pull request #731 from RustPython/cleaning-tweaks
Use extend_class macro even more
2019-03-23 10:49:09 -07:00
Joey
f413beb051 Fix test 2019-03-23 10:03:40 -07:00
Windel Bouwman
fa8d3524bf Use extend_class macro even more 2019-03-23 17:49:49 +01:00
Joey
2aee2981e3 Remove FromPyObjectRef, replace with downcast 2019-03-23 09:38:03 -07:00
Aviv Palivoda
dc05d5f94b Remove Refcell around PyFrozenSet elements 2019-03-23 17:28:50 +02:00
Aviv Palivoda
2626a800ab Support frozenset 2019-03-23 17:27:33 +02:00
coolreader18
a830d8e131 Add PyDocument and PyElement 2019-03-23 09:36:15 -05:00
coolreader18
430bc4bac2 Fix vm.import when there are no frames on stack 2019-03-23 09:35:53 -05:00
Windel Bouwman
9b4d719197 Merge pull request #728 from RustPython/remove_attribute_protocol
Remove attribute protocol
2019-03-23 13:13:34 +01:00
Adam Kelly
441560b691 Delete Attribute Protocol. 2019-03-23 11:29:22 +00:00
Adam Kelly
386f90fa25 Remove PyContext.get_attr. 2019-03-23 11:29:22 +00:00
Windel Bouwman
9630c5cee1 Merge pull request #727 from RustPython/wasm_no_attribute_protocol
Remove attribute protocol from wasm.
2019-03-23 12:13:02 +01:00
Windel Bouwman
8fa315110e Merge pull request #726 from RustPython/bool_magic_methods
Replace special cases in boolval with __bool__ method on types.
2019-03-23 11:41:36 +01:00
Adam Kelly
c8bdb249b0 Remove attribute protocol from wasm. 2019-03-23 10:11:39 +00:00
Adam Kelly
9ebbde8126 Replace special cases in boolval with __bool__ method on types. 2019-03-23 09:31:42 +00:00
Adam
26a238085f Merge pull request #724 from RustPython/cleaning-tweaks
Increase usage of extend_class macro.
2019-03-23 09:14:50 +00:00
Adam
cea5341473 Merge pull request #723 from skinny121/isinstance_classref
Change isinstance/issubclass to accept PyClassRef
2019-03-23 09:14:16 +00:00
Windel Bouwman
b93f96d491 Increase usage of extend_class macro. 2019-03-23 09:16:32 +01:00
ben
983cb9e886 Fix Never::class signature 2019-03-23 19:35:42 +13:00
ben
4e7e503785 Fix wasm build, to reflect that isinstance now takes a PyClassRef 2019-03-23 19:32:31 +13:00
ben
ad584df120 Allow context.set_attr to accept PyRef values in addition to PyObjectRef 2019-03-23 19:32:31 +13:00
ben
c1d5ce715f Change isinstance/issubclass to accept PyClassRef instead of PyCObject.
Also changed PyValue::class to return a PyClassRef.
2019-03-23 19:32:31 +13:00
Joey
b7fa08eb36 Merge pull request #722 from RustPython/joey/unboxed-payload-2
Remove Box from PyObject
2019-03-22 20:29:36 -07:00
Joey
3f98a8ab1b Merge pull request #721 from skinny121/context_ref_types
Change types in PyContext to be PyClassRef's than PyObjectRef's
2019-03-22 19:14:01 -07:00
Joey
050bf0730e Remove HeldRcInner 2019-03-22 19:10:22 -07:00
Joey Hain
85ffde7382 Fix wasm 2019-03-22 18:37:06 -07:00
Joey Hain
c06b1c70df Fix merge issue 2019-03-22 18:05:24 -07:00
Joey Hain
7b4b0979f4 Merge remote-tracking branch 'origin/master' into joey/unboxed-payload-2 2019-03-22 18:04:15 -07:00
Joey Hain
bb161a5a67 Remove Box from PyObject 2019-03-22 18:04:09 -07:00
ben
b354b86b7b Fix none_new, return same object that is in PyContext 2019-03-23 13:00:17 +13:00
ben
5c7812734d Use more specific ref type than PyObjectRef in PyContext 2019-03-23 13:00:12 +13:00
coolreader18
79a7aed46d Make logo larger 2019-03-22 18:12:08 -05:00
coolreader18
c430b5a597 Fix logo in README 2019-03-22 18:10:46 -05:00
coolreader18
cf78d6b3eb Add logo to README 2019-03-22 18:09:05 -05:00
Adam
52943bf73c Merge pull request #710 from RustPython/class_get_attr_2
Class get attr 2
2019-03-22 22:21:55 +00:00
Joey
bcc3aa0910 Merge pull request #720 from RustPython/cleaning-tweaks
Use the extend class macro more.
2019-03-22 13:56:39 -07:00
Adam Kelly
c67cb07d9d Rename class_has_item and class_has_attr. 2019-03-22 20:54:14 +00:00
Adam Kelly
50437f8a75 Use class_get_attr in various places where we need the internal interface 2019-03-22 19:51:02 +00:00
Adam Kelly
909b38e774 Adapt objobject to avoid AttributeProtocol. 2019-03-22 19:49:09 +00:00
Adam Kelly
66adc25201 objtype - replace AttributeProtocol access with class_get_attr. 2019-03-22 19:47:51 +00:00
Windel Bouwman
68ba050030 Use the extend class macro more. 2019-03-22 20:45:34 +01:00
coolreader18
8f6d8a78de Keepalive WASM webpack build 2019-03-22 13:14:08 -05:00
coolreader18
162c2dc207 Merge branch 'coolreader18/multiline-repl'
Make the REPL handle line continuation better #711
2019-03-22 11:27:05 -05:00
Windel Bouwman
7ed4bc4aa8 Merge pull request #698 from palaviv/super
Use first argument in super
2019-03-22 17:13:13 +01:00
Aviv Palivoda
2c8657c3b3 Add load_cell to NameProtocol 2019-03-22 16:37:28 +02:00
Aviv Palivoda
84e89d37e2 Use __class__ cell in super 2019-03-22 16:37:28 +02:00
Aviv Palivoda
6230a25c4b Use first argument in super 2019-03-22 16:37:28 +02:00
coolreader18
5e74d53fb4 Merge pull request #716 from palaviv/fix-format
Fix format
2019-03-22 09:32:54 -05:00
Aviv Palivoda
474577beca Fix format 2019-03-22 16:23:15 +02:00
coolreader18
a9e2cc90d4 Merge pull request #714 from RustPython/coolreader18/immutable-vm-ref
Convert all &mut VirtualMachine to &VirtualMachine
2019-03-22 07:36:45 -05:00
coolreader18
18be23a2ec Merge branch 'master' into coolreader18/multiline-repl 2019-03-22 07:29:53 -05:00
coolreader18
36ff4e37d3 Use vm.get_attribute 2019-03-22 07:29:14 -05:00
coolreader18
5c8c4a849d Merge branch 'master' into coolreader18/multiline-repl 2019-03-22 07:27:10 -05:00
coolreader18
79666c255a Fix some issues wrt mutability 2019-03-22 07:24:06 -05:00
coolreader18
b0d8935731 Merge branch 'master' into coolreader18/immutable-vm-ref 2019-03-22 07:21:45 -05:00
Adam
e7eff34e13 Merge pull request #709 from RustPython/avoid_attribute_protocol
Avoid attribute protocol
2019-03-22 11:42:30 +00:00
Adam Kelly
23ee751880 Use vm.get_attribute to access attributes of modules. 2019-03-22 10:54:28 +00:00
coolreader18
2c93c79ac8 Immutable prompt variable 2019-03-22 01:53:55 -05:00
coolreader18
243826679c Remove unnecessary &mut 2019-03-22 01:51:44 -05:00
coolreader18
a9051ab462 Convert all &mut VirtualMachine to &VirtualMachine 2019-03-22 01:48:14 -05:00
Windel Bouwman
0838e301c7 Merge pull request #706 from RustPython/immutable-vm
Put RefCell around frames member of VirtualMachine.
2019-03-22 07:06:18 +01:00
coolreader18
88d6926f78 Make the REPL handle continuation better 2019-03-21 20:25:16 -05:00
Windel Bouwman
08520a68cf Merge pull request #700 from RustPython/coolreader18/wasm-example-npm
Change the WASM example to use rustpython from npm
2019-03-21 18:40:20 +01:00
Joey
90db9812e5 Merge pull request #707 from RustPython/joey/proper-pyref-display
Fix the Display impl for PyRef
2019-03-21 09:32:02 -07:00
Adam Kelly
19fc202e1a Classmethod/staticmethod - rewrite using structs and new style methods. 2019-03-21 13:03:51 +00:00
Adam
ce120c13b7 Merge pull request #705 from RustPython/into_pystringref
Introduce IntoPyStringRef to make vm.get_attribute more usable.
2019-03-21 12:13:19 +00:00
Adam Kelly
e66b5078a8 Introduce TryIntoRef<T> to make vm.get_attribute more usable. 2019-03-21 10:58:32 +00:00
Joey
59807710f7 Merge remote-tracking branch 'origin/master' into joey/proper-pyref-display 2019-03-21 03:43:40 -07:00
Adam
5a1a436c1e Merge pull request #708 from skinny121/descriptor_set_delete
Implement calling __set__ and __delete__ magic methods
2019-03-21 10:43:10 +00:00
ben
4ad8d5ed9b Make property.__get__ owner parameter optional 2019-03-21 19:57:35 +13:00
ben
a5f6a7b10d Implement calling __set__ and __delete__ 2019-03-21 19:34:47 +13:00
coolreader18
f5bbc7f664 Merge pull request #701 from RustPython/coolreader18/fix-wasm-import-json
Fix the WASM build
2019-03-21 01:01:02 -05:00
coolreader18
ed60b19612 Use vm.{,de}serialize in rustpython_wasm 2019-03-21 00:10:02 -05:00
coolreader18
d024e7ed8d Switch from an stdlib function to a vm method 2019-03-21 00:08:36 -05:00
coolreader18
7a980b3b47 Merge branch 'master' into coolreader18/fix-wasm-import-json 2019-03-20 23:58:19 -05:00
Joey Hain
0b1b6682c1 Fix Display impl for PyRef 2019-03-20 18:32:25 -07:00
Joey Hain
54753b3d14 list, tuple: return NotImplemented for unsupported comparisons 2019-03-20 18:32:08 -07:00
Windel Bouwman
8c0419e6b4 Put RefCell around frames member of VirtualMachine. This allows for VirtualMachine to be immutable. 2019-03-20 20:29:08 +01:00
coolreader18
6c660c9a6f Merge pull request #699 from RustPython/coolreader18/fix-clippy1
Fix a bunch of clippy lints (again)
2019-03-20 09:03:41 -05:00
coolreader18
3731148237 Merge branch 'master' into coolreader18/fix-clippy1 2019-03-20 09:03:07 -05:00
coolreader18
e35cc813a8 Rename to Unnamed and Named 2019-03-20 08:59:37 -05:00
Windel Bouwman
4c485202d1 Merge pull request #703 from RustPython/add_class_cell
Add __class__ cell to method scopes.
2019-03-20 13:56:03 +01:00
Adam Kelly
1958e47022 Add __class__ cell to method scopes. 2019-03-20 09:20:28 +00:00
Adam
32cb59909e Merge pull request #694 from skinny121/setattr
Various fixes for getattr/setattr/hasattr
2019-03-20 08:35:00 +00:00
ben
08e66b5002 Create workaround for properties on None 2019-03-20 19:58:56 +13:00
ben
a5050ebafe Make property return itself if invoke by class binding 2019-03-20 19:58:54 +13:00
ben
6c3a402eca Fix setting attributes on modules 2019-03-20 19:58:48 +13:00
ben
48dd507cad Remove dict from object 2019-03-20 19:58:46 +13:00
ben
c77b1f3cf5 Fix bug with __getattr__ 2019-03-20 19:56:25 +13:00
ben
63d40edbc6 Added bunch af attribute has/get/set/delete tests and fixed getattr and
hasattr handling of exceptions.
2019-03-20 19:56:23 +13:00
ben
4e42bd077c Implement __setattr__ based on @nhynes(#540) PR 2019-03-20 19:53:50 +13:00
coolreader18
de1bc937e7 Use json straight from json.rs 2019-03-19 22:20:10 -05:00
coolreader18
b7916cdb53 Fix varargs errors 2019-03-19 22:15:09 -05:00
coolreader18
ef3b9105ef Rename object_is back to payload_is 2019-03-19 20:59:48 -05:00
coolreader18
01bed2a051 Change the WASM example to use rustpython from npm 2019-03-19 20:54:53 -05:00
coolreader18
33b99b203f Some minor things 2019-03-19 20:34:35 -05:00
coolreader18
ff5c203b0e impl From<&ast::Varargs> for bytecode::Varargs 2019-03-19 20:13:03 -05:00
coolreader18
b30d56df29 Fix some more clippy warnings 2019-03-19 20:02:06 -05:00
coolreader18
ab53883f67 Change varargs from Option<Option<_>> to its own enum 2019-03-19 19:53:22 -05:00
coolreader18
4c9527be47 Merge branch 'master' into coolreader18/fix-clippy1 2019-03-19 19:19:36 -05:00
Windel Bouwman
5b6b33b644 Merge pull request #697 from RustPython/more_pyobject
More pyobject
2019-03-19 19:21:44 +01:00
Windel Bouwman
415f44da79 Merge pull request #673 from RustPython/string-io
Add write method to io.StringIO
2019-03-19 19:12:08 +01:00
Windel Bouwman
1969c90d98 Merge pull request #696 from palaviv/super
super in class methods
2019-03-19 19:08:53 +01:00
Adam Kelly
5384e07bf3 Remove PyObject::new from tuple and list. 2019-03-19 17:15:14 +00:00
Adam Kelly
c6e7d8901f Remove use of PyObject::new from objset. 2019-03-19 17:14:51 +00:00
Adam Kelly
638196bce4 Eliminate PyObject::new from objenumerate. 2019-03-19 16:42:40 +00:00
Adam Kelly
d38e89a811 Remove PyObject::new from objgenerator. 2019-03-19 16:28:53 +00:00
Adam Kelly
aeaa94966f Remove PyObject::new from objmap. 2019-03-19 16:24:19 +00:00
Aviv Palivoda
c3d0fddfcf Add PySuper 2019-03-19 18:08:43 +02:00
coolreader18
f78f558404 Fix clippy lints 2019-03-19 10:52:39 -05:00
Adam
4b5e75ea5b Merge pull request #683 from RustPython/objdict_refactor
Objdict refactor
2019-03-19 11:24:21 +00:00
Adam Kelly
6b3f61f3ca Merge branch 'master' into objdict_refactor 2019-03-19 10:19:03 +00:00
Aviv Palivoda
50cc9fa91f super works in class methods 2019-03-18 22:00:54 +02:00
Windel Bouwman
76dbd8c6e8 Apply cargo formatting. 2019-03-18 20:21:35 +01:00
Windel Bouwman
ac2aecd6fe Disable file argument in test. 2019-03-18 20:00:55 +01:00
Windel Bouwman
18fc8c150b Merge master 2019-03-18 20:00:00 +01:00
Windel Bouwman
3191725022 Refactor into new-style PyObject 2019-03-18 17:48:46 +01:00
Joey
c57be01711 Merge pull request #691 from RustPython/joey/builtin-print-newargs
Convert print() builtin to new args style
2019-03-18 09:35:46 -07:00
Windel Bouwman
39ee9172ff Merge pull request #693 from RustPython/joey/just-use-pyfuncargs
FromArgs: use PyFuncArgs instead of iterator
2019-03-17 07:34:59 +01:00
Joey
18b57188ba Add a custom derive for FromArgs 2019-03-16 17:13:23 -07:00
Joey
7cb889d42c Rebase against #693 and simplify 2019-03-16 16:38:28 -07:00
Joey
6550c52fa9 None doesn't mean no sep/end 2019-03-16 16:29:09 -07:00
Joey
55e7982835 Don't need while let 2019-03-16 16:29:09 -07:00
Joey
e83686cf3c Add clarifying note to KwArgs docs 2019-03-16 16:29:09 -07:00
Joey
d3b9714754 Convert print() builtin to new args style 2019-03-16 16:29:09 -07:00
Joey
7be5b8dafe FromArgs: use PyFuncArgs instead of iterator 2019-03-16 16:07:59 -07:00
Joey
3242ff3003 Merge pull request #690 from RustPython/joey/kwargs-surprise-positional
Handle unexpected positional argument in KwArgs
2019-03-16 12:58:35 -07:00
Joey
60ed1bd0a7 Handle unexpected positional argument in KwArgs 2019-03-16 10:18:46 -07:00
Joey
a32ebd530e Merge pull request #688 from RustPython/joey/pyobject-function-split
Move function items out of pyobject module
2019-03-16 09:15:51 -07:00
Joey
9de7285d23 Merge remote-tracking branch 'origin/master' into joey/pyobject-function-split
Conflicts:
      vm/src/frame.rs
      vm/src/obj/objbytearray.rs
      vm/src/obj/objbytes.rs
      vm/src/obj/objcomplex.rs
2019-03-16 08:37:18 -07:00
Adam
94e3cb8363 Merge pull request #682 from RustPython/prefer_pyvalue_into_ref
Prefer pyvalue into ref
2019-03-16 10:14:21 +00:00
Adam Kelly
9eeeeeae48 Change return type of vm.to_repr and vm.to_str to PyStringRef. 2019-03-16 09:42:54 +00:00
Adam Kelly
2f5c3ef1df Use PyStringRef to check type of dictionary keys. 2019-03-16 09:42:54 +00:00
Adam Kelly
a718a5a723 Refactor dict methods to new style declarations. 2019-03-16 09:42:54 +00:00
Adam Kelly
da6c56a001 Use extend_class in declaration of dictionary. 2019-03-16 09:22:02 +00:00
Adam Kelly
1f1b48c612 into_ref now needs the vm rather than a context. 2019-03-16 09:21:12 +00:00
Windel Bouwman
dbce329190 Merge pull request #687 from chylli/fix-any-memory-leak
#639
2019-03-16 10:18:27 +01:00
Chylli
6923490afc more test 2019-03-16 13:55:29 +08:00
Chylli
40a4e373af try 2019-03-16 13:52:57 +08:00
Chylli
144a8ae179 more test 2019-03-16 13:33:14 +08:00
Joey
7bfd2e6e84 Move function items out of pyobject module 2019-03-15 21:27:11 -07:00
Chylli
cf82a256da test any 2019-03-16 11:16:09 +08:00
Adam
0e6e8b617d Merge branch 'master' into prefer_pyvalue_into_ref 2019-03-15 22:11:51 +00:00
Windel Bouwman
7a4d653268 Merge pull request #679 from RustPython/joey/vm-not-pycontext
Make it possible to implement PyValue in stdlib
2019-03-15 19:23:39 +01:00
Windel Bouwman
bbe2704678 Merge pull request #684 from palaviv/selenium
Selenium tests for WASM
2019-03-15 19:19:03 +01:00
Windel Bouwman
ca47ddc02c Merge pull request #672 from coolreader18/wasm-vm-exec_single
Use compile::Mode::Single for the demo terminal
2019-03-15 19:10:25 +01:00
Adam Kelly
e8e8544b4b Avoid use of PyObject in objcomplex. 2019-03-15 16:09:04 +00:00
Aviv Palivoda
abb4d41e5b Add selenium test to travis 2019-03-15 17:24:34 +02:00
coolreader18
5b5d3e789a Merge branch 'coolreader18/wasm-remove-hashmap-rcs' 2019-03-15 07:25:43 -05:00
Adam Kelly
871ac15675 Avoid use of PyObject in objbytes. 2019-03-15 12:22:19 +00:00
Adam Kelly
7aa9b94243 Avoid use of PyObject in objbytearray. 2019-03-15 12:21:48 +00:00
Adam Kelly
a0acc7aa6a Avoid use of PyObject in frame.rs. 2019-03-15 12:21:05 +00:00
Adam Kelly
111208b46f Remove PyRef::new/new_with_type. 2019-03-15 11:36:25 +00:00
Aviv Palivoda
f281aab721 Move selenium test to wasm folder 2019-03-15 10:01:10 +02:00
Aviv Palivoda
3d95b70e0f Add selenium test for wasm 2019-03-15 09:13:55 +02:00
Joey
976afeda31 Add helper for obtaining class from module 2019-03-14 23:08:07 -07:00
Joey
fa9e48a5b3 Take &mut VirtualMachine insteadof &PyContext 2019-03-14 21:43:19 -07:00
Joey
737ec12fa5 Rename PyValue::{required_type => class} 2019-03-14 20:08:41 -07:00
coolreader18
a1e0c03a34 Merge pull request #670 from coolreader18/pyvaluepayload
Add PyObjectPayload trait and use it for PyObject.payload
2019-03-14 21:05:55 -05:00
coolreader18
8c1f18157d Remove leftover trace from debugging 2019-03-14 20:41:23 -05:00
coolreader18
f093aa4d6a Merge branch 'master' into pyvaluepayload 2019-03-14 20:25:51 -05:00
coolreader18
d7299bac99 Remove the Rcs around the WASM global HashMaps 2019-03-14 18:13:26 -05:00
coolreader18
2af998ea86 Prevent recursion for Debug impls 2019-03-14 17:54:38 -05:00
Adam
529da3fdfe Merge pull request #678 from RustPython/py_value_into_ref
Py value into ref
2019-03-14 16:22:46 +00:00
Joey
574be4ed3e Merge pull request #674 from RustPython/subclass_str
Fix subclasses of string. (Fixes #130)
2019-03-14 08:54:09 -07:00
Adam Kelly
b204c2b33e Add PyValue::into_ref and into_ref_with_type. 2019-03-14 09:42:40 +00:00
Adam Kelly
5b41cc4b0d Fix subclasses of string. (Fixes #130) 2019-03-14 09:06:29 +00:00
Joey
964a0410e0 Merge pull request #677 from skinny121/property
Implement property attributes and functions
2019-03-13 22:20:10 -07:00
ben
3f301bd684 Implement property attributes and functions 2019-03-14 17:19:43 +13:00
coolreader18
4b655b9ab7 Fix recursive Scope Debug impl 2019-03-13 22:49:09 -05:00
Joey
36204f29fe Merge pull request #676 from adrian17/master
Use Into<BigInt> instead of ToBigInt to avoid copies
2019-03-13 18:54:36 -07:00
Joey
b50ecf1023 Merge pull request #675 from skinny121/property_type_param
Remove type parameter from PropertyBuilder
2019-03-13 18:53:54 -07:00
Adrian Wielgosik
6b1598dbb4 Change some methods to return BigInt directly 2019-03-13 20:21:07 +01:00
Adrian Wielgosik
f647f346f2 Use Into<BigInt> instead of ToBigInt to avoid copies 2019-03-13 20:20:42 +01:00
ben
067fc0927d Remove type parameter from PropertyBuilder 2019-03-14 07:24:49 +13:00
coolreader18
913bb1438a Merge branch 'master' into wasm-vm-exec_single 2019-03-13 08:20:42 -05:00
coolreader18
6436d2cb9c fmt again 2019-03-13 08:16:41 -05:00
Windel Bouwman
c0b7ddfd2c Add write method to io.StringIO 2019-03-13 13:32:57 +01:00
Windel Bouwman
8dcea92bb2 Merge pull request #654 from coolreader18/wasm-explicit-stdout
[WASM] Make setStdout arguments more explicit in what they print to
2019-03-13 12:12:14 +01:00
Windel Bouwman
f0e285d124 Merge pull request #665 from RustPython/type_mro
Type mro
2019-03-13 12:05:59 +01:00
coolreader18
df68acb36b cargo fmt 2019-03-12 23:20:17 -05:00
coolreader18
bde86d32b1 Use compile::Mode::Single for the demo terminal 2019-03-12 22:46:55 -05:00
coolreader18
fb8351c5d1 Inline some functions 2019-03-12 20:59:03 -05:00
coolreader18
7bac1285d4 Fix all the tests 2019-03-12 20:26:33 -05:00
coolreader18
f31003614a Fix wasm 2019-03-12 19:42:52 -05:00
coolreader18
d305d4f74b Clean up a bit 2019-03-12 19:06:12 -05:00
coolreader18
c0e572767e Rename PyValuePayload to PyObjectPayload 2019-03-12 18:59:43 -05:00
coolreader18
070f5aa322 Merge master into pyvaluepayload 2019-03-12 18:36:10 -05:00
coolreader18
e49d7146a0 Add PyValuePayload trait and use it for PyObject.payload 2019-03-12 18:31:59 -05:00
Joey
83788b9d3c Merge pull request #667 from adrian17/no-option-typ
Remove Option from PyObject.typ; Refactor type hierarchy initialization.
2019-03-12 15:59:04 -07:00
Joey
051b382356 Merge pull request #668 from adrian17/compile_opts
Use default opt-level for release builds.
2019-03-12 15:47:20 -07:00
Adrian Wielgosik
a8f7c80e37 Use default opt-level for release builds. 2019-03-12 22:07:24 +01:00
Adrian Wielgosik
b334689e55 Remove Option from PyObject.typ; Refactor type hierarchy initialization. 2019-03-12 21:58:03 +01:00
Windel Bouwman
3cfee902ab Merge pull request #630 from lili668668/dict_get
Implement dict.get
2019-03-12 19:59:25 +01:00
Windel Bouwman
048a9547ce Merge pull request #652 from palaviv/__import__
Add __import__
2019-03-12 19:56:04 +01:00
Adam Kelly
336aa53b13 Allow IdProtocol to compare PyRef and non-PyRef. 2019-03-12 18:44:35 +00:00
Aviv Palivoda
6a3e82efd9 Fix typo 2019-03-12 20:21:59 +02:00
Adam
17082942e4 Merge pull request #666 from RustPython/pyclassref_protocols
Pyclassref protocols
2019-03-12 17:56:25 +00:00
Aviv Palivoda
2c6baacbac Return ImportError __import__ is not in builtins 2019-03-12 19:31:18 +02:00
Aviv Palivoda
e6c460fd97 Add import method to VirtualMachine 2019-03-12 18:35:15 +02:00
Adam Kelly
9f96b16624 Turn PyClass.mro into a Vec<PyClassRef> 2019-03-12 15:09:03 +00:00
Adam Kelly
3082f5faef Trivial implementations of IdProtocol and TypeProtocol for PyClassRef. 2019-03-12 13:43:30 +00:00
Adam Kelly
48fba05e20 Change .__mro__ to read-only attribute so type.__mro__ works. 2019-03-12 11:27:42 +00:00
Adam Kelly
5742e32669 PropertyBuilder: Constraint on setter type is too strong. 2019-03-12 11:27:18 +00:00
Tzu-Yin Hong
de2b928676 Format the code 2019-03-12 11:46:47 +08:00
Joey
a8c02105d1 Merge pull request #662 from adrian17/objint
Convert most objint functions to new args style
2019-03-11 19:39:32 -07:00
Joey
db7d736c68 Merge pull request #661 from RustPython/obj-improvements
Move classmethod and staticmethod to own files. Also use extend_class…
2019-03-11 19:34:35 -07:00
coolreader18
88fff7102e cargo fmt 2019-03-11 20:01:34 -05:00
coolreader18
18f77cee42 Merge branch 'master' into wasm-explicit-stdout 2019-03-11 19:25:13 -05:00
coolreader18
dac75019e5 Remove builtin_print_html, move functionality to JS 2019-03-11 19:18:21 -05:00
Adrian Wielgosik
e3a5ac1378 Make objint::get_value return a reference 2019-03-11 23:07:56 +01:00
Aviv Palivoda
a3823b4540 Test override __import__ 2019-03-11 22:49:55 +02:00
Adam
8ec1af52e8 Merge pull request #660 from RustPython/typetype_clean
Typetype clean
2019-03-11 20:34:26 +00:00
Aviv Palivoda
8c92636a82 Fix wasm code 2019-03-11 22:30:37 +02:00
Aviv Palivoda
87e6d8d13d Add __import__ 2019-03-11 22:29:50 +02:00
Adam Kelly
633a9b0365 Move more methods onto PyClassRef. 2019-03-11 18:58:15 +00:00
Adam Kelly
1e39512e74 Convert _mro to iterator. 2019-03-11 18:58:15 +00:00
Windel Bouwman
3d306fc3e4 Merge pull request #655 from coolreader18/mandelbrot-snippet-generator
Use a generator for the mandelbrot demo snippet
2019-03-11 19:42:17 +01:00
Windel Bouwman
c00d368448 Move classmethod and staticmethod to own files. Also use extend_class more. 2019-03-11 19:38:26 +01:00
Adrian Wielgosik
4cbb1a38f1 Convert most objint functions to new args style 2019-03-11 19:20:22 +01:00
Adam Kelly
3711881a60 Add type_pyref() to TypeProtocol. 2019-03-11 17:42:28 +00:00
coolreader18
482025045f Rearrange mandelbrot.py 2019-03-11 12:17:34 -05:00
coolreader18
31c6df31dc Okay now it works without browser 2019-03-11 12:14:37 -05:00
coolreader18
5ab41f9c54 Make mandelbrot.py work without browser module 2019-03-11 11:59:17 -05:00
Windel Bouwman
caae69fc35 Merge pull request #658 from RustPython/mro
Cleaner type_type declaration, and faster instance checking.
2019-03-11 17:40:09 +01:00
Windel Bouwman
b8aa38db1a Merge pull request #653 from RustPython/joey/pyobject-2.0-prep
Remove PyObjectPayload enum
2019-03-11 17:33:51 +01:00
Adam Kelly
d7e1d69430 Avoid additional clone in objtype::subinstance. 2019-03-11 11:44:25 +00:00
Adam Kelly
4d779bbf98 isinstance/issubclass - avoid expensive construction of full mro. 2019-03-11 11:18:40 +00:00
Adam Kelly
7894627b9d Use extend_class in objtype. 2019-03-11 10:22:53 +00:00
Joey
dfb24d7f11 Merge pull request #657 from skinny121/attribute_error
Use new_attribute_error in more places
2019-03-10 22:13:38 -07:00
ben
65c26a1f1b Use new_attribute_error in more places 2019-03-11 17:38:19 +13:00
Joey
a48340d591 Merge pull request #651 from RustPython/make_module_not_mk_module
Rename mk_module to make_module.
2019-03-10 21:25:31 -07:00
Joey Hain
2449c12bf9 Merge remote-tracking branch 'origin/master' into make_module_not_mk_module
Conflicts:
      vm/src/stdlib/weakref.rs
2019-03-10 20:43:11 -07:00
Joey Hain
053ceb1a30 Move payload boxing into PyObject::new 2019-03-10 20:19:28 -07:00
Joey
cf659b80c0 Merge pull request #656 from adrian17/master
Support index in list.pop()
2019-03-10 17:17:50 -07:00
coolreader18
09ab6d1d7c Reformat 2019-03-10 19:12:48 -05:00
Adrian Wielgosik
b123e58c55 Support index in list.pop() 2019-03-11 00:31:26 +01:00
coolreader18
40ef62db70 Use a generator for the mandelbrot demo snippet 2019-03-10 17:42:39 -05:00
coolreader18
29ec84ead9 Change main.js to print to the console 2019-03-10 17:22:22 -05:00
coolreader18
8407f7498e Change setStdout to take "console" instead of undefined 2019-03-10 17:20:32 -05:00
Joey Hain
4510489bba Fix PyObjectPayload usage in wasm 2019-03-10 15:19:04 -07:00
Joey Hain
5971fc3bd4 rename PyObjectPayload2 to PyValue 2019-03-10 13:48:51 -07:00
Joey Hain
e2e13af7ea Remove PyObjectPayload 2019-03-10 13:45:38 -07:00
Joey Hain
45bc8c8f7a Move PyRef to pyobject module 2019-03-10 13:01:46 -07:00
Joey
8143adc837 Merge pull request #636 from skinny121/weakref_type
Move weakref object type to obj module
2019-03-10 12:57:04 -07:00
Joey Hain
6024e3ea0c Fix irrefutable pattern errors 2019-03-10 12:43:25 -07:00
ben
7c5be7d6b7 Add proper weakref type 2019-03-11 07:49:12 +13:00
Windel Bouwman
ded7acc427 Merge pull request #643 from palaviv/interactive-shell
Add interactive shell to WASM demo
2019-03-10 18:18:41 +01:00
Adam Kelly
0ff5155af9 Rename mk_module to make_module. 2019-03-10 17:10:51 +00:00
Aviv Palivoda
f27cb5b8ed Don't delete prompt 2019-03-10 18:40:03 +02:00
Aviv Palivoda
625e181fd8 Use snakeCase 2019-03-10 18:38:17 +02:00
Aviv Palivoda
264d218b70 Use seperate VM for interactive shell 2019-03-10 18:36:29 +02:00
Windel Bouwman
e8ec497b02 Merge pull request #637 from RustPython/scope_globals_locals
Scope globals locals
2019-03-10 17:13:03 +01:00
Windel Bouwman
1751333686 Merge pull request #650 from chylli/add_str__doc__
add __doc__ to str
2019-03-10 17:08:13 +01:00
Chylli
e38a82e540 add __doc__ to str 2019-03-10 22:39:22 +08:00
Adam Kelly
3fbf627582 Merge branch 'master' into scope_globals_locals 2019-03-10 13:00:03 +00:00
Adam Kelly
4a82c8fad5 Rename AttributeProtocol2 -> NameProtocol with method name changes. 2019-03-10 12:51:34 +00:00
Adam Kelly
15aaa6d3f6 Add builtin_globals. 2019-03-10 12:51:34 +00:00
Adam Kelly
372f09aaa3 Abstract rc linked list so we can just use a loop. 2019-03-10 12:38:43 +00:00
Adam Kelly
ddf4f55af7 Enable tests that now pass thanks to new scope scheme. 2019-03-10 12:38:43 +00:00
Adam Kelly
6ad528c15c Reintroduce new_scope for the common case of an empty scope. 2019-03-10 12:38:43 +00:00
Adam Kelly
0e23e706c9 Restructure scope to distinguish between locals and globals. 2019-03-10 12:38:43 +00:00
Adam
9e5b76c9b6 Merge pull request #635 from skinny121/property_refactor
Unify property like objects
2019-03-10 12:35:24 +00:00
Windel Bouwman
eb19eaa6d6 Merge pull request #646 from RustPython/joey/memoryview-slice
Convert memoryview and slice to Any payload
2019-03-10 10:56:36 +01:00
Joey Hain
f6765cf16e less explicit returns 2019-03-10 00:34:21 -08:00
Windel Bouwman
eb14ada7ad Merge pull request #645 from RustPython/joey/convert-iterator
Convert iterator to Any payload
2019-03-10 09:18:14 +01:00
Windel Bouwman
79b4f62300 Merge pull request #642 from RustPython/joey/function-to-any
Convert function, method, builtin_*, frame, and generator to Any payload
2019-03-10 09:12:20 +01:00
Ryan Liddle
f57d2e22bf Merge pull request #649 from jaroel/context-manager-open
Make IOBase a context manager
2019-03-10 13:41:26 +11:00
Ryan Liddle
6072954024 Merge pull request #647 from RustPython/joey/no-arg-functions
Allow functions that don't take any args
2019-03-10 13:34:53 +11:00
Roel Bruggink
8f6257b37f Make open a context manager 2019-03-10 03:11:28 +01:00
Joey Hain
cd3ca16693 Allow functions that don't take any args 2019-03-09 16:46:29 -08:00
Joey Hain
e1d728e81f slice 2019-03-09 15:10:44 -08:00
Joey Hain
776dd80591 memoryview 2019-03-09 14:58:33 -08:00
Joey
157d18d7a1 Convert iterator 2019-03-09 14:45:55 -08:00
ben
7d01323e09 Merge branch 'master' into property_refactor
# Conflicts:
#	vm/src/function.rs
2019-03-10 09:06:21 +13:00
ben
3c3c1f2b6f Fixed new_attribute_error and added more tests for property 2019-03-10 09:01:46 +13:00
Aviv Palivoda
669aa70aab Support ':' in interactive shell 2019-03-09 21:23:59 +02:00
Aviv Palivoda
03d431ecac Support backspace in interactive shell 2019-03-09 21:17:13 +02:00
Aviv Palivoda
ec3ace527b Change prompt to >>>>> 2019-03-09 20:57:36 +02:00
Joey
6eea40799b generator 2019-03-09 09:28:15 -08:00
Joey
53e4591911 frame 2019-03-09 09:28:12 -08:00
Joey
c1180fc564 builtin_function_or_method 2019-03-09 08:45:46 -08:00
Aviv Palivoda
976c9e8b58 Add interactive shell to WASM demo 2019-03-09 18:41:02 +02:00
Joey Hain
5a74121c76 method 2019-03-09 07:11:28 -08:00
Joey Hain
dd56d1d5a2 function 2019-03-09 07:09:53 -08:00
Joey
010969f2d2 Merge pull request #641 from RustPython/py_module_use
Use py_module at more places.
2019-03-09 07:04:43 -08:00
Joey
1444a1f98c Merge pull request #640 from RustPython/type_annotations2
Add __annotations__ attribute to functions.
2019-03-09 07:04:32 -08:00
Joey
fae776d4ae Merge pull request #638 from adrian17/tuple_list
Convert most tuple/list methods to new args style
2019-03-09 07:04:02 -08:00
Windel Bouwman
6ba5b091e9 Use py_module at more places. 2019-03-09 12:38:14 +01:00
Windel Bouwman
adde4e731f Merge pull request #616 from coolreader18/wasm-syntax-error-location
[WASM] Add row and column info of a syntax error to the JS error
2019-03-09 12:13:23 +01:00
Windel Bouwman
c1ddcbb05f Merge pull request #632 from palaviv/socket-errors
Socket OSError
2019-03-09 11:55:03 +01:00
Windel Bouwman
3f492e5a3f Add __annotations__ attribute to functions. 2019-03-09 11:48:35 +01:00
Aviv Palivoda
8df0e46c32 Try to fix windows CI errors 2019-03-09 09:29:33 +02:00
Adam
56bb6d23cc Merge pull request #634 from RustPython/joey/map-zip-filter-enumerate-to-any
Convert map, zip, filter, and enumerate to Any payload
2019-03-09 06:42:04 +00:00
Adam
3730ca2b43 Merge pull request #551 from coolreader18/store-rcs-in-stored-vm
[WASM] Keep a PyObjectWeakRef to the PyObjectRef being moved to a closure
2019-03-09 06:36:01 +00:00
Adam
9e827cfc9d Merge pull request #631 from RustPython/py_module_payload
Replace PyObjectPayload::Module with PyModule.
2019-03-09 06:33:15 +00:00
Joey Hain
a2951f8a8b enumerate 2019-03-08 18:29:58 -08:00
Joey Hain
9544a47f46 filter 2019-03-08 18:29:57 -08:00
Joey Hain
9d8bdd7012 zip 2019-03-08 18:29:51 -08:00
Joey Hain
303e19d713 map 2019-03-08 18:29:41 -08:00
coolreader18
f1b156dfbf Merge branch 'master' into store-rcs-in-stored-vm 2019-03-08 20:03:13 -06:00
ben
0ec034df51 Change property.__new__ to use new style function and construct
PyProperty
2019-03-09 14:07:42 +13:00
ben
2edfe4c7be Migrate usage of member_descriptor and data_descriptor to
new_property/PropertyBuilder
2019-03-09 13:00:54 +13:00
ben
3fe32d0527 Merge branch 'master' into property_refactor 2019-03-09 12:13:00 +13:00
ben
5abc674737 Change property implementation to have rust payload and to use new
function style.
2019-03-09 12:11:07 +13:00
Adam
9a3b731894 Merge pull request #612 from RustPython/type_annotations2
Compile type annotations on function.
2019-03-08 21:34:40 +00:00
Adrian Wielgosik
10531191bb Convert most tuple/list methods to new args style 2019-03-08 20:43:20 +01:00
Windel Bouwman
8362b8da80 Merge pull request #623 from RustPython/code-of-conduct
Add a code of conduct
2019-03-08 18:53:43 +01:00
Windel Bouwman
502f8098b4 Change returns into return. 2019-03-08 18:51:20 +01:00
Aviv Palivoda
76c43457b5 Add more OSError exceptions to socket 2019-03-08 17:05:05 +02:00
Aviv Palivoda
de0e76baf8 socket connect and bind throws OSError with indicative error message 2019-03-08 16:43:11 +02:00
Aviv Palivoda
3fae8ccfbc Handle unknown socket kind 2019-03-08 16:19:26 +02:00
Aviv Palivoda
40c10ab70a Handle unknown address family 2019-03-08 16:16:59 +02:00
Adam Kelly
3f665ce673 Replace PyObjectPayload::Module with PyModule. 2019-03-08 08:43:07 +00:00
Adam
0febcb9c23 Merge pull request #625 from RustPython/py_class
Add PyClass.
2019-03-08 08:10:35 +00:00
Adam
21382fadbd Merge branch 'master' into py_class 2019-03-08 08:04:23 +00:00
Adam
50de0856ff Merge pull request #627 from RustPython/joey/list-tuple-any
Convert list and tuple to Any payload
2019-03-08 07:22:42 +00:00
Adam
d44129c53c Merge pull request #629 from coolreader18/anyrustvalue-debug
Have AnyRustValue actually format with its own Debug impl
2019-03-08 06:50:55 +00:00
Adam
9b317af586 Merge pull request #628 from coolreader18/objcode-any
Convert CodeObject payload to AnyRustValue
2019-03-08 06:50:26 +00:00
Adam
406ec46ce8 Merge pull request #619 from skinny121/class_property
Fix __class__
2019-03-08 06:47:55 +00:00
Adam
62a2344ba5 Merge pull request #621 from RustPython/pynone
Pynone
2019-03-08 06:47:27 +00:00
Tzu-Yin Hong
cdba098e70 Implement dict.get 2019-03-08 14:41:08 +08:00
Joey
1bcbb28715 Convert list and tuple to Any payload 2019-03-07 21:10:43 -08:00
coolreader18
87a58786af Have AnyRustValue actually format with its own Debug impl 2019-03-07 22:20:10 -06:00
coolreader18
231ab682b9 Convert CodeObject payload to AnyRustValue 2019-03-07 22:18:23 -06:00
ben
4b1cd72355 Add todo for using PyClassRef when that lands 2019-03-08 17:04:32 +13:00
coolreader18
c563a6d498 Convert Python errors to JS errors with row 2019-03-07 20:48:14 -06:00
Joey
3495b04e1a Merge pull request #624 from adrian17/string
Convert most remaining string methods to implicit args
2019-03-07 18:33:12 -08:00
coolreader18
5569f8d322 Merge branch 'master' of git://github.com/RustPython/RustPython into wasm-syntax-error-location 2019-03-07 20:27:11 -06:00
Joey
29e902957e Merge pull request #615 from adrian17/float
Migrate PyFloat to new method style
2019-03-07 12:42:14 -08:00
Adam Kelly
e220f0a571 Add PyClass and remove old Class payload 2019-03-07 20:42:10 +00:00
Adrian Wielgosik
b81a0a16d8 Convert most remaining string methods to implicit args
Also support out-of-range start/end params for some functions.
2019-03-07 20:39:57 +01:00
Windel Bouwman
4b783b1523 Add a code of conduct 2019-03-07 20:00:02 +01:00
Adrian Wielgosik
1601da0692 Migrate PyFloat to new method style 2019-03-07 19:47:16 +01:00
Adam Kelly
995212040a Use PyInstance as the payload rather than (). 2019-03-07 18:42:46 +00:00
Adam Kelly
5b1384814c Move attributes dictionary to PyObject. 2019-03-07 18:04:02 +00:00
Adam Kelly
303f9b95a0 Add (unused) dict element to PyObject struct. 2019-03-07 18:04:02 +00:00
Adam
e0e0734524 Merge pull request #617 from RustPython/joey/int-any
Convert int to Any payload
2019-03-07 18:03:25 +00:00
Adam Kelly
488d9a5922 Merge branch 'master' into joey/int-any 2019-03-07 18:00:59 +00:00
Adam Kelly
adf473faf4 Use macro for NoneType. 2019-03-07 17:06:34 +00:00
Adam Kelly
289c86de67 Add extend_class! macro to neaten definitions of builtins types. 2019-03-07 17:06:11 +00:00
ben
f2f0f1d742 Remove debug statements 2019-03-08 06:03:13 +13:00
Adam Kelly
22811c0d56 Add PyNone and new style definition for NoneType methods. 2019-03-07 17:00:24 +00:00
Adam
ac6521564f Merge pull request #618 from RustPython/joey/optional-arg-2
Improvements to OptionalArg extractor
2019-03-07 08:22:21 +00:00
Adam
cae87f6384 Merge pull request #604 from RustPython/unit-payload
Unit payload
2019-03-07 08:17:43 +00:00
ben
720bec2f4f Convert __class__ descriptor to use new style functions 2019-03-07 20:47:31 +13:00
ben
9d03abf652 Move __class__ attribute to object to make it work in more situations 2019-03-07 20:47:31 +13:00
Joey
f9ab27296a Add conversions for all primitive ints 2019-03-06 20:38:52 -08:00
Joey
4a000c424c Improvements to OptionalArg extractor 2019-03-06 19:53:03 -08:00
Joey
ecc92ffe33 Convert int to Any payload 2019-03-06 19:25:54 -08:00
coolreader18
7b8c8900bc Allow JS errors to get the row and column info of the error 2019-03-06 18:54:57 -06:00
Windel Bouwman
d7f8961a12 Simplify some PyFuncArgs occurences. 2019-03-06 22:30:11 +01:00
Windel Bouwman
eacf2fecc9 Merge pull request #614 from RustPython/__dir__
Dir
2019-03-06 22:14:16 +01:00
Adam Kelly
e0c398cbd5 Eliminate NoPayload and just use a boxed (). 2019-03-06 20:57:03 +00:00
Adam Kelly
d769fa9317 Remove unused function. 2019-03-06 19:08:37 +00:00
Adam Kelly
10bbfc6a34 Implement dir via __dir__. 2019-03-06 19:05:18 +00:00
Adam Kelly
2a593aa100 Add objmodule. 2019-03-06 18:11:52 +00:00
Windel Bouwman
e5ead870bc Merge pull request #605 from RustPython/subscript_list
Add subscript list in grammar.
2019-03-06 17:10:32 +01:00
Windel Bouwman
507a5b698f Merge pull request #611 from RustPython/pyargs
Less explicit PyFuncArgs is better.
2019-03-06 17:10:13 +01:00
Adam Kelly
a72af4d967 Remove None and NotImplemented payloads and replace with NoPayload 2019-03-06 16:04:26 +00:00
Adam Kelly
5afbfafa8b Remove special case for None payload from boolval. 2019-03-06 16:04:26 +00:00
Adam
03b419917e Merge pull request #591 from RustPython/re_module
Re module
2019-03-06 15:57:33 +00:00
Adam
11d0de24c3 Merge pull request #610 from RustPython/joey/impl-on-pyref
Improve readability of methods on PyRef<PyString>
2019-03-06 15:44:55 +00:00
Windel Bouwman
69efc7f223 Compile type annotations on function. 2019-03-06 13:48:30 +01:00
Windel Bouwman
6d84b4d4e9 Less explicit PyFuncArgs is better. implemented a From trait for PyFuncArgs 2019-03-06 12:02:01 +01:00
Windel Bouwman
f3791a3867 Fix test script for python3.6 2019-03-06 11:25:16 +01:00
Ryan Liddle
0000551c0e Merge pull request #608 from palaviv/dict-methods
Add dict.{keys,values,items}
2019-03-06 18:30:30 +11:00
Joey Hain
c68dbcc1ab Improve readability of methods on PyRef<PyString>
- Introduce PyStringRef type alias
- Impl python methods on PyStringRef to allow receiver to just be `self`
2019-03-05 19:56:25 -08:00
Joey
06e17af6cc Merge pull request #607 from adrian17/strings
Convert a bunch of string methods to new-args-style.
2019-03-05 20:50:36 -07:00
Joey
6f61e5847e Merge pull request #603 from RustPython/joey/set-dict-payload
Convert set and dict to Any payload
2019-03-05 20:45:11 -07:00
Joey
c5fca1bb0f Merge pull request #609 from coolreader18/fix-cargo-versions
Fix Cargo.toml versions
2019-03-05 19:41:19 -07:00
Joey Hain
894fa591d0 Merge remote-tracking branch 'origin/master' into joey/set-dict-payload
Conflicts:
      vm/src/pyobject.rs
2019-03-05 18:39:51 -08:00
coolreader18
b5248fbd82 Fix Cargo.toml versions 2019-03-05 17:27:56 -06:00
coolreader18
63613802ca Merge branch 'master' into store-rcs-in-stored-vm 2019-03-05 17:18:43 -06:00
Aviv Palivoda
24dcc06c24 add dict.keys 2019-03-05 22:46:13 +02:00
Aviv Palivoda
475476df71 Add dict.items 2019-03-05 22:41:42 +02:00
Aviv Palivoda
37118c7d75 Add dict.values 2019-03-05 22:34:45 +02:00
Adrian Wielgosik
e4e8b135ef Convert a bunch of string methods to new-args-style.
Mostly skipped the ones dealing with ints.
2019-03-05 20:41:02 +01:00
Windel Bouwman
c1a5e31c3c Extend re module. 2019-03-05 20:24:48 +01:00
Windel Bouwman
6ba25ef1c8 Merge pull request #575 from holygits/fix/bytearray-as-hex
Bytearray hex formatting
2019-03-05 19:58:32 +01:00
Windel Bouwman
0292146a42 Add subscript list in grammar. 2019-03-05 17:28:15 +01:00
holygits
f4ba94a397 Fix formatting 2019-03-05 19:03:25 +13:00
Joey Hain
d9c35f94c2 Convert dict payload 2019-03-04 21:46:21 -08:00
Joey Hain
bf1fe9e5f2 Convert set payload 2019-03-04 21:46:17 -08:00
holygits
0584b85d86 Bytearray hex formatting 2019-03-05 10:59:10 +13:00
coolreader18
5428154c81 Merge branch 'master' into store-rcs-in-stored-vm 2019-03-02 07:53:48 -06:00
coolreader18
88665e9ebd Keep a Weak to the py_obj being moved to a closure 2019-02-25 22:27:43 -06:00
305 changed files with 46181 additions and 14777 deletions

View File

@@ -0,0 +1,16 @@
---
name: Report incompatibility
about: Report an incompatibility between RustPython and CPython
title: ''
labels: feat
assignees: ''
---
## Feature
<!-- What Python feature is missing from RustPython? Give a short description of the feature and how you ran into its absence. -->
## Python Documentation
<!-- Give a link to the feature in the CPython documentation (https://docs.python.org/3/) in order to assist in its implementation. -->

24
.github/ISSUE_TEMPLATE/rfc.md vendored Normal file
View File

@@ -0,0 +1,24 @@
---
name: RFC
about: Make a suggestion in a Request for Comments format to RustPython
title: "[RFC] "
labels: RFC
assignees: ''
---
## Summary
<!-- A quick overview of your suggestion -->
## Detailed Explanation
<!-- Elaborate on your suggestion in all its details -->
## Drawbacks, Rationale, and Alternatives
<!-- What drawbacks might this solution have? Why do you feel it is necessary? What other options might there be to solving this problem? -->
## Unresolved Questions
<!-- What would you like feedback on for fleshing out your suggestion? -->

2
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/target
/*/target
**/*.rs.bk
**/*.bytecode
__pycache__
@@ -8,3 +9,4 @@ __pycache__
.vscode
wasm-pack.log
.idea/
tests/snippets/resources

View File

@@ -1,68 +1,44 @@
language: rust
rust:
- stable
- beta
- nightly
script:
- cargo build --verbose --all
- cargo test --verbose --all
env:
# This is used to only capture the regular nightly test in allow_failures
- REGULAR_TEST=true
cache: cargo
matrix:
fast_finish: true
include:
- name: Run rust tests
language: rust
rust: stable
cache: cargo
script:
- cargo build --verbose --all
- cargo test --verbose --all
env:
# Prevention of cache corruption.
# See: https://docs.travis-ci.com/user/caching/#caches-and-build-matrices
- JOBCACHE=1
# To test the snippets, we use Travis' Python environment (because
# installing rust ourselves is a lot easier than installing Python)
- language: python
- name: python test snippets
language: python
python: 3.6
cache:
pip: true
# Because we're using the Python Travis environment, we can't use
# the built-in cargo cacher
directories:
- /home/travis/.cargo
- target
- pip
- cargo
env:
- JOBCACHE=2
- TRAVIS_RUST_VERSION=stable
- REGULAR_TEST=false
- CODE_COVERAGE=false
script: tests/.travis-runner.sh
- language: python
python: 3.6
cache:
pip: true
# Because we're using the Python Travis environment, we can't use
# the built-in cargo cacher
directories:
- /home/travis/.cargo
- target
env:
- TRAVIS_RUST_VERSION=beta
- REGULAR_TEST=false
- CODE_COVERAGE=false
script: tests/.travis-runner.sh
- name: rustfmt
- name: Check rust code style with rustfmt
language: rust
rust: stable
cache: cargo
before_script:
- rustup component add rustfmt-preview
- rustup component add rustfmt
script:
# Code references the generated python.rs, so put something in
# place to make `cargo fmt` happy. (We use `echo` rather than
# `touch` because rustfmt complains about the empty file touch
# creates.)
- echo > parser/src/python.rs
- cargo fmt --all -- --check
env:
- REGULAR_TEST=false
- JOBCACHE=3
- name: publish documentation
language: rust
rust: stable
@@ -71,11 +47,20 @@ matrix:
- cargo doc --no-deps --all
if: branch = release
env:
- REGULAR_TEST=false
- DEPLOY_DOC=true
- JOBCACHE=4
deploy:
- provider: pages
repo: RustPython/website
target-branch: master
local-dir: target/doc
skip-cleanup: true
# Set in the settings page of your repository, as a secure variable
github-token: $WEBSITE_GITHUB_TOKEN
keep-history: true
- name: WASM online demo
language: rust
rust: nightly
rust: stable
cache: cargo
install:
- nvm install node
@@ -87,59 +72,45 @@ matrix:
- npm run dist
if: branch = release
env:
- REGULAR_TEST=false
- DEPLOY_DEMO=true
- name: cargo-clippy
language: rust
rust: stable
cache: cargo
before_script:
- rustup component add clippy
script:
- cargo clippy
env:
- REGULAR_TEST=true
- JOBCACHE=5
deploy:
- provider: pages
repo: RustPython/demo
target-branch: master
local-dir: wasm/demo/dist
skip-cleanup: true
# Set in the settings page of your repository, as a secure variable
github-token: $WEBSITE_GITHUB_TOKEN
keep-history: true
- name: Code Coverage
language: python
python: 3.6
cache:
pip: true
# Because we're using the Python Travis environment, we can't use
# the built-in cargo cacher
directories:
- /home/travis/.cargo
- target
- pip
- cargo
script:
- tests/.travis-runner.sh
# Only do code coverage on master via a cron job.
if: branch = master AND type = cron
env:
- JOBCACHE=6
- TRAVIS_RUST_VERSION=nightly
- REGULAR_TEST=false
- CODE_COVERAGE=true
allow_failures:
- rust: nightly
env: REGULAR_TEST=true
- name: cargo-clippy
deploy:
- provider: pages
repo: RustPython/website
target-branch: master
local-dir: target/doc
skip-cleanup: true
# Set in the settings page of your repository, as a secure variable
github-token: $WEBSITE_GITHUB_TOKEN
keep-history: true
on:
branch: release
condition: $DEPLOY_DOC = true
- provider: pages
repo: RustPython/demo
target-branch: master
local-dir: wasm/demo/dist
skip-cleanup: true
# Set in the settings page of your repository, as a secure variable
github-token: $WEBSITE_GITHUB_TOKEN
keep-history: true
on:
branch: release
condition: $DEPLOY_DEMO = true
- name: test WASM
language: python
python: 3.6
cache:
- pip
- cargo
addons:
firefox: latest
install:
- nvm install node
- pip install pipenv
script:
- wasm/tests/.travis-runner.sh
env:
- JOBCACHE=7
- TRAVIS_RUST_VERSION=stable

1692
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,29 @@
[package]
name = "rustpython"
version = "0.0.1-pre-alpha.1"
authors = ["Windel Bouwman", "Shing Lyu <shing.lyu@gmail.com>"]
version = "0.1.0"
authors = ["RustPython Team"]
edition = "2018"
description = "A python interpreter written in rust."
repository = "https://github.com/RustPython/RustPython"
license = "MIT"
[workspace]
members = [".", "vm", "wasm/lib", "parser"]
members = [".", "derive", "vm", "wasm/lib", "parser", "compiler", "bytecode"]
[[bench]]
name = "bench"
path = "./benchmarks/bench.rs"
[dependencies]
log="0.4.1"
env_logger="0.5.10"
clap = "2.31.2"
rustpython_parser = {path = "parser"}
rustpython_vm = {path = "vm"}
rustyline = "2.1.0"
rustpython-compiler = {path = "compiler", version = "0.1.0"}
rustpython-parser = {path = "parser", version = "0.1.0"}
rustpython-vm = {path = "vm", version = "0.1.0"}
rustyline = "4.1.0"
xdg = "2.2.0"
[profile.release]
opt-level = "s"
[dev-dependencies.cpython]
version = "0.2"

254
Lib/PSF-LICENSE Normal file
View File

@@ -0,0 +1,254 @@
A. HISTORY OF THE SOFTWARE
==========================
Python was created in the early 1990s by Guido van Rossum at Stichting
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
as a successor of a language called ABC. Guido remains Python's
principal author, although it includes many contributions from others.
In 1995, Guido continued his work on Python at the Corporation for
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
in Reston, Virginia where he released several versions of the
software.
In May 2000, Guido and the Python core development team moved to
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
year, the PythonLabs team moved to Digital Creations, which became
Zope Corporation. In 2001, the Python Software Foundation (PSF, see
https://www.python.org/psf/) was formed, a non-profit organization
created specifically to own Python-related Intellectual Property.
Zope Corporation was a sponsoring member of the PSF.
All Python releases are Open Source (see http://www.opensource.org for
the Open Source Definition). Historically, most, but not all, Python
releases have also been GPL-compatible; the table below summarizes
the various releases.
Release Derived Year Owner GPL-
from compatible? (1)
0.9.0 thru 1.2 1991-1995 CWI yes
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
1.6 1.5.2 2000 CNRI no
2.0 1.6 2000 BeOpen.com no
1.6.1 1.6 2001 CNRI yes (2)
2.1 2.0+1.6.1 2001 PSF no
2.0.1 2.0+1.6.1 2001 PSF yes
2.1.1 2.1+2.0.1 2001 PSF yes
2.1.2 2.1.1 2002 PSF yes
2.1.3 2.1.2 2002 PSF yes
2.2 and above 2.1.1 2001-now PSF yes
Footnotes:
(1) GPL-compatible doesn't mean that we're distributing Python under
the GPL. All Python licenses, unlike the GPL, let you distribute
a modified version without making your changes open source. The
GPL-compatible licenses make it possible to combine Python with
other software that is released under the GPL; the others don't.
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
because its license has a choice of law clause. According to
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
is "not incompatible" with the GPL.
Thanks to the many outside volunteers who have worked under Guido's
direction to make these releases possible.
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
===============================================================
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Python Software Foundation; All
Rights Reserved" are retained in Python alone or in any derivative version
prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.
4. PSF is making Python available to Licensee on an "AS IS"
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee. This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
-------------------------------------------
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
Individual or Organization ("Licensee") accessing and otherwise using
this software in source or binary form and its associated
documentation ("the Software").
2. Subject to the terms and conditions of this BeOpen Python License
Agreement, BeOpen hereby grants Licensee a non-exclusive,
royalty-free, world-wide license to reproduce, analyze, test, perform
and/or display publicly, prepare derivative works, distribute, and
otherwise use the Software alone or in any derivative version,
provided, however, that the BeOpen Python License is retained in the
Software, alone or in any derivative version prepared by Licensee.
3. BeOpen is making the Software available to Licensee on an "AS IS"
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
5. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
6. This License Agreement shall be governed by and interpreted in all
respects by the law of the State of California, excluding conflict of
law provisions. Nothing in this License Agreement shall be deemed to
create any relationship of agency, partnership, or joint venture
between BeOpen and Licensee. This License Agreement does not grant
permission to use BeOpen trademarks or trade names in a trademark
sense to endorse or promote products or services of Licensee, or any
third party. As an exception, the "BeOpen Python" logos available at
http://www.pythonlabs.com/logos.html may be used according to the
permissions granted on that web page.
7. By copying, installing or otherwise using the software, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
---------------------------------------
1. This LICENSE AGREEMENT is between the Corporation for National
Research Initiatives, having an office at 1895 Preston White Drive,
Reston, VA 20191 ("CNRI"), and the Individual or Organization
("Licensee") accessing and otherwise using Python 1.6.1 software in
source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, CNRI
hereby grants Licensee a nonexclusive, royalty-free, world-wide
license to reproduce, analyze, test, perform and/or display publicly,
prepare derivative works, distribute, and otherwise use Python 1.6.1
alone or in any derivative version, provided, however, that CNRI's
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
1995-2001 Corporation for National Research Initiatives; All Rights
Reserved" are retained in Python 1.6.1 alone or in any derivative
version prepared by Licensee. Alternately, in lieu of CNRI's License
Agreement, Licensee may substitute the following text (omitting the
quotes): "Python 1.6.1 is made available subject to the terms and
conditions in CNRI's License Agreement. This Agreement together with
Python 1.6.1 may be located on the Internet using the following
unique, persistent identifier (known as a handle): 1895.22/1013. This
Agreement may also be obtained from a proxy server on the Internet
using the following URL: http://hdl.handle.net/1895.22/1013".
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 1.6.1 or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python 1.6.1.
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. This License Agreement shall be governed by the federal
intellectual property law of the United States, including without
limitation the federal copyright law, and, to the extent such
U.S. federal law does not apply, by the law of the Commonwealth of
Virginia, excluding Virginia's conflict of law provisions.
Notwithstanding the foregoing, with regard to derivative works based
on Python 1.6.1 that incorporate non-separable material that was
previously distributed under the GNU General Public License (GPL), the
law of the Commonwealth of Virginia shall govern this License
Agreement only as to issues arising under or with respect to
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
License Agreement shall be deemed to create any relationship of
agency, partnership, or joint venture between CNRI and Licensee. This
License Agreement does not grant permission to use CNRI trademarks or
trade name in a trademark sense to endorse or promote products or
services of Licensee, or any third party.
8. By clicking on the "ACCEPT" button where indicated, or by copying,
installing or otherwise using Python 1.6.1, Licensee agrees to be
bound by the terms and conditions of this License Agreement.
ACCEPT
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
--------------------------------------------------
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
The Netherlands. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

10
Lib/README.md Normal file
View File

@@ -0,0 +1,10 @@
Standard Library for RustPython
===============================
This directory contains all of the Python files that make up the standard library for RustPython.
Most of these files are copied over from the CPython repository(the 3.7 branch), with slight modifications to allow them
to work under RustPython. The current goal is to complete the standard library with as few modifications as possible.
Current modifications are just temporary workarounds for bugs/missing feature within the RustPython implementation.
The first target is to run the ``unittest`` module, so we can leverage the CPython test suite.

1013
Lib/_collections_abc.py Normal file

File diff suppressed because it is too large Load Diff

147
Lib/_py_abc.py Normal file
View File

@@ -0,0 +1,147 @@
from _weakrefset import WeakSet
def get_cache_token():
"""Returns the current ABC cache token.
The token is an opaque object (supporting equality testing) identifying the
current version of the ABC cache for virtual subclasses. The token changes
with every call to ``register()`` on any ABC.
"""
return ABCMeta._abc_invalidation_counter
class ABCMeta(type):
"""Metaclass for defining Abstract Base Classes (ABCs).
Use this metaclass to create an ABC. An ABC can be subclassed
directly, and then acts as a mix-in class. You can also register
unrelated concrete classes (even built-in classes) and unrelated
ABCs as 'virtual subclasses' -- these and their descendants will
be considered subclasses of the registering ABC by the built-in
issubclass() function, but the registering ABC won't show up in
their MRO (Method Resolution Order) nor will method
implementations defined by the registering ABC be callable (not
even via super()).
"""
# A global counter that is incremented each time a class is
# registered as a virtual subclass of anything. It forces the
# negative cache to be cleared before its next use.
# Note: this counter is private. Use `abc.get_cache_token()` for
# external code.
_abc_invalidation_counter = 0
def __new__(mcls, name, bases, namespace, **kwargs):
cls = type.__new__(mcls, name, bases, namespace, **kwargs)
# Compute set of abstract method names
abstracts = {name
for name, value in namespace.items()
if getattr(value, "__isabstractmethod__", False)}
for base in bases:
for name in getattr(base, "__abstractmethods__", set()):
value = getattr(cls, name, None)
if getattr(value, "__isabstractmethod__", False):
abstracts.add(name)
cls.__abstractmethods__ = set(abstracts)
# Set up inheritance registry
cls._abc_registry = WeakSet()
cls._abc_cache = WeakSet()
cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
return cls
def register(cls, subclass):
"""Register a virtual subclass of an ABC.
Returns the subclass, to allow usage as a class decorator.
"""
if not isinstance(subclass, type):
raise TypeError("Can only register classes")
if issubclass(subclass, cls):
return subclass # Already a subclass
# Subtle: test for cycles *after* testing for "already a subclass";
# this means we allow X.register(X) and interpret it as a no-op.
if issubclass(cls, subclass):
# This would create a cycle, which is bad for the algorithm below
raise RuntimeError("Refusing to create an inheritance cycle")
cls._abc_registry.add(subclass)
ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache
return subclass
def _dump_registry(cls, file=None):
"""Debug helper to print the ABC registry."""
print(f"Class: {cls.__module__}.{cls.__qualname__}", file=file)
print(f"Inv. counter: {get_cache_token()}", file=file)
for name in cls.__dict__:
if name.startswith("_abc_"):
value = getattr(cls, name)
if isinstance(value, WeakSet):
value = set(value)
print(f"{name}: {value!r}", file=file)
def _abc_registry_clear(cls):
"""Clear the registry (for debugging or testing)."""
cls._abc_registry.clear()
def _abc_caches_clear(cls):
"""Clear the caches (for debugging or testing)."""
cls._abc_cache.clear()
cls._abc_negative_cache.clear()
def __instancecheck__(cls, instance):
"""Override for isinstance(instance, cls)."""
# Inline the cache checking
subclass = instance.__class__
if subclass in cls._abc_cache:
return True
subtype = type(instance)
if subtype is subclass:
if (cls._abc_negative_cache_version ==
ABCMeta._abc_invalidation_counter and
subclass in cls._abc_negative_cache):
return False
# Fall back to the subclass check.
return cls.__subclasscheck__(subclass)
return any(cls.__subclasscheck__(c) for c in (subclass, subtype))
def __subclasscheck__(cls, subclass):
"""Override for issubclass(subclass, cls)."""
if not isinstance(subclass, type):
raise TypeError('issubclass() arg 1 must be a class')
# Check cache
if subclass in cls._abc_cache:
return True
# Check negative cache; may have to invalidate
if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
# Invalidate the negative cache
cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
elif subclass in cls._abc_negative_cache:
return False
# Check the subclass hook
ok = cls.__subclasshook__(subclass)
if ok is not NotImplemented:
assert isinstance(ok, bool)
if ok:
cls._abc_cache.add(subclass)
else:
cls._abc_negative_cache.add(subclass)
return ok
# Check if it's a direct subclass
if cls in getattr(subclass, '__mro__', ()):
cls._abc_cache.add(subclass)
return True
# Check if it's a subclass of a registered class (recursive)
for rcls in cls._abc_registry:
if issubclass(subclass, rcls):
cls._abc_cache.add(subclass)
return True
# Check if it's a subclass of a subclass (recursive)
for scls in cls.__subclasses__():
if issubclass(subclass, scls):
cls._abc_cache.add(subclass)
return True
# No dice; update negative cache
cls._abc_negative_cache.add(subclass)
return False

196
Lib/_weakrefset.py Normal file
View File

@@ -0,0 +1,196 @@
# Access WeakSet through the weakref module.
# This code is separated-out because it is needed
# by abc.py to load everything else at startup.
from _weakref import ref
__all__ = ['WeakSet']
class _IterationGuard:
# This context manager registers itself in the current iterators of the
# weak container, such as to delay all removals until the context manager
# exits.
# This technique should be relatively thread-safe (since sets are).
def __init__(self, weakcontainer):
# Don't create cycles
self.weakcontainer = ref(weakcontainer)
def __enter__(self):
w = self.weakcontainer()
if w is not None:
w._iterating.add(self)
return self
def __exit__(self, e, t, b):
w = self.weakcontainer()
if w is not None:
s = w._iterating
s.remove(self)
if not s:
w._commit_removals()
class WeakSet:
def __init__(self, data=None):
self.data = set()
def _remove(item, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(item)
else:
self.data.discard(item)
self._remove = _remove
# A list of keys to be removed
self._pending_removals = []
self._iterating = set()
if data is not None:
self.update(data)
def _commit_removals(self):
l = self._pending_removals
discard = self.data.discard
while l:
discard(l.pop())
def __iter__(self):
with _IterationGuard(self):
for itemref in self.data:
item = itemref()
if item is not None:
# Caveat: the iterator will keep a strong reference to
# `item` until it is resumed or closed.
yield item
def __len__(self):
return len(self.data) - len(self._pending_removals)
def __contains__(self, item):
try:
wr = ref(item)
except TypeError:
return False
return wr in self.data
def __reduce__(self):
return (self.__class__, (list(self),),
getattr(self, '__dict__', None))
def add(self, item):
if self._pending_removals:
self._commit_removals()
self.data.add(ref(item, self._remove))
def clear(self):
if self._pending_removals:
self._commit_removals()
self.data.clear()
def copy(self):
return self.__class__(self)
def pop(self):
if self._pending_removals:
self._commit_removals()
while True:
try:
itemref = self.data.pop()
except KeyError:
raise KeyError('pop from empty WeakSet') from None
item = itemref()
if item is not None:
return item
def remove(self, item):
if self._pending_removals:
self._commit_removals()
self.data.remove(ref(item))
def discard(self, item):
if self._pending_removals:
self._commit_removals()
self.data.discard(ref(item))
def update(self, other):
if self._pending_removals:
self._commit_removals()
for element in other:
self.add(element)
def __ior__(self, other):
self.update(other)
return self
def difference(self, other):
newset = self.copy()
newset.difference_update(other)
return newset
__sub__ = difference
def difference_update(self, other):
self.__isub__(other)
def __isub__(self, other):
if self._pending_removals:
self._commit_removals()
if self is other:
self.data.clear()
else:
self.data.difference_update(ref(item) for item in other)
return self
def intersection(self, other):
return self.__class__(item for item in other if item in self)
__and__ = intersection
def intersection_update(self, other):
self.__iand__(other)
def __iand__(self, other):
if self._pending_removals:
self._commit_removals()
self.data.intersection_update(ref(item) for item in other)
return self
def issubset(self, other):
return self.data.issubset(ref(item) for item in other)
__le__ = issubset
def __lt__(self, other):
return self.data < set(map(ref, other))
def issuperset(self, other):
return self.data.issuperset(ref(item) for item in other)
__ge__ = issuperset
def __gt__(self, other):
return self.data > set(map(ref, other))
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.data == set(map(ref, other))
def symmetric_difference(self, other):
newset = self.copy()
newset.symmetric_difference_update(other)
return newset
__xor__ = symmetric_difference
def symmetric_difference_update(self, other):
self.__ixor__(other)
def __ixor__(self, other):
if self._pending_removals:
self._commit_removals()
if self is other:
self.data.clear()
else:
self.data.symmetric_difference_update(ref(item, self._remove) for item in other)
return self
def union(self, other):
return self.__class__(e for s in (self, other) for e in s)
__or__ = union
def isdisjoint(self, other):
return len(self.intersection(other)) == 0

170
Lib/abc.py Normal file
View File

@@ -0,0 +1,170 @@
# Copyright 2007 Google, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.
"""Abstract Base Classes (ABCs) according to PEP 3119."""
def abstractmethod(funcobj):
"""A decorator indicating abstract methods.
Requires that the metaclass is ABCMeta or derived from it. A
class that has a metaclass derived from ABCMeta cannot be
instantiated unless all of its abstract methods are overridden.
The abstract methods can be called using any of the normal
'super' call mechanisms.
Usage:
class C(metaclass=ABCMeta):
@abstractmethod
def my_abstract_method(self, ...):
...
"""
funcobj.__isabstractmethod__ = True
return funcobj
class abstractclassmethod(classmethod):
"""A decorator indicating abstract classmethods.
Similar to abstractmethod.
Usage:
class C(metaclass=ABCMeta):
@abstractclassmethod
def my_abstract_classmethod(cls, ...):
...
'abstractclassmethod' is deprecated. Use 'classmethod' with
'abstractmethod' instead.
"""
__isabstractmethod__ = True
def __init__(self, callable):
callable.__isabstractmethod__ = True
super().__init__(callable)
class abstractstaticmethod(staticmethod):
"""A decorator indicating abstract staticmethods.
Similar to abstractmethod.
Usage:
class C(metaclass=ABCMeta):
@abstractstaticmethod
def my_abstract_staticmethod(...):
...
'abstractstaticmethod' is deprecated. Use 'staticmethod' with
'abstractmethod' instead.
"""
__isabstractmethod__ = True
def __init__(self, callable):
callable.__isabstractmethod__ = True
super().__init__(callable)
class abstractproperty(property):
"""A decorator indicating abstract properties.
Requires that the metaclass is ABCMeta or derived from it. A
class that has a metaclass derived from ABCMeta cannot be
instantiated unless all of its abstract properties are overridden.
The abstract properties can be called using any of the normal
'super' call mechanisms.
Usage:
class C(metaclass=ABCMeta):
@abstractproperty
def my_abstract_property(self):
...
This defines a read-only property; you can also define a read-write
abstract property using the 'long' form of property declaration:
class C(metaclass=ABCMeta):
def getx(self): ...
def setx(self, value): ...
x = abstractproperty(getx, setx)
'abstractproperty' is deprecated. Use 'property' with 'abstractmethod'
instead.
"""
__isabstractmethod__ = True
try:
from _abc import (get_cache_token, _abc_init, _abc_register,
_abc_instancecheck, _abc_subclasscheck, _get_dump,
_reset_registry, _reset_caches)
except ImportError:
from _py_abc import ABCMeta, get_cache_token
ABCMeta.__module__ = 'abc'
else:
class ABCMeta(type):
"""Metaclass for defining Abstract Base Classes (ABCs).
Use this metaclass to create an ABC. An ABC can be subclassed
directly, and then acts as a mix-in class. You can also register
unrelated concrete classes (even built-in classes) and unrelated
ABCs as 'virtual subclasses' -- these and their descendants will
be considered subclasses of the registering ABC by the built-in
issubclass() function, but the registering ABC won't show up in
their MRO (Method Resolution Order) nor will method
implementations defined by the registering ABC be callable (not
even via super()).
"""
def __new__(mcls, name, bases, namespace, **kwargs):
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
_abc_init(cls)
return cls
def register(cls, subclass):
"""Register a virtual subclass of an ABC.
Returns the subclass, to allow usage as a class decorator.
"""
return _abc_register(cls, subclass)
def __instancecheck__(cls, instance):
"""Override for isinstance(instance, cls)."""
return _abc_instancecheck(cls, instance)
def __subclasscheck__(cls, subclass):
"""Override for issubclass(subclass, cls)."""
return _abc_subclasscheck(cls, subclass)
def _dump_registry(cls, file=None):
"""Debug helper to print the ABC registry."""
print(f"Class: {cls.__module__}.{cls.__qualname__}", file=file)
print(f"Inv. counter: {get_cache_token()}", file=file)
(_abc_registry, _abc_cache, _abc_negative_cache,
_abc_negative_cache_version) = _get_dump(cls)
print(f"_abc_registry: {_abc_registry!r}", file=file)
print(f"_abc_cache: {_abc_cache!r}", file=file)
print(f"_abc_negative_cache: {_abc_negative_cache!r}", file=file)
print(f"_abc_negative_cache_version: {_abc_negative_cache_version!r}",
file=file)
def _abc_registry_clear(cls):
"""Clear the registry (for debugging or testing)."""
_reset_registry(cls)
def _abc_caches_clear(cls):
"""Clear the caches (for debugging or testing)."""
_reset_caches(cls)
class ABC(metaclass=ABCMeta):
"""Helper class that provides a standard way to create an ABC using
inheritance.
"""
__slots__ = ()

1279
Lib/collections/__init__.py Normal file

File diff suppressed because it is too large Load Diff

2
Lib/collections/abc.py Normal file
View File

@@ -0,0 +1,2 @@
from _collections_abc import *
from _collections_abc import __all__

2097
Lib/difflib.py Normal file

File diff suppressed because it is too large Load Diff

828
Lib/functools.py Normal file
View File

@@ -0,0 +1,828 @@
"""functools.py - Tools for working with functions and callable objects
"""
# Python module wrapper for _functools C module
# to allow utilities written in Python to be added
# to the functools module.
# Written by Nick Coghlan <ncoghlan at gmail.com>,
# Raymond Hettinger <python at rcn.com>,
# and Łukasz Langa <lukasz at langa.pl>.
# Copyright (C) 2006-2013 Python Software Foundation.
# See C source code for _functools credits/copyright
__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial',
'partialmethod', 'singledispatch']
try:
from _functools import reduce
except ImportError:
pass
from abc import get_cache_token
from collections import namedtuple
# import types, weakref # Deferred to single_dispatch()
from reprlib import recursive_repr
from _thread import RLock
################################################################################
### update_wrapper() and wraps() decorator
################################################################################
# update_wrapper() and wraps() are tools to help write
# wrapper functions that can handle naive introspection
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
'__annotations__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Update a wrapper function to look like the wrapped function
wrapper is the function to be updated
wrapped is the original function
assigned is a tuple naming the attributes assigned directly
from the wrapped function to the wrapper function (defaults to
functools.WRAPPER_ASSIGNMENTS)
updated is a tuple naming the attributes of the wrapper that
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)
"""
for attr in assigned:
try:
value = getattr(wrapped, attr)
except AttributeError:
pass
else:
setattr(wrapper, attr, value)
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
# Issue #17482: set __wrapped__ last so we don't inadvertently copy it
# from the wrapped function when updating __dict__
wrapper.__wrapped__ = wrapped
# Return the wrapper so this can be used as a decorator via partial()
return wrapper
def wraps(wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Decorator factory to apply update_wrapper() to a wrapper function
Returns a decorator that invokes update_wrapper() with the decorated
function as the wrapper argument and the arguments to wraps() as the
remaining arguments. Default arguments are as for update_wrapper().
This is a convenience function to simplify applying partial() to
update_wrapper().
"""
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
################################################################################
### total_ordering class decorator
################################################################################
# The total ordering functions all invoke the root magic method directly
# rather than using the corresponding operator. This avoids possible
# infinite recursion that could occur when the operator dispatch logic
# detects a NotImplemented result and then calls a reflected method.
def _gt_from_lt(self, other, NotImplemented=NotImplemented):
'Return a > b. Computed by @total_ordering from (not a < b) and (a != b).'
op_result = self.__lt__(other)
if op_result is NotImplemented:
return op_result
return not op_result and self != other
def _le_from_lt(self, other, NotImplemented=NotImplemented):
'Return a <= b. Computed by @total_ordering from (a < b) or (a == b).'
op_result = self.__lt__(other)
return op_result or self == other
def _ge_from_lt(self, other, NotImplemented=NotImplemented):
'Return a >= b. Computed by @total_ordering from (not a < b).'
op_result = self.__lt__(other)
if op_result is NotImplemented:
return op_result
return not op_result
def _ge_from_le(self, other, NotImplemented=NotImplemented):
'Return a >= b. Computed by @total_ordering from (not a <= b) or (a == b).'
op_result = self.__le__(other)
if op_result is NotImplemented:
return op_result
return not op_result or self == other
def _lt_from_le(self, other, NotImplemented=NotImplemented):
'Return a < b. Computed by @total_ordering from (a <= b) and (a != b).'
op_result = self.__le__(other)
if op_result is NotImplemented:
return op_result
return op_result and self != other
def _gt_from_le(self, other, NotImplemented=NotImplemented):
'Return a > b. Computed by @total_ordering from (not a <= b).'
op_result = self.__le__(other)
if op_result is NotImplemented:
return op_result
return not op_result
def _lt_from_gt(self, other, NotImplemented=NotImplemented):
'Return a < b. Computed by @total_ordering from (not a > b) and (a != b).'
op_result = self.__gt__(other)
if op_result is NotImplemented:
return op_result
return not op_result and self != other
def _ge_from_gt(self, other, NotImplemented=NotImplemented):
'Return a >= b. Computed by @total_ordering from (a > b) or (a == b).'
op_result = self.__gt__(other)
return op_result or self == other
def _le_from_gt(self, other, NotImplemented=NotImplemented):
'Return a <= b. Computed by @total_ordering from (not a > b).'
op_result = self.__gt__(other)
if op_result is NotImplemented:
return op_result
return not op_result
def _le_from_ge(self, other, NotImplemented=NotImplemented):
'Return a <= b. Computed by @total_ordering from (not a >= b) or (a == b).'
op_result = self.__ge__(other)
if op_result is NotImplemented:
return op_result
return not op_result or self == other
def _gt_from_ge(self, other, NotImplemented=NotImplemented):
'Return a > b. Computed by @total_ordering from (a >= b) and (a != b).'
op_result = self.__ge__(other)
if op_result is NotImplemented:
return op_result
return op_result and self != other
def _lt_from_ge(self, other, NotImplemented=NotImplemented):
'Return a < b. Computed by @total_ordering from (not a >= b).'
op_result = self.__ge__(other)
if op_result is NotImplemented:
return op_result
return not op_result
_convert = {
'__lt__': [('__gt__', _gt_from_lt),
('__le__', _le_from_lt),
('__ge__', _ge_from_lt)],
'__le__': [('__ge__', _ge_from_le),
('__lt__', _lt_from_le),
('__gt__', _gt_from_le)],
'__gt__': [('__lt__', _lt_from_gt),
('__ge__', _ge_from_gt),
('__le__', _le_from_gt)],
'__ge__': [('__le__', _le_from_ge),
('__gt__', _gt_from_ge),
('__lt__', _lt_from_ge)]
}
def total_ordering(cls):
"""Class decorator that fills in missing ordering methods"""
# Find user-defined comparisons (not those inherited from object).
roots = {op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)}
if not roots:
raise ValueError('must define at least one ordering operation: < > <= >=')
root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__
for opname, opfunc in _convert[root]:
if opname not in roots:
opfunc.__name__ = opname
setattr(cls, opname, opfunc)
return cls
################################################################################
### cmp_to_key() function converter
################################################################################
def cmp_to_key(mycmp):
"""Convert a cmp= function into a key= function"""
class K(object):
__slots__ = ['obj']
def __init__(self, obj):
self.obj = obj
def __lt__(self, other):
return mycmp(self.obj, other.obj) < 0
def __gt__(self, other):
return mycmp(self.obj, other.obj) > 0
def __eq__(self, other):
return mycmp(self.obj, other.obj) == 0
def __le__(self, other):
return mycmp(self.obj, other.obj) <= 0
def __ge__(self, other):
return mycmp(self.obj, other.obj) >= 0
__hash__ = None
return K
try:
from _functools import cmp_to_key
except ImportError:
pass
################################################################################
### partial() argument application
################################################################################
# Purely functional, no descriptor behaviour
class partial:
"""New function with partial application of the given arguments
and keywords.
"""
__slots__ = "func", "args", "keywords", "__dict__", "__weakref__"
def __new__(*args, **keywords):
if not args:
raise TypeError("descriptor '__new__' of partial needs an argument")
if len(args) < 2:
raise TypeError("type 'partial' takes at least one argument")
cls, func, *args = args
if not callable(func):
raise TypeError("the first argument must be callable")
args = tuple(args)
if hasattr(func, "func"):
args = func.args + args
tmpkw = func.keywords.copy()
tmpkw.update(keywords)
keywords = tmpkw
del tmpkw
func = func.func
self = super(partial, cls).__new__(cls)
self.func = func
self.args = args
self.keywords = keywords
return self
def __call__(*args, **keywords):
if not args:
raise TypeError("descriptor '__call__' of partial needs an argument")
self, *args = args
newkeywords = self.keywords.copy()
newkeywords.update(keywords)
return self.func(*self.args, *args, **newkeywords)
@recursive_repr()
def __repr__(self):
qualname = type(self).__qualname__
args = [repr(self.func)]
args.extend(repr(x) for x in self.args)
args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items())
if type(self).__module__ == "functools":
return f"functools.{qualname}({', '.join(args)})"
return f"{qualname}({', '.join(args)})"
def __reduce__(self):
return type(self), (self.func,), (self.func, self.args,
self.keywords or None, self.__dict__ or None)
def __setstate__(self, state):
if not isinstance(state, tuple):
raise TypeError("argument to __setstate__ must be a tuple")
if len(state) != 4:
raise TypeError(f"expected 4 items in state, got {len(state)}")
func, args, kwds, namespace = state
if (not callable(func) or not isinstance(args, tuple) or
(kwds is not None and not isinstance(kwds, dict)) or
(namespace is not None and not isinstance(namespace, dict))):
raise TypeError("invalid partial state")
args = tuple(args) # just in case it's a subclass
if kwds is None:
kwds = {}
elif type(kwds) is not dict: # XXX does it need to be *exactly* dict?
kwds = dict(kwds)
if namespace is None:
namespace = {}
self.__dict__ = namespace
self.func = func
self.args = args
self.keywords = kwds
try:
from _functools import partial
except ImportError:
pass
# Descriptor version
class partialmethod(object):
"""Method descriptor with partial application of the given arguments
and keywords.
Supports wrapping existing descriptors and handles non-descriptor
callables as instance methods.
"""
def __init__(self, func, *args, **keywords):
if not callable(func) and not hasattr(func, "__get__"):
raise TypeError("{!r} is not callable or a descriptor"
.format(func))
# func could be a descriptor like classmethod which isn't callable,
# so we can't inherit from partial (it verifies func is callable)
if isinstance(func, partialmethod):
# flattening is mandatory in order to place cls/self before all
# other arguments
# it's also more efficient since only one function will be called
self.func = func.func
self.args = func.args + args
self.keywords = func.keywords.copy()
self.keywords.update(keywords)
else:
self.func = func
self.args = args
self.keywords = keywords
def __repr__(self):
args = ", ".join(map(repr, self.args))
keywords = ", ".join("{}={!r}".format(k, v)
for k, v in self.keywords.items())
format_string = "{module}.{cls}({func}, {args}, {keywords})"
return format_string.format(module=self.__class__.__module__,
cls=self.__class__.__qualname__,
func=self.func,
args=args,
keywords=keywords)
def _make_unbound_method(self):
def _method(*args, **keywords):
call_keywords = self.keywords.copy()
call_keywords.update(keywords)
cls_or_self, *rest = args
call_args = (cls_or_self,) + self.args + tuple(rest)
return self.func(*call_args, **call_keywords)
_method.__isabstractmethod__ = self.__isabstractmethod__
_method._partialmethod = self
return _method
def __get__(self, obj, cls):
get = getattr(self.func, "__get__", None)
result = None
if get is not None:
new_func = get(obj, cls)
if new_func is not self.func:
# Assume __get__ returning something new indicates the
# creation of an appropriate callable
result = partial(new_func, *self.args, **self.keywords)
try:
result.__self__ = new_func.__self__
except AttributeError:
pass
if result is None:
# If the underlying descriptor didn't do anything, treat this
# like an instance method
result = self._make_unbound_method().__get__(obj, cls)
return result
@property
def __isabstractmethod__(self):
return getattr(self.func, "__isabstractmethod__", False)
################################################################################
### LRU Cache function decorator
################################################################################
_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
class _HashedSeq(list):
""" This class guarantees that hash() will be called no more than once
per element. This is important because the lru_cache() will hash
the key multiple times on a cache miss.
"""
__slots__ = 'hashvalue'
def __init__(self, tup, hash=hash):
self[:] = tup
self.hashvalue = hash(tup)
def __hash__(self):
return self.hashvalue
def _make_key(args, kwds, typed,
kwd_mark = (object(),),
fasttypes = {int, str, frozenset, type(None)},
tuple=tuple, type=type, len=len):
"""Make a cache key from optionally typed positional and keyword arguments
The key is constructed in a way that is flat as possible rather than
as a nested structure that would take more memory.
If there is only a single argument and its data type is known to cache
its hash value, then that argument is returned without a wrapper. This
saves space and improves lookup speed.
"""
# All of code below relies on kwds preserving the order input by the user.
# Formerly, we sorted() the kwds before looping. The new way is *much*
# faster; however, it means that f(x=1, y=2) will now be treated as a
# distinct call from f(y=2, x=1) which will be cached separately.
key = args
if kwds:
key += kwd_mark
for item in kwds.items():
key += item
if typed:
key += tuple(type(v) for v in args)
if kwds:
key += tuple(type(v) for v in kwds.values())
elif len(key) == 1 and type(key[0]) in fasttypes:
return key[0]
return _HashedSeq(key)
def lru_cache(maxsize=128, typed=False):
"""Least-recently-used cache decorator.
If *maxsize* is set to None, the LRU features are disabled and the cache
can grow without bound.
If *typed* is True, arguments of different types will be cached separately.
For example, f(3.0) and f(3) will be treated as distinct calls with
distinct results.
Arguments to the cached function must be hashable.
View the cache statistics named tuple (hits, misses, maxsize, currsize)
with f.cache_info(). Clear the cache and statistics with f.cache_clear().
Access the underlying function with f.__wrapped__.
See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
"""
# Users should only access the lru_cache through its public API:
# cache_info, cache_clear, and f.__wrapped__
# The internals of the lru_cache are encapsulated for thread safety and
# to allow the implementation to change (including a possible C version).
# Early detection of an erroneous call to @lru_cache without any arguments
# resulting in the inner function being passed to maxsize instead of an
# integer or None.
if maxsize is not None and not isinstance(maxsize, int):
raise TypeError('Expected maxsize to be an integer or None')
def decorating_function(user_function):
wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)
return update_wrapper(wrapper, user_function)
return decorating_function
def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):
# Constants shared by all lru cache instances:
sentinel = object() # unique object used to signal cache misses
make_key = _make_key # build a key from the function arguments
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
cache = {}
hits = misses = 0
full = False
cache_get = cache.get # bound method to lookup a key or return None
cache_len = cache.__len__ # get cache size without calling len()
lock = RLock() # because linkedlist updates aren't threadsafe
root = [] # root of the circular doubly linked list
root[:] = [root, root, None, None] # initialize by pointing to self
if maxsize == 0:
def wrapper(*args, **kwds):
# No caching -- just a statistics update after a successful call
nonlocal misses
result = user_function(*args, **kwds)
misses += 1
return result
elif maxsize is None:
def wrapper(*args, **kwds):
# Simple caching without ordering or size limit
nonlocal hits, misses
key = make_key(args, kwds, typed)
result = cache_get(key, sentinel)
if result is not sentinel:
hits += 1
return result
result = user_function(*args, **kwds)
cache[key] = result
misses += 1
return result
else:
def wrapper(*args, **kwds):
# Size limited caching that tracks accesses by recency
nonlocal root, hits, misses, full
key = make_key(args, kwds, typed)
with lock:
link = cache_get(key)
if link is not None:
# Move the link to the front of the circular queue
link_prev, link_next, _key, result = link
link_prev[NEXT] = link_next
link_next[PREV] = link_prev
last = root[PREV]
last[NEXT] = root[PREV] = link
link[PREV] = last
link[NEXT] = root
hits += 1
return result
result = user_function(*args, **kwds)
with lock:
if key in cache:
# Getting here means that this same key was added to the
# cache while the lock was released. Since the link
# update is already done, we need only return the
# computed result and update the count of misses.
pass
elif full:
# Use the old root to store the new key and result.
oldroot = root
oldroot[KEY] = key
oldroot[RESULT] = result
# Empty the oldest link and make it the new root.
# Keep a reference to the old key and old result to
# prevent their ref counts from going to zero during the
# update. That will prevent potentially arbitrary object
# clean-up code (i.e. __del__) from running while we're
# still adjusting the links.
root = oldroot[NEXT]
oldkey = root[KEY]
oldresult = root[RESULT]
root[KEY] = root[RESULT] = None
# Now update the cache dictionary.
del cache[oldkey]
# Save the potentially reentrant cache[key] assignment
# for last, after the root and links have been put in
# a consistent state.
cache[key] = oldroot
else:
# Put result in a new link at the front of the queue.
last = root[PREV]
link = [last, root, key, result]
last[NEXT] = root[PREV] = cache[key] = link
# Use the cache_len bound method instead of the len() function
# which could potentially be wrapped in an lru_cache itself.
full = (cache_len() >= maxsize)
misses += 1
return result
def cache_info():
"""Report cache statistics"""
with lock:
return _CacheInfo(hits, misses, maxsize, cache_len())
def cache_clear():
"""Clear the cache and cache statistics"""
nonlocal hits, misses, full
with lock:
cache.clear()
root[:] = [root, root, None, None]
hits = misses = 0
full = False
wrapper.cache_info = cache_info
wrapper.cache_clear = cache_clear
return wrapper
try:
from _functools import _lru_cache_wrapper
except ImportError:
pass
################################################################################
### singledispatch() - single-dispatch generic function decorator
################################################################################
def _c3_merge(sequences):
"""Merges MROs in *sequences* to a single MRO using the C3 algorithm.
Adapted from http://www.python.org/download/releases/2.3/mro/.
"""
result = []
while True:
sequences = [s for s in sequences if s] # purge empty sequences
if not sequences:
return result
for s1 in sequences: # find merge candidates among seq heads
candidate = s1[0]
for s2 in sequences:
if candidate in s2[1:]:
candidate = None
break # reject the current head, it appears later
else:
break
if candidate is None:
raise RuntimeError("Inconsistent hierarchy")
result.append(candidate)
# remove the chosen candidate
for seq in sequences:
if seq[0] == candidate:
del seq[0]
def _c3_mro(cls, abcs=None):
"""Computes the method resolution order using extended C3 linearization.
If no *abcs* are given, the algorithm works exactly like the built-in C3
linearization used for method resolution.
If given, *abcs* is a list of abstract base classes that should be inserted
into the resulting MRO. Unrelated ABCs are ignored and don't end up in the
result. The algorithm inserts ABCs where their functionality is introduced,
i.e. issubclass(cls, abc) returns True for the class itself but returns
False for all its direct base classes. Implicit ABCs for a given class
(either registered or inferred from the presence of a special method like
__len__) are inserted directly after the last ABC explicitly listed in the
MRO of said class. If two implicit ABCs end up next to each other in the
resulting MRO, their ordering depends on the order of types in *abcs*.
"""
for i, base in enumerate(reversed(cls.__bases__)):
if hasattr(base, '__abstractmethods__'):
boundary = len(cls.__bases__) - i
break # Bases up to the last explicit ABC are considered first.
else:
boundary = 0
abcs = list(abcs) if abcs else []
explicit_bases = list(cls.__bases__[:boundary])
abstract_bases = []
other_bases = list(cls.__bases__[boundary:])
for base in abcs:
if issubclass(cls, base) and not any(
issubclass(b, base) for b in cls.__bases__
):
# If *cls* is the class that introduces behaviour described by
# an ABC *base*, insert said ABC to its MRO.
abstract_bases.append(base)
for base in abstract_bases:
abcs.remove(base)
explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases]
abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases]
other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases]
return _c3_merge(
[[cls]] +
explicit_c3_mros + abstract_c3_mros + other_c3_mros +
[explicit_bases] + [abstract_bases] + [other_bases]
)
def _compose_mro(cls, types):
"""Calculates the method resolution order for a given class *cls*.
Includes relevant abstract base classes (with their respective bases) from
the *types* iterable. Uses a modified C3 linearization algorithm.
"""
bases = set(cls.__mro__)
# Remove entries which are already present in the __mro__ or unrelated.
def is_related(typ):
return (typ not in bases and hasattr(typ, '__mro__')
and issubclass(cls, typ))
types = [n for n in types if is_related(n)]
# Remove entries which are strict bases of other entries (they will end up
# in the MRO anyway.
def is_strict_base(typ):
for other in types:
if typ != other and typ in other.__mro__:
return True
return False
types = [n for n in types if not is_strict_base(n)]
# Subclasses of the ABCs in *types* which are also implemented by
# *cls* can be used to stabilize ABC ordering.
type_set = set(types)
mro = []
for typ in types:
found = []
for sub in typ.__subclasses__():
if sub not in bases and issubclass(cls, sub):
found.append([s for s in sub.__mro__ if s in type_set])
if not found:
mro.append(typ)
continue
# Favor subclasses with the biggest number of useful bases
found.sort(key=len, reverse=True)
for sub in found:
for subcls in sub:
if subcls not in mro:
mro.append(subcls)
return _c3_mro(cls, abcs=mro)
def _find_impl(cls, registry):
"""Returns the best matching implementation from *registry* for type *cls*.
Where there is no registered implementation for a specific type, its method
resolution order is used to find a more generic implementation.
Note: if *registry* does not contain an implementation for the base
*object* type, this function may return None.
"""
mro = _compose_mro(cls, registry.keys())
match = None
for t in mro:
if match is not None:
# If *match* is an implicit ABC but there is another unrelated,
# equally matching implicit ABC, refuse the temptation to guess.
if (t in registry and t not in cls.__mro__
and match not in cls.__mro__
and not issubclass(match, t)):
raise RuntimeError("Ambiguous dispatch: {} or {}".format(
match, t))
break
if t in registry:
match = t
return registry.get(match)
def singledispatch(func):
"""Single-dispatch generic function decorator.
Transforms a function into a generic function, which can have different
behaviours depending upon the type of its first argument. The decorated
function acts as the default implementation, and additional
implementations can be registered using the register() attribute of the
generic function.
"""
# There are many programs that use functools without singledispatch, so we
# trade-off making singledispatch marginally slower for the benefit of
# making start-up of such applications slightly faster.
import types, weakref
registry = {}
dispatch_cache = weakref.WeakKeyDictionary()
cache_token = None
def dispatch(cls):
"""generic_func.dispatch(cls) -> <function implementation>
Runs the dispatch algorithm to return the best available implementation
for the given *cls* registered on *generic_func*.
"""
nonlocal cache_token
if cache_token is not None:
current_token = get_cache_token()
if cache_token != current_token:
dispatch_cache.clear()
cache_token = current_token
try:
impl = dispatch_cache[cls]
except KeyError:
try:
impl = registry[cls]
except KeyError:
impl = _find_impl(cls, registry)
dispatch_cache[cls] = impl
return impl
def register(cls, func=None):
"""generic_func.register(cls, func) -> func
Registers a new implementation for the given *cls* on a *generic_func*.
"""
nonlocal cache_token
if func is None:
if isinstance(cls, type):
return lambda f: register(cls, f)
ann = getattr(cls, '__annotations__', {})
if not ann:
raise TypeError(
f"Invalid first argument to `register()`: {cls!r}. "
f"Use either `@register(some_class)` or plain `@register` "
f"on an annotated function."
)
func = cls
# only import typing if annotation parsing is necessary
from typing import get_type_hints
argname, cls = next(iter(get_type_hints(func).items()))
assert isinstance(cls, type), (
f"Invalid annotation for {argname!r}. {cls!r} is not a class."
)
registry[cls] = func
if cache_token is None and hasattr(cls, '__abstractmethods__'):
cache_token = get_cache_token()
dispatch_cache.clear()
return func
def wrapper(*args, **kw):
return dispatch(args[0].__class__)(*args, **kw)
registry[object] = func
wrapper.register = register
wrapper.dispatch = dispatch
wrapper.registry = types.MappingProxyType(registry)
wrapper._clear_cache = dispatch_cache.clear
update_wrapper(wrapper, func)
return wrapper

151
Lib/genericpath.py Normal file
View File

@@ -0,0 +1,151 @@
"""
Path operations common to more than one OS
Do not use directly. The OS specific modules import the appropriate
functions from this module themselves.
"""
import os
import stat
__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime',
'getsize', 'isdir', 'isfile', 'samefile', 'sameopenfile',
'samestat']
# Does a path exist?
# This is false for dangling symbolic links on systems that support them.
def exists(path):
"""Test whether a path exists. Returns False for broken symbolic links"""
try:
os.stat(path)
except (OSError, ValueError):
return False
return True
# This follows symbolic links, so both islink() and isdir() can be true
# for the same path on systems that support symlinks
def isfile(path):
"""Test whether a path is a regular file"""
try:
st = os.stat(path)
except (OSError, ValueError):
return False
return stat.S_ISREG(st.st_mode)
# Is a path a directory?
# This follows symbolic links, so both islink() and isdir()
# can be true for the same path on systems that support symlinks
def isdir(s):
"""Return true if the pathname refers to an existing directory."""
try:
st = os.stat(s)
except (OSError, ValueError):
return False
return stat.S_ISDIR(st.st_mode)
def getsize(filename):
"""Return the size of a file, reported by os.stat()."""
return os.stat(filename).st_size
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()."""
return os.stat(filename).st_mtime
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()."""
return os.stat(filename).st_atime
def getctime(filename):
"""Return the metadata change time of a file, reported by os.stat()."""
return os.stat(filename).st_ctime
# Return the longest prefix of all list elements.
def commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
# Some people pass in a list of pathname parts to operate in an OS-agnostic
# fashion; don't try to translate in that case as that's an abuse of the
# API and they are already doing what they need to be OS-agnostic and so
# they most likely won't be using an os.PathLike object in the sublists.
if not isinstance(m[0], (list, tuple)):
m = tuple(map(os.fspath, m))
s1 = min(m)
s2 = max(m)
for i, c in enumerate(s1):
if c != s2[i]:
return s1[:i]
return s1
# Are two stat buffers (obtained from stat, fstat or lstat)
# describing the same file?
def samestat(s1, s2):
"""Test whether two stat buffers reference the same file"""
return (s1.st_ino == s2.st_ino and
s1.st_dev == s2.st_dev)
# Are two filenames really pointing to the same file?
def samefile(f1, f2):
"""Test whether two pathnames reference the same actual file"""
s1 = os.stat(f1)
s2 = os.stat(f2)
return samestat(s1, s2)
# Are two open files really referencing the same file?
# (Not necessarily the same file descriptor!)
def sameopenfile(fp1, fp2):
"""Test whether two open file objects reference the same file"""
s1 = os.fstat(fp1)
s2 = os.fstat(fp2)
return samestat(s1, s2)
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
# Generic implementation of splitext, to be parametrized with
# the separators
def _splitext(p, sep, altsep, extsep):
"""Split the extension from a pathname.
Extension is everything from the last dot to the end, ignoring
leading dots. Returns "(root, ext)"; ext may be empty."""
# NOTE: This code must work for text and bytes strings.
sepIndex = p.rfind(sep)
if altsep:
altsepIndex = p.rfind(altsep)
sepIndex = max(sepIndex, altsepIndex)
dotIndex = p.rfind(extsep)
if dotIndex > sepIndex:
# skip all leading dots
filenameIndex = sepIndex + 1
while filenameIndex < dotIndex:
if p[filenameIndex:filenameIndex+1] != extsep:
return p[:dotIndex], p[dotIndex:]
filenameIndex += 1
return p, p[:0]
def _check_arg_types(funcname, *args):
hasstr = hasbytes = False
for s in args:
if isinstance(s, str):
hasstr = True
elif isinstance(s, bytes):
hasbytes = True
else:
raise TypeError('%s() argument must be str or bytes, not %r' %
(funcname, s.__class__.__name__)) from None
if hasstr and hasbytes:
raise TypeError("Can't mix strings and bytes in path components") from None

601
Lib/heapq.py Normal file
View File

@@ -0,0 +1,601 @@
"""Heap queue algorithm (a.k.a. priority queue).
Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for
all k, counting elements from 0. For the sake of comparison,
non-existing elements are considered to be infinite. The interesting
property of a heap is that a[0] is always its smallest element.
Usage:
heap = [] # creates an empty heap
heappush(heap, item) # pushes a new item on the heap
item = heappop(heap) # pops the smallest item from the heap
item = heap[0] # smallest item on the heap without popping it
heapify(x) # transforms list into a heap, in-place, in linear time
item = heapreplace(heap, item) # pops and returns smallest item, and adds
# new item; the heap size is unchanged
Our API differs from textbook heap algorithms as follows:
- We use 0-based indexing. This makes the relationship between the
index for a node and the indexes for its children slightly less
obvious, but is more suitable since Python uses 0-based indexing.
- Our heappop() method returns the smallest item, not the largest.
These two make it possible to view the heap as a regular Python list
without surprises: heap[0] is the smallest item, and heap.sort()
maintains the heap invariant!
"""
# Original code by Kevin O'Connor, augmented by Tim Peters and Raymond Hettinger
__about__ = """Heap queues
[explanation by François Pinard]
Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for
all k, counting elements from 0. For the sake of comparison,
non-existing elements are considered to be infinite. The interesting
property of a heap is that a[0] is always its smallest element.
The strange invariant above is meant to be an efficient memory
representation for a tournament. The numbers below are `k', not a[k]:
0
1 2
3 4 5 6
7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In
a usual binary tournament we see in sports, each cell is the winner
over the two cells it tops, and we can trace the winner down the tree
to see all opponents s/he had. However, in many computer applications
of such tournaments, we do not need to trace the history of a winner.
To be more memory efficient, when a winner is promoted, we try to
replace it by something else at a lower level, and the rule becomes
that a cell and the two cells it tops contain three different items,
but the top cell "wins" over the two topped cells.
If this heap invariant is protected at all time, index 0 is clearly
the overall winner. The simplest algorithmic way to remove it and
find the "next" winner is to move some loser (let's say cell 30 in the
diagram above) into the 0 position, and then percolate this new 0 down
the tree, exchanging values, until the invariant is re-established.
This is clearly logarithmic on the total number of items in the tree.
By iterating over all items, you get an O(n ln n) sort.
A nice feature of this sort is that you can efficiently insert new
items while the sort is going on, provided that the inserted items are
not "better" than the last 0'th element you extracted. This is
especially useful in simulation contexts, where the tree holds all
incoming events, and the "win" condition means the smallest scheduled
time. When an event schedule other events for execution, they are
scheduled into the future, so they can easily go into the heap. So, a
heap is a good structure for implementing schedulers (this is what I
used for my MIDI sequencer :-).
Various structures for implementing schedulers have been extensively
studied, and heaps are good for this, as they are reasonably speedy,
the speed is almost constant, and the worst case is not much different
than the average case. However, there are other representations which
are more efficient overall, yet the worst cases might be terrible.
Heaps are also very useful in big disk sorts. You most probably all
know that a big sort implies producing "runs" (which are pre-sorted
sequences, which size is usually related to the amount of CPU memory),
followed by a merging passes for these runs, which merging is often
very cleverly organised[1]. It is very important that the initial
sort produces the longest runs possible. Tournaments are a good way
to that. If, using all the memory available to hold a tournament, you
replace and percolate items that happen to fit the current run, you'll
produce runs which are twice the size of the memory for random input,
and much better for input fuzzily ordered.
Moreover, if you output the 0'th item on disk and get an input which
may not fit in the current tournament (because the value "wins" over
the last output value), it cannot fit in the heap, so the size of the
heap decreases. The freed memory could be cleverly reused immediately
for progressively building a second heap, which grows at exactly the
same rate the first heap is melting. When the first heap completely
vanishes, you switch heaps and start a new run. Clever and quite
effective!
In a word, heaps are useful memory structures to know. I use them in
a few applications, and I think it is good to keep a `heap' module
around. :-)
--------------------
[1] The disk balancing algorithms which are current, nowadays, are
more annoying than clever, and this is a consequence of the seeking
capabilities of the disks. On devices which cannot seek, like big
tape drives, the story was quite different, and one had to be very
clever to ensure (far in advance) that each tape movement will be the
most effective possible (that is, will best participate at
"progressing" the merge). Some tapes were even able to read
backwards, and this was also used to avoid the rewinding time.
Believe me, real good tape sorts were quite spectacular to watch!
From all times, sorting has always been a Great Art! :-)
"""
__all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'merge',
'nlargest', 'nsmallest', 'heappushpop']
def heappush(heap, item):
"""Push item onto heap, maintaining the heap invariant."""
heap.append(item)
_siftdown(heap, 0, len(heap)-1)
def heappop(heap):
"""Pop the smallest item off the heap, maintaining the heap invariant."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
_siftup(heap, 0)
return returnitem
return lastelt
def heapreplace(heap, item):
"""Pop and return the current smallest value, and add the new item.
This is more efficient than heappop() followed by heappush(), and can be
more appropriate when using a fixed-size heap. Note that the value
returned may be larger than item! That constrains reasonable uses of
this routine unless written as part of a conditional replacement:
if item > heap[0]:
item = heapreplace(heap, item)
"""
returnitem = heap[0] # raises appropriate IndexError if heap is empty
heap[0] = item
_siftup(heap, 0)
return returnitem
def heappushpop(heap, item):
"""Fast version of a heappush followed by a heappop."""
if heap and heap[0] < item:
item, heap[0] = heap[0], item
_siftup(heap, 0)
return item
def heapify(x):
"""Transform list into a heap, in-place, in O(len(x)) time."""
n = len(x)
# Transform bottom-up. The largest index there's any point to looking at
# is the largest with a child index in-range, so must have 2*i + 1 < n,
# or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so
# j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is
# (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.
for i in reversed(range(n//2)):
_siftup(x, i)
def _heappop_max(heap):
"""Maxheap version of a heappop."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
_siftup_max(heap, 0)
return returnitem
return lastelt
def _heapreplace_max(heap, item):
"""Maxheap version of a heappop followed by a heappush."""
returnitem = heap[0] # raises appropriate IndexError if heap is empty
heap[0] = item
_siftup_max(heap, 0)
return returnitem
def _heapify_max(x):
"""Transform list into a maxheap, in-place, in O(len(x)) time."""
n = len(x)
for i in reversed(range(n//2)):
_siftup_max(x, i)
# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos
# is the index of a leaf with a possibly out-of-order value. Restore the
# heap invariant.
def _siftdown(heap, startpos, pos):
newitem = heap[pos]
# Follow the path to the root, moving parents down until finding a place
# newitem fits.
while pos > startpos:
parentpos = (pos - 1) >> 1
parent = heap[parentpos]
if newitem < parent:
heap[pos] = parent
pos = parentpos
continue
break
heap[pos] = newitem
# The child indices of heap index pos are already heaps, and we want to make
# a heap at index pos too. We do this by bubbling the smaller child of
# pos up (and so on with that child's children, etc) until hitting a leaf,
# then using _siftdown to move the oddball originally at index pos into place.
#
# We *could* break out of the loop as soon as we find a pos where newitem <=
# both its children, but turns out that's not a good idea, and despite that
# many books write the algorithm that way. During a heap pop, the last array
# element is sifted in, and that tends to be large, so that comparing it
# against values starting from the root usually doesn't pay (= usually doesn't
# get us out of the loop early). See Knuth, Volume 3, where this is
# explained and quantified in an exercise.
#
# Cutting the # of comparisons is important, since these routines have no
# way to extract "the priority" from an array element, so that intelligence
# is likely to be hiding in custom comparison methods, or in array elements
# storing (priority, record) tuples. Comparisons are thus potentially
# expensive.
#
# On random arrays of length 1000, making this change cut the number of
# comparisons made by heapify() a little, and those made by exhaustive
# heappop() a lot, in accord with theory. Here are typical results from 3
# runs (3 just to demonstrate how small the variance is):
#
# Compares needed by heapify Compares needed by 1000 heappops
# -------------------------- --------------------------------
# 1837 cut to 1663 14996 cut to 8680
# 1855 cut to 1659 14966 cut to 8678
# 1847 cut to 1660 15024 cut to 8703
#
# Building the heap by using heappush() 1000 times instead required
# 2198, 2148, and 2219 compares: heapify() is more efficient, when
# you can use it.
#
# The total compares needed by list.sort() on the same lists were 8627,
# 8627, and 8632 (this should be compared to the sum of heapify() and
# heappop() compares): list.sort() is (unsurprisingly!) more efficient
# for sorting.
def _siftup(heap, pos):
endpos = len(heap)
startpos = pos
newitem = heap[pos]
# Bubble up the smaller child until hitting a leaf.
childpos = 2*pos + 1 # leftmost child position
while childpos < endpos:
# Set childpos to index of smaller child.
rightpos = childpos + 1
if rightpos < endpos and not heap[childpos] < heap[rightpos]:
childpos = rightpos
# Move the smaller child up.
heap[pos] = heap[childpos]
pos = childpos
childpos = 2*pos + 1
# The leaf at pos is empty now. Put newitem there, and bubble it up
# to its final resting place (by sifting its parents down).
heap[pos] = newitem
_siftdown(heap, startpos, pos)
def _siftdown_max(heap, startpos, pos):
'Maxheap variant of _siftdown'
newitem = heap[pos]
# Follow the path to the root, moving parents down until finding a place
# newitem fits.
while pos > startpos:
parentpos = (pos - 1) >> 1
parent = heap[parentpos]
if parent < newitem:
heap[pos] = parent
pos = parentpos
continue
break
heap[pos] = newitem
def _siftup_max(heap, pos):
'Maxheap variant of _siftup'
endpos = len(heap)
startpos = pos
newitem = heap[pos]
# Bubble up the larger child until hitting a leaf.
childpos = 2*pos + 1 # leftmost child position
while childpos < endpos:
# Set childpos to index of larger child.
rightpos = childpos + 1
if rightpos < endpos and not heap[rightpos] < heap[childpos]:
childpos = rightpos
# Move the larger child up.
heap[pos] = heap[childpos]
pos = childpos
childpos = 2*pos + 1
# The leaf at pos is empty now. Put newitem there, and bubble it up
# to its final resting place (by sifting its parents down).
heap[pos] = newitem
_siftdown_max(heap, startpos, pos)
def merge(*iterables, key=None, reverse=False):
'''Merge multiple sorted inputs into a single sorted output.
Similar to sorted(itertools.chain(*iterables)) but returns a generator,
does not pull the data into memory all at once, and assumes that each of
the input streams is already sorted (smallest to largest).
>>> list(merge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25]))
[0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
If *key* is not None, applies a key function to each element to determine
its sort order.
>>> list(merge(['dog', 'horse'], ['cat', 'fish', 'kangaroo'], key=len))
['dog', 'cat', 'fish', 'horse', 'kangaroo']
'''
h = []
h_append = h.append
if reverse:
_heapify = _heapify_max
_heappop = _heappop_max
_heapreplace = _heapreplace_max
direction = -1
else:
_heapify = heapify
_heappop = heappop
_heapreplace = heapreplace
direction = 1
if key is None:
for order, it in enumerate(map(iter, iterables)):
try:
next = it.__next__
h_append([next(), order * direction, next])
except StopIteration:
pass
_heapify(h)
while len(h) > 1:
try:
while True:
value, order, next = s = h[0]
yield value
s[0] = next() # raises StopIteration when exhausted
_heapreplace(h, s) # restore heap condition
except StopIteration:
_heappop(h) # remove empty iterator
if h:
# fast case when only a single iterator remains
value, order, next = h[0]
yield value
yield from next.__self__
return
for order, it in enumerate(map(iter, iterables)):
try:
next = it.__next__
value = next()
h_append([key(value), order * direction, value, next])
except StopIteration:
pass
_heapify(h)
while len(h) > 1:
try:
while True:
key_value, order, value, next = s = h[0]
yield value
value = next()
s[0] = key(value)
s[2] = value
_heapreplace(h, s)
except StopIteration:
_heappop(h)
if h:
key_value, order, value, next = h[0]
yield value
yield from next.__self__
# Algorithm notes for nlargest() and nsmallest()
# ==============================================
#
# Make a single pass over the data while keeping the k most extreme values
# in a heap. Memory consumption is limited to keeping k values in a list.
#
# Measured performance for random inputs:
#
# number of comparisons
# n inputs k-extreme values (average of 5 trials) % more than min()
# ------------- ---------------- --------------------- -----------------
# 1,000 100 3,317 231.7%
# 10,000 100 14,046 40.5%
# 100,000 100 105,749 5.7%
# 1,000,000 100 1,007,751 0.8%
# 10,000,000 100 10,009,401 0.1%
#
# Theoretical number of comparisons for k smallest of n random inputs:
#
# Step Comparisons Action
# ---- -------------------------- ---------------------------
# 1 1.66 * k heapify the first k-inputs
# 2 n - k compare remaining elements to top of heap
# 3 k * (1 + lg2(k)) * ln(n/k) replace the topmost value on the heap
# 4 k * lg2(k) - (k/2) final sort of the k most extreme values
#
# Combining and simplifying for a rough estimate gives:
#
# comparisons = n + k * (log(k, 2) * log(n/k) + log(k, 2) + log(n/k))
#
# Computing the number of comparisons for step 3:
# -----------------------------------------------
# * For the i-th new value from the iterable, the probability of being in the
# k most extreme values is k/i. For example, the probability of the 101st
# value seen being in the 100 most extreme values is 100/101.
# * If the value is a new extreme value, the cost of inserting it into the
# heap is 1 + log(k, 2).
# * The probability times the cost gives:
# (k/i) * (1 + log(k, 2))
# * Summing across the remaining n-k elements gives:
# sum((k/i) * (1 + log(k, 2)) for i in range(k+1, n+1))
# * This reduces to:
# (H(n) - H(k)) * k * (1 + log(k, 2))
# * Where H(n) is the n-th harmonic number estimated by:
# gamma = 0.5772156649
# H(n) = log(n, e) + gamma + 1 / (2 * n)
# http://en.wikipedia.org/wiki/Harmonic_series_(mathematics)#Rate_of_divergence
# * Substituting the H(n) formula:
# comparisons = k * (1 + log(k, 2)) * (log(n/k, e) + (1/n - 1/k) / 2)
#
# Worst-case for step 3:
# ----------------------
# In the worst case, the input data is reversed sorted so that every new element
# must be inserted in the heap:
#
# comparisons = 1.66 * k + log(k, 2) * (n - k)
#
# Alternative Algorithms
# ----------------------
# Other algorithms were not used because they:
# 1) Took much more auxiliary memory,
# 2) Made multiple passes over the data.
# 3) Made more comparisons in common cases (small k, large n, semi-random input).
# See the more detailed comparison of approach at:
# http://code.activestate.com/recipes/577573-compare-algorithms-for-heapqsmallest
def nsmallest(n, iterable, key=None):
"""Find the n smallest elements in a dataset.
Equivalent to: sorted(iterable, key=key)[:n]
"""
# Short-cut for n==1 is to use min()
if n == 1:
it = iter(iterable)
sentinel = object()
result = min(it, default=sentinel, key=key)
return [] if result is sentinel else [result]
# When n>=size, it's faster to use sorted()
try:
size = len(iterable)
except (TypeError, AttributeError):
pass
else:
if n >= size:
return sorted(iterable, key=key)[:n]
# When key is none, use simpler decoration
if key is None:
it = iter(iterable)
# put the range(n) first so that zip() doesn't
# consume one too many elements from the iterator
result = [(elem, i) for i, elem in zip(range(n), it)]
if not result:
return result
_heapify_max(result)
top = result[0][0]
order = n
_heapreplace = _heapreplace_max
for elem in it:
if elem < top:
_heapreplace(result, (elem, order))
top, _order = result[0]
order += 1
result.sort()
return [elem for (elem, order) in result]
# General case, slowest method
it = iter(iterable)
result = [(key(elem), i, elem) for i, elem in zip(range(n), it)]
if not result:
return result
_heapify_max(result)
top = result[0][0]
order = n
_heapreplace = _heapreplace_max
for elem in it:
k = key(elem)
if k < top:
_heapreplace(result, (k, order, elem))
top, _order, _elem = result[0]
order += 1
result.sort()
return [elem for (k, order, elem) in result]
def nlargest(n, iterable, key=None):
"""Find the n largest elements in a dataset.
Equivalent to: sorted(iterable, key=key, reverse=True)[:n]
"""
# Short-cut for n==1 is to use max()
if n == 1:
it = iter(iterable)
sentinel = object()
result = max(it, default=sentinel, key=key)
return [] if result is sentinel else [result]
# When n>=size, it's faster to use sorted()
try:
size = len(iterable)
except (TypeError, AttributeError):
pass
else:
if n >= size:
return sorted(iterable, key=key, reverse=True)[:n]
# When key is none, use simpler decoration
if key is None:
it = iter(iterable)
result = [(elem, i) for i, elem in zip(range(0, -n, -1), it)]
if not result:
return result
heapify(result)
top = result[0][0]
order = -n
_heapreplace = heapreplace
for elem in it:
if top < elem:
_heapreplace(result, (elem, order))
top, _order = result[0]
order -= 1
result.sort(reverse=True)
return [elem for (elem, order) in result]
# General case, slowest method
it = iter(iterable)
result = [(key(elem), i, elem) for i, elem in zip(range(0, -n, -1), it)]
if not result:
return result
heapify(result)
top = result[0][0]
order = -n
_heapreplace = heapreplace
for elem in it:
k = key(elem)
if top < k:
_heapreplace(result, (k, order, elem))
top, _order, _elem = result[0]
order -= 1
result.sort(reverse=True)
return [elem for (k, order, elem) in result]
# If available, use C implementation
try:
from _heapq import *
except ImportError:
pass
try:
from _heapq import _heapreplace_max
except ImportError:
pass
try:
from _heapq import _heapify_max
except ImportError:
pass
try:
from _heapq import _heappop_max
except ImportError:
pass
if __name__ == "__main__":
import doctest
print(doctest.testmod())

1173
Lib/importlib/_bootstrap.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
Lib/io.py Normal file
View File

@@ -0,0 +1 @@
from _io import *

177
Lib/linecache.py Normal file
View File

@@ -0,0 +1,177 @@
"""Cache lines from Python source files.
This is intended to read lines from modules imported -- hence if a filename
is not found, it will look down the module search path for a file by
that name.
"""
import functools
import sys
import os
import tokenize
__all__ = ["getline", "clearcache", "checkcache"]
def getline(filename, lineno, module_globals=None):
lines = getlines(filename, module_globals)
if 1 <= lineno <= len(lines):
return lines[lineno-1]
else:
return ''
# The cache
# The cache. Maps filenames to either a thunk which will provide source code,
# or a tuple (size, mtime, lines, fullname) once loaded.
cache = {}
def clearcache():
"""Clear the cache entirely."""
global cache
cache = {}
def getlines(filename, module_globals=None):
"""Get the lines for a Python source file from the cache.
Update the cache if it doesn't contain an entry for this file already."""
if filename in cache:
entry = cache[filename]
if len(entry) != 1:
return cache[filename][2]
try:
return updatecache(filename, module_globals)
except MemoryError:
clearcache()
return []
def checkcache(filename=None):
"""Discard cache entries that are out of date.
(This is not checked upon each call!)"""
if filename is None:
filenames = list(cache.keys())
else:
if filename in cache:
filenames = [filename]
else:
return
for filename in filenames:
entry = cache[filename]
if len(entry) == 1:
# lazy cache entry, leave it lazy.
continue
size, mtime, lines, fullname = entry
if mtime is None:
continue # no-op for files loaded via a __loader__
try:
stat = os.stat(fullname)
except OSError:
del cache[filename]
continue
if size != stat.st_size or mtime != stat.st_mtime:
del cache[filename]
def updatecache(filename, module_globals=None):
"""Update a cache entry and return its list of lines.
If something's wrong, print a message, discard the cache entry,
and return an empty list."""
if filename in cache:
if len(cache[filename]) != 1:
del cache[filename]
if not filename or (filename.startswith('<') and filename.endswith('>')):
return []
fullname = filename
try:
stat = os.stat(fullname)
except OSError:
basename = filename
# Realise a lazy loader based lookup if there is one
# otherwise try to lookup right now.
if lazycache(filename, module_globals):
try:
data = cache[filename][0]()
except (ImportError, OSError):
pass
else:
if data is None:
# No luck, the PEP302 loader cannot find the source
# for this module.
return []
cache[filename] = (
len(data), None,
[line+'\n' for line in data.splitlines()], fullname
)
return cache[filename][2]
# Try looking through the module search path, which is only useful
# when handling a relative filename.
if os.path.isabs(filename):
return []
for dirname in sys.path:
try:
fullname = os.path.join(dirname, basename)
except (TypeError, AttributeError):
# Not sufficiently string-like to do anything useful with.
continue
try:
stat = os.stat(fullname)
break
except OSError:
pass
else:
return []
try:
with tokenize.open(fullname) as fp:
lines = fp.readlines()
except OSError:
return []
if lines and not lines[-1].endswith('\n'):
lines[-1] += '\n'
size, mtime = stat.st_size, stat.st_mtime
cache[filename] = size, mtime, lines, fullname
return lines
def lazycache(filename, module_globals):
"""Seed the cache for filename with module_globals.
The module loader will be asked for the source only when getlines is
called, not immediately.
If there is an entry in the cache already, it is not altered.
:return: True if a lazy load is registered in the cache,
otherwise False. To register such a load a module loader with a
get_source method must be found, the filename must be a cachable
filename, and the filename must not be already cached.
"""
if filename in cache:
if len(cache[filename]) == 1:
return True
else:
return False
if not filename or (filename.startswith('<') and filename.endswith('>')):
return False
# Try for a __loader__, if available
if module_globals and '__loader__' in module_globals:
name = module_globals.get('__name__')
loader = module_globals['__loader__']
get_source = getattr(loader, 'get_source', None)
if name and get_source:
get_lines = functools.partial(get_source, name)
cache[filename] = (get_lines,)
return True
return False

661
Lib/ntpath.py Normal file
View File

@@ -0,0 +1,661 @@
# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
"""Common pathname manipulations, WindowsNT/95 version.
Instead of importing this module directly, import os and refer to this
module as os.path.
"""
# strings representing various path-related bits and pieces
# These are primarily for export; internally, they are hardcoded.
# Should be set before imports for resolving cyclic dependency.
curdir = '.'
pardir = '..'
extsep = '.'
sep = '\\'
pathsep = ';'
altsep = '/'
defpath = '.;C:\\bin'
devnull = 'nul'
import os
import sys
import stat
import genericpath
from genericpath import *
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
"getatime","getctime", "islink","exists","lexists","isdir","isfile",
"ismount", "expanduser","expandvars","normpath","abspath",
"curdir","pardir","sep","pathsep","defpath","altsep",
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
"samefile", "sameopenfile", "samestat", "commonpath"]
def _get_bothseps(path):
if isinstance(path, bytes):
return b'\\/'
else:
return '\\/'
# Normalize the case of a pathname and map slashes to backslashes.
# Other normalizations (such as optimizing '../' away) are not done
# (this is done by normpath).
def normcase(s):
"""Normalize case of pathname.
Makes all characters lowercase and all slashes into backslashes."""
s = os.fspath(s)
if isinstance(s, bytes):
return s.replace(b'/', b'\\').lower()
else:
return s.replace('/', '\\').lower()
# Return whether a path is absolute.
# Trivial in Posix, harder on Windows.
# For Windows it is absolute if it starts with a slash or backslash (current
# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
# starts with a slash or backslash.
def isabs(s):
"""Test whether a path is absolute"""
s = os.fspath(s)
s = splitdrive(s)[1]
return len(s) > 0 and s[0] in _get_bothseps(s)
# Join two (or more) paths.
def join(path, *paths):
path = os.fspath(path)
if isinstance(path, bytes):
sep = b'\\'
seps = b'\\/'
colon = b':'
else:
sep = '\\'
seps = '\\/'
colon = ':'
try:
if not paths:
path[:0] + sep #23780: Ensure compatible data type even if p is null.
result_drive, result_path = splitdrive(path)
for p in map(os.fspath, paths):
p_drive, p_path = splitdrive(p)
if p_path and p_path[0] in seps:
# Second path is absolute
if p_drive or not result_drive:
result_drive = p_drive
result_path = p_path
continue
elif p_drive and p_drive != result_drive:
if p_drive.lower() != result_drive.lower():
# Different drives => ignore the first path entirely
result_drive = p_drive
result_path = p_path
continue
# Same drive in different case
result_drive = p_drive
# Second path is relative to the first
if result_path and result_path[-1] not in seps:
result_path = result_path + sep
result_path = result_path + p_path
## add separator between UNC and non-absolute path
if (result_path and result_path[0] not in seps and
result_drive and result_drive[-1:] != colon):
return result_drive + sep + result_path
return result_drive + result_path
except (TypeError, AttributeError, BytesWarning):
genericpath._check_arg_types('join', path, *paths)
raise
# Split a path in a drive specification (a drive letter followed by a
# colon) and the path specification.
# It is always true that drivespec + pathspec == p
def splitdrive(p):
"""Split a pathname into drive/UNC sharepoint and relative path specifiers.
Returns a 2-tuple (drive_or_unc, path); either part may be empty.
If you assign
result = splitdrive(p)
It is always true that:
result[0] + result[1] == p
If the path contained a drive letter, drive_or_unc will contain everything
up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
If the path contained a UNC path, the drive_or_unc will contain the host name
and share up to but not including the fourth directory separator character.
e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
Paths cannot contain both a drive letter and a UNC path.
"""
p = os.fspath(p)
if len(p) >= 2:
if isinstance(p, bytes):
sep = b'\\'
altsep = b'/'
colon = b':'
else:
sep = '\\'
altsep = '/'
colon = ':'
normp = p.replace(altsep, sep)
if (normp[0:2] == sep*2) and (normp[2:3] != sep):
# is a UNC path:
# vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
# \\machine\mountpoint\directory\etc\...
# directory ^^^^^^^^^^^^^^^
index = normp.find(sep, 2)
if index == -1:
return p[:0], p
index2 = normp.find(sep, index + 1)
# a UNC path can't have two slashes in a row
# (after the initial two)
if index2 == index + 1:
return p[:0], p
if index2 == -1:
index2 = len(p)
return p[:index2], p[index2:]
if normp[1:2] == colon:
return p[:2], p[2:]
return p[:0], p
# Split a path in head (everything up to the last '/') and tail (the
# rest). After the trailing '/' is stripped, the invariant
# join(head, tail) == p holds.
# The resulting head won't end in '/' unless it is the root.
def split(p):
"""Split a pathname.
Return tuple (head, tail) where tail is everything after the final slash.
Either part may be empty."""
p = os.fspath(p)
seps = _get_bothseps(p)
d, p = splitdrive(p)
# set i to index beyond p's last slash
i = len(p)
while i and p[i-1] not in seps:
i -= 1
head, tail = p[:i], p[i:] # now tail has no slashes
# remove trailing slashes from head, unless it's all slashes
head = head.rstrip(seps) or head
return d + head, tail
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
def splitext(p):
p = os.fspath(p)
if isinstance(p, bytes):
return genericpath._splitext(p, b'\\', b'/', b'.')
else:
return genericpath._splitext(p, '\\', '/', '.')
splitext.__doc__ = genericpath._splitext.__doc__
# Return the tail (basename) part of a path.
def basename(p):
"""Returns the final component of a pathname"""
return split(p)[1]
# Return the head (dirname) part of a path.
def dirname(p):
"""Returns the directory component of a pathname"""
return split(p)[0]
# Is a path a symbolic link?
# This will always return false on systems where os.lstat doesn't exist.
def islink(path):
"""Test whether a path is a symbolic link.
This will always return false for Windows prior to 6.0.
"""
try:
st = os.lstat(path)
except (OSError, ValueError, AttributeError):
return False
return stat.S_ISLNK(st.st_mode)
# Being true for dangling symbolic links is also useful.
def lexists(path):
"""Test whether a path exists. Returns True for broken symbolic links"""
try:
st = os.lstat(path)
except (OSError, ValueError):
return False
return True
# Is a path a mount point?
# Any drive letter root (eg c:\)
# Any share UNC (eg \\server\share)
# Any volume mounted on a filesystem folder
#
# No one method detects all three situations. Historically we've lexically
# detected drive letter roots and share UNCs. The canonical approach to
# detecting mounted volumes (querying the reparse tag) fails for the most
# common case: drive letter roots. The alternative which uses GetVolumePathName
# fails if the drive letter is the result of a SUBST.
try:
from nt import _getvolumepathname
except ImportError:
_getvolumepathname = None
def ismount(path):
"""Test whether a path is a mount point (a drive root, the root of a
share, or a mounted volume)"""
path = os.fspath(path)
seps = _get_bothseps(path)
path = abspath(path)
root, rest = splitdrive(path)
if root and root[0] in seps:
return (not rest) or (rest in seps)
if rest in seps:
return True
if _getvolumepathname:
return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
else:
return False
# Expand paths beginning with '~' or '~user'.
# '~' means $HOME; '~user' means that user's home directory.
# If the path doesn't begin with '~', or if the user or $HOME is unknown,
# the path is returned unchanged (leaving error reporting to whatever
# function is called with the expanded path as argument).
# See also module 'glob' for expansion of *, ? and [...] in pathnames.
# (A function should also be defined to do full *sh-style environment
# variable expansion.)
def expanduser(path):
"""Expand ~ and ~user constructs.
If user or $HOME is unknown, do nothing."""
path = os.fspath(path)
if isinstance(path, bytes):
tilde = b'~'
else:
tilde = '~'
if not path.startswith(tilde):
return path
i, n = 1, len(path)
while i < n and path[i] not in _get_bothseps(path):
i += 1
if 'USERPROFILE' in os.environ:
userhome = os.environ['USERPROFILE']
elif not 'HOMEPATH' in os.environ:
return path
else:
try:
drive = os.environ['HOMEDRIVE']
except KeyError:
drive = ''
userhome = join(drive, os.environ['HOMEPATH'])
if isinstance(path, bytes):
userhome = os.fsencode(userhome)
if i != 1: #~user
userhome = join(dirname(userhome), path[1:i])
return userhome + path[i:]
# Expand paths containing shell variable substitutions.
# The following rules apply:
# - no expansion within single quotes
# - '$$' is translated into '$'
# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
# - ${varname} is accepted.
# - $varname is accepted.
# - %varname% is accepted.
# - varnames can be made out of letters, digits and the characters '_-'
# (though is not verified in the ${varname} and %varname% cases)
# XXX With COMMAND.COM you can use any characters in a variable name,
# XXX except '^|<>='.
def expandvars(path):
"""Expand shell variables of the forms $var, ${var} and %var%.
Unknown variables are left unchanged."""
path = os.fspath(path)
if isinstance(path, bytes):
if b'$' not in path and b'%' not in path:
return path
import string
varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
quote = b'\''
percent = b'%'
brace = b'{'
rbrace = b'}'
dollar = b'$'
environ = getattr(os, 'environb', None)
else:
if '$' not in path and '%' not in path:
return path
import string
varchars = string.ascii_letters + string.digits + '_-'
quote = '\''
percent = '%'
brace = '{'
rbrace = '}'
dollar = '$'
environ = os.environ
res = path[:0]
index = 0
pathlen = len(path)
while index < pathlen:
c = path[index:index+1]
if c == quote: # no expansion within single quotes
path = path[index + 1:]
pathlen = len(path)
try:
index = path.index(c)
res += c + path[:index + 1]
except ValueError:
res += c + path
index = pathlen - 1
elif c == percent: # variable or '%'
if path[index + 1:index + 2] == percent:
res += c
index += 1
else:
path = path[index+1:]
pathlen = len(path)
try:
index = path.index(percent)
except ValueError:
res += percent + path
index = pathlen - 1
else:
var = path[:index]
try:
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
except KeyError:
value = percent + var + percent
res += value
elif c == dollar: # variable or '$$'
if path[index + 1:index + 2] == dollar:
res += c
index += 1
elif path[index + 1:index + 2] == brace:
path = path[index+2:]
pathlen = len(path)
try:
index = path.index(rbrace)
except ValueError:
res += dollar + brace + path
index = pathlen - 1
else:
var = path[:index]
try:
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
except KeyError:
value = dollar + brace + var + rbrace
res += value
else:
var = path[:0]
index += 1
c = path[index:index + 1]
while c and c in varchars:
var += c
index += 1
c = path[index:index + 1]
try:
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
except KeyError:
value = dollar + var
res += value
if c:
index -= 1
else:
res += c
index += 1
return res
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
# Previously, this function also truncated pathnames to 8+3 format,
# but as this module is called "ntpath", that's obviously wrong!
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
path = os.fspath(path)
if isinstance(path, bytes):
sep = b'\\'
altsep = b'/'
curdir = b'.'
pardir = b'..'
special_prefixes = (b'\\\\.\\', b'\\\\?\\')
else:
sep = '\\'
altsep = '/'
curdir = '.'
pardir = '..'
special_prefixes = ('\\\\.\\', '\\\\?\\')
if path.startswith(special_prefixes):
# in the case of paths with these prefixes:
# \\.\ -> device names
# \\?\ -> literal paths
# do not do any normalization, but return the path unchanged
return path
path = path.replace(altsep, sep)
prefix, path = splitdrive(path)
# collapse initial backslashes
if path.startswith(sep):
prefix += sep
path = path.lstrip(sep)
comps = path.split(sep)
i = 0
while i < len(comps):
if not comps[i] or comps[i] == curdir:
del comps[i]
elif comps[i] == pardir:
if i > 0 and comps[i-1] != pardir:
del comps[i-1:i+1]
i -= 1
elif i == 0 and prefix.endswith(sep):
del comps[i]
else:
i += 1
else:
i += 1
# If the path is now empty, substitute '.'
if not prefix and not comps:
comps.append(curdir)
return prefix + sep.join(comps)
def _abspath_fallback(path):
"""Return the absolute version of a path as a fallback function in case
`nt._getfullpathname` is not available or raises OSError. See bpo-31047 for
more.
"""
path = os.fspath(path)
if not isabs(path):
if isinstance(path, bytes):
cwd = os.getcwdb()
else:
cwd = os.getcwd()
path = join(cwd, path)
return normpath(path)
# Return an absolute path.
try:
from nt import _getfullpathname
except ImportError: # not running on Windows - mock up something sensible
abspath = _abspath_fallback
else: # use native Windows method on Windows
def abspath(path):
"""Return the absolute version of a path."""
try:
return normpath(_getfullpathname(path))
except (OSError, ValueError):
return _abspath_fallback(path)
# realpath is a no-op on systems without islink support
realpath = abspath
# Win9x family and earlier have no Unicode filename support.
supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
sys.getwindowsversion()[3] >= 2)
def relpath(path, start=None):
"""Return a relative version of a path"""
path = os.fspath(path)
if isinstance(path, bytes):
sep = b'\\'
curdir = b'.'
pardir = b'..'
else:
sep = '\\'
curdir = '.'
pardir = '..'
if start is None:
start = curdir
if not path:
raise ValueError("no path specified")
start = os.fspath(start)
try:
start_abs = abspath(normpath(start))
path_abs = abspath(normpath(path))
start_drive, start_rest = splitdrive(start_abs)
path_drive, path_rest = splitdrive(path_abs)
if normcase(start_drive) != normcase(path_drive):
raise ValueError("path is on mount %r, start on mount %r" % (
path_drive, start_drive))
start_list = [x for x in start_rest.split(sep) if x]
path_list = [x for x in path_rest.split(sep) if x]
# Work out how much of the filepath is shared by start and path.
i = 0
for e1, e2 in zip(start_list, path_list):
if normcase(e1) != normcase(e2):
break
i += 1
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return curdir
return join(*rel_list)
except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning):
genericpath._check_arg_types('relpath', path, start)
raise
# Return the longest common sub-path of the sequence of paths given as input.
# The function is case-insensitive and 'separator-insensitive', i.e. if the
# only difference between two paths is the use of '\' versus '/' as separator,
# they are deemed to be equal.
#
# However, the returned path will have the standard '\' separator (even if the
# given paths had the alternative '/' separator) and will have the case of the
# first path given in the sequence. Additionally, any trailing separator is
# stripped from the returned path.
def commonpath(paths):
"""Given a sequence of path names, returns the longest common sub-path."""
if not paths:
raise ValueError('commonpath() arg is an empty sequence')
paths = tuple(map(os.fspath, paths))
if isinstance(paths[0], bytes):
sep = b'\\'
altsep = b'/'
curdir = b'.'
else:
sep = '\\'
altsep = '/'
curdir = '.'
try:
drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
split_paths = [p.split(sep) for d, p in drivesplits]
try:
isabs, = set(p[:1] == sep for d, p in drivesplits)
except ValueError:
raise ValueError("Can't mix absolute and relative paths") from None
# Check that all drive letters or UNC paths match. The check is made only
# now otherwise type errors for mixing strings and bytes would not be
# caught.
if len(set(d for d, p in drivesplits)) != 1:
raise ValueError("Paths don't have the same drive")
drive, path = splitdrive(paths[0].replace(altsep, sep))
common = path.split(sep)
common = [c for c in common if c and c != curdir]
split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
s1 = min(split_paths)
s2 = max(split_paths)
for i, c in enumerate(s1):
if c != s2[i]:
common = common[:i]
break
else:
common = common[:len(s1)]
prefix = drive + sep if isabs else drive
return prefix + sep.join(common)
except (TypeError, AttributeError):
genericpath._check_arg_types('commonpath', *paths)
raise
# determine if two files are in fact the same file
try:
# GetFinalPathNameByHandle is available starting with Windows 6.0.
# Windows XP and non-Windows OS'es will mock _getfinalpathname.
if sys.getwindowsversion()[:2] >= (6, 0):
from nt import _getfinalpathname
else:
raise ImportError
except (AttributeError, ImportError):
# On Windows XP and earlier, two files are the same if their absolute
# pathnames are the same.
# Non-Windows operating systems fake this method with an XP
# approximation.
def _getfinalpathname(f):
return normcase(abspath(f))
try:
# The genericpath.isdir implementation uses os.stat and checks the mode
# attribute to tell whether or not the path is a directory.
# This is overkill on Windows - just pass the path to GetFileAttributes
# and check the attribute from there.
from nt import _isdir as isdir
except ImportError:
# Use genericpath.isdir as imported above.
pass

View File

@@ -1,15 +1,464 @@
"""
Operator Interface
This module exports a set of functions corresponding to the intrinsic
operators of Python. For example, operator.add(x, y) is equivalent
to the expression x+y. The function names are those used for special
methods; variants without leading and trailing '__' are also provided
for convenience.
This is the pure Python implementation of the module.
"""
__all__ = ['abs', 'add', 'and_', 'attrgetter', 'concat', 'contains', 'countOf',
'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand',
'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul',
'index', 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift',
'is_', 'is_not', 'isub', 'itemgetter', 'itruediv', 'ixor', 'le',
'length_hint', 'lshift', 'lt', 'matmul', 'methodcaller', 'mod',
'mul', 'ne', 'neg', 'not_', 'or_', 'pos', 'pow', 'rshift',
'setitem', 'sub', 'truediv', 'truth', 'xor']
from builtins import abs as _abs
# Comparison operations:
# Comparison Operations *******************************************************#
def lt(a, b):
"Same as a < b."
return a < b
def le(a, b):
"Same as a <= b."
return a <= b
def eq(a, b):
"Same as a == b."
return a == b
def ne(a, b):
"Same as a != b."
return a != b
def ge(a, b):
"Same as a >= b."
return a >= b
def gt(a, b):
"Same as a > b."
return a > b
# Logical Operations **********************************************************#
def not_(a):
"Same as not a."
return not a
def truth(a):
"Return True if a is true, False otherwise."
return True if a else False
def is_(a, b):
"Same as a is b."
return a is b
def is_not(a, b):
"Same as a is not b."
return a is not b
# Mathematical/Bitwise Operations *********************************************#
def abs(a):
"Same as abs(a)."
return _abs(a)
def add(a, b):
"Same as a + b."
return a + b
def and_(a, b):
"Same as a & b."
return a & b
def floordiv(a, b):
"Same as a // b."
return a // b
def index(a):
"Same as a.__index__()."
return a.__index__()
def inv(a):
"Same as ~a."
return ~a
invert = inv
def lshift(a, b):
"Same as a << b."
return a << b
def mod(a, b):
"Same as a % b."
return a % b
def mul(a, b):
"Same as a * b."
return a * b
def matmul(a, b):
"Same as a @ b."
return a @ b
def neg(a):
"Same as -a."
return -a
def or_(a, b):
"Same as a | b."
return a | b
def pos(a):
"Same as +a."
return +a
def pow(a, b):
"Same as a ** b."
return a ** b
def rshift(a, b):
"Same as a >> b."
return a >> b
def sub(a, b):
"Same as a - b."
return a - b
def truediv(a, b):
"Same as a / b."
return a / b
def xor(a, b):
"Same as a ^ b."
return a ^ b
# Sequence Operations *********************************************************#
def concat(a, b):
"Same as a + b, for a and b sequences."
if not hasattr(a, '__getitem__'):
msg = "'%s' object can't be concatenated" % type(a).__name__
raise TypeError(msg)
return a + b
def contains(a, b):
"Same as b in a (note reversed operands)."
return b in a
def countOf(a, b):
"Return the number of times b occurs in a."
count = 0
for i in a:
if i == b:
count += 1
return count
def delitem(a, b):
"Same as del a[b]."
del a[b]
def getitem(a, b):
"Same as a[b]."
return a[b]
def indexOf(a, b):
"Return the first index of b in a."
for i, j in enumerate(a):
if j == b:
return i
else:
raise ValueError('sequence.index(x): x not in sequence')
def setitem(a, b, c):
"Same as a[b] = c."
a[b] = c
def length_hint(obj, default=0):
"""
Return an estimate of the number of items in obj.
This is useful for presizing containers when building from an iterable.
If the object supports len(), the result will be exact. Otherwise, it may
over- or under-estimate by an arbitrary amount. The result will be an
integer >= 0.
"""
if not isinstance(default, int):
msg = ("'%s' object cannot be interpreted as an integer" %
type(default).__name__)
raise TypeError(msg)
try:
return len(obj)
except TypeError:
pass
try:
hint = type(obj).__length_hint__
except AttributeError:
return default
try:
val = hint(obj)
except TypeError:
return default
if val is NotImplemented:
return default
if not isinstance(val, int):
msg = ('__length_hint__ must be integer, not %s' %
type(val).__name__)
raise TypeError(msg)
if val < 0:
msg = '__length_hint__() should return >= 0'
raise ValueError(msg)
return val
# Generalized Lookup Objects **************************************************#
class attrgetter:
"""
Return a callable object that fetches the given attribute(s) from its operand.
After f = attrgetter('name'), the call f(r) returns r.name.
After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).
After h = attrgetter('name.first', 'name.last'), the call h(r) returns
(r.name.first, r.name.last).
"""
__slots__ = ('_attrs', '_call')
def __init__(self, attr, *attrs):
if not attrs:
if not isinstance(attr, str):
raise TypeError('attribute name must be a string')
self._attrs = (attr,)
names = attr.split('.')
def func(obj):
for name in names:
obj = getattr(obj, name)
return obj
self._call = func
else:
self._attrs = (attr,) + attrs
getters = tuple(map(attrgetter, self._attrs))
def func(obj):
return tuple(getter(obj) for getter in getters)
self._call = func
def __call__(self, obj):
return self._call(obj)
def __repr__(self):
return '%s.%s(%s)' % (self.__class__.__module__,
self.__class__.__qualname__,
', '.join(map(repr, self._attrs)))
def __reduce__(self):
return self.__class__, self._attrs
class itemgetter:
"""
Return a callable object that fetches the given item(s) from its operand.
After f = itemgetter(2), the call f(r) returns r[2].
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])
"""
__slots__ = ('_items', '_call')
def __init__(self, item, *items):
if not items:
self._items = (item,)
def func(obj):
return obj[item]
self._call = func
else:
self._items = items = (item,) + items
def func(obj):
return tuple(obj[i] for i in items)
self._call = func
def __call__(self, obj):
return self._call(obj)
def __repr__(self):
return '%s.%s(%s)' % (self.__class__.__module__,
self.__class__.__name__,
', '.join(map(repr, self._items)))
def __reduce__(self):
return self.__class__, self._items
class methodcaller:
"""
Return a callable object that calls the given method on its operand.
After f = methodcaller('name'), the call f(r) returns r.name().
After g = methodcaller('name', 'date', foo=1), the call g(r) returns
r.name('date', foo=1).
"""
__slots__ = ('_name', '_args', '_kwargs')
def __init__(*args, **kwargs):
if len(args) < 2:
msg = "methodcaller needs at least one argument, the method name"
raise TypeError(msg)
self = args[0]
self._name = args[1]
if not isinstance(self._name, str):
raise TypeError('method name must be a string')
self._args = args[2:]
self._kwargs = kwargs
def __call__(self, obj):
return getattr(obj, self._name)(*self._args, **self._kwargs)
def __repr__(self):
args = [repr(self._name)]
args.extend(map(repr, self._args))
args.extend('%s=%r' % (k, v) for k, v in self._kwargs.items())
return '%s.%s(%s)' % (self.__class__.__module__,
self.__class__.__name__,
', '.join(args))
def __reduce__(self):
if not self._kwargs:
return self.__class__, (self._name,) + self._args
else:
from functools import partial
return partial(self.__class__, self._name, **self._kwargs), self._args
# In-place Operations *********************************************************#
def iadd(a, b):
"Same as a += b."
a += b
return a
def iand(a, b):
"Same as a &= b."
a &= b
return a
def iconcat(a, b):
"Same as a += b, for a and b sequences."
if not hasattr(a, '__getitem__'):
msg = "'%s' object can't be concatenated" % type(a).__name__
raise TypeError(msg)
a += b
return a
def ifloordiv(a, b):
"Same as a //= b."
a //= b
return a
def ilshift(a, b):
"Same as a <<= b."
a <<= b
return a
def imod(a, b):
"Same as a %= b."
a %= b
return a
def imul(a, b):
"Same as a *= b."
a *= b
return a
def imatmul(a, b):
"Same as a @= b."
a @= b
return a
def ior(a, b):
"Same as a |= b."
a |= b
return a
def ipow(a, b):
"Same as a **= b."
a **=b
return a
def irshift(a, b):
"Same as a >>= b."
a >>= b
return a
def isub(a, b):
"Same as a -= b."
a -= b
return a
def itruediv(a, b):
"Same as a /= b."
a /= b
return a
def ixor(a, b):
"Same as a ^= b."
a ^= b
return a
try:
from _operator import *
except ImportError:
pass
else:
from _operator import __doc__
# All of these "__func__ = func" assignments have to happen after importing
# from _operator to make sure they're set to the right function
__lt__ = lt
__le__ = le
__eq__ = eq
__ne__ = ne
__ge__ = ge
__gt__ = gt
__not__ = not_
__abs__ = abs
__add__ = add
__and__ = and_
__floordiv__ = floordiv
__index__ = index
__inv__ = inv
__invert__ = invert
__lshift__ = lshift
__mod__ = mod
__mul__ = mul
__matmul__ = matmul
__neg__ = neg
__or__ = or_
__pos__ = pos
__pow__ = pow
__rshift__ = rshift
__sub__ = sub
__truediv__ = truediv
__xor__ = xor
__concat__ = concat
__contains__ = contains
__delitem__ = delitem
__getitem__ = getitem
__setitem__ = setitem
__iadd__ = iadd
__iand__ = iand
__iconcat__ = iconcat
__ifloordiv__ = ifloordiv
__ilshift__ = ilshift
__imod__ = imod
__imul__ = imul
__imatmul__ = imatmul
__ior__ = ior
__ipow__ = ipow
__irshift__ = irshift
__isub__ = isub
__itruediv__ = itruediv
__ixor__ = ixor

135
Lib/os.py Normal file
View File

@@ -0,0 +1,135 @@
import sys
from _os import *
if name == 'nt':
linesep = '\r\n'
import ntpath as path
else:
linesep = '\n'
import posixpath as path
sys.modules['os.path'] = path
from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep,
devnull)
# Change environ to automatically call putenv(), unsetenv if they exist.
from _collections_abc import MutableMapping
class _Environ(MutableMapping):
def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, putenv, unsetenv):
self.encodekey = encodekey
self.decodekey = decodekey
self.encodevalue = encodevalue
self.decodevalue = decodevalue
self.putenv = putenv
self.unsetenv = unsetenv
self._data = data
def __getitem__(self, key):
try:
value = self._data[self.encodekey(key)]
except KeyError:
# raise KeyError with the original key value
raise KeyError(key) from None
return self.decodevalue(value)
def __setitem__(self, key, value):
key = self.encodekey(key)
value = self.encodevalue(value)
self.putenv(key, value)
self._data[key] = value
def __delitem__(self, key):
encodedkey = self.encodekey(key)
self.unsetenv(encodedkey)
try:
del self._data[encodedkey]
except KeyError:
# raise KeyError with the original key value
raise KeyError(key) from None
def __iter__(self):
# list() from dict object is an atomic operation
keys = list(self._data)
for key in keys:
yield self.decodekey(key)
def __len__(self):
return len(self._data)
def __repr__(self):
return 'environ({{{}}})'.format(', '.join(
('{!r}: {!r}'.format(self.decodekey(key), self.decodevalue(value))
for key, value in self._data.items())))
def copy(self):
return dict(self)
def setdefault(self, key, value):
if key not in self:
self[key] = value
return self[key]
try:
_putenv = putenv
except NameError:
_putenv = lambda key, value: None
# else:
# if "putenv" not in __all__:
# __all__.append("putenv")
try:
_unsetenv = unsetenv
except NameError:
_unsetenv = lambda key: _putenv(key, "")
# else:
# if "unsetenv" not in __all__:
# __all__.append("unsetenv")
def _createenviron():
# if name == 'nt':
# # Where Env Var Names Must Be UPPERCASE
# def check_str(value):
# if not isinstance(value, str):
# raise TypeError("str expected, not %s" % type(value).__name__)
# return value
# encode = check_str
# decode = str
# def encodekey(key):
# return encode(key).upper()
# data = {}
# for key, value in environ.items():
# data[encodekey(key)] = value
# else:
# # Where Env Var Names Can Be Mixed Case
# encoding = sys.getfilesystemencoding()
# def encode(value):
# if not isinstance(value, str):
# raise TypeError("str expected, not %s" % type(value).__name__)
# return value.encode(encoding, 'surrogateescape')
# def decode(value):
# return value.decode(encoding, 'surrogateescape')
# encodekey = encode
decode = str
encode = str
encodekey = encode
data = environ
return _Environ(data,
encodekey, decode,
encode, decode,
_putenv, _unsetenv)
# unicode environ
environ = _createenviron()
del _createenviron
def getenv(key, default=None):
"""Get an environment variable, return None if it doesn't exist.
The optional second argument can specify an alternate default.
key, default and the result are str."""
return environ.get(key, default)

525
Lib/posixpath.py Normal file
View File

@@ -0,0 +1,525 @@
"""Common operations on Posix pathnames.
Instead of importing this module directly, import os and refer to
this module as os.path. The "os.path" name is an alias for this
module on Posix systems; on other systems (e.g. Windows),
os.path provides the same operations in a manner specific to that
platform, and is an alias to another module (e.g. ntpath).
Some of this can actually be useful on non-Posix systems too, e.g.
for manipulation of the pathname component of URLs.
"""
# Strings representing various path-related bits and pieces.
# These are primarily for export; internally, they are hardcoded.
# Should be set before imports for resolving cyclic dependency.
curdir = '.'
pardir = '..'
extsep = '.'
sep = '/'
pathsep = ':'
defpath = '/bin:/usr/bin'
altsep = None
devnull = '/dev/null'
import os
import sys
import stat
import genericpath
from genericpath import *
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
"getatime","getctime","islink","exists","lexists","isdir","isfile",
"ismount", "expanduser","expandvars","normpath","abspath",
"samefile","sameopenfile","samestat",
"curdir","pardir","sep","pathsep","defpath","altsep","extsep",
"devnull","realpath","supports_unicode_filenames","relpath",
"commonpath"]
def _get_sep(path):
if isinstance(path, bytes):
return b'/'
else:
return '/'
# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
# On MS-DOS this may also turn slashes into backslashes; however, other
# normalizations (such as optimizing '../' away) are not allowed
# (another function should be defined to do that).
def normcase(s):
"""Normalize case of pathname. Has no effect under Posix"""
return os.fspath(s)
# Return whether a path is absolute.
# Trivial in Posix, harder on the Mac or MS-DOS.
def isabs(s):
"""Test whether a path is absolute"""
s = os.fspath(s)
sep = _get_sep(s)
return s.startswith(sep)
# Join pathnames.
# Ignore the previous parts if a part is absolute.
# Insert a '/' unless the first part is empty or already ends in '/'.
def join(a, *p):
"""Join two or more pathname components, inserting '/' as needed.
If any component is an absolute path, all previous path components
will be discarded. An empty last part will result in a path that
ends with a separator."""
a = os.fspath(a)
sep = _get_sep(a)
path = a
try:
if not p:
path[:0] + sep #23780: Ensure compatible data type even if p is null.
for b in map(os.fspath, p):
if b.startswith(sep):
path = b
elif not path or path.endswith(sep):
path += b
else:
path += sep + b
except (TypeError, AttributeError, BytesWarning):
genericpath._check_arg_types('join', a, *p)
raise
return path
# Split a path in head (everything up to the last '/') and tail (the
# rest). If the path ends in '/', tail will be empty. If there is no
# '/' in the path, head will be empty.
# Trailing '/'es are stripped from head unless it is the root.
def split(p):
"""Split a pathname. Returns tuple "(head, tail)" where "tail" is
everything after the final slash. Either part may be empty."""
p = os.fspath(p)
sep = _get_sep(p)
i = p.rfind(sep) + 1
head, tail = p[:i], p[i:]
if head and head != sep*len(head):
head = head.rstrip(sep)
return head, tail
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
def splitext(p):
p = os.fspath(p)
if isinstance(p, bytes):
sep = b'/'
extsep = b'.'
else:
sep = '/'
extsep = '.'
return genericpath._splitext(p, sep, None, extsep)
splitext.__doc__ = genericpath._splitext.__doc__
# Split a pathname into a drive specification and the rest of the
# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
def splitdrive(p):
"""Split a pathname into drive and path. On Posix, drive is always
empty."""
p = os.fspath(p)
return p[:0], p
# Return the tail (basename) part of a path, same as split(path)[1].
def basename(p):
"""Returns the final component of a pathname"""
p = os.fspath(p)
sep = _get_sep(p)
i = p.rfind(sep) + 1
return p[i:]
# Return the head (dirname) part of a path, same as split(path)[0].
def dirname(p):
"""Returns the directory component of a pathname"""
p = os.fspath(p)
sep = _get_sep(p)
i = p.rfind(sep) + 1
head = p[:i]
if head and head != sep*len(head):
head = head.rstrip(sep)
return head
# Is a path a symbolic link?
# This will always return false on systems where os.lstat doesn't exist.
def islink(path):
"""Test whether a path is a symbolic link"""
try:
st = os.lstat(path)
except (OSError, ValueError, AttributeError):
return False
return stat.S_ISLNK(st.st_mode)
# Being true for dangling symbolic links is also useful.
def lexists(path):
"""Test whether a path exists. Returns True for broken symbolic links"""
try:
os.lstat(path)
except (OSError, ValueError):
return False
return True
# Is a path a mount point?
# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
def ismount(path):
"""Test whether a path is a mount point"""
try:
s1 = os.lstat(path)
except (OSError, ValueError):
# It doesn't exist -- so not a mount point. :-)
return False
else:
# A symlink can never be a mount point
if stat.S_ISLNK(s1.st_mode):
return False
if isinstance(path, bytes):
parent = join(path, b'..')
else:
parent = join(path, '..')
parent = realpath(parent)
try:
s2 = os.lstat(parent)
except (OSError, ValueError):
return False
dev1 = s1.st_dev
dev2 = s2.st_dev
if dev1 != dev2:
return True # path/.. on a different device as path
ino1 = s1.st_ino
ino2 = s2.st_ino
if ino1 == ino2:
return True # path/.. is the same i-node as path
return False
# Expand paths beginning with '~' or '~user'.
# '~' means $HOME; '~user' means that user's home directory.
# If the path doesn't begin with '~', or if the user or $HOME is unknown,
# the path is returned unchanged (leaving error reporting to whatever
# function is called with the expanded path as argument).
# See also module 'glob' for expansion of *, ? and [...] in pathnames.
# (A function should also be defined to do full *sh-style environment
# variable expansion.)
def expanduser(path):
"""Expand ~ and ~user constructions. If user or $HOME is unknown,
do nothing."""
path = os.fspath(path)
if isinstance(path, bytes):
tilde = b'~'
else:
tilde = '~'
if not path.startswith(tilde):
return path
sep = _get_sep(path)
i = path.find(sep, 1)
if i < 0:
i = len(path)
if i == 1:
if 'HOME' not in os.environ:
import pwd
try:
userhome = pwd.getpwuid(os.getuid()).pw_dir
except KeyError:
# bpo-10496: if the current user identifier doesn't exist in the
# password database, return the path unchanged
return path
else:
userhome = os.environ['HOME']
else:
import pwd
name = path[1:i]
if isinstance(name, bytes):
name = str(name, 'ASCII')
try:
pwent = pwd.getpwnam(name)
except KeyError:
# bpo-10496: if the user name from the path doesn't exist in the
# password database, return the path unchanged
return path
userhome = pwent.pw_dir
if isinstance(path, bytes):
userhome = os.fsencode(userhome)
root = b'/'
else:
root = '/'
userhome = userhome.rstrip(root)
return (userhome + path[i:]) or root
# Expand paths containing shell variable substitutions.
# This expands the forms $variable and ${variable} only.
# Non-existent variables are left unchanged.
_varprog = None
_varprogb = None
def expandvars(path):
"""Expand shell variables of form $var and ${var}. Unknown variables
are left unchanged."""
path = os.fspath(path)
global _varprog, _varprogb
if isinstance(path, bytes):
if b'$' not in path:
return path
if not _varprogb:
import re
_varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
search = _varprogb.search
start = b'{'
end = b'}'
environ = getattr(os, 'environb', None)
else:
if '$' not in path:
return path
if not _varprog:
import re
_varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
search = _varprog.search
start = '{'
end = '}'
environ = os.environ
i = 0
while True:
m = search(path, i)
if not m:
break
i, j = m.span(0)
name = m.group(1)
if name.startswith(start) and name.endswith(end):
name = name[1:-1]
try:
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(name)])
else:
value = environ[name]
except KeyError:
i = j
else:
tail = path[j:]
path = path[:i] + value
i = len(path)
path += tail
return path
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
# It should be understood that this may change the meaning of the path
# if it contains symbolic links!
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
path = os.fspath(path)
if isinstance(path, bytes):
sep = b'/'
empty = b''
dot = b'.'
dotdot = b'..'
else:
sep = '/'
empty = ''
dot = '.'
dotdot = '..'
if path == empty:
return dot
initial_slashes = path.startswith(sep)
# POSIX allows one or two initial slashes, but treats three or more
# as single slash.
if (initial_slashes and
path.startswith(sep*2) and not path.startswith(sep*3)):
initial_slashes = 2
comps = path.split(sep)
new_comps = []
for comp in comps:
if comp in (empty, dot):
continue
if (comp != dotdot or (not initial_slashes and not new_comps) or
(new_comps and new_comps[-1] == dotdot)):
new_comps.append(comp)
elif new_comps:
new_comps.pop()
comps = new_comps
path = sep.join(comps)
if initial_slashes:
path = sep*initial_slashes + path
return path or dot
def abspath(path):
"""Return an absolute path."""
path = os.fspath(path)
if not isabs(path):
if isinstance(path, bytes):
cwd = os.getcwdb()
else:
cwd = os.getcwd()
path = join(cwd, path)
return normpath(path)
# Return a canonical path (i.e. the absolute location of a file on the
# filesystem).
def realpath(filename):
"""Return the canonical path of the specified filename, eliminating any
symbolic links encountered in the path."""
filename = os.fspath(filename)
path, ok = _joinrealpath(filename[:0], filename, {})
return abspath(path)
# Join two paths, normalizing and eliminating any symbolic links
# encountered in the second path.
def _joinrealpath(path, rest, seen):
if isinstance(path, bytes):
sep = b'/'
curdir = b'.'
pardir = b'..'
else:
sep = '/'
curdir = '.'
pardir = '..'
if isabs(rest):
rest = rest[1:]
path = sep
while rest:
name, _, rest = rest.partition(sep)
if not name or name == curdir:
# current dir
continue
if name == pardir:
# parent dir
if path:
path, name = split(path)
if name == pardir:
path = join(path, pardir, pardir)
else:
path = pardir
continue
newpath = join(path, name)
if not islink(newpath):
path = newpath
continue
# Resolve the symbolic link
if newpath in seen:
# Already seen this path
path = seen[newpath]
if path is not None:
# use cached value
continue
# The symlink is not resolved, so we must have a symlink loop.
# Return already resolved part + rest of the path unchanged.
return join(newpath, rest), False
seen[newpath] = None # not resolved symlink
path, ok = _joinrealpath(path, os.readlink(newpath), seen)
if not ok:
return join(path, rest), False
seen[newpath] = path # resolved symlink
return path, True
supports_unicode_filenames = (sys.platform == 'darwin')
def relpath(path, start=None):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
path = os.fspath(path)
if isinstance(path, bytes):
curdir = b'.'
sep = b'/'
pardir = b'..'
else:
curdir = '.'
sep = '/'
pardir = '..'
if start is None:
start = curdir
else:
start = os.fspath(start)
try:
start_list = [x for x in abspath(start).split(sep) if x]
path_list = [x for x in abspath(path).split(sep) if x]
# Work out how much of the filepath is shared by start and path.
i = len(commonprefix([start_list, path_list]))
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return curdir
return join(*rel_list)
except (TypeError, AttributeError, BytesWarning, DeprecationWarning):
genericpath._check_arg_types('relpath', path, start)
raise
# Return the longest common sub-path of the sequence of paths given as input.
# The paths are not normalized before comparing them (this is the
# responsibility of the caller). Any trailing separator is stripped from the
# returned path.
def commonpath(paths):
"""Given a sequence of path names, returns the longest common sub-path."""
if not paths:
raise ValueError('commonpath() arg is an empty sequence')
paths = tuple(map(os.fspath, paths))
if isinstance(paths[0], bytes):
sep = b'/'
curdir = b'.'
else:
sep = '/'
curdir = '.'
try:
split_paths = [path.split(sep) for path in paths]
try:
isabs, = set(p[:1] == sep for p in paths)
except ValueError:
raise ValueError("Can't mix absolute and relative paths") from None
split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
s1 = min(split_paths)
s2 = max(split_paths)
common = s1
for i, c in enumerate(s1):
if c != s2[i]:
common = s1[:i]
break
prefix = sep if isabs else sep[:0]
return prefix + sep.join(common)
except (TypeError, AttributeError):
genericpath._check_arg_types('commonpath', *paths)
raise

View File

@@ -1,11 +0,0 @@
""" Regular expressions """
def match(pattern, string, flags=0):
return _compile(pattern, flags).match(string)
def _compile(pattern, flags):
p = sre_compile.compile(pattern, flags)
return p

161
Lib/reprlib.py Normal file
View File

@@ -0,0 +1,161 @@
"""Redo the builtin repr() (representation) but with limits on most sizes."""
__all__ = ["Repr", "repr", "recursive_repr"]
import builtins
from itertools import islice
from _thread import get_ident
def recursive_repr(fillvalue='...'):
'Decorator to make a repr function return fillvalue for a recursive call'
def decorating_function(user_function):
repr_running = set()
def wrapper(self):
key = id(self), get_ident()
if key in repr_running:
return fillvalue
repr_running.add(key)
try:
result = user_function(self)
finally:
repr_running.discard(key)
return result
# Can't use functools.wraps() here because of bootstrap issues
wrapper.__module__ = getattr(user_function, '__module__')
wrapper.__doc__ = getattr(user_function, '__doc__')
wrapper.__name__ = getattr(user_function, '__name__')
wrapper.__qualname__ = getattr(user_function, '__qualname__')
wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
return wrapper
return decorating_function
class Repr:
def __init__(self):
self.maxlevel = 6
self.maxtuple = 6
self.maxlist = 6
self.maxarray = 5
self.maxdict = 4
self.maxset = 6
self.maxfrozenset = 6
self.maxdeque = 6
self.maxstring = 30
self.maxlong = 40
self.maxother = 30
def repr(self, x):
return self.repr1(x, self.maxlevel)
def repr1(self, x, level):
typename = type(x).__name__
if ' ' in typename:
parts = typename.split()
typename = '_'.join(parts)
if hasattr(self, 'repr_' + typename):
return getattr(self, 'repr_' + typename)(x, level)
else:
return self.repr_instance(x, level)
def _repr_iterable(self, x, level, left, right, maxiter, trail=''):
n = len(x)
if level <= 0 and n:
s = '...'
else:
newlevel = level - 1
repr1 = self.repr1
pieces = [repr1(elem, newlevel) for elem in islice(x, maxiter)]
if n > maxiter: pieces.append('...')
s = ', '.join(pieces)
if n == 1 and trail: right = trail + right
return '%s%s%s' % (left, s, right)
def repr_tuple(self, x, level):
return self._repr_iterable(x, level, '(', ')', self.maxtuple, ',')
def repr_list(self, x, level):
return self._repr_iterable(x, level, '[', ']', self.maxlist)
def repr_array(self, x, level):
if not x:
return "array('%s')" % x.typecode
header = "array('%s', [" % x.typecode
return self._repr_iterable(x, level, header, '])', self.maxarray)
def repr_set(self, x, level):
if not x:
return 'set()'
x = _possibly_sorted(x)
return self._repr_iterable(x, level, '{', '}', self.maxset)
def repr_frozenset(self, x, level):
if not x:
return 'frozenset()'
x = _possibly_sorted(x)
return self._repr_iterable(x, level, 'frozenset({', '})',
self.maxfrozenset)
def repr_deque(self, x, level):
return self._repr_iterable(x, level, 'deque([', '])', self.maxdeque)
def repr_dict(self, x, level):
n = len(x)
if n == 0: return '{}'
if level <= 0: return '{...}'
newlevel = level - 1
repr1 = self.repr1
pieces = []
for key in islice(_possibly_sorted(x), self.maxdict):
keyrepr = repr1(key, newlevel)
valrepr = repr1(x[key], newlevel)
pieces.append('%s: %s' % (keyrepr, valrepr))
if n > self.maxdict: pieces.append('...')
s = ', '.join(pieces)
return '{%s}' % (s,)
def repr_str(self, x, level):
s = builtins.repr(x[:self.maxstring])
if len(s) > self.maxstring:
i = max(0, (self.maxstring-3)//2)
j = max(0, self.maxstring-3-i)
s = builtins.repr(x[:i] + x[len(x)-j:])
s = s[:i] + '...' + s[len(s)-j:]
return s
def repr_int(self, x, level):
s = builtins.repr(x) # XXX Hope this isn't too slow...
if len(s) > self.maxlong:
i = max(0, (self.maxlong-3)//2)
j = max(0, self.maxlong-3-i)
s = s[:i] + '...' + s[len(s)-j:]
return s
def repr_instance(self, x, level):
try:
s = builtins.repr(x)
# Bugs in x.__repr__() can cause arbitrary
# exceptions -- then make up something
except Exception:
return '<%s instance at %#x>' % (x.__class__.__name__, id(x))
if len(s) > self.maxother:
i = max(0, (self.maxother-3)//2)
j = max(0, self.maxother-3-i)
s = s[:i] + '...' + s[len(s)-j:]
return s
def _possibly_sorted(x):
# Since not all sequences of items can be sorted and comparison
# functions may raise arbitrary exceptions, return an unsorted
# sequence in that case.
try:
return sorted(x)
except Exception:
return list(x)
aRepr = Repr()
repr = aRepr.repr

179
Lib/stat.py Normal file
View File

@@ -0,0 +1,179 @@
"""Constants/functions for interpreting results of os.stat() and os.lstat().
Suggested usage: from stat import *
"""
# Indices for stat struct members in the tuple returned by os.stat()
ST_MODE = 0
ST_INO = 1
ST_DEV = 2
ST_NLINK = 3
ST_UID = 4
ST_GID = 5
ST_SIZE = 6
ST_ATIME = 7
ST_MTIME = 8
ST_CTIME = 9
# Extract bits from the mode
def S_IMODE(mode):
"""Return the portion of the file's mode that can be set by
os.chmod().
"""
return mode & 0o7777
def S_IFMT(mode):
"""Return the portion of the file's mode that describes the
file type.
"""
return mode & 0o170000
# Constants used as S_IFMT() for various file types
# (not all are implemented on all systems)
S_IFDIR = 0o040000 # directory
S_IFCHR = 0o020000 # character device
S_IFBLK = 0o060000 # block device
S_IFREG = 0o100000 # regular file
S_IFIFO = 0o010000 # fifo (named pipe)
S_IFLNK = 0o120000 # symbolic link
S_IFSOCK = 0o140000 # socket file
# Functions to test for each file type
def S_ISDIR(mode):
"""Return True if mode is from a directory."""
return S_IFMT(mode) == S_IFDIR
def S_ISCHR(mode):
"""Return True if mode is from a character special device file."""
return S_IFMT(mode) == S_IFCHR
def S_ISBLK(mode):
"""Return True if mode is from a block special device file."""
return S_IFMT(mode) == S_IFBLK
def S_ISREG(mode):
"""Return True if mode is from a regular file."""
return S_IFMT(mode) == S_IFREG
def S_ISFIFO(mode):
"""Return True if mode is from a FIFO (named pipe)."""
return S_IFMT(mode) == S_IFIFO
def S_ISLNK(mode):
"""Return True if mode is from a symbolic link."""
return S_IFMT(mode) == S_IFLNK
def S_ISSOCK(mode):
"""Return True if mode is from a socket."""
return S_IFMT(mode) == S_IFSOCK
# Names for permission bits
S_ISUID = 0o4000 # set UID bit
S_ISGID = 0o2000 # set GID bit
S_ENFMT = S_ISGID # file locking enforcement
S_ISVTX = 0o1000 # sticky bit
S_IREAD = 0o0400 # Unix V7 synonym for S_IRUSR
S_IWRITE = 0o0200 # Unix V7 synonym for S_IWUSR
S_IEXEC = 0o0100 # Unix V7 synonym for S_IXUSR
S_IRWXU = 0o0700 # mask for owner permissions
S_IRUSR = 0o0400 # read by owner
S_IWUSR = 0o0200 # write by owner
S_IXUSR = 0o0100 # execute by owner
S_IRWXG = 0o0070 # mask for group permissions
S_IRGRP = 0o0040 # read by group
S_IWGRP = 0o0020 # write by group
S_IXGRP = 0o0010 # execute by group
S_IRWXO = 0o0007 # mask for others (not in group) permissions
S_IROTH = 0o0004 # read by others
S_IWOTH = 0o0002 # write by others
S_IXOTH = 0o0001 # execute by others
# Names for file flags
UF_NODUMP = 0x00000001 # do not dump file
UF_IMMUTABLE = 0x00000002 # file may not be changed
UF_APPEND = 0x00000004 # file may only be appended to
UF_OPAQUE = 0x00000008 # directory is opaque when viewed through a union stack
UF_NOUNLINK = 0x00000010 # file may not be renamed or deleted
UF_COMPRESSED = 0x00000020 # OS X: file is hfs-compressed
UF_HIDDEN = 0x00008000 # OS X: file should not be displayed
SF_ARCHIVED = 0x00010000 # file may be archived
SF_IMMUTABLE = 0x00020000 # file may not be changed
SF_APPEND = 0x00040000 # file may only be appended to
SF_NOUNLINK = 0x00100000 # file may not be renamed or deleted
SF_SNAPSHOT = 0x00200000 # file is a snapshot file
_filemode_table = (
((S_IFLNK, "l"),
(S_IFSOCK, "s"), # Must appear before IFREG and IFDIR as IFSOCK == IFREG | IFDIR
(S_IFREG, "-"),
(S_IFBLK, "b"),
(S_IFDIR, "d"),
(S_IFCHR, "c"),
(S_IFIFO, "p")),
((S_IRUSR, "r"),),
((S_IWUSR, "w"),),
((S_IXUSR|S_ISUID, "s"),
(S_ISUID, "S"),
(S_IXUSR, "x")),
((S_IRGRP, "r"),),
((S_IWGRP, "w"),),
((S_IXGRP|S_ISGID, "s"),
(S_ISGID, "S"),
(S_IXGRP, "x")),
((S_IROTH, "r"),),
((S_IWOTH, "w"),),
((S_IXOTH|S_ISVTX, "t"),
(S_ISVTX, "T"),
(S_IXOTH, "x"))
)
def filemode(mode):
"""Convert a file's mode to a string of the form '-rwxrwxrwx'."""
perm = []
for table in _filemode_table:
for bit, char in table:
if mode & bit == bit:
perm.append(char)
break
else:
perm.append("-")
return "".join(perm)
# Windows FILE_ATTRIBUTE constants for interpreting os.stat()'s
# "st_file_attributes" member
FILE_ATTRIBUTE_ARCHIVE = 32
FILE_ATTRIBUTE_COMPRESSED = 2048
FILE_ATTRIBUTE_DEVICE = 64
FILE_ATTRIBUTE_DIRECTORY = 16
FILE_ATTRIBUTE_ENCRYPTED = 16384
FILE_ATTRIBUTE_HIDDEN = 2
FILE_ATTRIBUTE_INTEGRITY_STREAM = 32768
FILE_ATTRIBUTE_NORMAL = 128
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 8192
FILE_ATTRIBUTE_NO_SCRUB_DATA = 131072
FILE_ATTRIBUTE_OFFLINE = 4096
FILE_ATTRIBUTE_READONLY = 1
FILE_ATTRIBUTE_REPARSE_POINT = 1024
FILE_ATTRIBUTE_SPARSE_FILE = 512
FILE_ATTRIBUTE_SYSTEM = 4
FILE_ATTRIBUTE_TEMPORARY = 256
FILE_ATTRIBUTE_VIRTUAL = 65536
# If available, use C implementation
try:
from _stat import *
except ImportError:
pass

28
Lib/this.py Normal file
View File

@@ -0,0 +1,28 @@
s = """Gur Mra bs Clguba, ol Gvz Crgref
Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""
d = {}
for c in (65, 97):
for i in range(26):
d[chr(i+c)] = chr((i+13) % 26 + c)
print("".join([d.get(c, c) for c in s]))

295
Lib/types.py Normal file
View File

@@ -0,0 +1,295 @@
"""
Define names for built-in types that aren't directly accessible as a builtin.
"""
import sys
# Iterators in Python aren't a matter of type but of protocol. A large
# and changing number of builtin types implement *some* flavor of
# iterator. Don't check the type! Use hasattr to check for both
# "__iter__" and "__next__" attributes instead.
def _f(): pass
FunctionType = type(_f)
LambdaType = type(lambda: None) # Same as FunctionType
CodeType = type(_f.__code__)
MappingProxyType = type(type.__dict__)
SimpleNamespace = type(sys.implementation)
def _g():
yield 1
GeneratorType = type(_g())
# async def _c(): pass
# _c = _c()
# CoroutineType = type(_c)
# _c.close() # Prevent ResourceWarning
# async def _ag():
# yield
# _ag = _ag()
# AsyncGeneratorType = type(_ag)
class _C:
def _m(self): pass
MethodType = type(_C()._m)
BuiltinFunctionType = type(len)
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
WrapperDescriptorType = type(object.__init__)
MethodWrapperType = type(object().__str__)
MethodDescriptorType = type(str.join)
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
ModuleType = type(sys)
# try:
# raise TypeError
# except TypeError:
# tb = sys.exc_info()[2]
# TracebackType = type(tb)
# FrameType = type(tb.tb_frame)
# tb = None; del tb
# For Jython, the following two types are identical
GetSetDescriptorType = type(FunctionType.__code__)
# MemberDescriptorType = type(FunctionType.__globals__)
del sys, _f, _g, _C # Not for export
# Provide a PEP 3115 compliant mechanism for class creation
def new_class(name, bases=(), kwds=None, exec_body=None):
"""Create a class object dynamically using the appropriate metaclass."""
resolved_bases = resolve_bases(bases)
meta, ns, kwds = prepare_class(name, resolved_bases, kwds)
if exec_body is not None:
exec_body(ns)
if resolved_bases is not bases:
ns['__orig_bases__'] = bases
return meta(name, resolved_bases, ns, **kwds)
def resolve_bases(bases):
"""Resolve MRO entries dynamically as specified by PEP 560."""
new_bases = list(bases)
updated = False
shift = 0
for i, base in enumerate(bases):
if isinstance(base, type):
continue
if not hasattr(base, "__mro_entries__"):
continue
new_base = base.__mro_entries__(bases)
updated = True
if not isinstance(new_base, tuple):
raise TypeError("__mro_entries__ must return a tuple")
else:
new_bases[i+shift:i+shift+1] = new_base
shift += len(new_base) - 1
if not updated:
return bases
return tuple(new_bases)
def prepare_class(name, bases=(), kwds=None):
"""Call the __prepare__ method of the appropriate metaclass.
Returns (metaclass, namespace, kwds) as a 3-tuple
*metaclass* is the appropriate metaclass
*namespace* is the prepared class namespace
*kwds* is an updated copy of the passed in kwds argument with any
'metaclass' entry removed. If no kwds argument is passed in, this will
be an empty dict.
"""
if kwds is None:
kwds = {}
else:
kwds = dict(kwds) # Don't alter the provided mapping
if 'metaclass' in kwds:
meta = kwds.pop('metaclass')
else:
if bases:
meta = type(bases[0])
else:
meta = type
if isinstance(meta, type):
# when meta is a type, we first determine the most-derived metaclass
# instead of invoking the initial candidate directly
meta = _calculate_meta(meta, bases)
if hasattr(meta, '__prepare__'):
ns = meta.__prepare__(name, bases, **kwds)
else:
ns = {}
return meta, ns, kwds
def _calculate_meta(meta, bases):
"""Calculate the most derived metaclass."""
winner = meta
for base in bases:
base_meta = type(base)
if issubclass(winner, base_meta):
continue
if issubclass(base_meta, winner):
winner = base_meta
continue
# else:
raise TypeError("metaclass conflict: "
"the metaclass of a derived class "
"must be a (non-strict) subclass "
"of the metaclasses of all its bases")
return winner
class DynamicClassAttribute:
"""Route attribute access on a class to __getattr__.
This is a descriptor, used to define attributes that act differently when
accessed through an instance and through a class. Instance access remains
normal, but access to an attribute through a class will be routed to the
class's __getattr__ method; this is done by raising AttributeError.
This allows one to have properties active on an instance, and have virtual
attributes on the class with the same name (see Enum for an example).
"""
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
# next two lines make DynamicClassAttribute act the same as property
self.__doc__ = doc or fget.__doc__
self.overwrite_doc = doc is None
# support for abstract methods
self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False))
def __get__(self, instance, ownerclass=None):
if instance is None:
if self.__isabstractmethod__:
return self
raise AttributeError()
elif self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(instance)
def __set__(self, instance, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(instance, value)
def __delete__(self, instance):
if self.fdel is None:
raise AttributeError("can't delete attribute")
self.fdel(instance)
def getter(self, fget):
fdoc = fget.__doc__ if self.overwrite_doc else None
result = type(self)(fget, self.fset, self.fdel, fdoc or self.__doc__)
result.overwrite_doc = self.overwrite_doc
return result
def setter(self, fset):
result = type(self)(self.fget, fset, self.fdel, self.__doc__)
result.overwrite_doc = self.overwrite_doc
return result
def deleter(self, fdel):
result = type(self)(self.fget, self.fset, fdel, self.__doc__)
result.overwrite_doc = self.overwrite_doc
return result
class _GeneratorWrapper:
# TODO: Implement this in C.
def __init__(self, gen):
self.__wrapped = gen
self.__isgen = gen.__class__ is GeneratorType
self.__name__ = getattr(gen, '__name__', None)
self.__qualname__ = getattr(gen, '__qualname__', None)
def send(self, val):
return self.__wrapped.send(val)
def throw(self, tp, *rest):
return self.__wrapped.throw(tp, *rest)
def close(self):
return self.__wrapped.close()
@property
def gi_code(self):
return self.__wrapped.gi_code
@property
def gi_frame(self):
return self.__wrapped.gi_frame
@property
def gi_running(self):
return self.__wrapped.gi_running
@property
def gi_yieldfrom(self):
return self.__wrapped.gi_yieldfrom
cr_code = gi_code
cr_frame = gi_frame
cr_running = gi_running
cr_await = gi_yieldfrom
def __next__(self):
return next(self.__wrapped)
def __iter__(self):
if self.__isgen:
return self.__wrapped
return self
__await__ = __iter__
def coroutine(func):
"""Convert regular generator function to a coroutine."""
if not callable(func):
raise TypeError('types.coroutine() expects a callable')
if (func.__class__ is FunctionType and
getattr(func, '__code__', None).__class__ is CodeType):
co_flags = func.__code__.co_flags
# Check if 'func' is a coroutine function.
# (0x180 == CO_COROUTINE | CO_ITERABLE_COROUTINE)
if co_flags & 0x180:
return func
# Check if 'func' is a generator function.
# (0x20 == CO_GENERATOR)
if co_flags & 0x20:
# TODO: Implement this in C.
co = func.__code__
func.__code__ = CodeType(
co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
co.co_stacksize,
co.co_flags | 0x100, # 0x100 == CO_ITERABLE_COROUTINE
co.co_code,
co.co_consts, co.co_names, co.co_varnames, co.co_filename,
co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars,
co.co_cellvars)
return func
# The following code is primarily to support functions that
# return generator-like objects (for instance generators
# compiled with Cython).
# Delay functools and _collections_abc import for speeding up types import.
import functools
import _collections_abc
@functools.wraps(func)
def wrapped(*args, **kwargs):
coro = func(*args, **kwargs)
if (coro.__class__ is CoroutineType or
coro.__class__ is GeneratorType and coro.gi_code.co_flags & 0x100):
# 'coro' is a native coroutine object or an iterable coroutine
return coro
if (isinstance(coro, _collections_abc.Generator) and
not isinstance(coro, _collections_abc.Coroutine)):
# 'coro' is either a pure Python generator iterator, or it
# implements collections.abc.Generator (and does not implement
# collections.abc.Coroutine).
return _GeneratorWrapper(coro)
# 'coro' is either an instance of collections.abc.Coroutine or
# some other object -- pass it through.
return coro
return wrapped
__all__ = [n for n in globals() if n[:1] != '_']

554
Lib/warnings.py Normal file
View File

@@ -0,0 +1,554 @@
"""Python part of the warnings subsystem."""
import sys
__all__ = ["warn", "warn_explicit", "showwarning",
"formatwarning", "filterwarnings", "simplefilter",
"resetwarnings", "catch_warnings"]
def showwarning(message, category, filename, lineno, file=None, line=None):
"""Hook to write a warning to a file; replace if you like."""
msg = WarningMessage(message, category, filename, lineno, file, line)
_showwarnmsg_impl(msg)
def formatwarning(message, category, filename, lineno, line=None):
"""Function to format a warning the standard way."""
msg = WarningMessage(message, category, filename, lineno, None, line)
return _formatwarnmsg_impl(msg)
def _showwarnmsg_impl(msg):
file = msg.file
if file is None:
file = sys.stderr
if file is None:
# sys.stderr is None when run with pythonw.exe:
# warnings get lost
return
text = _formatwarnmsg(msg)
try:
file.write(text)
except OSError:
# the file (probably stderr) is invalid - this warning gets lost.
pass
def _formatwarnmsg_impl(msg):
s = ("%s:%s: %s: %s\n"
% (msg.filename, msg.lineno, msg.category.__name__,
msg.message))
if msg.line is None:
try:
import linecache
line = linecache.getline(msg.filename, msg.lineno)
except Exception:
# When a warning is logged during Python shutdown, linecache
# and the import machinery don't work anymore
line = None
linecache = None
else:
line = msg.line
if line:
line = line.strip()
s += " %s\n" % line
if msg.source is not None:
try:
import tracemalloc
tb = tracemalloc.get_object_traceback(msg.source)
except Exception:
# When a warning is logged during Python shutdown, tracemalloc
# and the import machinery don't work anymore
tb = None
if tb is not None:
s += 'Object allocated at (most recent call last):\n'
for frame in tb:
s += (' File "%s", lineno %s\n'
% (frame.filename, frame.lineno))
try:
if linecache is not None:
line = linecache.getline(frame.filename, frame.lineno)
else:
line = None
except Exception:
line = None
if line:
line = line.strip()
s += ' %s\n' % line
return s
# Keep a reference to check if the function was replaced
_showwarning_orig = showwarning
def _showwarnmsg(msg):
"""Hook to write a warning to a file; replace if you like."""
try:
sw = showwarning
except NameError:
pass
else:
if sw is not _showwarning_orig:
# warnings.showwarning() was replaced
if not callable(sw):
raise TypeError("warnings.showwarning() must be set to a "
"function or method")
sw(msg.message, msg.category, msg.filename, msg.lineno,
msg.file, msg.line)
return
_showwarnmsg_impl(msg)
# Keep a reference to check if the function was replaced
_formatwarning_orig = formatwarning
def _formatwarnmsg(msg):
"""Function to format a warning the standard way."""
try:
fw = formatwarning
except NameError:
pass
else:
if fw is not _formatwarning_orig:
# warnings.formatwarning() was replaced
return fw(msg.message, msg.category,
msg.filename, msg.lineno, line=msg.line)
return _formatwarnmsg_impl(msg)
def filterwarnings(action, message="", category=Warning, module="", lineno=0,
append=False):
"""Insert an entry into the list of warnings filters (at the front).
'action' -- one of "error", "ignore", "always", "default", "module",
or "once"
'message' -- a regex that the warning message must match
'category' -- a class that the warning must be a subclass of
'module' -- a regex that the module name must match
'lineno' -- an integer line number, 0 matches all warnings
'append' -- if true, append to the list of filters
"""
assert action in ("error", "ignore", "always", "default", "module",
"once"), "invalid action: %r" % (action,)
assert isinstance(message, str), "message must be a string"
assert isinstance(category, type), "category must be a class"
assert issubclass(category, Warning), "category must be a Warning subclass"
assert isinstance(module, str), "module must be a string"
assert isinstance(lineno, int) and lineno >= 0, \
"lineno must be an int >= 0"
if message or module:
import re
if message:
message = re.compile(message, re.I)
else:
message = None
if module:
module = re.compile(module)
else:
module = None
_add_filter(action, message, category, module, lineno, append=append)
def simplefilter(action, category=Warning, lineno=0, append=False):
"""Insert a simple entry into the list of warnings filters (at the front).
A simple filter matches all modules and messages.
'action' -- one of "error", "ignore", "always", "default", "module",
or "once"
'category' -- a class that the warning must be a subclass of
'lineno' -- an integer line number, 0 matches all warnings
'append' -- if true, append to the list of filters
"""
assert action in ("error", "ignore", "always", "default", "module",
"once"), "invalid action: %r" % (action,)
assert isinstance(lineno, int) and lineno >= 0, \
"lineno must be an int >= 0"
_add_filter(action, None, category, None, lineno, append=append)
def _add_filter(*item, append):
# Remove possible duplicate filters, so new one will be placed
# in correct place. If append=True and duplicate exists, do nothing.
if not append:
try:
filters.remove(item)
except ValueError:
pass
filters.insert(0, item)
else:
if item not in filters:
filters.append(item)
_filters_mutated()
def resetwarnings():
"""Clear the list of warning filters, so that no filters are active."""
filters[:] = []
_filters_mutated()
class _OptionError(Exception):
"""Exception used by option processing helpers."""
pass
# Helper to process -W options passed via sys.warnoptions
def _processoptions(args):
for arg in args:
try:
_setoption(arg)
except _OptionError as msg:
print("Invalid -W option ignored:", msg, file=sys.stderr)
# Helper for _processoptions()
def _setoption(arg):
import re
parts = arg.split(':')
if len(parts) > 5:
raise _OptionError("too many fields (max 5): %r" % (arg,))
while len(parts) < 5:
parts.append('')
action, message, category, module, lineno = [s.strip()
for s in parts]
action = _getaction(action)
message = re.escape(message)
category = _getcategory(category)
module = re.escape(module)
if module:
module = module + '$'
if lineno:
try:
lineno = int(lineno)
if lineno < 0:
raise ValueError
except (ValueError, OverflowError):
raise _OptionError("invalid lineno %r" % (lineno,)) from None
else:
lineno = 0
filterwarnings(action, message, category, module, lineno)
# Helper for _setoption()
def _getaction(action):
if not action:
return "default"
if action == "all": return "always" # Alias
for a in ('default', 'always', 'ignore', 'module', 'once', 'error'):
if a.startswith(action):
return a
raise _OptionError("invalid action: %r" % (action,))
# Helper for _setoption()
def _getcategory(category):
import re
if not category:
return Warning
if re.match("^[a-zA-Z0-9_]+$", category):
try:
cat = eval(category)
except NameError:
raise _OptionError("unknown warning category: %r" % (category,)) from None
else:
i = category.rfind(".")
module = category[:i]
klass = category[i+1:]
try:
m = __import__(module, None, None, [klass])
except ImportError:
raise _OptionError("invalid module name: %r" % (module,)) from None
try:
cat = getattr(m, klass)
except AttributeError:
raise _OptionError("unknown warning category: %r" % (category,)) from None
if not issubclass(cat, Warning):
raise _OptionError("invalid warning category: %r" % (category,))
return cat
def _is_internal_frame(frame):
"""Signal whether the frame is an internal CPython implementation detail."""
filename = frame.f_code.co_filename
return 'importlib' in filename and '_bootstrap' in filename
def _next_external_frame(frame):
"""Find the next frame that doesn't involve CPython internals."""
frame = frame.f_back
while frame is not None and _is_internal_frame(frame):
frame = frame.f_back
return frame
# Code typically replaced by _warnings
def warn(message, category=None, stacklevel=1, source=None):
"""Issue a warning, or maybe ignore it or raise an exception."""
# Check if message is already a Warning object
if isinstance(message, Warning):
category = message.__class__
# Check category argument
if category is None:
category = UserWarning
if not (isinstance(category, type) and issubclass(category, Warning)):
raise TypeError("category must be a Warning subclass, "
"not '{:s}'".format(type(category).__name__))
# Get context information
try:
if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)):
# If frame is too small to care or if the warning originated in
# internal code, then do not try to hide any frames.
frame = sys._getframe(stacklevel)
else:
frame = sys._getframe(1)
# Look for one frame less since the above line starts us off.
for x in range(stacklevel-1):
frame = _next_external_frame(frame)
if frame is None:
raise ValueError
except ValueError:
globals = sys.__dict__
lineno = 1
else:
globals = frame.f_globals
lineno = frame.f_lineno
if '__name__' in globals:
module = globals['__name__']
else:
module = "<string>"
filename = globals.get('__file__')
if filename:
fnl = filename.lower()
if fnl.endswith(".pyc"):
filename = filename[:-1]
else:
if module == "__main__":
try:
filename = sys.argv[0]
except AttributeError:
# embedded interpreters don't have sys.argv, see bug #839151
filename = '__main__'
if not filename:
filename = module
registry = globals.setdefault("__warningregistry__", {})
warn_explicit(message, category, filename, lineno, module, registry,
globals, source)
def warn_explicit(message, category, filename, lineno,
module=None, registry=None, module_globals=None,
source=None):
lineno = int(lineno)
if module is None:
module = filename or "<unknown>"
if module[-3:].lower() == ".py":
module = module[:-3] # XXX What about leading pathname?
if registry is None:
registry = {}
if registry.get('version', 0) != _filters_version:
registry.clear()
registry['version'] = _filters_version
if isinstance(message, Warning):
text = str(message)
category = message.__class__
else:
text = message
message = category(message)
key = (text, category, lineno)
# Quick test for common case
if registry.get(key):
return
# Search the filters
for item in filters:
action, msg, cat, mod, ln = item
if ((msg is None or msg.match(text)) and
issubclass(category, cat) and
(mod is None or mod.match(module)) and
(ln == 0 or lineno == ln)):
break
else:
action = defaultaction
# Early exit actions
if action == "ignore":
return
# Prime the linecache for formatting, in case the
# "file" is actually in a zipfile or something.
import linecache
linecache.getlines(filename, module_globals)
if action == "error":
raise message
# Other actions
if action == "once":
registry[key] = 1
oncekey = (text, category)
if onceregistry.get(oncekey):
return
onceregistry[oncekey] = 1
elif action == "always":
pass
elif action == "module":
registry[key] = 1
altkey = (text, category, 0)
if registry.get(altkey):
return
registry[altkey] = 1
elif action == "default":
registry[key] = 1
else:
# Unrecognized actions are errors
raise RuntimeError(
"Unrecognized action (%r) in warnings.filters:\n %s" %
(action, item))
# Print message and context
msg = WarningMessage(message, category, filename, lineno, source)
_showwarnmsg(msg)
class WarningMessage(object):
_WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
"line", "source")
def __init__(self, message, category, filename, lineno, file=None,
line=None, source=None):
self.message = message
self.category = category
self.filename = filename
self.lineno = lineno
self.file = file
self.line = line
self.source = source
self._category_name = category.__name__ if category else None
def __str__(self):
return ("{message : %r, category : %r, filename : %r, lineno : %s, "
"line : %r}" % (self.message, self._category_name,
self.filename, self.lineno, self.line))
class catch_warnings(object):
"""A context manager that copies and restores the warnings filter upon
exiting the context.
The 'record' argument specifies whether warnings should be captured by a
custom implementation of warnings.showwarning() and be appended to a list
returned by the context manager. Otherwise None is returned by the context
manager. The objects appended to the list are arguments whose attributes
mirror the arguments to showwarning().
The 'module' argument is to specify an alternative module to the module
named 'warnings' and imported under that name. This argument is only useful
when testing the warnings module itself.
"""
def __init__(self, *, record=False, module=None):
"""Specify whether to record warnings and if an alternative module
should be used other than sys.modules['warnings'].
For compatibility with Python 3.0, please consider all arguments to be
keyword-only.
"""
self._record = record
self._module = sys.modules['warnings'] if module is None else module
self._entered = False
def __repr__(self):
args = []
if self._record:
args.append("record=True")
if self._module is not sys.modules['warnings']:
args.append("module=%r" % self._module)
name = type(self).__name__
return "%s(%s)" % (name, ", ".join(args))
def __enter__(self):
if self._entered:
raise RuntimeError("Cannot enter %r twice" % self)
self._entered = True
self._filters = self._module.filters
self._module.filters = self._filters[:]
self._module._filters_mutated()
self._showwarning = self._module.showwarning
self._showwarnmsg_impl = self._module._showwarnmsg_impl
if self._record:
log = []
self._module._showwarnmsg_impl = log.append
# Reset showwarning() to the default implementation to make sure
# that _showwarnmsg() calls _showwarnmsg_impl()
self._module.showwarning = self._module._showwarning_orig
return log
else:
return None
def __exit__(self, *exc_info):
if not self._entered:
raise RuntimeError("Cannot exit %r without entering first" % self)
self._module.filters = self._filters
self._module._filters_mutated()
self._module.showwarning = self._showwarning
self._module._showwarnmsg_impl = self._showwarnmsg_impl
# Private utility function called by _PyErr_WarnUnawaitedCoroutine
def _warn_unawaited_coroutine(coro):
msg_lines = [
f"coroutine '{coro.__qualname__}' was never awaited\n"
]
if coro.cr_origin is not None:
import linecache, traceback
def extract():
for filename, lineno, funcname in reversed(coro.cr_origin):
line = linecache.getline(filename, lineno)
yield (filename, lineno, funcname, line)
msg_lines.append("Coroutine created at (most recent call last)\n")
msg_lines += traceback.format_list(list(extract()))
msg = "".join(msg_lines).rstrip("\n")
# Passing source= here means that if the user happens to have tracemalloc
# enabled and tracking where the coroutine was created, the warning will
# contain that traceback. This does mean that if they have *both*
# coroutine origin tracking *and* tracemalloc enabled, they'll get two
# partially-redundant tracebacks. If we wanted to be clever we could
# probably detect this case and avoid it, but for now we don't bother.
warn(msg, category=RuntimeWarning, stacklevel=2, source=coro)
# filters contains a sequence of filter 5-tuples
# The components of the 5-tuple are:
# - an action: error, ignore, always, default, module, or once
# - a compiled regex that must match the warning message
# - a class representing the warning category
# - a compiled regex that must match the module that is being warned
# - a line number for the line being warning, or 0 to mean any line
# If either if the compiled regexs are None, match anything.
try:
from _warnings import (filters, _defaultaction, _onceregistry,
warn, warn_explicit, _filters_mutated)
defaultaction = _defaultaction
onceregistry = _onceregistry
_warnings_defaults = True
except ImportError:
filters = []
defaultaction = "default"
onceregistry = {}
_filters_version = 1
def _filters_mutated():
global _filters_version
_filters_version += 1
_warnings_defaults = False
# Module initialization
_processoptions(sys.warnoptions)
if not _warnings_defaults:
# Several warning categories are ignored by default in regular builds
if not hasattr(sys, 'gettotalrefcount'):
filterwarnings("default", category=DeprecationWarning,
module="__main__", append=1)
simplefilter("ignore", category=DeprecationWarning, append=1)
simplefilter("ignore", category=PendingDeprecationWarning, append=1)
simplefilter("ignore", category=ImportWarning, append=1)
simplefilter("ignore", category=ResourceWarning, append=1)
del _warnings_defaults

632
Lib/weakref.py Normal file
View File

@@ -0,0 +1,632 @@
"""Weak reference support for Python.
This module is an implementation of PEP 205:
http://www.python.org/dev/peps/pep-0205/
"""
# Naming convention: Variables named "wr" are weak reference objects;
# they are called this instead of "ref" to avoid name collisions with
# the module-global ref() function imported from _weakref.
from _weakref import (
getweakrefcount,
getweakrefs,
ref,
proxy,
CallableProxyType,
ProxyType,
ReferenceType,
_remove_dead_weakref)
from _weakrefset import WeakSet, _IterationGuard
import _collections_abc # Import after _weakref to avoid circular import.
import sys
import itertools
ProxyTypes = (ProxyType, CallableProxyType)
__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
"WeakKeyDictionary", "ReferenceType", "ProxyType",
"CallableProxyType", "ProxyTypes", "WeakValueDictionary",
"WeakSet", "WeakMethod", "finalize"]
class WeakMethod(ref):
"""
A custom `weakref.ref` subclass which simulates a weak reference to
a bound method, working around the lifetime problem of bound methods.
"""
__slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
def __new__(cls, meth, callback=None):
try:
obj = meth.__self__
func = meth.__func__
except AttributeError:
raise TypeError("argument should be a bound method, not {}"
.format(type(meth))) from None
def _cb(arg):
# The self-weakref trick is needed to avoid creating a reference
# cycle.
self = self_wr()
if self._alive:
self._alive = False
if callback is not None:
callback(self)
self = ref.__new__(cls, obj, _cb)
self._func_ref = ref(func, _cb)
self._meth_type = type(meth)
self._alive = True
self_wr = ref(self)
return self
def __call__(self):
obj = super().__call__()
func = self._func_ref()
if obj is None or func is None:
return None
return self._meth_type(func, obj)
def __eq__(self, other):
if isinstance(other, WeakMethod):
if not self._alive or not other._alive:
return self is other
return ref.__eq__(self, other) and self._func_ref == other._func_ref
return False
def __ne__(self, other):
if isinstance(other, WeakMethod):
if not self._alive or not other._alive:
return self is not other
return ref.__ne__(self, other) or self._func_ref != other._func_ref
return True
__hash__ = ref.__hash__
class WeakValueDictionary(_collections_abc.MutableMapping):
"""Mapping class that references values weakly.
Entries in the dictionary will be discarded when no strong
reference to the value exists anymore
"""
# We inherit the constructor without worrying about the input
# dictionary; since it uses our .update() method, we get the right
# checks (if the other dictionary is a WeakValueDictionary,
# objects are unwrapped on the way out, and we always wrap on the
# way in).
def __init__(*args, **kw):
if not args:
raise TypeError("descriptor '__init__' of 'WeakValueDictionary' "
"object needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(wr.key)
else:
# Atomic removal is necessary since this function
# can be called asynchronously by the GC
_atomic_removal(d, wr.key)
self._remove = remove
# A list of keys to be removed
self._pending_removals = []
self._iterating = set()
self.data = d = {}
self.update(*args, **kw)
def _commit_removals(self):
l = self._pending_removals
d = self.data
# We shouldn't encounter any KeyError, because this method should
# always be called *before* mutating the dict.
while l:
key = l.pop()
_remove_dead_weakref(d, key)
def __getitem__(self, key):
if self._pending_removals:
self._commit_removals()
o = self.data[key]()
if o is None:
raise KeyError(key)
else:
return o
def __delitem__(self, key):
if self._pending_removals:
self._commit_removals()
del self.data[key]
def __len__(self):
if self._pending_removals:
self._commit_removals()
return len(self.data)
def __contains__(self, key):
if self._pending_removals:
self._commit_removals()
try:
o = self.data[key]()
except KeyError:
return False
return o is not None
def __repr__(self):
return "<%s at %#x>" % (self.__class__.__name__, id(self))
def __setitem__(self, key, value):
if self._pending_removals:
self._commit_removals()
self.data[key] = KeyedRef(value, self._remove, key)
def copy(self):
if self._pending_removals:
self._commit_removals()
new = WeakValueDictionary()
for key, wr in self.data.items():
o = wr()
if o is not None:
new[key] = o
return new
__copy__ = copy
def __deepcopy__(self, memo):
from copy import deepcopy
if self._pending_removals:
self._commit_removals()
new = self.__class__()
for key, wr in self.data.items():
o = wr()
if o is not None:
new[deepcopy(key, memo)] = o
return new
def get(self, key, default=None):
if self._pending_removals:
self._commit_removals()
try:
wr = self.data[key]
except KeyError:
return default
else:
o = wr()
if o is None:
# This should only happen
return default
else:
return o
def items(self):
if self._pending_removals:
self._commit_removals()
with _IterationGuard(self):
for k, wr in self.data.items():
v = wr()
if v is not None:
yield k, v
def keys(self):
if self._pending_removals:
self._commit_removals()
with _IterationGuard(self):
for k, wr in self.data.items():
if wr() is not None:
yield k
__iter__ = keys
def itervaluerefs(self):
"""Return an iterator that yields the weak references to the values.
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used. This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
"""
if self._pending_removals:
self._commit_removals()
with _IterationGuard(self):
yield from self.data.values()
def values(self):
if self._pending_removals:
self._commit_removals()
with _IterationGuard(self):
for wr in self.data.values():
obj = wr()
if obj is not None:
yield obj
def popitem(self):
if self._pending_removals:
self._commit_removals()
while True:
key, wr = self.data.popitem()
o = wr()
if o is not None:
return key, o
def pop(self, key, *args):
if self._pending_removals:
self._commit_removals()
try:
o = self.data.pop(key)()
except KeyError:
o = None
if o is None:
if args:
return args[0]
else:
raise KeyError(key)
else:
return o
def setdefault(self, key, default=None):
try:
o = self.data[key]()
except KeyError:
o = None
if o is None:
if self._pending_removals:
self._commit_removals()
self.data[key] = KeyedRef(default, self._remove, key)
return default
else:
return o
def update(*args, **kwargs):
if not args:
raise TypeError("descriptor 'update' of 'WeakValueDictionary' "
"object needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
dict = args[0] if args else None
if self._pending_removals:
self._commit_removals()
d = self.data
if dict is not None:
if not hasattr(dict, "items"):
dict = type({})(dict)
for key, o in dict.items():
d[key] = KeyedRef(o, self._remove, key)
if len(kwargs):
self.update(kwargs)
def valuerefs(self):
"""Return a list of weak references to the values.
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used. This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
"""
if self._pending_removals:
self._commit_removals()
return list(self.data.values())
class KeyedRef(ref):
"""Specialized reference that includes a key corresponding to the value.
This is used in the WeakValueDictionary to avoid having to create
a function object for each key stored in the mapping. A shared
callback object can use the 'key' attribute of a KeyedRef instead
of getting a reference to the key from an enclosing scope.
"""
__slots__ = "key",
def __new__(type, ob, callback, key):
self = ref.__new__(type, ob, callback)
self.key = key
return self
def __init__(self, ob, callback, key):
super().__init__(ob, callback)
class WeakKeyDictionary(_collections_abc.MutableMapping):
""" Mapping class that references keys weakly.
Entries in the dictionary will be discarded when there is no
longer a strong reference to the key. This can be used to
associate additional data with an object owned by other parts of
an application without adding attributes to those objects. This
can be especially useful with objects that override attribute
accesses.
"""
def __init__(self, dict=None):
self.data = {}
def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove
# A list of dead weakrefs (keys to be removed)
self._pending_removals = []
self._iterating = set()
self._dirty_len = False
if dict is not None:
self.update(dict)
def _commit_removals(self):
# NOTE: We don't need to call this method before mutating the dict,
# because a dead weakref never compares equal to a live weakref,
# even if they happened to refer to equal objects.
# However, it means keys may already have been removed.
l = self._pending_removals
d = self.data
while l:
try:
del d[l.pop()]
except KeyError:
pass
def _scrub_removals(self):
d = self.data
self._pending_removals = [k for k in self._pending_removals if k in d]
self._dirty_len = False
def __delitem__(self, key):
self._dirty_len = True
del self.data[ref(key)]
def __getitem__(self, key):
return self.data[ref(key)]
def __len__(self):
if self._dirty_len and self._pending_removals:
# self._pending_removals may still contain keys which were
# explicitly removed, we have to scrub them (see issue #21173).
self._scrub_removals()
return len(self.data) - len(self._pending_removals)
def __repr__(self):
return "<%s at %#x>" % (self.__class__.__name__, id(self))
def __setitem__(self, key, value):
self.data[ref(key, self._remove)] = value
def copy(self):
new = WeakKeyDictionary()
for key, value in self.data.items():
o = key()
if o is not None:
new[o] = value
return new
__copy__ = copy
def __deepcopy__(self, memo):
from copy import deepcopy
new = self.__class__()
for key, value in self.data.items():
o = key()
if o is not None:
new[o] = deepcopy(value, memo)
return new
def get(self, key, default=None):
return self.data.get(ref(key),default)
def __contains__(self, key):
try:
wr = ref(key)
except TypeError:
return False
return wr in self.data
def items(self):
with _IterationGuard(self):
for wr, value in self.data.items():
key = wr()
if key is not None:
yield key, value
def keys(self):
with _IterationGuard(self):
for wr in self.data:
obj = wr()
if obj is not None:
yield obj
__iter__ = keys
def values(self):
with _IterationGuard(self):
for wr, value in self.data.items():
if wr() is not None:
yield value
def keyrefs(self):
"""Return a list of weak references to the keys.
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used. This can be used to avoid
creating references that will cause the garbage collector to
keep the keys around longer than needed.
"""
return list(self.data)
def popitem(self):
self._dirty_len = True
while True:
key, value = self.data.popitem()
o = key()
if o is not None:
return o, value
def pop(self, key, *args):
self._dirty_len = True
return self.data.pop(ref(key), *args)
def setdefault(self, key, default=None):
return self.data.setdefault(ref(key, self._remove),default)
def update(self, dict=None, **kwargs):
d = self.data
if dict is not None:
if not hasattr(dict, "items"):
dict = type({})(dict)
for key, value in dict.items():
d[ref(key, self._remove)] = value
if len(kwargs):
self.update(kwargs)
class finalize:
"""Class for finalization of weakrefable objects
finalize(obj, func, *args, **kwargs) returns a callable finalizer
object which will be called when obj is garbage collected. The
first time the finalizer is called it evaluates func(*arg, **kwargs)
and returns the result. After this the finalizer is dead, and
calling it just returns None.
When the program exits any remaining finalizers for which the
atexit attribute is true will be run in reverse order of creation.
By default atexit is true.
"""
# Finalizer objects don't have any state of their own. They are
# just used as keys to lookup _Info objects in the registry. This
# ensures that they cannot be part of a ref-cycle.
__slots__ = ()
_registry = {}
_shutdown = False
_index_iter = itertools.count()
_dirty = False
_registered_with_atexit = False
class _Info:
__slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
def __init__(self, obj, func, *args, **kwargs):
if not self._registered_with_atexit:
# We may register the exit function more than once because
# of a thread race, but that is harmless
import atexit
atexit.register(self._exitfunc)
finalize._registered_with_atexit = True
info = self._Info()
info.weakref = ref(obj, self)
info.func = func
info.args = args
info.kwargs = kwargs or None
info.atexit = True
info.index = next(self._index_iter)
self._registry[self] = info
finalize._dirty = True
def __call__(self, _=None):
"""If alive then mark as dead and return func(*args, **kwargs);
otherwise return None"""
info = self._registry.pop(self, None)
if info and not self._shutdown:
return info.func(*info.args, **(info.kwargs or {}))
def detach(self):
"""If alive then mark as dead and return (obj, func, args, kwargs);
otherwise return None"""
info = self._registry.get(self)
obj = info and info.weakref()
if obj is not None and self._registry.pop(self, None):
return (obj, info.func, info.args, info.kwargs or {})
def peek(self):
"""If alive then return (obj, func, args, kwargs);
otherwise return None"""
info = self._registry.get(self)
obj = info and info.weakref()
if obj is not None:
return (obj, info.func, info.args, info.kwargs or {})
@property
def alive(self):
"""Whether finalizer is alive"""
return self in self._registry
@property
def atexit(self):
"""Whether finalizer should be called at exit"""
info = self._registry.get(self)
return bool(info) and info.atexit
@atexit.setter
def atexit(self, value):
info = self._registry.get(self)
if info:
info.atexit = bool(value)
def __repr__(self):
info = self._registry.get(self)
obj = info and info.weakref()
if obj is None:
return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
else:
return '<%s object at %#x; for %r at %#x>' % \
(type(self).__name__, id(self), type(obj).__name__, id(obj))
@classmethod
def _select_for_exit(cls):
# Return live finalizers marked for exit, oldest first
L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
L.sort(key=lambda item:item[1].index)
return [f for (f,i) in L]
@classmethod
def _exitfunc(cls):
# At shutdown invoke finalizers for which atexit is true.
# This is called once all other non-daemonic threads have been
# joined.
reenable_gc = False
try:
if cls._registry:
import gc
if gc.isenabled():
reenable_gc = True
gc.disable()
pending = None
while True:
if pending is None or finalize._dirty:
pending = cls._select_for_exit()
finalize._dirty = False
if not pending:
break
f = pending.pop()
try:
# gc is disabled, so (assuming no daemonic
# threads) the following is the only line in
# this function which might trigger creation
# of a new finalizer
f()
except Exception:
sys.excepthook(*sys.exc_info())
assert f not in cls._registry
finally:
# prevent any more finalizers from executing during shutdown
finalize._shutdown = True
if reenable_gc:
gc.enable()

241
Lib/xdrlib.py Normal file
View File

@@ -0,0 +1,241 @@
"""Implements (a subset of) Sun XDR -- eXternal Data Representation.
See: RFC 1014
"""
import struct
from io import BytesIO
from functools import wraps
__all__ = ["Error", "Packer", "Unpacker", "ConversionError"]
# exceptions
class Error(Exception):
"""Exception class for this module. Use:
except xdrlib.Error as var:
# var has the Error instance for the exception
Public ivars:
msg -- contains the message
"""
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return repr(self.msg)
def __str__(self):
return str(self.msg)
class ConversionError(Error):
pass
def raise_conversion_error(function):
""" Wrap any raised struct.errors in a ConversionError. """
@wraps(function)
def result(self, value):
try:
return function(self, value)
except struct.error as e:
raise ConversionError(e.args[0]) from None
return result
class Packer:
"""Pack various data representations into a buffer."""
def __init__(self):
self.reset()
def reset(self):
self.__buf = BytesIO()
def get_buffer(self):
return self.__buf.getvalue()
# backwards compatibility
get_buf = get_buffer
@raise_conversion_error
def pack_uint(self, x):
self.__buf.write(struct.pack('>L', x))
@raise_conversion_error
def pack_int(self, x):
self.__buf.write(struct.pack('>l', x))
pack_enum = pack_int
def pack_bool(self, x):
if x: self.__buf.write(b'\0\0\0\1')
else: self.__buf.write(b'\0\0\0\0')
def pack_uhyper(self, x):
try:
self.pack_uint(x>>32 & 0xffffffff)
except (TypeError, struct.error) as e:
raise ConversionError(e.args[0]) from None
try:
self.pack_uint(x & 0xffffffff)
except (TypeError, struct.error) as e:
raise ConversionError(e.args[0]) from None
pack_hyper = pack_uhyper
@raise_conversion_error
def pack_float(self, x):
self.__buf.write(struct.pack('>f', x))
@raise_conversion_error
def pack_double(self, x):
self.__buf.write(struct.pack('>d', x))
def pack_fstring(self, n, s):
if n < 0:
raise ValueError('fstring size must be nonnegative')
data = s[:n]
n = ((n+3)//4)*4
data = data + (n - len(data)) * b'\0'
self.__buf.write(data)
pack_fopaque = pack_fstring
def pack_string(self, s):
n = len(s)
self.pack_uint(n)
self.pack_fstring(n, s)
pack_opaque = pack_string
pack_bytes = pack_string
def pack_list(self, list, pack_item):
for item in list:
self.pack_uint(1)
pack_item(item)
self.pack_uint(0)
def pack_farray(self, n, list, pack_item):
if len(list) != n:
raise ValueError('wrong array size')
for item in list:
pack_item(item)
def pack_array(self, list, pack_item):
n = len(list)
self.pack_uint(n)
self.pack_farray(n, list, pack_item)
class Unpacker:
"""Unpacks various data representations from the given buffer."""
def __init__(self, data):
self.reset(data)
def reset(self, data):
self.__buf = data
self.__pos = 0
def get_position(self):
return self.__pos
def set_position(self, position):
self.__pos = position
def get_buffer(self):
return self.__buf
def done(self):
if self.__pos < len(self.__buf):
raise Error('unextracted data remains')
def unpack_uint(self):
i = self.__pos
self.__pos = j = i+4
data = self.__buf[i:j]
if len(data) < 4:
raise EOFError
return struct.unpack('>L', data)[0]
def unpack_int(self):
i = self.__pos
self.__pos = j = i+4
data = self.__buf[i:j]
if len(data) < 4:
raise EOFError
return struct.unpack('>l', data)[0]
unpack_enum = unpack_int
def unpack_bool(self):
return bool(self.unpack_int())
def unpack_uhyper(self):
hi = self.unpack_uint()
lo = self.unpack_uint()
return int(hi)<<32 | lo
def unpack_hyper(self):
x = self.unpack_uhyper()
if x >= 0x8000000000000000:
x = x - 0x10000000000000000
return x
def unpack_float(self):
i = self.__pos
self.__pos = j = i+4
data = self.__buf[i:j]
if len(data) < 4:
raise EOFError
return struct.unpack('>f', data)[0]
def unpack_double(self):
i = self.__pos
self.__pos = j = i+8
data = self.__buf[i:j]
if len(data) < 8:
raise EOFError
return struct.unpack('>d', data)[0]
def unpack_fstring(self, n):
if n < 0:
raise ValueError('fstring size must be nonnegative')
i = self.__pos
j = i + (n+3)//4*4
if j > len(self.__buf):
raise EOFError
self.__pos = j
return self.__buf[i:i+n]
unpack_fopaque = unpack_fstring
def unpack_string(self):
n = self.unpack_uint()
return self.unpack_fstring(n)
unpack_opaque = unpack_string
unpack_bytes = unpack_string
def unpack_list(self, unpack_item):
list = []
while 1:
x = self.unpack_uint()
if x == 0: break
if x != 1:
raise ConversionError('0 or 1 expected, got %r' % (x,))
item = unpack_item()
list.append(item)
return list
def unpack_farray(self, n, unpack_item):
list = []
for i in range(n):
list.append(unpack_item())
return list
def unpack_array(self, unpack_item):
n = self.unpack_uint()
return self.unpack_farray(n, unpack_item)

104
README.md
View File

@@ -1,3 +1,5 @@
<img src="./logo.png" width="125" height="125" align="right" />
# RustPython
A Python-3 (CPython >= 3.5.0) Interpreter written in Rust :snake: :scream: :metal:.
@@ -83,7 +85,7 @@ Another approach is to checkout the source code: builtin functions and object me
and easiest way to contribute.
You can also simply run
`cargo run tests/snippets/whats_left_to_implement.py` to assist in finding any
`./whats_left.sh` to assist in finding any
unimplemented method.
# Testing
@@ -103,104 +105,40 @@ There also are some unit tests, you can run those with cargo:
$ cargo test --all
```
# Using another standard library
# Using a standard library
As of now the standard library is under construction.
As of now the standard library is under construction. You can
use a standard library by setting the RUSTPYTHONPATH environment
variable.
To do this, follow this method:
```shell
$ export RUSTPYTHONPATH=~/GIT/RustPython/Lib
$ cargo run -- -c 'import xdrlib'
```
You can play around
with other standard libraries for python. For example,
the [ouroboros library](https://github.com/pybee/ouroboros).
To do this, follow this method:
```shell
$ cd ~/GIT
$ git clone git@github.com:pybee/ouroboros.git
$ export PYTHONPATH=~/GIT/ouroboros/ouroboros
$ cd RustPython
$ cargo run -- -c 'import statistics'
```
# Compiling to WebAssembly
At this stage RustPython only has preliminary support for web assembly. The instructions here are intended for developers or those wishing to run a toy example.
## Setup
To get started, install [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) and `npm`. ([wasm-bindgen](https://rustwasm.github.io/wasm-bindgen/whirlwind-tour/basic-usage.html) should be installed by `wasm-pack`. if not, install it yourself)
<!-- Using `rustup` add the compile target `wasm32-unknown-emscripten`. To do so you will need to have [rustup](https://rustup.rs/) installed.
```bash
rustup target add wasm32-unknown-emscripten
```
Next, install `emsdk`:
```bash
curl https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | tar -zxv
cd emsdk-portable/
./emsdk update
./emsdk install sdk-incoming-64bit
./emsdk activate sdk-incoming-64bit
``` -->
## Build
Move into the `wasm` directory. This directory contains a library crate for interop
with python to rust to js and back in `wasm/lib`, the demo website found at
https://rustpython.github.io/demo in `wasm/demo`, and an example of how to use
the crate as a library in one's own JS app in `wasm/example`.
```sh
cd wasm
```
Go to the demo directory. This is the best way of seeing the changes made to either
the library or the JS demo, as the `rustpython_wasm` module is set to the global
JS variable `rp` on the website.
```sh
cd demo
```
Now, start the webpack development server. It'll compile the crate and then
the demo app. This will likely take a long time, both the wasm-pack portion and
the webpack portion (from after it says "Your crate has been correctly compiled"),
so be patient.
```sh
npm run dev
```
You can now open the webpage on https://localhost:8080 and Python code in either
the text box or browser devtools with:
```js
rp.pyEval(
`
print(js_vars['a'] * 9)
`,
{
vars: {
a: 9
}
}
);
```
Alternatively, you can run `npm run build` to build the app once, without watching
for changes, or `npm run dist` to build the app in release mode, both for the
crate and webpack.
[See this doc](wasm/README.md)
# Code style
The code style used is the default rustfmt codestyle. Please format your code accordingly.
The code style used is the default [rustfmt](https://github.com/rust-lang/rustfmt) codestyle. Please format your code accordingly.
We also use [clippy](https://github.com/rust-lang/rust-clippy) to detect rust code issues.
# Community
Chat with us on [gitter][gitter].
# Code of conduct
Our code of conduct [can be found here](code-of-conduct.md).
# Credit
The initial work was based on [windelbouwman/rspython](https://github.com/windelbouwman/rspython) and [shinglyu/RustPython](https://github.com/shinglyu/RustPython)

View File

@@ -8,8 +8,8 @@ jobs:
vmImage: 'vs2017-win2016'
strategy:
matrix:
Python37:
python.version: '3.7'
Python36:
python.version: '3.6'
maxParallel: 10
steps:

19
benchmarks/README.md Normal file
View File

@@ -0,0 +1,19 @@
# Benchmarking
These are some files to determine performance of rustpython.
# Usage
Install pytest and pytest-benchmark:
$ pip install pytest-benchmark
Then run:
$ pytest
# Benchmark source
- https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/nbody-python3-2.html

125
benchmarks/bench.rs Normal file
View File

@@ -0,0 +1,125 @@
#![feature(test)]
extern crate cpython;
extern crate rustpython_parser;
extern crate rustpython_vm;
extern crate test;
use rustpython_vm::pyobject::PyResult;
use rustpython_vm::{compile, VirtualMachine};
#[bench]
fn bench_tokenization(b: &mut test::Bencher) {
use rustpython_parser::lexer::{make_tokenizer, Tok};
let source = include_str!("./benchmarks/minidom.py");
b.bytes = source.len() as _;
b.iter(|| {
let lexer = make_tokenizer(source);
for res in lexer {
let _token: Tok = res.unwrap().1;
}
})
}
#[bench]
fn bench_rustpy_parse_to_ast(b: &mut test::Bencher) {
use rustpython_parser::parser::parse_program;
let source = include_str!("./benchmarks/minidom.py");
b.bytes = source.len() as _;
b.iter(|| parse_program(source).unwrap())
}
#[bench]
fn bench_cpython_parse_to_ast(b: &mut test::Bencher) {
let source = include_str!("./benchmarks/minidom.py");
let gil = cpython::Python::acquire_gil();
let python = gil.python();
let globals = None;
let locals = cpython::PyDict::new(python);
locals.set_item(python, "SOURCE_CODE", source).unwrap();
let code = "compile(SOURCE_CODE, mode=\"exec\", filename=\"minidom.py\")";
b.bytes = source.len() as _;
b.iter(|| {
let res: cpython::PyResult<cpython::PyObject> = python.eval(code, globals, Some(&locals));
assert!(res.is_ok());
})
}
#[bench]
fn bench_cpython_nbody(b: &mut test::Bencher) {
let source = include_str!("./benchmarks/nbody.py");
let gil = cpython::Python::acquire_gil();
let python = gil.python();
let globals = None;
let locals = None;
b.iter(|| {
let res: cpython::PyResult<()> = python.run(source, globals, locals);
assert!(res.is_ok());
})
}
#[bench]
fn bench_cpython_mandelbrot(b: &mut test::Bencher) {
let source = include_str!("./benchmarks/mandelbrot.py");
let gil = cpython::Python::acquire_gil();
let python = gil.python();
let globals = None;
let locals = None;
b.iter(|| {
let res: cpython::PyResult<()> = python.run(source, globals, locals);
assert!(res.is_ok());
})
}
#[bench]
fn bench_rustpy_nbody(b: &mut test::Bencher) {
// NOTE: Take long time.
let source = include_str!("./benchmarks/nbody.py");
let vm = VirtualMachine::new();
let code = match vm.compile(source, &compile::Mode::Single, "<stdin>".to_string()) {
Ok(code) => code,
Err(e) => panic!("{:?}", e),
};
b.iter(|| {
let scope = vm.new_scope_with_builtins();
let res: PyResult = vm.run_code_obj(code.clone(), scope);
assert!(res.is_ok());
})
}
#[bench]
fn bench_rustpy_mandelbrot(b: &mut test::Bencher) {
// NOTE: Take long time.
let source = include_str!("./benchmarks/mandelbrot.py");
let vm = VirtualMachine::new();
let code = match vm.compile(source, &compile::Mode::Single, "<stdin>".to_string()) {
Ok(code) => code,
Err(e) => panic!("{:?}", e),
};
b.iter(|| {
let scope = vm.new_scope_with_builtins();
let res: PyResult = vm.run_code_obj(code.clone(), scope);
assert!(res.is_ok());
})
}

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# coding: utf-8
w = 50.0
h = 50.0
y = 0.0
while y < h:
x = 0.0
while x < w:
Zr, Zi, Tr, Ti = 0.0, 0.0, 0.0, 0.0
Cr = 2*x/w - 1.5
Ci = 2*y/h - 1.0
i = 0
while i < 50 and Tr+Ti <= 4:
Zi = 2*Zr*Zi + Ci
Zr = Tr - Ti + Cr
Tr = Zr * Zr
Ti = Zi * Zi
i = i+1
if Tr+Ti <= 4:
# print('*', end='')
pass
else:
# print('·', end='')
pass
x = x+1
# print()
y = y+1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
# The Computer Language Benchmarks Game
# https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
#
# originally by Kevin Carson
# modified by Tupteq, Fredrik Johansson, and Daniel Nanz
# modified by Maciej Fijalkowski
# 2to3
# modified by Andriy Misyura
from math import sqrt
def combinations(l):
result = []
for x in range(len(l) - 1):
ls = l[x+1:]
for y in ls:
result.append((l[x][0],l[x][1],l[x][2],y[0],y[1],y[2]))
return result
PI = 3.14159265358979323
SOLAR_MASS = 4 * PI * PI
DAYS_PER_YEAR = 365.24
BODIES = {
'sun': ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS),
'jupiter': ([4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01],
[1.66007664274403694e-03 * DAYS_PER_YEAR,
7.69901118419740425e-03 * DAYS_PER_YEAR,
-6.90460016972063023e-05 * DAYS_PER_YEAR],
9.54791938424326609e-04 * SOLAR_MASS),
'saturn': ([8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01],
[-2.76742510726862411e-03 * DAYS_PER_YEAR,
4.99852801234917238e-03 * DAYS_PER_YEAR,
2.30417297573763929e-05 * DAYS_PER_YEAR],
2.85885980666130812e-04 * SOLAR_MASS),
'uranus': ([1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01],
[2.96460137564761618e-03 * DAYS_PER_YEAR,
2.37847173959480950e-03 * DAYS_PER_YEAR,
-2.96589568540237556e-05 * DAYS_PER_YEAR],
4.36624404335156298e-05 * SOLAR_MASS),
'neptune': ([1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01],
[2.68067772490389322e-03 * DAYS_PER_YEAR,
1.62824170038242295e-03 * DAYS_PER_YEAR,
-9.51592254519715870e-05 * DAYS_PER_YEAR],
5.15138902046611451e-05 * SOLAR_MASS) }
SYSTEM = tuple(BODIES.values())
PAIRS = tuple(combinations(SYSTEM))
def advance(dt, n, bodies=SYSTEM, pairs=PAIRS):
for i in range(n):
for ([x1, y1, z1], v1, m1, [x2, y2, z2], v2, m2) in pairs:
dx = x1 - x2
dy = y1 - y2
dz = z1 - z2
dist = sqrt(dx * dx + dy * dy + dz * dz);
mag = dt / (dist*dist*dist)
b1m = m1 * mag
b2m = m2 * mag
v1[0] -= dx * b2m
v1[1] -= dy * b2m
v1[2] -= dz * b2m
v2[2] += dz * b1m
v2[1] += dy * b1m
v2[0] += dx * b1m
for (r, [vx, vy, vz], m) in bodies:
r[0] += dt * vx
r[1] += dt * vy
r[2] += dt * vz
def report_energy(bodies=SYSTEM, pairs=PAIRS, e=0.0):
for ((x1, y1, z1), v1, m1, (x2, y2, z2), v2, m2) in pairs:
dx = x1 - x2
dy = y1 - y2
dz = z1 - z2
e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5)
for (r, [vx, vy, vz], m) in bodies:
e += m * (vx * vx + vy * vy + vz * vz) / 2.
# print(f"{e}")
def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0):
for (r, [vx, vy, vz], m) in bodies:
px -= vx * m
py -= vy * m
pz -= vz * m
(r, v, m) = ref
v[0] = px / m
v[1] = py / m
v[2] = pz / m
def main(n, ref='sun'):
offset_momentum(BODIES[ref])
report_energy()
advance(0.01, n)
report_energy()
main(500)

View File

@@ -0,0 +1,31 @@
import time
import sys
import pytest
import subprocess
from benchmarks import nbody
# Interpreters:
rustpython_exe = '../target/release/rustpython'
cpython_exe = sys.executable
pythons = [
cpython_exe,
rustpython_exe
]
# Benchmark scripts:
benchmarks = [
['benchmarks/nbody.py'],
['benchmarks/mandelbrot.py'],
]
@pytest.mark.parametrize('exe', pythons)
@pytest.mark.parametrize('args', benchmarks)
def test_bench(exe, args, benchmark):
def bench():
subprocess.run([exe] + args)
benchmark(bench)

15
bytecode/Cargo.toml Normal file
View File

@@ -0,0 +1,15 @@
[package]
name = "rustpython-bytecode"
description = "RustPython specific bytecode."
version = "0.1.0"
authors = ["RustPython Team"]
edition = "2018"
repository = "https://github.com/RustPython/RustPython"
license = "MIT"
[dependencies]
bitflags = "1.1"
num-bigint = { version = "0.2", features = ["serde"] }
num-complex = { version = "0.2", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }

View File

@@ -1,27 +1,46 @@
//! Implement python as a virtual machine with bytecodes. This module
//! implements bytecode structure.
/*
* Primitive instruction type, which can be encoded and decoded.
*/
use bitflags::bitflags;
use num_bigint::BigInt;
use num_complex::Complex64;
use rustpython_parser::ast;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::fmt;
/// Sourcode location.
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Location {
row: usize,
column: usize,
}
impl Location {
pub fn new(row: usize, column: usize) -> Self {
Location { row, column }
}
pub fn row(&self) -> usize {
self.row
}
pub fn column(&self) -> usize {
self.column
}
}
/// Primary container of a single code object. Each python function has
/// a codeobject. Also a module has a codeobject.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct CodeObject {
pub instructions: Vec<Instruction>,
/// Jump targets.
pub label_map: HashMap<Label, usize>,
pub locations: Vec<ast::Location>,
pub arg_names: Vec<String>, // Names of positional arguments
pub varargs: Option<Option<String>>, // *args or *
pub locations: Vec<Location>,
pub arg_names: Vec<String>, // Names of positional arguments
pub varargs: Varargs, // *args or *
pub kwonlyarg_names: Vec<String>,
pub varkeywords: Option<Option<String>>, // **kwargs or **
pub varkeywords: Varargs, // **kwargs or **
pub source_path: String,
pub first_line_number: usize,
pub obj_name: String, // Name of the object that created this code object
@@ -29,28 +48,53 @@ pub struct CodeObject {
}
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct FunctionOpArg: u8 {
const HAS_DEFAULTS = 0x01;
const HAS_KW_ONLY_DEFAULTS = 0x02;
const HAS_ANNOTATIONS = 0x04;
}
}
pub type Label = usize;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum NameScope {
Local,
NonLocal,
Global,
}
/// Transforms a value prior to formatting it.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ConversionFlag {
/// Converts by calling `str(<value>)`.
Str,
/// Converts by calling `ascii(<value>)`.
Ascii,
/// Converts by calling `repr(<value>)`.
Repr,
}
/// A Single bytecode instruction.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Instruction {
Import {
name: String,
symbol: Option<String>,
symbols: Vec<String>,
level: usize,
},
ImportStar {
name: String,
level: usize,
},
LoadName {
name: String,
scope: NameScope,
},
StoreName {
name: String,
scope: NameScope,
},
DeleteName {
name: String,
@@ -168,21 +212,22 @@ pub enum Instruction {
},
Unpack,
FormatValue {
conversion: Option<ast::ConversionFlag>,
conversion: Option<ConversionFlag>,
spec: String,
},
PopException,
}
use self::Instruction::*;
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CallType {
Positional(usize),
Keyword(usize),
Ex(bool),
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Constant {
Integer { value: BigInt },
Float { value: f64 },
@@ -196,7 +241,7 @@ pub enum Constant {
Ellipsis,
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ComparisonOperator {
Greater,
GreaterOrEqual,
@@ -210,7 +255,7 @@ pub enum ComparisonOperator {
IsNot,
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum BinaryOperator {
Power,
Multiply,
@@ -228,7 +273,7 @@ pub enum BinaryOperator {
Or,
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum UnaryOperator {
Not,
Invert,
@@ -236,6 +281,13 @@ pub enum UnaryOperator {
Plus,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Varargs {
None,
Unnamed,
Named(String),
}
/*
Maintain a stack of blocks on the VM.
pub enum BlockType {
@@ -247,9 +299,9 @@ pub enum BlockType {
impl CodeObject {
pub fn new(
arg_names: Vec<String>,
varargs: Option<Option<String>>,
varargs: Varargs,
kwonlyarg_names: Vec<String>,
varkeywords: Option<Option<String>>,
varkeywords: Varargs,
source_path: String,
first_line_number: usize,
obj_name: String,
@@ -308,13 +360,27 @@ impl Instruction {
($variant:ident, $var1:expr, $var2:expr) => {
write!(f, "{:20} ({}, {})\n", stringify!($variant), $var1, $var2)
};
($variant:ident, $var1:expr, $var2:expr, $var3:expr) => {
write!(
f,
"{:20} ({}, {}, {})\n",
stringify!($variant),
$var1,
$var2,
$var3
)
};
}
match self {
Import { name, symbol } => w!(Import, name, format!("{:?}", symbol)),
ImportStar { name } => w!(ImportStar, name),
LoadName { name } => w!(LoadName, name),
StoreName { name } => w!(StoreName, name),
Import {
name,
symbols,
level,
} => w!(Import, name, format!("{:?}", symbols), level),
ImportStar { name, level } => w!(ImportStar, name, level),
LoadName { name, scope } => w!(LoadName, name, format!("{:?}", scope)),
StoreName { name, scope } => w!(StoreName, name, format!("{:?}", scope)),
DeleteName { name } => w!(DeleteName, name),
StoreSubscript => w!(StoreSubscript),
DeleteSubscript => w!(DeleteSubscript),
@@ -362,6 +428,7 @@ impl Instruction {
UnpackEx { before, after } => w!(UnpackEx, before, after),
Unpack => w!(Unpack),
FormatValue { spec, .. } => w!(FormatValue, spec), // TODO: write conversion
PopException => w!(PopException),
}
}
}

1
bytecode/src/lib.rs Normal file
View File

@@ -0,0 +1 @@
pub mod bytecode;

77
code-of-conduct.md Normal file
View File

@@ -0,0 +1,77 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at windel.bouwman@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

14
compiler/Cargo.toml Normal file
View File

@@ -0,0 +1,14 @@
[package]
name = "rustpython-compiler"
version = "0.1.0"
description = "Compiler for python code into bytecode for the rustpython VM."
authors = ["RustPython Team"]
repository = "https://github.com/RustPython/RustPython"
license = "MIT"
edition = "2018"
[dependencies]
rustpython-bytecode = { path = "../bytecode", version = "0.1.0" }
rustpython-parser = { path = "../parser", version = "0.1.0" }
num-complex = { version = "0.2", features = ["serde"] }
log = "0.3"

File diff suppressed because it is too large Load Diff

67
compiler/src/error.rs Normal file
View File

@@ -0,0 +1,67 @@
use rustpython_parser::error::{ParseError, ParseErrorType};
use rustpython_parser::lexer::Location;
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub struct CompileError {
pub error: CompileErrorType,
pub location: Location,
}
impl From<ParseError> for CompileError {
fn from(error: ParseError) -> Self {
CompileError {
error: CompileErrorType::Parse(error.error),
location: error.location,
}
}
}
#[derive(Debug)]
pub enum CompileErrorType {
/// Invalid assignment, cannot store value in target.
Assign(&'static str),
/// Invalid delete
Delete(&'static str),
/// Expected an expression got a statement
ExpectExpr,
/// Parser error
Parse(ParseErrorType),
SyntaxError(String),
/// Multiple `*` detected
StarArgs,
/// Break statement outside of loop.
InvalidBreak,
/// Continue statement outside of loop.
InvalidContinue,
InvalidReturn,
InvalidYield,
}
impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.error {
CompileErrorType::Assign(target) => write!(f, "can't assign to {}", target),
CompileErrorType::Delete(target) => write!(f, "can't delete {}", target),
CompileErrorType::ExpectExpr => write!(f, "Expecting expression, got statement"),
CompileErrorType::Parse(err) => write!(f, "{}", err),
CompileErrorType::SyntaxError(err) => write!(f, "{}", err),
CompileErrorType::StarArgs => write!(f, "Two starred expressions in assignment"),
CompileErrorType::InvalidBreak => write!(f, "'break' outside loop"),
CompileErrorType::InvalidContinue => write!(f, "'continue' outside loop"),
CompileErrorType::InvalidReturn => write!(f, "'return' outside function"),
CompileErrorType::InvalidYield => write!(f, "'yield' outside function"),
}?;
// Print line number:
write!(f, " at {}", self.location)
}
}
impl Error for CompileError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}

9
compiler/src/lib.rs Normal file
View File

@@ -0,0 +1,9 @@
//! Compile a Python AST or source code into bytecode consumable by RustPython or
//! (eventually) CPython.
#[macro_use]
extern crate log;
pub mod compile;
pub mod error;
mod symboltable;

596
compiler/src/symboltable.rs Normal file
View File

@@ -0,0 +1,596 @@
/* Python code is pre-scanned for symbols in the ast.
This ensures that global and nonlocal keywords are picked up.
Then the compiler can use the symbol table to generate proper
load and store instructions for names.
Inspirational file: https://github.com/python/cpython/blob/master/Python/symtable.c
*/
use crate::error::{CompileError, CompileErrorType};
use rustpython_parser::ast;
use rustpython_parser::lexer::Location;
use std::collections::HashMap;
pub fn make_symbol_table(program: &ast::Program) -> Result<SymbolScope, SymbolTableError> {
let mut builder = SymbolTableBuilder::new();
builder.enter_scope();
builder.scan_program(program)?;
assert_eq!(builder.scopes.len(), 1);
let symbol_table = builder.scopes.pop().unwrap();
analyze_symbol_table(&symbol_table, None)?;
Ok(symbol_table)
}
pub fn statements_to_symbol_table(
statements: &[ast::LocatedStatement],
) -> Result<SymbolScope, SymbolTableError> {
let mut builder = SymbolTableBuilder::new();
builder.enter_scope();
builder.scan_statements(statements)?;
assert_eq!(builder.scopes.len(), 1);
let symbol_table = builder.scopes.pop().unwrap();
analyze_symbol_table(&symbol_table, None)?;
Ok(symbol_table)
}
#[derive(Debug)]
pub enum SymbolRole {
Global,
Nonlocal,
Used,
Assigned,
}
/// Captures all symbols in the current scope, and has a list of subscopes in this scope.
pub struct SymbolScope {
/// A set of symbols present on this scope level.
pub symbols: HashMap<String, SymbolRole>,
/// A list of subscopes in the order as found in the
/// AST nodes.
pub sub_scopes: Vec<SymbolScope>,
}
#[derive(Debug)]
pub struct SymbolTableError {
error: String,
location: Location,
}
impl From<SymbolTableError> for CompileError {
fn from(error: SymbolTableError) -> Self {
CompileError {
error: CompileErrorType::SyntaxError(error.error),
location: error.location,
}
}
}
type SymbolTableResult = Result<(), SymbolTableError>;
impl SymbolScope {
pub fn new() -> Self {
SymbolScope {
symbols: HashMap::new(),
sub_scopes: vec![],
}
}
pub fn lookup(&self, name: &str) -> Option<&SymbolRole> {
self.symbols.get(name)
}
}
impl std::fmt::Debug for SymbolScope {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"SymbolScope({:?} symbols, {:?} sub scopes)",
self.symbols.len(),
self.sub_scopes.len()
)
}
}
/* Perform some sort of analysis on nonlocals, globals etc..
See also: https://github.com/python/cpython/blob/master/Python/symtable.c#L410
*/
fn analyze_symbol_table(
symbol_scope: &SymbolScope,
parent_symbol_scope: Option<&SymbolScope>,
) -> SymbolTableResult {
// Analyze sub scopes:
for sub_scope in &symbol_scope.sub_scopes {
analyze_symbol_table(&sub_scope, Some(symbol_scope))?;
}
// Analyze symbols:
for (symbol_name, symbol_role) in &symbol_scope.symbols {
analyze_symbol(symbol_name, symbol_role, parent_symbol_scope)?;
}
Ok(())
}
#[allow(clippy::single_match)]
fn analyze_symbol(
symbol_name: &str,
symbol_role: &SymbolRole,
parent_symbol_scope: Option<&SymbolScope>,
) -> SymbolTableResult {
match symbol_role {
SymbolRole::Nonlocal => {
// check if name is defined in parent scope!
if let Some(parent_symbol_scope) = parent_symbol_scope {
if !parent_symbol_scope.symbols.contains_key(symbol_name) {
return Err(SymbolTableError {
error: format!("no binding for nonlocal '{}' found", symbol_name),
location: Default::default(),
});
}
} else {
return Err(SymbolTableError {
error: format!(
"nonlocal {} defined at place without an enclosing scope",
symbol_name
),
location: Default::default(),
});
}
}
// TODO: add more checks for globals
_ => {}
}
Ok(())
}
pub struct SymbolTableBuilder {
// Scope stack.
pub scopes: Vec<SymbolScope>,
}
impl SymbolTableBuilder {
pub fn new() -> Self {
SymbolTableBuilder { scopes: vec![] }
}
pub fn enter_scope(&mut self) {
let scope = SymbolScope::new();
self.scopes.push(scope);
}
fn leave_scope(&mut self) {
// Pop scope and add to subscopes of parent scope.
let scope = self.scopes.pop().unwrap();
self.scopes.last_mut().unwrap().sub_scopes.push(scope);
}
pub fn scan_program(&mut self, program: &ast::Program) -> SymbolTableResult {
self.scan_statements(&program.statements)?;
Ok(())
}
pub fn scan_statements(&mut self, statements: &[ast::LocatedStatement]) -> SymbolTableResult {
for statement in statements {
self.scan_statement(statement)?;
}
Ok(())
}
fn scan_parameters(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult {
for parameter in parameters {
self.scan_parameter(parameter)?;
}
Ok(())
}
fn scan_parameter(&mut self, parameter: &ast::Parameter) -> SymbolTableResult {
self.register_name(&parameter.arg, SymbolRole::Assigned)
}
fn scan_parameters_annotations(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult {
for parameter in parameters {
self.scan_parameter_annotation(parameter)?;
}
Ok(())
}
fn scan_parameter_annotation(&mut self, parameter: &ast::Parameter) -> SymbolTableResult {
if let Some(annotation) = &parameter.annotation {
self.scan_expression(&annotation)?;
}
Ok(())
}
fn scan_statement(&mut self, statement: &ast::LocatedStatement) -> SymbolTableResult {
match &statement.node {
ast::Statement::Global { names } => {
for name in names {
self.register_name(name, SymbolRole::Global)?;
}
}
ast::Statement::Nonlocal { names } => {
for name in names {
self.register_name(name, SymbolRole::Nonlocal)?;
}
}
ast::Statement::FunctionDef {
name,
body,
args,
decorator_list,
returns,
}
| ast::Statement::AsyncFunctionDef {
name,
body,
args,
decorator_list,
returns,
} => {
self.scan_expressions(decorator_list)?;
self.register_name(name, SymbolRole::Assigned)?;
self.enter_function(args)?;
self.scan_statements(body)?;
if let Some(expression) = returns {
self.scan_expression(expression)?;
}
self.leave_scope();
}
ast::Statement::ClassDef {
name,
body,
bases,
keywords,
decorator_list,
} => {
self.register_name(name, SymbolRole::Assigned)?;
self.enter_scope();
self.scan_statements(body)?;
self.leave_scope();
self.scan_expressions(bases)?;
for keyword in keywords {
self.scan_expression(&keyword.value)?;
}
self.scan_expressions(decorator_list)?;
}
ast::Statement::Expression { expression } => self.scan_expression(expression)?,
ast::Statement::If { test, body, orelse } => {
self.scan_expression(test)?;
self.scan_statements(body)?;
if let Some(code) = orelse {
self.scan_statements(code)?;
}
}
ast::Statement::For {
target,
iter,
body,
orelse,
}
| ast::Statement::AsyncFor {
target,
iter,
body,
orelse,
} => {
self.scan_expression(target)?;
self.scan_expression(iter)?;
self.scan_statements(body)?;
if let Some(code) = orelse {
self.scan_statements(code)?;
}
}
ast::Statement::While { test, body, orelse } => {
self.scan_expression(test)?;
self.scan_statements(body)?;
if let Some(code) = orelse {
self.scan_statements(code)?;
}
}
ast::Statement::Break | ast::Statement::Continue | ast::Statement::Pass => {
// No symbols here.
}
ast::Statement::Import { import_parts } => {
for part in import_parts {
if let Some(alias) = &part.alias {
// `import mymodule as myalias`
self.register_name(alias, SymbolRole::Assigned)?;
} else {
if part.symbols.is_empty() {
// `import module`
self.register_name(&part.module, SymbolRole::Assigned)?;
} else {
// `from mymodule import myimport`
for symbol in &part.symbols {
if let Some(alias) = &symbol.alias {
// `from mymodule import myimportname as myalias`
self.register_name(alias, SymbolRole::Assigned)?;
} else {
self.register_name(&symbol.symbol, SymbolRole::Assigned)?;
}
}
}
}
}
}
ast::Statement::Return { value } => {
if let Some(expression) = value {
self.scan_expression(expression)?;
}
}
ast::Statement::Assert { test, msg } => {
self.scan_expression(test)?;
if let Some(expression) = msg {
self.scan_expression(expression)?;
}
}
ast::Statement::Delete { targets } => {
self.scan_expressions(targets)?;
}
ast::Statement::Assign { targets, value } => {
self.scan_expressions(targets)?;
self.scan_expression(value)?;
}
ast::Statement::AugAssign { target, value, .. } => {
self.scan_expression(target)?;
self.scan_expression(value)?;
}
ast::Statement::With { items, body } => {
for item in items {
self.scan_expression(&item.context_expr)?;
if let Some(expression) = &item.optional_vars {
self.scan_expression(expression)?;
}
}
self.scan_statements(body)?;
}
ast::Statement::Try {
body,
handlers,
orelse,
finalbody,
} => {
self.scan_statements(body)?;
for handler in handlers {
if let Some(expression) = &handler.typ {
self.scan_expression(expression)?;
}
if let Some(name) = &handler.name {
self.register_name(name, SymbolRole::Assigned)?;
}
self.scan_statements(&handler.body)?;
}
if let Some(code) = orelse {
self.scan_statements(code)?;
}
if let Some(code) = finalbody {
self.scan_statements(code)?;
}
}
ast::Statement::Raise { exception, cause } => {
if let Some(expression) = exception {
self.scan_expression(expression)?;
}
if let Some(expression) = cause {
self.scan_expression(expression)?;
}
}
}
Ok(())
}
fn scan_expressions(&mut self, expressions: &[ast::Expression]) -> SymbolTableResult {
for expression in expressions {
self.scan_expression(expression)?;
}
Ok(())
}
fn scan_expression(&mut self, expression: &ast::Expression) -> SymbolTableResult {
match expression {
ast::Expression::Binop { a, b, .. } => {
self.scan_expression(a)?;
self.scan_expression(b)?;
}
ast::Expression::BoolOp { a, b, .. } => {
self.scan_expression(a)?;
self.scan_expression(b)?;
}
ast::Expression::Compare { vals, .. } => {
self.scan_expressions(vals)?;
}
ast::Expression::Subscript { a, b } => {
self.scan_expression(a)?;
self.scan_expression(b)?;
}
ast::Expression::Attribute { value, .. } => {
self.scan_expression(value)?;
}
ast::Expression::Dict { elements } => {
for (key, value) in elements {
if let Some(key) = key {
self.scan_expression(key)?;
} else {
// dict unpacking marker
}
self.scan_expression(value)?;
}
}
ast::Expression::Await { value } => {
self.scan_expression(value)?;
}
ast::Expression::Yield { value } => {
if let Some(expression) = value {
self.scan_expression(expression)?;
}
}
ast::Expression::YieldFrom { value } => {
self.scan_expression(value)?;
}
ast::Expression::Unop { a, .. } => {
self.scan_expression(a)?;
}
ast::Expression::True
| ast::Expression::False
| ast::Expression::None
| ast::Expression::Ellipsis => {}
ast::Expression::Number { .. } => {}
ast::Expression::Starred { value } => {
self.scan_expression(value)?;
}
ast::Expression::Bytes { .. } => {}
ast::Expression::Tuple { elements }
| ast::Expression::Set { elements }
| ast::Expression::List { elements }
| ast::Expression::Slice { elements } => {
self.scan_expressions(elements)?;
}
ast::Expression::Comprehension { kind, generators } => {
match **kind {
ast::ComprehensionKind::GeneratorExpression { ref element }
| ast::ComprehensionKind::List { ref element }
| ast::ComprehensionKind::Set { ref element } => {
self.scan_expression(element)?;
}
ast::ComprehensionKind::Dict { ref key, ref value } => {
self.scan_expression(&key)?;
self.scan_expression(&value)?;
}
}
for generator in generators {
self.scan_expression(&generator.target)?;
self.scan_expression(&generator.iter)?;
for if_expr in &generator.ifs {
self.scan_expression(if_expr)?;
}
}
}
ast::Expression::Call {
function,
args,
keywords,
} => {
self.scan_expression(function)?;
self.scan_expressions(args)?;
for keyword in keywords {
self.scan_expression(&keyword.value)?;
}
}
ast::Expression::String { value } => {
self.scan_string_group(value)?;
}
ast::Expression::Identifier { name } => {
self.register_name(name, SymbolRole::Used)?;
}
ast::Expression::Lambda { args, body } => {
self.enter_function(args)?;
self.scan_expression(body)?;
self.leave_scope();
}
ast::Expression::IfExpression { test, body, orelse } => {
self.scan_expression(test)?;
self.scan_expression(body)?;
self.scan_expression(orelse)?;
}
}
Ok(())
}
fn enter_function(&mut self, args: &ast::Parameters) -> SymbolTableResult {
// Evaluate eventual default parameters:
self.scan_expressions(&args.defaults)?;
for kw_default in &args.kw_defaults {
if let Some(expression) = kw_default {
self.scan_expression(&expression)?;
}
}
// Annotations are scanned in outer scope:
self.scan_parameters_annotations(&args.args)?;
self.scan_parameters_annotations(&args.kwonlyargs)?;
if let ast::Varargs::Named(name) = &args.vararg {
self.scan_parameter_annotation(name)?;
}
if let ast::Varargs::Named(name) = &args.kwarg {
self.scan_parameter_annotation(name)?;
}
self.enter_scope();
// Fill scope with parameter names:
self.scan_parameters(&args.args)?;
self.scan_parameters(&args.kwonlyargs)?;
if let ast::Varargs::Named(name) = &args.vararg {
self.scan_parameter(name)?;
}
if let ast::Varargs::Named(name) = &args.kwarg {
self.scan_parameter(name)?;
}
Ok(())
}
fn scan_string_group(&mut self, group: &ast::StringGroup) -> SymbolTableResult {
match group {
ast::StringGroup::Constant { .. } => {}
ast::StringGroup::FormattedValue { value, .. } => {
self.scan_expression(value)?;
}
ast::StringGroup::Joined { values } => {
for subgroup in values {
self.scan_string_group(subgroup)?;
}
}
}
Ok(())
}
#[allow(clippy::single_match)]
fn register_name(&mut self, name: &str, role: SymbolRole) -> SymbolTableResult {
let scope_depth = self.scopes.len();
let current_scope = self.scopes.last_mut().unwrap();
let location = Default::default();
if current_scope.symbols.contains_key(name) {
// Role already set..
match role {
SymbolRole::Global => {
return Err(SymbolTableError {
error: format!("name '{}' is used prior to global declaration", name),
location,
})
}
SymbolRole::Nonlocal => {
return Err(SymbolTableError {
error: format!("name '{}' is used prior to nonlocal declaration", name),
location,
})
}
_ => {
// Ok?
}
}
} else {
match role {
SymbolRole::Nonlocal => {
if scope_depth < 2 {
return Err(SymbolTableError {
error: format!("cannot define nonlocal '{}' at top level.", name),
location,
});
}
}
_ => {
// Ok!
}
}
current_scope.symbols.insert(name.to_string(), role);
}
Ok(())
}
}

20
derive/Cargo.toml Normal file
View File

@@ -0,0 +1,20 @@
[package]
name = "rustpython-derive"
version = "0.1.0"
description = "Rust language extensions and macros specific to rustpython."
authors = ["RustPython Team"]
repository = "https://github.com/RustPython/RustPython"
license = "MIT"
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = { version = "0.15.29", features = ["full"] }
quote = "0.6.11"
proc-macro2 = "0.4.27"
rustpython-compiler = { path = "../compiler", version = "0.1.0" }
rustpython-bytecode = { path = "../bytecode", version = "0.1.0" }
bincode = "1.1"
proc-macro-hack = "0.5"

View File

@@ -0,0 +1,174 @@
//! Parsing and processing for this form:
//! ```ignore
//! py_compile_input!(
//! // either:
//! source = "python_source_code",
//! // or
//! file = "file/path/relative/to/$CARGO_MANIFEST_DIR",
//!
//! // the mode to compile the code in
//! mode = "exec", // or "eval" or "single"
//! // the path put into the CodeObject, defaults to "frozen"
//! module_name = "frozen",
//! )
//! ```
use crate::{extract_spans, Diagnostic};
use bincode;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
use rustpython_bytecode::bytecode::CodeObject;
use rustpython_compiler::compile;
use std::env;
use std::fs;
use std::path::PathBuf;
use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::{self, parse2, Lit, LitByteStr, Meta, Token};
enum CompilationSourceKind {
File(PathBuf),
SourceCode(String),
}
struct CompilationSource {
kind: CompilationSourceKind,
span: (Span, Span),
}
impl CompilationSource {
fn compile(self, mode: &compile::Mode, module_name: String) -> Result<CodeObject, Diagnostic> {
let compile = |source| {
compile::compile(source, mode, module_name).map_err(|err| {
Diagnostic::spans_error(self.span, format!("Compile error: {}", err))
})
};
match &self.kind {
CompilationSourceKind::File(rel_path) => {
let mut path = PathBuf::from(
env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not present"),
);
path.push(rel_path);
let source = fs::read_to_string(&path).map_err(|err| {
Diagnostic::spans_error(
self.span,
format!("Error reading file {:?}: {}", path, err),
)
})?;
compile(&source)
}
CompilationSourceKind::SourceCode(code) => compile(code),
}
}
}
/// This is essentially just a comma-separated list of Meta nodes, aka the inside of a MetaList.
struct PyCompileInput {
span: Span,
metas: Vec<Meta>,
}
impl PyCompileInput {
fn compile(&self) -> Result<CodeObject, Diagnostic> {
let mut module_name = None;
let mut mode = None;
let mut source: Option<CompilationSource> = None;
fn assert_source_empty(source: &Option<CompilationSource>) -> Result<(), Diagnostic> {
if let Some(source) = source {
Err(Diagnostic::spans_error(
source.span.clone(),
"Cannot have more than one source",
))
} else {
Ok(())
}
}
for meta in &self.metas {
match meta {
Meta::NameValue(name_value) => {
if name_value.ident == "mode" {
mode = Some(match &name_value.lit {
Lit::Str(s) => match s.value().as_str() {
"exec" => compile::Mode::Exec,
"eval" => compile::Mode::Eval,
"single" => compile::Mode::Single,
_ => bail_span!(s, "mode must be exec, eval, or single"),
},
_ => bail_span!(name_value.lit, "mode must be a string"),
})
} else if name_value.ident == "module_name" {
module_name = Some(match &name_value.lit {
Lit::Str(s) => s.value(),
_ => bail_span!(name_value.lit, "module_name must be string"),
})
} else if name_value.ident == "source" {
assert_source_empty(&source)?;
let code = match &name_value.lit {
Lit::Str(s) => s.value(),
_ => bail_span!(name_value.lit, "source must be a string"),
};
source = Some(CompilationSource {
kind: CompilationSourceKind::SourceCode(code),
span: extract_spans(&name_value).unwrap(),
});
} else if name_value.ident == "file" {
assert_source_empty(&source)?;
let path = match &name_value.lit {
Lit::Str(s) => PathBuf::from(s.value()),
_ => bail_span!(name_value.lit, "source must be a string"),
};
source = Some(CompilationSource {
kind: CompilationSourceKind::File(path),
span: extract_spans(&name_value).unwrap(),
});
}
}
_ => {}
}
}
source
.ok_or_else(|| {
Diagnostic::span_error(
self.span.clone(),
"Must have either file or source in py_compile_bytecode!()",
)
})?
.compile(
&mode.unwrap_or(compile::Mode::Exec),
module_name.unwrap_or_else(|| "frozen".to_string()),
)
}
}
impl Parse for PyCompileInput {
fn parse(input: ParseStream) -> ParseResult<Self> {
let span = input.cursor().span();
let metas = input
.parse_terminated::<Meta, Token![,]>(Meta::parse)?
.into_iter()
.collect();
Ok(PyCompileInput { span, metas })
}
}
pub fn impl_py_compile_bytecode(input: TokenStream2) -> Result<TokenStream2, Diagnostic> {
let input: PyCompileInput = parse2(input)?;
let code_obj = input.compile()?;
let bytes = bincode::serialize(&code_obj).expect("Failed to serialize");
let bytes = LitByteStr::new(&bytes, Span::call_site());
let output = quote! {
({
use ::rustpython_vm::__exports::bincode;
bincode::deserialize::<::rustpython_vm::bytecode::CodeObject>(#bytes)
.expect("Deserializing CodeObject failed")
})
};
Ok(output)
}

167
derive/src/error.rs Normal file
View File

@@ -0,0 +1,167 @@
// Taken from https://github.com/rustwasm/wasm-bindgen/blob/master/crates/backend/src/error.rs
//
// Copyright (c) 2014 Alex Crichton
//
// 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.
#![allow(dead_code)]
use proc_macro2::*;
use quote::{ToTokens, TokenStreamExt};
use syn::parse::Error;
macro_rules! err_span {
($span:expr, $($msg:tt)*) => (
$crate::Diagnostic::spanned_error(&$span, format!($($msg)*))
)
}
macro_rules! bail_span {
($($t:tt)*) => (
return Err(err_span!($($t)*).into())
)
}
macro_rules! push_err_span {
($diagnostics:expr, $($t:tt)*) => {
$diagnostics.push(err_span!($($t)*))
};
}
#[derive(Debug)]
pub struct Diagnostic {
inner: Repr,
}
#[derive(Debug)]
enum Repr {
Single {
text: String,
span: Option<(Span, Span)>,
},
SynError(Error),
Multi {
diagnostics: Vec<Diagnostic>,
},
}
impl Diagnostic {
pub fn error<T: Into<String>>(text: T) -> Diagnostic {
Diagnostic {
inner: Repr::Single {
text: text.into(),
span: None,
},
}
}
pub fn span_error<T: Into<String>>(span: Span, text: T) -> Diagnostic {
Diagnostic {
inner: Repr::Single {
text: text.into(),
span: Some((span, span)),
},
}
}
pub fn spans_error<T: Into<String>>(spans: (Span, Span), text: T) -> Diagnostic {
Diagnostic {
inner: Repr::Single {
text: text.into(),
span: Some(spans),
},
}
}
pub fn spanned_error<T: Into<String>>(node: &ToTokens, text: T) -> Diagnostic {
Diagnostic {
inner: Repr::Single {
text: text.into(),
span: extract_spans(node),
},
}
}
pub fn from_vec(diagnostics: Vec<Diagnostic>) -> Result<(), Diagnostic> {
if diagnostics.len() == 0 {
Ok(())
} else {
Err(Diagnostic {
inner: Repr::Multi { diagnostics },
})
}
}
#[allow(unconditional_recursion)]
pub fn panic(&self) -> ! {
match &self.inner {
Repr::Single { text, .. } => panic!("{}", text),
Repr::SynError(error) => panic!("{}", error),
Repr::Multi { diagnostics } => diagnostics[0].panic(),
}
}
}
impl From<Error> for Diagnostic {
fn from(err: Error) -> Diagnostic {
Diagnostic {
inner: Repr::SynError(err),
}
}
}
pub fn extract_spans(node: &dyn ToTokens) -> Option<(Span, Span)> {
let mut t = TokenStream::new();
node.to_tokens(&mut t);
let mut tokens = t.into_iter();
let start = tokens.next().map(|t| t.span());
let end = tokens.last().map(|t| t.span());
start.map(|start| (start, end.unwrap_or(start)))
}
impl ToTokens for Diagnostic {
fn to_tokens(&self, dst: &mut TokenStream) {
match &self.inner {
Repr::Single { text, span } => {
let cs2 = (Span::call_site(), Span::call_site());
let (start, end) = span.unwrap_or(cs2);
dst.append(Ident::new("compile_error", start));
dst.append(Punct::new('!', Spacing::Alone));
let mut message = TokenStream::new();
message.append(Literal::string(text));
let mut group = Group::new(Delimiter::Brace, message);
group.set_span(end);
dst.append(group);
}
Repr::Multi { diagnostics } => {
for diagnostic in diagnostics {
diagnostic.to_tokens(dst);
}
}
Repr::SynError(err) => {
err.to_compile_error().to_tokens(dst);
}
}
}
}

221
derive/src/from_args.rs Normal file
View File

@@ -0,0 +1,221 @@
use crate::Diagnostic;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{
parse_quote, Attribute, Data, DeriveInput, Expr, Field, Fields, Ident, Lit, Meta, NestedMeta,
};
/// The kind of the python parameter, this corresponds to the value of Parameter.kind
/// (https://docs.python.org/3/library/inspect.html#inspect.Parameter.kind)
enum ParameterKind {
PositionalOnly,
PositionalOrKeyword,
KeywordOnly,
}
impl ParameterKind {
fn from_ident(ident: &Ident) -> Option<ParameterKind> {
if ident == "positional_only" {
Some(ParameterKind::PositionalOnly)
} else if ident == "positional_or_keyword" {
Some(ParameterKind::PositionalOrKeyword)
} else if ident == "keyword_only" {
Some(ParameterKind::KeywordOnly)
} else {
None
}
}
}
struct ArgAttribute {
kind: ParameterKind,
default: Option<Expr>,
optional: bool,
}
impl ArgAttribute {
fn from_attribute(attr: &Attribute) -> Option<Result<ArgAttribute, Diagnostic>> {
if !attr.path.is_ident("pyarg") {
return None;
}
let inner = move || match attr.parse_meta()? {
Meta::List(list) => {
let mut iter = list.nested.iter();
let first_arg = iter.next().ok_or_else(|| {
err_span!(list, "There must be at least one argument to #[pyarg()]")
})?;
let kind = match first_arg {
NestedMeta::Meta(Meta::Word(ident)) => ParameterKind::from_ident(ident),
_ => None,
};
let kind = kind.ok_or_else(|| {
err_span!(
first_arg,
"The first argument to #[pyarg()] must be the parameter type, either \
'positional_only', 'positional_or_keyword', or 'keyword_only'."
)
})?;
let mut attribute = ArgAttribute {
kind,
default: None,
optional: false,
};
while let Some(arg) = iter.next() {
attribute.parse_argument(arg)?;
}
if attribute.default.is_some() && attribute.optional {
bail_span!(attr, "Can't set both a default value and optional");
}
Ok(attribute)
}
_ => bail_span!(attr, "pyarg must be a list, like #[pyarg(...)]"),
};
Some(inner())
}
fn parse_argument(&mut self, arg: &NestedMeta) -> Result<(), Diagnostic> {
match arg {
NestedMeta::Meta(Meta::Word(ident)) => {
if ident == "default" {
if self.default.is_some() {
bail_span!(ident, "Default already set");
}
let expr = parse_quote!(Default::default());
self.default = Some(expr);
} else if ident == "optional" {
self.optional = true;
} else {
bail_span!(ident, "Unrecognised pyarg attribute");
}
}
NestedMeta::Meta(Meta::NameValue(name_value)) => {
if name_value.ident == "default" {
if self.default.is_some() {
bail_span!(name_value, "Default already set");
}
match name_value.lit {
Lit::Str(ref val) => {
let expr = val.parse::<Expr>().map_err(|_| {
err_span!(val, "Expected a valid expression for default argument")
})?;
self.default = Some(expr);
}
_ => bail_span!(name_value, "Expected string value for default argument"),
}
} else if name_value.ident == "optional" {
match name_value.lit {
Lit::Bool(ref val) => {
self.optional = val.value;
}
_ => bail_span!(
name_value.lit,
"Expected boolean value for optional argument"
),
}
} else {
bail_span!(name_value, "Unrecognised pyarg attribute");
}
}
_ => bail_span!(arg, "Unrecognised pyarg attribute"),
}
Ok(())
}
}
fn generate_field(field: &Field) -> Result<TokenStream2, Diagnostic> {
let mut pyarg_attrs = field
.attrs
.iter()
.filter_map(ArgAttribute::from_attribute)
.collect::<Result<Vec<_>, _>>()?;
let attr = if pyarg_attrs.is_empty() {
ArgAttribute {
kind: ParameterKind::PositionalOrKeyword,
default: None,
optional: false,
}
} else if pyarg_attrs.len() == 1 {
pyarg_attrs.remove(0)
} else {
bail_span!(field, "Multiple pyarg attributes on field");
};
let name = &field.ident;
let middle = quote! {
.map(|x| ::rustpython_vm::pyobject::TryFromObject::try_from_object(vm, x)).transpose()?
};
let ending = if let Some(default) = attr.default {
quote! {
.unwrap_or_else(|| #default)
}
} else if attr.optional {
quote! {
.map(::rustpython_vm::function::OptionalArg::Present)
.unwrap_or(::rustpython_vm::function::OptionalArg::Missing)
}
} else {
let err = match attr.kind {
ParameterKind::PositionalOnly | ParameterKind::PositionalOrKeyword => quote! {
::rustpython_vm::function::ArgumentError::TooFewArgs
},
ParameterKind::KeywordOnly => quote! {
::rustpython_vm::function::ArgumentError::RequiredKeywordArgument(tringify!(#name))
},
};
quote! {
.ok_or_else(|| #err)?
}
};
let file_output = match attr.kind {
ParameterKind::PositionalOnly => {
quote! {
#name: args.take_positional()#middle#ending,
}
}
ParameterKind::PositionalOrKeyword => {
quote! {
#name: args.take_positional_keyword(stringify!(#name))#middle#ending,
}
}
ParameterKind::KeywordOnly => {
quote! {
#name: args.take_keyword(stringify!(#name))#middle#ending,
}
}
};
Ok(file_output)
}
pub fn impl_from_args(input: DeriveInput) -> Result<TokenStream2, Diagnostic> {
let fields = match input.data {
Data::Struct(syn::DataStruct {
fields: Fields::Named(fields),
..
}) => fields
.named
.iter()
.map(generate_field)
.collect::<Result<TokenStream2, Diagnostic>>()?,
_ => bail_span!(input, "FromArgs input must be a struct with named fields"),
};
let name = input.ident;
let output = quote! {
impl ::rustpython_vm::function::FromArgs for #name {
fn from_args(
vm: &::rustpython_vm::VirtualMachine,
args: &mut ::rustpython_vm::function::PyFuncArgs
) -> Result<Self, ::rustpython_vm::function::ArgumentError> {
Ok(#name { #fields })
}
}
};
Ok(output)
}

55
derive/src/lib.rs Normal file
View File

@@ -0,0 +1,55 @@
#![recursion_limit = "128"]
extern crate proc_macro;
#[macro_use]
mod error;
mod compile_bytecode;
mod from_args;
mod pyclass;
use error::{extract_spans, Diagnostic};
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use proc_macro_hack::proc_macro_hack;
use quote::ToTokens;
use syn::{parse_macro_input, AttributeArgs, DeriveInput, Item};
fn result_to_tokens(result: Result<TokenStream2, Diagnostic>) -> TokenStream {
match result {
Ok(tokens) => tokens.into(),
Err(diagnostic) => diagnostic.into_token_stream().into(),
}
}
#[proc_macro_derive(FromArgs, attributes(pyarg))]
pub fn derive_from_args(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
result_to_tokens(from_args::impl_from_args(input))
}
#[proc_macro_attribute]
pub fn pyclass(attr: TokenStream, item: TokenStream) -> TokenStream {
let attr = parse_macro_input!(attr as AttributeArgs);
let item = parse_macro_input!(item as Item);
result_to_tokens(pyclass::impl_pyclass(attr, item))
}
#[proc_macro_attribute]
pub fn pyimpl(attr: TokenStream, item: TokenStream) -> TokenStream {
let attr = parse_macro_input!(attr as AttributeArgs);
let item = parse_macro_input!(item as Item);
result_to_tokens(pyclass::impl_pyimpl(attr, item))
}
#[proc_macro_attribute]
pub fn pystruct_sequence(attr: TokenStream, item: TokenStream) -> TokenStream {
let attr = parse_macro_input!(attr as AttributeArgs);
let item = parse_macro_input!(item as Item);
result_to_tokens(pyclass::impl_pystruct_sequence(attr, item))
}
#[proc_macro_hack]
pub fn py_compile_bytecode(input: TokenStream) -> TokenStream {
result_to_tokens(compile_bytecode::impl_py_compile_bytecode(input.into()))
}

463
derive/src/pyclass.rs Normal file
View File

@@ -0,0 +1,463 @@
use super::Diagnostic;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use std::collections::HashMap;
use syn::{
Attribute, AttributeArgs, Ident, ImplItem, Index, Item, Lit, Meta, MethodSig, NestedMeta,
};
enum ClassItem {
Method {
item_ident: Ident,
py_name: String,
},
ClassMethod {
item_ident: Ident,
py_name: String,
},
Property {
item_ident: Ident,
py_name: String,
setter: bool,
},
}
fn meta_to_vec(meta: Meta) -> Result<Vec<NestedMeta>, Meta> {
match meta {
Meta::Word(_) => Ok(Vec::new()),
Meta::List(list) => Ok(list.nested.into_iter().collect()),
Meta::NameValue(_) => Err(meta),
}
}
impl ClassItem {
fn extract_from_syn(
attrs: &mut Vec<Attribute>,
sig: &MethodSig,
) -> Result<Option<ClassItem>, Diagnostic> {
let mut item = None;
let mut attr_idx = None;
for (i, meta) in attrs
.iter()
.filter_map(|attr| attr.parse_meta().ok())
.enumerate()
{
let name = meta.name();
if name == "pymethod" {
if item.is_some() {
bail_span!(
sig.ident,
"You can only have one #[py*] attribute on an impl item"
)
}
let nesteds = meta_to_vec(meta).map_err(|meta| {
err_span!(
meta,
"#[pymethod = \"...\"] cannot be a name/value, you probably meant \
#[pymethod(name = \"...\")]",
)
})?;
let mut py_name = None;
for meta in nesteds {
let meta = match meta {
NestedMeta::Meta(meta) => meta,
NestedMeta::Literal(_) => continue,
};
match meta {
Meta::NameValue(name_value) => {
if name_value.ident == "name" {
if let Lit::Str(s) = &name_value.lit {
py_name = Some(s.value());
} else {
bail_span!(
&sig.ident,
"#[pymethod(name = ...)] must be a string"
);
}
}
}
_ => {}
}
}
item = Some(ClassItem::Method {
item_ident: sig.ident.clone(),
py_name: py_name.unwrap_or_else(|| sig.ident.to_string()),
});
attr_idx = Some(i);
} else if name == "pyclassmethod" {
if item.is_some() {
bail_span!(
sig.ident,
"You can only have one #[py*] attribute on an impl item"
)
}
let nesteds = meta_to_vec(meta).map_err(|meta| {
err_span!(
meta,
"#[pyclassmethod = \"...\"] cannot be a name/value, you probably meant \
#[pyclassmethod(name = \"...\")]",
)
})?;
let mut py_name = None;
for meta in nesteds {
let meta = match meta {
NestedMeta::Meta(meta) => meta,
NestedMeta::Literal(_) => continue,
};
match meta {
Meta::NameValue(name_value) => {
if name_value.ident == "name" {
if let Lit::Str(s) = &name_value.lit {
py_name = Some(s.value());
} else {
bail_span!(
&sig.ident,
"#[pyclassmethod(name = ...)] must be a string"
);
}
}
}
_ => {}
}
}
item = Some(ClassItem::ClassMethod {
item_ident: sig.ident.clone(),
py_name: py_name.unwrap_or_else(|| sig.ident.to_string()),
});
attr_idx = Some(i);
} else if name == "pyproperty" {
if item.is_some() {
bail_span!(
sig.ident,
"You can only have one #[py*] attribute on an impl item"
)
}
let nesteds = meta_to_vec(meta).map_err(|meta| {
err_span!(
meta,
"#[pyproperty = \"...\"] cannot be a name/value, you probably meant \
#[pyproperty(name = \"...\")]"
)
})?;
let mut setter = false;
let mut py_name = None;
for meta in nesteds {
let meta = match meta {
NestedMeta::Meta(meta) => meta,
NestedMeta::Literal(_) => continue,
};
match meta {
Meta::NameValue(name_value) => {
if name_value.ident == "name" {
if let Lit::Str(s) = &name_value.lit {
py_name = Some(s.value());
} else {
bail_span!(
&sig.ident,
"#[pyproperty(name = ...)] must be a string"
);
}
}
}
Meta::Word(ident) => {
if ident == "setter" {
setter = true;
}
}
_ => {}
}
}
let py_name = match py_name {
Some(py_name) => py_name,
None => {
let item_ident = sig.ident.to_string();
if setter {
if item_ident.starts_with("set_") {
let name = &item_ident["set_".len()..];
if name.is_empty() {
bail_span!(
&sig.ident,
"A #[pyproperty(setter)] fn with a set_* name must \
have something after \"set_\""
)
} else {
name.to_string()
}
} else {
bail_span!(
&sig.ident,
"A #[pyproperty(setter)] fn must either have a `name` \
parameter or a fn name along the lines of \"set_*\""
)
}
} else {
item_ident
}
}
};
item = Some(ClassItem::Property {
py_name,
item_ident: sig.ident.clone(),
setter,
});
attr_idx = Some(i);
}
}
if let Some(attr_idx) = attr_idx {
attrs.remove(attr_idx);
}
Ok(item)
}
}
pub fn impl_pyimpl(_attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
let mut imp = if let Item::Impl(imp) = item {
imp
} else {
return Ok(quote!(#item));
};
let mut diagnostics: Vec<Diagnostic> = Vec::new();
let items = imp
.items
.iter_mut()
.filter_map(|item| {
if let ImplItem::Method(meth) = item {
ClassItem::extract_from_syn(&mut meth.attrs, &meth.sig)
.map_err(|err| diagnostics.push(err))
.unwrap_or_default()
} else {
None
}
})
.collect::<Vec<_>>();
let ty = &imp.self_ty;
let mut properties: HashMap<&str, (Option<&Ident>, Option<&Ident>)> = HashMap::new();
for item in items.iter() {
match item {
ClassItem::Property {
ref item_ident,
ref py_name,
setter,
} => {
let entry = properties.entry(py_name).or_default();
let func = if *setter { &mut entry.1 } else { &mut entry.0 };
if func.is_some() {
bail_span!(
item_ident,
"Multiple property accessors with name {:?}",
py_name
)
}
*func = Some(item_ident);
}
_ => {}
}
}
let methods = items.iter().filter_map(|item| match item {
ClassItem::Method {
item_ident,
py_name,
} => Some(quote! {
class.set_str_attr(#py_name, ctx.new_rustfunc(Self::#item_ident));
}),
ClassItem::ClassMethod {
item_ident,
py_name,
} => Some(quote! {
class.set_str_attr(#py_name, ctx.new_classmethod(Self::#item_ident));
}),
_ => None,
});
let properties = properties
.iter()
.map(|(name, prop)| {
let getter = match prop.0 {
Some(getter) => getter,
None => {
push_err_span!(
diagnostics,
prop.1.unwrap(),
"Property {:?} is missing a getter",
name
);
return TokenStream2::new();
}
};
let add_setter = prop.1.map(|setter| quote!(.add_setter(Self::#setter)));
quote! {
class.set_str_attr(
#name,
::rustpython_vm::obj::objproperty::PropertyBuilder::new(ctx)
.add_getter(Self::#getter)
#add_setter
.create(),
);
}
})
.collect::<Vec<_>>();
Diagnostic::from_vec(diagnostics)?;
let ret = quote! {
#imp
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
fn impl_extend_class(
ctx: &::rustpython_vm::pyobject::PyContext,
class: &::rustpython_vm::obj::objtype::PyClassRef,
) {
#(#methods)*
#(#properties)*
}
}
};
Ok(ret)
}
fn generate_class_def(
ident: &Ident,
attr_name: &'static str,
attr: AttributeArgs,
attrs: &Vec<Attribute>,
) -> Result<TokenStream2, Diagnostic> {
let mut class_name = None;
for attr in attr {
if let NestedMeta::Meta(meta) = attr {
if let Meta::NameValue(name_value) = meta {
if name_value.ident == "name" {
if let Lit::Str(s) = name_value.lit {
class_name = Some(s.value());
} else {
bail_span!(
name_value.lit,
"#[{}(name = ...)] must be a string",
attr_name
);
}
}
}
}
}
let class_name = class_name.unwrap_or_else(|| ident.to_string());
let mut doc: Option<Vec<String>> = None;
for attr in attrs.iter() {
if attr.path.is_ident("doc") {
let meta = attr.parse_meta().expect("expected doc attr to be a meta");
if let Meta::NameValue(name_value) = meta {
if let Lit::Str(s) = name_value.lit {
let val = s.value().trim().to_string();
match doc {
Some(ref mut doc) => doc.push(val),
None => doc = Some(vec![val]),
}
}
}
}
}
let doc = match doc {
Some(doc) => {
let doc = doc.join("\n");
quote!(Some(#doc))
}
None => quote!(None),
};
let ret = quote! {
impl ::rustpython_vm::pyobject::PyClassDef for #ident {
const NAME: &'static str = #class_name;
const DOC: Option<&'static str> = #doc;
}
};
Ok(ret)
}
pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
let (item, ident, attrs) = match item {
Item::Struct(struc) => (quote!(#struc), struc.ident, struc.attrs),
Item::Enum(enu) => (quote!(#enu), enu.ident, enu.attrs),
other => bail_span!(
other,
"#[pyclass] can only be on a struct or enum declaration"
),
};
let class_def = generate_class_def(&ident, "pyclass", attr, &attrs)?;
let ret = quote! {
#item
#class_def
};
Ok(ret)
}
pub fn impl_pystruct_sequence(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
let struc = if let Item::Struct(struc) = item {
struc
} else {
bail_span!(
item,
"#[pystruct_sequence] can only be on a struct declaration"
)
};
let class_def = generate_class_def(&struc.ident, "pystruct_sequence", attr, &struc.attrs)?;
let mut properties = Vec::new();
let mut field_names = Vec::new();
for (i, field) in struc.fields.iter().enumerate() {
let idx = Index::from(i);
if let Some(ref field_name) = field.ident {
let field_name_str = field_name.to_string();
// TODO add doc to the generated property
let property = quote! {
class.set_str_attr(
#field_name_str,
::rustpython_vm::obj::objproperty::PropertyBuilder::new(ctx)
.add_getter(|zelf: &::rustpython_vm::obj::objtuple::PyTuple,
_vm: &::rustpython_vm::vm::VirtualMachine|
zelf.fast_getitem(#idx))
.create(),
);
};
properties.push(property);
field_names.push(quote!(#field_name));
} else {
field_names.push(quote!(#idx));
}
}
let ty = &struc.ident;
let ret = quote! {
#struc
#class_def
impl #ty {
fn into_struct_sequence(&self,
vm: &::rustpython_vm::vm::VirtualMachine,
cls: ::rustpython_vm::obj::objtype::PyClassRef,
) -> ::rustpython_vm::pyobject::PyResult<::rustpython_vm::obj::objtuple::PyTupleRef> {
let tuple: ::rustpython_vm::obj::objtuple::PyTuple =
vec![#(::rustpython_vm::pyobject::IntoPyObject
::into_pyobject(self.#field_names, vm)?
),*].into();
::rustpython_vm::pyobject::PyValue::into_ref_with_type(tuple, vm, cls)
}
}
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
fn impl_extend_class(
ctx: &::rustpython_vm::pyobject::PyContext,
class: &::rustpython_vm::obj::objtype::PyClassRef,
) {
#(#properties)*
}
fn make_class(
ctx: &::rustpython_vm::pyobject::PyContext
) -> ::rustpython_vm::obj::objtype::PyClassRef {
let py_class = ctx.new_class(<Self as ::rustpython_vm::pyobject::PyClassDef>::NAME, ctx.tuple_type());
Self::extend_class(ctx, &py_class);
py_class
}
}
};
Ok(ret)
}

View File

@@ -1,30 +0,0 @@
Byterun
* Builtins are exposed to frame.f_builtins
* f_builtins is assigned during frame creation,
self.f_builtins = f_locals['__builtins__']
if hasattr(self.f_builtins, '__dict__'):
self.f_builtins = self.f_builtins.__dict__
* f_locals has a __`____builtins___` field which is directly the `__builtins__` module
Jaspy
* The `module()` function creates either a NativeModule or PythonModule
* The objects in the module are PyType.native
* The function call is abstracted as a `call` function, which handles different
* IMPORT_NAME depends on `__import__()` in builtins
TODO:
* Implement a new type NativeFunction
* Wrap a function pointer in NativeFunction
* Refactor the CALL_FUNCTION case so it can call both python function and native function
* During frame creation, force push a native function `print` into the namespace
* Modify LOAD_* so they can search for names in builtins
* Create a module type
* In VM initialization, load the builtins module into locals
* During frame creation, create a field that contains the builtins dict

View File

@@ -1,17 +0,0 @@
https://wiki.python.org/moin/SimplePrograms
Simple HTTP Server
bottle.py
http://pypi-ranking.info/alltime
- simplejson
- pep8
- httplib2
- argparse
http://learning-python.com/books/lp4e-examples.html
https://docs.python.org/3/tutorial/introduction.html#numbers
http://doc.pypy.org/en/latest/getting-started-dev.html#running-pypy-s-unit-tests
CPython Regression suite
https://github.com/python/cpython/tree/master/Lib/test

View File

@@ -1,13 +0,0 @@
Create a frame class
change the environment to locals
turn run into run_code -> run_frame
TEST
Create a function class
implement MAKE_FUNCTION
implement CALL_FUNCTION
implement RETURN_VALUE
TEST function

View File

@@ -1,13 +0,0 @@
# TODO: other notes should be put into here
# getattr()
- Required by this opcode [LOAD_ATTR](https://docs.python.org/3/library/dis.html#opcode-LOAD_ATTR)
- The builtin function: https://docs.python.org/3/library/functions.html?highlight=getattr#getattr
-
# Memory management
- https://docs.python.org/3.6/c-api/memory.html
# Bootstraping
- http://doc.pypy.org/en/latest/coding-guide.html#our-runtime-interpreter-is-rpython
- http://www.aosabook.org/en/pypy.html

View File

@@ -1,5 +0,0 @@
Python bytecode: https://docs.python.org/3.4/library/dis.html
Python VM in python: https://github.com/nedbat/byterun
Python VM in JS: https://github.com/koehlma/jaspy
http://www.skulpt.org/

View File

@@ -1,43 +0,0 @@
# Sharing plan
## Topics
* Python architecture
* Compiler -> VM
* Flavors
* Cpython
* Pypy
* Byterun
* JSapy (?)
* Why Rust
* Security
* Learning
* Implementation plan
* VM first
* Compiler second
* Tools for study
* dis doc
* byterun doc
* bytrun code
* cpython source
---
* Python VM
* Stack machine
* Load add print
* dis
* Interpreter loop
* Python Types
* Control flow
* Jump
* If
* Loop
---
* Function call
* Frame
* Builtins

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -1,286 +0,0 @@
class: center, middle
##Python Interpreter in Rust
#### 2017/8/6, COSCUP
#### Shing Lyu
???
top, middle, bottom
left, center, right
---
### About Me
* 呂行 Shing Lyu
* Mozilla engineer
* Servo team
![rust_and_servo](pic/rust-servo.png)
---
### Python's architecture
* Interpreted
* Garbage Collected
* Compiler => bytecode => VM
![python](pic/python-logo.png)
---
background-image: url('pic/ice-cream.jpg')
class: center, middle, bleed, text-bg
# Flavors
---
### Python Flavors
* CPython (THE python)
* Jython (JVM)
* IronPython (.NET)
* Pypy
* Educational
* Byterun
* Jsapy (JS)
* Brython (Python in browser)
---
class: center, middle
# Why & How?
---
### Why rewriting Python in Rust?
* Memory safety (?)
* Learn about Python's internal
* Learn to write Rust from scratch
* FUN!
---
### Implementation strategy
* Mostly follow CPython 3.6
* Focus on the VM first, then the compiler
* Use the Python built-in compiler to generate bytecode
* Focus on learning rather than usability
---
### Milestones
* Basic arithmetics
* Variables
* Control flows (require JUMP)
* Function call (require call stack)
* Built-in functions (require native code)
* Run Python tutorial example code <= We're here
* Exceptions
* GC
* Run popular libraries
---
class: center, middle, bleed, text-bg
background-image: url('pic/car_cutaway.jpg')
# Python Internals
---
### How Python VM works
* Stack machine
* Call stack and frames
* Has a NAMES list and CONSTS list
* Has a STACK as workspace
* Accepts Python bytecode
* `python -m dis source.py`
---
### A simple Python code
```
#!/usr/bin/env python3
print(1+1)
```
Running `python3 -m dis source.py` gives us
```
1 0 LOAD_NAME 0 (print)
3 LOAD_CONST 2 (2)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
```
---
### LOAD_NAME "print"
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| print (native code)|
+--------------------+
```
---
### LOAD_CONST 2
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| 2 |
| print (native code)|
+--------------------+
```
---
### CALL_FUNCTION 1
1. `argument = stack.pop()` (argument == 2)
2. `function = stack.top()` (function == print)
3. call `print(2)`
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| print (native code)|
+--------------------+
```
---
### POP_TOP
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| (empty) |
+--------------------+
```
---
### LOAD_CONST None
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| None |
+--------------------+
```
---
### RETURN_VALUE
(returns top of stack == None)
---
class: center, middle, bleed, text-bg
background-image: url('pic/electronic_parts.jpg')
# Technical Detail
---
### Bytecode format
* `dis` output format is for human reader
* Implementing a `dis` format parser is a waste of time
* Emit JSON bytecode using the [bytecode](https://pypi.python.org/pypi/bytecode/0.5) module
```
code = compile(f,...) # Python built-in, return a Code object
bytecode.Bytecode()
.from_code(code)
.to_concrete_bytecode()
```
* Load into Rust using `serde_json`
---
### Types
* Everything is a `PyObject` in CPython
* We'll need that class hierarchy eventually
* Use a Rust `enum` for now
```
pub enum NativeType{
NoneType,
Boolean(bool),
Int(i32),
Str(String),
Tuple(Vec<NativeType>),
...
}
```
---
### Testing
* `assert` is essential to for unittests
* `assert` raises `AssertionError`
* Use `panic!()` before we implement exception
```
assert 1 == 1
```
```
1 0 LOAD_CONST 0 (1)
3 LOAD_CONST 0 (1)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_TRUE 18
12 LOAD_GLOBAL 0 (AssertionError)
15 RAISE_VARARGS 1
>> 18 LOAD_CONST 1 (None)
21 RETURN_VALUE
```
---
### Native Function
* e.g. `print()`
```
pub enum NativeType {
NativeFunction(fn(Vec<NativeType>) -> NativeType),
...
}
match stack.pop() {
NativeFunction(func) => return_val = func(),
_ => ...
}
```
---
### Next steps
* Exceptions
* Make it run a small but popular tool/library
* Implement the parser
* Figure out garbage collection
* Performance benchmarking
---
### Contribute
## https://github.com/shinglyu/RustPython
![qr_code](pic/repo_QR.png)
---
class: middle, center
# Thank you
---
### References
* [`dis` documentation](https://docs.python.org/3.4/library/dis.html)
* [byterun](http://www.aosabook.org/en/500L/a-python-interpreter-written-in-python.html)
* [byterun (GitHub)](https://github.com/nedbat/byterun/)
* [cpython source code](https://github.com/python/cpython)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

View File

@@ -1,180 +0,0 @@
class: center, middle
##Python Interpreter in Rust
###Introduction
#### 2017/3/28
#### Shing Lyu
???
top, middle, bottom
left, center, right
---
name: toc
###Agenda
1. Category
1. Category
1. Category
1. Category
1. Category
1. Category
1. Category
???
This is a template
---
### Python's architecture
* Interpreted
* Garbage Collected
* Compiler => bytecode => VM
---
background-image: url('pic/ice-cream.jpg')
class: bleed
# Flavors
---
### Python Flavors
* CPython (THE python)
* Jython (JVM)
* IronPython (.NET)
* Pypy
* Educational
* Byterun
* Jsapy (JS)
* Brython (Python in browser)
---
### Why rewriting Python in Rust?
* Memory safety
* Learn about Python internal
* Learn real world Rust
---
### Implementation strategy
* Focus on the VM first, then the compiler
* Reuse the Python built-in compiler to generate bytecode
* Basic arithmetics
* Control flows (require JUMP)
* Function call (require call stack)
* Built-in functions (require native code)
* Run popular libraries
---
### References
* [`dis` documentation](https://docs.python.org/3.4/library/dis.html)
* [byterun](http://www.aosabook.org/en/500L/a-python-interpreter-written-in-python.html)
* [byterun (GitHub)](https://github.com/nedbat/byterun/)
* [cpython source code](https://github.com/python/cpython)
---
### How Python VM works
* Stack machine
* Accepts Python bytecode
* `python -m dis source.py`
---
### A simple Python code
```
#!/usr/bin/env python3
print(1+1)
```
We run `python3 -m dis source.py`
---
### The bytecode
```
1 0 LOAD_NAME 0 (print)
3 LOAD_CONST 2 (2)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
```
---
### LOAD_NAME "print"
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| print (native code)|
+--------------------+
```
---
### LOAD_CONST 2
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| 2 |
| print (native code)|
+--------------------+
```
---
### CALL_FUNCTION 1
1. argument = stack.pop() (argument == 2)
2. function = stack.top() (function == print)
3. call print(2)
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| print (native code)|
+--------------------+
```
---
### POP_TOP
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| (empty) |
+--------------------+
```
---
### LOAD_CONST 1
* NAMES = ["print"]
* CONSTS = [None, 2]
* STACK:
```
| |
| None |
+--------------------+
```
---
### RETURN_VALUE
(returns top of stack == None)
---
### Next step
* Make it run a small but popular tool/library
* Implement the parser
* Performance benchmarking

View File

@@ -1,6 +0,0 @@
Topic to study
==================
* How to save a Rust Iterator on the stack?
* Study how blocks are handled in CPython.
* The `why` var?
* Why unwind everything when a `break` happened?

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

4
parser/.gitignore vendored
View File

@@ -1,4 +0,0 @@
src/python.rs
target/
Cargo.lock

View File

@@ -1,17 +1,23 @@
[package]
name = "rustpython_parser"
version = "0.0.1"
authors = [ "Shing Lyu", "Windel Bouwman" ]
name = "rustpython-parser"
version = "0.1.0"
description = "Parser for python code."
authors = [ "RustPython Team" ]
build = "build.rs"
repository = "https://github.com/RustPython/RustPython"
license = "MIT"
edition = "2018"
[build-dependencies]
lalrpop="0.15.1"
lalrpop="0.16.3"
[dependencies]
lalrpop-util="0.15.1"
lalrpop-util="0.16.3"
log="0.4.1"
regex="0.2.2"
num-bigint = "0.2"
num-traits = "0.2"
unicode-xid = "0.1.0"
unic-emoji-char = "0.9.0"
serde = { version = "1.0.66", features = ["derive"] }
wtf8 = "0.0.3"

View File

@@ -1,5 +1,5 @@
use lalrpop;
fn main() {
lalrpop::process_root().unwrap();
lalrpop::process_root().unwrap()
}

View File

@@ -4,6 +4,8 @@
pub use super::lexer::Location;
use num_bigint::BigInt;
use serde::{Deserialize, Serialize};
/*
#[derive(Debug)]
@@ -16,7 +18,7 @@ pub struct Node {
#[derive(Debug, PartialEq)]
pub enum Top {
Program(Program),
Statement(LocatedStatement),
Statement(Vec<LocatedStatement>),
Expression(Expression),
}
@@ -25,12 +27,18 @@ pub struct Program {
pub statements: Vec<LocatedStatement>,
}
#[derive(Debug, PartialEq)]
pub struct ImportSymbol {
pub symbol: String,
pub alias: Option<String>,
}
#[derive(Debug, PartialEq)]
pub struct SingleImport {
pub module: String,
// (symbol name in module, name it should be assigned locally)
pub symbol: Option<String>,
pub alias: Option<String>,
pub symbols: Vec<ImportSymbol>,
pub level: usize,
}
#[derive(Debug, PartialEq)]
@@ -42,12 +50,13 @@ pub struct Located<T> {
pub type LocatedStatement = Located<Statement>;
/// Abstract syntax tree nodes for python statements.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, PartialEq)]
pub enum Statement {
Break,
Continue,
Return {
value: Option<Vec<Expression>>,
value: Option<Box<Expression>>,
},
Import {
import_parts: Vec<SingleImport>,
@@ -94,7 +103,13 @@ pub enum Statement {
},
For {
target: Expression,
iter: Vec<Expression>,
iter: Expression,
body: Vec<LocatedStatement>,
orelse: Option<Vec<LocatedStatement>>,
},
AsyncFor {
target: Expression,
iter: Expression,
body: Vec<LocatedStatement>,
orelse: Option<Vec<LocatedStatement>>,
},
@@ -114,12 +129,17 @@ pub enum Statement {
bases: Vec<Expression>,
keywords: Vec<Keyword>,
decorator_list: Vec<Expression>,
// TODO: docstring: String,
},
FunctionDef {
name: String,
args: Parameters,
// docstring: String,
body: Vec<LocatedStatement>,
decorator_list: Vec<Expression>,
returns: Option<Expression>,
},
AsyncFunctionDef {
name: String,
args: Parameters,
body: Vec<LocatedStatement>,
decorator_list: Vec<Expression>,
returns: Option<Expression>,
@@ -152,6 +172,9 @@ pub enum Expression {
op: UnaryOperator,
a: Box<Expression>,
},
Await {
value: Box<Expression>,
},
Yield {
value: Option<Box<Expression>>,
},
@@ -159,9 +182,8 @@ pub enum Expression {
value: Box<Expression>,
},
Compare {
a: Box<Expression>,
op: Comparison,
b: Box<Expression>,
vals: Vec<Expression>,
ops: Vec<Comparison>,
},
Attribute {
value: Box<Expression>,
@@ -182,7 +204,7 @@ pub enum Expression {
elements: Vec<Expression>,
},
Dict {
elements: Vec<(Expression, Expression)>,
elements: Vec<(Option<Expression>, Expression)>,
},
Set {
elements: Vec<Expression>,
@@ -230,6 +252,7 @@ impl Expression {
match self {
BoolOp { .. } | Binop { .. } | Unop { .. } => "operator",
Subscript { .. } => "subscript",
Await { .. } => "await expression",
Yield { .. } | YieldFrom { .. } => "yield expression",
Compare { .. } => "comparison",
Attribute { .. } => "attribute",
@@ -274,8 +297,8 @@ impl Expression {
pub struct Parameters {
pub args: Vec<Parameter>,
pub kwonlyargs: Vec<Parameter>,
pub vararg: Option<Option<Parameter>>, // Optionally we handle optionally named '*args' or '*'
pub kwarg: Option<Option<Parameter>>,
pub vararg: Varargs, // Optionally we handle optionally named '*args' or '*'
pub kwarg: Varargs,
pub defaults: Vec<Expression>,
pub kw_defaults: Vec<Option<Expression>>,
}
@@ -367,7 +390,7 @@ pub enum Number {
}
/// Transforms a value prior to formatting it.
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ConversionFlag {
/// Converts by calling `str(<value>)`.
Str,
@@ -391,3 +414,28 @@ pub enum StringGroup {
values: Vec<StringGroup>,
},
}
#[derive(Debug, PartialEq)]
pub enum Varargs {
None,
Unnamed,
Named(Parameter),
}
impl Default for Varargs {
fn default() -> Varargs {
Varargs::None
}
}
impl From<Option<Option<Parameter>>> for Varargs {
fn from(opt: Option<Option<Parameter>>) -> Varargs {
match opt {
Some(inner_opt) => match inner_opt {
Some(param) => Varargs::Named(param),
None => Varargs::Unnamed,
},
None => Varargs::None,
}
}
}

View File

@@ -3,28 +3,31 @@
extern crate lalrpop_util;
use self::lalrpop_util::ParseError as InnerError;
use crate::lexer::{LexicalError, Location};
use crate::lexer::{LexicalError, LexicalErrorType, Location};
use crate::token::Tok;
use std::error::Error;
use std::fmt;
// A token of type `Tok` was observed, with a span given by the two Location values
type TokSpan = (Location, Tok, Location);
/// Represents an error during parsing
#[derive(Debug, PartialEq)]
pub enum ParseError {
pub struct ParseError {
pub error: ParseErrorType,
pub location: Location,
}
#[derive(Debug, PartialEq)]
pub enum ParseErrorType {
/// Parser encountered an unexpected end of input
EOF(Option<Location>),
EOF,
/// Parser encountered an extra token
ExtraToken(TokSpan),
ExtraToken(Tok),
/// Parser encountered an invalid token
InvalidToken(Location),
InvalidToken,
/// Parser encountered an unexpected token
UnrecognizedToken(TokSpan, Vec<String>),
UnrecognizedToken(Tok, Vec<String>),
/// Maps to `User` type from `lalrpop-util`
Other,
Lexical(LexicalErrorType),
}
/// Convert `lalrpop_util::ParseError` to our internal type
@@ -32,15 +35,29 @@ impl From<InnerError<Location, Tok, LexicalError>> for ParseError {
fn from(err: InnerError<Location, Tok, LexicalError>) -> Self {
match err {
// TODO: Are there cases where this isn't an EOF?
InnerError::InvalidToken { location } => ParseError::EOF(Some(location)),
InnerError::ExtraToken { token } => ParseError::ExtraToken(token),
// Inner field is a unit-like enum `LexicalError::StringError` with no useful info
InnerError::User { .. } => ParseError::Other,
InnerError::InvalidToken { location } => ParseError {
error: ParseErrorType::EOF,
location,
},
InnerError::ExtraToken { token } => ParseError {
error: ParseErrorType::ExtraToken(token.1),
location: token.0,
},
InnerError::User { error } => ParseError {
error: ParseErrorType::Lexical(error.error),
location: error.location,
},
InnerError::UnrecognizedToken { token, expected } => {
match token {
Some(tok) => ParseError::UnrecognizedToken(tok, expected),
Some(tok) => ParseError {
error: ParseErrorType::UnrecognizedToken(tok.1, expected),
location: tok.0,
},
// EOF was observed when it was unexpected
None => ParseError::EOF(None),
None => ParseError {
error: ParseErrorType::EOF,
location: Default::default(),
},
}
}
}
@@ -48,26 +65,21 @@ impl From<InnerError<Location, Tok, LexicalError>> for ParseError {
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} at {}", self.error, self.location)
}
}
impl fmt::Display for ParseErrorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ParseError::EOF(ref location) => {
if let Some(l) = location {
write!(f, "Got unexpected EOF at: {:?}", l)
} else {
write!(f, "Got unexpected EOF")
}
ParseErrorType::EOF => write!(f, "Got unexpected EOF"),
ParseErrorType::ExtraToken(ref tok) => write!(f, "Got extraneous token: {:?}", tok),
ParseErrorType::InvalidToken => write!(f, "Got invalid token"),
ParseErrorType::UnrecognizedToken(ref tok, _) => {
write!(f, "Got unexpected token: {:?}", tok)
}
ParseError::ExtraToken(ref t_span) => {
write!(f, "Got extraneous token: {:?} at: {:?}", t_span.1, t_span.0)
}
ParseError::InvalidToken(ref location) => {
write!(f, "Got invalid token at: {:?}", location)
}
ParseError::UnrecognizedToken(ref t_span, _) => {
write!(f, "Got unexpected token: {:?} at {:?}", t_span.1, t_span.0)
}
// This is user defined, it probably means a more useful error should have been given upstream.
ParseError::Other => write!(f, "Got unsupported token(s)"),
ParseErrorType::Lexical(ref error) => write!(f, "{}", error),
}
}
}

View File

@@ -5,7 +5,7 @@ use std::str;
use lalrpop_util::ParseError as LalrpopError;
use crate::ast::{ConversionFlag, StringGroup};
use crate::lexer::{LexicalError, Location, Tok};
use crate::lexer::{LexicalError, LexicalErrorType, Location, Tok};
use crate::parser::parse_expression;
use self::FStringError::*;
@@ -25,7 +25,10 @@ pub enum FStringError {
impl From<FStringError> for LalrpopError<Location, Tok, LexicalError> {
fn from(_err: FStringError) -> Self {
lalrpop_util::ParseError::User {
error: LexicalError::StringError,
error: LexicalError {
error: LexicalErrorType::StringError,
location: Default::default(),
},
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,14 @@
#[macro_use]
extern crate log;
use lalrpop_util::lalrpop_mod;
pub mod ast;
pub mod error;
mod fstring;
pub mod lexer;
pub mod parser;
#[cfg_attr(rustfmt, rustfmt_skip)]
mod python;
lalrpop_mod!(
#[allow(clippy::all)]
python
);
pub mod token;

View File

@@ -35,7 +35,7 @@ pub fn parse_program(source: &str) -> Result<ast::Program, ParseError> {
do_lalr_parsing!(source, Program, StartProgram)
}
pub fn parse_statement(source: &str) -> Result<ast::LocatedStatement, ParseError> {
pub fn parse_statement(source: &str) -> Result<Vec<ast::LocatedStatement>, ParseError> {
do_lalr_parsing!(source, Statement, StartStatement)
}
@@ -44,7 +44,6 @@ pub fn parse_statement(source: &str) -> Result<ast::LocatedStatement, ParseError
/// # Example
/// ```
/// extern crate num_bigint;
/// extern crate rustpython_parser;
/// use num_bigint::BigInt;
/// use rustpython_parser::{parser, ast};
/// let expr = parser::parse_expression("1+2").unwrap();
@@ -180,7 +179,7 @@ mod tests {
let parse_ast = parse_statement(&source).unwrap();
assert_eq!(
parse_ast,
ast::LocatedStatement {
vec![ast::LocatedStatement {
location: ast::Location::new(1, 1),
node: ast::Statement::If {
test: ast::Expression::Number {
@@ -229,7 +228,7 @@ mod tests {
}
},]),
}
}
}]
);
}
@@ -239,7 +238,7 @@ mod tests {
let parse_ast = parse_statement(&source);
assert_eq!(
parse_ast,
Ok(ast::LocatedStatement {
Ok(vec![ast::LocatedStatement {
location: ast::Location::new(1, 1),
node: ast::Statement::Expression {
expression: ast::Expression::Lambda {
@@ -255,8 +254,8 @@ mod tests {
}
],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
vararg: ast::Varargs::None,
kwarg: ast::Varargs::None,
defaults: vec![],
kw_defaults: vec![],
},
@@ -271,7 +270,7 @@ mod tests {
})
}
}
})
}])
)
}
@@ -281,7 +280,7 @@ mod tests {
assert_eq!(
parse_statement(&source),
Ok(ast::LocatedStatement {
Ok(vec![ast::LocatedStatement {
location: ast::Location::new(1, 1),
node: ast::Statement::Assign {
targets: vec![ast::Expression::Tuple {
@@ -309,7 +308,7 @@ mod tests {
]
}
}
})
}])
)
}
@@ -320,7 +319,7 @@ mod tests {
);
assert_eq!(
parse_statement(&source),
Ok(ast::LocatedStatement {
Ok(vec![ast::LocatedStatement {
location: ast::Location::new(1, 1),
node: ast::Statement::ClassDef {
name: String::from("Foo"),
@@ -344,8 +343,8 @@ mod tests {
annotation: None,
}],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
vararg: ast::Varargs::None,
kwarg: ast::Varargs::None,
defaults: vec![],
kw_defaults: vec![],
},
@@ -373,8 +372,8 @@ mod tests {
}
],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
vararg: ast::Varargs::None,
kwarg: ast::Varargs::None,
defaults: vec![ast::Expression::String {
value: ast::StringGroup::Constant {
value: "default".to_string()
@@ -393,7 +392,7 @@ mod tests {
],
decorator_list: vec![],
}
})
}])
)
}
@@ -460,26 +459,30 @@ mod tests {
},
ifs: vec![
ast::Expression::Compare {
a: Box::new(ast::Expression::Identifier {
name: "a".to_string()
}),
op: ast::Comparison::Less,
b: Box::new(ast::Expression::Number {
value: ast::Number::Integer {
value: BigInt::from(5)
vals: vec![
ast::Expression::Identifier {
name: "a".to_string()
},
ast::Expression::Number {
value: ast::Number::Integer {
value: BigInt::from(5)
}
}
}),
],
ops: vec![ast::Comparison::Less],
},
ast::Expression::Compare {
a: Box::new(ast::Expression::Identifier {
name: "a".to_string()
}),
op: ast::Comparison::Greater,
b: Box::new(ast::Expression::Number {
value: ast::Number::Integer {
value: BigInt::from(10)
vals: vec![
ast::Expression::Identifier {
name: "a".to_string()
},
ast::Expression::Number {
value: ast::Number::Integer {
value: BigInt::from(10)
}
}
}),
],
ops: vec![ast::Comparison::Greater],
},
],
}

View File

@@ -2,7 +2,6 @@
// See also: https://github.com/antlr/grammars-v4/blob/master/python3/Python3.g4
// See also: file:///usr/share/doc/python/html/reference/compound_stmts.html#function-definitions
// See also: https://greentreesnakes.readthedocs.io/en/latest/nodes.html#keyword
#![allow(unknown_lints,clippy)]
use std::iter::FromIterator;
@@ -25,29 +24,32 @@ pub Top: ast::Top = {
Program: ast::Program = {
<lines:FileLine*> => ast::Program {
statements: Vec::from_iter(lines.into_iter().filter_map(|e| e))
statements: Vec::from_iter(lines.into_iter().flatten())
},
};
// A file line either has a declaration, or an empty newline:
FileLine: Option<ast::LocatedStatement> = {
<s:Statement> => Some(s),
"\n" => None,
FileLine: Vec<ast::LocatedStatement> = {
Statement,
"\n" => vec![],
};
Suite: Vec<ast::LocatedStatement> = {
<s:SimpleStatement> => vec![s],
"\n" indent <s:Statement+> dedent => s,
};
Statement: ast::LocatedStatement = {
SimpleStatement,
CompoundStatement,
"\n" indent <s:Statement+> dedent => s.into_iter().flatten().collect(),
};
SimpleStatement: ast::LocatedStatement = {
<s:SmallStatement> "\n" => s,
<s:SmallStatement> ";" => s,
Statement: Vec<ast::LocatedStatement> = {
SimpleStatement,
<s:CompoundStatement> => vec![s],
};
SimpleStatement: Vec<ast::LocatedStatement> = {
<s1:SmallStatement> <s2:(";" SmallStatement)*> ";"? "\n" => {
let mut statements = vec![s1];
statements.extend(s2.into_iter().map(|e| e.1));
statements
}
};
SmallStatement: ast::LocatedStatement = {
@@ -103,9 +105,7 @@ ExpressionStatement: ast::LocatedStatement = {
}
}
},
<loc:@L> <expr:TestOrStarExprList> <op:AugAssign> <e2:TestList> => {
// TODO: this works in most cases:
let rhs = e2.into_iter().next().unwrap();
<loc:@L> <expr:TestOrStarExprList> <op:AugAssign> <rhs:TestList> => {
ast::LocatedStatement {
location: loc,
node: ast::Statement::AugAssign {
@@ -118,31 +118,17 @@ ExpressionStatement: ast::LocatedStatement = {
};
AssignSuffix: ast::Expression = {
"=" <e:TestList> => {
if e.len() > 1 {
ast::Expression::Tuple {
elements: e
}
} else {
e.into_iter().next().unwrap()
}
},
"=" <e:TestList> => e,
"=" <e:YieldExpr> => e,
};
TestOrStarExprList: ast::Expression = {
<e:TestOrStarExpr> <e2:("," TestOrStarExpr)*> <comma:","?> => {
let mut res = vec![e];
res.extend(e2.into_iter().map(|x| x.1));
// First build tuple from first item:
let expr = if (res.len() > 1) || comma.is_some() {
ast::Expression::Tuple { elements: res }
<elements:OneOrMore<TestOrStarExpr>> <comma:","?> => {
if elements.len() == 1 && comma.is_none() {
elements.into_iter().next().unwrap()
} else {
res.into_iter().next().unwrap()
};
expr
ast::Expression::Tuple { elements }
}
}
};
@@ -183,7 +169,7 @@ FlowStatement: ast::LocatedStatement = {
<loc:@L> "return" <t:TestList?> => {
ast::LocatedStatement {
location: loc,
node: ast::Statement::Return { value: t },
node: ast::Statement::Return { value: t.map(Box::new) },
}
},
<loc:@L> <y:YieldExpr> => {
@@ -220,8 +206,9 @@ ImportStatement: ast::LocatedStatement = {
.map(|(n, a)|
ast::SingleImport {
module: n.to_string(),
symbol: None,
alias: a.clone()
symbols: vec![],
alias: a.clone(),
level: 0,
})
.collect()
},
@@ -231,35 +218,30 @@ ImportStatement: ast::LocatedStatement = {
ast::LocatedStatement {
location: loc,
node: ast::Statement::Import {
import_parts: i
.iter()
.map(|(i, a)|
ast::SingleImport {
module: n.to_string(),
symbol: Some(i.to_string()),
alias: a.clone()
})
.collect()
import_parts: vec![
ast::SingleImport {
module: n.0.to_string(),
symbols: i.iter()
.map(|(i, a)|
ast::ImportSymbol {
symbol: i.to_string(),
alias: a.clone(),
})
.collect(),
alias: None,
level: n.1
}]
},
}
},
};
ImportFromLocation: String = {
ImportFromLocation: (String, usize) = {
<dots: "."*> <name:DottedName> => {
let mut r = "".to_string();
for _dot in dots {
r.push_str(".");
}
r.push_str(&name);
r
(name, dots.len())
},
<dots: "."+> => {
let mut r = "".to_string();
for _dot in dots {
r.push_str(".");
}
r
("".to_string(), dots.len())
},
};
@@ -310,15 +292,11 @@ NonlocalStatement: ast::LocatedStatement = {
};
AssertStatement: ast::LocatedStatement = {
<loc:@L> "assert" <t:Test> <m: ("," Test)?> => {
<loc:@L> "assert" <test:Test> <msg: ("," Test)?> => {
ast::LocatedStatement {
location: loc,
node: ast::Statement::Assert {
test: t,
msg: match m {
Some(e) => Some(e.1),
None => None,
}
test, msg: msg.map(|e| e.1)
}
}
},
@@ -335,12 +313,9 @@ CompoundStatement: ast::LocatedStatement = {
};
IfStatement: ast::LocatedStatement = {
<loc:@L> "if" <t:Test> ":" <s1:Suite> <s2:(@L "elif" Test ":" Suite)*> <s3:("else" ":" Suite)?> => {
<loc:@L> "if" <test:Test> ":" <s1:Suite> <s2:(@L "elif" Test ":" Suite)*> <s3:("else" ":" Suite)?> => {
// Determine last else:
let mut last = match s3 {
Some(s) => Some(s.2),
None => None,
};
let mut last = s3.map(|s| s.2);
// handle elif:
for i in s2.into_iter().rev() {
@@ -353,35 +328,30 @@ IfStatement: ast::LocatedStatement = {
ast::LocatedStatement {
location: loc,
node: ast::Statement::If { test: t, body: s1, orelse: last }
node: ast::Statement::If { test, body: s1, orelse: last }
}
},
};
WhileStatement: ast::LocatedStatement = {
<loc:@L> "while" <e:Test> ":" <s:Suite> <s2:("else" ":" Suite)?> => {
let or_else = match s2 {
Some(s) => Some(s.2),
None => None,
};
<loc:@L> "while" <test:Test> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
let or_else = s2.map(|s| s.2);
ast::LocatedStatement {
location: loc,
node: ast::Statement::While { test: e, body: s, orelse: or_else },
node: ast::Statement::While { test, body, orelse: or_else },
}
},
};
ForStatement: ast::LocatedStatement = {
<loc:@L> "for" <e:ExpressionList> "in" <t:TestList> ":" <s:Suite> <s2:("else" ":" Suite)?> => {
let or_else = match s2 {
Some(s) => Some(s.2),
None => None,
};
<loc:@L> <is_async:"async"?> "for" <target:ExpressionList> "in" <iter:TestList> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
let orelse = s2.map(|s| s.2);
ast::LocatedStatement {
location: loc,
node: ast::Statement::For {
target: e,
iter: t, body: s, orelse: or_else
node: if is_async.is_some() {
ast::Statement::AsyncFor { target, iter, body, orelse }
} else {
ast::Statement::For { target, iter, body, orelse }
},
}
},
@@ -389,14 +359,8 @@ ForStatement: ast::LocatedStatement = {
TryStatement: ast::LocatedStatement = {
<loc:@L> "try" ":" <body:Suite> <handlers:ExceptClause*> <else_suite:("else" ":" Suite)?> <finally:("finally" ":" Suite)?> => {
let or_else = match else_suite {
Some(s) => Some(s.2),
None => None,
};
let finalbody = match finally {
Some(s) => Some(s.2),
None => None,
};
let or_else = else_suite.map(|s| s.2);
let finalbody = finally.map(|s| s.2);
ast::LocatedStatement {
location: loc,
node: ast::Statement::Try {
@@ -437,62 +401,59 @@ WithStatement: ast::LocatedStatement = {
WithItem: ast::WithItem = {
<t:Test> <n:("as" Expression)?> => {
let optional_vars = match n {
Some(val) => Some(val.1),
None => None,
};
let optional_vars = n.map(|val| val.1);
ast::WithItem { context_expr: t, optional_vars }
},
};
FuncDef: ast::LocatedStatement = {
<d:Decorator*> <loc:@L> "def" <i:Identifier> <a:Parameters> <r:("->" Test)?> ":" <s:Suite> => {
<d:Decorator*> <loc:@L> <is_async:"async"?> "def" <i:Identifier> <a:Parameters> <r:("->" Test)?> ":" <s:Suite> => {
ast::LocatedStatement {
location: loc,
node: ast::Statement::FunctionDef {
name: i,
args: a,
body: s,
decorator_list: d,
returns: r.map(|x| x.1),
}
node: if is_async.is_some() {
ast::Statement::AsyncFunctionDef {
name: i,
args: a,
body: s,
decorator_list: d,
returns: r.map(|x| x.1),
}
} else {
ast::Statement::FunctionDef {
name: i,
args: a,
body: s,
decorator_list: d,
returns: r.map(|x| x.1),
}
}
}
},
};
Parameters: ast::Parameters = {
"(" <a: (TypedArgsList<TypedParameter>)?> ")" => {
match a {
Some(a) => a,
None => Default::default(),
}
},
"(" <a: (ParameterList<TypedParameter>)?> ")" => a.unwrap_or_else(Default::default),
};
// parameters are (String, None), kwargs are (String, Some(Test)) where Test is
// the default
// Note that this is a macro which is used once for function defs, and
// once for lambda defs.
TypedArgsList<ArgType>: ast::Parameters = {
<param1:TypedParameters<ArgType>> <args2:("," ParameterListStarArgs<ArgType>)?> => {
ParameterList<ArgType>: ast::Parameters = {
<param1:ParameterDefs<ArgType>> <args2:("," ParameterListStarArgs<ArgType>)?> ","? => {
let (names, default_elements) = param1;
// Now gather rest of parameters:
let (vararg, kwonlyargs, kw_defaults, kwarg) = match args2 {
Some((_, x)) => x,
None => (None, vec![], vec![], None),
};
let (vararg, kwonlyargs, kw_defaults, kwarg) = args2.map_or((None, vec![], vec![], None), |x| x.1);
ast::Parameters {
args: names,
kwonlyargs: kwonlyargs,
vararg: vararg,
kwarg: kwarg,
vararg: vararg.into(),
kwarg: kwarg.into(),
defaults: default_elements,
kw_defaults: kw_defaults,
}
},
<param1:TypedParameters<ArgType>> <kw:("," KwargParameter<ArgType>)> => {
<param1:ParameterDefs<ArgType>> <kw:("," KwargParameter<ArgType>)> ","? => {
let (names, default_elements) = param1;
// Now gather rest of parameters:
@@ -504,29 +465,29 @@ TypedArgsList<ArgType>: ast::Parameters = {
ast::Parameters {
args: names,
kwonlyargs: kwonlyargs,
vararg: vararg,
kwarg: kwarg,
vararg: vararg.into(),
kwarg: kwarg.into(),
defaults: default_elements,
kw_defaults: kw_defaults,
}
},
<params:ParameterListStarArgs<ArgType>> => {
<params:ParameterListStarArgs<ArgType>> ","? => {
let (vararg, kwonlyargs, kw_defaults, kwarg) = params;
ast::Parameters {
args: vec![],
kwonlyargs: kwonlyargs,
vararg: vararg,
kwarg: kwarg,
vararg: vararg.into(),
kwarg: kwarg.into(),
defaults: vec![],
kw_defaults: kw_defaults,
}
},
<kw:KwargParameter<ArgType>> => {
<kw:KwargParameter<ArgType>> ","? => {
ast::Parameters {
args: vec![],
kwonlyargs: vec![],
vararg: None,
kwarg: Some(kw),
vararg: ast::Varargs::None,
kwarg: Some(kw).into(),
defaults: vec![],
kw_defaults: vec![],
}
@@ -535,8 +496,8 @@ TypedArgsList<ArgType>: ast::Parameters = {
// Use inline here to make sure the "," is not creating an ambiguity.
#[inline]
TypedParameters<ArgType>: (Vec<ast::Parameter>, Vec<ast::Expression>) = {
<param1:TypedParameterDef<ArgType>> <param2:("," TypedParameterDef<ArgType>)*> => {
ParameterDefs<ArgType>: (Vec<ast::Parameter>, Vec<ast::Expression>) = {
<param1:ParameterDef<ArgType>> <param2:("," ParameterDef<ArgType>)*> => {
// Combine first parameters:
let mut args = vec![param1];
args.extend(param2.into_iter().map(|x| x.1));
@@ -564,7 +525,7 @@ TypedParameters<ArgType>: (Vec<ast::Parameter>, Vec<ast::Expression>) = {
}
};
TypedParameterDef<ArgType>: (ast::Parameter, Option<ast::Expression>) = {
ParameterDef<ArgType>: (ast::Parameter, Option<ast::Expression>) = {
<i:ArgType> => (i, None),
<i:ArgType> "=" <e:Test> => (i, Some(e)),
};
@@ -580,8 +541,11 @@ TypedParameter: ast::Parameter = {
},
};
// Use inline here to make sure the "," is not creating an ambiguity.
// TODO: figure out another grammar that makes this inline no longer required.
#[inline]
ParameterListStarArgs<ArgType>: (Option<Option<ast::Parameter>>, Vec<ast::Parameter>, Vec<Option<ast::Expression>>, Option<Option<ast::Parameter>>) = {
"*" <va:ArgType?> <kw:("," TypedParameterDef<ArgType>)*> <kwarg:("," KwargParameter<ArgType>)?> => {
"*" <va:ArgType?> <kw:("," ParameterDef<ArgType>)*> <kwarg:("," KwargParameter<ArgType>)?> => {
// Extract keyword arguments:
let mut kwonlyargs = vec![];
let mut kw_defaults = vec![];
@@ -590,10 +554,7 @@ ParameterListStarArgs<ArgType>: (Option<Option<ast::Parameter>>, Vec<ast::Parame
kw_defaults.push(value);
}
let kwarg = match kwarg {
Some((_, name)) => Some(name),
None => None,
};
let kwarg = kwarg.map(|n| n.1);
(Some(va), kwonlyargs, kw_defaults, kwarg)
}
@@ -649,66 +610,59 @@ Decorator: ast::Expression = {
};
YieldExpr: ast::Expression = {
"yield" <ex:TestList?> => {
ast::Expression::Yield {
value: ex.map(|expr| Box::new(
if expr.len() > 1 {
ast::Expression::Tuple { elements: expr }
} else {
expr.into_iter().next().unwrap()
})
)
}
},
"yield" "from" <e:Test> => {
ast::Expression::YieldFrom {
value: Box::new(e),
}
},
"yield" <value:TestList?> => ast::Expression::Yield { value: value.map(Box::new) },
"yield" "from" <e:Test> => ast::Expression::YieldFrom { value: Box::new(e) },
};
Test: ast::Expression = {
<e:OrTest> <c: ("if" OrTest "else" Test)?> => {
match c {
Some(c) => {
ast::Expression::IfExpression {
test: Box::new(c.1),
body: Box::new(e),
orelse: Box::new(c.3),
}
},
None => e,
<expr:OrTest> <condition: ("if" OrTest "else" Test)?> => {
if let Some(c) = condition {
ast::Expression::IfExpression {
test: Box::new(c.1),
body: Box::new(expr),
orelse: Box::new(c.3),
}
} else {
expr
}
},
<e:LambdaDef> => e,
LambdaDef,
};
LambdaDef: ast::Expression = {
"lambda" <p:TypedArgsList<UntypedParameter>?> ":" <b:Test> =>
"lambda" <p:ParameterList<UntypedParameter>?> ":" <body:Test> =>
ast::Expression::Lambda {
args: p.unwrap_or(Default::default()),
body:Box::new(b)
body: Box::new(body)
}
}
OrTest: ast::Expression = {
<e:AndTest> => e,
AndTest,
<e1:OrTest> "or" <e2:AndTest> => ast::Expression::BoolOp { a: Box::new(e1), op: ast::BooleanOperator::Or, b: Box::new(e2) },
};
AndTest: ast::Expression = {
<e:NotTest> => e,
NotTest,
<e1:AndTest> "and" <e2:NotTest> => ast::Expression::BoolOp { a: Box::new(e1), op: ast::BooleanOperator::And, b: Box::new(e2) },
};
NotTest: ast::Expression = {
"not" <e:NotTest> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Not },
<e:Comparison> => e,
Comparison,
};
Comparison: ast::Expression = {
<e1:Comparison> <op:CompOp> <e2:Expression> => ast::Expression::Compare { a: Box::new(e1), op: op, b: Box::new(e2) },
<e:Expression> => e,
<e:Expression> <comparisons:(CompOp Expression)+> => {
let mut vals = vec![e];
let mut ops = vec![];
for x in comparisons {
ops.push(x.0);
vals.push(x.1);
}
ast::Expression::Compare { vals, ops }
},
Expression,
};
CompOp: ast::Comparison = {
@@ -726,7 +680,7 @@ CompOp: ast::Comparison = {
Expression: ast::Expression = {
<e1:Expression> "|" <e2:XorExpression> => ast::Expression::Binop { a: Box::new(e1), op: ast::Operator::BitOr, b: Box::new(e2) },
<e:XorExpression> => e,
XorExpression,
};
XorExpression: ast::Expression = {
@@ -776,7 +730,7 @@ Factor: ast::Expression = {
"+" <e:Factor> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Pos },
"-" <e:Factor> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Neg },
"~" <e:Factor> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Inv },
<e:Power> => e,
Power,
};
Power: ast::Expression = {
@@ -789,14 +743,38 @@ Power: ast::Expression = {
};
AtomExpr: ast::Expression = {
<e:Atom> => e,
<f:AtomExpr> "(" <a:ArgumentList> ")" => ast::Expression::Call { function: Box::new(f), args: a.0, keywords: a.1 },
<e:AtomExpr> "[" <s:Subscript> "]" => ast::Expression::Subscript { a: Box::new(e), b: Box::new(s) },
<e:AtomExpr> "." <n:Identifier> => ast::Expression::Attribute { value: Box::new(e), name: n },
<is_await:"await"?> <atom:AtomExpr2> => {
if is_await.is_some() {
ast::Expression::Await { value: Box::new(atom) }
} else {
atom
}
}
}
AtomExpr2: ast::Expression = {
Atom,
<f:AtomExpr2> "(" <a:ArgumentList> ")" => ast::Expression::Call { function: Box::new(f), args: a.0, keywords: a.1 },
<e:AtomExpr2> "[" <s:SubscriptList> "]" => ast::Expression::Subscript { a: Box::new(e), b: Box::new(s) },
<e:AtomExpr2> "." <n:Identifier> => ast::Expression::Attribute { value: Box::new(e), name: n },
};
SubscriptList: ast::Expression = {
<s1:Subscript> <s2:("," Subscript)*> ","? => {
if s2.is_empty() {
s1
} else {
let mut dims = vec![s1];
for x in s2 {
dims.push(x.1)
}
ast::Expression::Tuple { elements: dims }
}
}
};
Subscript: ast::Expression = {
<e:Test> => e,
Test,
<e1:Test?> ":" <e2:Test?> <e3:SliceOp?> => {
let s1 = e1.unwrap_or(ast::Expression::None);
let s2 = e2.unwrap_or(ast::Expression::None);
@@ -810,30 +788,17 @@ SliceOp: ast::Expression = {
}
Atom: ast::Expression = {
<s:StringGroup> => ast::Expression::String { value: s },
<b:Bytes> => ast::Expression::Bytes { value: b },
<n:Number> => ast::Expression::Number { value: n },
<i:Identifier> => ast::Expression::Identifier { name: i },
<value:StringGroup> => ast::Expression::String { value },
<value:Bytes> => ast::Expression::Bytes { value },
<value:Number> => ast::Expression::Number { value },
<name:Identifier> => ast::Expression::Identifier { name },
"[" <e:TestListComp?> "]" => {
let elements = e.unwrap_or(Vec::new());
ast::Expression::List { elements }
},
"[" <e:TestListComp2> "]" => {
// List comprehension:
e
},
"(" <e:TestList?> <trailing_comma:","?> ")" => {
match e {
None => ast::Expression::Tuple { elements: Vec::new() },
Some(elements) => {
if elements.len() == 1 && trailing_comma.is_none() {
// This is "(e)", which is equivalent to "e"
elements.into_iter().next().unwrap()
} else {
ast::Expression::Tuple { elements }
}
}
}
"[" <e:TestListComp2> "]" => e,
"(" <elements:TestList?> ")" => {
elements.unwrap_or(ast::Expression::Tuple { elements: Vec::new() })
},
"(" <e:Test> <c:CompFor> ")" => {
ast::Expression::Comprehension {
@@ -852,9 +817,7 @@ Atom: ast::Expression = {
};
TestListComp: Vec<ast::Expression> = {
<e:OneOrMore<TestOrStarExpr>> <_trailing_comma:","?> => {
e
},
<e:OneOrMore<TestOrStarExpr>> <_trailing_comma:","?> => e,
};
TestListComp2: ast::Expression = {
@@ -866,10 +829,8 @@ TestListComp2: ast::Expression = {
},
};
TestDict: Vec<(ast::Expression, ast::Expression)> = {
<e1:OneOrMore<DictEntry>> <_trailing_comma:","?> => {
e1
}
TestDict: Vec<(Option<ast::Expression>, ast::Expression)> = {
<elements:OneOrMore<DictElement>> <_trailing_comma:","?> => elements,
};
TestDictComp: ast::Expression = {
@@ -885,10 +846,13 @@ DictEntry: (ast::Expression, ast::Expression) = {
<e1: Test> ":" <e2: Test> => (e1, e2),
};
DictElement: (Option<ast::Expression>, ast::Expression) = {
<e:DictEntry> => (Some(e.0), e.1),
"**" <e:Expression> => (None, e),
};
TestSet: Vec<ast::Expression> = {
<e1:OneOrMore<Test>> ","? => {
e1
}
<e1:OneOrMore<Test>> ","? => e1
};
TestSetComp: ast::Expression = {
@@ -900,31 +864,37 @@ TestSetComp: ast::Expression = {
}
};
ExpressionOrStarExpression = {
Expression,
StarExpr
};
ExpressionList: ast::Expression = {
<e: ExpressionList2> => {
if e.len() == 1 {
e.into_iter().next().unwrap()
<elements: OneOrMore<ExpressionOrStarExpression>> <trailing_comma:","?> => {
if elements.len() == 1 && trailing_comma.is_none() {
elements.into_iter().next().unwrap()
} else {
ast::Expression::Tuple { elements: e }
ast::Expression::Tuple { elements }
}
},
};
ExpressionList2: Vec<ast::Expression> = {
<e1:Expression> <e2:("," Expression)*> ","? => {
let mut l = vec![e1];
l.extend(e2.into_iter().map(|x| x.1));
l
},
<elements:OneOrMore<Expression>> ","? => elements,
};
#[inline]
TestList: Vec<ast::Expression> = {
<e1:Test> <e2: ("," Test)*> => {
let mut l = vec![e1];
l.extend(e2.into_iter().map(|x| x.1));
l
}
// A test list is one of:
// - a list of expressions
// - a single expression
// - a single expression followed by a trailing comma
TestList: ast::Expression = {
<elements:OneOrMore<Test>> <trailing_comma: ","?> => {
if elements.len() == 1 && trailing_comma.is_none() {
elements.into_iter().next().unwrap()
} else {
ast::Expression::Tuple { elements }
}
}
};
// Test
@@ -933,27 +903,16 @@ StarExpr: ast::Expression = {
};
// Comprehensions:
CompFor: Vec<ast::Comprehension> = {
<c:SingleForComprehension+> => c,
};
CompFor: Vec<ast::Comprehension> = <c:SingleForComprehension+> => c;
SingleForComprehension: ast::Comprehension = {
"for" <e:ExpressionList> "in" <i:OrTest> <c2:ComprehensionIf*> => {
ast::Comprehension {
target: e,
iter: i,
ifs: c2,
}
"for" <target:ExpressionList> "in" <iter:OrTest> <c2:ComprehensionIf*> => {
ast::Comprehension { target, iter, ifs: c2 }
}
};
ExpressionNoCond: ast::Expression = {
OrTest,
};
ComprehensionIf: ast::Expression = {
"if" <c:ExpressionNoCond> => c,
};
ExpressionNoCond: ast::Expression = OrTest;
ComprehensionIf: ast::Expression = "if" <c:ExpressionNoCond> => c;
ArgumentList: (Vec<ast::Expression>, Vec<ast::Keyword>) = {
<e: Comma<FunctionArgument>> => {
@@ -965,8 +924,15 @@ ArgumentList: (Vec<ast::Expression>, Vec<ast::Keyword>) = {
keywords.push(ast::Keyword { name: n, value: value });
},
None => {
if keywords.len() > 0 {
panic!("positional argument follows keyword argument");
// Allow starred args after keyword arguments.
let is_starred = if let ast::Expression::Starred { .. } = &value {
true
} else {
false
};
if keywords.len() > 0 && !is_starred {
panic!("positional argument follows keyword argument {:?}", keywords);
};
args.push(value);
},
@@ -1010,8 +976,8 @@ OneOrMore<T>: Vec<T> = {
};
Number: ast::Number = {
<s:int> => { ast::Number::Integer { value: s } },
<s:float> => { ast::Number::Float { value: s } },
<value:int> => { ast::Number::Integer { value } },
<value:float> => { ast::Number::Float { value } },
<s:complex> => { ast::Number::Complex { real: s.0, imag: s.1 } },
};
@@ -1101,6 +1067,8 @@ extern {
"and" => lexer::Tok::And,
"as" => lexer::Tok::As,
"assert" => lexer::Tok::Assert,
"async" => lexer::Tok::Async,
"await" => lexer::Tok::Await,
"break" => lexer::Tok::Break,
"class" => lexer::Tok::Class,
"continue" => lexer::Tok::Continue,

View File

@@ -3,7 +3,7 @@
use num_bigint::BigInt;
/// Python source code can be tokenized in a sequence of these tokens.
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum Tok {
Name { name: String },
Int { value: BigInt },
@@ -17,6 +17,7 @@ pub enum Tok {
StartProgram,
StartStatement,
StartExpression,
EndOfFile,
Lpar,
Rpar,
Lsqb,
@@ -72,6 +73,8 @@ pub enum Tok {
And,
As,
Assert,
Async,
Await,
Break,
Class,
Continue,

View File

@@ -3,24 +3,22 @@ extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate rustpython_parser;
extern crate rustpython_vm;
extern crate rustyline;
use clap::{App, Arg};
use rustpython_parser::error::ParseError;
use rustpython_compiler::{compile, error::CompileError, error::CompileErrorType};
use rustpython_parser::error::ParseErrorType;
use rustpython_vm::{
compile,
error::CompileError,
frame::ScopeRef,
frame::Scope,
import,
obj::objstr,
print_exception,
pyobject::{AttributeProtocol, PyResult},
pyobject::{ItemProtocol, PyResult},
util, VirtualMachine,
};
use rustyline::{error::ReadlineError, Editor};
use std::path::{Path, PathBuf};
use std::path::PathBuf;
fn main() {
env_logger::init();
@@ -51,50 +49,46 @@ fn main() {
.get_matches();
// Construct vm:
let mut vm = VirtualMachine::new();
let vm = VirtualMachine::new();
let res = import::init_importlib(&vm, true);
handle_exception(&vm, res);
// Figure out if a -c option was given:
let result = if let Some(command) = matches.value_of("c") {
run_command(&mut vm, command.to_string())
run_command(&vm, command.to_string())
} else if let Some(module) = matches.value_of("m") {
run_module(&mut vm, module)
run_module(&vm, module)
} else {
// Figure out if a script was passed:
match matches.value_of("script") {
None => run_shell(&mut vm),
Some(filename) => run_script(&mut vm, filename),
None => run_shell(&vm),
Some(filename) => run_script(&vm, filename),
}
};
// See if any exception leaked out:
handle_exception(&mut vm, result);
handle_exception(&vm, result);
}
fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: String) -> PyResult {
let code_obj = compile::compile(
source,
&compile::Mode::Exec,
source_path,
vm.ctx.code_type(),
)
.map_err(|err| {
let syntax_error = vm.context().exceptions.syntax_error.clone();
vm.new_exception(syntax_error, err.to_string())
})?;
fn _run_string(vm: &VirtualMachine, source: &str, source_path: String) -> PyResult {
let code_obj = vm
.compile(source, &compile::Mode::Exec, source_path.clone())
.map_err(|err| vm.new_syntax_error(&err))?;
// trace!("Code object: {:?}", code_obj.borrow());
let builtins = vm.get_builtin_scope();
let vars = vm.context().new_scope(Some(builtins)); // Keep track of local variables
vm.run_code_obj(code_obj, vars)
let attrs = vm.ctx.new_dict();
attrs.set_item("__file__", vm.new_str(source_path), vm)?;
vm.run_code_obj(code_obj, Scope::with_builtins(None, attrs, vm))
}
fn handle_exception(vm: &mut VirtualMachine, result: PyResult) {
fn handle_exception(vm: &VirtualMachine, result: PyResult) {
if let Err(err) = result {
print_exception(vm, &err);
std::process::exit(1);
}
}
fn run_command(vm: &mut VirtualMachine, mut source: String) -> PyResult {
fn run_command(vm: &VirtualMachine, mut source: String) -> PyResult {
debug!("Running command {}", source);
// This works around https://github.com/RustPython/RustPython/issues/17
@@ -102,43 +96,97 @@ fn run_command(vm: &mut VirtualMachine, mut source: String) -> PyResult {
_run_string(vm, &source, "<stdin>".to_string())
}
fn run_module(vm: &mut VirtualMachine, module: &str) -> PyResult {
fn run_module(vm: &VirtualMachine, module: &str) -> PyResult {
debug!("Running module {}", module);
let current_path = PathBuf::from(".");
import::import_module(vm, current_path, module)
vm.import(module, &vm.ctx.new_tuple(vec![]), 0)
}
fn run_script(vm: &mut VirtualMachine, script_file: &str) -> PyResult {
fn run_script(vm: &VirtualMachine, script_file: &str) -> PyResult {
debug!("Running file {}", script_file);
// Parse an ast from it:
let file_path = Path::new(script_file);
match util::read_file(file_path) {
let file_path = PathBuf::from(script_file);
let file_path = if file_path.is_file() {
file_path
} else if file_path.is_dir() {
let main_file_path = file_path.join("__main__.py");
if main_file_path.is_file() {
main_file_path
} else {
error!(
"can't find '__main__' module in '{}'",
file_path.to_str().unwrap()
);
std::process::exit(1);
}
} else {
error!(
"can't open file '{}': No such file or directory",
file_path.to_str().unwrap()
);
std::process::exit(1);
};
let dir = file_path.parent().unwrap().to_str().unwrap().to_string();
let sys_path = vm.get_attribute(vm.sys_module.clone(), "path").unwrap();
vm.call_method(&sys_path, "insert", vec![vm.new_int(0), vm.new_str(dir)])?;
match util::read_file(&file_path) {
Ok(source) => _run_string(vm, &source, file_path.to_str().unwrap().to_string()),
Err(err) => {
error!("Failed reading file: {:?}", err.kind());
error!(
"Failed reading file '{}': {:?}",
file_path.to_str().unwrap(),
err.kind()
);
std::process::exit(1);
}
}
}
fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: ScopeRef) -> Result<(), CompileError> {
match compile::compile(
source,
&compile::Mode::Single,
"<stdin>".to_string(),
vm.ctx.code_type(),
) {
#[test]
fn test_run_script() {
let vm = VirtualMachine::new();
// test file run
let r = run_script(&vm, "tests/snippets/dir_main/__main__.py");
assert!(r.is_ok());
// test module run
let r = run_script(&vm, "tests/snippets/dir_main");
assert!(r.is_ok());
}
fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> Result<(), CompileError> {
match vm.compile(source, &compile::Mode::Single, "<stdin>".to_string()) {
Ok(code) => {
if let Err(err) = vm.run_code_obj(code, scope) {
print_exception(vm, &err);
match vm.run_code_obj(code, scope.clone()) {
Ok(value) => {
// Save non-None values as "_"
use rustpython_vm::pyobject::{IdProtocol, IntoPyObject};
if !value.is(&vm.get_none()) {
let key = objstr::PyString::from("_").into_pyobject(vm);
scope.globals.set_item(key, value, vm).unwrap();
}
}
Err(err) => {
print_exception(vm, &err);
}
}
Ok(())
}
// Don't inject syntax errors for line continuation
Err(err @ CompileError::Parse(ParseError::EOF(_))) => Err(err),
Err(
err @ CompileError {
error: CompileErrorType::Parse(ParseErrorType::EOF),
..
},
) => Err(err),
Err(err) => {
let syntax_error = vm.context().exceptions.syntax_error.clone();
let exc = vm.new_exception(syntax_error, format!("{}", err));
let exc = vm.new_syntax_error(&err);
print_exception(vm, &exc);
Err(err)
}
@@ -160,13 +208,20 @@ fn get_history_path() -> PathBuf {
xdg_dirs.place_cache_file("repl_history.txt").unwrap()
}
fn run_shell(vm: &mut VirtualMachine) -> PyResult {
fn get_prompt(vm: &VirtualMachine, prompt_name: &str) -> String {
vm.get_attribute(vm.sys_module.clone(), prompt_name)
.ok()
.as_ref()
.map(objstr::get_value)
.unwrap_or_else(String::new)
}
fn run_shell(vm: &VirtualMachine) -> PyResult {
println!(
"Welcome to the magnificent Rust Python {} interpreter",
"Welcome to the magnificent Rust Python {} interpreter \u{1f631} \u{1f596}",
crate_version!()
);
let builtins = vm.get_builtin_scope();
let vars = vm.context().new_scope(Some(builtins)); // Keep track of local variables
let vars = vm.new_scope_with_builtins();
// Read a single line:
let mut input = String::new();
@@ -178,25 +233,38 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
println!("No previous history.");
}
let ps1 = &objstr::get_value(&vm.sys_module.get_attr("ps1").unwrap());
let ps2 = &objstr::get_value(&vm.sys_module.get_attr("ps2").unwrap());
let mut prompt = ps1;
let mut continuing = false;
loop {
match repl.readline(prompt) {
let prompt = if continuing {
get_prompt(vm, "ps2")
} else {
get_prompt(vm, "ps1")
};
match repl.readline(&prompt) {
Ok(line) => {
debug!("You entered {:?}", line);
input.push_str(&line);
input.push_str("\n");
repl.add_history_entry(line.trim_end().as_ref());
input.push('\n');
repl.add_history_entry(line.trim_end());
if continuing {
if line.is_empty() {
continuing = false;
} else {
continue;
}
}
match shell_exec(vm, &input, vars.clone()) {
Err(CompileError::Parse(ParseError::EOF(_))) => {
prompt = ps2;
Err(CompileError {
error: CompileErrorType::Parse(ParseErrorType::EOF),
..
}) => {
continuing = true;
continue;
}
_ => {
prompt = ps1;
input = String::new();
}
}
@@ -204,7 +272,8 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
Err(ReadlineError::Interrupted) => {
// TODO: Raise a real KeyboardInterrupt exception
println!("^C");
break;
continuing = false;
continue;
}
Err(ReadlineError::Eof) => {
break;

1
tests/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
snippets/whats_left_*.py

View File

@@ -13,6 +13,7 @@ pip install pipenv
if [ $CODE_COVERAGE = "true" ]
then
find . -name '*.gcda' -delete
find . -name '*.gcno' -delete
export CARGO_INCREMENTAL=0
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads"
@@ -31,7 +32,7 @@ then
zip -0 ccov.zip `find . \( -name "rustpython*.gc*" \) -print`
# Install grcov
curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf -
curl -L https://github.com/mozilla/grcov/releases/download/v0.4.2/grcov-linux-x86_64.tar.bz2 | tar jxf -
./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" -p "x" > lcov.info

View File

@@ -10,4 +10,4 @@ pytest = "*"
[dev-packages]
[requires]
python_version = "3"
python_version = "3.6"

99
tests/Pipfile.lock generated
View File

@@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "b2d2d68e7d4330ff8d889816c56b9cee4bf54962c86b2c11382108176a201ec8"
"sha256": "ce98de5914393363a8cb86a4753b3964caa53a4659a403a3ef357e2086363ef7"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3"
"python_version": "3.6"
},
"sources": [
{
@@ -16,74 +16,99 @@
]
},
"default": {
"aenum": {
"hashes": [
"sha256:3df9b84cce5dc9ed77c337079f97b66c44c0053eb87d6f4d46b888dc45801e38",
"sha256:7a77c205c4bc9d7fe9bd73b3193002d724aebf5909fa0d297534208953891ec8",
"sha256:a3208e4b28db3a7b232ff69b934aef2ea1bf27286d9978e1e597d46f490e4687"
],
"version": "==2.1.2"
},
"atomicwrites": {
"hashes": [
"sha256:240831ea22da9ab882b551b31d4225591e5e447a68c5e188db5b89ca1d487585",
"sha256:a24da68318b08ac9c9c45029f4a10371ab5b20e4226738e150e6e7c571630ae6"
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
"sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
],
"version": "==1.1.5"
"version": "==1.3.0"
},
"attrs": {
"hashes": [
"sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265",
"sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b"
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
],
"version": "==18.1.0"
"version": "==19.1.0"
},
"bytecode": {
"hashes": [
"sha256:cc6931151c7f0a542f8cf7619fe1639af3b9529c4678860fa3239397cb0f7de0",
"sha256:e464004d4a9eeeca987cb4950dba11b827964b6c90cd331c1f20abd2dab3c962"
"sha256:68b1d591c7af0e5c5273e028d3cc0299fbe374dff0cf9149ec7e569be0c573e7",
"sha256:c43d5052cbff076bfdf5b0b93ff6c76e461aab628ce47d30637bb200b6b7bb2c"
],
"index": "pypi",
"version": "==0.7.0"
"version": "==0.8.0"
},
"importlib-metadata": {
"hashes": [
"sha256:6dfd58dfe281e8d240937776065dd3624ad5469c835248219bd16cf2e12dbeb7",
"sha256:cb6ee23b46173539939964df59d3d72c3e0c1b5d54b84f1d8a7e912fe43612db"
],
"version": "==0.18"
},
"more-itertools": {
"hashes": [
"sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092",
"sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e",
"sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"
"sha256:2112d2ca570bb7c3e53ea1a35cd5df42bb0fd10c45f0fb97178679c3c03d64c7",
"sha256:c3e4748ba1aad8dba30a4886b0b1a2004f9a863837b8654e7059eebf727afa5a"
],
"version": "==4.3.0"
"markers": "python_version > '2.7'",
"version": "==7.0.0"
},
"packaging": {
"hashes": [
"sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af",
"sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"
],
"version": "==19.0"
},
"pluggy": {
"hashes": [
"sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1",
"sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1"
"sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc",
"sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c"
],
"markers": "python_version != '3.3.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.2.*'",
"version": "==0.7.1"
"version": "==0.12.0"
},
"py": {
"hashes": [
"sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7",
"sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e"
"sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa",
"sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"
],
"markers": "python_version != '3.3.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.2.*'",
"version": "==1.5.4"
"version": "==1.8.0"
},
"pyparsing": {
"hashes": [
"sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a",
"sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"
],
"version": "==2.4.0"
},
"pytest": {
"hashes": [
"sha256:86a8dbf407e437351cef4dba46736e9c5a6e3c3ac71b2e942209748e76ff2086",
"sha256:e74466e97ac14582a8188ff4c53e6cc3810315f342f6096899332ae864c1d432"
"sha256:4a784f1d4f2ef198fe9b7aef793e9fa1a3b2f84e822d9b3a64a181293a572d45",
"sha256:926855726d8ae8371803f7b2e6ec0a69953d9c6311fa7c3b6c1b929ff92d27da"
],
"index": "pypi",
"version": "==3.7.1"
"version": "==4.6.3"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.11.0"
"version": "==1.12.0"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
],
"version": "==0.1.7"
},
"zipp": {
"hashes": [
"sha256:8c1019c6aad13642199fbe458275ad6a84907634cc9f0989877ccc4a2840139d",
"sha256:ca943a7e809cc12257001ccfb99e3563da9af99d52f261725e96dfe0f9275bc3"
],
"version": "==0.5.1"
}
},
"develop": {}

View File

@@ -1,4 +1,3 @@
# Test snippets
This directory contains two sets of test snippets which can be run in
@@ -6,6 +5,10 @@ Python. The `snippets/` directory contains functional tests, and the
`benchmarks/` directory contains snippets for use in benchmarking
RustPython's performance.
## Generates the test for not implemented methods
run using cpython not_impl_gen.py it automatically generate a
test snippet to check not yet implemented methods
## Running with CPython + RustPython
@@ -15,4 +18,3 @@ compilation to bytecode. When this is done, run the bytecode with rustpython.
## Running with RustPython
The other option is to run all snippets with RustPython.

View File

@@ -0,0 +1,12 @@
not_implemented = [(name, method)
for name, (val, methods) in expected_methods.items()
for method in methods
if not hasattr(val, method)]
for r in not_implemented:
print(r[0], ".", r[1], sep="")
if not not_implemented:
print("Not much \\o/")
if platform.python_implementation() == "CPython":
assert len(not_implemented) == 0, "CPython should have all the methods"

View File

@@ -0,0 +1,7 @@
# WARNING: THIS IS AN AUTOMATICALLY GENERATED FILE
# EDIT tests/not_impl_gen.py, NOT THIS FILE.
# RESULTS OF THIS TEST DEPEND ON THE CPYTHON
# VERSION USED TO RUN not_impl_gen.py
import platform

View File

@@ -0,0 +1,32 @@
rustpymods = list(
map(
lambda mod: mod[0],
filter(
lambda mod: (mod[1] == "" or mod[1] == ".py") and "LICENSE" not in mod[0],
map(os.path.splitext, os.listdir(libdir)),
),
)
)
rustpymods += list(sys.builtin_module_names)
rustpymods = dict(map(
lambda mod: (
mod,
set(dir(__import__(mod)))
if mod not in ("this", "antigravity")
else None,
),
rustpymods
))
for modname, cpymod in cpymods.items():
if modname in rustpymods:
rustpymod = rustpymods[modname]
if rustpymod:
for item in cpymod - rustpymod:
print(f"{modname}.{item}")
else:
print(f"{modname} (entire module)")

View File

@@ -0,0 +1,8 @@
# WARNING: THIS IS AN AUTOMATICALLY GENERATED FILE
# EDIT tests/not_impl_mods_gen.sh, NOT THIS FILE.
# RESULTS OF THIS TEST DEPEND ON THE CPYTHON
# VERSION AND PYTHON ENVIRONMENT USED
# TO RUN not_impl_mods_gen.py
import sys
import os

105
tests/not_impl_gen.py Normal file
View File

@@ -0,0 +1,105 @@
# It's recommended to run this with `python3 -I not_impl_gen.py`, to make sure
# that nothing in your global Python environment interferes with what's being
# extracted here.
import pkgutil
import os
import sys
sys.path = list(
filter(
lambda path: "site-packages" not in path and "dist-packages" not in path,
sys.path,
)
)
def attr_is_not_inherited(type_, attr):
"""
returns True if type_'s attr is not inherited from any of its base classes
"""
bases = type_.__mro__[1:]
return getattr(type_, attr) not in (getattr(base, attr, None) for base in bases)
def gen_methods(header, footer, output):
objects = [
bool,
bytearray,
bytes,
complex,
dict,
float,
frozenset,
int,
list,
memoryview,
range,
set,
str,
tuple,
object,
]
output.write(header.read())
output.write("expected_methods = {\n")
for obj in objects:
output.write(f" '{obj.__name__}': ({obj.__name__}, [\n")
output.write(
"\n".join(
f" {attr!r},"
for attr in dir(obj)
if attr_is_not_inherited(obj, attr)
)
)
output.write("\n ])," + ("\n" if objects[-1] == obj else "\n\n"))
output.write("}\n\n")
output.write(footer.read())
def get_module_methods(name):
try:
return set(dir(__import__(name))) if name not in ("this", "antigravity") else None
except ModuleNotFoundError:
return None
def gen_modules(header, footer, output):
output.write(header.read())
modules = dict(
map(
lambda mod: (
mod.name,
# check name b/c modules listed have side effects on import,
# e.g. printing something or opening a webpage
get_module_methods(mod.name)
),
pkgutil.iter_modules(),
)
)
print(
f"""
cpymods = {modules!r}
libdir = {os.path.abspath("../Lib/")!r}
""",
file=output,
)
output.write(footer.read())
gen_funcs = {"methods": gen_methods, "modules": gen_modules}
for name, gen_func in gen_funcs.items():
gen_func(
header=open(f"generator/not_impl_{name}_header.txt"),
footer=open(f"generator/not_impl_{name}_footer.txt"),
output=open(f"snippets/whats_left_{name}.py", "w"),
)

View File

@@ -1,2 +0,0 @@
x = []
x.append(1)

View File

@@ -21,3 +21,10 @@ print(foo.body[0].value.func.id)
assert foo.body[0].value.func.id == 'print'
assert foo.body[0].lineno == 3
assert foo.body[1].lineno == 4
n = ast.parse("3 < 4 > 5\n")
assert n.body[0].value.left.n == 3
assert 'Lt' in str(n.body[0].value.ops[0])
assert 'Gt' in str(n.body[0].value.ops[1])
assert n.body[0].value.comparators[0].n == 4
assert n.body[0].value.comparators[1].n == 5

Some files were not shown because too many files have changed in this diff Show More