diff --git a/.gitattributes b/.gitattributes index c30b96f056b219555832334fdebd7217437a2784..1815c810bcab07646132a6dc7dd1e391dd96727a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -84,3 +84,5 @@ MLPY/Lib/site-packages/numpy/core/_simd.cp39-win_amd64.pyd filter=lfs diff=lfs m MLPY/Lib/site-packages/onnx/onnx_cpp2py_export.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text MLPY/Lib/site-packages/PIL/_imaging.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text MLPY/Lib/site-packages/PIL/_imagingft.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text +MLPY/Lib/site-packages/pythonwin/mfc140u.dll filter=lfs diff=lfs merge=lfs -text +MLPY/Lib/site-packages/pythonwin/win32ui.pyd filter=lfs diff=lfs merge=lfs -text diff --git a/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/INSTALLER b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/LICENSE b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..2f1b8e15e5627d92f0521605c9870bc8e5505cb4 --- /dev/null +++ b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2017-2021 Ingy döt Net +Copyright (c) 2006-2016 Kirill Simonov + +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. diff --git a/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/METADATA b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..a9e63798b51e49200bd9312fdc27a8b6c3218813 --- /dev/null +++ b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/METADATA @@ -0,0 +1,47 @@ +Metadata-Version: 2.1 +Name: PyYAML +Version: 6.0.1 +Summary: YAML parser and emitter for Python +Home-page: https://pyyaml.org/ +Author: Kirill Simonov +Author-email: xi@resolvent.net +License: MIT +Download-URL: https://pypi.org/project/PyYAML/ +Project-URL: Bug Tracker, https://github.com/yaml/pyyaml/issues +Project-URL: CI, https://github.com/yaml/pyyaml/actions +Project-URL: Documentation, https://pyyaml.org/wiki/PyYAMLDocumentation +Project-URL: Mailing lists, http://lists.sourceforge.net/lists/listinfo/yaml-core +Project-URL: Source Code, https://github.com/yaml/pyyaml +Platform: Any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Cython +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup +Requires-Python: >=3.6 +License-File: LICENSE + +YAML is a data serialization format designed for human readability +and interaction with scripting languages. PyYAML is a YAML parser +and emitter for Python. + +PyYAML features a complete YAML 1.1 parser, Unicode support, pickle +support, capable extension API, and sensible error messages. PyYAML +supports standard YAML tags and provides Python-specific tags that +allow to represent an arbitrary Python object. + +PyYAML is applicable for a broad range of tasks from complex +configuration files to object serialization and persistence. + diff --git a/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/RECORD b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..0fcbdd99d75bb97b41e98015468db44e53c51c28 --- /dev/null +++ b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/RECORD @@ -0,0 +1,43 @@ +PyYAML-6.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +PyYAML-6.0.1.dist-info/LICENSE,sha256=jTko-dxEkP1jVwfLiOsmvXZBAqcoKVQwfT5RZ6V36KQ,1101 +PyYAML-6.0.1.dist-info/METADATA,sha256=9LqpZ7ARc_UDWHhaztw28ggwznRds8xf8oJCGOCT60I,2106 +PyYAML-6.0.1.dist-info/RECORD,, +PyYAML-6.0.1.dist-info/WHEEL,sha256=eep6QWEFiQfg2wcclssb_WY-D33AnLYLnEKGA9Rn-VU,100 +PyYAML-6.0.1.dist-info/top_level.txt,sha256=rpj0IVMTisAjh_1vG3Ccf9v5jpCQwAz6cD1IVU5ZdhQ,11 +_yaml/__init__.py,sha256=04Ae_5osxahpJHa3XBZUAf4wi6XX32gR8D6X6p64GEA,1402 +_yaml/__pycache__/__init__.cpython-39.pyc,, +yaml/__init__.py,sha256=bhl05qSeO-1ZxlSRjGrvl2m9nrXb1n9-GQatTN0Mrqc,12311 +yaml/__pycache__/__init__.cpython-39.pyc,, +yaml/__pycache__/composer.cpython-39.pyc,, +yaml/__pycache__/constructor.cpython-39.pyc,, +yaml/__pycache__/cyaml.cpython-39.pyc,, +yaml/__pycache__/dumper.cpython-39.pyc,, +yaml/__pycache__/emitter.cpython-39.pyc,, +yaml/__pycache__/error.cpython-39.pyc,, +yaml/__pycache__/events.cpython-39.pyc,, +yaml/__pycache__/loader.cpython-39.pyc,, +yaml/__pycache__/nodes.cpython-39.pyc,, +yaml/__pycache__/parser.cpython-39.pyc,, +yaml/__pycache__/reader.cpython-39.pyc,, +yaml/__pycache__/representer.cpython-39.pyc,, +yaml/__pycache__/resolver.cpython-39.pyc,, +yaml/__pycache__/scanner.cpython-39.pyc,, +yaml/__pycache__/serializer.cpython-39.pyc,, +yaml/__pycache__/tokens.cpython-39.pyc,, +yaml/_yaml.cp39-win_amd64.pyd,sha256=AULP_23onG6Yy5UUqIe4N5f4szwfM5lkHQ60Ak04FTQ,251904 +yaml/composer.py,sha256=_Ko30Wr6eDWUeUpauUGT3Lcg9QPBnOPVlTnIMRGJ9FM,4883 +yaml/constructor.py,sha256=kNgkfaeLUkwQYY_Q6Ff1Tz2XVw_pG1xVE9Ak7z-viLA,28639 +yaml/cyaml.py,sha256=6ZrAG9fAYvdVe2FK_w0hmXoG7ZYsoYUwapG8CiC72H0,3851 +yaml/dumper.py,sha256=PLctZlYwZLp7XmeUdwRuv4nYOZ2UBnDIUy8-lKfLF-o,2837 +yaml/emitter.py,sha256=jghtaU7eFwg31bG0B7RZea_29Adi9CKmXq_QjgQpCkQ,43006 +yaml/error.py,sha256=Ah9z-toHJUbE9j-M8YpxgSRM5CgLCcwVzJgLLRF2Fxo,2533 +yaml/events.py,sha256=50_TksgQiE4up-lKo_V-nBy-tAIxkIPQxY5qDhKCeHw,2445 +yaml/loader.py,sha256=UVa-zIqmkFSCIYq_PgSGm4NSJttHY2Rf_zQ4_b1fHN0,2061 +yaml/nodes.py,sha256=gPKNj8pKCdh2d4gr3gIYINnPOaOxGhJAUiYhGRnPE84,1440 +yaml/parser.py,sha256=ilWp5vvgoHFGzvOZDItFoGjD6D42nhlZrZyjAwa0oJo,25495 +yaml/reader.py,sha256=0dmzirOiDG4Xo41RnuQS7K9rkY3xjHiVasfDMNTqCNw,6794 +yaml/representer.py,sha256=IuWP-cAW9sHKEnS0gCqSa894k1Bg4cgTxaDwIcbRQ-Y,14190 +yaml/resolver.py,sha256=9L-VYfm4mWHxUD1Vg4X7rjDRK_7VZd6b92wzq7Y2IKY,9004 +yaml/scanner.py,sha256=YEM3iLZSaQwXcQRg2l2R4MdT0zGP2F9eHkKGKnHyWQY,51279 +yaml/serializer.py,sha256=ChuFgmhU01hj4xgI8GaKv6vfM2Bujwa9i7d2FAHj7cA,4165 +yaml/tokens.py,sha256=lTQIzSVw8Mg9wv459-TjiOQe6wVziqaRlqX2_89rp54,2573 diff --git a/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/WHEEL b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..d5ae687e23d0112bda36fe6af4e8353bddd09a8d --- /dev/null +++ b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: false +Tag: cp39-cp39-win_amd64 + diff --git a/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/top_level.txt b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6475e911f628412049bc4090d86f23ac403adde --- /dev/null +++ b/MLPY/Lib/site-packages/PyYAML-6.0.1.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_yaml +yaml diff --git a/MLPY/Lib/site-packages/pythonwin/Pythonwin.exe b/MLPY/Lib/site-packages/pythonwin/Pythonwin.exe new file mode 100644 index 0000000000000000000000000000000000000000..64415946271505f1f161cfa3dbc12334113f3357 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/Pythonwin.exe differ diff --git a/MLPY/Lib/site-packages/pythonwin/dde.pyd b/MLPY/Lib/site-packages/pythonwin/dde.pyd new file mode 100644 index 0000000000000000000000000000000000000000..3bf751d5fa9fb057814249c86ff6d315b71002fd Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/dde.pyd differ diff --git a/MLPY/Lib/site-packages/pythonwin/license.txt b/MLPY/Lib/site-packages/pythonwin/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa340d745e5641761532cae88802d09f10b69b7a --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/license.txt @@ -0,0 +1,30 @@ +Unless stated in the specfic source file, this work is +Copyright (c) 1994-2008, Mark Hammond +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the distribution. + +Neither name of Mark Hammond nor the name of contributors may be used +to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS +IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MLPY/Lib/site-packages/pythonwin/mfc140u.dll b/MLPY/Lib/site-packages/pythonwin/mfc140u.dll new file mode 100644 index 0000000000000000000000000000000000000000..c066f02e9ef7f4e7f438d60489f6f303849cb492 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/mfc140u.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e06c4bd078f4690aa8874a3deb38e802b2a16ccb602a7edc2e077e98c05b5807 +size 5653424 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/cmdserver.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/cmdserver.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1984a5b06a1ce179a3b28e99bdd57e7a797b3cf9 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/cmdserver.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/createwin.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/createwin.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c44d6515a2117f47e7d532ecf0fa679396f5dc7 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/createwin.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/demoutils.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/demoutils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51c6761c035716c5bf2a384a7d920f98c06b20c1 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/demoutils.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dibdemo.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dibdemo.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a426e3ceeaa322e31bb30d6f0579602cb137ebe0 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dibdemo.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dlgtest.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dlgtest.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9cb3afead3bfde8220865d927e9db05ae528bab Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dlgtest.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dyndlg.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dyndlg.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3df386261f35f7b67c32eaf95f8d86e50618221 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/dyndlg.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/fontdemo.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/fontdemo.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05109cd6ca26b7ebf426769fbaa3b0aff2206e11 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/fontdemo.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/guidemo.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/guidemo.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64f2ecf8b7850b515f644213a24b86923eb501fd Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/guidemo.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/hiertest.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/hiertest.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d69a933d6a81bbf328c43ae99278da5634fcd50 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/hiertest.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/menutest.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/menutest.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7cb03b14176f8eac390bb006b547cf89018469da Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/menutest.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/objdoc.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/objdoc.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04acfa419f16087f5039b37a75e5f013104e4ec9 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/objdoc.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/openGLDemo.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/openGLDemo.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a1e2f644149ca6515fca472aa045415fb4fef3e Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/openGLDemo.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/progressbar.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/progressbar.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..940de671e2a305df54ac74a2caf61ad6f183b96e Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/progressbar.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/sliderdemo.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/sliderdemo.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7559e05fc6900aee4f1a5bde6f6ee03c47281629 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/sliderdemo.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/splittst.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/splittst.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3746c872a230456de4da2083ab45fea3faad9a1 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/splittst.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/threadedgui.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/threadedgui.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..16f413d12343558b98d9a105e48b89540805be65 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/threadedgui.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/toolbar.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/toolbar.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a82424935245c8db4c161365330a32d1fb97a942 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/__pycache__/toolbar.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/basictimerapp.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/basictimerapp.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9699758463e698d5360d5b23312bc2c36169c1ec Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/basictimerapp.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/customprint.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/customprint.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29c0514e726245acd51b5e53f713f18662abc43b Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/customprint.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/demoutils.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/demoutils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86c2bd9bd171a311be06c871e08bbbe140a57d12 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/demoutils.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/dlgappdemo.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/dlgappdemo.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6b56102edc075f09118fc0ca13a34e41f3efa4d Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/dlgappdemo.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/dojobapp.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/dojobapp.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a58ca560cab028235e84c25170225f50c03f624 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/dojobapp.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/helloapp.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/helloapp.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ac1143c44f5c3092ed4c78aaf824291e873f69e Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/__pycache__/helloapp.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/basictimerapp.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/basictimerapp.py new file mode 100644 index 0000000000000000000000000000000000000000..da771da115cee9e0819df92002562149581a6e2c --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/basictimerapp.py @@ -0,0 +1,258 @@ +# basictimerapp - a really simple timer application. +# This should be run using the command line: +# pythonwin /app demos\basictimerapp.py +import sys +import time + +import timer +import win32api +import win32con +import win32ui +from pywin.framework import app, cmdline, dlgappcore + + +class TimerAppDialog(dlgappcore.AppDialog): + softspace = 1 + + def __init__(self, appName=""): + dlgappcore.AppDialog.__init__(self, win32ui.IDD_GENERAL_STATUS) + self.timerAppName = appName + self.argOff = 0 + if len(self.timerAppName) == 0: + if len(sys.argv) > 1 and sys.argv[1][0] != "/": + self.timerAppName = sys.argv[1] + self.argOff = 1 + + def PreDoModal(self): + # sys.stderr = sys.stdout + pass + + def ProcessArgs(self, args): + for arg in args: + if arg == "/now": + self.OnOK() + + def OnInitDialog(self): + win32ui.SetProfileFileName("pytimer.ini") + self.title = win32ui.GetProfileVal( + self.timerAppName, "Title", "Remote System Timer" + ) + self.buildTimer = win32ui.GetProfileVal( + self.timerAppName, "Timer", "EachMinuteIntervaler()" + ) + self.doWork = win32ui.GetProfileVal(self.timerAppName, "Work", "DoDemoWork()") + # replace "\n" with real \n. + self.doWork = self.doWork.replace("\\n", "\n") + dlgappcore.AppDialog.OnInitDialog(self) + + self.SetWindowText(self.title) + self.prompt1 = self.GetDlgItem(win32ui.IDC_PROMPT1) + self.prompt2 = self.GetDlgItem(win32ui.IDC_PROMPT2) + self.prompt3 = self.GetDlgItem(win32ui.IDC_PROMPT3) + self.butOK = self.GetDlgItem(win32con.IDOK) + self.butCancel = self.GetDlgItem(win32con.IDCANCEL) + self.prompt1.SetWindowText("Python Timer App") + self.prompt2.SetWindowText("") + self.prompt3.SetWindowText("") + self.butOK.SetWindowText("Do it now") + self.butCancel.SetWindowText("Close") + + self.timerManager = TimerManager(self) + self.ProcessArgs(sys.argv[self.argOff :]) + self.timerManager.go() + return 1 + + def OnDestroy(self, msg): + dlgappcore.AppDialog.OnDestroy(self, msg) + self.timerManager.stop() + + def OnOK(self): + # stop the timer, then restart after setting special boolean + self.timerManager.stop() + self.timerManager.bConnectNow = 1 + self.timerManager.go() + return + + +# def OnCancel(self): default behaviour - cancel == close. +# return + + +class TimerManager: + def __init__(self, dlg): + self.dlg = dlg + self.timerId = None + self.intervaler = eval(self.dlg.buildTimer) + self.bConnectNow = 0 + self.bHaveSetPrompt1 = 0 + + def CaptureOutput(self): + self.oldOut = sys.stdout + self.oldErr = sys.stderr + sys.stdout = sys.stderr = self + self.bHaveSetPrompt1 = 0 + + def ReleaseOutput(self): + sys.stdout = self.oldOut + sys.stderr = self.oldErr + + def write(self, str): + s = str.strip() + if len(s): + if self.bHaveSetPrompt1: + dest = self.dlg.prompt3 + else: + dest = self.dlg.prompt1 + self.bHaveSetPrompt1 = 1 + dest.SetWindowText(s) + + def go(self): + self.OnTimer(None, None) + + def stop(self): + if self.timerId: + timer.kill_timer(self.timerId) + self.timerId = None + + def OnTimer(self, id, timeVal): + if id: + timer.kill_timer(id) + if self.intervaler.IsTime() or self.bConnectNow: + # do the work. + try: + self.dlg.SetWindowText(self.dlg.title + " - Working...") + self.dlg.butOK.EnableWindow(0) + self.dlg.butCancel.EnableWindow(0) + self.CaptureOutput() + try: + exec(self.dlg.doWork) + print("The last operation completed successfully.") + except: + t, v, tb = sys.exc_info() + str = "Failed: %s: %s" % (t, repr(v)) + print(str) + self.oldErr.write(str) + tb = None # Prevent cycle + finally: + self.ReleaseOutput() + self.dlg.butOK.EnableWindow() + self.dlg.butCancel.EnableWindow() + self.dlg.SetWindowText(self.dlg.title) + else: + now = time.time() + nextTime = self.intervaler.GetNextTime() + if nextTime: + timeDiffSeconds = nextTime - now + timeDiffMinutes = int(timeDiffSeconds / 60) + timeDiffSeconds = timeDiffSeconds % 60 + timeDiffHours = int(timeDiffMinutes / 60) + timeDiffMinutes = timeDiffMinutes % 60 + self.dlg.prompt1.SetWindowText( + "Next connection due in %02d:%02d:%02d" + % (timeDiffHours, timeDiffMinutes, timeDiffSeconds) + ) + self.timerId = timer.set_timer( + self.intervaler.GetWakeupInterval(), self.OnTimer + ) + self.bConnectNow = 0 + + +class TimerIntervaler: + def __init__(self): + self.nextTime = None + self.wakeUpInterval = 2000 + + def GetWakeupInterval(self): + return self.wakeUpInterval + + def GetNextTime(self): + return self.nextTime + + def IsTime(self): + now = time.time() + if self.nextTime is None: + self.nextTime = self.SetFirstTime(now) + ret = 0 + if now >= self.nextTime: + ret = 1 + self.nextTime = self.SetNextTime(self.nextTime, now) + # do the work. + return ret + + +class EachAnyIntervaler(TimerIntervaler): + def __init__(self, timeAt, timePos, timeAdd, wakeUpInterval=None): + TimerIntervaler.__init__(self) + self.timeAt = timeAt + self.timePos = timePos + self.timeAdd = timeAdd + if wakeUpInterval: + self.wakeUpInterval = wakeUpInterval + + def SetFirstTime(self, now): + timeTup = time.localtime(now) + lst = [] + for item in timeTup: + lst.append(item) + bAdd = timeTup[self.timePos] > self.timeAt + lst[self.timePos] = self.timeAt + for pos in range(self.timePos + 1, 6): + lst[pos] = 0 + ret = time.mktime(tuple(lst)) + if bAdd: + ret = ret + self.timeAdd + return ret + + def SetNextTime(self, lastTime, now): + return lastTime + self.timeAdd + + +class EachMinuteIntervaler(EachAnyIntervaler): + def __init__(self, at=0): + EachAnyIntervaler.__init__(self, at, 5, 60, 2000) + + +class EachHourIntervaler(EachAnyIntervaler): + def __init__(self, at=0): + EachAnyIntervaler.__init__(self, at, 4, 3600, 10000) + + +class EachDayIntervaler(EachAnyIntervaler): + def __init__(self, at=0): + EachAnyIntervaler.__init__(self, at, 3, 86400, 10000) + + +class TimerDialogApp(dlgappcore.DialogApp): + def CreateDialog(self): + return TimerAppDialog() + + +def DoDemoWork(): + print("Doing the work...") + print("About to connect") + win32api.MessageBeep(win32con.MB_ICONASTERISK) + win32api.Sleep(2000) + print("Doing something else...") + win32api.MessageBeep(win32con.MB_ICONEXCLAMATION) + win32api.Sleep(2000) + print("More work.") + win32api.MessageBeep(win32con.MB_ICONHAND) + win32api.Sleep(2000) + print("The last bit.") + win32api.MessageBeep(win32con.MB_OK) + win32api.Sleep(2000) + + +app = TimerDialogApp() + + +def t(): + t = TimerAppDialog("Test Dialog") + t.DoModal() + return t + + +if __name__ == "__main__": + import demoutils + + demoutils.NeedApp() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/customprint.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/customprint.py new file mode 100644 index 0000000000000000000000000000000000000000..356073e5fb73c2a125caf2c1634c05a412adb4e1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/customprint.py @@ -0,0 +1,186 @@ +# A demo of an Application object that has some custom print functionality. + +# If you desire, you can also run this from inside Pythonwin, in which +# case it will do the demo inside the Pythonwin environment. + +# This sample was contributed by Roger Burnham. + +import win32api +import win32con +import win32ui +from pywin.framework import app +from pywin.mfc import afxres, dialog, docview + +PRINTDLGORD = 1538 +IDC_PRINT_MAG_EDIT = 1010 + + +class PrintDemoTemplate(docview.DocTemplate): + def _SetupSharedMenu_(self): + pass + + +class PrintDemoView(docview.ScrollView): + def OnInitialUpdate(self): + ret = self._obj_.OnInitialUpdate() + self.colors = { + "Black": (0x00 << 0) + (0x00 << 8) + (0x00 << 16), + "Red": (0xFF << 0) + (0x00 << 8) + (0x00 << 16), + "Green": (0x00 << 0) + (0xFF << 8) + (0x00 << 16), + "Blue": (0x00 << 0) + (0x00 << 8) + (0xFF << 16), + "Cyan": (0x00 << 0) + (0xFF << 8) + (0xFF << 16), + "Magenta": (0xFF << 0) + (0x00 << 8) + (0xFF << 16), + "Yellow": (0xFF << 0) + (0xFF << 8) + (0x00 << 16), + } + self.pens = {} + for name, color in self.colors.items(): + self.pens[name] = win32ui.CreatePen(win32con.PS_SOLID, 5, color) + self.pen = None + self.size = (128, 128) + self.SetScaleToFitSize(self.size) + self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT) + self.HookCommand(self.OnFilePrintPreview, win32ui.ID_FILE_PRINT_PREVIEW) + return ret + + def OnDraw(self, dc): + oldPen = None + x, y = self.size + delta = 2 + colors = list(self.colors.keys()) + colors.sort() + colors = colors * 2 + for color in colors: + if oldPen is None: + oldPen = dc.SelectObject(self.pens[color]) + else: + dc.SelectObject(self.pens[color]) + dc.MoveTo((delta, delta)) + dc.LineTo((x - delta, delta)) + dc.LineTo((x - delta, y - delta)) + dc.LineTo((delta, y - delta)) + dc.LineTo((delta, delta)) + delta = delta + 4 + if x - delta <= 0 or y - delta <= 0: + break + dc.SelectObject(oldPen) + + def OnPrepareDC(self, dc, pInfo): + if dc.IsPrinting(): + mag = self.prtDlg["mag"] + dc.SetMapMode(win32con.MM_ANISOTROPIC) + dc.SetWindowOrg((0, 0)) + dc.SetWindowExt((1, 1)) + dc.SetViewportOrg((0, 0)) + dc.SetViewportExt((mag, mag)) + + def OnPreparePrinting(self, pInfo): + flags = ( + win32ui.PD_USEDEVMODECOPIES + | win32ui.PD_PAGENUMS + | win32ui.PD_NOPAGENUMS + | win32ui.PD_NOSELECTION + ) + self.prtDlg = ImagePrintDialog(pInfo, PRINTDLGORD, flags) + pInfo.SetPrintDialog(self.prtDlg) + pInfo.SetMinPage(1) + pInfo.SetMaxPage(1) + pInfo.SetFromPage(1) + pInfo.SetToPage(1) + ret = self.DoPreparePrinting(pInfo) + return ret + + def OnBeginPrinting(self, dc, pInfo): + return self._obj_.OnBeginPrinting(dc, pInfo) + + def OnEndPrinting(self, dc, pInfo): + del self.prtDlg + return self._obj_.OnEndPrinting(dc, pInfo) + + def OnFilePrintPreview(self, *arg): + self._obj_.OnFilePrintPreview() + + def OnFilePrint(self, *arg): + self._obj_.OnFilePrint() + + def OnPrint(self, dc, pInfo): + doc = self.GetDocument() + metrics = dc.GetTextMetrics() + cxChar = metrics["tmAveCharWidth"] + cyChar = metrics["tmHeight"] + left, top, right, bottom = pInfo.GetDraw() + dc.TextOut(0, 2 * cyChar, doc.GetTitle()) + top = top + (7 * cyChar) / 2 + dc.MoveTo(left, top) + dc.LineTo(right, top) + top = top + cyChar + # this seems to have not effect... + # get what I want with the dc.SetWindowOrg calls + pInfo.SetDraw((left, top, right, bottom)) + dc.SetWindowOrg((0, -top)) + + self.OnDraw(dc) + dc.SetTextAlign(win32con.TA_LEFT | win32con.TA_BOTTOM) + + rect = self.GetWindowRect() + rect = self.ScreenToClient(rect) + height = rect[3] - rect[1] + dc.SetWindowOrg((0, -(top + height + cyChar))) + dc.MoveTo(left, 0) + dc.LineTo(right, 0) + + x = 0 + y = (3 * cyChar) / 2 + + dc.TextOut(x, y, doc.GetTitle()) + y = y + cyChar + + +class PrintDemoApp(app.CApp): + def __init__(self): + app.CApp.__init__(self) + + def InitInstance(self): + template = PrintDemoTemplate(None, None, None, PrintDemoView) + self.AddDocTemplate(template) + self._obj_.InitMDIInstance() + self.LoadMainFrame() + doc = template.OpenDocumentFile(None) + doc.SetTitle("Custom Print Document") + + +class ImagePrintDialog(dialog.PrintDialog): + sectionPos = "Image Print Demo" + + def __init__(self, pInfo, dlgID, flags=win32ui.PD_USEDEVMODECOPIES): + dialog.PrintDialog.__init__(self, pInfo, dlgID, flags=flags) + mag = win32ui.GetProfileVal(self.sectionPos, "Document Magnification", 0) + if mag <= 0: + mag = 2 + win32ui.WriteProfileVal(self.sectionPos, "Document Magnification", mag) + + self["mag"] = mag + + def OnInitDialog(self): + self.magCtl = self.GetDlgItem(IDC_PRINT_MAG_EDIT) + self.magCtl.SetWindowText(repr(self["mag"])) + return dialog.PrintDialog.OnInitDialog(self) + + def OnOK(self): + dialog.PrintDialog.OnOK(self) + strMag = self.magCtl.GetWindowText() + try: + self["mag"] = int(strMag) + except: + pass + win32ui.WriteProfileVal(self.sectionPos, "Document Magnification", self["mag"]) + + +if __name__ == "__main__": + # Running under Pythonwin + def test(): + template = PrintDemoTemplate(None, None, None, PrintDemoView) + template.OpenDocumentFile(None) + + test() +else: + app = PrintDemoApp() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/demoutils.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/demoutils.py new file mode 100644 index 0000000000000000000000000000000000000000..ee1fefcfad0f0d77f60056a38b0a7e69397ec58c --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/demoutils.py @@ -0,0 +1,65 @@ +# Utilities for the demos + +import sys + +import win32api +import win32con +import win32ui + +NotScriptMsg = """\ +This demo program is not designed to be run as a Script, but is +probably used by some other test program. Please try another demo. +""" + +NeedGUIMsg = """\ +This demo program can only be run from inside of Pythonwin + +You must start Pythonwin, and select 'Run' from the toolbar or File menu +""" + + +NeedAppMsg = """\ +This demo program is a 'Pythonwin Application'. + +It is more demo code than an example of Pythonwin's capabilities. + +To run it, you must execute the command: +pythonwin.exe /app "%s" + +Would you like to execute it now? +""" + + +def NotAScript(): + import win32ui + + win32ui.MessageBox(NotScriptMsg, "Demos") + + +def NeedGoodGUI(): + from pywin.framework.app import HaveGoodGUI + + rc = HaveGoodGUI() + if not rc: + win32ui.MessageBox(NeedGUIMsg, "Demos") + return rc + + +def NeedApp(): + import win32ui + + rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO) + if rc == win32con.IDYES: + try: + parent = win32ui.GetMainFrame().GetSafeHwnd() + win32api.ShellExecute( + parent, None, "pythonwin.exe", '/app "%s"' % sys.argv[0], None, 1 + ) + except win32api.error as details: + win32ui.MessageBox("Error executing command - %s" % (details), "Demos") + + +if __name__ == "__main__": + import demoutils + + demoutils.NotAScript() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/dlgappdemo.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/dlgappdemo.py new file mode 100644 index 0000000000000000000000000000000000000000..38659a62fc1840ec69e459caa0475a91f51fd69f --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/dlgappdemo.py @@ -0,0 +1,51 @@ +# dlgappdemo - a demo of a dialog application. +# This is a demonstration of both a custom "application" module, +# and a Python program in a dialog box. +# +# NOTE: You CAN NOT import this module from either PythonWin or Python. +# This module must be specified on the commandline to PythonWin only. +# eg, PythonWin /app dlgappdemo.py + +import sys + +import win32ui +from pywin.framework import app, dlgappcore + + +class TestDialogApp(dlgappcore.DialogApp): + def CreateDialog(self): + return TestAppDialog() + + +class TestAppDialog(dlgappcore.AppDialog): + def __init__(self): + self.edit = None + dlgappcore.AppDialog.__init__(self, win32ui.IDD_LARGE_EDIT) + + def OnInitDialog(self): + self.SetWindowText("Test dialog application") + self.edit = self.GetDlgItem(win32ui.IDC_EDIT1) + print("Hello from Python") + print("args are:", end=" ") + for arg in sys.argv: + print(arg) + return 1 + + def PreDoModal(self): + sys.stdout = sys.stderr = self + + def write(self, str): + if self.edit: + self.edit.SetSel(-2) + # translate \n to \n\r + self.edit.ReplaceSel(str.replace("\n", "\r\n")) + else: + win32ui.OutputDebug("dlgapp - no edit control! >>\n%s\n<<\n" % str) + + +app.AppBuilder = TestDialogApp + +if __name__ == "__main__": + import demoutils + + demoutils.NeedApp() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/dojobapp.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/dojobapp.py new file mode 100644 index 0000000000000000000000000000000000000000..d97ce5e2a8fca72ebc3ff825f1c20f97693220f2 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/dojobapp.py @@ -0,0 +1,72 @@ +# dojobapp - do a job, show the result in a dialog, and exit. +# +# Very simple - faily minimal dialog based app. +# +# This should be run using the command line: +# pythonwin /app demos\dojobapp.py + + +import win32api +import win32con +import win32ui +from pywin.framework import app, dlgappcore + + +class DoJobAppDialog(dlgappcore.AppDialog): + softspace = 1 + + def __init__(self, appName=""): + self.appName = appName + dlgappcore.AppDialog.__init__(self, win32ui.IDD_GENERAL_STATUS) + + def PreDoModal(self): + pass + + def ProcessArgs(self, args): + pass + + def OnInitDialog(self): + self.SetWindowText(self.appName) + butCancel = self.GetDlgItem(win32con.IDCANCEL) + butCancel.ShowWindow(win32con.SW_HIDE) + p1 = self.GetDlgItem(win32ui.IDC_PROMPT1) + p2 = self.GetDlgItem(win32ui.IDC_PROMPT2) + + # Do something here! + + p1.SetWindowText("Hello there") + p2.SetWindowText("from the demo") + + def OnDestroy(self, msg): + pass + + +# def OnOK(self): +# pass +# def OnCancel(self): default behaviour - cancel == close. +# return + + +class DoJobDialogApp(dlgappcore.DialogApp): + def CreateDialog(self): + return DoJobAppDialog("Do Something") + + +class CopyToDialogApp(DoJobDialogApp): + def __init__(self): + DoJobDialogApp.__init__(self) + + +app.AppBuilder = DoJobDialogApp + + +def t(): + t = DoJobAppDialog("Copy To") + t.DoModal() + return t + + +if __name__ == "__main__": + import demoutils + + demoutils.NeedApp() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/helloapp.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/helloapp.py new file mode 100644 index 0000000000000000000000000000000000000000..876f16f71d3ea22f23112c9a37f4ebde19c80a1d --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/app/helloapp.py @@ -0,0 +1,53 @@ +## +## helloapp.py +## +## +## A nice, small 'hello world' Pythonwin application. +## NOT an MDI application - just a single, normal, top-level window. +## +## MUST be run with the command line "pythonwin.exe /app helloapp.py" +## (or if you are really keen, rename "pythonwin.exe" to something else, then +## using MSVC or similar, edit the string section in the .EXE to name this file) +## +## Originally by Willy Heineman + + +import win32con +import win32ui +from pywin.mfc import afxres, dialog, window +from pywin.mfc.thread import WinApp + + +# The main frame. +# Does almost nothing at all - doesnt even create a child window! +class HelloWindow(window.Wnd): + def __init__(self): + # The window.Wnd ctor creates a Window object, and places it in + # self._obj_. Note the window object exists, but the window itself + # does not! + window.Wnd.__init__(self, win32ui.CreateWnd()) + + # Now we ask the window object to create the window itself. + self._obj_.CreateWindowEx( + win32con.WS_EX_CLIENTEDGE, + win32ui.RegisterWndClass(0, 0, win32con.COLOR_WINDOW + 1), + "Hello World!", + win32con.WS_OVERLAPPEDWINDOW, + (100, 100, 400, 300), + None, + 0, + None, + ) + + +# The application object itself. +class HelloApp(WinApp): + def InitInstance(self): + self.frame = HelloWindow() + self.frame.ShowWindow(win32con.SW_SHOWNORMAL) + # We need to tell MFC what our main frame is. + self.SetMainFrame(self.frame) + + +# Now create the application object itself! +app = HelloApp() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/cmdserver.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/cmdserver.py new file mode 100644 index 0000000000000000000000000000000000000000..7b1c257a386ab48218614ebfd4ed11a6bee6114d --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/cmdserver.py @@ -0,0 +1,116 @@ +# cmdserver.py + +# Demo code that is not Pythonwin related, but too good to throw away... + +import _thread +import sys +import traceback + +import win32api +from pywin.framework import winout + + +class ThreadWriter: + "Assign an instance to sys.stdout for per-thread printing objects - Courtesy Guido!" + + def __init__(self): + "Constructor -- initialize the table of writers" + self.writers = {} + self.origStdOut = None + + def register(self, writer): + "Register the writer for the current thread" + self.writers[_thread.get_ident()] = writer + if self.origStdOut is None: + self.origStdOut = sys.stdout + sys.stdout = self + + def unregister(self): + "Remove the writer for the current thread, if any" + try: + del self.writers[_thread.get_ident()] + except KeyError: + pass + if len(self.writers) == 0: + sys.stdout = self.origStdOut + self.origStdOut = None + + def getwriter(self): + "Return the current thread's writer, default sys.stdout" + try: + return self.writers[_thread.get_ident()] + except KeyError: + return self.origStdOut + + def write(self, str): + "Write to the current thread's writer, default sys.stdout" + self.getwriter().write(str) + + +def Test(): + num = 1 + while num < 1000: + print("Hello there no " + str(num)) + win32api.Sleep(50) + num = num + 1 + + +class flags: + SERVER_BEST = 0 + SERVER_IMMEDIATE = 1 + SERVER_THREAD = 2 + SERVER_PROCESS = 3 + + +def StartServer(cmd, title=None, bCloseOnEnd=0, serverFlags=flags.SERVER_BEST): + out = winout.WindowOutput(title, None, winout.flags.WQ_IDLE) + if not title: + title = cmd + out.Create(title) + # ServerThread((out, cmd, title, bCloseOnEnd)) + # out = sys.stdout + _thread.start_new_thread(ServerThread, (out, cmd, title, bCloseOnEnd)) + + +def ServerThread(myout, cmd, title, bCloseOnEnd): + try: + writer.register(myout) + print('Executing "%s"\n' % cmd) + bOK = 1 + try: + import __main__ + + exec(cmd + "\n", __main__.__dict__) + except: + bOK = 0 + if bOK: + print("Command terminated without errors.") + else: + t, v, tb = sys.exc_info() + print(t, ": ", v) + traceback.print_tb(tb) + tb = None # prevent a cycle + print("Command terminated with an unhandled exception") + writer.unregister() + if bOK and bCloseOnEnd: + myout.frame.DestroyWindow() + + # Unhandled exception of any kind in a thread kills the gui! + except: + t, v, tb = sys.exc_info() + print(t, ": ", v) + traceback.print_tb(tb) + tb = None + print("Thread failed") + + +# assist for reloading (when debugging) - use only 1 tracer object, +# else a large chain of tracer objects will exist. +# try: +# writer +# except NameError: +# writer=ThreadWriter() +if __name__ == "__main__": + import demoutils + + demoutils.NotAScript() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/createwin.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/createwin.py new file mode 100644 index 0000000000000000000000000000000000000000..38f6947edd85cd6001d519010c22023dffe543ad --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/createwin.py @@ -0,0 +1,114 @@ +# +# Window creation example +# +# This example creates a minimal "control" that just fills in its +# window with red. To make your own control, subclass Control and +# write your own OnPaint() method. See PyCWnd.HookMessage for what +# the parameters to OnPaint are. +# + +import win32api +import win32con +import win32ui +from pywin.mfc import dialog, window + + +class Control(window.Wnd): + """Generic control class""" + + def __init__(self): + window.Wnd.__init__(self, win32ui.CreateWnd()) + + def OnPaint(self): + dc, paintStruct = self.BeginPaint() + self.DoPaint(dc) + self.EndPaint(paintStruct) + + def DoPaint(self, dc): # Override this! + pass + + +class RedBox(Control): + def DoPaint(self, dc): + dc.FillSolidRect(self.GetClientRect(), win32api.RGB(255, 0, 0)) + + +class RedBoxWithPie(RedBox): + def DoPaint(self, dc): + RedBox.DoPaint(self, dc) + r = self.GetClientRect() + dc.Pie(r[0], r[1], r[2], r[3], 0, 0, r[2], r[3] // 2) + + +def MakeDlgTemplate(): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + + w = 64 + h = 64 + + dlg = [ + ["Red box", (0, 0, w, h), style, None, (8, "MS Sans Serif")], + ] + + s = win32con.WS_TABSTOP | cs + + dlg.append( + [ + 128, + "Cancel", + win32con.IDCANCEL, + (7, h - 18, 50, 14), + s | win32con.BS_PUSHBUTTON, + ] + ) + + return dlg + + +class TestDialog(dialog.Dialog): + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + self.redbox = RedBox() + self.redbox.CreateWindow( + None, + "RedBox", + win32con.WS_CHILD | win32con.WS_VISIBLE, + (5, 5, 90, 68), + self, + 1003, + ) + return rc + + +class TestPieDialog(dialog.Dialog): + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + self.control = RedBoxWithPie() + self.control.CreateWindow( + None, + "RedBox with Pie", + win32con.WS_CHILD | win32con.WS_VISIBLE, + (5, 5, 90, 68), + self, + 1003, + ) + + +def demo(modal=0): + d = TestPieDialog(MakeDlgTemplate()) + if modal: + d.DoModal() + else: + d.CreateWindow() + + +if __name__ == "__main__": + demo(1) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/demoutils.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/demoutils.py new file mode 100644 index 0000000000000000000000000000000000000000..f6080c465b606fed58fd9e255d54c3db573ff095 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/demoutils.py @@ -0,0 +1,67 @@ +# Utilities for the demos + +import sys + +import win32api +import win32con +import win32ui + +NotScriptMsg = """\ +This demo program is not designed to be run as a Script, but is +probably used by some other test program. Please try another demo. +""" + +NeedGUIMsg = """\ +This demo program can only be run from inside of Pythonwin + +You must start Pythonwin, and select 'Run' from the toolbar or File menu +""" + + +NeedAppMsg = """\ +This demo program is a 'Pythonwin Application'. + +It is more demo code than an example of Pythonwin's capabilities. + +To run it, you must execute the command: +pythonwin.exe /app "%s" + +Would you like to execute it now? +""" + + +def NotAScript(): + import win32ui + + win32ui.MessageBox(NotScriptMsg, "Demos") + + +def NeedGoodGUI(): + from pywin.framework.app import HaveGoodGUI + + rc = HaveGoodGUI() + if not rc: + win32ui.MessageBox(NeedGUIMsg, "Demos") + return rc + + +def NeedApp(): + import win32ui + + rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO) + if rc == win32con.IDYES: + try: + parent = win32ui.GetMainFrame().GetSafeHwnd() + win32api.ShellExecute( + parent, None, "pythonwin.exe", '/app "%s"' % sys.argv[0], None, 1 + ) + except win32api.error as details: + win32ui.MessageBox("Error executing command - %s" % (details), "Demos") + + +from pywin.framework.app import HaveGoodGUI + +if __name__ == "__main__": + import demoutils + + demoutils.NotAScript() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dibdemo.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dibdemo.py new file mode 100644 index 0000000000000000000000000000000000000000..615227abf294924af9f992e56b3325e8ad3a6613 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dibdemo.py @@ -0,0 +1,73 @@ +# A demo which creates a view and a frame which displays a PPM format bitmap +# +# This hasnnt been run in a while, as I dont have many of that format around! + +import win32api +import win32con +import win32ui + + +class DIBView: + def __init__(self, doc, dib): + self.dib = dib + self.view = win32ui.CreateView(doc) + self.width = self.height = 0 + # set up message handlers + # self.view.OnPrepareDC = self.OnPrepareDC + self.view.HookMessage(self.OnSize, win32con.WM_SIZE) + + def OnSize(self, params): + lParam = params[3] + self.width = win32api.LOWORD(lParam) + self.height = win32api.HIWORD(lParam) + + def OnDraw(self, ob, dc): + # set sizes used for "non strecth" mode. + self.view.SetScrollSizes(win32con.MM_TEXT, self.dib.GetSize()) + dibSize = self.dib.GetSize() + dibRect = (0, 0, dibSize[0], dibSize[1]) + # stretch BMP. + # self.dib.Paint(dc, (0,0,self.width, self.height),dibRect) + # non stretch. + self.dib.Paint(dc) + + +class DIBDemo: + def __init__(self, filename, *bPBM): + # init data members + f = open(filename, "rb") + dib = win32ui.CreateDIBitmap() + if len(bPBM) > 0: + magic = f.readline() + if magic != "P6\n": + print("The file is not a PBM format file") + raise ValueError("Failed - The file is not a PBM format file") + # check magic? + rowcollist = f.readline().split() + cols = int(rowcollist[0]) + rows = int(rowcollist[1]) + f.readline() # whats this one? + dib.LoadPBMData(f, (cols, rows)) + else: + dib.LoadWindowsFormatFile(f) + f.close() + # create doc/view + self.doc = win32ui.CreateDoc() + self.dibView = DIBView(self.doc, dib) + self.frame = win32ui.CreateMDIFrame() + self.frame.LoadFrame() # this will force OnCreateClient + self.doc.SetTitle("DIB Demo") + self.frame.ShowWindow() + + # display the sucka + self.frame.ActivateFrame() + + def OnCreateClient(self, createparams, context): + self.dibView.view.CreateWindow(self.frame) + return 1 + + +if __name__ == "__main__": + import demoutils + + demoutils.NotAScript() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dlgtest.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dlgtest.py new file mode 100644 index 0000000000000000000000000000000000000000..8dcb0e5efa4f9026b56c3435bd80ae43596707c3 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dlgtest.py @@ -0,0 +1,145 @@ +# A Demo of Pythonwin's Dialog and Property Page support. + +################### +# +# First demo - use the built-in to Pythonwin "Tab Stop" dialog, but +# customise it heavily. +# +# ID's for the tabstop dialog - out test. +# +import win32con +import win32ui +from pywin.mfc import dialog +from win32con import IDCANCEL +from win32ui import IDC_EDIT_TABS, IDC_PROMPT_TABS, IDD_SET_TABSTOPS + + +class TestDialog(dialog.Dialog): + def __init__(self, modal=1): + dialog.Dialog.__init__(self, IDD_SET_TABSTOPS) + self.counter = 0 + if modal: + self.DoModal() + else: + self.CreateWindow() + + def OnInitDialog(self): + # Set the caption of the dialog itself. + self.SetWindowText("Used to be Tab Stops!") + # Get a child control, remember it, and change its text. + self.edit = self.GetDlgItem(IDC_EDIT_TABS) # the text box. + self.edit.SetWindowText("Test") + # Hook a Windows message for the dialog. + self.edit.HookMessage(self.KillFocus, win32con.WM_KILLFOCUS) + # Get the prompt control, and change its next. + prompt = self.GetDlgItem(IDC_PROMPT_TABS) # the prompt box. + prompt.SetWindowText("Prompt") + # And the same for the button.. + cancel = self.GetDlgItem(IDCANCEL) # the cancel button + cancel.SetWindowText("&Kill me") + + # And just for demonstration purposes, we hook the notify message for the dialog. + # This allows us to be notified when the Edit Control text changes. + self.HookCommand(self.OnNotify, IDC_EDIT_TABS) + + def OnNotify(self, controlid, code): + if code == win32con.EN_CHANGE: + print("Edit text changed!") + return 1 # I handled this, so no need to call defaults! + + # kill focus for the edit box. + # Simply increment the value in the text box. + def KillFocus(self, msg): + self.counter = self.counter + 1 + if self.edit != None: + self.edit.SetWindowText(str(self.counter)) + + # Called when the dialog box is terminating... + def OnDestroy(self, msg): + del self.edit + del self.counter + + +# A very simply Property Sheet. +# We only make a new class for demonstration purposes. +class TestSheet(dialog.PropertySheet): + def __init__(self, title): + dialog.PropertySheet.__init__(self, title) + self.HookMessage(self.OnActivate, win32con.WM_ACTIVATE) + + def OnActivate(self, msg): + pass + + +# A very simply Property Page, which will be "owned" by the above +# Property Sheet. +# We create a new class, just so we can hook a control notification. +class TestPage(dialog.PropertyPage): + def OnInitDialog(self): + # We use the HookNotify function to allow Python to respond to + # Windows WM_NOTIFY messages. + # In this case, we are interested in BN_CLICKED messages. + self.HookNotify(self.OnNotify, win32con.BN_CLICKED) + + def OnNotify(self, std, extra): + print("OnNotify", std, extra) + + +# Some code that actually uses these objects. +def demo(modal=0): + TestDialog(modal) + + # property sheet/page demo + ps = win32ui.CreatePropertySheet("Property Sheet/Page Demo") + # Create a completely standard PropertyPage. + page1 = win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO1) + # Create our custom property page. + page2 = TestPage(win32ui.IDD_PROPDEMO2) + ps.AddPage(page1) + ps.AddPage(page2) + if modal: + ps.DoModal() + else: + style = ( + win32con.WS_SYSMENU + | win32con.WS_POPUP + | win32con.WS_CAPTION + | win32con.DS_MODALFRAME + | win32con.WS_VISIBLE + ) + styleex = win32con.WS_EX_DLGMODALFRAME | win32con.WS_EX_PALETTEWINDOW + ps.CreateWindow(win32ui.GetMainFrame(), style, styleex) + + +def test(modal=1): + # dlg=dialog.Dialog(1010) + # dlg.CreateWindow() + # dlg.EndDialog(0) + # del dlg + # return + # property sheet/page demo + ps = TestSheet("Property Sheet/Page Demo") + page1 = win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO1) + page2 = win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO2) + ps.AddPage(page1) + ps.AddPage(page2) + del page1 + del page2 + if modal: + ps.DoModal() + else: + ps.CreateWindow(win32ui.GetMainFrame()) + return ps + + +def d(): + dlg = win32ui.CreateDialog(win32ui.IDD_DEBUGGER) + dlg.datalist.append((win32ui.IDC_DBG_RADIOSTACK, "radio")) + print("data list is ", dlg.datalist) + dlg.data["radio"] = 1 + dlg.DoModal() + print(dlg.data["radio"]) + + +if __name__ == "__main__": + demo(1) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dyndlg.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dyndlg.py new file mode 100644 index 0000000000000000000000000000000000000000..46a4e7fc67dce5884f7384e945a8efdbf7b5df4c --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/dyndlg.py @@ -0,0 +1,104 @@ +# dyndlg.py +# contributed by Curt Hagenlocher + +# Dialog Template params: +# Parameter 0 - Window caption +# Parameter 1 - Bounds (rect tuple) +# Parameter 2 - Window style +# Parameter 3 - Extended style +# Parameter 4 - Font tuple +# Parameter 5 - Menu name +# Parameter 6 - Window class +# Dialog item params: +# Parameter 0 - Window class +# Parameter 1 - Text +# Parameter 2 - ID +# Parameter 3 - Bounds +# Parameter 4 - Style +# Parameter 5 - Extended style +# Parameter 6 - Extra data + + +import win32con +import win32ui +from pywin.mfc import dialog, window + + +def MakeDlgTemplate(): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + dlg = [ + ["Select Warehouse", (0, 0, 177, 93), style, None, (8, "MS Sans Serif")], + ] + dlg.append([130, "Current Warehouse:", -1, (7, 7, 69, 9), cs | win32con.SS_LEFT]) + dlg.append([130, "ASTORIA", 128, (16, 17, 99, 7), cs | win32con.SS_LEFT]) + dlg.append([130, "New &Warehouse:", -1, (7, 29, 69, 9), cs | win32con.SS_LEFT]) + s = win32con.WS_TABSTOP | cs + # dlg.append([131, None, 130, (5, 40, 110, 48), + # s | win32con.LBS_NOTIFY | win32con.LBS_SORT | win32con.LBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL | win32con.WS_BORDER]) + dlg.append( + [ + "{8E27C92B-1264-101C-8A2F-040224009C02}", + None, + 131, + (5, 40, 110, 48), + win32con.WS_TABSTOP, + ] + ) + + dlg.append( + [128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON] + ) + s = win32con.BS_PUSHBUTTON | s + dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 22, 50, 14), s]) + dlg.append([128, "&Help", 100, (124, 74, 50, 14), s]) + + return dlg + + +def test1(): + win32ui.CreateDialogIndirect(MakeDlgTemplate()).DoModal() + + +def test2(): + dialog.Dialog(MakeDlgTemplate()).DoModal() + + +def test3(): + dlg = win32ui.LoadDialogResource(win32ui.IDD_SET_TABSTOPS) + dlg[0][0] = "New Dialog Title" + dlg[0][1] = (80, 20, 161, 60) + dlg[1][1] = "&Confusion:" + cs = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | win32con.WS_TABSTOP + | win32con.BS_PUSHBUTTON + ) + dlg.append([128, "&Help", 100, (111, 41, 40, 14), cs]) + dialog.Dialog(dlg).DoModal() + + +def test4(): + page1 = dialog.PropertyPage(win32ui.LoadDialogResource(win32ui.IDD_PROPDEMO1)) + page2 = dialog.PropertyPage(win32ui.LoadDialogResource(win32ui.IDD_PROPDEMO2)) + ps = dialog.PropertySheet("Property Sheet/Page Demo", None, [page1, page2]) + ps.DoModal() + + +def testall(): + test1() + test2() + test3() + test4() + + +if __name__ == "__main__": + testall() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/fontdemo.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/fontdemo.py new file mode 100644 index 0000000000000000000000000000000000000000..fc35f4ca388e6ed05616119898d1d6ef46dd4c66 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/fontdemo.py @@ -0,0 +1,86 @@ +# Demo of Generic document windows, DC, and Font usage +# by Dave Brennan (brennan@hal.com) + +# usage examples: + +# >>> from fontdemo import * +# >>> d = FontDemo('Hello, Python') +# >>> f1 = { 'name':'Arial', 'height':36, 'weight':win32con.FW_BOLD} +# >>> d.SetFont(f1) +# >>> f2 = {'name':'Courier New', 'height':24, 'italic':1} +# >>> d.SetFont (f2) + +import win32api +import win32con +import win32ui +from pywin.mfc import docview + +# font is a dictionary in which the following elements matter: +# (the best matching font to supplied parameters is returned) +# name string name of the font as known by Windows +# size point size of font in logical units +# weight weight of font (win32con.FW_NORMAL, win32con.FW_BOLD) +# italic boolean; true if set to anything but None +# underline boolean; true if set to anything but None + + +class FontView(docview.ScrollView): + def __init__( + self, doc, text="Python Rules!", font_spec={"name": "Arial", "height": 42} + ): + docview.ScrollView.__init__(self, doc) + self.font = win32ui.CreateFont(font_spec) + self.text = text + self.width = self.height = 0 + # set up message handlers + self.HookMessage(self.OnSize, win32con.WM_SIZE) + + def OnAttachedObjectDeath(self): + docview.ScrollView.OnAttachedObjectDeath(self) + del self.font + + def SetFont(self, new_font): + # Change font on the fly + self.font = win32ui.CreateFont(new_font) + # redraw the entire client window + selfInvalidateRect(None) + + def OnSize(self, params): + lParam = params[3] + self.width = win32api.LOWORD(lParam) + self.height = win32api.HIWORD(lParam) + + def OnPrepareDC(self, dc, printinfo): + # Set up the DC for forthcoming OnDraw call + self.SetScrollSizes(win32con.MM_TEXT, (100, 100)) + dc.SetTextColor(win32api.RGB(0, 0, 255)) + dc.SetBkColor(win32api.GetSysColor(win32con.COLOR_WINDOW)) + dc.SelectObject(self.font) + dc.SetTextAlign(win32con.TA_CENTER | win32con.TA_BASELINE) + + def OnDraw(self, dc): + if self.width == 0 and self.height == 0: + left, top, right, bottom = self.GetClientRect() + self.width = right - left + self.height = bottom - top + x, y = self.width // 2, self.height // 2 + dc.TextOut(x, y, self.text) + + +def FontDemo(): + # create doc/view + template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, None, None, FontView) + doc = template.OpenDocumentFile(None) + doc.SetTitle("Font Demo") + # print "template is ", template, "obj is", template._obj_ + template.close() + + +# print "closed" +# del template + +if __name__ == "__main__": + import demoutils + + if demoutils.NeedGoodGUI(): + FontDemo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/guidemo.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/guidemo.py new file mode 100644 index 0000000000000000000000000000000000000000..b4d88159a0257e7db4a2db2e6e81a837895d8fe1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/guidemo.py @@ -0,0 +1,86 @@ +# GUI Demo - just a worker script to invoke all the other demo/test scripts. +import sys + +import __main__ +import regutil +import win32api +import win32ui + +demos = [ # ('Font', 'import fontdemo;fontdemo.FontDemo()'), + ("Open GL Demo", "import openGLDemo;openGLDemo.test()"), + ("Threaded GUI", "import threadedgui;threadedgui.ThreadedDemo()"), + ("Tree View Demo", "import hiertest;hiertest.demoboth()"), + ("3-Way Splitter Window", "import splittst;splittst.demo()"), + ("Custom Toolbars and Tooltips", "import toolbar;toolbar.test()"), + ("Progress Bar", "import progressbar;progressbar.demo()"), + ("Slider Control", "import sliderdemo;sliderdemo.demo()"), + ("Dynamic window creation", "import createwin;createwin.demo()"), + ("Various Dialog demos", "import dlgtest;dlgtest.demo()"), + ("OCX Control Demo", "from ocx import ocxtest;ocxtest.demo()"), + ("OCX Serial Port Demo", "from ocx import ocxserialtest; ocxserialtest.test()"), + ( + "IE4 Control Demo", + 'from ocx import webbrowser; webbrowser.Demo("http://www.python.org")', + ), +] + + +def demo(): + try: + # seeif I can locate the demo files. + import fontdemo + except ImportError: + # else put the demos direectory on the path (if not already) + try: + instPath = regutil.GetRegistryDefaultValue( + regutil.BuildDefaultPythonKey() + "\\InstallPath" + ) + except win32api.error: + print( + "The InstallPath can not be located, and the Demos directory is not on the path" + ) + instPath = "." + + demosDir = win32ui.FullPath(instPath + "\\Demos") + for path in sys.path: + if win32ui.FullPath(path) == demosDir: + break + else: + sys.path.append(demosDir) + import fontdemo + + import sys + + if "/go" in sys.argv: + for name, cmd in demos: + try: + exec(cmd) + except: + print( + "Demo of %s failed - %s:%s" + % (cmd, sys.exc_info()[0], sys.exc_info()[1]) + ) + return + # Otherwise allow the user to select the demo to run + + import pywin.dialogs.list + + while 1: + rc = pywin.dialogs.list.SelectFromLists("Select a Demo", demos, ["Demo Title"]) + if rc is None: + break + title, cmd = demos[rc] + try: + exec(cmd) + except: + print( + "Demo of %s failed - %s:%s" + % (title, sys.exc_info()[0], sys.exc_info()[1]) + ) + + +if __name__ == __main__.__name__: + import demoutils + + if demoutils.NeedGoodGUI(): + demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/hiertest.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/hiertest.py new file mode 100644 index 0000000000000000000000000000000000000000..287b71dafac59d8de2d06f26f1642154b9a90bc2 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/hiertest.py @@ -0,0 +1,138 @@ +import os + +import commctrl +import win32ui +from pywin.mfc import docview, window +from pywin.tools import hierlist + + +# directory listbox +# This has obvious limitations - doesnt track subdirs, etc. Demonstrates +# simple use of Python code for querying the tree as needed. +# Only use strings, and lists of strings (from curdir()) +class DirHierList(hierlist.HierList): + def __init__(self, root, listBoxID=win32ui.IDC_LIST1): + hierlist.HierList.__init__(self, root, win32ui.IDB_HIERFOLDERS, listBoxID) + + def GetText(self, item): + return os.path.basename(item) + + def GetSubList(self, item): + if os.path.isdir(item): + ret = [os.path.join(item, fname) for fname in os.listdir(item)] + else: + ret = None + return ret + + # if the item is a dir, it is expandable. + def IsExpandable(self, item): + return os.path.isdir(item) + + def GetSelectedBitmapColumn(self, item): + return self.GetBitmapColumn(item) + 6 # Use different color for selection + + +class TestDocument(docview.Document): + def __init__(self, template): + docview.Document.__init__(self, template) + self.hierlist = hierlist.HierListWithItems( + HLIFileDir("\\"), win32ui.IDB_HIERFOLDERS, win32ui.AFX_IDW_PANE_FIRST + ) + + +class HierListView(docview.TreeView): + def OnInitialUpdate(self): + rc = self._obj_.OnInitialUpdate() + self.hierList = self.GetDocument().hierlist + self.hierList.HierInit(self.GetParent()) + self.hierList.SetStyle( + commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS + ) + return rc + + +class HierListFrame(window.MDIChildWnd): + pass + + +def GetTestRoot(): + tree1 = ("Tree 1", [("Item 1", "Item 1 data"), "Item 2", 3]) + tree2 = ("Tree 2", [("Item 2.1", "Item 2 data"), "Item 2.2", 2.3]) + return ("Root", [tree1, tree2, "Item 3"]) + + +def demoboth(): + template = docview.DocTemplate( + win32ui.IDR_PYTHONTYPE, TestDocument, HierListFrame, HierListView + ) + template.OpenDocumentFile(None).SetTitle("Hierlist demo") + + demomodeless() + + +def demomodeless(): + testList2 = DirHierList("\\") + dlg = hierlist.HierDialog("hier list test", testList2) + dlg.CreateWindow() + + +def demodlg(): + testList2 = DirHierList("\\") + dlg = hierlist.HierDialog("hier list test", testList2) + dlg.DoModal() + + +def demo(): + template = docview.DocTemplate( + win32ui.IDR_PYTHONTYPE, TestDocument, HierListFrame, HierListView + ) + template.OpenDocumentFile(None).SetTitle("Hierlist demo") + + +# +# Demo/Test for HierList items. +# +# Easy to make a better directory program. +# +class HLIFileDir(hierlist.HierListItem): + def __init__(self, filename): + self.filename = filename + hierlist.HierListItem.__init__(self) + + def GetText(self): + try: + return "%-20s %d bytes" % ( + os.path.basename(self.filename), + os.stat(self.filename)[6], + ) + except os.error as details: + return "%-20s - %s" % (self.filename, details[1]) + + def IsExpandable(self): + return os.path.isdir(self.filename) + + def GetSubList(self): + ret = [] + for newname in os.listdir(self.filename): + if newname not in (".", ".."): + ret.append(HLIFileDir(os.path.join(self.filename, newname))) + return ret + + +def demohli(): + template = docview.DocTemplate( + win32ui.IDR_PYTHONTYPE, + TestDocument, + hierlist.HierListFrame, + hierlist.HierListView, + ) + template.OpenDocumentFile(None).SetTitle("Hierlist demo") + + +if __name__ == "__main__": + import demoutils + + if demoutils.HaveGoodGUI(): + demoboth() + else: + demodlg() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/menutest.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/menutest.py new file mode 100644 index 0000000000000000000000000000000000000000..d2ba65b6dd4bc3310b13cf5911883d199e58c28f --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/menutest.py @@ -0,0 +1,13 @@ +# Run this as a python script, to gray "close" off the edit window system menu. +import win32con +from pywin.framework import interact + +if __name__ == "__main__": + import demoutils + + if demoutils.NeedGoodGUI(): + win = interact.edit.currentView.GetParent() + menu = win.GetSystemMenu() + id = menu.GetMenuItemID(6) + menu.EnableMenuItem(id, win32con.MF_BYCOMMAND | win32con.MF_GRAYED) + print("The interactive window's 'Close' menu item is now disabled.") diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/objdoc.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/objdoc.py new file mode 100644 index 0000000000000000000000000000000000000000..fff7925360da164cbb01f250917ca68fafc55d10 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/objdoc.py @@ -0,0 +1,57 @@ +# This is a sample file, and shows the basic framework for using an "Object" based +# document, rather than a "filename" based document. +# This is referenced by the Pythonwin .html documentation. + +# In the example below, the OpenObject() method is used instead of OpenDocumentFile, +# and all the core MFC document open functionality is retained. + +import win32ui +from pywin.mfc import docview + + +class object_template(docview.DocTemplate): + def __init__(self): + docview.DocTemplate.__init__(self, None, None, None, object_view) + + def OpenObject(self, object): # Use this instead of OpenDocumentFile. + # Look for existing open document + for doc in self.GetDocumentList(): + print("document is ", doc) + if doc.object is object: + doc.GetFirstView().ActivateFrame() + return doc + # not found - new one. + doc = object_document(self, object) + frame = self.CreateNewFrame(doc) + doc.OnNewDocument() + doc.SetTitle(str(object)) + self.InitialUpdateFrame(frame, doc) + return doc + + +class object_document(docview.Document): + def __init__(self, template, object): + docview.Document.__init__(self, template) + self.object = object + + def OnOpenDocument(self, name): + raise RuntimeError("Should not be called if template strings set up correctly") + return 0 + + +class object_view(docview.EditView): + def OnInitialUpdate(self): + self.ReplaceSel("Object is %s" % repr(self.GetDocument().object)) + + +def demo(): + t = object_template() + d = t.OpenObject(win32ui) + return (t, d) + + +if __name__ == "__main__": + import demoutils + + if demoutils.NeedGoodGUI(): + demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04a9718f1e918c5d26b04483ef7ce6513ab7ad9a Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/demoutils.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/demoutils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35dac7eb11f4722d4651e223cb35633f9c2ab386 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/demoutils.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/flash.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/flash.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61f4ac8d9398f86ce4362025f16eb9c15e6981b7 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/flash.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/msoffice.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/msoffice.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37b34cfeb93c962baa3215deeeb04f846b7aa659 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/msoffice.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/ocxserialtest.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/ocxserialtest.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0792c9a93e8fe67affa8e06a024d547476729bdc Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/ocxserialtest.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/ocxtest.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/ocxtest.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39c36395ee7a16ddc53d515c35a7a9fe02ec439b Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/ocxtest.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/webbrowser.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/webbrowser.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a6a49182d9817d0f4ca7dde99576c17c99823b9 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/__pycache__/webbrowser.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/demoutils.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/demoutils.py new file mode 100644 index 0000000000000000000000000000000000000000..27fa091cbc7de620f490d2a8b4fb61a35940a99a --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/demoutils.py @@ -0,0 +1,67 @@ +# Utilities for the demos + +import sys + +import win32api +import win32con +import win32ui + +NotScriptMsg = """\ +This demo program is not designed to be run as a Script, but is +probably used by some other test program. Please try another demo. +""" + +NeedGUIMsg = """\ +This demo program can only be run from inside of Pythonwin + +You must start Pythonwin, and select 'Run' from the toolbar or File menu +""" + + +NeedAppMsg = """\ +This demo program is a 'Pythonwin Application'. + +It is more demo code than an example of Pythonwin's capabilities. + +To run it, you must execute the command: +pythonwin.exe /app "%s" + +Would you like to execute it now? +""" + + +def NotAScript(): + import win32ui + + win32ui.MessageBox(NotScriptMsg, "Demos") + + +def NeedGoodGUI(): + from pywin.framework.app import HaveGoodGUI + + rc = HaveGoodGUI() + if not rc: + win32ui.MessageBox(NeedGUIMsg, "Demos") + return rc + + +def NeedApp(): + import win32ui + + rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO) + if rc == win32con.IDYES: + try: + parent = win32ui.GetMainFrame().GetSafeHwnd() + win32api.ShellExecute( + parent, None, "pythonwin.exe", '/app "%s"' % sys.argv[0], None, 1 + ) + except win32api.error as details: + win32ui.MessageBox("Error executing command - %s" % (details), "Demos") + + +from pywin.framework.app import HaveGoodGUI + +if __name__ == "__main__": + from . import demoutils + + demoutils.NotAScript() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/flash.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/flash.py new file mode 100644 index 0000000000000000000000000000000000000000..239240ee33a0791e391cf54df1f12afe491cbf48 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/flash.py @@ -0,0 +1,95 @@ +# By Bradley Schatz +# simple flash/python application demonstrating bidirectional +# communicaion between flash and python. Click the sphere to see +# behavior. Uses Bounce.swf from FlashBounce.zip, available from +# http://pages.cpsc.ucalgary.ca/~saul/vb_examples/tutorial12/ + +# Update to the path of the .swf file (note it could be a true URL) +flash_url = "c:\\bounce.swf" + +import sys + +import regutil +import win32api +import win32con +import win32ui +from pywin.mfc import activex, window +from win32com.client import gencache + +FlashModule = gencache.EnsureModule("{D27CDB6B-AE6D-11CF-96B8-444553540000}", 0, 1, 0) + +if FlashModule is None: + raise ImportError("Flash does not appear to be installed.") + + +class MyFlashComponent(activex.Control, FlashModule.ShockwaveFlash): + def __init__(self): + activex.Control.__init__(self) + FlashModule.ShockwaveFlash.__init__(self) + self.x = 50 + self.y = 50 + self.angle = 30 + self.started = 0 + + def OnFSCommand(self, command, args): + print("FSCommend", command, args) + self.x = self.x + 20 + self.y = self.y + 20 + self.angle = self.angle + 20 + if self.x > 200 or self.y > 200: + self.x = 0 + self.y = 0 + if self.angle > 360: + self.angle = 0 + self.SetVariable("xVal", self.x) + self.SetVariable("yVal", self.y) + self.SetVariable("angle", self.angle) + self.TPlay("_root.mikeBall") + + def OnProgress(self, percentDone): + print("PercentDone", percentDone) + + def OnReadyStateChange(self, newState): + # 0=Loading, 1=Uninitialized, 2=Loaded, 3=Interactive, 4=Complete + print("State", newState) + + +class BrowserFrame(window.MDIChildWnd): + def __init__(self, url=None): + if url is None: + self.url = regutil.GetRegisteredHelpFile("Main Python Documentation") + else: + self.url = url + pass # Dont call base class doc/view version... + + def Create(self, title, rect=None, parent=None): + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW + self._obj_ = win32ui.CreateMDIChild() + self._obj_.AttachObject(self) + self._obj_.CreateWindow(None, title, style, rect, parent) + rect = self.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + self.ocx = MyFlashComponent() + self.ocx.CreateControl( + "Flash Player", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000 + ) + self.ocx.LoadMovie(0, flash_url) + self.ocx.Play() + self.HookMessage(self.OnSize, win32con.WM_SIZE) + + def OnSize(self, params): + rect = self.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + self.ocx.SetWindowPos(0, rect, 0) + + +def Demo(): + url = None + if len(sys.argv) > 1: + url = win32api.GetFullPathName(sys.argv[1]) + f = BrowserFrame(url) + f.Create("Flash Player") + + +if __name__ == "__main__": + Demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/msoffice.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/msoffice.py new file mode 100644 index 0000000000000000000000000000000000000000..be24ead82f8f3358f221c07dac4f6c6a685bbca4 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/msoffice.py @@ -0,0 +1,152 @@ +# This demo uses some of the Microsoft Office components. +# +# It was taken from an MSDN article showing how to embed excel. +# It is not comlpete yet, but it _does_ show an Excel spreadsheet in a frame! +# + +import regutil +import win32con +import win32ui +import win32uiole +from pywin.mfc import activex, docview, object, window +from win32com.client import gencache + +# WordModule = gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 1033, 8, 0) +# if WordModule is None: +# raise ImportError, "Microsoft Word version 8 does not appear to be installed." + + +class OleClientItem(object.CmdTarget): + def __init__(self, doc): + object.CmdTarget.__init__(self, win32uiole.CreateOleClientItem(doc)) + + def OnGetItemPosition(self): + # For now return a hard-coded rect. + return (10, 10, 210, 210) + + def OnActivate(self): + # Allow only one inplace activate item per frame + view = self.GetActiveView() + item = self.GetDocument().GetInPlaceActiveItem(view) + if item is not None and item._obj_ != self._obj_: + item.Close() + self._obj_.OnActivate() + + def OnChange(self, oleNotification, dwParam): + self._obj_.OnChange(oleNotification, dwParam) + self.GetDocument().UpdateAllViews(None) + + def OnChangeItemPosition(self, rect): + # During in-place activation CEmbed_ExcelCntrItem::OnChangeItemPosition + # is called by the server to change the position of the in-place + # window. Usually, this is a result of the data in the server + # document changing such that the extent has changed or as a result + # of in-place resizing. + # + # The default here is to call the base class, which will call + # COleClientItem::SetItemRects to move the item + # to the new position. + if not self._obj_.OnChangeItemPosition(self, rect): + return 0 + + # TODO: update any cache you may have of the item's rectangle/extent + return 1 + + +class OleDocument(object.CmdTarget): + def __init__(self, template): + object.CmdTarget.__init__(self, win32uiole.CreateOleDocument(template)) + self.EnableCompoundFile() + + +class ExcelView(docview.ScrollView): + def OnInitialUpdate(self): + self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS) + self.HookMessage(self.OnSize, win32con.WM_SIZE) + + self.SetScrollSizes(win32con.MM_TEXT, (100, 100)) + rc = self._obj_.OnInitialUpdate() + self.EmbedExcel() + return rc + + def EmbedExcel(self): + doc = self.GetDocument() + self.clientItem = OleClientItem(doc) + self.clientItem.CreateNewItem("Excel.Sheet") + self.clientItem.DoVerb(-1, self) + doc.UpdateAllViews(None) + + def OnDraw(self, dc): + doc = self.GetDocument() + pos = doc.GetStartPosition() + clientItem, pos = doc.GetNextItem(pos) + clientItem.Draw(dc, (10, 10, 210, 210)) + + # Special handling of OnSetFocus and OnSize are required for a container + # when an object is being edited in-place. + def OnSetFocus(self, msg): + item = self.GetDocument().GetInPlaceActiveItem(self) + if ( + item is not None + and item.GetItemState() == win32uiole.COleClientItem_activeUIState + ): + wnd = item.GetInPlaceWindow() + if wnd is not None: + wnd.SetFocus() + return 0 # Dont get the base version called. + return 1 # Call the base version. + + def OnSize(self, params): + item = self.GetDocument().GetInPlaceActiveItem(self) + if item is not None: + item.SetItemRects() + return 1 # do call the base! + + +class OleTemplate(docview.DocTemplate): + def __init__( + self, resourceId=None, MakeDocument=None, MakeFrame=None, MakeView=None + ): + if MakeDocument is None: + MakeDocument = OleDocument + if MakeView is None: + MakeView = ExcelView + docview.DocTemplate.__init__( + self, resourceId, MakeDocument, MakeFrame, MakeView + ) + + +class WordFrame(window.MDIChildWnd): + def __init__(self, doc=None): + self._obj_ = win32ui.CreateMDIChild() + self._obj_.AttachObject(self) + # Dont call base class doc/view version... + + def Create(self, title, rect=None, parent=None): + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW + self._obj_.CreateWindow(None, title, style, rect, parent) + + rect = self.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + self.ocx = MyWordControl() + self.ocx.CreateControl( + "Microsoft Word", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 20000 + ) + + +def Demo(): + import sys + + import win32api + + docName = None + if len(sys.argv) > 1: + docName = win32api.GetFullPathName(sys.argv[1]) + OleTemplate().OpenDocumentFile(None) + + +# f = WordFrame(docName) +# f.Create("Microsoft Office") + +if __name__ == "__main__": + Demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxserialtest.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxserialtest.py new file mode 100644 index 0000000000000000000000000000000000000000..326d312c8f59d7e4d31820d0f57e88551dc24bfc --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxserialtest.py @@ -0,0 +1,133 @@ +# ocxserialtest.py +# +# Sample that uses the mscomm OCX to talk to a serial +# device. + +# Very simple - queries a modem for ATI responses + +import pythoncom +import win32con +import win32ui +import win32uiole +from pywin.mfc import activex, dialog +from win32com.client import gencache + +SERIAL_SETTINGS = "19200,n,8,1" +SERIAL_PORT = 2 + +win32ui.DoWaitCursor(1) +serialModule = gencache.EnsureModule("{648A5603-2C6E-101B-82B6-000000000014}", 0, 1, 1) +win32ui.DoWaitCursor(0) +if serialModule is None: + raise ImportError("MS COMM Control does not appear to be installed on the PC") + + +def MakeDlgTemplate(): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + dlg = [ + ["Very Basic Terminal", (0, 0, 350, 180), style, None, (8, "MS Sans Serif")], + ] + s = win32con.WS_TABSTOP | cs + dlg.append( + [ + "RICHEDIT", + None, + 132, + (5, 5, 340, 170), + s + | win32con.ES_WANTRETURN + | win32con.ES_MULTILINE + | win32con.ES_AUTOVSCROLL + | win32con.WS_VSCROLL, + ] + ) + return dlg + + +#################################### +# +# Serial Control +# +class MySerialControl(activex.Control, serialModule.MSComm): + def __init__(self, parent): + activex.Control.__init__(self) + serialModule.MSComm.__init__(self) + self.parent = parent + + def OnComm(self): + self.parent.OnComm() + + +class TestSerDialog(dialog.Dialog): + def __init__(self, *args): + dialog.Dialog.__init__(*(self,) + args) + self.olectl = None + + def OnComm(self): + event = self.olectl.CommEvent + if event == serialModule.OnCommConstants.comEvReceive: + self.editwindow.ReplaceSel(self.olectl.Input) + + def OnKey(self, key): + if self.olectl: + self.olectl.Output = chr(key) + + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + self.editwindow = self.GetDlgItem(132) + self.editwindow.HookAllKeyStrokes(self.OnKey) + + self.olectl = MySerialControl(self) + try: + self.olectl.CreateControl( + "OCX", + win32con.WS_TABSTOP | win32con.WS_VISIBLE, + (7, 43, 500, 300), + self._obj_, + 131, + ) + except win32ui.error: + self.MessageBox("The Serial Control could not be created") + self.olectl = None + self.EndDialog(win32con.IDCANCEL) + if self.olectl: + self.olectl.Settings = SERIAL_SETTINGS + self.olectl.CommPort = SERIAL_PORT + self.olectl.RThreshold = 1 + try: + self.olectl.PortOpen = 1 + except pythoncom.com_error as details: + print( + "Could not open the specified serial port - %s" + % (details.excepinfo[2]) + ) + self.EndDialog(win32con.IDCANCEL) + return rc + + def OnDestroy(self, msg): + if self.olectl: + try: + self.olectl.PortOpen = 0 + except pythoncom.com_error as details: + print("Error closing port - %s" % (details.excepinfo[2])) + return dialog.Dialog.OnDestroy(self, msg) + + +def test(): + d = TestSerDialog(MakeDlgTemplate()) + d.DoModal() + + +if __name__ == "__main__": + from . import demoutils + + if demoutils.NeedGoodGUI(): + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxtest.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxtest.py new file mode 100644 index 0000000000000000000000000000000000000000..4a3d73363d904132007c219642e87fe3b75a0744 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/ocxtest.py @@ -0,0 +1,250 @@ +# OCX Tester for Pythonwin +# +# This file _is_ ready to run. All that is required is that the OCXs being tested +# are installed on your machine. +# +# The .py files behind the OCXs will be automatically generated and imported. + +import glob +import os + +import win32api +import win32con +import win32ui +import win32uiole +from pywin.mfc import activex, dialog, window +from win32com.client import gencache + + +def MakeDlgTemplate(): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + dlg = [ + ["OCX Demos", (0, 0, 350, 350), style, None, (8, "MS Sans Serif")], + ] + s = win32con.WS_TABSTOP | cs + # dlg.append([131, None, 130, (5, 40, 110, 48), + # s | win32con.LBS_NOTIFY | win32con.LBS_SORT | win32con.LBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL | win32con.WS_BORDER]) + # dlg.append(["{8E27C92B-1264-101C-8A2F-040224009C02}", None, 131, (5, 40, 110, 48),win32con.WS_TABSTOP]) + + dlg.append( + [128, "About", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON] + ) + s = win32con.BS_PUSHBUTTON | s + dlg.append([128, "Close", win32con.IDCANCEL, (124, 22, 50, 14), s]) + + return dlg + + +#################################### +# +# Calendar test code +# + + +def GetTestCalendarClass(): + global calendarParentModule + win32ui.DoWaitCursor(1) + calendarParentModule = gencache.EnsureModule( + "{8E27C92E-1264-101C-8A2F-040224009C02}", 0, 7, 0 + ) + win32ui.DoWaitCursor(0) + if calendarParentModule is None: + return None + + class TestCalDialog(dialog.Dialog): + def OnInitDialog(self): + class MyCal(activex.Control, calendarParentModule.Calendar): + def OnAfterUpdate(self): + print("OnAfterUpdate") + + def OnClick(self): + print("OnClick") + + def OnDblClick(self): + print("OnDblClick") + + def OnKeyDown(self, KeyCode, Shift): + print("OnKeyDown", KeyCode, Shift) + + def OnKeyPress(self, KeyAscii): + print("OnKeyPress", KeyAscii) + + def OnKeyUp(self, KeyCode, Shift): + print("OnKeyUp", KeyCode, Shift) + + def OnBeforeUpdate(self, Cancel): + print("OnBeforeUpdate", Cancel) + + def OnNewMonth(self): + print("OnNewMonth") + + def OnNewYear(self): + print("OnNewYear") + + rc = dialog.Dialog.OnInitDialog(self) + self.olectl = MyCal() + try: + self.olectl.CreateControl( + "OCX", + win32con.WS_TABSTOP | win32con.WS_VISIBLE, + (7, 43, 500, 300), + self._obj_, + 131, + ) + except win32ui.error: + self.MessageBox("The Calendar Control could not be created") + self.olectl = None + self.EndDialog(win32con.IDCANCEL) + + return rc + + def OnOK(self): + self.olectl.AboutBox() + + return TestCalDialog + + +#################################### +# +# Video Control +# +def GetTestVideoModule(): + global videoControlModule, videoControlFileName + win32ui.DoWaitCursor(1) + videoControlModule = gencache.EnsureModule( + "{05589FA0-C356-11CE-BF01-00AA0055595A}", 0, 2, 0 + ) + win32ui.DoWaitCursor(0) + if videoControlModule is None: + return None + fnames = glob.glob(os.path.join(win32api.GetWindowsDirectory(), "*.avi")) + if not fnames: + print("No AVI files available in system directory") + return None + videoControlFileName = fnames[0] + return videoControlModule + + +def GetTestVideoDialogClass(): + if GetTestVideoModule() is None: + return None + + class TestVideoDialog(dialog.Dialog): + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + try: + self.olectl = activex.MakeControlInstance( + videoControlModule.ActiveMovie + ) + self.olectl.CreateControl( + "", + win32con.WS_TABSTOP | win32con.WS_VISIBLE, + (7, 43, 500, 300), + self._obj_, + 131, + ) + except win32ui.error: + self.MessageBox("The Video Control could not be created") + self.olectl = None + self.EndDialog(win32con.IDCANCEL) + return + + self.olectl.FileName = videoControlFileName + # self.olectl.Run() + return rc + + def OnOK(self): + self.olectl.AboutBox() + + return TestVideoDialog + + +############### +# +# An OCX in an MDI Frame +# +class OCXFrame(window.MDIChildWnd): + def __init__(self): + pass # Dont call base class doc/view version... + + def Create(self, controlClass, title, rect=None, parent=None): + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW + self._obj_ = win32ui.CreateMDIChild() + self._obj_.AttachObject(self) + self._obj_.CreateWindow(None, title, style, rect, parent) + + rect = self.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + self.ocx = controlClass() + self.ocx.CreateControl( + "", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000 + ) + + +def MDITest(): + calendarParentModule = gencache.EnsureModule( + "{8E27C92E-1264-101C-8A2F-040224009C02}", 0, 7, 0 + ) + + class MyCal(activex.Control, calendarParentModule.Calendar): + def OnAfterUpdate(self): + print("OnAfterUpdate") + + def OnClick(self): + print("OnClick") + + f = OCXFrame() + f.Create(MyCal, "Calendar Test") + + +def test1(): + klass = GetTestCalendarClass() + if klass is None: + print( + "Can not test the MSAccess Calendar control - it does not appear to be installed" + ) + return + + d = klass(MakeDlgTemplate()) + d.DoModal() + + +def test2(): + klass = GetTestVideoDialogClass() + if klass is None: + print("Can not test the Video OCX - it does not appear to be installed,") + print("or no AVI files can be found.") + return + d = klass(MakeDlgTemplate()) + d.DoModal() + d = None + + +def test3(): + d = TestCOMMDialog(MakeDlgTemplate()) + d.DoModal() + d = None + + +def testall(): + test1() + test2() + + +def demo(): + testall() + + +if __name__ == "__main__": + from . import demoutils + + if demoutils.NeedGoodGUI(): + testall() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/webbrowser.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/webbrowser.py new file mode 100644 index 0000000000000000000000000000000000000000..cc17445e9ad08a469c88032eb291796c3fde1b82 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/ocx/webbrowser.py @@ -0,0 +1,72 @@ +# This demo uses the IE4 Web Browser control. + +# It catches an "OnNavigate" event, and updates the frame title. +# (event stuff by Neil Hodgson) + +import sys + +import regutil +import win32api +import win32con +import win32ui +from pywin.mfc import activex, window +from win32com.client import gencache + +WebBrowserModule = gencache.EnsureModule( + "{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1 +) +if WebBrowserModule is None: + raise ImportError("IE4 does not appear to be installed.") + + +class MyWebBrowser(activex.Control, WebBrowserModule.WebBrowser): + def OnBeforeNavigate2( + self, pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel + ): + self.GetParent().OnNavigate(URL) + # print "BeforeNavigate2", pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel + + +class BrowserFrame(window.MDIChildWnd): + def __init__(self, url=None): + if url is None: + self.url = regutil.GetRegisteredHelpFile("Main Python Documentation") + if self.url is None: + self.url = "http://www.python.org" + else: + self.url = url + pass # Dont call base class doc/view version... + + def Create(self, title, rect=None, parent=None): + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW + self._obj_ = win32ui.CreateMDIChild() + self._obj_.AttachObject(self) + self._obj_.CreateWindow(None, title, style, rect, parent) + rect = self.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + self.ocx = MyWebBrowser() + self.ocx.CreateControl( + "Web Browser", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000 + ) + self.ocx.Navigate(self.url) + self.HookMessage(self.OnSize, win32con.WM_SIZE) + + def OnSize(self, params): + rect = self.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + self.ocx.SetWindowPos(0, rect, 0) + + def OnNavigate(self, url): + title = "Web Browser - %s" % (url,) + self.SetWindowText(title) + + +def Demo(url=None): + if url is None and len(sys.argv) > 1: + url = win32api.GetFullPathName(sys.argv[1]) + f = BrowserFrame(url) + f.Create("Web Browser") + + +if __name__ == "__main__": + Demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/openGLDemo.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/openGLDemo.py new file mode 100644 index 0000000000000000000000000000000000000000..9274949dea90a07eba5bb964c85388bb8e5d2ddb --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/openGLDemo.py @@ -0,0 +1,370 @@ +# Ported from the win32 and MFC OpenGL Samples. + +import sys + +from pywin.mfc import docview + +try: + from OpenGL.GL import * # nopycln: import + from OpenGL.GLU import * # nopycln: import +except ImportError: + print("The OpenGL extensions do not appear to be installed.") + print("This Pythonwin demo can not run") + sys.exit(1) + +import timer +import win32api +import win32con +import win32ui + +PFD_TYPE_RGBA = 0 +PFD_TYPE_COLORINDEX = 1 +PFD_MAIN_PLANE = 0 +PFD_OVERLAY_PLANE = 1 +PFD_UNDERLAY_PLANE = -1 +PFD_DOUBLEBUFFER = 0x00000001 +PFD_STEREO = 0x00000002 +PFD_DRAW_TO_WINDOW = 0x00000004 +PFD_DRAW_TO_BITMAP = 0x00000008 +PFD_SUPPORT_GDI = 0x00000010 +PFD_SUPPORT_OPENGL = 0x00000020 +PFD_GENERIC_FORMAT = 0x00000040 +PFD_NEED_PALETTE = 0x00000080 +PFD_NEED_SYSTEM_PALETTE = 0x00000100 +PFD_SWAP_EXCHANGE = 0x00000200 +PFD_SWAP_COPY = 0x00000400 +PFD_SWAP_LAYER_BUFFERS = 0x00000800 +PFD_GENERIC_ACCELERATED = 0x00001000 +PFD_DEPTH_DONTCARE = 0x20000000 +PFD_DOUBLEBUFFER_DONTCARE = 0x40000000 +PFD_STEREO_DONTCARE = 0x80000000 + + +# threeto8 = [0, 0o111>>1, 0o222>>1, 0o333>>1, 0o444>>1, 0o555>>1, 0o666>>1, 0o377] +threeto8 = [0, 73 >> 1, 146 >> 1, 219 >> 1, 292 >> 1, 365 >> 1, 438 >> 1, 255] +twoto8 = [0, 0x55, 0xAA, 0xFF] +oneto8 = [0, 255] + + +def ComponentFromIndex(i, nbits, shift): + # val = (unsigned char) (i >> shift); + val = (i >> shift) & 0xF + if nbits == 1: + val = val & 0x1 + return oneto8[val] + elif nbits == 2: + val = val & 0x3 + return twoto8[val] + elif nbits == 3: + val = val & 0x7 + return threeto8[val] + else: + return 0 + + +OpenGLViewParent = docview.ScrollView + + +class OpenGLView(OpenGLViewParent): + def PreCreateWindow(self, cc): + self.HookMessage(self.OnSize, win32con.WM_SIZE) + # An OpenGL window must be created with the following flags and must not + # include CS_PARENTDC for the class style. Refer to SetPixelFormat + # documentation in the "Comments" section for further information. + style = cc[5] + style = style | win32con.WS_CLIPSIBLINGS | win32con.WS_CLIPCHILDREN + cc = cc[0], cc[1], cc[2], cc[3], cc[4], style, cc[6], cc[7], cc[8] + cc = self._obj_.PreCreateWindow(cc) + return cc + + def OnSize(self, params): + lParam = params[3] + cx = win32api.LOWORD(lParam) + cy = win32api.HIWORD(lParam) + glViewport(0, 0, cx, cy) + + if self.oldrect[2] > cx or self.oldrect[3] > cy: + self.RedrawWindow() + + self.OnSizeChange(cx, cy) + + self.oldrect = self.oldrect[0], self.oldrect[1], cx, cy + + def OnInitialUpdate(self): + self.SetScaleToFitSize( + (100, 100) + ) # or SetScrollSizes() - A Pythonwin requirement + return self._obj_.OnInitialUpdate() + + # return rc + + def OnCreate(self, cs): + self.oldrect = self.GetClientRect() + self._InitContexts() + self.Init() + + def OnDestroy(self, msg): + self.Term() + self._DestroyContexts() + return OpenGLViewParent.OnDestroy(self, msg) + + def OnDraw(self, dc): + self.DrawScene() + + def OnEraseBkgnd(self, dc): + return 1 + + # The OpenGL helpers + def _SetupPixelFormat(self): + dc = self.dc.GetSafeHdc() + pfd = CreatePIXELFORMATDESCRIPTOR() + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER + pfd.iPixelType = PFD_TYPE_RGBA + pfd.cColorBits = 24 + pfd.cDepthBits = 32 + pfd.iLayerType = PFD_MAIN_PLANE + pixelformat = ChoosePixelFormat(dc, pfd) + SetPixelFormat(dc, pixelformat, pfd) + self._CreateRGBPalette() + + def _CreateRGBPalette(self): + dc = self.dc.GetSafeHdc() + n = GetPixelFormat(dc) + pfd = DescribePixelFormat(dc, n) + if pfd.dwFlags & PFD_NEED_PALETTE: + n = 1 << pfd.cColorBits + pal = [] + for i in range(n): + this = ( + ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift), + ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift), + ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift), + 0, + ) + pal.append(this) + hpal = win32ui.CreatePalette(pal) + self.dc.SelectPalette(hpal, 0) + self.dc.RealizePalette() + + def _InitContexts(self): + self.dc = self.GetDC() + self._SetupPixelFormat() + hrc = wglCreateContext(self.dc.GetSafeHdc()) + wglMakeCurrent(self.dc.GetSafeHdc(), hrc) + + def _DestroyContexts(self): + hrc = wglGetCurrentContext() + wglMakeCurrent(0, 0) + if hrc: + wglDeleteContext(hrc) + + # The methods to support OpenGL + def DrawScene(self): + assert 0, "You must override this method" + + def Init(self): + assert 0, "You must override this method" + + def OnSizeChange(self, cx, cy): + pass + + def Term(self): + pass + + +class TestView(OpenGLView): + def OnSizeChange(self, right, bottom): + glClearColor(0.0, 0.0, 0.0, 1.0) + glClearDepth(1.0) + glEnable(GL_DEPTH_TEST) + + glMatrixMode(GL_PROJECTION) + if bottom: + aspect = right / bottom + else: + aspect = 0 # When window created! + glLoadIdentity() + gluPerspective(45.0, aspect, 3.0, 7.0) + glMatrixMode(GL_MODELVIEW) + + near_plane = 3.0 + far_plane = 7.0 + maxObjectSize = 3.0 + self.radius = near_plane + maxObjectSize / 2.0 + + def Init(self): + pass + + def DrawScene(self): + glClearColor(0.0, 0.0, 0.0, 1.0) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + glPushMatrix() + glTranslatef(0.0, 0.0, -self.radius) + + self._DrawCone() + + self._DrawPyramid() + + glPopMatrix() + glFinish() + + SwapBuffers(wglGetCurrentDC()) + + def _DrawCone(self): + glColor3f(0.0, 1.0, 0.0) + + glPushMatrix() + glTranslatef(-1.0, 0.0, 0.0) + quadObj = gluNewQuadric() + gluQuadricDrawStyle(quadObj, GLU_FILL) + gluQuadricNormals(quadObj, GLU_SMOOTH) + gluCylinder(quadObj, 1.0, 0.0, 1.0, 20, 10) + # gluDeleteQuadric(quadObj); + glPopMatrix() + + def _DrawPyramid(self): + glPushMatrix() + glTranslatef(1.0, 0.0, 0.0) + glBegin(GL_TRIANGLE_FAN) + glColor3f(1.0, 0.0, 0.0) + glVertex3f(0.0, 1.0, 0.0) + glColor3f(0.0, 1.0, 0.0) + glVertex3f(-1.0, 0.0, 0.0) + glColor3f(0.0, 0.0, 1.0) + glVertex3f(0.0, 0.0, 1.0) + glColor3f(0.0, 1.0, 0.0) + glVertex3f(1.0, 0.0, 0.0) + glEnd() + glPopMatrix() + + +class CubeView(OpenGLView): + def OnSizeChange(self, right, bottom): + glClearColor(0.0, 0.0, 0.0, 1.0) + glClearDepth(1.0) + glEnable(GL_DEPTH_TEST) + + glMatrixMode(GL_PROJECTION) + if bottom: + aspect = right / bottom + else: + aspect = 0 # When window created! + glLoadIdentity() + gluPerspective(45.0, aspect, 3.0, 7.0) + glMatrixMode(GL_MODELVIEW) + + near_plane = 3.0 + far_plane = 7.0 + maxObjectSize = 3.0 + self.radius = near_plane + maxObjectSize / 2.0 + + def Init(self): + self.busy = 0 + self.wAngleY = 10.0 + self.wAngleX = 1.0 + self.wAngleZ = 5.0 + self.timerid = timer.set_timer(150, self.OnTimer) + + def OnTimer(self, id, timeVal): + self.DrawScene() + + def Term(self): + timer.kill_timer(self.timerid) + + def DrawScene(self): + if self.busy: + return + self.busy = 1 + + glClearColor(0.0, 0.0, 0.0, 1.0) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + glPushMatrix() + + glTranslatef(0.0, 0.0, -self.radius) + glRotatef(self.wAngleX, 1.0, 0.0, 0.0) + glRotatef(self.wAngleY, 0.0, 1.0, 0.0) + glRotatef(self.wAngleZ, 0.0, 0.0, 1.0) + + self.wAngleX = self.wAngleX + 1.0 + self.wAngleY = self.wAngleY + 10.0 + self.wAngleZ = self.wAngleZ + 5.0 + + glBegin(GL_QUAD_STRIP) + glColor3f(1.0, 0.0, 1.0) + glVertex3f(-0.5, 0.5, 0.5) + + glColor3f(1.0, 0.0, 0.0) + glVertex3f(-0.5, -0.5, 0.5) + + glColor3f(1.0, 1.0, 1.0) + glVertex3f(0.5, 0.5, 0.5) + + glColor3f(1.0, 1.0, 0.0) + glVertex3f(0.5, -0.5, 0.5) + + glColor3f(0.0, 1.0, 1.0) + glVertex3f(0.5, 0.5, -0.5) + + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0.5, -0.5, -0.5) + + glColor3f(0.0, 0.0, 1.0) + glVertex3f(-0.5, 0.5, -0.5) + + glColor3f(0.0, 0.0, 0.0) + glVertex3f(-0.5, -0.5, -0.5) + + glColor3f(1.0, 0.0, 1.0) + glVertex3f(-0.5, 0.5, 0.5) + + glColor3f(1.0, 0.0, 0.0) + glVertex3f(-0.5, -0.5, 0.5) + + glEnd() + + glBegin(GL_QUADS) + glColor3f(1.0, 0.0, 1.0) + glVertex3f(-0.5, 0.5, 0.5) + + glColor3f(1.0, 1.0, 1.0) + glVertex3f(0.5, 0.5, 0.5) + + glColor3f(0.0, 1.0, 1.0) + glVertex3f(0.5, 0.5, -0.5) + + glColor3f(0.0, 0.0, 1.0) + glVertex3f(-0.5, 0.5, -0.5) + glEnd() + + glBegin(GL_QUADS) + glColor3f(1.0, 0.0, 0.0) + glVertex3f(-0.5, -0.5, 0.5) + + glColor3f(1.0, 1.0, 0.0) + glVertex3f(0.5, -0.5, 0.5) + + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0.5, -0.5, -0.5) + + glColor3f(0.0, 0.0, 0.0) + glVertex3f(-0.5, -0.5, -0.5) + glEnd() + + glPopMatrix() + + glFinish() + SwapBuffers(wglGetCurrentDC()) + + self.busy = 0 + + +def test(): + template = docview.DocTemplate(None, None, None, CubeView) + # template = docview.DocTemplate(None, None, None, TestView ) + template.OpenDocumentFile(None) + + +if __name__ == "__main__": + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/progressbar.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/progressbar.py new file mode 100644 index 0000000000000000000000000000000000000000..81cd7e381d7677aad6220f3627dfbaa220e32a10 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/progressbar.py @@ -0,0 +1,105 @@ +# +# Progress bar control example +# +# PyCProgressCtrl encapsulates the MFC CProgressCtrl class. To use it, +# you: +# +# - Create the control with win32ui.CreateProgressCtrl() +# - Create the control window with PyCProgressCtrl.CreateWindow() +# - Initialize the range if you want it to be other than (0, 100) using +# PyCProgressCtrl.SetRange() +# - Either: +# - Set the step size with PyCProgressCtrl.SetStep(), and +# - Increment using PyCProgressCtrl.StepIt() +# or: +# - Set the amount completed using PyCProgressCtrl.SetPos() +# +# Example and progress bar code courtesy of KDL Technologies, Ltd., Hong Kong SAR, China. +# + +import win32con +import win32ui +from pywin.mfc import dialog + + +def MakeDlgTemplate(): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + + w = 215 + h = 36 + + dlg = [ + [ + "Progress bar control example", + (0, 0, w, h), + style, + None, + (8, "MS Sans Serif"), + ], + ] + + s = win32con.WS_TABSTOP | cs + + dlg.append( + [ + 128, + "Tick", + win32con.IDOK, + (10, h - 18, 50, 14), + s | win32con.BS_DEFPUSHBUTTON, + ] + ) + + dlg.append( + [ + 128, + "Cancel", + win32con.IDCANCEL, + (w - 60, h - 18, 50, 14), + s | win32con.BS_PUSHBUTTON, + ] + ) + + return dlg + + +class TestDialog(dialog.Dialog): + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + self.pbar = win32ui.CreateProgressCtrl() + self.pbar.CreateWindow( + win32con.WS_CHILD | win32con.WS_VISIBLE, (10, 10, 310, 24), self, 1001 + ) + # self.pbar.SetStep (5) + self.progress = 0 + self.pincr = 5 + return rc + + def OnOK(self): + # NB: StepIt wraps at the end if you increment past the upper limit! + # self.pbar.StepIt() + self.progress = self.progress + self.pincr + if self.progress > 100: + self.progress = 100 + if self.progress <= 100: + self.pbar.SetPos(self.progress) + + +def demo(modal=0): + d = TestDialog(MakeDlgTemplate()) + if modal: + d.DoModal() + else: + d.CreateWindow() + + +if __name__ == "__main__": + demo(1) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/sliderdemo.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/sliderdemo.py new file mode 100644 index 0000000000000000000000000000000000000000..9fc7b570576f569ff57da97560eb5dab806cbc75 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/sliderdemo.py @@ -0,0 +1,76 @@ +# sliderdemo.py +# Demo of the slider control courtesy of Mike Fletcher. + +import win32con +import win32ui +from pywin.mfc import dialog + + +class MyDialog(dialog.Dialog): + """ + Example using simple controls + """ + + _dialogstyle = ( + win32con.WS_MINIMIZEBOX + | win32con.WS_DLGFRAME + | win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + _buttonstyle = ( + win32con.BS_PUSHBUTTON + | win32con.WS_TABSTOP + | win32con.WS_CHILD + | win32con.WS_VISIBLE + ) + ### The static template, contains all "normal" dialog items + DIALOGTEMPLATE = [ + # the dialog itself is the first element in the template + ["Example slider", (0, 0, 50, 43), _dialogstyle, None, (8, "MS SansSerif")], + # rest of elements are the controls within the dialog + # standard "Close" button + [128, "Close", win32con.IDCANCEL, (0, 30, 50, 13), _buttonstyle], + ] + ### ID of the control to be created during dialog initialisation + IDC_SLIDER = 9500 + + def __init__(self): + dialog.Dialog.__init__(self, self.DIALOGTEMPLATE) + + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + # now initialise your controls that you want to create + # programmatically, including those which are OLE controls + # those created directly by win32ui.Create* + # and your "custom controls" which are subclasses/whatever + win32ui.EnableControlContainer() + self.slider = win32ui.CreateSliderCtrl() + self.slider.CreateWindow( + win32con.WS_TABSTOP | win32con.WS_VISIBLE, + (0, 0, 100, 30), + self._obj_, + self.IDC_SLIDER, + ) + self.HookMessage(self.OnSliderMove, win32con.WM_HSCROLL) + return rc + + def OnSliderMove(self, params): + print("Slider moved") + + def OnCancel(self): + print("The slider control is at position", self.slider.GetPos()) + self._obj_.OnCancel() + + +### +def demo(): + dia = MyDialog() + dia.DoModal() + + +if __name__ == "__main__": + demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/splittst.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/splittst.py new file mode 100644 index 0000000000000000000000000000000000000000..0114bf09a3ec8f40de4c6678a7f1dcee63d98cdc --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/splittst.py @@ -0,0 +1,79 @@ +import commctrl +import fontdemo +import win32ui +from pywin.mfc import docview, window + +# derive from CMDIChild. This does much work for us. + + +class SplitterFrame(window.MDIChildWnd): + def __init__(self): + # call base CreateFrame + self.images = None + window.MDIChildWnd.__init__(self) + + def OnCreateClient(self, cp, context): + splitter = win32ui.CreateSplitter() + doc = context.doc + frame_rect = self.GetWindowRect() + size = ((frame_rect[2] - frame_rect[0]), (frame_rect[3] - frame_rect[1]) // 2) + sub_size = (size[0] // 2, size[1]) + splitter.CreateStatic(self, 2, 1) + self.v1 = win32ui.CreateEditView(doc) + self.v2 = fontdemo.FontView(doc) + # CListControl view + self.v3 = win32ui.CreateListView(doc) + sub_splitter = win32ui.CreateSplitter() + # pass "splitter" so each view knows how to get to the others + sub_splitter.CreateStatic(splitter, 1, 2) + sub_splitter.CreateView(self.v1, 0, 0, (sub_size)) + sub_splitter.CreateView(self.v2, 0, 1, (0, 0)) # size ignored. + splitter.SetRowInfo(0, size[1], 0) + splitter.CreateView(self.v3, 1, 0, (0, 0)) # size ignored. + # Setup items in the imagelist + self.images = win32ui.CreateImageList(32, 32, 1, 5, 5) + self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_MAINFRAME)) + self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_PYTHONCONTYPE)) + self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_TEXTTYPE)) + self.v3.SetImageList(self.images, commctrl.LVSIL_NORMAL) + self.v3.InsertItem(0, "Icon 1", 0) + self.v3.InsertItem(0, "Icon 2", 1) + self.v3.InsertItem(0, "Icon 3", 2) + # self.v3.Arrange(commctrl.LVA_DEFAULT) Hmmm - win95 aligns left always??? + return 1 + + def OnDestroy(self, msg): + window.MDIChildWnd.OnDestroy(self, msg) + if self.images: + self.images.DeleteImageList() + self.images = None + + def InitialUpdateFrame(self, doc, makeVisible): + self.v1.ReplaceSel("Hello from Edit Window 1") + self.v1.SetModifiedFlag(0) + + +class SampleTemplate(docview.DocTemplate): + def __init__(self): + docview.DocTemplate.__init__( + self, win32ui.IDR_PYTHONTYPE, None, SplitterFrame, None + ) + + def InitialUpdateFrame(self, frame, doc, makeVisible): + # print "frame is ", frame, frame._obj_ + # print "doc is ", doc, doc._obj_ + self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler. + frame.InitialUpdateFrame(doc, makeVisible) + + +def demo(): + template = SampleTemplate() + doc = template.OpenDocumentFile(None) + doc.SetTitle("Splitter Demo") + + +if __name__ == "__main__": + import demoutils + + if demoutils.NeedGoodGUI(): + demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/threadedgui.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/threadedgui.py new file mode 100644 index 0000000000000000000000000000000000000000..bbe1369e482fda1475298c52400ce12c1aa46a08 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/threadedgui.py @@ -0,0 +1,189 @@ +# Demo of using just windows, without documents and views. + +# Also demo of a GUI thread, pretty much direct from the MFC C++ sample MTMDI. + +import timer +import win32api +import win32con +import win32ui +from pywin.mfc import docview, thread, window +from pywin.mfc.thread import WinThread + +WM_USER_PREPARE_TO_CLOSE = win32con.WM_USER + 32 + +# font is a dictionary in which the following elements matter: +# (the best matching font to supplied parameters is returned) +# name string name of the font as known by Windows +# size point size of font in logical units +# weight weight of font (win32con.FW_NORMAL, win32con.FW_BOLD) +# italic boolean; true if set to anything but None +# underline boolean; true if set to anything but None + + +# This window is a child window of a frame. It is not the frame window itself. +class FontWindow(window.Wnd): + def __init__(self, text="Python Rules!"): + window.Wnd.__init__(self) + self.text = text + self.index = 0 + self.incr = 1 + self.width = self.height = 0 + self.ChangeAttributes() + # set up message handlers + + def Create(self, title, style, rect, parent): + classStyle = win32con.CS_HREDRAW | win32con.CS_VREDRAW + className = win32ui.RegisterWndClass( + classStyle, 0, win32con.COLOR_WINDOW + 1, 0 + ) + self._obj_ = win32ui.CreateWnd() + self._obj_.AttachObject(self) + self._obj_.CreateWindow( + className, title, style, rect, parent, win32ui.AFX_IDW_PANE_FIRST + ) + self.HookMessage(self.OnSize, win32con.WM_SIZE) + self.HookMessage(self.OnPrepareToClose, WM_USER_PREPARE_TO_CLOSE) + self.HookMessage(self.OnDestroy, win32con.WM_DESTROY) + self.timerid = timer.set_timer(100, self.OnTimer) + self.InvalidateRect() + + def OnDestroy(self, msg): + timer.kill_timer(self.timerid) + + def OnTimer(self, id, timeVal): + self.index = self.index + self.incr + if self.index > len(self.text): + self.incr = -1 + self.index = len(self.text) + elif self.index < 0: + self.incr = 1 + self.index = 0 + self.InvalidateRect() + + def OnPaint(self): + # print "Paint message from thread", win32api.GetCurrentThreadId() + dc, paintStruct = self.BeginPaint() + self.OnPrepareDC(dc, None) + + if self.width == 0 and self.height == 0: + left, top, right, bottom = self.GetClientRect() + self.width = right - left + self.height = bottom - top + x, y = self.width // 2, self.height // 2 + dc.TextOut(x, y, self.text[: self.index]) + self.EndPaint(paintStruct) + + def ChangeAttributes(self): + font_spec = {"name": "Arial", "height": 42} + self.font = win32ui.CreateFont(font_spec) + + def OnPrepareToClose(self, params): + self.DestroyWindow() + + def OnSize(self, params): + lParam = params[3] + self.width = win32api.LOWORD(lParam) + self.height = win32api.HIWORD(lParam) + + def OnPrepareDC(self, dc, printinfo): + # Set up the DC for forthcoming OnDraw call + dc.SetTextColor(win32api.RGB(0, 0, 255)) + dc.SetBkColor(win32api.GetSysColor(win32con.COLOR_WINDOW)) + dc.SelectObject(self.font) + dc.SetTextAlign(win32con.TA_CENTER | win32con.TA_BASELINE) + + +class FontFrame(window.MDIChildWnd): + def __init__(self): + pass # Dont call base class doc/view version... + + def Create(self, title, rect=None, parent=None): + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW + self._obj_ = win32ui.CreateMDIChild() + self._obj_.AttachObject(self) + + self._obj_.CreateWindow(None, title, style, rect, parent) + rect = self.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + self.child = FontWindow("Not threaded") + self.child.Create( + "FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self + ) + + +class TestThread(WinThread): + def __init__(self, parentWindow): + self.parentWindow = parentWindow + self.child = None + WinThread.__init__(self) + + def InitInstance(self): + rect = self.parentWindow.GetClientRect() + rect = (0, 0, rect[2] - rect[0], rect[3] - rect[1]) + + self.child = FontWindow() + self.child.Create( + "FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self.parentWindow + ) + self.SetMainFrame(self.child) + return WinThread.InitInstance(self) + + def ExitInstance(self): + return 0 + + +class ThreadedFontFrame(window.MDIChildWnd): + def __init__(self): + pass # Dont call base class doc/view version... + self.thread = None + + def Create(self, title, rect=None, parent=None): + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW + self._obj_ = win32ui.CreateMDIChild() + self._obj_.CreateWindow(None, title, style, rect, parent) + self._obj_.HookMessage(self.OnDestroy, win32con.WM_DESTROY) + self._obj_.HookMessage(self.OnSize, win32con.WM_SIZE) + + self.thread = TestThread(self) + self.thread.CreateThread() + + def OnSize(self, msg): + pass + + def OnDestroy(self, msg): + win32ui.OutputDebugString("OnDestroy\n") + if self.thread and self.thread.child: + child = self.thread.child + child.SendMessage(WM_USER_PREPARE_TO_CLOSE, 0, 0) + win32ui.OutputDebugString("Destroyed\n") + + +def Demo(): + f = FontFrame() + f.Create("Font Demo") + + +def ThreadedDemo(): + rect = win32ui.GetMainFrame().GetMDIClient().GetClientRect() + rect = rect[0], int(rect[3] * 3 / 4), int(rect[2] / 4), rect[3] + incr = rect[2] + for i in range(4): + if i == 0: + f = FontFrame() + title = "Not threaded" + else: + f = ThreadedFontFrame() + title = "Threaded GUI Demo" + f.Create(title, rect) + rect = rect[0] + incr, rect[1], rect[2] + incr, rect[3] + # Givem a chance to start + win32api.Sleep(100) + win32ui.PumpWaitingMessages() + + +if __name__ == "__main__": + import demoutils + + if demoutils.NeedGoodGUI(): + ThreadedDemo() +# Demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/Demos/toolbar.py b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/toolbar.py new file mode 100644 index 0000000000000000000000000000000000000000..e56aefef18fd3440fd747cb86861149877c8cf9f --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/Demos/toolbar.py @@ -0,0 +1,106 @@ +# Demo of ToolBars + +# Shows the toolbar control. +# Demos how to make custom tooltips, etc. + +import commctrl +import win32api +import win32con +import win32ui +from pywin.mfc import afxres, docview, window + + +class GenericFrame(window.MDIChildWnd): + def OnCreateClient(self, cp, context): + # handlers for toolbar buttons + self.HookCommand(self.OnPrevious, 401) + self.HookCommand(self.OnNext, 402) + # Its not necessary for us to hook both of these - the + # common controls should fall-back all by themselves. + # Indeed, given we hook TTN_NEEDTEXTW, commctrl.TTN_NEEDTEXTA + # will not be called. + self.HookNotify(self.GetTTText, commctrl.TTN_NEEDTEXT) + self.HookNotify(self.GetTTText, commctrl.TTN_NEEDTEXTW) + + # parent = win32ui.GetMainFrame() + parent = self + style = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | afxres.CBRS_SIZE_DYNAMIC + | afxres.CBRS_TOP + | afxres.CBRS_TOOLTIPS + | afxres.CBRS_FLYBY + ) + + buttons = (win32ui.ID_APP_ABOUT, win32ui.ID_VIEW_INTERACTIVE) + bitmap = win32ui.IDB_BROWSER_HIER + tbid = 0xE840 + self.toolbar = tb = win32ui.CreateToolBar(parent, style, tbid) + tb.LoadBitmap(bitmap) + tb.SetButtons(buttons) + + tb.EnableDocking(afxres.CBRS_ALIGN_ANY) + tb.SetWindowText("Test") + parent.EnableDocking(afxres.CBRS_ALIGN_ANY) + parent.DockControlBar(tb) + parent.LoadBarState("ToolbarTest") + window.MDIChildWnd.OnCreateClient(self, cp, context) + return 1 + + def OnDestroy(self, msg): + self.SaveBarState("ToolbarTest") + + def GetTTText(self, std, extra): + (hwndFrom, idFrom, code) = std + text, hinst, flags = extra + if flags & commctrl.TTF_IDISHWND: + return # Not handled + if idFrom == win32ui.ID_APP_ABOUT: + # our 'extra' return value needs to be the following + # entries from a NMTTDISPINFO[W] struct: + # (szText, hinst, uFlags). None means 'don't change + # the value' + return 0, ("It works!", None, None) + return None # not handled. + + def GetMessageString(self, id): + if id == win32ui.ID_APP_ABOUT: + return "Dialog Test\nTest" + else: + return self._obj_.GetMessageString(id) + + def OnSize(self, params): + print("OnSize called with ", params) + + def OnNext(self, id, cmd): + print("OnNext called") + + def OnPrevious(self, id, cmd): + print("OnPrevious called") + + +msg = """\ +This toolbar was dynamically created.\r +\r +The first item's tooltips is provided by Python code.\r +\r +(Dont close the window with the toolbar in a floating state - it may not re-appear!)\r +""" + + +def test(): + template = docview.DocTemplate( + win32ui.IDR_PYTHONTYPE, None, GenericFrame, docview.EditView + ) + doc = template.OpenDocumentFile(None) + doc.SetTitle("Toolbar Test") + view = doc.GetFirstView() + view.SetWindowText(msg) + + +if __name__ == "__main__": + import demoutils + + if demoutils.NeedGoodGUI(): + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/IDLE.cfg b/MLPY/Lib/site-packages/pythonwin/pywin/IDLE.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b1987b14c1c7ba33a8950ccd350537ad7fa0b59f --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/IDLE.cfg @@ -0,0 +1,29 @@ +[General] +# We base this configuration on the default config. +# You can list "Based On" as many times as you like +Based On = default + +[Keys] +# Only list keys different to default. +# Note you may wish to rebind some of the default +# Pythonwin keys to "Beep" or "DoNothing" + +Alt+L = LocateSelectedFile +Ctrl+Q = AppExit + +# Other non-default Pythonwin keys +Alt+A = EditSelectAll +Alt+M = LocateModule + +# Movement +Ctrl+D = GotoEndOfFile + +# Tabs and other indent features +Alt+T = <> +Ctrl+[ = <> +Ctrl+] = <> + +[Keys:Interactive] +Alt+P = <> +Alt+N = <> + diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2e44fba5ca11a1242c6359738b8473e3245386e5 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/__init__.py @@ -0,0 +1,10 @@ +# is_platform_unicode is an old variable that was never correctly used and +# is no longer referenced in pywin32. It is staying for a few releases incase +# others are looking at it, but it will go away soon! +is_platform_unicode = 0 + +# Ditto default_platform_encoding - not referenced and will die. +default_platform_encoding = "mbcs" + +# This one *is* real and used - but in practice can't be changed. +default_scintilla_encoding = "utf-8" # Scintilla _only_ supports this ATM diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af9792f7639b60103016f30ee490b7dcea00d071 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5f41960d362087fe29e05e2f8fb460ac07fa8dde --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__init__.py @@ -0,0 +1,139 @@ +import sys + + +# Some cruft to deal with the Pythonwin GUI booting up from a non GUI app. +def _MakeDebuggerGUI(): + app.InitInstance() + + +isInprocApp = -1 + + +def _CheckNeedGUI(): + global isInprocApp + if isInprocApp == -1: + import win32ui + + isInprocApp = win32ui.GetApp().IsInproc() + if isInprocApp: + # MAY Need it - may already have one + need = "pywin.framework.app" not in sys.modules + else: + need = 0 + if need: + import pywin.framework.app + + from . import dbgpyapp + + pywin.framework.app.CreateDefaultGUI(dbgpyapp.DebuggerPythonApp) + + else: + # Check we have the appropriate editor + # No longer necessary! + pass + return need + + +# Inject some methods in the top level name-space. +currentDebugger = None # Wipe out any old one on reload. + + +def _GetCurrentDebugger(): + global currentDebugger + if currentDebugger is None: + _CheckNeedGUI() + from . import debugger + + currentDebugger = debugger.Debugger() + return currentDebugger + + +def GetDebugger(): + # An error here is not nice - as we are probably trying to + # break into the debugger on a Python error, any + # error raised by this is usually silent, and causes + # big problems later! + try: + rc = _GetCurrentDebugger() + rc.GUICheckInit() + return rc + except: + print("Could not create the debugger!") + import traceback + + traceback.print_exc() + return None + + +def close(): + if currentDebugger is not None: + currentDebugger.close() + + +def run(cmd, globals=None, locals=None, start_stepping=1): + _GetCurrentDebugger().run(cmd, globals, locals, start_stepping) + + +def runeval(expression, globals=None, locals=None): + return _GetCurrentDebugger().runeval(expression, globals, locals) + + +def runcall(*args): + return _GetCurrentDebugger().runcall(*args) + + +def set_trace(): + import sys + + d = _GetCurrentDebugger() + + if d.frameShutdown: + return # App closing + + if d.stopframe != d.botframe: + # If im not "running" + return + + sys.settrace(None) # May be hooked + d.reset() + d.set_trace() + + +# "brk" is an alias for "set_trace" ("break" is a reserved word :-( +brk = set_trace + +# Post-Mortem interface + + +def post_mortem(t=None): + if t is None: + t = sys.exc_info()[2] # Will be valid if we are called from an except handler. + if t is None: + try: + t = sys.last_traceback + except AttributeError: + print( + "No traceback can be found from which to perform post-mortem debugging!" + ) + print("No debugging can continue") + return + p = _GetCurrentDebugger() + if p.frameShutdown: + return # App closing + # No idea why I need to settrace to None - it should have been reset by now? + sys.settrace(None) + p.reset() + while t.tb_next != None: + t = t.tb_next + p.bAtPostMortem = 1 + p.prep_run(None) + try: + p.interaction(t.tb_frame, t) + finally: + t = None + p.bAtPostMortem = 0 + p.done_run() + + +def pm(t=None): + post_mortem(t) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3dab259301b196bb21c06e7f6fa154e2e6fecc7 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/configui.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/configui.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b31d56f2fb44f8b0928bfda89a6ddd0deb7153e Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/configui.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/dbgcon.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/dbgcon.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22dcea24ab23d24587c4c3b34973cdf5b2895d3f Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/dbgcon.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/dbgpyapp.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/dbgpyapp.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b4d7cea8d80ad3eda4bf1e44347c88945cb62e8 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/dbgpyapp.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/debugger.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/debugger.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abe8d1244d479e5c807f33061c8205329eafe32d Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/debugger.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/fail.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/fail.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e1bf66f2551c118fa03fcde2a4bef3d2be43ac56 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/__pycache__/fail.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/configui.py b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/configui.py new file mode 100644 index 0000000000000000000000000000000000000000..32de4ee5ff0c25fe33b4b71b594c914553eb88ef --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/configui.py @@ -0,0 +1,34 @@ +import win32ui +from pywin.mfc import dialog + +from . import dbgcon + + +class DebuggerOptionsPropPage(dialog.PropertyPage): + def __init__(self): + dialog.PropertyPage.__init__(self, win32ui.IDD_PP_DEBUGGER) + + def OnInitDialog(self): + options = self.options = dbgcon.LoadDebuggerOptions() + self.AddDDX(win32ui.IDC_CHECK1, dbgcon.OPT_HIDE) + self[dbgcon.OPT_STOP_EXCEPTIONS] = options[dbgcon.OPT_STOP_EXCEPTIONS] + self.AddDDX(win32ui.IDC_CHECK2, dbgcon.OPT_STOP_EXCEPTIONS) + self[dbgcon.OPT_HIDE] = options[dbgcon.OPT_HIDE] + return dialog.PropertyPage.OnInitDialog(self) + + def OnOK(self): + self.UpdateData() + dirty = 0 + for key, val in list(self.items()): + if key in self.options: + if self.options[key] != val: + self.options[key] = val + dirty = 1 + if dirty: + dbgcon.SaveDebuggerOptions(self.options) + # If there is a debugger open, then set its options. + import pywin.debugger + + if pywin.debugger.currentDebugger is not None: + pywin.debugger.currentDebugger.options = self.options + return 1 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/dbgcon.py b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/dbgcon.py new file mode 100644 index 0000000000000000000000000000000000000000..402ec64b353a793e1ff5cf2f3c4a113957d6fba9 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/dbgcon.py @@ -0,0 +1,32 @@ +# General constants for the debugger + +DBGSTATE_NOT_DEBUGGING = 0 +DBGSTATE_RUNNING = 1 +DBGSTATE_BREAK = 2 +DBGSTATE_QUITTING = 3 # Attempting to back out of the debug session. + +LINESTATE_CURRENT = 0x1 # This line is where we are stopped +LINESTATE_BREAKPOINT = 0x2 # This line is a breakpoint +LINESTATE_CALLSTACK = 0x4 # This line is in the callstack. + +OPT_HIDE = "hide" +OPT_STOP_EXCEPTIONS = "stopatexceptions" + +import win32api +import win32ui + + +def DoGetOption(optsDict, optName, default): + optsDict[optName] = win32ui.GetProfileVal("Debugger Options", optName, default) + + +def LoadDebuggerOptions(): + opts = {} + DoGetOption(opts, OPT_HIDE, 0) + DoGetOption(opts, OPT_STOP_EXCEPTIONS, 1) + return opts + + +def SaveDebuggerOptions(opts): + for key, val in opts.items(): + win32ui.WriteProfileVal("Debugger Options", key, val) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/dbgpyapp.py b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/dbgpyapp.py new file mode 100644 index 0000000000000000000000000000000000000000..207f404938e60e5bf01301c614d5602f8d1832c2 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/dbgpyapp.py @@ -0,0 +1,48 @@ +# dbgpyapp.py - Debugger Python application class +# +import sys + +import win32con +import win32ui +from pywin.framework import intpyapp + +version = "0.3.0" + + +class DebuggerPythonApp(intpyapp.InteractivePythonApp): + def LoadMainFrame(self): + "Create the main applications frame" + self.frame = self.CreateMainFrame() + self.SetMainFrame(self.frame) + self.frame.LoadFrame(win32ui.IDR_DEBUGGER, win32con.WS_OVERLAPPEDWINDOW) + self.frame.DragAcceptFiles() # we can accept these. + self.frame.ShowWindow(win32con.SW_HIDE) + self.frame.UpdateWindow() + + # but we do rehook, hooking the new code objects. + self.HookCommands() + + def InitInstance(self): + # Use a registry path of "Python\Pythonwin Debugger + win32ui.SetAppName(win32ui.LoadString(win32ui.IDR_DEBUGGER)) + win32ui.SetRegistryKey("Python %s" % (sys.winver,)) + # We _need_ the Scintilla color editor. + # (and we _always_ get it now :-) + + numMRU = win32ui.GetProfileVal("Settings", "Recent File List Size", 10) + win32ui.LoadStdProfileSettings(numMRU) + + self.LoadMainFrame() + + # Display the interactive window if the user wants it. + from pywin.framework import interact + + interact.CreateInteractiveWindowUserPreference() + + # Load the modules we use internally. + self.LoadSystemModules() + # Load additional module the user may want. + self.LoadUserModules() + + # win32ui.CreateDebuggerThread() + win32ui.EnableControlContainer() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/debugger.py b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/debugger.py new file mode 100644 index 0000000000000000000000000000000000000000..4acf9bc4d29f4d0032858a329f1f577d6c309e82 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/debugger.py @@ -0,0 +1,1105 @@ +# debugger.py + +# A debugger for Pythonwin. Built from pdb. + +# Mark Hammond (MHammond@skippinet.com.au) - Dec 94. + +# usage: +# >>> import pywin.debugger +# >>> pywin.debugger.GetDebugger().run("command") + +import bdb +import os +import pdb +import string +import sys +import traceback +import types + +import commctrl +import pywin.docking.DockingBar +import win32api +import win32con +import win32ui +from pywin.framework import app, editor, interact, scriptutils +from pywin.framework.editor.color.coloreditor import MARKER_BREAKPOINT, MARKER_CURRENT +from pywin.mfc import afxres, dialog, object, window +from pywin.tools import browser, hierlist + +# import win32traceutil +if win32ui.UNICODE: + LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW +else: + LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA + +from .dbgcon import * + +error = "pywin.debugger.error" + + +def SetInteractiveContext(globs, locs): + if interact.edit is not None and interact.edit.currentView is not None: + interact.edit.currentView.SetContext(globs, locs) + + +def _LineStateToMarker(ls): + if ls == LINESTATE_CURRENT: + return MARKER_CURRENT + # elif ls == LINESTATE_CALLSTACK: + # return MARKER_CALLSTACK + return MARKER_BREAKPOINT + + +class HierListItem(browser.HLIPythonObject): + pass + + +class HierFrameItem(HierListItem): + def __init__(self, frame, debugger): + HierListItem.__init__(self, frame, repr(frame)) + self.debugger = debugger + + def GetText(self): + name = self.myobject.f_code.co_name + if not name or name == "?": + # See if locals has a '__name__' (ie, a module) + if "__name__" in self.myobject.f_locals: + name = str(self.myobject.f_locals["__name__"]) + " module" + else: + name = "" + + return "%s (%s:%d)" % ( + name, + os.path.split(self.myobject.f_code.co_filename)[1], + self.myobject.f_lineno, + ) + + def GetBitmapColumn(self): + if self.debugger.curframe is self.myobject: + return 7 + else: + return 8 + + def GetSubList(self): + ret = [] + ret.append(HierFrameDict(self.myobject.f_locals, "Locals", 2)) + ret.append(HierFrameDict(self.myobject.f_globals, "Globals", 1)) + return ret + + def IsExpandable(self): + return 1 + + def TakeDefaultAction(self): + # Set the default frame to be this frame. + self.debugger.set_cur_frame(self.myobject) + return 1 + + +class HierFrameDict(browser.HLIDict): + def __init__(self, dict, name, bitmapColumn): + self.bitmapColumn = bitmapColumn + browser.HLIDict.__init__(self, dict, name) + + def GetBitmapColumn(self): + return self.bitmapColumn + + +class NoStackAvailableItem(HierListItem): + def __init__(self, why): + HierListItem.__init__(self, None, why) + + def IsExpandable(self): + return 0 + + def GetText(self): + return self.name + + def GetBitmapColumn(self): + return 8 + + +class HierStackRoot(HierListItem): + def __init__(self, debugger): + HierListItem.__init__(self, debugger, None) + self.last_stack = [] + + ## def __del__(self): + ## print "HierStackRoot dieing" + def GetSubList(self): + debugger = self.myobject + # print self.debugger.stack, self.debugger.curframe + ret = [] + if debugger.debuggerState == DBGSTATE_BREAK: + stackUse = debugger.stack[:] + stackUse.reverse() + self.last_stack = [] + for frame, lineno in stackUse: + self.last_stack.append((frame, lineno)) + if ( + frame is debugger.userbotframe + ): # Dont bother showing frames below our bottom frame. + break + for frame, lineno in self.last_stack: + ret.append(HierFrameItem(frame, debugger)) + ## elif debugger.debuggerState==DBGSTATE_NOT_DEBUGGING: + ## ret.append(NoStackAvailableItem('')) + ## else: + ## ret.append(NoStackAvailableItem('')) + return ret + + def GetText(self): + return "root item" + + def IsExpandable(self): + return 1 + + +class HierListDebugger(hierlist.HierListWithItems): + """Hier List of stack frames, breakpoints, whatever""" + + def __init__(self): + hierlist.HierListWithItems.__init__( + self, None, win32ui.IDB_DEBUGGER_HIER, None, win32api.RGB(255, 0, 0) + ) + + def Setup(self, debugger): + root = HierStackRoot(debugger) + self.AcceptRoot(root) + + +# def Refresh(self): +# self.Setup() + + +class DebuggerWindow(window.Wnd): + def __init__(self, ob): + window.Wnd.__init__(self, ob) + self.debugger = None + + def Init(self, debugger): + self.debugger = debugger + + def GetDefRect(self): + defRect = app.LoadWindowSize("Debugger Windows\\" + self.title) + if defRect[2] - defRect[0] == 0: + defRect = 0, 0, 150, 150 + return defRect + + def OnDestroy(self, msg): + newSize = self.GetWindowPlacement()[4] + pywin.framework.app.SaveWindowSize("Debugger Windows\\" + self.title, newSize) + return window.Wnd.OnDestroy(self, msg) + + def OnKeyDown(self, msg): + key = msg[2] + if key in (13, 27, 32): + return 1 + if key in (46, 8): # delete/BS key + self.DeleteSelected() + return 0 + view = scriptutils.GetActiveView() + try: + firer = view.bindings.fire_key_event + except AttributeError: + firer = None + if firer is not None: + return firer(msg) + else: + return 1 + + def DeleteSelected(self): + win32api.MessageBeep() + + def EditSelected(self): + win32api.MessageBeep() + + +class DebuggerStackWindow(DebuggerWindow): + title = "Stack" + + def __init__(self): + DebuggerWindow.__init__(self, win32ui.CreateTreeCtrl()) + self.list = HierListDebugger() + self.listOK = 0 + + def SaveState(self): + self.list.DeleteAllItems() + self.listOK = 0 + win32ui.WriteProfileVal( + "Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible() + ) + + def CreateWindow(self, parent): + style = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | win32con.WS_BORDER + | commctrl.TVS_HASLINES + | commctrl.TVS_LINESATROOT + | commctrl.TVS_HASBUTTONS + ) + self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1) + self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN) + self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN) + self.list.HierInit(parent, self) + self.listOK = 0 # delayed setup + # self.list.Setup() + + def RespondDebuggerState(self, state): + assert self.debugger is not None, "Init not called" + if not self.listOK: + self.listOK = 1 + self.list.Setup(self.debugger) + else: + self.list.Refresh() + + def RespondDebuggerData(self): + try: + handle = self.GetChildItem(0) + except win32ui.error: + return # No items + while 1: + item = self.list.ItemFromHandle(handle) + col = self.list.GetBitmapColumn(item) + selCol = self.list.GetSelectedBitmapColumn(item) + if selCol is None: + selCol = col + if self.list.GetItemImage(handle) != (col, selCol): + self.list.SetItemImage(handle, col, selCol) + try: + handle = self.GetNextSiblingItem(handle) + except win32ui.error: + break + + +class DebuggerListViewWindow(DebuggerWindow): + def __init__(self): + DebuggerWindow.__init__(self, win32ui.CreateListCtrl()) + + def CreateWindow(self, parent): + list = self + style = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | win32con.WS_BORDER + | commctrl.LVS_EDITLABELS + | commctrl.LVS_REPORT + ) + self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1) + self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN) + self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN) + list = self + title, width = self.columns[0] + itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0) + list.InsertColumn(0, itemDetails) + col = 1 + for title, width in self.columns[1:]: + col = col + 1 + itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0) + list.InsertColumn(col, itemDetails) + parent.HookNotify(self.OnListEndLabelEdit, LVN_ENDLABELEDIT) + parent.HookNotify(self.OnItemRightClick, commctrl.NM_RCLICK) + parent.HookNotify(self.OnItemDoubleClick, commctrl.NM_DBLCLK) + + def RespondDebuggerData(self): + pass + + def RespondDebuggerState(self, state): + pass + + def EditSelected(self): + try: + sel = self.GetNextItem(-1, commctrl.LVNI_SELECTED) + except win32ui.error: + return + self.EditLabel(sel) + + def OnKeyDown(self, msg): + key = msg[2] + # If someone starts typing, they probably are trying to edit the text! + if chr(key) in string.ascii_uppercase: + self.EditSelected() + return 0 + return DebuggerWindow.OnKeyDown(self, msg) + + def OnItemDoubleClick(self, notify_data, extra): + self.EditSelected() + + def OnItemRightClick(self, notify_data, extra): + # First select the item we right-clicked on. + pt = self.ScreenToClient(win32api.GetCursorPos()) + flags, hItem, subitem = self.HitTest(pt) + if hItem == -1 or commctrl.TVHT_ONITEM & flags == 0: + return None + self.SetItemState(hItem, commctrl.LVIS_SELECTED, commctrl.LVIS_SELECTED) + + menu = win32ui.CreatePopupMenu() + menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1000, "Edit item") + menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1001, "Delete item") + dockbar = self.GetParent() + if dockbar.IsFloating(): + hook_parent = win32ui.GetMainFrame() + else: + hook_parent = self.GetParentFrame() + hook_parent.HookCommand(self.OnEditItem, 1000) + hook_parent.HookCommand(self.OnDeleteItem, 1001) + menu.TrackPopupMenu(win32api.GetCursorPos()) # track at mouse position. + return None + + def OnDeleteItem(self, command, code): + self.DeleteSelected() + + def OnEditItem(self, command, code): + self.EditSelected() + + +class DebuggerBreakpointsWindow(DebuggerListViewWindow): + title = "Breakpoints" + columns = [("Condition", 70), ("Location", 1024)] + + def SaveState(self): + items = [] + for i in range(self.GetItemCount()): + items.append(self.GetItemText(i, 0)) + items.append(self.GetItemText(i, 1)) + win32ui.WriteProfileVal( + "Debugger Windows\\" + self.title, "BreakpointList", "\t".join(items) + ) + win32ui.WriteProfileVal( + "Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible() + ) + return 1 + + def OnListEndLabelEdit(self, std, extra): + item = extra[0] + text = item[4] + if text is None: + return + + item_id = self.GetItem(item[0])[6] + + from bdb import Breakpoint + + for bplist in Breakpoint.bplist.values(): + for bp in bplist: + if id(bp) == item_id: + if text.strip().lower() == "none": + text = None + bp.cond = text + break + self.RespondDebuggerData() + + def DeleteSelected(self): + try: + num = self.GetNextItem(-1, commctrl.LVNI_SELECTED) + item_id = self.GetItem(num)[6] + from bdb import Breakpoint + + for bplist in list(Breakpoint.bplist.values()): + for bp in bplist: + if id(bp) == item_id: + self.debugger.clear_break(bp.file, bp.line) + break + except win32ui.error: + win32api.MessageBeep() + self.RespondDebuggerData() + + def RespondDebuggerData(self): + l = self + l.DeleteAllItems() + index = -1 + from bdb import Breakpoint + + for bplist in Breakpoint.bplist.values(): + for bp in bplist: + baseName = os.path.split(bp.file)[1] + cond = bp.cond + item = index + 1, 0, 0, 0, str(cond), 0, id(bp) + index = l.InsertItem(item) + l.SetItemText(index, 1, "%s: %s" % (baseName, bp.line)) + + +class DebuggerWatchWindow(DebuggerListViewWindow): + title = "Watch" + columns = [("Expression", 70), ("Value", 1024)] + + def CreateWindow(self, parent): + DebuggerListViewWindow.CreateWindow(self, parent) + items = win32ui.GetProfileVal( + "Debugger Windows\\" + self.title, "Items", "" + ).split("\t") + index = -1 + for item in items: + if item: + index = self.InsertItem(index + 1, item) + self.InsertItem(index + 1, "") + + def SaveState(self): + items = [] + for i in range(self.GetItemCount() - 1): + items.append(self.GetItemText(i, 0)) + win32ui.WriteProfileVal( + "Debugger Windows\\" + self.title, "Items", "\t".join(items) + ) + win32ui.WriteProfileVal( + "Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible() + ) + return 1 + + def OnListEndLabelEdit(self, std, extra): + item = extra[0] + itemno = item[0] + text = item[4] + if text is None: + return + self.SetItemText(itemno, 0, text) + if itemno == self.GetItemCount() - 1: + self.InsertItem(itemno + 1, "") + self.RespondDebuggerState(self.debugger.debuggerState) + + def DeleteSelected(self): + try: + num = self.GetNextItem(-1, commctrl.LVNI_SELECTED) + if num < self.GetItemCount() - 1: # We cant delete the last + self.DeleteItem(num) + except win32ui.error: + win32api.MessageBeep() + + def RespondDebuggerState(self, state): + globs = locs = None + if state == DBGSTATE_BREAK: + if self.debugger.curframe: + globs = self.debugger.curframe.f_globals + locs = self.debugger.curframe.f_locals + elif state == DBGSTATE_NOT_DEBUGGING: + import __main__ + + globs = locs = __main__.__dict__ + for i in range(self.GetItemCount() - 1): + text = self.GetItemText(i, 0) + if globs is None: + val = "" + else: + try: + val = repr(eval(text, globs, locs)) + except SyntaxError: + val = "Syntax Error" + except: + t, v, tb = sys.exc_info() + val = traceback.format_exception_only(t, v)[0].strip() + tb = None # prevent a cycle. + self.SetItemText(i, 1, val) + + +def CreateDebuggerDialog(parent, klass): + control = klass() + control.CreateWindow(parent) + return control + + +DebuggerDialogInfos = ( + (0xE810, DebuggerStackWindow, None), + (0xE811, DebuggerBreakpointsWindow, (10, 10)), + (0xE812, DebuggerWatchWindow, None), +) + + +# Prepare all the "control bars" for this package. +# If control bars are not all loaded when the toolbar-state functions are +# called, things go horribly wrong. +def PrepareControlBars(frame): + style = ( + win32con.WS_CHILD + | afxres.CBRS_SIZE_DYNAMIC + | afxres.CBRS_TOP + | afxres.CBRS_TOOLTIPS + | afxres.CBRS_FLYBY + ) + tbd = win32ui.CreateToolBar(frame, style, win32ui.ID_VIEW_TOOLBAR_DBG) + tbd.ModifyStyle(0, commctrl.TBSTYLE_FLAT) + tbd.LoadToolBar(win32ui.IDR_DEBUGGER) + tbd.EnableDocking(afxres.CBRS_ALIGN_ANY) + tbd.SetWindowText("Debugger") + frame.DockControlBar(tbd) + + # and the other windows. + for id, klass, float in DebuggerDialogInfos: + try: + frame.GetControlBar(id) + exists = 1 + except win32ui.error: + exists = 0 + if exists: + continue + bar = pywin.docking.DockingBar.DockingBar() + style = win32con.WS_CHILD | afxres.CBRS_LEFT # don't create visible. + bar.CreateWindow( + frame, + CreateDebuggerDialog, + klass.title, + id, + style, + childCreatorArgs=(klass,), + ) + bar.SetBarStyle( + bar.GetBarStyle() + | afxres.CBRS_TOOLTIPS + | afxres.CBRS_FLYBY + | afxres.CBRS_SIZE_DYNAMIC + ) + bar.EnableDocking(afxres.CBRS_ALIGN_ANY) + if float is None: + frame.DockControlBar(bar) + else: + frame.FloatControlBar(bar, float, afxres.CBRS_ALIGN_ANY) + + ## frame.ShowControlBar(bar, 0, 1) + + +SKIP_NONE = 0 +SKIP_STEP = 1 +SKIP_RUN = 2 + +debugger_parent = pdb.Pdb + + +class Debugger(debugger_parent): + def __init__(self): + self.inited = 0 + self.skipBotFrame = SKIP_NONE + self.userbotframe = None + self.frameShutdown = 0 + self.pumping = 0 + self.debuggerState = DBGSTATE_NOT_DEBUGGING # Assume so, anyway. + self.shownLineCurrent = None # The last filename I highlighted. + self.shownLineCallstack = None # The last filename I highlighted. + self.last_cmd_debugged = "" + self.abortClosed = 0 + self.isInitialBreakpoint = 0 + debugger_parent.__init__(self) + + # See if any break-points have been set in the editor + for doc in editor.editorTemplate.GetDocumentList(): + lineNo = -1 + while 1: + lineNo = doc.MarkerGetNext(lineNo + 1, MARKER_BREAKPOINT) + if lineNo <= 0: + break + self.set_break(doc.GetPathName(), lineNo) + + self.reset() + self.inForcedGUI = win32ui.GetApp().IsInproc() + self.options = LoadDebuggerOptions() + self.bAtException = self.bAtPostMortem = 0 + + def __del__(self): + self.close() + + def close(self, frameShutdown=0): + # abortClose indicates if we have total shutdown + # (ie, main window is dieing) + if self.pumping: + # Can stop pump here, as it only posts a message, and + # returns immediately. + if not self.StopDebuggerPump(): # User cancelled close. + return 0 + # NOTE - from this point on the close can not be + # stopped - the WM_QUIT message is already in the queue. + self.frameShutdown = frameShutdown + if not self.inited: + return 1 + self.inited = 0 + + SetInteractiveContext(None, None) + + frame = win32ui.GetMainFrame() + # Hide the debuger toolbars (as they wont normally form part of the main toolbar state. + for id, klass, float in DebuggerDialogInfos: + try: + tb = frame.GetControlBar(id) + if tb.dialog is not None: # We may never have actually been shown. + tb.dialog.SaveState() + frame.ShowControlBar(tb, 0, 1) + except win32ui.error: + pass + + self._UnshowCurrentLine() + self.set_quit() + return 1 + + def StopDebuggerPump(self): + assert self.pumping, "Can't stop the debugger pump if Im not pumping!" + # After stopping a pump, I may never return. + if self.GUIAboutToFinishInteract(): + self.pumping = 0 + win32ui.StopDebuggerPump() # Posts a message, so we do return. + return 1 + return 0 + + def get_option(self, option): + """Public interface into debugger options""" + try: + return self.options[option] + except KeyError: + raise error("Option %s is not a valid option" % option) + + def prep_run(self, cmd): + pass + + def done_run(self, cmd=None): + self.RespondDebuggerState(DBGSTATE_NOT_DEBUGGING) + self.close() + + def canonic(self, fname): + return os.path.abspath(fname).lower() + + def reset(self): + debugger_parent.reset(self) + self.userbotframe = None + self.UpdateAllLineStates() + self._UnshowCurrentLine() + + def setup(self, f, t): + debugger_parent.setup(self, f, t) + self.bAtException = t is not None + + def set_break(self, filename, lineno, temporary=0, cond=None): + filename = self.canonic(filename) + self.SetLineState(filename, lineno, LINESTATE_BREAKPOINT) + return debugger_parent.set_break(self, filename, lineno, temporary, cond) + + def clear_break(self, filename, lineno): + filename = self.canonic(filename) + self.ResetLineState(filename, lineno, LINESTATE_BREAKPOINT) + return debugger_parent.clear_break(self, filename, lineno) + + def cmdloop(self): + if self.frameShutdown: + return # App in the process of closing - never break in! + self.GUIAboutToBreak() + + def print_stack_entry(self, frame): + # We dont want a stack printed - our GUI is better :-) + pass + + def user_return(self, frame, return_value): + # Same as parent, just no "print" + # This function is called when a return trap is set here + frame.f_locals["__return__"] = return_value + self.interaction(frame, None) + + def user_call(self, frame, args): + # base class has an annoying 'print' that adds no value to us... + if self.stop_here(frame): + self.interaction(frame, None) + + def user_exception(self, frame, exc_info): + # This function is called if an exception occurs, + # but only if we are to stop at or just below this level + (exc_type, exc_value, exc_traceback) = exc_info + if self.get_option(OPT_STOP_EXCEPTIONS): + frame.f_locals["__exception__"] = exc_type, exc_value + print("Unhandled exception while debugging...") + # on both py2k and py3k, we may be called with exc_value + # being the args to the exception, or it may already be + # instantiated (IOW, PyErr_Normalize() hasn't been + # called on the args). In py2k this is fine, but in + # py3k, traceback.print_exception fails. So on py3k + # we instantiate an exception instance to print. + if sys.version_info > (3,) and not isinstance(exc_value, BaseException): + # they are args - may be a single item or already a tuple + if not isinstance(exc_value, tuple): + exc_value = (exc_value,) + exc_value = exc_type(*exc_value) + + traceback.print_exception(exc_type, exc_value, exc_traceback) + self.interaction(frame, exc_traceback) + + def user_line(self, frame): + if frame.f_lineno == 0: + return + debugger_parent.user_line(self, frame) + + def stop_here(self, frame): + if self.isInitialBreakpoint: + self.isInitialBreakpoint = 0 + self.set_continue() + return 0 + if frame is self.botframe and self.skipBotFrame == SKIP_RUN: + self.set_continue() + return 0 + if frame is self.botframe and self.skipBotFrame == SKIP_STEP: + self.set_step() + return 0 + return debugger_parent.stop_here(self, frame) + + def run(self, cmd, globals=None, locals=None, start_stepping=1): + if not isinstance(cmd, (str, types.CodeType)): + raise TypeError("Only strings can be run") + self.last_cmd_debugged = cmd + if start_stepping: + self.isInitialBreakpoint = 0 + else: + self.isInitialBreakpoint = 1 + try: + if globals is None: + import __main__ + + globals = __main__.__dict__ + if locals is None: + locals = globals + self.reset() + self.prep_run(cmd) + sys.settrace(self.trace_dispatch) + if type(cmd) != types.CodeType: + cmd = cmd + "\n" + try: + try: + if start_stepping: + self.skipBotFrame = SKIP_STEP + else: + self.skipBotFrame = SKIP_RUN + exec(cmd, globals, locals) + except bdb.BdbQuit: + pass + finally: + self.skipBotFrame = SKIP_NONE + self.quitting = 1 + sys.settrace(None) + + finally: + self.done_run(cmd) + + def runeval(self, expr, globals=None, locals=None): + self.prep_run(expr) + try: + debugger_parent.runeval(self, expr, globals, locals) + finally: + self.done_run(expr) + + def runexec(self, what, globs=None, locs=None): + self.reset() + sys.settrace(self.trace_dispatch) + try: + try: + exec(what, globs, locs) + except bdb.BdbQuit: + pass + finally: + self.quitting = 1 + sys.settrace(None) + + def do_set_step(self): + if self.GUIAboutToRun(): + self.set_step() + + def do_set_next(self): + if self.GUIAboutToRun(): + self.set_next(self.curframe) + + def do_set_return(self): + if self.GUIAboutToRun(): + self.set_return(self.curframe) + + def do_set_continue(self): + if self.GUIAboutToRun(): + self.set_continue() + + def set_quit(self): + ok = 1 + if self.pumping: + ok = self.StopDebuggerPump() + if ok: + debugger_parent.set_quit(self) + + def _dump_frame_(self, frame, name=None): + if name is None: + name = "" + if frame: + if frame.f_code and frame.f_code.co_filename: + fname = os.path.split(frame.f_code.co_filename)[1] + else: + fname = "??" + print(repr(name), fname, frame.f_lineno, frame) + else: + print(repr(name), "None") + + def set_trace(self): + # Start debugging from _2_ levels up! + try: + 1 + "" + except: + frame = sys.exc_info()[2].tb_frame.f_back.f_back + self.reset() + self.userbotframe = None + while frame: + # scriptutils.py creates a local variable with name + # '_debugger_stop_frame_', and we dont go past it + # (everything above this is Pythonwin framework code) + if "_debugger_stop_frame_" in frame.f_locals: + self.userbotframe = frame + break + + frame.f_trace = self.trace_dispatch + self.botframe = frame + frame = frame.f_back + self.set_step() + sys.settrace(self.trace_dispatch) + + def set_cur_frame(self, frame): + # Sets the "current" frame - ie, the frame with focus. This is the + # frame on which "step out" etc actions are taken. + # This may or may not be the top of the stack. + assert frame is not None, "You must pass a valid frame" + self.curframe = frame + for f, index in self.stack: + if f is frame: + self.curindex = index + break + else: + assert 0, "Can't find the frame in the stack." + SetInteractiveContext(frame.f_globals, frame.f_locals) + self.GUIRespondDebuggerData() + self.ShowCurrentLine() + + def IsBreak(self): + return self.debuggerState == DBGSTATE_BREAK + + def IsDebugging(self): + return self.debuggerState != DBGSTATE_NOT_DEBUGGING + + def RespondDebuggerState(self, state): + if state == self.debuggerState: + return + if state == DBGSTATE_NOT_DEBUGGING: # Debugger exists, but not doing anything + title = "" + elif state == DBGSTATE_RUNNING: # Code is running under the debugger. + title = " - running" + elif state == DBGSTATE_BREAK: # We are at a breakpoint or stepping or whatever. + if self.bAtException: + if self.bAtPostMortem: + title = " - post mortem exception" + else: + title = " - exception" + else: + title = " - break" + else: + raise error("Invalid debugger state passed!") + win32ui.GetMainFrame().SetWindowText( + win32ui.LoadString(win32ui.IDR_MAINFRAME) + title + ) + if self.debuggerState == DBGSTATE_QUITTING and state != DBGSTATE_NOT_DEBUGGING: + print("Ignoring state change cos Im trying to stop!", state) + return + self.debuggerState = state + try: + frame = win32ui.GetMainFrame() + except win32ui.error: + frame = None + if frame is not None: + for id, klass, float in DebuggerDialogInfos: + cb = win32ui.GetMainFrame().GetControlBar(id).dialog + cb.RespondDebuggerState(state) + # Tell each open editor window about the state transition + for doc in editor.editorTemplate.GetDocumentList(): + doc.OnDebuggerStateChange(state) + self.ShowCurrentLine() + + # + # GUI debugger interface. + # + def GUICheckInit(self): + if self.inited: + return + self.inited = 1 + frame = win32ui.GetMainFrame() + + # Ensure the debugger windows are attached to the debugger. + for id, klass, float in DebuggerDialogInfos: + w = frame.GetControlBar(id) + w.dialog.Init(self) + # Show toolbar if it was visible during last debug session + # This would be better done using a CDockState, but that class is not wrapped yet + if win32ui.GetProfileVal( + "Debugger Windows\\" + w.dialog.title, "Visible", 0 + ): + frame.ShowControlBar(w, 1, 1) + + # ALWAYS show debugging toolbar, regardless of saved state + tb = frame.GetControlBar(win32ui.ID_VIEW_TOOLBAR_DBG) + frame.ShowControlBar(tb, 1, 1) + self.GUIRespondDebuggerData() + + # frame.RecalcLayout() + + def GetDebuggerBar(self, barName): + frame = win32ui.GetMainFrame() + for id, klass, float in DebuggerDialogInfos: + if klass.title == barName: + return frame.GetControlBar(id) + assert 0, "Can't find a bar of that name!" + + def GUIRespondDebuggerData(self): + if not self.inited: # GUI not inited - no toolbars etc. + return + + for id, klass, float in DebuggerDialogInfos: + cb = win32ui.GetMainFrame().GetControlBar(id).dialog + cb.RespondDebuggerData() + + def GUIAboutToRun(self): + if not self.StopDebuggerPump(): + return 0 + self._UnshowCurrentLine() + self.RespondDebuggerState(DBGSTATE_RUNNING) + SetInteractiveContext(None, None) + return 1 + + def GUIAboutToBreak(self): + "Called as the GUI debugger is about to get context, and take control of the running program." + self.GUICheckInit() + self.RespondDebuggerState(DBGSTATE_BREAK) + self.GUIAboutToInteract() + if self.pumping: + print("!!! Already pumping - outa here") + return + self.pumping = 1 + win32ui.StartDebuggerPump() # NOTE - This will NOT return until the user is finished interacting + assert not self.pumping, "Should not be pumping once the pump has finished" + if self.frameShutdown: # User shut down app while debugging + win32ui.GetMainFrame().PostMessage(win32con.WM_CLOSE) + + def GUIAboutToInteract(self): + "Called as the GUI is about to perform any interaction with the user" + frame = win32ui.GetMainFrame() + # Remember the enabled state of our main frame + # may be disabled primarily if a modal dialog is displayed. + # Only get at enabled via GetWindowLong. + self.bFrameEnabled = frame.IsWindowEnabled() + self.oldForeground = None + fw = win32ui.GetForegroundWindow() + if fw is not frame: + self.oldForeground = fw + # fw.EnableWindow(0) Leave enabled for now? + self.oldFrameEnableState = frame.IsWindowEnabled() + frame.EnableWindow(1) + if self.inForcedGUI and not frame.IsWindowVisible(): + frame.ShowWindow(win32con.SW_SHOW) + frame.UpdateWindow() + if self.curframe: + SetInteractiveContext(self.curframe.f_globals, self.curframe.f_locals) + else: + SetInteractiveContext(None, None) + self.GUIRespondDebuggerData() + + def GUIAboutToFinishInteract(self): + """Called as the GUI is about to finish any interaction with the user + Returns non zero if we are allowed to stop interacting""" + if self.oldForeground is not None: + try: + win32ui.GetMainFrame().EnableWindow(self.oldFrameEnableState) + self.oldForeground.EnableWindow(1) + except win32ui.error: + # old window may be dead. + pass + # self.oldForeground.SetForegroundWindow() - fails?? + if not self.inForcedGUI: + return 1 # Never a problem, and nothing else to do. + # If we are running a forced GUI, we may never get an opportunity + # to interact again. Therefore we perform a "SaveAll", to makesure that + # any documents are saved before leaving. + for template in win32ui.GetApp().GetDocTemplateList(): + for doc in template.GetDocumentList(): + if not doc.SaveModified(): + return 0 + # All documents saved - now hide the app and debugger. + if self.get_option(OPT_HIDE): + frame = win32ui.GetMainFrame() + frame.ShowWindow(win32con.SW_HIDE) + return 1 + + # + # Pythonwin interface - all stuff to do with showing source files, + # changing line states etc. + # + def ShowLineState(self, fileName, lineNo, lineState): + # Set the state of a line, open if not already + self.ShowLineNo(fileName, lineNo) + self.SetLineState(fileName, lineNo, lineState) + + def SetLineState(self, fileName, lineNo, lineState): + # Set the state of a line if the document is open. + doc = editor.editorTemplate.FindOpenDocument(fileName) + if doc is not None: + marker = _LineStateToMarker(lineState) + if not doc.MarkerCheck(lineNo, marker): + doc.MarkerAdd(lineNo, marker) + + def ResetLineState(self, fileName, lineNo, lineState): + # Set the state of a line if the document is open. + doc = editor.editorTemplate.FindOpenDocument(fileName) + if doc is not None: + marker = _LineStateToMarker(lineState) + doc.MarkerDelete(lineNo, marker) + + def UpdateDocumentLineStates(self, doc): + # Show all lines in their special status color. If the doc is open + # all line states are reset. + doc.MarkerDeleteAll(MARKER_BREAKPOINT) + doc.MarkerDeleteAll(MARKER_CURRENT) + fname = self.canonic(doc.GetPathName()) + # Now loop over all break-points + for line in self.breaks.get(fname, []): + doc.MarkerAdd(line, MARKER_BREAKPOINT) + # And the current line if in this document. + if self.shownLineCurrent and fname == self.shownLineCurrent[0]: + lineNo = self.shownLineCurrent[1] + if not doc.MarkerCheck(lineNo, MARKER_CURRENT): + doc.MarkerAdd(lineNo, MARKER_CURRENT) + + # if self.shownLineCallstack and fname == self.shownLineCallstack[0]: + # doc.MarkerAdd(self.shownLineCallstack[1], MARKER_CURRENT) + + def UpdateAllLineStates(self): + for doc in editor.editorTemplate.GetDocumentList(): + self.UpdateDocumentLineStates(doc) + + def ShowCurrentLine(self): + # Show the current line. Only ever 1 current line - undoes last current + # The "Current Line" is self.curframe. + # The "Callstack Line" is the top of the stack. + # If current == callstack, only show as current. + self._UnshowCurrentLine() # un-highlight the old one. + if self.curframe: + fileName = self.canonic(self.curframe.f_code.co_filename) + lineNo = self.curframe.f_lineno + self.shownLineCurrent = fileName, lineNo + self.ShowLineState(fileName, lineNo, LINESTATE_CURRENT) + + def _UnshowCurrentLine(self): + "Unshow the current line, and forget it" + if self.shownLineCurrent is not None: + fname, lineno = self.shownLineCurrent + self.ResetLineState(fname, lineno, LINESTATE_CURRENT) + self.shownLineCurrent = None + + def ShowLineNo(self, filename, lineno): + wasOpen = editor.editorTemplate.FindOpenDocument(filename) is not None + if os.path.isfile(filename) and scriptutils.JumpToDocument(filename, lineno): + if not wasOpen: + doc = editor.editorTemplate.FindOpenDocument(filename) + if doc is not None: + self.UpdateDocumentLineStates(doc) + return 1 + return 0 + return 1 + else: + # Can't find the source file - linecache may have it? + import linecache + + line = linecache.getline(filename, lineno) + print( + "%s(%d): %s" + % (os.path.basename(filename), lineno, line[:-1].expandtabs(4)) + ) + return 0 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/debugger/fail.py b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/fail.py new file mode 100644 index 0000000000000000000000000000000000000000..97721576c8224cf49c08f52c97743086c41d83d6 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/debugger/fail.py @@ -0,0 +1,54 @@ +# NOTE NOTE - This module is designed to fail! +# +# The ONLY purpose for this script is testing/demoing the +# Pythonwin debugger package. + +# It does nothing useful, and it even doesnt do that! + +import sys +import time + +import pywin.debugger + + +def a(): + a = 1 + try: + b() + except: + # Break into the debugger with the exception information. + pywin.debugger.post_mortem(sys.exc_info()[2]) + a = 1 + a = 2 + a = 3 + a = 4 + + +def b(): + b = 1 + pywin.debugger.set_trace() + # After importing or running this module, you are likely to be + # sitting at the next line. This is because we explicitely + # broke into the debugger using the "set_trace() function + # "pywin.debugger.brk()" is a shorter alias for this. + c() + + +def c(): + c = 1 + d() + + +def d(): + d = 1 + e(d) + raise ValueError("Hi") + + +def e(arg): + e = 1 + time.sleep(1) + return e + + +a() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/default.cfg b/MLPY/Lib/site-packages/pythonwin/pywin/default.cfg new file mode 100644 index 0000000000000000000000000000000000000000..55371f6b216662151fd9f97c2ef4651fbf09888b --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/default.cfg @@ -0,0 +1,215 @@ +# The default keyboard etc configuration file for Pythonwin. +# +# The format of this file is very similar to a Windows INI file. +# Sections are identified with [Section] lines, but comments +# use the standatd Python # character. Depending on the section, +# lines may not be in the standard "key=value" format. + +# NOTE: You should not need to modify this file. +# Simply create a new .CFG file, and add an entry: +# [General] +# BasedOn = Default +# +# and add your customisations. Then select your new configuration +# from the Pythonwin View/Options/Editor dialog. +# This way you get to add your own customisations, +# but still take advantage of changes to the default +# configuration in new releases. + +# See IDLE.cfg for an example extension configuration. +# +########################################################################## + +[IDLE Extensions] + +# The list of IDLE extensions to load. The extensions +# AutoIndent, AutoFormat and possibly others are +# "built-in", so do not need specifying. + +FormatParagraph +CallTips + + +[Keys] + +# The list of _default_ key definitions. +# See [Keys:Interactive] and [Keys:Editor] below for further defs. + +#Events of the format <> +# are events defined in IDLE extensions. + +Alt+Q = <> + +Ctrl+W = ViewWhitespace +Ctrl+Shift+8 = ViewWhitespace # The MSVC default key def. + +Ctrl+Shift+F = ViewFixedFont + +# Auto-complete, call-tips, etc. +Alt+/ = <> +Ctrl+Space = <> +( = <> +) = <> +Up = <> +Down = <> +Left = <> +Right = <> +. = KeyDot + +# Debugger - These are the MSVC default keys, for want of a better choice. +F9 = DbgBreakpointToggle +F5 = DbgGo +Shift+F5 = DbgClose +F11 = DbgStep +F10 = DbgStepOver +Shift+F11 = DbgStepOut + +Ctrl+F3 = AutoFindNext + + +[Keys:Editor] +# Key bindings specific to the editor +F2 = GotoNextBookmark +Ctrl+F2 = ToggleBookmark +Ctrl+G = GotoLine + +Alt+I = ShowInteractiveWindow +Alt-B = AddBanner # A sample Event defined in this file. + +# Block operations +Alt+3 = <> +Shift+Alt+3 = <> +Alt+4 = <> # IDLE default. +Alt+5 = <> +Alt+6 = <> + +# Tabs and other indent features +Back = <> +Ctrl+T = <> +Alt+U = <> +Enter = EnterKey +Tab = TabKey +Shift-Tab = <> + +# Folding +Add = FoldExpand +Alt+Add = FoldExpandAll +Shift+Add = FoldExpandSecondLevel +Subtract = FoldCollapse +Alt+Subtract = FoldCollapseAll +Shift+Subtract = FoldCollapseSecondLevel +Multiply = FoldTopLevel + +[Keys:Interactive] +# Key bindings specific to the interactive window. +# History for the interactive window +Ctrl+Up = <> +Ctrl+Down = <> +Enter = ProcessEnter +Ctrl+Enter = ProcessEnter +Shift+Enter = ProcessEnter +Esc = ProcessEsc +Alt+I = WindowBack # Toggle back to previous window. +Home = InteractiveHome # A sample Event defined in this file. +Shift+Home = InteractiveHomeExtend # A sample Event defined in this file. + +# When docked, the Ctrl+Tab and Shift+Ctrl+Tab keys dont work as expected. +Ctrl+Tab = MDINext +Ctrl+Shift+Tab = MDIPrev + +[Extensions] +# Python event handlers specific to this config file. +# All functions not starting with an "_" are assumed +# to be events, and take 2 params: +# * editor_window is the same object passed to IDLE +# extensions. editor_window.text is a text widget +# that conforms to the Tk text widget interface. +# * event is the event being fired. Will always be None +# in the current implementation. + +# Simply by defining these functions, they are available as +# events. +# Note that we bind keystrokes to these events in the various +# [Keys] sections. + +# Add a simple file/class/function simple banner +def AddBanner(editor_window, event): + + text = editor_window.text + big_line = "#" * 70 + banner = "%s\n## \n## \n## \n%s\n" % (big_line, big_line) + + # Insert at the start of the current line. + pos = text.index("insert linestart") + + text.undo_block_start() # Allow action to be undone as a single unit. + text.insert(pos, banner) + text.undo_block_stop() + + # Now set the insert point to the middle of the banner. + line, col = [int(s) for s in pos.split(".")] + text.mark_set("insert", "%d.1 lineend" % (line+2, ) ) + + +# Here is a sample event bound to the "Home" key in the +# interactive window +def InteractiveHome(editor_window, event): + return _DoInteractiveHome(editor_window.text, 0) + +def InteractiveHomeExtend(editor_window, event): + return _DoInteractiveHome(editor_window.text, 1) + +def _DoInteractiveHome(text, extend): + import sys + # If Scintilla has an autocomplete window open, then let Scintilla handle it. + if text.edit.SCIAutoCActive(): + return 1 + of_interest = "insert linestart + %d c" % len(sys.ps1) + if not text.compare("insert", "==", of_interest) and \ + text.get("insert linestart", of_interest) in [sys.ps1, sys.ps2]: # Not sys.ps? line + end = of_interest + else: + end = "insert linestart" + + if extend: start = "insert" + else: start = end + text.tag_add("sel", start, end) + +# From Niki Spahie +def AutoFindNext(editor_window, event): + "find selected text or word under cursor" + + from pywin.scintilla import find + from pywin.scintilla import scintillacon + + try: + sci = editor_window.edit + word = sci.GetSelText() + if word: + find.lastSearch.findText = word + find.lastSearch.sel = sci.GetSel() + else: + pos = sci.SendScintilla( scintillacon.SCI_GETCURRENTPOS ) + start = sci.SendScintilla( scintillacon.SCI_WORDSTARTPOSITION, pos, 1 ) + end = sci.SendScintilla( scintillacon.SCI_WORDENDPOSITION, pos, 1 ) + word = sci.GetTextRange( start, end ) + if word: + find.lastSearch.findText = word + find.lastSearch.sel = (start,end) + except Exception: + import traceback + traceback.print_exc() + find.FindNext() + + +# A couple of generic events. +def Beep(editor_window, event): + editor_window.text.beep() + +def DoNothing(editor_window, event): + pass + +def ContinueEvent(editor_window, event): + # Almost an "unbind" - allows Pythonwin/MFC to handle the keystroke + return 1 + diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0a95e8d0289d5b0f984e19667ff286dadd7f3e0 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/ideoptions.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/ideoptions.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a60c4d0634d0b7d70cc90e334913a3d7ef506df Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/ideoptions.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/list.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/list.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ac0cc688931a812976f10e887b7c8a3d517b66b Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/list.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/login.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/login.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51fc33a4eef6b05046215228eb618632b255625d Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/login.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/status.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/status.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2748186c1592582dc2c33c2aeacf8c7b441c2e10 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/__pycache__/status.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/ideoptions.py b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/ideoptions.py new file mode 100644 index 0000000000000000000000000000000000000000..f1bae90df7f62330b486db44893133aca69ac3e7 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/ideoptions.py @@ -0,0 +1,139 @@ +# The property page to define generic IDE options for Pythonwin + +import win32con +import win32ui +from pywin.framework import interact +from pywin.mfc import dialog + +buttonControlMap = { + win32ui.IDC_BUTTON1: win32ui.IDC_EDIT1, + win32ui.IDC_BUTTON2: win32ui.IDC_EDIT2, + win32ui.IDC_BUTTON3: win32ui.IDC_EDIT3, +} + + +class OptionsPropPage(dialog.PropertyPage): + def __init__(self): + dialog.PropertyPage.__init__(self, win32ui.IDD_PP_IDE) + self.AddDDX(win32ui.IDC_CHECK1, "bShowAtStartup") + self.AddDDX(win32ui.IDC_CHECK2, "bDocking") + self.AddDDX(win32ui.IDC_EDIT4, "MRUSize", "i") + + def OnInitDialog(self): + edit = self.GetDlgItem(win32ui.IDC_EDIT1) + format = eval( + win32ui.GetProfileVal( + interact.sectionProfile, + interact.STYLE_INTERACTIVE_PROMPT, + str(interact.formatInput), + ) + ) + edit.SetDefaultCharFormat(format) + edit.SetWindowText("Input Text") + + edit = self.GetDlgItem(win32ui.IDC_EDIT2) + format = eval( + win32ui.GetProfileVal( + interact.sectionProfile, + interact.STYLE_INTERACTIVE_OUTPUT, + str(interact.formatOutput), + ) + ) + edit.SetDefaultCharFormat(format) + edit.SetWindowText("Output Text") + + edit = self.GetDlgItem(win32ui.IDC_EDIT3) + format = eval( + win32ui.GetProfileVal( + interact.sectionProfile, + interact.STYLE_INTERACTIVE_ERROR, + str(interact.formatOutputError), + ) + ) + edit.SetDefaultCharFormat(format) + edit.SetWindowText("Error Text") + + self["bShowAtStartup"] = interact.LoadPreference("Show at startup", 1) + self["bDocking"] = interact.LoadPreference("Docking", 0) + self["MRUSize"] = win32ui.GetProfileVal("Settings", "Recent File List Size", 10) + + # Hook the button clicks. + self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON1) + self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON2) + self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON3) + + # Ensure the spin control remains in range. + spinner = self.GetDlgItem(win32ui.IDC_SPIN1) + spinner.SetRange(1, 16) + + return dialog.PropertyPage.OnInitDialog(self) + + # Called to save away the new format tuple for the specified item. + def HandleCharFormatChange(self, id, code): + if code == win32con.BN_CLICKED: + editId = buttonControlMap.get(id) + assert editId is not None, "Format button has no associated edit control" + editControl = self.GetDlgItem(editId) + existingFormat = editControl.GetDefaultCharFormat() + flags = win32con.CF_SCREENFONTS + d = win32ui.CreateFontDialog(existingFormat, flags, None, self) + if d.DoModal() == win32con.IDOK: + cf = d.GetCharFormat() + editControl.SetDefaultCharFormat(cf) + self.SetModified(1) + return 0 # We handled this fully! + + def OnOK(self): + # Handle the edit controls - get all the fonts, put them back into interact, then + # get interact to save its stuff! + controlAttrs = [ + (win32ui.IDC_EDIT1, interact.STYLE_INTERACTIVE_PROMPT), + (win32ui.IDC_EDIT2, interact.STYLE_INTERACTIVE_OUTPUT), + (win32ui.IDC_EDIT3, interact.STYLE_INTERACTIVE_ERROR), + ] + for id, key in controlAttrs: + control = self.GetDlgItem(id) + fmt = control.GetDefaultCharFormat() + win32ui.WriteProfileVal(interact.sectionProfile, key, str(fmt)) + + # Save the other interactive window options. + interact.SavePreference("Show at startup", self["bShowAtStartup"]) + interact.SavePreference("Docking", self["bDocking"]) + + # And the other options. + win32ui.WriteProfileVal("Settings", "Recent File List Size", self["MRUSize"]) + + return 1 + + def ChangeFormat(self, fmtAttribute, fmt): + dlg = win32ui.CreateFontDialog(fmt) + if dlg.DoModal() != win32con.IDOK: + return None + return dlg.GetCharFormat() + + def OnFormatTitle(self, command, code): + fmt = self.GetFormat(interact.formatTitle) + if fmt: + formatTitle = fmt + SaveFontPreferences() + + def OnFormatInput(self, command, code): + global formatInput + fmt = self.GetFormat(formatInput) + if fmt: + formatInput = fmt + SaveFontPreferences() + + def OnFormatOutput(self, command, code): + global formatOutput + fmt = self.GetFormat(formatOutput) + if fmt: + formatOutput = fmt + SaveFontPreferences() + + def OnFormatError(self, command, code): + global formatOutputError + fmt = self.GetFormat(formatOutputError) + if fmt: + formatOutputError = fmt + SaveFontPreferences() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/list.py b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/list.py new file mode 100644 index 0000000000000000000000000000000000000000..b9934ce71d764f5c9e1adaa33360555ed79d1d58 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/list.py @@ -0,0 +1,143 @@ +import commctrl +import win32api +import win32con +import win32ui +from pywin.mfc import dialog + + +class ListDialog(dialog.Dialog): + def __init__(self, title, list): + dialog.Dialog.__init__(self, self._maketemplate(title)) + self.HookMessage(self.on_size, win32con.WM_SIZE) + self.HookNotify(self.OnListItemChange, commctrl.LVN_ITEMCHANGED) + self.HookCommand(self.OnListClick, win32ui.IDC_LIST1) + self.items = list + + def _maketemplate(self, title): + style = win32con.WS_DLGFRAME | win32con.WS_SYSMENU | win32con.WS_VISIBLE + ls = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | commctrl.LVS_ALIGNLEFT + | commctrl.LVS_REPORT + ) + bs = win32con.WS_CHILD | win32con.WS_VISIBLE + return [ + [title, (0, 0, 200, 200), style, None, (8, "MS Sans Serif")], + ["SysListView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), ls], + [128, "OK", win32con.IDOK, (10, 0, 50, 14), bs | win32con.BS_DEFPUSHBUTTON], + [128, "Cancel", win32con.IDCANCEL, (0, 0, 50, 14), bs], + ] + + def FillList(self): + size = self.GetWindowRect() + width = size[2] - size[0] - (10) + itemDetails = (commctrl.LVCFMT_LEFT, width, "Item", 0) + self.itemsControl.InsertColumn(0, itemDetails) + index = 0 + for item in self.items: + index = self.itemsControl.InsertItem(index + 1, str(item), 0) + + def OnListClick(self, id, code): + if code == commctrl.NM_DBLCLK: + self.EndDialog(win32con.IDOK) + return 1 + + def OnListItemChange(self, std, extra): + (hwndFrom, idFrom, code), ( + itemNotify, + sub, + newState, + oldState, + change, + point, + lparam, + ) = (std, extra) + oldSel = (oldState & commctrl.LVIS_SELECTED) != 0 + newSel = (newState & commctrl.LVIS_SELECTED) != 0 + if oldSel != newSel: + try: + self.selecteditem = itemNotify + self.butOK.EnableWindow(1) + except win32ui.error: + self.selecteditem = None + + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + self.itemsControl = self.GetDlgItem(win32ui.IDC_LIST1) + self.butOK = self.GetDlgItem(win32con.IDOK) + self.butCancel = self.GetDlgItem(win32con.IDCANCEL) + + self.FillList() + + size = self.GetWindowRect() + self.LayoutControls(size[2] - size[0], size[3] - size[1]) + self.butOK.EnableWindow(0) # wait for first selection + return rc + + def LayoutControls(self, w, h): + self.itemsControl.MoveWindow((0, 0, w, h - 30)) + self.butCancel.MoveWindow((10, h - 24, 60, h - 4)) + self.butOK.MoveWindow((w - 60, h - 24, w - 10, h - 4)) + + def on_size(self, params): + lparam = params[3] + w = win32api.LOWORD(lparam) + h = win32api.HIWORD(lparam) + self.LayoutControls(w, h) + + +class ListsDialog(ListDialog): + def __init__(self, title, list, colHeadings=["Item"]): + ListDialog.__init__(self, title, list) + self.colHeadings = colHeadings + + def FillList(self): + index = 0 + size = self.GetWindowRect() + width = ( + size[2] - size[0] - (10) - win32api.GetSystemMetrics(win32con.SM_CXVSCROLL) + ) + numCols = len(self.colHeadings) + + for col in self.colHeadings: + itemDetails = (commctrl.LVCFMT_LEFT, int(width / numCols), col, 0) + self.itemsControl.InsertColumn(index, itemDetails) + index = index + 1 + index = 0 + for items in self.items: + index = self.itemsControl.InsertItem(index + 1, str(items[0]), 0) + for itemno in range(1, numCols): + item = items[itemno] + self.itemsControl.SetItemText(index, itemno, str(item)) + + +def SelectFromList(title, lst): + dlg = ListDialog(title, lst) + if dlg.DoModal() == win32con.IDOK: + return dlg.selecteditem + else: + return None + + +def SelectFromLists(title, lists, headings): + dlg = ListsDialog(title, lists, headings) + if dlg.DoModal() == win32con.IDOK: + return dlg.selecteditem + else: + return None + + +def test(): + # print SelectFromList('Single list', [1,2,3]) + print( + SelectFromLists( + "Multi-List", + [("1", 1, "a"), ("2", 2, "b"), ("3", 3, "c")], + ["Col 1", "Col 2"], + ) + ) + + +if __name__ == "__main__": + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/login.py b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/login.py new file mode 100644 index 0000000000000000000000000000000000000000..2a3295693e920cd9ed4ac054371ce803f798a302 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/login.py @@ -0,0 +1,156 @@ +"""login -- PythonWin user ID and password dialog box + +(Adapted from originally distributed with Mark Hammond's PythonWin - +this now replaces it!) + +login.GetLogin() displays a modal "OK/Cancel" dialog box with input +fields for a user ID and password. The password field input is masked +with *'s. GetLogin takes two optional parameters, a window title, and a +default user ID. If these parameters are omitted, the title defaults to +"Login", and the user ID is left blank. GetLogin returns a (userid, password) +tuple. GetLogin can be called from scripts running on the console - i.e. you +don't need to write a full-blown GUI app to use it. + +login.GetPassword() is similar, except there is no username field. + +Example: +import pywin.dialogs.login +title = "FTP Login" +def_user = "fred" +userid, password = pywin.dialogs.login.GetLogin(title, def_user) + +Jim Eggleston, 28 August 1996 +Merged with dlgpass and moved to pywin.dialogs by Mark Hammond Jan 1998. +""" + +import win32api +import win32con +import win32ui +from pywin.mfc import dialog + + +def MakeLoginDlgTemplate(title): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + + # Window frame and title + dlg = [ + [title, (0, 0, 184, 40), style, None, (8, "MS Sans Serif")], + ] + + # ID label and text box + dlg.append([130, "User ID:", -1, (7, 9, 69, 9), cs | win32con.SS_LEFT]) + s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER + dlg.append(["EDIT", None, win32ui.IDC_EDIT1, (50, 7, 60, 12), s]) + + # Password label and text box + dlg.append([130, "Password:", -1, (7, 22, 69, 9), cs | win32con.SS_LEFT]) + s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER + dlg.append( + ["EDIT", None, win32ui.IDC_EDIT2, (50, 20, 60, 12), s | win32con.ES_PASSWORD] + ) + + # OK/Cancel Buttons + s = cs | win32con.WS_TABSTOP + dlg.append( + [128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON] + ) + s = win32con.BS_PUSHBUTTON | s + dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 20, 50, 14), s]) + return dlg + + +def MakePasswordDlgTemplate(title): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + # Window frame and title + dlg = [ + [title, (0, 0, 177, 45), style, None, (8, "MS Sans Serif")], + ] + + # Password label and text box + dlg.append([130, "Password:", -1, (7, 7, 69, 9), cs | win32con.SS_LEFT]) + s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER + dlg.append( + ["EDIT", None, win32ui.IDC_EDIT1, (50, 7, 60, 12), s | win32con.ES_PASSWORD] + ) + + # OK/Cancel Buttons + s = cs | win32con.WS_TABSTOP | win32con.BS_PUSHBUTTON + dlg.append( + [128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON] + ) + dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 22, 50, 14), s]) + return dlg + + +class LoginDlg(dialog.Dialog): + Cancel = 0 + + def __init__(self, title): + dialog.Dialog.__init__(self, MakeLoginDlgTemplate(title)) + self.AddDDX(win32ui.IDC_EDIT1, "userid") + self.AddDDX(win32ui.IDC_EDIT2, "password") + + +def GetLogin(title="Login", userid="", password=""): + d = LoginDlg(title) + d["userid"] = userid + d["password"] = password + if d.DoModal() != win32con.IDOK: + return (None, None) + else: + return (d["userid"], d["password"]) + + +class PasswordDlg(dialog.Dialog): + def __init__(self, title): + dialog.Dialog.__init__(self, MakePasswordDlgTemplate(title)) + self.AddDDX(win32ui.IDC_EDIT1, "password") + + +def GetPassword(title="Password", password=""): + d = PasswordDlg(title) + d["password"] = password + if d.DoModal() != win32con.IDOK: + return None + return d["password"] + + +if __name__ == "__main__": + import sys + + title = "Login" + def_user = "" + if len(sys.argv) > 1: + title = sys.argv[1] + if len(sys.argv) > 2: + def_userid = sys.argv[2] + userid, password = GetLogin(title, def_user) + if userid == password == None: + print("User pressed Cancel") + else: + print("User ID: ", userid) + print("Password:", password) + newpassword = GetPassword("Reenter just for fun", password) + if newpassword is None: + print("User cancelled") + else: + what = "" + if newpassword != password: + what = "not " + print("The passwords did %smatch" % (what)) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/status.py b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/status.py new file mode 100644 index 0000000000000000000000000000000000000000..aef339148811532bdbd53594cd28d5b1276ce021 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/dialogs/status.py @@ -0,0 +1,242 @@ +# No cancel button. + +import threading +import time + +import win32api +import win32con +import win32ui +from pywin.mfc import dialog +from pywin.mfc.thread import WinThread + + +def MakeProgressDlgTemplate(caption, staticText=""): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + cs = win32con.WS_CHILD | win32con.WS_VISIBLE + + w = 215 + h = 36 # With button + h = 40 + + dlg = [ + [caption, (0, 0, w, h), style, None, (8, "MS Sans Serif")], + ] + + s = win32con.WS_TABSTOP | cs + + dlg.append([130, staticText, 1000, (7, 7, w - 7, h - 32), cs | win32con.SS_LEFT]) + + # dlg.append([128, + # "Cancel", + # win32con.IDCANCEL, + # (w - 60, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON]) + + return dlg + + +class CStatusProgressDialog(dialog.Dialog): + def __init__(self, title, msg="", maxticks=100, tickincr=1): + self.initMsg = msg + templ = MakeProgressDlgTemplate(title, msg) + dialog.Dialog.__init__(self, templ) + self.maxticks = maxticks + self.tickincr = tickincr + self.pbar = None + + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + self.static = self.GetDlgItem(1000) + self.pbar = win32ui.CreateProgressCtrl() + self.pbar.CreateWindow( + win32con.WS_CHILD | win32con.WS_VISIBLE, (10, 30, 310, 44), self, 1001 + ) + self.pbar.SetRange(0, self.maxticks) + self.pbar.SetStep(self.tickincr) + self.progress = 0 + self.pincr = 5 + return rc + + def Close(self): + self.EndDialog(0) + + def SetMaxTicks(self, maxticks): + if self.pbar is not None: + self.pbar.SetRange(0, maxticks) + + def Tick(self): + if self.pbar is not None: + self.pbar.StepIt() + + def SetTitle(self, text): + self.SetWindowText(text) + + def SetText(self, text): + self.SetDlgItemText(1000, text) + + def Set(self, pos, max=None): + if self.pbar is not None: + self.pbar.SetPos(pos) + if max is not None: + self.pbar.SetRange(0, max) + + +# a progress dialog created in a new thread - especially suitable for +# console apps with no message loop. +MYWM_SETTITLE = win32con.WM_USER + 10 +MYWM_SETMSG = win32con.WM_USER + 11 +MYWM_TICK = win32con.WM_USER + 12 +MYWM_SETMAXTICKS = win32con.WM_USER + 13 +MYWM_SET = win32con.WM_USER + 14 + + +class CThreadedStatusProcessDialog(CStatusProgressDialog): + def __init__(self, title, msg="", maxticks=100, tickincr=1): + self.title = title + self.msg = msg + self.threadid = win32api.GetCurrentThreadId() + CStatusProgressDialog.__init__(self, title, msg, maxticks, tickincr) + + def OnInitDialog(self): + rc = CStatusProgressDialog.OnInitDialog(self) + self.HookMessage(self.OnTitle, MYWM_SETTITLE) + self.HookMessage(self.OnMsg, MYWM_SETMSG) + self.HookMessage(self.OnTick, MYWM_TICK) + self.HookMessage(self.OnMaxTicks, MYWM_SETMAXTICKS) + self.HookMessage(self.OnSet, MYWM_SET) + return rc + + def _Send(self, msg): + try: + self.PostMessage(msg) + except win32ui.error: + # the user closed the window - but this does not cancel the + # process - so just ignore it. + pass + + def OnTitle(self, msg): + CStatusProgressDialog.SetTitle(self, self.title) + + def OnMsg(self, msg): + CStatusProgressDialog.SetText(self, self.msg) + + def OnTick(self, msg): + CStatusProgressDialog.Tick(self) + + def OnMaxTicks(self, msg): + CStatusProgressDialog.SetMaxTicks(self, self.maxticks) + + def OnSet(self, msg): + CStatusProgressDialog.Set(self, self.pos, self.max) + + def Close(self): + assert self.threadid, "No thread!" + win32api.PostThreadMessage(self.threadid, win32con.WM_QUIT, 0, 0) + + def SetMaxTicks(self, maxticks): + self.maxticks = maxticks + self._Send(MYWM_SETMAXTICKS) + + def SetTitle(self, title): + self.title = title + self._Send(MYWM_SETTITLE) + + def SetText(self, text): + self.msg = text + self._Send(MYWM_SETMSG) + + def Tick(self): + self._Send(MYWM_TICK) + + def Set(self, pos, max=None): + self.pos = pos + self.max = max + self._Send(MYWM_SET) + + +class ProgressThread(WinThread): + def __init__(self, title, msg="", maxticks=100, tickincr=1): + self.title = title + self.msg = msg + self.maxticks = maxticks + self.tickincr = tickincr + self.dialog = None + WinThread.__init__(self) + self.createdEvent = threading.Event() + + def InitInstance(self): + self.dialog = CThreadedStatusProcessDialog( + self.title, self.msg, self.maxticks, self.tickincr + ) + self.dialog.CreateWindow() + try: + self.dialog.SetForegroundWindow() + except win32ui.error: + pass + self.createdEvent.set() + return WinThread.InitInstance(self) + + def ExitInstance(self): + return 0 + + +def StatusProgressDialog(title, msg="", maxticks=100, parent=None): + d = CStatusProgressDialog(title, msg, maxticks) + d.CreateWindow(parent) + return d + + +def ThreadedStatusProgressDialog(title, msg="", maxticks=100): + t = ProgressThread(title, msg, maxticks) + t.CreateThread() + # Need to run a basic "PumpWaitingMessages" loop just incase we are + # running inside Pythonwin. + # Basic timeout incase things go terribly wrong. Ideally we should use + # win32event.MsgWaitForMultipleObjects(), but we use a threading module + # event - so use a dumb strategy + end_time = time.time() + 10 + while time.time() < end_time: + if t.createdEvent.isSet(): + break + win32ui.PumpWaitingMessages() + time.sleep(0.1) + return t.dialog + + +def demo(): + d = StatusProgressDialog("A Demo", "Doing something...") + import win32api + + for i in range(100): + if i == 50: + d.SetText("Getting there...") + if i == 90: + d.SetText("Nearly done...") + win32api.Sleep(20) + d.Tick() + d.Close() + + +def thread_demo(): + d = ThreadedStatusProgressDialog("A threaded demo", "Doing something") + import win32api + + for i in range(100): + if i == 50: + d.SetText("Getting there...") + if i == 90: + d.SetText("Nearly done...") + win32api.Sleep(20) + d.Tick() + d.Close() + + +if __name__ == "__main__": + thread_demo() + # demo() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/docking/DockingBar.py b/MLPY/Lib/site-packages/pythonwin/pywin/docking/DockingBar.py new file mode 100644 index 0000000000000000000000000000000000000000..3e51eb7031468c961dbe93e6b839fe2dc88176e1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/docking/DockingBar.py @@ -0,0 +1,679 @@ +# DockingBar.py + +# Ported directly (comments and all) from the samples at www.codeguru.com + +# WARNING: Use at your own risk, as this interface is highly likely to change. +# Currently we support only one child per DockingBar. Later we need to add +# support for multiple children. + +import struct + +import win32api +import win32con +import win32ui +from pywin.mfc import afxres, window + +clrBtnHilight = win32api.GetSysColor(win32con.COLOR_BTNHILIGHT) +clrBtnShadow = win32api.GetSysColor(win32con.COLOR_BTNSHADOW) + + +def CenterPoint(rect): + width = rect[2] - rect[0] + height = rect[3] - rect[1] + return rect[0] + width // 2, rect[1] + height // 2 + + +def OffsetRect(rect, point): + (x, y) = point + return rect[0] + x, rect[1] + y, rect[2] + x, rect[3] + y + + +def DeflateRect(rect, point): + (x, y) = point + return rect[0] + x, rect[1] + y, rect[2] - x, rect[3] - y + + +def PtInRect(rect, pt): + return rect[0] <= pt[0] < rect[2] and rect[1] <= pt[1] < rect[3] + + +class DockingBar(window.Wnd): + def __init__(self, obj=None): + if obj is None: + obj = win32ui.CreateControlBar() + window.Wnd.__init__(self, obj) + self.dialog = None + self.nDockBarID = 0 + self.sizeMin = 32, 32 + self.sizeHorz = 200, 200 + self.sizeVert = 200, 200 + self.sizeFloat = 200, 200 + self.bTracking = 0 + self.bInRecalcNC = 0 + self.cxEdge = 6 + self.cxBorder = 3 + self.cxGripper = 20 + self.brushBkgd = win32ui.CreateBrush() + self.brushBkgd.CreateSolidBrush(win32api.GetSysColor(win32con.COLOR_BTNFACE)) + + # Support for diagonal resizing + self.cyBorder = 3 + self.cCaptionSize = win32api.GetSystemMetrics(win32con.SM_CYSMCAPTION) + self.cMinWidth = win32api.GetSystemMetrics(win32con.SM_CXMIN) + self.cMinHeight = win32api.GetSystemMetrics(win32con.SM_CYMIN) + self.rectUndock = (0, 0, 0, 0) + + def OnUpdateCmdUI(self, target, bDisableIfNoHndler): + return self.UpdateDialogControls(target, bDisableIfNoHndler) + + def CreateWindow( + self, + parent, + childCreator, + title, + id, + style=win32con.WS_CHILD | win32con.WS_VISIBLE | afxres.CBRS_LEFT, + childCreatorArgs=(), + ): + assert not ( + (style & afxres.CBRS_SIZE_FIXED) and (style & afxres.CBRS_SIZE_DYNAMIC) + ), "Invalid style" + self.rectClose = self.rectBorder = self.rectGripper = self.rectTracker = ( + 0, + 0, + 0, + 0, + ) + + # save the style + self._obj_.dwStyle = style & afxres.CBRS_ALL + + cursor = win32api.LoadCursor(0, win32con.IDC_ARROW) + wndClass = win32ui.RegisterWndClass( + win32con.CS_DBLCLKS, cursor, self.brushBkgd.GetSafeHandle(), 0 + ) + + self._obj_.CreateWindow(wndClass, title, style, (0, 0, 0, 0), parent, id) + + # Create the child dialog + self.dialog = childCreator(*(self,) + childCreatorArgs) + + # use the dialog dimensions as default base dimensions + assert self.dialog.IsWindow(), ( + "The childCreator function %s did not create a window!" % childCreator + ) + rect = self.dialog.GetWindowRect() + self.sizeHorz = self.sizeVert = self.sizeFloat = ( + rect[2] - rect[0], + rect[3] - rect[1], + ) + + self.sizeHorz = self.sizeHorz[0], self.sizeHorz[1] + self.cxEdge + self.cxBorder + self.sizeVert = self.sizeVert[0] + self.cxEdge + self.cxBorder, self.sizeVert[1] + self.HookMessages() + + def CalcFixedLayout(self, bStretch, bHorz): + rectTop = self.dockSite.GetControlBar( + afxres.AFX_IDW_DOCKBAR_TOP + ).GetWindowRect() + rectLeft = self.dockSite.GetControlBar( + afxres.AFX_IDW_DOCKBAR_LEFT + ).GetWindowRect() + if bStretch: + nHorzDockBarWidth = 32767 + nVertDockBarHeight = 32767 + else: + nHorzDockBarWidth = rectTop[2] - rectTop[0] + 4 + nVertDockBarHeight = rectLeft[3] - rectLeft[1] + 4 + + if self.IsFloating(): + return self.sizeFloat + if bHorz: + return nHorzDockBarWidth, self.sizeHorz[1] + return self.sizeVert[0], nVertDockBarHeight + + def CalcDynamicLayout(self, length, mode): + # Support for diagonal sizing. + if self.IsFloating(): + self.GetParent().GetParent().ModifyStyle(win32ui.MFS_4THICKFRAME, 0) + if mode & (win32ui.LM_HORZDOCK | win32ui.LM_VERTDOCK): + flags = ( + win32con.SWP_NOSIZE + | win32con.SWP_NOMOVE + | win32con.SWP_NOZORDER + | win32con.SWP_NOACTIVATE + | win32con.SWP_FRAMECHANGED + ) + self.SetWindowPos( + 0, + ( + 0, + 0, + 0, + 0, + ), + flags, + ) + self.dockSite.RecalcLayout() + return self._obj_.CalcDynamicLayout(length, mode) + + if mode & win32ui.LM_MRUWIDTH: + return self.sizeFloat + if mode & win32ui.LM_COMMIT: + self.sizeFloat = length, self.sizeFloat[1] + return self.sizeFloat + # More diagonal sizing. + if self.IsFloating(): + dc = self.dockContext + pt = win32api.GetCursorPos() + windowRect = self.GetParent().GetParent().GetWindowRect() + + hittest = dc.nHitTest + if hittest == win32con.HTTOPLEFT: + cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder + cy = max(windowRect[3] - self.cCaptionSize - pt[1], self.cMinHeight) - 1 + self.sizeFloat = cx, cy + + top = ( + min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) + - self.cyBorder + ) + left = min(pt[0], windowRect[2] - self.cMinWidth) - 1 + dc.rectFrameDragHorz = ( + left, + top, + dc.rectFrameDragHorz[2], + dc.rectFrameDragHorz[3], + ) + return self.sizeFloat + if hittest == win32con.HTTOPRIGHT: + cx = max(pt[0] - windowRect[0], self.cMinWidth) + cy = max(windowRect[3] - self.cCaptionSize - pt[1], self.cMinHeight) - 1 + self.sizeFloat = cx, cy + + top = ( + min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) + - self.cyBorder + ) + dc.rectFrameDragHorz = ( + dc.rectFrameDragHorz[0], + top, + dc.rectFrameDragHorz[2], + dc.rectFrameDragHorz[3], + ) + return self.sizeFloat + + if hittest == win32con.HTBOTTOMLEFT: + cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder + cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight) + self.sizeFloat = cx, cy + + left = min(pt[0], windowRect[2] - self.cMinWidth) - 1 + dc.rectFrameDragHorz = ( + left, + dc.rectFrameDragHorz[1], + dc.rectFrameDragHorz[2], + dc.rectFrameDragHorz[3], + ) + return self.sizeFloat + + if hittest == win32con.HTBOTTOMRIGHT: + cx = max(pt[0] - windowRect[0], self.cMinWidth) + cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight) + self.sizeFloat = cx, cy + return self.sizeFloat + + if mode & win32ui.LM_LENGTHY: + self.sizeFloat = self.sizeFloat[0], max(self.sizeMin[1], length) + return self.sizeFloat + else: + return max(self.sizeMin[0], length), self.sizeFloat[1] + + def OnWindowPosChanged(self, msg): + if self.GetSafeHwnd() == 0 or self.dialog is None: + return 0 + lparam = msg[3] + """ LPARAM used with WM_WINDOWPOSCHANGED: + typedef struct { + HWND hwnd; + HWND hwndInsertAfter; + int x; + int y; + int cx; + int cy; + UINT flags;} WINDOWPOS; + """ + format = "PPiiiii" + bytes = win32ui.GetBytes(lparam, struct.calcsize(format)) + hwnd, hwndAfter, x, y, cx, cy, flags = struct.unpack(format, bytes) + + if self.bInRecalcNC: + rc = self.GetClientRect() + self.dialog.MoveWindow(rc) + return 0 + # Find on which side are we docked + nDockBarID = self.GetParent().GetDlgCtrlID() + # Return if dropped at same location + # no docking side change and no size change + if ( + (nDockBarID == self.nDockBarID) + and (flags & win32con.SWP_NOSIZE) + and ( + (self._obj_.dwStyle & afxres.CBRS_BORDER_ANY) != afxres.CBRS_BORDER_ANY + ) + ): + return + self.nDockBarID = nDockBarID + + # Force recalc the non-client area + self.bInRecalcNC = 1 + try: + swpflags = ( + win32con.SWP_NOSIZE + | win32con.SWP_NOMOVE + | win32con.SWP_NOZORDER + | win32con.SWP_FRAMECHANGED + ) + self.SetWindowPos(0, (0, 0, 0, 0), swpflags) + finally: + self.bInRecalcNC = 0 + return 0 + + # This is a virtual and not a message hook. + def OnSetCursor(self, window, nHitTest, wMouseMsg): + if nHitTest != win32con.HTSIZE or self.bTracking: + return self._obj_.OnSetCursor(window, nHitTest, wMouseMsg) + + if self.IsHorz(): + win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZENS)) + else: + win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZEWE)) + return 1 + + # Mouse Handling + def OnLButtonUp(self, msg): + if not self.bTracking: + return 1 # pass it on. + self.StopTracking(1) + return 0 # Dont pass on + + def OnLButtonDown(self, msg): + # UINT nFlags, CPoint point) + # only start dragging if clicked in "void" space + if self.dockBar is not None: + # start the drag + pt = msg[5] + pt = self.ClientToScreen(pt) + self.dockContext.StartDrag(pt) + return 0 + return 1 + + def OnNcLButtonDown(self, msg): + if self.bTracking: + return 0 + nHitTest = wparam = msg[2] + pt = msg[5] + + if nHitTest == win32con.HTSYSMENU and not self.IsFloating(): + self.GetDockingFrame().ShowControlBar(self, 0, 0) + elif nHitTest == win32con.HTMINBUTTON and not self.IsFloating(): + self.dockContext.ToggleDocking() + elif ( + nHitTest == win32con.HTCAPTION + and not self.IsFloating() + and self.dockBar is not None + ): + self.dockContext.StartDrag(pt) + elif nHitTest == win32con.HTSIZE and not self.IsFloating(): + self.StartTracking() + else: + return 1 + return 0 + + def OnLButtonDblClk(self, msg): + # only toggle docking if clicked in "void" space + if self.dockBar is not None: + # toggle docking + self.dockContext.ToggleDocking() + return 0 + return 1 + + def OnNcLButtonDblClk(self, msg): + nHitTest = wparam = msg[2] + # UINT nHitTest, CPoint point) + if self.dockBar is not None and nHitTest == win32con.HTCAPTION: + # toggle docking + self.dockContext.ToggleDocking() + return 0 + return 1 + + def OnMouseMove(self, msg): + flags = wparam = msg[2] + lparam = msg[3] + if self.IsFloating() or not self.bTracking: + return 1 + + # Convert unsigned 16 bit to signed 32 bit. + x = win32api.LOWORD(lparam) + if x & 32768: + x = x | -65536 + y = win32api.HIWORD(lparam) + if y & 32768: + y = y | -65536 + pt = x, y + cpt = CenterPoint(self.rectTracker) + pt = self.ClientToWnd(pt) + if self.IsHorz(): + if cpt[1] != pt[1]: + self.OnInvertTracker(self.rectTracker) + self.rectTracker = OffsetRect(self.rectTracker, (0, pt[1] - cpt[1])) + self.OnInvertTracker(self.rectTracker) + else: + if cpt[0] != pt[0]: + self.OnInvertTracker(self.rectTracker) + self.rectTracker = OffsetRect(self.rectTracker, (pt[0] - cpt[0], 0)) + self.OnInvertTracker(self.rectTracker) + + return 0 # Dont pass it on. + + # def OnBarStyleChange(self, old, new): + + def OnNcCalcSize(self, bCalcValid, size_info): + (rc0, rc1, rc2, pos) = size_info + self.rectBorder = self.GetWindowRect() + self.rectBorder = OffsetRect( + self.rectBorder, (-self.rectBorder[0], -self.rectBorder[1]) + ) + + dwBorderStyle = self._obj_.dwStyle | afxres.CBRS_BORDER_ANY + + if self.nDockBarID == afxres.AFX_IDW_DOCKBAR_TOP: + dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_BOTTOM + rc0.left = rc0.left + self.cxGripper + rc0.bottom = rc0.bottom - self.cxEdge + rc0.top = rc0.top + self.cxBorder + rc0.right = rc0.right - self.cxBorder + self.rectBorder = ( + self.rectBorder[0], + self.rectBorder[3] - self.cxEdge, + self.rectBorder[2], + self.rectBorder[3], + ) + elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM: + dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_TOP + rc0.left = rc0.left + self.cxGripper + rc0.top = rc0.top + self.cxEdge + rc0.bottom = rc0.bottom - self.cxBorder + rc0.right = rc0.right - self.cxBorder + self.rectBorder = ( + self.rectBorder[0], + self.rectBorder[1], + self.rectBorder[2], + self.rectBorder[1] + self.cxEdge, + ) + elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_LEFT: + dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_RIGHT + rc0.right = rc0.right - self.cxEdge + rc0.left = rc0.left + self.cxBorder + rc0.bottom = rc0.bottom - self.cxBorder + rc0.top = rc0.top + self.cxGripper + self.rectBorder = ( + self.rectBorder[2] - self.cxEdge, + self.rectBorder[1], + self.rectBorder[2], + self.rectBorder[3], + ) + elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT: + dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_LEFT + rc0.left = rc0.left + self.cxEdge + rc0.right = rc0.right - self.cxBorder + rc0.bottom = rc0.bottom - self.cxBorder + rc0.top = rc0.top + self.cxGripper + self.rectBorder = ( + self.rectBorder[0], + self.rectBorder[1], + self.rectBorder[0] + self.cxEdge, + self.rectBorder[3], + ) + else: + self.rectBorder = 0, 0, 0, 0 + + self.SetBarStyle(dwBorderStyle) + return 0 + + def OnNcPaint(self, msg): + self.EraseNonClient() + dc = self.GetWindowDC() + ctl = win32api.GetSysColor(win32con.COLOR_BTNHIGHLIGHT) + cbr = win32api.GetSysColor(win32con.COLOR_BTNSHADOW) + dc.Draw3dRect(self.rectBorder, ctl, cbr) + + self.DrawGripper(dc) + + rect = self.GetClientRect() + self.InvalidateRect(rect, 1) + return 0 + + def OnNcHitTest(self, pt): # A virtual, not a hooked message. + if self.IsFloating(): + return 1 + + ptOrig = pt + rect = self.GetWindowRect() + pt = pt[0] - rect[0], pt[1] - rect[1] + + if PtInRect(self.rectClose, pt): + return win32con.HTSYSMENU + elif PtInRect(self.rectUndock, pt): + return win32con.HTMINBUTTON + elif PtInRect(self.rectGripper, pt): + return win32con.HTCAPTION + elif PtInRect(self.rectBorder, pt): + return win32con.HTSIZE + else: + return self._obj_.OnNcHitTest(ptOrig) + + def StartTracking(self): + self.SetCapture() + + # make sure no updates are pending + self.RedrawWindow(None, None, win32con.RDW_ALLCHILDREN | win32con.RDW_UPDATENOW) + self.dockSite.LockWindowUpdate() + + self.ptOld = CenterPoint(self.rectBorder) + self.bTracking = 1 + + self.rectTracker = self.rectBorder + if not self.IsHorz(): + l, t, r, b = self.rectTracker + b = b - 4 + self.rectTracker = l, t, r, b + + self.OnInvertTracker(self.rectTracker) + + def OnCaptureChanged(self, msg): + hwnd = lparam = msg[3] + if self.bTracking and hwnd != self.GetSafeHwnd(): + self.StopTracking(0) # cancel tracking + return 1 + + def StopTracking(self, bAccept): + self.OnInvertTracker(self.rectTracker) + self.dockSite.UnlockWindowUpdate() + self.bTracking = 0 + self.ReleaseCapture() + if not bAccept: + return + + rcc = self.dockSite.GetWindowRect() + if self.IsHorz(): + newsize = self.sizeHorz[1] + maxsize = newsize + (rcc[3] - rcc[1]) + minsize = self.sizeMin[1] + else: + newsize = self.sizeVert[0] + maxsize = newsize + (rcc[2] - rcc[0]) + minsize = self.sizeMin[0] + + pt = CenterPoint(self.rectTracker) + if self.nDockBarID == afxres.AFX_IDW_DOCKBAR_TOP: + newsize = newsize + (pt[1] - self.ptOld[1]) + elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM: + newsize = newsize + (-pt[1] + self.ptOld[1]) + elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_LEFT: + newsize = newsize + (pt[0] - self.ptOld[0]) + elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT: + newsize = newsize + (-pt[0] + self.ptOld[0]) + newsize = max(minsize, min(maxsize, newsize)) + if self.IsHorz(): + self.sizeHorz = self.sizeHorz[0], newsize + else: + self.sizeVert = newsize, self.sizeVert[1] + self.dockSite.RecalcLayout() + return 0 + + def OnInvertTracker(self, rect): + assert rect[2] - rect[0] > 0 and rect[3] - rect[1] > 0, "rect is empty" + assert self.bTracking + rcc = self.GetWindowRect() + rcf = self.dockSite.GetWindowRect() + + rect = OffsetRect(rect, (rcc[0] - rcf[0], rcc[1] - rcf[1])) + rect = DeflateRect(rect, (1, 1)) + + flags = win32con.DCX_WINDOW | win32con.DCX_CACHE | win32con.DCX_LOCKWINDOWUPDATE + dc = self.dockSite.GetDCEx(None, flags) + try: + brush = win32ui.GetHalftoneBrush() + oldBrush = dc.SelectObject(brush) + + dc.PatBlt( + (rect[0], rect[1]), + (rect[2] - rect[0], rect[3] - rect[1]), + win32con.PATINVERT, + ) + dc.SelectObject(oldBrush) + finally: + self.dockSite.ReleaseDC(dc) + + def IsHorz(self): + return ( + self.nDockBarID == afxres.AFX_IDW_DOCKBAR_TOP + or self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM + ) + + def ClientToWnd(self, pt): + x, y = pt + if self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM: + y = y + self.cxEdge + elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT: + x = x + self.cxEdge + return x, y + + def DrawGripper(self, dc): + # no gripper if floating + if self._obj_.dwStyle & afxres.CBRS_FLOATING: + return + + # -==HACK==- + # in order to calculate the client area properly after docking, + # the client area must be recalculated twice (I have no idea why) + self.dockSite.RecalcLayout() + # -==END HACK==- + + gripper = self.GetWindowRect() + gripper = self.ScreenToClient(gripper) + gripper = OffsetRect(gripper, (-gripper[0], -gripper[1])) + gl, gt, gr, gb = gripper + + if self._obj_.dwStyle & afxres.CBRS_ORIENT_HORZ: + # gripper at left + self.rectGripper = gl, gt + 40, gl + 20, gb + # draw close box + self.rectClose = gl + 7, gt + 10, gl + 19, gt + 22 + dc.DrawFrameControl( + self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE + ) + # draw docking toggle box + self.rectUndock = OffsetRect(self.rectClose, (0, 13)) + dc.DrawFrameControl( + self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX + ) + + gt = gt + 38 + gb = gb - 10 + gl = gl + 10 + gr = gl + 3 + gripper = gl, gt, gr, gb + dc.Draw3dRect(gripper, clrBtnHilight, clrBtnShadow) + dc.Draw3dRect(OffsetRect(gripper, (4, 0)), clrBtnHilight, clrBtnShadow) + else: + # gripper at top + self.rectGripper = gl, gt, gr - 40, gt + 20 + # draw close box + self.rectClose = gr - 21, gt + 7, gr - 10, gt + 18 + dc.DrawFrameControl( + self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE + ) + # draw docking toggle box + self.rectUndock = OffsetRect(self.rectClose, (-13, 0)) + dc.DrawFrameControl( + self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX + ) + gr = gr - 38 + gl = gl + 10 + gt = gt + 10 + gb = gt + 3 + + gripper = gl, gt, gr, gb + dc.Draw3dRect(gripper, clrBtnHilight, clrBtnShadow) + dc.Draw3dRect(OffsetRect(gripper, (0, 4)), clrBtnHilight, clrBtnShadow) + + def HookMessages(self): + self.HookMessage(self.OnLButtonUp, win32con.WM_LBUTTONUP) + self.HookMessage(self.OnLButtonDown, win32con.WM_LBUTTONDOWN) + self.HookMessage(self.OnLButtonDblClk, win32con.WM_LBUTTONDBLCLK) + self.HookMessage(self.OnNcLButtonDown, win32con.WM_NCLBUTTONDOWN) + self.HookMessage(self.OnNcLButtonDblClk, win32con.WM_NCLBUTTONDBLCLK) + self.HookMessage(self.OnMouseMove, win32con.WM_MOUSEMOVE) + self.HookMessage(self.OnNcPaint, win32con.WM_NCPAINT) + self.HookMessage(self.OnCaptureChanged, win32con.WM_CAPTURECHANGED) + self.HookMessage(self.OnWindowPosChanged, win32con.WM_WINDOWPOSCHANGED) + + +# self.HookMessage(self.OnSize, win32con.WM_SIZE) + + +def EditCreator(parent): + d = win32ui.CreateEdit() + es = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | win32con.WS_BORDER + | win32con.ES_MULTILINE + | win32con.ES_WANTRETURN + ) + d.CreateWindow(es, (0, 0, 150, 150), parent, 1000) + return d + + +def test(): + import pywin.mfc.dialog + + global bar + bar = DockingBar() + creator = EditCreator + bar.CreateWindow(win32ui.GetMainFrame(), creator, "Coolbar Demo", 0xFFFFF) + # win32ui.GetMainFrame().ShowControlBar(bar, 1, 0) + bar.SetBarStyle( + bar.GetBarStyle() + | afxres.CBRS_TOOLTIPS + | afxres.CBRS_FLYBY + | afxres.CBRS_SIZE_DYNAMIC + ) + bar.EnableDocking(afxres.CBRS_ALIGN_ANY) + win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM) + + +if __name__ == "__main__": + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/docking/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/docking/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/docking/__pycache__/DockingBar.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/docking/__pycache__/DockingBar.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea3fa3f47518e0af6c1e965c61c3cb1007f294a8 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/docking/__pycache__/DockingBar.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/docking/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/docking/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c4fbecfcf3c359eac8aef0d88b5d47e1cb0b906 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/docking/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f25adfbfd393f36fbad350337cac04aea0f390e Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/app.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/app.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bed430c6d1b2f21a46fd3a81db44592552ecd82c Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/app.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/bitmap.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/bitmap.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ddf404877c6ac46c44754d62869790da12307fa Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/bitmap.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/cmdline.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/cmdline.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d0bb4a3636ce6a1c8e4edd248df27ee63a8191c Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/cmdline.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/dbgcommands.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/dbgcommands.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7eb434c5a7b0bd9c7e47c9c2ea1a0f439f26ece Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/dbgcommands.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/dlgappcore.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/dlgappcore.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4079ef6b8ee403d99747d52a16628a1169cf5654 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/dlgappcore.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/help.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/help.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14598d8903db714ed3f8a12e687ead2d0c26b4e2 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/help.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/interact.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/interact.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87b9b2d0bb979a0b47f337be919d3f76b4840f28 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/interact.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/intpyapp.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/intpyapp.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb0184744b6423eb9de8471d7ba79867249387eb Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/intpyapp.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/intpydde.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/intpydde.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c09ff7e273bc023d15ec519428af0dbdc24527d9 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/intpydde.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/mdi_pychecker.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/mdi_pychecker.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90be33686d68513d136f357c7093d2cfb938acd0 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/mdi_pychecker.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/scriptutils.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/scriptutils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c3fdf11204e7a3e761d8de2df5e90afc83451bd Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/scriptutils.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/sgrepmdi.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/sgrepmdi.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e77c1904eeb39351237b53e9f7a6e9df077c9da4 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/sgrepmdi.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/startup.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/startup.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e78717e11971988c2a5c00844dd473d112e2922a Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/startup.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/stdin.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/stdin.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec0931a787edb1b8ff75b09f8185b6af4fda4342 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/stdin.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/toolmenu.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/toolmenu.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f3cd5b9826fdded717fbf1552839b6796497732 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/toolmenu.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/window.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/window.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7b5d4576dc82757be7d2cb91629563de2e32ac1 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/window.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/winout.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/winout.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..626ffb690ce4a27da25406bdad506ffd79cf9e05 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/__pycache__/winout.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/app.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/app.py new file mode 100644 index 0000000000000000000000000000000000000000..f994f99f91fea16bf9e310cba504f94abaf6b305 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/app.py @@ -0,0 +1,457 @@ +# App.py +# Application stuff. +# The application is responsible for managing the main frame window. +# +# We also grab the FileOpen command, to invoke our Python editor +" The PythonWin application code. Manages most aspects of MDI, etc " +import os +import sys +import traceback + +import regutil +import win32api +import win32con +import win32ui +from pywin.mfc import afxres, dialog, window +from pywin.mfc.thread import WinApp + +from . import scriptutils + +## NOTE: App and AppBuild should NOT be used - instead, you should contruct your +## APP class manually whenever you like (just ensure you leave these 2 params None!) +## Whoever wants the generic "Application" should get it via win32iu.GetApp() + +# These are "legacy" +AppBuilder = None +App = None # default - if used, must end up a CApp derived class. + + +# Helpers that should one day be removed! +def AddIdleHandler(handler): + print( + "app.AddIdleHandler is deprecated - please use win32ui.GetApp().AddIdleHandler() instead." + ) + return win32ui.GetApp().AddIdleHandler(handler) + + +def DeleteIdleHandler(handler): + print( + "app.DeleteIdleHandler is deprecated - please use win32ui.GetApp().DeleteIdleHandler() instead." + ) + return win32ui.GetApp().DeleteIdleHandler(handler) + + +# Helper for writing a Window position by name, and later loading it. +def SaveWindowSize(section, rect, state=""): + """Writes a rectangle to an INI file + Args: section = section name in the applications INI file + rect = a rectangle in a (cy, cx, y, x) tuple + (same format as CREATESTRUCT position tuples).""" + left, top, right, bottom = rect + if state: + state = state + " " + win32ui.WriteProfileVal(section, state + "left", left) + win32ui.WriteProfileVal(section, state + "top", top) + win32ui.WriteProfileVal(section, state + "right", right) + win32ui.WriteProfileVal(section, state + "bottom", bottom) + + +def LoadWindowSize(section, state=""): + """Loads a section from an INI file, and returns a rect in a tuple (see SaveWindowSize)""" + if state: + state = state + " " + left = win32ui.GetProfileVal(section, state + "left", 0) + top = win32ui.GetProfileVal(section, state + "top", 0) + right = win32ui.GetProfileVal(section, state + "right", 0) + bottom = win32ui.GetProfileVal(section, state + "bottom", 0) + return (left, top, right, bottom) + + +def RectToCreateStructRect(rect): + return (rect[3] - rect[1], rect[2] - rect[0], rect[1], rect[0]) + + +# Define FrameWindow and Application objects +# +# The Main Frame of the application. +class MainFrame(window.MDIFrameWnd): + sectionPos = "Main Window" + statusBarIndicators = ( + afxres.ID_SEPARATOR, # // status line indicator + afxres.ID_INDICATOR_CAPS, + afxres.ID_INDICATOR_NUM, + afxres.ID_INDICATOR_SCRL, + win32ui.ID_INDICATOR_LINENUM, + win32ui.ID_INDICATOR_COLNUM, + ) + + def OnCreate(self, cs): + self._CreateStatusBar() + return 0 + + def _CreateStatusBar(self): + self.statusBar = win32ui.CreateStatusBar(self) + self.statusBar.SetIndicators(self.statusBarIndicators) + self.HookCommandUpdate(self.OnUpdatePosIndicator, win32ui.ID_INDICATOR_LINENUM) + self.HookCommandUpdate(self.OnUpdatePosIndicator, win32ui.ID_INDICATOR_COLNUM) + + def OnUpdatePosIndicator(self, cmdui): + editControl = scriptutils.GetActiveEditControl() + value = " " * 5 + if editControl is not None: + try: + startChar, endChar = editControl.GetSel() + lineNo = editControl.LineFromChar(startChar) + colNo = endChar - editControl.LineIndex(lineNo) + + if cmdui.m_nID == win32ui.ID_INDICATOR_LINENUM: + value = "%0*d" % (5, lineNo + 1) + else: + value = "%0*d" % (3, colNo + 1) + except win32ui.error: + pass + cmdui.SetText(value) + cmdui.Enable() + + def PreCreateWindow(self, cc): + cc = self._obj_.PreCreateWindow(cc) + pos = LoadWindowSize(self.sectionPos) + self.startRect = pos + if pos[2] - pos[0]: + rect = RectToCreateStructRect(pos) + cc = cc[0], cc[1], cc[2], cc[3], rect, cc[5], cc[6], cc[7], cc[8] + return cc + + def OnDestroy(self, msg): + # use GetWindowPlacement(), as it works even when min'd or max'd + rectNow = self.GetWindowPlacement()[4] + if rectNow != self.startRect: + SaveWindowSize(self.sectionPos, rectNow) + return 0 + + +class CApp(WinApp): + "A class for the application" + + def __init__(self): + self.oldCallbackCaller = None + WinApp.__init__(self, win32ui.GetApp()) + self.idleHandlers = [] + + def InitInstance(self): + "Called to crank up the app" + HookInput() + numMRU = win32ui.GetProfileVal("Settings", "Recent File List Size", 10) + win32ui.LoadStdProfileSettings(numMRU) + # self._obj_.InitMDIInstance() + if win32api.GetVersionEx()[0] < 4: + win32ui.SetDialogBkColor() + win32ui.Enable3dControls() + + # install a "callback caller" - a manager for the callbacks + # self.oldCallbackCaller = win32ui.InstallCallbackCaller(self.CallbackManager) + self.LoadMainFrame() + self.SetApplicationPaths() + + def ExitInstance(self): + "Called as the app dies - too late to prevent it here!" + win32ui.OutputDebug("Application shutdown\n") + # Restore the callback manager, if any. + try: + win32ui.InstallCallbackCaller(self.oldCallbackCaller) + except AttributeError: + pass + if self.oldCallbackCaller: + del self.oldCallbackCaller + self.frame = None # clean Python references to the now destroyed window object. + self.idleHandlers = [] + # Attempt cleanup if not already done! + if self._obj_: + self._obj_.AttachObject(None) + self._obj_ = None + global App + global AppBuilder + App = None + AppBuilder = None + return 0 + + def HaveIdleHandler(self, handler): + return handler in self.idleHandlers + + def AddIdleHandler(self, handler): + self.idleHandlers.append(handler) + + def DeleteIdleHandler(self, handler): + self.idleHandlers.remove(handler) + + def OnIdle(self, count): + try: + ret = 0 + handlers = self.idleHandlers[:] # copy list, as may be modified during loop + for handler in handlers: + try: + thisRet = handler(handler, count) + except: + print("Idle handler %s failed" % (repr(handler))) + traceback.print_exc() + print("Idle handler removed from list") + try: + self.DeleteIdleHandler(handler) + except ValueError: # Item not in list. + pass + thisRet = 0 + ret = ret or thisRet + return ret + except KeyboardInterrupt: + pass + + def CreateMainFrame(self): + return MainFrame() + + def LoadMainFrame(self): + "Create the main applications frame" + self.frame = self.CreateMainFrame() + self.SetMainFrame(self.frame) + self.frame.LoadFrame(win32ui.IDR_MAINFRAME, win32con.WS_OVERLAPPEDWINDOW) + self.frame.DragAcceptFiles() # we can accept these. + self.frame.ShowWindow(win32ui.GetInitialStateRequest()) + self.frame.UpdateWindow() + self.HookCommands() + + def OnHelp(self, id, code): + try: + if id == win32ui.ID_HELP_GUI_REF: + helpFile = regutil.GetRegisteredHelpFile("Pythonwin Reference") + helpCmd = win32con.HELP_CONTENTS + else: + helpFile = regutil.GetRegisteredHelpFile("Main Python Documentation") + helpCmd = win32con.HELP_FINDER + if helpFile is None: + win32ui.MessageBox("The help file is not registered!") + else: + from . import help + + help.OpenHelpFile(helpFile, helpCmd) + except: + t, v, tb = sys.exc_info() + win32ui.MessageBox( + "Internal error in help file processing\r\n%s: %s" % (t, v) + ) + tb = None # Prevent a cycle + + def DoLoadModules(self, modules): + # XXX - this should go, but the debugger uses it :-( + # dont do much checking! + for module in modules: + __import__(module) + + def HookCommands(self): + self.frame.HookMessage(self.OnDropFiles, win32con.WM_DROPFILES) + self.HookCommand(self.HandleOnFileOpen, win32ui.ID_FILE_OPEN) + self.HookCommand(self.HandleOnFileNew, win32ui.ID_FILE_NEW) + self.HookCommand(self.OnFileMRU, win32ui.ID_FILE_MRU_FILE1) + self.HookCommand(self.OnHelpAbout, win32ui.ID_APP_ABOUT) + self.HookCommand(self.OnHelp, win32ui.ID_HELP_PYTHON) + self.HookCommand(self.OnHelp, win32ui.ID_HELP_GUI_REF) + # Hook for the right-click menu. + self.frame.GetWindow(win32con.GW_CHILD).HookMessage( + self.OnRClick, win32con.WM_RBUTTONDOWN + ) + + def SetApplicationPaths(self): + # Load the users/application paths + new_path = [] + apppath = win32ui.GetProfileVal("Python", "Application Path", "").split(";") + for path in apppath: + if len(path) > 0: + new_path.append(win32ui.FullPath(path)) + for extra_num in range(1, 11): + apppath = win32ui.GetProfileVal( + "Python", "Application Path %d" % extra_num, "" + ).split(";") + if len(apppath) == 0: + break + for path in apppath: + if len(path) > 0: + new_path.append(win32ui.FullPath(path)) + sys.path = new_path + sys.path + + def OnRClick(self, params): + "Handle right click message" + # put up the entire FILE menu! + menu = win32ui.LoadMenu(win32ui.IDR_TEXTTYPE).GetSubMenu(0) + menu.TrackPopupMenu(params[5]) # track at mouse position. + return 0 + + def OnDropFiles(self, msg): + "Handle a file being dropped from file manager" + hDropInfo = msg[2] + self.frame.SetActiveWindow() # active us + nFiles = win32api.DragQueryFile(hDropInfo) + try: + for iFile in range(0, nFiles): + fileName = win32api.DragQueryFile(hDropInfo, iFile) + win32ui.GetApp().OpenDocumentFile(fileName) + finally: + win32api.DragFinish(hDropInfo) + + return 0 + + # No longer used by Pythonwin, as the C++ code has this same basic functionality + # but handles errors slightly better. + # It all still works, tho, so if you need similar functionality, you can use it. + # Therefore I havent deleted this code completely! + # def CallbackManager( self, ob, args = () ): + # """Manage win32 callbacks. Trap exceptions, report on them, then return 'All OK' + # to the frame-work. """ + # import traceback + # try: + # ret = apply(ob, args) + # return ret + # except: + # # take copies of the exception values, else other (handled) exceptions may get + # # copied over by the other fns called. + # win32ui.SetStatusText('An exception occured in a windows command handler.') + # t, v, tb = sys.exc_info() + # traceback.print_exception(t, v, tb.tb_next) + # try: + # sys.stdout.flush() + # except (NameError, AttributeError): + # pass + + # Command handlers. + def OnFileMRU(self, id, code): + "Called when a File 1-n message is recieved" + fileName = win32ui.GetRecentFileList()[id - win32ui.ID_FILE_MRU_FILE1] + win32ui.GetApp().OpenDocumentFile(fileName) + + def HandleOnFileOpen(self, id, code): + "Called when FileOpen message is received" + win32ui.GetApp().OnFileOpen() + + def HandleOnFileNew(self, id, code): + "Called when FileNew message is received" + win32ui.GetApp().OnFileNew() + + def OnHelpAbout(self, id, code): + "Called when HelpAbout message is received. Displays the About dialog." + win32ui.InitRichEdit() + dlg = AboutBox() + dlg.DoModal() + + +def _GetRegistryValue(key, val, default=None): + # val is registry value - None for default val. + try: + hkey = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, key) + return win32api.RegQueryValueEx(hkey, val)[0] + except win32api.error: + try: + hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, key) + return win32api.RegQueryValueEx(hkey, val)[0] + except win32api.error: + return default + + +scintilla = "Scintilla is Copyright 1998-2008 Neil Hodgson (http://www.scintilla.org)" +idle = "This program uses IDLE extensions by Guido van Rossum, Tim Peters and others." +contributors = "Thanks to the following people for making significant contributions: Roger Upole, Sidnei da Silva, Sam Rushing, Curt Hagenlocher, Dave Brennan, Roger Burnham, Gordon McMillan, Neil Hodgson, Laramie Leavitt. (let me know if I have forgotten you!)" + + +# The About Box +class AboutBox(dialog.Dialog): + def __init__(self, idd=win32ui.IDD_ABOUTBOX): + dialog.Dialog.__init__(self, idd) + + def OnInitDialog(self): + text = ( + "Pythonwin - Python IDE and GUI Framework for Windows.\n\n%s\n\nPython is %s\n\n%s\n\n%s\n\n%s" + % (win32ui.copyright, sys.copyright, scintilla, idle, contributors) + ) + self.SetDlgItemText(win32ui.IDC_EDIT1, text) + # Get the build number - written by installers. + # For distutils build, read pywin32.version.txt + import sysconfig + + site_packages = sysconfig.get_paths()["platlib"] + try: + build_no = ( + open(os.path.join(site_packages, "pywin32.version.txt")).read().strip() + ) + ver = "pywin32 build %s" % build_no + except EnvironmentError: + ver = None + if ver is None: + # See if we are Part of Active Python + ver = _GetRegistryValue( + "SOFTWARE\\ActiveState\\ActivePython", "CurrentVersion" + ) + if ver is not None: + ver = "ActivePython build %s" % (ver,) + if ver is None: + ver = "" + self.SetDlgItemText(win32ui.IDC_ABOUT_VERSION, ver) + self.HookCommand(self.OnButHomePage, win32ui.IDC_BUTTON1) + + def OnButHomePage(self, id, code): + if code == win32con.BN_CLICKED: + win32api.ShellExecute( + 0, "open", "https://github.com/mhammond/pywin32", None, "", 1 + ) + + +def Win32RawInput(prompt=None): + "Provide raw_input() for gui apps" + # flush stderr/out first. + try: + sys.stdout.flush() + sys.stderr.flush() + except: + pass + if prompt is None: + prompt = "" + ret = dialog.GetSimpleInput(prompt) + if ret == None: + raise KeyboardInterrupt("operation cancelled") + return ret + + +def Win32Input(prompt=None): + "Provide input() for gui apps" + return eval(input(prompt)) + + +def HookInput(): + try: + raw_input + # must be py2x... + sys.modules["__builtin__"].raw_input = Win32RawInput + sys.modules["__builtin__"].input = Win32Input + except NameError: + # must be py3k + import code + + sys.modules["builtins"].input = Win32RawInput + + +def HaveGoodGUI(): + """Returns true if we currently have a good gui available.""" + return "pywin.framework.startup" in sys.modules + + +def CreateDefaultGUI(appClass=None): + """Creates a default GUI environment""" + if appClass is None: + from . import intpyapp # Bring in the default app - could be param'd later. + + appClass = intpyapp.InteractivePythonApp + # Create and init the app. + appClass().InitInstance() + + +def CheckCreateDefaultGUI(): + """Checks and creates if necessary a default GUI environment.""" + rc = HaveGoodGUI() + if not rc: + CreateDefaultGUI() + return rc diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/bitmap.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/bitmap.py new file mode 100644 index 0000000000000000000000000000000000000000..1501f72d899dcf3e85c0f94a93e63f12a617c763 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/bitmap.py @@ -0,0 +1,164 @@ +import os + +import win32api +import win32con +import win32ui +from pywin.mfc import docview, window + +from . import app + +bStretch = 1 + + +class BitmapDocument(docview.Document): + "A bitmap document. Holds the bitmap data itself." + + def __init__(self, template): + docview.Document.__init__(self, template) + self.bitmap = None + + def OnNewDocument(self): + # I can not create new bitmaps. + win32ui.MessageBox("Bitmaps can not be created.") + + def OnOpenDocument(self, filename): + self.bitmap = win32ui.CreateBitmap() + # init data members + f = open(filename, "rb") + try: + try: + self.bitmap.LoadBitmapFile(f) + except IOError: + win32ui.MessageBox("Could not load the bitmap from %s" % filename) + return 0 + finally: + f.close() + self.size = self.bitmap.GetSize() + return 1 + + def DeleteContents(self): + self.bitmap = None + + +class BitmapView(docview.ScrollView): + "A view of a bitmap. Obtains data from document." + + def __init__(self, doc): + docview.ScrollView.__init__(self, doc) + self.width = self.height = 0 + # set up message handlers + self.HookMessage(self.OnSize, win32con.WM_SIZE) + + def OnInitialUpdate(self): + doc = self.GetDocument() + if doc.bitmap: + bitmapSize = doc.bitmap.GetSize() + self.SetScrollSizes(win32con.MM_TEXT, bitmapSize) + + def OnSize(self, params): + lParam = params[3] + self.width = win32api.LOWORD(lParam) + self.height = win32api.HIWORD(lParam) + + def OnDraw(self, dc): + # set sizes used for "non stretch" mode. + doc = self.GetDocument() + if doc.bitmap is None: + return + bitmapSize = doc.bitmap.GetSize() + if bStretch: + # stretch BMP. + viewRect = (0, 0, self.width, self.height) + bitmapRect = (0, 0, bitmapSize[0], bitmapSize[1]) + doc.bitmap.Paint(dc, viewRect, bitmapRect) + else: + # non stretch. + doc.bitmap.Paint(dc) + + +class BitmapFrame(window.MDIChildWnd): + def OnCreateClient(self, createparams, context): + borderX = win32api.GetSystemMetrics(win32con.SM_CXFRAME) + borderY = win32api.GetSystemMetrics(win32con.SM_CYFRAME) + titleY = win32api.GetSystemMetrics(win32con.SM_CYCAPTION) # includes border + # try and maintain default window pos, else adjust if cant fit + # get the main client window dimensions. + mdiClient = win32ui.GetMainFrame().GetWindow(win32con.GW_CHILD) + clientWindowRect = mdiClient.ScreenToClient(mdiClient.GetWindowRect()) + clientWindowSize = ( + clientWindowRect[2] - clientWindowRect[0], + clientWindowRect[3] - clientWindowRect[1], + ) + left, top, right, bottom = mdiClient.ScreenToClient(self.GetWindowRect()) + # width, height=context.doc.size[0], context.doc.size[1] + # width = width+borderX*2 + # height= height+titleY+borderY*2-1 + # if (left+width)>clientWindowSize[0]: + # left = clientWindowSize[0] - width + # if left<0: + # left = 0 + # width = clientWindowSize[0] + # if (top+height)>clientWindowSize[1]: + # top = clientWindowSize[1] - height + # if top<0: + # top = 0 + # height = clientWindowSize[1] + # self.frame.MoveWindow((left, top, left+width, top+height),0) + window.MDIChildWnd.OnCreateClient(self, createparams, context) + return 1 + + +class BitmapTemplate(docview.DocTemplate): + def __init__(self): + docview.DocTemplate.__init__( + self, win32ui.IDR_PYTHONTYPE, BitmapDocument, BitmapFrame, BitmapView + ) + + def MatchDocType(self, fileName, fileType): + doc = self.FindOpenDocument(fileName) + if doc: + return doc + ext = os.path.splitext(fileName)[1].lower() + if ext == ".bmp": # removed due to PIL! or ext=='.ppm': + return win32ui.CDocTemplate_Confidence_yesAttemptNative + return win32ui.CDocTemplate_Confidence_maybeAttemptForeign + + +# return win32ui.CDocTemplate_Confidence_noAttempt + +# For debugging purposes, when this module may be reloaded many times. +try: + win32ui.GetApp().RemoveDocTemplate(bitmapTemplate) +except NameError: + pass + +bitmapTemplate = BitmapTemplate() +bitmapTemplate.SetDocStrings( + "\nBitmap\nBitmap\nBitmap (*.bmp)\n.bmp\nPythonBitmapFileType\nPython Bitmap File" +) +win32ui.GetApp().AddDocTemplate(bitmapTemplate) + +# This works, but just didnt make it through the code reorg. +# class PPMBitmap(Bitmap): +# def LoadBitmapFile(self, file ): +# magic=file.readline() +# if magic <> "P6\n": +# raise TypeError, "The file is not a PPM format file" +# rowcollist=string.split(file.readline()) +# cols=string.atoi(rowcollist[0]) +# rows=string.atoi(rowcollist[1]) +# file.readline() # whats this one? +# self.bitmap.LoadPPMFile(file,(cols,rows)) + + +def t(): + bitmapTemplate.OpenDocumentFile("d:\\winnt\\arcade.bmp") + # OpenBMPFile( 'd:\\winnt\\arcade.bmp') + + +def demo(): + import glob + + winDir = win32api.GetWindowsDirectory() + for fileName in glob.glob1(winDir, "*.bmp")[:2]: + bitmapTemplate.OpenDocumentFile(os.path.join(winDir, fileName)) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/cmdline.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/cmdline.py new file mode 100644 index 0000000000000000000000000000000000000000..dba31d1ad1e4983c8f199889630561a0178d6834 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/cmdline.py @@ -0,0 +1,56 @@ +# cmdline - command line utilities. +import string +import sys + +import win32ui + + +def ParseArgs(str): + import string + + ret = [] + pos = 0 + length = len(str) + while pos < length: + try: + while str[pos] in string.whitespace: + pos = pos + 1 + except IndexError: + break + if pos >= length: + break + if str[pos] == '"': + pos = pos + 1 + try: + endPos = str.index('"', pos) - 1 + nextPos = endPos + 2 + except ValueError: + endPos = length + nextPos = endPos + 1 + else: + endPos = pos + while endPos < length and not str[endPos] in string.whitespace: + endPos = endPos + 1 + nextPos = endPos + 1 + ret.append(str[pos : endPos + 1].strip()) + pos = nextPos + return ret + + +def FixArgFileName(fileName): + """Convert a filename on the commandline to something useful. + Given an automatic filename on the commandline, turn it a python module name, + with the path added to sys.path.""" + import os + + path, fname = os.path.split(fileName) + if len(path) == 0: + path = os.curdir + path = os.path.abspath(path) + # must check that the command line arg's path is in sys.path + for syspath in sys.path: + if os.path.abspath(syspath) == path: + break + else: + sys.path.append(path) + return os.path.splitext(fname)[0] diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/dbgcommands.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/dbgcommands.py new file mode 100644 index 0000000000000000000000000000000000000000..e295926c799320c80513af1a2986fc1fdb3154d0 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/dbgcommands.py @@ -0,0 +1,189 @@ +# Command Handlers for the debugger. + +# Not in the debugger package, as I always want these interfaces to be +# available, even if the debugger has not yet been (or can not be) +# imported +import warnings + +import win32ui +from pywin.scintilla.control import CScintillaEditInterface + +from . import scriptutils + +IdToBarNames = { + win32ui.IDC_DBG_STACK: ("Stack", 0), + win32ui.IDC_DBG_BREAKPOINTS: ("Breakpoints", 0), + win32ui.IDC_DBG_WATCH: ("Watch", 1), +} + + +class DebuggerCommandHandler: + def HookCommands(self): + commands = ( + (self.OnStep, None, win32ui.IDC_DBG_STEP), + (self.OnStepOut, self.OnUpdateOnlyBreak, win32ui.IDC_DBG_STEPOUT), + (self.OnStepOver, None, win32ui.IDC_DBG_STEPOVER), + (self.OnGo, None, win32ui.IDC_DBG_GO), + (self.OnClose, self.OnUpdateClose, win32ui.IDC_DBG_CLOSE), + (self.OnAdd, self.OnUpdateAddBreakpoints, win32ui.IDC_DBG_ADD), + (self.OnClearAll, self.OnUpdateClearAllBreakpoints, win32ui.IDC_DBG_CLEAR), + # (self.OnDebuggerToolbar, self.OnUpdateDebuggerToolbar, win32ui.ID_DEBUGGER_TOOLBAR), + ) + + frame = win32ui.GetMainFrame() + + for methHandler, methUpdate, id in commands: + frame.HookCommand(methHandler, id) + if not methUpdate is None: + frame.HookCommandUpdate(methUpdate, id) + + for id in list(IdToBarNames.keys()): + frame.HookCommand(self.OnDebuggerBar, id) + frame.HookCommandUpdate(self.OnUpdateDebuggerBar, id) + + def OnDebuggerToolbar(self, id, code): + if code == 0: + return not win32ui.GetMainFrame().OnBarCheck(id) + + def OnUpdateDebuggerToolbar(self, cmdui): + win32ui.GetMainFrame().OnUpdateControlBarMenu(cmdui) + cmdui.Enable(1) + + def _GetDebugger(self): + try: + import pywin.debugger + + return pywin.debugger.currentDebugger + except ImportError: + return None + + def _DoOrStart(self, doMethod, startFlag): + d = self._GetDebugger() + if d is not None and d.IsDebugging(): + method = getattr(d, doMethod) + method() + else: + scriptutils.RunScript( + defName=None, defArgs=None, bShowDialog=0, debuggingType=startFlag + ) + + def OnStep(self, msg, code): + self._DoOrStart("do_set_step", scriptutils.RS_DEBUGGER_STEP) + + def OnStepOver(self, msg, code): + self._DoOrStart("do_set_next", scriptutils.RS_DEBUGGER_STEP) + + def OnStepOut(self, msg, code): + d = self._GetDebugger() + if d is not None and d.IsDebugging(): + d.do_set_return() + + def OnGo(self, msg, code): + self._DoOrStart("do_set_continue", scriptutils.RS_DEBUGGER_GO) + + def OnClose(self, msg, code): + d = self._GetDebugger() + if d is not None: + if d.IsDebugging(): + d.set_quit() + else: + d.close() + + def OnUpdateClose(self, cmdui): + d = self._GetDebugger() + if d is not None and d.inited: + cmdui.Enable(1) + else: + cmdui.Enable(0) + + def OnAdd(self, msg, code): + doc, view = scriptutils.GetActiveEditorDocument() + if doc is None: + ## Don't do a messagebox, as this could be triggered from the app's + ## idle loop whenever the debug toolbar is visible, giving a never-ending + ## series of dialogs. This can happen when the OnUpdate handler + ## for the toolbar button IDC_DBG_ADD fails, since MFC falls back to + ## sending a normal command if the UI update command fails. + ## win32ui.MessageBox('There is no active window - no breakpoint can be added') + warnings.warn("There is no active window - no breakpoint can be added") + return None + pathName = doc.GetPathName() + lineNo = view.LineFromChar(view.GetSel()[0]) + 1 + # If I have a debugger, then tell it, otherwise just add a marker + d = self._GetDebugger() + if d is None: + import pywin.framework.editor.color.coloreditor + + doc.MarkerToggle( + lineNo, pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT + ) + else: + if d.get_break(pathName, lineNo): + win32ui.SetStatusText("Clearing breakpoint", 1) + rc = d.clear_break(pathName, lineNo) + else: + win32ui.SetStatusText("Setting breakpoint", 1) + rc = d.set_break(pathName, lineNo) + if rc: + win32ui.MessageBox(rc) + d.GUIRespondDebuggerData() + + def OnClearAll(self, msg, code): + win32ui.SetStatusText("Clearing all breakpoints") + d = self._GetDebugger() + if d is None: + import pywin.framework.editor + import pywin.framework.editor.color.coloreditor + + for doc in pywin.framework.editor.editorTemplate.GetDocumentList(): + doc.MarkerDeleteAll( + pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT + ) + else: + d.clear_all_breaks() + d.UpdateAllLineStates() + d.GUIRespondDebuggerData() + + def OnUpdateOnlyBreak(self, cmdui): + d = self._GetDebugger() + ok = d is not None and d.IsBreak() + cmdui.Enable(ok) + + def OnUpdateAddBreakpoints(self, cmdui): + doc, view = scriptutils.GetActiveEditorDocument() + if doc is None or not isinstance(view, CScintillaEditInterface): + enabled = 0 + else: + enabled = 1 + lineNo = view.LineFromChar(view.GetSel()[0]) + 1 + import pywin.framework.editor.color.coloreditor + + cmdui.SetCheck( + doc.MarkerAtLine( + lineNo, pywin.framework.editor.color.coloreditor.MARKER_BREAKPOINT + ) + != 0 + ) + cmdui.Enable(enabled) + + def OnUpdateClearAllBreakpoints(self, cmdui): + d = self._GetDebugger() + cmdui.Enable(d is None or len(d.breaks) != 0) + + def OnUpdateDebuggerBar(self, cmdui): + name, always = IdToBarNames.get(cmdui.m_nID) + enabled = always + d = self._GetDebugger() + if d is not None and d.IsDebugging() and name is not None: + enabled = 1 + bar = d.GetDebuggerBar(name) + cmdui.SetCheck(bar.IsWindowVisible()) + cmdui.Enable(enabled) + + def OnDebuggerBar(self, id, code): + name = IdToBarNames.get(id)[0] + d = self._GetDebugger() + if d is not None and name is not None: + bar = d.GetDebuggerBar(name) + newState = not bar.IsWindowVisible() + win32ui.GetMainFrame().ShowControlBar(bar, newState, 1) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/dlgappcore.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/dlgappcore.py new file mode 100644 index 0000000000000000000000000000000000000000..4b60cc1c0ae92ad601e7fc84962f6c29374a9694 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/dlgappcore.py @@ -0,0 +1,75 @@ +# dlgappcore. +# +# base classes for dialog based apps. + + +import win32api +import win32con +import win32ui +from pywin.mfc import dialog + +from . import app + +error = "Dialog Application Error" + + +class AppDialog(dialog.Dialog): + "The dialog box for the application" + + def __init__(self, id, dll=None): + self.iconId = win32ui.IDR_MAINFRAME + dialog.Dialog.__init__(self, id, dll) + + def OnInitDialog(self): + return dialog.Dialog.OnInitDialog(self) + + # Provide support for a dlg app using an icon + def OnPaint(self): + if not self.IsIconic(): + return self._obj_.OnPaint() + self.DefWindowProc(win32con.WM_ICONERASEBKGND, dc.GetHandleOutput(), 0) + left, top, right, bottom = self.GetClientRect() + left = (right - win32api.GetSystemMetrics(win32con.SM_CXICON)) >> 1 + top = (bottom - win32api.GetSystemMetrics(win32con.SM_CYICON)) >> 1 + hIcon = win32ui.GetApp().LoadIcon(self.iconId) + self.GetDC().DrawIcon((left, top), hIcon) + + # Only needed to provide a minimized icon (and this seems + # less important under win95/NT4 + def OnEraseBkgnd(self, dc): + if self.IsIconic(): + return 1 + else: + return self._obj_.OnEraseBkgnd(dc) + + def OnQueryDragIcon(self): + return win32ui.GetApp().LoadIcon(self.iconId) + + def PreDoModal(self): + pass + + +class DialogApp(app.CApp): + "An application class, for an app with main dialog box" + + def InitInstance(self): + # win32ui.SetProfileFileName('dlgapp.ini') + win32ui.LoadStdProfileSettings() + win32ui.EnableControlContainer() + win32ui.Enable3dControls() + self.dlg = self.frame = self.CreateDialog() + + if self.frame is None: + raise error("No dialog was created by CreateDialog()") + return + + self._obj_.InitDlgInstance(self.dlg) + self.PreDoModal() + self.dlg.PreDoModal() + self.dlg.DoModal() + + def CreateDialog(self): + pass + + def PreDoModal(self): + pass diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/ModuleBrowser.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/ModuleBrowser.py new file mode 100644 index 0000000000000000000000000000000000000000..7fd965327d1d7c128c293d20f4511ee3af6de9b7 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/ModuleBrowser.py @@ -0,0 +1,235 @@ +# ModuleBrowser.py - A view that provides a module browser for an editor document. +import pyclbr + +import afxres +import commctrl +import pywin.framework.scriptutils +import pywin.mfc.docview +import win32api +import win32con +import win32ui +from pywin.tools import browser, hierlist + + +class HierListCLBRModule(hierlist.HierListItem): + def __init__(self, modName, clbrdata): + self.modName = modName + self.clbrdata = clbrdata + + def GetText(self): + return self.modName + + def GetSubList(self): + ret = [] + for item in self.clbrdata.values(): + if ( + item.__class__ != pyclbr.Class + ): # ie, it is a pyclbr Function instance (only introduced post 1.5.2) + ret.append(HierListCLBRFunction(item)) + else: + ret.append(HierListCLBRClass(item)) + ret.sort() + return ret + + def IsExpandable(self): + return 1 + + +class HierListCLBRItem(hierlist.HierListItem): + def __init__(self, name, file, lineno, suffix=""): + self.name = str(name) + self.file = file + self.lineno = lineno + self.suffix = suffix + + def __lt__(self, other): + return self.name < other.name + + def __eq__(self, other): + return self.name == other.name + + def GetText(self): + return self.name + self.suffix + + def TakeDefaultAction(self): + if self.file: + pywin.framework.scriptutils.JumpToDocument( + self.file, self.lineno, bScrollToTop=1 + ) + else: + win32ui.SetStatusText("Can not locate the source code for this object.") + + def PerformItemSelected(self): + if self.file is None: + msg = "%s - source can not be located." % (self.name,) + else: + msg = "%s defined at line %d of %s" % (self.name, self.lineno, self.file) + win32ui.SetStatusText(msg) + + +class HierListCLBRClass(HierListCLBRItem): + def __init__(self, clbrclass, suffix=""): + try: + name = clbrclass.name + file = clbrclass.file + lineno = clbrclass.lineno + self.super = clbrclass.super + self.methods = clbrclass.methods + except AttributeError: + name = clbrclass + file = lineno = None + self.super = [] + self.methods = {} + HierListCLBRItem.__init__(self, name, file, lineno, suffix) + + def GetSubList(self): + r1 = [] + for c in self.super: + r1.append(HierListCLBRClass(c, " (Parent class)")) + r1.sort() + r2 = [] + for meth, lineno in self.methods.items(): + r2.append(HierListCLBRMethod(meth, self.file, lineno)) + r2.sort() + return r1 + r2 + + def IsExpandable(self): + return len(self.methods) + len(self.super) + + def GetBitmapColumn(self): + return 21 + + +class HierListCLBRFunction(HierListCLBRItem): + def __init__(self, clbrfunc, suffix=""): + name = clbrfunc.name + file = clbrfunc.file + lineno = clbrfunc.lineno + HierListCLBRItem.__init__(self, name, file, lineno, suffix) + + def GetBitmapColumn(self): + return 22 + + +class HierListCLBRMethod(HierListCLBRItem): + def GetBitmapColumn(self): + return 22 + + +class HierListCLBRErrorItem(hierlist.HierListItem): + def __init__(self, text): + self.text = text + + def GetText(self): + return self.text + + def GetSubList(self): + return [HierListCLBRErrorItem(self.text)] + + def IsExpandable(self): + return 0 + + +class HierListCLBRErrorRoot(HierListCLBRErrorItem): + def IsExpandable(self): + return 1 + + +class BrowserView(pywin.mfc.docview.TreeView): + def OnInitialUpdate(self): + self.list = None + rc = self._obj_.OnInitialUpdate() + self.HookMessage(self.OnSize, win32con.WM_SIZE) + self.bDirty = 0 + self.destroying = 0 + return rc + + def DestroyBrowser(self): + self.DestroyList() + + def OnActivateView(self, activate, av, dv): + # print "AV", self.bDirty, activate + if activate: + self.CheckRefreshList() + return self._obj_.OnActivateView(activate, av, dv) + + def _MakeRoot(self): + path = self.GetDocument().GetPathName() + if not path: + return HierListCLBRErrorRoot( + "Error: Can not browse a file until it is saved" + ) + else: + mod, path = pywin.framework.scriptutils.GetPackageModuleName(path) + if self.bDirty: + what = "Refreshing" + # Hack for pyclbr being too smart + try: + del pyclbr._modules[mod] + except (KeyError, AttributeError): + pass + else: + what = "Building" + win32ui.SetStatusText("%s class list - please wait..." % (what,), 1) + win32ui.DoWaitCursor(1) + try: + reader = pyclbr.readmodule_ex # new version post 1.5.2 + except AttributeError: + reader = pyclbr.readmodule + try: + data = reader(mod, [path]) + if data: + return HierListCLBRModule(mod, data) + else: + return HierListCLBRErrorRoot("No Python classes in module.") + + finally: + win32ui.DoWaitCursor(0) + win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE)) + + def DestroyList(self): + self.destroying = 1 + list = getattr( + self, "list", None + ) # If the document was not successfully opened, we may not have a list. + self.list = None + if list is not None: + list.HierTerm() + self.destroying = 0 + + def CheckMadeList(self): + if self.list is not None or self.destroying: + return + self.rootitem = root = self._MakeRoot() + self.list = list = hierlist.HierListWithItems(root, win32ui.IDB_BROWSER_HIER) + list.HierInit(self.GetParentFrame(), self) + list.SetStyle( + commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS + ) + + def CheckRefreshList(self): + if self.bDirty: + if self.list is None: + self.CheckMadeList() + else: + new_root = self._MakeRoot() + if self.rootitem.__class__ == new_root.__class__ == HierListCLBRModule: + self.rootitem.modName = new_root.modName + self.rootitem.clbrdata = new_root.clbrdata + self.list.Refresh() + else: + self.list.AcceptRoot(self._MakeRoot()) + self.bDirty = 0 + + def OnSize(self, params): + lparam = params[3] + w = win32api.LOWORD(lparam) + h = win32api.HIWORD(lparam) + if w != 0: + self.CheckMadeList() + elif w == 0: + self.DestroyList() + return 1 + + def _UpdateUIForState(self): + self.bDirty = 1 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ce13ece65c1a776077acf0a9155baeb9f57ed0ff --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__init__.py @@ -0,0 +1,106 @@ +# __init__ for the Pythonwin editor package. +# +# We used to support optional editors - eg, color or non-color. +# +# This really isnt necessary with Scintilla, and scintilla +# is getting so deeply embedded that it was too much work. + +import sys + +import win32con +import win32ui + +defaultCharacterFormat = (-402653169, 0, 200, 0, 0, 0, 49, "Courier New") + +##def GetDefaultEditorModuleName(): +## import pywin +## # If someone has set pywin.editormodulename, then this is what we use +## try: +## prefModule = pywin.editormodulename +## except AttributeError: +## prefModule = win32ui.GetProfileVal("Editor","Module", "") +## return prefModule +## +##def WriteDefaultEditorModule(module): +## try: +## module = module.__name__ +## except: +## pass +## win32ui.WriteProfileVal("Editor", "Module", module) + + +def LoadDefaultEditor(): + pass + + +## prefModule = GetDefaultEditorModuleName() +## restorePrefModule = None +## mod = None +## if prefModule: +## try: +## mod = __import__(prefModule) +## except 'xx': +## msg = "Importing your preferred editor ('%s') failed.\n\nError %s: %s\n\nAn attempt will be made to load the default editor.\n\nWould you like this editor disabled in the future?" % (prefModule, sys.exc_info()[0], sys.exc_info()[1]) +## rc = win32ui.MessageBox(msg, "Error importing editor", win32con.MB_YESNO) +## if rc == win32con.IDNO: +## restorePrefModule = prefModule +## WriteDefaultEditorModule("") +## del rc +## +## try: +## # Try and load the default one - dont catch errors here. +## if mod is None: +## prefModule = "pywin.framework.editor.color.coloreditor" +## mod = __import__(prefModule) +## +## # Get at the real module. +## mod = sys.modules[prefModule] +## +## # Do a "from mod import *" +## globals().update(mod.__dict__) +## +## finally: +## # Restore the users default editor if it failed and they requested not to disable it. +## if restorePrefModule: +## WriteDefaultEditorModule(restorePrefModule) + + +def GetEditorOption(option, defaultValue, min=None, max=None): + rc = win32ui.GetProfileVal("Editor", option, defaultValue) + if min is not None and rc < min: + rc = defaultValue + if max is not None and rc > max: + rc = defaultValue + return rc + + +def SetEditorOption(option, newValue): + win32ui.WriteProfileVal("Editor", option, newValue) + + +def DeleteEditorOption(option): + try: + win32ui.WriteProfileVal("Editor", option, None) + except win32ui.error: + pass + + +# Load and save font tuples +def GetEditorFontOption(option, default=None): + if default is None: + default = defaultCharacterFormat + fmt = GetEditorOption(option, "") + if fmt == "": + return default + try: + return eval(fmt) + except: + print("WARNING: Invalid font setting in registry - setting ignored") + return default + + +def SetEditorFontOption(option, newValue): + SetEditorOption(option, str(newValue)) + + +from pywin.framework.editor.color.coloreditor import editorTemplate diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/ModuleBrowser.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/ModuleBrowser.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6655cf02ceed68a46896635406d9a9d82569558 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/ModuleBrowser.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..398587b8317cccca0ef54dcead19ee8451e39ed3 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/configui.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/configui.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1ab0a0a758119711f4aef233f63f801850c9133 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/configui.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/document.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/document.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94efa8b0570fe620a905c05c02009da47b6c1f43 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/document.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/editor.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/editor.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..382a757a02bdd4e82923b399770d7fa9ca474215 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/editor.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/frame.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/frame.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d34803f2321e3c56ca6d5251b4d3283c8fab1d49 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/frame.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/template.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/template.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b0be09a92453a6863fc1d2c14531c2a84875aad Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/template.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/vss.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/vss.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b57215da14f63f0a0eb257348bd3e81866515780 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/__pycache__/vss.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bfd7cc7a5f32904cc6f98044a9a8e93657e7c61 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__pycache__/coloreditor.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__pycache__/coloreditor.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..805613fca1fa21d628ae915f8f46ae41cbcdcc2a Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/__pycache__/coloreditor.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/coloreditor.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/coloreditor.py new file mode 100644 index 0000000000000000000000000000000000000000..4aacc0eab5b0fbc770d69a29b8c1b601cf30441b --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/color/coloreditor.py @@ -0,0 +1,664 @@ +# Color Editor originally by Neil Hodgson, but restructured by mh to integrate +# even tighter into Pythonwin. + +import pywin.scintilla.keycodes +import win32api +import win32con +import win32ui +from pywin.framework.editor import ( + GetEditorFontOption, + GetEditorOption, + SetEditorFontOption, + SetEditorOption, + defaultCharacterFormat, +) +from pywin.scintilla import bindings + +# from pywin.framework.editor import EditorPropertyPage + +MSG_CHECK_EXTERNAL_FILE = ( + win32con.WM_USER + 1999 +) ## WARNING: Duplicated in document.py and editor.py + +# Define a few common markers +MARKER_BOOKMARK = 0 +MARKER_BREAKPOINT = 1 +MARKER_CURRENT = 2 + +import pywin.scintilla.view +from pywin.debugger import dbgcon +from pywin.framework.editor.document import EditorDocumentBase +from pywin.scintilla import scintillacon # For the marker definitions +from pywin.scintilla.document import CScintillaDocument + + +class SyntEditDocument(EditorDocumentBase): + "A SyntEdit document." + + def OnDebuggerStateChange(self, state): + self._ApplyOptionalToViews("OnDebuggerStateChange", state) + + def HookViewNotifications(self, view): + EditorDocumentBase.HookViewNotifications(self, view) + view.SCISetUndoCollection(1) + + def FinalizeViewCreation(self, view): + EditorDocumentBase.FinalizeViewCreation(self, view) + if view == self.GetFirstView(): + self.GetDocTemplate().CheckIDLEMenus(view.idle) + + +SyntEditViewParent = pywin.scintilla.view.CScintillaView + + +class SyntEditView(SyntEditViewParent): + "A view of a SyntEdit. Obtains data from document." + + def __init__(self, doc): + SyntEditViewParent.__init__(self, doc) + self.bCheckingFile = 0 + + def OnInitialUpdate(self): + SyntEditViewParent.OnInitialUpdate(self) + + self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN) + + for id in ( + win32ui.ID_VIEW_FOLD_COLLAPSE, + win32ui.ID_VIEW_FOLD_COLLAPSE_ALL, + win32ui.ID_VIEW_FOLD_EXPAND, + win32ui.ID_VIEW_FOLD_EXPAND_ALL, + ): + self.HookCommand(self.OnCmdViewFold, id) + self.HookCommandUpdate(self.OnUpdateViewFold, id) + self.HookCommand(self.OnCmdViewFoldTopLevel, win32ui.ID_VIEW_FOLD_TOPLEVEL) + + # Define the markers + # self.SCIMarkerDeleteAll() + self.SCIMarkerDefineAll( + MARKER_BOOKMARK, + scintillacon.SC_MARK_ROUNDRECT, + win32api.RGB(0x0, 0x0, 0x0), + win32api.RGB(0, 0xFF, 0xFF), + ) + + self.SCIMarkerDefine(MARKER_CURRENT, scintillacon.SC_MARK_ARROW) + self.SCIMarkerSetBack(MARKER_CURRENT, win32api.RGB(0xFF, 0xFF, 0x00)) + + # Define the folding markers + if 1: # traditional markers + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDEROPEN, + scintillacon.SC_MARK_MINUS, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDER, + scintillacon.SC_MARK_PLUS, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDERSUB, + scintillacon.SC_MARK_EMPTY, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDERTAIL, + scintillacon.SC_MARK_EMPTY, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDEREND, + scintillacon.SC_MARK_EMPTY, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDEROPENMID, + scintillacon.SC_MARK_EMPTY, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDERMIDTAIL, + scintillacon.SC_MARK_EMPTY, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + else: # curved markers + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDEROPEN, + scintillacon.SC_MARK_CIRCLEMINUS, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDER, + scintillacon.SC_MARK_CIRCLEPLUS, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDERSUB, + scintillacon.SC_MARK_VLINE, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDERTAIL, + scintillacon.SC_MARK_LCORNERCURVE, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDEREND, + scintillacon.SC_MARK_CIRCLEPLUSCONNECTED, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDEROPENMID, + scintillacon.SC_MARK_CIRCLEMINUSCONNECTED, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + self.SCIMarkerDefineAll( + scintillacon.SC_MARKNUM_FOLDERMIDTAIL, + scintillacon.SC_MARK_TCORNERCURVE, + win32api.RGB(0xFF, 0xFF, 0xFF), + win32api.RGB(0, 0, 0), + ) + + self.SCIMarkerDefine(MARKER_BREAKPOINT, scintillacon.SC_MARK_CIRCLE) + # Marker background depends on debugger state + self.SCIMarkerSetFore(MARKER_BREAKPOINT, win32api.RGB(0x0, 0, 0)) + # Get the current debugger state. + try: + import pywin.debugger + + if pywin.debugger.currentDebugger is None: + state = dbgcon.DBGSTATE_NOT_DEBUGGING + else: + state = pywin.debugger.currentDebugger.debuggerState + except ImportError: + state = dbgcon.DBGSTATE_NOT_DEBUGGING + self.OnDebuggerStateChange(state) + + def _GetSubConfigNames(self): + return ["editor"] # Allow [Keys:Editor] sections to be specific to us + + def DoConfigChange(self): + SyntEditViewParent.DoConfigChange(self) + tabSize = GetEditorOption("Tab Size", 4, 2) + indentSize = GetEditorOption("Indent Size", 4, 2) + bUseTabs = GetEditorOption("Use Tabs", 0) + bSmartTabs = GetEditorOption("Smart Tabs", 1) + ext = self.idle.IDLEExtension("AutoIndent") # Required extension. + + self.SCISetViewWS(GetEditorOption("View Whitespace", 0)) + self.SCISetViewEOL(GetEditorOption("View EOL", 0)) + self.SCISetIndentationGuides(GetEditorOption("View Indentation Guides", 0)) + + if GetEditorOption("Right Edge Enabled", 0): + mode = scintillacon.EDGE_BACKGROUND + else: + mode = scintillacon.EDGE_NONE + self.SCISetEdgeMode(mode) + self.SCISetEdgeColumn(GetEditorOption("Right Edge Column", 75)) + self.SCISetEdgeColor( + GetEditorOption("Right Edge Color", win32api.RGB(0xEF, 0xEF, 0xEF)) + ) + + width = GetEditorOption("Marker Margin Width", 16) + self.SCISetMarginWidthN(1, width) + width = GetEditorOption("Fold Margin Width", 12) + self.SCISetMarginWidthN(2, width) + width = GetEditorOption("Line Number Margin Width", 0) + self.SCISetMarginWidthN(0, width) + self.bFolding = GetEditorOption("Enable Folding", 1) + fold_flags = 0 + self.SendScintilla( + scintillacon.SCI_SETMODEVENTMASK, scintillacon.SC_MOD_CHANGEFOLD + ) + if self.bFolding: + if GetEditorOption("Fold Lines", 1): + fold_flags = 16 + + self.SCISetProperty("fold", self.bFolding) + self.SCISetFoldFlags(fold_flags) + + tt_color = GetEditorOption("Tab Timmy Color", win32api.RGB(0xFF, 0, 0)) + self.SendScintilla(scintillacon.SCI_INDICSETFORE, 1, tt_color) + + tt_use = GetEditorOption("Use Tab Timmy", 1) + if tt_use: + self.SCISetProperty("tab.timmy.whinge.level", "1") + + # Auto-indent has very complicated behaviour. In a nutshell, the only + # way to get sensible behaviour from it is to ensure tabwidth != indentsize. + # Further, usetabs will only ever go from 1->0, never 0->1. + # This is _not_ the behaviour Pythonwin wants: + # * Tab width is arbitary, so should have no impact on smarts. + # * bUseTabs setting should reflect how new files are created, and + # if Smart Tabs disabled, existing files are edited + # * If "Smart Tabs" is enabled, bUseTabs should have no bearing + # for existing files (unless of course no context can be determined) + # + # So for smart tabs we configure the widget with completely dummy + # values (ensuring tabwidth != indentwidth), ask it to guess, then + # look at the values it has guessed, and re-configure + if bSmartTabs: + ext.config(usetabs=1, tabwidth=5, indentwidth=4) + ext.set_indentation_params(1) + if ext.indentwidth == 5: + # Either 5 literal spaces, or a single tab character. Assume a tab + usetabs = 1 + indentwidth = tabSize + else: + # Either Indented with spaces, and indent size has been guessed or + # an empty file (or no context found - tough!) + if self.GetTextLength() == 0: # emtpy + usetabs = bUseTabs + indentwidth = indentSize + else: # guessed. + indentwidth = ext.indentwidth + usetabs = 0 + # Tab size can never be guessed - set at user preference. + ext.config(usetabs=usetabs, indentwidth=indentwidth, tabwidth=tabSize) + else: + # Dont want smart-tabs - just set the options! + ext.config(usetabs=bUseTabs, tabwidth=tabSize, indentwidth=indentSize) + self.SCISetIndent(indentSize) + self.SCISetTabWidth(tabSize) + + def OnDebuggerStateChange(self, state): + if state == dbgcon.DBGSTATE_NOT_DEBUGGING: + # Indicate breakpoints arent really usable. + # Not quite white - useful when no marker margin, so set as background color. + self.SCIMarkerSetBack(MARKER_BREAKPOINT, win32api.RGB(0xEF, 0xEF, 0xEF)) + else: + # A light-red, so still readable when no marker margin. + self.SCIMarkerSetBack(MARKER_BREAKPOINT, win32api.RGB(0xFF, 0x80, 0x80)) + + def HookDocumentHandlers(self): + SyntEditViewParent.HookDocumentHandlers(self) + self.HookMessage(self.OnCheckExternalDocumentUpdated, MSG_CHECK_EXTERNAL_FILE) + + def HookHandlers(self): + SyntEditViewParent.HookHandlers(self) + self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS) + + def _PrepareUserStateChange(self): + return self.GetSel(), self.GetFirstVisibleLine() + + def _EndUserStateChange(self, info): + scrollOff = info[1] - self.GetFirstVisibleLine() + if scrollOff: + self.LineScroll(scrollOff) + # Make sure we dont reset the cursor beyond the buffer. + max = self.GetTextLength() + newPos = min(info[0][0], max), min(info[0][1], max) + self.SetSel(newPos) + + ####################################### + # The Windows Message or Notify handlers. + ####################################### + def OnMarginClick(self, std, extra): + notify = self.SCIUnpackNotifyMessage(extra) + if notify.margin == 2: # Our fold margin + line_click = self.LineFromChar(notify.position) + # max_line = self.GetLineCount() + if self.SCIGetFoldLevel(line_click) & scintillacon.SC_FOLDLEVELHEADERFLAG: + # If a fold point. + self.SCIToggleFold(line_click) + return 1 + + def OnSetFocus(self, msg): + # Even though we use file change notifications, we should be very sure about it here. + self.OnCheckExternalDocumentUpdated(msg) + return 1 + + def OnCheckExternalDocumentUpdated(self, msg): + if self.bCheckingFile: + return + self.bCheckingFile = 1 + self.GetDocument().CheckExternalDocumentUpdated() + self.bCheckingFile = 0 + + def OnRClick(self, params): + menu = win32ui.CreatePopupMenu() + self.AppendMenu(menu, "&Locate module", "LocateModule") + self.AppendMenu(menu, flags=win32con.MF_SEPARATOR) + self.AppendMenu(menu, "&Undo", "EditUndo") + self.AppendMenu(menu, "&Redo", "EditRedo") + self.AppendMenu(menu, flags=win32con.MF_SEPARATOR) + self.AppendMenu(menu, "Cu&t", "EditCut") + self.AppendMenu(menu, "&Copy", "EditCopy") + self.AppendMenu(menu, "&Paste", "EditPaste") + self.AppendMenu(menu, flags=win32con.MF_SEPARATOR) + self.AppendMenu(menu, "&Select all", "EditSelectAll") + self.AppendMenu( + menu, "View &Whitespace", "ViewWhitespace", checked=self.SCIGetViewWS() + ) + self.AppendMenu( + menu, "&Fixed Font", "ViewFixedFont", checked=self._GetColorizer().bUseFixed + ) + self.AppendMenu(menu, flags=win32con.MF_SEPARATOR) + self.AppendMenu(menu, "&Goto line...", "GotoLine") + + submenu = win32ui.CreatePopupMenu() + newitems = self.idle.GetMenuItems("edit") + for text, event in newitems: + self.AppendMenu(submenu, text, event) + + flags = win32con.MF_STRING | win32con.MF_ENABLED | win32con.MF_POPUP + menu.AppendMenu(flags, submenu.GetHandle(), "&Source code") + + flags = ( + win32con.TPM_LEFTALIGN | win32con.TPM_LEFTBUTTON | win32con.TPM_RIGHTBUTTON + ) + menu.TrackPopupMenu(params[5], flags, self) + return 0 + + def OnCmdViewFold(self, cid, code): # Handle the menu command + if cid == win32ui.ID_VIEW_FOLD_EXPAND_ALL: + self.FoldExpandAllEvent(None) + elif cid == win32ui.ID_VIEW_FOLD_EXPAND: + self.FoldExpandEvent(None) + elif cid == win32ui.ID_VIEW_FOLD_COLLAPSE_ALL: + self.FoldCollapseAllEvent(None) + elif cid == win32ui.ID_VIEW_FOLD_COLLAPSE: + self.FoldCollapseEvent(None) + else: + print("Unknown collapse/expand ID") + + def OnUpdateViewFold(self, cmdui): # Update the tick on the UI. + if not self.bFolding: + cmdui.Enable(0) + return + id = cmdui.m_nID + if id in (win32ui.ID_VIEW_FOLD_EXPAND_ALL, win32ui.ID_VIEW_FOLD_COLLAPSE_ALL): + cmdui.Enable() + else: + enable = 0 + lineno = self.LineFromChar(self.GetSel()[0]) + foldable = ( + self.SCIGetFoldLevel(lineno) & scintillacon.SC_FOLDLEVELHEADERFLAG + ) + is_expanded = self.SCIGetFoldExpanded(lineno) + if id == win32ui.ID_VIEW_FOLD_EXPAND: + if foldable and not is_expanded: + enable = 1 + elif id == win32ui.ID_VIEW_FOLD_COLLAPSE: + if foldable and is_expanded: + enable = 1 + cmdui.Enable(enable) + + def OnCmdViewFoldTopLevel(self, cid, code): # Handle the menu command + self.FoldTopLevelEvent(None) + + ####################################### + # The Events + ####################################### + def ToggleBookmarkEvent(self, event, pos=-1): + """Toggle a bookmark at the specified or current position""" + if pos == -1: + pos, end = self.GetSel() + startLine = self.LineFromChar(pos) + self.GetDocument().MarkerToggle(startLine + 1, MARKER_BOOKMARK) + return 0 + + def GotoNextBookmarkEvent(self, event, fromPos=-1): + """Move to the next bookmark""" + if fromPos == -1: + fromPos, end = self.GetSel() + startLine = self.LineFromChar(fromPos) + 1 # Zero based line to start + nextLine = self.GetDocument().MarkerGetNext(startLine + 1, MARKER_BOOKMARK) - 1 + if nextLine < 0: + nextLine = self.GetDocument().MarkerGetNext(0, MARKER_BOOKMARK) - 1 + if nextLine < 0 or nextLine == startLine - 1: + win32api.MessageBeep() + else: + self.SCIEnsureVisible(nextLine) + self.SCIGotoLine(nextLine) + return 0 + + def TabKeyEvent(self, event): + """Insert an indent. If no selection, a single indent, otherwise a block indent""" + # Handle auto-complete first. + if self.SCIAutoCActive(): + self.SCIAutoCComplete() + return 0 + # Call the IDLE event. + return self.bindings.fire("<>", event) + + def EnterKeyEvent(self, event): + """Handle the enter key with special handling for auto-complete""" + # Handle auto-complete first. + if self.SCIAutoCActive(): + self.SCIAutoCComplete() + self.SCIAutoCCancel() + # Call the IDLE event. + return self.bindings.fire("<>", event) + + def ShowInteractiveWindowEvent(self, event): + import pywin.framework.interact + + pywin.framework.interact.ShowInteractiveWindow() + + def FoldTopLevelEvent(self, event=None): + if not self.bFolding: + return 1 + + win32ui.DoWaitCursor(1) + try: + self.Colorize() + maxLine = self.GetLineCount() + # Find the first line, and check out its state. + for lineSeek in range(maxLine): + if self.SCIGetFoldLevel(lineSeek) & scintillacon.SC_FOLDLEVELHEADERFLAG: + expanding = not self.SCIGetFoldExpanded(lineSeek) + break + else: + # no folds here! + return + for lineSeek in range(lineSeek, maxLine): + level = self.SCIGetFoldLevel(lineSeek) + level_no = ( + level + & scintillacon.SC_FOLDLEVELNUMBERMASK + - scintillacon.SC_FOLDLEVELBASE + ) + is_header = level & scintillacon.SC_FOLDLEVELHEADERFLAG + # print lineSeek, level_no, is_header + if level_no == 0 and is_header: + if (expanding and not self.SCIGetFoldExpanded(lineSeek)) or ( + not expanding and self.SCIGetFoldExpanded(lineSeek) + ): + self.SCIToggleFold(lineSeek) + finally: + win32ui.DoWaitCursor(-1) + + def FoldExpandSecondLevelEvent(self, event): + if not self.bFolding: + return 1 + win32ui.DoWaitCursor(1) + ## I think this is needed since Scintilla may not have + ## already formatted parts of file outside visible window. + self.Colorize() + levels = [scintillacon.SC_FOLDLEVELBASE] + ## Scintilla's level number is based on amount of whitespace indentation + for lineno in range(self.GetLineCount()): + level = self.SCIGetFoldLevel(lineno) + if not level & scintillacon.SC_FOLDLEVELHEADERFLAG: + continue + curr_level = level & scintillacon.SC_FOLDLEVELNUMBERMASK + if curr_level > levels[-1]: + levels.append(curr_level) + try: + level_ind = levels.index(curr_level) + except ValueError: + ## probably syntax error in source file, bail + break + levels = levels[: level_ind + 1] + if level_ind == 1 and not self.SCIGetFoldExpanded(lineno): + self.SCIToggleFold(lineno) + win32ui.DoWaitCursor(-1) + + def FoldCollapseSecondLevelEvent(self, event): + if not self.bFolding: + return 1 + win32ui.DoWaitCursor(1) + ## I think this is needed since Scintilla may not have + ## already formatted parts of file outside visible window. + self.Colorize() + levels = [scintillacon.SC_FOLDLEVELBASE] + ## Scintilla's level number is based on amount of whitespace indentation + for lineno in range(self.GetLineCount()): + level = self.SCIGetFoldLevel(lineno) + if not level & scintillacon.SC_FOLDLEVELHEADERFLAG: + continue + curr_level = level & scintillacon.SC_FOLDLEVELNUMBERMASK + if curr_level > levels[-1]: + levels.append(curr_level) + try: + level_ind = levels.index(curr_level) + except ValueError: + ## probably syntax error in source file, bail + break + levels = levels[: level_ind + 1] + if level_ind == 1 and self.SCIGetFoldExpanded(lineno): + self.SCIToggleFold(lineno) + win32ui.DoWaitCursor(-1) + + def FoldExpandEvent(self, event): + if not self.bFolding: + return 1 + win32ui.DoWaitCursor(1) + lineno = self.LineFromChar(self.GetSel()[0]) + if self.SCIGetFoldLevel( + lineno + ) & scintillacon.SC_FOLDLEVELHEADERFLAG and not self.SCIGetFoldExpanded(lineno): + self.SCIToggleFold(lineno) + win32ui.DoWaitCursor(-1) + + def FoldExpandAllEvent(self, event): + if not self.bFolding: + return 1 + win32ui.DoWaitCursor(1) + for lineno in range(0, self.GetLineCount()): + if self.SCIGetFoldLevel( + lineno + ) & scintillacon.SC_FOLDLEVELHEADERFLAG and not self.SCIGetFoldExpanded( + lineno + ): + self.SCIToggleFold(lineno) + win32ui.DoWaitCursor(-1) + + def FoldCollapseEvent(self, event): + if not self.bFolding: + return 1 + win32ui.DoWaitCursor(1) + lineno = self.LineFromChar(self.GetSel()[0]) + if self.SCIGetFoldLevel( + lineno + ) & scintillacon.SC_FOLDLEVELHEADERFLAG and self.SCIGetFoldExpanded(lineno): + self.SCIToggleFold(lineno) + win32ui.DoWaitCursor(-1) + + def FoldCollapseAllEvent(self, event): + if not self.bFolding: + return 1 + win32ui.DoWaitCursor(1) + self.Colorize() + for lineno in range(0, self.GetLineCount()): + if self.SCIGetFoldLevel( + lineno + ) & scintillacon.SC_FOLDLEVELHEADERFLAG and self.SCIGetFoldExpanded(lineno): + self.SCIToggleFold(lineno) + win32ui.DoWaitCursor(-1) + + +from pywin.framework.editor.frame import EditorFrame + + +class SplitterFrame(EditorFrame): + def OnCreate(self, cs): + self.HookCommand(self.OnWindowSplit, win32ui.ID_WINDOW_SPLIT) + return 1 + + def OnWindowSplit(self, id, code): + self.GetDlgItem(win32ui.AFX_IDW_PANE_FIRST).DoKeyboardSplit() + return 1 + + +from pywin.framework.editor.template import EditorTemplateBase + + +class SyntEditTemplate(EditorTemplateBase): + def __init__( + self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None + ): + if makeDoc is None: + makeDoc = SyntEditDocument + if makeView is None: + makeView = SyntEditView + if makeFrame is None: + makeFrame = SplitterFrame + self.bSetMenus = 0 + EditorTemplateBase.__init__(self, res, makeDoc, makeFrame, makeView) + + def CheckIDLEMenus(self, idle): + if self.bSetMenus: + return + self.bSetMenus = 1 + + submenu = win32ui.CreatePopupMenu() + newitems = idle.GetMenuItems("edit") + flags = win32con.MF_STRING | win32con.MF_ENABLED + for text, event in newitems: + id = bindings.event_to_commands.get(event) + if id is not None: + keyname = pywin.scintilla.view.configManager.get_key_binding( + event, ["editor"] + ) + if keyname is not None: + text = text + "\t" + keyname + submenu.AppendMenu(flags, id, text) + + mainMenu = self.GetSharedMenu() + editMenu = mainMenu.GetSubMenu(1) + editMenu.AppendMenu(win32con.MF_SEPARATOR, 0, "") + editMenu.AppendMenu( + win32con.MF_STRING | win32con.MF_POPUP | win32con.MF_ENABLED, + submenu.GetHandle(), + "&Source Code", + ) + + def _CreateDocTemplate(self, resourceId): + return win32ui.CreateDocTemplate(resourceId) + + def CreateWin32uiDocument(self): + return self.DoCreateDoc() + + def GetPythonPropertyPages(self): + """Returns a list of property pages""" + from pywin.scintilla import configui + + return EditorTemplateBase.GetPythonPropertyPages(self) + [ + configui.ScintillaFormatPropertyPage() + ] + + +# For debugging purposes, when this module may be reloaded many times. +try: + win32ui.GetApp().RemoveDocTemplate(editorTemplate) +except NameError: + pass + +editorTemplate = SyntEditTemplate() +win32ui.GetApp().AddDocTemplate(editorTemplate) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/configui.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/configui.py new file mode 100644 index 0000000000000000000000000000000000000000..903ad66c749e82452c43b98c88abc62616cfb2e2 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/configui.py @@ -0,0 +1,308 @@ +import pywin.scintilla.config +import win32api +import win32con +import win32ui +from pywin.framework.editor import ( + DeleteEditorOption, + GetEditorFontOption, + GetEditorOption, + SetEditorFontOption, + SetEditorOption, + defaultCharacterFormat, + editorTemplate, +) +from pywin.mfc import dialog + +from . import document + +# The standard 16 color VGA palette should always be possible +paletteVGA = ( + ("Black", 0, 0, 0), + ("Navy", 0, 0, 128), + ("Green", 0, 128, 0), + ("Cyan", 0, 128, 128), + ("Maroon", 128, 0, 0), + ("Purple", 128, 0, 128), + ("Olive", 128, 128, 0), + ("Gray", 128, 128, 128), + ("Silver", 192, 192, 192), + ("Blue", 0, 0, 255), + ("Lime", 0, 255, 0), + ("Aqua", 0, 255, 255), + ("Red", 255, 0, 0), + ("Fuchsia", 255, 0, 255), + ("Yellow", 255, 255, 0), + ("White", 255, 255, 255), +) + + +###################################################### +# +# Property Page for editor options +# +class EditorPropertyPage(dialog.PropertyPage): + def __init__(self): + dialog.PropertyPage.__init__(self, win32ui.IDD_PP_EDITOR) + self.autooptions = [] + self._AddEditorOption(win32ui.IDC_AUTO_RELOAD, "i", "Auto Reload", 1) + self._AddEditorOption( + win32ui.IDC_COMBO1, "i", "Backup Type", document.BAK_DOT_BAK_BAK_DIR + ) + self._AddEditorOption( + win32ui.IDC_AUTOCOMPLETE, "i", "Autocomplete Attributes", 1 + ) + self._AddEditorOption(win32ui.IDC_CALLTIPS, "i", "Show Call Tips", 1) + self._AddEditorOption( + win32ui.IDC_MARGIN_LINENUMBER, "i", "Line Number Margin Width", 0 + ) + self._AddEditorOption(win32ui.IDC_RADIO1, "i", "MarkersInMargin", None) + self._AddEditorOption( + win32ui.IDC_MARGIN_MARKER, "i", "Marker Margin Width", None + ) + self["Marker Margin Width"] = GetEditorOption("Marker Margin Width", 16) + + # Folding + self._AddEditorOption(win32ui.IDC_MARGIN_FOLD, "i", "Fold Margin Width", 12) + self._AddEditorOption(win32ui.IDC_FOLD_ENABLE, "i", "Enable Folding", 1) + self._AddEditorOption(win32ui.IDC_FOLD_ON_OPEN, "i", "Fold On Open", 0) + self._AddEditorOption(win32ui.IDC_FOLD_SHOW_LINES, "i", "Fold Lines", 1) + + # Right edge. + self._AddEditorOption( + win32ui.IDC_RIGHTEDGE_ENABLE, "i", "Right Edge Enabled", 0 + ) + self._AddEditorOption( + win32ui.IDC_RIGHTEDGE_COLUMN, "i", "Right Edge Column", 75 + ) + + # Source control, etc + self.AddDDX(win32ui.IDC_VSS_INTEGRATE, "bVSS") + self.AddDDX(win32ui.IDC_KEYBOARD_CONFIG, "Configs", "l") + self["Configs"] = pywin.scintilla.config.find_config_files() + + def _AddEditorOption(self, idd, typ, optionName, defaultVal): + self.AddDDX(idd, optionName, typ) + # some options are "derived" - ie, can be implied from others + # (eg, "view markers in background" is implied from "markerMarginWidth==0" + # So we don't actually store these values, but they do still get DDX support. + if defaultVal is not None: + self[optionName] = GetEditorOption(optionName, defaultVal) + self.autooptions.append((optionName, defaultVal)) + + def OnInitDialog(self): + for name, val in self.autooptions: + self[name] = GetEditorOption(name, val) + + # Note that these MUST be in the same order as the BAK constants. + cbo = self.GetDlgItem(win32ui.IDC_COMBO1) + cbo.AddString("None") + cbo.AddString(".BAK File") + cbo.AddString("TEMP dir") + cbo.AddString("Own dir") + + # Source Safe + bVSS = ( + GetEditorOption("Source Control Module", "") == "pywin.framework.editor.vss" + ) + self["bVSS"] = bVSS + + edit = self.GetDlgItem(win32ui.IDC_RIGHTEDGE_SAMPLE) + edit.SetWindowText("Sample Color") + + rc = dialog.PropertyPage.OnInitDialog(self) + + try: + self.GetDlgItem(win32ui.IDC_KEYBOARD_CONFIG).SelectString( + -1, GetEditorOption("Keyboard Config", "default") + ) + except win32ui.error: + import traceback + + traceback.print_exc() + pass + + self.HookCommand(self.OnButSimple, win32ui.IDC_FOLD_ENABLE) + self.HookCommand(self.OnButSimple, win32ui.IDC_RADIO1) + self.HookCommand(self.OnButSimple, win32ui.IDC_RADIO2) + self.HookCommand(self.OnButSimple, win32ui.IDC_RIGHTEDGE_ENABLE) + self.HookCommand(self.OnButEdgeColor, win32ui.IDC_RIGHTEDGE_DEFINE) + + butMarginEnabled = self["Marker Margin Width"] > 0 + self.GetDlgItem(win32ui.IDC_RADIO1).SetCheck(butMarginEnabled) + self.GetDlgItem(win32ui.IDC_RADIO2).SetCheck(not butMarginEnabled) + + self.edgeColor = self.initialEdgeColor = GetEditorOption( + "Right Edge Color", win32api.RGB(0xEF, 0xEF, 0xEF) + ) + for spinner_id in (win32ui.IDC_SPIN1, win32ui.IDC_SPIN2, win32ui.IDC_SPIN3): + spinner = self.GetDlgItem(spinner_id) + spinner.SetRange(0, 100) + self.UpdateUIForState() + + return rc + + def OnButSimple(self, id, code): + if code == win32con.BN_CLICKED: + self.UpdateUIForState() + + def OnButEdgeColor(self, id, code): + if code == win32con.BN_CLICKED: + d = win32ui.CreateColorDialog(self.edgeColor, 0, self) + # Ensure the current color is a custom color (as it may not be in the swatch) + # plus some other nice gray scales. + ccs = [self.edgeColor] + for c in range(0xEF, 0x4F, -0x10): + ccs.append(win32api.RGB(c, c, c)) + d.SetCustomColors(ccs) + if d.DoModal() == win32con.IDOK: + self.edgeColor = d.GetColor() + self.UpdateUIForState() + + def UpdateUIForState(self): + folding = self.GetDlgItem(win32ui.IDC_FOLD_ENABLE).GetCheck() + self.GetDlgItem(win32ui.IDC_FOLD_ON_OPEN).EnableWindow(folding) + self.GetDlgItem(win32ui.IDC_FOLD_SHOW_LINES).EnableWindow(folding) + + widthEnabled = self.GetDlgItem(win32ui.IDC_RADIO1).GetCheck() + self.GetDlgItem(win32ui.IDC_MARGIN_MARKER).EnableWindow(widthEnabled) + self.UpdateData() # Ensure self[] is up to date with the control data. + if widthEnabled and self["Marker Margin Width"] == 0: + self["Marker Margin Width"] = 16 + self.UpdateData(0) # Ensure control up to date with self[] + + # Right edge + edgeEnabled = self.GetDlgItem(win32ui.IDC_RIGHTEDGE_ENABLE).GetCheck() + self.GetDlgItem(win32ui.IDC_RIGHTEDGE_COLUMN).EnableWindow(edgeEnabled) + self.GetDlgItem(win32ui.IDC_RIGHTEDGE_SAMPLE).EnableWindow(edgeEnabled) + self.GetDlgItem(win32ui.IDC_RIGHTEDGE_DEFINE).EnableWindow(edgeEnabled) + + edit = self.GetDlgItem(win32ui.IDC_RIGHTEDGE_SAMPLE) + edit.SetBackgroundColor(0, self.edgeColor) + + def OnOK(self): + for name, defVal in self.autooptions: + SetEditorOption(name, self[name]) + # Margin width gets handled differently. + if self["MarkersInMargin"] == 0: + SetEditorOption("Marker Margin Width", self["Marker Margin Width"]) + else: + SetEditorOption("Marker Margin Width", 0) + if self.edgeColor != self.initialEdgeColor: + SetEditorOption("Right Edge Color", self.edgeColor) + if self["bVSS"]: + SetEditorOption("Source Control Module", "pywin.framework.editor.vss") + else: + if ( + GetEditorOption("Source Control Module", "") + == "pywin.framework.editor.vss" + ): + SetEditorOption("Source Control Module", "") + # Keyboard config + configname = self.GetDlgItem(win32ui.IDC_KEYBOARD_CONFIG).GetWindowText() + if configname: + if configname == "default": + DeleteEditorOption("Keyboard Config") + else: + SetEditorOption("Keyboard Config", configname) + + import pywin.scintilla.view + + pywin.scintilla.view.LoadConfiguration() + + # Now tell all views we have changed. + ## for doc in editorTemplate.GetDocumentList(): + ## for view in doc.GetAllViews(): + ## try: + ## fn = view.OnConfigChange + ## except AttributeError: + ## continue + ## fn() + return 1 + + +class EditorWhitespacePropertyPage(dialog.PropertyPage): + def __init__(self): + dialog.PropertyPage.__init__(self, win32ui.IDD_PP_TABS) + self.autooptions = [] + self._AddEditorOption(win32ui.IDC_TAB_SIZE, "i", "Tab Size", 4) + self._AddEditorOption(win32ui.IDC_INDENT_SIZE, "i", "Indent Size", 4) + self._AddEditorOption(win32ui.IDC_USE_SMART_TABS, "i", "Smart Tabs", 1) + self._AddEditorOption(win32ui.IDC_VIEW_WHITESPACE, "i", "View Whitespace", 0) + self._AddEditorOption(win32ui.IDC_VIEW_EOL, "i", "View EOL", 0) + self._AddEditorOption( + win32ui.IDC_VIEW_INDENTATIONGUIDES, "i", "View Indentation Guides", 0 + ) + + def _AddEditorOption(self, idd, typ, optionName, defaultVal): + self.AddDDX(idd, optionName, typ) + self[optionName] = GetEditorOption(optionName, defaultVal) + self.autooptions.append((optionName, defaultVal)) + + def OnInitDialog(self): + for name, val in self.autooptions: + self[name] = GetEditorOption(name, val) + + rc = dialog.PropertyPage.OnInitDialog(self) + + idc = win32ui.IDC_TABTIMMY_NONE + if GetEditorOption("Use Tab Timmy", 1): + idc = win32ui.IDC_TABTIMMY_IND + self.GetDlgItem(idc).SetCheck(1) + + idc = win32ui.IDC_RADIO1 + if GetEditorOption("Use Tabs", 0): + idc = win32ui.IDC_USE_TABS + self.GetDlgItem(idc).SetCheck(1) + + tt_color = GetEditorOption("Tab Timmy Color", win32api.RGB(0xFF, 0, 0)) + self.cbo = self.GetDlgItem(win32ui.IDC_COMBO1) + for c in paletteVGA: + self.cbo.AddString(c[0]) + sel = 0 + for c in paletteVGA: + if tt_color == win32api.RGB(c[1], c[2], c[3]): + break + sel = sel + 1 + else: + sel = -1 + self.cbo.SetCurSel(sel) + self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_NONE) + self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_IND) + self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_BG) + # Set ranges for the spinners. + for spinner_id in [win32ui.IDC_SPIN1, win32ui.IDC_SPIN2]: + spinner = self.GetDlgItem(spinner_id) + spinner.SetRange(1, 16) + return rc + + def OnButSimple(self, id, code): + if code == win32con.BN_CLICKED: + self.UpdateUIForState() + + def UpdateUIForState(self): + timmy = self.GetDlgItem(win32ui.IDC_TABTIMMY_NONE).GetCheck() + self.GetDlgItem(win32ui.IDC_COMBO1).EnableWindow(not timmy) + + def OnOK(self): + for name, defVal in self.autooptions: + SetEditorOption(name, self[name]) + + SetEditorOption("Use Tabs", self.GetDlgItem(win32ui.IDC_USE_TABS).GetCheck()) + + SetEditorOption( + "Use Tab Timmy", self.GetDlgItem(win32ui.IDC_TABTIMMY_IND).GetCheck() + ) + c = paletteVGA[self.cbo.GetCurSel()] + SetEditorOption("Tab Timmy Color", win32api.RGB(c[1], c[2], c[3])) + + return 1 + + +def testpp(): + ps = dialog.PropertySheet("Editor Options") + ps.AddPage(EditorWhitespacePropertyPage()) + ps.DoModal() + + +if __name__ == "__main__": + testpp() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/document.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/document.py new file mode 100644 index 0000000000000000000000000000000000000000..e66947b81cc8dd52ee6bbdda4d5ae63d5c13fe45 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/document.py @@ -0,0 +1,378 @@ +# We no longer support the old, non-colour editor! + +import os +import shutil +import traceback + +import win32api +import win32con +import win32ui +from pywin.framework.editor import GetEditorOption +from pywin.mfc import docview, object + +BAK_NONE = 0 +BAK_DOT_BAK = 1 +BAK_DOT_BAK_TEMP_DIR = 2 +BAK_DOT_BAK_BAK_DIR = 3 + +MSG_CHECK_EXTERNAL_FILE = ( + win32con.WM_USER + 1999 +) ## WARNING: Duplicated in editor.py and coloreditor.py + +import pywin.scintilla.document + +ParentEditorDocument = pywin.scintilla.document.CScintillaDocument + + +class EditorDocumentBase(ParentEditorDocument): + def __init__(self, template): + self.bAutoReload = GetEditorOption("Auto Reload", 1) + self.bDeclinedReload = 0 # Has the user declined to reload. + self.fileStat = None + self.bReportedFileNotFound = 0 + + # what sort of bak file should I create. + # default to write to %temp%/bak/filename.ext + self.bakFileType = GetEditorOption("Backup Type", BAK_DOT_BAK_BAK_DIR) + + self.watcherThread = FileWatchingThread(self) + self.watcherThread.CreateThread() + # Should I try and use VSS integration? + self.scModuleName = GetEditorOption("Source Control Module", "") + self.scModule = None # Loaded when first used. + ParentEditorDocument.__init__(self, template, template.CreateWin32uiDocument()) + + def OnCloseDocument(self): + self.watcherThread.SignalStop() + return self._obj_.OnCloseDocument() + + # def OnOpenDocument(self, name): + # rc = ParentEditorDocument.OnOpenDocument(self, name) + # self.GetFirstView()._SetLoadedText(self.text) + # self._DocumentStateChanged() + # return rc + + def OnSaveDocument(self, fileName): + win32ui.SetStatusText("Saving file...", 1) + # rename to bak if required. + dir, basename = os.path.split(fileName) + if self.bakFileType == BAK_DOT_BAK: + bakFileName = dir + "\\" + os.path.splitext(basename)[0] + ".bak" + elif self.bakFileType == BAK_DOT_BAK_TEMP_DIR: + bakFileName = ( + win32api.GetTempPath() + "\\" + os.path.splitext(basename)[0] + ".bak" + ) + elif self.bakFileType == BAK_DOT_BAK_BAK_DIR: + tempPath = os.path.join(win32api.GetTempPath(), "bak") + try: + os.mkdir(tempPath, 0) + except os.error: + pass + bakFileName = os.path.join(tempPath, basename) + try: + os.unlink(bakFileName) # raise NameError if no bakups wanted. + except (os.error, NameError): + pass + try: + # Do a copy as it might be on different volumes, + # and the file may be a hard-link, causing the link + # to follow the backup. + shutil.copy2(fileName, bakFileName) + except (os.error, NameError, IOError): + pass + try: + self.SaveFile(fileName) + except IOError as details: + win32ui.MessageBox("Error - could not save file\r\n\r\n%s" % details) + return 0 + except (UnicodeEncodeError, LookupError) as details: + rc = win32ui.MessageBox( + "Encoding failed: \r\n%s" % details + + "\r\nPlease add desired source encoding as first line of file, eg \r\n" + + "# -*- coding: mbcs -*-\r\n\r\n" + + "If you continue, the file will be saved as binary and will\r\n" + + "not be valid in the declared encoding.\r\n\r\n" + + "Save the file as binary with an invalid encoding?", + "File save failed", + win32con.MB_YESNO | win32con.MB_DEFBUTTON2, + ) + if rc == win32con.IDYES: + try: + self.SaveFile(fileName, encoding="latin-1") + except IOError as details: + win32ui.MessageBox( + "Error - could not save file\r\n\r\n%s" % details + ) + return 0 + else: + return 0 + self.SetModifiedFlag(0) # No longer dirty + self.bDeclinedReload = 0 # They probably want to know if it changes again! + win32ui.AddToRecentFileList(fileName) + self.SetPathName(fileName) + win32ui.SetStatusText("Ready") + self._DocumentStateChanged() + return 1 + + def FinalizeViewCreation(self, view): + ParentEditorDocument.FinalizeViewCreation(self, view) + if view == self.GetFirstView(): + self._DocumentStateChanged() + if view.bFolding and GetEditorOption("Fold On Open", 0): + view.FoldTopLevelEvent() + + def HookViewNotifications(self, view): + ParentEditorDocument.HookViewNotifications(self, view) + + # Support for reloading the document from disk - presumably after some + # external application has modified it (or possibly source control has + # checked it out. + def ReloadDocument(self): + """Reloads the document from disk. Assumes the file has + been saved and user has been asked if necessary - it just does it! + """ + win32ui.SetStatusText("Reloading document. Please wait...", 1) + self.SetModifiedFlag(0) + # Loop over all views, saving their state, then reload the document + views = self.GetAllViews() + states = [] + for view in views: + try: + info = view._PrepareUserStateChange() + except AttributeError: # Not our editor view? + info = None + states.append(info) + self.OnOpenDocument(self.GetPathName()) + for view, info in zip(views, states): + if info is not None: + view._EndUserStateChange(info) + self._DocumentStateChanged() + win32ui.SetStatusText("Document reloaded.") + + # Reloading the file + def CheckExternalDocumentUpdated(self): + if self.bDeclinedReload or not self.GetPathName(): + return + try: + newstat = os.stat(self.GetPathName()) + except os.error as exc: + if not self.bReportedFileNotFound: + print( + "The file '%s' is open for editing, but\nchecking it for changes caused the error: %s" + % (self.GetPathName(), exc.strerror) + ) + self.bReportedFileNotFound = 1 + return + if self.bReportedFileNotFound: + print( + "The file '%s' has re-appeared - continuing to watch for changes..." + % (self.GetPathName(),) + ) + self.bReportedFileNotFound = ( + 0 # Once found again we want to start complaining. + ) + changed = ( + (self.fileStat is None) + or self.fileStat[0] != newstat[0] + or self.fileStat[6] != newstat[6] + or self.fileStat[8] != newstat[8] + or self.fileStat[9] != newstat[9] + ) + if changed: + question = None + if self.IsModified(): + question = ( + "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it and LOSE THE CHANGES in the source editor?" + % self.GetPathName() + ) + mbStyle = win32con.MB_YESNO | win32con.MB_DEFBUTTON2 # Default to "No" + else: + if not self.bAutoReload: + question = ( + "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it?" + % self.GetPathName() + ) + mbStyle = win32con.MB_YESNO # Default to "Yes" + if question: + rc = win32ui.MessageBox(question, None, mbStyle) + if rc != win32con.IDYES: + self.bDeclinedReload = 1 + return + self.ReloadDocument() + + def _DocumentStateChanged(self): + """Called whenever the documents state (on disk etc) has been changed + by the editor (eg, as the result of a save operation) + """ + if self.GetPathName(): + try: + self.fileStat = os.stat(self.GetPathName()) + except os.error: + self.fileStat = None + else: + self.fileStat = None + self.watcherThread._DocumentStateChanged() + self._UpdateUIForState() + self._ApplyOptionalToViews("_UpdateUIForState") + self._ApplyOptionalToViews("SetReadOnly", self._IsReadOnly()) + self._ApplyOptionalToViews("SCISetSavePoint") + # Allow the debugger to reset us too. + import pywin.debugger + + if pywin.debugger.currentDebugger is not None: + pywin.debugger.currentDebugger.UpdateDocumentLineStates(self) + + # Read-only document support - make it obvious to the user + # that the file is read-only. + def _IsReadOnly(self): + return self.fileStat is not None and (self.fileStat[0] & 128) == 0 + + def _UpdateUIForState(self): + """Change the title to reflect the state of the document - + eg ReadOnly, Dirty, etc + """ + filename = self.GetPathName() + if not filename: + return # New file - nothing to do + try: + # This seems necessary so the internal state of the window becomes + # "visible". without it, it is still shown, but certain functions + # (such as updating the title) dont immediately work? + self.GetFirstView().ShowWindow(win32con.SW_SHOW) + title = win32ui.GetFileTitle(filename) + except win32ui.error: + title = filename + if self._IsReadOnly(): + title = title + " (read-only)" + self.SetTitle(title) + + def MakeDocumentWritable(self): + pretend_ss = 0 # Set to 1 to test this without source safe :-) + if not self.scModuleName and not pretend_ss: # No Source Control support. + win32ui.SetStatusText( + "Document is read-only, and no source-control system is configured" + ) + win32api.MessageBeep() + return 0 + + # We have source control support - check if the user wants to use it. + msg = "Would you like to check this file out?" + defButton = win32con.MB_YESNO + if self.IsModified(): + msg = msg + "\r\n\r\nALL CHANGES IN THE EDITOR WILL BE LOST" + defButton = win32con.MB_YESNO + if win32ui.MessageBox(msg, None, defButton) != win32con.IDYES: + return 0 + + if pretend_ss: + print("We are only pretending to check it out!") + win32api.SetFileAttributes( + self.GetPathName(), win32con.FILE_ATTRIBUTE_NORMAL + ) + self.ReloadDocument() + return 1 + + # Now call on the module to do it. + if self.scModule is None: + try: + self.scModule = __import__(self.scModuleName) + for part in self.scModuleName.split(".")[1:]: + self.scModule = getattr(self.scModule, part) + except: + traceback.print_exc() + print("Error loading source control module.") + return 0 + + if self.scModule.CheckoutFile(self.GetPathName()): + self.ReloadDocument() + return 1 + return 0 + + def CheckMakeDocumentWritable(self): + if self._IsReadOnly(): + return self.MakeDocumentWritable() + return 1 + + def SaveModified(self): + # Called as the document is closed. If we are about + # to prompt for a save, bring the document to the foreground. + if self.IsModified(): + frame = self.GetFirstView().GetParentFrame() + try: + frame.MDIActivate() + frame.AutoRestore() + except: + print("Could not bring document to foreground") + return self._obj_.SaveModified() + + +# NOTE - I DONT use the standard threading module, +# as this waits for all threads to terminate at shutdown. +# When using the debugger, it is possible shutdown will +# occur without Pythonwin getting a complete shutdown, +# so we deadlock at the end - threading is waiting for +import pywin.mfc.thread +import win32event + + +class FileWatchingThread(pywin.mfc.thread.WinThread): + def __init__(self, doc): + self.doc = doc + self.adminEvent = win32event.CreateEvent(None, 0, 0, None) + self.stopEvent = win32event.CreateEvent(None, 0, 0, None) + self.watchEvent = None + pywin.mfc.thread.WinThread.__init__(self) + + def _DocumentStateChanged(self): + win32event.SetEvent(self.adminEvent) + + def RefreshEvent(self): + self.hwnd = self.doc.GetFirstView().GetSafeHwnd() + if self.watchEvent is not None: + win32api.FindCloseChangeNotification(self.watchEvent) + self.watchEvent = None + path = self.doc.GetPathName() + if path: + path = os.path.dirname(path) + if path: + filter = ( + win32con.FILE_NOTIFY_CHANGE_FILE_NAME + | win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES + | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE + ) + try: + self.watchEvent = win32api.FindFirstChangeNotification(path, 0, filter) + except win32api.error as exc: + print("Can not watch file", path, "for changes -", exc.strerror) + + def SignalStop(self): + win32event.SetEvent(self.stopEvent) + + def Run(self): + while 1: + handles = [self.stopEvent, self.adminEvent] + if self.watchEvent is not None: + handles.append(self.watchEvent) + rc = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE) + if rc == win32event.WAIT_OBJECT_0: + break + elif rc == win32event.WAIT_OBJECT_0 + 1: + self.RefreshEvent() + else: + win32api.PostMessage(self.hwnd, MSG_CHECK_EXTERNAL_FILE, 0, 0) + try: + # If the directory has been removed underneath us, we get this error. + win32api.FindNextChangeNotification(self.watchEvent) + except win32api.error as exc: + print( + "Can not watch file", + self.doc.GetPathName(), + "for changes -", + exc.strerror, + ) + break + + # close a circular reference + self.doc = None + if self.watchEvent: + win32api.FindCloseChangeNotification(self.watchEvent) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/editor.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/editor.py new file mode 100644 index 0000000000000000000000000000000000000000..aa1f53857dc9670ee61aadcb72368f014f7c0326 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/editor.py @@ -0,0 +1,516 @@ +##################################################################### +# +# editor.py +# +# A general purpose text editor, built on top of the win32ui edit +# type, which is built on an MFC CEditView +# +# +# We now support reloading of externally modified documented +# (eg, presumably by some other process, such as source control or +# another editor. +# We also suport auto-loading of externally modified files. +# - if the current document has not been modified in this +# editor, but has been modified on disk, then the file +# can be automatically reloaded. +# +# Note that it will _always_ prompt you if the file in the editor has been modified. + + +import re + +import regex +import win32api +import win32con +import win32ui +from pywin.framework.editor import ( + GetEditorFontOption, + GetEditorOption, + SetEditorFontOption, + SetEditorOption, + defaultCharacterFormat, +) +from pywin.mfc import afxres, dialog, docview + +patImport = regex.symcomp("import \(.*\)") +patIndent = regex.compile("^\\([ \t]*[~ \t]\\)") + +ID_LOCATE_FILE = 0xE200 +ID_GOTO_LINE = 0xE2001 +MSG_CHECK_EXTERNAL_FILE = ( + win32con.WM_USER + 1999 +) ## WARNING: Duplicated in document.py and coloreditor.py + +# Key Codes that modify the bufffer when Ctrl or Alt are NOT pressed. +MODIFYING_VK_KEYS = [ + win32con.VK_BACK, + win32con.VK_TAB, + win32con.VK_RETURN, + win32con.VK_SPACE, + win32con.VK_DELETE, +] +for k in range(48, 91): + MODIFYING_VK_KEYS.append(k) + +# Key Codes that modify the bufffer when Ctrl is pressed. +MODIFYING_VK_KEYS_CTRL = [ + win32con.VK_BACK, + win32con.VK_RETURN, + win32con.VK_SPACE, + win32con.VK_DELETE, +] + +# Key Codes that modify the bufffer when Alt is pressed. +MODIFYING_VK_KEYS_ALT = [ + win32con.VK_BACK, + win32con.VK_RETURN, + win32con.VK_SPACE, + win32con.VK_DELETE, +] + + +# The editor itself starts here. +# Using the MFC Document/View model, we have an EditorDocument, which is responsible for +# managing the contents of the file, and a view which is responsible for rendering it. +# +# Due to a limitation in the Windows edit controls, we are limited to one view +# per document, although nothing in this code assumes this (I hope!) + +isRichText = 1 # We are using the Rich Text control. This has not been tested with value "0" for quite some time! + +# ParentEditorDocument=docview.Document +from .document import EditorDocumentBase + +ParentEditorDocument = EditorDocumentBase + + +class EditorDocument(ParentEditorDocument): + # + # File loading and saving operations + # + def OnOpenDocument(self, filename): + # + # handle Unix and PC text file format. + # + + # Get the "long name" of the file name, as it may have been translated + # to short names by the shell. + self.SetPathName(filename) # Must set this early! + # Now do the work! + self.BeginWaitCursor() + win32ui.SetStatusText("Loading file...", 1) + try: + f = open(filename, "rb") + except IOError: + win32ui.MessageBox( + filename + + "\nCan not find this file\nPlease verify that the correct path and file name are given" + ) + self.EndWaitCursor() + return 0 + raw = f.read() + f.close() + contents = self.TranslateLoadedData(raw) + rc = 0 + try: + self.GetFirstView().SetWindowText(contents) + rc = 1 + except TypeError: # Null byte in file. + win32ui.MessageBox("This file contains NULL bytes, and can not be edited") + rc = 0 + + self.EndWaitCursor() + self.SetModifiedFlag(0) # No longer dirty + self._DocumentStateChanged() + return rc + + def TranslateLoadedData(self, data): + """Given raw data read from a file, massage it suitable for the edit window""" + # if a CR in the first 250 chars, then perform the expensive translate + if data[:250].find("\r") == -1: + win32ui.SetStatusText( + "Translating from Unix file format - please wait...", 1 + ) + return re.sub("\r*\n", "\r\n", data) + else: + return data + + def SaveFile(self, fileName, encoding=None): + if isRichText: + view = self.GetFirstView() + view.SaveTextFile(fileName, encoding=encoding) + else: # Old style edit view window. + self.GetFirstView().SaveFile(fileName) + try: + # Make sure line cache has updated info about me! + import linecache + + linecache.checkcache() + except: + pass + + # + # Color state stuff + # + def SetAllLineColors(self, color=None): + for view in self.GetAllViews(): + view.SetAllLineColors(color) + + def SetLineColor(self, lineNo, color): + "Color a line of all views" + for view in self.GetAllViews(): + view.SetLineColor(lineNo, color) + + +# def StreamTextOut(self, data): ### This seems unreliable??? +# self.saveFileHandle.write(data) +# return 1 # keep em coming! + +# ParentEditorView=docview.EditView +ParentEditorView = docview.RichEditView + + +class EditorView(ParentEditorView): + def __init__(self, doc): + ParentEditorView.__init__(self, doc) + if isRichText: + self.SetWordWrap(win32ui.CRichEditView_WrapNone) + + self.addToMRU = 1 + self.HookHandlers() + self.bCheckingFile = 0 + + self.defCharFormat = GetEditorFontOption("Default Font", defaultCharacterFormat) + + # Smart tabs override everything else if context can be worked out. + self.bSmartTabs = GetEditorOption("Smart Tabs", 1) + + self.tabSize = GetEditorOption("Tab Size", 8) + self.indentSize = GetEditorOption("Indent Size", 8) + # If next indent is at a tab position, and useTabs is set, a tab will be inserted. + self.bUseTabs = GetEditorOption("Use Tabs", 1) + + def OnInitialUpdate(self): + rc = self._obj_.OnInitialUpdate() + self.SetDefaultCharFormat(self.defCharFormat) + return rc + + def CutCurLine(self): + curLine = self._obj_.LineFromChar() + nextLine = curLine + 1 + start = self._obj_.LineIndex(curLine) + end = self._obj_.LineIndex(nextLine) + if end == 0: # must be last line. + end = start + self.end.GetLineLength(curLine) + self._obj_.SetSel(start, end) + self._obj_.Cut() + + def _PrepareUserStateChange(self): + "Return selection, lineindex, etc info, so it can be restored" + self.SetRedraw(0) + return self.GetModify(), self.GetSel(), self.GetFirstVisibleLine() + + def _EndUserStateChange(self, info): + scrollOff = info[2] - self.GetFirstVisibleLine() + if scrollOff: + self.LineScroll(scrollOff) + self.SetSel(info[1]) + self.SetModify(info[0]) + self.SetRedraw(1) + self.InvalidateRect() + self.UpdateWindow() + + def _UpdateUIForState(self): + self.SetReadOnly(self.GetDocument()._IsReadOnly()) + + def SetAllLineColors(self, color=None): + if isRichText: + info = self._PrepareUserStateChange() + try: + if color is None: + color = self.defCharFormat[4] + self.SetSel(0, -1) + self.SetSelectionCharFormat((win32con.CFM_COLOR, 0, 0, 0, color)) + finally: + self._EndUserStateChange(info) + + def SetLineColor(self, lineNo, color): + "lineNo is the 1 based line number to set. If color is None, default color is used." + if isRichText: + info = self._PrepareUserStateChange() + try: + if color is None: + color = self.defCharFormat[4] + lineNo = lineNo - 1 + startIndex = self.LineIndex(lineNo) + if startIndex != -1: + self.SetSel(startIndex, self.LineIndex(lineNo + 1)) + self.SetSelectionCharFormat((win32con.CFM_COLOR, 0, 0, 0, color)) + finally: + self._EndUserStateChange(info) + + def Indent(self): + """Insert an indent to move the cursor to the next tab position. + + Honors the tab size and 'use tabs' settings. Assumes the cursor is already at the + position to be indented, and the selection is a single character (ie, not a block) + """ + start, end = self._obj_.GetSel() + startLine = self._obj_.LineFromChar(start) + line = self._obj_.GetLine(startLine) + realCol = start - self._obj_.LineIndex(startLine) + # Calulate the next tab stop. + # Expand existing tabs. + curCol = 0 + for ch in line[:realCol]: + if ch == "\t": + curCol = ((curCol / self.tabSize) + 1) * self.tabSize + else: + curCol = curCol + 1 + nextColumn = ((curCol / self.indentSize) + 1) * self.indentSize + # print "curCol is", curCol, "nextColumn is", nextColumn + ins = None + if self.bSmartTabs: + # Look for some context. + if realCol == 0: # Start of the line - see if the line above can tell us + lookLine = startLine - 1 + while lookLine >= 0: + check = self._obj_.GetLine(lookLine)[0:1] + if check in ("\t", " "): + ins = check + break + lookLine = lookLine - 1 + else: # See if the previous char can tell us + check = line[realCol - 1] + if check in ("\t", " "): + ins = check + + # Either smart tabs off, or not smart enough! + # Use the "old style" settings. + if ins is None: + if self.bUseTabs and nextColumn % self.tabSize == 0: + ins = "\t" + else: + ins = " " + + if ins == " ": + # Calc the number of spaces to take us to the next stop + ins = ins * (nextColumn - curCol) + + self._obj_.ReplaceSel(ins) + + def BlockDent(self, isIndent, startLine, endLine): + "Indent/Undent all lines specified" + if not self.GetDocument().CheckMakeDocumentWritable(): + return 0 + tabSize = self.tabSize # hard-code for now! + info = self._PrepareUserStateChange() + try: + for lineNo in range(startLine, endLine): + pos = self._obj_.LineIndex(lineNo) + self._obj_.SetSel(pos, pos) + if isIndent: + self.Indent() + else: + line = self._obj_.GetLine(lineNo) + try: + noToDel = 0 + if line[0] == "\t": + noToDel = 1 + elif line[0] == " ": + for noToDel in range(0, tabSize): + if line[noToDel] != " ": + break + else: + noToDel = tabSize + if noToDel: + self._obj_.SetSel(pos, pos + noToDel) + self._obj_.Clear() + except IndexError: + pass + finally: + self._EndUserStateChange(info) + self.GetDocument().SetModifiedFlag(1) # Now dirty + self._obj_.SetSel(self.LineIndex(startLine), self.LineIndex(endLine)) + + def GotoLine(self, lineNo=None): + try: + if lineNo is None: + lineNo = int(input("Enter Line Number")) + except (ValueError, KeyboardInterrupt): + return 0 + self.GetLineCount() # Seems to be needed when file first opened??? + charNo = self.LineIndex(lineNo - 1) + self.SetSel(charNo) + + def HookHandlers(self): # children can override, but should still call me! + # self.HookAllKeyStrokes(self.OnKey) + self.HookMessage(self.OnCheckExternalDocumentUpdated, MSG_CHECK_EXTERNAL_FILE) + self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN) + self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS) + self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN) + self.HookKeyStroke(self.OnKeyCtrlY, 25) # ^Y + self.HookKeyStroke(self.OnKeyCtrlG, 7) # ^G + self.HookKeyStroke(self.OnKeyTab, 9) # TAB + self.HookKeyStroke(self.OnKeyEnter, 13) # Enter + self.HookCommand(self.OnCmdLocateFile, ID_LOCATE_FILE) + self.HookCommand(self.OnCmdGotoLine, ID_GOTO_LINE) + self.HookCommand(self.OnEditPaste, afxres.ID_EDIT_PASTE) + self.HookCommand(self.OnEditCut, afxres.ID_EDIT_CUT) + + # Hook Handlers + def OnSetFocus(self, msg): + # Even though we use file change notifications, we should be very sure about it here. + self.OnCheckExternalDocumentUpdated(msg) + + def OnRClick(self, params): + menu = win32ui.CreatePopupMenu() + + # look for a module name + line = self._obj_.GetLine().strip() + flags = win32con.MF_STRING | win32con.MF_ENABLED + if patImport.match(line) == len(line): + menu.AppendMenu( + flags, ID_LOCATE_FILE, "&Locate %s.py" % patImport.group("name") + ) + menu.AppendMenu(win32con.MF_SEPARATOR) + menu.AppendMenu(flags, win32ui.ID_EDIT_UNDO, "&Undo") + menu.AppendMenu(win32con.MF_SEPARATOR) + menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, "Cu&t") + menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, "&Copy") + menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, "&Paste") + menu.AppendMenu(flags, win32con.MF_SEPARATOR) + menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, "&Select all") + menu.AppendMenu(flags, win32con.MF_SEPARATOR) + menu.AppendMenu(flags, ID_GOTO_LINE, "&Goto line...") + menu.TrackPopupMenu(params[5]) + return 0 + + def OnCmdGotoLine(self, cmd, code): + self.GotoLine() + return 0 + + def OnCmdLocateFile(self, cmd, code): + modName = patImport.group("name") + if not modName: + return 0 + import pywin.framework.scriptutils + + fileName = pywin.framework.scriptutils.LocatePythonFile(modName) + if fileName is None: + win32ui.SetStatusText("Can't locate module %s" % modName) + else: + win32ui.GetApp().OpenDocumentFile(fileName) + return 0 + + # Key handlers + def OnKeyEnter(self, key): + if not self.GetDocument().CheckMakeDocumentWritable(): + return 0 + curLine = self._obj_.GetLine() + self._obj_.ReplaceSel("\r\n") # insert the newline + # If the current line indicates the next should be indented, + # then copy the current indentation to this line. + res = patIndent.match(curLine, 0) + if res > 0 and curLine.strip(): + curIndent = patIndent.group(1) + self._obj_.ReplaceSel(curIndent) + return 0 # dont pass on + + def OnKeyCtrlY(self, key): + if not self.GetDocument().CheckMakeDocumentWritable(): + return 0 + self.CutCurLine() + return 0 # dont let him have it! + + def OnKeyCtrlG(self, key): + self.GotoLine() + return 0 # dont let him have it! + + def OnKeyTab(self, key): + if not self.GetDocument().CheckMakeDocumentWritable(): + return 0 + start, end = self._obj_.GetSel() + if start == end: # normal TAB key + self.Indent() + return 0 # we handled this. + + # Otherwise it is a block indent/dedent. + if start > end: + start, end = end, start # swap them. + startLine = self._obj_.LineFromChar(start) + endLine = self._obj_.LineFromChar(end) + + self.BlockDent(win32api.GetKeyState(win32con.VK_SHIFT) >= 0, startLine, endLine) + return 0 + + def OnEditPaste(self, id, code): + # Return 1 if we can make the file editable.(or it already is!) + return self.GetDocument().CheckMakeDocumentWritable() + + def OnEditCut(self, id, code): + # Return 1 if we can make the file editable.(or it already is!) + return self.GetDocument().CheckMakeDocumentWritable() + + def OnKeyDown(self, msg): + key = msg[2] + if win32api.GetKeyState(win32con.VK_CONTROL) & 0x8000: + modList = MODIFYING_VK_KEYS_CTRL + elif win32api.GetKeyState(win32con.VK_MENU) & 0x8000: + modList = MODIFYING_VK_KEYS_ALT + else: + modList = MODIFYING_VK_KEYS + + if key in modList: + # Return 1 if we can make the file editable.(or it already is!) + return self.GetDocument().CheckMakeDocumentWritable() + return 1 # Pass it on OK + + # def OnKey(self, key): + # return self.GetDocument().CheckMakeDocumentWritable() + + def OnCheckExternalDocumentUpdated(self, msg): + if self._obj_ is None or self.bCheckingFile: + return + self.bCheckingFile = 1 + self.GetDocument().CheckExternalDocumentUpdated() + self.bCheckingFile = 0 + + +from .template import EditorTemplateBase + + +class EditorTemplate(EditorTemplateBase): + def __init__( + self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None + ): + if makeDoc is None: + makeDoc = EditorDocument + if makeView is None: + makeView = EditorView + EditorTemplateBase.__init__(self, res, makeDoc, makeFrame, makeView) + + def _CreateDocTemplate(self, resourceId): + return win32ui.CreateRichEditDocTemplate(resourceId) + + def CreateWin32uiDocument(self): + return self.DoCreateRichEditDoc() + + +def Create(fileName=None, title=None, template=None): + return editorTemplate.OpenDocumentFile(fileName) + + +from pywin.framework.editor import GetDefaultEditorModuleName + +prefModule = GetDefaultEditorModuleName() +# Initialize only if this is the "default" editor. +if __name__ == prefModule: + # For debugging purposes, when this module may be reloaded many times. + try: + win32ui.GetApp().RemoveDocTemplate(editorTemplate) + except (NameError, win32ui.error): + pass + + editorTemplate = EditorTemplate() + win32ui.GetApp().AddDocTemplate(editorTemplate) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/frame.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/frame.py new file mode 100644 index 0000000000000000000000000000000000000000..e927d16e5fe0bde37c9aed3316f8c59bddfd989d --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/frame.py @@ -0,0 +1,74 @@ +# frame.py - The MDI frame window for an editor. +import pywin.framework.window +import win32con +import win32ui + +from . import ModuleBrowser + + +class EditorFrame(pywin.framework.window.MDIChildWnd): + def OnCreateClient(self, cp, context): + # Create the default view as specified by the template (ie, the editor view) + view = context.template.MakeView(context.doc) + # Create the browser view. + browserView = ModuleBrowser.BrowserView(context.doc) + view2 = context.template.MakeView(context.doc) + + splitter = win32ui.CreateSplitter() + style = win32con.WS_CHILD | win32con.WS_VISIBLE + splitter.CreateStatic(self, 1, 2, style, win32ui.AFX_IDW_PANE_FIRST) + sub_splitter = self.sub_splitter = win32ui.CreateSplitter() + sub_splitter.CreateStatic(splitter, 2, 1, style, win32ui.AFX_IDW_PANE_FIRST + 1) + + # Note we must add the default view first, so that doc.GetFirstView() returns the editor view. + sub_splitter.CreateView(view, 1, 0, (0, 0)) + splitter.CreateView(browserView, 0, 0, (0, 0)) + sub_splitter.CreateView(view2, 0, 0, (0, 0)) + + ## print "First view is", context.doc.GetFirstView() + ## print "Views are", view, view2, browserView + ## print "Parents are", view.GetParent(), view2.GetParent(), browserView.GetParent() + ## print "Splitter is", splitter + ## print "sub splitter is", sub_splitter + ## Old + ## splitter.CreateStatic (self, 1, 2) + ## splitter.CreateView(view, 0, 1, (0,0)) # size ignored. + ## splitter.CreateView (browserView, 0, 0, (0, 0)) + + # Restrict the size of the browser splitter (and we can avoid filling + # it until it is shown) + splitter.SetColumnInfo(0, 10, 20) + # And the active view is our default view (so it gets initial focus) + self.SetActiveView(view) + + def GetEditorView(self): + # In a multi-view (eg, splitter) environment, get + # an editor (ie, scintilla) view + # Look for the splitter opened the most! + if self.sub_splitter is None: + return self.GetDlgItem(win32ui.AFX_IDW_PANE_FIRST) + v1 = self.sub_splitter.GetPane(0, 0) + v2 = self.sub_splitter.GetPane(1, 0) + r1 = v1.GetWindowRect() + r2 = v2.GetWindowRect() + if r1[3] - r1[1] > r2[3] - r2[1]: + return v1 + return v2 + + def GetBrowserView(self): + # XXX - should fix this :-) + return self.GetActiveDocument().GetAllViews()[1] + + def OnClose(self): + doc = self.GetActiveDocument() + if not doc.SaveModified(): + ## Cancel button selected from Save dialog, do not actually close + ## print 'close cancelled' + return 0 + ## So the 'Save' dialog doesn't come up twice + doc._obj_.SetModifiedFlag(False) + + # Must force the module browser to close itself here (OnDestroy for the view itself is too late!) + self.sub_splitter = None # ensure no circles! + self.GetBrowserView().DestroyBrowser() + return self._obj_.OnClose() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/template.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/template.py new file mode 100644 index 0000000000000000000000000000000000000000..362a74a62d9486113de2ee4daa39046fc526c55d --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/template.py @@ -0,0 +1,60 @@ +import os + +import pywin.framework.window +import win32api +import win32ui +from pywin.mfc import docview + +from . import frame + +ParentEditorTemplate = docview.DocTemplate + + +class EditorTemplateBase(ParentEditorTemplate): + def __init__( + self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None + ): + if makeFrame is None: + makeFrame = frame.EditorFrame + ParentEditorTemplate.__init__(self, res, makeDoc, makeFrame, makeView) + + def _CreateDocTemplate(self, resourceId): + assert 0, "You must override this" + + def CreateWin32uiDocument(self): + assert 0, "You must override this" + + def GetFileExtensions(self): + return ".txt", ".py" + + def MatchDocType(self, fileName, fileType): + doc = self.FindOpenDocument(fileName) + if doc: + return doc + ext = os.path.splitext(fileName)[1].lower() + if ext in self.GetFileExtensions(): + return win32ui.CDocTemplate_Confidence_yesAttemptNative + return win32ui.CDocTemplate_Confidence_maybeAttemptForeign + + def InitialUpdateFrame(self, frame, doc, makeVisible=1): + self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler. + doc._UpdateUIForState() + + def GetPythonPropertyPages(self): + """Returns a list of property pages""" + from . import configui + + return [configui.EditorPropertyPage(), configui.EditorWhitespacePropertyPage()] + + def OpenDocumentFile(self, filename, bMakeVisible=1): + if filename is not None: + try: + path = os.path.split(filename)[0] + # print "The editor is translating", `filename`,"to", + filename = win32api.FindFiles(filename)[0][8] + filename = os.path.join(path, filename) + # print `filename` + except (win32api.error, IndexError) as details: + pass + # print "Couldnt get the full filename!", details + return self._obj_.OpenDocumentFile(filename, bMakeVisible) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/vss.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/vss.py new file mode 100644 index 0000000000000000000000000000000000000000..718f83eea471ba6192eb1b547ec97c4213541aef --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/editor/vss.py @@ -0,0 +1,104 @@ +# vss.py -- Source Control using Microsoft VSS. + +# Provides routines for checking files out of VSS. +# +# Uses an INI file very similar to how VB integrates with VSS - even +# as far as using the same name. + +# The file must be named "Mssccprj.scc", and be in the format of +# an INI file. This file may be in a parent directory, in which +# case the project name will be built from what is specified in the +# ini file, plus the path from the INI file to the file itself. +# +# The INI file should have a [Python] section, and a +# Project=Project Name +# and optionally +# Database=?? + + +import os +import sys +import traceback + +import win32api +import win32ui + +g_iniName = "Mssccprj.scc" # Use the same INI name as VB! + +g_sourceSafe = None + + +def FindVssProjectInfo(fullfname): + """Looks up the file system for an INI file describing the project. + + Looking up the tree is for ni style packages. + + Returns (projectName, pathToFileName) where pathToFileName contains + the path from the ini file to the actual file. + """ + path, fnameonly = os.path.split(fullfname) + origPath = path + project = "" + retPaths = [fnameonly] + while not project: + iniName = os.path.join(path, g_iniName) + database = win32api.GetProfileVal("Python", "Database", "", iniName) + project = win32api.GetProfileVal("Python", "Project", "", iniName) + if project: + break + # No valid INI file in this directory - look up a level. + path, addpath = os.path.split(path) + if not addpath: # Root? + break + retPaths.insert(0, addpath) + if not project: + win32ui.MessageBox( + "%s\r\n\r\nThis directory is not configured for Python/VSS" % origPath + ) + return + return project, "/".join(retPaths), database + + +def CheckoutFile(fileName): + global g_sourceSafe + import pythoncom + + ok = 0 + # Assumes the fileName has a complete path, + # and that the INI file can be found in that path + # (or a parent path if a ni style package) + try: + import win32com.client + import win32com.client.gencache + + mod = win32com.client.gencache.EnsureModule( + "{783CD4E0-9D54-11CF-B8EE-00608CC9A71F}", 0, 5, 0 + ) + if mod is None: + win32ui.MessageBox( + "VSS does not appear to be installed. The TypeInfo can not be created" + ) + return ok + + rc = FindVssProjectInfo(fileName) + if rc is None: + return + project, vssFname, database = rc + if g_sourceSafe is None: + g_sourceSafe = win32com.client.Dispatch("SourceSafe") + # SS seems a bit wierd. It defaults the arguments as empty strings, but + # then complains when they are used - so we pass "Missing" + if not database: + database = pythoncom.Missing + g_sourceSafe.Open(database, pythoncom.Missing, pythoncom.Missing) + item = g_sourceSafe.VSSItem("$/%s/%s" % (project, vssFname)) + item.Checkout(None, fileName) + ok = 1 + except pythoncom.com_error as exc: + win32ui.MessageBox(exc.strerror, "Error checking out file") + except: + typ, val, tb = sys.exc_info() + traceback.print_exc() + win32ui.MessageBox("%s - %s" % (str(typ), str(val)), "Error checking out file") + tb = None # Cleanup a cycle + return ok diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/help.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/help.py new file mode 100644 index 0000000000000000000000000000000000000000..ab664b4d1a542810f834ee191aa2fdb04e973b69 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/help.py @@ -0,0 +1,173 @@ +# help.py - help utilities for PythonWin. +import os + +import regutil +import win32api +import win32con +import win32ui + +htmlhelp_handle = None + +html_help_command_translators = { + win32con.HELP_CONTENTS: 1, # HH_DISPLAY_TOC + win32con.HELP_CONTEXT: 15, # HH_HELP_CONTEXT + win32con.HELP_FINDER: 1, # HH_DISPLAY_TOC +} + + +def FinalizeHelp(): + global htmlhelp_handle + if htmlhelp_handle is not None: + import win32help + + try: + # frame = win32ui.GetMainFrame().GetSafeHwnd() + frame = 0 + win32help.HtmlHelp(frame, None, win32help.HH_UNINITIALIZE, htmlhelp_handle) + except win32help.error: + print("Failed to finalize htmlhelp!") + htmlhelp_handle = None + + +def OpenHelpFile(fileName, helpCmd=None, helpArg=None): + "Open a help file, given a full path" + # default help arg. + win32ui.DoWaitCursor(1) + try: + if helpCmd is None: + helpCmd = win32con.HELP_CONTENTS + ext = os.path.splitext(fileName)[1].lower() + if ext == ".hlp": + win32api.WinHelp( + win32ui.GetMainFrame().GetSafeHwnd(), fileName, helpCmd, helpArg + ) + # XXX - using the htmlhelp API wreaks havoc with keyboard shortcuts + # so we disable it, forcing ShellExecute, which works fine (but + # doesn't close the help file when Pythonwin is closed. + # Tom Heller also points out http://www.microsoft.com/mind/0499/faq/faq0499.asp, + # which may or may not be related. + elif 0 and ext == ".chm": + import win32help + + global htmlhelp_handle + helpCmd = html_help_command_translators.get(helpCmd, helpCmd) + # frame = win32ui.GetMainFrame().GetSafeHwnd() + frame = 0 # Dont want it overlapping ours! + if htmlhelp_handle is None: + htmlhelp_hwnd, htmlhelp_handle = win32help.HtmlHelp( + frame, None, win32help.HH_INITIALIZE + ) + win32help.HtmlHelp(frame, fileName, helpCmd, helpArg) + else: + # Hope that the extension is registered, and we know what to do! + win32api.ShellExecute(0, "open", fileName, None, "", win32con.SW_SHOW) + return fileName + finally: + win32ui.DoWaitCursor(-1) + + +def ListAllHelpFiles(): + ret = [] + ret = _ListAllHelpFilesInRoot(win32con.HKEY_LOCAL_MACHINE) + # Ensure we don't get dups. + for item in _ListAllHelpFilesInRoot(win32con.HKEY_CURRENT_USER): + if item not in ret: + ret.append(item) + return ret + + +def _ListAllHelpFilesInRoot(root): + """Returns a list of (helpDesc, helpFname) for all registered help files""" + import regutil + + retList = [] + try: + key = win32api.RegOpenKey( + root, regutil.BuildDefaultPythonKey() + "\\Help", 0, win32con.KEY_READ + ) + except win32api.error as exc: + import winerror + + if exc.winerror != winerror.ERROR_FILE_NOT_FOUND: + raise + return retList + try: + keyNo = 0 + while 1: + try: + helpDesc = win32api.RegEnumKey(key, keyNo) + helpFile = win32api.RegQueryValue(key, helpDesc) + retList.append((helpDesc, helpFile)) + keyNo = keyNo + 1 + except win32api.error as exc: + import winerror + + if exc.winerror != winerror.ERROR_NO_MORE_ITEMS: + raise + break + finally: + win32api.RegCloseKey(key) + return retList + + +def SelectAndRunHelpFile(): + from pywin.dialogs import list + + helpFiles = ListAllHelpFiles() + if len(helpFiles) == 1: + # only 1 help file registered - probably ours - no point asking + index = 0 + else: + index = list.SelectFromLists("Select Help file", helpFiles, ["Title"]) + if index is not None: + OpenHelpFile(helpFiles[index][1]) + + +helpIDMap = None + + +def SetHelpMenuOtherHelp(mainMenu): + """Modifies the main Help Menu to handle all registered help files. + mainMenu -- The main menu to modify - usually from docTemplate.GetSharedMenu() + """ + + # Load all help files from the registry. + global helpIDMap + if helpIDMap is None: + helpIDMap = {} + cmdID = win32ui.ID_HELP_OTHER + excludeList = ["Main Python Documentation", "Pythonwin Reference"] + firstList = ListAllHelpFiles() + # We actually want to not only exclude these entries, but + # their help file names (as many entries may share the same name) + excludeFnames = [] + for desc, fname in firstList: + if desc in excludeList: + excludeFnames.append(fname) + + helpDescs = [] + for desc, fname in firstList: + if fname not in excludeFnames: + helpIDMap[cmdID] = (desc, fname) + win32ui.GetMainFrame().HookCommand(HandleHelpOtherCommand, cmdID) + cmdID = cmdID + 1 + + helpMenu = mainMenu.GetSubMenu( + mainMenu.GetMenuItemCount() - 1 + ) # Help menu always last. + otherHelpMenuPos = 2 # cant search for ID, as sub-menu has no ID. + otherMenu = helpMenu.GetSubMenu(otherHelpMenuPos) + while otherMenu.GetMenuItemCount(): + otherMenu.DeleteMenu(0, win32con.MF_BYPOSITION) + + if helpIDMap: + for id, (desc, fname) in helpIDMap.items(): + otherMenu.AppendMenu(win32con.MF_ENABLED | win32con.MF_STRING, id, desc) + else: + helpMenu.EnableMenuItem( + otherHelpMenuPos, win32con.MF_BYPOSITION | win32con.MF_GRAYED + ) + + +def HandleHelpOtherCommand(cmd, code): + OpenHelpFile(helpIDMap[cmd][1]) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/interact.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/interact.py new file mode 100644 index 0000000000000000000000000000000000000000..5f0b87f2e16ad2ddd96ba878001fa542136992c1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/interact.py @@ -0,0 +1,985 @@ +################################################################## +## +## Interactive Shell Window +## + +import array +import code +import os +import string +import sys +import traceback + +import __main__ +import afxres +import pywin.framework.app +import pywin.scintilla.control +import pywin.scintilla.formatter +import pywin.scintilla.IDLEenvironment +import win32api +import win32clipboard +import win32con +import win32ui + +## sequential after ID_GOTO_LINE defined in editor.py +ID_EDIT_COPY_CODE = 0xE2002 +ID_EDIT_EXEC_CLIPBOARD = 0x2003 + +trace = pywin.scintilla.formatter.trace + +import re + +from . import winout + +# from IDLE. +_is_block_opener = re.compile(r":\s*(#.*)?$").search +_is_block_closer = re.compile( + r""" + \s* + ( return + | break + | continue + | raise + | pass + ) + \b +""", + re.VERBOSE, +).match + +tracebackHeader = "Traceback (".encode("ascii") + +sectionProfile = "Interactive Window" +valueFormatTitle = "FormatTitle" +valueFormatInput = "FormatInput" +valueFormatOutput = "FormatOutput" +valueFormatOutputError = "FormatOutputError" + +# These are defaults only. Values are read from the registry. +formatTitle = (-536870897, 0, 220, 0, 16711680, 184, 34, "Arial") +formatInput = (-402653169, 0, 200, 0, 0, 0, 49, "Courier New") +formatOutput = (-402653169, 0, 200, 0, 8421376, 0, 49, "Courier New") +formatOutputError = (-402653169, 0, 200, 0, 255, 0, 49, "Courier New") + +try: + sys.ps1 +except AttributeError: + sys.ps1 = ">>> " + sys.ps2 = "... " + + +def LoadPreference(preference, default=""): + return win32ui.GetProfileVal(sectionProfile, preference, default) + + +def SavePreference(prefName, prefValue): + win32ui.WriteProfileVal(sectionProfile, prefName, prefValue) + + +def GetPromptPrefix(line): + ps1 = sys.ps1 + if line[: len(ps1)] == ps1: + return ps1 + ps2 = sys.ps2 + if line[: len(ps2)] == ps2: + return ps2 + + +############################################################# +# +# Colorizer related code. +# +############################################################# +STYLE_INTERACTIVE_EOL = "Interactive EOL" +STYLE_INTERACTIVE_OUTPUT = "Interactive Output" +STYLE_INTERACTIVE_PROMPT = "Interactive Prompt" +STYLE_INTERACTIVE_BANNER = "Interactive Banner" +STYLE_INTERACTIVE_ERROR = "Interactive Error" +STYLE_INTERACTIVE_ERROR_FINALLINE = "Interactive Error (final line)" + +INTERACTIVE_STYLES = [ + STYLE_INTERACTIVE_EOL, + STYLE_INTERACTIVE_OUTPUT, + STYLE_INTERACTIVE_PROMPT, + STYLE_INTERACTIVE_BANNER, + STYLE_INTERACTIVE_ERROR, + STYLE_INTERACTIVE_ERROR_FINALLINE, +] + +FormatterParent = pywin.scintilla.formatter.PythonSourceFormatter + + +class InteractiveFormatter(FormatterParent): + def __init__(self, scintilla): + FormatterParent.__init__(self, scintilla) + self.bannerDisplayed = False + + def SetStyles(self): + FormatterParent.SetStyles(self) + Style = pywin.scintilla.formatter.Style + self.RegisterStyle(Style(STYLE_INTERACTIVE_EOL, STYLE_INTERACTIVE_PROMPT)) + self.RegisterStyle(Style(STYLE_INTERACTIVE_PROMPT, formatInput)) + self.RegisterStyle(Style(STYLE_INTERACTIVE_OUTPUT, formatOutput)) + self.RegisterStyle(Style(STYLE_INTERACTIVE_BANNER, formatTitle)) + self.RegisterStyle(Style(STYLE_INTERACTIVE_ERROR, formatOutputError)) + self.RegisterStyle( + Style(STYLE_INTERACTIVE_ERROR_FINALLINE, STYLE_INTERACTIVE_ERROR) + ) + + def LoadPreference(self, name, default): + rc = win32ui.GetProfileVal("Format", name, default) + if rc == default: + rc = win32ui.GetProfileVal(sectionProfile, name, default) + return rc + + def ColorizeInteractiveCode(self, cdoc, styleStart, stylePyStart): + lengthDoc = len(cdoc) + if lengthDoc == 0: + return + state = styleStart + # As per comments in Colorize(), we work with the raw utf8 + # bytes. To avoid too muych py3k pain, we treat each utf8 byte + # as a latin-1 unicode character - we only use it to compare + # against ascii chars anyway... + chNext = cdoc[0:1].decode("latin-1") + startSeg = 0 + i = 0 + lastState = state # debug only + while i < lengthDoc: + ch = chNext + chNext = cdoc[i + 1 : i + 2].decode("latin-1") + + # trace("ch=%r, i=%d, next=%r, state=%s" % (ch, i, chNext, state)) + if state == STYLE_INTERACTIVE_EOL: + if ch not in "\r\n": + self.ColorSeg(startSeg, i - 1, state) + startSeg = i + if ch in (sys.ps1[0], sys.ps2[0]): + state = STYLE_INTERACTIVE_PROMPT + elif cdoc[i : i + len(tracebackHeader)] == tracebackHeader: + state = STYLE_INTERACTIVE_ERROR + else: + state = STYLE_INTERACTIVE_OUTPUT + elif state == STYLE_INTERACTIVE_PROMPT: + if ch not in sys.ps1 + sys.ps2 + " ": + self.ColorSeg(startSeg, i - 1, state) + startSeg = i + if ch in "\r\n": + state = STYLE_INTERACTIVE_EOL + else: + state = stylePyStart # Start coloring Python code. + elif state in (STYLE_INTERACTIVE_OUTPUT,): + if ch in "\r\n": + self.ColorSeg(startSeg, i - 1, state) + startSeg = i + state = STYLE_INTERACTIVE_EOL + elif state == STYLE_INTERACTIVE_ERROR: + if ch in "\r\n" and chNext and chNext not in string.whitespace: + # Everything including me + self.ColorSeg(startSeg, i, state) + startSeg = i + 1 + state = STYLE_INTERACTIVE_ERROR_FINALLINE + elif i == 0 and ch not in string.whitespace: + # If we are coloring from the start of a line, + # we need this better check for the last line + # Color up to not including me + self.ColorSeg(startSeg, i - 1, state) + startSeg = i + state = STYLE_INTERACTIVE_ERROR_FINALLINE + elif state == STYLE_INTERACTIVE_ERROR_FINALLINE: + if ch in "\r\n": + self.ColorSeg(startSeg, i - 1, state) + startSeg = i + state = STYLE_INTERACTIVE_EOL + elif state == STYLE_INTERACTIVE_BANNER: + if ch in "\r\n" and (chNext == "" or chNext in ">["): + # Everything including me + self.ColorSeg(startSeg, i - 1, state) + startSeg = i + state = STYLE_INTERACTIVE_EOL + else: + # It is a PythonColorizer state - seek past the end of the line + # and ask the Python colorizer to color that. + end = startSeg + while end < lengthDoc and cdoc[end] not in "\r\n".encode("ascii"): + end = end + 1 + self.ColorizePythonCode(cdoc[:end], startSeg, state) + stylePyStart = self.GetStringStyle(end - 1) + if stylePyStart is None: + stylePyStart = pywin.scintilla.formatter.STYLE_DEFAULT + else: + stylePyStart = stylePyStart.name + startSeg = end + i = end - 1 # ready for increment. + chNext = cdoc[end : end + 1].decode("latin-1") + state = STYLE_INTERACTIVE_EOL + if lastState != state: + lastState = state + i = i + 1 + # and the rest + if startSeg < i: + self.ColorSeg(startSeg, i - 1, state) + + def Colorize(self, start=0, end=-1): + # scintilla's formatting is all done in terms of utf, so + # we work with utf8 bytes instead of unicode. This magically + # works as any extended chars found in the utf8 don't change + # the semantics. + stringVal = self.scintilla.GetTextRange(start, end, decode=False) + styleStart = None + stylePyStart = None + if start > 1: + # Likely we are being asked to color from the start of the line. + # We find the last formatted character on the previous line. + # If TQString, we continue it. Otherwise, we reset. + look = start - 1 + while look and self.scintilla.SCIGetCharAt(look) in "\n\r": + look = look - 1 + if look and look < start - 1: # Did we find a char before the \n\r sets? + strstyle = self.GetStringStyle(look) + quote_char = None + if strstyle is not None: + if strstyle.name == pywin.scintilla.formatter.STYLE_TQSSTRING: + quote_char = "'" + elif strstyle.name == pywin.scintilla.formatter.STYLE_TQDSTRING: + quote_char = '"' + if quote_char is not None: + # It is a TQS. If the TQS is not terminated, we + # carry the style through. + if look > 2: + look_str = ( + self.scintilla.SCIGetCharAt(look - 2) + + self.scintilla.SCIGetCharAt(look - 1) + + self.scintilla.SCIGetCharAt(look) + ) + if look_str != quote_char * 3: + stylePyStart = strstyle.name + if stylePyStart is None: + stylePyStart = pywin.scintilla.formatter.STYLE_DEFAULT + + if start > 0: + stylenum = self.scintilla.SCIGetStyleAt(start - 1) + styleStart = self.GetStyleByNum(stylenum).name + elif self.bannerDisplayed: + styleStart = STYLE_INTERACTIVE_EOL + else: + styleStart = STYLE_INTERACTIVE_BANNER + self.bannerDisplayed = True + self.scintilla.SCIStartStyling(start, 31) + self.style_buffer = array.array("b", (0,) * len(stringVal)) + self.ColorizeInteractiveCode(stringVal, styleStart, stylePyStart) + self.scintilla.SCISetStylingEx(self.style_buffer) + self.style_buffer = None + + +############################################################### +# +# This class handles the Python interactive interpreter. +# +# It uses a basic EditWindow, and does all the magic. +# This is triggered by the enter key hander attached by the +# start-up code. It determines if a command is to be executed +# or continued (ie, emit "... ") by snooping around the current +# line, looking for the prompts +# +class PythonwinInteractiveInterpreter(code.InteractiveInterpreter): + def __init__(self, locals=None, globals=None): + if locals is None: + locals = __main__.__dict__ + if globals is None: + globals = locals + self.globals = globals + code.InteractiveInterpreter.__init__(self, locals) + + def showsyntaxerror(self, filename=None): + sys.stderr.write( + tracebackHeader.decode("ascii") + ) # So the color syntaxer recognises it. + code.InteractiveInterpreter.showsyntaxerror(self, filename) + + def runcode(self, code): + try: + exec(code, self.globals, self.locals) + except SystemExit: + raise + except: + self.showtraceback() + + +class InteractiveCore: + def __init__(self, banner=None): + self.banner = banner + + # LoadFontPreferences() + def Init(self): + self.oldStdOut = self.oldStdErr = None + + # self.SetWordWrap(win32ui.CRichEditView_WrapNone) + self.interp = PythonwinInteractiveInterpreter() + + self.OutputGrab() # Release at cleanup. + + if self.GetTextLength() == 0: + if self.banner is None: + suffix = "" + if win32ui.debug: + suffix = ", debug build" + sys.stderr.write( + "PythonWin %s on %s%s.\n" % (sys.version, sys.platform, suffix) + ) + sys.stderr.write( + "Portions %s - see 'Help/About PythonWin' for further copyright information.\n" + % (win32ui.copyright,) + ) + else: + sys.stderr.write(banner) + rcfile = os.environ.get("PYTHONSTARTUP") + if rcfile: + import __main__ + + try: + exec( + compile( + open(rcfile, "rb").read(), rcfile, "exec", dont_inherit=True + ), + __main__.__dict__, + __main__.__dict__, + ) + except: + sys.stderr.write( + ">>> \nError executing PYTHONSTARTUP script %r\n" % (rcfile) + ) + traceback.print_exc(file=sys.stderr) + self.AppendToPrompt([]) + + def SetContext(self, globals, locals, name="Dbg"): + oldPrompt = sys.ps1 + if globals is None: + # Reset + sys.ps1 = ">>> " + sys.ps2 = "... " + locals = globals = __main__.__dict__ + else: + sys.ps1 = "[%s]>>> " % name + sys.ps2 = "[%s]... " % name + self.interp.locals = locals + self.interp.globals = globals + self.AppendToPrompt([], oldPrompt) + + def GetContext(self): + return self.interp.globals, self.interp.locals + + def DoGetLine(self, line=-1): + if line == -1: + line = self.LineFromChar() + line = self.GetLine(line) + while line and line[-1] in ("\r", "\n"): + line = line[:-1] + return line + + def AppendToPrompt(self, bufLines, oldPrompt=None): + "Take a command and stick it at the end of the buffer (with python prompts inserted if required)." + self.flush() + lastLineNo = self.GetLineCount() - 1 + line = self.DoGetLine(lastLineNo) + if oldPrompt and line == oldPrompt: + self.SetSel(self.GetTextLength() - len(oldPrompt), self.GetTextLength()) + self.ReplaceSel(sys.ps1) + elif line != str(sys.ps1): + if len(line) != 0: + self.write("\n") + self.write(sys.ps1) + self.flush() + self.idle.text.mark_set("iomark", "end-1c") + if not bufLines: + return + terms = (["\n" + sys.ps2] * (len(bufLines) - 1)) + [""] + for bufLine, term in zip(bufLines, terms): + if bufLine.strip(): + self.write(bufLine + term) + self.flush() + + def EnsureNoPrompt(self): + # Get ready to write some text NOT at a Python prompt. + self.flush() + lastLineNo = self.GetLineCount() - 1 + line = self.DoGetLine(lastLineNo) + if not line or line in (sys.ps1, sys.ps2): + self.SetSel(self.GetTextLength() - len(line), self.GetTextLength()) + self.ReplaceSel("") + else: + # Just add a new line. + self.write("\n") + + def _GetSubConfigNames(self): + return ["interactive"] # Allow [Keys:Interactive] sections to be specific + + def HookHandlers(self): + # Hook menu command (executed when a menu item with that ID is selected from a menu/toolbar + self.HookCommand(self.OnSelectBlock, win32ui.ID_EDIT_SELECT_BLOCK) + self.HookCommand(self.OnEditCopyCode, ID_EDIT_COPY_CODE) + self.HookCommand(self.OnEditExecClipboard, ID_EDIT_EXEC_CLIPBOARD) + mod = pywin.scintilla.IDLEenvironment.GetIDLEModule("IdleHistory") + if mod is not None: + self.history = mod.History(self.idle.text, "\n" + sys.ps2) + else: + self.history = None + # hack for now for event handling. + + # GetBlockBoundary takes a line number, and will return the + # start and and line numbers of the block, and a flag indicating if the + # block is a Python code block. + # If the line specified has a Python prompt, then the lines are parsed + # backwards and forwards, and the flag is true. + # If the line does not start with a prompt, the block is searched forward + # and backward until a prompt _is_ found, and all lines in between without + # prompts are returned, and the flag is false. + def GetBlockBoundary(self, lineNo): + line = self.DoGetLine(lineNo) + maxLineNo = self.GetLineCount() - 1 + prefix = GetPromptPrefix(line) + if prefix is None: # Non code block + flag = 0 + startLineNo = lineNo + while startLineNo > 0: + if GetPromptPrefix(self.DoGetLine(startLineNo - 1)) is not None: + break # there _is_ a prompt + startLineNo = startLineNo - 1 + endLineNo = lineNo + while endLineNo < maxLineNo: + if GetPromptPrefix(self.DoGetLine(endLineNo + 1)) is not None: + break # there _is_ a prompt + endLineNo = endLineNo + 1 + else: # Code block + flag = 1 + startLineNo = lineNo + while startLineNo > 0 and prefix != str(sys.ps1): + prefix = GetPromptPrefix(self.DoGetLine(startLineNo - 1)) + if prefix is None: + break + # there is no prompt. + startLineNo = startLineNo - 1 + endLineNo = lineNo + while endLineNo < maxLineNo: + prefix = GetPromptPrefix(self.DoGetLine(endLineNo + 1)) + if prefix is None: + break # there is no prompt + if prefix == str(sys.ps1): + break # this is another command + endLineNo = endLineNo + 1 + # continue until end of buffer, or no prompt + return (startLineNo, endLineNo, flag) + + def ExtractCommand(self, lines): + start, end = lines + retList = [] + while end >= start: + thisLine = self.DoGetLine(end) + promptLen = len(GetPromptPrefix(thisLine)) + retList = [thisLine[promptLen:]] + retList + end = end - 1 + return retList + + def OutputGrab(self): + # import win32traceutil; return + self.oldStdOut = sys.stdout + self.oldStdErr = sys.stderr + sys.stdout = self + sys.stderr = self + self.flush() + + def OutputRelease(self): + # a command may have overwritten these - only restore if not. + if self.oldStdOut is not None: + if sys.stdout == self: + sys.stdout = self.oldStdOut + if self.oldStdErr is not None: + if sys.stderr == self: + sys.stderr = self.oldStdErr + self.oldStdOut = None + self.oldStdErr = None + self.flush() + + ################################### + # + # Message/Command/Key Hooks. + # + # Enter key handler + # + def ProcessEnterEvent(self, event): + # If autocompletion has been triggered, complete and do not process event + if self.SCIAutoCActive(): + self.SCIAutoCComplete() + self.SCICancel() + return + + self.SCICancel() + # First, check for an error message + haveGrabbedOutput = 0 + if self.HandleSpecialLine(): + return 0 + + lineNo = self.LineFromChar() + start, end, isCode = self.GetBlockBoundary(lineNo) + # If we are not in a code block just go to the prompt (or create a new one) + if not isCode: + self.AppendToPrompt([]) + win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE)) + return + + lines = self.ExtractCommand((start, end)) + + # If we are in a code-block, but it isnt at the end of the buffer + # then copy it to the end ready for editing and subsequent execution + if end != self.GetLineCount() - 1: + win32ui.SetStatusText("Press ENTER to execute command") + self.AppendToPrompt(lines) + self.SetSel(-2) + return + + # If SHIFT held down, we want new code here and now! + bNeedIndent = ( + win32api.GetKeyState(win32con.VK_SHIFT) < 0 + or win32api.GetKeyState(win32con.VK_CONTROL) < 0 + ) + if bNeedIndent: + self.ReplaceSel("\n") + else: + self.SetSel(-2) + self.ReplaceSel("\n") + source = "\n".join(lines) + while source and source[-1] in "\t ": + source = source[:-1] + self.OutputGrab() # grab the output for the command exec. + try: + if self.interp.runsource( + source, "" + ): # Need more input! + bNeedIndent = 1 + else: + # If the last line isnt empty, append a newline + if self.history is not None: + self.history.history_store(source) + self.AppendToPrompt([]) + win32ui.SetStatusText( + win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE) + ) + # win32ui.SetStatusText('Successfully executed statement') + finally: + self.OutputRelease() + if bNeedIndent: + win32ui.SetStatusText("Ready to continue the command") + # Now attempt correct indentation (should use IDLE?) + curLine = self.DoGetLine(lineNo)[len(sys.ps2) :] + pos = 0 + indent = "" + while len(curLine) > pos and curLine[pos] in string.whitespace: + indent = indent + curLine[pos] + pos = pos + 1 + if _is_block_opener(curLine): + indent = indent + "\t" + elif _is_block_closer(curLine): + indent = indent[:-1] + # use ReplaceSel to ensure it goes at the cursor rather than end of buffer. + self.ReplaceSel(sys.ps2 + indent) + return 0 + + # ESC key handler + def ProcessEscEvent(self, event): + # Implement a cancel. + if self.SCIAutoCActive() or self.SCICallTipActive(): + self.SCICancel() + else: + win32ui.SetStatusText("Cancelled.") + self.AppendToPrompt(("",)) + return 0 + + def OnSelectBlock(self, command, code): + lineNo = self.LineFromChar() + start, end, isCode = self.GetBlockBoundary(lineNo) + startIndex = self.LineIndex(start) + endIndex = self.LineIndex(end + 1) - 2 # skip \r + \n + if endIndex < 0: # must be beyond end of buffer + endIndex = -2 # self.Length() + self.SetSel(startIndex, endIndex) + + def OnEditCopyCode(self, command, code): + """Sanitizes code from interactive window, removing prompts and output, + and inserts it in the clipboard.""" + code = self.GetSelText() + lines = code.splitlines() + out_lines = [] + for line in lines: + if line.startswith(sys.ps1): + line = line[len(sys.ps1) :] + out_lines.append(line) + elif line.startswith(sys.ps2): + line = line[len(sys.ps2) :] + out_lines.append(line) + out_code = os.linesep.join(out_lines) + win32clipboard.OpenClipboard() + try: + win32clipboard.SetClipboardData( + win32clipboard.CF_UNICODETEXT, str(out_code) + ) + finally: + win32clipboard.CloseClipboard() + + def OnEditExecClipboard(self, command, code): + """Executes python code directly from the clipboard.""" + win32clipboard.OpenClipboard() + try: + code = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT) + finally: + win32clipboard.CloseClipboard() + + code = code.replace("\r\n", "\n") + "\n" + try: + o = compile(code, "", "exec") + exec(o, __main__.__dict__) + except: + traceback.print_exc() + + def GetRightMenuItems(self): + # Just override parents + ret = [] + flags = 0 + ret.append((flags, win32ui.ID_EDIT_UNDO, "&Undo")) + ret.append(win32con.MF_SEPARATOR) + ret.append((flags, win32ui.ID_EDIT_CUT, "Cu&t")) + ret.append((flags, win32ui.ID_EDIT_COPY, "&Copy")) + + start, end = self.GetSel() + if start != end: + ret.append((flags, ID_EDIT_COPY_CODE, "Copy code without prompts")) + if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_UNICODETEXT): + ret.append( + (flags, ID_EDIT_EXEC_CLIPBOARD, "Execute python code from clipboard") + ) + + ret.append((flags, win32ui.ID_EDIT_PASTE, "&Paste")) + ret.append(win32con.MF_SEPARATOR) + ret.append((flags, win32ui.ID_EDIT_SELECT_ALL, "&Select all")) + ret.append((flags, win32ui.ID_EDIT_SELECT_BLOCK, "Select &block")) + ret.append((flags, win32ui.ID_VIEW_WHITESPACE, "View &Whitespace")) + return ret + + def MDINextEvent(self, event): + win32ui.GetMainFrame().MDINext(0) + + def MDIPrevEvent(self, event): + win32ui.GetMainFrame().MDINext(0) + + def WindowBackEvent(self, event): + parent = self.GetParentFrame() + if parent == win32ui.GetMainFrame(): + # It is docked. + try: + wnd, isactive = parent.MDIGetActive() + wnd.SetFocus() + except win32ui.error: + # No MDI window active! + pass + else: + # Normal Window + try: + lastActive = self.GetParentFrame().lastActive + # If the window is invalid, reset it. + if lastActive is not None and ( + lastActive._obj_ is None or lastActive.GetSafeHwnd() == 0 + ): + lastActive = self.GetParentFrame().lastActive = None + win32ui.SetStatusText("The last active Window has been closed.") + except AttributeError: + print("Can't find the last active window!") + lastActive = None + if lastActive is not None: + lastActive.MDIActivate() + + +class InteractiveView(InteractiveCore, winout.WindowOutputView): + def __init__(self, doc): + InteractiveCore.__init__(self) + winout.WindowOutputView.__init__(self, doc) + self.encoding = pywin.default_scintilla_encoding + + def _MakeColorizer(self): + return InteractiveFormatter(self) + + def OnInitialUpdate(self): + winout.WindowOutputView.OnInitialUpdate(self) + self.SetWordWrap() + self.Init() + + def HookHandlers(self): + winout.WindowOutputView.HookHandlers(self) + InteractiveCore.HookHandlers(self) + + +class CInteractivePython(winout.WindowOutput): + def __init__(self, makeDoc=None, makeFrame=None): + self.IsFinalDestroy = 0 + winout.WindowOutput.__init__( + self, + sectionProfile, + sectionProfile, + winout.flags.WQ_LINE, + 1, + None, + makeDoc, + makeFrame, + InteractiveView, + ) + self.Create() + + def OnViewDestroy(self, view): + if self.IsFinalDestroy: + view.OutputRelease() + winout.WindowOutput.OnViewDestroy(self, view) + + def Close(self): + self.IsFinalDestroy = 1 + winout.WindowOutput.Close(self) + + +class InteractiveFrame(winout.WindowOutputFrame): + def __init__(self): + self.lastActive = None + winout.WindowOutputFrame.__init__(self) + + def OnMDIActivate(self, bActive, wndActive, wndDeactive): + if bActive: + self.lastActive = wndDeactive + + +###################################################################### +## +## Dockable Window Support +## +###################################################################### +ID_DOCKED_INTERACTIVE_CONTROLBAR = 0xE802 + +DockedInteractiveViewParent = InteractiveView + + +class DockedInteractiveView(DockedInteractiveViewParent): + def HookHandlers(self): + DockedInteractiveViewParent.HookHandlers(self) + self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS) + self.HookMessage(self.OnKillFocus, win32con.WM_KILLFOCUS) + + def OnSetFocus(self, msg): + self.GetParentFrame().SetActiveView(self) + return 1 + + def OnKillFocus(self, msg): + # If we are losing focus to another in this app, reset the main frame's active view. + hwnd = wparam = msg[2] + try: + wnd = win32ui.CreateWindowFromHandle(hwnd) + reset = wnd.GetTopLevelFrame() == self.GetTopLevelFrame() + except win32ui.error: + reset = 0 # Not my window + if reset: + self.GetParentFrame().SetActiveView(None) + return 1 + + def OnDestroy(self, msg): + newSize = self.GetWindowPlacement()[4] + pywin.framework.app.SaveWindowSize("Interactive Window", newSize, "docked") + try: + if self.GetParentFrame().GetActiveView == self: + self.GetParentFrame().SetActiveView(None) + except win32ui.error: + pass + try: + if win32ui.GetMainFrame().GetActiveView() == self: + win32ui.GetMainFrame().SetActiveView(None) + except win32ui.error: + pass + return DockedInteractiveViewParent.OnDestroy(self, msg) + + +class CDockedInteractivePython(CInteractivePython): + def __init__(self, dockbar): + self.bFirstCreated = 0 + self.dockbar = dockbar + CInteractivePython.__init__(self) + + def NeedRecreateWindow(self): + if self.bCreating: + return 0 + try: + frame = win32ui.GetMainFrame() + if frame.closing: + return 0 # Dieing! + except (win32ui.error, AttributeError): + return 0 # The app is dieing! + try: + cb = frame.GetControlBar(ID_DOCKED_INTERACTIVE_CONTROLBAR) + return not cb.IsWindowVisible() + except win32ui.error: + return 1 # Control bar does not exist! + + def RecreateWindow(self): + try: + dockbar = win32ui.GetMainFrame().GetControlBar( + ID_DOCKED_INTERACTIVE_CONTROLBAR + ) + win32ui.GetMainFrame().ShowControlBar(dockbar, 1, 1) + except win32ui.error: + CreateDockedInteractiveWindow() + + def Create(self): + self.bCreating = 1 + doc = InteractiveDocument(None, self.DoCreateDoc()) + view = DockedInteractiveView(doc) + defRect = pywin.framework.app.LoadWindowSize("Interactive Window", "docked") + if defRect[2] - defRect[0] == 0: + defRect = 0, 0, 500, 200 + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER + id = 1050 # win32ui.AFX_IDW_PANE_FIRST + view.CreateWindow(self.dockbar, id, style, defRect) + view.OnInitialUpdate() + self.bFirstCreated = 1 + + self.currentView = doc.GetFirstView() + self.bCreating = 0 + if self.title: + doc.SetTitle(self.title) + + +# The factory we pass to the dockable window support. +def InteractiveViewCreator(parent): + global edit + edit = CDockedInteractivePython(parent) + return edit.currentView + + +def CreateDockedInteractiveWindow(): + # Later, the DockingBar should be capable of hosting multiple + # children. + from pywin.docking.DockingBar import DockingBar + + bar = DockingBar() + creator = InteractiveViewCreator + bar.CreateWindow( + win32ui.GetMainFrame(), + creator, + "Interactive Window", + ID_DOCKED_INTERACTIVE_CONTROLBAR, + ) + bar.SetBarStyle( + bar.GetBarStyle() + | afxres.CBRS_TOOLTIPS + | afxres.CBRS_FLYBY + | afxres.CBRS_SIZE_DYNAMIC + ) + bar.EnableDocking(afxres.CBRS_ALIGN_ANY) + win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM) + + +###################################################################### +# +# The public interface to this module. +# +###################################################################### +# No extra functionality now, but maybe later, so +# publicize these names. +InteractiveDocument = winout.WindowOutputDocument + +# We remember our one and only interactive window in the "edit" variable. +edit = None + + +def CreateInteractiveWindowUserPreference(makeDoc=None, makeFrame=None): + """Create some sort of interactive window if the user's preference say we should.""" + bCreate = LoadPreference("Show at startup", 1) + if bCreate: + CreateInteractiveWindow(makeDoc, makeFrame) + + +def CreateInteractiveWindow(makeDoc=None, makeFrame=None): + """Create a standard or docked interactive window unconditionally""" + assert edit is None, "Creating second interactive window!" + bDocking = LoadPreference("Docking", 0) + if bDocking: + CreateDockedInteractiveWindow() + else: + CreateMDIInteractiveWindow(makeDoc, makeFrame) + assert edit is not None, "Created interactive window, but did not set the global!" + edit.currentView.SetFocus() + + +def CreateMDIInteractiveWindow(makeDoc=None, makeFrame=None): + """Create a standard (non-docked) interactive window unconditionally""" + global edit + if makeDoc is None: + makeDoc = InteractiveDocument + if makeFrame is None: + makeFrame = InteractiveFrame + edit = CInteractivePython(makeDoc=makeDoc, makeFrame=makeFrame) + + +def DestroyInteractiveWindow(): + """Destroy the interactive window. + This is different to Closing the window, + which may automatically re-appear. Once destroyed, it can never be recreated, + and a complete new instance must be created (which the various other helper + functions will then do after making this call + """ + global edit + if edit is not None and edit.currentView is not None: + if edit.currentView.GetParentFrame() == win32ui.GetMainFrame(): + # It is docked - do nothing now (this is only called at shutdown!) + pass + else: + # It is a standard window - call Close on the container. + edit.Close() + edit = None + + +def CloseInteractiveWindow(): + """Close the interactive window, allowing it to be re-created on demand.""" + global edit + if edit is not None and edit.currentView is not None: + if edit.currentView.GetParentFrame() == win32ui.GetMainFrame(): + # It is docked, just hide the dock bar. + frame = win32ui.GetMainFrame() + cb = frame.GetControlBar(ID_DOCKED_INTERACTIVE_CONTROLBAR) + frame.ShowControlBar(cb, 0, 1) + else: + # It is a standard window - destroy the frame/view, allowing the object itself to remain. + edit.currentView.GetParentFrame().DestroyWindow() + + +def ToggleInteractiveWindow(): + """If the interactive window is visible, hide it, otherwise show it.""" + if edit is None: + CreateInteractiveWindow() + else: + if edit.NeedRecreateWindow(): + edit.RecreateWindow() + else: + # Close it, allowing a reopen. + CloseInteractiveWindow() + + +def ShowInteractiveWindow(): + """Shows (or creates if necessary) an interactive window""" + if edit is None: + CreateInteractiveWindow() + else: + if edit.NeedRecreateWindow(): + edit.RecreateWindow() + else: + parent = edit.currentView.GetParentFrame() + if parent == win32ui.GetMainFrame(): # It is docked. + edit.currentView.SetFocus() + else: # It is a "normal" window + edit.currentView.GetParentFrame().AutoRestore() + win32ui.GetMainFrame().MDIActivate(edit.currentView.GetParentFrame()) + + +def IsInteractiveWindowVisible(): + return edit is not None and not edit.NeedRecreateWindow() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/intpyapp.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/intpyapp.py new file mode 100644 index 0000000000000000000000000000000000000000..48461dbab079a2493a30cd25d5eee9527274ec7b --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/intpyapp.py @@ -0,0 +1,555 @@ +# intpyapp.py - Interactive Python application class +# +import os +import sys +import traceback + +import __main__ +import commctrl +import win32api +import win32con +import win32ui +from pywin.mfc import afxres, dialog + +from . import app, dbgcommands + +lastLocateFileName = ".py" # used in the "File/Locate" dialog... + + +# todo - _SetupSharedMenu should be moved to a framework class. +def _SetupSharedMenu_(self): + sharedMenu = self.GetSharedMenu() + from pywin.framework import toolmenu + + toolmenu.SetToolsMenu(sharedMenu) + from pywin.framework import help + + help.SetHelpMenuOtherHelp(sharedMenu) + + +from pywin.mfc import docview + +docview.DocTemplate._SetupSharedMenu_ = _SetupSharedMenu_ + + +class MainFrame(app.MainFrame): + def OnCreate(self, createStruct): + self.closing = 0 + if app.MainFrame.OnCreate(self, createStruct) == -1: + return -1 + style = ( + win32con.WS_CHILD + | afxres.CBRS_SIZE_DYNAMIC + | afxres.CBRS_TOP + | afxres.CBRS_TOOLTIPS + | afxres.CBRS_FLYBY + ) + + self.EnableDocking(afxres.CBRS_ALIGN_ANY) + + tb = win32ui.CreateToolBar(self, style | win32con.WS_VISIBLE) + tb.ModifyStyle(0, commctrl.TBSTYLE_FLAT) + tb.LoadToolBar(win32ui.IDR_MAINFRAME) + tb.EnableDocking(afxres.CBRS_ALIGN_ANY) + tb.SetWindowText("Standard") + self.DockControlBar(tb) + # Any other packages which use toolbars + from pywin.debugger.debugger import PrepareControlBars + + PrepareControlBars(self) + # Note "interact" also uses dockable windows, but they already happen + + # And a "Tools" menu on the main frame. + menu = self.GetMenu() + from . import toolmenu + + toolmenu.SetToolsMenu(menu, 2) + # And fix the "Help" menu on the main frame + from pywin.framework import help + + help.SetHelpMenuOtherHelp(menu) + + def OnClose(self): + try: + import pywin.debugger + + if ( + pywin.debugger.currentDebugger is not None + and pywin.debugger.currentDebugger.pumping + ): + try: + pywin.debugger.currentDebugger.close(1) + except: + traceback.print_exc() + return + except win32ui.error: + pass + self.closing = 1 + self.SaveBarState("ToolbarDefault") + self.SetActiveView(None) # Otherwise MFC's OnClose may _not_ prompt for save. + + from pywin.framework import help + + help.FinalizeHelp() + + self.DestroyControlBar(afxres.AFX_IDW_TOOLBAR) + self.DestroyControlBar(win32ui.ID_VIEW_TOOLBAR_DBG) + + return self._obj_.OnClose() + + def DestroyControlBar(self, id): + try: + bar = self.GetControlBar(id) + except win32ui.error: + return + bar.DestroyWindow() + + def OnCommand(self, wparam, lparam): + # By default, the current MDI child frame will process WM_COMMAND + # messages before any docked control bars - even if the control bar + # has focus. This is a problem for the interactive window when docked. + # Therefore, we detect the situation of a view having the main frame + # as its parent, and assume it must be a docked view (which it will in an MDI app) + try: + v = ( + self.GetActiveView() + ) # Raise an exception if none - good - then we want default handling + # Main frame _does_ have a current view (ie, a docking view) - see if it wants it. + if v.OnCommand(wparam, lparam): + return 1 + except (win32ui.error, AttributeError): + pass + return self._obj_.OnCommand(wparam, lparam) + + +class InteractivePythonApp(app.CApp): + # This works if necessary - just we dont need to override the Run method. + # def Run(self): + # return self._obj_.Run() + + def HookCommands(self): + app.CApp.HookCommands(self) + dbgcommands.DebuggerCommandHandler().HookCommands() + self.HookCommand(self.OnViewBrowse, win32ui.ID_VIEW_BROWSE) + self.HookCommand(self.OnFileImport, win32ui.ID_FILE_IMPORT) + self.HookCommand(self.OnFileCheck, win32ui.ID_FILE_CHECK) + self.HookCommandUpdate(self.OnUpdateFileCheck, win32ui.ID_FILE_CHECK) + self.HookCommand(self.OnFileRun, win32ui.ID_FILE_RUN) + self.HookCommand(self.OnFileLocate, win32ui.ID_FILE_LOCATE) + self.HookCommand(self.OnInteractiveWindow, win32ui.ID_VIEW_INTERACTIVE) + self.HookCommandUpdate( + self.OnUpdateInteractiveWindow, win32ui.ID_VIEW_INTERACTIVE + ) + self.HookCommand(self.OnViewOptions, win32ui.ID_VIEW_OPTIONS) + self.HookCommand(self.OnHelpIndex, afxres.ID_HELP_INDEX) + self.HookCommand(self.OnFileSaveAll, win32ui.ID_FILE_SAVE_ALL) + self.HookCommand(self.OnViewToolbarDbg, win32ui.ID_VIEW_TOOLBAR_DBG) + self.HookCommandUpdate(self.OnUpdateViewToolbarDbg, win32ui.ID_VIEW_TOOLBAR_DBG) + + def CreateMainFrame(self): + return MainFrame() + + def MakeExistingDDEConnection(self): + # Use DDE to connect to an existing instance + # Return None if no existing instance + try: + from . import intpydde + except ImportError: + # No dde support! + return None + conv = intpydde.CreateConversation(self.ddeServer) + try: + conv.ConnectTo("Pythonwin", "System") + return conv + except intpydde.error: + return None + + def InitDDE(self): + # Do all the magic DDE handling. + # Returns TRUE if we have pumped the arguments to our + # remote DDE app, and we should terminate. + try: + from . import intpydde + except ImportError: + self.ddeServer = None + intpydde = None + if intpydde is not None: + self.ddeServer = intpydde.DDEServer(self) + self.ddeServer.Create("Pythonwin", intpydde.CBF_FAIL_SELFCONNECTIONS) + try: + # If there is an existing instance, pump the arguments to it. + connection = self.MakeExistingDDEConnection() + if connection is not None: + connection.Exec("self.Activate()") + if self.ProcessArgs(sys.argv, connection) is None: + return 1 + except: + # It is too early to 'print' an exception - we + # don't have stdout setup yet! + win32ui.DisplayTraceback( + sys.exc_info(), " - error in DDE conversation with Pythonwin" + ) + return 1 + + def InitInstance(self): + # Allow "/nodde" and "/new" to optimize this! + if ( + "/nodde" not in sys.argv + and "/new" not in sys.argv + and "-nodde" not in sys.argv + and "-new" not in sys.argv + ): + if self.InitDDE(): + return 1 # A remote DDE client is doing it for us! + else: + self.ddeServer = None + + win32ui.SetRegistryKey( + "Python %s" % (sys.winver,) + ) # MFC automatically puts the main frame caption on! + app.CApp.InitInstance(self) + + # Create the taskbar icon + win32ui.CreateDebuggerThread() + + # Allow Pythonwin to host OCX controls. + win32ui.EnableControlContainer() + + # Display the interactive window if the user wants it. + from . import interact + + interact.CreateInteractiveWindowUserPreference() + + # Load the modules we use internally. + self.LoadSystemModules() + + # Load additional module the user may want. + self.LoadUserModules() + + # Load the ToolBar state near the end of the init process, as + # there may be Toolbar IDs created by the user or other modules. + # By now all these modules should be loaded, so all the toolbar IDs loaded. + try: + self.frame.LoadBarState("ToolbarDefault") + except win32ui.error: + # MFC sucks. It does essentially "GetDlgItem(x)->Something", so if the + # toolbar with ID x does not exist, MFC crashes! Pythonwin has a trap for this + # but I need to investigate more how to prevent it (AFAIK, ensuring all the + # toolbars are created by now _should_ stop it!) + pass + + # Finally process the command line arguments. + try: + self.ProcessArgs(sys.argv) + except: + # too early for printing anything. + win32ui.DisplayTraceback( + sys.exc_info(), " - error processing command line args" + ) + + def ExitInstance(self): + win32ui.DestroyDebuggerThread() + try: + from . import interact + + interact.DestroyInteractiveWindow() + except: + pass + if self.ddeServer is not None: + self.ddeServer.Shutdown() + self.ddeServer = None + return app.CApp.ExitInstance(self) + + def Activate(self): + # Bring to the foreground. Mainly used when another app starts up, it asks + # this one to activate itself, then it terminates. + frame = win32ui.GetMainFrame() + frame.SetForegroundWindow() + if frame.GetWindowPlacement()[1] == win32con.SW_SHOWMINIMIZED: + frame.ShowWindow(win32con.SW_RESTORE) + + def ProcessArgs(self, args, dde=None): + # If we are going to talk to a remote app via DDE, then + # activate it! + if ( + len(args) < 1 or not args[0] + ): # argv[0]=='' when started without args, just like Python.exe! + return + + i = 0 + while i < len(args): + argType = args[i] + i += 1 + if argType.startswith("-"): + # Support dash options. Slash options are misinterpreted by python init + # as path and not finding usually 'C:\\' ends up in sys.path[0] + argType = "/" + argType[1:] + if not argType.startswith("/"): + argType = win32ui.GetProfileVal( + "Python", "Default Arg Type", "/edit" + ).lower() + i -= 1 # arg is /edit's parameter + par = i < len(args) and args[i] or "MISSING" + if argType in ("/nodde", "/new", "-nodde", "-new"): + # Already handled + pass + elif argType.startswith("/goto:"): + gotoline = int(argType[len("/goto:") :]) + if dde: + dde.Exec( + "from pywin.framework import scriptutils\n" + "ed = scriptutils.GetActiveEditControl()\n" + "if ed: ed.SetSel(ed.LineIndex(%s - 1))" % gotoline + ) + else: + from . import scriptutils + + ed = scriptutils.GetActiveEditControl() + if ed: + ed.SetSel(ed.LineIndex(gotoline - 1)) + elif argType == "/edit": + # Load up the default application. + i += 1 + fname = win32api.GetFullPathName(par) + if not os.path.isfile(fname): + # if we don't catch this, OpenDocumentFile() (actually + # PyCDocument.SetPathName() in + # pywin.scintilla.document.CScintillaDocument.OnOpenDocument) + # segfaults Pythonwin on recent PY3 builds (b228) + win32ui.MessageBox( + "No such file: %s\n\nCommand Line: %s" + % (fname, win32api.GetCommandLine()), + "Open file for edit", + win32con.MB_ICONERROR, + ) + continue + if dde: + dde.Exec("win32ui.GetApp().OpenDocumentFile(%s)" % (repr(fname))) + else: + win32ui.GetApp().OpenDocumentFile(par) + elif argType == "/rundlg": + if dde: + dde.Exec( + "from pywin.framework import scriptutils;scriptutils.RunScript(%r, %r, 1)" + % (par, " ".join(args[i + 1 :])) + ) + else: + from . import scriptutils + + scriptutils.RunScript(par, " ".join(args[i + 1 :])) + return + elif argType == "/run": + if dde: + dde.Exec( + "from pywin.framework import scriptutils;scriptutils.RunScript(%r, %r, 0)" + % (par, " ".join(args[i + 1 :])) + ) + else: + from . import scriptutils + + scriptutils.RunScript(par, " ".join(args[i + 1 :]), 0) + return + elif argType == "/app": + raise RuntimeError( + "/app only supported for new instances of Pythonwin.exe" + ) + elif argType == "/dde": # Send arbitary command + if dde is not None: + dde.Exec(par) + else: + win32ui.MessageBox( + "The /dde command can only be used\r\nwhen Pythonwin is already running" + ) + i += 1 + else: + raise ValueError("Command line argument not recognised: %s" % argType) + + def LoadSystemModules(self): + self.DoLoadModules("pywin.framework.editor,pywin.framework.stdin") + + def LoadUserModules(self, moduleNames=None): + # Load the users modules. + if moduleNames is None: + default = "pywin.framework.sgrepmdi,pywin.framework.mdi_pychecker" + moduleNames = win32ui.GetProfileVal("Python", "Startup Modules", default) + self.DoLoadModules(moduleNames) + + def DoLoadModules(self, moduleNames): # ", sep string of module names. + if not moduleNames: + return + modules = moduleNames.split(",") + for module in modules: + try: + __import__(module) + except: # Catch em all, else the app itself dies! 'ImportError: + traceback.print_exc() + msg = 'Startup import of user module "%s" failed' % module + print(msg) + win32ui.MessageBox(msg) + + # + # DDE Callback + # + def OnDDECommand(self, command): + try: + exec(command + "\n") + except: + print("ERROR executing DDE command: ", command) + traceback.print_exc() + raise + + # + # General handlers + # + def OnViewBrowse(self, id, code): + "Called when ViewBrowse message is received" + from pywin.tools import browser + + obName = dialog.GetSimpleInput("Object", "__builtins__", "Browse Python Object") + if obName is None: + return + try: + browser.Browse(eval(obName, __main__.__dict__, __main__.__dict__)) + except NameError: + win32ui.MessageBox("This is no object with this name") + except AttributeError: + win32ui.MessageBox("The object has no attribute of that name") + except: + traceback.print_exc() + win32ui.MessageBox("This object can not be browsed") + + def OnFileImport(self, id, code): + "Called when a FileImport message is received. Import the current or specified file" + from . import scriptutils + + scriptutils.ImportFile() + + def OnFileCheck(self, id, code): + "Called when a FileCheck message is received. Check the current file." + from . import scriptutils + + scriptutils.CheckFile() + + def OnUpdateFileCheck(self, cmdui): + from . import scriptutils + + cmdui.Enable(scriptutils.GetActiveFileName(0) is not None) + + def OnFileRun(self, id, code): + "Called when a FileRun message is received." + from . import scriptutils + + showDlg = win32api.GetKeyState(win32con.VK_SHIFT) >= 0 + scriptutils.RunScript(None, None, showDlg) + + def OnFileLocate(self, id, code): + from . import scriptutils + + global lastLocateFileName # save the new version away for next time... + + name = dialog.GetSimpleInput( + "File name", lastLocateFileName, "Locate Python File" + ) + if name is None: # Cancelled. + return + lastLocateFileName = name + # if ".py" supplied, rip it off! + # should also check for .pys and .pyw + if lastLocateFileName[-3:].lower() == ".py": + lastLocateFileName = lastLocateFileName[:-3] + lastLocateFileName = lastLocateFileName.replace(".", "\\") + newName = scriptutils.LocatePythonFile(lastLocateFileName) + if newName is None: + win32ui.MessageBox("The file '%s' can not be located" % lastLocateFileName) + else: + win32ui.GetApp().OpenDocumentFile(newName) + + # Display all the "options" proprety pages we can find + def OnViewOptions(self, id, code): + win32ui.InitRichEdit() + sheet = dialog.PropertySheet("Pythonwin Options") + # Add property pages we know about that need manual work. + from pywin.dialogs import ideoptions + + sheet.AddPage(ideoptions.OptionsPropPage()) + + from . import toolmenu + + sheet.AddPage(toolmenu.ToolMenuPropPage()) + + # Get other dynamic pages from templates. + pages = [] + for template in self.GetDocTemplateList(): + try: + # Dont actually call the function with the exception handler. + getter = template.GetPythonPropertyPages + except AttributeError: + # Template does not provide property pages! + continue + pages = pages + getter() + + # Debugger template goes at the end + try: + from pywin.debugger import configui + except ImportError: + configui = None + if configui is not None: + pages.append(configui.DebuggerOptionsPropPage()) + # Now simply add the pages, and display the dialog. + for page in pages: + sheet.AddPage(page) + + if sheet.DoModal() == win32con.IDOK: + win32ui.SetStatusText("Applying configuration changes...", 1) + win32ui.DoWaitCursor(1) + # Tell every Window in our app that win.ini has changed! + win32ui.GetMainFrame().SendMessageToDescendants( + win32con.WM_WININICHANGE, 0, 0 + ) + win32ui.DoWaitCursor(0) + + def OnInteractiveWindow(self, id, code): + # toggle the existing state. + from . import interact + + interact.ToggleInteractiveWindow() + + def OnUpdateInteractiveWindow(self, cmdui): + try: + interact = sys.modules["pywin.framework.interact"] + state = interact.IsInteractiveWindowVisible() + except KeyError: # Interactive module hasnt ever been imported. + state = 0 + cmdui.Enable() + cmdui.SetCheck(state) + + def OnFileSaveAll(self, id, code): + # Only attempt to save editor documents. + from pywin.framework.editor import editorTemplate + + num = 0 + for doc in editorTemplate.GetDocumentList(): + if doc.IsModified() and doc.GetPathName(): + num = num = 1 + doc.OnSaveDocument(doc.GetPathName()) + win32ui.SetStatusText("%d documents saved" % num, 1) + + def OnViewToolbarDbg(self, id, code): + if code == 0: + return not win32ui.GetMainFrame().OnBarCheck(id) + + def OnUpdateViewToolbarDbg(self, cmdui): + win32ui.GetMainFrame().OnUpdateControlBarMenu(cmdui) + cmdui.Enable(1) + + def OnHelpIndex(self, id, code): + from . import help + + help.SelectAndRunHelpFile() + + +# As per the comments in app.py, this use is depreciated. +# app.AppBuilder = InteractivePythonApp + +# Now all we do is create the application +thisApp = InteractivePythonApp() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/intpydde.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/intpydde.py new file mode 100644 index 0000000000000000000000000000000000000000..1f869b0f68f9fbf20324a0eead3fbb2110e68eb2 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/intpydde.py @@ -0,0 +1,60 @@ +# DDE support for Pythonwin +# +# Seems to work fine (in the context that IE4 seems to have broken +# DDE on _all_ NT4 machines I have tried, but only when a "Command Prompt" window +# is open. Strange, but true. If you have problems with this, close all Command Prompts! + + +import sys +import traceback + +import win32api +import win32ui +from dde import * +from pywin.mfc import object + + +class DDESystemTopic(object.Object): + def __init__(self, app): + self.app = app + object.Object.__init__(self, CreateServerSystemTopic()) + + def Exec(self, data): + try: + # print "Executing", cmd + self.app.OnDDECommand(data) + except: + t, v, tb = sys.exc_info() + # The DDE Execution failed. + print("Error executing DDE command.") + traceback.print_exception(t, v, tb) + return 0 + + +class DDEServer(object.Object): + def __init__(self, app): + self.app = app + object.Object.__init__(self, CreateServer()) + self.topic = self.item = None + + def CreateSystemTopic(self): + return DDESystemTopic(self.app) + + def Shutdown(self): + self._obj_.Shutdown() + self._obj_.Destroy() + if self.topic is not None: + self.topic.Destroy() + self.topic = None + if self.item is not None: + self.item.Destroy() + self.item = None + + def OnCreate(self): + return 1 + + def Status(self, msg): + try: + win32ui.SetStatusText(msg) + except win32ui.error: + pass diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/mdi_pychecker.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/mdi_pychecker.py new file mode 100644 index 0000000000000000000000000000000000000000..c89f33b9b9622961fac5f2c8388408bad0310da1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/mdi_pychecker.py @@ -0,0 +1,849 @@ +###################################################################### +## +## The Pychecker MDI Plug-In UserModule for Pythonwin +## +## contributed by Robert Kiendl +## +## Style is similar to (and inherited) from the SGrepMDI UserModule +## +## Usage: +## +## Start Pychecker on current file: Menu/File/New../Pychecker. +## Use it: Jump to Pychecker warning source lines by double-click. +## Auto-add "#$pycheck_no" / "#$pycheck_no=specific-re-pattern" tags +## to source lines by context/right-mouse-click on warning lines. +## +## It requires pychecker installed and the pychecker.bat to be on +## the PATH. Example pychecker.bat: +## +## REM pychecker.bat +## C:\bin\python.exe C:\PYTHON23\Lib\site-packages\pychecker\checker.py %1 %2 %3 %4 %5 %6 %7 %8 %9 +## +## Adding it as default module in PythonWin: +## +## +++ ./intpyapp.py 2006-10-02 17:59:32.974161600 +0200 +## @@ -272,7 +282,7 @@ +## def LoadUserModules(self, moduleNames = None): +## # Load the users modules. +## if moduleNames is None: +## - default = "sgrepmdi" +## + default = "sgrepmdi,mdi_pychecker" +## moduleNames=win32ui.GetProfileVal('Python','Startup Modules',default) +## self.DoLoadModules(moduleNames) +## +###################################################################### + +import glob +import os +import re +import sys +import time + +import win32api +import win32con +import win32ui +from pywin.mfc import dialog, docview, window + +from . import scriptutils + + +def getsubdirs(d): + dlist = [] + flist = glob.glob(d + "\\*") + for f in flist: + if os.path.isdir(f): + dlist.append(f) + dlist = dlist + getsubdirs(f) + return dlist + + +class dirpath: + def __init__(self, str, recurse=0): + dp = str.split(";") + dirs = {} + for d in dp: + if os.path.isdir(d): + d = d.lower() + if d not in dirs: + dirs[d] = None + if recurse: + subdirs = getsubdirs(d) + for sd in subdirs: + sd = sd.lower() + if sd not in dirs: + dirs[sd] = None + elif os.path.isfile(d): + pass + else: + x = None + if d in os.environ: + x = dirpath(os.environ[d]) + elif d[:5] == "HKEY_": + keystr = d.split("\\") + try: + root = eval("win32con." + keystr[0]) + except: + win32ui.MessageBox( + "Can't interpret registry key name '%s'" % keystr[0] + ) + try: + subkey = "\\".join(keystr[1:]) + val = win32api.RegQueryValue(root, subkey) + if val: + x = dirpath(val) + else: + win32ui.MessageBox( + "Registry path '%s' did not return a path entry" % d + ) + except: + win32ui.MessageBox( + "Can't interpret registry key value: %s" % keystr[1:] + ) + else: + win32ui.MessageBox("Directory '%s' not found" % d) + if x: + for xd in x: + if xd not in dirs: + dirs[xd] = None + if recurse: + subdirs = getsubdirs(xd) + for sd in subdirs: + sd = sd.lower() + if sd not in dirs: + dirs[sd] = None + self.dirs = [] + for d in dirs.keys(): + self.dirs.append(d) + + def __getitem__(self, key): + return self.dirs[key] + + def __len__(self): + return len(self.dirs) + + def __setitem__(self, key, value): + self.dirs[key] = value + + def __delitem__(self, key): + del self.dirs[key] + + def __getslice__(self, lo, hi): + return self.dirs[lo:hi] + + def __setslice__(self, lo, hi, seq): + self.dirs[lo:hi] = seq + + def __delslice__(self, lo, hi): + del self.dirs[lo:hi] + + def __add__(self, other): + if type(other) == type(self) or type(other) == type([]): + return self.dirs + other.dirs + + def __radd__(self, other): + if type(other) == type(self) or type(other) == type([]): + return other.dirs + self.dirs + + +# Group(1) is the filename, group(2) is the lineno. +# regexGrepResult=regex.compile("^\\([a-zA-Z]:.*\\)(\\([0-9]+\\))") +# regexGrep=re.compile(r"^([a-zA-Z]:[^(]*)\((\d+)\)") +regexGrep = re.compile(r"^(..[^\(:]+)?[\(:](\d+)[\):]:?\s*(.*)") + +# these are the atom numbers defined by Windows for basic dialog controls + +BUTTON = 0x80 +EDIT = 0x81 +STATIC = 0x82 +LISTBOX = 0x83 +SCROLLBAR = 0x84 +COMBOBOX = 0x85 + + +class TheTemplate(docview.RichEditDocTemplate): + def __init__(self): + docview.RichEditDocTemplate.__init__( + self, win32ui.IDR_TEXTTYPE, TheDocument, TheFrame, TheView + ) + self.SetDocStrings( + "\nPychecker\nPychecker\nPychecker params (*.pychecker)\n.pychecker\n\n\n" + ) + win32ui.GetApp().AddDocTemplate(self) + self.docparams = None + + def MatchDocType(self, fileName, fileType): + doc = self.FindOpenDocument(fileName) + if doc: + return doc + ext = os.path.splitext(fileName)[1].lower() + if ext == ".pychecker": + return win32ui.CDocTemplate_Confidence_yesAttemptNative + return win32ui.CDocTemplate_Confidence_noAttempt + + def setParams(self, params): + self.docparams = params + + def readParams(self): + tmp = self.docparams + self.docparams = None + return tmp + + +class TheFrame(window.MDIChildWnd): + # The template and doc params will one day be removed. + def __init__(self, wnd=None): + window.MDIChildWnd.__init__(self, wnd) + + +class TheDocument(docview.RichEditDoc): + def __init__(self, template): + docview.RichEditDoc.__init__(self, template) + self.dirpattern = "" + self.filpattern = "" + self.greppattern = "" + self.casesensitive = 1 + self.recurse = 1 + self.verbose = 0 + + def OnOpenDocument(self, fnm): + # this bizarre stuff with params is so right clicking in a result window + # and starting a new grep can communicate the default parameters to the + # new grep. + try: + params = open(fnm, "r").read() + except: + params = None + self.setInitParams(params) + return self.OnNewDocument() + + def OnCloseDocument(self): + try: + win32ui.GetApp().DeleteIdleHandler(self.idleHandler) + except: + pass + return self._obj_.OnCloseDocument() + + def saveInitParams(self): + # Only save the flags, not the text boxes. + paramstr = "\t\t\t%d\t%d" % (self.casesensitive, self.recurse) + win32ui.WriteProfileVal("Pychecker", "Params", paramstr) + + def setInitParams(self, paramstr): + if paramstr is None: + paramstr = win32ui.GetProfileVal("Pychecker", "Params", "\t\t\t1\t0\t0") + params = paramstr.split("\t") + if len(params) < 3: + params = params + [""] * (3 - len(params)) + if len(params) < 6: + params = params + [0] * (6 - len(params)) + self.dirpattern = params[0] + self.filpattern = params[1] + self.greppattern = params[2] or "-#1000 --only" + self.casesensitive = int(params[3]) + self.recurse = int(params[4]) + self.verbose = int(params[5]) + # setup some reasonable defaults. + if not self.dirpattern: + try: + editor = win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView() + self.dirpattern = os.path.abspath( + os.path.dirname(editor.GetDocument().GetPathName()) + ) + except (AttributeError, win32ui.error): + self.dirpattern = os.getcwd() + if not self.filpattern: + try: + editor = win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView() + self.filpattern = editor.GetDocument().GetPathName() + except AttributeError: + self.filpattern = "*.py" + + def OnNewDocument(self): + if self.dirpattern == "": + self.setInitParams(greptemplate.readParams()) + d = TheDialog( + self.dirpattern, + self.filpattern, + self.greppattern, + self.casesensitive, + self.recurse, + self.verbose, + ) + if d.DoModal() == win32con.IDOK: + self.dirpattern = d["dirpattern"] + self.filpattern = d["filpattern"] + self.greppattern = d["greppattern"] + # self.casesensitive = d['casesensitive'] + # self.recurse = d['recursive'] + # self.verbose = d['verbose'] + self.doSearch() + self.saveInitParams() + return 1 + return 0 # cancelled - return zero to stop frame creation. + + def doSearch(self): + self.dp = dirpath(self.dirpattern, self.recurse) + self.SetTitle( + "Pychecker Run '%s' (options: %s)" % (self.filpattern, self.greppattern) + ) + # self.text = [] + self.GetFirstView().Append( + "#Pychecker Run in " + self.dirpattern + " %s\n" % time.asctime() + ) + if self.verbose: + self.GetFirstView().Append("# =" + repr(self.dp.dirs) + "\n") + self.GetFirstView().Append("# Files " + self.filpattern + "\n") + self.GetFirstView().Append("# Options " + self.greppattern + "\n") + self.fplist = self.filpattern.split(";") + self.GetFirstView().Append( + "# Running... ( double click on result lines in order to jump to the source code ) \n" + ) + win32ui.SetStatusText("Pychecker running. Please wait...", 0) + self.dpndx = self.fpndx = 0 + self.fndx = -1 + if not self.dp: + self.GetFirstView().Append( + "# ERROR: '%s' does not resolve to any search locations" + % self.dirpattern + ) + self.SetModifiedFlag(0) + else: + ##self.flist = glob.glob(self.dp[0]+'\\'+self.fplist[0]) + import operator + + self.flist = reduce(operator.add, list(map(glob.glob, self.fplist))) + # import pywin.debugger;pywin.debugger.set_trace() + self.startPycheckerRun() + + def idleHandler(self, handler, count): + import time + + time.sleep(0.001) + if self.result != None: + win32ui.GetApp().DeleteIdleHandler(self.idleHandler) + return 0 + return 1 # more + + def startPycheckerRun(self): + self.result = None + old = win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_APPSTARTING)) + win32ui.GetApp().AddIdleHandler(self.idleHandler) + import _thread + + _thread.start_new(self.threadPycheckerRun, ()) + ##win32api.SetCursor(old) + + def threadPycheckerRun(self): + result = "" + rc = -1 + try: + options = self.greppattern + files = " ".join(self.flist) + # Recently MarkH has failed to run pychecker without it having + # been explicitly installed - so we assume it is and locate it + # from its default location. + # Step1 - get python.exe + py = os.path.join(sys.prefix, "python.exe") + if not os.path.isfile(py): + if "64 bit" in sys.version: + py = os.path.join(sys.prefix, "PCBuild", "amd64", "python.exe") + else: + py = os.path.join(sys.prefix, "PCBuild", "python.exe") + try: + py = win32api.GetShortPathName(py) + except win32api.error: + py = "" + # Find checker.py + import sysconfig + + pychecker = os.path.join( + sysconfig.get_paths()["purelib"], "pychecker", "checker.py" + ) + if not os.path.isfile(py): + result = "Can't find python.exe!\n" + elif not os.path.isfile(pychecker): + result = ( + "Can't find checker.py - please install pychecker " + "(or run 'setup.py install' if you have the source version)\n" + ) + else: + cmd = '%s "%s" %s %s 2>&1' % (py, pychecker, options, files) + ##fin,fout,ferr=os.popen3(cmd) + ##result=ferr.read()+fout.read() + result = os.popen(cmd).read() + ##rc=f.close() + self.GetFirstView().Append(result) + finally: + self.result = result + print("== Pychecker run finished ==") + self.GetFirstView().Append("\n" + "== Pychecker run finished ==") + self.SetModifiedFlag(0) + + def _inactive_idleHandler(self, handler, count): + self.fndx = self.fndx + 1 + if self.fndx < len(self.flist): + f = self.flist[self.fndx] + if self.verbose: + self.GetFirstView().Append("# .." + f + "\n") + win32ui.SetStatusText("Searching " + f, 0) + lines = open(f, "r").readlines() + for i in range(len(lines)): + line = lines[i] + if self.pat.search(line) != None: + self.GetFirstView().Append(f + "(" + repr(i + 1) + ") " + line) + else: + self.fndx = -1 + self.fpndx = self.fpndx + 1 + if self.fpndx < len(self.fplist): + self.flist = glob.glob( + self.dp[self.dpndx] + "\\" + self.fplist[self.fpndx] + ) + else: + self.fpndx = 0 + self.dpndx = self.dpndx + 1 + if self.dpndx < len(self.dp): + self.flist = glob.glob( + self.dp[self.dpndx] + "\\" + self.fplist[self.fpndx] + ) + else: + win32ui.SetStatusText("Search complete.", 0) + self.SetModifiedFlag(0) # default to not modified. + try: + win32ui.GetApp().DeleteIdleHandler(self.idleHandler) + except: + pass + return 0 + return 1 + + def GetParams(self): + return ( + self.dirpattern + + "\t" + + self.filpattern + + "\t" + + self.greppattern + + "\t" + + repr(self.casesensitive) + + "\t" + + repr(self.recurse) + + "\t" + + repr(self.verbose) + ) + + def OnSaveDocument(self, filename): + # print 'OnSaveDocument() filename=',filename + savefile = open(filename, "wb") + txt = self.GetParams() + "\n" + # print 'writing',txt + savefile.write(txt) + savefile.close() + self.SetModifiedFlag(0) + return 1 + + +ID_OPEN_FILE = 0xE500 +ID_PYCHECKER = 0xE501 +ID_SAVERESULTS = 0x502 +ID_TRYAGAIN = 0x503 +ID_ADDCOMMENT = 0x504 +ID_ADDPYCHECKNO2 = 0x505 + + +class TheView(docview.RichEditView): + def __init__(self, doc): + docview.RichEditView.__init__(self, doc) + self.SetWordWrap(win32ui.CRichEditView_WrapNone) + self.HookHandlers() + + def OnInitialUpdate(self): + rc = self._obj_.OnInitialUpdate() + format = (-402653169, 0, 200, 0, 0, 0, 49, "Courier New") + self.SetDefaultCharFormat(format) + return rc + + def HookHandlers(self): + self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN) + self.HookCommand(self.OnCmdOpenFile, ID_OPEN_FILE) + self.HookCommand(self.OnCmdThe, ID_PYCHECKER) + self.HookCommand(self.OnCmdSave, ID_SAVERESULTS) + self.HookCommand(self.OnTryAgain, ID_TRYAGAIN) + self.HookCommand(self.OnAddComment, ID_ADDCOMMENT) + self.HookCommand(self.OnAddComment, ID_ADDPYCHECKNO2) + self.HookMessage(self.OnLDblClick, win32con.WM_LBUTTONDBLCLK) + + def OnLDblClick(self, params): + line = self.GetLine() + regexGrepResult = regexGrep.match(line) + if regexGrepResult: + fname = regexGrepResult.group(1) + line = int(regexGrepResult.group(2)) + scriptutils.JumpToDocument(fname, line) + return 0 # dont pass on + return 1 # pass it on by default. + + def OnRClick(self, params): + menu = win32ui.CreatePopupMenu() + flags = win32con.MF_STRING | win32con.MF_ENABLED + lineno = self._obj_.LineFromChar(-1) # selection or current line + line = self._obj_.GetLine(lineno) + regexGrepResult = regexGrep.match(line) + charstart, charend = self._obj_.GetSel() + if regexGrepResult: + self.fnm = regexGrepResult.group(1) + self.lnnum = int(regexGrepResult.group(2)) + menu.AppendMenu(flags, ID_OPEN_FILE, "&Open " + self.fnm) + menu.AppendMenu( + flags, ID_ADDCOMMENT, "&Add to source: Comment Tag/#$pycheck_no .." + ) + menu.AppendMenu( + flags, + ID_ADDPYCHECKNO2, + "&Add to source: Specific #$pycheck_no=%(errtext)s ..", + ) + menu.AppendMenu(win32con.MF_SEPARATOR) + menu.AppendMenu(flags, ID_TRYAGAIN, "&Try Again") + menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, "Cu&t") + menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, "&Copy") + menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, "&Paste") + menu.AppendMenu(flags, win32con.MF_SEPARATOR) + menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, "&Select all") + menu.AppendMenu(flags, win32con.MF_SEPARATOR) + menu.AppendMenu(flags, ID_SAVERESULTS, "Sa&ve results") + menu.TrackPopupMenu(params[5]) + return 0 + + def OnAddComment(self, cmd, code): + addspecific = cmd == ID_ADDPYCHECKNO2 + _ = list(self.GetSel()) + _.sort() + start, end = _ + line_start, line_end = self.LineFromChar(start), self.LineFromChar(end) + first = 1 + for i in range(line_start, line_end + 1): + line = self.GetLine(i) + m = regexGrep.match(line) + if m: + if first: + first = 0 + cmnt = dialog.GetSimpleInput( + "Add to %s lines" % (line_end - line_start + 1), + addspecific + and " #$pycheck_no=%(errtext)s" + or " #$pycheck_no", + ) + if not cmnt: + return 0 + ##import pywin.debugger;pywin.debugger.set_trace() + fname = m.group(1) + line = int(m.group(2)) + view = scriptutils.JumpToDocument(fname, line) + pos = view.LineIndex(line) - 1 + if view.GetTextRange(pos - 1, pos) in ("\r", "\n"): + pos -= 1 + view.SetSel(pos, pos) + errtext = m.group(3) + if start != end and line_start == line_end: + errtext = self.GetSelText() + errtext = repr(re.escape(errtext).replace("\ ", " ")) + view.ReplaceSel(addspecific and cmnt % locals() or cmnt) + return 0 + + def OnCmdOpenFile(self, cmd, code): + doc = win32ui.GetApp().OpenDocumentFile(self.fnm) + if doc: + vw = doc.GetFirstView() + # hope you have an editor that implements GotoLine()! + try: + vw.GotoLine(int(self.lnnum)) + except: + pass + return 0 + + def OnCmdThe(self, cmd, code): + curparamsstr = self.GetDocument().GetParams() + params = curparamsstr.split("\t") + params[2] = self.sel + greptemplate.setParams("\t".join(params)) + greptemplate.OpenDocumentFile() + return 0 + + def OnTryAgain(self, cmd, code): + greptemplate.setParams(self.GetDocument().GetParams()) + greptemplate.OpenDocumentFile() + return 0 + + def OnCmdSave(self, cmd, code): + flags = win32con.OFN_OVERWRITEPROMPT + dlg = win32ui.CreateFileDialog( + 0, None, None, flags, "Text Files (*.txt)|*.txt||", self + ) + dlg.SetOFNTitle("Save Results As") + if dlg.DoModal() == win32con.IDOK: + pn = dlg.GetPathName() + self._obj_.SaveFile(pn) + return 0 + + def Append(self, strng): + numlines = self.GetLineCount() + endpos = self.LineIndex(numlines - 1) + len(self.GetLine(numlines - 1)) + self.SetSel(endpos, endpos) + self.ReplaceSel(strng) + + +class TheDialog(dialog.Dialog): + def __init__(self, dp, fp, gp, cs, r, v): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + CS = win32con.WS_CHILD | win32con.WS_VISIBLE + tmp = [ + ["Pychecker Run", (0, 0, 210, 90), style, None, (8, "MS Sans Serif")], + ] + tmp.append([STATIC, "Files:", -1, (7, 7, 50, 9), CS]) + tmp.append( + [ + EDIT, + gp, + 103, + (52, 7, 144, 11), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append([STATIC, "Directories:", -1, (7, 20, 50, 9), CS]) + tmp.append( + [ + EDIT, + dp, + 102, + (52, 20, 128, 11), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append( + [ + BUTTON, + "...", + 110, + (182, 20, 16, 11), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append([STATIC, "Options:", -1, (7, 33, 50, 9), CS]) + tmp.append( + [ + EDIT, + fp, + 101, + (52, 33, 128, 11), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append( + [ + BUTTON, + "...", + 111, + (182, 33, 16, 11), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + # tmp.append([BUTTON,'Case sensitive', 104, (7, 45, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP]) + # tmp.append([BUTTON,'Subdirectories', 105, (7, 56, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP]) + # tmp.append([BUTTON,'Verbose', 106, (7, 67, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP]) + tmp.append( + [ + BUTTON, + "OK", + win32con.IDOK, + (166, 53, 32, 12), + CS | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "Cancel", + win32con.IDCANCEL, + (166, 67, 32, 12), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + dialog.Dialog.__init__(self, tmp) + self.AddDDX(101, "greppattern") + self.AddDDX(102, "dirpattern") + self.AddDDX(103, "filpattern") + # self.AddDDX(104,'casesensitive') + # self.AddDDX(105,'recursive') + # self.AddDDX(106,'verbose') + self._obj_.data["greppattern"] = gp + self._obj_.data["dirpattern"] = dp + self._obj_.data["filpattern"] = fp + # self._obj_.data['casesensitive'] = cs + # self._obj_.data['recursive'] = r + # self._obj_.data['verbose'] = v + self.HookCommand(self.OnMoreDirectories, 110) + self.HookCommand(self.OnMoreFiles, 111) + + def OnMoreDirectories(self, cmd, code): + self.getMore("Pychecker\\Directories", "dirpattern") + + def OnMoreFiles(self, cmd, code): + self.getMore("Pychecker\\File Types", "filpattern") + + def getMore(self, section, key): + self.UpdateData(1) + # get the items out of the ini file + ini = win32ui.GetProfileFileName() + secitems = win32api.GetProfileSection(section, ini) + items = [] + for secitem in secitems: + items.append(secitem.split("=")[1]) + dlg = TheParamsDialog(items) + if dlg.DoModal() == win32con.IDOK: + itemstr = ";".join(dlg.getItems()) + self._obj_.data[key] = itemstr + # update the ini file with dlg.getNew() + i = 0 + newitems = dlg.getNew() + if newitems: + items = items + newitems + for item in items: + win32api.WriteProfileVal(section, repr(i), item, ini) + i = i + 1 + self.UpdateData(0) + + def OnOK(self): + self.UpdateData(1) + for id, name in ( + (101, "greppattern"), + (102, "dirpattern"), + (103, "filpattern"), + ): + if not self[name]: + self.GetDlgItem(id).SetFocus() + win32api.MessageBeep() + win32ui.SetStatusText("Please enter a value") + return + self._obj_.OnOK() + + +class TheParamsDialog(dialog.Dialog): + def __init__(self, items): + self.items = items + self.newitems = [] + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + CS = win32con.WS_CHILD | win32con.WS_VISIBLE + tmp = [ + [ + "Pychecker Parameters", + (0, 0, 205, 100), + style, + None, + (8, "MS Sans Serif"), + ], + ] + tmp.append( + [ + LISTBOX, + "", + 107, + (7, 7, 150, 72), + CS + | win32con.LBS_MULTIPLESEL + | win32con.LBS_STANDARD + | win32con.LBS_HASSTRINGS + | win32con.WS_TABSTOP + | win32con.LBS_NOTIFY, + ] + ) + tmp.append( + [ + BUTTON, + "OK", + win32con.IDOK, + (167, 7, 32, 12), + CS | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "Cancel", + win32con.IDCANCEL, + (167, 23, 32, 12), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append([STATIC, "New:", -1, (2, 83, 15, 12), CS]) + tmp.append( + [ + EDIT, + "", + 108, + (18, 83, 139, 12), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append( + [ + BUTTON, + "Add", + 109, + (167, 83, 32, 12), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + dialog.Dialog.__init__(self, tmp) + self.HookCommand(self.OnAddItem, 109) + self.HookCommand(self.OnListDoubleClick, 107) + + def OnInitDialog(self): + lb = self.GetDlgItem(107) + for item in self.items: + lb.AddString(item) + return self._obj_.OnInitDialog() + + def OnAddItem(self, cmd, code): + eb = self.GetDlgItem(108) + item = eb.GetLine(0) + self.newitems.append(item) + lb = self.GetDlgItem(107) + i = lb.AddString(item) + lb.SetSel(i, 1) + return 1 + + def OnListDoubleClick(self, cmd, code): + if code == win32con.LBN_DBLCLK: + self.OnOK() + return 1 + + def OnOK(self): + lb = self.GetDlgItem(107) + self.selections = lb.GetSelTextItems() + self._obj_.OnOK() + + def getItems(self): + return self.selections + + def getNew(self): + return self.newitems + + +try: + win32ui.GetApp().RemoveDocTemplate(greptemplate) +except NameError: + pass + +greptemplate = TheTemplate() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/scriptutils.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/scriptutils.py new file mode 100644 index 0000000000000000000000000000000000000000..e5bc57c8ff90bcb235ddab50cc737f494fd46342 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/scriptutils.py @@ -0,0 +1,688 @@ +""" +Various utilities for running/importing a script +""" +import bdb +import linecache +import os +import sys +import traceback + +import __main__ +import win32api +import win32con +import win32ui +from pywin.mfc import dialog +from pywin.mfc.docview import TreeView + +from .cmdline import ParseArgs + +RS_DEBUGGER_NONE = 0 # Dont run under the debugger. +RS_DEBUGGER_STEP = 1 # Start stepping under the debugger +RS_DEBUGGER_GO = 2 # Just run under the debugger, stopping only at break-points. +RS_DEBUGGER_PM = 3 # Dont run under debugger, but do post-mortem analysis on exception. + +debugging_options = """No debugging +Step-through in the debugger +Run in the debugger +Post-Mortem of unhandled exceptions""".split( + "\n" +) + +byte_cr = "\r".encode("ascii") +byte_lf = "\n".encode("ascii") +byte_crlf = "\r\n".encode("ascii") + + +# A dialog box for the "Run Script" command. +class DlgRunScript(dialog.Dialog): + "A class for the 'run script' dialog" + + def __init__(self, bHaveDebugger): + dialog.Dialog.__init__(self, win32ui.IDD_RUN_SCRIPT) + self.AddDDX(win32ui.IDC_EDIT1, "script") + self.AddDDX(win32ui.IDC_EDIT2, "args") + self.AddDDX(win32ui.IDC_COMBO1, "debuggingType", "i") + self.HookCommand(self.OnBrowse, win32ui.IDC_BUTTON2) + self.bHaveDebugger = bHaveDebugger + + def OnInitDialog(self): + rc = dialog.Dialog.OnInitDialog(self) + cbo = self.GetDlgItem(win32ui.IDC_COMBO1) + for o in debugging_options: + cbo.AddString(o) + cbo.SetCurSel(self["debuggingType"]) + if not self.bHaveDebugger: + cbo.EnableWindow(0) + + def OnBrowse(self, id, code): + if code != 0: # BN_CLICKED + return 1 + openFlags = win32con.OFN_OVERWRITEPROMPT | win32con.OFN_FILEMUSTEXIST + dlg = win32ui.CreateFileDialog( + 1, None, None, openFlags, "Python Scripts (*.py)|*.py||", self + ) + dlg.SetOFNTitle("Run Script") + if dlg.DoModal() != win32con.IDOK: + return 0 + self["script"] = dlg.GetPathName() + self.UpdateData(0) + return 0 + + +def GetDebugger(): + """Get the default Python debugger. Returns the debugger, or None. + + It is assumed the debugger has a standard "pdb" defined interface. + Currently always returns the 'pywin.debugger' debugger, or None + (pdb is _not_ returned as it is not effective in this GUI environment) + """ + try: + import pywin.debugger + + return pywin.debugger + except ImportError: + return None + + +def IsOnPythonPath(path): + "Given a path only, see if it is on the Pythonpath. Assumes path is a full path spec." + # must check that the command line arg's path is in sys.path + for syspath in sys.path: + try: + # Python 1.5 and later allows an empty sys.path entry. + if syspath and win32ui.FullPath(syspath) == path: + return 1 + except win32ui.error as details: + print( + "Warning: The sys.path entry '%s' is invalid\n%s" % (syspath, details) + ) + return 0 + + +def GetPackageModuleName(fileName): + """Given a filename, return (module name, new path). + eg - given "c:\a\b\c\my.py", return ("b.c.my",None) if "c:\a" is on sys.path. + If no package found, will return ("my", "c:\a\b\c") + """ + path, fname = os.path.split(fileName) + path = origPath = win32ui.FullPath(path) + fname = os.path.splitext(fname)[0] + modBits = [] + newPathReturn = None + if not IsOnPythonPath(path): + # Module not directly on the search path - see if under a package. + while len(path) > 3: # ie 'C:\' + path, modBit = os.path.split(path) + modBits.append(modBit) + # If on path, _and_ existing package of that name loaded. + if ( + IsOnPythonPath(path) + and modBit in sys.modules + and ( + os.path.exists(os.path.join(path, modBit, "__init__.py")) + or os.path.exists(os.path.join(path, modBit, "__init__.pyc")) + or os.path.exists(os.path.join(path, modBit, "__init__.pyo")) + ) + ): + modBits.reverse() + return ".".join(modBits) + "." + fname, newPathReturn + # Not found - look a level higher + else: + newPathReturn = origPath + + return fname, newPathReturn + + +def GetActiveView(): + """Gets the edit control (eg, EditView) with the focus, or None""" + try: + childFrame, bIsMaximised = win32ui.GetMainFrame().MDIGetActive() + return childFrame.GetActiveView() + except win32ui.error: + return None + + +def GetActiveEditControl(): + view = GetActiveView() + if view is None: + return None + if hasattr(view, "SCIAddText"): # Is it a scintilla control? + return view + try: + return view.GetRichEditCtrl() + except AttributeError: + pass + try: + return view.GetEditCtrl() + except AttributeError: + pass + + +def GetActiveEditorDocument(): + """Returns the active editor document and view, or (None,None) if no + active document or its not an editor document. + """ + view = GetActiveView() + if view is None or isinstance(view, TreeView): + return (None, None) + doc = view.GetDocument() + if hasattr(doc, "MarkerAdd"): # Is it an Editor document? + return doc, view + return (None, None) + + +def GetActiveFileName(bAutoSave=1): + """Gets the file name for the active frame, saving it if necessary. + + Returns None if it cant be found, or raises KeyboardInterrupt. + """ + pathName = None + active = GetActiveView() + if active is None: + return None + try: + doc = active.GetDocument() + pathName = doc.GetPathName() + + if bAutoSave and ( + len(pathName) > 0 + or doc.GetTitle()[:8] == "Untitled" + or doc.GetTitle()[:6] == "Script" + ): # if not a special purpose window + if doc.IsModified(): + try: + doc.OnSaveDocument(pathName) + pathName = doc.GetPathName() + + # clear the linecache buffer + linecache.clearcache() + + except win32ui.error: + raise KeyboardInterrupt + + except (win32ui.error, AttributeError): + pass + if not pathName: + return None + return pathName + + +lastScript = "" +lastArgs = "" +lastDebuggingType = RS_DEBUGGER_NONE + + +def RunScript(defName=None, defArgs=None, bShowDialog=1, debuggingType=None): + global lastScript, lastArgs, lastDebuggingType + _debugger_stop_frame_ = 1 # Magic variable so the debugger will hide me! + + # Get the debugger - may be None! + debugger = GetDebugger() + + if defName is None: + try: + pathName = GetActiveFileName() + except KeyboardInterrupt: + return # User cancelled save. + else: + pathName = defName + if not pathName: + pathName = lastScript + if defArgs is None: + args = "" + if pathName == lastScript: + args = lastArgs + else: + args = defArgs + if debuggingType is None: + debuggingType = lastDebuggingType + + if not pathName or bShowDialog: + dlg = DlgRunScript(debugger is not None) + dlg["script"] = pathName + dlg["args"] = args + dlg["debuggingType"] = debuggingType + if dlg.DoModal() != win32con.IDOK: + return + script = dlg["script"] + args = dlg["args"] + debuggingType = dlg["debuggingType"] + if not script: + return + if debuggingType == RS_DEBUGGER_GO and debugger is not None: + # This may surprise users - they select "Run under debugger", but + # it appears not to! Only warn when they pick from the dialog! + # First - ensure the debugger is activated to pickup any break-points + # set in the editor. + try: + # Create the debugger, but _dont_ init the debugger GUI. + rd = debugger._GetCurrentDebugger() + except AttributeError: + rd = None + if rd is not None and len(rd.breaks) == 0: + msg = "There are no active break-points.\r\n\r\nSelecting this debug option without any\r\nbreak-points is unlikely to have the desired effect\r\nas the debugger is unlikely to be invoked..\r\n\r\nWould you like to step-through in the debugger instead?" + rc = win32ui.MessageBox( + msg, + win32ui.LoadString(win32ui.IDR_DEBUGGER), + win32con.MB_YESNOCANCEL | win32con.MB_ICONINFORMATION, + ) + if rc == win32con.IDCANCEL: + return + if rc == win32con.IDYES: + debuggingType = RS_DEBUGGER_STEP + + lastDebuggingType = debuggingType + lastScript = script + lastArgs = args + else: + script = pathName + + # try and open the script. + if ( + len(os.path.splitext(script)[1]) == 0 + ): # check if no extension supplied, and give one. + script = script + ".py" + # If no path specified, try and locate the file + path, fnameonly = os.path.split(script) + if len(path) == 0: + try: + os.stat(fnameonly) # See if it is OK as is... + script = fnameonly + except os.error: + fullScript = LocatePythonFile(script) + if fullScript is None: + win32ui.MessageBox("The file '%s' can not be located" % script) + return + script = fullScript + else: + path = win32ui.FullPath(path) + if not IsOnPythonPath(path): + sys.path.append(path) + + # py3k fun: If we use text mode to open the file, we get \r\n + # translated so Python allows the syntax (good!), but we get back + # text already decoded from the default encoding (bad!) and Python + # ignores any encoding decls (bad!). If we use binary mode we get + # the raw bytes and Python looks at the encoding (good!) but \r\n + # chars stay in place so Python throws a syntax error (bad!). + # So: so the binary thing and manually normalize \r\n. + try: + f = open(script, "rb") + except IOError as exc: + win32ui.MessageBox( + "The file could not be opened - %s (%d)" % (exc.strerror, exc.errno) + ) + return + + # Get the source-code - as above, normalize \r\n + code = f.read().replace(byte_crlf, byte_lf).replace(byte_cr, byte_lf) + byte_lf + + # Remember and hack sys.argv for the script. + oldArgv = sys.argv + sys.argv = ParseArgs(args) + sys.argv.insert(0, script) + # sys.path[0] is the path of the script + oldPath0 = sys.path[0] + newPath0 = os.path.split(script)[0] + if not oldPath0: # if sys.path[0] is empty + sys.path[0] = newPath0 + insertedPath0 = 0 + else: + sys.path.insert(0, newPath0) + insertedPath0 = 1 + bWorked = 0 + win32ui.DoWaitCursor(1) + base = os.path.split(script)[1] + # Allow windows to repaint before starting. + win32ui.PumpWaitingMessages() + win32ui.SetStatusText("Running script %s..." % base, 1) + exitCode = 0 + from pywin.framework import interact + + # Check the debugger flags + if debugger is None and (debuggingType != RS_DEBUGGER_NONE): + win32ui.MessageBox( + "No debugger is installed. Debugging options have been ignored!" + ) + debuggingType = RS_DEBUGGER_NONE + + # Get a code object - ignore the debugger for this, as it is probably a syntax error + # at this point + try: + codeObject = compile(code, script, "exec") + except: + # Almost certainly a syntax error! + _HandlePythonFailure("run script", script) + # No code object which to run/debug. + return + __main__.__file__ = script + try: + if debuggingType == RS_DEBUGGER_STEP: + debugger.run(codeObject, __main__.__dict__, start_stepping=1) + elif debuggingType == RS_DEBUGGER_GO: + debugger.run(codeObject, __main__.__dict__, start_stepping=0) + else: + # Post mortem or no debugging + exec(codeObject, __main__.__dict__) + bWorked = 1 + except bdb.BdbQuit: + # Dont print tracebacks when the debugger quit, but do print a message. + print("Debugging session cancelled.") + exitCode = 1 + bWorked = 1 + except SystemExit as code: + exitCode = code + bWorked = 1 + except KeyboardInterrupt: + # Consider this successful, as we dont want the debugger. + # (but we do want a traceback!) + if interact.edit and interact.edit.currentView: + interact.edit.currentView.EnsureNoPrompt() + traceback.print_exc() + if interact.edit and interact.edit.currentView: + interact.edit.currentView.AppendToPrompt([]) + bWorked = 1 + except: + if interact.edit and interact.edit.currentView: + interact.edit.currentView.EnsureNoPrompt() + traceback.print_exc() + if interact.edit and interact.edit.currentView: + interact.edit.currentView.AppendToPrompt([]) + if debuggingType == RS_DEBUGGER_PM: + debugger.pm() + del __main__.__file__ + sys.argv = oldArgv + if insertedPath0: + del sys.path[0] + else: + sys.path[0] = oldPath0 + f.close() + if bWorked: + win32ui.SetStatusText("Script '%s' returned exit code %s" % (script, exitCode)) + else: + win32ui.SetStatusText("Exception raised while running script %s" % base) + try: + sys.stdout.flush() + except AttributeError: + pass + + win32ui.DoWaitCursor(0) + + +def ImportFile(): + """This code looks for the current window, and determines if it can be imported. If not, + it will prompt for a file name, and allow it to be imported.""" + try: + pathName = GetActiveFileName() + except KeyboardInterrupt: + pathName = None + + if pathName is not None: + if os.path.splitext(pathName)[1].lower() not in (".py", ".pyw", ".pyx"): + pathName = None + + if pathName is None: + openFlags = win32con.OFN_OVERWRITEPROMPT | win32con.OFN_FILEMUSTEXIST + dlg = win32ui.CreateFileDialog( + 1, None, None, openFlags, "Python Scripts (*.py;*.pyw)|*.py;*.pyw;*.pyx||" + ) + dlg.SetOFNTitle("Import Script") + if dlg.DoModal() != win32con.IDOK: + return 0 + + pathName = dlg.GetPathName() + + # If already imported, dont look for package + path, modName = os.path.split(pathName) + modName, modExt = os.path.splitext(modName) + newPath = None + # note that some packages (*cough* email *cough*) use "lazy importers" + # meaning sys.modules can change as a side-effect of looking at + # module.__file__ - so we must take a copy (ie, items() in py2k, + # list(items()) in py3k) + for key, mod in list(sys.modules.items()): + if getattr(mod, "__file__", None): + fname = mod.__file__ + base, ext = os.path.splitext(fname) + if ext.lower() in (".pyo", ".pyc"): + ext = ".py" + fname = base + ext + if win32ui.ComparePath(fname, pathName): + modName = key + break + else: # for not broken + modName, newPath = GetPackageModuleName(pathName) + if newPath: + sys.path.append(newPath) + + if modName in sys.modules: + bNeedReload = 1 + what = "reload" + else: + what = "import" + bNeedReload = 0 + + win32ui.SetStatusText(what.capitalize() + "ing module...", 1) + win32ui.DoWaitCursor(1) + # win32ui.GetMainFrame().BeginWaitCursor() + + try: + # always do an import, as it is cheap if it's already loaded. This ensures + # it is in our name space. + codeObj = compile("import " + modName, "", "exec") + except SyntaxError: + win32ui.SetStatusText('Invalid filename for import: "' + modName + '"') + return + try: + exec(codeObj, __main__.__dict__) + mod = sys.modules.get(modName) + if bNeedReload: + from importlib import reload + + mod = reload(sys.modules[modName]) + win32ui.SetStatusText( + "Successfully " + + what + + "ed module '" + + modName + + "': %s" % getattr(mod, "__file__", "") + ) + except: + _HandlePythonFailure(what) + win32ui.DoWaitCursor(0) + + +def CheckFile(): + """This code looks for the current window, and gets Python to check it + without actually executing any code (ie, by compiling only) + """ + try: + pathName = GetActiveFileName() + except KeyboardInterrupt: + return + + what = "check" + win32ui.SetStatusText(what.capitalize() + "ing module...", 1) + win32ui.DoWaitCursor(1) + try: + f = open(pathName) + except IOError as details: + print("Cant open file '%s' - %s" % (pathName, details)) + return + try: + code = f.read() + "\n" + finally: + f.close() + try: + codeObj = compile(code, pathName, "exec") + if RunTabNanny(pathName): + win32ui.SetStatusText( + "Python and the TabNanny successfully checked the file '" + + os.path.basename(pathName) + + "'" + ) + except SyntaxError: + _HandlePythonFailure(what, pathName) + except: + traceback.print_exc() + _HandlePythonFailure(what) + win32ui.DoWaitCursor(0) + + +def RunTabNanny(filename): + import io as io + + tabnanny = FindTabNanny() + if tabnanny is None: + win32ui.MessageBox("The TabNanny is not around, so the children can run amok!") + return + + # Capture the tab-nanny output + newout = io.StringIO() + old_out = sys.stderr, sys.stdout + sys.stderr = sys.stdout = newout + try: + tabnanny.check(filename) + finally: + # Restore output + sys.stderr, sys.stdout = old_out + data = newout.getvalue() + if data: + try: + lineno = data.split()[1] + lineno = int(lineno) + _JumpToPosition(filename, lineno) + try: # Try and display whitespace + GetActiveEditControl().SCISetViewWS(1) + except: + pass + win32ui.SetStatusText("The TabNanny found trouble at line %d" % lineno) + except (IndexError, TypeError, ValueError): + print("The tab nanny complained, but I cant see where!") + print(data) + return 0 + return 1 + + +def _JumpToPosition(fileName, lineno, col=1): + JumpToDocument(fileName, lineno, col) + + +def JumpToDocument(fileName, lineno=0, col=1, nChars=0, bScrollToTop=0): + # Jump to the position in a file. + # If lineno is <= 0, dont move the position - just open/restore. + # if nChars > 0, select that many characters. + # if bScrollToTop, the specified line will be moved to the top of the window + # (eg, bScrollToTop should be false when jumping to an error line to retain the + # context, but true when jumping to a method defn, where we want the full body. + # Return the view which is editing the file, or None on error. + doc = win32ui.GetApp().OpenDocumentFile(fileName) + if doc is None: + return None + frame = doc.GetFirstView().GetParentFrame() + try: + view = frame.GetEditorView() + if frame.GetActiveView() != view: + frame.SetActiveView(view) + frame.AutoRestore() + except AttributeError: # Not an editor frame?? + view = doc.GetFirstView() + if lineno > 0: + charNo = view.LineIndex(lineno - 1) + start = charNo + col - 1 + size = view.GetTextLength() + try: + view.EnsureCharsVisible(charNo) + except AttributeError: + print("Doesnt appear to be one of our views?") + view.SetSel(min(start, size), min(start + nChars, size)) + if bScrollToTop: + curTop = view.GetFirstVisibleLine() + nScroll = (lineno - 1) - curTop + view.LineScroll(nScroll, 0) + view.SetFocus() + return view + + +def _HandlePythonFailure(what, syntaxErrorPathName=None): + typ, details, tb = sys.exc_info() + if isinstance(details, SyntaxError): + try: + msg, (fileName, line, col, text) = details + if (not fileName or fileName == "") and syntaxErrorPathName: + fileName = syntaxErrorPathName + _JumpToPosition(fileName, line, col) + except (TypeError, ValueError): + msg = str(details) + win32ui.SetStatusText("Failed to " + what + " - syntax error - %s" % msg) + else: + traceback.print_exc() + win32ui.SetStatusText("Failed to " + what + " - " + str(details)) + tb = None # Clean up a cycle. + + +# Find the Python TabNanny in either the standard library or the Python Tools/Scripts directory. +def FindTabNanny(): + try: + return __import__("tabnanny") + except ImportError: + pass + # OK - not in the standard library - go looking. + filename = "tabnanny.py" + try: + path = win32api.RegQueryValue( + win32con.HKEY_LOCAL_MACHINE, + "SOFTWARE\\Python\\PythonCore\\%s\\InstallPath" % (sys.winver), + ) + except win32api.error: + print("WARNING - The Python registry does not have an 'InstallPath' setting") + print(" The file '%s' can not be located" % (filename)) + return None + fname = os.path.join(path, "Tools\\Scripts\\%s" % filename) + try: + os.stat(fname) + except os.error: + print( + "WARNING - The file '%s' can not be located in path '%s'" % (filename, path) + ) + return None + + tabnannyhome, tabnannybase = os.path.split(fname) + tabnannybase = os.path.splitext(tabnannybase)[0] + # Put tab nanny at the top of the path. + sys.path.insert(0, tabnannyhome) + try: + return __import__(tabnannybase) + finally: + # remove the tab-nanny from the path + del sys.path[0] + + +def LocatePythonFile(fileName, bBrowseIfDir=1): + "Given a file name, return a fully qualified file name, or None" + # first look for the exact file as specified + if not os.path.isfile(fileName): + # Go looking! + baseName = fileName + for path in sys.path: + fileName = os.path.abspath(os.path.join(path, baseName)) + if os.path.isdir(fileName): + if bBrowseIfDir: + d = win32ui.CreateFileDialog( + 1, "*.py", None, 0, "Python Files (*.py)|*.py|All files|*.*" + ) + d.SetOFNInitialDir(fileName) + rc = d.DoModal() + if rc == win32con.IDOK: + fileName = d.GetPathName() + break + else: + return None + else: + fileName = fileName + ".py" + if os.path.isfile(fileName): + break # Found it! + + else: # for not broken out of + return None + return win32ui.FullPath(fileName) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/sgrepmdi.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/sgrepmdi.py new file mode 100644 index 0000000000000000000000000000000000000000..b7d938bbb3e463959b97e48d6238259f0be82160 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/sgrepmdi.py @@ -0,0 +1,758 @@ +# SGrepMDI is by Gordon McMillan (gmcm@hypernet.com) +# It does basically what Find In Files does in MSVC with a couple enhancements. +# - It saves any directories in the app's ini file (if you want to get rid +# of them you'll have to edit the file) +# - "Directories" can be directories, +# - semicolon separated lists of "directories", +# - environment variables that evaluate to "directories", +# - registry path names that evaluate to "directories", +# - all of which is recursive, so you can mix them all up. +# - It is MDI, so you can 'nest' greps and return to earlier ones, +# (ie, have multiple results open at the same time) +# - Like FIF, double clicking a line opens an editor and takes you to the line. +# - You can highlight text, right click and start a new grep with the selected +# text as search pattern and same directories etc as before. +# - You can save grep parameters (so you don't lose your hardearned pattern) +# from File|Save +# - You can save grep results by right clicking in the result window. +# Hats off to Mark Hammond for providing an environment where I could cobble +# something like this together in a couple evenings! + +import glob +import os +import re + +import win32api +import win32con +import win32ui +from pywin.mfc import dialog, docview, window + +from . import scriptutils + + +def getsubdirs(d): + dlist = [] + flist = glob.glob(d + "\\*") + for f in flist: + if os.path.isdir(f): + dlist.append(f) + dlist = dlist + getsubdirs(f) + return dlist + + +class dirpath: + def __init__(self, str, recurse=0): + dp = str.split(";") + dirs = {} + for d in dp: + if os.path.isdir(d): + d = d.lower() + if d not in dirs: + dirs[d] = None + if recurse: + subdirs = getsubdirs(d) + for sd in subdirs: + sd = sd.lower() + if sd not in dirs: + dirs[sd] = None + elif os.path.isfile(d): + pass + else: + x = None + if d in os.environ: + x = dirpath(os.environ[d]) + elif d[:5] == "HKEY_": + keystr = d.split("\\") + try: + root = eval("win32con." + keystr[0]) + except: + win32ui.MessageBox( + "Can't interpret registry key name '%s'" % keystr[0] + ) + try: + subkey = "\\".join(keystr[1:]) + val = win32api.RegQueryValue(root, subkey) + if val: + x = dirpath(val) + else: + win32ui.MessageBox( + "Registry path '%s' did not return a path entry" % d + ) + except: + win32ui.MessageBox( + "Can't interpret registry key value: %s" % keystr[1:] + ) + else: + win32ui.MessageBox("Directory '%s' not found" % d) + if x: + for xd in x: + if xd not in dirs: + dirs[xd] = None + if recurse: + subdirs = getsubdirs(xd) + for sd in subdirs: + sd = sd.lower() + if sd not in dirs: + dirs[sd] = None + self.dirs = [] + for d in list(dirs.keys()): + self.dirs.append(d) + + def __getitem__(self, key): + return self.dirs[key] + + def __len__(self): + return len(self.dirs) + + def __setitem__(self, key, value): + self.dirs[key] = value + + def __delitem__(self, key): + del self.dirs[key] + + def __getslice__(self, lo, hi): + return self.dirs[lo:hi] + + def __setslice__(self, lo, hi, seq): + self.dirs[lo:hi] = seq + + def __delslice__(self, lo, hi): + del self.dirs[lo:hi] + + def __add__(self, other): + if type(other) == type(self) or type(other) == type([]): + return self.dirs + other.dirs + + def __radd__(self, other): + if type(other) == type(self) or type(other) == type([]): + return other.dirs + self.dirs + + +# Group(1) is the filename, group(2) is the lineno. +# regexGrepResult=regex.compile("^\\([a-zA-Z]:.*\\)(\\([0-9]+\\))") + +regexGrep = re.compile(r"^([a-zA-Z]:[^(]*)\(([0-9]+)\)") + +# these are the atom numbers defined by Windows for basic dialog controls + +BUTTON = 0x80 +EDIT = 0x81 +STATIC = 0x82 +LISTBOX = 0x83 +SCROLLBAR = 0x84 +COMBOBOX = 0x85 + + +class GrepTemplate(docview.RichEditDocTemplate): + def __init__(self): + docview.RichEditDocTemplate.__init__( + self, win32ui.IDR_TEXTTYPE, GrepDocument, GrepFrame, GrepView + ) + self.SetDocStrings("\nGrep\nGrep\nGrep params (*.grep)\n.grep\n\n\n") + win32ui.GetApp().AddDocTemplate(self) + self.docparams = None + + def MatchDocType(self, fileName, fileType): + doc = self.FindOpenDocument(fileName) + if doc: + return doc + ext = os.path.splitext(fileName)[1].lower() + if ext == ".grep": + return win32ui.CDocTemplate_Confidence_yesAttemptNative + return win32ui.CDocTemplate_Confidence_noAttempt + + def setParams(self, params): + self.docparams = params + + def readParams(self): + tmp = self.docparams + self.docparams = None + return tmp + + +class GrepFrame(window.MDIChildWnd): + # The template and doc params will one day be removed. + def __init__(self, wnd=None): + window.MDIChildWnd.__init__(self, wnd) + + +class GrepDocument(docview.RichEditDoc): + def __init__(self, template): + docview.RichEditDoc.__init__(self, template) + self.dirpattern = "" + self.filpattern = "" + self.greppattern = "" + self.casesensitive = 1 + self.recurse = 1 + self.verbose = 0 + + def OnOpenDocument(self, fnm): + # this bizarre stuff with params is so right clicking in a result window + # and starting a new grep can communicate the default parameters to the + # new grep. + try: + params = open(fnm, "r").read() + except: + params = None + self.setInitParams(params) + return self.OnNewDocument() + + def OnCloseDocument(self): + try: + win32ui.GetApp().DeleteIdleHandler(self.SearchFile) + except: + pass + return self._obj_.OnCloseDocument() + + def saveInitParams(self): + # Only save the flags, not the text boxes. + paramstr = "\t%s\t\t%d\t%d" % ( + self.filpattern, + self.casesensitive, + self.recurse, + ) + win32ui.WriteProfileVal("Grep", "Params", paramstr) + + def setInitParams(self, paramstr): + if paramstr is None: + paramstr = win32ui.GetProfileVal("Grep", "Params", "\t\t\t1\t0\t0") + params = paramstr.split("\t") + if len(params) < 3: + params = params + [""] * (3 - len(params)) + if len(params) < 6: + params = params + [0] * (6 - len(params)) + self.dirpattern = params[0] + self.filpattern = params[1] + self.greppattern = params[2] + self.casesensitive = int(params[3]) + self.recurse = int(params[4]) + self.verbose = int(params[5]) + # setup some reasonable defaults. + if not self.dirpattern: + try: + editor = win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView() + self.dirpattern = os.path.abspath( + os.path.dirname(editor.GetDocument().GetPathName()) + ) + except (AttributeError, win32ui.error): + self.dirpattern = os.getcwd() + if not self.filpattern: + self.filpattern = "*.py" + + def OnNewDocument(self): + if self.dirpattern == "": + self.setInitParams(greptemplate.readParams()) + d = GrepDialog( + self.dirpattern, + self.filpattern, + self.greppattern, + self.casesensitive, + self.recurse, + self.verbose, + ) + if d.DoModal() == win32con.IDOK: + self.dirpattern = d["dirpattern"] + self.filpattern = d["filpattern"] + self.greppattern = d["greppattern"] + self.casesensitive = d["casesensitive"] + self.recurse = d["recursive"] + self.verbose = d["verbose"] + self.doSearch() + self.saveInitParams() + return 1 + return 0 # cancelled - return zero to stop frame creation. + + def doSearch(self): + self.dp = dirpath(self.dirpattern, self.recurse) + self.SetTitle("Grep for %s in %s" % (self.greppattern, self.filpattern)) + # self.text = [] + self.GetFirstView().Append("#Search " + self.dirpattern + "\n") + if self.verbose: + self.GetFirstView().Append("# =" + repr(self.dp.dirs) + "\n") + self.GetFirstView().Append("# Files " + self.filpattern + "\n") + self.GetFirstView().Append("# For " + self.greppattern + "\n") + self.fplist = self.filpattern.split(";") + if self.casesensitive: + self.pat = re.compile(self.greppattern) + else: + self.pat = re.compile(self.greppattern, re.IGNORECASE) + win32ui.SetStatusText("Searching. Please wait...", 0) + self.dpndx = self.fpndx = 0 + self.fndx = -1 + if not self.dp: + self.GetFirstView().Append( + "# ERROR: '%s' does not resolve to any search locations" + % self.dirpattern + ) + self.SetModifiedFlag(0) + else: + self.flist = glob.glob(self.dp[0] + "\\" + self.fplist[0]) + win32ui.GetApp().AddIdleHandler(self.SearchFile) + + def SearchFile(self, handler, count): + self.fndx = self.fndx + 1 + if self.fndx < len(self.flist): + f = self.flist[self.fndx] + if self.verbose: + self.GetFirstView().Append("# .." + f + "\n") + # Directories may match the file type pattern, and files may be removed + # while grep is running + if os.path.isfile(f): + win32ui.SetStatusText("Searching " + f, 0) + lines = open(f, "r").readlines() + for i in range(len(lines)): + line = lines[i] + if self.pat.search(line) != None: + self.GetFirstView().Append(f + "(" + repr(i + 1) + ") " + line) + else: + self.fndx = -1 + self.fpndx = self.fpndx + 1 + if self.fpndx < len(self.fplist): + self.flist = glob.glob( + self.dp[self.dpndx] + "\\" + self.fplist[self.fpndx] + ) + else: + self.fpndx = 0 + self.dpndx = self.dpndx + 1 + if self.dpndx < len(self.dp): + self.flist = glob.glob( + self.dp[self.dpndx] + "\\" + self.fplist[self.fpndx] + ) + else: + win32ui.SetStatusText("Search complete.", 0) + self.SetModifiedFlag(0) # default to not modified. + try: + win32ui.GetApp().DeleteIdleHandler(self.SearchFile) + except: + pass + return 0 + return 1 + + def GetParams(self): + return ( + self.dirpattern + + "\t" + + self.filpattern + + "\t" + + self.greppattern + + "\t" + + repr(self.casesensitive) + + "\t" + + repr(self.recurse) + + "\t" + + repr(self.verbose) + ) + + def OnSaveDocument(self, filename): + # print 'OnSaveDocument() filename=',filename + savefile = open(filename, "wb") + txt = self.GetParams() + "\n" + # print 'writing',txt + savefile.write(txt) + savefile.close() + self.SetModifiedFlag(0) + return 1 + + +ID_OPEN_FILE = 0xE400 +ID_GREP = 0xE401 +ID_SAVERESULTS = 0x402 +ID_TRYAGAIN = 0x403 + + +class GrepView(docview.RichEditView): + def __init__(self, doc): + docview.RichEditView.__init__(self, doc) + self.SetWordWrap(win32ui.CRichEditView_WrapNone) + self.HookHandlers() + + def OnInitialUpdate(self): + rc = self._obj_.OnInitialUpdate() + format = (-402653169, 0, 200, 0, 0, 0, 49, "Courier New") + self.SetDefaultCharFormat(format) + return rc + + def HookHandlers(self): + self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN) + self.HookCommand(self.OnCmdOpenFile, ID_OPEN_FILE) + self.HookCommand(self.OnCmdGrep, ID_GREP) + self.HookCommand(self.OnCmdSave, ID_SAVERESULTS) + self.HookCommand(self.OnTryAgain, ID_TRYAGAIN) + self.HookMessage(self.OnLDblClick, win32con.WM_LBUTTONDBLCLK) + + def OnLDblClick(self, params): + line = self.GetLine() + regexGrepResult = regexGrep.match(line) + if regexGrepResult: + fname = regexGrepResult.group(1) + line = int(regexGrepResult.group(2)) + scriptutils.JumpToDocument(fname, line) + return 0 # dont pass on + return 1 # pass it on by default. + + def OnRClick(self, params): + menu = win32ui.CreatePopupMenu() + flags = win32con.MF_STRING | win32con.MF_ENABLED + lineno = self._obj_.LineFromChar(-1) # selection or current line + line = self._obj_.GetLine(lineno) + regexGrepResult = regexGrep.match(line) + if regexGrepResult: + self.fnm = regexGrepResult.group(1) + self.lnnum = int(regexGrepResult.group(2)) + menu.AppendMenu(flags, ID_OPEN_FILE, "&Open " + self.fnm) + menu.AppendMenu(win32con.MF_SEPARATOR) + menu.AppendMenu(flags, ID_TRYAGAIN, "&Try Again") + charstart, charend = self._obj_.GetSel() + if charstart != charend: + linestart = self._obj_.LineIndex(lineno) + self.sel = line[charstart - linestart : charend - linestart] + menu.AppendMenu(flags, ID_GREP, "&Grep for " + self.sel) + menu.AppendMenu(win32con.MF_SEPARATOR) + menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, "Cu&t") + menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, "&Copy") + menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, "&Paste") + menu.AppendMenu(flags, win32con.MF_SEPARATOR) + menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, "&Select all") + menu.AppendMenu(flags, win32con.MF_SEPARATOR) + menu.AppendMenu(flags, ID_SAVERESULTS, "Sa&ve results") + menu.TrackPopupMenu(params[5]) + return 0 + + def OnCmdOpenFile(self, cmd, code): + doc = win32ui.GetApp().OpenDocumentFile(self.fnm) + if doc: + vw = doc.GetFirstView() + # hope you have an editor that implements GotoLine()! + try: + vw.GotoLine(int(self.lnnum)) + except: + pass + return 0 + + def OnCmdGrep(self, cmd, code): + if code != 0: + return 1 + curparamsstr = self.GetDocument().GetParams() + params = curparamsstr.split("\t") + params[2] = self.sel + greptemplate.setParams("\t".join(params)) + greptemplate.OpenDocumentFile() + return 0 + + def OnTryAgain(self, cmd, code): + if code != 0: + return 1 + greptemplate.setParams(self.GetDocument().GetParams()) + greptemplate.OpenDocumentFile() + return 0 + + def OnCmdSave(self, cmd, code): + if code != 0: + return 1 + flags = win32con.OFN_OVERWRITEPROMPT + dlg = win32ui.CreateFileDialog( + 0, None, None, flags, "Text Files (*.txt)|*.txt||", self + ) + dlg.SetOFNTitle("Save Results As") + if dlg.DoModal() == win32con.IDOK: + pn = dlg.GetPathName() + self._obj_.SaveTextFile(pn) + return 0 + + def Append(self, strng): + numlines = self.GetLineCount() + endpos = self.LineIndex(numlines - 1) + len(self.GetLine(numlines - 1)) + self.SetSel(endpos, endpos) + self.ReplaceSel(strng) + + +class GrepDialog(dialog.Dialog): + def __init__(self, dp, fp, gp, cs, r, v): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + CS = win32con.WS_CHILD | win32con.WS_VISIBLE + tmp = [ + ["Grep", (0, 0, 210, 90), style, None, (8, "MS Sans Serif")], + ] + tmp.append([STATIC, "Grep For:", -1, (7, 7, 50, 9), CS]) + tmp.append( + [ + EDIT, + gp, + 101, + (52, 7, 144, 11), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append([STATIC, "Directories:", -1, (7, 20, 50, 9), CS]) + tmp.append( + [ + EDIT, + dp, + 102, + (52, 20, 128, 11), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append( + [ + BUTTON, + "...", + 110, + (182, 20, 16, 11), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append([STATIC, "File types:", -1, (7, 33, 50, 9), CS]) + tmp.append( + [ + EDIT, + fp, + 103, + (52, 33, 128, 11), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append( + [ + BUTTON, + "...", + 111, + (182, 33, 16, 11), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "Case sensitive", + 104, + (7, 45, 72, 9), + CS + | win32con.BS_AUTOCHECKBOX + | win32con.BS_LEFTTEXT + | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "Subdirectories", + 105, + (7, 56, 72, 9), + CS + | win32con.BS_AUTOCHECKBOX + | win32con.BS_LEFTTEXT + | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "Verbose", + 106, + (7, 67, 72, 9), + CS + | win32con.BS_AUTOCHECKBOX + | win32con.BS_LEFTTEXT + | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "OK", + win32con.IDOK, + (166, 53, 32, 12), + CS | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "Cancel", + win32con.IDCANCEL, + (166, 67, 32, 12), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + dialog.Dialog.__init__(self, tmp) + self.AddDDX(101, "greppattern") + self.AddDDX(102, "dirpattern") + self.AddDDX(103, "filpattern") + self.AddDDX(104, "casesensitive") + self.AddDDX(105, "recursive") + self.AddDDX(106, "verbose") + self._obj_.data["greppattern"] = gp + self._obj_.data["dirpattern"] = dp + self._obj_.data["filpattern"] = fp + self._obj_.data["casesensitive"] = cs + self._obj_.data["recursive"] = r + self._obj_.data["verbose"] = v + self.HookCommand(self.OnMoreDirectories, 110) + self.HookCommand(self.OnMoreFiles, 111) + + def OnMoreDirectories(self, cmd, code): + if code != 0: + return 1 + self.getMore("Grep\\Directories", "dirpattern") + + def OnMoreFiles(self, cmd, code): + if code != 0: + return 1 + self.getMore("Grep\\File Types", "filpattern") + + def getMore(self, section, key): + self.UpdateData(1) + # get the items out of the ini file + ini = win32ui.GetProfileFileName() + secitems = win32api.GetProfileSection(section, ini) + items = [] + for secitem in secitems: + items.append(secitem.split("=")[1]) + dlg = GrepParamsDialog(items) + if dlg.DoModal() == win32con.IDOK: + itemstr = ";".join(dlg.getItems()) + self._obj_.data[key] = itemstr + # update the ini file with dlg.getNew() + i = 0 + newitems = dlg.getNew() + if newitems: + items = items + newitems + for item in items: + win32api.WriteProfileVal(section, repr(i), item, ini) + i = i + 1 + self.UpdateData(0) + + def OnOK(self): + self.UpdateData(1) + for id, name in ( + (101, "greppattern"), + (102, "dirpattern"), + (103, "filpattern"), + ): + if not self[name]: + self.GetDlgItem(id).SetFocus() + win32api.MessageBeep() + win32ui.SetStatusText("Please enter a value") + return + self._obj_.OnOK() + + +class GrepParamsDialog(dialog.Dialog): + def __init__(self, items): + self.items = items + self.newitems = [] + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + CS = win32con.WS_CHILD | win32con.WS_VISIBLE + tmp = [ + ["Grep Parameters", (0, 0, 205, 100), style, None, (8, "MS Sans Serif")], + ] + tmp.append( + [ + LISTBOX, + "", + 107, + (7, 7, 150, 72), + CS + | win32con.LBS_MULTIPLESEL + | win32con.LBS_STANDARD + | win32con.LBS_HASSTRINGS + | win32con.WS_TABSTOP + | win32con.LBS_NOTIFY, + ] + ) + tmp.append( + [ + BUTTON, + "OK", + win32con.IDOK, + (167, 7, 32, 12), + CS | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append( + [ + BUTTON, + "Cancel", + win32con.IDCANCEL, + (167, 23, 32, 12), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + tmp.append([STATIC, "New:", -1, (2, 83, 15, 12), CS]) + tmp.append( + [ + EDIT, + "", + 108, + (18, 83, 139, 12), + CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER, + ] + ) + tmp.append( + [ + BUTTON, + "Add", + 109, + (167, 83, 32, 12), + CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP, + ] + ) + dialog.Dialog.__init__(self, tmp) + self.HookCommand(self.OnAddItem, 109) + self.HookCommand(self.OnListDoubleClick, 107) + + def OnInitDialog(self): + lb = self.GetDlgItem(107) + for item in self.items: + lb.AddString(item) + return self._obj_.OnInitDialog() + + def OnAddItem(self, cmd, code): + if code != 0: + return 1 + eb = self.GetDlgItem(108) + item = eb.GetLine(0) + self.newitems.append(item) + lb = self.GetDlgItem(107) + i = lb.AddString(item) + lb.SetSel(i, 1) + return 1 + + def OnListDoubleClick(self, cmd, code): + if code == win32con.LBN_DBLCLK: + self.OnOK() + return 1 + + def OnOK(self): + lb = self.GetDlgItem(107) + self.selections = lb.GetSelTextItems() + self._obj_.OnOK() + + def getItems(self): + return self.selections + + def getNew(self): + return self.newitems + + +try: + win32ui.GetApp().RemoveDocTemplate(greptemplate) +except NameError: + pass + +greptemplate = GrepTemplate() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/startup.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/startup.py new file mode 100644 index 0000000000000000000000000000000000000000..4a7323225d7b3cbae8ee88a3e803da509b6f1f55 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/startup.py @@ -0,0 +1,80 @@ +# startup.py +# +"The main application startup code for PythonWin." + +# +# This does the basic command line handling. + +# Keep this as short as possible, cos error output is only redirected if +# this runs OK. Errors in imported modules are much better - the messages go somewhere (not any more :-) + +import os +import sys + +import win32api +import win32ui + +if not sys.argv: + # Initialize sys.argv from commandline. When sys.argv is empty list ( + # different from [''] meaning "no cmd line arguments" ), then C + # bootstrapping or another method of invocation failed to initialize + # sys.argv and it will be done here. ( This was a workaround for a bug in + # win32ui but is retained for other situations. ) + argv = win32api.CommandLineToArgv(win32api.GetCommandLine()) + sys.argv = argv[1:] + if os.getcwd() not in sys.path and "." not in sys.path: + sys.path.insert(0, os.getcwd()) + +# You may wish to redirect error output somewhere useful if you have startup errors. +# eg, 'import win32traceutil' will do this for you. +# import win32traceutil # Just uncomment this line to see error output! + +# An old class I used to use - generally only useful if Pythonwin is running under MSVC +# class DebugOutput: +# softspace=1 +# def write(self,message): +# win32ui.OutputDebug(message) +# sys.stderr=sys.stdout=DebugOutput() + +# To fix a problem with Pythonwin when started from the Pythonwin directory, +# we update the pywin path to ensure it is absolute. +# If it is indeed relative, it will be relative to our current directory. +# If its already absolute, then this will have no affect. +import pywin +import pywin.framework + +pywin.__path__[0] = win32ui.FullPath(pywin.__path__[0]) +pywin.framework.__path__[0] = win32ui.FullPath(pywin.framework.__path__[0]) + +# make a few wierd sys values. This is so later we can clobber sys.argv to trick +# scripts when running under a GUI environment. + +moduleName = "pywin.framework.intpyapp" +sys.appargvoffset = 0 +sys.appargv = sys.argv[:] +# Must check for /app param here. +if len(sys.argv) >= 2 and sys.argv[0].lower() in ("/app", "-app"): + from . import cmdline + + moduleName = cmdline.FixArgFileName(sys.argv[1]) + sys.appargvoffset = 2 + newargv = sys.argv[sys.appargvoffset :] + # newargv.insert(0, sys.argv[0]) + sys.argv = newargv + +# Import the application module. +__import__(moduleName) + +try: + win32ui.GetApp()._obj_ + # This worked - an app already exists - do nothing more +except (AttributeError, win32ui.error): + # This means either no app object exists at all, or the one + # that does exist does not have a Python class (ie, was created + # by the host .EXE). In this case, we do the "old style" init... + from . import app + + if app.AppBuilder is None: + raise TypeError("No application object has been registered") + + app.App = app.AppBuilder() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/stdin.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/stdin.py new file mode 100644 index 0000000000000000000000000000000000000000..2f3adcb6b5758b238cd9ea26ac10b6ebdae2fdae --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/stdin.py @@ -0,0 +1,176 @@ +# Copyright (c) 2000 David Abrahams. Permission to copy, use, modify, sell +# and distribute this software is granted provided this copyright +# notice appears in all copies. This software is provided "as is" without +# express or implied warranty, and with no claim as to its suitability for +# any purpose. +"""Provides a class Stdin which can be used to emulate the regular old +sys.stdin for the PythonWin interactive window. Right now it just pops +up a raw_input() dialog. With luck, someone will integrate it into the +actual PythonWin interactive window someday. + +WARNING: Importing this file automatically replaces sys.stdin with an +instance of Stdin (below). This is useful because you can just open +Stdin.py in PythonWin and hit the import button to get it set up right +if you don't feel like changing PythonWin's source. To put things back +the way they were, simply use this magic incantation: + import sys + sys.stdin = sys.stdin.real_file +""" +import sys + +try: + get_input_line = raw_input # py2x +except NameError: + get_input_line = input # py3k + + +class Stdin: + def __init__(self): + self.real_file = sys.stdin # NOTE: Likely to be None in py3k + self.buffer = "" + self.closed = False + + def __getattr__(self, name): + """Forward most functions to the real sys.stdin for absolute realism.""" + if self.real_file is None: + raise AttributeError(name) + return getattr(self.real_file, name) + + def isatty(self): + """Return 1 if the file is connected to a tty(-like) device, else 0.""" + return 1 + + def read(self, size=-1): + """Read at most size bytes from the file (less if the read + hits EOF or no more data is immediately available on a pipe, + tty or similar device). If the size argument is negative or + omitted, read all data until EOF is reached. The bytes are + returned as a string object. An empty string is returned when + EOF is encountered immediately. (For certain files, like ttys, + it makes sense to continue reading after an EOF is hit.)""" + result_size = self.__get_lines(size) + return self.__extract_from_buffer(result_size) + + def readline(self, size=-1): + """Read one entire line from the file. A trailing newline + character is kept in the string2.6 (but may be absent when a file ends + with an incomplete line). If the size argument is present and + non-negative, it is a maximum byte count (including the trailing + newline) and an incomplete line may be returned. An empty string is + returned when EOF is hit immediately. Note: unlike stdio's fgets(), + the returned string contains null characters ('\0') if they occurred + in the input. + """ + maximum_result_size = self.__get_lines(size, lambda buffer: "\n" in buffer) + + if "\n" in self.buffer[:maximum_result_size]: + result_size = self.buffer.find("\n", 0, maximum_result_size) + 1 + assert result_size > 0 + else: + result_size = maximum_result_size + + return self.__extract_from_buffer(result_size) + + def __extract_from_buffer(self, character_count): + """Remove the first character_count characters from the internal buffer and + return them. + """ + result = self.buffer[:character_count] + self.buffer = self.buffer[character_count:] + return result + + def __get_lines(self, desired_size, done_reading=lambda buffer: False): + """Keep adding lines to our internal buffer until done_reading(self.buffer) + is true or EOF has been reached or we have desired_size bytes in the buffer. + If desired_size < 0, we are never satisfied until we reach EOF. If done_reading + is not supplied, it is not consulted. + + If desired_size < 0, returns the length of the internal buffer. Otherwise, + returns desired_size. + """ + while not done_reading(self.buffer) and ( + desired_size < 0 or len(self.buffer) < desired_size + ): + try: + self.__get_line() + except ( + EOFError, + KeyboardInterrupt, + ): # deal with cancellation of get_input_line dialog + desired_size = len(self.buffer) # Be satisfied! + + if desired_size < 0: + return len(self.buffer) + else: + return desired_size + + def __get_line(self): + """Grab one line from get_input_line() and append it to the buffer.""" + line = get_input_line() + print(">>>", line) # echo input to console + self.buffer = self.buffer + line + "\n" + + def readlines(self, *sizehint): + """Read until EOF using readline() and return a list containing the lines + thus read. If the optional sizehint argument is present, instead of + reading up to EOF, whole lines totalling approximately sizehint bytes + (possibly after rounding up to an internal buffer size) are read. + """ + result = [] + total_read = 0 + while sizehint == () or total_read < sizehint[0]: + line = self.readline() + if line == "": + break + total_read = total_read + len(line) + result.append(line) + return result + + +if __name__ == "__main__": + test_input = r"""this is some test +input that I am hoping +~ +will be very instructive +and when I am done +I will have tested everything. +Twelve and twenty blackbirds +baked in a pie. Patty cake +patty cake so am I. +~ +Thirty-five niggling idiots! +Sell you soul to the devil, baby +""" + + def fake_raw_input(prompt=None): + """Replacement for raw_input() which pulls lines out of global test_input. + For testing only! + """ + global test_input + if "\n" not in test_input: + end_of_line_pos = len(test_input) + else: + end_of_line_pos = test_input.find("\n") + result = test_input[:end_of_line_pos] + test_input = test_input[end_of_line_pos + 1 :] + if len(result) == 0 or result[0] == "~": + raise EOFError() + return result + + get_input_line = fake_raw_input + + # Some completely inadequate tests, just to make sure the code's not totally broken + try: + x = Stdin() + print(x.read()) + print(x.readline()) + print(x.read(12)) + print(x.readline(47)) + print(x.readline(3)) + print(x.readlines()) + finally: + get_input_line = raw_input +else: + import sys + + sys.stdin = Stdin() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/toolmenu.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/toolmenu.py new file mode 100644 index 0000000000000000000000000000000000000000..3f739e09e8a26d97ecba2d2c7fb4cebc4bf72ff6 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/toolmenu.py @@ -0,0 +1,284 @@ +# toolmenu.py + +import sys + +import win32api +import win32con +import win32ui + +from . import app + +tools = {} +idPos = 100 + +# The default items should no tools menu exist in the INI file. +defaultToolMenuItems = [ + ("Browser", "win32ui.GetApp().OnViewBrowse(0,0)"), + ( + "Browse PythonPath", + "from pywin.tools import browseProjects;browseProjects.Browse()", + ), + ("Edit Python Path", "from pywin.tools import regedit;regedit.EditRegistry()"), + ("COM Makepy utility", "from win32com.client import makepy;makepy.main()"), + ( + "COM Browser", + "from win32com.client import combrowse;combrowse.main(modal=False)", + ), + ( + "Trace Collector Debugging tool", + "from pywin.tools import TraceCollector;TraceCollector.MakeOutputWindow()", + ), +] + + +def LoadToolMenuItems(): + # Load from the registry. + items = [] + lookNo = 1 + while 1: + menu = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "", "") + if menu == "": + break + cmd = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "Command", "") + items.append((menu, cmd)) + lookNo = lookNo + 1 + + if len(items) == 0: + items = defaultToolMenuItems + return items + + +def WriteToolMenuItems(items): + # Items is a list of (menu, command) + # Delete the entire registry tree. + try: + mainKey = win32ui.GetAppRegistryKey() + toolKey = win32api.RegOpenKey(mainKey, "Tools Menu") + except win32ui.error: + toolKey = None + if toolKey is not None: + while 1: + try: + subkey = win32api.RegEnumKey(toolKey, 0) + except win32api.error: + break + win32api.RegDeleteKey(toolKey, subkey) + # Keys are now removed - write the new ones. + # But first check if we have the defaults - and if so, dont write anything! + if items == defaultToolMenuItems: + return + itemNo = 1 + for menu, cmd in items: + win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "", menu) + win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "Command", cmd) + itemNo = itemNo + 1 + + +def SetToolsMenu(menu, menuPos=None): + global tools + global idPos + + # todo - check the menu does not already exist. + # Create the new menu + toolsMenu = win32ui.CreatePopupMenu() + + # Load from the ini file. + items = LoadToolMenuItems() + for menuString, cmd in items: + tools[idPos] = (menuString, cmd, menuString) + toolsMenu.AppendMenu( + win32con.MF_ENABLED | win32con.MF_STRING, idPos, menuString + ) + win32ui.GetMainFrame().HookCommand(HandleToolCommand, idPos) + idPos = idPos + 1 + + # Find the correct spot to insert the new tools menu. + if menuPos is None: + menuPos = menu.GetMenuItemCount() - 2 + if menuPos < 0: + menuPos = 0 + + menu.InsertMenu( + menuPos, + win32con.MF_BYPOSITION + | win32con.MF_ENABLED + | win32con.MF_STRING + | win32con.MF_POPUP, + toolsMenu.GetHandle(), + "&Tools", + ) + + +def HandleToolCommand(cmd, code): + import re + import traceback + + global tools + (menuString, pyCmd, desc) = tools[cmd] + win32ui.SetStatusText("Executing tool %s" % desc, 1) + pyCmd = re.sub("\\\\n", "\n", pyCmd) + win32ui.DoWaitCursor(1) + oldFlag = None + try: + oldFlag = sys.stdout.template.writeQueueing + sys.stdout.template.writeQueueing = 0 + except (NameError, AttributeError): + pass + + try: + exec("%s\n" % pyCmd) + worked = 1 + except SystemExit: + # The program raised a SystemExit - ignore it. + worked = 1 + except: + print("Failed to execute command:\n%s" % pyCmd) + traceback.print_exc() + worked = 0 + if oldFlag is not None: + sys.stdout.template.writeQueueing = oldFlag + win32ui.DoWaitCursor(0) + if worked: + text = "Completed successfully." + else: + text = "Error executing %s." % desc + win32ui.SetStatusText(text, 1) + + +# The property page for maintaing the items on the Tools menu. +import commctrl +from pywin.mfc import dialog + +if win32ui.UNICODE: + LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW +else: + LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA + + +class ToolMenuPropPage(dialog.PropertyPage): + def __init__(self): + self.bImChangingEditControls = 0 # Am I programatically changing the controls? + dialog.PropertyPage.__init__(self, win32ui.IDD_PP_TOOLMENU) + + def OnInitDialog(self): + self.editMenuCommand = self.GetDlgItem(win32ui.IDC_EDIT2) + self.butNew = self.GetDlgItem(win32ui.IDC_BUTTON3) + + # Now hook the change notification messages for the edit controls. + self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT1) + self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT2) + + self.HookNotify(self.OnNotifyListControl, commctrl.LVN_ITEMCHANGED) + self.HookNotify(self.OnNotifyListControlEndLabelEdit, commctrl.LVN_ENDLABELEDIT) + + # Hook the button clicks. + self.HookCommand(self.OnButtonNew, win32ui.IDC_BUTTON3) # New Item + self.HookCommand(self.OnButtonDelete, win32ui.IDC_BUTTON4) # Delete item + self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON1) # Move up + self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON2) # Move down + + # Setup the columns in the list control + lc = self.GetDlgItem(win32ui.IDC_LIST1) + rect = lc.GetWindowRect() + cx = rect[2] - rect[0] + colSize = cx / 2 - win32api.GetSystemMetrics(win32con.SM_CXBORDER) - 1 + + item = commctrl.LVCFMT_LEFT, colSize, "Menu Text" + lc.InsertColumn(0, item) + + item = commctrl.LVCFMT_LEFT, colSize, "Python Command" + lc.InsertColumn(1, item) + + # Insert the existing tools menu + itemNo = 0 + for desc, cmd in LoadToolMenuItems(): + lc.InsertItem(itemNo, desc) + lc.SetItemText(itemNo, 1, cmd) + itemNo = itemNo + 1 + + self.listControl = lc + return dialog.PropertyPage.OnInitDialog(self) + + def OnOK(self): + # Write the menu back to the registry. + items = [] + itemLook = 0 + while 1: + try: + text = self.listControl.GetItemText(itemLook, 0) + if not text: + break + items.append((text, self.listControl.GetItemText(itemLook, 1))) + except win32ui.error: + # no more items! + break + itemLook = itemLook + 1 + WriteToolMenuItems(items) + return self._obj_.OnOK() + + def OnCommandEditControls(self, id, cmd): + # print "OnEditControls", id, cmd + if cmd == win32con.EN_CHANGE and not self.bImChangingEditControls: + itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED) + newText = self.editMenuCommand.GetWindowText() + self.listControl.SetItemText(itemNo, 1, newText) + + return 0 + + def OnNotifyListControlEndLabelEdit(self, id, cmd): + newText = self.listControl.GetEditControl().GetWindowText() + itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED) + self.listControl.SetItemText(itemNo, 0, newText) + + def OnNotifyListControl(self, id, cmd): + # print id, cmd + try: + itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED) + except win32ui.error: # No selection! + return + + self.bImChangingEditControls = 1 + try: + item = self.listControl.GetItem(itemNo, 1) + self.editMenuCommand.SetWindowText(item[4]) + finally: + self.bImChangingEditControls = 0 + + return 0 # we have handled this! + + def OnButtonNew(self, id, cmd): + if cmd == win32con.BN_CLICKED: + newIndex = self.listControl.GetItemCount() + self.listControl.InsertItem(newIndex, "Click to edit the text") + self.listControl.EnsureVisible(newIndex, 0) + + def OnButtonMove(self, id, cmd): + if cmd == win32con.BN_CLICKED: + try: + itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED) + except win32ui.error: + return + menu = self.listControl.GetItemText(itemNo, 0) + cmd = self.listControl.GetItemText(itemNo, 1) + if id == win32ui.IDC_BUTTON1: + # Move up + if itemNo > 0: + self.listControl.DeleteItem(itemNo) + # reinsert it. + self.listControl.InsertItem(itemNo - 1, menu) + self.listControl.SetItemText(itemNo - 1, 1, cmd) + else: + # Move down. + if itemNo < self.listControl.GetItemCount() - 1: + self.listControl.DeleteItem(itemNo) + # reinsert it. + self.listControl.InsertItem(itemNo + 1, menu) + self.listControl.SetItemText(itemNo + 1, 1, cmd) + + def OnButtonDelete(self, id, cmd): + if cmd == win32con.BN_CLICKED: + try: + itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED) + except win32ui.error: # No selection! + return + self.listControl.DeleteItem(itemNo) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/window.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/window.py new file mode 100644 index 0000000000000000000000000000000000000000..58fd4d953404821d5bd0f114dec808b23f33c0bc --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/window.py @@ -0,0 +1,14 @@ +# Framework Window classes. + +# Most Pythonwin windows should use these classes rather than +# the raw MFC ones if they want Pythonwin specific functionality. +import pywin.mfc.window +import win32con + + +class MDIChildWnd(pywin.mfc.window.MDIChildWnd): + def AutoRestore(self): + "If the window is minimised or maximised, restore it." + p = self.GetWindowPlacement() + if p[1] == win32con.SW_MINIMIZE or p[1] == win32con.SW_SHOWMINIMIZED: + self.SetWindowPlacement(p[0], win32con.SW_RESTORE, p[2], p[3], p[4]) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/framework/winout.py b/MLPY/Lib/site-packages/pythonwin/pywin/framework/winout.py new file mode 100644 index 0000000000000000000000000000000000000000..e78e959a9a232081539768f920624f3e6b7797ba --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/framework/winout.py @@ -0,0 +1,594 @@ +# winout.py +# +# generic "output window" +# +# This Window will detect itself closing, and recreate next time output is +# written to it. + +# This has the option of writing output at idle time (by hooking the +# idle message, and queueing output) or writing as each +# write is executed. +# Updating the window directly gives a jerky appearance as many writes +# take place between commands, and the windows scrolls, and updates etc +# Updating at idle-time may defer all output of a long process, giving the +# appearence nothing is happening. +# There is a compromise "line" mode, which will output whenever +# a complete line is available. + +# behaviour depends on self.writeQueueing + +# This module is thread safe - output can originate from any thread. If any thread +# other than the main thread attempts to print, it is always queued until next idle time + +import queue +import re + +import win32api +import win32con +import win32ui +from pywin.framework import app, window +from pywin.mfc import docview + +debug = lambda msg: None + +##debug=win32ui.OutputDebugString +##import win32trace;win32trace.InitWrite() # for debugging - delete me! +##debug = win32trace.write + + +class flags: + # queueing of output. + WQ_NONE = 0 + WQ_LINE = 1 + WQ_IDLE = 2 + + +# WindowOutputDocumentParent=docview.RichEditDoc +# WindowOutputDocumentParent=docview.Document +import pywin.scintilla.document +from pywin import default_scintilla_encoding +from pywin.scintilla import scintillacon + +WindowOutputDocumentParent = pywin.scintilla.document.CScintillaDocument + + +class WindowOutputDocument(WindowOutputDocumentParent): + def SaveModified(self): + return 1 # say it is OK to destroy my document + + def OnSaveDocument(self, fileName): + win32ui.SetStatusText("Saving file...", 1) + try: + self.SaveFile(fileName) + except IOError as details: + win32ui.MessageBox("Error - could not save file\r\n\r\n%s" % details) + return 0 + win32ui.SetStatusText("Ready") + return 1 + + +class WindowOutputFrame(window.MDIChildWnd): + def __init__(self, wnd=None): + window.MDIChildWnd.__init__(self, wnd) + self.HookMessage(self.OnSizeMove, win32con.WM_SIZE) + self.HookMessage(self.OnSizeMove, win32con.WM_MOVE) + + def LoadFrame(self, idResource, style, wndParent, context): + self.template = context.template + return self._obj_.LoadFrame(idResource, style, wndParent, context) + + def PreCreateWindow(self, cc): + cc = self._obj_.PreCreateWindow(cc) + if ( + self.template.defSize + and self.template.defSize[0] != self.template.defSize[1] + ): + rect = app.RectToCreateStructRect(self.template.defSize) + cc = cc[0], cc[1], cc[2], cc[3], rect, cc[5], cc[6], cc[7], cc[8] + return cc + + def OnSizeMove(self, msg): + # so recreate maintains position. + # Need to map coordinates from the + # frame windows first child. + mdiClient = self.GetParent() + self.template.defSize = mdiClient.ScreenToClient(self.GetWindowRect()) + + def OnDestroy(self, message): + self.template.OnFrameDestroy(self) + return 1 + + +class WindowOutputViewImpl: + def __init__(self): + self.patErrorMessage = re.compile('\W*File "(.*)", line ([0-9]+)') + self.template = self.GetDocument().GetDocTemplate() + + def HookHandlers(self): + # Hook for the right-click menu. + self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN) + + def OnDestroy(self, msg): + self.template.OnViewDestroy(self) + + def OnInitialUpdate(self): + self.RestoreKillBuffer() + self.SetSel(-2) # end of buffer + + def GetRightMenuItems(self): + ret = [] + flags = win32con.MF_STRING | win32con.MF_ENABLED + ret.append((flags, win32ui.ID_EDIT_COPY, "&Copy")) + ret.append((flags, win32ui.ID_EDIT_SELECT_ALL, "&Select all")) + return ret + + # + # Windows command handlers, virtuals, etc. + # + def OnRClick(self, params): + paramsList = self.GetRightMenuItems() + menu = win32ui.CreatePopupMenu() + for appendParams in paramsList: + if type(appendParams) != type(()): + appendParams = (appendParams,) + menu.AppendMenu(*appendParams) + menu.TrackPopupMenu(params[5]) # track at mouse position. + return 0 + + # as this is often used as an output window, exeptions will often + # be printed. Therefore, we support this functionality at this level. + # Returns TRUE if the current line is an error message line, and will + # jump to it. FALSE if no error (and no action taken) + def HandleSpecialLine(self): + from . import scriptutils + + line = self.GetLine() + if line[:11] == "com_error: ": + # An OLE Exception - pull apart the exception + # and try and locate a help file. + try: + import win32api + import win32con + + det = eval(line[line.find(":") + 1 :].strip()) + win32ui.SetStatusText("Opening help file on OLE error...") + from . import help + + help.OpenHelpFile(det[2][3], win32con.HELP_CONTEXT, det[2][4]) + return 1 + except win32api.error as details: + win32ui.SetStatusText( + "The help file could not be opened - %s" % details.strerror + ) + return 1 + except: + win32ui.SetStatusText( + "Line is a COM error, but no WinHelp details can be parsed" + ) + # Look for a Python traceback. + matchResult = self.patErrorMessage.match(line) + if matchResult is None: + # No match - try the previous line + lineNo = self.LineFromChar() + if lineNo > 0: + line = self.GetLine(lineNo - 1) + matchResult = self.patErrorMessage.match(line) + if matchResult is not None: + # we have an error line. + fileName = matchResult.group(1) + if fileName[0] == "<": + win32ui.SetStatusText("Can not load this file") + return 1 # still was an error message. + else: + lineNoString = matchResult.group(2) + # Attempt to locate the file (in case it is a relative spec) + fileNameSpec = fileName + fileName = scriptutils.LocatePythonFile(fileName) + if fileName is None: + # Dont force update, so it replaces the idle prompt. + win32ui.SetStatusText( + "Cant locate the file '%s'" % (fileNameSpec), 0 + ) + return 1 + + win32ui.SetStatusText( + "Jumping to line " + lineNoString + " of file " + fileName, 1 + ) + if not scriptutils.JumpToDocument(fileName, int(lineNoString)): + win32ui.SetStatusText("Could not open %s" % fileName) + return 1 # still was an error message. + return 1 + return 0 # not an error line + + def write(self, msg): + return self.template.write(msg) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def flush(self): + self.template.flush() + + +class WindowOutputViewRTF(docview.RichEditView, WindowOutputViewImpl): + def __init__(self, doc): + docview.RichEditView.__init__(self, doc) + WindowOutputViewImpl.__init__(self) + + def OnInitialUpdate(self): + WindowOutputViewImpl.OnInitialUpdate(self) + return docview.RichEditView.OnInitialUpdate(self) + + def OnDestroy(self, msg): + WindowOutputViewImpl.OnDestroy(self, msg) + docview.RichEditView.OnDestroy(self, msg) + + def HookHandlers(self): + WindowOutputViewImpl.HookHandlers(self) + # Hook for finding and locating error messages + self.HookMessage(self.OnLDoubleClick, win32con.WM_LBUTTONDBLCLK) + + # docview.RichEditView.HookHandlers(self) + + def OnLDoubleClick(self, params): + if self.HandleSpecialLine(): + return 0 # dont pass on + return 1 # pass it on by default. + + def RestoreKillBuffer(self): + if len(self.template.killBuffer): + self.StreamIn(win32con.SF_RTF, self._StreamRTFIn) + self.template.killBuffer = [] + + def SaveKillBuffer(self): + self.StreamOut(win32con.SF_RTFNOOBJS, self._StreamRTFOut) + + def _StreamRTFOut(self, data): + self.template.killBuffer.append(data) + return 1 # keep em coming! + + def _StreamRTFIn(self, bytes): + try: + item = self.template.killBuffer[0] + self.template.killBuffer.remove(item) + if bytes < len(item): + print("Warning - output buffer not big enough!") + return item + except IndexError: + return None + + def dowrite(self, str): + self.SetSel(-2) + self.ReplaceSel(str) + + +import pywin.scintilla.view + + +class WindowOutputViewScintilla( + pywin.scintilla.view.CScintillaView, WindowOutputViewImpl +): + def __init__(self, doc): + pywin.scintilla.view.CScintillaView.__init__(self, doc) + WindowOutputViewImpl.__init__(self) + + def OnInitialUpdate(self): + pywin.scintilla.view.CScintillaView.OnInitialUpdate(self) + self.SCISetMarginWidth(3) + WindowOutputViewImpl.OnInitialUpdate(self) + + def OnDestroy(self, msg): + WindowOutputViewImpl.OnDestroy(self, msg) + pywin.scintilla.view.CScintillaView.OnDestroy(self, msg) + + def HookHandlers(self): + WindowOutputViewImpl.HookHandlers(self) + pywin.scintilla.view.CScintillaView.HookHandlers(self) + self.GetParent().HookNotify( + self.OnScintillaDoubleClick, scintillacon.SCN_DOUBLECLICK + ) + + ## self.HookMessage(self.OnLDoubleClick,win32con.WM_LBUTTONDBLCLK) + + def OnScintillaDoubleClick(self, std, extra): + self.HandleSpecialLine() + + ## def OnLDoubleClick(self,params): + ## return 0 # never dont pass on + + def RestoreKillBuffer(self): + assert len(self.template.killBuffer) in (0, 1), "Unexpected killbuffer contents" + if self.template.killBuffer: + self.SCIAddText(self.template.killBuffer[0]) + self.template.killBuffer = [] + + def SaveKillBuffer(self): + self.template.killBuffer = [self.GetTextRange(0, -1)] + + def dowrite(self, str): + end = self.GetTextLength() + atEnd = end == self.GetSel()[0] + self.SCIInsertText(str, end) + if atEnd: + self.SetSel(self.GetTextLength()) + + def SetWordWrap(self, bWrapOn=1): + if bWrapOn: + wrap_mode = scintillacon.SC_WRAP_WORD + else: + wrap_mode = scintillacon.SC_WRAP_NONE + self.SCISetWrapMode(wrap_mode) + + def _MakeColorizer(self): + return None # No colorizer for me! + + +WindowOutputView = WindowOutputViewScintilla + + +# The WindowOutput class is actually an MFC template. This is a conventient way of +# making sure that my state can exist beyond the life of the windows themselves. +# This is primarily to support the functionality of a WindowOutput window automatically +# being recreated if necessary when written to. +class WindowOutput(docview.DocTemplate): + """Looks like a general Output Window - text can be written by the 'write' method. + Will auto-create itself on first write, and also on next write after being closed""" + + softspace = 1 + + def __init__( + self, + title=None, + defSize=None, + queueing=flags.WQ_LINE, + bAutoRestore=1, + style=None, + makeDoc=None, + makeFrame=None, + makeView=None, + ): + """init the output window - + Params + title=None -- What is the title of the window + defSize=None -- What is the default size for the window - if this + is a string, the size will be loaded from the ini file. + queueing = flags.WQ_LINE -- When should output be written + bAutoRestore=1 -- Should a minimized window be restored. + style -- Style for Window, or None for default. + makeDoc, makeFrame, makeView -- Classes for frame, view and window respectively. + """ + if makeDoc is None: + makeDoc = WindowOutputDocument + if makeFrame is None: + makeFrame = WindowOutputFrame + if makeView is None: + makeView = WindowOutputViewScintilla + docview.DocTemplate.__init__( + self, win32ui.IDR_PYTHONTYPE, makeDoc, makeFrame, makeView + ) + self.SetDocStrings("\nOutput\n\nText Documents (*.txt)\n.txt\n\n\n") + win32ui.GetApp().AddDocTemplate(self) + self.writeQueueing = queueing + self.errorCantRecreate = 0 + self.killBuffer = [] + self.style = style + self.bAutoRestore = bAutoRestore + self.title = title + self.bCreating = 0 + self.interruptCount = 0 + if type(defSize) == type(""): # is a string - maintain size pos from ini file. + self.iniSizeSection = defSize + self.defSize = app.LoadWindowSize(defSize) + self.loadedSize = self.defSize + else: + self.iniSizeSection = None + self.defSize = defSize + self.currentView = None + self.outputQueue = queue.Queue(-1) + self.mainThreadId = win32api.GetCurrentThreadId() + self.idleHandlerSet = 0 + self.SetIdleHandler() + + def __del__(self): + self.Close() + + def Create(self, title=None, style=None): + self.bCreating = 1 + if title: + self.title = title + if style: + self.style = style + doc = self.OpenDocumentFile() + if doc is None: + return + self.currentView = doc.GetFirstView() + self.bCreating = 0 + if self.title: + doc.SetTitle(self.title) + + def Close(self): + self.RemoveIdleHandler() + try: + parent = self.currentView.GetParent() + except (AttributeError, win32ui.error): # Already closed + return + parent.DestroyWindow() + + def SetTitle(self, title): + self.title = title + if self.currentView: + self.currentView.GetDocument().SetTitle(self.title) + + def OnViewDestroy(self, view): + self.currentView.SaveKillBuffer() + self.currentView = None + + def OnFrameDestroy(self, frame): + if self.iniSizeSection: + # use GetWindowPlacement(), as it works even when min'd or max'd + newSize = frame.GetWindowPlacement()[4] + if self.loadedSize != newSize: + app.SaveWindowSize(self.iniSizeSection, newSize) + + def SetIdleHandler(self): + if not self.idleHandlerSet: + debug("Idle handler set\n") + win32ui.GetApp().AddIdleHandler(self.QueueIdleHandler) + self.idleHandlerSet = 1 + + def RemoveIdleHandler(self): + if self.idleHandlerSet: + debug("Idle handler reset\n") + if win32ui.GetApp().DeleteIdleHandler(self.QueueIdleHandler) == 0: + debug("Error deleting idle handler\n") + self.idleHandlerSet = 0 + + def RecreateWindow(self): + if self.errorCantRecreate: + debug("Error = not trying again") + return 0 + try: + # This will fail if app shutting down + win32ui.GetMainFrame().GetSafeHwnd() + self.Create() + return 1 + except (win32ui.error, AttributeError): + self.errorCantRecreate = 1 + debug("Winout can not recreate the Window!\n") + return 0 + + # this handles the idle message, and does the printing. + def QueueIdleHandler(self, handler, count): + try: + bEmpty = self.QueueFlush(20) + # If the queue is empty, then we are back to idle and restart interrupt logic. + if bEmpty: + self.interruptCount = 0 + except KeyboardInterrupt: + # First interrupt since idle we just pass on. + # later ones we dump the queue and give up. + self.interruptCount = self.interruptCount + 1 + if self.interruptCount > 1: + # Drop the queue quickly as the user is already annoyed :-) + self.outputQueue = queue.Queue(-1) + print("Interrupted.") + bEmpty = 1 + else: + raise # re-raise the error so the users exception filters up. + return not bEmpty # More to do if not empty. + + # Returns true if the Window needs to be recreated. + def NeedRecreateWindow(self): + try: + if self.currentView is not None and self.currentView.IsWindow(): + return 0 + except ( + win32ui.error, + AttributeError, + ): # Attribute error if the win32ui object has died. + pass + return 1 + + # Returns true if the Window is OK (either cos it was, or because it was recreated + def CheckRecreateWindow(self): + if self.bCreating: + return 1 + if not self.NeedRecreateWindow(): + return 1 + if self.bAutoRestore: + if self.RecreateWindow(): + return 1 + return 0 + + def QueueFlush(self, max=None): + # Returns true if the queue is empty after the flush + # debug("Queueflush - %d, %d\n" % (max, self.outputQueue.qsize())) + if self.bCreating: + return 1 + items = [] + rc = 0 + while max is None or max > 0: + try: + item = self.outputQueue.get_nowait() + items.append(item) + except queue.Empty: + rc = 1 + break + if max is not None: + max = max - 1 + if len(items) != 0: + if not self.CheckRecreateWindow(): + debug(":Recreate failed!\n") + return 1 # In trouble - so say we have nothing to do. + win32ui.PumpWaitingMessages() # Pump paint messages + self.currentView.dowrite("".join(items)) + return rc + + def HandleOutput(self, message): + # debug("QueueOutput on thread %d, flags %d with '%s'...\n" % (win32api.GetCurrentThreadId(), self.writeQueueing, message )) + self.outputQueue.put(message) + if win32api.GetCurrentThreadId() != self.mainThreadId: + pass + # debug("not my thread - ignoring queue options!\n") + elif self.writeQueueing == flags.WQ_LINE: + pos = message.rfind("\n") + if pos >= 0: + # debug("Line queueing - forcing flush\n") + self.QueueFlush() + return + elif self.writeQueueing == flags.WQ_NONE: + # debug("WQ_NONE - flushing!\n") + self.QueueFlush() + return + # Let our idle handler get it - wake it up + try: + win32ui.GetMainFrame().PostMessage( + win32con.WM_USER + ) # Kick main thread off. + except win32ui.error: + # This can happen as the app is shutting down, so we send it to the C++ debugger + win32api.OutputDebugString(message) + + # delegate certain fns to my view. + def writelines(self, lines): + for line in lines: + self.write(line) + + def write(self, message): + self.HandleOutput(message) + + def flush(self): + self.QueueFlush() + + def HandleSpecialLine(self): + self.currentView.HandleSpecialLine() + + +def RTFWindowOutput(*args, **kw): + kw["makeView"] = WindowOutputViewRTF + return WindowOutput(*args, **kw) + + +def thread_test(o): + for i in range(5): + o.write("Hi from thread %d\n" % (win32api.GetCurrentThreadId())) + win32api.Sleep(100) + + +def test(): + w = WindowOutput(queueing=flags.WQ_IDLE) + w.write("First bit of text\n") + import _thread + + for i in range(5): + w.write("Hello from the main thread\n") + _thread.start_new(thread_test, (w,)) + for i in range(2): + w.write("Hello from the main thread\n") + win32api.Sleep(50) + return w + + +if __name__ == "__main__": + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/AutoExpand.py b/MLPY/Lib/site-packages/pythonwin/pywin/idle/AutoExpand.py new file mode 100644 index 0000000000000000000000000000000000000000..3b302ee93def3aa4e4029915612af4af9b81f995 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/idle/AutoExpand.py @@ -0,0 +1,95 @@ +import re +import string + +###$ event <> +###$ win +###$ unix + + +class AutoExpand: + keydefs = { + "<>": [""], + } + + unix_keydefs = { + "<>": [""], + } + + menudefs = [ + ( + "edit", + [ + ("E_xpand word", "<>"), + ], + ), + ] + + wordchars = string.ascii_letters + string.digits + "_" + + def __init__(self, editwin): + self.text = editwin.text + self.text.wordlist = None # XXX what is this? + self.state = None + + def expand_word_event(self, event): + curinsert = self.text.index("insert") + curline = self.text.get("insert linestart", "insert lineend") + if not self.state: + words = self.getwords() + index = 0 + else: + words, index, insert, line = self.state + if insert != curinsert or line != curline: + words = self.getwords() + index = 0 + if not words: + self.text.bell() + return "break" + word = self.getprevword() + self.text.delete("insert - %d chars" % len(word), "insert") + newword = words[index] + index = (index + 1) % len(words) + if index == 0: + self.text.bell() # Warn we cycled around + self.text.insert("insert", newword) + curinsert = self.text.index("insert") + curline = self.text.get("insert linestart", "insert lineend") + self.state = words, index, curinsert, curline + return "break" + + def getwords(self): + word = self.getprevword() + if not word: + return [] + before = self.text.get("1.0", "insert wordstart") + wbefore = re.findall(r"\b" + word + r"\w+\b", before) + del before + after = self.text.get("insert wordend", "end") + wafter = re.findall(r"\b" + word + r"\w+\b", after) + del after + if not wbefore and not wafter: + return [] + words = [] + dict = {} + # search backwards through words before + wbefore.reverse() + for w in wbefore: + if dict.get(w): + continue + words.append(w) + dict[w] = w + # search onwards through words after + for w in wafter: + if dict.get(w): + continue + words.append(w) + dict[w] = w + words.append(word) + return words + + def getprevword(self): + line = self.text.get("insert linestart", "insert") + i = len(line) + while i > 0 and line[i - 1] in self.wordchars: + i = i - 1 + return line[i:] diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/AutoIndent.py b/MLPY/Lib/site-packages/pythonwin/pywin/idle/AutoIndent.py new file mode 100644 index 0000000000000000000000000000000000000000..c5adc5f8665d25320e0b49699cb5272be03c7abe --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/idle/AutoIndent.py @@ -0,0 +1,547 @@ +import sys +import tokenize + +from pywin import default_scintilla_encoding + +from . import PyParse + +if sys.version_info < (3,): + # in py2k, tokenize() takes a 'token eater' callback, while + # generate_tokens is a generator that works with str objects. + token_generator = tokenize.generate_tokens +else: + # in py3k tokenize() is the generator working with 'byte' objects, and + # token_generator is the 'undocumented b/w compat' function that + # theoretically works with str objects - but actually seems to fail) + token_generator = tokenize.tokenize + + +class AutoIndent: + menudefs = [ + ( + "edit", + [ + None, + ("_Indent region", "<>"), + ("_Dedent region", "<>"), + ("Comment _out region", "<>"), + ("U_ncomment region", "<>"), + ("Tabify region", "<>"), + ("Untabify region", "<>"), + ("Toggle tabs", "<>"), + ("New indent width", "<>"), + ], + ), + ] + + keydefs = { + "<>": [""], + "<>": ["", ""], + "<>": [""], + } + + windows_keydefs = { + "<>": [""], + "<>": [""], + "<>": [""], + "<>": [""], + "<>": [""], + "<>": [""], + "<>": [""], + "<>": [""], + } + + unix_keydefs = { + "<>": [ + "", + "", + "", + ], + "<>": [ + "", + "", + "", + ], + "<>": ["", ""], + "<>": ["", ""], + "<>": ["", ""], + "<>": ["", ""], + "<>": [""], + "<>": [""], + } + + # usetabs true -> literal tab characters are used by indent and + # dedent cmds, possibly mixed with spaces if + # indentwidth is not a multiple of tabwidth + # false -> tab characters are converted to spaces by indent + # and dedent cmds, and ditto TAB keystrokes + # indentwidth is the number of characters per logical indent level. + # tabwidth is the display width of a literal tab character. + # CAUTION: telling Tk to use anything other than its default + # tab setting causes it to use an entirely different tabbing algorithm, + # treating tab stops as fixed distances from the left margin. + # Nobody expects this, so for now tabwidth should never be changed. + usetabs = 1 + indentwidth = 4 + tabwidth = 8 # for IDLE use, must remain 8 until Tk is fixed + + # If context_use_ps1 is true, parsing searches back for a ps1 line; + # else searches for a popular (if, def, ...) Python stmt. + context_use_ps1 = 0 + + # When searching backwards for a reliable place to begin parsing, + # first start num_context_lines[0] lines back, then + # num_context_lines[1] lines back if that didn't work, and so on. + # The last value should be huge (larger than the # of lines in a + # conceivable file). + # Making the initial values larger slows things down more often. + num_context_lines = 50, 500, 5000000 + + def __init__(self, editwin): + self.editwin = editwin + self.text = editwin.text + + def config(self, **options): + for key, value in options.items(): + if key == "usetabs": + self.usetabs = value + elif key == "indentwidth": + self.indentwidth = value + elif key == "tabwidth": + self.tabwidth = value + elif key == "context_use_ps1": + self.context_use_ps1 = value + else: + raise KeyError("bad option name: %s" % repr(key)) + + # If ispythonsource and guess are true, guess a good value for + # indentwidth based on file content (if possible), and if + # indentwidth != tabwidth set usetabs false. + # In any case, adjust the Text widget's view of what a tab + # character means. + + def set_indentation_params(self, ispythonsource, guess=1): + if guess and ispythonsource: + i = self.guess_indent() + if 2 <= i <= 8: + self.indentwidth = i + if self.indentwidth != self.tabwidth: + self.usetabs = 0 + + self.editwin.set_tabwidth(self.tabwidth) + + def smart_backspace_event(self, event): + text = self.text + first, last = self.editwin.get_selection_indices() + if first and last: + text.delete(first, last) + text.mark_set("insert", first) + return "break" + # Delete whitespace left, until hitting a real char or closest + # preceding virtual tab stop. + chars = text.get("insert linestart", "insert") + if chars == "": + if text.compare("insert", ">", "1.0"): + # easy: delete preceding newline + text.delete("insert-1c") + else: + text.bell() # at start of buffer + return "break" + if chars[-1] not in " \t": + # easy: delete preceding real char + text.delete("insert-1c") + return "break" + # Ick. It may require *inserting* spaces if we back up over a + # tab character! This is written to be clear, not fast. + have = len(chars.expandtabs(self.tabwidth)) + assert have > 0 + want = int((have - 1) / self.indentwidth) * self.indentwidth + ncharsdeleted = 0 + while 1: + chars = chars[:-1] + ncharsdeleted = ncharsdeleted + 1 + have = len(chars.expandtabs(self.tabwidth)) + if have <= want or chars[-1] not in " \t": + break + text.undo_block_start() + text.delete("insert-%dc" % ncharsdeleted, "insert") + if have < want: + text.insert("insert", " " * (want - have)) + text.undo_block_stop() + return "break" + + def smart_indent_event(self, event): + # if intraline selection: + # delete it + # elif multiline selection: + # do indent-region & return + # indent one level + text = self.text + first, last = self.editwin.get_selection_indices() + text.undo_block_start() + try: + if first and last: + if index2line(first) != index2line(last): + return self.indent_region_event(event) + text.delete(first, last) + text.mark_set("insert", first) + prefix = text.get("insert linestart", "insert") + raw, effective = classifyws(prefix, self.tabwidth) + if raw == len(prefix): + # only whitespace to the left + self.reindent_to(effective + self.indentwidth) + else: + if self.usetabs: + pad = "\t" + else: + effective = len(prefix.expandtabs(self.tabwidth)) + n = self.indentwidth + pad = " " * (n - effective % n) + text.insert("insert", pad) + text.see("insert") + return "break" + finally: + text.undo_block_stop() + + def newline_and_indent_event(self, event): + text = self.text + first, last = self.editwin.get_selection_indices() + text.undo_block_start() + try: + if first and last: + text.delete(first, last) + text.mark_set("insert", first) + line = text.get("insert linestart", "insert") + i, n = 0, len(line) + while i < n and line[i] in " \t": + i = i + 1 + if i == n: + # the cursor is in or at leading indentation; just inject + # an empty line at the start and strip space from current line + text.delete("insert - %d chars" % i, "insert") + text.insert("insert linestart", "\n") + return "break" + indent = line[:i] + # strip whitespace before insert point + i = 0 + while line and line[-1] in " \t": + line = line[:-1] + i = i + 1 + if i: + text.delete("insert - %d chars" % i, "insert") + # strip whitespace after insert point + while text.get("insert") in " \t": + text.delete("insert") + # start new line + text.insert("insert", "\n") + + # adjust indentation for continuations and block + # open/close first need to find the last stmt + lno = index2line(text.index("insert")) + y = PyParse.Parser(self.indentwidth, self.tabwidth) + for context in self.num_context_lines: + startat = max(lno - context, 1) + startatindex = repr(startat) + ".0" + rawtext = text.get(startatindex, "insert") + y.set_str(rawtext) + bod = y.find_good_parse_start( + self.context_use_ps1, self._build_char_in_string_func(startatindex) + ) + if bod is not None or startat == 1: + break + y.set_lo(bod or 0) + c = y.get_continuation_type() + if c != PyParse.C_NONE: + # The current stmt hasn't ended yet. + if c == PyParse.C_STRING: + # inside a string; just mimic the current indent + text.insert("insert", indent) + elif c == PyParse.C_BRACKET: + # line up with the first (if any) element of the + # last open bracket structure; else indent one + # level beyond the indent of the line with the + # last open bracket + self.reindent_to(y.compute_bracket_indent()) + elif c == PyParse.C_BACKSLASH: + # if more than one line in this stmt already, just + # mimic the current indent; else if initial line + # has a start on an assignment stmt, indent to + # beyond leftmost =; else to beyond first chunk of + # non-whitespace on initial line + if y.get_num_lines_in_stmt() > 1: + text.insert("insert", indent) + else: + self.reindent_to(y.compute_backslash_indent()) + else: + assert 0, "bogus continuation type " + repr(c) + return "break" + + # This line starts a brand new stmt; indent relative to + # indentation of initial line of closest preceding + # interesting stmt. + indent = y.get_base_indent_string() + text.insert("insert", indent) + if y.is_block_opener(): + self.smart_indent_event(event) + elif indent and y.is_block_closer(): + self.smart_backspace_event(event) + return "break" + finally: + text.see("insert") + text.undo_block_stop() + + auto_indent = newline_and_indent_event + + # Our editwin provides a is_char_in_string function that works + # with a Tk text index, but PyParse only knows about offsets into + # a string. This builds a function for PyParse that accepts an + # offset. + + def _build_char_in_string_func(self, startindex): + def inner(offset, _startindex=startindex, _icis=self.editwin.is_char_in_string): + return _icis(_startindex + "+%dc" % offset) + + return inner + + def indent_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines)): + line = lines[pos] + if line: + raw, effective = classifyws(line, self.tabwidth) + effective = effective + self.indentwidth + lines[pos] = self._make_blanks(effective) + line[raw:] + self.set_region(head, tail, chars, lines) + return "break" + + def dedent_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines)): + line = lines[pos] + if line: + raw, effective = classifyws(line, self.tabwidth) + effective = max(effective - self.indentwidth, 0) + lines[pos] = self._make_blanks(effective) + line[raw:] + self.set_region(head, tail, chars, lines) + return "break" + + def comment_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines) - 1): + line = lines[pos] + lines[pos] = "##" + line + self.set_region(head, tail, chars, lines) + + def uncomment_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines)): + line = lines[pos] + if not line: + continue + if line[:2] == "##": + line = line[2:] + elif line[:1] == "#": + line = line[1:] + lines[pos] = line + self.set_region(head, tail, chars, lines) + + def tabify_region_event(self, event): + head, tail, chars, lines = self.get_region() + tabwidth = self._asktabwidth() + for pos in range(len(lines)): + line = lines[pos] + if line: + raw, effective = classifyws(line, tabwidth) + ntabs, nspaces = divmod(effective, tabwidth) + lines[pos] = "\t" * ntabs + " " * nspaces + line[raw:] + self.set_region(head, tail, chars, lines) + + def untabify_region_event(self, event): + head, tail, chars, lines = self.get_region() + tabwidth = self._asktabwidth() + for pos in range(len(lines)): + lines[pos] = lines[pos].expandtabs(tabwidth) + self.set_region(head, tail, chars, lines) + + def toggle_tabs_event(self, event): + if self.editwin.askyesno( + "Toggle tabs", + "Turn tabs " + ("on", "off")[self.usetabs] + "?", + parent=self.text, + ): + self.usetabs = not self.usetabs + return "break" + + # XXX this isn't bound to anything -- see class tabwidth comments + def change_tabwidth_event(self, event): + new = self._asktabwidth() + if new != self.tabwidth: + self.tabwidth = new + self.set_indentation_params(0, guess=0) + return "break" + + def change_indentwidth_event(self, event): + new = self.editwin.askinteger( + "Indent width", + "New indent width (1-16)", + parent=self.text, + initialvalue=self.indentwidth, + minvalue=1, + maxvalue=16, + ) + if new and new != self.indentwidth: + self.indentwidth = new + return "break" + + def get_region(self): + text = self.text + first, last = self.editwin.get_selection_indices() + if first and last: + head = text.index(first + " linestart") + tail = text.index(last + "-1c lineend +1c") + else: + head = text.index("insert linestart") + tail = text.index("insert lineend +1c") + chars = text.get(head, tail) + lines = chars.split("\n") + return head, tail, chars, lines + + def set_region(self, head, tail, chars, lines): + text = self.text + newchars = "\n".join(lines) + if newchars == chars: + text.bell() + return + text.tag_remove("sel", "1.0", "end") + text.mark_set("insert", head) + text.undo_block_start() + text.delete(head, tail) + text.insert(head, newchars) + text.undo_block_stop() + text.tag_add("sel", head, "insert") + + # Make string that displays as n leading blanks. + + def _make_blanks(self, n): + if self.usetabs: + ntabs, nspaces = divmod(n, self.tabwidth) + return "\t" * ntabs + " " * nspaces + else: + return " " * n + + # Delete from beginning of line to insert point, then reinsert + # column logical (meaning use tabs if appropriate) spaces. + + def reindent_to(self, column): + text = self.text + text.undo_block_start() + if text.compare("insert linestart", "!=", "insert"): + text.delete("insert linestart", "insert") + if column: + text.insert("insert", self._make_blanks(column)) + text.undo_block_stop() + + def _asktabwidth(self): + return ( + self.editwin.askinteger( + "Tab width", + "Spaces per tab?", + parent=self.text, + initialvalue=self.tabwidth, + minvalue=1, + maxvalue=16, + ) + or self.tabwidth + ) + + # Guess indentwidth from text content. + # Return guessed indentwidth. This should not be believed unless + # it's in a reasonable range (e.g., it will be 0 if no indented + # blocks are found). + + def guess_indent(self): + opener, indented = IndentSearcher(self.text, self.tabwidth).run() + if opener and indented: + raw, indentsmall = classifyws(opener, self.tabwidth) + raw, indentlarge = classifyws(indented, self.tabwidth) + else: + indentsmall = indentlarge = 0 + return indentlarge - indentsmall + + +# "line.col" -> line, as an int +def index2line(index): + return int(float(index)) + + +# Look at the leading whitespace in s. +# Return pair (# of leading ws characters, +# effective # of leading blanks after expanding +# tabs to width tabwidth) + + +def classifyws(s, tabwidth): + raw = effective = 0 + for ch in s: + if ch == " ": + raw = raw + 1 + effective = effective + 1 + elif ch == "\t": + raw = raw + 1 + effective = (effective // tabwidth + 1) * tabwidth + else: + break + return raw, effective + + +class IndentSearcher: + # .run() chews over the Text widget, looking for a block opener + # and the stmt following it. Returns a pair, + # (line containing block opener, line containing stmt) + # Either or both may be None. + + def __init__(self, text, tabwidth): + self.text = text + self.tabwidth = tabwidth + self.i = self.finished = 0 + self.blkopenline = self.indentedline = None + + def readline(self): + if self.finished: + val = "" + else: + i = self.i = self.i + 1 + mark = repr(i) + ".0" + if self.text.compare(mark, ">=", "end"): + val = "" + else: + val = self.text.get(mark, mark + " lineend+1c") + # hrm - not sure this is correct in py3k - the source code may have + # an encoding declared, but the data will *always* be in + # default_scintilla_encoding - so if anyone looks at the encoding decl + # in the source they will be wrong. I think. Maybe. Or something... + return val.encode(default_scintilla_encoding) + + def run(self): + OPENERS = ("class", "def", "for", "if", "try", "while") + INDENT = tokenize.INDENT + NAME = tokenize.NAME + + save_tabsize = tokenize.tabsize + tokenize.tabsize = self.tabwidth + try: + try: + for typ, token, start, end, line in token_generator(self.readline): + if typ == NAME and token in OPENERS: + self.blkopenline = line + elif typ == INDENT and self.blkopenline: + self.indentedline = line + break + + except (tokenize.TokenError, IndentationError): + # since we cut off the tokenizer early, we can trigger + # spurious errors + pass + finally: + tokenize.tabsize = save_tabsize + return self.blkopenline, self.indentedline diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/CallTips.py b/MLPY/Lib/site-packages/pythonwin/pywin/idle/CallTips.py new file mode 100644 index 0000000000000000000000000000000000000000..cecc760a14b69e16e210bf7f6ac8fc45b60d746e --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/idle/CallTips.py @@ -0,0 +1,219 @@ +# CallTips.py - An IDLE extension that provides "Call Tips" - ie, a floating window that +# displays parameter information as you open parens. + +import inspect +import string +import sys +import traceback + + +class CallTips: + menudefs = [] + + keydefs = { + "<>": [""], + "<>": [""], + "<>": [""], + "<>": ["", ""], + } + + windows_keydefs = {} + + unix_keydefs = {} + + def __init__(self, editwin): + self.editwin = editwin + self.text = editwin.text + self.calltip = None + if hasattr(self.text, "make_calltip_window"): + self._make_calltip_window = self.text.make_calltip_window + else: + self._make_calltip_window = self._make_tk_calltip_window + + def close(self): + self._make_calltip_window = None + + # Makes a Tk based calltip window. Used by IDLE, but not Pythonwin. + # See __init__ above for how this is used. + def _make_tk_calltip_window(self): + import CallTipWindow + + return CallTipWindow.CallTip(self.text) + + def _remove_calltip_window(self): + if self.calltip: + self.calltip.hidetip() + self.calltip = None + + def paren_open_event(self, event): + self._remove_calltip_window() + arg_text = get_arg_text(self.get_object_at_cursor()) + if arg_text: + self.calltip_start = self.text.index("insert") + self.calltip = self._make_calltip_window() + self.calltip.showtip(arg_text) + return "" # so the event is handled normally. + + def paren_close_event(self, event): + # Now just hides, but later we should check if other + # paren'd expressions remain open. + self._remove_calltip_window() + return "" # so the event is handled normally. + + def check_calltip_cancel_event(self, event): + if self.calltip: + # If we have moved before the start of the calltip, + # or off the calltip line, then cancel the tip. + # (Later need to be smarter about multi-line, etc) + if self.text.compare( + "insert", "<=", self.calltip_start + ) or self.text.compare("insert", ">", self.calltip_start + " lineend"): + self._remove_calltip_window() + return "" # so the event is handled normally. + + def calltip_cancel_event(self, event): + self._remove_calltip_window() + return "" # so the event is handled normally. + + def get_object_at_cursor( + self, + wordchars="._" + + string.ascii_uppercase + + string.ascii_lowercase + + string.digits, + ): + # XXX - This needs to be moved to a better place + # so the "." attribute lookup code can also use it. + text = self.text + chars = text.get("insert linestart", "insert") + i = len(chars) + while i and chars[i - 1] in wordchars: + i = i - 1 + word = chars[i:] + if word: + # How is this for a hack! + import __main__ + + namespace = sys.modules.copy() + namespace.update(__main__.__dict__) + try: + return eval(word, namespace) + except: + pass + return None # Can't find an object. + + +def _find_constructor(class_ob): + # Given a class object, return a function object used for the + # constructor (ie, __init__() ) or None if we can't find one. + try: + return class_ob.__init__ + except AttributeError: + for base in class_ob.__bases__: + rc = _find_constructor(base) + if rc is not None: + return rc + return None + + +def get_arg_text(ob): + # Get a string describing the arguments for the given object. + argText = "" + if ob is not None: + if inspect.isclass(ob): + # Look for the highest __init__ in the class chain. + fob = _find_constructor(ob) + if fob is None: + fob = lambda: None + else: + fob = ob + if inspect.isfunction(fob) or inspect.ismethod(fob): + try: + argText = str(inspect.signature(fob)) + except: + print("Failed to format the args") + traceback.print_exc() + # See if we can use the docstring + if hasattr(ob, "__doc__"): + doc = ob.__doc__ + try: + doc = doc.strip() + pos = doc.find("\n") + except AttributeError: + ## New style classes may have __doc__ slot without actually + ## having a string assigned to it + pass + else: + if pos < 0 or pos > 70: + pos = 70 + if argText: + argText = argText + "\n" + argText = argText + doc[:pos] + + return argText + + +################################################# +# +# Test code +# +if __name__ == "__main__": + + def t1(): + "()" + + def t2(a, b=None): + "(a, b=None)" + + def t3(a, *args): + "(a, *args)" + + def t4(*args): + "(*args)" + + def t5(a, *args): + "(a, *args)" + + def t6(a, b=None, *args, **kw): + "(a, b=None, *args, **kw)" + + class TC: + "(self, a=None, *b)" + + def __init__(self, a=None, *b): + "(self, a=None, *b)" + + def t1(self): + "(self)" + + def t2(self, a, b=None): + "(self, a, b=None)" + + def t3(self, a, *args): + "(self, a, *args)" + + def t4(self, *args): + "(self, *args)" + + def t5(self, a, *args): + "(self, a, *args)" + + def t6(self, a, b=None, *args, **kw): + "(self, a, b=None, *args, **kw)" + + def test(tests): + failed = [] + for t in tests: + expected = t.__doc__ + "\n" + t.__doc__ + if get_arg_text(t) != expected: + failed.append(t) + print( + "%s - expected %s, but got %s" + % (t, repr(expected), repr(get_arg_text(t))) + ) + print("%d of %d tests failed" % (len(failed), len(tests))) + + tc = TC() + tests = t1, t2, t3, t4, t5, t6, TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6 + + test(tests) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/FormatParagraph.py b/MLPY/Lib/site-packages/pythonwin/pywin/idle/FormatParagraph.py new file mode 100644 index 0000000000000000000000000000000000000000..143c18ee32f98990e38b553fd234d93da5dd1fc9 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/idle/FormatParagraph.py @@ -0,0 +1,166 @@ +# Extension to format a paragraph + +# Does basic, standard text formatting, and also understands Python +# comment blocks. Thus, for editing Python source code, this +# extension is really only suitable for reformatting these comment +# blocks or triple-quoted strings. + +# Known problems with comment reformatting: +# * If there is a selection marked, and the first line of the +# selection is not complete, the block will probably not be detected +# as comments, and will have the normal "text formatting" rules +# applied. +# * If a comment block has leading whitespace that mixes tabs and +# spaces, they will not be considered part of the same block. +# * Fancy comments, like this bulleted list, arent handled :-) + +import re + + +class FormatParagraph: + menudefs = [ + ( + "edit", + [ + ("Format Paragraph", "<>"), + ], + ) + ] + + keydefs = { + "<>": [""], + } + + unix_keydefs = { + "<>": [""], + } + + def __init__(self, editwin): + self.editwin = editwin + + def close(self): + self.editwin = None + + def format_paragraph_event(self, event): + text = self.editwin.text + first, last = self.editwin.get_selection_indices() + if first and last: + data = text.get(first, last) + comment_header = "" + else: + first, last, comment_header, data = find_paragraph( + text, text.index("insert") + ) + if comment_header: + # Reformat the comment lines - convert to text sans header. + lines = data.split("\n") + lines = map(lambda st, l=len(comment_header): st[l:], lines) + data = "\n".join(lines) + # Reformat to 70 chars or a 20 char width, whichever is greater. + format_width = max(70 - len(comment_header), 20) + newdata = reformat_paragraph(data, format_width) + # re-split and re-insert the comment header. + newdata = newdata.split("\n") + # If the block ends in a \n, we dont want the comment + # prefix inserted after it. (Im not sure it makes sense to + # reformat a comment block that isnt made of complete + # lines, but whatever!) Can't think of a clean soltution, + # so we hack away + block_suffix = "" + if not newdata[-1]: + block_suffix = "\n" + newdata = newdata[:-1] + builder = lambda item, prefix=comment_header: prefix + item + newdata = "\n".join([builder(d) for d in newdata]) + block_suffix + else: + # Just a normal text format + newdata = reformat_paragraph(data) + text.tag_remove("sel", "1.0", "end") + if newdata != data: + text.mark_set("insert", first) + text.undo_block_start() + text.delete(first, last) + text.insert(first, newdata) + text.undo_block_stop() + else: + text.mark_set("insert", last) + text.see("insert") + + +def find_paragraph(text, mark): + lineno, col = list(map(int, mark.split("."))) + line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) + while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line): + lineno = lineno + 1 + line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) + first_lineno = lineno + comment_header = get_comment_header(line) + comment_header_len = len(comment_header) + while get_comment_header(line) == comment_header and not is_all_white( + line[comment_header_len:] + ): + lineno = lineno + 1 + line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) + last = "%d.0" % lineno + # Search back to beginning of paragraph + lineno = first_lineno - 1 + line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) + while ( + lineno > 0 + and get_comment_header(line) == comment_header + and not is_all_white(line[comment_header_len:]) + ): + lineno = lineno - 1 + line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) + first = "%d.0" % (lineno + 1) + return first, last, comment_header, text.get(first, last) + + +def reformat_paragraph(data, limit=70): + lines = data.split("\n") + i = 0 + n = len(lines) + while i < n and is_all_white(lines[i]): + i = i + 1 + if i >= n: + return data + indent1 = get_indent(lines[i]) + if i + 1 < n and not is_all_white(lines[i + 1]): + indent2 = get_indent(lines[i + 1]) + else: + indent2 = indent1 + new = lines[:i] + partial = indent1 + while i < n and not is_all_white(lines[i]): + # XXX Should take double space after period (etc.) into account + words = re.split("(\s+)", lines[i]) + for j in range(0, len(words), 2): + word = words[j] + if not word: + continue # Can happen when line ends in whitespace + if len((partial + word).expandtabs()) > limit and partial != indent1: + new.append(partial.rstrip()) + partial = indent2 + partial = partial + word + " " + if j + 1 < len(words) and words[j + 1] != " ": + partial = partial + " " + i = i + 1 + new.append(partial.rstrip()) + # XXX Should reformat remaining paragraphs as well + new.extend(lines[i:]) + return "\n".join(new) + + +def is_all_white(line): + return re.match(r"^\s*$", line) is not None + + +def get_indent(line): + return re.match(r"^(\s*)", line).group() + + +def get_comment_header(line): + m = re.match(r"^(\s*#*)", line) + if m is None: + return "" + return m.group(1) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/IdleHistory.py b/MLPY/Lib/site-packages/pythonwin/pywin/idle/IdleHistory.py new file mode 100644 index 0000000000000000000000000000000000000000..24e69240087a5c008d51ac9059ff40a6e95bc8d3 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/idle/IdleHistory.py @@ -0,0 +1,87 @@ +class History: + def __init__(self, text, output_sep="\n"): + self.text = text + self.history = [] + self.history_prefix = None + self.history_pointer = None + self.output_sep = output_sep + text.bind("<>", self.history_prev) + text.bind("<>", self.history_next) + + def history_next(self, event): + self.history_do(0) + return "break" + + def history_prev(self, event): + self.history_do(1) + return "break" + + def _get_source(self, start, end): + # Get source code from start index to end index. Lines in the + # text control may be separated by sys.ps2 . + lines = self.text.get(start, end).split(self.output_sep) + return "\n".join(lines) + + def _put_source(self, where, source): + output = self.output_sep.join(source.split("\n")) + self.text.insert(where, output) + + def history_do(self, reverse): + nhist = len(self.history) + pointer = self.history_pointer + prefix = self.history_prefix + if pointer is not None and prefix is not None: + if ( + self.text.compare("insert", "!=", "end-1c") + or self._get_source("iomark", "end-1c") != self.history[pointer] + ): + pointer = prefix = None + if pointer is None or prefix is None: + prefix = self._get_source("iomark", "end-1c") + if reverse: + pointer = nhist + else: + pointer = -1 + nprefix = len(prefix) + while 1: + if reverse: + pointer = pointer - 1 + else: + pointer = pointer + 1 + if pointer < 0 or pointer >= nhist: + self.text.bell() + if self._get_source("iomark", "end-1c") != prefix: + self.text.delete("iomark", "end-1c") + self._put_source("iomark", prefix) + pointer = prefix = None + break + item = self.history[pointer] + if item[:nprefix] == prefix and len(item) > nprefix: + self.text.delete("iomark", "end-1c") + self._put_source("iomark", item) + break + self.text.mark_set("insert", "end-1c") + self.text.see("insert") + self.text.tag_remove("sel", "1.0", "end") + self.history_pointer = pointer + self.history_prefix = prefix + + def history_store(self, source): + source = source.strip() + if len(source) > 2: + # avoid duplicates + try: + self.history.remove(source) + except ValueError: + pass + self.history.append(source) + self.history_pointer = None + self.history_prefix = None + + def recall(self, s): + s = s.strip() + self.text.tag_remove("sel", "1.0", "end") + self.text.delete("iomark", "end-1c") + self.text.mark_set("insert", "end-1c") + self.text.insert("insert", s) + self.text.see("insert") diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/PyParse.py b/MLPY/Lib/site-packages/pythonwin/pywin/idle/PyParse.py new file mode 100644 index 0000000000000000000000000000000000000000..173336cadef2d57d5502555c9934b6b5dfbe5323 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/idle/PyParse.py @@ -0,0 +1,591 @@ +import re +import string +import sys + +# Reason last stmt is continued (or C_NONE if it's not). +C_NONE, C_BACKSLASH, C_STRING, C_BRACKET = list(range(4)) + +if 0: # for throwaway debugging output + + def dump(*stuff): + sys.__stdout__.write(" ".join(map(str, stuff)) + "\n") + + +# Find what looks like the start of a popular stmt. + +_synchre = re.compile( + r""" + ^ + [ \t]* + (?: if + | for + | while + | else + | def + | return + | assert + | break + | class + | continue + | elif + | try + | except + | raise + | import + ) + \b +""", + re.VERBOSE | re.MULTILINE, +).search + +# Match blank line or non-indenting comment line. + +_junkre = re.compile( + r""" + [ \t]* + (?: \# \S .* )? + \n +""", + re.VERBOSE, +).match + +# Match any flavor of string; the terminating quote is optional +# so that we're robust in the face of incomplete program text. + +_match_stringre = re.compile( + r""" + \""" [^"\\]* (?: + (?: \\. | "(?!"") ) + [^"\\]* + )* + (?: \""" )? + +| " [^"\\\n]* (?: \\. [^"\\\n]* )* "? + +| ''' [^'\\]* (?: + (?: \\. | '(?!'') ) + [^'\\]* + )* + (?: ''' )? + +| ' [^'\\\n]* (?: \\. [^'\\\n]* )* '? +""", + re.VERBOSE | re.DOTALL, +).match + +# Match a line that starts with something interesting; +# used to find the first item of a bracket structure. + +_itemre = re.compile( + r""" + [ \t]* + [^\s#\\] # if we match, m.end()-1 is the interesting char +""", + re.VERBOSE, +).match + +# Match start of stmts that should be followed by a dedent. + +_closere = re.compile( + r""" + \s* + (?: return + | break + | continue + | raise + | pass + ) + \b +""", + re.VERBOSE, +).match + +# Chew up non-special chars as quickly as possible. If match is +# successful, m.end() less 1 is the index of the last boring char +# matched. If match is unsuccessful, the string starts with an +# interesting char. + +_chew_ordinaryre = re.compile( + r""" + [^[\](){}#'"\\]+ +""", + re.VERBOSE, +).match + +# Build translation table to map uninteresting chars to "x", open +# brackets to "(", and close brackets to ")". + +_tran = ["x"] * 256 +for ch in "({[": + _tran[ord(ch)] = "(" +for ch in ")}]": + _tran[ord(ch)] = ")" +for ch in "\"'\\\n#": + _tran[ord(ch)] = ch +# We are called with unicode strings, and str.translate is one of the few +# py2k functions which can't 'do the right thing' - so take care to ensure +# _tran is full of unicode... +_tran = "".join(_tran) +del ch + + +class Parser: + def __init__(self, indentwidth, tabwidth): + self.indentwidth = indentwidth + self.tabwidth = tabwidth + + def set_str(self, str): + assert len(str) == 0 or str[-1] == "\n", "Oops - have str %r" % (str,) + self.str = str + self.study_level = 0 + + # Return index of a good place to begin parsing, as close to the + # end of the string as possible. This will be the start of some + # popular stmt like "if" or "def". Return None if none found: + # the caller should pass more prior context then, if possible, or + # if not (the entire program text up until the point of interest + # has already been tried) pass 0 to set_lo. + # + # This will be reliable iff given a reliable is_char_in_string + # function, meaning that when it says "no", it's absolutely + # guaranteed that the char is not in a string. + # + # Ack, hack: in the shell window this kills us, because there's + # no way to tell the differences between output, >>> etc and + # user input. Indeed, IDLE's first output line makes the rest + # look like it's in an unclosed paren!: + # Python 1.5.2 (#0, Apr 13 1999, ... + + def find_good_parse_start(self, use_ps1, is_char_in_string=None): + str, pos = self.str, None + if use_ps1: + # shell window + ps1 = "\n" + sys.ps1 + i = str.rfind(ps1) + if i >= 0: + pos = i + len(ps1) + # make it look like there's a newline instead + # of ps1 at the start -- hacking here once avoids + # repeated hackery later + self.str = str[: pos - 1] + "\n" + str[pos:] + return pos + + # File window -- real work. + if not is_char_in_string: + # no clue -- make the caller pass everything + return None + + # Peek back from the end for a good place to start, + # but don't try too often; pos will be left None, or + # bumped to a legitimate synch point. + limit = len(str) + for tries in range(5): + i = str.rfind(":\n", 0, limit) + if i < 0: + break + i = str.rfind("\n", 0, i) + 1 # start of colon line + m = _synchre(str, i, limit) + if m and not is_char_in_string(m.start()): + pos = m.start() + break + limit = i + if pos is None: + # Nothing looks like a block-opener, or stuff does + # but is_char_in_string keeps returning true; most likely + # we're in or near a giant string, the colorizer hasn't + # caught up enough to be helpful, or there simply *aren't* + # any interesting stmts. In any of these cases we're + # going to have to parse the whole thing to be sure, so + # give it one last try from the start, but stop wasting + # time here regardless of the outcome. + m = _synchre(str) + if m and not is_char_in_string(m.start()): + pos = m.start() + return pos + + # Peeking back worked; look forward until _synchre no longer + # matches. + i = pos + 1 + while 1: + m = _synchre(str, i) + if m: + s, i = m.span() + if not is_char_in_string(s): + pos = s + else: + break + return pos + + # Throw away the start of the string. Intended to be called with + # find_good_parse_start's result. + + def set_lo(self, lo): + assert lo == 0 or self.str[lo - 1] == "\n" + if lo > 0: + self.str = self.str[lo:] + + # As quickly as humanly possible , find the line numbers (0- + # based) of the non-continuation lines. + # Creates self.{goodlines, continuation}. + + def _study1(self): + if self.study_level >= 1: + return + self.study_level = 1 + + # Map all uninteresting characters to "x", all open brackets + # to "(", all close brackets to ")", then collapse runs of + # uninteresting characters. This can cut the number of chars + # by a factor of 10-40, and so greatly speed the following loop. + str = self.str + str = str.translate(_tran) + str = str.replace("xxxxxxxx", "x") + str = str.replace("xxxx", "x") + str = str.replace("xx", "x") + str = str.replace("xx", "x") + str = str.replace("\nx", "\n") + # note that replacing x\n with \n would be incorrect, because + # x may be preceded by a backslash + + # March over the squashed version of the program, accumulating + # the line numbers of non-continued stmts, and determining + # whether & why the last stmt is a continuation. + continuation = C_NONE + level = lno = 0 # level is nesting level; lno is line number + self.goodlines = goodlines = [0] + push_good = goodlines.append + i, n = 0, len(str) + while i < n: + ch = str[i] + i = i + 1 + + # cases are checked in decreasing order of frequency + if ch == "x": + continue + + if ch == "\n": + lno = lno + 1 + if level == 0: + push_good(lno) + # else we're in an unclosed bracket structure + continue + + if ch == "(": + level = level + 1 + continue + + if ch == ")": + if level: + level = level - 1 + # else the program is invalid, but we can't complain + continue + + if ch == '"' or ch == "'": + # consume the string + quote = ch + if str[i - 1 : i + 2] == quote * 3: + quote = quote * 3 + w = len(quote) - 1 + i = i + w + while i < n: + ch = str[i] + i = i + 1 + + if ch == "x": + continue + + if str[i - 1 : i + w] == quote: + i = i + w + break + + if ch == "\n": + lno = lno + 1 + if w == 0: + # unterminated single-quoted string + if level == 0: + push_good(lno) + break + continue + + if ch == "\\": + assert i < n + if str[i] == "\n": + lno = lno + 1 + i = i + 1 + continue + + # else comment char or paren inside string + + else: + # didn't break out of the loop, so we're still + # inside a string + continuation = C_STRING + continue # with outer loop + + if ch == "#": + # consume the comment + i = str.find("\n", i) + assert i >= 0 + continue + + assert ch == "\\" + assert i < n + if str[i] == "\n": + lno = lno + 1 + if i + 1 == n: + continuation = C_BACKSLASH + i = i + 1 + + # The last stmt may be continued for all 3 reasons. + # String continuation takes precedence over bracket + # continuation, which beats backslash continuation. + if continuation != C_STRING and level > 0: + continuation = C_BRACKET + self.continuation = continuation + + # Push the final line number as a sentinel value, regardless of + # whether it's continued. + assert (continuation == C_NONE) == (goodlines[-1] == lno) + if goodlines[-1] != lno: + push_good(lno) + + def get_continuation_type(self): + self._study1() + return self.continuation + + # study1 was sufficient to determine the continuation status, + # but doing more requires looking at every character. study2 + # does this for the last interesting statement in the block. + # Creates: + # self.stmt_start, stmt_end + # slice indices of last interesting stmt + # self.lastch + # last non-whitespace character before optional trailing + # comment + # self.lastopenbracketpos + # if continuation is C_BRACKET, index of last open bracket + + def _study2(self): + _ws = string.whitespace + if self.study_level >= 2: + return + self._study1() + self.study_level = 2 + + # Set p and q to slice indices of last interesting stmt. + str, goodlines = self.str, self.goodlines + i = len(goodlines) - 1 + p = len(str) # index of newest line + while i: + assert p + # p is the index of the stmt at line number goodlines[i]. + # Move p back to the stmt at line number goodlines[i-1]. + q = p + for nothing in range(goodlines[i - 1], goodlines[i]): + # tricky: sets p to 0 if no preceding newline + p = str.rfind("\n", 0, p - 1) + 1 + # The stmt str[p:q] isn't a continuation, but may be blank + # or a non-indenting comment line. + if _junkre(str, p): + i = i - 1 + else: + break + if i == 0: + # nothing but junk! + assert p == 0 + q = p + self.stmt_start, self.stmt_end = p, q + + # Analyze this stmt, to find the last open bracket (if any) + # and last interesting character (if any). + lastch = "" + stack = [] # stack of open bracket indices + push_stack = stack.append + while p < q: + # suck up all except ()[]{}'"#\\ + m = _chew_ordinaryre(str, p, q) + if m: + # we skipped at least one boring char + newp = m.end() + # back up over totally boring whitespace + i = newp - 1 # index of last boring char + while i >= p and str[i] in " \t\n": + i = i - 1 + if i >= p: + lastch = str[i] + p = newp + if p >= q: + break + + ch = str[p] + + if ch in "([{": + push_stack(p) + lastch = ch + p = p + 1 + continue + + if ch in ")]}": + if stack: + del stack[-1] + lastch = ch + p = p + 1 + continue + + if ch == '"' or ch == "'": + # consume string + # Note that study1 did this with a Python loop, but + # we use a regexp here; the reason is speed in both + # cases; the string may be huge, but study1 pre-squashed + # strings to a couple of characters per line. study1 + # also needed to keep track of newlines, and we don't + # have to. + lastch = ch + p = _match_stringre(str, p, q).end() + continue + + if ch == "#": + # consume comment and trailing newline + p = str.find("\n", p, q) + 1 + assert p > 0 + continue + + assert ch == "\\" + p = p + 1 # beyond backslash + assert p < q + if str[p] != "\n": + # the program is invalid, but can't complain + lastch = ch + str[p] + p = p + 1 # beyond escaped char + + # end while p < q: + + self.lastch = lastch + if stack: + self.lastopenbracketpos = stack[-1] + + # Assuming continuation is C_BRACKET, return the number + # of spaces the next line should be indented. + + def compute_bracket_indent(self): + self._study2() + assert self.continuation == C_BRACKET + j = self.lastopenbracketpos + str = self.str + n = len(str) + origi = i = str.rfind("\n", 0, j) + 1 + j = j + 1 # one beyond open bracket + # find first list item; set i to start of its line + while j < n: + m = _itemre(str, j) + if m: + j = m.end() - 1 # index of first interesting char + extra = 0 + break + else: + # this line is junk; advance to next line + i = j = str.find("\n", j) + 1 + else: + # nothing interesting follows the bracket; + # reproduce the bracket line's indentation + a level + j = i = origi + while str[j] in " \t": + j = j + 1 + extra = self.indentwidth + return len(str[i:j].expandtabs(self.tabwidth)) + extra + + # Return number of physical lines in last stmt (whether or not + # it's an interesting stmt! this is intended to be called when + # continuation is C_BACKSLASH). + + def get_num_lines_in_stmt(self): + self._study1() + goodlines = self.goodlines + return goodlines[-1] - goodlines[-2] + + # Assuming continuation is C_BACKSLASH, return the number of spaces + # the next line should be indented. Also assuming the new line is + # the first one following the initial line of the stmt. + + def compute_backslash_indent(self): + self._study2() + assert self.continuation == C_BACKSLASH + str = self.str + i = self.stmt_start + while str[i] in " \t": + i = i + 1 + startpos = i + + # See whether the initial line starts an assignment stmt; i.e., + # look for an = operator + endpos = str.find("\n", startpos) + 1 + found = level = 0 + while i < endpos: + ch = str[i] + if ch in "([{": + level = level + 1 + i = i + 1 + elif ch in ")]}": + if level: + level = level - 1 + i = i + 1 + elif ch == '"' or ch == "'": + i = _match_stringre(str, i, endpos).end() + elif ch == "#": + break + elif ( + level == 0 + and ch == "=" + and (i == 0 or str[i - 1] not in "=<>!") + and str[i + 1] != "=" + ): + found = 1 + break + else: + i = i + 1 + + if found: + # found a legit =, but it may be the last interesting + # thing on the line + i = i + 1 # move beyond the = + found = re.match(r"\s*\\", str[i:endpos]) is None + + if not found: + # oh well ... settle for moving beyond the first chunk + # of non-whitespace chars + i = startpos + while str[i] not in " \t\n": + i = i + 1 + + return len(str[self.stmt_start : i].expandtabs(self.tabwidth)) + 1 + + # Return the leading whitespace on the initial line of the last + # interesting stmt. + + def get_base_indent_string(self): + self._study2() + i, n = self.stmt_start, self.stmt_end + j = i + str = self.str + while j < n and str[j] in " \t": + j = j + 1 + return str[i:j] + + # Did the last interesting stmt open a block? + + def is_block_opener(self): + self._study2() + return self.lastch == ":" + + # Did the last interesting stmt close a block? + + def is_block_closer(self): + self._study2() + return _closere(self.str, self.stmt_start) is not None + + # index of last open bracket ({[, or None if none + lastopenbracketpos = None + + def get_last_open_bracket_pos(self): + self._study2() + return self.lastopenbracketpos diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b175d75542a65e75b46893ad90d35f27ac589ee0 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__init__.py @@ -0,0 +1 @@ +# This file denotes the directory as a Python package. diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/AutoExpand.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/AutoExpand.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58ae3a2e5710c4b37e9e6c717e5e1562dbb0ebc4 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/AutoExpand.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/AutoIndent.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/AutoIndent.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b48f13668f96456298f9617c5b57de849aca71ff Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/AutoIndent.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/CallTips.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/CallTips.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..598dadb30ed21f9713bc7155b1e54254253aef64 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/CallTips.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/FormatParagraph.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/FormatParagraph.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a8945186ee57451272f3af02fb0b25250cf710e Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/FormatParagraph.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/IdleHistory.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/IdleHistory.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ad7f79a959df80f731437a3f66a4c26ca688f48 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/IdleHistory.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/PyParse.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/PyParse.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97788071a30b0878e30220352cf1e9d0934079ec Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/PyParse.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2def03a1c566c81fec1464bf5ba43181cf83cb10 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/idle/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7cc5cdf60888ebe24e8ebf51e54e534a93c5e05 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/activex.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/activex.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c3181a7d3ffdacfca7c74d0004abdca2c02b5d4 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/activex.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/afxres.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/afxres.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4eddae30544a8ede1155d8a55133ddd9bc48b0ab Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/afxres.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/dialog.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/dialog.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b19548ed0df76982e3b8bc81e016dc0c7b30c6d Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/dialog.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/docview.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/docview.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38de0416615feeec3fd9671ca107ac58e157f404 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/docview.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/object.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/object.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..881e73ba564ec0fe4a44e98b4da3b6fa5e8982aa Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/object.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/thread.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/thread.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0dfd6ca96fa3de76d3643d9ba8db3678c18423f Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/thread.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/window.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/window.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52482c5bc1e7defd059d56f45645c1992dfc2a12 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/__pycache__/window.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/activex.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/activex.py new file mode 100644 index 0000000000000000000000000000000000000000..596bbef5e87137a5c2da9b9afbfa0331fbd9daa0 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/activex.py @@ -0,0 +1,86 @@ +"""Support for ActiveX control hosting in Pythonwin. +""" +import win32ui +import win32uiole + +from . import window + +# XXX - we are still "classic style" classes in py2x, so we need can't yet +# use 'type()' everywhere - revisit soon, as py2x will move to new-style too... +try: + from types import ClassType as new_type +except ImportError: + new_type = type # py3k + + +class Control(window.Wnd): + """An ActiveX control base class. A new class must be derived from both + this class and the Events class. See the demos for more details. + """ + + def __init__(self): + self.__dict__["_dispobj_"] = None + window.Wnd.__init__(self) + + def _GetControlCLSID(self): + return self.CLSID + + def _GetDispatchClass(self): + return self.default_interface + + def _GetEventMap(self): + return self.default_source._dispid_to_func_ + + def CreateControl(self, windowTitle, style, rect, parent, id, lic_string=None): + clsid = str(self._GetControlCLSID()) + self.__dict__["_obj_"] = win32ui.CreateControl( + clsid, windowTitle, style, rect, parent, id, None, False, lic_string + ) + klass = self._GetDispatchClass() + dispobj = klass(win32uiole.GetIDispatchForWindow(self._obj_)) + self.HookOleEvents() + self.__dict__["_dispobj_"] = dispobj + + def HookOleEvents(self): + dict = self._GetEventMap() + for dispid, methodName in dict.items(): + if hasattr(self, methodName): + self._obj_.HookOleEvent(getattr(self, methodName), dispid) + + def __getattr__(self, attr): + # Delegate attributes to the windows and the Dispatch object for this class + try: + return window.Wnd.__getattr__(self, attr) + except AttributeError: + pass + return getattr(self._dispobj_, attr) + + def __setattr__(self, attr, value): + if hasattr(self.__dict__, attr): + self.__dict__[attr] = value + return + try: + if self._dispobj_: + self._dispobj_.__setattr__(attr, value) + return + except AttributeError: + pass + self.__dict__[attr] = value + + +def MakeControlClass(controlClass, name=None): + """Given a CoClass in a generated .py file, this function will return a Class + object which can be used as an OCX control. + + This function is used when you do not want to handle any events from the OCX + control. If you need events, then you should derive a class from both the + activex.Control class and the CoClass + """ + if name is None: + name = controlClass.__name__ + return new_type("OCX" + name, (Control, controlClass), {}) + + +def MakeControlInstance(controlClass, name=None): + """As for MakeControlClass(), but returns an instance of the class.""" + return MakeControlClass(controlClass, name)() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/afxres.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/afxres.py new file mode 100644 index 0000000000000000000000000000000000000000..249211ff359e746a17995d28a2ead6c89bac4f64 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/afxres.py @@ -0,0 +1,501 @@ +# Generated by h2py from stdin +TCS_MULTILINE = 0x0200 +CBRS_ALIGN_LEFT = 0x1000 +CBRS_ALIGN_TOP = 0x2000 +CBRS_ALIGN_RIGHT = 0x4000 +CBRS_ALIGN_BOTTOM = 0x8000 +CBRS_ALIGN_ANY = 0xF000 +CBRS_BORDER_LEFT = 0x0100 +CBRS_BORDER_TOP = 0x0200 +CBRS_BORDER_RIGHT = 0x0400 +CBRS_BORDER_BOTTOM = 0x0800 +CBRS_BORDER_ANY = 0x0F00 +CBRS_TOOLTIPS = 0x0010 +CBRS_FLYBY = 0x0020 +CBRS_FLOAT_MULTI = 0x0040 +CBRS_BORDER_3D = 0x0080 +CBRS_HIDE_INPLACE = 0x0008 +CBRS_SIZE_DYNAMIC = 0x0004 +CBRS_SIZE_FIXED = 0x0002 +CBRS_FLOATING = 0x0001 +CBRS_GRIPPER = 0x00400000 +CBRS_ORIENT_HORZ = CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM +CBRS_ORIENT_VERT = CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT +CBRS_ORIENT_ANY = CBRS_ORIENT_HORZ | CBRS_ORIENT_VERT +CBRS_ALL = 0xFFFF +CBRS_NOALIGN = 0x00000000 +CBRS_LEFT = CBRS_ALIGN_LEFT | CBRS_BORDER_RIGHT +CBRS_TOP = CBRS_ALIGN_TOP | CBRS_BORDER_BOTTOM +CBRS_RIGHT = CBRS_ALIGN_RIGHT | CBRS_BORDER_LEFT +CBRS_BOTTOM = CBRS_ALIGN_BOTTOM | CBRS_BORDER_TOP +SBPS_NORMAL = 0x0000 +SBPS_NOBORDERS = 0x0100 +SBPS_POPOUT = 0x0200 +SBPS_OWNERDRAW = 0x1000 +SBPS_DISABLED = 0x04000000 +SBPS_STRETCH = 0x08000000 +ID_INDICATOR_EXT = 0xE700 +ID_INDICATOR_CAPS = 0xE701 +ID_INDICATOR_NUM = 0xE702 +ID_INDICATOR_SCRL = 0xE703 +ID_INDICATOR_OVR = 0xE704 +ID_INDICATOR_REC = 0xE705 +ID_INDICATOR_KANA = 0xE706 +ID_SEPARATOR = 0 +AFX_IDW_CONTROLBAR_FIRST = 0xE800 +AFX_IDW_CONTROLBAR_LAST = 0xE8FF +AFX_IDW_TOOLBAR = 0xE800 +AFX_IDW_STATUS_BAR = 0xE801 +AFX_IDW_PREVIEW_BAR = 0xE802 +AFX_IDW_RESIZE_BAR = 0xE803 +AFX_IDW_DOCKBAR_TOP = 0xE81B +AFX_IDW_DOCKBAR_LEFT = 0xE81C +AFX_IDW_DOCKBAR_RIGHT = 0xE81D +AFX_IDW_DOCKBAR_BOTTOM = 0xE81E +AFX_IDW_DOCKBAR_FLOAT = 0xE81F + + +def AFX_CONTROLBAR_MASK(nIDC): + return 1 << (nIDC - AFX_IDW_CONTROLBAR_FIRST) + + +AFX_IDW_PANE_FIRST = 0xE900 +AFX_IDW_PANE_LAST = 0xE9FF +AFX_IDW_HSCROLL_FIRST = 0xEA00 +AFX_IDW_VSCROLL_FIRST = 0xEA10 +AFX_IDW_SIZE_BOX = 0xEA20 +AFX_IDW_PANE_SAVE = 0xEA21 +AFX_IDS_APP_TITLE = 0xE000 +AFX_IDS_IDLEMESSAGE = 0xE001 +AFX_IDS_HELPMODEMESSAGE = 0xE002 +AFX_IDS_APP_TITLE_EMBEDDING = 0xE003 +AFX_IDS_COMPANY_NAME = 0xE004 +AFX_IDS_OBJ_TITLE_INPLACE = 0xE005 +ID_FILE_NEW = 0xE100 +ID_FILE_OPEN = 0xE101 +ID_FILE_CLOSE = 0xE102 +ID_FILE_SAVE = 0xE103 +ID_FILE_SAVE_AS = 0xE104 +ID_FILE_PAGE_SETUP = 0xE105 +ID_FILE_PRINT_SETUP = 0xE106 +ID_FILE_PRINT = 0xE107 +ID_FILE_PRINT_DIRECT = 0xE108 +ID_FILE_PRINT_PREVIEW = 0xE109 +ID_FILE_UPDATE = 0xE10A +ID_FILE_SAVE_COPY_AS = 0xE10B +ID_FILE_SEND_MAIL = 0xE10C +ID_FILE_MRU_FIRST = 0xE110 +ID_FILE_MRU_FILE1 = 0xE110 +ID_FILE_MRU_FILE2 = 0xE111 +ID_FILE_MRU_FILE3 = 0xE112 +ID_FILE_MRU_FILE4 = 0xE113 +ID_FILE_MRU_FILE5 = 0xE114 +ID_FILE_MRU_FILE6 = 0xE115 +ID_FILE_MRU_FILE7 = 0xE116 +ID_FILE_MRU_FILE8 = 0xE117 +ID_FILE_MRU_FILE9 = 0xE118 +ID_FILE_MRU_FILE10 = 0xE119 +ID_FILE_MRU_FILE11 = 0xE11A +ID_FILE_MRU_FILE12 = 0xE11B +ID_FILE_MRU_FILE13 = 0xE11C +ID_FILE_MRU_FILE14 = 0xE11D +ID_FILE_MRU_FILE15 = 0xE11E +ID_FILE_MRU_FILE16 = 0xE11F +ID_FILE_MRU_LAST = 0xE11F +ID_EDIT_CLEAR = 0xE120 +ID_EDIT_CLEAR_ALL = 0xE121 +ID_EDIT_COPY = 0xE122 +ID_EDIT_CUT = 0xE123 +ID_EDIT_FIND = 0xE124 +ID_EDIT_PASTE = 0xE125 +ID_EDIT_PASTE_LINK = 0xE126 +ID_EDIT_PASTE_SPECIAL = 0xE127 +ID_EDIT_REPEAT = 0xE128 +ID_EDIT_REPLACE = 0xE129 +ID_EDIT_SELECT_ALL = 0xE12A +ID_EDIT_UNDO = 0xE12B +ID_EDIT_REDO = 0xE12C +ID_WINDOW_NEW = 0xE130 +ID_WINDOW_ARRANGE = 0xE131 +ID_WINDOW_CASCADE = 0xE132 +ID_WINDOW_TILE_HORZ = 0xE133 +ID_WINDOW_TILE_VERT = 0xE134 +ID_WINDOW_SPLIT = 0xE135 +AFX_IDM_WINDOW_FIRST = 0xE130 +AFX_IDM_WINDOW_LAST = 0xE13F +AFX_IDM_FIRST_MDICHILD = 0xFF00 +ID_APP_ABOUT = 0xE140 +ID_APP_EXIT = 0xE141 +ID_HELP_INDEX = 0xE142 +ID_HELP_FINDER = 0xE143 +ID_HELP_USING = 0xE144 +ID_CONTEXT_HELP = 0xE145 +ID_HELP = 0xE146 +ID_DEFAULT_HELP = 0xE147 +ID_NEXT_PANE = 0xE150 +ID_PREV_PANE = 0xE151 +ID_FORMAT_FONT = 0xE160 +ID_OLE_INSERT_NEW = 0xE200 +ID_OLE_EDIT_LINKS = 0xE201 +ID_OLE_EDIT_CONVERT = 0xE202 +ID_OLE_EDIT_CHANGE_ICON = 0xE203 +ID_OLE_EDIT_PROPERTIES = 0xE204 +ID_OLE_VERB_FIRST = 0xE210 +ID_OLE_VERB_LAST = 0xE21F +AFX_ID_PREVIEW_CLOSE = 0xE300 +AFX_ID_PREVIEW_NUMPAGE = 0xE301 +AFX_ID_PREVIEW_NEXT = 0xE302 +AFX_ID_PREVIEW_PREV = 0xE303 +AFX_ID_PREVIEW_PRINT = 0xE304 +AFX_ID_PREVIEW_ZOOMIN = 0xE305 +AFX_ID_PREVIEW_ZOOMOUT = 0xE306 +ID_VIEW_TOOLBAR = 0xE800 +ID_VIEW_STATUS_BAR = 0xE801 +ID_RECORD_FIRST = 0xE900 +ID_RECORD_LAST = 0xE901 +ID_RECORD_NEXT = 0xE902 +ID_RECORD_PREV = 0xE903 +IDC_STATIC = -1 +AFX_IDS_SCFIRST = 0xEF00 +AFX_IDS_SCSIZE = 0xEF00 +AFX_IDS_SCMOVE = 0xEF01 +AFX_IDS_SCMINIMIZE = 0xEF02 +AFX_IDS_SCMAXIMIZE = 0xEF03 +AFX_IDS_SCNEXTWINDOW = 0xEF04 +AFX_IDS_SCPREVWINDOW = 0xEF05 +AFX_IDS_SCCLOSE = 0xEF06 +AFX_IDS_SCRESTORE = 0xEF12 +AFX_IDS_SCTASKLIST = 0xEF13 +AFX_IDS_MDICHILD = 0xEF1F +AFX_IDS_DESKACCESSORY = 0xEFDA +AFX_IDS_OPENFILE = 0xF000 +AFX_IDS_SAVEFILE = 0xF001 +AFX_IDS_ALLFILTER = 0xF002 +AFX_IDS_UNTITLED = 0xF003 +AFX_IDS_SAVEFILECOPY = 0xF004 +AFX_IDS_PREVIEW_CLOSE = 0xF005 +AFX_IDS_UNNAMED_FILE = 0xF006 +AFX_IDS_ABOUT = 0xF010 +AFX_IDS_HIDE = 0xF011 +AFX_IDP_NO_ERROR_AVAILABLE = 0xF020 +AFX_IDS_NOT_SUPPORTED_EXCEPTION = 0xF021 +AFX_IDS_RESOURCE_EXCEPTION = 0xF022 +AFX_IDS_MEMORY_EXCEPTION = 0xF023 +AFX_IDS_USER_EXCEPTION = 0xF024 +AFX_IDS_PRINTONPORT = 0xF040 +AFX_IDS_ONEPAGE = 0xF041 +AFX_IDS_TWOPAGE = 0xF042 +AFX_IDS_PRINTPAGENUM = 0xF043 +AFX_IDS_PREVIEWPAGEDESC = 0xF044 +AFX_IDS_PRINTDEFAULTEXT = 0xF045 +AFX_IDS_PRINTDEFAULT = 0xF046 +AFX_IDS_PRINTFILTER = 0xF047 +AFX_IDS_PRINTCAPTION = 0xF048 +AFX_IDS_PRINTTOFILE = 0xF049 +AFX_IDS_OBJECT_MENUITEM = 0xF080 +AFX_IDS_EDIT_VERB = 0xF081 +AFX_IDS_ACTIVATE_VERB = 0xF082 +AFX_IDS_CHANGE_LINK = 0xF083 +AFX_IDS_AUTO = 0xF084 +AFX_IDS_MANUAL = 0xF085 +AFX_IDS_FROZEN = 0xF086 +AFX_IDS_ALL_FILES = 0xF087 +AFX_IDS_SAVE_MENU = 0xF088 +AFX_IDS_UPDATE_MENU = 0xF089 +AFX_IDS_SAVE_AS_MENU = 0xF08A +AFX_IDS_SAVE_COPY_AS_MENU = 0xF08B +AFX_IDS_EXIT_MENU = 0xF08C +AFX_IDS_UPDATING_ITEMS = 0xF08D +AFX_IDS_METAFILE_FORMAT = 0xF08E +AFX_IDS_DIB_FORMAT = 0xF08F +AFX_IDS_BITMAP_FORMAT = 0xF090 +AFX_IDS_LINKSOURCE_FORMAT = 0xF091 +AFX_IDS_EMBED_FORMAT = 0xF092 +AFX_IDS_PASTELINKEDTYPE = 0xF094 +AFX_IDS_UNKNOWNTYPE = 0xF095 +AFX_IDS_RTF_FORMAT = 0xF096 +AFX_IDS_TEXT_FORMAT = 0xF097 +AFX_IDS_INVALID_CURRENCY = 0xF098 +AFX_IDS_INVALID_DATETIME = 0xF099 +AFX_IDS_INVALID_DATETIMESPAN = 0xF09A +AFX_IDP_INVALID_FILENAME = 0xF100 +AFX_IDP_FAILED_TO_OPEN_DOC = 0xF101 +AFX_IDP_FAILED_TO_SAVE_DOC = 0xF102 +AFX_IDP_ASK_TO_SAVE = 0xF103 +AFX_IDP_FAILED_TO_CREATE_DOC = 0xF104 +AFX_IDP_FILE_TOO_LARGE = 0xF105 +AFX_IDP_FAILED_TO_START_PRINT = 0xF106 +AFX_IDP_FAILED_TO_LAUNCH_HELP = 0xF107 +AFX_IDP_INTERNAL_FAILURE = 0xF108 +AFX_IDP_COMMAND_FAILURE = 0xF109 +AFX_IDP_FAILED_MEMORY_ALLOC = 0xF10A +AFX_IDP_PARSE_INT = 0xF110 +AFX_IDP_PARSE_REAL = 0xF111 +AFX_IDP_PARSE_INT_RANGE = 0xF112 +AFX_IDP_PARSE_REAL_RANGE = 0xF113 +AFX_IDP_PARSE_STRING_SIZE = 0xF114 +AFX_IDP_PARSE_RADIO_BUTTON = 0xF115 +AFX_IDP_PARSE_BYTE = 0xF116 +AFX_IDP_PARSE_UINT = 0xF117 +AFX_IDP_PARSE_DATETIME = 0xF118 +AFX_IDP_PARSE_CURRENCY = 0xF119 +AFX_IDP_FAILED_INVALID_FORMAT = 0xF120 +AFX_IDP_FAILED_INVALID_PATH = 0xF121 +AFX_IDP_FAILED_DISK_FULL = 0xF122 +AFX_IDP_FAILED_ACCESS_READ = 0xF123 +AFX_IDP_FAILED_ACCESS_WRITE = 0xF124 +AFX_IDP_FAILED_IO_ERROR_READ = 0xF125 +AFX_IDP_FAILED_IO_ERROR_WRITE = 0xF126 +AFX_IDP_STATIC_OBJECT = 0xF180 +AFX_IDP_FAILED_TO_CONNECT = 0xF181 +AFX_IDP_SERVER_BUSY = 0xF182 +AFX_IDP_BAD_VERB = 0xF183 +AFX_IDP_FAILED_TO_NOTIFY = 0xF185 +AFX_IDP_FAILED_TO_LAUNCH = 0xF186 +AFX_IDP_ASK_TO_UPDATE = 0xF187 +AFX_IDP_FAILED_TO_UPDATE = 0xF188 +AFX_IDP_FAILED_TO_REGISTER = 0xF189 +AFX_IDP_FAILED_TO_AUTO_REGISTER = 0xF18A +AFX_IDP_FAILED_TO_CONVERT = 0xF18B +AFX_IDP_GET_NOT_SUPPORTED = 0xF18C +AFX_IDP_SET_NOT_SUPPORTED = 0xF18D +AFX_IDP_ASK_TO_DISCARD = 0xF18E +AFX_IDP_FAILED_TO_CREATE = 0xF18F +AFX_IDP_FAILED_MAPI_LOAD = 0xF190 +AFX_IDP_INVALID_MAPI_DLL = 0xF191 +AFX_IDP_FAILED_MAPI_SEND = 0xF192 +AFX_IDP_FILE_NONE = 0xF1A0 +AFX_IDP_FILE_GENERIC = 0xF1A1 +AFX_IDP_FILE_NOT_FOUND = 0xF1A2 +AFX_IDP_FILE_BAD_PATH = 0xF1A3 +AFX_IDP_FILE_TOO_MANY_OPEN = 0xF1A4 +AFX_IDP_FILE_ACCESS_DENIED = 0xF1A5 +AFX_IDP_FILE_INVALID_FILE = 0xF1A6 +AFX_IDP_FILE_REMOVE_CURRENT = 0xF1A7 +AFX_IDP_FILE_DIR_FULL = 0xF1A8 +AFX_IDP_FILE_BAD_SEEK = 0xF1A9 +AFX_IDP_FILE_HARD_IO = 0xF1AA +AFX_IDP_FILE_SHARING = 0xF1AB +AFX_IDP_FILE_LOCKING = 0xF1AC +AFX_IDP_FILE_DISKFULL = 0xF1AD +AFX_IDP_FILE_EOF = 0xF1AE +AFX_IDP_ARCH_NONE = 0xF1B0 +AFX_IDP_ARCH_GENERIC = 0xF1B1 +AFX_IDP_ARCH_READONLY = 0xF1B2 +AFX_IDP_ARCH_ENDOFFILE = 0xF1B3 +AFX_IDP_ARCH_WRITEONLY = 0xF1B4 +AFX_IDP_ARCH_BADINDEX = 0xF1B5 +AFX_IDP_ARCH_BADCLASS = 0xF1B6 +AFX_IDP_ARCH_BADSCHEMA = 0xF1B7 +AFX_IDS_OCC_SCALEUNITS_PIXELS = 0xF1C0 +AFX_IDS_STATUS_FONT = 0xF230 +AFX_IDS_TOOLTIP_FONT = 0xF231 +AFX_IDS_UNICODE_FONT = 0xF232 +AFX_IDS_MINI_FONT = 0xF233 +AFX_IDP_SQL_FIRST = 0xF280 +AFX_IDP_SQL_CONNECT_FAIL = 0xF281 +AFX_IDP_SQL_RECORDSET_FORWARD_ONLY = 0xF282 +AFX_IDP_SQL_EMPTY_COLUMN_LIST = 0xF283 +AFX_IDP_SQL_FIELD_SCHEMA_MISMATCH = 0xF284 +AFX_IDP_SQL_ILLEGAL_MODE = 0xF285 +AFX_IDP_SQL_MULTIPLE_ROWS_AFFECTED = 0xF286 +AFX_IDP_SQL_NO_CURRENT_RECORD = 0xF287 +AFX_IDP_SQL_NO_ROWS_AFFECTED = 0xF288 +AFX_IDP_SQL_RECORDSET_READONLY = 0xF289 +AFX_IDP_SQL_SQL_NO_TOTAL = 0xF28A +AFX_IDP_SQL_ODBC_LOAD_FAILED = 0xF28B +AFX_IDP_SQL_DYNASET_NOT_SUPPORTED = 0xF28C +AFX_IDP_SQL_SNAPSHOT_NOT_SUPPORTED = 0xF28D +AFX_IDP_SQL_API_CONFORMANCE = 0xF28E +AFX_IDP_SQL_SQL_CONFORMANCE = 0xF28F +AFX_IDP_SQL_NO_DATA_FOUND = 0xF290 +AFX_IDP_SQL_ROW_UPDATE_NOT_SUPPORTED = 0xF291 +AFX_IDP_SQL_ODBC_V2_REQUIRED = 0xF292 +AFX_IDP_SQL_NO_POSITIONED_UPDATES = 0xF293 +AFX_IDP_SQL_LOCK_MODE_NOT_SUPPORTED = 0xF294 +AFX_IDP_SQL_DATA_TRUNCATED = 0xF295 +AFX_IDP_SQL_ROW_FETCH = 0xF296 +AFX_IDP_SQL_INCORRECT_ODBC = 0xF297 +AFX_IDP_SQL_UPDATE_DELETE_FAILED = 0xF298 +AFX_IDP_SQL_DYNAMIC_CURSOR_NOT_SUPPORTED = 0xF299 +AFX_IDP_DAO_FIRST = 0xF2A0 +AFX_IDP_DAO_ENGINE_INITIALIZATION = 0xF2A0 +AFX_IDP_DAO_DFX_BIND = 0xF2A1 +AFX_IDP_DAO_OBJECT_NOT_OPEN = 0xF2A2 +AFX_IDP_DAO_ROWTOOSHORT = 0xF2A3 +AFX_IDP_DAO_BADBINDINFO = 0xF2A4 +AFX_IDP_DAO_COLUMNUNAVAILABLE = 0xF2A5 +AFX_IDC_LISTBOX = 100 +AFX_IDC_CHANGE = 101 +AFX_IDC_PRINT_DOCNAME = 201 +AFX_IDC_PRINT_PRINTERNAME = 202 +AFX_IDC_PRINT_PORTNAME = 203 +AFX_IDC_PRINT_PAGENUM = 204 +ID_APPLY_NOW = 0x3021 +ID_WIZBACK = 0x3023 +ID_WIZNEXT = 0x3024 +ID_WIZFINISH = 0x3025 +AFX_IDC_TAB_CONTROL = 0x3020 +AFX_IDD_FILEOPEN = 28676 +AFX_IDD_FILESAVE = 28677 +AFX_IDD_FONT = 28678 +AFX_IDD_COLOR = 28679 +AFX_IDD_PRINT = 28680 +AFX_IDD_PRINTSETUP = 28681 +AFX_IDD_FIND = 28682 +AFX_IDD_REPLACE = 28683 +AFX_IDD_NEWTYPEDLG = 30721 +AFX_IDD_PRINTDLG = 30722 +AFX_IDD_PREVIEW_TOOLBAR = 30723 +AFX_IDD_PREVIEW_SHORTTOOLBAR = 30731 +AFX_IDD_INSERTOBJECT = 30724 +AFX_IDD_CHANGEICON = 30725 +AFX_IDD_CONVERT = 30726 +AFX_IDD_PASTESPECIAL = 30727 +AFX_IDD_EDITLINKS = 30728 +AFX_IDD_FILEBROWSE = 30729 +AFX_IDD_BUSY = 30730 +AFX_IDD_OBJECTPROPERTIES = 30732 +AFX_IDD_CHANGESOURCE = 30733 +AFX_IDC_CONTEXTHELP = 30977 +AFX_IDC_MAGNIFY = 30978 +AFX_IDC_SMALLARROWS = 30979 +AFX_IDC_HSPLITBAR = 30980 +AFX_IDC_VSPLITBAR = 30981 +AFX_IDC_NODROPCRSR = 30982 +AFX_IDC_TRACKNWSE = 30983 +AFX_IDC_TRACKNESW = 30984 +AFX_IDC_TRACKNS = 30985 +AFX_IDC_TRACKWE = 30986 +AFX_IDC_TRACK4WAY = 30987 +AFX_IDC_MOVE4WAY = 30988 +AFX_IDB_MINIFRAME_MENU = 30994 +AFX_IDB_CHECKLISTBOX_NT = 30995 +AFX_IDB_CHECKLISTBOX_95 = 30996 +AFX_IDR_PREVIEW_ACCEL = 30997 +AFX_IDI_STD_MDIFRAME = 31233 +AFX_IDI_STD_FRAME = 31234 +AFX_IDC_FONTPROP = 1000 +AFX_IDC_FONTNAMES = 1001 +AFX_IDC_FONTSTYLES = 1002 +AFX_IDC_FONTSIZES = 1003 +AFX_IDC_STRIKEOUT = 1004 +AFX_IDC_UNDERLINE = 1005 +AFX_IDC_SAMPLEBOX = 1006 +AFX_IDC_COLOR_BLACK = 1100 +AFX_IDC_COLOR_WHITE = 1101 +AFX_IDC_COLOR_RED = 1102 +AFX_IDC_COLOR_GREEN = 1103 +AFX_IDC_COLOR_BLUE = 1104 +AFX_IDC_COLOR_YELLOW = 1105 +AFX_IDC_COLOR_MAGENTA = 1106 +AFX_IDC_COLOR_CYAN = 1107 +AFX_IDC_COLOR_GRAY = 1108 +AFX_IDC_COLOR_LIGHTGRAY = 1109 +AFX_IDC_COLOR_DARKRED = 1110 +AFX_IDC_COLOR_DARKGREEN = 1111 +AFX_IDC_COLOR_DARKBLUE = 1112 +AFX_IDC_COLOR_LIGHTBROWN = 1113 +AFX_IDC_COLOR_DARKMAGENTA = 1114 +AFX_IDC_COLOR_DARKCYAN = 1115 +AFX_IDC_COLORPROP = 1116 +AFX_IDC_SYSTEMCOLORS = 1117 +AFX_IDC_PROPNAME = 1201 +AFX_IDC_PICTURE = 1202 +AFX_IDC_BROWSE = 1203 +AFX_IDC_CLEAR = 1204 +AFX_IDD_PROPPAGE_COLOR = 32257 +AFX_IDD_PROPPAGE_FONT = 32258 +AFX_IDD_PROPPAGE_PICTURE = 32259 +AFX_IDB_TRUETYPE = 32384 +AFX_IDS_PROPPAGE_UNKNOWN = 0xFE01 +AFX_IDS_COLOR_DESKTOP = 0xFE04 +AFX_IDS_COLOR_APPWORKSPACE = 0xFE05 +AFX_IDS_COLOR_WNDBACKGND = 0xFE06 +AFX_IDS_COLOR_WNDTEXT = 0xFE07 +AFX_IDS_COLOR_MENUBAR = 0xFE08 +AFX_IDS_COLOR_MENUTEXT = 0xFE09 +AFX_IDS_COLOR_ACTIVEBAR = 0xFE0A +AFX_IDS_COLOR_INACTIVEBAR = 0xFE0B +AFX_IDS_COLOR_ACTIVETEXT = 0xFE0C +AFX_IDS_COLOR_INACTIVETEXT = 0xFE0D +AFX_IDS_COLOR_ACTIVEBORDER = 0xFE0E +AFX_IDS_COLOR_INACTIVEBORDER = 0xFE0F +AFX_IDS_COLOR_WNDFRAME = 0xFE10 +AFX_IDS_COLOR_SCROLLBARS = 0xFE11 +AFX_IDS_COLOR_BTNFACE = 0xFE12 +AFX_IDS_COLOR_BTNSHADOW = 0xFE13 +AFX_IDS_COLOR_BTNTEXT = 0xFE14 +AFX_IDS_COLOR_BTNHIGHLIGHT = 0xFE15 +AFX_IDS_COLOR_DISABLEDTEXT = 0xFE16 +AFX_IDS_COLOR_HIGHLIGHT = 0xFE17 +AFX_IDS_COLOR_HIGHLIGHTTEXT = 0xFE18 +AFX_IDS_REGULAR = 0xFE19 +AFX_IDS_BOLD = 0xFE1A +AFX_IDS_ITALIC = 0xFE1B +AFX_IDS_BOLDITALIC = 0xFE1C +AFX_IDS_SAMPLETEXT = 0xFE1D +AFX_IDS_DISPLAYSTRING_FONT = 0xFE1E +AFX_IDS_DISPLAYSTRING_COLOR = 0xFE1F +AFX_IDS_DISPLAYSTRING_PICTURE = 0xFE20 +AFX_IDS_PICTUREFILTER = 0xFE21 +AFX_IDS_PICTYPE_UNKNOWN = 0xFE22 +AFX_IDS_PICTYPE_NONE = 0xFE23 +AFX_IDS_PICTYPE_BITMAP = 0xFE24 +AFX_IDS_PICTYPE_METAFILE = 0xFE25 +AFX_IDS_PICTYPE_ICON = 0xFE26 +AFX_IDS_COLOR_PPG = 0xFE28 +AFX_IDS_COLOR_PPG_CAPTION = 0xFE29 +AFX_IDS_FONT_PPG = 0xFE2A +AFX_IDS_FONT_PPG_CAPTION = 0xFE2B +AFX_IDS_PICTURE_PPG = 0xFE2C +AFX_IDS_PICTURE_PPG_CAPTION = 0xFE2D +AFX_IDS_PICTUREBROWSETITLE = 0xFE30 +AFX_IDS_BORDERSTYLE_0 = 0xFE31 +AFX_IDS_BORDERSTYLE_1 = 0xFE32 +AFX_IDS_VERB_EDIT = 0xFE40 +AFX_IDS_VERB_PROPERTIES = 0xFE41 +AFX_IDP_PICTURECANTOPEN = 0xFE83 +AFX_IDP_PICTURECANTLOAD = 0xFE84 +AFX_IDP_PICTURETOOLARGE = 0xFE85 +AFX_IDP_PICTUREREADFAILED = 0xFE86 +AFX_IDP_E_ILLEGALFUNCTIONCALL = 0xFEA0 +AFX_IDP_E_OVERFLOW = 0xFEA1 +AFX_IDP_E_OUTOFMEMORY = 0xFEA2 +AFX_IDP_E_DIVISIONBYZERO = 0xFEA3 +AFX_IDP_E_OUTOFSTRINGSPACE = 0xFEA4 +AFX_IDP_E_OUTOFSTACKSPACE = 0xFEA5 +AFX_IDP_E_BADFILENAMEORNUMBER = 0xFEA6 +AFX_IDP_E_FILENOTFOUND = 0xFEA7 +AFX_IDP_E_BADFILEMODE = 0xFEA8 +AFX_IDP_E_FILEALREADYOPEN = 0xFEA9 +AFX_IDP_E_DEVICEIOERROR = 0xFEAA +AFX_IDP_E_FILEALREADYEXISTS = 0xFEAB +AFX_IDP_E_BADRECORDLENGTH = 0xFEAC +AFX_IDP_E_DISKFULL = 0xFEAD +AFX_IDP_E_BADRECORDNUMBER = 0xFEAE +AFX_IDP_E_BADFILENAME = 0xFEAF +AFX_IDP_E_TOOMANYFILES = 0xFEB0 +AFX_IDP_E_DEVICEUNAVAILABLE = 0xFEB1 +AFX_IDP_E_PERMISSIONDENIED = 0xFEB2 +AFX_IDP_E_DISKNOTREADY = 0xFEB3 +AFX_IDP_E_PATHFILEACCESSERROR = 0xFEB4 +AFX_IDP_E_PATHNOTFOUND = 0xFEB5 +AFX_IDP_E_INVALIDPATTERNSTRING = 0xFEB6 +AFX_IDP_E_INVALIDUSEOFNULL = 0xFEB7 +AFX_IDP_E_INVALIDFILEFORMAT = 0xFEB8 +AFX_IDP_E_INVALIDPROPERTYVALUE = 0xFEB9 +AFX_IDP_E_INVALIDPROPERTYARRAYINDEX = 0xFEBA +AFX_IDP_E_SETNOTSUPPORTEDATRUNTIME = 0xFEBB +AFX_IDP_E_SETNOTSUPPORTED = 0xFEBC +AFX_IDP_E_NEEDPROPERTYARRAYINDEX = 0xFEBD +AFX_IDP_E_SETNOTPERMITTED = 0xFEBE +AFX_IDP_E_GETNOTSUPPORTEDATRUNTIME = 0xFEBF +AFX_IDP_E_GETNOTSUPPORTED = 0xFEC0 +AFX_IDP_E_PROPERTYNOTFOUND = 0xFEC1 +AFX_IDP_E_INVALIDCLIPBOARDFORMAT = 0xFEC2 +AFX_IDP_E_INVALIDPICTURE = 0xFEC3 +AFX_IDP_E_PRINTERERROR = 0xFEC4 +AFX_IDP_E_CANTSAVEFILETOTEMP = 0xFEC5 +AFX_IDP_E_SEARCHTEXTNOTFOUND = 0xFEC6 +AFX_IDP_E_REPLACEMENTSTOOLONG = 0xFEC7 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/dialog.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/dialog.py new file mode 100644 index 0000000000000000000000000000000000000000..25fe13635bced28e12fb931e7b03163ef454c009 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/dialog.py @@ -0,0 +1,278 @@ +""" \ +Base class for Dialogs. Also contains a few useful utility functions +""" +# dialog.py +# Python class for Dialog Boxes in PythonWin. + +import win32con +import win32ui + +# sob - 2to3 doesn't see this as a relative import :( +from pywin.mfc import window + + +def dllFromDll(dllid): + "given a 'dll' (maybe a dll, filename, etc), return a DLL object" + if dllid == None: + return None + elif type("") == type(dllid): + return win32ui.LoadLibrary(dllid) + else: + try: + dllid.GetFileName() + except AttributeError: + raise TypeError("DLL parameter must be None, a filename or a dll object") + return dllid + + +class Dialog(window.Wnd): + "Base class for a dialog" + + def __init__(self, id, dllid=None): + """id is the resource ID, or a template + dllid may be None, a dll object, or a string with a dll name""" + # must take a reference to the DLL until InitDialog. + self.dll = dllFromDll(dllid) + if type(id) == type([]): # a template + dlg = win32ui.CreateDialogIndirect(id) + else: + dlg = win32ui.CreateDialog(id, self.dll) + window.Wnd.__init__(self, dlg) + self.HookCommands() + self.bHaveInit = None + + def HookCommands(self): + pass + + def OnAttachedObjectDeath(self): + self.data = self._obj_.data + window.Wnd.OnAttachedObjectDeath(self) + + # provide virtuals. + def OnOK(self): + self._obj_.OnOK() + + def OnCancel(self): + self._obj_.OnCancel() + + def OnInitDialog(self): + self.bHaveInit = 1 + if self._obj_.data: + self._obj_.UpdateData(0) + return 1 # I did NOT set focus to a child window. + + def OnDestroy(self, msg): + self.dll = None # theoretically not needed if object destructs normally. + + # DDX support + def AddDDX(self, *args): + self._obj_.datalist.append(args) + + # Make a dialog object look like a dictionary for the DDX support + def __bool__(self): + return True + + def __len__(self): + return len(self.data) + + def __getitem__(self, key): + return self.data[key] + + def __setitem__(self, key, item): + self._obj_.data[key] = item # self.UpdateData(0) + + def keys(self): + return list(self.data.keys()) + + def items(self): + return list(self.data.items()) + + def values(self): + return list(self.data.values()) + + # XXX - needs py3k work! + def has_key(self, key): + return key in self.data + + +class PrintDialog(Dialog): + "Base class for a print dialog" + + def __init__( + self, + pInfo, + dlgID, + printSetupOnly=0, + flags=( + win32ui.PD_ALLPAGES + | win32ui.PD_USEDEVMODECOPIES + | win32ui.PD_NOPAGENUMS + | win32ui.PD_HIDEPRINTTOFILE + | win32ui.PD_NOSELECTION + ), + parent=None, + dllid=None, + ): + self.dll = dllFromDll(dllid) + if type(dlgID) == type([]): # a template + raise TypeError("dlgID parameter must be an integer resource ID") + dlg = win32ui.CreatePrintDialog(dlgID, printSetupOnly, flags, parent, self.dll) + window.Wnd.__init__(self, dlg) + self.HookCommands() + self.bHaveInit = None + self.pInfo = pInfo + # init values (if PrintSetup is called, values still available) + flags = pInfo.GetFlags() + self["toFile"] = flags & win32ui.PD_PRINTTOFILE != 0 + self["direct"] = pInfo.GetDirect() + self["preview"] = pInfo.GetPreview() + self["continuePrinting"] = pInfo.GetContinuePrinting() + self["curPage"] = pInfo.GetCurPage() + self["numPreviewPages"] = pInfo.GetNumPreviewPages() + self["userData"] = pInfo.GetUserData() + self["draw"] = pInfo.GetDraw() + self["pageDesc"] = pInfo.GetPageDesc() + self["minPage"] = pInfo.GetMinPage() + self["maxPage"] = pInfo.GetMaxPage() + self["offsetPage"] = pInfo.GetOffsetPage() + self["fromPage"] = pInfo.GetFromPage() + self["toPage"] = pInfo.GetToPage() + # these values updated after OnOK + self["copies"] = 0 + self["deviceName"] = "" + self["driverName"] = "" + self["printAll"] = 0 + self["printCollate"] = 0 + self["printRange"] = 0 + self["printSelection"] = 0 + + def OnInitDialog(self): + self.pInfo.CreatePrinterDC() # This also sets the hDC of the pInfo structure. + return self._obj_.OnInitDialog() + + def OnCancel(self): + del self.pInfo + + def OnOK(self): + """DoModal has finished. Can now access the users choices""" + self._obj_.OnOK() + pInfo = self.pInfo + # user values + flags = pInfo.GetFlags() + self["toFile"] = flags & win32ui.PD_PRINTTOFILE != 0 + self["direct"] = pInfo.GetDirect() + self["preview"] = pInfo.GetPreview() + self["continuePrinting"] = pInfo.GetContinuePrinting() + self["curPage"] = pInfo.GetCurPage() + self["numPreviewPages"] = pInfo.GetNumPreviewPages() + self["userData"] = pInfo.GetUserData() + self["draw"] = pInfo.GetDraw() + self["pageDesc"] = pInfo.GetPageDesc() + self["minPage"] = pInfo.GetMinPage() + self["maxPage"] = pInfo.GetMaxPage() + self["offsetPage"] = pInfo.GetOffsetPage() + self["fromPage"] = pInfo.GetFromPage() + self["toPage"] = pInfo.GetToPage() + self["copies"] = pInfo.GetCopies() + self["deviceName"] = pInfo.GetDeviceName() + self["driverName"] = pInfo.GetDriverName() + self["printAll"] = pInfo.PrintAll() + self["printCollate"] = pInfo.PrintCollate() + self["printRange"] = pInfo.PrintRange() + self["printSelection"] = pInfo.PrintSelection() + del self.pInfo + + +class PropertyPage(Dialog): + "Base class for a Property Page" + + def __init__(self, id, dllid=None, caption=0): + """id is the resource ID + dllid may be None, a dll object, or a string with a dll name""" + + self.dll = dllFromDll(dllid) + if self.dll: + oldRes = win32ui.SetResource(self.dll) + if type(id) == type([]): + dlg = win32ui.CreatePropertyPageIndirect(id) + else: + dlg = win32ui.CreatePropertyPage(id, caption) + if self.dll: + win32ui.SetResource(oldRes) + # dont call dialog init! + window.Wnd.__init__(self, dlg) + self.HookCommands() + + +class PropertySheet(window.Wnd): + def __init__(self, caption, dll=None, pageList=None): # parent=None, style,etc): + "Initialize a property sheet. pageList is a list of ID's" + # must take a reference to the DLL until InitDialog. + self.dll = dllFromDll(dll) + self.sheet = win32ui.CreatePropertySheet(caption) + window.Wnd.__init__(self, self.sheet) + if not pageList is None: + self.AddPage(pageList) + + def OnInitDialog(self): + return self._obj_.OnInitDialog() + + def DoModal(self): + if self.dll: + oldRes = win32ui.SetResource(self.dll) + rc = self.sheet.DoModal() + if self.dll: + win32ui.SetResource(oldRes) + return rc + + def AddPage(self, pages): + if self.dll: + oldRes = win32ui.SetResource(self.dll) + try: # try list style access + pages[0] + isSeq = 1 + except (TypeError, KeyError): + isSeq = 0 + if isSeq: + for page in pages: + self.DoAddSinglePage(page) + else: + self.DoAddSinglePage(pages) + if self.dll: + win32ui.SetResource(oldRes) + + def DoAddSinglePage(self, page): + "Page may be page, or int ID. Assumes DLL setup" + if type(page) == type(0): + self.sheet.AddPage(win32ui.CreatePropertyPage(page)) + else: + self.sheet.AddPage(page) + + +# define some app utility functions. +def GetSimpleInput(prompt, defValue="", title=None): + """displays a dialog, and returns a string, or None if cancelled. + args prompt, defValue='', title=main frames title""" + # uses a simple dialog to return a string object. + if title is None: + title = win32ui.GetMainFrame().GetWindowText() + # 2to3 insists on converting 'Dialog.__init__' to 'tkinter.dialog...' + DlgBaseClass = Dialog + + class DlgSimpleInput(DlgBaseClass): + def __init__(self, prompt, defValue, title): + self.title = title + DlgBaseClass.__init__(self, win32ui.IDD_SIMPLE_INPUT) + self.AddDDX(win32ui.IDC_EDIT1, "result") + self.AddDDX(win32ui.IDC_PROMPT1, "prompt") + self._obj_.data["result"] = defValue + self._obj_.data["prompt"] = prompt + + def OnInitDialog(self): + self.SetWindowText(self.title) + return DlgBaseClass.OnInitDialog(self) + + dlg = DlgSimpleInput(prompt, defValue, title) + if dlg.DoModal() != win32con.IDOK: + return None + return dlg["result"] diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/docview.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/docview.py new file mode 100644 index 0000000000000000000000000000000000000000..7da91b460d3545bfcd02ebbfdc063086a26f1890 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/docview.py @@ -0,0 +1,151 @@ +# document and view classes for MFC. +import win32ui + +from . import object, window + + +class View(window.Wnd): + def __init__(self, initobj): + window.Wnd.__init__(self, initobj) + + def OnInitialUpdate(self): + pass + + +# Simple control based views. +class CtrlView(View): + def __init__(self, doc, wndclass, style=0): + View.__init__(self, win32ui.CreateCtrlView(doc, wndclass, style)) + + +class EditView(CtrlView): + def __init__(self, doc): + View.__init__(self, win32ui.CreateEditView(doc)) + + +class RichEditView(CtrlView): + def __init__(self, doc): + View.__init__(self, win32ui.CreateRichEditView(doc)) + + +class ListView(CtrlView): + def __init__(self, doc): + View.__init__(self, win32ui.CreateListView(doc)) + + +class TreeView(CtrlView): + def __init__(self, doc): + View.__init__(self, win32ui.CreateTreeView(doc)) + + +# Other more advanced views. +class ScrollView(View): + def __init__(self, doc): + View.__init__(self, win32ui.CreateView(doc)) + + +class FormView(View): + def __init__(self, doc, id): + View.__init__(self, win32ui.CreateFormView(doc, id)) + + +class Document(object.CmdTarget): + def __init__(self, template, docobj=None): + if docobj is None: + docobj = template.DoCreateDoc() + object.CmdTarget.__init__(self, docobj) + + +class RichEditDoc(object.CmdTarget): + def __init__(self, template): + object.CmdTarget.__init__(self, template.DoCreateRichEditDoc()) + + +class CreateContext: + "A transient base class used as a CreateContext" + + def __init__(self, template, doc=None): + self.template = template + self.doc = doc + + def __del__(self): + self.close() + + def close(self): + self.doc = None + self.template = None + + +class DocTemplate(object.CmdTarget): + def __init__( + self, resourceId=None, MakeDocument=None, MakeFrame=None, MakeView=None + ): + if resourceId is None: + resourceId = win32ui.IDR_PYTHONTYPE + object.CmdTarget.__init__(self, self._CreateDocTemplate(resourceId)) + self.MakeDocument = MakeDocument + self.MakeFrame = MakeFrame + self.MakeView = MakeView + self._SetupSharedMenu_() + + def _SetupSharedMenu_(self): + pass # to be overridden by each "app" + + def _CreateDocTemplate(self, resourceId): + return win32ui.CreateDocTemplate(resourceId) + + def __del__(self): + object.CmdTarget.__del__(self) + + def CreateCreateContext(self, doc=None): + return CreateContext(self, doc) + + def CreateNewFrame(self, doc): + makeFrame = self.MakeFrame + if makeFrame is None: + makeFrame = window.MDIChildWnd + wnd = makeFrame() + context = self.CreateCreateContext(doc) + wnd.LoadFrame( + self.GetResourceID(), -1, None, context + ) # triggers OnCreateClient... + return wnd + + def CreateNewDocument(self): + makeDocument = self.MakeDocument + if makeDocument is None: + makeDocument = Document + return makeDocument(self) + + def CreateView(self, frame, context): + makeView = self.MakeView + if makeView is None: + makeView = EditView + view = makeView(context.doc) + view.CreateWindow(frame) + + +class RichEditDocTemplate(DocTemplate): + def __init__( + self, resourceId=None, MakeDocument=None, MakeFrame=None, MakeView=None + ): + if MakeView is None: + MakeView = RichEditView + if MakeDocument is None: + MakeDocument = RichEditDoc + DocTemplate.__init__(self, resourceId, MakeDocument, MakeFrame, MakeView) + + def _CreateDocTemplate(self, resourceId): + return win32ui.CreateRichEditDocTemplate(resourceId) + + +def t(): + class FormTemplate(DocTemplate): + def CreateView(self, frame, context): + makeView = self.MakeView + # view = FormView(context.doc, win32ui.IDD_PROPDEMO1) + view = ListView(context.doc) + view.CreateWindow(frame) + + t = FormTemplate() + return t.OpenDocumentFile(None) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/object.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/object.py new file mode 100644 index 0000000000000000000000000000000000000000..70138b6ee2ab05d3404a97bd0597750796dc4c6c --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/object.py @@ -0,0 +1,66 @@ +# MFC base classes. + +import win32ui + + +class Object: + def __init__(self, initObj=None): + self.__dict__["_obj_"] = initObj + # self._obj_ = initObj + if initObj is not None: + initObj.AttachObject(self) + + def __del__(self): + self.close() + + def __getattr__( + self, attr + ): # Make this object look like the underlying win32ui one. + # During cleanup __dict__ is not available, causing recursive death. + if not attr.startswith("__"): + try: + o = self.__dict__["_obj_"] + if o is not None: + return getattr(o, attr) + # Only raise this error for non "internal" names - + # Python may be calling __len__, __nonzero__, etc, so + # we dont want this exception + if attr[0] != "_" and attr[-1] != "_": + raise win32ui.error("The MFC object has died.") + except KeyError: + # No _obj_ at all - dont report MFC object died when there isnt one! + pass + raise AttributeError(attr) + + def OnAttachedObjectDeath(self): + # print "object", self.__class__.__name__, "dieing" + self._obj_ = None + + def close(self): + if "_obj_" in self.__dict__: + if self._obj_ is not None: + self._obj_.AttachObject(None) + self._obj_ = None + + +class CmdTarget(Object): + def __init__(self, initObj): + Object.__init__(self, initObj) + + def HookNotifyRange(self, handler, firstID, lastID): + oldhandlers = [] + for i in range(firstID, lastID + 1): + oldhandlers.append(self.HookNotify(handler, i)) + return oldhandlers + + def HookCommandRange(self, handler, firstID, lastID): + oldhandlers = [] + for i in range(firstID, lastID + 1): + oldhandlers.append(self.HookCommand(handler, i)) + return oldhandlers + + def HookCommandUpdateRange(self, handler, firstID, lastID): + oldhandlers = [] + for i in range(firstID, lastID + 1): + oldhandlers.append(self.HookCommandUpdate(handler, i)) + return oldhandlers diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/thread.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/thread.py new file mode 100644 index 0000000000000000000000000000000000000000..90a0a762cb4453db678c6e1060ccc7f9759d7b3c --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/thread.py @@ -0,0 +1,25 @@ +# Thread and application objects + +import win32ui + +from . import object + + +class WinThread(object.CmdTarget): + def __init__(self, initObj=None): + if initObj is None: + initObj = win32ui.CreateThread() + object.CmdTarget.__init__(self, initObj) + + def InitInstance(self): + pass # Default None/0 return indicates success for InitInstance() + + def ExitInstance(self): + pass + + +class WinApp(WinThread): + def __init__(self, initApp=None): + if initApp is None: + initApp = win32ui.GetApp() + WinThread.__init__(self, initApp) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/mfc/window.py b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/window.py new file mode 100644 index 0000000000000000000000000000000000000000..e52a7c1cfb19a3ee752f72d0e7495a34690e1d00 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/mfc/window.py @@ -0,0 +1,50 @@ +# The MFCish window classes. +import win32con +import win32ui + +from . import object + + +class Wnd(object.CmdTarget): + def __init__(self, initobj=None): + object.CmdTarget.__init__(self, initobj) + if self._obj_: + self._obj_.HookMessage(self.OnDestroy, win32con.WM_DESTROY) + + def OnDestroy(self, msg): + pass + + +# NOTE NOTE - This facility is currently disabled in Pythonwin!!!!! +# Note - to process all messages for your window, add the following method +# to a derived class. This code provides default message handling (ie, is +# identical, except presumably in speed, as if the method did not exist at +# all, so presumably will be modified to test for specific messages to be +# useful! +# def WindowProc(self, msg, wParam, lParam): +# rc, lResult = self._obj_.OnWndMsg(msg, wParam, lParam) +# if not rc: lResult = self._obj_.DefWindowProc(msg, wParam, lParam) +# return lResult + + +class FrameWnd(Wnd): + def __init__(self, wnd): + Wnd.__init__(self, wnd) + + +class MDIChildWnd(FrameWnd): + def __init__(self, wnd=None): + if wnd is None: + wnd = win32ui.CreateMDIChild() + FrameWnd.__init__(self, wnd) + + def OnCreateClient(self, cp, context): + if context is not None and context.template is not None: + context.template.CreateView(self, context) + + +class MDIFrameWnd(FrameWnd): + def __init__(self, wnd=None): + if wnd is None: + wnd = win32ui.CreateMDIFrame() + FrameWnd.__init__(self, wnd) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/IDLEenvironment.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/IDLEenvironment.py new file mode 100644 index 0000000000000000000000000000000000000000..b1db5093160c4df79ccac6314c27d14b16f235a4 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/IDLEenvironment.py @@ -0,0 +1,598 @@ +# Code that allows Pythonwin to pretend it is IDLE +# (at least as far as most IDLE extensions are concerned) + +import string +import sys + +import win32api +import win32con +import win32ui +from pywin import default_scintilla_encoding +from pywin.mfc.dialog import GetSimpleInput + +wordchars = string.ascii_uppercase + string.ascii_lowercase + string.digits + + +class TextError(Exception): # When a TclError would normally be raised. + pass + + +class EmptyRange(Exception): # Internally raised. + pass + + +def GetIDLEModule(module): + try: + # First get it from Pythonwin it is exists. + modname = "pywin.idle." + module + __import__(modname) + except ImportError as details: + msg = ( + "The IDLE extension '%s' can not be located.\r\n\r\n" + "Please correct the installation and restart the" + " application.\r\n\r\n%s" % (module, details) + ) + win32ui.MessageBox(msg) + return None + mod = sys.modules[modname] + mod.TclError = TextError # A hack that can go soon! + return mod + + +# A class that is injected into the IDLE auto-indent extension. +# It allows for decent performance when opening a new file, +# as auto-indent uses the tokenizer module to determine indents. +# The default AutoIndent readline method works OK, but it goes through +# this layer of Tk index indirection for every single line. For large files +# without indents (and even small files with indents :-) it was pretty slow! +def fast_readline(self): + if self.finished: + val = "" + else: + if "_scint_lines" not in self.__dict__: + # XXX - note - assumes this is only called once the file is loaded! + self._scint_lines = self.text.edit.GetTextRange().split("\n") + sl = self._scint_lines + i = self.i = self.i + 1 + if i >= len(sl): + val = "" + else: + val = sl[i] + "\n" + return val.encode(default_scintilla_encoding) + + +try: + GetIDLEModule("AutoIndent").IndentSearcher.readline = fast_readline +except AttributeError: # GetIDLEModule may return None + pass + + +# A class that attempts to emulate an IDLE editor window. +# Construct with a Pythonwin view. +class IDLEEditorWindow: + def __init__(self, edit): + self.edit = edit + self.text = TkText(edit) + self.extensions = {} + self.extension_menus = {} + + def close(self): + self.edit = self.text = None + self.extension_menus = None + try: + for ext in self.extensions.values(): + closer = getattr(ext, "close", None) + if closer is not None: + closer() + finally: + self.extensions = {} + + def IDLEExtension(self, extension): + ext = self.extensions.get(extension) + if ext is not None: + return ext + mod = GetIDLEModule(extension) + if mod is None: + return None + klass = getattr(mod, extension) + ext = self.extensions[extension] = klass(self) + # Find and bind all the events defined in the extension. + events = [item for item in dir(klass) if item[-6:] == "_event"] + for event in events: + name = "<<%s>>" % (event[:-6].replace("_", "-"),) + self.edit.bindings.bind(name, getattr(ext, event)) + return ext + + def GetMenuItems(self, menu_name): + # Get all menu items for the menu name (eg, "edit") + bindings = self.edit.bindings + ret = [] + for ext in self.extensions.values(): + menudefs = getattr(ext, "menudefs", []) + for name, items in menudefs: + if name == menu_name: + for text, event in [item for item in items if item is not None]: + text = text.replace("&", "&&") + text = text.replace("_", "&") + ret.append((text, event)) + return ret + + ###################################################################### + # The IDLE "Virtual UI" methods that are exposed to the IDLE extensions. + # + def askinteger( + self, caption, prompt, parent=None, initialvalue=0, minvalue=None, maxvalue=None + ): + while 1: + rc = GetSimpleInput(prompt, str(initialvalue), caption) + if rc is None: + return 0 # Correct "cancel" semantics? + err = None + try: + rc = int(rc) + except ValueError: + err = "Please enter an integer" + if not err and minvalue is not None and rc < minvalue: + err = "Please enter an integer greater then or equal to %s" % ( + minvalue, + ) + if not err and maxvalue is not None and rc > maxvalue: + err = "Please enter an integer less then or equal to %s" % (maxvalue,) + if err: + win32ui.MessageBox(err, caption, win32con.MB_OK) + continue + return rc + + def askyesno(self, caption, prompt, parent=None): + return win32ui.MessageBox(prompt, caption, win32con.MB_YESNO) == win32con.IDYES + + ###################################################################### + # The IDLE "Virtual Text Widget" methods that are exposed to the IDLE extensions. + # + + # Is character at text_index in a Python string? Return 0 for + # "guaranteed no", true for anything else. + def is_char_in_string(self, text_index): + # A helper for the code analyser - we need internal knowledge of + # the colorizer to get this information + # This assumes the colorizer has got to this point! + text_index = self.text._getoffset(text_index) + c = self.text.edit._GetColorizer() + if c and c.GetStringStyle(text_index) is None: + return 0 + return 1 + + # If a selection is defined in the text widget, return + # (start, end) as Tkinter text indices, otherwise return + # (None, None) + def get_selection_indices(self): + try: + first = self.text.index("sel.first") + last = self.text.index("sel.last") + return first, last + except TextError: + return None, None + + def set_tabwidth(self, width): + self.edit.SCISetTabWidth(width) + + def get_tabwidth(self): + return self.edit.GetTabWidth() + + +# A class providing the generic "Call Tips" interface +class CallTips: + def __init__(self, edit): + self.edit = edit + + def showtip(self, tip_text): + self.edit.SCICallTipShow(tip_text) + + def hidetip(self): + self.edit.SCICallTipCancel() + + +######################################## +# +# Helpers for the TkText emulation. +def TkOffsetToIndex(offset, edit): + lineoff = 0 + # May be 1 > actual end if we pretended there was a trailing '\n' + offset = min(offset, edit.GetTextLength()) + line = edit.LineFromChar(offset) + lineIndex = edit.LineIndex(line) + return "%d.%d" % (line + 1, offset - lineIndex) + + +def _NextTok(str, pos): + # Returns (token, endPos) + end = len(str) + if pos >= end: + return None, 0 + while pos < end and str[pos] in string.whitespace: + pos = pos + 1 + # Special case for +- + if str[pos] in "+-": + return str[pos], pos + 1 + # Digits also a special case. + endPos = pos + while endPos < end and str[endPos] in string.digits + ".": + endPos = endPos + 1 + if pos != endPos: + return str[pos:endPos], endPos + endPos = pos + while endPos < end and str[endPos] not in string.whitespace + string.digits + "+-": + endPos = endPos + 1 + if pos != endPos: + return str[pos:endPos], endPos + return None, 0 + + +def TkIndexToOffset(bm, edit, marks): + base, nextTokPos = _NextTok(bm, 0) + if base is None: + raise ValueError("Empty bookmark ID!") + if base.find(".") > 0: + try: + line, col = base.split(".", 2) + if col == "first" or col == "last": + # Tag name + if line != "sel": + raise ValueError("Tags arent here!") + sel = edit.GetSel() + if sel[0] == sel[1]: + raise EmptyRange + if col == "first": + pos = sel[0] + else: + pos = sel[1] + else: + # Lines are 1 based for tkinter + line = int(line) - 1 + if line > edit.GetLineCount(): + pos = edit.GetTextLength() + 1 + else: + pos = edit.LineIndex(line) + if pos == -1: + pos = edit.GetTextLength() + pos = pos + int(col) + except (ValueError, IndexError): + raise ValueError("Unexpected literal in '%s'" % base) + elif base == "insert": + pos = edit.GetSel()[0] + elif base == "end": + pos = edit.GetTextLength() + # Pretend there is a trailing '\n' if necessary + if pos and edit.SCIGetCharAt(pos - 1) != "\n": + pos = pos + 1 + else: + try: + pos = marks[base] + except KeyError: + raise ValueError("Unsupported base offset or undefined mark '%s'" % base) + + while 1: + word, nextTokPos = _NextTok(bm, nextTokPos) + if word is None: + break + if word in ("+", "-"): + num, nextTokPos = _NextTok(bm, nextTokPos) + if num is None: + raise ValueError("+/- operator needs 2 args") + what, nextTokPos = _NextTok(bm, nextTokPos) + if what is None: + raise ValueError("+/- operator needs 2 args") + if what[0] != "c": + raise ValueError("+/- only supports chars") + if word == "+": + pos = pos + int(num) + else: + pos = pos - int(num) + elif word == "wordstart": + while pos > 0 and edit.SCIGetCharAt(pos - 1) in wordchars: + pos = pos - 1 + elif word == "wordend": + end = edit.GetTextLength() + while pos < end and edit.SCIGetCharAt(pos) in wordchars: + pos = pos + 1 + elif word == "linestart": + while pos > 0 and edit.SCIGetCharAt(pos - 1) not in "\n\r": + pos = pos - 1 + elif word == "lineend": + end = edit.GetTextLength() + while pos < end and edit.SCIGetCharAt(pos) not in "\n\r": + pos = pos + 1 + else: + raise ValueError("Unsupported relative offset '%s'" % word) + return max(pos, 0) # Tkinter is tollerant of -ve indexes - we aren't + + +# A class that resembles an IDLE (ie, a Tk) text widget. +# Construct with an edit object (eg, an editor view) +class TkText: + def __init__(self, edit): + self.calltips = None + self.edit = edit + self.marks = {} + + ## def __getattr__(self, attr): + ## if attr=="tk": return self # So text.tk.call works. + ## if attr=="master": return None # ditto! + ## raise AttributeError, attr + ## def __getitem__(self, item): + ## if item=="tabs": + ## size = self.edit.GetTabWidth() + ## if size==8: return "" # Tk default + ## return size # correct semantics? + ## elif item=="font": # Used for measurements we dont need to do! + ## return "Dont know the font" + ## raise IndexError, "Invalid index '%s'" % item + def make_calltip_window(self): + if self.calltips is None: + self.calltips = CallTips(self.edit) + return self.calltips + + def _getoffset(self, index): + return TkIndexToOffset(index, self.edit, self.marks) + + def _getindex(self, off): + return TkOffsetToIndex(off, self.edit) + + def _fix_indexes(self, start, end): + # first some magic to handle skipping over utf8 extended chars. + while start > 0 and ord(self.edit.SCIGetCharAt(start)) & 0xC0 == 0x80: + start -= 1 + while ( + end < self.edit.GetTextLength() + and ord(self.edit.SCIGetCharAt(end)) & 0xC0 == 0x80 + ): + end += 1 + # now handling fixing \r\n->\n disparities... + if ( + start > 0 + and self.edit.SCIGetCharAt(start) == "\n" + and self.edit.SCIGetCharAt(start - 1) == "\r" + ): + start = start - 1 + if ( + end < self.edit.GetTextLength() + and self.edit.SCIGetCharAt(end - 1) == "\r" + and self.edit.SCIGetCharAt(end) == "\n" + ): + end = end + 1 + return start, end + + ## def get_tab_width(self): + ## return self.edit.GetTabWidth() + ## def call(self, *rest): + ## # Crap to support Tk measurement hacks for tab widths + ## if rest[0] != "font" or rest[1] != "measure": + ## raise ValueError, "Unsupport call type" + ## return len(rest[5]) + ## def configure(self, **kw): + ## for name, val in kw.items(): + ## if name=="tabs": + ## self.edit.SCISetTabWidth(int(val)) + ## else: + ## raise ValueError, "Unsupported configuration item %s" % kw + def bind(self, binding, handler): + self.edit.bindings.bind(binding, handler) + + def get(self, start, end=None): + try: + start = self._getoffset(start) + if end is None: + end = start + 1 + else: + end = self._getoffset(end) + except EmptyRange: + return "" + # Simple semantic checks to conform to the Tk text interface + if end <= start: + return "" + max = self.edit.GetTextLength() + checkEnd = 0 + if end > max: + end = max + checkEnd = 1 + start, end = self._fix_indexes(start, end) + ret = self.edit.GetTextRange(start, end) + # pretend a trailing '\n' exists if necessary. + if checkEnd and (not ret or ret[-1] != "\n"): + ret = ret + "\n" + return ret.replace("\r", "") + + def index(self, spec): + try: + return self._getindex(self._getoffset(spec)) + except EmptyRange: + return "" + + def insert(self, pos, text): + try: + pos = self._getoffset(pos) + except EmptyRange: + raise TextError("Empty range") + self.edit.SetSel((pos, pos)) + # IDLE only deals with "\n" - we will be nicer + + bits = text.split("\n") + self.edit.SCIAddText(bits[0]) + for bit in bits[1:]: + self.edit.SCINewline() + self.edit.SCIAddText(bit) + + def delete(self, start, end=None): + try: + start = self._getoffset(start) + if end is not None: + end = self._getoffset(end) + except EmptyRange: + raise TextError("Empty range") + # If end is specified and == start, then we must delete nothing. + if start == end: + return + # If end is not specified, delete one char + if end is None: + end = start + 1 + else: + # Tk says not to delete in this case, but our control would. + if end < start: + return + if start == self.edit.GetTextLength(): + return # Nothing to delete. + old = self.edit.GetSel()[0] # Lose a selection + # Hack for partial '\r\n' and UTF-8 char removal + start, end = self._fix_indexes(start, end) + self.edit.SetSel((start, end)) + self.edit.Clear() + if old >= start and old < end: + old = start + elif old >= end: + old = old - (end - start) + self.edit.SetSel(old) + + def bell(self): + win32api.MessageBeep() + + def see(self, pos): + # Most commands we use in Scintilla actually force the selection + # to be seen, making this unnecessary. + pass + + def mark_set(self, name, pos): + try: + pos = self._getoffset(pos) + except EmptyRange: + raise TextError("Empty range '%s'" % pos) + if name == "insert": + self.edit.SetSel(pos) + else: + self.marks[name] = pos + + def tag_add(self, name, start, end): + if name != "sel": + raise ValueError("Only sel tag is supported") + try: + start = self._getoffset(start) + end = self._getoffset(end) + except EmptyRange: + raise TextError("Empty range") + self.edit.SetSel(start, end) + + def tag_remove(self, name, start, end): + if name != "sel" or start != "1.0" or end != "end": + raise ValueError("Cant remove this tag") + # Turn the sel into a cursor + self.edit.SetSel(self.edit.GetSel()[0]) + + def compare(self, i1, op, i2): + try: + i1 = self._getoffset(i1) + except EmptyRange: + i1 = "" + try: + i2 = self._getoffset(i2) + except EmptyRange: + i2 = "" + return eval("%d%s%d" % (i1, op, i2)) + + def undo_block_start(self): + self.edit.SCIBeginUndoAction() + + def undo_block_stop(self): + self.edit.SCIEndUndoAction() + + +###################################################################### +# +# Test related code. +# +###################################################################### +def TestCheck(index, edit, expected=None): + rc = TkIndexToOffset(index, edit, {}) + if rc != expected: + print("ERROR: Index", index, ", expected", expected, "but got", rc) + + +def TestGet(fr, to, t, expected): + got = t.get(fr, to) + if got != expected: + print( + "ERROR: get(%s, %s) expected %s, but got %s" + % (repr(fr), repr(to), repr(expected), repr(got)) + ) + + +def test(): + import pywin.framework.editor + + d = pywin.framework.editor.editorTemplate.OpenDocumentFile(None) + e = d.GetFirstView() + t = TkText(e) + e.SCIAddText("hi there how\nare you today\r\nI hope you are well") + e.SetSel((4, 4)) + + skip = """ + TestCheck("insert", e, 4) + TestCheck("insert wordstart", e, 3) + TestCheck("insert wordend", e, 8) + TestCheck("insert linestart", e, 0) + TestCheck("insert lineend", e, 12) + TestCheck("insert + 4 chars", e, 8) + TestCheck("insert +4c", e, 8) + TestCheck("insert - 2 chars", e, 2) + TestCheck("insert -2c", e, 2) + TestCheck("insert-2c", e, 2) + TestCheck("insert-2 c", e, 2) + TestCheck("insert- 2c", e, 2) + TestCheck("1.1", e, 1) + TestCheck("1.0", e, 0) + TestCheck("2.0", e, 13) + try: + TestCheck("sel.first", e, 0) + print "*** sel.first worked with an empty selection" + except TextError: + pass + e.SetSel((4,5)) + TestCheck("sel.first- 2c", e, 2) + TestCheck("sel.last- 2c", e, 3) + """ + # Check EOL semantics + e.SetSel((4, 4)) + TestGet("insert lineend", "insert lineend +1c", t, "\n") + e.SetSel((20, 20)) + TestGet("insert lineend", "insert lineend +1c", t, "\n") + e.SetSel((35, 35)) + TestGet("insert lineend", "insert lineend +1c", t, "\n") + + +class IDLEWrapper: + def __init__(self, control): + self.text = control + + +def IDLETest(extension): + import os + import sys + + modname = "pywin.idle." + extension + __import__(modname) + mod = sys.modules[modname] + mod.TclError = TextError + klass = getattr(mod, extension) + + # Create a new Scintilla Window. + import pywin.framework.editor + + d = pywin.framework.editor.editorTemplate.OpenDocumentFile(None) + v = d.GetFirstView() + fname = os.path.splitext(__file__)[0] + ".py" + v.SCIAddText(open(fname).read()) + d.SetModifiedFlag(0) + r = klass(IDLEWrapper(TkText(v))) + return r + + +if __name__ == "__main__": + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0981b62284aa583d4750d3492b6ef892fa851d88 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__init__.py @@ -0,0 +1 @@ +# package init. diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/IDLEenvironment.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/IDLEenvironment.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..641b61c3d9819b662e97cbc8441342f1b35cb0bd Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/IDLEenvironment.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..985b58968b28018601ad2944fb03b2a11046ceea Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/bindings.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/bindings.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42355e27bb549c66f65b1576637b31a0c1ff5abe Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/bindings.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/config.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..435efb697e6ed74d115c93af4812c442c2f1584a Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/config.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/configui.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/configui.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fddfb2d65a37cf188d061cd455dfb8d4006ff5b2 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/configui.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/control.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/control.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10a57da91f13b139ce9bfa2d4f9654782cb486bc Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/control.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/document.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/document.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..478e0fc362202cfc2978bc3f87aaafb670c5dfce Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/document.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/find.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/find.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a77c16d0d1311af1aa110c29592d139aa8a44833 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/find.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/formatter.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/formatter.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..957514324431add6c32088f975faba498e0c2f2d Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/formatter.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/keycodes.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/keycodes.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb2079c05c04a53669635244c8b6b812ac554439 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/keycodes.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/scintillacon.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/scintillacon.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab0dd428341a0289edad332e75451e52b6e283d2 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/scintillacon.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/view.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/view.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2e9477028c08cd9fef5835dff4248baac57abca Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/__pycache__/view.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/bindings.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/bindings.py new file mode 100644 index 0000000000000000000000000000000000000000..785bd42a13a24ed36ed959998c93d47d3fa1ca1d --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/bindings.py @@ -0,0 +1,178 @@ +import traceback + +import win32api +import win32con +import win32ui + +from . import IDLEenvironment, keycodes + +HANDLER_ARGS_GUESS = 0 +HANDLER_ARGS_NATIVE = 1 +HANDLER_ARGS_IDLE = 2 +HANDLER_ARGS_EXTENSION = 3 + +next_id = 5000 + +event_to_commands = {} # dict of integer IDs to event names. +command_to_events = {} # dict of event names to int IDs + + +def assign_command_id(event, id=0): + global next_id + if id == 0: + id = event_to_commands.get(event, 0) + if id == 0: + id = next_id + next_id = next_id + 1 + # Only map the ones we allocated - specified ones are assumed to have a handler + command_to_events[id] = event + event_to_commands[event] = id + return id + + +class SendCommandHandler: + def __init__(self, cmd): + self.cmd = cmd + + def __call__(self, *args): + win32ui.GetMainFrame().SendMessage(win32con.WM_COMMAND, self.cmd) + + +class Binding: + def __init__(self, handler, handler_args_type): + self.handler = handler + self.handler_args_type = handler_args_type + + +class BindingsManager: + def __init__(self, parent_view): + self.parent_view = parent_view + self.bindings = {} # dict of Binding instances. + self.keymap = {} + + def prepare_configure(self): + self.keymap = {} + + def complete_configure(self): + for id in command_to_events.keys(): + self.parent_view.HookCommand(self._OnCommand, id) + + def close(self): + self.parent_view = self.bindings = self.keymap = None + + def report_error(self, problem): + try: + win32ui.SetStatusText(problem, 1) + except win32ui.error: + # No status bar! + print(problem) + + def update_keymap(self, keymap): + self.keymap.update(keymap) + + def bind(self, event, handler, handler_args_type=HANDLER_ARGS_GUESS, cid=0): + if handler is None: + handler = SendCommandHandler(cid) + self.bindings[event] = self._new_binding(handler, handler_args_type) + self.bind_command(event, cid) + + def bind_command(self, event, id=0): + "Binds an event to a Windows control/command ID" + id = assign_command_id(event, id) + return id + + def get_command_id(self, event): + id = event_to_commands.get(event) + if id is None: + # See if we even have an event of that name!? + if event not in self.bindings: + return None + id = self.bind_command(event) + return id + + def _OnCommand(self, id, code): + event = command_to_events.get(id) + if event is None: + self.report_error("No event associated with event ID %d" % id) + return 1 + return self.fire(event) + + def _new_binding(self, event, handler_args_type): + return Binding(event, handler_args_type) + + def _get_IDLE_handler(self, ext, handler): + try: + instance = self.parent_view.idle.IDLEExtension(ext) + name = handler.replace("-", "_") + "_event" + return getattr(instance, name) + except (ImportError, AttributeError): + msg = "Can not find event '%s' in IDLE extension '%s'" % (handler, ext) + self.report_error(msg) + return None + + def fire(self, event, event_param=None): + # Fire the specified event. Result is native Pythonwin result + # (ie, 1==pass one, 0 or None==handled) + + # First look up the event directly - if there, we are set. + binding = self.bindings.get(event) + if binding is None: + # If possible, find it! + # A native method name + handler = getattr(self.parent_view, event + "Event", None) + if handler is None: + # Can't decide if I should report an error?? + self.report_error("The event name '%s' can not be found." % event) + # Either way, just let the default handlers grab it. + return 1 + binding = self._new_binding(handler, HANDLER_ARGS_NATIVE) + # Cache it. + self.bindings[event] = binding + + handler_args_type = binding.handler_args_type + # Now actually fire it. + if handler_args_type == HANDLER_ARGS_GUESS: + # Can't be native, as natives are never added with "guess". + # Must be extension or IDLE. + if event[0] == "<": + handler_args_type = HANDLER_ARGS_IDLE + else: + handler_args_type = HANDLER_ARGS_EXTENSION + try: + if handler_args_type == HANDLER_ARGS_EXTENSION: + args = self.parent_view.idle, event_param + else: + args = (event_param,) + rc = binding.handler(*args) + if handler_args_type == HANDLER_ARGS_IDLE: + # Convert to our return code. + if rc in (None, "break"): + rc = 0 + else: + rc = 1 + except: + message = "Firing event '%s' failed." % event + print(message) + traceback.print_exc() + self.report_error(message) + rc = 1 # Let any default handlers have a go! + return rc + + def fire_key_event(self, msg): + key = msg[2] + keyState = 0 + if win32api.GetKeyState(win32con.VK_CONTROL) & 0x8000: + keyState = ( + keyState | win32con.RIGHT_CTRL_PRESSED | win32con.LEFT_CTRL_PRESSED + ) + if win32api.GetKeyState(win32con.VK_SHIFT) & 0x8000: + keyState = keyState | win32con.SHIFT_PRESSED + if win32api.GetKeyState(win32con.VK_MENU) & 0x8000: + keyState = keyState | win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED + keyinfo = key, keyState + # Special hacks for the dead-char key on non-US keyboards. + # (XXX - which do not work :-( + event = self.keymap.get(keyinfo) + if event is None: + return 1 + return self.fire(event, None) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/config.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/config.py new file mode 100644 index 0000000000000000000000000000000000000000..9a1b210e9c46c1a2ddaf4f20256cb802215fbfd1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/config.py @@ -0,0 +1,365 @@ +# config.py - deals with loading configuration information. + +# Loads config data from a .cfg file. Also caches the compiled +# data back into a .cfc file. + +# If you are wondering how to avoid needing .cfg files (eg, +# if you are freezing Pythonwin etc) I suggest you create a +# .py file, and put the config info in a docstring. Then +# pass a CStringIO file (rather than a filename) to the +# config manager. +import glob +import importlib.util +import marshal +import os +import stat +import sys +import traceback +import types + +import pywin +import win32api + +from . import keycodes + +debugging = 0 +if debugging: + import win32traceutil # Some trace statements fire before the interactive window is open. + + def trace(*args): + sys.stderr.write(" ".join(map(str, args)) + "\n") + +else: + trace = lambda *args: None + +compiled_config_version = 3 + + +def split_line(line, lineno): + comment_pos = line.find("#") + if comment_pos >= 0: + line = line[:comment_pos] + sep_pos = line.rfind("=") + if sep_pos == -1: + if line.strip(): + print("Warning: Line %d: %s is an invalid entry" % (lineno, repr(line))) + return None, None + return "", "" + return line[:sep_pos].strip(), line[sep_pos + 1 :].strip() + + +def get_section_header(line): + # Returns the section if the line is a section header, else None + if line[0] == "[": + end = line.find("]") + if end == -1: + end = len(line) + rc = line[1:end].lower() + try: + i = rc.index(":") + return rc[:i], rc[i + 1 :] + except ValueError: + return rc, "" + return None, None + + +def find_config_file(f): + return os.path.join(pywin.__path__[0], f + ".cfg") + + +def find_config_files(): + return [ + os.path.split(x)[1] + for x in [ + os.path.splitext(x)[0] + for x in glob.glob(os.path.join(pywin.__path__[0], "*.cfg")) + ] + ] + + +class ConfigManager: + def __init__(self, f): + self.filename = "unknown" + self.last_error = None + self.key_to_events = {} + b_close = False + if hasattr(f, "readline"): + fp = f + self.filename = "" + compiled_name = None + else: + try: + f = find_config_file(f) + src_stat = os.stat(f) + except os.error: + self.report_error("Config file '%s' not found" % f) + return + self.filename = f + self.basename = os.path.basename(f) + trace("Loading configuration", self.basename) + compiled_name = os.path.splitext(f)[0] + ".cfc" + try: + cf = open(compiled_name, "rb") + try: + ver = marshal.load(cf) + ok = compiled_config_version == ver + if ok: + kblayoutname = marshal.load(cf) + magic = marshal.load(cf) + size = marshal.load(cf) + mtime = marshal.load(cf) + if ( + magic == importlib.util.MAGIC_NUMBER + and win32api.GetKeyboardLayoutName() == kblayoutname + and src_stat[stat.ST_MTIME] == mtime + and src_stat[stat.ST_SIZE] == size + ): + self.cache = marshal.load(cf) + trace("Configuration loaded cached", compiled_name) + return # We are ready to roll! + finally: + cf.close() + except (os.error, IOError, EOFError): + pass + fp = open(f) + b_close = True + self.cache = {} + lineno = 1 + line = fp.readline() + while line: + # Skip to the next section (maybe already there!) + section, subsection = get_section_header(line) + while line and section is None: + line = fp.readline() + if not line: + break + lineno = lineno + 1 + section, subsection = get_section_header(line) + if not line: + break + + if section == "keys": + line, lineno = self._load_keys(subsection, fp, lineno) + elif section == "extensions": + line, lineno = self._load_extensions(subsection, fp, lineno) + elif section == "idle extensions": + line, lineno = self._load_idle_extensions(subsection, fp, lineno) + elif section == "general": + line, lineno = self._load_general(subsection, fp, lineno) + else: + self.report_error( + "Unrecognised section header '%s:%s'" % (section, subsection) + ) + line = fp.readline() + lineno = lineno + 1 + if b_close: + fp.close() + # Check critical data. + if not self.cache.get("keys"): + self.report_error("No keyboard definitions were loaded") + if not self.last_error and compiled_name: + try: + cf = open(compiled_name, "wb") + marshal.dump(compiled_config_version, cf) + marshal.dump(win32api.GetKeyboardLayoutName(), cf) + marshal.dump(importlib.util.MAGIC_NUMBER, cf) + marshal.dump(src_stat[stat.ST_SIZE], cf) + marshal.dump(src_stat[stat.ST_MTIME], cf) + marshal.dump(self.cache, cf) + cf.close() + except (IOError, EOFError): + pass # Ignore errors - may be read only. + + def configure(self, editor, subsections=None): + # Execute the extension code, and find any events. + # First, we "recursively" connect any we are based on. + if subsections is None: + subsections = [] + subsections = [""] + subsections + general = self.get_data("general") + if general: + parents = general.get("based on", []) + for parent in parents: + trace("Configuration based on", parent, "- loading.") + parent = self.__class__(parent) + parent.configure(editor, subsections) + if parent.last_error: + self.report_error(parent.last_error) + + bindings = editor.bindings + codeob = self.get_data("extension code") + if codeob is not None: + ns = {} + try: + exec(codeob, ns) + except: + traceback.print_exc() + self.report_error("Executing extension code failed") + ns = None + if ns: + num = 0 + for name, func in list(ns.items()): + if type(func) == types.FunctionType and name[:1] != "_": + bindings.bind(name, func) + num = num + 1 + trace("Configuration Extension code loaded", num, "events") + # Load the idle extensions + for subsection in subsections: + for ext in self.get_data("idle extensions", {}).get(subsection, []): + try: + editor.idle.IDLEExtension(ext) + trace("Loaded IDLE extension", ext) + except: + self.report_error("Can not load the IDLE extension '%s'" % ext) + + # Now bind up the key-map (remembering a reverse map + subsection_keymap = self.get_data("keys") + num_bound = 0 + for subsection in subsections: + keymap = subsection_keymap.get(subsection, {}) + bindings.update_keymap(keymap) + num_bound = num_bound + len(keymap) + trace("Configuration bound", num_bound, "keys") + + def get_key_binding(self, event, subsections=None): + if subsections is None: + subsections = [] + subsections = [""] + subsections + + subsection_keymap = self.get_data("keys") + for subsection in subsections: + map = self.key_to_events.get(subsection) + if map is None: # Build it + map = {} + keymap = subsection_keymap.get(subsection, {}) + for key_info, map_event in list(keymap.items()): + map[map_event] = key_info + self.key_to_events[subsection] = map + + info = map.get(event) + if info is not None: + return keycodes.make_key_name(info[0], info[1]) + return None + + def report_error(self, msg): + self.last_error = msg + print("Error in %s: %s" % (self.filename, msg)) + + def report_warning(self, msg): + print("Warning in %s: %s" % (self.filename, msg)) + + def _readline(self, fp, lineno, bStripComments=1): + line = fp.readline() + lineno = lineno + 1 + if line: + bBreak = ( + get_section_header(line)[0] is not None + ) # A new section is starting + if bStripComments and not bBreak: + pos = line.find("#") + if pos >= 0: + line = line[:pos] + "\n" + else: + bBreak = 1 + return line, lineno, bBreak + + def get_data(self, name, default=None): + return self.cache.get(name, default) + + def _save_data(self, name, data): + self.cache[name] = data + return data + + def _load_general(self, sub_section, fp, lineno): + map = {} + while 1: + line, lineno, bBreak = self._readline(fp, lineno) + if bBreak: + break + + key, val = split_line(line, lineno) + if not key: + continue + key = key.lower() + l = map.get(key, []) + l.append(val) + map[key] = l + self._save_data("general", map) + return line, lineno + + def _load_keys(self, sub_section, fp, lineno): + # Builds a nested dictionary of + # (scancode, flags) = event_name + main_map = self.get_data("keys", {}) + map = main_map.get(sub_section, {}) + while 1: + line, lineno, bBreak = self._readline(fp, lineno) + if bBreak: + break + + key, event = split_line(line, lineno) + if not event: + continue + sc, flag = keycodes.parse_key_name(key) + if sc is None: + self.report_warning("Line %d: Invalid key name '%s'" % (lineno, key)) + else: + map[sc, flag] = event + main_map[sub_section] = map + self._save_data("keys", main_map) + return line, lineno + + def _load_extensions(self, sub_section, fp, lineno): + start_lineno = lineno + lines = [] + while 1: + line, lineno, bBreak = self._readline(fp, lineno, 0) + if bBreak: + break + lines.append(line) + try: + c = compile( + "\n" * start_lineno + "".join(lines), # produces correct tracebacks + self.filename, + "exec", + ) + self._save_data("extension code", c) + except SyntaxError as details: + errlineno = details.lineno + start_lineno + # Should handle syntax errors better here, and offset the lineno. + self.report_error( + "Compiling extension code failed:\r\nFile: %s\r\nLine %d\r\n%s" + % (details.filename, errlineno, details.msg) + ) + return line, lineno + + def _load_idle_extensions(self, sub_section, fp, lineno): + extension_map = self.get_data("idle extensions") + if extension_map is None: + extension_map = {} + extensions = [] + while 1: + line, lineno, bBreak = self._readline(fp, lineno) + if bBreak: + break + line = line.strip() + if line: + extensions.append(line) + extension_map[sub_section] = extensions + self._save_data("idle extensions", extension_map) + return line, lineno + + +def test(): + import time + + start = time.clock() + f = "default" + cm = ConfigManager(f) + map = cm.get_data("keys") + took = time.clock() - start + print("Loaded %s items in %.4f secs" % (len(map), took)) + + +if __name__ == "__main__": + test() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/configui.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/configui.py new file mode 100644 index 0000000000000000000000000000000000000000..8b6157b60418967af59e7e9d5787149fdcdaa8cc --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/configui.py @@ -0,0 +1,292 @@ +import win32api +import win32con +import win32ui +from pywin.mfc import dialog + +# Used to indicate that style should use default color +from win32con import CLR_INVALID + +from . import scintillacon + +###################################################### +# Property Page for syntax formatting options + +# The standard 16 color VGA palette should always be possible +paletteVGA = ( + ("Black", win32api.RGB(0, 0, 0)), + ("Navy", win32api.RGB(0, 0, 128)), + ("Green", win32api.RGB(0, 128, 0)), + ("Cyan", win32api.RGB(0, 128, 128)), + ("Maroon", win32api.RGB(128, 0, 0)), + ("Purple", win32api.RGB(128, 0, 128)), + ("Olive", win32api.RGB(128, 128, 0)), + ("Gray", win32api.RGB(128, 128, 128)), + ("Silver", win32api.RGB(192, 192, 192)), + ("Blue", win32api.RGB(0, 0, 255)), + ("Lime", win32api.RGB(0, 255, 0)), + ("Aqua", win32api.RGB(0, 255, 255)), + ("Red", win32api.RGB(255, 0, 0)), + ("Fuchsia", win32api.RGB(255, 0, 255)), + ("Yellow", win32api.RGB(255, 255, 0)), + ("White", win32api.RGB(255, 255, 255)), + # and a few others will generally be possible. + ("DarkGrey", win32api.RGB(64, 64, 64)), + ("PurpleBlue", win32api.RGB(64, 64, 192)), + ("DarkGreen", win32api.RGB(0, 96, 0)), + ("DarkOlive", win32api.RGB(128, 128, 64)), + ("MediumBlue", win32api.RGB(0, 0, 192)), + ("DarkNavy", win32api.RGB(0, 0, 96)), + ("Magenta", win32api.RGB(96, 0, 96)), + ("OffWhite", win32api.RGB(255, 255, 220)), + ("LightPurple", win32api.RGB(220, 220, 255)), + ("", win32con.CLR_INVALID), +) + + +class ScintillaFormatPropertyPage(dialog.PropertyPage): + def __init__(self, scintillaClass=None, caption=0): + self.scintillaClass = scintillaClass + dialog.PropertyPage.__init__(self, win32ui.IDD_PP_FORMAT, caption=caption) + + def OnInitDialog(self): + try: + if self.scintillaClass is None: + from . import control + + sc = control.CScintillaEdit + else: + sc = self.scintillaClass + + self.scintilla = sc() + style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.ES_MULTILINE + # Convert the rect size + rect = self.MapDialogRect((5, 5, 120, 75)) + self.scintilla.CreateWindow(style, rect, self, 111) + self.HookNotify(self.OnBraceMatch, scintillacon.SCN_CHECKBRACE) + self.scintilla.HookKeyStroke(self.OnEsc, 27) + self.scintilla.SCISetViewWS(1) + self.pos_bstart = self.pos_bend = self.pos_bbad = 0 + + colorizer = self.scintilla._GetColorizer() + text = colorizer.GetSampleText() + items = text.split("|", 2) + pos = len(items[0]) + self.scintilla.SCIAddText("".join(items)) + self.scintilla.SetSel(pos, pos) + self.scintilla.ApplyFormattingStyles() + self.styles = self.scintilla._GetColorizer().styles + + self.cbo = self.GetDlgItem(win32ui.IDC_COMBO1) + for c in paletteVGA: + self.cbo.AddString(c[0]) + + self.cboBoldItalic = self.GetDlgItem(win32ui.IDC_COMBO2) + for item in ("Bold Italic", "Bold", "Italic", "Regular"): + self.cboBoldItalic.InsertString(0, item) + + self.butIsDefault = self.GetDlgItem(win32ui.IDC_CHECK1) + self.butIsDefaultBackground = self.GetDlgItem(win32ui.IDC_CHECK2) + self.listbox = self.GetDlgItem(win32ui.IDC_LIST1) + self.HookCommand(self.OnListCommand, win32ui.IDC_LIST1) + names = list(self.styles.keys()) + names.sort() + for name in names: + if self.styles[name].aliased is None: + self.listbox.AddString(name) + self.listbox.SetCurSel(0) + + idc = win32ui.IDC_RADIO1 + if not self.scintilla._GetColorizer().bUseFixed: + idc = win32ui.IDC_RADIO2 + self.GetDlgItem(idc).SetCheck(1) + self.UpdateUIForStyle(self.styles[names[0]]) + + self.scintilla.HookFormatter(self) + self.HookCommand(self.OnButDefaultFixedFont, win32ui.IDC_BUTTON1) + self.HookCommand(self.OnButDefaultPropFont, win32ui.IDC_BUTTON2) + self.HookCommand(self.OnButThisFont, win32ui.IDC_BUTTON3) + self.HookCommand(self.OnButUseDefaultFont, win32ui.IDC_CHECK1) + self.HookCommand(self.OnButThisBackground, win32ui.IDC_BUTTON4) + self.HookCommand(self.OnButUseDefaultBackground, win32ui.IDC_CHECK2) + self.HookCommand(self.OnStyleUIChanged, win32ui.IDC_COMBO1) + self.HookCommand(self.OnStyleUIChanged, win32ui.IDC_COMBO2) + self.HookCommand(self.OnButFixedOrDefault, win32ui.IDC_RADIO1) + self.HookCommand(self.OnButFixedOrDefault, win32ui.IDC_RADIO2) + except: + import traceback + + traceback.print_exc() + + def OnEsc(self, ch): + self.GetParent().EndDialog(win32con.IDCANCEL) + + def OnBraceMatch(self, std, extra): + import pywin.scintilla.view + + pywin.scintilla.view.DoBraceMatch(self.scintilla) + + def GetSelectedStyle(self): + return self.styles[self.listbox.GetText(self.listbox.GetCurSel())] + + def _DoButDefaultFont(self, extra_flags, attr): + baseFormat = getattr(self.scintilla._GetColorizer(), attr) + flags = ( + extra_flags + | win32con.CF_SCREENFONTS + | win32con.CF_EFFECTS + | win32con.CF_FORCEFONTEXIST + ) + d = win32ui.CreateFontDialog(baseFormat, flags, None, self) + if d.DoModal() == win32con.IDOK: + setattr(self.scintilla._GetColorizer(), attr, d.GetCharFormat()) + self.OnStyleUIChanged(0, win32con.BN_CLICKED) + + def OnButDefaultFixedFont(self, id, code): + if code == win32con.BN_CLICKED: + self._DoButDefaultFont(win32con.CF_FIXEDPITCHONLY, "baseFormatFixed") + return 1 + + def OnButDefaultPropFont(self, id, code): + if code == win32con.BN_CLICKED: + self._DoButDefaultFont(win32con.CF_SCALABLEONLY, "baseFormatProp") + return 1 + + def OnButFixedOrDefault(self, id, code): + if code == win32con.BN_CLICKED: + bUseFixed = id == win32ui.IDC_RADIO1 + self.GetDlgItem(win32ui.IDC_RADIO1).GetCheck() != 0 + self.scintilla._GetColorizer().bUseFixed = bUseFixed + self.scintilla.ApplyFormattingStyles(0) + return 1 + + def OnButThisFont(self, id, code): + if code == win32con.BN_CLICKED: + flags = ( + win32con.CF_SCREENFONTS + | win32con.CF_EFFECTS + | win32con.CF_FORCEFONTEXIST + ) + style = self.GetSelectedStyle() + # If the selected style is based on the default, we need to apply + # the default to it. + def_format = self.scintilla._GetColorizer().GetDefaultFormat() + format = style.GetCompleteFormat(def_format) + d = win32ui.CreateFontDialog(format, flags, None, self) + if d.DoModal() == win32con.IDOK: + style.format = d.GetCharFormat() + self.scintilla.ApplyFormattingStyles(0) + return 1 + + def OnButUseDefaultFont(self, id, code): + if code == win32con.BN_CLICKED: + isDef = self.butIsDefault.GetCheck() + self.GetDlgItem(win32ui.IDC_BUTTON3).EnableWindow(not isDef) + if isDef: # Being reset to the default font. + style = self.GetSelectedStyle() + style.ForceAgainstDefault() + self.UpdateUIForStyle(style) + self.scintilla.ApplyFormattingStyles(0) + else: + # User wants to override default - + # do nothing! + pass + + def OnButThisBackground(self, id, code): + if code == win32con.BN_CLICKED: + style = self.GetSelectedStyle() + bg = win32api.RGB(0xFF, 0xFF, 0xFF) + if style.background != CLR_INVALID: + bg = style.background + d = win32ui.CreateColorDialog(bg, 0, self) + if d.DoModal() == win32con.IDOK: + style.background = d.GetColor() + self.scintilla.ApplyFormattingStyles(0) + return 1 + + def OnButUseDefaultBackground(self, id, code): + if code == win32con.BN_CLICKED: + isDef = self.butIsDefaultBackground.GetCheck() + self.GetDlgItem(win32ui.IDC_BUTTON4).EnableWindow(not isDef) + if isDef: # Being reset to the default color + style = self.GetSelectedStyle() + style.background = style.default_background + self.UpdateUIForStyle(style) + self.scintilla.ApplyFormattingStyles(0) + else: + # User wants to override default - + # do nothing! + pass + + def OnListCommand(self, id, code): + if code == win32con.LBN_SELCHANGE: + style = self.GetSelectedStyle() + self.UpdateUIForStyle(style) + return 1 + + def UpdateUIForStyle(self, style): + format = style.format + sel = 0 + for c in paletteVGA: + if format[4] == c[1]: + # print "Style", style.name, "is", c[0] + break + sel = sel + 1 + else: + sel = -1 + self.cbo.SetCurSel(sel) + self.butIsDefault.SetCheck(style.IsBasedOnDefault()) + self.GetDlgItem(win32ui.IDC_BUTTON3).EnableWindow(not style.IsBasedOnDefault()) + + self.butIsDefaultBackground.SetCheck( + style.background == style.default_background + ) + self.GetDlgItem(win32ui.IDC_BUTTON4).EnableWindow( + style.background != style.default_background + ) + + bold = format[1] & win32con.CFE_BOLD != 0 + italic = format[1] & win32con.CFE_ITALIC != 0 + self.cboBoldItalic.SetCurSel(bold * 2 + italic) + + def OnStyleUIChanged(self, id, code): + if code in [win32con.BN_CLICKED, win32con.CBN_SELCHANGE]: + style = self.GetSelectedStyle() + self.ApplyUIFormatToStyle(style) + self.scintilla.ApplyFormattingStyles(0) + return 0 + return 1 + + def ApplyUIFormatToStyle(self, style): + format = style.format + color = paletteVGA[self.cbo.GetCurSel()] + effect = 0 + sel = self.cboBoldItalic.GetCurSel() + if sel == 0: + effect = 0 + elif sel == 1: + effect = win32con.CFE_ITALIC + elif sel == 2: + effect = win32con.CFE_BOLD + else: + effect = win32con.CFE_BOLD | win32con.CFE_ITALIC + maskFlags = ( + format[0] | win32con.CFM_COLOR | win32con.CFM_BOLD | win32con.CFM_ITALIC + ) + style.format = ( + maskFlags, + effect, + style.format[2], + style.format[3], + color[1], + ) + style.format[5:] + + def OnOK(self): + self.scintilla._GetColorizer().SavePreferences() + return 1 + + +def test(): + page = ColorEditorPropertyPage() + sheet = pywin.mfc.dialog.PropertySheet("Test") + sheet.AddPage(page) + sheet.CreateWindow() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/control.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/control.py new file mode 100644 index 0000000000000000000000000000000000000000..460b1686453a18dc52ed9bb2ae73820ef750f8d7 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/control.py @@ -0,0 +1,569 @@ +# An Python interface to the Scintilla control. +# +# Exposes Python classes that allow you to use Scintilla as +# a "standard" MFC edit control (eg, control.GetTextLength(), control.GetSel() +# plus many Scintilla specific features (eg control.SCIAddStyledText()) + +import array +import os +import struct + +import win32api +import win32con +import win32ui +from pywin import default_scintilla_encoding +from pywin.mfc import window + +from . import scintillacon + +# Load Scintilla.dll to get access to the control. +# We expect to find this in the same directory as win32ui.pyd +dllid = None +if win32ui.debug: # If running _d version of Pythonwin... + try: + dllid = win32api.LoadLibrary( + os.path.join(os.path.split(win32ui.__file__)[0], "Scintilla_d.DLL") + ) + except ( + win32api.error + ): # Not there - we dont _need_ a debug ver, so ignore this error. + pass +if dllid is None: + try: + dllid = win32api.LoadLibrary( + os.path.join(os.path.split(win32ui.__file__)[0], "Scintilla.DLL") + ) + except win32api.error: + pass +if dllid is None: + # Still not there - lets see if Windows can find it by searching? + dllid = win32api.LoadLibrary("Scintilla.DLL") + +# null_byte is str in py2k, bytes on py3k +null_byte = "\0".encode("ascii") + +## These are from Richedit.h - need to add to win32con or commctrl +EM_GETTEXTRANGE = 1099 +EM_EXLINEFROMCHAR = 1078 +EM_FINDTEXTEX = 1103 +EM_GETSELTEXT = 1086 +EM_EXSETSEL = win32con.WM_USER + 55 + + +class ScintillaNotification: + def __init__(self, **args): + self.__dict__.update(args) + + +class ScintillaControlInterface: + def SCIUnpackNotifyMessage(self, msg): + format = "iiiiPiiiPPiiii" + bytes = win32ui.GetBytes(msg, struct.calcsize(format)) + ( + position, + ch, + modifiers, + modificationType, + text_ptr, + length, + linesAdded, + msg, + wParam, + lParam, + line, + foldLevelNow, + foldLevelPrev, + margin, + ) = struct.unpack(format, bytes) + return ScintillaNotification( + position=position, + ch=ch, + modifiers=modifiers, + modificationType=modificationType, + text_ptr=text_ptr, + length=length, + linesAdded=linesAdded, + msg=msg, + wParam=wParam, + lParam=lParam, + line=line, + foldLevelNow=foldLevelNow, + foldLevelPrev=foldLevelPrev, + margin=margin, + ) + + def SCIAddText(self, text): + self.SendMessage( + scintillacon.SCI_ADDTEXT, text.encode(default_scintilla_encoding) + ) + + def SCIAddStyledText(self, text, style=None): + # If style is None, text is assumed to be a "native" Scintilla buffer. + # If style is specified, text is a normal string, and the style is + # assumed to apply to the entire string. + if style is not None: + text = list(map(lambda char, style=style: char + chr(style), text)) + text = "".join(text) + self.SendMessage( + scintillacon.SCI_ADDSTYLEDTEXT, text.encode(default_scintilla_encoding) + ) + + def SCIInsertText(self, text, pos=-1): + # SCIInsertText allows unicode or bytes - but if they are bytes, + # the caller must ensure it is encoded correctly. + if isinstance(text, str): + text = text.encode(default_scintilla_encoding) + self.SendScintilla(scintillacon.SCI_INSERTTEXT, pos, text + null_byte) + + def SCISetSavePoint(self): + self.SendScintilla(scintillacon.SCI_SETSAVEPOINT) + + def SCISetUndoCollection(self, collectFlag): + self.SendScintilla(scintillacon.SCI_SETUNDOCOLLECTION, collectFlag) + + def SCIBeginUndoAction(self): + self.SendScintilla(scintillacon.SCI_BEGINUNDOACTION) + + def SCIEndUndoAction(self): + self.SendScintilla(scintillacon.SCI_ENDUNDOACTION) + + def SCIGetCurrentPos(self): + return self.SendScintilla(scintillacon.SCI_GETCURRENTPOS) + + def SCIGetCharAt(self, pos): + # Must ensure char is unsigned! + return chr(self.SendScintilla(scintillacon.SCI_GETCHARAT, pos) & 0xFF) + + def SCIGotoLine(self, line): + self.SendScintilla(scintillacon.SCI_GOTOLINE, line) + + def SCIBraceMatch(self, pos, maxReStyle): + return self.SendScintilla(scintillacon.SCI_BRACEMATCH, pos, maxReStyle) + + def SCIBraceHighlight(self, pos, posOpposite): + return self.SendScintilla(scintillacon.SCI_BRACEHIGHLIGHT, pos, posOpposite) + + def SCIBraceBadHighlight(self, pos): + return self.SendScintilla(scintillacon.SCI_BRACEBADLIGHT, pos) + + #################################### + # Styling + # def SCIColourise(self, start=0, end=-1): + # NOTE - dependent on of we use builtin lexer, so handled below. + def SCIGetEndStyled(self): + return self.SendScintilla(scintillacon.SCI_GETENDSTYLED) + + def SCIStyleSetFore(self, num, v): + return self.SendScintilla(scintillacon.SCI_STYLESETFORE, num, v) + + def SCIStyleSetBack(self, num, v): + return self.SendScintilla(scintillacon.SCI_STYLESETBACK, num, v) + + def SCIStyleSetEOLFilled(self, num, v): + return self.SendScintilla(scintillacon.SCI_STYLESETEOLFILLED, num, v) + + def SCIStyleSetFont(self, num, name, characterset=0): + buff = (name + "\0").encode(default_scintilla_encoding) + self.SendScintilla(scintillacon.SCI_STYLESETFONT, num, buff) + self.SendScintilla(scintillacon.SCI_STYLESETCHARACTERSET, num, characterset) + + def SCIStyleSetBold(self, num, bBold): + self.SendScintilla(scintillacon.SCI_STYLESETBOLD, num, bBold) + + def SCIStyleSetItalic(self, num, bItalic): + self.SendScintilla(scintillacon.SCI_STYLESETITALIC, num, bItalic) + + def SCIStyleSetSize(self, num, size): + self.SendScintilla(scintillacon.SCI_STYLESETSIZE, num, size) + + def SCIGetViewWS(self): + return self.SendScintilla(scintillacon.SCI_GETVIEWWS) + + def SCISetViewWS(self, val): + self.SendScintilla(scintillacon.SCI_SETVIEWWS, not (val == 0)) + self.InvalidateRect() + + def SCISetIndentationGuides(self, val): + self.SendScintilla(scintillacon.SCI_SETINDENTATIONGUIDES, val) + + def SCIGetIndentationGuides(self): + return self.SendScintilla(scintillacon.SCI_GETINDENTATIONGUIDES) + + def SCISetIndent(self, val): + self.SendScintilla(scintillacon.SCI_SETINDENT, val) + + def SCIGetIndent(self, val): + return self.SendScintilla(scintillacon.SCI_GETINDENT) + + def SCIGetViewEOL(self): + return self.SendScintilla(scintillacon.SCI_GETVIEWEOL) + + def SCISetViewEOL(self, val): + self.SendScintilla(scintillacon.SCI_SETVIEWEOL, not (val == 0)) + self.InvalidateRect() + + def SCISetTabWidth(self, width): + self.SendScintilla(scintillacon.SCI_SETTABWIDTH, width, 0) + + def SCIStartStyling(self, pos, mask): + self.SendScintilla(scintillacon.SCI_STARTSTYLING, pos, mask) + + def SCISetStyling(self, pos, attr): + self.SendScintilla(scintillacon.SCI_SETSTYLING, pos, attr) + + def SCISetStylingEx(self, ray): # ray is an array. + address, length = ray.buffer_info() + self.SendScintilla(scintillacon.SCI_SETSTYLINGEX, length, address) + + def SCIGetStyleAt(self, pos): + return self.SendScintilla(scintillacon.SCI_GETSTYLEAT, pos) + + def SCISetMarginWidth(self, width): + self.SendScintilla(scintillacon.SCI_SETMARGINWIDTHN, 1, width) + + def SCISetMarginWidthN(self, n, width): + self.SendScintilla(scintillacon.SCI_SETMARGINWIDTHN, n, width) + + def SCISetFoldFlags(self, flags): + self.SendScintilla(scintillacon.SCI_SETFOLDFLAGS, flags) + + # Markers + def SCIMarkerDefineAll(self, markerNum, markerType, fore, back): + self.SCIMarkerDefine(markerNum, markerType) + self.SCIMarkerSetFore(markerNum, fore) + self.SCIMarkerSetBack(markerNum, back) + + def SCIMarkerDefine(self, markerNum, markerType): + self.SendScintilla(scintillacon.SCI_MARKERDEFINE, markerNum, markerType) + + def SCIMarkerSetFore(self, markerNum, fore): + self.SendScintilla(scintillacon.SCI_MARKERSETFORE, markerNum, fore) + + def SCIMarkerSetBack(self, markerNum, back): + self.SendScintilla(scintillacon.SCI_MARKERSETBACK, markerNum, back) + + def SCIMarkerAdd(self, lineNo, markerNum): + self.SendScintilla(scintillacon.SCI_MARKERADD, lineNo, markerNum) + + def SCIMarkerDelete(self, lineNo, markerNum): + self.SendScintilla(scintillacon.SCI_MARKERDELETE, lineNo, markerNum) + + def SCIMarkerDeleteAll(self, markerNum=-1): + self.SendScintilla(scintillacon.SCI_MARKERDELETEALL, markerNum) + + def SCIMarkerGet(self, lineNo): + return self.SendScintilla(scintillacon.SCI_MARKERGET, lineNo) + + def SCIMarkerNext(self, lineNo, markerNum): + return self.SendScintilla(scintillacon.SCI_MARKERNEXT, lineNo, markerNum) + + def SCICancel(self): + self.SendScintilla(scintillacon.SCI_CANCEL) + + # AutoComplete + def SCIAutoCShow(self, text): + if type(text) in [type([]), type(())]: + text = " ".join(text) + buff = (text + "\0").encode(default_scintilla_encoding) + return self.SendScintilla(scintillacon.SCI_AUTOCSHOW, 0, buff) + + def SCIAutoCCancel(self): + self.SendScintilla(scintillacon.SCI_AUTOCCANCEL) + + def SCIAutoCActive(self): + return self.SendScintilla(scintillacon.SCI_AUTOCACTIVE) + + def SCIAutoCComplete(self): + return self.SendScintilla(scintillacon.SCI_AUTOCCOMPLETE) + + def SCIAutoCStops(self, stops): + buff = (stops + "\0").encode(default_scintilla_encoding) + self.SendScintilla(scintillacon.SCI_AUTOCSTOPS, 0, buff) + + def SCIAutoCSetAutoHide(self, hide): + self.SendScintilla(scintillacon.SCI_AUTOCSETAUTOHIDE, hide) + + def SCIAutoCSetFillups(self, fillups): + self.SendScintilla(scintillacon.SCI_AUTOCSETFILLUPS, fillups) + + # Call tips + def SCICallTipShow(self, text, pos=-1): + if pos == -1: + pos = self.GetSel()[0] + buff = (text + "\0").encode(default_scintilla_encoding) + self.SendScintilla(scintillacon.SCI_CALLTIPSHOW, pos, buff) + + def SCICallTipCancel(self): + self.SendScintilla(scintillacon.SCI_CALLTIPCANCEL) + + def SCICallTipActive(self): + return self.SendScintilla(scintillacon.SCI_CALLTIPACTIVE) + + def SCICallTipPosStart(self): + return self.SendScintilla(scintillacon.SCI_CALLTIPPOSSTART) + + def SCINewline(self): + self.SendScintilla(scintillacon.SCI_NEWLINE) + + # Lexer etc + def SCISetKeywords(self, keywords, kw_list_no=0): + buff = (keywords + "\0").encode(default_scintilla_encoding) + self.SendScintilla(scintillacon.SCI_SETKEYWORDS, kw_list_no, buff) + + def SCISetProperty(self, name, value): + name_buff = array.array("b", (name + "\0").encode(default_scintilla_encoding)) + val_buff = array.array( + "b", (str(value) + "\0").encode(default_scintilla_encoding) + ) + address_name_buffer = name_buff.buffer_info()[0] + address_val_buffer = val_buff.buffer_info()[0] + self.SendScintilla( + scintillacon.SCI_SETPROPERTY, address_name_buffer, address_val_buffer + ) + + def SCISetStyleBits(self, nbits): + self.SendScintilla(scintillacon.SCI_SETSTYLEBITS, nbits) + + # Folding + def SCIGetFoldLevel(self, lineno): + return self.SendScintilla(scintillacon.SCI_GETFOLDLEVEL, lineno) + + def SCIToggleFold(self, lineno): + return self.SendScintilla(scintillacon.SCI_TOGGLEFOLD, lineno) + + def SCIEnsureVisible(self, lineno): + self.SendScintilla(scintillacon.SCI_ENSUREVISIBLE, lineno) + + def SCIGetFoldExpanded(self, lineno): + return self.SendScintilla(scintillacon.SCI_GETFOLDEXPANDED, lineno) + + # right edge + def SCISetEdgeColumn(self, edge): + self.SendScintilla(scintillacon.SCI_SETEDGECOLUMN, edge) + + def SCIGetEdgeColumn(self): + return self.SendScintilla(scintillacon.SCI_GETEDGECOLUMN) + + def SCISetEdgeMode(self, mode): + self.SendScintilla(scintillacon.SCI_SETEDGEMODE, mode) + + def SCIGetEdgeMode(self): + return self.SendScintilla(scintillacon.SCI_GETEDGEMODE) + + def SCISetEdgeColor(self, color): + self.SendScintilla(scintillacon.SCI_SETEDGECOLOUR, color) + + def SCIGetEdgeColor(self): + return self.SendScintilla(scintillacon.SCI_GETEDGECOLOR) + + # Multi-doc + def SCIGetDocPointer(self): + return self.SendScintilla(scintillacon.SCI_GETDOCPOINTER) + + def SCISetDocPointer(self, p): + return self.SendScintilla(scintillacon.SCI_SETDOCPOINTER, 0, p) + + def SCISetWrapMode(self, mode): + return self.SendScintilla(scintillacon.SCI_SETWRAPMODE, mode) + + def SCIGetWrapMode(self): + return self.SendScintilla(scintillacon.SCI_GETWRAPMODE) + + +class CScintillaEditInterface(ScintillaControlInterface): + def close(self): + self.colorizer = None + + def Clear(self): + self.SendScintilla(win32con.WM_CLEAR) + + def FindText(self, flags, range, findText): + """LPARAM for EM_FINDTEXTEX: + typedef struct _findtextex { + CHARRANGE chrg; + LPCTSTR lpstrText; + CHARRANGE chrgText;} FINDTEXTEX; + typedef struct _charrange { + LONG cpMin; + LONG cpMax;} CHARRANGE; + """ + findtextex_fmt = "llPll" + ## Scintilla does not handle unicode in EM_FINDTEXT msg (FINDTEXTEX struct) + txt_buff = (findText + "\0").encode(default_scintilla_encoding) + txt_array = array.array("b", txt_buff) + ft_buff = struct.pack( + findtextex_fmt, range[0], range[1], txt_array.buffer_info()[0], 0, 0 + ) + ft_array = array.array("b", ft_buff) + rc = self.SendScintilla(EM_FINDTEXTEX, flags, ft_array.buffer_info()[0]) + ftUnpacked = struct.unpack(findtextex_fmt, ft_array) + return rc, (ftUnpacked[3], ftUnpacked[4]) + + def GetSel(self): + currentPos = self.SendScintilla(scintillacon.SCI_GETCURRENTPOS) + anchorPos = self.SendScintilla(scintillacon.SCI_GETANCHOR) + if currentPos < anchorPos: + return (currentPos, anchorPos) + else: + return (anchorPos, currentPos) + return currentPos + + def GetSelText(self): + start, end = self.GetSel() + txtBuf = array.array("b", null_byte * (end - start + 1)) + addressTxtBuf = txtBuf.buffer_info()[0] + # EM_GETSELTEXT is documented as returning the number of chars + # not including the NULL, but scintilla includes the NULL. A + # quick glance at the scintilla impl doesn't make this + # obvious - the NULL is included in the 'selection' object + # and reflected in the length of that 'selection' object. + # I expect that is a bug in scintilla and may be fixed by now, + # but we just blindly assume that the last char is \0 and + # strip it. + self.SendScintilla(EM_GETSELTEXT, 0, addressTxtBuf) + return txtBuf.tobytes()[:-1].decode(default_scintilla_encoding) + + def SetSel(self, start=0, end=None): + if type(start) == type(()): + assert ( + end is None + ), "If you pass a point in the first param, the second must be None" + start, end = start + elif end is None: + end = start + if start < 0: + start = self.GetTextLength() + if end < 0: + end = self.GetTextLength() + assert start <= self.GetTextLength(), "The start postion is invalid (%d/%d)" % ( + start, + self.GetTextLength(), + ) + assert end <= self.GetTextLength(), "The end postion is invalid (%d/%d)" % ( + end, + self.GetTextLength(), + ) + cr = struct.pack("ll", start, end) + crBuff = array.array("b", cr) + addressCrBuff = crBuff.buffer_info()[0] + rc = self.SendScintilla(EM_EXSETSEL, 0, addressCrBuff) + + def GetLineCount(self): + return self.SendScintilla(win32con.EM_GETLINECOUNT) + + def LineFromChar(self, charPos=-1): + if charPos == -1: + charPos = self.GetSel()[0] + assert ( + charPos >= 0 and charPos <= self.GetTextLength() + ), "The charPos postion (%s) is invalid (max=%s)" % ( + charPos, + self.GetTextLength(), + ) + # return self.SendScintilla(EM_EXLINEFROMCHAR, charPos) + # EM_EXLINEFROMCHAR puts charPos in lParam, not wParam + return self.SendScintilla(EM_EXLINEFROMCHAR, 0, charPos) + + def LineIndex(self, line): + return self.SendScintilla(win32con.EM_LINEINDEX, line) + + def ScrollCaret(self): + return self.SendScintilla(win32con.EM_SCROLLCARET) + + def GetCurLineNumber(self): + return self.LineFromChar(self.SCIGetCurrentPos()) + + def GetTextLength(self): + return self.SendScintilla(scintillacon.SCI_GETTEXTLENGTH) + + def GetTextRange(self, start=0, end=-1, decode=True): + if end == -1: + end = self.SendScintilla(scintillacon.SCI_GETTEXTLENGTH) + assert end >= start, "Negative index requested (%d/%d)" % (start, end) + assert ( + start >= 0 and start <= self.GetTextLength() + ), "The start postion is invalid" + assert end >= 0 and end <= self.GetTextLength(), "The end postion is invalid" + initer = null_byte * (end - start + 1) + buff = array.array("b", initer) + addressBuffer = buff.buffer_info()[0] + tr = struct.pack("llP", start, end, addressBuffer) + trBuff = array.array("b", tr) + addressTrBuff = trBuff.buffer_info()[0] + num_bytes = self.SendScintilla(EM_GETTEXTRANGE, 0, addressTrBuff) + ret = buff.tobytes()[:num_bytes] + if decode: + ret = ret.decode(default_scintilla_encoding) + return ret + + def ReplaceSel(self, str): + buff = (str + "\0").encode(default_scintilla_encoding) + self.SendScintilla(scintillacon.SCI_REPLACESEL, 0, buff) + + def GetLine(self, line=-1): + if line == -1: + line = self.GetCurLineNumber() + start = self.LineIndex(line) + end = self.LineIndex(line + 1) + return self.GetTextRange(start, end) + + def SetReadOnly(self, flag=1): + return self.SendScintilla(win32con.EM_SETREADONLY, flag) + + def LineScroll(self, lines, cols=0): + return self.SendScintilla(win32con.EM_LINESCROLL, cols, lines) + + def GetFirstVisibleLine(self): + return self.SendScintilla(win32con.EM_GETFIRSTVISIBLELINE) + + def SetWordWrap(self, mode): + if mode != win32ui.CRichEditView_WrapNone: + raise ValueError("We dont support word-wrap (I dont think :-)") + + +class CScintillaColorEditInterface(CScintillaEditInterface): + ################################ + # Plug-in colorizer support + def _GetColorizer(self): + if not hasattr(self, "colorizer"): + self.colorizer = self._MakeColorizer() + return self.colorizer + + def _MakeColorizer(self): + # Give parent a chance to hook. + parent_func = getattr(self.GetParentFrame(), "_MakeColorizer", None) + if parent_func is not None: + return parent_func() + from . import formatter + + ## return formatter.PythonSourceFormatter(self) + return formatter.BuiltinPythonSourceFormatter(self) + + def Colorize(self, start=0, end=-1): + c = self._GetColorizer() + if c is not None: + c.Colorize(start, end) + + def ApplyFormattingStyles(self, bReload=1): + c = self._GetColorizer() + if c is not None: + c.ApplyFormattingStyles(bReload) + + # The Parent window will normally hook + def HookFormatter(self, parent=None): + c = self._GetColorizer() + if c is not None: # No need if we have no color! + c.HookFormatter(parent) + + +class CScintillaEdit(window.Wnd, CScintillaColorEditInterface): + def __init__(self, wnd=None): + if wnd is None: + wnd = win32ui.CreateWnd() + window.Wnd.__init__(self, wnd) + + def SendScintilla(self, msg, w=0, l=0): + return self.SendMessage(msg, w, l) + + def CreateWindow(self, style, rect, parent, id): + self._obj_.CreateWindow("Scintilla", "Scintilla", style, rect, parent, id, None) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/document.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/document.py new file mode 100644 index 0000000000000000000000000000000000000000..cddb442c113ae857216daa24cb5a56006a935f3c --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/document.py @@ -0,0 +1,312 @@ +import codecs +import re +import string + +import win32con +import win32ui +from pywin import default_scintilla_encoding +from pywin.mfc import docview + +from . import scintillacon + +crlf_bytes = "\r\n".encode("ascii") +lf_bytes = "\n".encode("ascii") + +# re from pep263 - but we use it both on bytes and strings. +re_encoding_bytes = re.compile("coding[:=]\s*([-\w.]+)".encode("ascii")) +re_encoding_text = re.compile("coding[:=]\s*([-\w.]+)") + +ParentScintillaDocument = docview.Document + + +class CScintillaDocument(ParentScintillaDocument): + "A SyntEdit document." + + def __init__(self, *args): + self.bom = None # the BOM, if any, read from the file. + # the encoding we detected from the source. Might have + # detected via the BOM or an encoding decl. Note that in + # the latter case (ie, while self.bom is None), it can't be + # trusted - the user may have edited the encoding decl between + # open and save. + self.source_encoding = None + ParentScintillaDocument.__init__(self, *args) + + def DeleteContents(self): + pass + + def OnOpenDocument(self, filename): + # init data members + # print "Opening", filename + self.SetPathName(filename) # Must set this early! + try: + # load the text as binary we can get smart + # about detecting any existing EOL conventions. + f = open(filename, "rb") + try: + self._LoadTextFromFile(f) + finally: + f.close() + except IOError: + rc = win32ui.MessageBox( + "Could not load the file from %s\n\nDo you want to create a new file?" + % filename, + "Pythonwin", + win32con.MB_YESNO | win32con.MB_ICONWARNING, + ) + if rc == win32con.IDNO: + return 0 + assert rc == win32con.IDYES, rc + try: + f = open(filename, "wb+") + try: + self._LoadTextFromFile(f) + finally: + f.close() + except IOError as e: + rc = win32ui.MessageBox("Cannot create the file %s" % filename) + return 1 + + def SaveFile(self, fileName, encoding=None): + view = self.GetFirstView() + ok = view.SaveTextFile(fileName, encoding=encoding) + if ok: + view.SCISetSavePoint() + return ok + + def ApplyFormattingStyles(self): + self._ApplyOptionalToViews("ApplyFormattingStyles") + + # ##################### + # File related functions + # Helper to transfer text from the MFC document to the control. + def _LoadTextFromFile(self, f): + # detect EOL mode - we don't support \r only - so find the + # first '\n' and guess based on the char before. + l = f.readline() + l2 = f.readline() + # If line ends with \r\n or has no line ending, use CRLF. + if l.endswith(crlf_bytes) or not l.endswith(lf_bytes): + eol_mode = scintillacon.SC_EOL_CRLF + else: + eol_mode = scintillacon.SC_EOL_LF + + # Detect the encoding - first look for a BOM, and if not found, + # look for a pep263 encoding declaration. + for bom, encoding in ( + (codecs.BOM_UTF8, "utf8"), + (codecs.BOM_UTF16_LE, "utf_16_le"), + (codecs.BOM_UTF16_BE, "utf_16_be"), + ): + if l.startswith(bom): + self.bom = bom + self.source_encoding = encoding + l = l[len(bom) :] # remove it. + break + else: + # no bom detected - look for pep263 encoding decl. + for look in (l, l2): + # Note we are looking at raw bytes here: so + # both the re itself uses bytes and the result + # is bytes - but we need the result as a string. + match = re_encoding_bytes.search(look) + if match is not None: + self.source_encoding = match.group(1).decode("ascii") + break + + # reading by lines would be too slow? Maybe we can use the + # incremental encoders? For now just stick with loading the + # entire file in memory. + text = l + l2 + f.read() + + # Translate from source encoding to UTF-8 bytes for Scintilla + source_encoding = self.source_encoding + # If we don't know an encoding, try utf-8 - if that fails we will + # fallback to latin-1 to treat it as bytes... + if source_encoding is None: + source_encoding = "utf-8" + # we could optimize this by avoiding utf8 to-ing and from-ing, + # but then we would lose the ability to handle invalid utf8 + # (and even then, the use of encoding aliases makes this tricky) + # To create an invalid utf8 file: + # >>> open(filename, "wb").write(codecs.BOM_UTF8+"bad \xa9har\r\n") + try: + dec = text.decode(source_encoding) + except UnicodeError: + print( + "WARNING: Failed to decode bytes from '%s' encoding - treating as latin1" + % source_encoding + ) + dec = text.decode("latin1") + except LookupError: + print( + "WARNING: Invalid encoding '%s' specified - treating as latin1" + % source_encoding + ) + dec = text.decode("latin1") + # and put it back as utf8 - this shouldn't fail. + text = dec.encode(default_scintilla_encoding) + + view = self.GetFirstView() + if view.IsWindow(): + # Turn off undo collection while loading + view.SendScintilla(scintillacon.SCI_SETUNDOCOLLECTION, 0, 0) + # Make sure the control isnt read-only + view.SetReadOnly(0) + view.SendScintilla(scintillacon.SCI_CLEARALL) + view.SendMessage(scintillacon.SCI_ADDTEXT, text) + view.SendScintilla(scintillacon.SCI_SETUNDOCOLLECTION, 1, 0) + view.SendScintilla(win32con.EM_EMPTYUNDOBUFFER, 0, 0) + # set EOL mode + view.SendScintilla(scintillacon.SCI_SETEOLMODE, eol_mode) + + def _SaveTextToFile(self, view, filename, encoding=None): + s = view.GetTextRange() # already decoded from scintilla's encoding + source_encoding = encoding + if source_encoding is None: + if self.bom: + source_encoding = self.source_encoding + else: + # no BOM - look for an encoding. + bits = re.split("[\r\n]+", s, 3) + for look in bits[:-1]: + match = re_encoding_text.search(look) + if match is not None: + source_encoding = match.group(1) + self.source_encoding = source_encoding + break + + if source_encoding is None: + source_encoding = "utf-8" + + ## encode data before opening file so script is not lost if encoding fails + file_contents = s.encode(source_encoding) + # Open in binary mode as scintilla itself ensures the + # line endings are already appropriate + f = open(filename, "wb") + try: + if self.bom: + f.write(self.bom) + f.write(file_contents) + finally: + f.close() + self.SetModifiedFlag(0) + + def FinalizeViewCreation(self, view): + pass + + def HookViewNotifications(self, view): + parent = view.GetParentFrame() + parent.HookNotify( + ViewNotifyDelegate(self, "OnBraceMatch"), scintillacon.SCN_CHECKBRACE + ) + parent.HookNotify( + ViewNotifyDelegate(self, "OnMarginClick"), scintillacon.SCN_MARGINCLICK + ) + parent.HookNotify( + ViewNotifyDelegate(self, "OnNeedShown"), scintillacon.SCN_NEEDSHOWN + ) + + parent.HookNotify( + DocumentNotifyDelegate(self, "OnSavePointReached"), + scintillacon.SCN_SAVEPOINTREACHED, + ) + parent.HookNotify( + DocumentNotifyDelegate(self, "OnSavePointLeft"), + scintillacon.SCN_SAVEPOINTLEFT, + ) + parent.HookNotify( + DocumentNotifyDelegate(self, "OnModifyAttemptRO"), + scintillacon.SCN_MODIFYATTEMPTRO, + ) + # Tell scintilla what characters should abort auto-complete. + view.SCIAutoCStops(string.whitespace + "()[]:;+-/*=\\?'!#@$%^&,<>\"'|") + + if view != self.GetFirstView(): + view.SCISetDocPointer(self.GetFirstView().SCIGetDocPointer()) + + def OnSavePointReached(self, std, extra): + self.SetModifiedFlag(0) + + def OnSavePointLeft(self, std, extra): + self.SetModifiedFlag(1) + + def OnModifyAttemptRO(self, std, extra): + self.MakeDocumentWritable() + + # All Marker functions are 1 based. + def MarkerAdd(self, lineNo, marker): + self.GetEditorView().SCIMarkerAdd(lineNo - 1, marker) + + def MarkerCheck(self, lineNo, marker): + v = self.GetEditorView() + lineNo = lineNo - 1 # Make 0 based + markerState = v.SCIMarkerGet(lineNo) + return markerState & (1 << marker) != 0 + + def MarkerToggle(self, lineNo, marker): + v = self.GetEditorView() + if self.MarkerCheck(lineNo, marker): + v.SCIMarkerDelete(lineNo - 1, marker) + else: + v.SCIMarkerAdd(lineNo - 1, marker) + + def MarkerDelete(self, lineNo, marker): + self.GetEditorView().SCIMarkerDelete(lineNo - 1, marker) + + def MarkerDeleteAll(self, marker): + self.GetEditorView().SCIMarkerDeleteAll(marker) + + def MarkerGetNext(self, lineNo, marker): + return self.GetEditorView().SCIMarkerNext(lineNo - 1, 1 << marker) + 1 + + def MarkerAtLine(self, lineNo, marker): + markerState = self.GetEditorView().SCIMarkerGet(lineNo - 1) + return markerState & (1 << marker) + + # Helper for reflecting functions to views. + def _ApplyToViews(self, funcName, *args): + for view in self.GetAllViews(): + func = getattr(view, funcName) + func(*args) + + def _ApplyOptionalToViews(self, funcName, *args): + for view in self.GetAllViews(): + func = getattr(view, funcName, None) + if func is not None: + func(*args) + + def GetEditorView(self): + # Find the first frame with a view, + # then ask it to give the editor view + # as it knows which one is "active" + try: + frame_gev = self.GetFirstView().GetParentFrame().GetEditorView + except AttributeError: + return self.GetFirstView() + return frame_gev() + + +# Delegate to the correct view, based on the control that sent it. +class ViewNotifyDelegate: + def __init__(self, doc, name): + self.doc = doc + self.name = name + + def __call__(self, std, extra): + (hwndFrom, idFrom, code) = std + for v in self.doc.GetAllViews(): + if v.GetSafeHwnd() == hwndFrom: + return getattr(v, self.name)(*(std, extra)) + + +# Delegate to the document, but only from a single view (as each view sends it seperately) +class DocumentNotifyDelegate: + def __init__(self, doc, name): + self.doc = doc + self.delegate = getattr(doc, name) + + def __call__(self, std, extra): + (hwndFrom, idFrom, code) = std + if hwndFrom == self.doc.GetEditorView().GetSafeHwnd(): + self.delegate(*(std, extra)) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/find.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/find.py new file mode 100644 index 0000000000000000000000000000000000000000..e1d21a5bceec6359e2d9023b5098e38346905f29 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/find.py @@ -0,0 +1,510 @@ +# find.py - Find and Replace +import afxres +import win32api +import win32con +import win32ui +from pywin.framework import scriptutils +from pywin.mfc import dialog + +FOUND_NOTHING = 0 +FOUND_NORMAL = 1 +FOUND_LOOPED_BACK = 2 +FOUND_NEXT_FILE = 3 + + +class SearchParams: + def __init__(self, other=None): + if other is None: + self.__dict__["findText"] = "" + self.__dict__["replaceText"] = "" + self.__dict__["matchCase"] = 0 + self.__dict__["matchWords"] = 0 + self.__dict__["acrossFiles"] = 0 + self.__dict__["remember"] = 1 + self.__dict__["sel"] = (-1, -1) + self.__dict__["keepDialogOpen"] = 0 + else: + self.__dict__.update(other.__dict__) + + # Helper so we cant misspell attributes :-) + def __setattr__(self, attr, val): + if not hasattr(self, attr): + raise AttributeError(attr) + self.__dict__[attr] = val + + +curDialog = None +lastSearch = defaultSearch = SearchParams() +searchHistory = [] + + +def ShowFindDialog(): + _ShowDialog(FindDialog) + + +def ShowReplaceDialog(): + _ShowDialog(ReplaceDialog) + + +def _ShowDialog(dlgClass): + global curDialog + if curDialog is not None: + if curDialog.__class__ != dlgClass: + curDialog.DestroyWindow() + curDialog = None + else: + curDialog.SetFocus() + if curDialog is None: + curDialog = dlgClass() + curDialog.CreateWindow() + + +def FindNext(): + params = SearchParams(lastSearch) + params.sel = (-1, -1) + if not params.findText: + ShowFindDialog() + else: + return _FindIt(None, params) + + +def _GetControl(control=None): + if control is None: + control = scriptutils.GetActiveEditControl() + return control + + +def _FindIt(control, searchParams): + global lastSearch, defaultSearch + control = _GetControl(control) + if control is None: + return FOUND_NOTHING + + # Move to the next char, so we find the next one. + flags = 0 + if searchParams.matchWords: + flags = flags | win32con.FR_WHOLEWORD + if searchParams.matchCase: + flags = flags | win32con.FR_MATCHCASE + if searchParams.sel == (-1, -1): + sel = control.GetSel() + # If the position is the same as we found last time, + # then we assume it is a "FindNext" + if sel == lastSearch.sel: + sel = sel[0] + 1, sel[0] + 1 + else: + sel = searchParams.sel + + if sel[0] == sel[1]: + sel = sel[0], control.GetTextLength() + + rc = FOUND_NOTHING + # (Old edit control will fail here!) + posFind, foundSel = control.FindText(flags, sel, searchParams.findText) + lastSearch = SearchParams(searchParams) + if posFind >= 0: + rc = FOUND_NORMAL + lineno = control.LineFromChar(posFind) + control.SCIEnsureVisible(lineno) + control.SetSel(foundSel) + control.SetFocus() + win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE)) + if rc == FOUND_NOTHING and lastSearch.acrossFiles: + # Loop around all documents. First find this document. + try: + try: + doc = control.GetDocument() + except AttributeError: + try: + doc = control.GetParent().GetDocument() + except AttributeError: + print("Cant find a document for the control!") + doc = None + if doc is not None: + template = doc.GetDocTemplate() + alldocs = template.GetDocumentList() + mypos = lookpos = alldocs.index(doc) + while 1: + lookpos = (lookpos + 1) % len(alldocs) + if lookpos == mypos: + break + view = alldocs[lookpos].GetFirstView() + posFind, foundSel = view.FindText( + flags, (0, view.GetTextLength()), searchParams.findText + ) + if posFind >= 0: + nChars = foundSel[1] - foundSel[0] + lineNo = view.LineFromChar(posFind) # zero based. + lineStart = view.LineIndex(lineNo) + colNo = posFind - lineStart # zero based. + scriptutils.JumpToDocument( + alldocs[lookpos].GetPathName(), + lineNo + 1, + colNo + 1, + nChars, + ) + rc = FOUND_NEXT_FILE + break + except win32ui.error: + pass + if rc == FOUND_NOTHING: + # Loop around this control - attempt to find from the start of the control. + posFind, foundSel = control.FindText( + flags, (0, sel[0] - 1), searchParams.findText + ) + if posFind >= 0: + control.SCIEnsureVisible(control.LineFromChar(foundSel[0])) + control.SetSel(foundSel) + control.SetFocus() + win32ui.SetStatusText("Not found! Searching from the top of the file.") + rc = FOUND_LOOPED_BACK + else: + lastSearch.sel = -1, -1 + win32ui.SetStatusText("Can not find '%s'" % searchParams.findText) + + if rc != FOUND_NOTHING: + lastSearch.sel = foundSel + + if lastSearch.remember: + defaultSearch = lastSearch + + # track search history + try: + ix = searchHistory.index(searchParams.findText) + except ValueError: + if len(searchHistory) > 50: + searchHistory[50:] = [] + else: + del searchHistory[ix] + searchHistory.insert(0, searchParams.findText) + + return rc + + +def _ReplaceIt(control): + control = _GetControl(control) + statusText = "Can not find '%s'." % lastSearch.findText + rc = FOUND_NOTHING + if control is not None and lastSearch.sel != (-1, -1): + control.ReplaceSel(lastSearch.replaceText) + rc = FindNext() + if rc != FOUND_NOTHING: + statusText = win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE) + win32ui.SetStatusText(statusText) + return rc + + +class FindReplaceDialog(dialog.Dialog): + def __init__(self): + dialog.Dialog.__init__(self, self._GetDialogTemplate()) + self.HookCommand(self.OnFindNext, 109) + + def OnInitDialog(self): + self.editFindText = self.GetDlgItem(102) + self.butMatchWords = self.GetDlgItem(105) + self.butMatchCase = self.GetDlgItem(107) + self.butKeepDialogOpen = self.GetDlgItem(115) + self.butAcrossFiles = self.GetDlgItem(116) + self.butRemember = self.GetDlgItem(117) + + self.editFindText.SetWindowText(defaultSearch.findText) + control = _GetControl() + # _GetControl only gets normal MDI windows; if the interactive + # window is docked and no document open, we get None. + if control: + # If we have a selection, default to that. + sel = control.GetSelText() + if len(sel) != 0: + self.editFindText.SetWindowText(sel) + if defaultSearch.remember: + defaultSearch.findText = sel + for hist in searchHistory: + self.editFindText.AddString(hist) + + if hasattr(self.editFindText, "SetEditSel"): + self.editFindText.SetEditSel(0, -1) + else: + self.editFindText.SetSel(0, -1) + self.butMatchWords.SetCheck(defaultSearch.matchWords) + self.butMatchCase.SetCheck(defaultSearch.matchCase) + self.butKeepDialogOpen.SetCheck(defaultSearch.keepDialogOpen) + self.butAcrossFiles.SetCheck(defaultSearch.acrossFiles) + self.butRemember.SetCheck(defaultSearch.remember) + return dialog.Dialog.OnInitDialog(self) + + def OnDestroy(self, msg): + global curDialog + curDialog = None + return dialog.Dialog.OnDestroy(self, msg) + + def DoFindNext(self): + params = SearchParams() + params.findText = self.editFindText.GetWindowText() + params.matchCase = self.butMatchCase.GetCheck() + params.matchWords = self.butMatchWords.GetCheck() + params.acrossFiles = self.butAcrossFiles.GetCheck() + params.remember = self.butRemember.GetCheck() + return _FindIt(None, params) + + def OnFindNext(self, id, code): + if code != 0: # BN_CLICKED + # 3d controls (python.exe + start_pythonwin.pyw) send + # other notification codes + return 1 # + if not self.editFindText.GetWindowText(): + win32api.MessageBeep() + return 1 + if self.DoFindNext() != FOUND_NOTHING: + if not self.butKeepDialogOpen.GetCheck(): + self.DestroyWindow() + + +class FindDialog(FindReplaceDialog): + def _GetDialogTemplate(self): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + visible = win32con.WS_CHILD | win32con.WS_VISIBLE + dt = [ + ["Find", (0, 2, 240, 75), style, None, (8, "MS Sans Serif")], + ["Static", "Fi&nd What:", 101, (5, 8, 40, 10), visible], + [ + "ComboBox", + "", + 102, + (50, 7, 120, 120), + visible + | win32con.WS_BORDER + | win32con.WS_TABSTOP + | win32con.WS_VSCROLL + | win32con.CBS_DROPDOWN + | win32con.CBS_AUTOHSCROLL, + ], + [ + "Button", + "Match &whole word only", + 105, + (5, 23, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "Match &case", + 107, + (5, 33, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "Keep &dialog open", + 115, + (5, 43, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "Across &open files", + 116, + (5, 52, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "&Remember as default search", + 117, + (5, 61, 150, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "&Find Next", + 109, + (185, 5, 50, 14), + visible | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP, + ], + [ + "Button", + "Cancel", + win32con.IDCANCEL, + (185, 23, 50, 14), + visible | win32con.WS_TABSTOP, + ], + ] + return dt + + +class ReplaceDialog(FindReplaceDialog): + def _GetDialogTemplate(self): + style = ( + win32con.DS_MODALFRAME + | win32con.WS_POPUP + | win32con.WS_VISIBLE + | win32con.WS_CAPTION + | win32con.WS_SYSMENU + | win32con.DS_SETFONT + ) + visible = win32con.WS_CHILD | win32con.WS_VISIBLE + dt = [ + ["Replace", (0, 2, 240, 95), style, 0, (8, "MS Sans Serif")], + ["Static", "Fi&nd What:", 101, (5, 8, 40, 10), visible], + [ + "ComboBox", + "", + 102, + (60, 7, 110, 120), + visible + | win32con.WS_BORDER + | win32con.WS_TABSTOP + | win32con.WS_VSCROLL + | win32con.CBS_DROPDOWN + | win32con.CBS_AUTOHSCROLL, + ], + ["Static", "Re&place with:", 103, (5, 25, 50, 10), visible], + [ + "ComboBox", + "", + 104, + (60, 24, 110, 120), + visible + | win32con.WS_BORDER + | win32con.WS_TABSTOP + | win32con.WS_VSCROLL + | win32con.CBS_DROPDOWN + | win32con.CBS_AUTOHSCROLL, + ], + [ + "Button", + "Match &whole word only", + 105, + (5, 42, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "Match &case", + 107, + (5, 52, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "Keep &dialog open", + 115, + (5, 62, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "Across &open files", + 116, + (5, 72, 100, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "&Remember as default search", + 117, + (5, 81, 150, 10), + visible | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP, + ], + [ + "Button", + "&Find Next", + 109, + (185, 5, 50, 14), + visible | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP, + ], + [ + "Button", + "&Replace", + 110, + (185, 23, 50, 14), + visible | win32con.WS_TABSTOP, + ], + [ + "Button", + "Replace &All", + 111, + (185, 41, 50, 14), + visible | win32con.WS_TABSTOP, + ], + [ + "Button", + "Cancel", + win32con.IDCANCEL, + (185, 59, 50, 14), + visible | win32con.WS_TABSTOP, + ], + ] + return dt + + def OnInitDialog(self): + rc = FindReplaceDialog.OnInitDialog(self) + self.HookCommand(self.OnReplace, 110) + self.HookCommand(self.OnReplaceAll, 111) + self.HookMessage(self.OnActivate, win32con.WM_ACTIVATE) + self.editReplaceText = self.GetDlgItem(104) + self.editReplaceText.SetWindowText(lastSearch.replaceText) + if hasattr(self.editReplaceText, "SetEditSel"): + self.editReplaceText.SetEditSel(0, -1) + else: + self.editReplaceText.SetSel(0, -1) + self.butReplace = self.GetDlgItem(110) + self.butReplaceAll = self.GetDlgItem(111) + self.CheckButtonStates() + return rc # 0 when focus set + + def CheckButtonStates(self): + # We can do a "Replace" or "Replace All" if the current selection + # is the same as the search text. + ft = self.editFindText.GetWindowText() + control = _GetControl() + # bCanReplace = len(ft)>0 and control.GetSelText() == ft + bCanReplace = control is not None and lastSearch.sel == control.GetSel() + self.butReplace.EnableWindow(bCanReplace) + + # self.butReplaceAll.EnableWindow(bCanReplace) + + def OnActivate(self, msg): + wparam = msg[2] + fActive = win32api.LOWORD(wparam) + if fActive != win32con.WA_INACTIVE: + self.CheckButtonStates() + + def OnFindNext(self, id, code): + if code != 0: + return 1 + self.DoFindNext() + self.CheckButtonStates() + + def OnReplace(self, id, code): + if code != 0: + return 1 + lastSearch.replaceText = self.editReplaceText.GetWindowText() + _ReplaceIt(None) + + def OnReplaceAll(self, id, code): + if code != 0: + return 1 + control = _GetControl(None) + if control is not None: + control.SetSel(0) + num = 0 + if self.DoFindNext() == FOUND_NORMAL: + num = 1 + lastSearch.replaceText = self.editReplaceText.GetWindowText() + while _ReplaceIt(control) == FOUND_NORMAL: + num = num + 1 + + win32ui.SetStatusText("Replaced %d occurrences" % num) + if num > 0 and not self.butKeepDialogOpen.GetCheck(): + self.DestroyWindow() + + +if __name__ == "__main__": + ShowFindDialog() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/formatter.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/formatter.py new file mode 100644 index 0000000000000000000000000000000000000000..56100ccfcf52f6f8b7d7afa299e002a15756b887 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/formatter.py @@ -0,0 +1,695 @@ +# Does Python source formatting for Scintilla controls. +import array +import string + +import win32api +import win32con +import win32ui + +from . import scintillacon + +WM_KICKIDLE = 0x036A + +# Used to indicate that style should use default color +from win32con import CLR_INVALID + +debugging = 0 +if debugging: + # Output must go to another process else the result of + # the printing itself will trigger again trigger a trace. + + import win32trace + import win32traceutil + + def trace(*args): + win32trace.write(" ".join(map(str, args)) + "\n") + +else: + trace = lambda *args: None + + +class Style: + """Represents a single format""" + + def __init__(self, name, format, background=CLR_INVALID): + self.name = name # Name the format representes eg, "String", "Class" + # Default background for each style is only used when there are no + # saved settings (generally on first startup) + self.background = self.default_background = background + if type(format) == type(""): + self.aliased = format + self.format = None + else: + self.format = format + self.aliased = None + self.stylenum = None # Not yet registered. + + def IsBasedOnDefault(self): + return len(self.format) == 5 + + # If the currently extended font defintion matches the + # default format, restore the format to the "simple" format. + def NormalizeAgainstDefault(self, defaultFormat): + if self.IsBasedOnDefault(): + return 0 # No more to do, and not changed. + bIsDefault = ( + self.format[7] == defaultFormat[7] and self.format[2] == defaultFormat[2] + ) + if bIsDefault: + self.ForceAgainstDefault() + return bIsDefault + + def ForceAgainstDefault(self): + self.format = self.format[:5] + + def GetCompleteFormat(self, defaultFormat): + # Get the complete style after applying any relevant defaults. + if len(self.format) == 5: # It is a default one + fmt = self.format + defaultFormat[5:] + else: + fmt = self.format + flags = ( + win32con.CFM_BOLD + | win32con.CFM_CHARSET + | win32con.CFM_COLOR + | win32con.CFM_FACE + | win32con.CFM_ITALIC + | win32con.CFM_SIZE + ) + return (flags,) + fmt[1:] + + +# The Formatter interface +# used primarily when the actual formatting is done by Scintilla! +class FormatterBase: + def __init__(self, scintilla): + self.scintilla = scintilla + self.baseFormatFixed = (-402653169, 0, 200, 0, 0, 0, 49, "Courier New") + self.baseFormatProp = (-402653169, 0, 200, 0, 0, 0, 49, "Arial") + self.bUseFixed = 1 + self.styles = {} # Indexed by name + self.styles_by_id = {} # Indexed by allocated ID. + self.SetStyles() + + def HookFormatter(self, parent=None): + raise NotImplementedError() + + # Used by the IDLE extensions to quickly determine if a character is a string. + def GetStringStyle(self, pos): + try: + style = self.styles_by_id[self.scintilla.SCIGetStyleAt(pos)] + except KeyError: + # A style we dont know about - probably not even a .py file - can't be a string + return None + if style.name in self.string_style_names: + return style + return None + + def RegisterStyle(self, style, stylenum): + assert stylenum is not None, "We must have a style number" + assert style.stylenum is None, "Style has already been registered" + assert stylenum not in self.styles, "We are reusing a style number!" + style.stylenum = stylenum + self.styles[style.name] = style + self.styles_by_id[stylenum] = style + + def SetStyles(self): + raise NotImplementedError() + + def GetSampleText(self): + return "Sample Text for the Format Dialog" + + def GetDefaultFormat(self): + if self.bUseFixed: + return self.baseFormatFixed + return self.baseFormatProp + + # Update the control with the new style format. + def _ReformatStyle(self, style): + ## Selection (background only for now) + ## Passing False for WPARAM to SCI_SETSELBACK is documented as resetting to scintilla default, + ## but does not work - selection background is not visible at all. + ## Default value in SPECIAL_STYLES taken from scintilla source. + if style.name == STYLE_SELECTION: + clr = style.background + self.scintilla.SendScintilla(scintillacon.SCI_SETSELBACK, True, clr) + + ## Can't change font for selection, but could set color + ## However, the font color dropbox has no option for default, and thus would + ## always override syntax coloring + ## clr = style.format[4] + ## self.scintilla.SendScintilla(scintillacon.SCI_SETSELFORE, clr != CLR_INVALID, clr) + return + + assert style.stylenum is not None, "Unregistered style." + # print "Reformat style", style.name, style.stylenum + scintilla = self.scintilla + stylenum = style.stylenum + # Now we have the style number, indirect for the actual style. + if style.aliased is not None: + style = self.styles[style.aliased] + f = style.format + if style.IsBasedOnDefault(): + baseFormat = self.GetDefaultFormat() + else: + baseFormat = f + scintilla.SCIStyleSetFore(stylenum, f[4]) + scintilla.SCIStyleSetFont(stylenum, baseFormat[7], baseFormat[5]) + if f[1] & 1: + scintilla.SCIStyleSetBold(stylenum, 1) + else: + scintilla.SCIStyleSetBold(stylenum, 0) + if f[1] & 2: + scintilla.SCIStyleSetItalic(stylenum, 1) + else: + scintilla.SCIStyleSetItalic(stylenum, 0) + scintilla.SCIStyleSetSize(stylenum, int(baseFormat[2] / 20)) + scintilla.SCIStyleSetEOLFilled(stylenum, 1) # Only needed for unclosed strings. + + ## Default style background to whitespace background if set, + ## otherwise use system window color + bg = style.background + if bg == CLR_INVALID: + bg = self.styles[STYLE_DEFAULT].background + if bg == CLR_INVALID: + bg = win32api.GetSysColor(win32con.COLOR_WINDOW) + scintilla.SCIStyleSetBack(stylenum, bg) + + def GetStyleByNum(self, stylenum): + return self.styles_by_id[stylenum] + + def ApplyFormattingStyles(self, bReload=1): + if bReload: + self.LoadPreferences() + baseFormat = self.GetDefaultFormat() + defaultStyle = Style("default", baseFormat) + defaultStyle.stylenum = scintillacon.STYLE_DEFAULT + self._ReformatStyle(defaultStyle) + for style in list(self.styles.values()): + if style.aliased is None: + style.NormalizeAgainstDefault(baseFormat) + self._ReformatStyle(style) + self.scintilla.InvalidateRect() + + # Some functions for loading and saving preferences. By default + # an INI file (well, MFC maps this to the registry) is used. + def LoadPreferences(self): + self.baseFormatFixed = eval( + self.LoadPreference("Base Format Fixed", str(self.baseFormatFixed)) + ) + self.baseFormatProp = eval( + self.LoadPreference("Base Format Proportional", str(self.baseFormatProp)) + ) + self.bUseFixed = int(self.LoadPreference("Use Fixed", 1)) + + for style in list(self.styles.values()): + new = self.LoadPreference(style.name, str(style.format)) + try: + style.format = eval(new) + except: + print("Error loading style data for", style.name) + # Use "vanilla" background hardcoded in PYTHON_STYLES if no settings in registry + style.background = int( + self.LoadPreference( + style.name + " background", style.default_background + ) + ) + + def LoadPreference(self, name, default): + return win32ui.GetProfileVal("Format", name, default) + + def SavePreferences(self): + self.SavePreference("Base Format Fixed", str(self.baseFormatFixed)) + self.SavePreference("Base Format Proportional", str(self.baseFormatProp)) + self.SavePreference("Use Fixed", self.bUseFixed) + for style in list(self.styles.values()): + if style.aliased is None: + self.SavePreference(style.name, str(style.format)) + bg_name = style.name + " background" + self.SavePreference(bg_name, style.background) + + def SavePreference(self, name, value): + win32ui.WriteProfileVal("Format", name, value) + + +# An abstract formatter +# For all formatters we actually implement here. +# (as opposed to those formatters built in to Scintilla) +class Formatter(FormatterBase): + def __init__(self, scintilla): + self.bCompleteWhileIdle = 0 + self.bHaveIdleHandler = 0 # Dont currently have an idle handle + self.nextstylenum = 0 + FormatterBase.__init__(self, scintilla) + + def HookFormatter(self, parent=None): + if parent is None: + parent = self.scintilla.GetParent() # was GetParentFrame()!? + parent.HookNotify(self.OnStyleNeeded, scintillacon.SCN_STYLENEEDED) + + def OnStyleNeeded(self, std, extra): + notify = self.scintilla.SCIUnpackNotifyMessage(extra) + endStyledChar = self.scintilla.SendScintilla(scintillacon.SCI_GETENDSTYLED) + lineEndStyled = self.scintilla.LineFromChar(endStyledChar) + endStyled = self.scintilla.LineIndex(lineEndStyled) + # print "enPosPaint %d endStyledChar %d lineEndStyled %d endStyled %d" % (endPosPaint, endStyledChar, lineEndStyled, endStyled) + self.Colorize(endStyled, notify.position) + + def ColorSeg(self, start, end, styleName): + end = end + 1 + # assert end-start>=0, "Can't have negative styling" + stylenum = self.styles[styleName].stylenum + while start < end: + self.style_buffer[start] = stylenum + start = start + 1 + # self.scintilla.SCISetStyling(end - start + 1, stylenum) + + def RegisterStyle(self, style, stylenum=None): + if stylenum is None: + stylenum = self.nextstylenum + self.nextstylenum = self.nextstylenum + 1 + FormatterBase.RegisterStyle(self, style, stylenum) + + def ColorizeString(self, str, charStart, styleStart): + raise RuntimeError("You must override this method") + + def Colorize(self, start=0, end=-1): + scintilla = self.scintilla + # scintilla's formatting is all done in terms of utf, so + # we work with utf8 bytes instead of unicode. This magically + # works as any extended chars found in the utf8 don't change + # the semantics. + stringVal = scintilla.GetTextRange(start, end, decode=False) + if start > 0: + stylenum = scintilla.SCIGetStyleAt(start - 1) + styleStart = self.GetStyleByNum(stylenum).name + else: + styleStart = None + # trace("Coloring", start, end, end-start, len(stringVal), styleStart, self.scintilla.SCIGetCharAt(start)) + scintilla.SCIStartStyling(start, 31) + self.style_buffer = array.array("b", (0,) * len(stringVal)) + self.ColorizeString(stringVal, styleStart) + scintilla.SCISetStylingEx(self.style_buffer) + self.style_buffer = None + # trace("After styling, end styled is", self.scintilla.SCIGetEndStyled()) + if ( + self.bCompleteWhileIdle + and not self.bHaveIdleHandler + and end != -1 + and end < scintilla.GetTextLength() + ): + self.bHaveIdleHandler = 1 + win32ui.GetApp().AddIdleHandler(self.DoMoreColoring) + # Kicking idle makes the app seem slower when initially repainting! + + # win32ui.GetMainFrame().PostMessage(WM_KICKIDLE, 0, 0) + + def DoMoreColoring(self, handler, count): + try: + scintilla = self.scintilla + endStyled = scintilla.SCIGetEndStyled() + lineStartStyled = scintilla.LineFromChar(endStyled) + start = scintilla.LineIndex(lineStartStyled) + end = scintilla.LineIndex(lineStartStyled + 1) + textlen = scintilla.GetTextLength() + if end < 0: + end = textlen + + finished = end >= textlen + self.Colorize(start, end) + except (win32ui.error, AttributeError): + # Window may have closed before we finished - no big deal! + finished = 1 + + if finished: + self.bHaveIdleHandler = 0 + win32ui.GetApp().DeleteIdleHandler(handler) + return not finished + + +# A Formatter that knows how to format Python source +from keyword import iskeyword, kwlist + +wordstarts = "_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +wordchars = "._0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +operators = "%^&*()-+=|{}[]:;<>,/?!.~" + +STYLE_DEFAULT = "Whitespace" +STYLE_COMMENT = "Comment" +STYLE_COMMENT_BLOCK = "Comment Blocks" +STYLE_NUMBER = "Number" +STYLE_STRING = "String" +STYLE_SQSTRING = "SQ String" +STYLE_TQSSTRING = "TQS String" +STYLE_TQDSTRING = "TQD String" +STYLE_KEYWORD = "Keyword" +STYLE_CLASS = "Class" +STYLE_METHOD = "Method" +STYLE_OPERATOR = "Operator" +STYLE_IDENTIFIER = "Identifier" +STYLE_BRACE = "Brace/Paren - matching" +STYLE_BRACEBAD = "Brace/Paren - unmatched" +STYLE_STRINGEOL = "String with no terminator" +STYLE_LINENUMBER = "Line numbers" +STYLE_INDENTGUIDE = "Indent guide" +STYLE_SELECTION = "Selection" + +STRING_STYLES = [ + STYLE_STRING, + STYLE_SQSTRING, + STYLE_TQSSTRING, + STYLE_TQDSTRING, + STYLE_STRINGEOL, +] + +# These styles can have any ID - they are not special to scintilla itself. +# However, if we use the built-in lexer, then we must use its style numbers +# so in that case, they _are_ special. +# (name, format, background, scintilla id) +PYTHON_STYLES = [ + (STYLE_DEFAULT, (0, 0, 200, 0, 0x808080), CLR_INVALID, scintillacon.SCE_P_DEFAULT), + ( + STYLE_COMMENT, + (0, 2, 200, 0, 0x008000), + CLR_INVALID, + scintillacon.SCE_P_COMMENTLINE, + ), + ( + STYLE_COMMENT_BLOCK, + (0, 2, 200, 0, 0x808080), + CLR_INVALID, + scintillacon.SCE_P_COMMENTBLOCK, + ), + (STYLE_NUMBER, (0, 0, 200, 0, 0x808000), CLR_INVALID, scintillacon.SCE_P_NUMBER), + (STYLE_STRING, (0, 0, 200, 0, 0x008080), CLR_INVALID, scintillacon.SCE_P_STRING), + (STYLE_SQSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_CHARACTER), + (STYLE_TQSSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_TRIPLE), + (STYLE_TQDSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_TRIPLEDOUBLE), + (STYLE_STRINGEOL, (0, 0, 200, 0, 0x000000), 0x008080, scintillacon.SCE_P_STRINGEOL), + (STYLE_KEYWORD, (0, 1, 200, 0, 0x800000), CLR_INVALID, scintillacon.SCE_P_WORD), + (STYLE_CLASS, (0, 1, 200, 0, 0xFF0000), CLR_INVALID, scintillacon.SCE_P_CLASSNAME), + (STYLE_METHOD, (0, 1, 200, 0, 0x808000), CLR_INVALID, scintillacon.SCE_P_DEFNAME), + ( + STYLE_OPERATOR, + (0, 0, 200, 0, 0x000000), + CLR_INVALID, + scintillacon.SCE_P_OPERATOR, + ), + ( + STYLE_IDENTIFIER, + (0, 0, 200, 0, 0x000000), + CLR_INVALID, + scintillacon.SCE_P_IDENTIFIER, + ), +] + +# These styles _always_ have this specific style number, regardless of +# internal or external formatter. +SPECIAL_STYLES = [ + (STYLE_BRACE, (0, 0, 200, 0, 0x000000), 0xFFFF80, scintillacon.STYLE_BRACELIGHT), + (STYLE_BRACEBAD, (0, 0, 200, 0, 0x000000), 0x8EA5F2, scintillacon.STYLE_BRACEBAD), + ( + STYLE_LINENUMBER, + (0, 0, 200, 0, 0x000000), + win32api.GetSysColor(win32con.COLOR_3DFACE), + scintillacon.STYLE_LINENUMBER, + ), + ( + STYLE_INDENTGUIDE, + (0, 0, 200, 0, 0x000000), + CLR_INVALID, + scintillacon.STYLE_INDENTGUIDE, + ), + ## Not actually a style; requires special handling to send appropriate messages to scintilla + ( + STYLE_SELECTION, + (0, 0, 200, 0, CLR_INVALID), + win32api.RGB(0xC0, 0xC0, 0xC0), + 999999, + ), +] + +PythonSampleCode = """\ +# Some Python +class Sample(Super): + def Fn(self): +\tself.v = 1024 +dest = 'dest.html' +x = func(a + 1)|) +s = "I forget... +## A large +## comment block""" + + +class PythonSourceFormatter(Formatter): + string_style_names = STRING_STYLES + + def GetSampleText(self): + return PythonSampleCode + + def LoadStyles(self): + pass + + def SetStyles(self): + for name, format, bg, ignore in PYTHON_STYLES: + self.RegisterStyle(Style(name, format, bg)) + for name, format, bg, sc_id in SPECIAL_STYLES: + self.RegisterStyle(Style(name, format, bg), sc_id) + + def ClassifyWord(self, cdoc, start, end, prevWord): + word = cdoc[start : end + 1].decode("latin-1") + attr = STYLE_IDENTIFIER + if prevWord == "class": + attr = STYLE_CLASS + elif prevWord == "def": + attr = STYLE_METHOD + elif word[0] in string.digits: + attr = STYLE_NUMBER + elif iskeyword(word): + attr = STYLE_KEYWORD + self.ColorSeg(start, end, attr) + return word + + def ColorizeString(self, str, styleStart): + if styleStart is None: + styleStart = STYLE_DEFAULT + return self.ColorizePythonCode(str, 0, styleStart) + + def ColorizePythonCode(self, cdoc, charStart, styleStart): + # Straight translation of C++, should do better + lengthDoc = len(cdoc) + if lengthDoc <= charStart: + return + prevWord = "" + state = styleStart + chPrev = chPrev2 = chPrev3 = " " + chNext2 = chNext = cdoc[charStart : charStart + 1].decode("latin-1") + startSeg = i = charStart + while i < lengthDoc: + ch = chNext + chNext = " " + if i + 1 < lengthDoc: + chNext = cdoc[i + 1 : i + 2].decode("latin-1") + chNext2 = " " + if i + 2 < lengthDoc: + chNext2 = cdoc[i + 2 : i + 3].decode("latin-1") + if state == STYLE_DEFAULT: + if ch in wordstarts: + self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT) + state = STYLE_KEYWORD + startSeg = i + elif ch == "#": + self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT) + if chNext == "#": + state = STYLE_COMMENT_BLOCK + else: + state = STYLE_COMMENT + startSeg = i + elif ch == '"': + self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT) + startSeg = i + state = STYLE_COMMENT + if chNext == '"' and chNext2 == '"': + i = i + 2 + state = STYLE_TQDSTRING + ch = " " + chPrev = " " + chNext = " " + if i + 1 < lengthDoc: + chNext = cdoc[i + 1] + else: + state = STYLE_STRING + elif ch == "'": + self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT) + startSeg = i + state = STYLE_COMMENT + if chNext == "'" and chNext2 == "'": + i = i + 2 + state = STYLE_TQSSTRING + ch = " " + chPrev = " " + chNext = " " + if i + 1 < lengthDoc: + chNext = cdoc[i + 1] + else: + state = STYLE_SQSTRING + elif ch in operators: + self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT) + self.ColorSeg(i, i, STYLE_OPERATOR) + startSeg = i + 1 + elif state == STYLE_KEYWORD: + if ch not in wordchars: + prevWord = self.ClassifyWord(cdoc, startSeg, i - 1, prevWord) + state = STYLE_DEFAULT + startSeg = i + if ch == "#": + if chNext == "#": + state = STYLE_COMMENT_BLOCK + else: + state = STYLE_COMMENT + elif ch == '"': + if chNext == '"' and chNext2 == '"': + i = i + 2 + state = STYLE_TQDSTRING + ch = " " + chPrev = " " + chNext = " " + if i + 1 < lengthDoc: + chNext = cdoc[i + 1] + else: + state = STYLE_STRING + elif ch == "'": + if chNext == "'" and chNext2 == "'": + i = i + 2 + state = STYLE_TQSSTRING + ch = " " + chPrev = " " + chNext = " " + if i + 1 < lengthDoc: + chNext = cdoc[i + 1] + else: + state = STYLE_SQSTRING + elif ch in operators: + self.ColorSeg(startSeg, i, STYLE_OPERATOR) + startSeg = i + 1 + elif state == STYLE_COMMENT or state == STYLE_COMMENT_BLOCK: + if ch == "\r" or ch == "\n": + self.ColorSeg(startSeg, i - 1, state) + state = STYLE_DEFAULT + startSeg = i + elif state == STYLE_STRING: + if ch == "\\": + if chNext == '"' or chNext == "'" or chNext == "\\": + i = i + 1 + ch = chNext + chNext = " " + if i + 1 < lengthDoc: + chNext = cdoc[i + 1] + elif ch == '"': + self.ColorSeg(startSeg, i, STYLE_STRING) + state = STYLE_DEFAULT + startSeg = i + 1 + elif state == STYLE_SQSTRING: + if ch == "\\": + if chNext == '"' or chNext == "'" or chNext == "\\": + i = i + 1 + ch = chNext + chNext = " " + if i + 1 < lengthDoc: + chNext = cdoc[i + 1] + elif ch == "'": + self.ColorSeg(startSeg, i, STYLE_SQSTRING) + state = STYLE_DEFAULT + startSeg = i + 1 + elif state == STYLE_TQSSTRING: + if ch == "'" and chPrev == "'" and chPrev2 == "'" and chPrev3 != "\\": + self.ColorSeg(startSeg, i, STYLE_TQSSTRING) + state = STYLE_DEFAULT + startSeg = i + 1 + elif ( + state == STYLE_TQDSTRING + and ch == '"' + and chPrev == '"' + and chPrev2 == '"' + and chPrev3 != "\\" + ): + self.ColorSeg(startSeg, i, STYLE_TQDSTRING) + state = STYLE_DEFAULT + startSeg = i + 1 + chPrev3 = chPrev2 + chPrev2 = chPrev + chPrev = ch + i = i + 1 + if startSeg < lengthDoc: + if state == STYLE_KEYWORD: + self.ClassifyWord(cdoc, startSeg, lengthDoc - 1, prevWord) + else: + self.ColorSeg(startSeg, lengthDoc - 1, state) + + +# These taken from the SciTE properties file. +source_formatter_extensions = [ + (".py .pys .pyw".split(), scintillacon.SCLEX_PYTHON), + (".html .htm .asp .shtml".split(), scintillacon.SCLEX_HTML), + ( + "c .cc .cpp .cxx .h .hh .hpp .hxx .idl .odl .php3 .phtml .inc .js".split(), + scintillacon.SCLEX_CPP, + ), + (".vbs .frm .ctl .cls".split(), scintillacon.SCLEX_VB), + (".pl .pm .cgi .pod".split(), scintillacon.SCLEX_PERL), + (".sql .spec .body .sps .spb .sf .sp".split(), scintillacon.SCLEX_SQL), + (".tex .sty".split(), scintillacon.SCLEX_LATEX), + (".xml .xul".split(), scintillacon.SCLEX_XML), + (".err".split(), scintillacon.SCLEX_ERRORLIST), + (".mak".split(), scintillacon.SCLEX_MAKEFILE), + (".bat .cmd".split(), scintillacon.SCLEX_BATCH), +] + + +class BuiltinSourceFormatter(FormatterBase): + # A class that represents a formatter built-in to Scintilla + def __init__(self, scintilla, ext): + self.ext = ext + FormatterBase.__init__(self, scintilla) + + def Colorize(self, start=0, end=-1): + self.scintilla.SendScintilla(scintillacon.SCI_COLOURISE, start, end) + + def RegisterStyle(self, style, stylenum=None): + assert style.stylenum is None, "Style has already been registered" + if stylenum is None: + stylenum = self.nextstylenum + self.nextstylenum = self.nextstylenum + 1 + assert self.styles.get(stylenum) is None, "We are reusing a style number!" + style.stylenum = stylenum + self.styles[style.name] = style + self.styles_by_id[stylenum] = style + + def HookFormatter(self, parent=None): + sc = self.scintilla + for exts, formatter in source_formatter_extensions: + if self.ext in exts: + formatter_use = formatter + break + else: + formatter_use = scintillacon.SCLEX_PYTHON + sc.SendScintilla(scintillacon.SCI_SETLEXER, formatter_use) + keywords = " ".join(kwlist) + sc.SCISetKeywords(keywords) + + +class BuiltinPythonSourceFormatter(BuiltinSourceFormatter): + sci_lexer_name = scintillacon.SCLEX_PYTHON + string_style_names = STRING_STYLES + + def __init__(self, sc, ext=".py"): + BuiltinSourceFormatter.__init__(self, sc, ext) + + def SetStyles(self): + for name, format, bg, sc_id in PYTHON_STYLES: + self.RegisterStyle(Style(name, format, bg), sc_id) + for name, format, bg, sc_id in SPECIAL_STYLES: + self.RegisterStyle(Style(name, format, bg), sc_id) + + def GetSampleText(self): + return PythonSampleCode diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/keycodes.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/keycodes.py new file mode 100644 index 0000000000000000000000000000000000000000..badcef3e70544fd9bd3bfdb6e0e627d318592573 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/keycodes.py @@ -0,0 +1,190 @@ +import win32api +import win32con +import win32ui + +MAPVK_VK_TO_CHAR = 2 + +key_name_to_vk = {} +key_code_to_name = {} + +_better_names = { + "escape": "esc", + "return": "enter", + "back": "pgup", + "next": "pgdn", +} + + +def _fillvkmap(): + # Pull the VK_names from win32con + names = [entry for entry in win32con.__dict__ if entry.startswith("VK_")] + for name in names: + code = getattr(win32con, name) + n = name[3:].lower() + key_name_to_vk[n] = code + if n in _better_names: + n = _better_names[n] + key_name_to_vk[n] = code + key_code_to_name[code] = n + + +_fillvkmap() + + +def get_vk(chardesc): + if len(chardesc) == 1: + # it is a character. + info = win32api.VkKeyScan(chardesc) + if info == -1: + # Note: returning None, None causes an error when keyboard layout is non-English, see the report below + # https://stackoverflow.com/questions/45138084/pythonwin-occasionally-gives-an-error-on-opening + return 0, 0 + vk = win32api.LOBYTE(info) + state = win32api.HIBYTE(info) + modifiers = 0 + if state & 0x1: + modifiers |= win32con.SHIFT_PRESSED + if state & 0x2: + modifiers |= win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED + if state & 0x4: + modifiers |= win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED + return vk, modifiers + # must be a 'key name' + return key_name_to_vk.get(chardesc.lower()), 0 + + +modifiers = { + "alt": win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED, + "lalt": win32con.LEFT_ALT_PRESSED, + "ralt": win32con.RIGHT_ALT_PRESSED, + "ctrl": win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED, + "ctl": win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED, + "control": win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED, + "lctrl": win32con.LEFT_CTRL_PRESSED, + "lctl": win32con.LEFT_CTRL_PRESSED, + "rctrl": win32con.RIGHT_CTRL_PRESSED, + "rctl": win32con.RIGHT_CTRL_PRESSED, + "shift": win32con.SHIFT_PRESSED, + "key": 0, # ignore key tag. +} + + +def parse_key_name(name): + name = name + "-" # Add a sentinal + start = pos = 0 + max = len(name) + toks = [] + while pos < max: + if name[pos] in "+-": + tok = name[start:pos] + # use the ascii lower() version of tok, so ascii chars require + # an explicit shift modifier - ie 'Ctrl+G' should be treated as + # 'ctrl+g' - 'ctrl+shift+g' would be needed if desired. + # This is mainly to avoid changing all the old keystroke defs + toks.append(tok.lower()) + pos += 1 # skip the sep + start = pos + pos += 1 + flags = 0 + # do the modifiers + for tok in toks[:-1]: + mod = modifiers.get(tok.lower()) + if mod is not None: + flags |= mod + # the key name + vk, this_flags = get_vk(toks[-1]) + return vk, flags | this_flags + + +_checks = [ + [ # Shift + ("Shift", win32con.SHIFT_PRESSED), + ], + [ # Ctrl key + ("Ctrl", win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED), + ("LCtrl", win32con.LEFT_CTRL_PRESSED), + ("RCtrl", win32con.RIGHT_CTRL_PRESSED), + ], + [ # Alt key + ("Alt", win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED), + ("LAlt", win32con.LEFT_ALT_PRESSED), + ("RAlt", win32con.RIGHT_ALT_PRESSED), + ], +] + + +def make_key_name(vk, flags): + # Check alt keys. + flags_done = 0 + parts = [] + for moddata in _checks: + for name, checkflag in moddata: + if flags & checkflag: + parts.append(name) + flags_done = flags_done & checkflag + break + if flags_done & flags: + parts.append(hex(flags & ~flags_done)) + # Now the key name. + if vk is None: + parts.append("") + else: + try: + parts.append(key_code_to_name[vk]) + except KeyError: + # Not in our virtual key map - ask Windows what character this + # key corresponds to. + scancode = win32api.MapVirtualKey(vk, MAPVK_VK_TO_CHAR) + parts.append(chr(scancode)) + sep = "+" + if sep in parts: + sep = "-" + return sep.join([p.capitalize() for p in parts]) + + +def _psc(char): + sc, mods = get_vk(char) + print("Char %s -> %d -> %s" % (repr(char), sc, key_code_to_name.get(sc))) + + +def test1(): + for ch in """aA0/?[{}];:'"`~_-+=\\|,<.>/?""": + _psc(ch) + for code in ["Home", "End", "Left", "Right", "Up", "Down", "Menu", "Next"]: + _psc(code) + + +def _pkn(n): + vk, flags = parse_key_name(n) + print("%s -> %s,%s -> %s" % (n, vk, flags, make_key_name(vk, flags))) + + +def test2(): + _pkn("ctrl+alt-shift+x") + _pkn("ctrl-home") + _pkn("Shift-+") + _pkn("Shift--") + _pkn("Shift+-") + _pkn("Shift++") + _pkn("LShift-+") + _pkn("ctl+home") + _pkn("ctl+enter") + _pkn("alt+return") + _pkn("Alt+/") + _pkn("Alt+BadKeyName") + _pkn("A") # an ascii char - should be seen as 'a' + _pkn("a") + _pkn("Shift-A") + _pkn("Shift-a") + _pkn("a") + _pkn("(") + _pkn("Ctrl+(") + _pkn("Ctrl+Shift-8") + _pkn("Ctrl+*") + _pkn("{") + _pkn("!") + _pkn(".") + + +if __name__ == "__main__": + test2() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/scintillacon.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/scintillacon.py new file mode 100644 index 0000000000000000000000000000000000000000..e7657dc77098655ab885dd68239b2ba3c3513f49 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/scintillacon.py @@ -0,0 +1,2001 @@ +# Generated by h2py from Include\scintilla.h + + +# Included from BaseTsd.h +def HandleToUlong(h): + return HandleToULong(h) + + +def UlongToHandle(ul): + return ULongToHandle(ul) + + +def UlongToPtr(ul): + return ULongToPtr(ul) + + +def UintToPtr(ui): + return UIntToPtr(ui) + + +INVALID_POSITION = -1 +SCI_START = 2000 +SCI_OPTIONAL_START = 3000 +SCI_LEXER_START = 4000 +SCI_ADDTEXT = 2001 +SCI_ADDSTYLEDTEXT = 2002 +SCI_INSERTTEXT = 2003 +SCI_CLEARALL = 2004 +SCI_CLEARDOCUMENTSTYLE = 2005 +SCI_GETLENGTH = 2006 +SCI_GETCHARAT = 2007 +SCI_GETCURRENTPOS = 2008 +SCI_GETANCHOR = 2009 +SCI_GETSTYLEAT = 2010 +SCI_REDO = 2011 +SCI_SETUNDOCOLLECTION = 2012 +SCI_SELECTALL = 2013 +SCI_SETSAVEPOINT = 2014 +SCI_GETSTYLEDTEXT = 2015 +SCI_CANREDO = 2016 +SCI_MARKERLINEFROMHANDLE = 2017 +SCI_MARKERDELETEHANDLE = 2018 +SCI_GETUNDOCOLLECTION = 2019 +SCWS_INVISIBLE = 0 +SCWS_VISIBLEALWAYS = 1 +SCWS_VISIBLEAFTERINDENT = 2 +SCI_GETVIEWWS = 2020 +SCI_SETVIEWWS = 2021 +SCI_POSITIONFROMPOINT = 2022 +SCI_POSITIONFROMPOINTCLOSE = 2023 +SCI_GOTOLINE = 2024 +SCI_GOTOPOS = 2025 +SCI_SETANCHOR = 2026 +SCI_GETCURLINE = 2027 +SCI_GETENDSTYLED = 2028 +SC_EOL_CRLF = 0 +SC_EOL_CR = 1 +SC_EOL_LF = 2 +SCI_CONVERTEOLS = 2029 +SCI_GETEOLMODE = 2030 +SCI_SETEOLMODE = 2031 +SCI_STARTSTYLING = 2032 +SCI_SETSTYLING = 2033 +SCI_GETBUFFEREDDRAW = 2034 +SCI_SETBUFFEREDDRAW = 2035 +SCI_SETTABWIDTH = 2036 +SCI_GETTABWIDTH = 2121 +SC_CP_UTF8 = 65001 +SC_CP_DBCS = 1 +SCI_SETCODEPAGE = 2037 +SCI_SETUSEPALETTE = 2039 +MARKER_MAX = 31 +SC_MARK_CIRCLE = 0 +SC_MARK_ROUNDRECT = 1 +SC_MARK_ARROW = 2 +SC_MARK_SMALLRECT = 3 +SC_MARK_SHORTARROW = 4 +SC_MARK_EMPTY = 5 +SC_MARK_ARROWDOWN = 6 +SC_MARK_MINUS = 7 +SC_MARK_PLUS = 8 +SC_MARK_VLINE = 9 +SC_MARK_LCORNER = 10 +SC_MARK_TCORNER = 11 +SC_MARK_BOXPLUS = 12 +SC_MARK_BOXPLUSCONNECTED = 13 +SC_MARK_BOXMINUS = 14 +SC_MARK_BOXMINUSCONNECTED = 15 +SC_MARK_LCORNERCURVE = 16 +SC_MARK_TCORNERCURVE = 17 +SC_MARK_CIRCLEPLUS = 18 +SC_MARK_CIRCLEPLUSCONNECTED = 19 +SC_MARK_CIRCLEMINUS = 20 +SC_MARK_CIRCLEMINUSCONNECTED = 21 +SC_MARK_BACKGROUND = 22 +SC_MARK_DOTDOTDOT = 23 +SC_MARK_ARROWS = 24 +SC_MARK_PIXMAP = 25 +SC_MARK_FULLRECT = 26 +SC_MARK_LEFTRECT = 27 +SC_MARK_CHARACTER = 10000 +SC_MARKNUM_FOLDEREND = 25 +SC_MARKNUM_FOLDEROPENMID = 26 +SC_MARKNUM_FOLDERMIDTAIL = 27 +SC_MARKNUM_FOLDERTAIL = 28 +SC_MARKNUM_FOLDERSUB = 29 +SC_MARKNUM_FOLDER = 30 +SC_MARKNUM_FOLDEROPEN = 31 +SC_MASK_FOLDERS = -33554432 +SCI_MARKERDEFINE = 2040 +SCI_MARKERSETFORE = 2041 +SCI_MARKERSETBACK = 2042 +SCI_MARKERADD = 2043 +SCI_MARKERDELETE = 2044 +SCI_MARKERDELETEALL = 2045 +SCI_MARKERGET = 2046 +SCI_MARKERNEXT = 2047 +SCI_MARKERPREVIOUS = 2048 +SCI_MARKERDEFINEPIXMAP = 2049 +SCI_MARKERADDSET = 2466 +SCI_MARKERSETALPHA = 2476 +SC_MARGIN_SYMBOL = 0 +SC_MARGIN_NUMBER = 1 +SC_MARGIN_BACK = 2 +SC_MARGIN_FORE = 3 +SCI_SETMARGINTYPEN = 2240 +SCI_GETMARGINTYPEN = 2241 +SCI_SETMARGINWIDTHN = 2242 +SCI_GETMARGINWIDTHN = 2243 +SCI_SETMARGINMASKN = 2244 +SCI_GETMARGINMASKN = 2245 +SCI_SETMARGINSENSITIVEN = 2246 +SCI_GETMARGINSENSITIVEN = 2247 +STYLE_DEFAULT = 32 +STYLE_LINENUMBER = 33 +STYLE_BRACELIGHT = 34 +STYLE_BRACEBAD = 35 +STYLE_CONTROLCHAR = 36 +STYLE_INDENTGUIDE = 37 +STYLE_CALLTIP = 38 +STYLE_LASTPREDEFINED = 39 +STYLE_MAX = 255 +SC_CHARSET_ANSI = 0 +SC_CHARSET_DEFAULT = 1 +SC_CHARSET_BALTIC = 186 +SC_CHARSET_CHINESEBIG5 = 136 +SC_CHARSET_EASTEUROPE = 238 +SC_CHARSET_GB2312 = 134 +SC_CHARSET_GREEK = 161 +SC_CHARSET_HANGUL = 129 +SC_CHARSET_MAC = 77 +SC_CHARSET_OEM = 255 +SC_CHARSET_RUSSIAN = 204 +SC_CHARSET_CYRILLIC = 1251 +SC_CHARSET_SHIFTJIS = 128 +SC_CHARSET_SYMBOL = 2 +SC_CHARSET_TURKISH = 162 +SC_CHARSET_JOHAB = 130 +SC_CHARSET_HEBREW = 177 +SC_CHARSET_ARABIC = 178 +SC_CHARSET_VIETNAMESE = 163 +SC_CHARSET_THAI = 222 +SC_CHARSET_8859_15 = 1000 +SCI_STYLECLEARALL = 2050 +SCI_STYLESETFORE = 2051 +SCI_STYLESETBACK = 2052 +SCI_STYLESETBOLD = 2053 +SCI_STYLESETITALIC = 2054 +SCI_STYLESETSIZE = 2055 +SCI_STYLESETFONT = 2056 +SCI_STYLESETEOLFILLED = 2057 +SCI_STYLERESETDEFAULT = 2058 +SCI_STYLESETUNDERLINE = 2059 +SC_CASE_MIXED = 0 +SC_CASE_UPPER = 1 +SC_CASE_LOWER = 2 +SCI_STYLEGETFORE = 2481 +SCI_STYLEGETBACK = 2482 +SCI_STYLEGETBOLD = 2483 +SCI_STYLEGETITALIC = 2484 +SCI_STYLEGETSIZE = 2485 +SCI_STYLEGETFONT = 2486 +SCI_STYLEGETEOLFILLED = 2487 +SCI_STYLEGETUNDERLINE = 2488 +SCI_STYLEGETCASE = 2489 +SCI_STYLEGETCHARACTERSET = 2490 +SCI_STYLEGETVISIBLE = 2491 +SCI_STYLEGETCHANGEABLE = 2492 +SCI_STYLEGETHOTSPOT = 2493 +SCI_STYLESETCASE = 2060 +SCI_STYLESETCHARACTERSET = 2066 +SCI_STYLESETHOTSPOT = 2409 +SCI_SETSELFORE = 2067 +SCI_SETSELBACK = 2068 +SCI_GETSELALPHA = 2477 +SCI_SETSELALPHA = 2478 +SCI_GETSELEOLFILLED = 2479 +SCI_SETSELEOLFILLED = 2480 +SCI_SETCARETFORE = 2069 +SCI_ASSIGNCMDKEY = 2070 +SCI_CLEARCMDKEY = 2071 +SCI_CLEARALLCMDKEYS = 2072 +SCI_SETSTYLINGEX = 2073 +SCI_STYLESETVISIBLE = 2074 +SCI_GETCARETPERIOD = 2075 +SCI_SETCARETPERIOD = 2076 +SCI_SETWORDCHARS = 2077 +SCI_BEGINUNDOACTION = 2078 +SCI_ENDUNDOACTION = 2079 +INDIC_PLAIN = 0 +INDIC_SQUIGGLE = 1 +INDIC_TT = 2 +INDIC_DIAGONAL = 3 +INDIC_STRIKE = 4 +INDIC_HIDDEN = 5 +INDIC_BOX = 6 +INDIC_ROUNDBOX = 7 +INDIC_MAX = 31 +INDIC_CONTAINER = 8 +INDIC0_MASK = 0x20 +INDIC1_MASK = 0x40 +INDIC2_MASK = 0x80 +INDICS_MASK = 0xE0 +SCI_INDICSETSTYLE = 2080 +SCI_INDICGETSTYLE = 2081 +SCI_INDICSETFORE = 2082 +SCI_INDICGETFORE = 2083 +SCI_INDICSETUNDER = 2510 +SCI_INDICGETUNDER = 2511 +SCI_SETWHITESPACEFORE = 2084 +SCI_SETWHITESPACEBACK = 2085 +SCI_SETSTYLEBITS = 2090 +SCI_GETSTYLEBITS = 2091 +SCI_SETLINESTATE = 2092 +SCI_GETLINESTATE = 2093 +SCI_GETMAXLINESTATE = 2094 +SCI_GETCARETLINEVISIBLE = 2095 +SCI_SETCARETLINEVISIBLE = 2096 +SCI_GETCARETLINEBACK = 2097 +SCI_SETCARETLINEBACK = 2098 +SCI_STYLESETCHANGEABLE = 2099 +SCI_AUTOCSHOW = 2100 +SCI_AUTOCCANCEL = 2101 +SCI_AUTOCACTIVE = 2102 +SCI_AUTOCPOSSTART = 2103 +SCI_AUTOCCOMPLETE = 2104 +SCI_AUTOCSTOPS = 2105 +SCI_AUTOCSETSEPARATOR = 2106 +SCI_AUTOCGETSEPARATOR = 2107 +SCI_AUTOCSELECT = 2108 +SCI_AUTOCSETCANCELATSTART = 2110 +SCI_AUTOCGETCANCELATSTART = 2111 +SCI_AUTOCSETFILLUPS = 2112 +SCI_AUTOCSETCHOOSESINGLE = 2113 +SCI_AUTOCGETCHOOSESINGLE = 2114 +SCI_AUTOCSETIGNORECASE = 2115 +SCI_AUTOCGETIGNORECASE = 2116 +SCI_USERLISTSHOW = 2117 +SCI_AUTOCSETAUTOHIDE = 2118 +SCI_AUTOCGETAUTOHIDE = 2119 +SCI_AUTOCSETDROPRESTOFWORD = 2270 +SCI_AUTOCGETDROPRESTOFWORD = 2271 +SCI_REGISTERIMAGE = 2405 +SCI_CLEARREGISTEREDIMAGES = 2408 +SCI_AUTOCGETTYPESEPARATOR = 2285 +SCI_AUTOCSETTYPESEPARATOR = 2286 +SCI_AUTOCSETMAXWIDTH = 2208 +SCI_AUTOCGETMAXWIDTH = 2209 +SCI_AUTOCSETMAXHEIGHT = 2210 +SCI_AUTOCGETMAXHEIGHT = 2211 +SCI_SETINDENT = 2122 +SCI_GETINDENT = 2123 +SCI_SETUSETABS = 2124 +SCI_GETUSETABS = 2125 +SCI_SETLINEINDENTATION = 2126 +SCI_GETLINEINDENTATION = 2127 +SCI_GETLINEINDENTPOSITION = 2128 +SCI_GETCOLUMN = 2129 +SCI_SETHSCROLLBAR = 2130 +SCI_GETHSCROLLBAR = 2131 +SC_IV_NONE = 0 +SC_IV_REAL = 1 +SC_IV_LOOKFORWARD = 2 +SC_IV_LOOKBOTH = 3 +SCI_SETINDENTATIONGUIDES = 2132 +SCI_GETINDENTATIONGUIDES = 2133 +SCI_SETHIGHLIGHTGUIDE = 2134 +SCI_GETHIGHLIGHTGUIDE = 2135 +SCI_GETLINEENDPOSITION = 2136 +SCI_GETCODEPAGE = 2137 +SCI_GETCARETFORE = 2138 +SCI_GETUSEPALETTE = 2139 +SCI_GETREADONLY = 2140 +SCI_SETCURRENTPOS = 2141 +SCI_SETSELECTIONSTART = 2142 +SCI_GETSELECTIONSTART = 2143 +SCI_SETSELECTIONEND = 2144 +SCI_GETSELECTIONEND = 2145 +SCI_SETPRINTMAGNIFICATION = 2146 +SCI_GETPRINTMAGNIFICATION = 2147 +SC_PRINT_NORMAL = 0 +SC_PRINT_INVERTLIGHT = 1 +SC_PRINT_BLACKONWHITE = 2 +SC_PRINT_COLOURONWHITE = 3 +SC_PRINT_COLOURONWHITEDEFAULTBG = 4 +SCI_SETPRINTCOLOURMODE = 2148 +SCI_GETPRINTCOLOURMODE = 2149 +SCFIND_WHOLEWORD = 2 +SCFIND_MATCHCASE = 4 +SCFIND_WORDSTART = 0x00100000 +SCFIND_REGEXP = 0x00200000 +SCFIND_POSIX = 0x00400000 +SCI_FINDTEXT = 2150 +SCI_FORMATRANGE = 2151 +SCI_GETFIRSTVISIBLELINE = 2152 +SCI_GETLINE = 2153 +SCI_GETLINECOUNT = 2154 +SCI_SETMARGINLEFT = 2155 +SCI_GETMARGINLEFT = 2156 +SCI_SETMARGINRIGHT = 2157 +SCI_GETMARGINRIGHT = 2158 +SCI_GETMODIFY = 2159 +SCI_SETSEL = 2160 +SCI_GETSELTEXT = 2161 +SCI_GETTEXTRANGE = 2162 +SCI_HIDESELECTION = 2163 +SCI_POINTXFROMPOSITION = 2164 +SCI_POINTYFROMPOSITION = 2165 +SCI_LINEFROMPOSITION = 2166 +SCI_POSITIONFROMLINE = 2167 +SCI_LINESCROLL = 2168 +SCI_SCROLLCARET = 2169 +SCI_REPLACESEL = 2170 +SCI_SETREADONLY = 2171 +SCI_NULL = 2172 +SCI_CANPASTE = 2173 +SCI_CANUNDO = 2174 +SCI_EMPTYUNDOBUFFER = 2175 +SCI_UNDO = 2176 +SCI_CUT = 2177 +SCI_COPY = 2178 +SCI_PASTE = 2179 +SCI_CLEAR = 2180 +SCI_SETTEXT = 2181 +SCI_GETTEXT = 2182 +SCI_GETTEXTLENGTH = 2183 +SCI_GETDIRECTFUNCTION = 2184 +SCI_GETDIRECTPOINTER = 2185 +SCI_SETOVERTYPE = 2186 +SCI_GETOVERTYPE = 2187 +SCI_SETCARETWIDTH = 2188 +SCI_GETCARETWIDTH = 2189 +SCI_SETTARGETSTART = 2190 +SCI_GETTARGETSTART = 2191 +SCI_SETTARGETEND = 2192 +SCI_GETTARGETEND = 2193 +SCI_REPLACETARGET = 2194 +SCI_REPLACETARGETRE = 2195 +SCI_SEARCHINTARGET = 2197 +SCI_SETSEARCHFLAGS = 2198 +SCI_GETSEARCHFLAGS = 2199 +SCI_CALLTIPSHOW = 2200 +SCI_CALLTIPCANCEL = 2201 +SCI_CALLTIPACTIVE = 2202 +SCI_CALLTIPPOSSTART = 2203 +SCI_CALLTIPSETHLT = 2204 +SCI_CALLTIPSETBACK = 2205 +SCI_CALLTIPSETFORE = 2206 +SCI_CALLTIPSETFOREHLT = 2207 +SCI_CALLTIPUSESTYLE = 2212 +SCI_VISIBLEFROMDOCLINE = 2220 +SCI_DOCLINEFROMVISIBLE = 2221 +SCI_WRAPCOUNT = 2235 +SC_FOLDLEVELBASE = 0x400 +SC_FOLDLEVELWHITEFLAG = 0x1000 +SC_FOLDLEVELHEADERFLAG = 0x2000 +SC_FOLDLEVELBOXHEADERFLAG = 0x4000 +SC_FOLDLEVELBOXFOOTERFLAG = 0x8000 +SC_FOLDLEVELCONTRACTED = 0x10000 +SC_FOLDLEVELUNINDENT = 0x20000 +SC_FOLDLEVELNUMBERMASK = 0x0FFF +SCI_SETFOLDLEVEL = 2222 +SCI_GETFOLDLEVEL = 2223 +SCI_GETLASTCHILD = 2224 +SCI_GETFOLDPARENT = 2225 +SCI_SHOWLINES = 2226 +SCI_HIDELINES = 2227 +SCI_GETLINEVISIBLE = 2228 +SCI_SETFOLDEXPANDED = 2229 +SCI_GETFOLDEXPANDED = 2230 +SCI_TOGGLEFOLD = 2231 +SCI_ENSUREVISIBLE = 2232 +SC_FOLDFLAG_LINEBEFORE_EXPANDED = 0x0002 +SC_FOLDFLAG_LINEBEFORE_CONTRACTED = 0x0004 +SC_FOLDFLAG_LINEAFTER_EXPANDED = 0x0008 +SC_FOLDFLAG_LINEAFTER_CONTRACTED = 0x0010 +SC_FOLDFLAG_LEVELNUMBERS = 0x0040 +SC_FOLDFLAG_BOX = 0x0001 +SCI_SETFOLDFLAGS = 2233 +SCI_ENSUREVISIBLEENFORCEPOLICY = 2234 +SCI_SETTABINDENTS = 2260 +SCI_GETTABINDENTS = 2261 +SCI_SETBACKSPACEUNINDENTS = 2262 +SCI_GETBACKSPACEUNINDENTS = 2263 +SC_TIME_FOREVER = 10000000 +SCI_SETMOUSEDWELLTIME = 2264 +SCI_GETMOUSEDWELLTIME = 2265 +SCI_WORDSTARTPOSITION = 2266 +SCI_WORDENDPOSITION = 2267 +SC_WRAP_NONE = 0 +SC_WRAP_WORD = 1 +SC_WRAP_CHAR = 2 +SCI_SETWRAPMODE = 2268 +SCI_GETWRAPMODE = 2269 +SC_WRAPVISUALFLAG_NONE = 0x0000 +SC_WRAPVISUALFLAG_END = 0x0001 +SC_WRAPVISUALFLAG_START = 0x0002 +SCI_SETWRAPVISUALFLAGS = 2460 +SCI_GETWRAPVISUALFLAGS = 2461 +SC_WRAPVISUALFLAGLOC_DEFAULT = 0x0000 +SC_WRAPVISUALFLAGLOC_END_BY_TEXT = 0x0001 +SC_WRAPVISUALFLAGLOC_START_BY_TEXT = 0x0002 +SCI_SETWRAPVISUALFLAGSLOCATION = 2462 +SCI_GETWRAPVISUALFLAGSLOCATION = 2463 +SCI_SETWRAPSTARTINDENT = 2464 +SCI_GETWRAPSTARTINDENT = 2465 +SC_CACHE_NONE = 0 +SC_CACHE_CARET = 1 +SC_CACHE_PAGE = 2 +SC_CACHE_DOCUMENT = 3 +SCI_SETLAYOUTCACHE = 2272 +SCI_GETLAYOUTCACHE = 2273 +SCI_SETSCROLLWIDTH = 2274 +SCI_GETSCROLLWIDTH = 2275 +SCI_SETSCROLLWIDTHTRACKING = 2516 +SCI_GETSCROLLWIDTHTRACKING = 2517 +SCI_TEXTWIDTH = 2276 +SCI_SETENDATLASTLINE = 2277 +SCI_GETENDATLASTLINE = 2278 +SCI_TEXTHEIGHT = 2279 +SCI_SETVSCROLLBAR = 2280 +SCI_GETVSCROLLBAR = 2281 +SCI_APPENDTEXT = 2282 +SCI_GETTWOPHASEDRAW = 2283 +SCI_SETTWOPHASEDRAW = 2284 +SCI_TARGETFROMSELECTION = 2287 +SCI_LINESJOIN = 2288 +SCI_LINESSPLIT = 2289 +SCI_SETFOLDMARGINCOLOUR = 2290 +SCI_SETFOLDMARGINHICOLOUR = 2291 +SCI_LINEDOWN = 2300 +SCI_LINEDOWNEXTEND = 2301 +SCI_LINEUP = 2302 +SCI_LINEUPEXTEND = 2303 +SCI_CHARLEFT = 2304 +SCI_CHARLEFTEXTEND = 2305 +SCI_CHARRIGHT = 2306 +SCI_CHARRIGHTEXTEND = 2307 +SCI_WORDLEFT = 2308 +SCI_WORDLEFTEXTEND = 2309 +SCI_WORDRIGHT = 2310 +SCI_WORDRIGHTEXTEND = 2311 +SCI_HOME = 2312 +SCI_HOMEEXTEND = 2313 +SCI_LINEEND = 2314 +SCI_LINEENDEXTEND = 2315 +SCI_DOCUMENTSTART = 2316 +SCI_DOCUMENTSTARTEXTEND = 2317 +SCI_DOCUMENTEND = 2318 +SCI_DOCUMENTENDEXTEND = 2319 +SCI_PAGEUP = 2320 +SCI_PAGEUPEXTEND = 2321 +SCI_PAGEDOWN = 2322 +SCI_PAGEDOWNEXTEND = 2323 +SCI_EDITTOGGLEOVERTYPE = 2324 +SCI_CANCEL = 2325 +SCI_DELETEBACK = 2326 +SCI_TAB = 2327 +SCI_BACKTAB = 2328 +SCI_NEWLINE = 2329 +SCI_FORMFEED = 2330 +SCI_VCHOME = 2331 +SCI_VCHOMEEXTEND = 2332 +SCI_ZOOMIN = 2333 +SCI_ZOOMOUT = 2334 +SCI_DELWORDLEFT = 2335 +SCI_DELWORDRIGHT = 2336 +SCI_DELWORDRIGHTEND = 2518 +SCI_LINECUT = 2337 +SCI_LINEDELETE = 2338 +SCI_LINETRANSPOSE = 2339 +SCI_LINEDUPLICATE = 2404 +SCI_LOWERCASE = 2340 +SCI_UPPERCASE = 2341 +SCI_LINESCROLLDOWN = 2342 +SCI_LINESCROLLUP = 2343 +SCI_DELETEBACKNOTLINE = 2344 +SCI_HOMEDISPLAY = 2345 +SCI_HOMEDISPLAYEXTEND = 2346 +SCI_LINEENDDISPLAY = 2347 +SCI_LINEENDDISPLAYEXTEND = 2348 +SCI_HOMEWRAP = 2349 +SCI_HOMEWRAPEXTEND = 2450 +SCI_LINEENDWRAP = 2451 +SCI_LINEENDWRAPEXTEND = 2452 +SCI_VCHOMEWRAP = 2453 +SCI_VCHOMEWRAPEXTEND = 2454 +SCI_LINECOPY = 2455 +SCI_MOVECARETINSIDEVIEW = 2401 +SCI_LINELENGTH = 2350 +SCI_BRACEHIGHLIGHT = 2351 +SCI_BRACEBADLIGHT = 2352 +SCI_BRACEMATCH = 2353 +SCI_GETVIEWEOL = 2355 +SCI_SETVIEWEOL = 2356 +SCI_GETDOCPOINTER = 2357 +SCI_SETDOCPOINTER = 2358 +SCI_SETMODEVENTMASK = 2359 +EDGE_NONE = 0 +EDGE_LINE = 1 +EDGE_BACKGROUND = 2 +SCI_GETEDGECOLUMN = 2360 +SCI_SETEDGECOLUMN = 2361 +SCI_GETEDGEMODE = 2362 +SCI_SETEDGEMODE = 2363 +SCI_GETEDGECOLOUR = 2364 +SCI_SETEDGECOLOUR = 2365 +SCI_SEARCHANCHOR = 2366 +SCI_SEARCHNEXT = 2367 +SCI_SEARCHPREV = 2368 +SCI_LINESONSCREEN = 2370 +SCI_USEPOPUP = 2371 +SCI_SELECTIONISRECTANGLE = 2372 +SCI_SETZOOM = 2373 +SCI_GETZOOM = 2374 +SCI_CREATEDOCUMENT = 2375 +SCI_ADDREFDOCUMENT = 2376 +SCI_RELEASEDOCUMENT = 2377 +SCI_GETMODEVENTMASK = 2378 +SCI_SETFOCUS = 2380 +SCI_GETFOCUS = 2381 +SCI_SETSTATUS = 2382 +SCI_GETSTATUS = 2383 +SCI_SETMOUSEDOWNCAPTURES = 2384 +SCI_GETMOUSEDOWNCAPTURES = 2385 +SC_CURSORNORMAL = -1 +SC_CURSORWAIT = 4 +SCI_SETCURSOR = 2386 +SCI_GETCURSOR = 2387 +SCI_SETCONTROLCHARSYMBOL = 2388 +SCI_GETCONTROLCHARSYMBOL = 2389 +SCI_WORDPARTLEFT = 2390 +SCI_WORDPARTLEFTEXTEND = 2391 +SCI_WORDPARTRIGHT = 2392 +SCI_WORDPARTRIGHTEXTEND = 2393 +VISIBLE_SLOP = 0x01 +VISIBLE_STRICT = 0x04 +SCI_SETVISIBLEPOLICY = 2394 +SCI_DELLINELEFT = 2395 +SCI_DELLINERIGHT = 2396 +SCI_SETXOFFSET = 2397 +SCI_GETXOFFSET = 2398 +SCI_CHOOSECARETX = 2399 +SCI_GRABFOCUS = 2400 +CARET_SLOP = 0x01 +CARET_STRICT = 0x04 +CARET_JUMPS = 0x10 +CARET_EVEN = 0x08 +SCI_SETXCARETPOLICY = 2402 +SCI_SETYCARETPOLICY = 2403 +SCI_SETPRINTWRAPMODE = 2406 +SCI_GETPRINTWRAPMODE = 2407 +SCI_SETHOTSPOTACTIVEFORE = 2410 +SCI_GETHOTSPOTACTIVEFORE = 2494 +SCI_SETHOTSPOTACTIVEBACK = 2411 +SCI_GETHOTSPOTACTIVEBACK = 2495 +SCI_SETHOTSPOTACTIVEUNDERLINE = 2412 +SCI_GETHOTSPOTACTIVEUNDERLINE = 2496 +SCI_SETHOTSPOTSINGLELINE = 2421 +SCI_GETHOTSPOTSINGLELINE = 2497 +SCI_PARADOWN = 2413 +SCI_PARADOWNEXTEND = 2414 +SCI_PARAUP = 2415 +SCI_PARAUPEXTEND = 2416 +SCI_POSITIONBEFORE = 2417 +SCI_POSITIONAFTER = 2418 +SCI_COPYRANGE = 2419 +SCI_COPYTEXT = 2420 +SC_SEL_STREAM = 0 +SC_SEL_RECTANGLE = 1 +SC_SEL_LINES = 2 +SCI_SETSELECTIONMODE = 2422 +SCI_GETSELECTIONMODE = 2423 +SCI_GETLINESELSTARTPOSITION = 2424 +SCI_GETLINESELENDPOSITION = 2425 +SCI_LINEDOWNRECTEXTEND = 2426 +SCI_LINEUPRECTEXTEND = 2427 +SCI_CHARLEFTRECTEXTEND = 2428 +SCI_CHARRIGHTRECTEXTEND = 2429 +SCI_HOMERECTEXTEND = 2430 +SCI_VCHOMERECTEXTEND = 2431 +SCI_LINEENDRECTEXTEND = 2432 +SCI_PAGEUPRECTEXTEND = 2433 +SCI_PAGEDOWNRECTEXTEND = 2434 +SCI_STUTTEREDPAGEUP = 2435 +SCI_STUTTEREDPAGEUPEXTEND = 2436 +SCI_STUTTEREDPAGEDOWN = 2437 +SCI_STUTTEREDPAGEDOWNEXTEND = 2438 +SCI_WORDLEFTEND = 2439 +SCI_WORDLEFTENDEXTEND = 2440 +SCI_WORDRIGHTEND = 2441 +SCI_WORDRIGHTENDEXTEND = 2442 +SCI_SETWHITESPACECHARS = 2443 +SCI_SETCHARSDEFAULT = 2444 +SCI_AUTOCGETCURRENT = 2445 +SCI_ALLOCATE = 2446 +SCI_TARGETASUTF8 = 2447 +SCI_SETLENGTHFORENCODE = 2448 +SCI_ENCODEDFROMUTF8 = 2449 +SCI_FINDCOLUMN = 2456 +SCI_GETCARETSTICKY = 2457 +SCI_SETCARETSTICKY = 2458 +SCI_TOGGLECARETSTICKY = 2459 +SCI_SETPASTECONVERTENDINGS = 2467 +SCI_GETPASTECONVERTENDINGS = 2468 +SCI_SELECTIONDUPLICATE = 2469 +SC_ALPHA_TRANSPARENT = 0 +SC_ALPHA_OPAQUE = 255 +SC_ALPHA_NOALPHA = 256 +SCI_SETCARETLINEBACKALPHA = 2470 +SCI_GETCARETLINEBACKALPHA = 2471 +CARETSTYLE_INVISIBLE = 0 +CARETSTYLE_LINE = 1 +CARETSTYLE_BLOCK = 2 +SCI_SETCARETSTYLE = 2512 +SCI_GETCARETSTYLE = 2513 +SCI_SETINDICATORCURRENT = 2500 +SCI_GETINDICATORCURRENT = 2501 +SCI_SETINDICATORVALUE = 2502 +SCI_GETINDICATORVALUE = 2503 +SCI_INDICATORFILLRANGE = 2504 +SCI_INDICATORCLEARRANGE = 2505 +SCI_INDICATORALLONFOR = 2506 +SCI_INDICATORVALUEAT = 2507 +SCI_INDICATORSTART = 2508 +SCI_INDICATOREND = 2509 +SCI_SETPOSITIONCACHE = 2514 +SCI_GETPOSITIONCACHE = 2515 +SCI_COPYALLOWLINE = 2519 +SCI_GETCHARACTERPOINTER = 2520 +SCI_SETKEYSUNICODE = 2521 +SCI_GETKEYSUNICODE = 2522 +SCI_STARTRECORD = 3001 +SCI_STOPRECORD = 3002 +SCI_SETLEXER = 4001 +SCI_GETLEXER = 4002 +SCI_COLOURISE = 4003 +SCI_SETPROPERTY = 4004 +KEYWORDSET_MAX = 8 +SCI_SETKEYWORDS = 4005 +SCI_SETLEXERLANGUAGE = 4006 +SCI_LOADLEXERLIBRARY = 4007 +SCI_GETPROPERTY = 4008 +SCI_GETPROPERTYEXPANDED = 4009 +SCI_GETPROPERTYINT = 4010 +SCI_GETSTYLEBITSNEEDED = 4011 +SC_MOD_INSERTTEXT = 0x1 +SC_MOD_DELETETEXT = 0x2 +SC_MOD_CHANGESTYLE = 0x4 +SC_MOD_CHANGEFOLD = 0x8 +SC_PERFORMED_USER = 0x10 +SC_PERFORMED_UNDO = 0x20 +SC_PERFORMED_REDO = 0x40 +SC_MULTISTEPUNDOREDO = 0x80 +SC_LASTSTEPINUNDOREDO = 0x100 +SC_MOD_CHANGEMARKER = 0x200 +SC_MOD_BEFOREINSERT = 0x400 +SC_MOD_BEFOREDELETE = 0x800 +SC_MULTILINEUNDOREDO = 0x1000 +SC_STARTACTION = 0x2000 +SC_MOD_CHANGEINDICATOR = 0x4000 +SC_MOD_CHANGELINESTATE = 0x8000 +SC_MODEVENTMASKALL = 0xFFFF +SCEN_CHANGE = 768 +SCEN_SETFOCUS = 512 +SCEN_KILLFOCUS = 256 +SCK_DOWN = 300 +SCK_UP = 301 +SCK_LEFT = 302 +SCK_RIGHT = 303 +SCK_HOME = 304 +SCK_END = 305 +SCK_PRIOR = 306 +SCK_NEXT = 307 +SCK_DELETE = 308 +SCK_INSERT = 309 +SCK_ESCAPE = 7 +SCK_BACK = 8 +SCK_TAB = 9 +SCK_RETURN = 13 +SCK_ADD = 310 +SCK_SUBTRACT = 311 +SCK_DIVIDE = 312 +SCK_WIN = 313 +SCK_RWIN = 314 +SCK_MENU = 315 +SCMOD_NORM = 0 +SCMOD_SHIFT = 1 +SCMOD_CTRL = 2 +SCMOD_ALT = 4 +SCN_STYLENEEDED = 2000 +SCN_CHARADDED = 2001 +SCN_SAVEPOINTREACHED = 2002 +SCN_SAVEPOINTLEFT = 2003 +SCN_MODIFYATTEMPTRO = 2004 +SCN_KEY = 2005 +SCN_DOUBLECLICK = 2006 +SCN_UPDATEUI = 2007 +SCN_MODIFIED = 2008 +SCN_MACRORECORD = 2009 +SCN_MARGINCLICK = 2010 +SCN_NEEDSHOWN = 2011 +SCN_PAINTED = 2013 +SCN_USERLISTSELECTION = 2014 +SCN_URIDROPPED = 2015 +SCN_DWELLSTART = 2016 +SCN_DWELLEND = 2017 +SCN_ZOOM = 2018 +SCN_HOTSPOTCLICK = 2019 +SCN_HOTSPOTDOUBLECLICK = 2020 +SCN_CALLTIPCLICK = 2021 +SCN_AUTOCSELECTION = 2022 +SCN_INDICATORCLICK = 2023 +SCN_INDICATORRELEASE = 2024 +SCN_AUTOCCANCELLED = 2025 +SCI_SETCARETPOLICY = 2369 +CARET_CENTER = 0x02 +CARET_XEVEN = 0x08 +CARET_XJUMPS = 0x10 +SCN_POSCHANGED = 2012 +SCN_CHECKBRACE = 2007 +# Generated by h2py from Include\scilexer.h +SCLEX_CONTAINER = 0 +SCLEX_NULL = 1 +SCLEX_PYTHON = 2 +SCLEX_CPP = 3 +SCLEX_HTML = 4 +SCLEX_XML = 5 +SCLEX_PERL = 6 +SCLEX_SQL = 7 +SCLEX_VB = 8 +SCLEX_PROPERTIES = 9 +SCLEX_ERRORLIST = 10 +SCLEX_MAKEFILE = 11 +SCLEX_BATCH = 12 +SCLEX_XCODE = 13 +SCLEX_LATEX = 14 +SCLEX_LUA = 15 +SCLEX_DIFF = 16 +SCLEX_CONF = 17 +SCLEX_PASCAL = 18 +SCLEX_AVE = 19 +SCLEX_ADA = 20 +SCLEX_LISP = 21 +SCLEX_RUBY = 22 +SCLEX_EIFFEL = 23 +SCLEX_EIFFELKW = 24 +SCLEX_TCL = 25 +SCLEX_NNCRONTAB = 26 +SCLEX_BULLANT = 27 +SCLEX_VBSCRIPT = 28 +SCLEX_BAAN = 31 +SCLEX_MATLAB = 32 +SCLEX_SCRIPTOL = 33 +SCLEX_ASM = 34 +SCLEX_CPPNOCASE = 35 +SCLEX_FORTRAN = 36 +SCLEX_F77 = 37 +SCLEX_CSS = 38 +SCLEX_POV = 39 +SCLEX_LOUT = 40 +SCLEX_ESCRIPT = 41 +SCLEX_PS = 42 +SCLEX_NSIS = 43 +SCLEX_MMIXAL = 44 +SCLEX_CLW = 45 +SCLEX_CLWNOCASE = 46 +SCLEX_LOT = 47 +SCLEX_YAML = 48 +SCLEX_TEX = 49 +SCLEX_METAPOST = 50 +SCLEX_POWERBASIC = 51 +SCLEX_FORTH = 52 +SCLEX_ERLANG = 53 +SCLEX_OCTAVE = 54 +SCLEX_MSSQL = 55 +SCLEX_VERILOG = 56 +SCLEX_KIX = 57 +SCLEX_GUI4CLI = 58 +SCLEX_SPECMAN = 59 +SCLEX_AU3 = 60 +SCLEX_APDL = 61 +SCLEX_BASH = 62 +SCLEX_ASN1 = 63 +SCLEX_VHDL = 64 +SCLEX_CAML = 65 +SCLEX_BLITZBASIC = 66 +SCLEX_PUREBASIC = 67 +SCLEX_HASKELL = 68 +SCLEX_PHPSCRIPT = 69 +SCLEX_TADS3 = 70 +SCLEX_REBOL = 71 +SCLEX_SMALLTALK = 72 +SCLEX_FLAGSHIP = 73 +SCLEX_CSOUND = 74 +SCLEX_FREEBASIC = 75 +SCLEX_INNOSETUP = 76 +SCLEX_OPAL = 77 +SCLEX_SPICE = 78 +SCLEX_D = 79 +SCLEX_CMAKE = 80 +SCLEX_GAP = 81 +SCLEX_PLM = 82 +SCLEX_PROGRESS = 83 +SCLEX_ABAQUS = 84 +SCLEX_ASYMPTOTE = 85 +SCLEX_R = 86 +SCLEX_MAGIK = 87 +SCLEX_POWERSHELL = 88 +SCLEX_MYSQL = 89 +SCLEX_PO = 90 +SCLEX_AUTOMATIC = 1000 +SCE_P_DEFAULT = 0 +SCE_P_COMMENTLINE = 1 +SCE_P_NUMBER = 2 +SCE_P_STRING = 3 +SCE_P_CHARACTER = 4 +SCE_P_WORD = 5 +SCE_P_TRIPLE = 6 +SCE_P_TRIPLEDOUBLE = 7 +SCE_P_CLASSNAME = 8 +SCE_P_DEFNAME = 9 +SCE_P_OPERATOR = 10 +SCE_P_IDENTIFIER = 11 +SCE_P_COMMENTBLOCK = 12 +SCE_P_STRINGEOL = 13 +SCE_P_WORD2 = 14 +SCE_P_DECORATOR = 15 +SCE_C_DEFAULT = 0 +SCE_C_COMMENT = 1 +SCE_C_COMMENTLINE = 2 +SCE_C_COMMENTDOC = 3 +SCE_C_NUMBER = 4 +SCE_C_WORD = 5 +SCE_C_STRING = 6 +SCE_C_CHARACTER = 7 +SCE_C_UUID = 8 +SCE_C_PREPROCESSOR = 9 +SCE_C_OPERATOR = 10 +SCE_C_IDENTIFIER = 11 +SCE_C_STRINGEOL = 12 +SCE_C_VERBATIM = 13 +SCE_C_REGEX = 14 +SCE_C_COMMENTLINEDOC = 15 +SCE_C_WORD2 = 16 +SCE_C_COMMENTDOCKEYWORD = 17 +SCE_C_COMMENTDOCKEYWORDERROR = 18 +SCE_C_GLOBALCLASS = 19 +SCE_D_DEFAULT = 0 +SCE_D_COMMENT = 1 +SCE_D_COMMENTLINE = 2 +SCE_D_COMMENTDOC = 3 +SCE_D_COMMENTNESTED = 4 +SCE_D_NUMBER = 5 +SCE_D_WORD = 6 +SCE_D_WORD2 = 7 +SCE_D_WORD3 = 8 +SCE_D_TYPEDEF = 9 +SCE_D_STRING = 10 +SCE_D_STRINGEOL = 11 +SCE_D_CHARACTER = 12 +SCE_D_OPERATOR = 13 +SCE_D_IDENTIFIER = 14 +SCE_D_COMMENTLINEDOC = 15 +SCE_D_COMMENTDOCKEYWORD = 16 +SCE_D_COMMENTDOCKEYWORDERROR = 17 +SCE_TCL_DEFAULT = 0 +SCE_TCL_COMMENT = 1 +SCE_TCL_COMMENTLINE = 2 +SCE_TCL_NUMBER = 3 +SCE_TCL_WORD_IN_QUOTE = 4 +SCE_TCL_IN_QUOTE = 5 +SCE_TCL_OPERATOR = 6 +SCE_TCL_IDENTIFIER = 7 +SCE_TCL_SUBSTITUTION = 8 +SCE_TCL_SUB_BRACE = 9 +SCE_TCL_MODIFIER = 10 +SCE_TCL_EXPAND = 11 +SCE_TCL_WORD = 12 +SCE_TCL_WORD2 = 13 +SCE_TCL_WORD3 = 14 +SCE_TCL_WORD4 = 15 +SCE_TCL_WORD5 = 16 +SCE_TCL_WORD6 = 17 +SCE_TCL_WORD7 = 18 +SCE_TCL_WORD8 = 19 +SCE_TCL_COMMENT_BOX = 20 +SCE_TCL_BLOCK_COMMENT = 21 +SCE_H_DEFAULT = 0 +SCE_H_TAG = 1 +SCE_H_TAGUNKNOWN = 2 +SCE_H_ATTRIBUTE = 3 +SCE_H_ATTRIBUTEUNKNOWN = 4 +SCE_H_NUMBER = 5 +SCE_H_DOUBLESTRING = 6 +SCE_H_SINGLESTRING = 7 +SCE_H_OTHER = 8 +SCE_H_COMMENT = 9 +SCE_H_ENTITY = 10 +SCE_H_TAGEND = 11 +SCE_H_XMLSTART = 12 +SCE_H_XMLEND = 13 +SCE_H_SCRIPT = 14 +SCE_H_ASP = 15 +SCE_H_ASPAT = 16 +SCE_H_CDATA = 17 +SCE_H_QUESTION = 18 +SCE_H_VALUE = 19 +SCE_H_XCCOMMENT = 20 +SCE_H_SGML_DEFAULT = 21 +SCE_H_SGML_COMMAND = 22 +SCE_H_SGML_1ST_PARAM = 23 +SCE_H_SGML_DOUBLESTRING = 24 +SCE_H_SGML_SIMPLESTRING = 25 +SCE_H_SGML_ERROR = 26 +SCE_H_SGML_SPECIAL = 27 +SCE_H_SGML_ENTITY = 28 +SCE_H_SGML_COMMENT = 29 +SCE_H_SGML_1ST_PARAM_COMMENT = 30 +SCE_H_SGML_BLOCK_DEFAULT = 31 +SCE_HJ_START = 40 +SCE_HJ_DEFAULT = 41 +SCE_HJ_COMMENT = 42 +SCE_HJ_COMMENTLINE = 43 +SCE_HJ_COMMENTDOC = 44 +SCE_HJ_NUMBER = 45 +SCE_HJ_WORD = 46 +SCE_HJ_KEYWORD = 47 +SCE_HJ_DOUBLESTRING = 48 +SCE_HJ_SINGLESTRING = 49 +SCE_HJ_SYMBOLS = 50 +SCE_HJ_STRINGEOL = 51 +SCE_HJ_REGEX = 52 +SCE_HJA_START = 55 +SCE_HJA_DEFAULT = 56 +SCE_HJA_COMMENT = 57 +SCE_HJA_COMMENTLINE = 58 +SCE_HJA_COMMENTDOC = 59 +SCE_HJA_NUMBER = 60 +SCE_HJA_WORD = 61 +SCE_HJA_KEYWORD = 62 +SCE_HJA_DOUBLESTRING = 63 +SCE_HJA_SINGLESTRING = 64 +SCE_HJA_SYMBOLS = 65 +SCE_HJA_STRINGEOL = 66 +SCE_HJA_REGEX = 67 +SCE_HB_START = 70 +SCE_HB_DEFAULT = 71 +SCE_HB_COMMENTLINE = 72 +SCE_HB_NUMBER = 73 +SCE_HB_WORD = 74 +SCE_HB_STRING = 75 +SCE_HB_IDENTIFIER = 76 +SCE_HB_STRINGEOL = 77 +SCE_HBA_START = 80 +SCE_HBA_DEFAULT = 81 +SCE_HBA_COMMENTLINE = 82 +SCE_HBA_NUMBER = 83 +SCE_HBA_WORD = 84 +SCE_HBA_STRING = 85 +SCE_HBA_IDENTIFIER = 86 +SCE_HBA_STRINGEOL = 87 +SCE_HP_START = 90 +SCE_HP_DEFAULT = 91 +SCE_HP_COMMENTLINE = 92 +SCE_HP_NUMBER = 93 +SCE_HP_STRING = 94 +SCE_HP_CHARACTER = 95 +SCE_HP_WORD = 96 +SCE_HP_TRIPLE = 97 +SCE_HP_TRIPLEDOUBLE = 98 +SCE_HP_CLASSNAME = 99 +SCE_HP_DEFNAME = 100 +SCE_HP_OPERATOR = 101 +SCE_HP_IDENTIFIER = 102 +SCE_HPHP_COMPLEX_VARIABLE = 104 +SCE_HPA_START = 105 +SCE_HPA_DEFAULT = 106 +SCE_HPA_COMMENTLINE = 107 +SCE_HPA_NUMBER = 108 +SCE_HPA_STRING = 109 +SCE_HPA_CHARACTER = 110 +SCE_HPA_WORD = 111 +SCE_HPA_TRIPLE = 112 +SCE_HPA_TRIPLEDOUBLE = 113 +SCE_HPA_CLASSNAME = 114 +SCE_HPA_DEFNAME = 115 +SCE_HPA_OPERATOR = 116 +SCE_HPA_IDENTIFIER = 117 +SCE_HPHP_DEFAULT = 118 +SCE_HPHP_HSTRING = 119 +SCE_HPHP_SIMPLESTRING = 120 +SCE_HPHP_WORD = 121 +SCE_HPHP_NUMBER = 122 +SCE_HPHP_VARIABLE = 123 +SCE_HPHP_COMMENT = 124 +SCE_HPHP_COMMENTLINE = 125 +SCE_HPHP_HSTRING_VARIABLE = 126 +SCE_HPHP_OPERATOR = 127 +SCE_PL_DEFAULT = 0 +SCE_PL_ERROR = 1 +SCE_PL_COMMENTLINE = 2 +SCE_PL_POD = 3 +SCE_PL_NUMBER = 4 +SCE_PL_WORD = 5 +SCE_PL_STRING = 6 +SCE_PL_CHARACTER = 7 +SCE_PL_PUNCTUATION = 8 +SCE_PL_PREPROCESSOR = 9 +SCE_PL_OPERATOR = 10 +SCE_PL_IDENTIFIER = 11 +SCE_PL_SCALAR = 12 +SCE_PL_ARRAY = 13 +SCE_PL_HASH = 14 +SCE_PL_SYMBOLTABLE = 15 +SCE_PL_VARIABLE_INDEXER = 16 +SCE_PL_REGEX = 17 +SCE_PL_REGSUBST = 18 +SCE_PL_LONGQUOTE = 19 +SCE_PL_BACKTICKS = 20 +SCE_PL_DATASECTION = 21 +SCE_PL_HERE_DELIM = 22 +SCE_PL_HERE_Q = 23 +SCE_PL_HERE_QQ = 24 +SCE_PL_HERE_QX = 25 +SCE_PL_STRING_Q = 26 +SCE_PL_STRING_QQ = 27 +SCE_PL_STRING_QX = 28 +SCE_PL_STRING_QR = 29 +SCE_PL_STRING_QW = 30 +SCE_PL_POD_VERB = 31 +SCE_PL_SUB_PROTOTYPE = 40 +SCE_PL_FORMAT_IDENT = 41 +SCE_PL_FORMAT = 42 +SCE_RB_DEFAULT = 0 +SCE_RB_ERROR = 1 +SCE_RB_COMMENTLINE = 2 +SCE_RB_POD = 3 +SCE_RB_NUMBER = 4 +SCE_RB_WORD = 5 +SCE_RB_STRING = 6 +SCE_RB_CHARACTER = 7 +SCE_RB_CLASSNAME = 8 +SCE_RB_DEFNAME = 9 +SCE_RB_OPERATOR = 10 +SCE_RB_IDENTIFIER = 11 +SCE_RB_REGEX = 12 +SCE_RB_GLOBAL = 13 +SCE_RB_SYMBOL = 14 +SCE_RB_MODULE_NAME = 15 +SCE_RB_INSTANCE_VAR = 16 +SCE_RB_CLASS_VAR = 17 +SCE_RB_BACKTICKS = 18 +SCE_RB_DATASECTION = 19 +SCE_RB_HERE_DELIM = 20 +SCE_RB_HERE_Q = 21 +SCE_RB_HERE_QQ = 22 +SCE_RB_HERE_QX = 23 +SCE_RB_STRING_Q = 24 +SCE_RB_STRING_QQ = 25 +SCE_RB_STRING_QX = 26 +SCE_RB_STRING_QR = 27 +SCE_RB_STRING_QW = 28 +SCE_RB_WORD_DEMOTED = 29 +SCE_RB_STDIN = 30 +SCE_RB_STDOUT = 31 +SCE_RB_STDERR = 40 +SCE_RB_UPPER_BOUND = 41 +SCE_B_DEFAULT = 0 +SCE_B_COMMENT = 1 +SCE_B_NUMBER = 2 +SCE_B_KEYWORD = 3 +SCE_B_STRING = 4 +SCE_B_PREPROCESSOR = 5 +SCE_B_OPERATOR = 6 +SCE_B_IDENTIFIER = 7 +SCE_B_DATE = 8 +SCE_B_STRINGEOL = 9 +SCE_B_KEYWORD2 = 10 +SCE_B_KEYWORD3 = 11 +SCE_B_KEYWORD4 = 12 +SCE_B_CONSTANT = 13 +SCE_B_ASM = 14 +SCE_B_LABEL = 15 +SCE_B_ERROR = 16 +SCE_B_HEXNUMBER = 17 +SCE_B_BINNUMBER = 18 +SCE_PROPS_DEFAULT = 0 +SCE_PROPS_COMMENT = 1 +SCE_PROPS_SECTION = 2 +SCE_PROPS_ASSIGNMENT = 3 +SCE_PROPS_DEFVAL = 4 +SCE_PROPS_KEY = 5 +SCE_L_DEFAULT = 0 +SCE_L_COMMAND = 1 +SCE_L_TAG = 2 +SCE_L_MATH = 3 +SCE_L_COMMENT = 4 +SCE_LUA_DEFAULT = 0 +SCE_LUA_COMMENT = 1 +SCE_LUA_COMMENTLINE = 2 +SCE_LUA_COMMENTDOC = 3 +SCE_LUA_NUMBER = 4 +SCE_LUA_WORD = 5 +SCE_LUA_STRING = 6 +SCE_LUA_CHARACTER = 7 +SCE_LUA_LITERALSTRING = 8 +SCE_LUA_PREPROCESSOR = 9 +SCE_LUA_OPERATOR = 10 +SCE_LUA_IDENTIFIER = 11 +SCE_LUA_STRINGEOL = 12 +SCE_LUA_WORD2 = 13 +SCE_LUA_WORD3 = 14 +SCE_LUA_WORD4 = 15 +SCE_LUA_WORD5 = 16 +SCE_LUA_WORD6 = 17 +SCE_LUA_WORD7 = 18 +SCE_LUA_WORD8 = 19 +SCE_ERR_DEFAULT = 0 +SCE_ERR_PYTHON = 1 +SCE_ERR_GCC = 2 +SCE_ERR_MS = 3 +SCE_ERR_CMD = 4 +SCE_ERR_BORLAND = 5 +SCE_ERR_PERL = 6 +SCE_ERR_NET = 7 +SCE_ERR_LUA = 8 +SCE_ERR_CTAG = 9 +SCE_ERR_DIFF_CHANGED = 10 +SCE_ERR_DIFF_ADDITION = 11 +SCE_ERR_DIFF_DELETION = 12 +SCE_ERR_DIFF_MESSAGE = 13 +SCE_ERR_PHP = 14 +SCE_ERR_ELF = 15 +SCE_ERR_IFC = 16 +SCE_ERR_IFORT = 17 +SCE_ERR_ABSF = 18 +SCE_ERR_TIDY = 19 +SCE_ERR_JAVA_STACK = 20 +SCE_ERR_VALUE = 21 +SCE_BAT_DEFAULT = 0 +SCE_BAT_COMMENT = 1 +SCE_BAT_WORD = 2 +SCE_BAT_LABEL = 3 +SCE_BAT_HIDE = 4 +SCE_BAT_COMMAND = 5 +SCE_BAT_IDENTIFIER = 6 +SCE_BAT_OPERATOR = 7 +SCE_MAKE_DEFAULT = 0 +SCE_MAKE_COMMENT = 1 +SCE_MAKE_PREPROCESSOR = 2 +SCE_MAKE_IDENTIFIER = 3 +SCE_MAKE_OPERATOR = 4 +SCE_MAKE_TARGET = 5 +SCE_MAKE_IDEOL = 9 +SCE_DIFF_DEFAULT = 0 +SCE_DIFF_COMMENT = 1 +SCE_DIFF_COMMAND = 2 +SCE_DIFF_HEADER = 3 +SCE_DIFF_POSITION = 4 +SCE_DIFF_DELETED = 5 +SCE_DIFF_ADDED = 6 +SCE_DIFF_CHANGED = 7 +SCE_CONF_DEFAULT = 0 +SCE_CONF_COMMENT = 1 +SCE_CONF_NUMBER = 2 +SCE_CONF_IDENTIFIER = 3 +SCE_CONF_EXTENSION = 4 +SCE_CONF_PARAMETER = 5 +SCE_CONF_STRING = 6 +SCE_CONF_OPERATOR = 7 +SCE_CONF_IP = 8 +SCE_CONF_DIRECTIVE = 9 +SCE_AVE_DEFAULT = 0 +SCE_AVE_COMMENT = 1 +SCE_AVE_NUMBER = 2 +SCE_AVE_WORD = 3 +SCE_AVE_STRING = 6 +SCE_AVE_ENUM = 7 +SCE_AVE_STRINGEOL = 8 +SCE_AVE_IDENTIFIER = 9 +SCE_AVE_OPERATOR = 10 +SCE_AVE_WORD1 = 11 +SCE_AVE_WORD2 = 12 +SCE_AVE_WORD3 = 13 +SCE_AVE_WORD4 = 14 +SCE_AVE_WORD5 = 15 +SCE_AVE_WORD6 = 16 +SCE_ADA_DEFAULT = 0 +SCE_ADA_WORD = 1 +SCE_ADA_IDENTIFIER = 2 +SCE_ADA_NUMBER = 3 +SCE_ADA_DELIMITER = 4 +SCE_ADA_CHARACTER = 5 +SCE_ADA_CHARACTEREOL = 6 +SCE_ADA_STRING = 7 +SCE_ADA_STRINGEOL = 8 +SCE_ADA_LABEL = 9 +SCE_ADA_COMMENTLINE = 10 +SCE_ADA_ILLEGAL = 11 +SCE_BAAN_DEFAULT = 0 +SCE_BAAN_COMMENT = 1 +SCE_BAAN_COMMENTDOC = 2 +SCE_BAAN_NUMBER = 3 +SCE_BAAN_WORD = 4 +SCE_BAAN_STRING = 5 +SCE_BAAN_PREPROCESSOR = 6 +SCE_BAAN_OPERATOR = 7 +SCE_BAAN_IDENTIFIER = 8 +SCE_BAAN_STRINGEOL = 9 +SCE_BAAN_WORD2 = 10 +SCE_LISP_DEFAULT = 0 +SCE_LISP_COMMENT = 1 +SCE_LISP_NUMBER = 2 +SCE_LISP_KEYWORD = 3 +SCE_LISP_KEYWORD_KW = 4 +SCE_LISP_SYMBOL = 5 +SCE_LISP_STRING = 6 +SCE_LISP_STRINGEOL = 8 +SCE_LISP_IDENTIFIER = 9 +SCE_LISP_OPERATOR = 10 +SCE_LISP_SPECIAL = 11 +SCE_LISP_MULTI_COMMENT = 12 +SCE_EIFFEL_DEFAULT = 0 +SCE_EIFFEL_COMMENTLINE = 1 +SCE_EIFFEL_NUMBER = 2 +SCE_EIFFEL_WORD = 3 +SCE_EIFFEL_STRING = 4 +SCE_EIFFEL_CHARACTER = 5 +SCE_EIFFEL_OPERATOR = 6 +SCE_EIFFEL_IDENTIFIER = 7 +SCE_EIFFEL_STRINGEOL = 8 +SCE_NNCRONTAB_DEFAULT = 0 +SCE_NNCRONTAB_COMMENT = 1 +SCE_NNCRONTAB_TASK = 2 +SCE_NNCRONTAB_SECTION = 3 +SCE_NNCRONTAB_KEYWORD = 4 +SCE_NNCRONTAB_MODIFIER = 5 +SCE_NNCRONTAB_ASTERISK = 6 +SCE_NNCRONTAB_NUMBER = 7 +SCE_NNCRONTAB_STRING = 8 +SCE_NNCRONTAB_ENVIRONMENT = 9 +SCE_NNCRONTAB_IDENTIFIER = 10 +SCE_FORTH_DEFAULT = 0 +SCE_FORTH_COMMENT = 1 +SCE_FORTH_COMMENT_ML = 2 +SCE_FORTH_IDENTIFIER = 3 +SCE_FORTH_CONTROL = 4 +SCE_FORTH_KEYWORD = 5 +SCE_FORTH_DEFWORD = 6 +SCE_FORTH_PREWORD1 = 7 +SCE_FORTH_PREWORD2 = 8 +SCE_FORTH_NUMBER = 9 +SCE_FORTH_STRING = 10 +SCE_FORTH_LOCALE = 11 +SCE_MATLAB_DEFAULT = 0 +SCE_MATLAB_COMMENT = 1 +SCE_MATLAB_COMMAND = 2 +SCE_MATLAB_NUMBER = 3 +SCE_MATLAB_KEYWORD = 4 +SCE_MATLAB_STRING = 5 +SCE_MATLAB_OPERATOR = 6 +SCE_MATLAB_IDENTIFIER = 7 +SCE_MATLAB_DOUBLEQUOTESTRING = 8 +SCE_SCRIPTOL_DEFAULT = 0 +SCE_SCRIPTOL_WHITE = 1 +SCE_SCRIPTOL_COMMENTLINE = 2 +SCE_SCRIPTOL_PERSISTENT = 3 +SCE_SCRIPTOL_CSTYLE = 4 +SCE_SCRIPTOL_COMMENTBLOCK = 5 +SCE_SCRIPTOL_NUMBER = 6 +SCE_SCRIPTOL_STRING = 7 +SCE_SCRIPTOL_CHARACTER = 8 +SCE_SCRIPTOL_STRINGEOL = 9 +SCE_SCRIPTOL_KEYWORD = 10 +SCE_SCRIPTOL_OPERATOR = 11 +SCE_SCRIPTOL_IDENTIFIER = 12 +SCE_SCRIPTOL_TRIPLE = 13 +SCE_SCRIPTOL_CLASSNAME = 14 +SCE_SCRIPTOL_PREPROCESSOR = 15 +SCE_ASM_DEFAULT = 0 +SCE_ASM_COMMENT = 1 +SCE_ASM_NUMBER = 2 +SCE_ASM_STRING = 3 +SCE_ASM_OPERATOR = 4 +SCE_ASM_IDENTIFIER = 5 +SCE_ASM_CPUINSTRUCTION = 6 +SCE_ASM_MATHINSTRUCTION = 7 +SCE_ASM_REGISTER = 8 +SCE_ASM_DIRECTIVE = 9 +SCE_ASM_DIRECTIVEOPERAND = 10 +SCE_ASM_COMMENTBLOCK = 11 +SCE_ASM_CHARACTER = 12 +SCE_ASM_STRINGEOL = 13 +SCE_ASM_EXTINSTRUCTION = 14 +SCE_F_DEFAULT = 0 +SCE_F_COMMENT = 1 +SCE_F_NUMBER = 2 +SCE_F_STRING1 = 3 +SCE_F_STRING2 = 4 +SCE_F_STRINGEOL = 5 +SCE_F_OPERATOR = 6 +SCE_F_IDENTIFIER = 7 +SCE_F_WORD = 8 +SCE_F_WORD2 = 9 +SCE_F_WORD3 = 10 +SCE_F_PREPROCESSOR = 11 +SCE_F_OPERATOR2 = 12 +SCE_F_LABEL = 13 +SCE_F_CONTINUATION = 14 +SCE_CSS_DEFAULT = 0 +SCE_CSS_TAG = 1 +SCE_CSS_CLASS = 2 +SCE_CSS_PSEUDOCLASS = 3 +SCE_CSS_UNKNOWN_PSEUDOCLASS = 4 +SCE_CSS_OPERATOR = 5 +SCE_CSS_IDENTIFIER = 6 +SCE_CSS_UNKNOWN_IDENTIFIER = 7 +SCE_CSS_VALUE = 8 +SCE_CSS_COMMENT = 9 +SCE_CSS_ID = 10 +SCE_CSS_IMPORTANT = 11 +SCE_CSS_DIRECTIVE = 12 +SCE_CSS_DOUBLESTRING = 13 +SCE_CSS_SINGLESTRING = 14 +SCE_CSS_IDENTIFIER2 = 15 +SCE_CSS_ATTRIBUTE = 16 +SCE_CSS_IDENTIFIER3 = 17 +SCE_CSS_PSEUDOELEMENT = 18 +SCE_CSS_EXTENDED_IDENTIFIER = 19 +SCE_CSS_EXTENDED_PSEUDOCLASS = 20 +SCE_CSS_EXTENDED_PSEUDOELEMENT = 21 +SCE_POV_DEFAULT = 0 +SCE_POV_COMMENT = 1 +SCE_POV_COMMENTLINE = 2 +SCE_POV_NUMBER = 3 +SCE_POV_OPERATOR = 4 +SCE_POV_IDENTIFIER = 5 +SCE_POV_STRING = 6 +SCE_POV_STRINGEOL = 7 +SCE_POV_DIRECTIVE = 8 +SCE_POV_BADDIRECTIVE = 9 +SCE_POV_WORD2 = 10 +SCE_POV_WORD3 = 11 +SCE_POV_WORD4 = 12 +SCE_POV_WORD5 = 13 +SCE_POV_WORD6 = 14 +SCE_POV_WORD7 = 15 +SCE_POV_WORD8 = 16 +SCE_LOUT_DEFAULT = 0 +SCE_LOUT_COMMENT = 1 +SCE_LOUT_NUMBER = 2 +SCE_LOUT_WORD = 3 +SCE_LOUT_WORD2 = 4 +SCE_LOUT_WORD3 = 5 +SCE_LOUT_WORD4 = 6 +SCE_LOUT_STRING = 7 +SCE_LOUT_OPERATOR = 8 +SCE_LOUT_IDENTIFIER = 9 +SCE_LOUT_STRINGEOL = 10 +SCE_ESCRIPT_DEFAULT = 0 +SCE_ESCRIPT_COMMENT = 1 +SCE_ESCRIPT_COMMENTLINE = 2 +SCE_ESCRIPT_COMMENTDOC = 3 +SCE_ESCRIPT_NUMBER = 4 +SCE_ESCRIPT_WORD = 5 +SCE_ESCRIPT_STRING = 6 +SCE_ESCRIPT_OPERATOR = 7 +SCE_ESCRIPT_IDENTIFIER = 8 +SCE_ESCRIPT_BRACE = 9 +SCE_ESCRIPT_WORD2 = 10 +SCE_ESCRIPT_WORD3 = 11 +SCE_PS_DEFAULT = 0 +SCE_PS_COMMENT = 1 +SCE_PS_DSC_COMMENT = 2 +SCE_PS_DSC_VALUE = 3 +SCE_PS_NUMBER = 4 +SCE_PS_NAME = 5 +SCE_PS_KEYWORD = 6 +SCE_PS_LITERAL = 7 +SCE_PS_IMMEVAL = 8 +SCE_PS_PAREN_ARRAY = 9 +SCE_PS_PAREN_DICT = 10 +SCE_PS_PAREN_PROC = 11 +SCE_PS_TEXT = 12 +SCE_PS_HEXSTRING = 13 +SCE_PS_BASE85STRING = 14 +SCE_PS_BADSTRINGCHAR = 15 +SCE_NSIS_DEFAULT = 0 +SCE_NSIS_COMMENT = 1 +SCE_NSIS_STRINGDQ = 2 +SCE_NSIS_STRINGLQ = 3 +SCE_NSIS_STRINGRQ = 4 +SCE_NSIS_FUNCTION = 5 +SCE_NSIS_VARIABLE = 6 +SCE_NSIS_LABEL = 7 +SCE_NSIS_USERDEFINED = 8 +SCE_NSIS_SECTIONDEF = 9 +SCE_NSIS_SUBSECTIONDEF = 10 +SCE_NSIS_IFDEFINEDEF = 11 +SCE_NSIS_MACRODEF = 12 +SCE_NSIS_STRINGVAR = 13 +SCE_NSIS_NUMBER = 14 +SCE_NSIS_SECTIONGROUP = 15 +SCE_NSIS_PAGEEX = 16 +SCE_NSIS_FUNCTIONDEF = 17 +SCE_NSIS_COMMENTBOX = 18 +SCE_MMIXAL_LEADWS = 0 +SCE_MMIXAL_COMMENT = 1 +SCE_MMIXAL_LABEL = 2 +SCE_MMIXAL_OPCODE = 3 +SCE_MMIXAL_OPCODE_PRE = 4 +SCE_MMIXAL_OPCODE_VALID = 5 +SCE_MMIXAL_OPCODE_UNKNOWN = 6 +SCE_MMIXAL_OPCODE_POST = 7 +SCE_MMIXAL_OPERANDS = 8 +SCE_MMIXAL_NUMBER = 9 +SCE_MMIXAL_REF = 10 +SCE_MMIXAL_CHAR = 11 +SCE_MMIXAL_STRING = 12 +SCE_MMIXAL_REGISTER = 13 +SCE_MMIXAL_HEX = 14 +SCE_MMIXAL_OPERATOR = 15 +SCE_MMIXAL_SYMBOL = 16 +SCE_MMIXAL_INCLUDE = 17 +SCE_CLW_DEFAULT = 0 +SCE_CLW_LABEL = 1 +SCE_CLW_COMMENT = 2 +SCE_CLW_STRING = 3 +SCE_CLW_USER_IDENTIFIER = 4 +SCE_CLW_INTEGER_CONSTANT = 5 +SCE_CLW_REAL_CONSTANT = 6 +SCE_CLW_PICTURE_STRING = 7 +SCE_CLW_KEYWORD = 8 +SCE_CLW_COMPILER_DIRECTIVE = 9 +SCE_CLW_RUNTIME_EXPRESSIONS = 10 +SCE_CLW_BUILTIN_PROCEDURES_FUNCTION = 11 +SCE_CLW_STRUCTURE_DATA_TYPE = 12 +SCE_CLW_ATTRIBUTE = 13 +SCE_CLW_STANDARD_EQUATE = 14 +SCE_CLW_ERROR = 15 +SCE_CLW_DEPRECATED = 16 +SCE_LOT_DEFAULT = 0 +SCE_LOT_HEADER = 1 +SCE_LOT_BREAK = 2 +SCE_LOT_SET = 3 +SCE_LOT_PASS = 4 +SCE_LOT_FAIL = 5 +SCE_LOT_ABORT = 6 +SCE_YAML_DEFAULT = 0 +SCE_YAML_COMMENT = 1 +SCE_YAML_IDENTIFIER = 2 +SCE_YAML_KEYWORD = 3 +SCE_YAML_NUMBER = 4 +SCE_YAML_REFERENCE = 5 +SCE_YAML_DOCUMENT = 6 +SCE_YAML_TEXT = 7 +SCE_YAML_ERROR = 8 +SCE_YAML_OPERATOR = 9 +SCE_TEX_DEFAULT = 0 +SCE_TEX_SPECIAL = 1 +SCE_TEX_GROUP = 2 +SCE_TEX_SYMBOL = 3 +SCE_TEX_COMMAND = 4 +SCE_TEX_TEXT = 5 +SCE_METAPOST_DEFAULT = 0 +SCE_METAPOST_SPECIAL = 1 +SCE_METAPOST_GROUP = 2 +SCE_METAPOST_SYMBOL = 3 +SCE_METAPOST_COMMAND = 4 +SCE_METAPOST_TEXT = 5 +SCE_METAPOST_EXTRA = 6 +SCE_ERLANG_DEFAULT = 0 +SCE_ERLANG_COMMENT = 1 +SCE_ERLANG_VARIABLE = 2 +SCE_ERLANG_NUMBER = 3 +SCE_ERLANG_KEYWORD = 4 +SCE_ERLANG_STRING = 5 +SCE_ERLANG_OPERATOR = 6 +SCE_ERLANG_ATOM = 7 +SCE_ERLANG_FUNCTION_NAME = 8 +SCE_ERLANG_CHARACTER = 9 +SCE_ERLANG_MACRO = 10 +SCE_ERLANG_RECORD = 11 +SCE_ERLANG_SEPARATOR = 12 +SCE_ERLANG_NODE_NAME = 13 +SCE_ERLANG_UNKNOWN = 31 +SCE_MSSQL_DEFAULT = 0 +SCE_MSSQL_COMMENT = 1 +SCE_MSSQL_LINE_COMMENT = 2 +SCE_MSSQL_NUMBER = 3 +SCE_MSSQL_STRING = 4 +SCE_MSSQL_OPERATOR = 5 +SCE_MSSQL_IDENTIFIER = 6 +SCE_MSSQL_VARIABLE = 7 +SCE_MSSQL_COLUMN_NAME = 8 +SCE_MSSQL_STATEMENT = 9 +SCE_MSSQL_DATATYPE = 10 +SCE_MSSQL_SYSTABLE = 11 +SCE_MSSQL_GLOBAL_VARIABLE = 12 +SCE_MSSQL_FUNCTION = 13 +SCE_MSSQL_STORED_PROCEDURE = 14 +SCE_MSSQL_DEFAULT_PREF_DATATYPE = 15 +SCE_MSSQL_COLUMN_NAME_2 = 16 +SCE_V_DEFAULT = 0 +SCE_V_COMMENT = 1 +SCE_V_COMMENTLINE = 2 +SCE_V_COMMENTLINEBANG = 3 +SCE_V_NUMBER = 4 +SCE_V_WORD = 5 +SCE_V_STRING = 6 +SCE_V_WORD2 = 7 +SCE_V_WORD3 = 8 +SCE_V_PREPROCESSOR = 9 +SCE_V_OPERATOR = 10 +SCE_V_IDENTIFIER = 11 +SCE_V_STRINGEOL = 12 +SCE_V_USER = 19 +SCE_KIX_DEFAULT = 0 +SCE_KIX_COMMENT = 1 +SCE_KIX_STRING1 = 2 +SCE_KIX_STRING2 = 3 +SCE_KIX_NUMBER = 4 +SCE_KIX_VAR = 5 +SCE_KIX_MACRO = 6 +SCE_KIX_KEYWORD = 7 +SCE_KIX_FUNCTIONS = 8 +SCE_KIX_OPERATOR = 9 +SCE_KIX_IDENTIFIER = 31 +SCE_GC_DEFAULT = 0 +SCE_GC_COMMENTLINE = 1 +SCE_GC_COMMENTBLOCK = 2 +SCE_GC_GLOBAL = 3 +SCE_GC_EVENT = 4 +SCE_GC_ATTRIBUTE = 5 +SCE_GC_CONTROL = 6 +SCE_GC_COMMAND = 7 +SCE_GC_STRING = 8 +SCE_GC_OPERATOR = 9 +SCE_SN_DEFAULT = 0 +SCE_SN_CODE = 1 +SCE_SN_COMMENTLINE = 2 +SCE_SN_COMMENTLINEBANG = 3 +SCE_SN_NUMBER = 4 +SCE_SN_WORD = 5 +SCE_SN_STRING = 6 +SCE_SN_WORD2 = 7 +SCE_SN_WORD3 = 8 +SCE_SN_PREPROCESSOR = 9 +SCE_SN_OPERATOR = 10 +SCE_SN_IDENTIFIER = 11 +SCE_SN_STRINGEOL = 12 +SCE_SN_REGEXTAG = 13 +SCE_SN_SIGNAL = 14 +SCE_SN_USER = 19 +SCE_AU3_DEFAULT = 0 +SCE_AU3_COMMENT = 1 +SCE_AU3_COMMENTBLOCK = 2 +SCE_AU3_NUMBER = 3 +SCE_AU3_FUNCTION = 4 +SCE_AU3_KEYWORD = 5 +SCE_AU3_MACRO = 6 +SCE_AU3_STRING = 7 +SCE_AU3_OPERATOR = 8 +SCE_AU3_VARIABLE = 9 +SCE_AU3_SENT = 10 +SCE_AU3_PREPROCESSOR = 11 +SCE_AU3_SPECIAL = 12 +SCE_AU3_EXPAND = 13 +SCE_AU3_COMOBJ = 14 +SCE_AU3_UDF = 15 +SCE_APDL_DEFAULT = 0 +SCE_APDL_COMMENT = 1 +SCE_APDL_COMMENTBLOCK = 2 +SCE_APDL_NUMBER = 3 +SCE_APDL_STRING = 4 +SCE_APDL_OPERATOR = 5 +SCE_APDL_WORD = 6 +SCE_APDL_PROCESSOR = 7 +SCE_APDL_COMMAND = 8 +SCE_APDL_SLASHCOMMAND = 9 +SCE_APDL_STARCOMMAND = 10 +SCE_APDL_ARGUMENT = 11 +SCE_APDL_FUNCTION = 12 +SCE_SH_DEFAULT = 0 +SCE_SH_ERROR = 1 +SCE_SH_COMMENTLINE = 2 +SCE_SH_NUMBER = 3 +SCE_SH_WORD = 4 +SCE_SH_STRING = 5 +SCE_SH_CHARACTER = 6 +SCE_SH_OPERATOR = 7 +SCE_SH_IDENTIFIER = 8 +SCE_SH_SCALAR = 9 +SCE_SH_PARAM = 10 +SCE_SH_BACKTICKS = 11 +SCE_SH_HERE_DELIM = 12 +SCE_SH_HERE_Q = 13 +SCE_ASN1_DEFAULT = 0 +SCE_ASN1_COMMENT = 1 +SCE_ASN1_IDENTIFIER = 2 +SCE_ASN1_STRING = 3 +SCE_ASN1_OID = 4 +SCE_ASN1_SCALAR = 5 +SCE_ASN1_KEYWORD = 6 +SCE_ASN1_ATTRIBUTE = 7 +SCE_ASN1_DESCRIPTOR = 8 +SCE_ASN1_TYPE = 9 +SCE_ASN1_OPERATOR = 10 +SCE_VHDL_DEFAULT = 0 +SCE_VHDL_COMMENT = 1 +SCE_VHDL_COMMENTLINEBANG = 2 +SCE_VHDL_NUMBER = 3 +SCE_VHDL_STRING = 4 +SCE_VHDL_OPERATOR = 5 +SCE_VHDL_IDENTIFIER = 6 +SCE_VHDL_STRINGEOL = 7 +SCE_VHDL_KEYWORD = 8 +SCE_VHDL_STDOPERATOR = 9 +SCE_VHDL_ATTRIBUTE = 10 +SCE_VHDL_STDFUNCTION = 11 +SCE_VHDL_STDPACKAGE = 12 +SCE_VHDL_STDTYPE = 13 +SCE_VHDL_USERWORD = 14 +SCE_CAML_DEFAULT = 0 +SCE_CAML_IDENTIFIER = 1 +SCE_CAML_TAGNAME = 2 +SCE_CAML_KEYWORD = 3 +SCE_CAML_KEYWORD2 = 4 +SCE_CAML_KEYWORD3 = 5 +SCE_CAML_LINENUM = 6 +SCE_CAML_OPERATOR = 7 +SCE_CAML_NUMBER = 8 +SCE_CAML_CHAR = 9 +SCE_CAML_STRING = 11 +SCE_CAML_COMMENT = 12 +SCE_CAML_COMMENT1 = 13 +SCE_CAML_COMMENT2 = 14 +SCE_CAML_COMMENT3 = 15 +SCE_HA_DEFAULT = 0 +SCE_HA_IDENTIFIER = 1 +SCE_HA_KEYWORD = 2 +SCE_HA_NUMBER = 3 +SCE_HA_STRING = 4 +SCE_HA_CHARACTER = 5 +SCE_HA_CLASS = 6 +SCE_HA_MODULE = 7 +SCE_HA_CAPITAL = 8 +SCE_HA_DATA = 9 +SCE_HA_IMPORT = 10 +SCE_HA_OPERATOR = 11 +SCE_HA_INSTANCE = 12 +SCE_HA_COMMENTLINE = 13 +SCE_HA_COMMENTBLOCK = 14 +SCE_HA_COMMENTBLOCK2 = 15 +SCE_HA_COMMENTBLOCK3 = 16 +SCE_T3_DEFAULT = 0 +SCE_T3_X_DEFAULT = 1 +SCE_T3_PREPROCESSOR = 2 +SCE_T3_BLOCK_COMMENT = 3 +SCE_T3_LINE_COMMENT = 4 +SCE_T3_OPERATOR = 5 +SCE_T3_KEYWORD = 6 +SCE_T3_NUMBER = 7 +SCE_T3_IDENTIFIER = 8 +SCE_T3_S_STRING = 9 +SCE_T3_D_STRING = 10 +SCE_T3_X_STRING = 11 +SCE_T3_LIB_DIRECTIVE = 12 +SCE_T3_MSG_PARAM = 13 +SCE_T3_HTML_TAG = 14 +SCE_T3_HTML_DEFAULT = 15 +SCE_T3_HTML_STRING = 16 +SCE_T3_USER1 = 17 +SCE_T3_USER2 = 18 +SCE_T3_USER3 = 19 +SCE_T3_BRACE = 20 +SCE_REBOL_DEFAULT = 0 +SCE_REBOL_COMMENTLINE = 1 +SCE_REBOL_COMMENTBLOCK = 2 +SCE_REBOL_PREFACE = 3 +SCE_REBOL_OPERATOR = 4 +SCE_REBOL_CHARACTER = 5 +SCE_REBOL_QUOTEDSTRING = 6 +SCE_REBOL_BRACEDSTRING = 7 +SCE_REBOL_NUMBER = 8 +SCE_REBOL_PAIR = 9 +SCE_REBOL_TUPLE = 10 +SCE_REBOL_BINARY = 11 +SCE_REBOL_MONEY = 12 +SCE_REBOL_ISSUE = 13 +SCE_REBOL_TAG = 14 +SCE_REBOL_FILE = 15 +SCE_REBOL_EMAIL = 16 +SCE_REBOL_URL = 17 +SCE_REBOL_DATE = 18 +SCE_REBOL_TIME = 19 +SCE_REBOL_IDENTIFIER = 20 +SCE_REBOL_WORD = 21 +SCE_REBOL_WORD2 = 22 +SCE_REBOL_WORD3 = 23 +SCE_REBOL_WORD4 = 24 +SCE_REBOL_WORD5 = 25 +SCE_REBOL_WORD6 = 26 +SCE_REBOL_WORD7 = 27 +SCE_REBOL_WORD8 = 28 +SCE_SQL_DEFAULT = 0 +SCE_SQL_COMMENT = 1 +SCE_SQL_COMMENTLINE = 2 +SCE_SQL_COMMENTDOC = 3 +SCE_SQL_NUMBER = 4 +SCE_SQL_WORD = 5 +SCE_SQL_STRING = 6 +SCE_SQL_CHARACTER = 7 +SCE_SQL_SQLPLUS = 8 +SCE_SQL_SQLPLUS_PROMPT = 9 +SCE_SQL_OPERATOR = 10 +SCE_SQL_IDENTIFIER = 11 +SCE_SQL_SQLPLUS_COMMENT = 13 +SCE_SQL_COMMENTLINEDOC = 15 +SCE_SQL_WORD2 = 16 +SCE_SQL_COMMENTDOCKEYWORD = 17 +SCE_SQL_COMMENTDOCKEYWORDERROR = 18 +SCE_SQL_USER1 = 19 +SCE_SQL_USER2 = 20 +SCE_SQL_USER3 = 21 +SCE_SQL_USER4 = 22 +SCE_SQL_QUOTEDIDENTIFIER = 23 +SCE_ST_DEFAULT = 0 +SCE_ST_STRING = 1 +SCE_ST_NUMBER = 2 +SCE_ST_COMMENT = 3 +SCE_ST_SYMBOL = 4 +SCE_ST_BINARY = 5 +SCE_ST_BOOL = 6 +SCE_ST_SELF = 7 +SCE_ST_SUPER = 8 +SCE_ST_NIL = 9 +SCE_ST_GLOBAL = 10 +SCE_ST_RETURN = 11 +SCE_ST_SPECIAL = 12 +SCE_ST_KWSEND = 13 +SCE_ST_ASSIGN = 14 +SCE_ST_CHARACTER = 15 +SCE_ST_SPEC_SEL = 16 +SCE_FS_DEFAULT = 0 +SCE_FS_COMMENT = 1 +SCE_FS_COMMENTLINE = 2 +SCE_FS_COMMENTDOC = 3 +SCE_FS_COMMENTLINEDOC = 4 +SCE_FS_COMMENTDOCKEYWORD = 5 +SCE_FS_COMMENTDOCKEYWORDERROR = 6 +SCE_FS_KEYWORD = 7 +SCE_FS_KEYWORD2 = 8 +SCE_FS_KEYWORD3 = 9 +SCE_FS_KEYWORD4 = 10 +SCE_FS_NUMBER = 11 +SCE_FS_STRING = 12 +SCE_FS_PREPROCESSOR = 13 +SCE_FS_OPERATOR = 14 +SCE_FS_IDENTIFIER = 15 +SCE_FS_DATE = 16 +SCE_FS_STRINGEOL = 17 +SCE_FS_CONSTANT = 18 +SCE_FS_ASM = 19 +SCE_FS_LABEL = 20 +SCE_FS_ERROR = 21 +SCE_FS_HEXNUMBER = 22 +SCE_FS_BINNUMBER = 23 +SCE_CSOUND_DEFAULT = 0 +SCE_CSOUND_COMMENT = 1 +SCE_CSOUND_NUMBER = 2 +SCE_CSOUND_OPERATOR = 3 +SCE_CSOUND_INSTR = 4 +SCE_CSOUND_IDENTIFIER = 5 +SCE_CSOUND_OPCODE = 6 +SCE_CSOUND_HEADERSTMT = 7 +SCE_CSOUND_USERKEYWORD = 8 +SCE_CSOUND_COMMENTBLOCK = 9 +SCE_CSOUND_PARAM = 10 +SCE_CSOUND_ARATE_VAR = 11 +SCE_CSOUND_KRATE_VAR = 12 +SCE_CSOUND_IRATE_VAR = 13 +SCE_CSOUND_GLOBAL_VAR = 14 +SCE_CSOUND_STRINGEOL = 15 +SCE_INNO_DEFAULT = 0 +SCE_INNO_COMMENT = 1 +SCE_INNO_KEYWORD = 2 +SCE_INNO_PARAMETER = 3 +SCE_INNO_SECTION = 4 +SCE_INNO_PREPROC = 5 +SCE_INNO_PREPROC_INLINE = 6 +SCE_INNO_COMMENT_PASCAL = 7 +SCE_INNO_KEYWORD_PASCAL = 8 +SCE_INNO_KEYWORD_USER = 9 +SCE_INNO_STRING_DOUBLE = 10 +SCE_INNO_STRING_SINGLE = 11 +SCE_INNO_IDENTIFIER = 12 +SCE_OPAL_SPACE = 0 +SCE_OPAL_COMMENT_BLOCK = 1 +SCE_OPAL_COMMENT_LINE = 2 +SCE_OPAL_INTEGER = 3 +SCE_OPAL_KEYWORD = 4 +SCE_OPAL_SORT = 5 +SCE_OPAL_STRING = 6 +SCE_OPAL_PAR = 7 +SCE_OPAL_BOOL_CONST = 8 +SCE_OPAL_DEFAULT = 32 +SCE_SPICE_DEFAULT = 0 +SCE_SPICE_IDENTIFIER = 1 +SCE_SPICE_KEYWORD = 2 +SCE_SPICE_KEYWORD2 = 3 +SCE_SPICE_KEYWORD3 = 4 +SCE_SPICE_NUMBER = 5 +SCE_SPICE_DELIMITER = 6 +SCE_SPICE_VALUE = 7 +SCE_SPICE_COMMENTLINE = 8 +SCE_CMAKE_DEFAULT = 0 +SCE_CMAKE_COMMENT = 1 +SCE_CMAKE_STRINGDQ = 2 +SCE_CMAKE_STRINGLQ = 3 +SCE_CMAKE_STRINGRQ = 4 +SCE_CMAKE_COMMANDS = 5 +SCE_CMAKE_PARAMETERS = 6 +SCE_CMAKE_VARIABLE = 7 +SCE_CMAKE_USERDEFINED = 8 +SCE_CMAKE_WHILEDEF = 9 +SCE_CMAKE_FOREACHDEF = 10 +SCE_CMAKE_IFDEFINEDEF = 11 +SCE_CMAKE_MACRODEF = 12 +SCE_CMAKE_STRINGVAR = 13 +SCE_CMAKE_NUMBER = 14 +SCE_GAP_DEFAULT = 0 +SCE_GAP_IDENTIFIER = 1 +SCE_GAP_KEYWORD = 2 +SCE_GAP_KEYWORD2 = 3 +SCE_GAP_KEYWORD3 = 4 +SCE_GAP_KEYWORD4 = 5 +SCE_GAP_STRING = 6 +SCE_GAP_CHAR = 7 +SCE_GAP_OPERATOR = 8 +SCE_GAP_COMMENT = 9 +SCE_GAP_NUMBER = 10 +SCE_GAP_STRINGEOL = 11 +SCE_PLM_DEFAULT = 0 +SCE_PLM_COMMENT = 1 +SCE_PLM_STRING = 2 +SCE_PLM_NUMBER = 3 +SCE_PLM_IDENTIFIER = 4 +SCE_PLM_OPERATOR = 5 +SCE_PLM_CONTROL = 6 +SCE_PLM_KEYWORD = 7 +SCE_4GL_DEFAULT = 0 +SCE_4GL_NUMBER = 1 +SCE_4GL_WORD = 2 +SCE_4GL_STRING = 3 +SCE_4GL_CHARACTER = 4 +SCE_4GL_PREPROCESSOR = 5 +SCE_4GL_OPERATOR = 6 +SCE_4GL_IDENTIFIER = 7 +SCE_4GL_BLOCK = 8 +SCE_4GL_END = 9 +SCE_4GL_COMMENT1 = 10 +SCE_4GL_COMMENT2 = 11 +SCE_4GL_COMMENT3 = 12 +SCE_4GL_COMMENT4 = 13 +SCE_4GL_COMMENT5 = 14 +SCE_4GL_COMMENT6 = 15 +SCE_4GL_DEFAULT_ = 16 +SCE_4GL_NUMBER_ = 17 +SCE_4GL_WORD_ = 18 +SCE_4GL_STRING_ = 19 +SCE_4GL_CHARACTER_ = 20 +SCE_4GL_PREPROCESSOR_ = 21 +SCE_4GL_OPERATOR_ = 22 +SCE_4GL_IDENTIFIER_ = 23 +SCE_4GL_BLOCK_ = 24 +SCE_4GL_END_ = 25 +SCE_4GL_COMMENT1_ = 26 +SCE_4GL_COMMENT2_ = 27 +SCE_4GL_COMMENT3_ = 28 +SCE_4GL_COMMENT4_ = 29 +SCE_4GL_COMMENT5_ = 30 +SCE_4GL_COMMENT6_ = 31 +SCE_ABAQUS_DEFAULT = 0 +SCE_ABAQUS_COMMENT = 1 +SCE_ABAQUS_COMMENTBLOCK = 2 +SCE_ABAQUS_NUMBER = 3 +SCE_ABAQUS_STRING = 4 +SCE_ABAQUS_OPERATOR = 5 +SCE_ABAQUS_WORD = 6 +SCE_ABAQUS_PROCESSOR = 7 +SCE_ABAQUS_COMMAND = 8 +SCE_ABAQUS_SLASHCOMMAND = 9 +SCE_ABAQUS_STARCOMMAND = 10 +SCE_ABAQUS_ARGUMENT = 11 +SCE_ABAQUS_FUNCTION = 12 +SCE_ASY_DEFAULT = 0 +SCE_ASY_COMMENT = 1 +SCE_ASY_COMMENTLINE = 2 +SCE_ASY_NUMBER = 3 +SCE_ASY_WORD = 4 +SCE_ASY_STRING = 5 +SCE_ASY_CHARACTER = 6 +SCE_ASY_OPERATOR = 7 +SCE_ASY_IDENTIFIER = 8 +SCE_ASY_STRINGEOL = 9 +SCE_ASY_COMMENTLINEDOC = 10 +SCE_ASY_WORD2 = 11 +SCE_R_DEFAULT = 0 +SCE_R_COMMENT = 1 +SCE_R_KWORD = 2 +SCE_R_BASEKWORD = 3 +SCE_R_OTHERKWORD = 4 +SCE_R_NUMBER = 5 +SCE_R_STRING = 6 +SCE_R_STRING2 = 7 +SCE_R_OPERATOR = 8 +SCE_R_IDENTIFIER = 9 +SCE_R_INFIX = 10 +SCE_R_INFIXEOL = 11 +SCE_MAGIK_DEFAULT = 0 +SCE_MAGIK_COMMENT = 1 +SCE_MAGIK_HYPER_COMMENT = 16 +SCE_MAGIK_STRING = 2 +SCE_MAGIK_CHARACTER = 3 +SCE_MAGIK_NUMBER = 4 +SCE_MAGIK_IDENTIFIER = 5 +SCE_MAGIK_OPERATOR = 6 +SCE_MAGIK_FLOW = 7 +SCE_MAGIK_CONTAINER = 8 +SCE_MAGIK_BRACKET_BLOCK = 9 +SCE_MAGIK_BRACE_BLOCK = 10 +SCE_MAGIK_SQBRACKET_BLOCK = 11 +SCE_MAGIK_UNKNOWN_KEYWORD = 12 +SCE_MAGIK_KEYWORD = 13 +SCE_MAGIK_PRAGMA = 14 +SCE_MAGIK_SYMBOL = 15 +SCE_POWERSHELL_DEFAULT = 0 +SCE_POWERSHELL_COMMENT = 1 +SCE_POWERSHELL_STRING = 2 +SCE_POWERSHELL_CHARACTER = 3 +SCE_POWERSHELL_NUMBER = 4 +SCE_POWERSHELL_VARIABLE = 5 +SCE_POWERSHELL_OPERATOR = 6 +SCE_POWERSHELL_IDENTIFIER = 7 +SCE_POWERSHELL_KEYWORD = 8 +SCE_POWERSHELL_CMDLET = 9 +SCE_POWERSHELL_ALIAS = 10 +SCE_MYSQL_DEFAULT = 0 +SCE_MYSQL_COMMENT = 1 +SCE_MYSQL_COMMENTLINE = 2 +SCE_MYSQL_VARIABLE = 3 +SCE_MYSQL_SYSTEMVARIABLE = 4 +SCE_MYSQL_KNOWNSYSTEMVARIABLE = 5 +SCE_MYSQL_NUMBER = 6 +SCE_MYSQL_MAJORKEYWORD = 7 +SCE_MYSQL_KEYWORD = 8 +SCE_MYSQL_DATABASEOBJECT = 9 +SCE_MYSQL_PROCEDUREKEYWORD = 10 +SCE_MYSQL_STRING = 11 +SCE_MYSQL_SQSTRING = 12 +SCE_MYSQL_DQSTRING = 13 +SCE_MYSQL_OPERATOR = 14 +SCE_MYSQL_FUNCTION = 15 +SCE_MYSQL_IDENTIFIER = 16 +SCE_MYSQL_QUOTEDIDENTIFIER = 17 +SCE_MYSQL_USER1 = 18 +SCE_MYSQL_USER2 = 19 +SCE_MYSQL_USER3 = 20 +SCE_PO_DEFAULT = 0 +SCE_PO_COMMENT = 1 +SCE_PO_MSGID = 2 +SCE_PO_MSGID_TEXT = 3 +SCE_PO_MSGSTR = 4 +SCE_PO_MSGSTR_TEXT = 5 +SCE_PO_MSGCTXT = 6 +SCE_PO_MSGCTXT_TEXT = 7 +SCE_PO_FUZZY = 8 +SCLEX_ASP = 29 +SCLEX_PHP = 30 diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/view.py b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/view.py new file mode 100644 index 0000000000000000000000000000000000000000..3783666fc8dcb7b1b53411ab5dfc07ea061efe29 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/scintilla/view.py @@ -0,0 +1,832 @@ +# A general purpose MFC CCtrlView view that uses Scintilla. + +import array +import os +import re +import string +import struct +import sys + +import __main__ # for attribute lookup +import afxres +import win32con +import win32ui +from pywin.mfc import dialog, docview + +from . import IDLEenvironment # IDLE emulation. +from . import bindings, control, keycodes, scintillacon + +PRINTDLGORD = 1538 +IDC_PRINT_MAG_EDIT = 1010 +EM_FORMATRANGE = win32con.WM_USER + 57 + +wordbreaks = "._" + string.ascii_uppercase + string.ascii_lowercase + string.digits + +patImport = re.compile("import (?P.*)") + +_event_commands = [ + # File menu + "win32ui.ID_FILE_LOCATE", + "win32ui.ID_FILE_CHECK", + "afxres.ID_FILE_CLOSE", + "afxres.ID_FILE_NEW", + "afxres.ID_FILE_OPEN", + "afxres.ID_FILE_SAVE", + "afxres.ID_FILE_SAVE_AS", + "win32ui.ID_FILE_SAVE_ALL", + # Edit menu + "afxres.ID_EDIT_UNDO", + "afxres.ID_EDIT_REDO", + "afxres.ID_EDIT_CUT", + "afxres.ID_EDIT_COPY", + "afxres.ID_EDIT_PASTE", + "afxres.ID_EDIT_SELECT_ALL", + "afxres.ID_EDIT_FIND", + "afxres.ID_EDIT_REPEAT", + "afxres.ID_EDIT_REPLACE", + # View menu + "win32ui.ID_VIEW_WHITESPACE", + "win32ui.ID_VIEW_FIXED_FONT", + "win32ui.ID_VIEW_BROWSE", + "win32ui.ID_VIEW_INTERACTIVE", + # Window menu + "afxres.ID_WINDOW_ARRANGE", + "afxres.ID_WINDOW_CASCADE", + "afxres.ID_WINDOW_NEW", + "afxres.ID_WINDOW_SPLIT", + "afxres.ID_WINDOW_TILE_HORZ", + "afxres.ID_WINDOW_TILE_VERT", + # Others + "afxres.ID_APP_EXIT", + "afxres.ID_APP_ABOUT", +] + +_extra_event_commands = [ + ("EditDelete", afxres.ID_EDIT_CLEAR), + ("LocateModule", win32ui.ID_FILE_LOCATE), + ("GotoLine", win32ui.ID_EDIT_GOTO_LINE), + ("DbgBreakpointToggle", win32ui.IDC_DBG_ADD), + ("DbgGo", win32ui.IDC_DBG_GO), + ("DbgStepOver", win32ui.IDC_DBG_STEPOVER), + ("DbgStep", win32ui.IDC_DBG_STEP), + ("DbgStepOut", win32ui.IDC_DBG_STEPOUT), + ("DbgBreakpointClearAll", win32ui.IDC_DBG_CLEAR), + ("DbgClose", win32ui.IDC_DBG_CLOSE), +] + +event_commands = [] + + +def _CreateEvents(): + for name in _event_commands: + val = eval(name) + name_parts = name.split("_")[1:] + name_parts = [p.capitalize() for p in name_parts] + event = "".join(name_parts) + event_commands.append((event, val)) + for name, id in _extra_event_commands: + event_commands.append((name, id)) + + +_CreateEvents() +del _event_commands +del _extra_event_commands + +command_reflectors = [ + (win32ui.ID_EDIT_UNDO, win32con.WM_UNDO), + (win32ui.ID_EDIT_REDO, scintillacon.SCI_REDO), + (win32ui.ID_EDIT_CUT, win32con.WM_CUT), + (win32ui.ID_EDIT_COPY, win32con.WM_COPY), + (win32ui.ID_EDIT_PASTE, win32con.WM_PASTE), + (win32ui.ID_EDIT_CLEAR, win32con.WM_CLEAR), + (win32ui.ID_EDIT_SELECT_ALL, scintillacon.SCI_SELECTALL), +] + + +def DoBraceMatch(control): + curPos = control.SCIGetCurrentPos() + charBefore = " " + if curPos: + charBefore = control.SCIGetCharAt(curPos - 1) + charAt = control.SCIGetCharAt(curPos) + braceAtPos = braceOpposite = -1 + if charBefore in "[](){}": + braceAtPos = curPos - 1 + if braceAtPos == -1: + if charAt in "[](){}": + braceAtPos = curPos + if braceAtPos != -1: + braceOpposite = control.SCIBraceMatch(braceAtPos, 0) + if braceAtPos != -1 and braceOpposite == -1: + control.SCIBraceBadHighlight(braceAtPos) + else: + # either clear them both or set them both. + control.SCIBraceHighlight(braceAtPos, braceOpposite) + + +def _get_class_attributes(ob): + # Recurse into base classes looking for attributes + items = [] + try: + items = items + dir(ob) + for i in ob.__bases__: + for item in _get_class_attributes(i): + if item not in items: + items.append(item) + except AttributeError: + pass + return items + + +# Supposed to look like an MFC CEditView, but +# also supports IDLE extensions and other source code generic features. +class CScintillaView(docview.CtrlView, control.CScintillaColorEditInterface): + def __init__(self, doc): + docview.CtrlView.__init__( + self, + doc, + "Scintilla", + win32con.WS_CHILD + | win32con.WS_VSCROLL + | win32con.WS_HSCROLL + | win32con.WS_CLIPCHILDREN + | win32con.WS_VISIBLE, + ) + self._tabWidth = ( + 8 # Mirror of what we send to Scintilla - never change this directly + ) + self.bAutoCompleteAttributes = 1 + self.bShowCallTips = 1 + self.bMatchBraces = 0 # Editor option will default this to true later! + self.bindings = bindings.BindingsManager(self) + + self.idle = IDLEenvironment.IDLEEditorWindow(self) + self.idle.IDLEExtension("AutoExpand") + # SendScintilla is called so frequently it is worth optimizing. + self.SendScintilla = self._obj_.SendMessage + + def _MakeColorizer(self): + ext = os.path.splitext(self.GetDocument().GetPathName())[1] + from . import formatter + + return formatter.BuiltinPythonSourceFormatter(self, ext) + + # def SendScintilla(self, msg, w=0, l=0): + # return self._obj_.SendMessage(msg, w, l) + + def SCISetTabWidth(self, width): + # I need to remember the tab-width for the AutoIndent extension. This may go. + self._tabWidth = width + control.CScintillaEditInterface.SCISetTabWidth(self, width) + + def GetTabWidth(self): + return self._tabWidth + + def HookHandlers(self): + # Create events for all the menu names. + for name, val in event_commands: + # handler = lambda id, code, tosend=val, parent=parent: parent.OnCommand(tosend, 0) and 0 + self.bindings.bind(name, None, cid=val) + + # Hook commands that do nothing other than send Scintilla messages. + for command, reflection in command_reflectors: + handler = ( + lambda id, code, ss=self.SendScintilla, tosend=reflection: ss(tosend) + and 0 + ) + self.HookCommand(handler, command) + + self.HookCommand(self.OnCmdViewWS, win32ui.ID_VIEW_WHITESPACE) + self.HookCommandUpdate(self.OnUpdateViewWS, win32ui.ID_VIEW_WHITESPACE) + self.HookCommand( + self.OnCmdViewIndentationGuides, win32ui.ID_VIEW_INDENTATIONGUIDES + ) + self.HookCommandUpdate( + self.OnUpdateViewIndentationGuides, win32ui.ID_VIEW_INDENTATIONGUIDES + ) + self.HookCommand(self.OnCmdViewRightEdge, win32ui.ID_VIEW_RIGHT_EDGE) + self.HookCommandUpdate(self.OnUpdateViewRightEdge, win32ui.ID_VIEW_RIGHT_EDGE) + self.HookCommand(self.OnCmdViewEOL, win32ui.ID_VIEW_EOL) + self.HookCommandUpdate(self.OnUpdateViewEOL, win32ui.ID_VIEW_EOL) + self.HookCommand(self.OnCmdViewFixedFont, win32ui.ID_VIEW_FIXED_FONT) + self.HookCommandUpdate(self.OnUpdateViewFixedFont, win32ui.ID_VIEW_FIXED_FONT) + self.HookCommand(self.OnCmdFileLocate, win32ui.ID_FILE_LOCATE) + self.HookCommand(self.OnCmdEditFind, win32ui.ID_EDIT_FIND) + self.HookCommand(self.OnCmdEditRepeat, win32ui.ID_EDIT_REPEAT) + self.HookCommand(self.OnCmdEditReplace, win32ui.ID_EDIT_REPLACE) + self.HookCommand(self.OnCmdGotoLine, win32ui.ID_EDIT_GOTO_LINE) + self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT) + self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT_DIRECT) + self.HookCommand(self.OnFilePrintPreview, win32ui.ID_FILE_PRINT_PREVIEW) + # Key bindings. + self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN) + self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN) + # Hook wheeley mouse events + # self.HookMessage(self.OnMouseWheel, win32con.WM_MOUSEWHEEL) + self.HookFormatter() + + def OnInitialUpdate(self): + doc = self.GetDocument() + + # Enable Unicode + self.SendScintilla(scintillacon.SCI_SETCODEPAGE, scintillacon.SC_CP_UTF8, 0) + self.SendScintilla(scintillacon.SCI_SETKEYSUNICODE, 1, 0) + + # Create margins + self.SendScintilla( + scintillacon.SCI_SETMARGINTYPEN, 1, scintillacon.SC_MARGIN_SYMBOL + ) + self.SendScintilla(scintillacon.SCI_SETMARGINMASKN, 1, 0xF) + self.SendScintilla( + scintillacon.SCI_SETMARGINTYPEN, 2, scintillacon.SC_MARGIN_SYMBOL + ) + self.SendScintilla( + scintillacon.SCI_SETMARGINMASKN, 2, scintillacon.SC_MASK_FOLDERS + ) + self.SendScintilla(scintillacon.SCI_SETMARGINSENSITIVEN, 2, 1) + + self.GetDocument().HookViewNotifications( + self + ) # is there an MFC way to grab this? + self.HookHandlers() + + # Load the configuration information. + self.OnWinIniChange(None) + + self.SetSel() + + self.GetDocument().FinalizeViewCreation( + self + ) # is there an MFC way to grab this? + + def _GetSubConfigNames(self): + return None # By default we use only sections without sub-sections. + + def OnWinIniChange(self, section=None): + self.bindings.prepare_configure() + try: + self.DoConfigChange() + finally: + self.bindings.complete_configure() + + def DoConfigChange(self): + # Bit of a hack I dont kow what to do about - these should be "editor options" + from pywin.framework.editor import GetEditorOption + + self.bAutoCompleteAttributes = GetEditorOption("Autocomplete Attributes", 1) + self.bShowCallTips = GetEditorOption("Show Call Tips", 1) + # Update the key map and extension data. + configManager.configure(self, self._GetSubConfigNames()) + if configManager.last_error: + win32ui.MessageBox(configManager.last_error, "Configuration Error") + self.bMatchBraces = GetEditorOption("Match Braces", 1) + self.ApplyFormattingStyles(1) + + def OnDestroy(self, msg): + self.bindings.close() + self.bindings = None + self.idle.close() + self.idle = None + control.CScintillaColorEditInterface.close(self) + return docview.CtrlView.OnDestroy(self, msg) + + def OnMouseWheel(self, msg): + zDelta = msg[2] >> 16 + vpos = self.GetScrollPos(win32con.SB_VERT) + vpos = vpos - zDelta / 40 # 3 lines per notch + self.SetScrollPos(win32con.SB_VERT, vpos) + self.SendScintilla( + win32con.WM_VSCROLL, (vpos << 16) | win32con.SB_THUMBPOSITION, 0 + ) + + def OnBraceMatch(self, std, extra): + if not self.bMatchBraces: + return + DoBraceMatch(self) + + def OnNeedShown(self, std, extra): + notify = self.SCIUnpackNotifyMessage(extra) + # OnNeedShown is called before an edit operation when + # text is folded (as it is possible the text insertion will happen + # in a folded region.) As this happens _before_ the insert, + # we ignore the length (if we are at EOF, pos + length may + # actually be beyond the end of buffer) + self.EnsureCharsVisible(notify.position) + + def EnsureCharsVisible(self, start, end=None): + if end is None: + end = start + lineStart = self.LineFromChar(min(start, end)) + lineEnd = self.LineFromChar(max(start, end)) + while lineStart <= lineEnd: + self.SCIEnsureVisible(lineStart) + lineStart = lineStart + 1 + + # Helper to add an event to a menu. + def AppendMenu(self, menu, text="", event=None, flags=None, checked=0): + if event is None: + assert flags is not None, "No event or custom flags!" + cmdid = 0 + else: + cmdid = self.bindings.get_command_id(event) + if cmdid is None: + # No event of that name - no point displaying it. + print( + 'View.AppendMenu(): Unknown event "%s" specified for menu text "%s" - ignored' + % (event, text) + ) + return + keyname = configManager.get_key_binding(event, self._GetSubConfigNames()) + if keyname is not None: + text = text + "\t" + keyname + if flags is None: + flags = win32con.MF_STRING | win32con.MF_ENABLED + if checked: + flags = flags | win32con.MF_CHECKED + menu.AppendMenu(flags, cmdid, text) + + def OnKeyDown(self, msg): + return self.bindings.fire_key_event(msg) + + def GotoEndOfFileEvent(self, event): + self.SetSel(-1) + + def KeyDotEvent(self, event): + ## Don't trigger autocomplete if any text is selected + s, e = self.GetSel() + if s != e: + return 1 + self.SCIAddText(".") + if self.bAutoCompleteAttributes: + self._AutoComplete() + + # View Whitespace/EOL/Indentation UI. + + def OnCmdViewWS(self, cmd, code): # Handle the menu command + viewWS = self.SCIGetViewWS() + self.SCISetViewWS(not viewWS) + + def OnUpdateViewWS(self, cmdui): # Update the tick on the UI. + cmdui.SetCheck(self.SCIGetViewWS()) + cmdui.Enable() + + def OnCmdViewIndentationGuides(self, cmd, code): # Handle the menu command + viewIG = self.SCIGetIndentationGuides() + self.SCISetIndentationGuides(not viewIG) + + def OnUpdateViewIndentationGuides(self, cmdui): # Update the tick on the UI. + cmdui.SetCheck(self.SCIGetIndentationGuides()) + cmdui.Enable() + + def OnCmdViewRightEdge(self, cmd, code): # Handle the menu command + if self.SCIGetEdgeMode() == scintillacon.EDGE_NONE: + mode = scintillacon.EDGE_BACKGROUND + else: + mode = scintillacon.EDGE_NONE + self.SCISetEdgeMode(mode) + + def OnUpdateViewRightEdge(self, cmdui): # Update the tick on the UI. + cmdui.SetCheck(self.SCIGetEdgeMode() != scintillacon.EDGE_NONE) + cmdui.Enable() + + def OnCmdViewEOL(self, cmd, code): # Handle the menu command + viewEOL = self.SCIGetViewEOL() + self.SCISetViewEOL(not viewEOL) + + def OnUpdateViewEOL(self, cmdui): # Update the tick on the UI. + cmdui.SetCheck(self.SCIGetViewEOL()) + cmdui.Enable() + + def OnCmdViewFixedFont(self, cmd, code): # Handle the menu command + self._GetColorizer().bUseFixed = not self._GetColorizer().bUseFixed + self.ApplyFormattingStyles(0) + # Ensure the selection is visible! + self.ScrollCaret() + + def OnUpdateViewFixedFont(self, cmdui): # Update the tick on the UI. + c = self._GetColorizer() + if c is not None: + cmdui.SetCheck(c.bUseFixed) + cmdui.Enable(c is not None) + + def OnCmdEditFind(self, cmd, code): + from . import find + + find.ShowFindDialog() + + def OnCmdEditRepeat(self, cmd, code): + from . import find + + find.FindNext() + + def OnCmdEditReplace(self, cmd, code): + from . import find + + find.ShowReplaceDialog() + + def OnCmdFileLocate(self, cmd, id): + line = self.GetLine().strip() + import pywin.framework.scriptutils + + m = patImport.match(line) + if m: + # Module name on this line - locate that! + modName = m.group("name") + fileName = pywin.framework.scriptutils.LocatePythonFile(modName) + if fileName is None: + win32ui.SetStatusText("Can't locate module %s" % modName) + return 1 # Let the default get it. + else: + win32ui.GetApp().OpenDocumentFile(fileName) + else: + # Just to a "normal" locate - let the default handler get it. + return 1 + return 0 + + def OnCmdGotoLine(self, cmd, id): + try: + lineNo = int(input("Enter Line Number")) - 1 + except (ValueError, KeyboardInterrupt): + return 0 + self.SCIEnsureVisible(lineNo) + self.SCIGotoLine(lineNo) + return 0 + + def SaveTextFile(self, filename, encoding=None): + doc = self.GetDocument() + doc._SaveTextToFile(self, filename, encoding=encoding) + doc.SetModifiedFlag(0) + return 1 + + def _AutoComplete(self): + def list2dict(l): + ret = {} + for i in l: + ret[i] = None + return ret + + self.SCIAutoCCancel() # Cancel old auto-complete lists. + # First try and get an object without evaluating calls + ob = self._GetObjectAtPos(bAllowCalls=0) + # If that failed, try and process call or indexing to get the object. + if ob is None: + ob = self._GetObjectAtPos(bAllowCalls=1) + items_dict = {} + if ob is not None: + try: # Catch unexpected errors when fetching attribute names from the object + # extra attributes of win32ui objects + if hasattr(ob, "_obj_"): + try: + items_dict.update(list2dict(dir(ob._obj_))) + except AttributeError: + pass # object has no __dict__ + + # normal attributes + try: + items_dict.update(list2dict(dir(ob))) + except AttributeError: + pass # object has no __dict__ + if hasattr(ob, "__class__"): + items_dict.update(list2dict(_get_class_attributes(ob.__class__))) + # The object may be a COM object with typelib support - lets see if we can get its props. + # (contributed by Stefan Migowsky) + try: + # Get the automation attributes + items_dict.update(ob.__class__._prop_map_get_) + # See if there is an write only property + # could be optimized + items_dict.update(ob.__class__._prop_map_put_) + # append to the already evaluated list + except AttributeError: + pass + # The object might be a pure COM dynamic dispatch with typelib support - lets see if we can get its props. + if hasattr(ob, "_oleobj_"): + try: + for iTI in range(0, ob._oleobj_.GetTypeInfoCount()): + typeInfo = ob._oleobj_.GetTypeInfo(iTI) + self._UpdateWithITypeInfo(items_dict, typeInfo) + except: + pass + except: + win32ui.SetStatusText( + "Error attempting to get object attributes - %s" + % (repr(sys.exc_info()[0]),) + ) + + # ensure all keys are strings. + items = [str(k) for k in items_dict.keys()] + # All names that start with "_" go! + items = [k for k in items if not k.startswith("_")] + + if not items: + # Heuristics a-la AutoExpand + # The idea is to find other usages of the current binding + # and assume, that it refers to the same object (or at least, + # to an object of the same type) + # Contributed by Vadim Chugunov [vadimch@yahoo.com] + left, right = self._GetWordSplit() + if left == "": # Ignore standalone dots + return None + # We limit our search to the current class, if that + # information is available + minline, maxline, curclass = self._GetClassInfoFromBrowser() + endpos = self.LineIndex(maxline) + text = self.GetTextRange(self.LineIndex(minline), endpos) + try: + l = re.findall(r"\b" + left + "\.\w+", text) + except re.error: + # parens etc may make an invalid RE, but this code wouldnt + # benefit even if the RE did work :-) + l = [] + prefix = len(left) + 1 + unique = {} + for li in l: + unique[li[prefix:]] = 1 + # Assuming traditional usage of self... + if curclass and left == "self": + self._UpdateWithClassMethods(unique, curclass) + + items = [ + word for word in unique.keys() if word[:2] != "__" or word[-2:] != "__" + ] + # Ignore the word currently to the right of the dot - probably a red-herring. + try: + items.remove(right[1:]) + except ValueError: + pass + if items: + items.sort() + self.SCIAutoCSetAutoHide(0) + self.SCIAutoCShow(items) + + def _UpdateWithITypeInfo(self, items_dict, typeInfo): + import pythoncom + + typeInfos = [typeInfo] + # suppress IDispatch and IUnknown methods + inspectedIIDs = {pythoncom.IID_IDispatch: None} + + while len(typeInfos) > 0: + typeInfo = typeInfos.pop() + typeAttr = typeInfo.GetTypeAttr() + + if typeAttr.iid not in inspectedIIDs: + inspectedIIDs[typeAttr.iid] = None + for iFun in range(0, typeAttr.cFuncs): + funDesc = typeInfo.GetFuncDesc(iFun) + funName = typeInfo.GetNames(funDesc.memid)[0] + if funName not in items_dict: + items_dict[funName] = None + + # Inspect the type info of all implemented types + # E.g. IShellDispatch5 implements IShellDispatch4 which implements IShellDispatch3 ... + for iImplType in range(0, typeAttr.cImplTypes): + iRefType = typeInfo.GetRefTypeOfImplType(iImplType) + refTypeInfo = typeInfo.GetRefTypeInfo(iRefType) + typeInfos.append(refTypeInfo) + + # TODO: This is kinda slow. Probably need some kind of cache + # here that is flushed upon file save + # Or maybe we don't need the superclass methods at all ? + def _UpdateWithClassMethods(self, dict, classinfo): + if not hasattr(classinfo, "methods"): + # No 'methods' - probably not what we think it is. + return + dict.update(classinfo.methods) + for super in classinfo.super: + if hasattr(super, "methods"): + self._UpdateWithClassMethods(dict, super) + + # Find which class definition caret is currently in and return + # indexes of the the first and the last lines of that class definition + # Data is obtained from module browser (if enabled) + def _GetClassInfoFromBrowser(self, pos=-1): + minline = 0 + maxline = self.GetLineCount() - 1 + doc = self.GetParentFrame().GetActiveDocument() + browser = None + try: + if doc is not None: + browser = doc.GetAllViews()[1] + except IndexError: + pass + if browser is None: + return (minline, maxline, None) # Current window has no browser + if not browser.list: + return (minline, maxline, None) # Not initialized + path = self.GetDocument().GetPathName() + if not path: + return (minline, maxline, None) # No current path + + import pywin.framework.scriptutils + + curmodule, path = pywin.framework.scriptutils.GetPackageModuleName(path) + try: + clbrdata = browser.list.root.clbrdata + except AttributeError: + return (minline, maxline, None) # No class data for this module. + curline = self.LineFromChar(pos) + curclass = None + # Find out which class we are in + for item in clbrdata.values(): + if item.module == curmodule: + item_lineno = ( + item.lineno - 1 + ) # Scintilla counts lines from 0, whereas pyclbr - from 1 + if minline < item_lineno <= curline: + minline = item_lineno + curclass = item + if curline < item_lineno < maxline: + maxline = item_lineno + return (minline, maxline, curclass) + + def _GetObjectAtPos(self, pos=-1, bAllowCalls=0): + left, right = self._GetWordSplit(pos, bAllowCalls) + if left: # It is an attribute lookup + # How is this for a hack! + namespace = sys.modules.copy() + namespace.update(__main__.__dict__) + # Get the debugger's context. + try: + from pywin.framework import interact + + if interact.edit is not None and interact.edit.currentView is not None: + globs, locs = interact.edit.currentView.GetContext()[:2] + if globs: + namespace.update(globs) + if locs: + namespace.update(locs) + except ImportError: + pass + try: + return eval(left, namespace) + except: + pass + return None + + def _GetWordSplit(self, pos=-1, bAllowCalls=0): + if pos == -1: + pos = self.GetSel()[0] - 1 # Character before current one + limit = self.GetTextLength() + before = [] + after = [] + index = pos - 1 + wordbreaks_use = wordbreaks + if bAllowCalls: + wordbreaks_use = wordbreaks_use + "()[]" + while index >= 0: + char = self.SCIGetCharAt(index) + if char not in wordbreaks_use: + break + before.insert(0, char) + index = index - 1 + index = pos + while index <= limit: + char = self.SCIGetCharAt(index) + if char not in wordbreaks_use: + break + after.append(char) + index = index + 1 + return "".join(before), "".join(after) + + def OnPrepareDC(self, dc, pInfo): + # print "OnPrepareDC for page", pInfo.GetCurPage(), "of", pInfo.GetFromPage(), "to", pInfo.GetToPage(), ", starts=", self.starts + if dc.IsPrinting(): + # Check if we are beyond the end. + # (only do this when actually printing, else messes up print preview!) + if not pInfo.GetPreview() and self.starts is not None: + prevPage = pInfo.GetCurPage() - 1 + if prevPage > 0 and self.starts[prevPage] >= self.GetTextLength(): + # All finished. + pInfo.SetContinuePrinting(0) + return + dc.SetMapMode(win32con.MM_TEXT) + + def OnPreparePrinting(self, pInfo): + flags = ( + win32ui.PD_USEDEVMODECOPIES | win32ui.PD_ALLPAGES | win32ui.PD_NOSELECTION + ) # Dont support printing just a selection. + # NOTE: Custom print dialogs are stopping the user's values from coming back :-( + # self.prtDlg = PrintDialog(pInfo, PRINTDLGORD, flags) + # pInfo.SetPrintDialog(self.prtDlg) + pInfo.SetMinPage(1) + # max page remains undefined for now. + pInfo.SetFromPage(1) + pInfo.SetToPage(1) + ret = self.DoPreparePrinting(pInfo) + return ret + + def OnBeginPrinting(self, dc, pInfo): + self.starts = None + return self._obj_.OnBeginPrinting(dc, pInfo) + + def CalculatePageRanges(self, dc, pInfo): + # Calculate page ranges and max page + self.starts = {0: 0} + metrics = dc.GetTextMetrics() + left, top, right, bottom = pInfo.GetDraw() + # Leave space at the top for the header. + rc = (left, top + int((9 * metrics["tmHeight"]) / 2), right, bottom) + pageStart = 0 + maxPage = 0 + textLen = self.GetTextLength() + while pageStart < textLen: + pageStart = self.FormatRange(dc, pageStart, textLen, rc, 0) + maxPage = maxPage + 1 + self.starts[maxPage] = pageStart + # And a sentinal for one page past the end + self.starts[maxPage + 1] = textLen + # When actually printing, maxPage doesnt have any effect at this late state. + # but is needed to make the Print Preview work correctly. + pInfo.SetMaxPage(maxPage) + + def OnFilePrintPreview(self, *arg): + self._obj_.OnFilePrintPreview() + + def OnFilePrint(self, *arg): + self._obj_.OnFilePrint() + + def FormatRange(self, dc, pageStart, lengthDoc, rc, draw): + """ + typedef struct _formatrange { + HDC hdc; + HDC hdcTarget; + RECT rc; + RECT rcPage; + CHARRANGE chrg;} FORMATRANGE; + """ + fmt = "PPIIIIIIIIll" + hdcRender = dc.GetHandleOutput() + hdcFormat = dc.GetHandleAttrib() + fr = struct.pack( + fmt, + hdcRender, + hdcFormat, + rc[0], + rc[1], + rc[2], + rc[3], + rc[0], + rc[1], + rc[2], + rc[3], + pageStart, + lengthDoc, + ) + nextPageStart = self.SendScintilla(EM_FORMATRANGE, draw, fr) + return nextPageStart + + def OnPrint(self, dc, pInfo): + metrics = dc.GetTextMetrics() + # print "dev", w, h, l, metrics['tmAscent'], metrics['tmDescent'] + if self.starts is None: + self.CalculatePageRanges(dc, pInfo) + pageNum = pInfo.GetCurPage() - 1 + # Setup the header of the page - docname on left, pagenum on right. + doc = self.GetDocument() + cxChar = metrics["tmAveCharWidth"] + cyChar = metrics["tmHeight"] + left, top, right, bottom = pInfo.GetDraw() + dc.TextOut(0, 2 * cyChar, doc.GetTitle()) + pagenum_str = win32ui.LoadString(afxres.AFX_IDS_PRINTPAGENUM) % (pageNum + 1,) + dc.SetTextAlign(win32con.TA_RIGHT) + dc.TextOut(right, 2 * cyChar, pagenum_str) + dc.SetTextAlign(win32con.TA_LEFT) + top = top + int((7 * cyChar) / 2) + dc.MoveTo(left, top) + dc.LineTo(right, top) + top = top + cyChar + rc = (left, top, right, bottom) + nextPageStart = self.FormatRange( + dc, self.starts[pageNum], self.starts[pageNum + 1], rc, 1 + ) + + +def LoadConfiguration(): + global configManager + # Bit of a hack I dont kow what to do about? + from .config import ConfigManager + + configName = rc = win32ui.GetProfileVal("Editor", "Keyboard Config", "default") + configManager = ConfigManager(configName) + if configManager.last_error: + bTryDefault = 0 + msg = "Error loading configuration '%s'\n\n%s" % ( + configName, + configManager.last_error, + ) + if configName != "default": + msg = msg + "\n\nThe default configuration will be loaded." + bTryDefault = 1 + win32ui.MessageBox(msg) + if bTryDefault: + configManager = ConfigManager("default") + if configManager.last_error: + win32ui.MessageBox( + "Error loading configuration 'default'\n\n%s" + % (configManager.last_error) + ) + + +configManager = None +LoadConfiguration() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/TraceCollector.py b/MLPY/Lib/site-packages/pythonwin/pywin/tools/TraceCollector.py new file mode 100644 index 0000000000000000000000000000000000000000..5800488b917afeac3c4e2f0cf84d271b4f069278 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/tools/TraceCollector.py @@ -0,0 +1,79 @@ +# win32traceutil like utility for Pythonwin +import _thread + +import win32api +import win32event +import win32trace +from pywin.framework import winout + +outputWindow = None + + +def CollectorThread(stopEvent, file): + win32trace.InitRead() + handle = win32trace.GetHandle() + # Run this thread at a lower priority to the main message-loop (and printing output) + # thread can keep up + import win32process + + win32process.SetThreadPriority( + win32api.GetCurrentThread(), win32process.THREAD_PRIORITY_BELOW_NORMAL + ) + + try: + while 1: + rc = win32event.WaitForMultipleObjects( + (handle, stopEvent), 0, win32event.INFINITE + ) + if rc == win32event.WAIT_OBJECT_0: + # About the only char we can't live with is \0! + file.write(win32trace.read().replace("\0", "")) + else: + # Stop event + break + finally: + win32trace.TermRead() + print("Thread dieing") + + +class WindowOutput(winout.WindowOutput): + def __init__(self, *args): + winout.WindowOutput.__init__(*(self,) + args) + self.hStopThread = win32event.CreateEvent(None, 0, 0, None) + _thread.start_new(CollectorThread, (self.hStopThread, self)) + + def _StopThread(self): + win32event.SetEvent(self.hStopThread) + self.hStopThread = None + + def Close(self): + self._StopThread() + winout.WindowOutput.Close(self) + # def OnViewDestroy(self, frame): + # return winout.WindowOutput.OnViewDestroy(self, frame) + # def Create(self, title=None, style = None): + # rc = winout.WindowOutput.Create(self, title, style) + return rc + + +def MakeOutputWindow(): + # Note that it will not show until the first string written or + # you pass bShow = 1 + global outputWindow + if outputWindow is None: + title = "Python Trace Collector" + # queueingFlag doesnt matter, as all output will come from new thread + outputWindow = WindowOutput(title, title) + # Let people know what this does! + msg = """\ +# This window will display output from any programs that import win32traceutil +# win32com servers registered with '--debug' are in this category. +""" + outputWindow.write(msg) + # force existing window open + outputWindow.write("") + return outputWindow + + +if __name__ == "__main__": + MakeOutputWindow() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__init__.py b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__init__.py @@ -0,0 +1 @@ + diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/TraceCollector.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/TraceCollector.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74858dd1c6315209ef5a7e1cfe4cc47aaf312fcd Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/TraceCollector.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0831581092e3211da204c38d5f534ff0052a9da Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/browseProjects.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/browseProjects.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7d7b41dea89e807e88153fa3cb6ed841bc6af8c Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/browseProjects.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/browser.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/browser.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1816bfb18861c21efa51f89f08929ea2293f6e8 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/browser.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/hierlist.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/hierlist.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4bbfa79c2f01788388b54f051a87bddb62d1a33 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/hierlist.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/regedit.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/regedit.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..637c4da139a79358da17a2628bc52917031fc8b6 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/regedit.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/regpy.cpython-39.pyc b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/regpy.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29741b5977d9ca9285dddc170ce673a133f9e516 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/pywin/tools/__pycache__/regpy.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/browseProjects.py b/MLPY/Lib/site-packages/pythonwin/pywin/tools/browseProjects.py new file mode 100644 index 0000000000000000000000000000000000000000..e3255579a1c0217ae20e5fb41b44044e29d14b7b --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/tools/browseProjects.py @@ -0,0 +1,324 @@ +import glob +import os +import pyclbr + +import afxres +import commctrl +import pywin.framework.scriptutils +import regutil +import win32api +import win32con +import win32ui +from pywin.mfc import dialog + +from . import hierlist + + +class HLIErrorItem(hierlist.HierListItem): + def __init__(self, text): + self.text = text + hierlist.HierListItem.__init__(self) + + def GetText(self): + return self.text + + +class HLICLBRItem(hierlist.HierListItem): + def __init__(self, name, file, lineno, suffix=""): + # If the 'name' object itself has a .name, use it. Not sure + # how this happens, but seems pyclbr related. + # See PyWin32 bug 817035 + self.name = getattr(name, "name", name) + self.file = file + self.lineno = lineno + self.suffix = suffix + + def __lt__(self, other): + return self.name < other.name + + def __eq__(self, other): + return self.name == other.name + + def GetText(self): + return self.name + self.suffix + + def TakeDefaultAction(self): + if self.file: + pywin.framework.scriptutils.JumpToDocument( + self.file, self.lineno, bScrollToTop=1 + ) + else: + win32ui.SetStatusText("The source of this object is unknown") + + def PerformItemSelected(self): + if self.file is None: + msg = "%s - source can not be located." % (self.name,) + else: + msg = "%s defined at line %d of %s" % (self.name, self.lineno, self.file) + win32ui.SetStatusText(msg) + + +class HLICLBRClass(HLICLBRItem): + def __init__(self, clbrclass, suffix=""): + try: + name = clbrclass.name + file = clbrclass.file + lineno = clbrclass.lineno + self.super = clbrclass.super + self.methods = clbrclass.methods + except AttributeError: + name = clbrclass + file = lineno = None + self.super = [] + self.methods = {} + HLICLBRItem.__init__(self, name, file, lineno, suffix) + + def GetSubList(self): + ret = [] + for c in self.super: + ret.append(HLICLBRClass(c, " (Parent class)")) + for meth, lineno in self.methods.items(): + ret.append(HLICLBRMethod(meth, self.file, lineno, " (method)")) + return ret + + def IsExpandable(self): + return len(self.methods) + len(self.super) + + def GetBitmapColumn(self): + return 21 + + +class HLICLBRFunction(HLICLBRClass): + def GetBitmapColumn(self): + return 22 + + +class HLICLBRMethod(HLICLBRItem): + def GetBitmapColumn(self): + return 22 + + +class HLIModuleItem(hierlist.HierListItem): + def __init__(self, path): + hierlist.HierListItem.__init__(self) + self.path = path + + def GetText(self): + return os.path.split(self.path)[1] + " (module)" + + def IsExpandable(self): + return 1 + + def TakeDefaultAction(self): + win32ui.GetApp().OpenDocumentFile(self.path) + + def GetBitmapColumn(self): + col = 4 # Default + try: + if win32api.GetFileAttributes(self.path) & win32con.FILE_ATTRIBUTE_READONLY: + col = 5 + except win32api.error: + pass + return col + + def GetSubList(self): + mod, path = pywin.framework.scriptutils.GetPackageModuleName(self.path) + win32ui.SetStatusText("Building class list - please wait...", 1) + win32ui.DoWaitCursor(1) + try: + try: + reader = pyclbr.readmodule_ex # Post 1.5.2 interface. + extra_msg = " or functions" + except AttributeError: + reader = pyclbr.readmodule + extra_msg = "" + data = reader(mod, [path]) + if data: + ret = [] + for item in data.values(): + if ( + item.__class__ != pyclbr.Class + ): # ie, it is a pyclbr Function instance (only introduced post 1.5.2) + ret.append(HLICLBRFunction(item, " (function)")) + else: + ret.append(HLICLBRClass(item, " (class)")) + ret.sort() + return ret + else: + return [HLIErrorItem("No Python classes%s in module." % (extra_msg,))] + finally: + win32ui.DoWaitCursor(0) + win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE)) + + +def MakePathSubList(path): + ret = [] + for filename in glob.glob(os.path.join(path, "*")): + if os.path.isdir(filename) and os.path.isfile( + os.path.join(filename, "__init__.py") + ): + ret.append(HLIDirectoryItem(filename, os.path.split(filename)[1])) + else: + if os.path.splitext(filename)[1].lower() in [".py", ".pyw"]: + ret.append(HLIModuleItem(filename)) + return ret + + +class HLIDirectoryItem(hierlist.HierListItem): + def __init__(self, path, displayName=None, bSubDirs=0): + hierlist.HierListItem.__init__(self) + self.path = path + self.bSubDirs = bSubDirs + if displayName: + self.displayName = displayName + else: + self.displayName = path + + def IsExpandable(self): + return 1 + + def GetText(self): + return self.displayName + + def GetSubList(self): + ret = MakePathSubList(self.path) + if ( + os.path.split(self.path)[1] == "win32com" + ): # Complete and utter hack for win32com. + try: + path = win32api.GetFullPathName( + os.path.join(self.path, "..\\win32comext") + ) + ret = ret + MakePathSubList(path) + except win32ui.error: + pass + return ret + + +class HLIProjectRoot(hierlist.HierListItem): + def __init__(self, projectName, displayName=None): + hierlist.HierListItem.__init__(self) + self.projectName = projectName + self.displayName = displayName or projectName + + def GetText(self): + return self.displayName + + def IsExpandable(self): + return 1 + + def GetSubList(self): + paths = regutil.GetRegisteredNamedPath(self.projectName) + pathList = paths.split(";") + if len(pathList) == 1: # Single dir - dont bother putting the dir in + ret = MakePathSubList(pathList[0]) + else: + ret = list(map(HLIDirectoryItem, pathList)) + return ret + + +class HLIRoot(hierlist.HierListItem): + def __init__(self): + hierlist.HierListItem.__init__(self) + + def IsExpandable(self): + return 1 + + def GetSubList(self): + keyStr = regutil.BuildDefaultPythonKey() + "\\PythonPath" + hKey = win32api.RegOpenKey(regutil.GetRootKey(), keyStr) + try: + ret = [] + ret.append(HLIProjectRoot("", "Standard Python Library")) # The core path. + index = 0 + while 1: + try: + ret.append(HLIProjectRoot(win32api.RegEnumKey(hKey, index))) + index = index + 1 + except win32api.error: + break + return ret + finally: + win32api.RegCloseKey(hKey) + + +class dynamic_browser(dialog.Dialog): + style = win32con.WS_OVERLAPPEDWINDOW | win32con.WS_VISIBLE + cs = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | commctrl.TVS_HASLINES + | commctrl.TVS_LINESATROOT + | commctrl.TVS_HASBUTTONS + ) + + dt = [ + ["Python Projects", (0, 0, 200, 200), style, None, (8, "MS Sans Serif")], + ["SysTreeView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), cs], + ] + + def __init__(self, hli_root): + dialog.Dialog.__init__(self, self.dt) + self.hier_list = hierlist.HierListWithItems(hli_root, win32ui.IDB_BROWSER_HIER) + self.HookMessage(self.on_size, win32con.WM_SIZE) + + def OnInitDialog(self): + self.hier_list.HierInit(self) + return dialog.Dialog.OnInitDialog(self) + + def on_size(self, params): + lparam = params[3] + w = win32api.LOWORD(lparam) + h = win32api.HIWORD(lparam) + self.GetDlgItem(win32ui.IDC_LIST1).MoveWindow((0, 0, w, h)) + + +def BrowseDialog(): + root = HLIRoot() + if not root.IsExpandable(): + raise TypeError( + "Browse() argument must have __dict__ attribute, or be a Browser supported type" + ) + + dlg = dynamic_browser(root) + dlg.CreateWindow() + + +def DockableBrowserCreator(parent): + root = HLIRoot() + hl = hierlist.HierListWithItems(root, win32ui.IDB_BROWSER_HIER) + + style = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | win32con.WS_BORDER + | commctrl.TVS_HASLINES + | commctrl.TVS_LINESATROOT + | commctrl.TVS_HASBUTTONS + ) + + control = win32ui.CreateTreeCtrl() + control.CreateWindow(style, (0, 0, 150, 300), parent, win32ui.IDC_LIST1) + list = hl.HierInit(parent, control) + return control + + +def DockablePathBrowser(): + import pywin.docking.DockingBar + + bar = pywin.docking.DockingBar.DockingBar() + bar.CreateWindow( + win32ui.GetMainFrame(), DockableBrowserCreator, "Path Browser", 0x8E0A + ) + bar.SetBarStyle( + bar.GetBarStyle() + | afxres.CBRS_TOOLTIPS + | afxres.CBRS_FLYBY + | afxres.CBRS_SIZE_DYNAMIC + ) + bar.EnableDocking(afxres.CBRS_ALIGN_ANY) + win32ui.GetMainFrame().DockControlBar(bar) + + +# The "default" entry point +Browse = DockablePathBrowser diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/browser.py b/MLPY/Lib/site-packages/pythonwin/pywin/tools/browser.py new file mode 100644 index 0000000000000000000000000000000000000000..9d9a193db7ea0fba645a0c3bfd08d1a26c5726d1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/tools/browser.py @@ -0,0 +1,517 @@ +# basic module browser. + +# usage: +# >>> import browser +# >>> browser.Browse() +# or +# >>> browser.Browse(your_module) +import sys +import types + +import __main__ +import win32ui +from pywin.mfc import dialog + +from . import hierlist + +special_names = ["__doc__", "__name__", "__self__"] + + +# +# HierList items +class HLIPythonObject(hierlist.HierListItem): + def __init__(self, myobject=None, name=None): + hierlist.HierListItem.__init__(self) + self.myobject = myobject + self.knownExpandable = None + if name: + self.name = name + else: + try: + self.name = myobject.__name__ + except (AttributeError, TypeError): + try: + r = repr(myobject) + if len(r) > 20: + r = r[:20] + "..." + self.name = r + except (AttributeError, TypeError): + self.name = "???" + + def __lt__(self, other): + return self.name < other.name + + def __eq__(self, other): + return self.name == other.name + + def __repr__(self): + try: + type = self.GetHLIType() + except: + type = "Generic" + return ( + "HLIPythonObject(" + + type + + ") - name: " + + self.name + + " object: " + + repr(self.myobject) + ) + + def GetText(self): + try: + return str(self.name) + " (" + self.GetHLIType() + ")" + except AttributeError: + return str(self.name) + " = " + repr(self.myobject) + + def InsertDocString(self, lst): + ob = None + try: + ob = self.myobject.__doc__ + except (AttributeError, TypeError): + pass + # I don't quite grok descriptors enough to know how to + # best hook them up. Eg: + # >>> object.__getattribute__.__class__.__doc__ + # + if ob and isinstance(ob, str): + lst.insert(0, HLIDocString(ob, "Doc")) + + def GetSubList(self): + ret = [] + try: + for key, ob in self.myobject.__dict__.items(): + if key not in special_names: + ret.append(MakeHLI(ob, key)) + except (AttributeError, TypeError): + pass + try: + for name in self.myobject.__methods__: + ret.append(HLIMethod(name)) # no MakeHLI, as cant auto detect + except (AttributeError, TypeError): + pass + try: + for member in self.myobject.__members__: + if not member in special_names: + ret.append(MakeHLI(getattr(self.myobject, member), member)) + except (AttributeError, TypeError): + pass + ret.sort() + self.InsertDocString(ret) + return ret + + # if the has a dict, it is expandable. + def IsExpandable(self): + if self.knownExpandable is None: + self.knownExpandable = self.CalculateIsExpandable() + return self.knownExpandable + + def CalculateIsExpandable(self): + if hasattr(self.myobject, "__doc__"): + return 1 + try: + for key in self.myobject.__dict__.keys(): + if key not in special_names: + return 1 + except (AttributeError, TypeError): + pass + try: + self.myobject.__methods__ + return 1 + except (AttributeError, TypeError): + pass + try: + for item in self.myobject.__members__: + if item not in special_names: + return 1 + except (AttributeError, TypeError): + pass + return 0 + + def GetBitmapColumn(self): + if self.IsExpandable(): + return 0 + else: + return 4 + + def TakeDefaultAction(self): + ShowObject(self.myobject, self.name) + + +class HLIDocString(HLIPythonObject): + def GetHLIType(self): + return "DocString" + + def GetText(self): + return self.myobject.strip() + + def IsExpandable(self): + return 0 + + def GetBitmapColumn(self): + return 6 + + +class HLIModule(HLIPythonObject): + def GetHLIType(self): + return "Module" + + +class HLIFrame(HLIPythonObject): + def GetHLIType(self): + return "Stack Frame" + + +class HLITraceback(HLIPythonObject): + def GetHLIType(self): + return "Traceback" + + +class HLIClass(HLIPythonObject): + def GetHLIType(self): + return "Class" + + def GetSubList(self): + ret = [] + for base in self.myobject.__bases__: + ret.append(MakeHLI(base, "Base class: " + base.__name__)) + ret = ret + HLIPythonObject.GetSubList(self) + return ret + + +class HLIMethod(HLIPythonObject): + # myobject is just a string for methods. + def GetHLIType(self): + return "Method" + + def GetText(self): + return "Method: " + self.myobject + "()" + + +class HLICode(HLIPythonObject): + def GetHLIType(self): + return "Code" + + def IsExpandable(self): + return self.myobject + + def GetSubList(self): + ret = [] + ret.append(MakeHLI(self.myobject.co_consts, "Constants (co_consts)")) + ret.append(MakeHLI(self.myobject.co_names, "Names (co_names)")) + ret.append(MakeHLI(self.myobject.co_filename, "Filename (co_filename)")) + ret.append(MakeHLI(self.myobject.co_argcount, "Number of args (co_argcount)")) + ret.append(MakeHLI(self.myobject.co_varnames, "Param names (co_varnames)")) + + return ret + + +class HLIInstance(HLIPythonObject): + def GetHLIType(self): + return "Instance" + + def GetText(self): + return ( + str(self.name) + + " (Instance of class " + + str(self.myobject.__class__.__name__) + + ")" + ) + + def IsExpandable(self): + return 1 + + def GetSubList(self): + ret = [] + ret.append(MakeHLI(self.myobject.__class__)) + ret = ret + HLIPythonObject.GetSubList(self) + return ret + + +class HLIBuiltinFunction(HLIPythonObject): + def GetHLIType(self): + return "Builtin Function" + + +class HLIFunction(HLIPythonObject): + def GetHLIType(self): + return "Function" + + def IsExpandable(self): + return 1 + + def GetSubList(self): + ret = [] + # ret.append( MakeHLI( self.myobject.func_argcount, "Arg Count" )) + try: + ret.append(MakeHLI(self.myobject.func_argdefs, "Arg Defs")) + except AttributeError: + pass + try: + code = self.myobject.__code__ + globs = self.myobject.__globals__ + except AttributeError: + # must be py2.5 or earlier... + code = self.myobject.func_code + globs = self.myobject.func_globals + ret.append(MakeHLI(code, "Code")) + ret.append(MakeHLI(globs, "Globals")) + self.InsertDocString(ret) + return ret + + +class HLISeq(HLIPythonObject): + def GetHLIType(self): + return "Sequence (abstract!)" + + def IsExpandable(self): + return len(self.myobject) > 0 + + def GetSubList(self): + ret = [] + pos = 0 + for item in self.myobject: + ret.append(MakeHLI(item, "[" + str(pos) + "]")) + pos = pos + 1 + self.InsertDocString(ret) + return ret + + +class HLIList(HLISeq): + def GetHLIType(self): + return "List" + + +class HLITuple(HLISeq): + def GetHLIType(self): + return "Tuple" + + +class HLIDict(HLIPythonObject): + def GetHLIType(self): + return "Dict" + + def IsExpandable(self): + try: + self.myobject.__doc__ + return 1 + except (AttributeError, TypeError): + return len(self.myobject) > 0 + + def GetSubList(self): + ret = [] + keys = list(self.myobject.keys()) + keys.sort() + for key in keys: + ob = self.myobject[key] + ret.append(MakeHLI(ob, str(key))) + self.InsertDocString(ret) + return ret + + +# In Python 1.6, strings and Unicode have builtin methods, but we dont really want to see these +class HLIString(HLIPythonObject): + def IsExpandable(self): + return 0 + + +TypeMap = { + type: HLIClass, + types.FunctionType: HLIFunction, + tuple: HLITuple, + dict: HLIDict, + list: HLIList, + types.ModuleType: HLIModule, + types.CodeType: HLICode, + types.BuiltinFunctionType: HLIBuiltinFunction, + types.FrameType: HLIFrame, + types.TracebackType: HLITraceback, + str: HLIString, + int: HLIPythonObject, + bool: HLIPythonObject, + float: HLIPythonObject, +} + + +def MakeHLI(ob, name=None): + try: + cls = TypeMap[type(ob)] + except KeyError: + # hrmph - this check gets more and more bogus as Python + # improves. Its possible we should just *always* use + # HLIInstance? + if hasattr(ob, "__class__"): # 'new style' class + cls = HLIInstance + else: + cls = HLIPythonObject + return cls(ob, name) + + +######################################### +# +# Dialog related. + + +class DialogShowObject(dialog.Dialog): + def __init__(self, object, title): + self.object = object + self.title = title + dialog.Dialog.__init__(self, win32ui.IDD_LARGE_EDIT) + + def OnInitDialog(self): + import re + + self.SetWindowText(self.title) + self.edit = self.GetDlgItem(win32ui.IDC_EDIT1) + try: + strval = str(self.object) + except: + t, v, tb = sys.exc_info() + strval = "Exception getting object value\n\n%s:%s" % (t, v) + tb = None + strval = re.sub("\n", "\r\n", strval) + self.edit.ReplaceSel(strval) + + +def ShowObject(object, title): + dlg = DialogShowObject(object, title) + dlg.DoModal() + + +# And some mods for a sizable dialog from Sam Rushing! +import commctrl +import win32api +import win32con + + +class dynamic_browser(dialog.Dialog): + style = win32con.WS_OVERLAPPEDWINDOW | win32con.WS_VISIBLE + cs = ( + win32con.WS_CHILD + | win32con.WS_VISIBLE + | commctrl.TVS_HASLINES + | commctrl.TVS_LINESATROOT + | commctrl.TVS_HASBUTTONS + ) + + dt = [ + ["Python Object Browser", (0, 0, 200, 200), style, None, (8, "MS Sans Serif")], + ["SysTreeView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), cs], + ] + + def __init__(self, hli_root): + dialog.Dialog.__init__(self, self.dt) + self.hier_list = hierlist.HierListWithItems(hli_root, win32ui.IDB_BROWSER_HIER) + self.HookMessage(self.on_size, win32con.WM_SIZE) + + def OnInitDialog(self): + self.hier_list.HierInit(self) + return dialog.Dialog.OnInitDialog(self) + + def OnOK(self): + self.hier_list.HierTerm() + self.hier_list = None + return self._obj_.OnOK() + + def OnCancel(self): + self.hier_list.HierTerm() + self.hier_list = None + return self._obj_.OnCancel() + + def on_size(self, params): + lparam = params[3] + w = win32api.LOWORD(lparam) + h = win32api.HIWORD(lparam) + self.GetDlgItem(win32ui.IDC_LIST1).MoveWindow((0, 0, w, h)) + + +def Browse(ob=__main__): + "Browse the argument, or the main dictionary" + root = MakeHLI(ob, "root") + if not root.IsExpandable(): + raise TypeError( + "Browse() argument must have __dict__ attribute, or be a Browser supported type" + ) + + dlg = dynamic_browser(root) + dlg.CreateWindow() + return dlg + + +# +# +# Classes for using the browser in an MDI window, rather than a dialog +# +from pywin.mfc import docview + + +class BrowserTemplate(docview.DocTemplate): + def __init__(self): + docview.DocTemplate.__init__( + self, win32ui.IDR_PYTHONTYPE, BrowserDocument, None, BrowserView + ) + + def OpenObject(self, root): # Use this instead of OpenDocumentFile. + # Look for existing open document + for doc in self.GetDocumentList(): + if doc.root == root: + doc.GetFirstView().ActivateFrame() + return doc + # not found - new one. + doc = BrowserDocument(self, root) + frame = self.CreateNewFrame(doc) + doc.OnNewDocument() + self.InitialUpdateFrame(frame, doc, 1) + return doc + + +class BrowserDocument(docview.Document): + def __init__(self, template, root): + docview.Document.__init__(self, template) + self.root = root + self.SetTitle("Browser: " + root.name) + + def OnOpenDocument(self, name): + raise TypeError("This template can not open files") + return 0 + + +class BrowserView(docview.TreeView): + def OnInitialUpdate(self): + import commctrl + + rc = self._obj_.OnInitialUpdate() + list = hierlist.HierListWithItems( + self.GetDocument().root, + win32ui.IDB_BROWSER_HIER, + win32ui.AFX_IDW_PANE_FIRST, + ) + list.HierInit(self.GetParent()) + list.SetStyle( + commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS + ) + return rc + + +template = None + + +def MakeTemplate(): + global template + if template is None: + template = ( + BrowserTemplate() + ) # win32ui.IDR_PYTHONTYPE, BrowserDocument, None, BrowserView) + + +def BrowseMDI(ob=__main__): + """Browse an object using an MDI window.""" + + MakeTemplate() + root = MakeHLI(ob, repr(ob)) + if not root.IsExpandable(): + raise TypeError( + "Browse() argument must have __dict__ attribute, or be a Browser supported type" + ) + + template.OpenObject(root) diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/hierlist.py b/MLPY/Lib/site-packages/pythonwin/pywin/tools/hierlist.py new file mode 100644 index 0000000000000000000000000000000000000000..a60b732472234cf09ae2fdb0a4c4dcf6114e3851 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/tools/hierlist.py @@ -0,0 +1,367 @@ +# hierlist +# +# IMPORTANT - Please read before using. + +# This module exposes an API for a Hierarchical Tree Control. +# Previously, a custom tree control was included in Pythonwin which +# has an API very similar to this. + +# The current control used is the common "Tree Control". This module exists now +# to provide an API similar to the old control, but for the new Tree control. + +# If you need to use the Tree Control, you may still find this API a reasonable +# choice. However, you should investigate using the tree control directly +# to provide maximum flexibility (but with extra work). + +import sys + +import commctrl +import win32api +import win32con +import win32ui +from pywin.mfc import dialog, docview, object, window +from win32api import RGB + + +# helper to get the text of an arbitary item +def GetItemText(item): + if type(item) == type(()) or type(item) == type([]): + use = item[0] + else: + use = item + if type(use) == type(""): + return use + else: + return repr(item) + + +class HierDialog(dialog.Dialog): + def __init__( + self, + title, + hierList, + bitmapID=win32ui.IDB_HIERFOLDERS, + dlgID=win32ui.IDD_TREE, + dll=None, + childListBoxID=win32ui.IDC_LIST1, + ): + dialog.Dialog.__init__(self, dlgID, dll) # reuse this dialog. + self.hierList = hierList + self.dlgID = dlgID + self.title = title + + # self.childListBoxID = childListBoxID + def OnInitDialog(self): + self.SetWindowText(self.title) + self.hierList.HierInit(self) + return dialog.Dialog.OnInitDialog(self) + + +class HierList(object.Object): + def __init__( + self, root, bitmapID=win32ui.IDB_HIERFOLDERS, listBoxId=None, bitmapMask=None + ): # used to create object. + self.listControl = None + self.bitmapID = bitmapID + self.root = root + self.listBoxId = listBoxId + self.itemHandleMap = {} + self.filledItemHandlesMap = {} + self.bitmapMask = bitmapMask + + def __getattr__(self, attr): + try: + return getattr(self.listControl, attr) + except AttributeError: + return object.Object.__getattr__(self, attr) + + def ItemFromHandle(self, handle): + return self.itemHandleMap[handle] + + def SetStyle(self, newStyle): + hwnd = self.listControl.GetSafeHwnd() + style = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE) + win32api.SetWindowLong(hwnd, win32con.GWL_STYLE, (style | newStyle)) + + def HierInit(self, parent, listControl=None): # Used when window first exists. + # this also calls "Create" on the listbox. + # params - id of listbbox, ID of bitmap, size of bitmaps + if self.bitmapMask is None: + bitmapMask = RGB(0, 0, 255) + else: + bitmapMask = self.bitmapMask + self.imageList = win32ui.CreateImageList(self.bitmapID, 16, 0, bitmapMask) + if listControl is None: + if self.listBoxId is None: + self.listBoxId = win32ui.IDC_LIST1 + self.listControl = parent.GetDlgItem(self.listBoxId) + else: + self.listControl = listControl + lbid = listControl.GetDlgCtrlID() + assert self.listBoxId is None or self.listBoxId == lbid, ( + "An invalid listbox control ID has been specified (specified as %s, but exists as %s)" + % (self.listBoxId, lbid) + ) + self.listBoxId = lbid + self.listControl.SetImageList(self.imageList, commctrl.LVSIL_NORMAL) + # self.list.AttachObject(self) + + ## ??? Need a better way to do this - either some way to detect if it's compiled with UNICODE + ## defined, and/or a way to switch the constants based on UNICODE ??? + if sys.version_info[0] < 3: + parent.HookNotify(self.OnTreeItemExpanding, commctrl.TVN_ITEMEXPANDINGA) + parent.HookNotify(self.OnTreeItemSelChanged, commctrl.TVN_SELCHANGEDA) + else: + parent.HookNotify(self.OnTreeItemExpanding, commctrl.TVN_ITEMEXPANDINGW) + parent.HookNotify(self.OnTreeItemSelChanged, commctrl.TVN_SELCHANGEDW) + parent.HookNotify(self.OnTreeItemDoubleClick, commctrl.NM_DBLCLK) + self.notify_parent = parent + + if self.root: + self.AcceptRoot(self.root) + + def DeleteAllItems(self): + self.listControl.DeleteAllItems() + self.root = None + self.itemHandleMap = {} + self.filledItemHandlesMap = {} + + def HierTerm(self): + # Dont want notifies as we kill the list. + parent = self.notify_parent # GetParentFrame() + if sys.version_info[0] < 3: + parent.HookNotify(None, commctrl.TVN_ITEMEXPANDINGA) + parent.HookNotify(None, commctrl.TVN_SELCHANGEDA) + else: + parent.HookNotify(None, commctrl.TVN_ITEMEXPANDINGW) + parent.HookNotify(None, commctrl.TVN_SELCHANGEDW) + parent.HookNotify(None, commctrl.NM_DBLCLK) + + self.DeleteAllItems() + self.listControl = None + self.notify_parent = None # Break a possible cycle + + def OnTreeItemDoubleClick(self, info, extra): + (hwndFrom, idFrom, code) = info + if idFrom != self.listBoxId: + return None + item = self.itemHandleMap[self.listControl.GetSelectedItem()] + self.TakeDefaultAction(item) + return 1 + + def OnTreeItemExpanding(self, info, extra): + (hwndFrom, idFrom, code) = info + if idFrom != self.listBoxId: + return None + action, itemOld, itemNew, pt = extra + itemHandle = itemNew[0] + if itemHandle not in self.filledItemHandlesMap: + item = self.itemHandleMap[itemHandle] + self.AddSubList(itemHandle, self.GetSubList(item)) + self.filledItemHandlesMap[itemHandle] = None + return 0 + + def OnTreeItemSelChanged(self, info, extra): + (hwndFrom, idFrom, code) = info + if idFrom != self.listBoxId: + return None + action, itemOld, itemNew, pt = extra + itemHandle = itemNew[0] + item = self.itemHandleMap[itemHandle] + self.PerformItemSelected(item) + return 1 + + def AddSubList(self, parentHandle, subItems): + for item in subItems: + self.AddItem(parentHandle, item) + + def AddItem(self, parentHandle, item, hInsertAfter=commctrl.TVI_LAST): + text = self.GetText(item) + if self.IsExpandable(item): + cItems = 1 # Trick it !! + else: + cItems = 0 + bitmapCol = self.GetBitmapColumn(item) + bitmapSel = self.GetSelectedBitmapColumn(item) + if bitmapSel is None: + bitmapSel = bitmapCol + ## if type(text) is str: + ## text = text.encode("mbcs") + hitem = self.listControl.InsertItem( + parentHandle, + hInsertAfter, + (None, None, None, text, bitmapCol, bitmapSel, cItems, 0), + ) + self.itemHandleMap[hitem] = item + return hitem + + def _GetChildHandles(self, handle): + ret = [] + try: + handle = self.listControl.GetChildItem(handle) + while 1: + ret.append(handle) + handle = self.listControl.GetNextItem(handle, commctrl.TVGN_NEXT) + except win32ui.error: + # out of children + pass + return ret + + def Refresh(self, hparent=None): + # Attempt to refresh the given item's sub-entries, but maintain the tree state + # (ie, the selected item, expanded items, etc) + if hparent is None: + hparent = commctrl.TVI_ROOT + if hparent not in self.filledItemHandlesMap: + # This item has never been expanded, so no refresh can possibly be required. + return + root_item = self.itemHandleMap[hparent] + old_handles = self._GetChildHandles(hparent) + old_items = list(map(self.ItemFromHandle, old_handles)) + new_items = self.GetSubList(root_item) + # Now an inefficient technique for synching the items. + inew = 0 + hAfter = commctrl.TVI_FIRST + for iold in range(len(old_items)): + inewlook = inew + matched = 0 + while inewlook < len(new_items): + if old_items[iold] == new_items[inewlook]: + matched = 1 + break + inewlook = inewlook + 1 + if matched: + # Insert the new items. + # print "Inserting after", old_items[iold], old_handles[iold] + for i in range(inew, inewlook): + # print "Inserting index %d (%s)" % (i, new_items[i]) + hAfter = self.AddItem(hparent, new_items[i], hAfter) + + inew = inewlook + 1 + # And recursively refresh iold + hold = old_handles[iold] + if hold in self.filledItemHandlesMap: + self.Refresh(hold) + else: + # Remove the deleted items. + # print "Deleting %d (%s)" % (iold, old_items[iold]) + hdelete = old_handles[iold] + # First recurse and remove the children from the map. + for hchild in self._GetChildHandles(hdelete): + del self.itemHandleMap[hchild] + if hchild in self.filledItemHandlesMap: + del self.filledItemHandlesMap[hchild] + self.listControl.DeleteItem(hdelete) + hAfter = old_handles[iold] + # Fill any remaining new items: + for newItem in new_items[inew:]: + # print "Inserting new item", newItem + self.AddItem(hparent, newItem) + + def AcceptRoot(self, root): + self.listControl.DeleteAllItems() + self.itemHandleMap = {commctrl.TVI_ROOT: root} + self.filledItemHandlesMap = {commctrl.TVI_ROOT: root} + subItems = self.GetSubList(root) + self.AddSubList(0, subItems) + + def GetBitmapColumn(self, item): + if self.IsExpandable(item): + return 0 + else: + return 4 + + def GetSelectedBitmapColumn(self, item): + return 0 + + def CheckChangedChildren(self): + return self.listControl.CheckChangedChildren() + + def GetText(self, item): + return GetItemText(item) + + def PerformItemSelected(self, item): + try: + win32ui.SetStatusText("Selected " + self.GetText(item)) + except win32ui.error: # No status bar! + pass + + def TakeDefaultAction(self, item): + win32ui.MessageBox("Got item " + self.GetText(item)) + + +########################################################################## +# +# Classes for use with seperate HierListItems. +# +# +class HierListWithItems(HierList): + def __init__( + self, root, bitmapID=win32ui.IDB_HIERFOLDERS, listBoxID=None, bitmapMask=None + ): # used to create object. + HierList.__init__(self, root, bitmapID, listBoxID, bitmapMask) + + def DelegateCall(self, fn): + return fn() + + def GetBitmapColumn(self, item): + rc = self.DelegateCall(item.GetBitmapColumn) + if rc is None: + rc = HierList.GetBitmapColumn(self, item) + return rc + + def GetSelectedBitmapColumn(self, item): + return self.DelegateCall(item.GetSelectedBitmapColumn) + + def IsExpandable(self, item): + return self.DelegateCall(item.IsExpandable) + + def GetText(self, item): + return self.DelegateCall(item.GetText) + + def GetSubList(self, item): + return self.DelegateCall(item.GetSubList) + + def PerformItemSelected(self, item): + func = getattr(item, "PerformItemSelected", None) + if func is None: + return HierList.PerformItemSelected(self, item) + else: + return self.DelegateCall(func) + + def TakeDefaultAction(self, item): + func = getattr(item, "TakeDefaultAction", None) + if func is None: + return HierList.TakeDefaultAction(self, item) + else: + return self.DelegateCall(func) + + +# A hier list item - for use with a HierListWithItems +class HierListItem: + def __init__(self): + pass + + def GetText(self): + pass + + def GetSubList(self): + pass + + def IsExpandable(self): + pass + + def GetBitmapColumn(self): + return None # indicate he should do it. + + def GetSelectedBitmapColumn(self): + return None # same as other + + # for py3k/rich-comp sorting compatibility. + def __lt__(self, other): + # we want unrelated items to be sortable... + return id(self) < id(other) + + # for py3k/rich-comp equality compatibility. + def __eq__(self, other): + return False diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/regedit.py b/MLPY/Lib/site-packages/pythonwin/pywin/tools/regedit.py new file mode 100644 index 0000000000000000000000000000000000000000..b94d3050fb4fd0187b3b8613c875a400c7e9f398 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/tools/regedit.py @@ -0,0 +1,386 @@ +# Regedit - a Registry Editor for Python + +import commctrl +import regutil +import win32api +import win32con +import win32ui +from pywin.mfc import dialog, docview, window + +from . import hierlist + + +def SafeApply(fn, args, err_desc=""): + try: + fn(*args) + return 1 + except win32api.error as exc: + msg = "Error " + err_desc + "\r\n\r\n" + exc.strerror + win32ui.MessageBox(msg) + return 0 + + +class SplitterFrame(window.MDIChildWnd): + def __init__(self): + # call base CreateFrame + self.images = None + window.MDIChildWnd.__init__(self) + + def OnCreateClient(self, cp, context): + splitter = win32ui.CreateSplitter() + doc = context.doc + frame_rect = self.GetWindowRect() + size = ((frame_rect[2] - frame_rect[0]), (frame_rect[3] - frame_rect[1]) // 2) + sub_size = (size[0] // 3, size[1]) + splitter.CreateStatic(self, 1, 2) + # CTreeControl view + self.keysview = RegistryTreeView(doc) + # CListControl view + self.valuesview = RegistryValueView(doc) + + splitter.CreatePane(self.keysview, 0, 0, (sub_size)) + splitter.CreatePane(self.valuesview, 0, 1, (0, 0)) # size ignored. + splitter.SetRowInfo(0, size[1], 0) + # Setup items in the imagelist + + return 1 + + def OnItemDoubleClick(self, info, extra): + (hwndFrom, idFrom, code) = info + if idFrom == win32ui.AFX_IDW_PANE_FIRST: + # Tree control + return None + elif idFrom == win32ui.AFX_IDW_PANE_FIRST + 1: + item = self.keysview.SelectedItem() + self.valuesview.EditValue(item) + return 0 + # List control + else: + return None # Pass it on + + def PerformItemSelected(self, item): + return self.valuesview.UpdateForRegItem(item) + + def OnDestroy(self, msg): + window.MDIChildWnd.OnDestroy(self, msg) + if self.images: + self.images.DeleteImageList() + self.images = None + + +class RegistryTreeView(docview.TreeView): + def OnInitialUpdate(self): + rc = self._obj_.OnInitialUpdate() + self.frame = self.GetParent().GetParent() + self.hierList = hierlist.HierListWithItems( + self.GetHLIRoot(), win32ui.IDB_HIERFOLDERS, win32ui.AFX_IDW_PANE_FIRST + ) + self.hierList.HierInit(self.frame, self.GetTreeCtrl()) + self.hierList.SetStyle( + commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS + ) + self.hierList.PerformItemSelected = self.PerformItemSelected + + self.frame.HookNotify(self.frame.OnItemDoubleClick, commctrl.NM_DBLCLK) + self.frame.HookNotify(self.OnItemRightClick, commctrl.NM_RCLICK) + + # self.HookMessage(self.OnItemRightClick, win32con.WM_RBUTTONUP) + + def GetHLIRoot(self): + doc = self.GetDocument() + regroot = doc.root + subkey = doc.subkey + return HLIRegistryKey(regroot, subkey, "Root") + + def OnItemRightClick(self, notify_data, extra): + # First select the item we right-clicked on. + pt = self.ScreenToClient(win32api.GetCursorPos()) + flags, hItem = self.HitTest(pt) + if hItem == 0 or commctrl.TVHT_ONITEM & flags == 0: + return None + self.Select(hItem, commctrl.TVGN_CARET) + + menu = win32ui.CreatePopupMenu() + menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1000, "Add Key") + menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1001, "Add Value") + menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1002, "Delete Key") + self.HookCommand(self.OnAddKey, 1000) + self.HookCommand(self.OnAddValue, 1001) + self.HookCommand(self.OnDeleteKey, 1002) + menu.TrackPopupMenu(win32api.GetCursorPos()) # track at mouse position. + return None + + def OnDeleteKey(self, command, code): + hitem = self.hierList.GetSelectedItem() + item = self.hierList.ItemFromHandle(hitem) + msg = "Are you sure you wish to delete the key '%s'?" % (item.keyName,) + id = win32ui.MessageBox(msg, None, win32con.MB_YESNO) + if id != win32con.IDYES: + return + if SafeApply( + win32api.RegDeleteKey, (item.keyRoot, item.keyName), "deleting registry key" + ): + # Get the items parent. + try: + hparent = self.GetParentItem(hitem) + except win32ui.error: + hparent = None + self.hierList.Refresh(hparent) + + def OnAddKey(self, command, code): + from pywin.mfc import dialog + + val = dialog.GetSimpleInput("New key name", "", "Add new key") + if val is None: + return # cancelled. + hitem = self.hierList.GetSelectedItem() + item = self.hierList.ItemFromHandle(hitem) + if SafeApply(win32api.RegCreateKey, (item.keyRoot, item.keyName + "\\" + val)): + self.hierList.Refresh(hitem) + + def OnAddValue(self, command, code): + from pywin.mfc import dialog + + val = dialog.GetSimpleInput("New value", "", "Add new value") + if val is None: + return # cancelled. + hitem = self.hierList.GetSelectedItem() + item = self.hierList.ItemFromHandle(hitem) + if SafeApply( + win32api.RegSetValue, (item.keyRoot, item.keyName, win32con.REG_SZ, val) + ): + # Simply re-select the current item to refresh the right spitter. + self.PerformItemSelected(item) + + # self.Select(hitem, commctrl.TVGN_CARET) + + def PerformItemSelected(self, item): + return self.frame.PerformItemSelected(item) + + def SelectedItem(self): + return self.hierList.ItemFromHandle(self.hierList.GetSelectedItem()) + + def SearchSelectedItem(self): + handle = self.hierList.GetChildItem(0) + while 1: + # print "State is", self.hierList.GetItemState(handle, -1) + if self.hierList.GetItemState(handle, commctrl.TVIS_SELECTED): + # print "Item is ", self.hierList.ItemFromHandle(handle) + return self.hierList.ItemFromHandle(handle) + handle = self.hierList.GetNextSiblingItem(handle) + + +class RegistryValueView(docview.ListView): + def OnInitialUpdate(self): + hwnd = self._obj_.GetSafeHwnd() + style = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE) + win32api.SetWindowLong( + hwnd, + win32con.GWL_STYLE, + (style & ~commctrl.LVS_TYPEMASK) | commctrl.LVS_REPORT, + ) + + itemDetails = (commctrl.LVCFMT_LEFT, 100, "Name", 0) + self.InsertColumn(0, itemDetails) + itemDetails = (commctrl.LVCFMT_LEFT, 500, "Data", 0) + self.InsertColumn(1, itemDetails) + + def UpdateForRegItem(self, item): + self.DeleteAllItems() + hkey = win32api.RegOpenKey(item.keyRoot, item.keyName) + try: + valNum = 0 + ret = [] + while 1: + try: + res = win32api.RegEnumValue(hkey, valNum) + except win32api.error: + break + name = res[0] + if not name: + name = "(Default)" + self.InsertItem(valNum, name) + self.SetItemText(valNum, 1, str(res[1])) + valNum = valNum + 1 + finally: + win32api.RegCloseKey(hkey) + + def EditValue(self, item): + # Edit the current value + class EditDialog(dialog.Dialog): + def __init__(self, item): + self.item = item + dialog.Dialog.__init__(self, win32ui.IDD_LARGE_EDIT) + + def OnInitDialog(self): + self.SetWindowText("Enter new value") + self.GetDlgItem(win32con.IDCANCEL).ShowWindow(win32con.SW_SHOW) + self.edit = self.GetDlgItem(win32ui.IDC_EDIT1) + # Modify the edit windows style + style = win32api.GetWindowLong( + self.edit.GetSafeHwnd(), win32con.GWL_STYLE + ) + style = style & (~win32con.ES_WANTRETURN) + win32api.SetWindowLong( + self.edit.GetSafeHwnd(), win32con.GWL_STYLE, style + ) + self.edit.SetWindowText(str(self.item)) + self.edit.SetSel(-1) + return dialog.Dialog.OnInitDialog(self) + + def OnDestroy(self, msg): + self.newvalue = self.edit.GetWindowText() + + try: + index = self.GetNextItem(-1, commctrl.LVNI_SELECTED) + except win32ui.error: + return # No item selected. + + if index == 0: + keyVal = "" + else: + keyVal = self.GetItemText(index, 0) + # Query for a new value. + try: + newVal = self.GetItemsCurrentValue(item, keyVal) + except TypeError as details: + win32ui.MessageBox(details) + return + + d = EditDialog(newVal) + if d.DoModal() == win32con.IDOK: + try: + self.SetItemsCurrentValue(item, keyVal, d.newvalue) + except win32api.error as exc: + win32ui.MessageBox("Error setting value\r\n\n%s" % exc.strerror) + self.UpdateForRegItem(item) + + def GetItemsCurrentValue(self, item, valueName): + hkey = win32api.RegOpenKey(item.keyRoot, item.keyName) + try: + val, type = win32api.RegQueryValueEx(hkey, valueName) + if type != win32con.REG_SZ: + raise TypeError("Only strings can be edited") + return val + finally: + win32api.RegCloseKey(hkey) + + def SetItemsCurrentValue(self, item, valueName, value): + # ** Assumes already checked is a string. + hkey = win32api.RegOpenKey( + item.keyRoot, item.keyName, 0, win32con.KEY_SET_VALUE + ) + try: + win32api.RegSetValueEx(hkey, valueName, 0, win32con.REG_SZ, value) + finally: + win32api.RegCloseKey(hkey) + + +class RegTemplate(docview.DocTemplate): + def __init__(self): + docview.DocTemplate.__init__( + self, win32ui.IDR_PYTHONTYPE, None, SplitterFrame, None + ) + + # def InitialUpdateFrame(self, frame, doc, makeVisible=1): + # self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler. + # frame.InitialUpdateFrame(doc, makeVisible) + + def OpenRegistryKey( + self, root=None, subkey=None + ): # Use this instead of OpenDocumentFile. + # Look for existing open document + if root is None: + root = regutil.GetRootKey() + if subkey is None: + subkey = regutil.BuildDefaultPythonKey() + for doc in self.GetDocumentList(): + if doc.root == root and doc.subkey == subkey: + doc.GetFirstView().ActivateFrame() + return doc + # not found - new one. + doc = RegDocument(self, root, subkey) + frame = self.CreateNewFrame(doc) + doc.OnNewDocument() + self.InitialUpdateFrame(frame, doc, 1) + return doc + + +class RegDocument(docview.Document): + def __init__(self, template, root, subkey): + docview.Document.__init__(self, template) + self.root = root + self.subkey = subkey + self.SetTitle("Registry Editor: " + subkey) + + def OnOpenDocument(self, name): + raise TypeError("This template can not open files") + return 0 + + +class HLIRegistryKey(hierlist.HierListItem): + def __init__(self, keyRoot, keyName, userName): + self.keyRoot = keyRoot + self.keyName = keyName + self.userName = userName + hierlist.HierListItem.__init__(self) + + def __lt__(self, other): + return self.name < other.name + + def __eq__(self, other): + return ( + self.keyRoot == other.keyRoot + and self.keyName == other.keyName + and self.userName == other.userName + ) + + def __repr__(self): + return "<%s with root=%s, key=%s>" % ( + self.__class__.__name__, + self.keyRoot, + self.keyName, + ) + + def GetText(self): + return self.userName + + def IsExpandable(self): + # All keys are expandable, even if they currently have zero children. + return 1 + + ## hkey = win32api.RegOpenKey(self.keyRoot, self.keyName) + ## try: + ## keys, vals, dt = win32api.RegQueryInfoKey(hkey) + ## return (keys>0) + ## finally: + ## win32api.RegCloseKey(hkey) + + def GetSubList(self): + hkey = win32api.RegOpenKey(self.keyRoot, self.keyName) + win32ui.DoWaitCursor(1) + try: + keyNum = 0 + ret = [] + while 1: + try: + key = win32api.RegEnumKey(hkey, keyNum) + except win32api.error: + break + ret.append(HLIRegistryKey(self.keyRoot, self.keyName + "\\" + key, key)) + keyNum = keyNum + 1 + finally: + win32api.RegCloseKey(hkey) + win32ui.DoWaitCursor(0) + return ret + + +template = RegTemplate() + + +def EditRegistry(root=None, key=None): + doc = template.OpenRegistryKey(root, key) + + +if __name__ == "__main__": + EditRegistry() diff --git a/MLPY/Lib/site-packages/pythonwin/pywin/tools/regpy.py b/MLPY/Lib/site-packages/pythonwin/pywin/tools/regpy.py new file mode 100644 index 0000000000000000000000000000000000000000..11ad63af56d0d08df9c08f6efec91c1bc840e1f1 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/pywin/tools/regpy.py @@ -0,0 +1,81 @@ +# (sort-of) Registry editor +import commctrl +import dialog +import win32con +import win32ui + + +class RegistryControl: + def __init__(self, key): + self.key = key + + +class RegEditPropertyPage(dialog.PropertyPage): + IDC_LISTVIEW = 1000 + + def GetTemplate(self): + "Return the template used to create this dialog" + + w = 152 # Dialog width + h = 122 # Dialog height + SS_STD = win32con.WS_CHILD | win32con.WS_VISIBLE + FRAMEDLG_STD = win32con.WS_CAPTION | win32con.WS_SYSMENU + style = ( + FRAMEDLG_STD + | win32con.WS_VISIBLE + | win32con.DS_SETFONT + | win32con.WS_MINIMIZEBOX + ) + template = [ + [self.caption, (0, 0, w, h), style, None, (8, "Helv")], + ] + lvStyle = ( + SS_STD + | commctrl.LVS_EDITLABELS + | commctrl.LVS_REPORT + | commctrl.LVS_AUTOARRANGE + | commctrl.LVS_ALIGNLEFT + | win32con.WS_BORDER + | win32con.WS_TABSTOP + ) + template.append( + ["SysListView32", "", self.IDC_LISTVIEW, (10, 10, 185, 100), lvStyle] + ) + return template + + +class RegistryPage(RegEditPropertyPage): + def __init__(self): + self.caption = "Path" + RegEditPropertyPage.__init__(self, self.GetTemplate()) + + def OnInitDialog(self): + self.listview = self.GetDlgItem(self.IDC_LISTVIEW) + RegEditPropertyPage.OnInitDialog(self) + # Setup the listview columns + itemDetails = (commctrl.LVCFMT_LEFT, 100, "App", 0) + self.listview.InsertColumn(0, itemDetails) + itemDetails = (commctrl.LVCFMT_LEFT, 1024, "Paths", 0) + self.listview.InsertColumn(1, itemDetails) + + index = self.listview.InsertItem(0, "App") + self.listview.SetItemText(index, 1, "Path") + + +class RegistrySheet(dialog.PropertySheet): + def __init__(self, title): + dialog.PropertySheet.__init__(self, title) + self.HookMessage(self.OnActivate, win32con.WM_ACTIVATE) + + def OnActivate(self, msg): + print("OnAcivate") + + +def t(): + ps = RegistrySheet("Registry Settings") + ps.AddPage(RegistryPage()) + ps.DoModal() + + +if __name__ == "__main__": + t() diff --git a/MLPY/Lib/site-packages/pythonwin/scintilla.dll b/MLPY/Lib/site-packages/pythonwin/scintilla.dll new file mode 100644 index 0000000000000000000000000000000000000000..42ff69289f8e5a346887c18a8a133bff4003ff59 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/scintilla.dll differ diff --git a/MLPY/Lib/site-packages/pythonwin/start_pythonwin.pyw b/MLPY/Lib/site-packages/pythonwin/start_pythonwin.pyw new file mode 100644 index 0000000000000000000000000000000000000000..0a1b2e60ba8ada64ac2f6268e50510c12d12c91d --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/start_pythonwin.pyw @@ -0,0 +1,19 @@ +# A Python file that can be used to start Pythonwin, instead of using +# pythonwin.exe +import os +import sys + +import win32ui + +import pywin.framework.intpyapp # InteractivePythonApp() + +assert pywin.framework.intpyapp # not unused +# Pretend this script doesn't exist, or pythonwin tries to edit it +sys.argv[:] = sys.argv[1:] or [""] # like PySys_SetArgv(Ex) +if sys.path[0] not in ("", ".", os.getcwd()): + sys.path.insert(0, os.getcwd()) +# And bootstrap the app. +app = win32ui.GetApp() +if not app.InitInstance(): + # Run when not already handled by DDE + app.Run() diff --git a/MLPY/Lib/site-packages/pythonwin/win32ui.pyd b/MLPY/Lib/site-packages/pythonwin/win32ui.pyd new file mode 100644 index 0000000000000000000000000000000000000000..f15c08bc39b1310298b3607f946ab7e0044bc989 --- /dev/null +++ b/MLPY/Lib/site-packages/pythonwin/win32ui.pyd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12713a63044ada7d907c2678a5cc765da01df29104c148759bdd8b1f4353a80f +size 1143296 diff --git a/MLPY/Lib/site-packages/pythonwin/win32uiole.pyd b/MLPY/Lib/site-packages/pythonwin/win32uiole.pyd new file mode 100644 index 0000000000000000000000000000000000000000..011e529cdeaca7b94852f653011613e831f53394 Binary files /dev/null and b/MLPY/Lib/site-packages/pythonwin/win32uiole.pyd differ diff --git a/MLPY/Lib/site-packages/pywin32-306.dist-info/INSTALLER b/MLPY/Lib/site-packages/pywin32-306.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/MLPY/Lib/site-packages/pywin32-306.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/MLPY/Lib/site-packages/pywin32-306.dist-info/METADATA b/MLPY/Lib/site-packages/pywin32-306.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..75b0d227bb6b7e2aa7abe57b9d5905691cb78db0 --- /dev/null +++ b/MLPY/Lib/site-packages/pywin32-306.dist-info/METADATA @@ -0,0 +1,154 @@ +Metadata-Version: 2.1 +Name: pywin32 +Version: 306 +Summary: Python for Window Extensions +Home-page: https://github.com/mhammond/pywin32 +Author: Mark Hammond (et al) +Author-email: mhammond@skippinet.com.au +License: PSF +Platform: UNKNOWN +Classifier: Environment :: Win32 (MS Windows) +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: Implementation :: CPython +Description-Content-Type: text/markdown + +# pywin32 + +[![CI](https://github.com/mhammond/pywin32/workflows/CI/badge.svg)](https://github.com/mhammond/pywin32/actions?query=workflow%3ACI) +[![PyPI - Version](https://img.shields.io/pypi/v/pywin32.svg)](https://pypi.org/project/pywin32) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pywin32.svg)](https://pypi.org/project/pywin32) +[![PyPI - Downloads](https://img.shields.io/pypi/dm/pywin32.svg)](https://pypi.org/project/pywin32) +[![License - PSF-2.0](https://img.shields.io/badge/license-PSF--2.0-9400d3.svg)](https://spdx.org/licenses/PSF-2.0.html) + +----- + +This is the readme for the Python for Win32 (pywin32) extensions, which provides access to many of the Windows APIs from Python. + +See [CHANGES.txt](https://github.com/mhammond/pywin32/blob/master/CHANGES.txt) for recent notable changes. + +Only Python 3 is supported. If you want Python 2 support, you want build `228`. + +## Docs + +The docs are a long and sad story, but [there's now an online version](https://mhammond.github.io/pywin32/) +of the helpfile that ships with the installers (thanks [@ofek](https://github.com/mhammond/pywin32/pull/1774)!). +Lots of that is very old, but some is auto-generated and current. Would love help untangling the docs! + +## Support + +Feel free to [open issues](https://github.com/mhammond/pywin32/issues) for +all bugs (or suspected bugs) in pywin32. [pull-requests](https://github.com/mhammond/pywin32/pulls) +for all bugs or features are also welcome. + +However, please **do not open github issues for general support requests**, or +for problems or questions using the modules in this package - they will be +closed. For such issues, please email the +[python-win32 mailing list](http://mail.python.org/mailman/listinfo/python-win32) - +note that you must be subscribed to the list before posting. + +## Binaries +[Binary releases are deprecated.](https://mhammond.github.io/pywin32_installers.html) +While they are still provided, [find them here](https://github.com/mhammond/pywin32/releases) + +## Installing via PIP + +You should install pywin32 via pip - eg, +> python -m pip install --upgrade pywin32 + +If you encounter any problems when upgrading (eg, "module not found" errors or similar), you +should execute: + +> python Scripts/pywin32_postinstall.py -install + +This will make some small attempts to cleanup older conflicting installs. + +Note that if you want to use pywin32 for "system wide" features, such as +registering COM objects or implementing Windows Services, then you must run +that command from an elevated (ie, "Run as Administrator) command prompt. + +For unreleased changes, you can download builds made by [github actions](https://github.com/mhammond/pywin32/actions/) - +choose any "workflow" from the `main` branch and download its "artifacts") + +### `The specified procedure could not be found` / `Entry-point not found` Errors? +A very common report is that people install pywin32, but many imports fail with errors +similar to the above. + +In almost all cases, this tends to mean there are other pywin32 DLLs installed in your system, +but in a different location than the new ones. This sometimes happens in environments that +come with pywin32 pre-shipped (eg, anaconda?). + +The possible solutions are: + +* Run the "post_install" script documented above. + +* Otherwise, find and remove all other copies of `pywintypesXX.dll` and `pythoncomXX.dll` + (where `XX` is the Python version - eg, "39") + +### Running as a Windows Service + +Modern Python installers do not, by default, install Python in a way that is suitable for +running as a service, particularly for other users. + +* Ensure Python is installed in a location where the user running the service has + access to the installation and is able to load `pywintypesXX.dll` and `pythonXX.dll`. + +* Manually copy `pythonservice.exe` from the `site-packages/win32` directory to + the same place as these DLLs. + +## Building from source + +Install Visual Studio 2019 (later probably works, but options might be different), +select "Desktop Development with C++", then the following options: +* Windows 10 SDK (latest offered I guess? At time of writing, 10.0.18362) +* "C++ for MFC for ..." +* ARM build tools if necessary. + +(the free compilers probably work too, but haven't been tested - let me know your experiences!) + +`setup.py` is a standard distutils build script, so you probably want: + +> python setup.py install + +or + +> python setup.py --help + +Some modules need obscure SDKs to build - `setup.py` should succeed, gracefully +telling you why it failed to build them - if the build actually fails with your +configuration, please [open an issue](https://github.com/mhammond/pywin32/issues). + +## Release process + +The following steps are performed when making a new release - this is mainly +to form a checklist so mhammond doesn't forget what to do :) + +* Ensure CHANGES.txt has everything worth noting, commit it. + +* Update setup.py with the new build number. + +* Execute build.bat, wait forever, test the artifacts. + +* Upload .whl artifacts to pypi - we do this before pushing the tag because they might be + rejected for an invalid `README.md`. Done via `py -3.? -m twine upload dist/*XXX*.whl`. + +* Commit setup.py (so the new build number is in the repo), create a new git tag + +* Upload the .exe installers to github. + +* Update setup.py with the new build number + ".1" (eg, 123.1), to ensure + future test builds aren't mistaken for the real release. + +* Make sure everything is pushed to github, including the tag (ie, + `git push --tags`) + +* Send mail to python-win32 + + diff --git a/MLPY/Lib/site-packages/pywin32-306.dist-info/RECORD b/MLPY/Lib/site-packages/pywin32-306.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..f2c1029883fa6ba8f96ac0f26784136598c14f94 --- /dev/null +++ b/MLPY/Lib/site-packages/pywin32-306.dist-info/RECORD @@ -0,0 +1,1050 @@ +../../Scripts/__pycache__/pywin32_postinstall.cpython-39.pyc,, +../../Scripts/__pycache__/pywin32_testall.cpython-39.pyc,, +../../Scripts/pywin32_postinstall.py,sha256=e4s4TN_VFKAB6aLbZwgev14hpXgo6DM94WzSnH3IAHA,27255 +../../Scripts/pywin32_testall.py,sha256=A0z0Sq5Fr4mtc60vwXp5N5JFi0GGB2VrMYUwsk-jdnA,3721 +PyWin32.chm,sha256=dyuZzyPHHFaZP7otuGRp05nX2tQ9GC4KWaJdwcBxOww,2648456 +__pycache__/pythoncom.cpython-39.pyc,, +adodbapi/__init__.py,sha256=Gc5YvxHpKF9C7bRlZ6fK4hxfmtYZIAOMKaDstrSRnKY,2146 +adodbapi/__pycache__/__init__.cpython-39.pyc,, +adodbapi/__pycache__/ado_consts.cpython-39.pyc,, +adodbapi/__pycache__/adodbapi.cpython-39.pyc,, +adodbapi/__pycache__/apibase.cpython-39.pyc,, +adodbapi/__pycache__/is64bit.cpython-39.pyc,, +adodbapi/__pycache__/process_connect_string.cpython-39.pyc,, +adodbapi/__pycache__/remote.cpython-39.pyc,, +adodbapi/__pycache__/schema_table.cpython-39.pyc,, +adodbapi/__pycache__/setup.cpython-39.pyc,, +adodbapi/ado_consts.py,sha256=M1-zHqq7PdgLX_1j4eRDmtEPcz1nBFjKpHi36DVBCEM,9392 +adodbapi/adodbapi.py,sha256=H5Qm4E0OobFdoCVydKmBDAX-DV3zTOr0H7LKsxCvuv4,49816 +adodbapi/apibase.py,sha256=OnraP-mEzMg1EtIeD6dQzPjC_F1PIZ_Peq0Tej5Nu1A,29656 +adodbapi/examples/__pycache__/db_print.cpython-39.pyc,, +adodbapi/examples/__pycache__/db_table_names.cpython-39.pyc,, +adodbapi/examples/__pycache__/xls_read.cpython-39.pyc,, +adodbapi/examples/__pycache__/xls_write.cpython-39.pyc,, +adodbapi/examples/db_print.py,sha256=LK8YiSZUfYu2oq-ORNUp7KwwBbTXRFSz8mr4VKTgBBQ,2289 +adodbapi/examples/db_table_names.py,sha256=0vKCffkq03Sanl1LdMwARpv7Z6dxkZWwe_eAaXuBJ6E,525 +adodbapi/examples/xls_read.py,sha256=Wm9Q4zA9HuvfUXfYwGb0050wS9EeKhiSBaVF8ABdUT4,1131 +adodbapi/examples/xls_write.py,sha256=id_xuH2YWvw2c22trCJAjPs5gSymeq4FWovSzjpLkrg,1463 +adodbapi/is64bit.py,sha256=pk0wqj4phOx0tyBcyaz8-NbqsnB8wDPUL0AQyOxSkf4,1246 +adodbapi/license.txt,sha256=YQ4MOiSiassEcPj16wKY35Zvw4DO6OD-vaxnkbYgnWw,26423 +adodbapi/process_connect_string.py,sha256=1OBvWWfx0zVjZmh4PLucaW93Nh6042q_FeK6MX8wbRk,5766 +adodbapi/readme.txt,sha256=Lk7i9ZFICl7T4nULsEzKBiHw8bGVyaLzIMFO0FQd290,5077 +adodbapi/remote.py,sha256=XD9YMVuSdmEX0g8hhe7Qg-YlCB9KLfaNxxS631tREIA,21235 +adodbapi/schema_table.py,sha256=lO0EGPNNaH7g63VxgQVTVnbR_1e84LXNcHzgj32oaF4,436 +adodbapi/setup.py,sha256=MJjzPblx-H3Bg3N_O2mBxmzF4ci55sIlZsWpHe5tbtU,2142 +adodbapi/test/__pycache__/adodbapitest.cpython-39.pyc,, +adodbapi/test/__pycache__/adodbapitestconfig.cpython-39.pyc,, +adodbapi/test/__pycache__/dbapi20.cpython-39.pyc,, +adodbapi/test/__pycache__/is64bit.cpython-39.pyc,, +adodbapi/test/__pycache__/setuptestframework.cpython-39.pyc,, +adodbapi/test/__pycache__/test_adodbapi_dbapi20.cpython-39.pyc,, +adodbapi/test/__pycache__/tryconnection.cpython-39.pyc,, +adodbapi/test/adodbapitest.py,sha256=wXLWqE-GOXs2q0e7M_mEbfTVeTcOjuoG5_9nfv2KzK8,60337 +adodbapi/test/adodbapitestconfig.py,sha256=5C5gBj1YNmrQKBzR4lylgYeVssvMnxFpT8I-O2BcnuU,7594 +adodbapi/test/dbapi20.py,sha256=-2VkK_exl3E6UDVfIZUX8WtHhZx2pbJS3CeurzqscLg,34421 +adodbapi/test/is64bit.py,sha256=YZh2vzR_OsNJxN_ND-OcBJUmLw50BqDYol4hQeef39I,1234 +adodbapi/test/setuptestframework.py,sha256=HcpneIpV8xpLNOeX1Ji4c0bZ3M4DUunVl6RZgFy_pvg,4284 +adodbapi/test/test_adodbapi_dbapi20.py,sha256=hFp7OAT6NXjzSh-z2LitUrSWwJPKGSaYCHNIrwRptzM,6112 +adodbapi/test/tryconnection.py,sha256=WYdCgZ5RoWfSrXzm6WFn9GQDUyBIYr8fEKWRZHfq2ls,1087 +isapi/PyISAPI_loader.dll,sha256=zHi76cW4a36MmE5Py_M2oLYj6s0D2HfVNSXzWFYJyKk,68608 +isapi/README.txt,sha256=0ItkP01QDhdLobsX2askhZMJV8wBaPFMjQVmb7jD9VA,323 +isapi/__init__.py,sha256=JWbKxyGeLZO_irlm-VQiRzB0UP8hOk_hwRVjV3Sr8xA,1228 +isapi/__pycache__/__init__.cpython-39.pyc,, +isapi/__pycache__/install.cpython-39.pyc,, +isapi/__pycache__/isapicon.cpython-39.pyc,, +isapi/__pycache__/simple.cpython-39.pyc,, +isapi/__pycache__/threaded_extension.cpython-39.pyc,, +isapi/doc/isapi.html,sha256=C2fMHvBsz9iBwp2mHHdcUrY0x7yh6rWxmsKhaFsBZO4,4160 +isapi/install.py,sha256=48vbfuxVu7-wEkfamZxEwP3SoZXulAECx9SGqk2PSpU,27548 +isapi/isapicon.py,sha256=h4du99mAUa575d7udKkAdCO2w0R1Cc3g22of2LobM4U,4114 +isapi/samples/README.txt,sha256=xHvkVPsulzb8b-yrMWVqOZmZFCPVNO19qGtgeN_JJB4,1007 +isapi/samples/__pycache__/advanced.cpython-39.pyc,, +isapi/samples/__pycache__/redirector.cpython-39.pyc,, +isapi/samples/__pycache__/redirector_asynch.cpython-39.pyc,, +isapi/samples/__pycache__/redirector_with_filter.cpython-39.pyc,, +isapi/samples/__pycache__/test.cpython-39.pyc,, +isapi/samples/advanced.py,sha256=JEFxx2TX418FWNO-RtdiI6EbRp3YsBhmBAWeTygzxMs,7877 +isapi/samples/redirector.py,sha256=SZx2EQtdUGSZo4VNoPsZcAFRWnVYOO-e3Zgh4SawQ2Y,4789 +isapi/samples/redirector_asynch.py,sha256=bg7WJZjWgGiJtFVKhdufpjtxmvdPBgvuWuTBuZr0SvQ,2723 +isapi/samples/redirector_with_filter.py,sha256=8biqM9QRgu4_-tMppMonZrHJaT7myA-E5yXEDW5SKus,6459 +isapi/samples/test.py,sha256=B6DtJRpG1z4rAKE1l_K2m7e-YDX4i4FyVzFiQH-mt8w,6318 +isapi/simple.py,sha256=Q1-5rzdRVCULpSGi1HjRENHhqC4DEaYpNhEGWCS-0fA,2444 +isapi/test/README.txt,sha256=0gZX7PtEg8dFwGzDVUqFOgAvhvo5NTjVwIeVpTvhNYc,111 +isapi/test/__pycache__/extension_simple.cpython-39.pyc,, +isapi/test/extension_simple.py,sha256=2dZyS_ztRWCfHWCtt3bfaytW29z7xrbLbAwk89oynbU,4374 +isapi/threaded_extension.py,sha256=wvPKSVwMMms-4H9jN9n_Qq_i0MvF9-i63ez7EjklFaA,7325 +pythoncom.py,sha256=GGP8gKVVyOuXyHXN-gNm9iTE45sEh9hNllNtBjcaWk0,139 +pythonwin/Pythonwin.exe,sha256=t-DeA7J4d3ySD3qJKuH9oQJsRvoxnlMXF_nbaJNOT-U,58368 +pythonwin/dde.pyd,sha256=KV8e9RcPSI9ew_mXTXx6cpneiCnDshnRrchEWnTNUnk,96768 +pythonwin/license.txt,sha256=ETzTz3hOWGiF8B-T5d9498fACzTXbMQQHgKc0v1iIRM,1520 +pythonwin/mfc140u.dll,sha256=4GxL0Hj0aQqoh0o96zjoArKhbMtgKn7cLgd-mMBbWAc,5653424 +pythonwin/pywin/Demos/__pycache__/cmdserver.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/createwin.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/demoutils.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/dibdemo.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/dlgtest.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/dyndlg.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/fontdemo.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/guidemo.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/hiertest.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/menutest.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/objdoc.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/openGLDemo.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/progressbar.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/sliderdemo.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/splittst.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/threadedgui.cpython-39.pyc,, +pythonwin/pywin/Demos/__pycache__/toolbar.cpython-39.pyc,, +pythonwin/pywin/Demos/app/__pycache__/basictimerapp.cpython-39.pyc,, +pythonwin/pywin/Demos/app/__pycache__/customprint.cpython-39.pyc,, +pythonwin/pywin/Demos/app/__pycache__/demoutils.cpython-39.pyc,, +pythonwin/pywin/Demos/app/__pycache__/dlgappdemo.cpython-39.pyc,, +pythonwin/pywin/Demos/app/__pycache__/dojobapp.cpython-39.pyc,, +pythonwin/pywin/Demos/app/__pycache__/helloapp.cpython-39.pyc,, +pythonwin/pywin/Demos/app/basictimerapp.py,sha256=WQd8OSSW2Zv0kJ62-2Po83e83PmVDofbxIKUDzVwA0s,7718 +pythonwin/pywin/Demos/app/customprint.py,sha256=i66EQV6Iw7lEXyCVmqi9F29VGWtWsrqgKf1xpIwjHgM,5955 +pythonwin/pywin/Demos/app/demoutils.py,sha256=BR6SdKIsBEg8K1AOZ5oEhWV6SUGeLrx5V-XNqdMIHSc,1449 +pythonwin/pywin/Demos/app/dlgappdemo.py,sha256=t8_MCh084noI5YQv0TzEzxnVuMD024FFcvSA2bC1Xus,1392 +pythonwin/pywin/Demos/app/dojobapp.py,sha256=TKdi3e_msrirYTVx3ua2mMrSFGS834M0qfYIE6OPWZs,1514 +pythonwin/pywin/Demos/app/helloapp.py,sha256=in6glzU1jLlTWS9Z3rg0OgcNxnC4kOI_o7EGrPcfPEs,1626 +pythonwin/pywin/Demos/cmdserver.py,sha256=vE5yP5E81116L2dklR5v8biz7K60K0oHEu5ySNP87kM,3081 +pythonwin/pywin/Demos/createwin.py,sha256=W88Cg-ef2T-ChHn2v6CiXiNbRFBbdsg5s3Df-p8k6eY,2507 +pythonwin/pywin/Demos/demoutils.py,sha256=J2pL_S2czeSqpzI91RuY4-OfPGyWLlYIFLGeVkQciqA,1494 +pythonwin/pywin/Demos/dibdemo.py,sha256=7iXQ7FMjC_vHF_GRUw0c7n7DIZ0mI8c3ITmkJ_huxss,2289 +pythonwin/pywin/Demos/dlgtest.py,sha256=hR7Hy3Kt55CI7VTAGK1Kl2qiqCuyAcy2A8WSAj1Skxk,4574 +pythonwin/pywin/Demos/dyndlg.py,sha256=Enfk8XVDENaHv2hcoztibgSSnv4_NU_dkIGx7498dm8,2829 +pythonwin/pywin/Demos/fontdemo.py,sha256=Vm7QxUYLhZHkl4jyDmD3Fva96Z9Jfa-cuKFywQHRxYY,2759 +pythonwin/pywin/Demos/guidemo.py,sha256=I645pOW-ifqB8t8pCseb-DxKLSQCbYHtzLs0dOXj7nE,2709 +pythonwin/pywin/Demos/hiertest.py,sha256=UAL3UhN6hfHq0ECmt2P2sbGNFZ4ZzfYYyuxBHR2i1sA,3766 +pythonwin/pywin/Demos/menutest.py,sha256=mzKJbZkx8WkHV4UZpIpRcrqPJX1k9lxBwyes8ZSNsdg,490 +pythonwin/pywin/Demos/objdoc.py,sha256=vkDKnrm_3ffTtrUG6OEeInRryalw7RcFuHP4cZaMvLw,1727 +pythonwin/pywin/Demos/ocx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pythonwin/pywin/Demos/ocx/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/Demos/ocx/__pycache__/demoutils.cpython-39.pyc,, +pythonwin/pywin/Demos/ocx/__pycache__/flash.cpython-39.pyc,, +pythonwin/pywin/Demos/ocx/__pycache__/msoffice.cpython-39.pyc,, +pythonwin/pywin/Demos/ocx/__pycache__/ocxserialtest.cpython-39.pyc,, +pythonwin/pywin/Demos/ocx/__pycache__/ocxtest.cpython-39.pyc,, +pythonwin/pywin/Demos/ocx/__pycache__/webbrowser.cpython-39.pyc,, +pythonwin/pywin/Demos/ocx/demoutils.py,sha256=mMjY78oTg04ccoi-gl2_tRZeDQC90l4iEjFH7WOnV-g,1501 +pythonwin/pywin/Demos/ocx/flash.py,sha256=RrZz67OMSaVIgOgMI5OozcHmJIdt875Xms9QaVpoti0,3019 +pythonwin/pywin/Demos/ocx/msoffice.py,sha256=ojz16PDa4zIDXdEIGzKn3bwL1pfbGmjtq1Kw-sJbO_c,5048 +pythonwin/pywin/Demos/ocx/ocxserialtest.py,sha256=aUpLDIzDBlWSQsKXP_9jivwThI6atJxtITWBAQ7cVZE,3611 +pythonwin/pywin/Demos/ocx/ocxtest.py,sha256=yAKb-Gga9CU-hDi2usNcSILjhhPKBUCvZM9HtTL1WpQ,6805 +pythonwin/pywin/Demos/ocx/webbrowser.py,sha256=3UAJ64VzgO-YXEs5SfRrl5eC3PM0UaTDIylogKAjgME,2293 +pythonwin/pywin/Demos/openGLDemo.py,sha256=9fjJXPTgPM7SRgOK-ZhjWFjm6_RnbI1xrTbnmFCIgkg,9789 +pythonwin/pywin/Demos/progressbar.py,sha256=TdlH0LkLbLLt_PW4pEKewT1Yq-uMM82IAFNrXYAp1yU,2470 +pythonwin/pywin/Demos/sliderdemo.py,sha256=1Yp3h0-Ar2KMmsKikB_cnmomYqMC9waLWQkUcrwHzI4,2191 +pythonwin/pywin/Demos/splittst.py,sha256=hZakQNvfC1mC4pwbBNUEkEQRp2qkMs1h-lAu3QXUvME,2847 +pythonwin/pywin/Demos/threadedgui.py,sha256=c-VKbClxQR9t843s1MGrB5VSx0ZQLeu-4kYweNP_IA8,6272 +pythonwin/pywin/Demos/toolbar.py,sha256=wpS3QOtZ26HlNlGFbKVLEBDq5jIN1QDZhQoS1IgQDak,3165 +pythonwin/pywin/IDLE.cfg,sha256=Cc0zS72KlyM2CRPbY-HdNEu1-urNonC1dSnA2juK9z4,742 +pythonwin/pywin/__init__.py,sha256=Y-fTGuKvhscAa5XWU5H3_gVQOOMcDi2Zo03lSV0tglo,475 +pythonwin/pywin/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/debugger/__init__.py,sha256=5MxKK-Ng1soaK_c6fFIhC-X8_hWvE4H7I0fI5moqcbA,3160 +pythonwin/pywin/debugger/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/debugger/__pycache__/configui.cpython-39.pyc,, +pythonwin/pywin/debugger/__pycache__/dbgcon.cpython-39.pyc,, +pythonwin/pywin/debugger/__pycache__/dbgpyapp.cpython-39.pyc,, +pythonwin/pywin/debugger/__pycache__/debugger.cpython-39.pyc,, +pythonwin/pywin/debugger/__pycache__/fail.cpython-39.pyc,, +pythonwin/pywin/debugger/configui.py,sha256=2HD71Ew5acqCvhJgtmyS3-bt_7T4fSNQbgZA0QPgPH8,1183 +pythonwin/pywin/debugger/dbgcon.py,sha256=5HBTKYRPchpH8XYEa_nf_ZuhFRnhn4M2H4jTZ5YQ990,845 +pythonwin/pywin/debugger/dbgpyapp.py,sha256=-s3KpJoxlBsWXcE9iHStlmDY01BUQ8NsksjHkhn7Il0,1558 +pythonwin/pywin/debugger/debugger.py,sha256=DrPoD0nYE-_09IYcn51HstA1UBkSd4liDR3CcV4jIfo,37931 +pythonwin/pywin/debugger/fail.py,sha256=5XTVLniaQE2yAgtn-LAXjaPwMJkaeUHqpkg7qukUOLU,927 +pythonwin/pywin/default.cfg,sha256=G56DWfOgVjBbjSUbUBfKL5Uq-0IMG-aj_31bt_X2sZ8,6785 +pythonwin/pywin/dialogs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pythonwin/pywin/dialogs/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/dialogs/__pycache__/ideoptions.cpython-39.pyc,, +pythonwin/pywin/dialogs/__pycache__/list.cpython-39.pyc,, +pythonwin/pywin/dialogs/__pycache__/login.cpython-39.pyc,, +pythonwin/pywin/dialogs/__pycache__/status.cpython-39.pyc,, +pythonwin/pywin/dialogs/ideoptions.py,sha256=YqHu67BS1ojQI9dSCneSYXwsUrJdyLDemFyls6qwxWM,5034 +pythonwin/pywin/dialogs/list.py,sha256=bXVtUaYobjQ_kalG30CbC5znL14VPOqw6CZJTj6RnXk,4553 +pythonwin/pywin/dialogs/login.py,sha256=u_UGn8Ihqg-39hxwUUZ9ophTny5IKgaiZ31pzG4Gb4w,4744 +pythonwin/pywin/dialogs/status.py,sha256=GtPZr3tTKOF5oLjd5hWTaiGREC3FwnFKF1L6XgANbe4,6620 +pythonwin/pywin/docking/DockingBar.py,sha256=QiNc-Gt4e7QCUVx2fbtZEh24FziN67l69A-uGZYt4Ok,23579 +pythonwin/pywin/docking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pythonwin/pywin/docking/__pycache__/DockingBar.cpython-39.pyc,, +pythonwin/pywin/docking/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/framework/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pythonwin/pywin/framework/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/app.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/bitmap.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/cmdline.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/dbgcommands.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/dlgappcore.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/help.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/interact.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/intpyapp.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/intpydde.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/mdi_pychecker.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/scriptutils.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/sgrepmdi.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/startup.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/stdin.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/toolmenu.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/window.cpython-39.pyc,, +pythonwin/pywin/framework/__pycache__/winout.cpython-39.pyc,, +pythonwin/pywin/framework/app.py,sha256=hE7nAwd6X6D7utfFRKoZ9WKeEgM71qQ84irpufTiLP4,16191 +pythonwin/pywin/framework/bitmap.py,sha256=t7M0JwkUhoTX9ycf32uzkz6GHwrAex_sqtpW8x527qQ,5358 +pythonwin/pywin/framework/cmdline.py,sha256=DRgVnPpZniM-GI__TF_JB-1Hs3L_ysFig5jw6I2ec1w,1491 +pythonwin/pywin/framework/dbgcommands.py,sha256=jpLCHX-PSOtIP8BPTaGeGYDoj15ZIc2RUVwZeBlrAaA,6831 +pythonwin/pywin/framework/dlgappcore.py,sha256=7oDbctCI744ytj5ShN7mq9fBQs3SxocrC1F6WGcrbX8,2044 +pythonwin/pywin/framework/editor/ModuleBrowser.py,sha256=0E46DQEyp-Jteq8zFJNK2_L59W6eKeJdIBtdMC9lgmY,7057 +pythonwin/pywin/framework/editor/__init__.py,sha256=ZDkP2_gEZ6ssek6Lw9Oy2A1mRfohUCjYTrnVGPCb3ew,2951 +pythonwin/pywin/framework/editor/__pycache__/ModuleBrowser.cpython-39.pyc,, +pythonwin/pywin/framework/editor/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/framework/editor/__pycache__/configui.cpython-39.pyc,, +pythonwin/pywin/framework/editor/__pycache__/document.cpython-39.pyc,, +pythonwin/pywin/framework/editor/__pycache__/editor.cpython-39.pyc,, +pythonwin/pywin/framework/editor/__pycache__/frame.cpython-39.pyc,, +pythonwin/pywin/framework/editor/__pycache__/template.cpython-39.pyc,, +pythonwin/pywin/framework/editor/__pycache__/vss.cpython-39.pyc,, +pythonwin/pywin/framework/editor/color/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pythonwin/pywin/framework/editor/color/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/framework/editor/color/__pycache__/coloreditor.cpython-39.pyc,, +pythonwin/pywin/framework/editor/color/coloreditor.py,sha256=_eJdsRQqz00hinaKgRoM1NC1Lsw6FhPpFPDZfnCiVUs,25627 +pythonwin/pywin/framework/editor/configui.py,sha256=tDz5SZGPchnOG1jlPkFgJ-n2K_H0gMabHGXcLA3rOV8,11603 +pythonwin/pywin/framework/editor/document.py,sha256=Y0i5CqAWrwcYVefFEummMasGWfkb46LXN9bFS1q6xoA,14762 +pythonwin/pywin/framework/editor/editor.py,sha256=kWo6y8LraNho63Waj4T6f60F-wJ_DLmIyESdd6QrbxU,18241 +pythonwin/pywin/framework/editor/frame.py,sha256=lhvDWFYG523aUmOWF79avIO3r0pcaCnAFJ6N0VbdYUo,3148 +pythonwin/pywin/framework/editor/template.py,sha256=vbvhtHJoyFi12zMSkiWWYGKxrb-nZ4cSpCEb-M3X3fk,2060 +pythonwin/pywin/framework/editor/vss.py,sha256=Vfx6KFN4fPykGo-0yNo_lhhEwOVlhbuC3U3H-MmuQl8,3398 +pythonwin/pywin/framework/help.py,sha256=rosnwb5Owsb3Ax1cZIlJoa06l-0jSL3W1AFbm_Ll_Hg,5650 +pythonwin/pywin/framework/interact.py,sha256=eje2BgP-bF9UE4OvjMg133MGK0znJJHjQtVmrDFo8DE,35912 +pythonwin/pywin/framework/intpyapp.py,sha256=oHNfi35KaNCpADT7PGrfTi3ljkSsUmFzbuufInm0ltA,20154 +pythonwin/pywin/framework/intpydde.py,sha256=cP9Iic9S24JRiiTF74zXZm4m3rDAXsV2lXnqVjRUKvg,1564 +pythonwin/pywin/framework/mdi_pychecker.py,sha256=WRe4fwV1itMuFB25Frg-vshfbA6VOzyDCHUkngZWOKI,28975 +pythonwin/pywin/framework/scriptutils.py,sha256=t7o8YzvYuRL6zbsOtwb1d4XfH1E3r25iUDk4swQqqrw,23232 +pythonwin/pywin/framework/sgrepmdi.py,sha256=MSwmDC4Dhbb7_pKXX8SJQ6jOs0r5PTPXbnFJcjXPFVo,24972 +pythonwin/pywin/framework/startup.py,sha256=Dbyqic1RAboVCSIJxCTcgDkIL0culCB2MtKHXy9cuyc,2847 +pythonwin/pywin/framework/stdin.py,sha256=WuzL2IEwa0UQDwmZfpPu1APl1XgJUXvXNF9NWtwSDLY,6584 +pythonwin/pywin/framework/toolmenu.py,sha256=3pQfqz7dAhNWmmJOfy38dE0pqSgszv-iDieLJz9lEiA,9369 +pythonwin/pywin/framework/window.py,sha256=iVZtSoyoHdzSkZCZFfTFId8ExPCL1uoec6rtEhSHywg,535 +pythonwin/pywin/framework/winout.py,sha256=Skf4iq5eWyEoafxggowrU83j3EsfEbSYibWfZZOLom8,20312 +pythonwin/pywin/idle/AutoExpand.py,sha256=6WUiYSO970yYlhu7W6iAg_TpWuQqB8TunwXZ3G0i8Ak,2714 +pythonwin/pywin/idle/AutoIndent.py,sha256=jQ4A-vGNfN7P5LssaWHbjfvnPtgpBCVYt6KvWcgCDdg,20682 +pythonwin/pywin/idle/CallTips.py,sha256=OjRU4Q9VGZdLLiV9sh7O9WET7X50ngXXvqqd76KcMIg,6372 +pythonwin/pywin/idle/FormatParagraph.py,sha256=x4CetQ8fz4-F49CGeSTfIEf-Eh8Tz1Js68sUAUZrvM0,5727 +pythonwin/pywin/idle/IdleHistory.py,sha256=vOTn5nInbQHWntecftHZ9YiQBq1rP7rGAsrJs1W8CUc,3069 +pythonwin/pywin/idle/PyParse.py,sha256=Q_BNqsDEfcqaeyUHsURbqHbev3O2WPf2LQoORLZmYZY,18492 +pythonwin/pywin/idle/__init__.py,sha256=RLHflH_1DXLVm5QZiZe3BBZPRaHNU_76lSqOF-NUf4Q,55 +pythonwin/pywin/idle/__pycache__/AutoExpand.cpython-39.pyc,, +pythonwin/pywin/idle/__pycache__/AutoIndent.cpython-39.pyc,, +pythonwin/pywin/idle/__pycache__/CallTips.cpython-39.pyc,, +pythonwin/pywin/idle/__pycache__/FormatParagraph.cpython-39.pyc,, +pythonwin/pywin/idle/__pycache__/IdleHistory.cpython-39.pyc,, +pythonwin/pywin/idle/__pycache__/PyParse.cpython-39.pyc,, +pythonwin/pywin/idle/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/mfc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pythonwin/pywin/mfc/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/mfc/__pycache__/activex.cpython-39.pyc,, +pythonwin/pywin/mfc/__pycache__/afxres.cpython-39.pyc,, +pythonwin/pywin/mfc/__pycache__/dialog.cpython-39.pyc,, +pythonwin/pywin/mfc/__pycache__/docview.cpython-39.pyc,, +pythonwin/pywin/mfc/__pycache__/object.cpython-39.pyc,, +pythonwin/pywin/mfc/__pycache__/thread.cpython-39.pyc,, +pythonwin/pywin/mfc/__pycache__/window.cpython-39.pyc,, +pythonwin/pywin/mfc/activex.py,sha256=eGzZA6rYAzLuwHAmqgKJd2vrzeWosFCGkCBU14LUa2o,2868 +pythonwin/pywin/mfc/afxres.py,sha256=RiZZ8okdHXZ-pOejL8HbvQXsn8-pMQ7NwDUbaPTBntU,15094 +pythonwin/pywin/mfc/dialog.py,sha256=E0M5kmL4c5TTitzLXGoqe5mcQfxIr9TR-JAUDbJQ8tk,9002 +pythonwin/pywin/mfc/docview.py,sha256=MOrEClmPEcIKC6EAhnRlEHDU_3zGIfFvV8WY2M26Utk,4089 +pythonwin/pywin/mfc/object.py,sha256=K7IMIhgwahdrBjvIYAkoUuqUGG84WBXz4HOIAzzGnxo,2179 +pythonwin/pywin/mfc/thread.py,sha256=ylsJyOUvgfIG3FjGMWBfkVIpsDQDjHkAtSfj3XzzqzM,588 +pythonwin/pywin/mfc/window.py,sha256=mpcOswFAtJxKQaGP9bQV2qHXKGfU-xYwLjcFJyojjjs,1499 +pythonwin/pywin/scintilla/IDLEenvironment.py,sha256=99ESVPu3jVjGZegLOjYKtywthRPBGOLvPU6xgMD7BAQ,19556 +pythonwin/pywin/scintilla/__init__.py,sha256=uqicIJ2NdMoqmLYuclt9Kmd19iB-w-QF3ycuBpeaO_A,16 +pythonwin/pywin/scintilla/__pycache__/IDLEenvironment.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/bindings.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/config.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/configui.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/control.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/document.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/find.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/formatter.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/keycodes.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/scintillacon.cpython-39.pyc,, +pythonwin/pywin/scintilla/__pycache__/view.cpython-39.pyc,, +pythonwin/pywin/scintilla/bindings.py,sha256=2r36qEbpj0sM4JZRjhIKjdu7hBB5bW2diBQyU68Jlag,6001 +pythonwin/pywin/scintilla/config.py,sha256=_nLgQ8bdM_faSLIKo93luXINm4BT-4tq5kekLoDf_mk,12462 +pythonwin/pywin/scintilla/configui.py,sha256=D6L6a2YvyS2yZd9YHops_Im5d3YYF6cptjvPUho1FpI,11205 +pythonwin/pywin/scintilla/control.py,sha256=QrqrgfVldwPPUgNoe8Bgj6R3Y2key6AzDUpxas-xhc0,20451 +pythonwin/pywin/scintilla/document.py,sha256=Knm47L4b79upd5dCwWYqXFH3tOAmMPCl55zKR8myBWw,11468 +pythonwin/pywin/scintilla/find.py,sha256=h5X_gllqaD-MZskGxp1N-akIBTIksrtC75M-RVY6w7E,16767 +pythonwin/pywin/scintilla/formatter.py,sha256=yUnYYxieU-ZKPk5GmCWafAiql-OwIdh0qwJVTT9T3v4,26477 +pythonwin/pywin/scintilla/keycodes.py,sha256=uOV3ujZ1IacyyJhQ_iWqN9NbvyjKZ35CQ7noophYjyQ,5311 +pythonwin/pywin/scintilla/scintillacon.py,sha256=oMRFlrH595tSdwHGQ_r92nG6cxo4E6PSmv7P5zTJGes,45141 +pythonwin/pywin/scintilla/view.py,sha256=5LfnXRY__-1COxWi8EdjvoY_9Q4u7D2jy2HGBwDs5Tc,30922 +pythonwin/pywin/tools/TraceCollector.py,sha256=IHXIS4K110UkSPcZmFfP5n-_Jipn2vu8Eigv2KJkf34,2432 +pythonwin/pywin/tools/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +pythonwin/pywin/tools/__pycache__/TraceCollector.cpython-39.pyc,, +pythonwin/pywin/tools/__pycache__/__init__.cpython-39.pyc,, +pythonwin/pywin/tools/__pycache__/browseProjects.cpython-39.pyc,, +pythonwin/pywin/tools/__pycache__/browser.cpython-39.pyc,, +pythonwin/pywin/tools/__pycache__/hierlist.cpython-39.pyc,, +pythonwin/pywin/tools/__pycache__/regedit.cpython-39.pyc,, +pythonwin/pywin/tools/__pycache__/regpy.cpython-39.pyc,, +pythonwin/pywin/tools/browseProjects.py,sha256=7s-XdM8lk6mCBYu8RTqrOrccadg9Gw8g1Vc-lDvtuEA,9513 +pythonwin/pywin/tools/browser.py,sha256=YpPTLDYeafsJ1SF97pSeSxXW4iVbTcw8N1mr7zD-nyg,13614 +pythonwin/pywin/tools/hierlist.py,sha256=L_CxAm22Qt0GanDzge_fy0nfmL-yoWSDrczu4zXmbkw,12728 +pythonwin/pywin/tools/regedit.py,sha256=9EW4CgHZEH8NXbsmX6O92GdROl87ErHDsj8zfq2SuY0,13258 +pythonwin/pywin/tools/regpy.py,sha256=3YPaUd54um4-VAwcZqhNzCo-JNhcCGUiwC8rxpO3S08,2227 +pythonwin/scintilla.dll,sha256=VLqgL2-446KgDWli8hTdIDEBaTY13f9XGpqitmE6bHc,632320 +pythonwin/start_pythonwin.pyw,sha256=DmArtYkMhOSsB_1gp8OpGvnGKsWYF0uJPc9XCq3PHqc,570 +pythonwin/win32ui.pyd,sha256=EnE6YwRK2n2QfCZ4pcx2XaAd8pEEwUh1m92LH0NTqA8,1143296 +pythonwin/win32uiole.pyd,sha256=KSpCIrPVB9XdH8I2fXJOREtq9PG_7iykNSXN2MIewow,74240 +pywin32-306.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pywin32-306.dist-info/METADATA,sha256=SJwInokbBL13go0fGsgyATBLEchHtZs9Cn_ewQUnMOw,6395 +pywin32-306.dist-info/RECORD,, +pywin32-306.dist-info/WHEEL,sha256=fVcVlLzi8CGi_Ul8vjMdn8gER25dn5GBg9E6k9z41-Y,100 +pywin32-306.dist-info/top_level.txt,sha256=rcw2AC70HErs1KauAgUmoFwYs79lqPtcwYta0CPlFQI,1313 +pywin32.pth,sha256=T2f_kq8Oo4vxisMI79l294HYTlb1ecYD7R6PDGmhf40,178 +pywin32.version.txt,sha256=pE4lSr6rQdzBwJdRo6J5KbUrqqhgk8ew1NZy5MIsoxc,5 +pywin32_system32/pythoncom39.dll,sha256=B4n5Mhq_o6ZAOkg8s7poTaXPw50mGV_OhmmnfGNnxBM,669696 +pywin32_system32/pywintypes39.dll,sha256=IL3o5Q5C96q_WRBu6iOPzA3s4MbjYsCn_usASrmB24o,134656 +win32/Demos/BackupRead_BackupWrite.py,sha256=xooeF1-3eEvTgwfi68W8U9JcYnLInS4E1KU_Pr5m_UQ,3769 +win32/Demos/BackupSeek_streamheaders.py,sha256=HVLC3L_rK2qQ0o9RPfwobj4XJ7aHlb5iMmYAP8N2T_Y,3864 +win32/Demos/CopyFileEx.py,sha256=NZPtj2n2pIhsd4MRcIafsJaxwlOndIy5Bbql-iEiIYk,1243 +win32/Demos/CreateFileTransacted_MiniVersion.py,sha256=8uFPPn2j6SkpYh7x2LY4teZYXAFQDq170yNedOt1N64,3678 +win32/Demos/EvtFormatMessage.py,sha256=XA32cdH7-OqvAne5pBhwfRW3KTm_0t2CAp-rf1Hon54,3360 +win32/Demos/EvtSubscribe_pull.py,sha256=pKoj-cFqoueKGiKgwSsYVLwAGavzNnBnKlJ3PFMkmRE,792 +win32/Demos/EvtSubscribe_push.py,sha256=tgJxQ-6U4OMy04UeI5SL9qmMT2_sJiYnA_r2d0_jNV0,692 +win32/Demos/FileSecurityTest.py,sha256=zLaiiAysfJ1nlm8Bhdv4F18B9sfadgWNK1XmHPqP5oc,4397 +win32/Demos/GetSaveFileName.py,sha256=qmfeHsCA7vrVyk9QVHeJFa-PKCwq99diQ-ZvQJoTZbU,1184 +win32/Demos/NetValidatePasswordPolicy.py,sha256=6mWbif8_nxlZwrevjwdaCiCZUzr-frHKfnKVdzKgX_A,3508 +win32/Demos/OpenEncryptedFileRaw.py,sha256=edkWmJwcpDnNYCv4x6X7d0lCHWTgv6y_8Dmz-R45oko,2023 +win32/Demos/RegCreateKeyTransacted.py,sha256=YeFfs-urFMB71ghWcpFhlboTJZv-4-fdTG743pnPC7s,1912 +win32/Demos/RegRestoreKey.py,sha256=sC6cQdblHr45JsF0blNy5irCYT-Ef_-Vxdb56jaFct8,2063 +win32/Demos/SystemParametersInfo.py,sha256=tXU4shDU_SNDfj8Pn82lL9oDj2zLfjv022JtLD748gA,7957 +win32/Demos/__pycache__/BackupRead_BackupWrite.cpython-39.pyc,, +win32/Demos/__pycache__/BackupSeek_streamheaders.cpython-39.pyc,, +win32/Demos/__pycache__/CopyFileEx.cpython-39.pyc,, +win32/Demos/__pycache__/CreateFileTransacted_MiniVersion.cpython-39.pyc,, +win32/Demos/__pycache__/EvtFormatMessage.cpython-39.pyc,, +win32/Demos/__pycache__/EvtSubscribe_pull.cpython-39.pyc,, +win32/Demos/__pycache__/EvtSubscribe_push.cpython-39.pyc,, +win32/Demos/__pycache__/FileSecurityTest.cpython-39.pyc,, +win32/Demos/__pycache__/GetSaveFileName.cpython-39.pyc,, +win32/Demos/__pycache__/NetValidatePasswordPolicy.cpython-39.pyc,, +win32/Demos/__pycache__/OpenEncryptedFileRaw.cpython-39.pyc,, +win32/Demos/__pycache__/RegCreateKeyTransacted.cpython-39.pyc,, +win32/Demos/__pycache__/RegRestoreKey.cpython-39.pyc,, +win32/Demos/__pycache__/SystemParametersInfo.cpython-39.pyc,, +win32/Demos/__pycache__/cerapi.cpython-39.pyc,, +win32/Demos/__pycache__/desktopmanager.cpython-39.pyc,, +win32/Demos/__pycache__/eventLogDemo.cpython-39.pyc,, +win32/Demos/__pycache__/getfilever.cpython-39.pyc,, +win32/Demos/__pycache__/mmapfile_demo.cpython-39.pyc,, +win32/Demos/__pycache__/print_desktop.cpython-39.pyc,, +win32/Demos/__pycache__/rastest.cpython-39.pyc,, +win32/Demos/__pycache__/timer_demo.cpython-39.pyc,, +win32/Demos/__pycache__/win32clipboardDemo.cpython-39.pyc,, +win32/Demos/__pycache__/win32clipboard_bitmapdemo.cpython-39.pyc,, +win32/Demos/__pycache__/win32comport_demo.cpython-39.pyc,, +win32/Demos/__pycache__/win32console_demo.cpython-39.pyc,, +win32/Demos/__pycache__/win32cred_demo.cpython-39.pyc,, +win32/Demos/__pycache__/win32fileDemo.cpython-39.pyc,, +win32/Demos/__pycache__/win32gui_demo.cpython-39.pyc,, +win32/Demos/__pycache__/win32gui_devicenotify.cpython-39.pyc,, +win32/Demos/__pycache__/win32gui_dialog.cpython-39.pyc,, +win32/Demos/__pycache__/win32gui_menu.cpython-39.pyc,, +win32/Demos/__pycache__/win32gui_taskbar.cpython-39.pyc,, +win32/Demos/__pycache__/win32netdemo.cpython-39.pyc,, +win32/Demos/__pycache__/win32rcparser_demo.cpython-39.pyc,, +win32/Demos/__pycache__/win32servicedemo.cpython-39.pyc,, +win32/Demos/__pycache__/win32ts_logoff_disconnected.cpython-39.pyc,, +win32/Demos/__pycache__/winprocess.cpython-39.pyc,, +win32/Demos/c_extension/__pycache__/setup.cpython-39.pyc,, +win32/Demos/c_extension/setup.py,sha256=JdWP1ebQKh3V7nTgdEbY8WwPG_4kSybvM-DUT-de5vM,767 +win32/Demos/cerapi.py,sha256=e8ay8SQ12tJIVOEg5NlCYmnB_VplyPi9G16xsbysz5Y,7919 +win32/Demos/dde/__pycache__/ddeclient.cpython-39.pyc,, +win32/Demos/dde/__pycache__/ddeserver.cpython-39.pyc,, +win32/Demos/dde/ddeclient.py,sha256=3-UKF1ZSpzYZvTHtWgNWfzix9PmwZUJz2gByM1oYHQs,434 +win32/Demos/dde/ddeserver.py,sha256=vbNHjGX0-K6P16-J-HyL0k6sW5K5FG5KQuaZysY0K1o,1093 +win32/Demos/desktopmanager.py,sha256=16hbSUPfxPkJc9Ru9V2-6GQrskF375XlYdWv3XRi4Bg,8141 +win32/Demos/eventLogDemo.py,sha256=JgAQJ6VKujqSzUltesB5m8tZXIt36Y_6BOdPLP_coRM,4421 +win32/Demos/getfilever.py,sha256=bbLE5-XV77JnP9GGD1FifwuE2yGmisMxxRs6-0H3toQ,1126 +win32/Demos/images/frowny.bmp,sha256=RgGveVt053KlmV4qVGwdCtrPyRA0JT57KQvf9PNOIvU,3126 +win32/Demos/images/smiley.bmp,sha256=wi53jYCy523fFYj_FYgzG1dxQdErw-ow2__dfoX9gsA,3126 +win32/Demos/mmapfile_demo.py,sha256=_-0M60tRoIAKGWAHduOJoRLkZehCvPyY7eHoQmrw318,2888 +win32/Demos/pipes/__pycache__/cat.cpython-39.pyc,, +win32/Demos/pipes/__pycache__/runproc.cpython-39.pyc,, +win32/Demos/pipes/cat.py,sha256=2kWkki-jLDZoh2BDgRzMxDGYyJwmOxf7083kvd2YhJY,335 +win32/Demos/pipes/runproc.py,sha256=g3qt57pJBXb9UHGJ872m6wUh9W70SCKovNEFfR4nHwg,4029 +win32/Demos/print_desktop.py,sha256=AItFduRpZoMmA2g_FnNbIq0JUJad-jYv9ZPhacZl6xI,2859 +win32/Demos/rastest.py,sha256=fgZyt7DezbTecP1uYDEPLHaAtrtyY3Uyz5sfcwnIfCU,5119 +win32/Demos/security/GetTokenInformation.py,sha256=SC1XvOtcF1_9sMK-bNJc7yEx2PMntHkmx9ppnbmomoA,3738 +win32/Demos/security/__pycache__/GetTokenInformation.cpython-39.pyc,, +win32/Demos/security/__pycache__/account_rights.cpython-39.pyc,, +win32/Demos/security/__pycache__/explicit_entries.cpython-39.pyc,, +win32/Demos/security/__pycache__/get_policy_info.cpython-39.pyc,, +win32/Demos/security/__pycache__/list_rights.cpython-39.pyc,, +win32/Demos/security/__pycache__/localized_names.cpython-39.pyc,, +win32/Demos/security/__pycache__/lsaregevent.cpython-39.pyc,, +win32/Demos/security/__pycache__/lsastore.cpython-39.pyc,, +win32/Demos/security/__pycache__/query_information.cpython-39.pyc,, +win32/Demos/security/__pycache__/regsave_sa.cpython-39.pyc,, +win32/Demos/security/__pycache__/regsecurity.cpython-39.pyc,, +win32/Demos/security/__pycache__/sa_inherit.cpython-39.pyc,, +win32/Demos/security/__pycache__/security_enums.cpython-39.pyc,, +win32/Demos/security/__pycache__/set_file_audit.cpython-39.pyc,, +win32/Demos/security/__pycache__/set_file_owner.cpython-39.pyc,, +win32/Demos/security/__pycache__/set_policy_info.cpython-39.pyc,, +win32/Demos/security/__pycache__/setkernelobjectsecurity.cpython-39.pyc,, +win32/Demos/security/__pycache__/setnamedsecurityinfo.cpython-39.pyc,, +win32/Demos/security/__pycache__/setsecurityinfo.cpython-39.pyc,, +win32/Demos/security/__pycache__/setuserobjectsecurity.cpython-39.pyc,, +win32/Demos/security/account_rights.py,sha256=FsqfkFAJoFJtHV7UZicfhvT3VmOuLmrn2iKl5apYXN8,1601 +win32/Demos/security/explicit_entries.py,sha256=mltZarR1A_Tl_LDQLRshwa2U8fA2uYGpn0_pyFAcoTk,4982 +win32/Demos/security/get_policy_info.py,sha256=7jJkpupbw-9FXbOxMI5tbv0VNzazhkxq_-PPg6TB3Sk,1243 +win32/Demos/security/list_rights.py,sha256=aKSBxrzW_NqIoMlXv98s79ruiV5P0eYcAP8keSCVqIM,1142 +win32/Demos/security/localized_names.py,sha256=d0qlbbxKfpgnQO9Yb8GhJYRZHYterMAOnn_O6BaRo7A,2014 +win32/Demos/security/lsaregevent.py,sha256=Y1BXw6_deapjxwAI6Enb4W3jw_DELkZ1atZrOsizpVU,532 +win32/Demos/security/lsastore.py,sha256=c3F20TTgqBF9KrlTnKtV19MLz34q3X98azv2VAm4JW8,472 +win32/Demos/security/query_information.py,sha256=37hU89b_vMMG-nSp-I2q4XxmnAGNHkpArZOdqfSX0EM,791 +win32/Demos/security/regsave_sa.py,sha256=euIJglnD7mU1Rg4GEgK3NF5ohO9WEjHk2FBdqQpXNVQ,1690 +win32/Demos/security/regsecurity.py,sha256=9_Yy6Z295hNQ0qMYSuSd6T_yiNCH7qkiFHaxSHlH8JU,1121 +win32/Demos/security/sa_inherit.py,sha256=BzaNVpPx9ZqadbC4AZYi7wwTaGz3afem_PEcgpj51rc,281 +win32/Demos/security/security_enums.py,sha256=kbohojv3qwRPSajn5yZKz_AQneMoHTCWm-0P_P5PxrA,9455 +win32/Demos/security/set_file_audit.py,sha256=28i198bU8o1lBnA6EQu9RS-0IxtBJygSI6RNjnnOXPw,3372 +win32/Demos/security/set_file_owner.py,sha256=zcTlt6531TfpMNQiiOLaQ0-1x64uj89vbKtDPmIQAig,2258 +win32/Demos/security/set_policy_info.py,sha256=5dM8SNOX9g_2D5pcbwQlxPsqhmkyDI0UrPT0MMI5RAo,965 +win32/Demos/security/setkernelobjectsecurity.py,sha256=S3xBNF8XnJSctu9gFLFwuFyu8ehYFa-tS27nAjYRWao,4917 +win32/Demos/security/setnamedsecurityinfo.py,sha256=fhFEUS51Rm1r6M4mX4jLsz6w-189btrOqZ8TF6L_mOE,4392 +win32/Demos/security/setsecurityinfo.py,sha256=KtMKjBGPolTUekwx4EtdFlJLSGqAx960qTgQUreGsLU,4541 +win32/Demos/security/setuserobjectsecurity.py,sha256=SmqVMeVH8bN8lWM9cMAYfELsgU6HVMG_ouScEFzElT4,3382 +win32/Demos/security/sspi/__pycache__/fetch_url.cpython-39.pyc,, +win32/Demos/security/sspi/__pycache__/simple_auth.cpython-39.pyc,, +win32/Demos/security/sspi/__pycache__/socket_server.cpython-39.pyc,, +win32/Demos/security/sspi/__pycache__/validate_password.cpython-39.pyc,, +win32/Demos/security/sspi/fetch_url.py,sha256=XxDLJ2zKoQ0A-9ARJrMWwEXcJtZcL18Dgl0ZCE1EBI0,5481 +win32/Demos/security/sspi/simple_auth.py,sha256=92hS8nXBg_kH30Qf9jqaU7xI3HJTMdPcqzhIpBpeoy8,2857 +win32/Demos/security/sspi/socket_server.py,sha256=mpr2xe9gRMoIKu3kPr_O4ZF7fewfN3Mjtnnx8jMGc98,6361 +win32/Demos/security/sspi/validate_password.py,sha256=Gj2r1u1SGj0NT5tcCLiIwx9bz0J5_ozHssmCEPd5Nvk,1128 +win32/Demos/service/__pycache__/nativePipeTestService.cpython-39.pyc,, +win32/Demos/service/__pycache__/pipeTestService.cpython-39.pyc,, +win32/Demos/service/__pycache__/pipeTestServiceClient.cpython-39.pyc,, +win32/Demos/service/__pycache__/serviceEvents.cpython-39.pyc,, +win32/Demos/service/nativePipeTestService.py,sha256=KXB4YFnk2z6V0404prv2oW1OUg_gd7-NhlghBmc6ILc,2135 +win32/Demos/service/pipeTestService.py,sha256=bqkQrDpLWMd_SzEnU_iUNn3KP621oj0fcKYFJsp_ETM,6893 +win32/Demos/service/pipeTestServiceClient.py,sha256=tKU1VU51U3QxdbRqN90DjwGjKs_3LZZcjtxyrudnbAY,4481 +win32/Demos/service/serviceEvents.py,sha256=XGu2Tqjhv3twEcZGTpCssVXzyIrR7e7lINxShXHoFcE,4075 +win32/Demos/timer_demo.py,sha256=lij0Of6r5ghh3E7fg4FkqBUAYo_XDZpDREsIz1D1XNs,2193 +win32/Demos/win32clipboardDemo.py,sha256=2EkkCOSVfTqmwvgo5RZTelABiQJDvfHwdXDSLqBwzt8,4666 +win32/Demos/win32clipboard_bitmapdemo.py,sha256=kFJ5BmyPVce8Y3bUtYORi7XO4VR-N7gygkURLqEVXBs,3905 +win32/Demos/win32comport_demo.py,sha256=Xo9KeibfPuz6uvWN-I4pHBqQ7IfctAxREj4AaDLILYk,5536 +win32/Demos/win32console_demo.py,sha256=U2H1v3LyWY3LTVBaHHTZaaEqlu-A-hTwCrjh_WOvIVI,5109 +win32/Demos/win32cred_demo.py,sha256=5oaFvckMwBTkqjuk9vyYjpRfV2o13rK__RxpsGww9_g,2747 +win32/Demos/win32fileDemo.py,sha256=TSA9sfxgQG2q0HwZvfo_UqcbfRbiW6DVbMzSgYSXrYc,1381 +win32/Demos/win32gui_demo.py,sha256=RhmGbFnu8UvbWCuKSMwYzNdeZ8L2SRPIBbWjyTC7LEs,5028 +win32/Demos/win32gui_devicenotify.py,sha256=PQnqxlZVird5m3O4OvPzyhR1Ypa5MmnObdmiDrrGHpU,3829 +win32/Demos/win32gui_dialog.py,sha256=ldOsaO1ufldw4zr0Chpv0qgF7pIj1TYk7UL9au2uD6o,15720 +win32/Demos/win32gui_menu.py,sha256=b23wrtt65MwNpqBjy7ipShMzoGULDdAWsgzON8m6p9g,16112 +win32/Demos/win32gui_taskbar.py,sha256=MgOrfh0Xjvv6Grlks6AQiE5r2Gcg3Q9VptydEkP0n14,5206 +win32/Demos/win32netdemo.py,sha256=BOjcaObHm1L4ewq1ofQRKrV7_8-0xX09LWRWI8I9Zls,8984 +win32/Demos/win32rcparser_demo.py,sha256=cNCMwKXkdTDaDkX5dSZLeVqEc7aiZGWTBB9SfcJmHKA,2809 +win32/Demos/win32servicedemo.py,sha256=i07Wc7Ys8WrjnDCHOaOcOxS7O1Z-hc5ZIkRRBB0PXuw,579 +win32/Demos/win32ts_logoff_disconnected.py,sha256=KOjz-vNXJJS1DbOyaiAPeoWJrBNcqKhmGsP8qZnMKgA,982 +win32/Demos/win32wnet/__pycache__/testwnet.cpython-39.pyc,, +win32/Demos/win32wnet/__pycache__/winnetwk.cpython-39.pyc,, +win32/Demos/win32wnet/testwnet.py,sha256=yvtMO4GP0DXmILS3juBSY3tylkz0swfu1QQ5yF3bdk0,4317 +win32/Demos/win32wnet/winnetwk.py,sha256=fG629VlAJpYQUZobQPrGF5BQIvdpB9JS4CKarKKgJ5Q,3193 +win32/Demos/winprocess.py,sha256=saxEdoi8a9mCTsq-0aXx_EHgsRYRkt6ANv6dnkH5HZY,7364 +win32/_win32sysloader.pyd,sha256=ryavCVi9mg_qUfD9ljDBh6Kbb0quo8CcYluTq6LMIr8,14848 +win32/_winxptheme.pyd,sha256=teaMDvz8cg0SyQnIaHoa7FJDy5cDA9JOAgoZZ2g08Bc,25600 +win32/include/PyWinTypes.h,sha256=vZkXXzqKeR7VwXW_Oz2HltucEdbZ_wu_I53uZ-7vUMY,30076 +win32/lib/__pycache__/afxres.cpython-39.pyc,, +win32/lib/__pycache__/commctrl.cpython-39.pyc,, +win32/lib/__pycache__/dbi.cpython-39.pyc,, +win32/lib/__pycache__/mmsystem.cpython-39.pyc,, +win32/lib/__pycache__/netbios.cpython-39.pyc,, +win32/lib/__pycache__/ntsecuritycon.cpython-39.pyc,, +win32/lib/__pycache__/pywin32_bootstrap.cpython-39.pyc,, +win32/lib/__pycache__/pywin32_testutil.cpython-39.pyc,, +win32/lib/__pycache__/pywintypes.cpython-39.pyc,, +win32/lib/__pycache__/rasutil.cpython-39.pyc,, +win32/lib/__pycache__/regcheck.cpython-39.pyc,, +win32/lib/__pycache__/regutil.cpython-39.pyc,, +win32/lib/__pycache__/sspi.cpython-39.pyc,, +win32/lib/__pycache__/sspicon.cpython-39.pyc,, +win32/lib/__pycache__/win2kras.cpython-39.pyc,, +win32/lib/__pycache__/win32con.cpython-39.pyc,, +win32/lib/__pycache__/win32cryptcon.cpython-39.pyc,, +win32/lib/__pycache__/win32evtlogutil.cpython-39.pyc,, +win32/lib/__pycache__/win32gui_struct.cpython-39.pyc,, +win32/lib/__pycache__/win32inetcon.cpython-39.pyc,, +win32/lib/__pycache__/win32netcon.cpython-39.pyc,, +win32/lib/__pycache__/win32pdhquery.cpython-39.pyc,, +win32/lib/__pycache__/win32pdhutil.cpython-39.pyc,, +win32/lib/__pycache__/win32rcparser.cpython-39.pyc,, +win32/lib/__pycache__/win32serviceutil.cpython-39.pyc,, +win32/lib/__pycache__/win32timezone.cpython-39.pyc,, +win32/lib/__pycache__/win32traceutil.cpython-39.pyc,, +win32/lib/__pycache__/win32verstamp.cpython-39.pyc,, +win32/lib/__pycache__/winerror.cpython-39.pyc,, +win32/lib/__pycache__/winioctlcon.cpython-39.pyc,, +win32/lib/__pycache__/winnt.cpython-39.pyc,, +win32/lib/__pycache__/winperf.cpython-39.pyc,, +win32/lib/__pycache__/winxptheme.cpython-39.pyc,, +win32/lib/afxres.py,sha256=RiZZ8okdHXZ-pOejL8HbvQXsn8-pMQ7NwDUbaPTBntU,15094 +win32/lib/commctrl.py,sha256=DmAOua7fRCr6lHbh_bPG2cdrelgRTb7HNqwAYHZefU4,46158 +win32/lib/dbi.py,sha256=vlUce_D8_wc2wMjVZG9pdtIvkS6gtFDPnfbv8uQfc7Q,713 +win32/lib/mmsystem.py,sha256=kw29KYoaJGqdgGBGfgbftym6_f8OD-mOrTNSz_tvgbA,30389 +win32/lib/netbios.py,sha256=pWoCH8JDIL617F8EbnzHWP86Awbj2ACwJS_PjP5mHbM,6948 +win32/lib/ntsecuritycon.py,sha256=_lPKpsii98qYvK-jQnd5u8pp7SlIG03qp-X6Oqiw5qM,22344 +win32/lib/pywin32_bootstrap.py,sha256=4pjdz8sCMiV_yqMwhEhFpOeAfE4rW9k4kp7ReRzZ0ZI,1283 +win32/lib/pywin32_testutil.py,sha256=eatBCMiaykGUds6blvMpZoAKP8FZgSwQsa4ePmffL7U,11552 +win32/lib/pywintypes.py,sha256=KY3OZoDVAF_jQkDGqsNUfZj-_DOgxNtenwoywoTtCbQ,5938 +win32/lib/rasutil.py,sha256=FjuhUcs9GJV738b87NW3M_Z5vM1vfnCpAukyeuAVJUY,1724 +win32/lib/regcheck.py,sha256=RROsPrf-5KgLDShfqIG5TNFJDBfHwpM0mXbrf8C7XvM,4484 +win32/lib/regutil.py,sha256=Dk7FRfoFBkFCNo5lARUtwpBSBnU0MUnymbvplNbFtl0,12341 +win32/lib/sspi.py,sha256=npvasRP6SQlonRfoiICQRgaEKQ5PLR98GYl1Rsau2wA,15590 +win32/lib/sspicon.py,sha256=QDqJuZF4RBuHad51PvmER_c1mPUuMHAcgaN-RHezQOA,15697 +win32/lib/win2kras.py,sha256=8EZ6HKb_wGbH7Sg82uXS6nau_lucwhw_4Ja10owjdlo,334 +win32/lib/win32con.py,sha256=fbmM7aXNk6WVSlQ0vQ13o0gl7HckAO1nA3qMh4OL3cc,117047 +win32/lib/win32cryptcon.py,sha256=TjsqyuGwrObbr7Wt6ZBIh591J1QjBjJHviX-R0nSPq0,72494 +win32/lib/win32evtlogutil.py,sha256=koAxNzU9o6sFVP-JgPUyvf2ZRxjgx2u-vh3acncqz8w,7612 +win32/lib/win32gui_struct.py,sha256=6-H1vAWeobUw5wHqZJ74ZE4JeFtyqxhm32l3yMDXobQ,30127 +win32/lib/win32inetcon.py,sha256=FB7ou-UCUSIhGZNrBZk2_KAQio9T8l2MjXYXKnPbaI8,43217 +win32/lib/win32netcon.py,sha256=fcWbv3RBPolR0Zmp3ht92v4Cf7EkTIE_Lb0984Qa6A4,18532 +win32/lib/win32pdhquery.py,sha256=sAA_SmLAQj7V_OeEzC2v1G1DJv83ecOMxrQVFHhdqqI,23345 +win32/lib/win32pdhutil.py,sha256=MGOB814wo4ZNDIt85KZD22RZtGpLKs293z9R-XI28oA,7572 +win32/lib/win32rcparser.py,sha256=CAD-KRP3n3_QG05uzDWJCuHnkMOzu4Itr15oPXg6PSU,21621 +win32/lib/win32serviceutil.py,sha256=WuwfsDByraKPt-akgbq2ge-G1qi1ZV1C7CAlSA0ZJik,37862 +win32/lib/win32timezone.py,sha256=C4QeUmGmYxp3mq3GhjgM2VBoe8_KXeuzgR8SObDUYhU,34707 +win32/lib/win32traceutil.py,sha256=DxDzgI06KikT1q0PL-dTPOD6l8ndmwduzadHRtOxSmE,1584 +win32/lib/win32verstamp.py,sha256=WQKPtDpB1fGjdCWqkezhDZozNklOn8EqhUViE-wVdSQ,7181 +win32/lib/winerror.py,sha256=ve_dHHk7N3yHEpJOwuncHdNs9NAjHEKgdU9IAMTDPOQ,101476 +win32/lib/winioctlcon.py,sha256=ljFa13irs2ZH36UOlyMnvzzjAuQGuoKgu8sUaPCwtyQ,35375 +win32/lib/winnt.py,sha256=8qiToFXnLxohR0otCvKEeHTSQdzG7i8R8CE8qJ8rMyg,37443 +win32/lib/winperf.py,sha256=p4fmgvYgDPHw3MvUjpD3WLlpyV2_61QwZRrEHhZY_gY,5911 +win32/lib/winxptheme.py,sha256=Ebg0pUmTrin3M0ORvfewXzcxqZGA1LN20O0Kuz4HuN8,254 +win32/libs/pywintypes.lib,sha256=vLahNG751DKTG6F-15vdMWydfIp7Rhh3GAasoF8Ovho,107442 +win32/license.txt,sha256=ETzTz3hOWGiF8B-T5d9498fACzTXbMQQHgKc0v1iIRM,1520 +win32/mmapfile.pyd,sha256=lgb9LyHA9_E2VUwufeYiTdEfkZEVj6RlqlrJKZuDOF0,21504 +win32/odbc.pyd,sha256=xokTeazb7H_5jx5rTDhHDqw4EevIGKtpZ3BymNXwoaU,42496 +win32/perfmon.pyd,sha256=SIuGpcB7TpczYNjCpql0IgCpvJgL2AOXoU9Q4Oy7epE,29696 +win32/perfmondata.dll,sha256=9rhuDqmDmvyc5llfn2RvjOUnqfS968JATn1pfvZMZpA,19456 +win32/pythonservice.exe,sha256=yl5DtJi4whYfo6Uo9ua5eRF_cJuPFmnQOulN2Uoh5vY,20992 +win32/scripts/ControlService.py,sha256=URoOH3hcdkPo_1NSRaPwcQAF8WGlQo1SLjUtdgwQI5M,18043 +win32/scripts/VersionStamp/BrandProject.py,sha256=KFHjxqZ3Yuc6QGqV7Gv8DIMm1PbCQnHNCJhTNoqGUYo,2789 +win32/scripts/VersionStamp/__pycache__/BrandProject.cpython-39.pyc,, +win32/scripts/VersionStamp/__pycache__/bulkstamp.cpython-39.pyc,, +win32/scripts/VersionStamp/__pycache__/vssutil.cpython-39.pyc,, +win32/scripts/VersionStamp/bulkstamp.py,sha256=dqLC-EevfZCrplxfOTBuI1UfUvL7dobPRas_TmyW9jU,4207 +win32/scripts/VersionStamp/vssutil.py,sha256=KdTKyGMdAdGr_f3ya43uiO8i6-9ITFAji8rI3x_q0sw,5690 +win32/scripts/__pycache__/ControlService.cpython-39.pyc,, +win32/scripts/__pycache__/backupEventLog.cpython-39.pyc,, +win32/scripts/__pycache__/killProcName.cpython-39.pyc,, +win32/scripts/__pycache__/rasutil.cpython-39.pyc,, +win32/scripts/__pycache__/regsetup.cpython-39.pyc,, +win32/scripts/__pycache__/setup_d.cpython-39.pyc,, +win32/scripts/backupEventLog.py,sha256=mvy1stDAciRVTlobLdCVQJKgmuGzCCQ3bL0pzqRDQOQ,1268 +win32/scripts/ce/__pycache__/pysynch.cpython-39.pyc,, +win32/scripts/ce/pysynch.py,sha256=Nvhynb-Ke2SPQ5KHXvMQ3R7G9nD1EhndeHbGfJQfBQk,8273 +win32/scripts/killProcName.py,sha256=2sJvQEC4ej2eiknuSghpaigOvJcQ45uYxXa34yIALfg,1994 +win32/scripts/rasutil.py,sha256=zEvSQzHxd3lzcaD29yX403ClRLlcnBRxuc5S2cegvw0,2722 +win32/scripts/regsetup.py,sha256=ilS8-DjzfLH0kHTcIlSvPqV5JsKszYxc8gH5xVS9GG4,20460 +win32/scripts/setup_d.py,sha256=HChtz62xaq7rcPXQywvK5RCEsA5YIoiW4bD6lCp6UJg,3500 +win32/servicemanager.pyd,sha256=6hH5jqSu7G0mCl1_venIrF2H-M_YL35X1Me-OOETanE,41984 +win32/test/__pycache__/handles.cpython-39.pyc,, +win32/test/__pycache__/test_clipboard.cpython-39.pyc,, +win32/test/__pycache__/test_exceptions.cpython-39.pyc,, +win32/test/__pycache__/test_odbc.cpython-39.pyc,, +win32/test/__pycache__/test_pywintypes.cpython-39.pyc,, +win32/test/__pycache__/test_security.cpython-39.pyc,, +win32/test/__pycache__/test_sspi.cpython-39.pyc,, +win32/test/__pycache__/test_win32api.cpython-39.pyc,, +win32/test/__pycache__/test_win32crypt.cpython-39.pyc,, +win32/test/__pycache__/test_win32event.cpython-39.pyc,, +win32/test/__pycache__/test_win32file.cpython-39.pyc,, +win32/test/__pycache__/test_win32gui.cpython-39.pyc,, +win32/test/__pycache__/test_win32guistruct.cpython-39.pyc,, +win32/test/__pycache__/test_win32inet.cpython-39.pyc,, +win32/test/__pycache__/test_win32net.cpython-39.pyc,, +win32/test/__pycache__/test_win32pipe.cpython-39.pyc,, +win32/test/__pycache__/test_win32print.cpython-39.pyc,, +win32/test/__pycache__/test_win32profile.cpython-39.pyc,, +win32/test/__pycache__/test_win32rcparser.cpython-39.pyc,, +win32/test/__pycache__/test_win32timezone.cpython-39.pyc,, +win32/test/__pycache__/test_win32trace.cpython-39.pyc,, +win32/test/__pycache__/test_win32wnet.cpython-39.pyc,, +win32/test/__pycache__/testall.cpython-39.pyc,, +win32/test/handles.py,sha256=mjn85rIgzBbGbow_DPWZyoZi8uTqo8m5cZJBfhM8D7s,5471 +win32/test/test_clipboard.py,sha256=zBp4de8exLa1xQ_Ppe6S04bmnvbfTbL_b06LCB4WoLI,4128 +win32/test/test_exceptions.py,sha256=JC0epOgJa0PbSZhwxO36EO2l9Dtyu4x1MNjtjMJ9ePM,8401 +win32/test/test_odbc.py,sha256=wZFdCemTuaCt1kc83xh17OMyQlYPooPUeZ8ZH418tA0,8472 +win32/test/test_pywintypes.py,sha256=W6ymR7AgMAZFA_nzrus9m6YNt_bKyEGrDkgu9obWen4,4174 +win32/test/test_security.py,sha256=wD2hHuIPRRFF6ZiAVr8kfmDx_xb5HTWS-FN-Qgvg2sc,6062 +win32/test/test_sspi.py,sha256=9HqzhMf7n3qR3zaiOqL-BPJPDEJjwAIn2mKVEZoy6Yw,8302 +win32/test/test_win32api.py,sha256=fkwl0JLCPjty7iUGRnI6ZR_fAdiJepsHDKnRSXS8K1s,9777 +win32/test/test_win32crypt.py,sha256=wmiF6JhjGAS7BEAvmXauK-gTyW5DSRz9xSqQgaEsj9c,4348 +win32/test/test_win32event.py,sha256=XQqBva9rMYVNiu7jAmwhIMepzme6fnId7lm7xQLTew4,4368 +win32/test/test_win32file.py,sha256=oVk9iGu6b1y-bD3DXhH4_UZVuq6quPoTsBIfbgYgD-8,41414 +win32/test/test_win32gui.py,sha256=JZOL8BzNJJiNgiZ_3sZut3q0ORuXlmTGNAjz9eHU7q0,2302 +win32/test/test_win32guistruct.py,sha256=kNDqhy0vvxblSohnSpdXxqDB4BfjLRi57SvvTR-XkMA,9207 +win32/test/test_win32inet.py,sha256=_FzexETpF3nGTrG_ypwInz7F_dqRbIV8ecQ2QXg088I,3119 +win32/test/test_win32net.py,sha256=wWJm50c_vtkMcoIHAPNiNvzcPhA6jX7DjZkFFCRbfXk,654 +win32/test/test_win32pipe.py,sha256=alZO1w8OeaXtFgVAoKWyQF5L9ASTC0MfuLdDxvjBdus,5007 +win32/test/test_win32print.py,sha256=Gx1ppuMryl-slhgqy439Na6PSLRS8t1hvmdBSreaQsQ,681 +win32/test/test_win32profile.py,sha256=1nu_IRuvyDBb_H4iPcVqiEZOG-W2XbQndFu_i8GB0kE,389 +win32/test/test_win32rcparser.py,sha256=9nfQwTX_di_mD5wcUjMu1sBKd2yyDlw8T_Cw8FUj0Ag,2462 +win32/test/test_win32timezone.py,sha256=LBNJbM01ChpgWe2LrOXZQ96ccCAdElf-4Gh7r-Uk-ac,774 +win32/test/test_win32trace.py,sha256=zd0poTUfdx65BIvEz-viTX2v35uAvkUei1s51WAu2DU,11415 +win32/test/test_win32wnet.py,sha256=pdYA2MKVzAeCPbT7saqpraz3Yn9Z73Hh7pKFuqnnbPw,5810 +win32/test/testall.py,sha256=3frOA0yR7wY4FPAL6Ut2uEbpl3CIt9p_t-xiosvh6nw,7254 +win32/test/win32rcparser/python.bmp,sha256=GWIxMoFdranqXHxIgyJ_dovJBNfCxc_OQlnSGxTfHLE,778 +win32/test/win32rcparser/python.ico,sha256=LnQC7RaDp1G7UiKgN55dilDjRn41wNDTWyo8ymRTctw,766 +win32/test/win32rcparser/test.h,sha256=znpRBpUSDy67a76sDHuP0uTAJYv09jfjkr1ehf_wi8I,1169 +win32/test/win32rcparser/test.rc,sha256=i6RNZ9n5bukZdZkLqlGNswPm7pCvq77WlT9LISaM4Bs,6273 +win32/timer.pyd,sha256=h0ROvrWhyPFbDtPnzF5Z44csUFG0um5wOR12vwG3-eU,16896 +win32/win32api.pyd,sha256=pS-L0otblVjN4QMzzkUqfW8zjOEAWiuEUXVQBYaOSpg,133632 +win32/win32clipboard.pyd,sha256=1t8H6bWr5rky32B9fTIWBT7LRYPkrX6PVr1DNhNCXG8,27648 +win32/win32console.pyd,sha256=SkCP4llfRkCaRJ4X8fjq8fXQ3Dl4pZT7TL8-kFMqu_w,59904 +win32/win32cred.pyd,sha256=g9pnxDQ1O1aZA_TJGq9WXaNvWPMtXuG8-oFWA8_d1-o,36352 +win32/win32crypt.pyd,sha256=01Hzt89aZECiRTU5heviM2CA1demKvbgQznT6O_wKL8,124416 +win32/win32event.pyd,sha256=5GnD6aaDbOON6gWFTSfKoz63ZoglJ_c_YOPiJUutxRs,28672 +win32/win32evtlog.pyd,sha256=pstvL83Ed5-T15hPHwfHij4TbcUCemTBVDg0_KkxUO8,73216 +win32/win32file.pyd,sha256=LFFNCE9b0u5RL6r92PSFg3udRHM36UIRN3ayu6HXzIg,143360 +win32/win32gui.pyd,sha256=j-TU5bfs3HkfVPAJ4XxRbUO8ar1M06MQimofKXaKyPo,217600 +win32/win32help.pyd,sha256=9Wz7n3TZQL6IkVdkcr9P8cgwaFa0j8qzFls67S3M3y4,53760 +win32/win32inet.pyd,sha256=6Rl27KmstPhdXkK1uzbW_l14Qmc-N071GdUqCZjgvEA,53248 +win32/win32job.pyd,sha256=cPSdNHTVKuFHr1g59ze0d6bO8MSTMK0JrsfNNW8y4o8,28672 +win32/win32lz.pyd,sha256=OGuUw2CyILCbyNJ3e2z1KBRsM2FmEWbbT9nTlC3i0DA,16896 +win32/win32net.pyd,sha256=PeaH-hvzt5KAf3Ud0VrrtpBropaDK-9Jry1rkb1l6Mc,93184 +win32/win32pdh.pyd,sha256=htb5VcFWQke2Y35IJ69XTrr0faaaPgVT0tXh9r2DEkc,34816 +win32/win32pipe.pyd,sha256=PCHKMVAvxpYS1ER291e2zJwaa5F2Ck7nd7KedCoo2ac,28160 +win32/win32print.pyd,sha256=-4nFrHMSRsbPRY7YdezwaQKAZn38UjFS02rH6S5HCP8,73728 +win32/win32process.pyd,sha256=Q0RofxkXimq1v1MyUerDxJWUQ_KVOXaCMg36PgMJ4xk,53248 +win32/win32profile.pyd,sha256=Ku6Q9wBkg-IEI0cu23VBmK688EznK__CUy88DCjwEfg,26624 +win32/win32ras.pyd,sha256=JJTWkgSa8kWA901Zl4Tnz-3LXBv3BUgZO3vG0G5rF6M,34304 +win32/win32security.pyd,sha256=aIM_L9ZnBvyAtDLZ0xWskr1A3_to-LLx0hO_AMifR28,136704 +win32/win32service.pyd,sha256=yqxoHkVZhZ7muIQqj97hytLh9bLBuLIl7sEvaTEJ_T8,58880 +win32/win32trace.pyd,sha256=lHONF_EBUSewHh5DdfyBYCziCsrE3_7Iz88pxnlZEhI,23552 +win32/win32transaction.pyd,sha256=lAdsp9jD1D2vBeZl2lX2AguOB4SF3tnPvb2vWhB1ZP4,19456 +win32/win32ts.pyd,sha256=xq1nMP7NyFf4YWt0ZRC3nl6DpDKGJ4XW-f3wIWyhEIU,33280 +win32/win32wnet.pyd,sha256=q6pZadIt05r4n10b3aNwWHUDeUewDbw-MxEfhDUnHdI,37888 +win32/winxpgui.pyd,sha256=3DRbk23BZBiOcDpzLzIZq3Z7KsthikBjMciqpJGFR1M,631296 +win32com/HTML/GeneratedSupport.html,sha256=kZ9Ocb7nmMiJu7oeXJmpIdkURovpTBN5WO9iebjT4sU,6023 +win32com/HTML/PythonCOM.html,sha256=nOFjOANTKZfr4sMFJRvDNlSeGTPWiR8iPRSNtnidVMg,8943 +win32com/HTML/QuickStartClientCom.html,sha256=DiflgPTFf6zP7us8EbMIkIlizL9BkqPhDvmBM7PTue4,7310 +win32com/HTML/QuickStartServerCom.html,sha256=Tkw5Q4HG9V6YMTbXiUbOqJoLLQUaUbAJRH3nwI-LoPQ,12940 +win32com/HTML/docindex.html,sha256=Scj_acL7n0w9Whkd7s3Xx8u0Iwt71pK34K83ypsUIDU,1295 +win32com/HTML/image/BTN_HomePage.gif,sha256=nTV7ZQiN6x1fFcWKt4jHj3WsIzjv04XjJrCbqRpSIBk,211 +win32com/HTML/image/BTN_ManualTop.gif,sha256=LwVu_ClkEDG1xhVBiCAy-OLi9-ZJ6BIINjAyi2R7jJ4,215 +win32com/HTML/image/BTN_NextPage.gif,sha256=hGnR6jZJERMUsnduVHP4AlntrkgehcFpDyfhI4xvj4k,218 +win32com/HTML/image/BTN_PrevPage.gif,sha256=wFJ1YHrsOEzBr3jDEOqBGKQmqWGBkADtnCPEMJHpm-U,216 +win32com/HTML/image/blank.gif,sha256=iJO_Up8XRXUyA8YYNoftgJlVONefdsXEFNfIuQxWFMs,864 +win32com/HTML/image/pycom_blowing.gif,sha256=s8ZSBzs8dfWsgTgbb0S43urQZcY1xjdxoIBuSHeLr6o,20926 +win32com/HTML/image/pythoncom.gif,sha256=pBINoAg9LpAFllAeRM5vHHgNcSUtWlAty7bYkjMnBho,5767 +win32com/HTML/image/www_icon.gif,sha256=TJw2huqtQFld280AhhQ39etm1ITsh4cg896hMi2Pr4c,275 +win32com/HTML/index.html,sha256=hL3O1peZWaQv9OSS5FFUVigqXmGd07e0y4YILZvIeXI,1629 +win32com/HTML/misc.html,sha256=HLInjzAaBT90JWKVnFr53OuINhMBgMsZ-lNukSgwbds,1164 +win32com/HTML/package.html,sha256=MtR3YxZRP2iB2dRYPSMjooX5UKdXSGT_WXqz3FxODxc,3253 +win32com/HTML/variant.html,sha256=gbKY45CQuRXg_Wg7qlu-vYCH8KUiZ5Mn2GDEYJogOBk,5874 +win32com/License.txt,sha256=0YrRjNvh0WhYlo721oPOGjR1IqK4wGIM3p0rL6xCkxQ,1548 +win32com/__init__.py,sha256=uFAxaqwWK-aJZqEEKFfYrOu1V2dY7XrqOAJrE7JPPxU,4883 +win32com/__pycache__/__init__.cpython-39.pyc,, +win32com/__pycache__/olectl.cpython-39.pyc,, +win32com/__pycache__/storagecon.cpython-39.pyc,, +win32com/__pycache__/universal.cpython-39.pyc,, +win32com/__pycache__/util.cpython-39.pyc,, +win32com/client/CLSIDToClass.py,sha256=dXl3awgzTc1KnoZSMPpxZZjXe4i65FbZcC2PpjQRm50,1757 +win32com/client/__init__.py,sha256=IQNd5g_UAbw0oo7ZYAnHqgSgc4Yg-YB8l5YwPxhtibA,26331 +win32com/client/__pycache__/CLSIDToClass.cpython-39.pyc,, +win32com/client/__pycache__/__init__.cpython-39.pyc,, +win32com/client/__pycache__/build.cpython-39.pyc,, +win32com/client/__pycache__/combrowse.cpython-39.pyc,, +win32com/client/__pycache__/connect.cpython-39.pyc,, +win32com/client/__pycache__/dynamic.cpython-39.pyc,, +win32com/client/__pycache__/gencache.cpython-39.pyc,, +win32com/client/__pycache__/genpy.cpython-39.pyc,, +win32com/client/__pycache__/makepy.cpython-39.pyc,, +win32com/client/__pycache__/selecttlb.cpython-39.pyc,, +win32com/client/__pycache__/tlbrowse.cpython-39.pyc,, +win32com/client/__pycache__/util.cpython-39.pyc,, +win32com/client/build.py,sha256=rEhmcUE27atIT2xG_o7WXZMsp6nwRdXjylxQBU7359Q,29075 +win32com/client/combrowse.py,sha256=U0a-lkcDHlTAmtIOl04ltIWappi8I5T4bCiEk5_1IYk,20283 +win32com/client/connect.py,sha256=9d5OGFwCEgx9AH-Luj_3nAX75mEVXN_0PmWAXlL4K7Q,1556 +win32com/client/dynamic.py,sha256=FILCgCRh442krTcWmsxrc9jsqbNDJp7XN5TJjdcs5oI,28118 +win32com/client/gencache.py,sha256=BYj4rZ4Uq4T8tuEYJIPfRDY-rUhtTpo6sZhgP-DZsrc,27995 +win32com/client/genpy.py,sha256=BqxWIIyF_ddjmmnXXjk2VhOrNhJrTmRW7mnPePONyYI,56188 +win32com/client/makepy.py,sha256=vecqHGEY3ZgJS9uJZqfHb2AZ-_v4HwaMoGrEQo2Gr_k,14916 +win32com/client/selecttlb.py,sha256=PAe1UYnTMwVKnTxTep2juL_GjjSbTohO4zdoeA2TQbc,6316 +win32com/client/tlbrowse.py,sha256=JiF-a3gLOS47E-ZFhb2wwxIPdc4Mnob9IOVbWfb2ZQk,9524 +win32com/client/util.py,sha256=zPxfrUeUArQcIpnMs0aGgN7hIL-nawoODE8054Zq9tw,3339 +win32com/demos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +win32com/demos/__pycache__/__init__.cpython-39.pyc,, +win32com/demos/__pycache__/connect.cpython-39.pyc,, +win32com/demos/__pycache__/dump_clipboard.cpython-39.pyc,, +win32com/demos/__pycache__/eventsApartmentThreaded.cpython-39.pyc,, +win32com/demos/__pycache__/eventsFreeThreaded.cpython-39.pyc,, +win32com/demos/__pycache__/excelAddin.cpython-39.pyc,, +win32com/demos/__pycache__/excelRTDServer.cpython-39.pyc,, +win32com/demos/__pycache__/iebutton.cpython-39.pyc,, +win32com/demos/__pycache__/ietoolbar.cpython-39.pyc,, +win32com/demos/__pycache__/outlookAddin.cpython-39.pyc,, +win32com/demos/__pycache__/trybag.cpython-39.pyc,, +win32com/demos/connect.py,sha256=mzBaW-4g1dJjeu6DKy3Loh4e4jYw-PLDukP3qitYXts,3894 +win32com/demos/dump_clipboard.py,sha256=Iw1AtoUEtB_m05BXNfbcB9Ko7Ysbdmwhdd29PebYla0,2948 +win32com/demos/eventsApartmentThreaded.py,sha256=VfOjVacTb_VXJbwEaAl6pgUCa6y_DN5KM3H6c5oMPpU,3666 +win32com/demos/eventsFreeThreaded.py,sha256=WocVD6sTc3d1ey0JrJQs8c68cRITmrNbNH6bSLzeqOo,3464 +win32com/demos/excelAddin.py,sha256=QdIZJE2Pd6RbBuyOmYGfphRJ7-SeEexHKubrPytYlwc,6113 +win32com/demos/excelRTDServer.py,sha256=qzNI-MkxShq7M1wIEaaTMS3dQcLjhtp4HVSn-o-P-gc,16255 +win32com/demos/iebutton.py,sha256=wOa4keXARP4LmGy7TqEQPIZbEciL2-And_mOO_k5_9M,7085 +win32com/demos/ietoolbar.py,sha256=xuIwFejrzvtDsuDLi79sCgcprKYpTKzh5Uil0RHQuO8,11009 +win32com/demos/outlookAddin.py,sha256=_mDgCOfznjX7e4aA2qIZgAE8yldLKgcq-lx70pPs9ck,4700 +win32com/demos/trybag.py,sha256=ZFXKNUt1zzz6uUAqHiApe2AP0H3gKLSforwSgYw5N7U,2088 +win32com/include/PythonCOM.h,sha256=tHh9oSLMQRpJjhzrjJ9VP2GrdcPGTIiA71_5FsYTJCc,30291 +win32com/include/PythonCOMRegister.h,sha256=Rye8T8o018cPzAiXp437lLiNggKWaNDdAw5dvYxlT_8,4264 +win32com/include/PythonCOMServer.h,sha256=yLr6uYaf757pBtUU6OBukovBwTX6Kmi8X4F9rYnuR48,9027 +win32com/libs/axscript.lib,sha256=u9wCzszI5ePrJyTSPeb8r0SgB-t81M80iypdFrO2ZBs,72478 +win32com/libs/pythoncom.lib,sha256=__1Cr5t19Yznhkn7VWANQCO6S_aWIgIQ-VNNBwpU6OY,159312 +win32com/makegw/__init__.py,sha256=_YglApLhpR2XszXs9oBtOgxSaAqUH53iH_trnoLJdus,30 +win32com/makegw/__pycache__/__init__.cpython-39.pyc,, +win32com/makegw/__pycache__/makegw.cpython-39.pyc,, +win32com/makegw/__pycache__/makegwenum.cpython-39.pyc,, +win32com/makegw/__pycache__/makegwparse.cpython-39.pyc,, +win32com/makegw/makegw.py,sha256=xJk2f0eFPWpBeL_DUXDq-VzPZiP1E58BrMVeOB_nDMI,20176 +win32com/makegw/makegwenum.py,sha256=6UmksMOTCyLrAcDTW6GSNg_u5us20nrLvgO4uAT8Al8,9847 +win32com/makegw/makegwparse.py,sha256=KDhEo1NhotzltnGo1m3xEd9nBJs-Aj4i_TMqZyVNfe8,34854 +win32com/olectl.py,sha256=7FAT0ftFpoSZK67OtT3GAvimyojpCwUA2DlSRLHYWqw,2626 +win32com/readme.html,sha256=YFr56hfOCiqi-I6adQtfK2gJ9qTSwZwFq7ZXZQz3cvY,3719 +win32com/server/__init__.py,sha256=WDdzHBFOO3yXjwHWIwKCpahesWtssIWIJTVRjCtYoLs,50 +win32com/server/__pycache__/__init__.cpython-39.pyc,, +win32com/server/__pycache__/connect.cpython-39.pyc,, +win32com/server/__pycache__/dispatcher.cpython-39.pyc,, +win32com/server/__pycache__/exception.cpython-39.pyc,, +win32com/server/__pycache__/factory.cpython-39.pyc,, +win32com/server/__pycache__/localserver.cpython-39.pyc,, +win32com/server/__pycache__/policy.cpython-39.pyc,, +win32com/server/__pycache__/register.cpython-39.pyc,, +win32com/server/__pycache__/util.cpython-39.pyc,, +win32com/server/connect.py,sha256=nH7Et4eKgxggOOqoVvPqL4xAX2_V34-M9jqgVmz_LY4,2780 +win32com/server/dispatcher.py,sha256=lAf9W3NcNgNGZjpdhOIU1Jhnpx-8f8iYHDKVumMMDZ8,9975 +win32com/server/exception.py,sha256=FPF_4rVf3I07g2L5ddwkiIWFua3pfZL0WOoruc25o4s,3496 +win32com/server/factory.py,sha256=khsZQfYi9cWl18YYn0iGpM9tlXcawJCLyscqNs-u-eE,850 +win32com/server/localserver.py,sha256=6mbJbwVRct45AJKb8h0lz5qXsgfVAJqvFku25_a60Q4,1194 +win32com/server/policy.py,sha256=mXjFNrN7n3NRKpHQ4_yZ9V0f7ZH6_LF6-mjp8rxXROk,33141 +win32com/server/register.py,sha256=jSCiUBXkvFTL_uxye__VPYZNRPy4hMawO-a-okd0SvU,25076 +win32com/server/util.py,sha256=DY6SXnEFOer8ynZRADTCoEaqDzWxz1V-fF_kCpv-cr4,6702 +win32com/servers/PythonTools.py,sha256=EU3hVKFSI9Gq1Q_M_wJJPHlr82fwnhgTDI8t05vryhs,1178 +win32com/servers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +win32com/servers/__pycache__/PythonTools.cpython-39.pyc,, +win32com/servers/__pycache__/__init__.cpython-39.pyc,, +win32com/servers/__pycache__/dictionary.cpython-39.pyc,, +win32com/servers/__pycache__/interp.cpython-39.pyc,, +win32com/servers/__pycache__/perfmon.cpython-39.pyc,, +win32com/servers/__pycache__/test_pycomtest.cpython-39.pyc,, +win32com/servers/dictionary.py,sha256=86bsUYyT1SvvGutYnqNpAIqAcvlZ-FNBuvjUvizkXyk,4463 +win32com/servers/interp.py,sha256=hlxbrLDNPr5ZaqoI-d19fd6bIDrNShY36JIO2YZVU5U,1664 +win32com/servers/perfmon.py,sha256=WzvgpOmWIYrLUwXZRoW4dSsXwy8AaFmHaXOjuKq-ekU,1164 +win32com/servers/test_pycomtest.py,sha256=nfjNeIfeimZ2sWRgP_E2-kVbMcqJPL-fwFxEYE-Y1z4,5105 +win32com/storagecon.py,sha256=TtwZ7gTHKM4QkNqLmcBk1kQCxYQNFLf_cQXzHVykBw0,3029 +win32com/test/GenTestScripts.py,sha256=vOD1pmB6IqJpFKKq9B8kkj9u1PV2IzdF74_stQte96Y,2590 +win32com/test/Testpys.sct,sha256=2Kt_ngKxBqmxcBsBpph4DReQPT1TitBLMgPaC7gACvU,1058 +win32com/test/__init__.py,sha256=b62TU9a3IDJpL-4jCbL_cO1Sa2iqfw8Q4hMehSwegwE,43 +win32com/test/__pycache__/GenTestScripts.cpython-39.pyc,, +win32com/test/__pycache__/__init__.cpython-39.pyc,, +win32com/test/__pycache__/daodump.cpython-39.pyc,, +win32com/test/__pycache__/errorSemantics.cpython-39.pyc,, +win32com/test/__pycache__/pippo_server.cpython-39.pyc,, +win32com/test/__pycache__/policySemantics.cpython-39.pyc,, +win32com/test/__pycache__/testADOEvents.cpython-39.pyc,, +win32com/test/__pycache__/testAXScript.cpython-39.pyc,, +win32com/test/__pycache__/testAccess.cpython-39.pyc,, +win32com/test/__pycache__/testArrays.cpython-39.pyc,, +win32com/test/__pycache__/testClipboard.cpython-39.pyc,, +win32com/test/__pycache__/testCollections.cpython-39.pyc,, +win32com/test/__pycache__/testConversionErrors.cpython-39.pyc,, +win32com/test/__pycache__/testDCOM.cpython-39.pyc,, +win32com/test/__pycache__/testDates.cpython-39.pyc,, +win32com/test/__pycache__/testDictionary.cpython-39.pyc,, +win32com/test/__pycache__/testDynamic.cpython-39.pyc,, +win32com/test/__pycache__/testExchange.cpython-39.pyc,, +win32com/test/__pycache__/testExplorer.cpython-39.pyc,, +win32com/test/__pycache__/testGIT.cpython-39.pyc,, +win32com/test/__pycache__/testGatewayAddresses.cpython-39.pyc,, +win32com/test/__pycache__/testIterators.cpython-39.pyc,, +win32com/test/__pycache__/testMSOffice.cpython-39.pyc,, +win32com/test/__pycache__/testMSOfficeEvents.cpython-39.pyc,, +win32com/test/__pycache__/testMarshal.cpython-39.pyc,, +win32com/test/__pycache__/testNetscape.cpython-39.pyc,, +win32com/test/__pycache__/testPersist.cpython-39.pyc,, +win32com/test/__pycache__/testPippo.cpython-39.pyc,, +win32com/test/__pycache__/testPyComTest.cpython-39.pyc,, +win32com/test/__pycache__/testROT.cpython-39.pyc,, +win32com/test/__pycache__/testServers.cpython-39.pyc,, +win32com/test/__pycache__/testShell.cpython-39.pyc,, +win32com/test/__pycache__/testStorage.cpython-39.pyc,, +win32com/test/__pycache__/testStreams.cpython-39.pyc,, +win32com/test/__pycache__/testWMI.cpython-39.pyc,, +win32com/test/__pycache__/testall.cpython-39.pyc,, +win32com/test/__pycache__/testmakepy.cpython-39.pyc,, +win32com/test/__pycache__/testvb.cpython-39.pyc,, +win32com/test/__pycache__/testvbscript_regexp.cpython-39.pyc,, +win32com/test/__pycache__/testxslt.cpython-39.pyc,, +win32com/test/__pycache__/util.cpython-39.pyc,, +win32com/test/daodump.py,sha256=e2me35YGDLq0GvNcDA-UWeQPZd910HdnpYXgamjnNrQ,2275 +win32com/test/errorSemantics.py,sha256=Au3k8JqdEeixmpJKiFrsIwn5_gx8Q8SH77F4sy6sHbY,9004 +win32com/test/pippo.idl,sha256=IKfyeUEzhBcbFsLdKC0fN7B1Kf8Y2yFwe30O6m5niNU,1852 +win32com/test/pippo_server.py,sha256=BCj5Q9d6tT08T7G0DM5wW5yuCatVFtF9O8D4MAH69aE,2668 +win32com/test/policySemantics.py,sha256=QnSL05CnxYKA5-z_X47cH_1zGIW3pb0gzYNeQjJswgw,3162 +win32com/test/readme.txt,sha256=SIaK0lTI8gVwn5r2MmbM1CNaOIk5PfW3g2CYgrSntDE,718 +win32com/test/testADOEvents.py,sha256=QdNtEnsFOwt3zXsoInXVK4kpicQEUjWEcfpDcpkjQyo,2788 +win32com/test/testAXScript.py,sha256=J9qtOSQh2dlo9zRI5YXskBDIpMbxGasAedgBWJnVg44,1334 +win32com/test/testAccess.py,sha256=EB2-GkoPyMeChGAgl9L32zQ0XBi5yeQWp3CbtU6ERRU,5780 +win32com/test/testArrays.py,sha256=FcG9Wo2zsn7JNCrSTu7YDk25Rp1DzQVYEO_Vv2y-auk,2061 +win32com/test/testClipboard.py,sha256=GXEtDlJql9sOmT9bjci1a0IEYdBq_WjBPgLurzmALY0,5802 +win32com/test/testCollections.py,sha256=zlx-EvZIFYQppjJIsffO8DU90Nqzg10R0oPPxoJgHk8,4443 +win32com/test/testConversionErrors.py,sha256=xy5gVl55KKvryed1yWp2ZQE92YOnCtXw23E6vpTUIWs,796 +win32com/test/testDCOM.py,sha256=_OYw2mB-WMUZCPxgTobJn4PayZCoj8D5GYmUUCePhF4,1732 +win32com/test/testDates.py,sha256=G7KKL9Cis4YczhHV-aRcv8N77NLunovLBYBKxHiTg_Y,1834 +win32com/test/testDictionary.py,sha256=Zb9ndXc8-hy7yNhyl11E0ukcTvpXNL2ZFHjtZ_GvYTs,2875 +win32com/test/testDictionary.vbs,sha256=XuTmRxUQHvq7BMCF77shUTuECD23XaOC9tVVUOGIbd0,562 +win32com/test/testDynamic.py,sha256=ylRliTeNgmFii_rGd_CISMJr1xL3WLGDJXyOmHn3ZUA,2804 +win32com/test/testExchange.py,sha256=tLahAG_gKqVBx4XpiSGr8B_3CZaVW8y9jTlIjO040b4,3352 +win32com/test/testExplorer.py,sha256=dUquki70gjTjRF9hFT9ExqwgsOUfVkC7yUYyt7uNgXM,4715 +win32com/test/testGIT.py,sha256=Pp9SIUIFzpNgWdT-NkXSoQRFu1dT1VpnWr6HKjmSVcY,4690 +win32com/test/testGatewayAddresses.py,sha256=8w4boEF7JBcsH_WGYKrAdNvRxUxuuPiiWG38yjPjle4,5217 +win32com/test/testInterp.vbs,sha256=5jsqgEH2g0kug8H9rDoMlOP2yynP-1T52X1OsGqaTgo,258 +win32com/test/testIterators.py,sha256=hszyUADAX1v6aj7EiUCDcJdiRLMCxUW4yd3_mCvzjiU,4619 +win32com/test/testMSOffice.py,sha256=fXvN16oh6cwvR0spD7-s4rdcim_n5yeiwlsR4hiVXeM,6086 +win32com/test/testMSOfficeEvents.py,sha256=qflmj0YiOhWo75QzXFdDZ73JKxCpCvheW7vxNSmm3nw,3982 +win32com/test/testMarshal.py,sha256=BNBjGhbZy3Euu-SseZgPHR2VmiHEB3ymI8mlv5i6sD4,6069 +win32com/test/testNetscape.py,sha256=5ITtp17a-jqJ0lzApuAcKBh09_j2srs2nqon4vt8PYA,660 +win32com/test/testPersist.py,sha256=03F1-iEsE-F1H32X2EUvaAGruR5S81oADzW5viAYp-8,6397 +win32com/test/testPippo.py,sha256=ysS_U5l0aTJv7LlgPwuMTMruR5xhrNFBkSWdGzr_OsQ,2700 +win32com/test/testPyComTest.py,sha256=U6XNFlQSWeHUle0-YoAYxutoFYz0tVhyWTTpKAwDP90,29052 +win32com/test/testPyScriptlet.js,sha256=DKTmlgw3MitKHXu9XCRl0_dJvROhj3FgmFWtgluKVz8,1087 +win32com/test/testROT.py,sha256=ciu7Uq8wT7s8tqwyWTO-Ta4CX2xe-14alJ-7d1PzpNA,762 +win32com/test/testServers.py,sha256=RYN4vIw-XTOlVQkfXbCq_NFCehjjTECCB0KIm1i5VYU,1391 +win32com/test/testShell.py,sha256=gLSexT1vs5Z3W63sSg0gDZiR5lTMtRUxCfyfPjIwUks,9712 +win32com/test/testStorage.py,sha256=GvT7HGcjbVUvjEuj_-jJGkxWhsmNOrHGRuHgXOOctQk,3625 +win32com/test/testStreams.py,sha256=SVFQZU_BQY8m8wUGHeTB0--IrmKzJFy_qdDBtJ8t-Vs,4310 +win32com/test/testWMI.py,sha256=wO54Y_tb7aRasvhnh4lxU5t-nPrMWqViFHZyn3RDLCM,468 +win32com/test/testall.py,sha256=0QladeGNUzECqQO7xqkB-rxyvOBDO8WmdB749Ek0S_Q,9904 +win32com/test/testmakepy.py,sha256=14ZbWbmj0POipf7eN0R_7aqB4KTvv9LeMpqsgqHR_x8,1922 +win32com/test/testvb.py,sha256=vJOLecHLYfO015w-I5y2Dw96-Yz4j6Pa27MOk16SlCE,20911 +win32com/test/testvbscript_regexp.py,sha256=EIEU4SjeFl2xxSDrLsdYg4-PivWPcj3AWXuT3ZXrp0E,1096 +win32com/test/testxslt.js,sha256=dfBCany-kdVVYXD5Ommgf7Fld5DOVhWq7olM4Xo57xE,569 +win32com/test/testxslt.py,sha256=ivmjlD6GYmxtbMkcEVlLEqPAKoJ2QXHwwGSZHYKiess,921 +win32com/test/testxslt.xsl,sha256=6-rByRIkFOQ1V68Hn0NBpzp6Ww5ch6uFvYJDC9jLjYE,2058 +win32com/test/util.py,sha256=rj9AquI5pJ_PLI0-mSyTS-FyA_oE7jibg8B7G6x7syQ,8175 +win32com/universal.py,sha256=l_veHcSa78Ejl0BVOooH0PdK4qGoBgxU2s0Bg0ffrZ8,8532 +win32com/util.py,sha256=7yZaay2Z1Fp3bxeLfElYAO2BeuAp49acUozlXBbdg4o,1030 +win32comext/adsi/__init__.py,sha256=W_wFLuhDumhBKpfzUagpoNCwzo71ZVtnaYbTL0K6V5E,3694 +win32comext/adsi/__pycache__/__init__.cpython-39.pyc,, +win32comext/adsi/__pycache__/adsicon.cpython-39.pyc,, +win32comext/adsi/adsi.pyd,sha256=HQAiH1NaVF1bCn3Yewu0KpJFnZXTjZ-hgbnpRaNVK9w,97792 +win32comext/adsi/adsicon.py,sha256=xtGK4ohhziqcJPb4KUPa2bsiuJyp4BC9s6T5h_WjdXg,12303 +win32comext/adsi/demos/__pycache__/objectPicker.cpython-39.pyc,, +win32comext/adsi/demos/__pycache__/scp.cpython-39.pyc,, +win32comext/adsi/demos/__pycache__/search.cpython-39.pyc,, +win32comext/adsi/demos/__pycache__/test.cpython-39.pyc,, +win32comext/adsi/demos/objectPicker.py,sha256=4RulV2CU-6Fd21vmbk5y_afn9GBZPouBXgJtI1a3adE,1941 +win32comext/adsi/demos/scp.py,sha256=LIv4-_eW8w0oOO5S0ODq2_VHdam51-scYWdxo21yNM8,19144 +win32comext/adsi/demos/search.py,sha256=_5JrO_qP0XzRzUwddGVj_i-WBkIq3t2loMUymXy95S4,4169 +win32comext/adsi/demos/test.py,sha256=1SC8xgaRAB717WD7E0gfzdjCkcBh3kovX75DKsMNV_U,8519 +win32comext/authorization/__init__.py,sha256=fRpv5U3JDCOw9goPCz-dXK6awa_sudZXj3W1Ac3llQg,192 +win32comext/authorization/__pycache__/__init__.cpython-39.pyc,, +win32comext/authorization/authorization.pyd,sha256=y3fpI4S9_yKRdxGFxtXflxzZLmeIKuQk1x6w5QQ9KC8,29696 +win32comext/authorization/demos/EditSecurity.py,sha256=mS4Yw9iMZ4tb4LLi-E79OwlrR95nJQjnEbbuPaiEqAc,9011 +win32comext/authorization/demos/EditServiceSecurity.py,sha256=8VE3d5f0GIGFeAnzO9hk00gOwD3doPVMlEJUFapAQKA,8637 +win32comext/authorization/demos/__pycache__/EditSecurity.cpython-39.pyc,, +win32comext/authorization/demos/__pycache__/EditServiceSecurity.cpython-39.pyc,, +win32comext/axcontrol/__init__.py,sha256=8LtQrxyupbKEvUY-WTginn0izGELLXZ-4XeOkqhYSbQ,135 +win32comext/axcontrol/__pycache__/__init__.cpython-39.pyc,, +win32comext/axcontrol/axcontrol.pyd,sha256=jSOFVa8eBW1BGpmjf1NmMvuUrXw-05accFWVWoQMOBE,143872 +win32comext/axdebug/__init__.py,sha256=8LtQrxyupbKEvUY-WTginn0izGELLXZ-4XeOkqhYSbQ,135 +win32comext/axdebug/__pycache__/__init__.cpython-39.pyc,, +win32comext/axdebug/__pycache__/adb.cpython-39.pyc,, +win32comext/axdebug/__pycache__/codecontainer.cpython-39.pyc,, +win32comext/axdebug/__pycache__/contexts.cpython-39.pyc,, +win32comext/axdebug/__pycache__/debugger.cpython-39.pyc,, +win32comext/axdebug/__pycache__/documents.cpython-39.pyc,, +win32comext/axdebug/__pycache__/dump.cpython-39.pyc,, +win32comext/axdebug/__pycache__/expressions.cpython-39.pyc,, +win32comext/axdebug/__pycache__/gateways.cpython-39.pyc,, +win32comext/axdebug/__pycache__/stackframe.cpython-39.pyc,, +win32comext/axdebug/__pycache__/util.cpython-39.pyc,, +win32comext/axdebug/adb.py,sha256=4d6QfbFZ0OCs12jxigkbB78A8ihfJeRw8VqcBTK-e5I,18119 +win32comext/axdebug/axdebug.pyd,sha256=chhj9_bu6I4Fd1-pLG6wWbrkCG8jKhIOwvcC8zk7YKA,285184 +win32comext/axdebug/codecontainer.py,sha256=gY23GYh8v5xeoJku8ZtkWW7zYMzWzf-bDeHULHIGVoc,9102 +win32comext/axdebug/contexts.py,sha256=80dDRCf5DWMrWIkoAOU-eIscbYWYZ0qxtXLdedK4ybk,2134 +win32comext/axdebug/debugger.py,sha256=Ie_HGrlm18cQunV0WW06NXzjtb3bZXPxlydJ602I1VQ,7322 +win32comext/axdebug/documents.py,sha256=iWdVmvoZzHbZ2tIq5Hn2xff0Un0kJ7cpzzFvlM_ElAU,4401 +win32comext/axdebug/dump.py,sha256=caNB9dIAN26mT-nMSgB0uawB8TF3u1vUhklZTWtZPp0,1848 +win32comext/axdebug/expressions.py,sha256=kqD2LqOGuAZhqwtFfvEGdCnPEwYm23DQrdJp1h6He7o,6660 +win32comext/axdebug/gateways.py,sha256=XB397a3kimt3-c6RuhhCDbxu8hCykgMa-w1oxX4-o9U,17368 +win32comext/axdebug/stackframe.py,sha256=3-n4aK6p2d5ugMCfX3YMtkXe0o24IsCllhb3MEInvYU,6188 +win32comext/axdebug/util.py,sha256=3KgUK8kqvkrszuzJ9FdL5MzDsPRa5jv_HPVk2EMh22Q,3880 +win32comext/axscript/Demos/client/asp/CreateObject.asp,sha256=Ab_XMgQqnGJSQPVJfC6t83_DnCbxf-i9oVEOgaL_gRM,494 +win32comext/axscript/Demos/client/asp/caps.asp,sha256=sGOLQB66zAKIYBuNzZ38BUkrgTAEcVPis9qqianVhOw,1315 +win32comext/axscript/Demos/client/asp/interrupt/test.asp,sha256=jJhHUg1VrUIFW79iITqxwq_g36QD4PCvmMNR3YWqjC4,73 +win32comext/axscript/Demos/client/asp/interrupt/test.html,sha256=JfBFiUkNMFyjI54LlmyWIjupDUtP4oyQqZyjZJlAHwc,156 +win32comext/axscript/Demos/client/asp/interrupt/test1.asp,sha256=q17ZW3dvKd0EAM2ChxFJnMEMfmkx6iD4OF_FM_0Yyfs,88 +win32comext/axscript/Demos/client/asp/interrupt/test1.html,sha256=LpebQ74Io9BaT9ECVTXLGmL9jBNUPeNJo6sjTXmnPxU,157 +win32comext/axscript/Demos/client/asp/tut1.asp,sha256=cPwYTeDSenN7vH-AkgGCQjdUMIpGOXJ0bYQC_TI-wTw,147 +win32comext/axscript/Demos/client/ie/MarqueeText1.htm,sha256=grlec9nDkqmnPBGnC-FIoxqwMZwKHGcakrXMriFE3N0,703 +win32comext/axscript/Demos/client/ie/calc.htm,sha256=oUwZ6saxEbER7tLJIf-6TGVoMzo3CeR8vnzA-Qd15Cg,4041 +win32comext/axscript/Demos/client/ie/dbgtest.htm,sha256=Cslod2hX_NdEg2_5qgJGbyldLBRA3_OwJAcpjwl1BUY,190 +win32comext/axscript/Demos/client/ie/demo.htm,sha256=v6gMz5uO9i3OMoWVOsK4YVe3uQnuEz0oLUBHx8QB20M,445 +win32comext/axscript/Demos/client/ie/demo_check.htm,sha256=3MGr54eyO4lN2o-8rLEuKSGuIs2AfZvV-fdbrFX6di4,1503 +win32comext/axscript/Demos/client/ie/demo_intro.htm,sha256=OVe1mY0N5OHuva2rAzLnbw8ivCQkugVMJU0xp39KvuI,1575 +win32comext/axscript/Demos/client/ie/demo_menu.htm,sha256=BLseA1TBxQqER5gdMXfTRKOO3sTPSIeyJDYxOlHD_ls,499 +win32comext/axscript/Demos/client/ie/docwrite.htm,sha256=OxMkqVDlqpK6kemfjIoPMu8CRFFvQV5-l0ac5CGLQpI,467 +win32comext/axscript/Demos/client/ie/foo2.htm,sha256=Z5KqLujmjhUnA_IhWWJkiil980cToEMdayeMfaZpqSg,3486 +win32comext/axscript/Demos/client/ie/form.htm,sha256=eNKi9irPf1Ig5qBJgZlVsf-GsOTXRI3JhNBN5GZGWsY,481 +win32comext/axscript/Demos/client/ie/marqueeDemo.htm,sha256=Q0HTmD73TgPrJ0Q8rcCkCxQ6vlntToHdKgK-dcHm78w,1167 +win32comext/axscript/Demos/client/ie/mousetrack.htm,sha256=FQFHkST8vtlHSlXduuSWS5eRvzyCjYnVI5mSARYPJHg,2219 +win32comext/axscript/Demos/client/ie/pycom_blowing.gif,sha256=s8ZSBzs8dfWsgTgbb0S43urQZcY1xjdxoIBuSHeLr6o,20926 +win32comext/axscript/Demos/client/wsh/blank.pys,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +win32comext/axscript/Demos/client/wsh/excel.pys,sha256=PtEytbnQb8JCVzrjLEzf6wl3S-yK1PewsfehMxc1TxQ,1049 +win32comext/axscript/Demos/client/wsh/registry.pys,sha256=NoKLD7xmsT_smd4cG4mT4kkXniaNVTKKJFf8hNUU6_k,1625 +win32comext/axscript/Demos/client/wsh/test.pys,sha256=bQo-cS0Tbay4hq7zS16Gbw7tP2jBWqVpu4gniTmpbcA,371 +win32comext/axscript/__init__.py,sha256=8LtQrxyupbKEvUY-WTginn0izGELLXZ-4XeOkqhYSbQ,135 +win32comext/axscript/__pycache__/__init__.cpython-39.pyc,, +win32comext/axscript/__pycache__/asputil.cpython-39.pyc,, +win32comext/axscript/asputil.py,sha256=Fi67pybHu1H1FUogPst34_BYEcyo72Z8wqdTjhJGjTU,246 +win32comext/axscript/axscript.pyd,sha256=E8pd4_TAPF8SNcgy0023RiLnAgFZRoJVzvJDcsWrJZo,93184 +win32comext/axscript/client/__init__.py,sha256=OGhvFgDvBsfP6lv7fbLJUtj7mgJmSytYdSjASiwDfBs,27 +win32comext/axscript/client/__pycache__/__init__.cpython-39.pyc,, +win32comext/axscript/client/__pycache__/debug.cpython-39.pyc,, +win32comext/axscript/client/__pycache__/error.cpython-39.pyc,, +win32comext/axscript/client/__pycache__/framework.cpython-39.pyc,, +win32comext/axscript/client/__pycache__/pydumper.cpython-39.pyc,, +win32comext/axscript/client/__pycache__/pyscript.cpython-39.pyc,, +win32comext/axscript/client/__pycache__/pyscript_rexec.cpython-39.pyc,, +win32comext/axscript/client/__pycache__/scriptdispatch.cpython-39.pyc,, +win32comext/axscript/client/debug.py,sha256=HZ6TyPDVlj3QmbbeXjow_Ir4nqU1m3xuMhdxfg4TceM,8600 +win32comext/axscript/client/error.py,sha256=7ZIUxRL2Aq1MovTd4NNMKNBbfX6kMkcFi2H-4GwTI8k,9551 +win32comext/axscript/client/framework.py,sha256=5VCOWp56Qs6mrqfsGygZxZo99Pn_DHpHJ-BMCNgGzSg,45609 +win32comext/axscript/client/pydumper.py,sha256=i8QoSi5jloWMf6HMzesFgZ3QdPBShFHTjmIJvdLo9QY,2209 +win32comext/axscript/client/pyscript.py,sha256=91_yEkqKjo9jGkm3vBgk2I2aYQYUXdgSqxKh9-kJ25M,15365 +win32comext/axscript/client/pyscript_rexec.py,sha256=xphJQSk6WErLlUOV3DLnCSYGxwj5murKgnu-Loun9y0,2079 +win32comext/axscript/client/scriptdispatch.py,sha256=wjed1XuySV09Pa1PV9eCqn4dLAWVx4v95JhAF68sIU4,3876 +win32comext/axscript/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +win32comext/axscript/server/__pycache__/__init__.cpython-39.pyc,, +win32comext/axscript/server/__pycache__/axsite.cpython-39.pyc,, +win32comext/axscript/server/__pycache__/error.cpython-39.pyc,, +win32comext/axscript/server/axsite.py,sha256=tB-D9QO09MQ-T3V0j7xxARF66RaKs7-_GE9Owef7WCE,4143 +win32comext/axscript/server/error.py,sha256=I0EGhllbX4c16ySa1MJo1b5cpYsFXe4hZAAzVO9ar78,489 +win32comext/axscript/test/__pycache__/leakTest.cpython-39.pyc,, +win32comext/axscript/test/__pycache__/testHost.cpython-39.pyc,, +win32comext/axscript/test/__pycache__/testHost4Dbg.cpython-39.pyc,, +win32comext/axscript/test/debugTest.pys,sha256=kwYIB_79cQeue5_4PnNp80vgzX5teuMxeuOAvPtcbe4,202 +win32comext/axscript/test/debugTest.vbs,sha256=O3a6y4VzTUdZ2BufrDibMeyc7lfquKNfNPTwPhe8t2s,84 +win32comext/axscript/test/leakTest.py,sha256=VCrFzTBNS9oZk_L7uyAoZvP2gwY83wnM-vaKUjC8JDM,4860 +win32comext/axscript/test/testHost.py,sha256=zonjUoDFExt0V2vgvNPp53oMf8uNUQxd1QZeYDiEdaA,8325 +win32comext/axscript/test/testHost4Dbg.py,sha256=NVnsn4JGfV7Olfl6J43av96eaQn8S1ZP0Onic_8DfBc,2821 +win32comext/bits/__init__.py,sha256=fRpv5U3JDCOw9goPCz-dXK6awa_sudZXj3W1Ac3llQg,192 +win32comext/bits/__pycache__/__init__.cpython-39.pyc,, +win32comext/bits/bits.pyd,sha256=Dd2K-qKBcAOMyZWaT9RHGdUxvhp6yrMK6pvMyJnPf-0,62976 +win32comext/bits/test/__pycache__/show_all_jobs.cpython-39.pyc,, +win32comext/bits/test/__pycache__/test_bits.cpython-39.pyc,, +win32comext/bits/test/show_all_jobs.py,sha256=aesP0uvvaApFOm2KC652LQNM2NE9Ac_52fScIQ-s1fs,1583 +win32comext/bits/test/test_bits.py,sha256=Y1-E41bk5RrO9B5QvT1psiU5sqOb4EvS_JkGTUQ6R8M,3911 +win32comext/directsound/__init__.py,sha256=8LtQrxyupbKEvUY-WTginn0izGELLXZ-4XeOkqhYSbQ,135 +win32comext/directsound/__pycache__/__init__.cpython-39.pyc,, +win32comext/directsound/directsound.pyd,sha256=gPKSxSdmmNw5AjCJIDrExPxs-gsYCZanPrH1BAB7Jis,76288 +win32comext/directsound/test/__init__.py,sha256=zXbiaII25PKM2hnu9yT8i7I7_p6gQfPMbt-euxHVn_I,65 +win32comext/directsound/test/__pycache__/__init__.cpython-39.pyc,, +win32comext/directsound/test/__pycache__/ds_record.cpython-39.pyc,, +win32comext/directsound/test/__pycache__/ds_test.cpython-39.pyc,, +win32comext/directsound/test/ds_record.py,sha256=G2ITlmmmKUO-UGn5S1DEzW9ZI7ujhg_ALC4XMcmjLNw,1403 +win32comext/directsound/test/ds_test.py,sha256=1KGkzc7ir7pI_6Ft0Qayj5Bda_65TzrjdNAjXi-5Gdc,12961 +win32comext/ifilter/__init__.py,sha256=PyA_K1FxiknS69_9xz7fAitw2hj27TXsGE27GzxF2VE,40 +win32comext/ifilter/__pycache__/__init__.cpython-39.pyc,, +win32comext/ifilter/__pycache__/ifiltercon.cpython-39.pyc,, +win32comext/ifilter/demo/__pycache__/filterDemo.cpython-39.pyc,, +win32comext/ifilter/demo/filterDemo.py,sha256=NXRZQCpQEDaS6ZuvZ15G77ynZGM_WLeJAV4SgKWvFrM,11463 +win32comext/ifilter/ifilter.pyd,sha256=n5oY5nF7fl4jvX-tvFNe4jP-RvgWBplQTCWznmvKS5k,30720 +win32comext/ifilter/ifiltercon.py,sha256=BDI-s30tIWjZfzUPao1zQuM1Obgpa2hsjNz-kmgD0Hg,3159 +win32comext/internet/__init__.py,sha256=8LtQrxyupbKEvUY-WTginn0izGELLXZ-4XeOkqhYSbQ,135 +win32comext/internet/__pycache__/__init__.cpython-39.pyc,, +win32comext/internet/__pycache__/inetcon.cpython-39.pyc,, +win32comext/internet/inetcon.py,sha256=7GEJI8myLlVMiYqxeKs2UwIS5oVS5LMJ5C1x9MGVA7U,11618 +win32comext/internet/internet.pyd,sha256=uSMy_Watt3P5R9kAd_RQkO6Qv6Q8k6wrXvxktEy5UoE,93696 +win32comext/mapi/__init__.py,sha256=LbbJo-_Ifyp3Tx1j0J72Sdyg92T1MXx2sUVZXoYIaZo,598 +win32comext/mapi/__pycache__/__init__.cpython-39.pyc,, +win32comext/mapi/__pycache__/emsabtags.cpython-39.pyc,, +win32comext/mapi/__pycache__/mapitags.cpython-39.pyc,, +win32comext/mapi/__pycache__/mapiutil.cpython-39.pyc,, +win32comext/mapi/demos/__pycache__/mapisend.cpython-39.pyc,, +win32comext/mapi/demos/mapisend.py,sha256=HNGotRR75nMmL2PnhMI_0mEYh9nu7Dq0mvJgkxSJs8I,3558 +win32comext/mapi/emsabtags.py,sha256=nNTQhHpnc4etQ6nifEWv_o3OKwPz21WFsZHj0OJEb70,49320 +win32comext/mapi/exchange.pyd,sha256=jgJbpvKFZwvdIJdiNDcxWejnLTYwRa_oMKAqP1r0dj4,88064 +win32comext/mapi/mapi.pyd,sha256=gUWhBCE-7sDc558KKYtWRppiX13nJ_yOzHdZKbipMe0,196608 +win32comext/mapi/mapitags.py,sha256=SqvStG7d6BETQzO_Y3CI5hEMayhJ__HAMB2jZd2s9bs,51436 +win32comext/mapi/mapiutil.py,sha256=NX1k59I0eWCkHMGrxiWnVZtTeueO3610ucdnz2a4iSg,7276 +win32comext/propsys/__init__.py,sha256=zAJTnC6qYGfhRKfJOR8-Wyrp7NspOnaeoY2FHnG4pDY,27 +win32comext/propsys/__pycache__/__init__.cpython-39.pyc,, +win32comext/propsys/__pycache__/pscon.cpython-39.pyc,, +win32comext/propsys/propsys.pyd,sha256=AG82QoDPjxJ6NRW5hnTav56toN8f0wUH2nAdSvhhwhU,138752 +win32comext/propsys/pscon.py,sha256=Is84vJu7t0AtXJp2nHXtvNkxgVA-dFBq40A2DvUP0Ak,48622 +win32comext/propsys/test/__pycache__/testpropsys.cpython-39.pyc,, +win32comext/propsys/test/testpropsys.py,sha256=5DHqHI_SVCXJIiMLzFWR8nRRn3fT4pEzhk7IE5JW_Vs,206 +win32comext/shell/__init__.py,sha256=8LtQrxyupbKEvUY-WTginn0izGELLXZ-4XeOkqhYSbQ,135 +win32comext/shell/__pycache__/__init__.cpython-39.pyc,, +win32comext/shell/__pycache__/shellcon.cpython-39.pyc,, +win32comext/shell/demos/IActiveDesktop.py,sha256=jZxKKdv86D6_0x2qwj00b9GScVeNArF7lSD-JuIrxHE,2122 +win32comext/shell/demos/IFileOperationProgressSink.py,sha256=NFp9RiNzjDPvD7T7FToWuk-0uMfDPkqCgBW8jNJEX7Q,5153 +win32comext/shell/demos/IShellLinkDataList.py,sha256=EEhQEqNOo730JFTwvlV7A6DJV_06SzhV3HT8lnPHxdg,1917 +win32comext/shell/demos/ITransferAdviseSink.py,sha256=vfh1Dzm4J8rTE50Ren-zMZNtPYK7TVaZGKcq4IGxevs,2870 +win32comext/shell/demos/IUniformResourceLocator.py,sha256=csaxp5_hMeSUeil4Z5UrADc8gSKJfEma6MnMMpKdMUw,1652 +win32comext/shell/demos/__pycache__/IActiveDesktop.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/IFileOperationProgressSink.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/IShellLinkDataList.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/ITransferAdviseSink.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/IUniformResourceLocator.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/browse_for_folder.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/create_link.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/dump_link.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/explorer_browser.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/shellexecuteex.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/viewstate.cpython-39.pyc,, +win32comext/shell/demos/__pycache__/walk_shell_folders.cpython-39.pyc,, +win32comext/shell/demos/browse_for_folder.py,sha256=ReGm8i78JdSmTt9PCZXs9wLuR9OdgfJn3a8tuDvIhqo,1502 +win32comext/shell/demos/create_link.py,sha256=ATyqT1nZL_ABtqfa2_E8AltJ4ngA4_B8gVBVUPFixxs,2336 +win32comext/shell/demos/dump_link.py,sha256=YK-UuNboEqOKr7tiDNW8WccAUSjn5rWl5OsmUqtTLrg,1688 +win32comext/shell/demos/explorer_browser.py,sha256=Z9K4ERAfcDSrA1WLdQLqUNDWavYO5pkkvT-0aHMQfzE,4956 +win32comext/shell/demos/servers/__pycache__/column_provider.cpython-39.pyc,, +win32comext/shell/demos/servers/__pycache__/context_menu.cpython-39.pyc,, +win32comext/shell/demos/servers/__pycache__/copy_hook.cpython-39.pyc,, +win32comext/shell/demos/servers/__pycache__/empty_volume_cache.cpython-39.pyc,, +win32comext/shell/demos/servers/__pycache__/folder_view.cpython-39.pyc,, +win32comext/shell/demos/servers/__pycache__/icon_handler.cpython-39.pyc,, +win32comext/shell/demos/servers/__pycache__/shell_view.cpython-39.pyc,, +win32comext/shell/demos/servers/column_provider.py,sha256=e82nvMK41QPiYNrRmeggLKFD4hTCL3CzGu4afso-jGY,3743 +win32comext/shell/demos/servers/context_menu.py,sha256=latktvf-Vrb-vBOQ4ENt8jc_4wJyfRZ9KBBl2Aaj0Bw,4413 +win32comext/shell/demos/servers/copy_hook.py,sha256=mlFwxC7imy_7051Sni4c-iLnpdz0ojirRUVC-QXm8r4,2691 +win32comext/shell/demos/servers/empty_volume_cache.py,sha256=R7qlxyJ4rhYVMtP50O97QfGHjnBbo2b6drh1HAyvRAE,7623 +win32comext/shell/demos/servers/folder_view.py,sha256=dQWssTPIgV4mVAJMoGA0Jp6uiTK43E-Vhlh2O-mmpxU,29247 +win32comext/shell/demos/servers/icon_handler.py,sha256=jVgd2JD3sypQfHH3NinBq_GdlqQb8RJDVLzDL5WBWbM,2550 +win32comext/shell/demos/servers/shell_view.py,sha256=qdpabMqarD0DFSo9W2MwGUkhaBlgt1As-W6EsaMjvJc,37215 +win32comext/shell/demos/shellexecuteex.py,sha256=WhrImtleFhx-Tfw6mjpcb4ueAEeJmLn7JYPAGt8mJ2M,470 +win32comext/shell/demos/viewstate.py,sha256=FABpUdhcqQsnfB_7djvj-nNmQf2YZKbmGZAKRxrBMM4,2318 +win32comext/shell/demos/walk_shell_folders.py,sha256=YXUDeEwL8AikBRVxe-_YgjpsPWhtAC7dMWc1Lt3fnTs,669 +win32comext/shell/shell.pyd,sha256=5Rw-EmCgkxCDCd0em_yeDyEtGbs4a5MkZx1hXDL7L4Q,528896 +win32comext/shell/shellcon.py,sha256=IeUpS8-DDwC0-rNeO7CsZQQJeaF-wN3X5xgw-mukoVE,49361 +win32comext/shell/test/__pycache__/testSHFileOperation.cpython-39.pyc,, +win32comext/shell/test/__pycache__/testShellFolder.cpython-39.pyc,, +win32comext/shell/test/__pycache__/testShellItem.cpython-39.pyc,, +win32comext/shell/test/testSHFileOperation.py,sha256=520lewK3R8bDbshexLe_CGiVuk_5DDZnFuLARiKRCCs,2092 +win32comext/shell/test/testShellFolder.py,sha256=2VFtNHHn65-9O13JIfuXEaou0WyOwbsL_Jc9AkyKJkk,582 +win32comext/shell/test/testShellItem.py,sha256=87kxXSp1k_MY6A2y0mqeo0vXQPHdCwsr5jb4fdzx56Q,2891 +win32comext/taskscheduler/__init__.py,sha256=fRpv5U3JDCOw9goPCz-dXK6awa_sudZXj3W1Ac3llQg,192 +win32comext/taskscheduler/__pycache__/__init__.cpython-39.pyc,, +win32comext/taskscheduler/taskscheduler.pyd,sha256=1af9CujWfNYO7dWmq39wTXyyprPLW6_NVKIYRWJYl00,53248 +win32comext/taskscheduler/test/__pycache__/test_addtask.cpython-39.pyc,, +win32comext/taskscheduler/test/__pycache__/test_addtask_1.cpython-39.pyc,, +win32comext/taskscheduler/test/__pycache__/test_addtask_2.cpython-39.pyc,, +win32comext/taskscheduler/test/__pycache__/test_localsystem.cpython-39.pyc,, +win32comext/taskscheduler/test/test_addtask.py,sha256=GSj-GLATG8iTDi11GVLLRG-OIKjdP8URi_SEh4RFLys,2212 +win32comext/taskscheduler/test/test_addtask_1.py,sha256=VlVbOGkqd-WPsYJKIltF5P68aOAY3oyvnXfv-EQTp0Y,2154 +win32comext/taskscheduler/test/test_addtask_2.py,sha256=_qKmCp77jjcXgP6sFAwAVtnF1v4K1V2ezWE7WWpSDDM,1682 +win32comext/taskscheduler/test/test_localsystem.py,sha256=yMbboNLs5K51CaA6kV1DMVAhVqIchUkprOI0K5l6yl8,72 diff --git a/MLPY/Lib/site-packages/pywin32-306.dist-info/WHEEL b/MLPY/Lib/site-packages/pywin32-306.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..d5a98374e27e610e1b9b96bd43954d22ff48a4c2 --- /dev/null +++ b/MLPY/Lib/site-packages/pywin32-306.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: false +Tag: cp39-cp39-win_amd64 + diff --git a/MLPY/Lib/site-packages/pywin32-306.dist-info/top_level.txt b/MLPY/Lib/site-packages/pywin32-306.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..e2bb184ce5a7248e1431bd56379fcb79d9658f5a --- /dev/null +++ b/MLPY/Lib/site-packages/pywin32-306.dist-info/top_level.txt @@ -0,0 +1,94 @@ +PyISAPI_loader +_win32sysloader +_winxptheme +adodbapi +adsi +authorization +axcontrol +axdebug +axscript +bits +dde +directsound +exchange +exchdapi +ifilter +internet +isapi +mapi +mmapfile +odbc +perfmon +perfmondata +propsys +pythoncom +pythonwin +pywintypes +servicemanager +shell +taskscheduler +timer +win32\lib\afxres +win32\lib\commctrl +win32\lib\dbi +win32\lib\mmsystem +win32\lib\netbios +win32\lib\ntsecuritycon +win32\lib\pywin32_bootstrap +win32\lib\pywin32_testutil +win32\lib\pywintypes +win32\lib\rasutil +win32\lib\regcheck +win32\lib\regutil +win32\lib\sspi +win32\lib\sspicon +win32\lib\win2kras +win32\lib\win32con +win32\lib\win32cryptcon +win32\lib\win32evtlogutil +win32\lib\win32gui_struct +win32\lib\win32inetcon +win32\lib\win32netcon +win32\lib\win32pdhquery +win32\lib\win32pdhutil +win32\lib\win32rcparser +win32\lib\win32serviceutil +win32\lib\win32timezone +win32\lib\win32traceutil +win32\lib\win32verstamp +win32\lib\winerror +win32\lib\winioctlcon +win32\lib\winnt +win32\lib\winperf +win32\lib\winxptheme +win32api +win32clipboard +win32com +win32comext +win32console +win32cred +win32crypt +win32event +win32evtlog +win32file +win32gui +win32help +win32inet +win32job +win32lz +win32net +win32pdh +win32pipe +win32print +win32process +win32profile +win32ras +win32security +win32service +win32trace +win32transaction +win32ts +win32ui +win32uiole +win32wnet +winxpgui diff --git a/MLPY/Lib/site-packages/pywin32_system32/pythoncom39.dll b/MLPY/Lib/site-packages/pywin32_system32/pythoncom39.dll new file mode 100644 index 0000000000000000000000000000000000000000..c5c55f1fae0539f6ddd82ea2da1b4253bfee8c2c Binary files /dev/null and b/MLPY/Lib/site-packages/pywin32_system32/pythoncom39.dll differ diff --git a/MLPY/Lib/site-packages/pywin32_system32/pywintypes39.dll b/MLPY/Lib/site-packages/pywin32_system32/pywintypes39.dll new file mode 100644 index 0000000000000000000000000000000000000000..9ea427921f941d62ad2b335ecbb55bf7573d4274 Binary files /dev/null and b/MLPY/Lib/site-packages/pywin32_system32/pywintypes39.dll differ diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/INSTALLER b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/LICENSE b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..353924be0e59b9ad7e6c22848c2189398481821d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright Jason R. Coombs + +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. diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/METADATA b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..fe760b18d9d02c9d223026265832a387a284ee0b --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/METADATA @@ -0,0 +1,119 @@ +Metadata-Version: 2.1 +Name: setuptools +Version: 58.1.0 +Summary: Easily download, build, install, upgrade, and uninstall Python packages +Home-page: https://github.com/pypa/setuptools +Author: Python Packaging Authority +Author-email: distutils-sig@python.org +License: UNKNOWN +Project-URL: Documentation, https://setuptools.readthedocs.io/ +Keywords: CPAN PyPI distutils eggs package management +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities +Requires-Python: >=3.6 +License-File: LICENSE +Provides-Extra: certs +Provides-Extra: docs +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: jaraco.packaging (>=8.2) ; extra == 'docs' +Requires-Dist: rst.linker (>=1.9) ; extra == 'docs' +Requires-Dist: jaraco.tidelift (>=1.4) ; extra == 'docs' +Requires-Dist: pygments-github-lexers (==0.0.5) ; extra == 'docs' +Requires-Dist: sphinx-inline-tabs ; extra == 'docs' +Requires-Dist: sphinxcontrib-towncrier ; extra == 'docs' +Requires-Dist: furo ; extra == 'docs' +Provides-Extra: ssl +Provides-Extra: testing +Requires-Dist: pytest (>=4.6) ; extra == 'testing' +Requires-Dist: pytest-checkdocs (>=2.4) ; extra == 'testing' +Requires-Dist: pytest-flake8 ; extra == 'testing' +Requires-Dist: pytest-cov ; extra == 'testing' +Requires-Dist: pytest-enabler (>=1.0.1) ; extra == 'testing' +Requires-Dist: mock ; extra == 'testing' +Requires-Dist: flake8-2020 ; extra == 'testing' +Requires-Dist: virtualenv (>=13.0.0) ; extra == 'testing' +Requires-Dist: pytest-virtualenv (>=1.2.7) ; extra == 'testing' +Requires-Dist: wheel ; extra == 'testing' +Requires-Dist: paver ; extra == 'testing' +Requires-Dist: pip (>=19.1) ; extra == 'testing' +Requires-Dist: jaraco.envs ; extra == 'testing' +Requires-Dist: pytest-xdist ; extra == 'testing' +Requires-Dist: sphinx ; extra == 'testing' +Requires-Dist: jaraco.path (>=3.2.0) ; extra == 'testing' +Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-mypy ; (platform_python_implementation != "PyPy") and extra == 'testing' + +.. image:: https://img.shields.io/pypi/v/setuptools.svg + :target: `PyPI link`_ + +.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg + :target: `PyPI link`_ + +.. _PyPI link: https://pypi.org/project/setuptools + +.. image:: https://github.com/pypa/setuptools/workflows/tests/badge.svg + :target: https://github.com/pypa/setuptools/actions?query=workflow%3A%22tests%22 + :alt: tests + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: Black + +.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg + :target: https://setuptools.readthedocs.io + +.. image:: https://img.shields.io/badge/skeleton-2021-informational + :target: https://blog.jaraco.com/skeleton + +.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white + :target: https://codecov.io/gh/pypa/setuptools + +.. image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat + :target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme + +See the `Installation Instructions +`_ in the Python Packaging +User's Guide for instructions on installing, upgrading, and uninstalling +Setuptools. + +Questions and comments should be directed to the `distutils-sig +mailing list `_. +Bug reports and especially tested patches may be +submitted directly to the `bug tracker +`_. + + +Code of Conduct +=============== + +Everyone interacting in the setuptools project's codebases, issue trackers, +chat rooms, and mailing lists is expected to follow the +`PSF Code of Conduct `_. + + +For Enterprise +============== + +Available as part of the Tidelift Subscription. + +Setuptools and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. + +`Learn more `_. + + +Security Contact +================ + +To report a security vulnerability, please use the +`Tidelift security contact `_. +Tidelift will coordinate the fix and disclosure. + + diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/RECORD b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..254299940088671e8cb9b3682610d60af071ddae --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/RECORD @@ -0,0 +1,296 @@ +_distutils_hack/__init__.py,sha256=X3RUiA6KBPoEmco_CjACyltyQbFRGVUpZRAbSkPGwMs,3688 +_distutils_hack/__pycache__/__init__.cpython-39.pyc,, +_distutils_hack/__pycache__/override.cpython-39.pyc,, +_distutils_hack/override.py,sha256=Eu_s-NF6VIZ4Cqd0tbbA5wtWky2IZPNd8et6GLt1mzo,44 +distutils-precedence.pth,sha256=fqf_7z_ioRfuEsaO1lU2F_DX_S8FkCV8JcSElZo7c3M,152 +pkg_resources/__init__.py,sha256=P3PNN3_m8JJrYMp-i-Sq-3rhK5vuViqqjn1UXKHfe7Q,108202 +pkg_resources/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pkg_resources/_vendor/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/__pycache__/appdirs.cpython-39.pyc,, +pkg_resources/_vendor/__pycache__/pyparsing.cpython-39.pyc,, +pkg_resources/_vendor/appdirs.py,sha256=MievUEuv3l_mQISH5SF0shDk_BNhHHzYiAPrT3ITN4I,24701 +pkg_resources/_vendor/packaging/__about__.py,sha256=PNMsaZn4UcCHyubgROH1bl6CluduPjI5kFrSp_Zgklo,736 +pkg_resources/_vendor/packaging/__init__.py,sha256=6enbp5XgRfjBjsI9-bn00HjHf5TH21PDMOKkJW8xw-w,562 +pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_typing.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/markers.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/tags.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/utils.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/version.cpython-39.pyc,, +pkg_resources/_vendor/packaging/_compat.py,sha256=MXdsGpSE_W-ZrHoC87andI4LV2FAwU7HLL-eHe_CjhU,1128 +pkg_resources/_vendor/packaging/_structures.py,sha256=ozkCX8Q8f2qE1Eic3YiQ4buDVfgz2iYevY9e7R2y3iY,2022 +pkg_resources/_vendor/packaging/_typing.py,sha256=x59EhQ57TMT-kTRyLZV25HZvYGGwbucTo6iKh_O0tMw,1812 +pkg_resources/_vendor/packaging/markers.py,sha256=YSntQkMnKyw1_FG6oRNNnGxLL6bAxcGXOtuFE-YTS3k,9518 +pkg_resources/_vendor/packaging/requirements.py,sha256=R8K4H4xX_iD4LvpGw1U3ouuPbGN-wzsFgD7brhAM71Y,4929 +pkg_resources/_vendor/packaging/specifiers.py,sha256=uYp9l13F0LcknS6d4N60ytiBgFmIhKideOq9AnsxTco,31944 +pkg_resources/_vendor/packaging/tags.py,sha256=NKMS37Zo_nWrZxgsD6zbXsXgc9edn9m160cBiLmHJdE,24067 +pkg_resources/_vendor/packaging/utils.py,sha256=RShlvnjO2CtYSD8uri32frMMFMTmB-3ihsq1-ghzLEw,1811 +pkg_resources/_vendor/packaging/version.py,sha256=Cnbm-OO9D_qd8ZTFxzFcjSavexSYFZmyeaoPvMsjgPc,15470 +pkg_resources/_vendor/pyparsing.py,sha256=mahtkgcp3grNAD0re_9R0DLvBnvjzpeLwgJqT-3H1CE,232056 +pkg_resources/extern/__init__.py,sha256=3PixaT9Tzzd4NoyV6CVhGd7S_9Z-U5yvMWAftZKvC6k,2362 +pkg_resources/extern/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/tests/data/my-test-package-source/__pycache__/setup.cpython-39.pyc,, +pkg_resources/tests/data/my-test-package-source/setup.py,sha256=Mrezl3nqxkYkjCYpIxmjhhg4AR8hgi4QZdEYmk-I7R8,104 +setuptools-58.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +setuptools-58.1.0.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050 +setuptools-58.1.0.dist-info/METADATA,sha256=jjOLGyArpWjlz4JTmU_TEhFruOOTABRjZYqBzJXus5A,4852 +setuptools-58.1.0.dist-info/RECORD,, +setuptools-58.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +setuptools-58.1.0.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92 +setuptools-58.1.0.dist-info/entry_points.txt,sha256=wpnhLrbtyk4hZ1qCCw48cCSxoQPzULMhIuaFqsB7GxQ,2636 +setuptools-58.1.0.dist-info/top_level.txt,sha256=d9yL39v_W7qmKDDSH6sT4bE0j_Ls1M3P161OGgdsm4g,41 +setuptools/__init__.py,sha256=l7ULo8jGk-4-8jbacmJ58cYpSRX4swS1ccbJaJVAGdM,7448 +setuptools/__pycache__/__init__.cpython-39.pyc,, +setuptools/__pycache__/_deprecation_warning.cpython-39.pyc,, +setuptools/__pycache__/_imp.cpython-39.pyc,, +setuptools/__pycache__/archive_util.cpython-39.pyc,, +setuptools/__pycache__/build_meta.cpython-39.pyc,, +setuptools/__pycache__/config.cpython-39.pyc,, +setuptools/__pycache__/dep_util.cpython-39.pyc,, +setuptools/__pycache__/depends.cpython-39.pyc,, +setuptools/__pycache__/dist.cpython-39.pyc,, +setuptools/__pycache__/errors.cpython-39.pyc,, +setuptools/__pycache__/extension.cpython-39.pyc,, +setuptools/__pycache__/glob.cpython-39.pyc,, +setuptools/__pycache__/installer.cpython-39.pyc,, +setuptools/__pycache__/launch.cpython-39.pyc,, +setuptools/__pycache__/monkey.cpython-39.pyc,, +setuptools/__pycache__/msvc.cpython-39.pyc,, +setuptools/__pycache__/namespaces.cpython-39.pyc,, +setuptools/__pycache__/package_index.cpython-39.pyc,, +setuptools/__pycache__/py34compat.cpython-39.pyc,, +setuptools/__pycache__/sandbox.cpython-39.pyc,, +setuptools/__pycache__/unicode_utils.cpython-39.pyc,, +setuptools/__pycache__/version.cpython-39.pyc,, +setuptools/__pycache__/wheel.cpython-39.pyc,, +setuptools/__pycache__/windows_support.cpython-39.pyc,, +setuptools/_deprecation_warning.py,sha256=jU9-dtfv6cKmtQJOXN8nP1mm7gONw5kKEtiPtbwnZyI,218 +setuptools/_distutils/__init__.py,sha256=lpQAphR_7uhWC2fbSEps4Ja9W4YwezN_IX_LJEt3khU,250 +setuptools/_distutils/__pycache__/__init__.cpython-39.pyc,, +setuptools/_distutils/__pycache__/_msvccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/archive_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/bcppcompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/ccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/cmd.cpython-39.pyc,, +setuptools/_distutils/__pycache__/config.cpython-39.pyc,, +setuptools/_distutils/__pycache__/core.cpython-39.pyc,, +setuptools/_distutils/__pycache__/cygwinccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/debug.cpython-39.pyc,, +setuptools/_distutils/__pycache__/dep_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/dir_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/dist.cpython-39.pyc,, +setuptools/_distutils/__pycache__/errors.cpython-39.pyc,, +setuptools/_distutils/__pycache__/extension.cpython-39.pyc,, +setuptools/_distutils/__pycache__/fancy_getopt.cpython-39.pyc,, +setuptools/_distutils/__pycache__/file_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/filelist.cpython-39.pyc,, +setuptools/_distutils/__pycache__/log.cpython-39.pyc,, +setuptools/_distutils/__pycache__/msvc9compiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/msvccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/py35compat.cpython-39.pyc,, +setuptools/_distutils/__pycache__/py38compat.cpython-39.pyc,, +setuptools/_distutils/__pycache__/spawn.cpython-39.pyc,, +setuptools/_distutils/__pycache__/sysconfig.cpython-39.pyc,, +setuptools/_distutils/__pycache__/text_file.cpython-39.pyc,, +setuptools/_distutils/__pycache__/unixccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/version.cpython-39.pyc,, +setuptools/_distutils/__pycache__/versionpredicate.cpython-39.pyc,, +setuptools/_distutils/_msvccompiler.py,sha256=jR0JM5A1JMnZ6xMDicQzhXWgXTVXs1lWAeUexC1z198,20813 +setuptools/_distutils/archive_util.py,sha256=qW-uiGwYexTvK5e-iSel_31Dshx-CqTanNPK6snwf98,8572 +setuptools/_distutils/bcppcompiler.py,sha256=OJDVpCUmX6H8v_7lV1zifV1fcx92Cr2dhiUh6989UJI,14894 +setuptools/_distutils/ccompiler.py,sha256=G2tn9Q3zQ0VUNfW1LM-nrnLt_6OhtiUunugCv85D1PQ,47607 +setuptools/_distutils/cmd.py,sha256=eco6LAGUtobLuPafuhmgKgkwRRL_WY8KJ4YeDCHpcls,18079 +setuptools/_distutils/command/__init__.py,sha256=2TA-rlNDlzeI-csbWHXFjGD8uOYqALMfyWOhT49nC6g,799 +setuptools/_distutils/command/__pycache__/__init__.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist_msi.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist_wininst.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_clib.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_ext.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_py.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_scripts.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/check.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/clean.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/config.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_data.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_egg_info.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_headers.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_lib.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_scripts.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/py37compat.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/register.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/sdist.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/upload.cpython-39.pyc,, +setuptools/_distutils/command/bdist.py,sha256=2z4eudRl_n7m3lG9leL0IYqes4bsm8c0fxfZuiafjMg,5562 +setuptools/_distutils/command/bdist_dumb.py,sha256=BTur9jcIppyP7Piavjfsk7YjElqvxeYO2npUyPPOekc,4913 +setuptools/_distutils/command/bdist_msi.py,sha256=EVFQYN_X-ExeeP8gmdV9JcINsuUGsLJUz9afMU0Rt8c,35579 +setuptools/_distutils/command/bdist_rpm.py,sha256=gjOw22GhDSbcq0bdq25cTb-n6HWWm0bShLQad_mkJ4k,21537 +setuptools/_distutils/command/bdist_wininst.py,sha256=iGlaI-VfElHOneeczKHWnSN5a10-7IMcJaXuR1mdS3c,16030 +setuptools/_distutils/command/build.py,sha256=1AF-dxN_NlOEyoydBz19AwpeWYPSYCZvOLJSN_PdatY,5773 +setuptools/_distutils/command/build_clib.py,sha256=bgVTHh28eLQA2Gkw68amApd_j7qQBX4MTI-zTvAK_J4,8022 +setuptools/_distutils/command/build_ext.py,sha256=hX4ksYXRC-Q3fEvLrANIG97mq3twO6ZwkMhfANNK3Yg,31683 +setuptools/_distutils/command/build_py.py,sha256=hXesMrH_epNj6K8SUtJdipgEis3EdICKeZ8VWe_ndck,16495 +setuptools/_distutils/command/build_scripts.py,sha256=urdn6wPxPMW5dLqpqFkZ8dqaFG1tf9TiAao6U9LCoEI,5963 +setuptools/_distutils/command/check.py,sha256=5qDtI75ccZg3sAItQWeaIu8y3FR314O4rr9Smz4HsEo,5637 +setuptools/_distutils/command/clean.py,sha256=2TCt47ru4hZZM0RfVfUYj5bbpicpGLP4Qhw5jBtvp9k,2776 +setuptools/_distutils/command/config.py,sha256=2aTjww3PwjMB8-ZibCe4P7B-qG1hM1gn_rJXYyxRz6c,13117 +setuptools/_distutils/command/install.py,sha256=oaYyzj2vAGb_HKqdFts7rY0gx80W9MrqPQCZpfvGj2k,27534 +setuptools/_distutils/command/install_data.py,sha256=YhGOAwh3gJPqF7em5XA0rmpR42z1bLh80ooElzDyUvk,2822 +setuptools/_distutils/command/install_egg_info.py,sha256=0kW0liVMeadkjX0ZcRfMptKFen07Gw6gyw1VHT5KIwc,2603 +setuptools/_distutils/command/install_headers.py,sha256=XQ6idkbIDfr1ljXCOznuVUMvOFpHBn6cK0Wz9gIM2b4,1298 +setuptools/_distutils/command/install_lib.py,sha256=9AofR-MO9lAtjwwuukCptepOaJEKMZW2VHiyR5hU7HA,8397 +setuptools/_distutils/command/install_scripts.py,sha256=_CLUeQwGJRcY2kik7azPMn5IdtDCrjWdUvZ1khlG6ck,2017 +setuptools/_distutils/command/py37compat.py,sha256=qzRhhvTihqx_PZZt2ZYECxh1X3Oj255VqatzelYFAKw,671 +setuptools/_distutils/command/register.py,sha256=2jaq9968rt2puRVDBx1HbNiXv27uOk8idE_4lPf_3VM,11712 +setuptools/_distutils/command/sdist.py,sha256=qotJjAOzyhJjq2-oDImjNFrOtaSneEFDJTB-sEk1wnU,19005 +setuptools/_distutils/command/upload.py,sha256=BLO1w7eSAqsCjCLXtf_CRVSjwF1WmyOByGVGNdcQ8oY,7597 +setuptools/_distutils/config.py,sha256=dtHgblx9JhfyrKx1-J7Jlxw_f7s8ZbPFQii2UWMTZpY,4827 +setuptools/_distutils/core.py,sha256=jbdOkpOK09xi-56vhhwvn3fYdhLb5DJO8q3K1fnQz0Q,8876 +setuptools/_distutils/cygwinccompiler.py,sha256=QpmRAopZOYEKww_iCWTu3KLjs9gggyl90E0fagAxqCM,16938 +setuptools/_distutils/debug.py,sha256=N6MrTAqK6l9SVk6tWweR108PM8Ol7qNlfyV-nHcLhsY,139 +setuptools/_distutils/dep_util.py,sha256=GuR9Iw_jzZRkyemJ5HX8rB_wRGxkIBcBm1qh54r7zhk,3491 +setuptools/_distutils/dir_util.py,sha256=UwhBOUTcV65GTwce4SPuTXR8Z8q3LYEcmttqcGb0bYo,7778 +setuptools/_distutils/dist.py,sha256=Biuf6ca8uiFfMScRFsYUKtb5neMPtxKxRtXn50_1f3U,50421 +setuptools/_distutils/errors.py,sha256=Yr6tKZGdzBoNi53vBtiq0UJ__X05CmxSdQJqOWaw6SY,3577 +setuptools/_distutils/extension.py,sha256=bTb3Q0CoevGKYv5dX1ls--Ln8tlB0-UEOsi9BwzlZ-s,10515 +setuptools/_distutils/fancy_getopt.py,sha256=OPxp2CxHi1Yp_d1D8JxW4Ueq9fC71tegQFaafh58GGU,17784 +setuptools/_distutils/file_util.py,sha256=0hUqfItN_x2DVihR0MHdA4KCMVCOO8VoByaFp_a6MDg,8148 +setuptools/_distutils/filelist.py,sha256=Z9f5hvepZnpniZ2IFmCnWIjdviWozs8sbARBhWajwoM,13407 +setuptools/_distutils/log.py,sha256=hWBmdUC2K927QcVv3REMW3HMPclxccPQngxLSuUXQl0,1969 +setuptools/_distutils/msvc9compiler.py,sha256=X623B92g0v8A3BEM9qpRf396AEd_hfjkfDUVTKu0hcE,30453 +setuptools/_distutils/msvccompiler.py,sha256=qruALeGRq8-CjtjE2tLQ8W26QnchcYedWzFme8AxZ4Q,23540 +setuptools/_distutils/py35compat.py,sha256=-sk1vBIsOgH-AobjIYbK_OEjdJF_54Ul_D1EiE9XM_c,455 +setuptools/_distutils/py38compat.py,sha256=II7ddBxOijC7uNN4z_46HYUjwYTJYMNiLJoGTormZm0,212 +setuptools/_distutils/spawn.py,sha256=4uE9k3VZWijxy7E_Rlcmh1MoamaPJ8rajdNBagKxjgU,3498 +setuptools/_distutils/sysconfig.py,sha256=mrtbAa9QXYXrNEe2HGKFyes2oJTNqImcgJGWiXnxOtQ,21630 +setuptools/_distutils/text_file.py,sha256=PsuAJeWdKJoLSV_6N6IpB5-0Pa84KzLUucJMFRazw3I,12483 +setuptools/_distutils/unixccompiler.py,sha256=VmkjwPXyVI8_nbHLqrGgS7xgf12JNeWXkWHcx1iRIj0,14980 +setuptools/_distutils/util.py,sha256=6UsgxxG3pzfimk2JHa5LBIHHddmBT-YdxoocXLlL6g4,20373 +setuptools/_distutils/version.py,sha256=8NogP6NPPQpp3EUMZcT9czEHia-ehqPo8spo_e7AgUU,12514 +setuptools/_distutils/versionpredicate.py,sha256=ZxpEA-TQv88mUWc6hetUO4qSqA2sa7ipjZ3QEK5evDk,5133 +setuptools/_imp.py,sha256=HmF91IbitRfsD5z-g4_wmcuH-RahyIONbPgiCOFgtzA,2392 +setuptools/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +setuptools/_vendor/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/__pycache__/ordered_set.cpython-39.pyc,, +setuptools/_vendor/__pycache__/pyparsing.cpython-39.pyc,, +setuptools/_vendor/more_itertools/__init__.py,sha256=C7sXffHTXM3P-iaLPPfqfmDoxOflQMJLcM7ed9p3jak,82 +setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/more_itertools/__pycache__/more.cpython-39.pyc,, +setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-39.pyc,, +setuptools/_vendor/more_itertools/more.py,sha256=DlZa8v6JihVwfQ5zHidOA-xDE0orcQIUyxVnCaUoDKE,117968 +setuptools/_vendor/more_itertools/recipes.py,sha256=UkNkrsZyqiwgLHANBTmvMhCvaNSvSNYhyOpz_Jc55DY,16256 +setuptools/_vendor/ordered_set.py,sha256=dbaCcs27dyN9gnMWGF5nA_BrVn6Q-NrjKYJpV9_fgBs,15130 +setuptools/_vendor/packaging/__about__.py,sha256=PNMsaZn4UcCHyubgROH1bl6CluduPjI5kFrSp_Zgklo,736 +setuptools/_vendor/packaging/__init__.py,sha256=6enbp5XgRfjBjsI9-bn00HjHf5TH21PDMOKkJW8xw-w,562 +setuptools/_vendor/packaging/__pycache__/__about__.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/_compat.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/_structures.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/_typing.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/markers.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/requirements.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/tags.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/utils.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/version.cpython-39.pyc,, +setuptools/_vendor/packaging/_compat.py,sha256=MXdsGpSE_W-ZrHoC87andI4LV2FAwU7HLL-eHe_CjhU,1128 +setuptools/_vendor/packaging/_structures.py,sha256=ozkCX8Q8f2qE1Eic3YiQ4buDVfgz2iYevY9e7R2y3iY,2022 +setuptools/_vendor/packaging/_typing.py,sha256=x59EhQ57TMT-kTRyLZV25HZvYGGwbucTo6iKh_O0tMw,1812 +setuptools/_vendor/packaging/markers.py,sha256=BCCxZbt8xgysH8v5pqbLkdtQnRZHIGkJQqlNBGek4nQ,9509 +setuptools/_vendor/packaging/requirements.py,sha256=VHydZdk8m3qFxReomNwKr71cmpjantEV_xOhkEyyINI,4917 +setuptools/_vendor/packaging/specifiers.py,sha256=uYp9l13F0LcknS6d4N60ytiBgFmIhKideOq9AnsxTco,31944 +setuptools/_vendor/packaging/tags.py,sha256=NKMS37Zo_nWrZxgsD6zbXsXgc9edn9m160cBiLmHJdE,24067 +setuptools/_vendor/packaging/utils.py,sha256=RShlvnjO2CtYSD8uri32frMMFMTmB-3ihsq1-ghzLEw,1811 +setuptools/_vendor/packaging/version.py,sha256=Cnbm-OO9D_qd8ZTFxzFcjSavexSYFZmyeaoPvMsjgPc,15470 +setuptools/_vendor/pyparsing.py,sha256=mahtkgcp3grNAD0re_9R0DLvBnvjzpeLwgJqT-3H1CE,232056 +setuptools/archive_util.py,sha256=maJDbozRbDeSPw53VT0cb_IS3W0Ap73lJR8tX8RZDx0,7077 +setuptools/build_meta.py,sha256=x7FI1UPKCKxBBSopXocfGDnJa98rQO8atKXSwJtdid8,10280 +setuptools/cli-32.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 +setuptools/cli-64.exe,sha256=KLABu5pyrnokJCv6skjXZ6GsXeyYHGcqOUT3oHI3Xpo,74752 +setuptools/cli.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 +setuptools/command/__init__.py,sha256=e-8TJOikUe3St0fw2b2p9u5EDdSxl5zHUBJJKifbcQ8,217 +setuptools/command/__pycache__/__init__.cpython-39.pyc,, +setuptools/command/__pycache__/alias.cpython-39.pyc,, +setuptools/command/__pycache__/bdist_egg.cpython-39.pyc,, +setuptools/command/__pycache__/bdist_rpm.cpython-39.pyc,, +setuptools/command/__pycache__/build_clib.cpython-39.pyc,, +setuptools/command/__pycache__/build_ext.cpython-39.pyc,, +setuptools/command/__pycache__/build_py.cpython-39.pyc,, +setuptools/command/__pycache__/develop.cpython-39.pyc,, +setuptools/command/__pycache__/dist_info.cpython-39.pyc,, +setuptools/command/__pycache__/easy_install.cpython-39.pyc,, +setuptools/command/__pycache__/egg_info.cpython-39.pyc,, +setuptools/command/__pycache__/install.cpython-39.pyc,, +setuptools/command/__pycache__/install_egg_info.cpython-39.pyc,, +setuptools/command/__pycache__/install_lib.cpython-39.pyc,, +setuptools/command/__pycache__/install_scripts.cpython-39.pyc,, +setuptools/command/__pycache__/py36compat.cpython-39.pyc,, +setuptools/command/__pycache__/register.cpython-39.pyc,, +setuptools/command/__pycache__/rotate.cpython-39.pyc,, +setuptools/command/__pycache__/saveopts.cpython-39.pyc,, +setuptools/command/__pycache__/sdist.cpython-39.pyc,, +setuptools/command/__pycache__/setopt.cpython-39.pyc,, +setuptools/command/__pycache__/test.cpython-39.pyc,, +setuptools/command/__pycache__/upload.cpython-39.pyc,, +setuptools/command/__pycache__/upload_docs.cpython-39.pyc,, +setuptools/command/alias.py,sha256=1sLQxZcNh6dDQpDmm4G7UGGTol83nY1NTPmNBbm2siI,2381 +setuptools/command/bdist_egg.py,sha256=-upiB6fFtm8cQSQj1LRDVpG1-T143DsXCvV0fh03u7U,16604 +setuptools/command/bdist_rpm.py,sha256=PxrgoHPNaw2Pw2qNjjHDPC-Ay_IaDbCqP3d_5N-cj2A,1182 +setuptools/command/build_clib.py,sha256=fWHSFGkk10VCddBWCszvNhowbG9Z9CZXVjQ2uSInoOs,4415 +setuptools/command/build_ext.py,sha256=SNK042HfB2ezlDQbSVRGFqI1IM5A4AsjU1wpV3fgskE,13212 +setuptools/command/build_py.py,sha256=UydjclXl6FSyrPjXOOwZD-gHby0tIKoP-qu5itvyP0g,8276 +setuptools/command/develop.py,sha256=5_Ss7ENd1_B_jVMY1tF5UV_y1Xu6jbVzAPG8oKeluGA,7012 +setuptools/command/dist_info.py,sha256=5t6kOfrdgALT-P3ogss6PF9k-Leyesueycuk3dUyZnI,960 +setuptools/command/easy_install.py,sha256=uK0hIXMflGuefmQuA8c6lwwT7Np0uVXRWhxPiextgb4,85344 +setuptools/command/egg_info.py,sha256=se-FhYI1sZMzKd6lndV_-vNkJ31hX4HY4ZcMUu71l9k,25335 +setuptools/command/install.py,sha256=8doMxeQEDoK4Eco0mO2WlXXzzp9QnsGJQ7Z7yWkZPG8,4705 +setuptools/command/install_egg_info.py,sha256=bMgeIeRiXzQ4DAGPV1328kcjwQjHjOWU4FngAWLV78Q,2203 +setuptools/command/install_lib.py,sha256=Uz42McsyHZAjrB6cw9E7Bz0xsaTbzxnM1PI9CBhiPtE,3875 +setuptools/command/install_scripts.py,sha256=o0jN_ex7yYYk8W5clymTFOXwkFMKzW9q_zd9Npcex7M,2593 +setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628 +setuptools/command/py36compat.py,sha256=7yLWzQj179Enx3pJ8V1cDDCzeLMFMd9XJXlK-iZTq5Y,4946 +setuptools/command/register.py,sha256=kk3DxXCb5lXTvqnhfwx2g6q7iwbUmgTyXUCaBooBOUk,468 +setuptools/command/rotate.py,sha256=SvsQPasezIojPjvMnfkqzh8P0U0tCj0daczF8uc3NQM,2128 +setuptools/command/saveopts.py,sha256=za7QCBcQimKKriWcoCcbhxPjUz30gSB74zuTL47xpP4,658 +setuptools/command/sdist.py,sha256=pEMF0GMVuaznNK6GFamK4GSXG9_qef0ic8z7jEsPmKo,5967 +setuptools/command/setopt.py,sha256=okxhqD1NM1nQlbSVDCNv6P7Y7g680sc2r-tUW7wPH1Y,5086 +setuptools/command/test.py,sha256=qGY-Hx1RPCndlVh2rsrEs5479CgmxRsrEflVLr98jVA,8088 +setuptools/command/upload.py,sha256=XT3YFVfYPAmA5qhGg0euluU98ftxRUW-PzKcODMLxUs,462 +setuptools/command/upload_docs.py,sha256=ba5kOyedD_u62weinrxqqnvpuQvBIuamXehJG6tAvO0,7218 +setuptools/config.py,sha256=sm9ZbziX9DlOugcVlIbhqttMJwxwznGEsk82D8MVaDM,23123 +setuptools/dep_util.py,sha256=BDx1BkzNQntvAB4alypHbW5UVBzjqths000PrUL4Zqc,949 +setuptools/depends.py,sha256=iHfZdLdlCu2BllSF9bRg7NU0oqbPWMH8ljm4BuwQDY0,5474 +setuptools/dist.py,sha256=cZtPPzGEhSomPH_vXH_DeCFetjJ9B8Hv8VUCG0KbZh8,43087 +setuptools/errors.py,sha256=MVOcv381HNSajDgEUWzOQ4J6B5BHCBMSjHfaWcEwA1o,524 +setuptools/extension.py,sha256=NMM46XjNdVelWemc0x8CyVKA5Ks6Zm3xTWSA2SS6xZM,1684 +setuptools/extern/__init__.py,sha256=Hhf9W73WAitw9TdRJfDIb6YFjmK56CF61afds1Mg0HY,2407 +setuptools/extern/__pycache__/__init__.cpython-39.pyc,, +setuptools/glob.py,sha256=1oZjbfjAHSXbgdhSuR6YGU8jKob9L8NtEmBYqcPTLYk,4873 +setuptools/gui-32.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 +setuptools/gui-64.exe,sha256=aYKMhX1IJLn4ULHgWX0sE0yREUt6B3TEHf_jOw6yNyE,75264 +setuptools/gui.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 +setuptools/installer.py,sha256=jbhb7ZVkNV_bSUMgfnLcZw0IHr6REFnKF4o7_1Jqxm0,3567 +setuptools/launch.py,sha256=TyPT-Ic1T2EnYvGO26gfNRP4ysBlrhpbRjQxWsiO414,812 +setuptools/monkey.py,sha256=0e3HdVKXHL415O7np-AUqhEFXPPuDdJKbI47chQ_DE4,5217 +setuptools/msvc.py,sha256=3LLt938e6OR7wWPzIvCQu7LCWZSIKqoKV6w3r8jV3kY,50561 +setuptools/namespaces.py,sha256=PMqGVPXPYQgjUTvEg9bGccRAkIODrQ6NmsDg_fwErwI,3093 +setuptools/package_index.py,sha256=2A1O7fpTXcfeD5IV4HWrIoEXXkgq5k8t9aWrjx90Vnw,39886 +setuptools/py34compat.py,sha256=KYOd6ybRxjBW8NJmYD8t_UyyVmysppFXqHpFLdslGXU,245 +setuptools/sandbox.py,sha256=mR83i-mu-ZUU_7TaMgYCeRSyzkqv8loJ_GR9xhS2DDw,14348 +setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218 +setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138 +setuptools/unicode_utils.py,sha256=aOOFo4JGwAsiBttGYDsqFS7YqWQeZ2j6DWiCuctR_00,941 +setuptools/version.py,sha256=og_cuZQb0QI6ukKZFfZWPlr1HgJBPPn2vO2m_bI9ZTE,144 +setuptools/wheel.py,sha256=0P8tSk105uF_Ub-30N2HU2X2v7MKDSdjpeQlRRW3SkI,8288 +setuptools/windows_support.py,sha256=5GrfqSP2-dLGJoZTq2g6dCKkyQxxa2n5IQiXlJCoYEE,714 diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/REQUESTED b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/REQUESTED new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/WHEEL b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..5bad85fdc1cd08553756d0fb2c7be8b5ad6af7fb --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/entry_points.txt b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/entry_points.txt new file mode 100644 index 0000000000000000000000000000000000000000..9466bf6320157d79e69d6940e2b09fb08f64da51 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/entry_points.txt @@ -0,0 +1,56 @@ +[distutils.commands] +alias = setuptools.command.alias:alias +bdist_egg = setuptools.command.bdist_egg:bdist_egg +bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm +build_clib = setuptools.command.build_clib:build_clib +build_ext = setuptools.command.build_ext:build_ext +build_py = setuptools.command.build_py:build_py +develop = setuptools.command.develop:develop +dist_info = setuptools.command.dist_info:dist_info +easy_install = setuptools.command.easy_install:easy_install +egg_info = setuptools.command.egg_info:egg_info +install = setuptools.command.install:install +install_egg_info = setuptools.command.install_egg_info:install_egg_info +install_lib = setuptools.command.install_lib:install_lib +install_scripts = setuptools.command.install_scripts:install_scripts +rotate = setuptools.command.rotate:rotate +saveopts = setuptools.command.saveopts:saveopts +sdist = setuptools.command.sdist:sdist +setopt = setuptools.command.setopt:setopt +test = setuptools.command.test:test +upload_docs = setuptools.command.upload_docs:upload_docs + +[distutils.setup_keywords] +dependency_links = setuptools.dist:assert_string_list +eager_resources = setuptools.dist:assert_string_list +entry_points = setuptools.dist:check_entry_points +exclude_package_data = setuptools.dist:check_package_data +extras_require = setuptools.dist:check_extras +include_package_data = setuptools.dist:assert_bool +install_requires = setuptools.dist:check_requirements +namespace_packages = setuptools.dist:check_nsp +package_data = setuptools.dist:check_package_data +packages = setuptools.dist:check_packages +python_requires = setuptools.dist:check_specifier +setup_requires = setuptools.dist:check_requirements +test_loader = setuptools.dist:check_importable +test_runner = setuptools.dist:check_importable +test_suite = setuptools.dist:check_test_suite +tests_require = setuptools.dist:check_requirements +use_2to3 = setuptools.dist:invalid_unless_false +zip_safe = setuptools.dist:assert_bool + +[egg_info.writers] +PKG-INFO = setuptools.command.egg_info:write_pkg_info +dependency_links.txt = setuptools.command.egg_info:overwrite_arg +depends.txt = setuptools.command.egg_info:warn_depends_obsolete +eager_resources.txt = setuptools.command.egg_info:overwrite_arg +entry_points.txt = setuptools.command.egg_info:write_entries +namespace_packages.txt = setuptools.command.egg_info:overwrite_arg +requires.txt = setuptools.command.egg_info:write_requirements +top_level.txt = setuptools.command.egg_info:write_toplevel_names + +[setuptools.finalize_distribution_options] +keywords = setuptools.dist:Distribution._finalize_setup_keywords +parent_finalize = setuptools.dist:_Distribution.finalize_options + diff --git a/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/top_level.txt b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5ac1070294b478b7cc2ce677207ee08813bfa37 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools-58.1.0.dist-info/top_level.txt @@ -0,0 +1,3 @@ +_distutils_hack +pkg_resources +setuptools diff --git a/MLPY/Lib/site-packages/setuptools/__init__.py b/MLPY/Lib/site-packages/setuptools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9d6f0bc0dd674e92a985a5f997b17039ade95217 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/__init__.py @@ -0,0 +1,242 @@ +"""Extensions to the 'distutils' for large or complex distributions""" + +from fnmatch import fnmatchcase +import functools +import os +import re + +import _distutils_hack.override # noqa: F401 + +import distutils.core +from distutils.errors import DistutilsOptionError +from distutils.util import convert_path + +from ._deprecation_warning import SetuptoolsDeprecationWarning + +import setuptools.version +from setuptools.extension import Extension +from setuptools.dist import Distribution +from setuptools.depends import Require +from . import monkey + + +__all__ = [ + 'setup', + 'Distribution', + 'Command', + 'Extension', + 'Require', + 'SetuptoolsDeprecationWarning', + 'find_packages', + 'find_namespace_packages', +] + +__version__ = setuptools.version.__version__ + +bootstrap_install_from = None + + +class PackageFinder: + """ + Generate a list of all Python packages found within a directory + """ + + @classmethod + def find(cls, where='.', exclude=(), include=('*',)): + """Return a list all Python packages found within directory 'where' + + 'where' is the root directory which will be searched for packages. It + should be supplied as a "cross-platform" (i.e. URL-style) path; it will + be converted to the appropriate local path syntax. + + 'exclude' is a sequence of package names to exclude; '*' can be used + as a wildcard in the names, such that 'foo.*' will exclude all + subpackages of 'foo' (but not 'foo' itself). + + 'include' is a sequence of package names to include. If it's + specified, only the named packages will be included. If it's not + specified, all found packages will be included. 'include' can contain + shell style wildcard patterns just like 'exclude'. + """ + + return list( + cls._find_packages_iter( + convert_path(where), + cls._build_filter('ez_setup', '*__pycache__', *exclude), + cls._build_filter(*include), + ) + ) + + @classmethod + def _find_packages_iter(cls, where, exclude, include): + """ + All the packages found in 'where' that pass the 'include' filter, but + not the 'exclude' filter. + """ + for root, dirs, files in os.walk(where, followlinks=True): + # Copy dirs to iterate over it, then empty dirs. + all_dirs = dirs[:] + dirs[:] = [] + + for dir in all_dirs: + full_path = os.path.join(root, dir) + rel_path = os.path.relpath(full_path, where) + package = rel_path.replace(os.path.sep, '.') + + # Skip directory trees that are not valid packages + if '.' in dir or not cls._looks_like_package(full_path): + continue + + # Should this package be included? + if include(package) and not exclude(package): + yield package + + # Keep searching subdirectories, as there may be more packages + # down there, even if the parent was excluded. + dirs.append(dir) + + @staticmethod + def _looks_like_package(path): + """Does a directory look like a package?""" + return os.path.isfile(os.path.join(path, '__init__.py')) + + @staticmethod + def _build_filter(*patterns): + """ + Given a list of patterns, return a callable that will be true only if + the input matches at least one of the patterns. + """ + return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns) + + +class PEP420PackageFinder(PackageFinder): + @staticmethod + def _looks_like_package(path): + return True + + +find_packages = PackageFinder.find +find_namespace_packages = PEP420PackageFinder.find + + +def _install_setup_requires(attrs): + # Note: do not use `setuptools.Distribution` directly, as + # our PEP 517 backend patch `distutils.core.Distribution`. + class MinimalDistribution(distutils.core.Distribution): + """ + A minimal version of a distribution for supporting the + fetch_build_eggs interface. + """ + + def __init__(self, attrs): + _incl = 'dependency_links', 'setup_requires' + filtered = {k: attrs[k] for k in set(_incl) & set(attrs)} + distutils.core.Distribution.__init__(self, filtered) + + def finalize_options(self): + """ + Disable finalize_options to avoid building the working set. + Ref #2158. + """ + + dist = MinimalDistribution(attrs) + + # Honor setup.cfg's options. + dist.parse_config_files(ignore_option_errors=True) + if dist.setup_requires: + dist.fetch_build_eggs(dist.setup_requires) + + +def setup(**attrs): + # Make sure we have any requirements needed to interpret 'attrs'. + _install_setup_requires(attrs) + return distutils.core.setup(**attrs) + + +setup.__doc__ = distutils.core.setup.__doc__ + + +_Command = monkey.get_unpatched(distutils.core.Command) + + +class Command(_Command): + __doc__ = _Command.__doc__ + + command_consumes_arguments = False + + def __init__(self, dist, **kw): + """ + Construct the command for dist, updating + vars(self) with any keyword parameters. + """ + _Command.__init__(self, dist) + vars(self).update(kw) + + def _ensure_stringlike(self, option, what, default=None): + val = getattr(self, option) + if val is None: + setattr(self, option, default) + return default + elif not isinstance(val, str): + raise DistutilsOptionError( + "'%s' must be a %s (got `%s`)" % (option, what, val) + ) + return val + + def ensure_string_list(self, option): + r"""Ensure that 'option' is a list of strings. If 'option' is + currently a string, we split it either on /,\s*/ or /\s+/, so + "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become + ["foo", "bar", "baz"]. + """ + val = getattr(self, option) + if val is None: + return + elif isinstance(val, str): + setattr(self, option, re.split(r',\s*|\s+', val)) + else: + if isinstance(val, list): + ok = all(isinstance(v, str) for v in val) + else: + ok = False + if not ok: + raise DistutilsOptionError( + "'%s' must be a list of strings (got %r)" % (option, val) + ) + + def reinitialize_command(self, command, reinit_subcommands=0, **kw): + cmd = _Command.reinitialize_command(self, command, reinit_subcommands) + vars(cmd).update(kw) + return cmd + + +def _find_all_simple(path): + """ + Find all files under 'path' + """ + results = ( + os.path.join(base, file) + for base, dirs, files in os.walk(path, followlinks=True) + for file in files + ) + return filter(os.path.isfile, results) + + +def findall(dir=os.curdir): + """ + Find all files under 'dir' and return the list of full filenames. + Unless dir is '.', return full filenames with dir prepended. + """ + files = _find_all_simple(dir) + if dir == os.curdir: + make_rel = functools.partial(os.path.relpath, start=dir) + files = map(make_rel, files) + return list(files) + + +class sic(str): + """Treat this string as-is (https://en.wikipedia.org/wiki/Sic)""" + + +# Apply monkey patches +monkey.patch_all() diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e562e66afe767ad3da1e84128b261c7629dcc18a Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3272683ad3c5cd7284f19c5bee0dbeee7d6721b2 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/_imp.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/_imp.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7521187b29b3fc197bae33fa39a2dc0a60b5f54c Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/_imp.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/archive_util.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/archive_util.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae768e167251af9bd8aa9b69b96d39bd8dbb90e2 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/archive_util.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/build_meta.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/build_meta.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95bacfb9464bb1c960e5fd20460874a2d8c568dc Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/build_meta.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/config.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..622c8b5e7571f8ef3d87c50829108839eae04382 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/config.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/dep_util.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/dep_util.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0715bdc690417d4f85669d838066ea98c6623dd6 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/dep_util.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/depends.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/depends.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ef1525a99127faefef179baa3640ae37ae877b4 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/depends.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/dist.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/dist.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f09e0c8a386417e800696803c80d367ccda949b0 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/dist.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/errors.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/errors.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf1dac065e9772a304b6afdbc52dcb71e4f09ec4 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/errors.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/extension.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/extension.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2d5c6a7f60a1e186fa2ea3597467ec94494e617 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/extension.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/glob.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/glob.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99a66abf56b51b2a3cf3e88938e40929e7eb9fd6 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/glob.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/installer.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/installer.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6acd17a6adf246bb60ab72c466d2e1ea84dc068 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/installer.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/launch.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/launch.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7b8017deac13eee5c0c8b2dae9bd7897657ff2c Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/launch.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/monkey.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/monkey.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebd1c002f3505a7277db32836051f3061841493b Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/monkey.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/msvc.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/msvc.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d5b3802453027b6436ba8ff1797e9bb54ddda8b Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/msvc.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/namespaces.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/namespaces.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18c5495a63aee680ad575ec709be00490544b57c Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/namespaces.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/package_index.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/package_index.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..206a7a04396f305bf2c8563c67980d5712e2da1a Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/package_index.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/py34compat.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/py34compat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fcc02cb4bf4fba1fbc8a67a84a36ae048070303 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/py34compat.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/sandbox.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/sandbox.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..930de80504f68dd1209595f5df918285ce4da338 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/sandbox.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/unicode_utils.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/unicode_utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38860c335e508f109c813a1ed4deeac2a21871f3 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/unicode_utils.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/version.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/version.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6204a54d7a044092d6cc089215b6694e38e2f80 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/version.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/wheel.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/wheel.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89895b751edf029c25108168b94c0fad4e3f4bbd Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/wheel.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/__pycache__/windows_support.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/__pycache__/windows_support.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63da1172ab293e4bb4e338894f97eeb1e2b61126 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/__pycache__/windows_support.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_deprecation_warning.py b/MLPY/Lib/site-packages/setuptools/_deprecation_warning.py new file mode 100644 index 0000000000000000000000000000000000000000..086b64dd3817c0c1a194ffc1959eeffdd2695bef --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_deprecation_warning.py @@ -0,0 +1,7 @@ +class SetuptoolsDeprecationWarning(Warning): + """ + Base class for warning deprecations in ``setuptools`` + + This class is not derived from ``DeprecationWarning``, and as such is + visible by default. + """ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__init__.py b/MLPY/Lib/site-packages/setuptools/_distutils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7dac55b601eef6950ddf24be9170f1656cb15366 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/__init__.py @@ -0,0 +1,15 @@ +"""distutils + +The main package for the Python Module Distribution Utilities. Normally +used from a setup script as + + from distutils.core import setup + + setup (...) +""" + +import sys + +__version__ = sys.version[:sys.version.index(' ')] + +local = True diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09d7ef192adc5358cd0b2b00b99c707efa574889 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/_msvccompiler.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/_msvccompiler.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..20a04ac85efdf75adbb3ca84ba9aae889a4d4fb9 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/_msvccompiler.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/archive_util.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/archive_util.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83a785238418333fef89e99fddaeeb326d298df7 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/archive_util.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/bcppcompiler.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/bcppcompiler.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..665ae79b5c030cb2b4bb6ec5296ba026e8d956cc Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/bcppcompiler.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/ccompiler.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/ccompiler.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..594a9cebf2578c034fc461bdc348d271bdfc62cb Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/ccompiler.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/cmd.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/cmd.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56ad89b5b037abdbab13631edac7913810f1ea9a Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/cmd.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/config.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8da42f278aa4ef51e3774e0eadedfd4b4a3c030f Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/config.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/core.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/core.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0738858eeed6a33ac552003872be292eaf5fe185 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/core.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/cygwinccompiler.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/cygwinccompiler.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7cbcfb226947a769097257b32205ec40df315cb9 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/cygwinccompiler.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/debug.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/debug.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aea3017433f5c46d3bd6499cc68a07f11ff24703 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/debug.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dep_util.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dep_util.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7851a99fa34c7c44d8b6f84ef47f6bdc3bedb368 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dep_util.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dir_util.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dir_util.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c0cc5aab9a84af1b5bdad39c50c1fdddec95684 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dir_util.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dist.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dist.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05b971828a2e9f5a6be786f78cd007ab05f082fa Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/dist.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/errors.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/errors.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f55af4b6bde4baa53790cf4257869479463cabfc Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/errors.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/extension.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/extension.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63a9550c8af57024f54f1b23dc6ba09234ea8b24 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/extension.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/fancy_getopt.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/fancy_getopt.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c3bc8627c490ba60619cc07a35aa99ee07f28da Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/fancy_getopt.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/file_util.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/file_util.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32d7a4696c958f0cc0bb655abb86274dac1e1e5e Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/file_util.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/filelist.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/filelist.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ea0063d86c1fe7377a35afa6a4bcc3d8ce208d1 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/filelist.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/log.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/log.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f459fbb4340409b25537cf76e943e002a04c5430 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/log.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/msvc9compiler.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/msvc9compiler.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06e8d2a4cd9209490bfffd2526548312b3d9bf3d Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/msvc9compiler.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/msvccompiler.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/msvccompiler.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df3ad1ff7c1ec4e1b9cd5426264a7ebba8340ddf Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/msvccompiler.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/py35compat.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/py35compat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45e306575c3fe04e596192d192957ee024b89648 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/py35compat.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/py38compat.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/py38compat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19febc7cb03067b7ef98de602c4acade48e60d66 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/py38compat.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/spawn.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/spawn.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cba8687382360cbb8ddf4c1e47de93414b0586a Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/spawn.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/sysconfig.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/sysconfig.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab58dc63f6a55f07f8a5fc33482433d217f86d5b Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/sysconfig.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/text_file.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/text_file.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a48e714d59de58e97b826ccec1b93664979c27cb Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/text_file.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/unixccompiler.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/unixccompiler.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..971304a09cad22db7d5bcce934a14228b931e6dc Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/unixccompiler.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/util.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/util.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c19cd7a1080caba5316118017d6278d5978ff289 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/util.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/version.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/version.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c60f378eb2baf55a286d64b49cb3ac160711a518 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/version.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/versionpredicate.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/versionpredicate.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3852e983bf750b2761bfb8193f8db8f23b237472 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/__pycache__/versionpredicate.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/_msvccompiler.py b/MLPY/Lib/site-packages/setuptools/_distutils/_msvccompiler.py new file mode 100644 index 0000000000000000000000000000000000000000..b7a06082ae7c34e31f9d4669768c9c6a153612fd --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/_msvccompiler.py @@ -0,0 +1,561 @@ +"""distutils._msvccompiler + +Contains MSVCCompiler, an implementation of the abstract CCompiler class +for Microsoft Visual Studio 2015. + +The module is compatible with VS 2015 and later. You can find legacy support +for older versions in distutils.msvc9compiler and distutils.msvccompiler. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) +# ported to VS 2005 and VS 2008 by Christian Heimes +# ported to VS 2015 by Steve Dower + +import os +import subprocess +import contextlib +import warnings +import unittest.mock +with contextlib.suppress(ImportError): + import winreg + +from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ + CompileError, LibError, LinkError +from distutils.ccompiler import CCompiler, gen_lib_options +from distutils import log +from distutils.util import get_platform + +from itertools import count + +def _find_vc2015(): + try: + key = winreg.OpenKeyEx( + winreg.HKEY_LOCAL_MACHINE, + r"Software\Microsoft\VisualStudio\SxS\VC7", + access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY + ) + except OSError: + log.debug("Visual C++ is not registered") + return None, None + + best_version = 0 + best_dir = None + with key: + for i in count(): + try: + v, vc_dir, vt = winreg.EnumValue(key, i) + except OSError: + break + if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir): + try: + version = int(float(v)) + except (ValueError, TypeError): + continue + if version >= 14 and version > best_version: + best_version, best_dir = version, vc_dir + return best_version, best_dir + +def _find_vc2017(): + """Returns "15, path" based on the result of invoking vswhere.exe + If no install is found, returns "None, None" + + The version is returned to avoid unnecessarily changing the function + result. It may be ignored when the path is not None. + + If vswhere.exe is not available, by definition, VS 2017 is not + installed. + """ + root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles") + if not root: + return None, None + + try: + path = subprocess.check_output([ + os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), + "-latest", + "-prerelease", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", "installationPath", + "-products", "*", + ], encoding="mbcs", errors="strict").strip() + except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): + return None, None + + path = os.path.join(path, "VC", "Auxiliary", "Build") + if os.path.isdir(path): + return 15, path + + return None, None + +PLAT_SPEC_TO_RUNTIME = { + 'x86' : 'x86', + 'x86_amd64' : 'x64', + 'x86_arm' : 'arm', + 'x86_arm64' : 'arm64' +} + +def _find_vcvarsall(plat_spec): + # bpo-38597: Removed vcruntime return value + _, best_dir = _find_vc2017() + + if not best_dir: + best_version, best_dir = _find_vc2015() + + if not best_dir: + log.debug("No suitable Visual C++ version found") + return None, None + + vcvarsall = os.path.join(best_dir, "vcvarsall.bat") + if not os.path.isfile(vcvarsall): + log.debug("%s cannot be found", vcvarsall) + return None, None + + return vcvarsall, None + +def _get_vc_env(plat_spec): + if os.getenv("DISTUTILS_USE_SDK"): + return { + key.lower(): value + for key, value in os.environ.items() + } + + vcvarsall, _ = _find_vcvarsall(plat_spec) + if not vcvarsall: + raise DistutilsPlatformError("Unable to find vcvarsall.bat") + + try: + out = subprocess.check_output( + 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec), + stderr=subprocess.STDOUT, + ).decode('utf-16le', errors='replace') + except subprocess.CalledProcessError as exc: + log.error(exc.output) + raise DistutilsPlatformError("Error executing {}" + .format(exc.cmd)) + + env = { + key.lower(): value + for key, _, value in + (line.partition('=') for line in out.splitlines()) + if key and value + } + + return env + +def _find_exe(exe, paths=None): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + if not paths: + paths = os.getenv('path').split(os.pathsep) + for p in paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + return exe + +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Always cross-compile from x86 to work with the +# lighter-weight MSVC installs that do not include native 64-bit tools. +PLAT_TO_VCVARS = { + 'win32' : 'x86', + 'win-amd64' : 'x86_amd64', + 'win-arm32' : 'x86_arm', + 'win-arm64' : 'x86_arm64' +} + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + compiler_type = 'msvc' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__ (self, verbose, dry_run, force) + # target platform (.plat_name is consistent with 'bdist') + self.plat_name = None + self.initialized = False + + def initialize(self, plat_name=None): + # multi-init means we would need to check platform same each time... + assert not self.initialized, "don't init multiple times" + if plat_name is None: + plat_name = get_platform() + # sanity check for platforms to prevent obscure errors later. + if plat_name not in PLAT_TO_VCVARS: + raise DistutilsPlatformError("--plat-name must be one of {}" + .format(tuple(PLAT_TO_VCVARS))) + + # Get the vcvarsall.bat spec for the requested platform. + plat_spec = PLAT_TO_VCVARS[plat_name] + + vc_env = _get_vc_env(plat_spec) + if not vc_env: + raise DistutilsPlatformError("Unable to find a compatible " + "Visual Studio installation.") + + self._paths = vc_env.get('path', '') + paths = self._paths.split(os.pathsep) + self.cc = _find_exe("cl.exe", paths) + self.linker = _find_exe("link.exe", paths) + self.lib = _find_exe("lib.exe", paths) + self.rc = _find_exe("rc.exe", paths) # resource compiler + self.mc = _find_exe("mc.exe", paths) # message compiler + self.mt = _find_exe("mt.exe", paths) # message compiler + + for dir in vc_env.get('include', '').split(os.pathsep): + if dir: + self.add_include_dir(dir.rstrip(os.sep)) + + for dir in vc_env.get('lib', '').split(os.pathsep): + if dir: + self.add_library_dir(dir.rstrip(os.sep)) + + self.preprocess_options = None + # bpo-38597: Always compile with dynamic linking + # Future releases of Python 3.x will include all past + # versions of vcruntime*.dll for compatibility. + self.compile_options = [ + '/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD' + ] + + self.compile_options_debug = [ + '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' + ] + + ldflags = [ + '/nologo', '/INCREMENTAL:NO', '/LTCG' + ] + + ldflags_debug = [ + '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL' + ] + + self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] + self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1'] + self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] + self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] + self.ldflags_static = [*ldflags] + self.ldflags_static_debug = [*ldflags_debug] + + self._ldflags = { + (CCompiler.EXECUTABLE, None): self.ldflags_exe, + (CCompiler.EXECUTABLE, False): self.ldflags_exe, + (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug, + (CCompiler.SHARED_OBJECT, None): self.ldflags_shared, + (CCompiler.SHARED_OBJECT, False): self.ldflags_shared, + (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug, + (CCompiler.SHARED_LIBRARY, None): self.ldflags_static, + (CCompiler.SHARED_LIBRARY, False): self.ldflags_static, + (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug, + } + + self.initialized = True + + # -- Worker methods ------------------------------------------------ + + def object_filenames(self, + source_filenames, + strip_dir=0, + output_dir=''): + ext_map = { + **{ext: self.obj_extension for ext in self.src_extensions}, + **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions}, + } + + output_dir = output_dir or '' + + def make_out_path(p): + base, ext = os.path.splitext(p) + if strip_dir: + base = os.path.basename(base) + else: + _, base = os.path.splitdrive(base) + if base.startswith((os.path.sep, os.path.altsep)): + base = base[1:] + try: + # XXX: This may produce absurdly long paths. We should check + # the length of the result and trim base until we fit within + # 260 characters. + return os.path.join(output_dir, base + ext_map[ext]) + except LookupError: + # Better to raise an exception instead of silently continuing + # and later complain about sources and targets having + # different lengths + raise CompileError("Don't know how to compile {}".format(p)) + + return list(map(make_out_path, source_filenames)) + + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=0, + extra_preargs=None, extra_postargs=None, depends=None): + + if not self.initialized: + self.initialize() + compile_info = self._setup_compile(output_dir, macros, include_dirs, + sources, depends, extra_postargs) + macros, objects, extra_postargs, pp_opts, build = compile_info + + compile_opts = extra_preargs or [] + compile_opts.append('/c') + if debug: + compile_opts.extend(self.compile_options_debug) + else: + compile_opts.extend(self.compile_options) + + + add_cpp_opts = False + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + if debug: + # pass the full pathname to MSVC in debug mode, + # this allows the debugger to find the source file + # without asking the user to browse for it + src = os.path.abspath(src) + + if ext in self._c_extensions: + input_opt = "/Tc" + src + elif ext in self._cpp_extensions: + input_opt = "/Tp" + src + add_cpp_opts = True + elif ext in self._rc_extensions: + # compile .RC to .RES file + input_opt = src + output_opt = "/fo" + obj + try: + self.spawn([self.rc] + pp_opts + [output_opt, input_opt]) + except DistutilsExecError as msg: + raise CompileError(msg) + continue + elif ext in self._mc_extensions: + # Compile .MC to .RC file to .RES file. + # * '-h dir' specifies the directory for the + # generated include file + # * '-r dir' specifies the target directory of the + # generated RC file and the binary message resource + # it includes + # + # For now (since there are no options to change this), + # we use the source-directory for the include file and + # the build directory for the RC file and message + # resources. This works at least for win32all. + h_dir = os.path.dirname(src) + rc_dir = os.path.dirname(obj) + try: + # first compile .MC to .RC and .H file + self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src]) + base, _ = os.path.splitext(os.path.basename (src)) + rc_file = os.path.join(rc_dir, base + '.rc') + # then compile .RC to .RES file + self.spawn([self.rc, "/fo" + obj, rc_file]) + + except DistutilsExecError as msg: + raise CompileError(msg) + continue + else: + # how to handle this file? + raise CompileError("Don't know how to compile {} to {}" + .format(src, obj)) + + args = [self.cc] + compile_opts + pp_opts + if add_cpp_opts: + args.append('/EHsc') + args.append(input_opt) + args.append("/Fo" + obj) + args.extend(extra_postargs) + + try: + self.spawn(args) + except DistutilsExecError as msg: + raise CompileError(msg) + + return objects + + + def create_static_lib(self, + objects, + output_libname, + output_dir=None, + debug=0, + target_lang=None): + + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + output_filename = self.library_filename(output_libname, + output_dir=output_dir) + + if self._need_link(objects, output_filename): + lib_args = objects + ['/OUT:' + output_filename] + if debug: + pass # XXX what goes here? + try: + log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args)) + self.spawn([self.lib] + lib_args) + except DistutilsExecError as msg: + raise LibError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + + def link(self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + fixed_args = self._fix_lib_args(libraries, library_dirs, + runtime_library_dirs) + libraries, library_dirs, runtime_library_dirs = fixed_args + + if runtime_library_dirs: + self.warn("I don't know what to do with 'runtime_library_dirs': " + + str(runtime_library_dirs)) + + lib_opts = gen_lib_options(self, + library_dirs, runtime_library_dirs, + libraries) + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + ldflags = self._ldflags[target_desc, debug] + + export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])] + + ld_args = (ldflags + lib_opts + export_opts + + objects + ['/OUT:' + output_filename]) + + # The MSVC linker generates .lib and .exp files, which cannot be + # suppressed by any linker switches. The .lib files may even be + # needed! Make sure they are generated in the temporary build + # directory. Since they have different names for debug and release + # builds, they can go into the same directory. + build_temp = os.path.dirname(objects[0]) + if export_symbols is not None: + (dll_name, dll_ext) = os.path.splitext( + os.path.basename(output_filename)) + implib_file = os.path.join( + build_temp, + self.library_filename(dll_name)) + ld_args.append ('/IMPLIB:' + implib_file) + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + output_dir = os.path.dirname(os.path.abspath(output_filename)) + self.mkpath(output_dir) + try: + log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args)) + self.spawn([self.linker] + ld_args) + except DistutilsExecError as msg: + raise LinkError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + def spawn(self, cmd): + env = dict(os.environ, PATH=self._paths) + with self._fallback_spawn(cmd, env) as fallback: + return super().spawn(cmd, env=env) + return fallback.value + + @contextlib.contextmanager + def _fallback_spawn(self, cmd, env): + """ + Discovered in pypa/distutils#15, some tools monkeypatch the compiler, + so the 'env' kwarg causes a TypeError. Detect this condition and + restore the legacy, unsafe behavior. + """ + bag = type('Bag', (), {})() + try: + yield bag + except TypeError as exc: + if "unexpected keyword argument 'env'" not in str(exc): + raise + else: + return + warnings.warn( + "Fallback spawn triggered. Please update distutils monkeypatch.") + with unittest.mock.patch('os.environ', env): + bag.value = super().spawn(cmd) + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "/LIBPATH:" + dir + + def runtime_library_dir_option(self, dir): + raise DistutilsPlatformError( + "don't know how to set runtime library search path for MSVC") + + def library_option(self, lib): + return self.library_filename(lib) + + def find_library_file(self, dirs, lib, debug=0): + # Prefer a debugging library if found (and requested), but deal + # with it if we don't have one. + if debug: + try_names = [lib + "_d", lib] + else: + try_names = [lib] + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename(name)) + if os.path.isfile(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/archive_util.py b/MLPY/Lib/site-packages/setuptools/_distutils/archive_util.py new file mode 100644 index 0000000000000000000000000000000000000000..565a3117b4b5e1a750bf2a4c9fdfa2d61381b0e2 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/archive_util.py @@ -0,0 +1,256 @@ +"""distutils.archive_util + +Utility functions for creating archive files (tarballs, zip files, +that sort of thing).""" + +import os +from warnings import warn +import sys + +try: + import zipfile +except ImportError: + zipfile = None + + +from distutils.errors import DistutilsExecError +from distutils.spawn import spawn +from distutils.dir_util import mkpath +from distutils import log + +try: + from pwd import getpwnam +except ImportError: + getpwnam = None + +try: + from grp import getgrnam +except ImportError: + getgrnam = None + +def _get_gid(name): + """Returns a gid, given a group name.""" + if getgrnam is None or name is None: + return None + try: + result = getgrnam(name) + except KeyError: + result = None + if result is not None: + return result[2] + return None + +def _get_uid(name): + """Returns an uid, given a user name.""" + if getpwnam is None or name is None: + return None + try: + result = getpwnam(name) + except KeyError: + result = None + if result is not None: + return result[2] + return None + +def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, + owner=None, group=None): + """Create a (possibly compressed) tar file from all the files under + 'base_dir'. + + 'compress' must be "gzip" (the default), "bzip2", "xz", "compress", or + None. ("compress" will be deprecated in Python 3.2) + + 'owner' and 'group' can be used to define an owner and a group for the + archive that is being built. If not provided, the current owner and group + will be used. + + The output tar file will be named 'base_dir' + ".tar", possibly plus + the appropriate compression extension (".gz", ".bz2", ".xz" or ".Z"). + + Returns the output filename. + """ + tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '', + 'compress': ''} + compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz', + 'compress': '.Z'} + + # flags for compression program, each element of list will be an argument + if compress is not None and compress not in compress_ext.keys(): + raise ValueError( + "bad value for 'compress': must be None, 'gzip', 'bzip2', " + "'xz' or 'compress'") + + archive_name = base_name + '.tar' + if compress != 'compress': + archive_name += compress_ext.get(compress, '') + + mkpath(os.path.dirname(archive_name), dry_run=dry_run) + + # creating the tarball + import tarfile # late import so Python build itself doesn't break + + log.info('Creating tar archive') + + uid = _get_uid(owner) + gid = _get_gid(group) + + def _set_uid_gid(tarinfo): + if gid is not None: + tarinfo.gid = gid + tarinfo.gname = group + if uid is not None: + tarinfo.uid = uid + tarinfo.uname = owner + return tarinfo + + if not dry_run: + tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) + try: + tar.add(base_dir, filter=_set_uid_gid) + finally: + tar.close() + + # compression using `compress` + if compress == 'compress': + warn("'compress' will be deprecated.", PendingDeprecationWarning) + # the option varies depending on the platform + compressed_name = archive_name + compress_ext[compress] + if sys.platform == 'win32': + cmd = [compress, archive_name, compressed_name] + else: + cmd = [compress, '-f', archive_name] + spawn(cmd, dry_run=dry_run) + return compressed_name + + return archive_name + +def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): + """Create a zip file from all the files under 'base_dir'. + + The output zip file will be named 'base_name' + ".zip". Uses either the + "zipfile" Python module (if available) or the InfoZIP "zip" utility + (if installed and found on the default search path). If neither tool is + available, raises DistutilsExecError. Returns the name of the output zip + file. + """ + zip_filename = base_name + ".zip" + mkpath(os.path.dirname(zip_filename), dry_run=dry_run) + + # If zipfile module is not available, try spawning an external + # 'zip' command. + if zipfile is None: + if verbose: + zipoptions = "-r" + else: + zipoptions = "-rq" + + try: + spawn(["zip", zipoptions, zip_filename, base_dir], + dry_run=dry_run) + except DistutilsExecError: + # XXX really should distinguish between "couldn't find + # external 'zip' command" and "zip failed". + raise DistutilsExecError(("unable to create zip file '%s': " + "could neither import the 'zipfile' module nor " + "find a standalone zip utility") % zip_filename) + + else: + log.info("creating '%s' and adding '%s' to it", + zip_filename, base_dir) + + if not dry_run: + try: + zip = zipfile.ZipFile(zip_filename, "w", + compression=zipfile.ZIP_DEFLATED) + except RuntimeError: + zip = zipfile.ZipFile(zip_filename, "w", + compression=zipfile.ZIP_STORED) + + with zip: + if base_dir != os.curdir: + path = os.path.normpath(os.path.join(base_dir, '')) + zip.write(path, path) + log.info("adding '%s'", path) + for dirpath, dirnames, filenames in os.walk(base_dir): + for name in dirnames: + path = os.path.normpath(os.path.join(dirpath, name, '')) + zip.write(path, path) + log.info("adding '%s'", path) + for name in filenames: + path = os.path.normpath(os.path.join(dirpath, name)) + if os.path.isfile(path): + zip.write(path, path) + log.info("adding '%s'", path) + + return zip_filename + +ARCHIVE_FORMATS = { + 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), + 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), + 'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"), + 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"), + 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"), + 'zip': (make_zipfile, [],"ZIP file") + } + +def check_archive_formats(formats): + """Returns the first format from the 'format' list that is unknown. + + If all formats are known, returns None + """ + for format in formats: + if format not in ARCHIVE_FORMATS: + return format + return None + +def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, + dry_run=0, owner=None, group=None): + """Create an archive file (eg. zip or tar). + + 'base_name' is the name of the file to create, minus any format-specific + extension; 'format' is the archive format: one of "zip", "tar", "gztar", + "bztar", "xztar", or "ztar". + + 'root_dir' is a directory that will be the root directory of the + archive; ie. we typically chdir into 'root_dir' before creating the + archive. 'base_dir' is the directory where we start archiving from; + ie. 'base_dir' will be the common prefix of all files and + directories in the archive. 'root_dir' and 'base_dir' both default + to the current directory. Returns the name of the archive file. + + 'owner' and 'group' are used when creating a tar archive. By default, + uses the current owner and group. + """ + save_cwd = os.getcwd() + if root_dir is not None: + log.debug("changing into '%s'", root_dir) + base_name = os.path.abspath(base_name) + if not dry_run: + os.chdir(root_dir) + + if base_dir is None: + base_dir = os.curdir + + kwargs = {'dry_run': dry_run} + + try: + format_info = ARCHIVE_FORMATS[format] + except KeyError: + raise ValueError("unknown archive format '%s'" % format) + + func = format_info[0] + for arg, val in format_info[1]: + kwargs[arg] = val + + if format != 'zip': + kwargs['owner'] = owner + kwargs['group'] = group + + try: + filename = func(base_name, base_dir, **kwargs) + finally: + if root_dir is not None: + log.debug("changing back to '%s'", save_cwd) + os.chdir(save_cwd) + + return filename diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/bcppcompiler.py b/MLPY/Lib/site-packages/setuptools/_distutils/bcppcompiler.py new file mode 100644 index 0000000000000000000000000000000000000000..071fea5d038cb0425a962a8b6bea55a9c158dd5d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/bcppcompiler.py @@ -0,0 +1,393 @@ +"""distutils.bcppcompiler + +Contains BorlandCCompiler, an implementation of the abstract CCompiler class +for the Borland C++ compiler. +""" + +# This implementation by Lyle Johnson, based on the original msvccompiler.py +# module and using the directions originally published by Gordon Williams. + +# XXX looks like there's a LOT of overlap between these two classes: +# someone should sit down and factor out the common code as +# WindowsCCompiler! --GPW + + +import os +from distutils.errors import \ + DistutilsExecError, \ + CompileError, LibError, LinkError, UnknownFileError +from distutils.ccompiler import \ + CCompiler, gen_preprocess_options +from distutils.file_util import write_file +from distutils.dep_util import newer +from distutils import log + +class BCPPCompiler(CCompiler) : + """Concrete class that implements an interface to the Borland C/C++ + compiler, as defined by the CCompiler abstract class. + """ + + compiler_type = 'bcpp' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = _c_extensions + _cpp_extensions + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + + def __init__ (self, + verbose=0, + dry_run=0, + force=0): + + CCompiler.__init__ (self, verbose, dry_run, force) + + # These executables are assumed to all be in the path. + # Borland doesn't seem to use any special registry settings to + # indicate their installation locations. + + self.cc = "bcc32.exe" + self.linker = "ilink32.exe" + self.lib = "tlib.exe" + + self.preprocess_options = None + self.compile_options = ['/tWM', '/O2', '/q', '/g0'] + self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0'] + + self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x'] + self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x'] + self.ldflags_static = [] + self.ldflags_exe = ['/Gn', '/q', '/x'] + self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r'] + + + # -- Worker methods ------------------------------------------------ + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=0, + extra_preargs=None, extra_postargs=None, depends=None): + + macros, objects, extra_postargs, pp_opts, build = \ + self._setup_compile(output_dir, macros, include_dirs, sources, + depends, extra_postargs) + compile_opts = extra_preargs or [] + compile_opts.append ('-c') + if debug: + compile_opts.extend (self.compile_options_debug) + else: + compile_opts.extend (self.compile_options) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + # XXX why do the normpath here? + src = os.path.normpath(src) + obj = os.path.normpath(obj) + # XXX _setup_compile() did a mkpath() too but before the normpath. + # Is it possible to skip the normpath? + self.mkpath(os.path.dirname(obj)) + + if ext == '.res': + # This is already a binary file -- skip it. + continue # the 'for' loop + if ext == '.rc': + # This needs to be compiled to a .res file -- do it now. + try: + self.spawn (["brcc32", "-fo", obj, src]) + except DistutilsExecError as msg: + raise CompileError(msg) + continue # the 'for' loop + + # The next two are both for the real compiler. + if ext in self._c_extensions: + input_opt = "" + elif ext in self._cpp_extensions: + input_opt = "-P" + else: + # Unknown file type -- no extra options. The compiler + # will probably fail, but let it just in case this is a + # file the compiler recognizes even if we don't. + input_opt = "" + + output_opt = "-o" + obj + + # Compiler command line syntax is: "bcc32 [options] file(s)". + # Note that the source file names must appear at the end of + # the command line. + try: + self.spawn ([self.cc] + compile_opts + pp_opts + + [input_opt, output_opt] + + extra_postargs + [src]) + except DistutilsExecError as msg: + raise CompileError(msg) + + return objects + + # compile () + + + def create_static_lib (self, + objects, + output_libname, + output_dir=None, + debug=0, + target_lang=None): + + (objects, output_dir) = self._fix_object_args (objects, output_dir) + output_filename = \ + self.library_filename (output_libname, output_dir=output_dir) + + if self._need_link (objects, output_filename): + lib_args = [output_filename, '/u'] + objects + if debug: + pass # XXX what goes here? + try: + self.spawn ([self.lib] + lib_args) + except DistutilsExecError as msg: + raise LibError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + # create_static_lib () + + + def link (self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + + # XXX this ignores 'build_temp'! should follow the lead of + # msvccompiler.py + + (objects, output_dir) = self._fix_object_args (objects, output_dir) + (libraries, library_dirs, runtime_library_dirs) = \ + self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) + + if runtime_library_dirs: + log.warn("I don't know what to do with 'runtime_library_dirs': %s", + str(runtime_library_dirs)) + + if output_dir is not None: + output_filename = os.path.join (output_dir, output_filename) + + if self._need_link (objects, output_filename): + + # Figure out linker args based on type of target. + if target_desc == CCompiler.EXECUTABLE: + startup_obj = 'c0w32' + if debug: + ld_args = self.ldflags_exe_debug[:] + else: + ld_args = self.ldflags_exe[:] + else: + startup_obj = 'c0d32' + if debug: + ld_args = self.ldflags_shared_debug[:] + else: + ld_args = self.ldflags_shared[:] + + + # Create a temporary exports file for use by the linker + if export_symbols is None: + def_file = '' + else: + head, tail = os.path.split (output_filename) + modname, ext = os.path.splitext (tail) + temp_dir = os.path.dirname(objects[0]) # preserve tree structure + def_file = os.path.join (temp_dir, '%s.def' % modname) + contents = ['EXPORTS'] + for sym in (export_symbols or []): + contents.append(' %s=_%s' % (sym, sym)) + self.execute(write_file, (def_file, contents), + "writing %s" % def_file) + + # Borland C++ has problems with '/' in paths + objects2 = map(os.path.normpath, objects) + # split objects in .obj and .res files + # Borland C++ needs them at different positions in the command line + objects = [startup_obj] + resources = [] + for file in objects2: + (base, ext) = os.path.splitext(os.path.normcase(file)) + if ext == '.res': + resources.append(file) + else: + objects.append(file) + + + for l in library_dirs: + ld_args.append("/L%s" % os.path.normpath(l)) + ld_args.append("/L.") # we sometimes use relative paths + + # list of object files + ld_args.extend(objects) + + # XXX the command-line syntax for Borland C++ is a bit wonky; + # certain filenames are jammed together in one big string, but + # comma-delimited. This doesn't mesh too well with the + # Unix-centric attitude (with a DOS/Windows quoting hack) of + # 'spawn()', so constructing the argument list is a bit + # awkward. Note that doing the obvious thing and jamming all + # the filenames and commas into one argument would be wrong, + # because 'spawn()' would quote any filenames with spaces in + # them. Arghghh!. Apparently it works fine as coded... + + # name of dll/exe file + ld_args.extend([',',output_filename]) + # no map file and start libraries + ld_args.append(',,') + + for lib in libraries: + # see if we find it and if there is a bcpp specific lib + # (xxx_bcpp.lib) + libfile = self.find_library_file(library_dirs, lib, debug) + if libfile is None: + ld_args.append(lib) + # probably a BCPP internal library -- don't warn + else: + # full name which prefers bcpp_xxx.lib over xxx.lib + ld_args.append(libfile) + + # some default libraries + ld_args.append ('import32') + ld_args.append ('cw32mt') + + # def file for export symbols + ld_args.extend([',',def_file]) + # add resource files + ld_args.append(',') + ld_args.extend(resources) + + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + self.mkpath (os.path.dirname (output_filename)) + try: + self.spawn ([self.linker] + ld_args) + except DistutilsExecError as msg: + raise LinkError(msg) + + else: + log.debug("skipping %s (up-to-date)", output_filename) + + # link () + + # -- Miscellaneous methods ----------------------------------------- + + + def find_library_file (self, dirs, lib, debug=0): + # List of effective library names to try, in order of preference: + # xxx_bcpp.lib is better than xxx.lib + # and xxx_d.lib is better than xxx.lib if debug is set + # + # The "_bcpp" suffix is to handle a Python installation for people + # with multiple compilers (primarily Distutils hackers, I suspect + # ;-). The idea is they'd have one static library for each + # compiler they care about, since (almost?) every Windows compiler + # seems to have a different format for static libraries. + if debug: + dlib = (lib + "_d") + try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib) + else: + try_names = (lib + "_bcpp", lib) + + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename(name)) + if os.path.exists(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None + + # overwrite the one from CCompiler to support rc and res-files + def object_filenames (self, + source_filenames, + strip_dir=0, + output_dir=''): + if output_dir is None: output_dir = '' + obj_names = [] + for src_name in source_filenames: + # use normcase to make sure '.rc' is really '.rc' and not '.RC' + (base, ext) = os.path.splitext (os.path.normcase(src_name)) + if ext not in (self.src_extensions + ['.rc','.res']): + raise UnknownFileError("unknown file type '%s' (from '%s')" % \ + (ext, src_name)) + if strip_dir: + base = os.path.basename (base) + if ext == '.res': + # these can go unchanged + obj_names.append (os.path.join (output_dir, base + ext)) + elif ext == '.rc': + # these need to be compiled to .res-files + obj_names.append (os.path.join (output_dir, base + '.res')) + else: + obj_names.append (os.path.join (output_dir, + base + self.obj_extension)) + return obj_names + + # object_filenames () + + def preprocess (self, + source, + output_file=None, + macros=None, + include_dirs=None, + extra_preargs=None, + extra_postargs=None): + + (_, macros, include_dirs) = \ + self._fix_compile_args(None, macros, include_dirs) + pp_opts = gen_preprocess_options(macros, include_dirs) + pp_args = ['cpp32.exe'] + pp_opts + if output_file is not None: + pp_args.append('-o' + output_file) + if extra_preargs: + pp_args[:0] = extra_preargs + if extra_postargs: + pp_args.extend(extra_postargs) + pp_args.append(source) + + # We need to preprocess: either we're being forced to, or the + # source file is newer than the target (or the target doesn't + # exist). + if self.force or output_file is None or newer(source, output_file): + if output_file: + self.mkpath(os.path.dirname(output_file)) + try: + self.spawn(pp_args) + except DistutilsExecError as msg: + print(msg) + raise CompileError(msg) + + # preprocess() diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/ccompiler.py b/MLPY/Lib/site-packages/setuptools/_distutils/ccompiler.py new file mode 100644 index 0000000000000000000000000000000000000000..48d160d27a5d7276287b4c42f1a9037de8ac3e2f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/ccompiler.py @@ -0,0 +1,1123 @@ +"""distutils.ccompiler + +Contains CCompiler, an abstract base class that defines the interface +for the Distutils compiler abstraction model.""" + +import sys, os, re +from distutils.errors import * +from distutils.spawn import spawn +from distutils.file_util import move_file +from distutils.dir_util import mkpath +from distutils.dep_util import newer_group +from distutils.util import split_quoted, execute +from distutils import log + +class CCompiler: + """Abstract base class to define the interface that must be implemented + by real compiler classes. Also has some utility methods used by + several compiler classes. + + The basic idea behind a compiler abstraction class is that each + instance can be used for all the compile/link steps in building a + single project. Thus, attributes common to all of those compile and + link steps -- include directories, macros to define, libraries to link + against, etc. -- are attributes of the compiler instance. To allow for + variability in how individual files are treated, most of those + attributes may be varied on a per-compilation or per-link basis. + """ + + # 'compiler_type' is a class attribute that identifies this class. It + # keeps code that wants to know what kind of compiler it's dealing with + # from having to import all possible compiler classes just to do an + # 'isinstance'. In concrete CCompiler subclasses, 'compiler_type' + # should really, really be one of the keys of the 'compiler_class' + # dictionary (see below -- used by the 'new_compiler()' factory + # function) -- authors of new compiler interface classes are + # responsible for updating 'compiler_class'! + compiler_type = None + + # XXX things not handled by this compiler abstraction model: + # * client can't provide additional options for a compiler, + # e.g. warning, optimization, debugging flags. Perhaps this + # should be the domain of concrete compiler abstraction classes + # (UnixCCompiler, MSVCCompiler, etc.) -- or perhaps the base + # class should have methods for the common ones. + # * can't completely override the include or library searchg + # path, ie. no "cc -I -Idir1 -Idir2" or "cc -L -Ldir1 -Ldir2". + # I'm not sure how widely supported this is even by Unix + # compilers, much less on other platforms. And I'm even less + # sure how useful it is; maybe for cross-compiling, but + # support for that is a ways off. (And anyways, cross + # compilers probably have a dedicated binary with the + # right paths compiled in. I hope.) + # * can't do really freaky things with the library list/library + # dirs, e.g. "-Ldir1 -lfoo -Ldir2 -lfoo" to link against + # different versions of libfoo.a in different locations. I + # think this is useless without the ability to null out the + # library search path anyways. + + + # Subclasses that rely on the standard filename generation methods + # implemented below should override these; see the comment near + # those methods ('object_filenames()' et. al.) for details: + src_extensions = None # list of strings + obj_extension = None # string + static_lib_extension = None + shared_lib_extension = None # string + static_lib_format = None # format string + shared_lib_format = None # prob. same as static_lib_format + exe_extension = None # string + + # Default language settings. language_map is used to detect a source + # file or Extension target language, checking source filenames. + # language_order is used to detect the language precedence, when deciding + # what language to use when mixing source types. For example, if some + # extension has two files with ".c" extension, and one with ".cpp", it + # is still linked as c++. + language_map = {".c" : "c", + ".cc" : "c++", + ".cpp" : "c++", + ".cxx" : "c++", + ".m" : "objc", + } + language_order = ["c++", "objc", "c"] + + def __init__(self, verbose=0, dry_run=0, force=0): + self.dry_run = dry_run + self.force = force + self.verbose = verbose + + # 'output_dir': a common output directory for object, library, + # shared object, and shared library files + self.output_dir = None + + # 'macros': a list of macro definitions (or undefinitions). A + # macro definition is a 2-tuple (name, value), where the value is + # either a string or None (no explicit value). A macro + # undefinition is a 1-tuple (name,). + self.macros = [] + + # 'include_dirs': a list of directories to search for include files + self.include_dirs = [] + + # 'libraries': a list of libraries to include in any link + # (library names, not filenames: eg. "foo" not "libfoo.a") + self.libraries = [] + + # 'library_dirs': a list of directories to search for libraries + self.library_dirs = [] + + # 'runtime_library_dirs': a list of directories to search for + # shared libraries/objects at runtime + self.runtime_library_dirs = [] + + # 'objects': a list of object files (or similar, such as explicitly + # named library files) to include on any link + self.objects = [] + + for key in self.executables.keys(): + self.set_executable(key, self.executables[key]) + + def set_executables(self, **kwargs): + """Define the executables (and options for them) that will be run + to perform the various stages of compilation. The exact set of + executables that may be specified here depends on the compiler + class (via the 'executables' class attribute), but most will have: + compiler the C/C++ compiler + linker_so linker used to create shared objects and libraries + linker_exe linker used to create binary executables + archiver static library creator + + On platforms with a command-line (Unix, DOS/Windows), each of these + is a string that will be split into executable name and (optional) + list of arguments. (Splitting the string is done similarly to how + Unix shells operate: words are delimited by spaces, but quotes and + backslashes can override this. See + 'distutils.util.split_quoted()'.) + """ + + # Note that some CCompiler implementation classes will define class + # attributes 'cpp', 'cc', etc. with hard-coded executable names; + # this is appropriate when a compiler class is for exactly one + # compiler/OS combination (eg. MSVCCompiler). Other compiler + # classes (UnixCCompiler, in particular) are driven by information + # discovered at run-time, since there are many different ways to do + # basically the same things with Unix C compilers. + + for key in kwargs: + if key not in self.executables: + raise ValueError("unknown executable '%s' for class %s" % + (key, self.__class__.__name__)) + self.set_executable(key, kwargs[key]) + + def set_executable(self, key, value): + if isinstance(value, str): + setattr(self, key, split_quoted(value)) + else: + setattr(self, key, value) + + def _find_macro(self, name): + i = 0 + for defn in self.macros: + if defn[0] == name: + return i + i += 1 + return None + + def _check_macro_definitions(self, definitions): + """Ensures that every element of 'definitions' is a valid macro + definition, ie. either (name,value) 2-tuple or a (name,) tuple. Do + nothing if all definitions are OK, raise TypeError otherwise. + """ + for defn in definitions: + if not (isinstance(defn, tuple) and + (len(defn) in (1, 2) and + (isinstance (defn[1], str) or defn[1] is None)) and + isinstance (defn[0], str)): + raise TypeError(("invalid macro definition '%s': " % defn) + \ + "must be tuple (string,), (string, string), or " + \ + "(string, None)") + + + # -- Bookkeeping methods ------------------------------------------- + + def define_macro(self, name, value=None): + """Define a preprocessor macro for all compilations driven by this + compiler object. The optional parameter 'value' should be a + string; if it is not supplied, then the macro will be defined + without an explicit value and the exact outcome depends on the + compiler used (XXX true? does ANSI say anything about this?) + """ + # Delete from the list of macro definitions/undefinitions if + # already there (so that this one will take precedence). + i = self._find_macro (name) + if i is not None: + del self.macros[i] + + self.macros.append((name, value)) + + def undefine_macro(self, name): + """Undefine a preprocessor macro for all compilations driven by + this compiler object. If the same macro is defined by + 'define_macro()' and undefined by 'undefine_macro()' the last call + takes precedence (including multiple redefinitions or + undefinitions). If the macro is redefined/undefined on a + per-compilation basis (ie. in the call to 'compile()'), then that + takes precedence. + """ + # Delete from the list of macro definitions/undefinitions if + # already there (so that this one will take precedence). + i = self._find_macro (name) + if i is not None: + del self.macros[i] + + undefn = (name,) + self.macros.append(undefn) + + def add_include_dir(self, dir): + """Add 'dir' to the list of directories that will be searched for + header files. The compiler is instructed to search directories in + the order in which they are supplied by successive calls to + 'add_include_dir()'. + """ + self.include_dirs.append(dir) + + def set_include_dirs(self, dirs): + """Set the list of directories that will be searched to 'dirs' (a + list of strings). Overrides any preceding calls to + 'add_include_dir()'; subsequence calls to 'add_include_dir()' add + to the list passed to 'set_include_dirs()'. This does not affect + any list of standard include directories that the compiler may + search by default. + """ + self.include_dirs = dirs[:] + + def add_library(self, libname): + """Add 'libname' to the list of libraries that will be included in + all links driven by this compiler object. Note that 'libname' + should *not* be the name of a file containing a library, but the + name of the library itself: the actual filename will be inferred by + the linker, the compiler, or the compiler class (depending on the + platform). + + The linker will be instructed to link against libraries in the + order they were supplied to 'add_library()' and/or + 'set_libraries()'. It is perfectly valid to duplicate library + names; the linker will be instructed to link against libraries as + many times as they are mentioned. + """ + self.libraries.append(libname) + + def set_libraries(self, libnames): + """Set the list of libraries to be included in all links driven by + this compiler object to 'libnames' (a list of strings). This does + not affect any standard system libraries that the linker may + include by default. + """ + self.libraries = libnames[:] + + def add_library_dir(self, dir): + """Add 'dir' to the list of directories that will be searched for + libraries specified to 'add_library()' and 'set_libraries()'. The + linker will be instructed to search for libraries in the order they + are supplied to 'add_library_dir()' and/or 'set_library_dirs()'. + """ + self.library_dirs.append(dir) + + def set_library_dirs(self, dirs): + """Set the list of library search directories to 'dirs' (a list of + strings). This does not affect any standard library search path + that the linker may search by default. + """ + self.library_dirs = dirs[:] + + def add_runtime_library_dir(self, dir): + """Add 'dir' to the list of directories that will be searched for + shared libraries at runtime. + """ + self.runtime_library_dirs.append(dir) + + def set_runtime_library_dirs(self, dirs): + """Set the list of directories to search for shared libraries at + runtime to 'dirs' (a list of strings). This does not affect any + standard search path that the runtime linker may search by + default. + """ + self.runtime_library_dirs = dirs[:] + + def add_link_object(self, object): + """Add 'object' to the list of object files (or analogues, such as + explicitly named library files or the output of "resource + compilers") to be included in every link driven by this compiler + object. + """ + self.objects.append(object) + + def set_link_objects(self, objects): + """Set the list of object files (or analogues) to be included in + every link to 'objects'. This does not affect any standard object + files that the linker may include by default (such as system + libraries). + """ + self.objects = objects[:] + + + # -- Private utility methods -------------------------------------- + # (here for the convenience of subclasses) + + # Helper method to prep compiler in subclass compile() methods + + def _setup_compile(self, outdir, macros, incdirs, sources, depends, + extra): + """Process arguments and decide which source files to compile.""" + if outdir is None: + outdir = self.output_dir + elif not isinstance(outdir, str): + raise TypeError("'output_dir' must be a string or None") + + if macros is None: + macros = self.macros + elif isinstance(macros, list): + macros = macros + (self.macros or []) + else: + raise TypeError("'macros' (if supplied) must be a list of tuples") + + if incdirs is None: + incdirs = self.include_dirs + elif isinstance(incdirs, (list, tuple)): + incdirs = list(incdirs) + (self.include_dirs or []) + else: + raise TypeError( + "'include_dirs' (if supplied) must be a list of strings") + + if extra is None: + extra = [] + + # Get the list of expected output (object) files + objects = self.object_filenames(sources, strip_dir=0, + output_dir=outdir) + assert len(objects) == len(sources) + + pp_opts = gen_preprocess_options(macros, incdirs) + + build = {} + for i in range(len(sources)): + src = sources[i] + obj = objects[i] + ext = os.path.splitext(src)[1] + self.mkpath(os.path.dirname(obj)) + build[obj] = (src, ext) + + return macros, objects, extra, pp_opts, build + + def _get_cc_args(self, pp_opts, debug, before): + # works for unixccompiler, cygwinccompiler + cc_args = pp_opts + ['-c'] + if debug: + cc_args[:0] = ['-g'] + if before: + cc_args[:0] = before + return cc_args + + def _fix_compile_args(self, output_dir, macros, include_dirs): + """Typecheck and fix-up some of the arguments to the 'compile()' + method, and return fixed-up values. Specifically: if 'output_dir' + is None, replaces it with 'self.output_dir'; ensures that 'macros' + is a list, and augments it with 'self.macros'; ensures that + 'include_dirs' is a list, and augments it with 'self.include_dirs'. + Guarantees that the returned values are of the correct type, + i.e. for 'output_dir' either string or None, and for 'macros' and + 'include_dirs' either list or None. + """ + if output_dir is None: + output_dir = self.output_dir + elif not isinstance(output_dir, str): + raise TypeError("'output_dir' must be a string or None") + + if macros is None: + macros = self.macros + elif isinstance(macros, list): + macros = macros + (self.macros or []) + else: + raise TypeError("'macros' (if supplied) must be a list of tuples") + + if include_dirs is None: + include_dirs = self.include_dirs + elif isinstance(include_dirs, (list, tuple)): + include_dirs = list(include_dirs) + (self.include_dirs or []) + else: + raise TypeError( + "'include_dirs' (if supplied) must be a list of strings") + + return output_dir, macros, include_dirs + + def _prep_compile(self, sources, output_dir, depends=None): + """Decide which source files must be recompiled. + + Determine the list of object files corresponding to 'sources', + and figure out which ones really need to be recompiled. + Return a list of all object files and a dictionary telling + which source files can be skipped. + """ + # Get the list of expected output (object) files + objects = self.object_filenames(sources, output_dir=output_dir) + assert len(objects) == len(sources) + + # Return an empty dict for the "which source files can be skipped" + # return value to preserve API compatibility. + return objects, {} + + def _fix_object_args(self, objects, output_dir): + """Typecheck and fix up some arguments supplied to various methods. + Specifically: ensure that 'objects' is a list; if output_dir is + None, replace with self.output_dir. Return fixed versions of + 'objects' and 'output_dir'. + """ + if not isinstance(objects, (list, tuple)): + raise TypeError("'objects' must be a list or tuple of strings") + objects = list(objects) + + if output_dir is None: + output_dir = self.output_dir + elif not isinstance(output_dir, str): + raise TypeError("'output_dir' must be a string or None") + + return (objects, output_dir) + + def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): + """Typecheck and fix up some of the arguments supplied to the + 'link_*' methods. Specifically: ensure that all arguments are + lists, and augment them with their permanent versions + (eg. 'self.libraries' augments 'libraries'). Return a tuple with + fixed versions of all arguments. + """ + if libraries is None: + libraries = self.libraries + elif isinstance(libraries, (list, tuple)): + libraries = list (libraries) + (self.libraries or []) + else: + raise TypeError( + "'libraries' (if supplied) must be a list of strings") + + if library_dirs is None: + library_dirs = self.library_dirs + elif isinstance(library_dirs, (list, tuple)): + library_dirs = list (library_dirs) + (self.library_dirs or []) + else: + raise TypeError( + "'library_dirs' (if supplied) must be a list of strings") + + if runtime_library_dirs is None: + runtime_library_dirs = self.runtime_library_dirs + elif isinstance(runtime_library_dirs, (list, tuple)): + runtime_library_dirs = (list(runtime_library_dirs) + + (self.runtime_library_dirs or [])) + else: + raise TypeError("'runtime_library_dirs' (if supplied) " + "must be a list of strings") + + return (libraries, library_dirs, runtime_library_dirs) + + def _need_link(self, objects, output_file): + """Return true if we need to relink the files listed in 'objects' + to recreate 'output_file'. + """ + if self.force: + return True + else: + if self.dry_run: + newer = newer_group (objects, output_file, missing='newer') + else: + newer = newer_group (objects, output_file) + return newer + + def detect_language(self, sources): + """Detect the language of a given file, or list of files. Uses + language_map, and language_order to do the job. + """ + if not isinstance(sources, list): + sources = [sources] + lang = None + index = len(self.language_order) + for source in sources: + base, ext = os.path.splitext(source) + extlang = self.language_map.get(ext) + try: + extindex = self.language_order.index(extlang) + if extindex < index: + lang = extlang + index = extindex + except ValueError: + pass + return lang + + + # -- Worker methods ------------------------------------------------ + # (must be implemented by subclasses) + + def preprocess(self, source, output_file=None, macros=None, + include_dirs=None, extra_preargs=None, extra_postargs=None): + """Preprocess a single C/C++ source file, named in 'source'. + Output will be written to file named 'output_file', or stdout if + 'output_file' not supplied. 'macros' is a list of macro + definitions as for 'compile()', which will augment the macros set + with 'define_macro()' and 'undefine_macro()'. 'include_dirs' is a + list of directory names that will be added to the default list. + + Raises PreprocessError on failure. + """ + pass + + def compile(self, sources, output_dir=None, macros=None, + include_dirs=None, debug=0, extra_preargs=None, + extra_postargs=None, depends=None): + """Compile one or more source files. + + 'sources' must be a list of filenames, most likely C/C++ + files, but in reality anything that can be handled by a + particular compiler and compiler class (eg. MSVCCompiler can + handle resource files in 'sources'). Return a list of object + filenames, one per source filename in 'sources'. Depending on + the implementation, not all source files will necessarily be + compiled, but all corresponding object filenames will be + returned. + + If 'output_dir' is given, object files will be put under it, while + retaining their original path component. That is, "foo/bar.c" + normally compiles to "foo/bar.o" (for a Unix implementation); if + 'output_dir' is "build", then it would compile to + "build/foo/bar.o". + + 'macros', if given, must be a list of macro definitions. A macro + definition is either a (name, value) 2-tuple or a (name,) 1-tuple. + The former defines a macro; if the value is None, the macro is + defined without an explicit value. The 1-tuple case undefines a + macro. Later definitions/redefinitions/ undefinitions take + precedence. + + 'include_dirs', if given, must be a list of strings, the + directories to add to the default include file search path for this + compilation only. + + 'debug' is a boolean; if true, the compiler will be instructed to + output debug symbols in (or alongside) the object file(s). + + 'extra_preargs' and 'extra_postargs' are implementation- dependent. + On platforms that have the notion of a command-line (e.g. Unix, + DOS/Windows), they are most likely lists of strings: extra + command-line arguments to prepend/append to the compiler command + line. On other platforms, consult the implementation class + documentation. In any event, they are intended as an escape hatch + for those occasions when the abstract compiler framework doesn't + cut the mustard. + + 'depends', if given, is a list of filenames that all targets + depend on. If a source file is older than any file in + depends, then the source file will be recompiled. This + supports dependency tracking, but only at a coarse + granularity. + + Raises CompileError on failure. + """ + # A concrete compiler class can either override this method + # entirely or implement _compile(). + macros, objects, extra_postargs, pp_opts, build = \ + self._setup_compile(output_dir, macros, include_dirs, sources, + depends, extra_postargs) + cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) + + # Return *all* object filenames, not just the ones we just built. + return objects + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + """Compile 'src' to product 'obj'.""" + # A concrete compiler class that does not override compile() + # should implement _compile(). + pass + + def create_static_lib(self, objects, output_libname, output_dir=None, + debug=0, target_lang=None): + """Link a bunch of stuff together to create a static library file. + The "bunch of stuff" consists of the list of object files supplied + as 'objects', the extra object files supplied to + 'add_link_object()' and/or 'set_link_objects()', the libraries + supplied to 'add_library()' and/or 'set_libraries()', and the + libraries supplied as 'libraries' (if any). + + 'output_libname' should be a library name, not a filename; the + filename will be inferred from the library name. 'output_dir' is + the directory where the library file will be put. + + 'debug' is a boolean; if true, debugging information will be + included in the library (note that on most platforms, it is the + compile step where this matters: the 'debug' flag is included here + just for consistency). + + 'target_lang' is the target language for which the given objects + are being compiled. This allows specific linkage time treatment of + certain languages. + + Raises LibError on failure. + """ + pass + + + # values for target_desc parameter in link() + SHARED_OBJECT = "shared_object" + SHARED_LIBRARY = "shared_library" + EXECUTABLE = "executable" + + def link(self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + """Link a bunch of stuff together to create an executable or + shared library file. + + The "bunch of stuff" consists of the list of object files supplied + as 'objects'. 'output_filename' should be a filename. If + 'output_dir' is supplied, 'output_filename' is relative to it + (i.e. 'output_filename' can provide directory components if + needed). + + 'libraries' is a list of libraries to link against. These are + library names, not filenames, since they're translated into + filenames in a platform-specific way (eg. "foo" becomes "libfoo.a" + on Unix and "foo.lib" on DOS/Windows). However, they can include a + directory component, which means the linker will look in that + specific directory rather than searching all the normal locations. + + 'library_dirs', if supplied, should be a list of directories to + search for libraries that were specified as bare library names + (ie. no directory component). These are on top of the system + default and those supplied to 'add_library_dir()' and/or + 'set_library_dirs()'. 'runtime_library_dirs' is a list of + directories that will be embedded into the shared library and used + to search for other shared libraries that *it* depends on at + run-time. (This may only be relevant on Unix.) + + 'export_symbols' is a list of symbols that the shared library will + export. (This appears to be relevant only on Windows.) + + 'debug' is as for 'compile()' and 'create_static_lib()', with the + slight distinction that it actually matters on most platforms (as + opposed to 'create_static_lib()', which includes a 'debug' flag + mostly for form's sake). + + 'extra_preargs' and 'extra_postargs' are as for 'compile()' (except + of course that they supply command-line arguments for the + particular linker being used). + + 'target_lang' is the target language for which the given objects + are being compiled. This allows specific linkage time treatment of + certain languages. + + Raises LinkError on failure. + """ + raise NotImplementedError + + + # Old 'link_*()' methods, rewritten to use the new 'link()' method. + + def link_shared_lib(self, + objects, + output_libname, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + self.link(CCompiler.SHARED_LIBRARY, objects, + self.library_filename(output_libname, lib_type='shared'), + output_dir, + libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, + extra_preargs, extra_postargs, build_temp, target_lang) + + + def link_shared_object(self, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + self.link(CCompiler.SHARED_OBJECT, objects, + output_filename, output_dir, + libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, + extra_preargs, extra_postargs, build_temp, target_lang) + + + def link_executable(self, + objects, + output_progname, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + target_lang=None): + self.link(CCompiler.EXECUTABLE, objects, + self.executable_filename(output_progname), output_dir, + libraries, library_dirs, runtime_library_dirs, None, + debug, extra_preargs, extra_postargs, None, target_lang) + + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function; there is + # no appropriate default implementation so subclasses should + # implement all of these. + + def library_dir_option(self, dir): + """Return the compiler option to add 'dir' to the list of + directories searched for libraries. + """ + raise NotImplementedError + + def runtime_library_dir_option(self, dir): + """Return the compiler option to add 'dir' to the list of + directories searched for runtime libraries. + """ + raise NotImplementedError + + def library_option(self, lib): + """Return the compiler option to add 'lib' to the list of libraries + linked into the shared library or executable. + """ + raise NotImplementedError + + def has_function(self, funcname, includes=None, include_dirs=None, + libraries=None, library_dirs=None): + """Return a boolean indicating whether funcname is supported on + the current platform. The optional arguments can be used to + augment the compilation environment. + """ + # this can't be included at module scope because it tries to + # import math which might not be available at that point - maybe + # the necessary logic should just be inlined? + import tempfile + if includes is None: + includes = [] + if include_dirs is None: + include_dirs = [] + if libraries is None: + libraries = [] + if library_dirs is None: + library_dirs = [] + fd, fname = tempfile.mkstemp(".c", funcname, text=True) + f = os.fdopen(fd, "w") + try: + for incl in includes: + f.write("""#include "%s"\n""" % incl) + f.write("""\ +int main (int argc, char **argv) { + %s(); + return 0; +} +""" % funcname) + finally: + f.close() + try: + objects = self.compile([fname], include_dirs=include_dirs) + except CompileError: + return False + finally: + os.remove(fname) + + try: + self.link_executable(objects, "a.out", + libraries=libraries, + library_dirs=library_dirs) + except (LinkError, TypeError): + return False + else: + os.remove("a.out") + finally: + for fn in objects: + os.remove(fn) + return True + + def find_library_file (self, dirs, lib, debug=0): + """Search the specified list of directories for a static or shared + library file 'lib' and return the full path to that file. If + 'debug' true, look for a debugging version (if that makes sense on + the current platform). Return None if 'lib' wasn't found in any of + the specified directories. + """ + raise NotImplementedError + + # -- Filename generation methods ----------------------------------- + + # The default implementation of the filename generating methods are + # prejudiced towards the Unix/DOS/Windows view of the world: + # * object files are named by replacing the source file extension + # (eg. .c/.cpp -> .o/.obj) + # * library files (shared or static) are named by plugging the + # library name and extension into a format string, eg. + # "lib%s.%s" % (lib_name, ".a") for Unix static libraries + # * executables are named by appending an extension (possibly + # empty) to the program name: eg. progname + ".exe" for + # Windows + # + # To reduce redundant code, these methods expect to find + # several attributes in the current object (presumably defined + # as class attributes): + # * src_extensions - + # list of C/C++ source file extensions, eg. ['.c', '.cpp'] + # * obj_extension - + # object file extension, eg. '.o' or '.obj' + # * static_lib_extension - + # extension for static library files, eg. '.a' or '.lib' + # * shared_lib_extension - + # extension for shared library/object files, eg. '.so', '.dll' + # * static_lib_format - + # format string for generating static library filenames, + # eg. 'lib%s.%s' or '%s.%s' + # * shared_lib_format + # format string for generating shared library filenames + # (probably same as static_lib_format, since the extension + # is one of the intended parameters to the format string) + # * exe_extension - + # extension for executable files, eg. '' or '.exe' + + def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): + if output_dir is None: + output_dir = '' + obj_names = [] + for src_name in source_filenames: + base, ext = os.path.splitext(src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / + if ext not in self.src_extensions: + raise UnknownFileError( + "unknown file type '%s' (from '%s')" % (ext, src_name)) + if strip_dir: + base = os.path.basename(base) + obj_names.append(os.path.join(output_dir, + base + self.obj_extension)) + return obj_names + + def shared_object_filename(self, basename, strip_dir=0, output_dir=''): + assert output_dir is not None + if strip_dir: + basename = os.path.basename(basename) + return os.path.join(output_dir, basename + self.shared_lib_extension) + + def executable_filename(self, basename, strip_dir=0, output_dir=''): + assert output_dir is not None + if strip_dir: + basename = os.path.basename(basename) + return os.path.join(output_dir, basename + (self.exe_extension or '')) + + def library_filename(self, libname, lib_type='static', # or 'shared' + strip_dir=0, output_dir=''): + assert output_dir is not None + if lib_type not in ("static", "shared", "dylib", "xcode_stub"): + raise ValueError( + "'lib_type' must be \"static\", \"shared\", \"dylib\", or \"xcode_stub\"") + fmt = getattr(self, lib_type + "_lib_format") + ext = getattr(self, lib_type + "_lib_extension") + + dir, base = os.path.split(libname) + filename = fmt % (base, ext) + if strip_dir: + dir = '' + + return os.path.join(output_dir, dir, filename) + + + # -- Utility methods ----------------------------------------------- + + def announce(self, msg, level=1): + log.debug(msg) + + def debug_print(self, msg): + from distutils.debug import DEBUG + if DEBUG: + print(msg) + + def warn(self, msg): + sys.stderr.write("warning: %s\n" % msg) + + def execute(self, func, args, msg=None, level=1): + execute(func, args, msg, self.dry_run) + + def spawn(self, cmd, **kwargs): + spawn(cmd, dry_run=self.dry_run, **kwargs) + + def move_file(self, src, dst): + return move_file(src, dst, dry_run=self.dry_run) + + def mkpath (self, name, mode=0o777): + mkpath(name, mode, dry_run=self.dry_run) + + +# Map a sys.platform/os.name ('posix', 'nt') to the default compiler +# type for that platform. Keys are interpreted as re match +# patterns. Order is important; platform mappings are preferred over +# OS names. +_default_compilers = ( + + # Platform string mappings + + # on a cygwin built python we can use gcc like an ordinary UNIXish + # compiler + ('cygwin.*', 'unix'), + + # OS name mappings + ('posix', 'unix'), + ('nt', 'msvc'), + + ) + +def get_default_compiler(osname=None, platform=None): + """Determine the default compiler to use for the given platform. + + osname should be one of the standard Python OS names (i.e. the + ones returned by os.name) and platform the common value + returned by sys.platform for the platform in question. + + The default values are os.name and sys.platform in case the + parameters are not given. + """ + if osname is None: + osname = os.name + if platform is None: + platform = sys.platform + for pattern, compiler in _default_compilers: + if re.match(pattern, platform) is not None or \ + re.match(pattern, osname) is not None: + return compiler + # Default to Unix compiler + return 'unix' + +# Map compiler types to (module_name, class_name) pairs -- ie. where to +# find the code that implements an interface to this compiler. (The module +# is assumed to be in the 'distutils' package.) +compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler', + "standard UNIX-style compiler"), + 'msvc': ('_msvccompiler', 'MSVCCompiler', + "Microsoft Visual C++"), + 'cygwin': ('cygwinccompiler', 'CygwinCCompiler', + "Cygwin port of GNU C Compiler for Win32"), + 'mingw32': ('cygwinccompiler', 'Mingw32CCompiler', + "Mingw32 port of GNU C Compiler for Win32"), + 'bcpp': ('bcppcompiler', 'BCPPCompiler', + "Borland C++ Compiler"), + } + +def show_compilers(): + """Print list of available compilers (used by the "--help-compiler" + options to "build", "build_ext", "build_clib"). + """ + # XXX this "knows" that the compiler option it's describing is + # "--compiler", which just happens to be the case for the three + # commands that use it. + from distutils.fancy_getopt import FancyGetopt + compilers = [] + for compiler in compiler_class.keys(): + compilers.append(("compiler="+compiler, None, + compiler_class[compiler][2])) + compilers.sort() + pretty_printer = FancyGetopt(compilers) + pretty_printer.print_help("List of available compilers:") + + +def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0): + """Generate an instance of some CCompiler subclass for the supplied + platform/compiler combination. 'plat' defaults to 'os.name' + (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler + for that platform. Currently only 'posix' and 'nt' are supported, and + the default compilers are "traditional Unix interface" (UnixCCompiler + class) and Visual C++ (MSVCCompiler class). Note that it's perfectly + possible to ask for a Unix compiler object under Windows, and a + Microsoft compiler object under Unix -- if you supply a value for + 'compiler', 'plat' is ignored. + """ + if plat is None: + plat = os.name + + try: + if compiler is None: + compiler = get_default_compiler(plat) + + (module_name, class_name, long_description) = compiler_class[compiler] + except KeyError: + msg = "don't know how to compile C/C++ code on platform '%s'" % plat + if compiler is not None: + msg = msg + " with '%s' compiler" % compiler + raise DistutilsPlatformError(msg) + + try: + module_name = "distutils." + module_name + __import__ (module_name) + module = sys.modules[module_name] + klass = vars(module)[class_name] + except ImportError: + raise DistutilsModuleError( + "can't compile C/C++ code: unable to load module '%s'" % \ + module_name) + except KeyError: + raise DistutilsModuleError( + "can't compile C/C++ code: unable to find class '%s' " + "in module '%s'" % (class_name, module_name)) + + # XXX The None is necessary to preserve backwards compatibility + # with classes that expect verbose to be the first positional + # argument. + return klass(None, dry_run, force) + + +def gen_preprocess_options(macros, include_dirs): + """Generate C pre-processor options (-D, -U, -I) as used by at least + two types of compilers: the typical Unix compiler and Visual C++. + 'macros' is the usual thing, a list of 1- or 2-tuples, where (name,) + means undefine (-U) macro 'name', and (name,value) means define (-D) + macro 'name' to 'value'. 'include_dirs' is just a list of directory + names to be added to the header file search path (-I). Returns a list + of command-line options suitable for either Unix compilers or Visual + C++. + """ + # XXX it would be nice (mainly aesthetic, and so we don't generate + # stupid-looking command lines) to go over 'macros' and eliminate + # redundant definitions/undefinitions (ie. ensure that only the + # latest mention of a particular macro winds up on the command + # line). I don't think it's essential, though, since most (all?) + # Unix C compilers only pay attention to the latest -D or -U + # mention of a macro on their command line. Similar situation for + # 'include_dirs'. I'm punting on both for now. Anyways, weeding out + # redundancies like this should probably be the province of + # CCompiler, since the data structures used are inherited from it + # and therefore common to all CCompiler classes. + pp_opts = [] + for macro in macros: + if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2): + raise TypeError( + "bad macro definition '%s': " + "each element of 'macros' list must be a 1- or 2-tuple" + % macro) + + if len(macro) == 1: # undefine this macro + pp_opts.append("-U%s" % macro[0]) + elif len(macro) == 2: + if macro[1] is None: # define with no explicit value + pp_opts.append("-D%s" % macro[0]) + else: + # XXX *don't* need to be clever about quoting the + # macro value here, because we're going to avoid the + # shell at all costs when we spawn the command! + pp_opts.append("-D%s=%s" % macro) + + for dir in include_dirs: + pp_opts.append("-I%s" % dir) + return pp_opts + + +def gen_lib_options (compiler, library_dirs, runtime_library_dirs, libraries): + """Generate linker options for searching library directories and + linking with specific libraries. 'libraries' and 'library_dirs' are, + respectively, lists of library names (not filenames!) and search + directories. Returns a list of command-line options suitable for use + with some compiler (depending on the two format strings passed in). + """ + lib_opts = [] + + for dir in library_dirs: + lib_opts.append(compiler.library_dir_option(dir)) + + for dir in runtime_library_dirs: + opt = compiler.runtime_library_dir_option(dir) + if isinstance(opt, list): + lib_opts = lib_opts + opt + else: + lib_opts.append(opt) + + # XXX it's important that we *not* remove redundant library mentions! + # sometimes you really do have to say "-lfoo -lbar -lfoo" in order to + # resolve all symbols. I just hope we never have to say "-lfoo obj.o + # -lbar" to get things to work -- that's certainly a possibility, but a + # pretty nasty way to arrange your C code. + + for lib in libraries: + (lib_dir, lib_name) = os.path.split(lib) + if lib_dir: + lib_file = compiler.find_library_file([lib_dir], lib_name) + if lib_file: + lib_opts.append(lib_file) + else: + compiler.warn("no library file corresponding to " + "'%s' found (skipping)" % lib) + else: + lib_opts.append(compiler.library_option (lib)) + return lib_opts diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/cmd.py b/MLPY/Lib/site-packages/setuptools/_distutils/cmd.py new file mode 100644 index 0000000000000000000000000000000000000000..dba3191e58474c95a66e86ed67b266198f3e7aac --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/cmd.py @@ -0,0 +1,403 @@ +"""distutils.cmd + +Provides the Command class, the base class for the command classes +in the distutils.command package. +""" + +import sys, os, re +from distutils.errors import DistutilsOptionError +from distutils import util, dir_util, file_util, archive_util, dep_util +from distutils import log + +class Command: + """Abstract base class for defining command classes, the "worker bees" + of the Distutils. A useful analogy for command classes is to think of + them as subroutines with local variables called "options". The options + are "declared" in 'initialize_options()' and "defined" (given their + final values, aka "finalized") in 'finalize_options()', both of which + must be defined by every command class. The distinction between the + two is necessary because option values might come from the outside + world (command line, config file, ...), and any options dependent on + other options must be computed *after* these outside influences have + been processed -- hence 'finalize_options()'. The "body" of the + subroutine, where it does all its work based on the values of its + options, is the 'run()' method, which must also be implemented by every + command class. + """ + + # 'sub_commands' formalizes the notion of a "family" of commands, + # eg. "install" as the parent with sub-commands "install_lib", + # "install_headers", etc. The parent of a family of commands + # defines 'sub_commands' as a class attribute; it's a list of + # (command_name : string, predicate : unbound_method | string | None) + # tuples, where 'predicate' is a method of the parent command that + # determines whether the corresponding command is applicable in the + # current situation. (Eg. we "install_headers" is only applicable if + # we have any C header files to install.) If 'predicate' is None, + # that command is always applicable. + # + # 'sub_commands' is usually defined at the *end* of a class, because + # predicates can be unbound methods, so they must already have been + # defined. The canonical example is the "install" command. + sub_commands = [] + + + # -- Creation/initialization methods ------------------------------- + + def __init__(self, dist): + """Create and initialize a new Command object. Most importantly, + invokes the 'initialize_options()' method, which is the real + initializer and depends on the actual command being + instantiated. + """ + # late import because of mutual dependence between these classes + from distutils.dist import Distribution + + if not isinstance(dist, Distribution): + raise TypeError("dist must be a Distribution instance") + if self.__class__ is Command: + raise RuntimeError("Command is an abstract class") + + self.distribution = dist + self.initialize_options() + + # Per-command versions of the global flags, so that the user can + # customize Distutils' behaviour command-by-command and let some + # commands fall back on the Distribution's behaviour. None means + # "not defined, check self.distribution's copy", while 0 or 1 mean + # false and true (duh). Note that this means figuring out the real + # value of each flag is a touch complicated -- hence "self._dry_run" + # will be handled by __getattr__, below. + # XXX This needs to be fixed. + self._dry_run = None + + # verbose is largely ignored, but needs to be set for + # backwards compatibility (I think)? + self.verbose = dist.verbose + + # Some commands define a 'self.force' option to ignore file + # timestamps, but methods defined *here* assume that + # 'self.force' exists for all commands. So define it here + # just to be safe. + self.force = None + + # The 'help' flag is just used for command-line parsing, so + # none of that complicated bureaucracy is needed. + self.help = 0 + + # 'finalized' records whether or not 'finalize_options()' has been + # called. 'finalize_options()' itself should not pay attention to + # this flag: it is the business of 'ensure_finalized()', which + # always calls 'finalize_options()', to respect/update it. + self.finalized = 0 + + # XXX A more explicit way to customize dry_run would be better. + def __getattr__(self, attr): + if attr == 'dry_run': + myval = getattr(self, "_" + attr) + if myval is None: + return getattr(self.distribution, attr) + else: + return myval + else: + raise AttributeError(attr) + + def ensure_finalized(self): + if not self.finalized: + self.finalize_options() + self.finalized = 1 + + # Subclasses must define: + # initialize_options() + # provide default values for all options; may be customized by + # setup script, by options from config file(s), or by command-line + # options + # finalize_options() + # decide on the final values for all options; this is called + # after all possible intervention from the outside world + # (command-line, option file, etc.) has been processed + # run() + # run the command: do whatever it is we're here to do, + # controlled by the command's various option values + + def initialize_options(self): + """Set default values for all the options that this command + supports. Note that these defaults may be overridden by other + commands, by the setup script, by config files, or by the + command-line. Thus, this is not the place to code dependencies + between options; generally, 'initialize_options()' implementations + are just a bunch of "self.foo = None" assignments. + + This method must be implemented by all command classes. + """ + raise RuntimeError("abstract method -- subclass %s must override" + % self.__class__) + + def finalize_options(self): + """Set final values for all the options that this command supports. + This is always called as late as possible, ie. after any option + assignments from the command-line or from other commands have been + done. Thus, this is the place to code option dependencies: if + 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as + long as 'foo' still has the same value it was assigned in + 'initialize_options()'. + + This method must be implemented by all command classes. + """ + raise RuntimeError("abstract method -- subclass %s must override" + % self.__class__) + + + def dump_options(self, header=None, indent=""): + from distutils.fancy_getopt import longopt_xlate + if header is None: + header = "command options for '%s':" % self.get_command_name() + self.announce(indent + header, level=log.INFO) + indent = indent + " " + for (option, _, _) in self.user_options: + option = option.translate(longopt_xlate) + if option[-1] == "=": + option = option[:-1] + value = getattr(self, option) + self.announce(indent + "%s = %s" % (option, value), + level=log.INFO) + + def run(self): + """A command's raison d'etre: carry out the action it exists to + perform, controlled by the options initialized in + 'initialize_options()', customized by other commands, the setup + script, the command-line, and config files, and finalized in + 'finalize_options()'. All terminal output and filesystem + interaction should be done by 'run()'. + + This method must be implemented by all command classes. + """ + raise RuntimeError("abstract method -- subclass %s must override" + % self.__class__) + + def announce(self, msg, level=1): + """If the current verbosity level is of greater than or equal to + 'level' print 'msg' to stdout. + """ + log.log(level, msg) + + def debug_print(self, msg): + """Print 'msg' to stdout if the global DEBUG (taken from the + DISTUTILS_DEBUG environment variable) flag is true. + """ + from distutils.debug import DEBUG + if DEBUG: + print(msg) + sys.stdout.flush() + + + # -- Option validation methods ------------------------------------- + # (these are very handy in writing the 'finalize_options()' method) + # + # NB. the general philosophy here is to ensure that a particular option + # value meets certain type and value constraints. If not, we try to + # force it into conformance (eg. if we expect a list but have a string, + # split the string on comma and/or whitespace). If we can't force the + # option into conformance, raise DistutilsOptionError. Thus, command + # classes need do nothing more than (eg.) + # self.ensure_string_list('foo') + # and they can be guaranteed that thereafter, self.foo will be + # a list of strings. + + def _ensure_stringlike(self, option, what, default=None): + val = getattr(self, option) + if val is None: + setattr(self, option, default) + return default + elif not isinstance(val, str): + raise DistutilsOptionError("'%s' must be a %s (got `%s`)" + % (option, what, val)) + return val + + def ensure_string(self, option, default=None): + """Ensure that 'option' is a string; if not defined, set it to + 'default'. + """ + self._ensure_stringlike(option, "string", default) + + def ensure_string_list(self, option): + r"""Ensure that 'option' is a list of strings. If 'option' is + currently a string, we split it either on /,\s*/ or /\s+/, so + "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become + ["foo", "bar", "baz"]. + """ + val = getattr(self, option) + if val is None: + return + elif isinstance(val, str): + setattr(self, option, re.split(r',\s*|\s+', val)) + else: + if isinstance(val, list): + ok = all(isinstance(v, str) for v in val) + else: + ok = False + if not ok: + raise DistutilsOptionError( + "'%s' must be a list of strings (got %r)" + % (option, val)) + + def _ensure_tested_string(self, option, tester, what, error_fmt, + default=None): + val = self._ensure_stringlike(option, what, default) + if val is not None and not tester(val): + raise DistutilsOptionError(("error in '%s' option: " + error_fmt) + % (option, val)) + + def ensure_filename(self, option): + """Ensure that 'option' is the name of an existing file.""" + self._ensure_tested_string(option, os.path.isfile, + "filename", + "'%s' does not exist or is not a file") + + def ensure_dirname(self, option): + self._ensure_tested_string(option, os.path.isdir, + "directory name", + "'%s' does not exist or is not a directory") + + + # -- Convenience methods for commands ------------------------------ + + def get_command_name(self): + if hasattr(self, 'command_name'): + return self.command_name + else: + return self.__class__.__name__ + + def set_undefined_options(self, src_cmd, *option_pairs): + """Set the values of any "undefined" options from corresponding + option values in some other command object. "Undefined" here means + "is None", which is the convention used to indicate that an option + has not been changed between 'initialize_options()' and + 'finalize_options()'. Usually called from 'finalize_options()' for + options that depend on some other command rather than another + option of the same command. 'src_cmd' is the other command from + which option values will be taken (a command object will be created + for it if necessary); the remaining arguments are + '(src_option,dst_option)' tuples which mean "take the value of + 'src_option' in the 'src_cmd' command object, and copy it to + 'dst_option' in the current command object". + """ + # Option_pairs: list of (src_option, dst_option) tuples + src_cmd_obj = self.distribution.get_command_obj(src_cmd) + src_cmd_obj.ensure_finalized() + for (src_option, dst_option) in option_pairs: + if getattr(self, dst_option) is None: + setattr(self, dst_option, getattr(src_cmd_obj, src_option)) + + def get_finalized_command(self, command, create=1): + """Wrapper around Distribution's 'get_command_obj()' method: find + (create if necessary and 'create' is true) the command object for + 'command', call its 'ensure_finalized()' method, and return the + finalized command object. + """ + cmd_obj = self.distribution.get_command_obj(command, create) + cmd_obj.ensure_finalized() + return cmd_obj + + # XXX rename to 'get_reinitialized_command()'? (should do the + # same in dist.py, if so) + def reinitialize_command(self, command, reinit_subcommands=0): + return self.distribution.reinitialize_command(command, + reinit_subcommands) + + def run_command(self, command): + """Run some other command: uses the 'run_command()' method of + Distribution, which creates and finalizes the command object if + necessary and then invokes its 'run()' method. + """ + self.distribution.run_command(command) + + def get_sub_commands(self): + """Determine the sub-commands that are relevant in the current + distribution (ie., that need to be run). This is based on the + 'sub_commands' class attribute: each tuple in that list may include + a method that we call to determine if the subcommand needs to be + run for the current distribution. Return a list of command names. + """ + commands = [] + for (cmd_name, method) in self.sub_commands: + if method is None or method(self): + commands.append(cmd_name) + return commands + + + # -- External world manipulation ----------------------------------- + + def warn(self, msg): + log.warn("warning: %s: %s\n", self.get_command_name(), msg) + + def execute(self, func, args, msg=None, level=1): + util.execute(func, args, msg, dry_run=self.dry_run) + + def mkpath(self, name, mode=0o777): + dir_util.mkpath(name, mode, dry_run=self.dry_run) + + def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, + link=None, level=1): + """Copy a file respecting verbose, dry-run and force flags. (The + former two default to whatever is in the Distribution object, and + the latter defaults to false for commands that don't define it.)""" + return file_util.copy_file(infile, outfile, preserve_mode, + preserve_times, not self.force, link, + dry_run=self.dry_run) + + def copy_tree(self, infile, outfile, preserve_mode=1, preserve_times=1, + preserve_symlinks=0, level=1): + """Copy an entire directory tree respecting verbose, dry-run, + and force flags. + """ + return dir_util.copy_tree(infile, outfile, preserve_mode, + preserve_times, preserve_symlinks, + not self.force, dry_run=self.dry_run) + + def move_file (self, src, dst, level=1): + """Move a file respecting dry-run flag.""" + return file_util.move_file(src, dst, dry_run=self.dry_run) + + def spawn(self, cmd, search_path=1, level=1): + """Spawn an external command respecting dry-run flag.""" + from distutils.spawn import spawn + spawn(cmd, search_path, dry_run=self.dry_run) + + def make_archive(self, base_name, format, root_dir=None, base_dir=None, + owner=None, group=None): + return archive_util.make_archive(base_name, format, root_dir, base_dir, + dry_run=self.dry_run, + owner=owner, group=group) + + def make_file(self, infiles, outfile, func, args, + exec_msg=None, skip_msg=None, level=1): + """Special case of 'execute()' for operations that process one or + more input files and generate one output file. Works just like + 'execute()', except the operation is skipped and a different + message printed if 'outfile' already exists and is newer than all + files listed in 'infiles'. If the command defined 'self.force', + and it is true, then the command is unconditionally run -- does no + timestamp checks. + """ + if skip_msg is None: + skip_msg = "skipping %s (inputs unchanged)" % outfile + + # Allow 'infiles' to be a single string + if isinstance(infiles, str): + infiles = (infiles,) + elif not isinstance(infiles, (list, tuple)): + raise TypeError( + "'infiles' must be a string, or a list or tuple of strings") + + if exec_msg is None: + exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles)) + + # If 'outfile' must be regenerated (either because it doesn't + # exist, is out-of-date, or the 'force' flag is true) then + # perform the action that presumably regenerates it + if self.force or dep_util.newer_group(infiles, outfile): + self.execute(func, args, exec_msg, level) + # Otherwise, print the "skip" message + else: + log.debug(skip_msg) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__init__.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..481eea9fd4b5a5ca67e75bc9d3b3effe6ce29194 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/__init__.py @@ -0,0 +1,31 @@ +"""distutils.command + +Package containing implementation of all the standard Distutils +commands.""" + +__all__ = ['build', + 'build_py', + 'build_ext', + 'build_clib', + 'build_scripts', + 'clean', + 'install', + 'install_lib', + 'install_headers', + 'install_scripts', + 'install_data', + 'sdist', + 'register', + 'bdist', + 'bdist_dumb', + 'bdist_rpm', + 'bdist_wininst', + 'check', + 'upload', + # These two are reserved for future use: + #'bdist_sdux', + #'bdist_pkgtool', + # Note: + # bdist_packager is not included because it only provides + # an abstract base class + ] diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d56060df9ced65280c03a1ba804b93e32fc1b67 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b9379c589d27317b28bea089acc0275dcab1811 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..859e3abb8d1aa4fa5a958b648b8dc58c9616e23d Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_msi.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_msi.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcfb3a202de6df5ca5f2d869534f2ed8abace489 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_msi.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1e615c80c15f17beb6971dd6a8369ad7714997c Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_wininst.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_wininst.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05120dfc404920454632e3a7d00284995ae1f47e Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_wininst.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9ef96c4a7d62a3ccdc98507cd674c367bb218b9 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c8b495260ae6e2733f904f55effc22b3014e90e Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_ext.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_ext.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f80c9d4450f9e36dcd3bf87fc9093a639f89bc8 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_ext.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_py.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_py.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd5ee25ab7af62653a7886ee8e96fb34062cda60 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_py.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1632f119895f0dd74a56f1c838b3698e68ea17b4 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/check.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/check.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..831154b51b320fb16024f45136103421146b09fb Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/check.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd510f7a3243e5302799544b8c76f1eb4d9ae794 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/config.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d58b379a44f4b9a7efe76e7fb72af1451ba4b04a Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/config.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83575e8ebafecfdafd21324e3b8558e61602e083 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..825225e4b0fb757b9fe7b26a4a1b73c1c4bba504 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_egg_info.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_egg_info.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3eaa564a3d6c1a3f11a6dde6c2a46ca2009312bd Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_egg_info.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..731a3975d8e71b16696174831392ab55c5f2fc13 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17867a29a6a83aaf987b4f9b7bccf718ee0d3320 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ee113c4284bf5d81420e67d384bd5951d6ce9c8 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..daf4938781e63ad5d9343c32374d5fd37abb27e4 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5197099499d9a56a010468f052a45cd2b7bdbdb Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1497903239f6fd53ad839c8649dcadab6794a143 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/upload.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/upload.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45a64e8b36e2a94a37cfcc6c42f04726d1b48de1 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_distutils/command/__pycache__/upload.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist.py new file mode 100644 index 0000000000000000000000000000000000000000..014871d280edb57971aa1eb0fbe26862ce43bf53 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist.py @@ -0,0 +1,143 @@ +"""distutils.command.bdist + +Implements the Distutils 'bdist' command (create a built [binary] +distribution).""" + +import os +from distutils.core import Command +from distutils.errors import * +from distutils.util import get_platform + + +def show_formats(): + """Print list of available formats (arguments to "--format" option). + """ + from distutils.fancy_getopt import FancyGetopt + formats = [] + for format in bdist.format_commands: + formats.append(("formats=" + format, None, + bdist.format_command[format][1])) + pretty_printer = FancyGetopt(formats) + pretty_printer.print_help("List of available distribution formats:") + + +class bdist(Command): + + description = "create a built (binary) distribution" + + user_options = [('bdist-base=', 'b', + "temporary directory for creating built distributions"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), + ('formats=', None, + "formats for distribution (comma-separated list)"), + ('dist-dir=', 'd', + "directory to put final built distributions in " + "[default: dist]"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('owner=', 'u', + "Owner name used when creating a tar file" + " [default: current user]"), + ('group=', 'g', + "Group name used when creating a tar file" + " [default: current group]"), + ] + + boolean_options = ['skip-build'] + + help_options = [ + ('help-formats', None, + "lists available distribution formats", show_formats), + ] + + # The following commands do not take a format option from bdist + no_format_option = ('bdist_rpm',) + + # This won't do in reality: will need to distinguish RPM-ish Linux, + # Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS. + default_format = {'posix': 'gztar', + 'nt': 'zip'} + + # Establish the preferred order (for the --help-formats option). + format_commands = ['rpm', 'gztar', 'bztar', 'xztar', 'ztar', 'tar', + 'wininst', 'zip', 'msi'] + + # And the real information. + format_command = {'rpm': ('bdist_rpm', "RPM distribution"), + 'gztar': ('bdist_dumb', "gzip'ed tar file"), + 'bztar': ('bdist_dumb', "bzip2'ed tar file"), + 'xztar': ('bdist_dumb', "xz'ed tar file"), + 'ztar': ('bdist_dumb', "compressed tar file"), + 'tar': ('bdist_dumb', "tar file"), + 'wininst': ('bdist_wininst', + "Windows executable installer"), + 'zip': ('bdist_dumb', "ZIP file"), + 'msi': ('bdist_msi', "Microsoft Installer") + } + + + def initialize_options(self): + self.bdist_base = None + self.plat_name = None + self.formats = None + self.dist_dir = None + self.skip_build = 0 + self.group = None + self.owner = None + + def finalize_options(self): + # have to finalize 'plat_name' before 'bdist_base' + if self.plat_name is None: + if self.skip_build: + self.plat_name = get_platform() + else: + self.plat_name = self.get_finalized_command('build').plat_name + + # 'bdist_base' -- parent of per-built-distribution-format + # temporary directories (eg. we'll probably have + # "build/bdist./dumb", "build/bdist./rpm", etc.) + if self.bdist_base is None: + build_base = self.get_finalized_command('build').build_base + self.bdist_base = os.path.join(build_base, + 'bdist.' + self.plat_name) + + self.ensure_string_list('formats') + if self.formats is None: + try: + self.formats = [self.default_format[os.name]] + except KeyError: + raise DistutilsPlatformError( + "don't know how to create built distributions " + "on platform %s" % os.name) + + if self.dist_dir is None: + self.dist_dir = "dist" + + def run(self): + # Figure out which sub-commands we need to run. + commands = [] + for format in self.formats: + try: + commands.append(self.format_command[format][0]) + except KeyError: + raise DistutilsOptionError("invalid format '%s'" % format) + + # Reinitialize and run each command. + for i in range(len(self.formats)): + cmd_name = commands[i] + sub_cmd = self.reinitialize_command(cmd_name) + if cmd_name not in self.no_format_option: + sub_cmd.format = self.formats[i] + + # passing the owner and group names for tar archiving + if cmd_name == 'bdist_dumb': + sub_cmd.owner = self.owner + sub_cmd.group = self.group + + # If we're going to need to run this command again, tell it to + # keep its temporary files around so subsequent runs go faster. + if cmd_name in commands[i+1:]: + sub_cmd.keep_temp = 1 + self.run_command(cmd_name) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_dumb.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_dumb.py new file mode 100644 index 0000000000000000000000000000000000000000..f0d6b5b8cd8ab3ceb772a6e9f962bbce0bc8c1d2 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_dumb.py @@ -0,0 +1,123 @@ +"""distutils.command.bdist_dumb + +Implements the Distutils 'bdist_dumb' command (create a "dumb" built +distribution -- i.e., just an archive to be unpacked under $prefix or +$exec_prefix).""" + +import os +from distutils.core import Command +from distutils.util import get_platform +from distutils.dir_util import remove_tree, ensure_relative +from distutils.errors import * +from distutils.sysconfig import get_python_version +from distutils import log + +class bdist_dumb(Command): + + description = "create a \"dumb\" built distribution" + + user_options = [('bdist-dir=', 'd', + "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), + ('format=', 'f', + "archive format to create (tar, gztar, bztar, xztar, " + "ztar, zip)"), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('relative', None, + "build the archive using relative paths " + "(default: false)"), + ('owner=', 'u', + "Owner name used when creating a tar file" + " [default: current user]"), + ('group=', 'g', + "Group name used when creating a tar file" + " [default: current group]"), + ] + + boolean_options = ['keep-temp', 'skip-build', 'relative'] + + default_format = { 'posix': 'gztar', + 'nt': 'zip' } + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.format = None + self.keep_temp = 0 + self.dist_dir = None + self.skip_build = None + self.relative = 0 + self.owner = None + self.group = None + + def finalize_options(self): + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'dumb') + + if self.format is None: + try: + self.format = self.default_format[os.name] + except KeyError: + raise DistutilsPlatformError( + "don't know how to create dumb built distributions " + "on platform %s" % os.name) + + self.set_undefined_options('bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ('skip_build', 'skip_build')) + + def run(self): + if not self.skip_build: + self.run_command('build') + + install = self.reinitialize_command('install', reinit_subcommands=1) + install.root = self.bdist_dir + install.skip_build = self.skip_build + install.warn_dir = 0 + + log.info("installing to %s", self.bdist_dir) + self.run_command('install') + + # And make an archive relative to the root of the + # pseudo-installation tree. + archive_basename = "%s.%s" % (self.distribution.get_fullname(), + self.plat_name) + + pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) + if not self.relative: + archive_root = self.bdist_dir + else: + if (self.distribution.has_ext_modules() and + (install.install_base != install.install_platbase)): + raise DistutilsPlatformError( + "can't make a dumb built distribution where " + "base and platbase are different (%s, %s)" + % (repr(install.install_base), + repr(install.install_platbase))) + else: + archive_root = os.path.join(self.bdist_dir, + ensure_relative(install.install_base)) + + # Make the archive + filename = self.make_archive(pseudoinstall_root, + self.format, root_dir=archive_root, + owner=self.owner, group=self.group) + if self.distribution.has_ext_modules(): + pyversion = get_python_version() + else: + pyversion = 'any' + self.distribution.dist_files.append(('bdist_dumb', pyversion, + filename)) + + if not self.keep_temp: + remove_tree(self.bdist_dir, dry_run=self.dry_run) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_msi.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_msi.py new file mode 100644 index 0000000000000000000000000000000000000000..0863a1883e72058a8701a946c644276f047f837e --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_msi.py @@ -0,0 +1,749 @@ +# Copyright (C) 2005, 2006 Martin von Löwis +# Licensed to PSF under a Contributor Agreement. +# The bdist_wininst command proper +# based on bdist_wininst +""" +Implements the bdist_msi command. +""" + +import os +import sys +import warnings +from distutils.core import Command +from distutils.dir_util import remove_tree +from distutils.sysconfig import get_python_version +from distutils.version import StrictVersion +from distutils.errors import DistutilsOptionError +from distutils.util import get_platform +from distutils import log +import msilib +from msilib import schema, sequence, text +from msilib import Directory, Feature, Dialog, add_data + +class PyDialog(Dialog): + """Dialog class with a fixed layout: controls at the top, then a ruler, + then a list of buttons: back, next, cancel. Optionally a bitmap at the + left.""" + def __init__(self, *args, **kw): + """Dialog(database, name, x, y, w, h, attributes, title, first, + default, cancel, bitmap=true)""" + Dialog.__init__(self, *args) + ruler = self.h - 36 + bmwidth = 152*ruler/328 + #if kw.get("bitmap", True): + # self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") + self.line("BottomLine", 0, ruler, self.w, 0) + + def title(self, title): + "Set the title text of the dialog at the top." + # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, + # text, in VerdanaBold10 + self.text("Title", 15, 10, 320, 60, 0x30003, + r"{\VerdanaBold10}%s" % title) + + def back(self, title, next, name = "Back", active = 1): + """Add a back button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) + + def cancel(self, title, next, name = "Cancel", active = 1): + """Add a cancel button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) + + def next(self, title, next, name = "Next", active = 1): + """Add a Next button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) + + def xbutton(self, name, title, next, xpos): + """Add a button with a given title, the tab-next button, + its name in the Control table, giving its x position; the + y-position is aligned with the other buttons. + + Return the button, so that events can be associated""" + return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) + +class bdist_msi(Command): + + description = "create a Microsoft Installer (.msi) binary distribution" + + user_options = [('bdist-dir=', None, + "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('target-version=', None, + "require a specific python version" + + " on the target system"), + ('no-target-compile', 'c', + "do not compile .py to .pyc on the target system"), + ('no-target-optimize', 'o', + "do not compile .py to .pyo (optimized) " + "on the target system"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('install-script=', None, + "basename of installation script to be run after " + "installation or before deinstallation"), + ('pre-install-script=', None, + "Fully qualified filename of a script to be run before " + "any files are installed. This script need not be in the " + "distribution"), + ] + + boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', + 'skip-build'] + + all_versions = ['2.0', '2.1', '2.2', '2.3', '2.4', + '2.5', '2.6', '2.7', '2.8', '2.9', + '3.0', '3.1', '3.2', '3.3', '3.4', + '3.5', '3.6', '3.7', '3.8', '3.9'] + other_version = 'X' + + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + warnings.warn("bdist_msi command is deprecated since Python 3.9, " + "use bdist_wheel (wheel packages) instead", + DeprecationWarning, 2) + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.keep_temp = 0 + self.no_target_compile = 0 + self.no_target_optimize = 0 + self.target_version = None + self.dist_dir = None + self.skip_build = None + self.install_script = None + self.pre_install_script = None + self.versions = None + + def finalize_options(self): + self.set_undefined_options('bdist', ('skip_build', 'skip_build')) + + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'msi') + + short_version = get_python_version() + if (not self.target_version) and self.distribution.has_ext_modules(): + self.target_version = short_version + + if self.target_version: + self.versions = [self.target_version] + if not self.skip_build and self.distribution.has_ext_modules()\ + and self.target_version != short_version: + raise DistutilsOptionError( + "target version can only be %s, or the '--skip-build'" + " option must be specified" % (short_version,)) + else: + self.versions = list(self.all_versions) + + self.set_undefined_options('bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ) + + if self.pre_install_script: + raise DistutilsOptionError( + "the pre-install-script feature is not yet implemented") + + if self.install_script: + for script in self.distribution.scripts: + if self.install_script == os.path.basename(script): + break + else: + raise DistutilsOptionError( + "install_script '%s' not found in scripts" + % self.install_script) + self.install_script_key = None + + def run(self): + if not self.skip_build: + self.run_command('build') + + install = self.reinitialize_command('install', reinit_subcommands=1) + install.prefix = self.bdist_dir + install.skip_build = self.skip_build + install.warn_dir = 0 + + install_lib = self.reinitialize_command('install_lib') + # we do not want to include pyc or pyo files + install_lib.compile = 0 + install_lib.optimize = 0 + + if self.distribution.has_ext_modules(): + # If we are building an installer for a Python version other + # than the one we are currently running, then we need to ensure + # our build_lib reflects the other Python version rather than ours. + # Note that for target_version!=sys.version, we must have skipped the + # build step, so there is no issue with enforcing the build of this + # version. + target_version = self.target_version + if not target_version: + assert self.skip_build, "Should have already checked this" + target_version = '%d.%d' % sys.version_info[:2] + plat_specifier = ".%s-%s" % (self.plat_name, target_version) + build = self.get_finalized_command('build') + build.build_lib = os.path.join(build.build_base, + 'lib' + plat_specifier) + + log.info("installing to %s", self.bdist_dir) + install.ensure_finalized() + + # avoid warning of 'install_lib' about installing + # into a directory not in sys.path + sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) + + install.run() + + del sys.path[0] + + self.mkpath(self.dist_dir) + fullname = self.distribution.get_fullname() + installer_name = self.get_installer_filename(fullname) + installer_name = os.path.abspath(installer_name) + if os.path.exists(installer_name): os.unlink(installer_name) + + metadata = self.distribution.metadata + author = metadata.author + if not author: + author = metadata.maintainer + if not author: + author = "UNKNOWN" + version = metadata.get_version() + # ProductVersion must be strictly numeric + # XXX need to deal with prerelease versions + sversion = "%d.%d.%d" % StrictVersion(version).version + # Prefix ProductName with Python x.y, so that + # it sorts together with the other Python packages + # in Add-Remove-Programs (APR) + fullname = self.distribution.get_fullname() + if self.target_version: + product_name = "Python %s %s" % (self.target_version, fullname) + else: + product_name = "Python %s" % (fullname) + self.db = msilib.init_database(installer_name, schema, + product_name, msilib.gen_uuid(), + sversion, author) + msilib.add_tables(self.db, sequence) + props = [('DistVersion', version)] + email = metadata.author_email or metadata.maintainer_email + if email: + props.append(("ARPCONTACT", email)) + if metadata.url: + props.append(("ARPURLINFOABOUT", metadata.url)) + if props: + add_data(self.db, 'Property', props) + + self.add_find_python() + self.add_files() + self.add_scripts() + self.add_ui() + self.db.Commit() + + if hasattr(self.distribution, 'dist_files'): + tup = 'bdist_msi', self.target_version or 'any', fullname + self.distribution.dist_files.append(tup) + + if not self.keep_temp: + remove_tree(self.bdist_dir, dry_run=self.dry_run) + + def add_files(self): + db = self.db + cab = msilib.CAB("distfiles") + rootdir = os.path.abspath(self.bdist_dir) + + root = Directory(db, cab, None, rootdir, "TARGETDIR", "SourceDir") + f = Feature(db, "Python", "Python", "Everything", + 0, 1, directory="TARGETDIR") + + items = [(f, root, '')] + for version in self.versions + [self.other_version]: + target = "TARGETDIR" + version + name = default = "Python" + version + desc = "Everything" + if version is self.other_version: + title = "Python from another location" + level = 2 + else: + title = "Python %s from registry" % version + level = 1 + f = Feature(db, name, title, desc, 1, level, directory=target) + dir = Directory(db, cab, root, rootdir, target, default) + items.append((f, dir, version)) + db.Commit() + + seen = {} + for feature, dir, version in items: + todo = [dir] + while todo: + dir = todo.pop() + for file in os.listdir(dir.absolute): + afile = os.path.join(dir.absolute, file) + if os.path.isdir(afile): + short = "%s|%s" % (dir.make_short(file), file) + default = file + version + newdir = Directory(db, cab, dir, file, default, short) + todo.append(newdir) + else: + if not dir.component: + dir.start_component(dir.logical, feature, 0) + if afile not in seen: + key = seen[afile] = dir.add_file(file) + if file==self.install_script: + if self.install_script_key: + raise DistutilsOptionError( + "Multiple files with name %s" % file) + self.install_script_key = '[#%s]' % key + else: + key = seen[afile] + add_data(self.db, "DuplicateFile", + [(key + version, dir.component, key, None, dir.logical)]) + db.Commit() + cab.commit(db) + + def add_find_python(self): + """Adds code to the installer to compute the location of Python. + + Properties PYTHON.MACHINE.X.Y and PYTHON.USER.X.Y will be set from the + registry for each version of Python. + + Properties TARGETDIRX.Y will be set from PYTHON.USER.X.Y if defined, + else from PYTHON.MACHINE.X.Y. + + Properties PYTHONX.Y will be set to TARGETDIRX.Y\\python.exe""" + + start = 402 + for ver in self.versions: + install_path = r"SOFTWARE\Python\PythonCore\%s\InstallPath" % ver + machine_reg = "python.machine." + ver + user_reg = "python.user." + ver + machine_prop = "PYTHON.MACHINE." + ver + user_prop = "PYTHON.USER." + ver + machine_action = "PythonFromMachine" + ver + user_action = "PythonFromUser" + ver + exe_action = "PythonExe" + ver + target_dir_prop = "TARGETDIR" + ver + exe_prop = "PYTHON" + ver + if msilib.Win64: + # type: msidbLocatorTypeRawValue + msidbLocatorType64bit + Type = 2+16 + else: + Type = 2 + add_data(self.db, "RegLocator", + [(machine_reg, 2, install_path, None, Type), + (user_reg, 1, install_path, None, Type)]) + add_data(self.db, "AppSearch", + [(machine_prop, machine_reg), + (user_prop, user_reg)]) + add_data(self.db, "CustomAction", + [(machine_action, 51+256, target_dir_prop, "[" + machine_prop + "]"), + (user_action, 51+256, target_dir_prop, "[" + user_prop + "]"), + (exe_action, 51+256, exe_prop, "[" + target_dir_prop + "]\\python.exe"), + ]) + add_data(self.db, "InstallExecuteSequence", + [(machine_action, machine_prop, start), + (user_action, user_prop, start + 1), + (exe_action, None, start + 2), + ]) + add_data(self.db, "InstallUISequence", + [(machine_action, machine_prop, start), + (user_action, user_prop, start + 1), + (exe_action, None, start + 2), + ]) + add_data(self.db, "Condition", + [("Python" + ver, 0, "NOT TARGETDIR" + ver)]) + start += 4 + assert start < 500 + + def add_scripts(self): + if self.install_script: + start = 6800 + for ver in self.versions + [self.other_version]: + install_action = "install_script." + ver + exe_prop = "PYTHON" + ver + add_data(self.db, "CustomAction", + [(install_action, 50, exe_prop, self.install_script_key)]) + add_data(self.db, "InstallExecuteSequence", + [(install_action, "&Python%s=3" % ver, start)]) + start += 1 + # XXX pre-install scripts are currently refused in finalize_options() + # but if this feature is completed, it will also need to add + # entries for each version as the above code does + if self.pre_install_script: + scriptfn = os.path.join(self.bdist_dir, "preinstall.bat") + with open(scriptfn, "w") as f: + # The batch file will be executed with [PYTHON], so that %1 + # is the path to the Python interpreter; %0 will be the path + # of the batch file. + # rem =""" + # %1 %0 + # exit + # """ + # + f.write('rem ="""\n%1 %0\nexit\n"""\n') + with open(self.pre_install_script) as fin: + f.write(fin.read()) + add_data(self.db, "Binary", + [("PreInstall", msilib.Binary(scriptfn)) + ]) + add_data(self.db, "CustomAction", + [("PreInstall", 2, "PreInstall", None) + ]) + add_data(self.db, "InstallExecuteSequence", + [("PreInstall", "NOT Installed", 450)]) + + + def add_ui(self): + db = self.db + x = y = 50 + w = 370 + h = 300 + title = "[ProductName] Setup" + + # see "Dialog Style Bits" + modal = 3 # visible | modal + modeless = 1 # visible + track_disk_space = 32 + + # UI customization properties + add_data(db, "Property", + # See "DefaultUIFont Property" + [("DefaultUIFont", "DlgFont8"), + # See "ErrorDialog Style Bit" + ("ErrorDialog", "ErrorDlg"), + ("Progress1", "Install"), # modified in maintenance type dlg + ("Progress2", "installs"), + ("MaintenanceForm_Action", "Repair"), + # possible values: ALL, JUSTME + ("WhichUsers", "ALL") + ]) + + # Fonts, see "TextStyle Table" + add_data(db, "TextStyle", + [("DlgFont8", "Tahoma", 9, None, 0), + ("DlgFontBold8", "Tahoma", 8, None, 1), #bold + ("VerdanaBold10", "Verdana", 10, None, 1), + ("VerdanaRed9", "Verdana", 9, 255, 0), + ]) + + # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" + # Numbers indicate sequence; see sequence.py for how these action integrate + add_data(db, "InstallUISequence", + [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), + ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), + # In the user interface, assume all-users installation if privileged. + ("SelectFeaturesDlg", "Not Installed", 1230), + # XXX no support for resume installations yet + #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), + ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), + ("ProgressDlg", None, 1280)]) + + add_data(db, 'ActionText', text.ActionText) + add_data(db, 'UIText', text.UIText) + ##################################################################### + # Standard dialogs: FatalError, UserExit, ExitDialog + fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + fatal.title("[ProductName] Installer ended prematurely") + fatal.back("< Back", "Finish", active = 0) + fatal.cancel("Cancel", "Back", active = 0) + fatal.text("Description1", 15, 70, 320, 80, 0x30003, + "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.") + fatal.text("Description2", 15, 155, 320, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c=fatal.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Exit") + + user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + user_exit.title("[ProductName] Installer was interrupted") + user_exit.back("< Back", "Finish", active = 0) + user_exit.cancel("Cancel", "Back", active = 0) + user_exit.text("Description1", 15, 70, 320, 80, 0x30003, + "[ProductName] setup was interrupted. Your system has not been modified. " + "To install this program at a later time, please run the installation again.") + user_exit.text("Description2", 15, 155, 320, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c = user_exit.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Exit") + + exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + exit_dialog.title("Completing the [ProductName] Installer") + exit_dialog.back("< Back", "Finish", active = 0) + exit_dialog.cancel("Cancel", "Back", active = 0) + exit_dialog.text("Description", 15, 235, 320, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c = exit_dialog.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Return") + + ##################################################################### + # Required dialog: FilesInUse, ErrorDlg + inuse = PyDialog(db, "FilesInUse", + x, y, w, h, + 19, # KeepModeless|Modal|Visible + title, + "Retry", "Retry", "Retry", bitmap=False) + inuse.text("Title", 15, 6, 200, 15, 0x30003, + r"{\DlgFontBold8}Files in Use") + inuse.text("Description", 20, 23, 280, 20, 0x30003, + "Some files that need to be updated are currently in use.") + inuse.text("Text", 20, 55, 330, 50, 3, + "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.") + inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", + None, None, None) + c=inuse.back("Exit", "Ignore", name="Exit") + c.event("EndDialog", "Exit") + c=inuse.next("Ignore", "Retry", name="Ignore") + c.event("EndDialog", "Ignore") + c=inuse.cancel("Retry", "Exit", name="Retry") + c.event("EndDialog","Retry") + + # See "Error Dialog". See "ICE20" for the required names of the controls. + error = Dialog(db, "ErrorDlg", + 50, 10, 330, 101, + 65543, # Error|Minimize|Modal|Visible + title, + "ErrorText", None, None) + error.text("ErrorText", 50,9,280,48,3, "") + #error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) + error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") + error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") + error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") + error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") + error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") + error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") + error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") + + ##################################################################### + # Global "Query Cancel" dialog + cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, + "No", "No", "No") + cancel.text("Text", 48, 15, 194, 30, 3, + "Are you sure you want to cancel [ProductName] installation?") + #cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, + # "py.ico", None, None) + c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") + c.event("EndDialog", "Exit") + + c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") + c.event("EndDialog", "Return") + + ##################################################################### + # Global "Wait for costing" dialog + costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, + "Return", "Return", "Return") + costing.text("Text", 48, 15, 194, 30, 3, + "Please wait while the installer finishes determining your disk space requirements.") + c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) + c.event("EndDialog", "Exit") + + ##################################################################### + # Preparation dialog: no user input except cancellation + prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, + "Cancel", "Cancel", "Cancel") + prep.text("Description", 15, 70, 320, 40, 0x30003, + "Please wait while the Installer prepares to guide you through the installation.") + prep.title("Welcome to the [ProductName] Installer") + c=prep.text("ActionText", 15, 110, 320, 20, 0x30003, "Pondering...") + c.mapping("ActionText", "Text") + c=prep.text("ActionData", 15, 135, 320, 30, 0x30003, None) + c.mapping("ActionData", "Text") + prep.back("Back", None, active=0) + prep.next("Next", None, active=0) + c=prep.cancel("Cancel", None) + c.event("SpawnDialog", "CancelDlg") + + ##################################################################### + # Feature (Python directory) selection + seldlg = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal, title, + "Next", "Next", "Cancel") + seldlg.title("Select Python Installations") + + seldlg.text("Hint", 15, 30, 300, 20, 3, + "Select the Python locations where %s should be installed." + % self.distribution.get_fullname()) + + seldlg.back("< Back", None, active=0) + c = seldlg.next("Next >", "Cancel") + order = 1 + c.event("[TARGETDIR]", "[SourceDir]", ordering=order) + for version in self.versions + [self.other_version]: + order += 1 + c.event("[TARGETDIR]", "[TARGETDIR%s]" % version, + "FEATURE_SELECTED AND &Python%s=3" % version, + ordering=order) + c.event("SpawnWaitDialog", "WaitForCostingDlg", ordering=order + 1) + c.event("EndDialog", "Return", ordering=order + 2) + c = seldlg.cancel("Cancel", "Features") + c.event("SpawnDialog", "CancelDlg") + + c = seldlg.control("Features", "SelectionTree", 15, 60, 300, 120, 3, + "FEATURE", None, "PathEdit", None) + c.event("[FEATURE_SELECTED]", "1") + ver = self.other_version + install_other_cond = "FEATURE_SELECTED AND &Python%s=3" % ver + dont_install_other_cond = "FEATURE_SELECTED AND &Python%s<>3" % ver + + c = seldlg.text("Other", 15, 200, 300, 15, 3, + "Provide an alternate Python location") + c.condition("Enable", install_other_cond) + c.condition("Show", install_other_cond) + c.condition("Disable", dont_install_other_cond) + c.condition("Hide", dont_install_other_cond) + + c = seldlg.control("PathEdit", "PathEdit", 15, 215, 300, 16, 1, + "TARGETDIR" + ver, None, "Next", None) + c.condition("Enable", install_other_cond) + c.condition("Show", install_other_cond) + c.condition("Disable", dont_install_other_cond) + c.condition("Hide", dont_install_other_cond) + + ##################################################################### + # Disk cost + cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, + "OK", "OK", "OK", bitmap=False) + cost.text("Title", 15, 6, 200, 15, 0x30003, + r"{\DlgFontBold8}Disk Space Requirements") + cost.text("Description", 20, 20, 280, 20, 0x30003, + "The disk space required for the installation of the selected features.") + cost.text("Text", 20, 53, 330, 60, 3, + "The highlighted volumes (if any) do not have enough disk space " + "available for the currently selected features. You can either " + "remove some files from the highlighted volumes, or choose to " + "install less features onto local drive(s), or select different " + "destination drive(s).") + cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, + None, "{120}{70}{70}{70}{70}", None, None) + cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") + + ##################################################################### + # WhichUsers Dialog. Only available on NT, and for privileged users. + # This must be run before FindRelatedProducts, because that will + # take into account whether the previous installation was per-user + # or per-machine. We currently don't support going back to this + # dialog after "Next" was selected; to support this, we would need to + # find how to reset the ALLUSERS property, and how to re-run + # FindRelatedProducts. + # On Windows9x, the ALLUSERS property is ignored on the command line + # and in the Property table, but installer fails according to the documentation + # if a dialog attempts to set ALLUSERS. + whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, + "AdminInstall", "Next", "Cancel") + whichusers.title("Select whether to install [ProductName] for all users of this computer.") + # A radio group with two options: allusers, justme + g = whichusers.radiogroup("AdminInstall", 15, 60, 260, 50, 3, + "WhichUsers", "", "Next") + g.add("ALL", 0, 5, 150, 20, "Install for all users") + g.add("JUSTME", 0, 25, 150, 20, "Install just for me") + + whichusers.back("Back", None, active=0) + + c = whichusers.next("Next >", "Cancel") + c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) + c.event("EndDialog", "Return", ordering = 2) + + c = whichusers.cancel("Cancel", "AdminInstall") + c.event("SpawnDialog", "CancelDlg") + + ##################################################################### + # Installation Progress dialog (modeless) + progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, + "Cancel", "Cancel", "Cancel", bitmap=False) + progress.text("Title", 20, 15, 200, 15, 0x30003, + r"{\DlgFontBold8}[Progress1] [ProductName]") + progress.text("Text", 35, 65, 300, 30, 3, + "Please wait while the Installer [Progress2] [ProductName]. " + "This may take several minutes.") + progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") + + c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") + c.mapping("ActionText", "Text") + + #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) + #c.mapping("ActionData", "Text") + + c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, + None, "Progress done", None, None) + c.mapping("SetProgress", "Progress") + + progress.back("< Back", "Next", active=False) + progress.next("Next >", "Cancel", active=False) + progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg") + + ################################################################### + # Maintenance type: repair/uninstall + maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, + "Next", "Next", "Cancel") + maint.title("Welcome to the [ProductName] Setup Wizard") + maint.text("BodyText", 15, 63, 330, 42, 3, + "Select whether you want to repair or remove [ProductName].") + g=maint.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3, + "MaintenanceForm_Action", "", "Next") + #g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") + g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") + g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") + + maint.back("< Back", None, active=False) + c=maint.next("Finish", "Cancel") + # Change installation: Change progress dialog to "Change", then ask + # for feature selection + #c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) + #c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) + + # Reinstall: Change progress dialog to "Repair", then invoke reinstall + # Also set list of reinstalled features to "ALL" + c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5) + c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6) + c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7) + c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8) + + # Uninstall: Change progress to "Remove", then invoke uninstall + # Also set list of removed features to "ALL" + c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11) + c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12) + c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13) + c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14) + + # Close dialog when maintenance action scheduled + c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) + #c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) + + maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") + + def get_installer_filename(self, fullname): + # Factored out to allow overriding in subclasses + if self.target_version: + base_name = "%s.%s-py%s.msi" % (fullname, self.plat_name, + self.target_version) + else: + base_name = "%s.%s.msi" % (fullname, self.plat_name) + installer_name = os.path.join(self.dist_dir, base_name) + return installer_name diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_rpm.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_rpm.py new file mode 100644 index 0000000000000000000000000000000000000000..550cbfa1e28a2376fe1b4f994bce86b446c0916e --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_rpm.py @@ -0,0 +1,579 @@ +"""distutils.command.bdist_rpm + +Implements the Distutils 'bdist_rpm' command (create RPM source and binary +distributions).""" + +import subprocess, sys, os +from distutils.core import Command +from distutils.debug import DEBUG +from distutils.file_util import write_file +from distutils.errors import * +from distutils.sysconfig import get_python_version +from distutils import log + +class bdist_rpm(Command): + + description = "create an RPM distribution" + + user_options = [ + ('bdist-base=', None, + "base directory for creating built distributions"), + ('rpm-base=', None, + "base directory for creating RPMs (defaults to \"rpm\" under " + "--bdist-base; must be specified for RPM 2)"), + ('dist-dir=', 'd', + "directory to put final RPM files in " + "(and .spec files if --spec-only)"), + ('python=', None, + "path to Python interpreter to hard-code in the .spec file " + "(default: \"python\")"), + ('fix-python', None, + "hard-code the exact path to the current Python interpreter in " + "the .spec file"), + ('spec-only', None, + "only regenerate spec file"), + ('source-only', None, + "only generate source RPM"), + ('binary-only', None, + "only generate binary RPM"), + ('use-bzip2', None, + "use bzip2 instead of gzip to create source distribution"), + + # More meta-data: too RPM-specific to put in the setup script, + # but needs to go in the .spec file -- so we make these options + # to "bdist_rpm". The idea is that packagers would put this + # info in setup.cfg, although they are of course free to + # supply it on the command line. + ('distribution-name=', None, + "name of the (Linux) distribution to which this " + "RPM applies (*not* the name of the module distribution!)"), + ('group=', None, + "package classification [default: \"Development/Libraries\"]"), + ('release=', None, + "RPM release number"), + ('serial=', None, + "RPM serial number"), + ('vendor=', None, + "RPM \"vendor\" (eg. \"Joe Blow \") " + "[default: maintainer or author from setup script]"), + ('packager=', None, + "RPM packager (eg. \"Jane Doe \") " + "[default: vendor]"), + ('doc-files=', None, + "list of documentation files (space or comma-separated)"), + ('changelog=', None, + "RPM changelog"), + ('icon=', None, + "name of icon file"), + ('provides=', None, + "capabilities provided by this package"), + ('requires=', None, + "capabilities required by this package"), + ('conflicts=', None, + "capabilities which conflict with this package"), + ('build-requires=', None, + "capabilities required to build this package"), + ('obsoletes=', None, + "capabilities made obsolete by this package"), + ('no-autoreq', None, + "do not automatically calculate dependencies"), + + # Actions to take when building RPM + ('keep-temp', 'k', + "don't clean up RPM build directory"), + ('no-keep-temp', None, + "clean up RPM build directory [default]"), + ('use-rpm-opt-flags', None, + "compile with RPM_OPT_FLAGS when building from source RPM"), + ('no-rpm-opt-flags', None, + "do not pass any RPM CFLAGS to compiler"), + ('rpm3-mode', None, + "RPM 3 compatibility mode (default)"), + ('rpm2-mode', None, + "RPM 2 compatibility mode"), + + # Add the hooks necessary for specifying custom scripts + ('prep-script=', None, + "Specify a script for the PREP phase of RPM building"), + ('build-script=', None, + "Specify a script for the BUILD phase of RPM building"), + + ('pre-install=', None, + "Specify a script for the pre-INSTALL phase of RPM building"), + ('install-script=', None, + "Specify a script for the INSTALL phase of RPM building"), + ('post-install=', None, + "Specify a script for the post-INSTALL phase of RPM building"), + + ('pre-uninstall=', None, + "Specify a script for the pre-UNINSTALL phase of RPM building"), + ('post-uninstall=', None, + "Specify a script for the post-UNINSTALL phase of RPM building"), + + ('clean-script=', None, + "Specify a script for the CLEAN phase of RPM building"), + + ('verify-script=', None, + "Specify a script for the VERIFY phase of the RPM build"), + + # Allow a packager to explicitly force an architecture + ('force-arch=', None, + "Force an architecture onto the RPM build process"), + + ('quiet', 'q', + "Run the INSTALL phase of RPM building in quiet mode"), + ] + + boolean_options = ['keep-temp', 'use-rpm-opt-flags', 'rpm3-mode', + 'no-autoreq', 'quiet'] + + negative_opt = {'no-keep-temp': 'keep-temp', + 'no-rpm-opt-flags': 'use-rpm-opt-flags', + 'rpm2-mode': 'rpm3-mode'} + + + def initialize_options(self): + self.bdist_base = None + self.rpm_base = None + self.dist_dir = None + self.python = None + self.fix_python = None + self.spec_only = None + self.binary_only = None + self.source_only = None + self.use_bzip2 = None + + self.distribution_name = None + self.group = None + self.release = None + self.serial = None + self.vendor = None + self.packager = None + self.doc_files = None + self.changelog = None + self.icon = None + + self.prep_script = None + self.build_script = None + self.install_script = None + self.clean_script = None + self.verify_script = None + self.pre_install = None + self.post_install = None + self.pre_uninstall = None + self.post_uninstall = None + self.prep = None + self.provides = None + self.requires = None + self.conflicts = None + self.build_requires = None + self.obsoletes = None + + self.keep_temp = 0 + self.use_rpm_opt_flags = 1 + self.rpm3_mode = 1 + self.no_autoreq = 0 + + self.force_arch = None + self.quiet = 0 + + def finalize_options(self): + self.set_undefined_options('bdist', ('bdist_base', 'bdist_base')) + if self.rpm_base is None: + if not self.rpm3_mode: + raise DistutilsOptionError( + "you must specify --rpm-base in RPM 2 mode") + self.rpm_base = os.path.join(self.bdist_base, "rpm") + + if self.python is None: + if self.fix_python: + self.python = sys.executable + else: + self.python = "python3" + elif self.fix_python: + raise DistutilsOptionError( + "--python and --fix-python are mutually exclusive options") + + if os.name != 'posix': + raise DistutilsPlatformError("don't know how to create RPM " + "distributions on platform %s" % os.name) + if self.binary_only and self.source_only: + raise DistutilsOptionError( + "cannot supply both '--source-only' and '--binary-only'") + + # don't pass CFLAGS to pure python distributions + if not self.distribution.has_ext_modules(): + self.use_rpm_opt_flags = 0 + + self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) + self.finalize_package_data() + + def finalize_package_data(self): + self.ensure_string('group', "Development/Libraries") + self.ensure_string('vendor', + "%s <%s>" % (self.distribution.get_contact(), + self.distribution.get_contact_email())) + self.ensure_string('packager') + self.ensure_string_list('doc_files') + if isinstance(self.doc_files, list): + for readme in ('README', 'README.txt'): + if os.path.exists(readme) and readme not in self.doc_files: + self.doc_files.append(readme) + + self.ensure_string('release', "1") + self.ensure_string('serial') # should it be an int? + + self.ensure_string('distribution_name') + + self.ensure_string('changelog') + # Format changelog correctly + self.changelog = self._format_changelog(self.changelog) + + self.ensure_filename('icon') + + self.ensure_filename('prep_script') + self.ensure_filename('build_script') + self.ensure_filename('install_script') + self.ensure_filename('clean_script') + self.ensure_filename('verify_script') + self.ensure_filename('pre_install') + self.ensure_filename('post_install') + self.ensure_filename('pre_uninstall') + self.ensure_filename('post_uninstall') + + # XXX don't forget we punted on summaries and descriptions -- they + # should be handled here eventually! + + # Now *this* is some meta-data that belongs in the setup script... + self.ensure_string_list('provides') + self.ensure_string_list('requires') + self.ensure_string_list('conflicts') + self.ensure_string_list('build_requires') + self.ensure_string_list('obsoletes') + + self.ensure_string('force_arch') + + def run(self): + if DEBUG: + print("before _get_package_data():") + print("vendor =", self.vendor) + print("packager =", self.packager) + print("doc_files =", self.doc_files) + print("changelog =", self.changelog) + + # make directories + if self.spec_only: + spec_dir = self.dist_dir + self.mkpath(spec_dir) + else: + rpm_dir = {} + for d in ('SOURCES', 'SPECS', 'BUILD', 'RPMS', 'SRPMS'): + rpm_dir[d] = os.path.join(self.rpm_base, d) + self.mkpath(rpm_dir[d]) + spec_dir = rpm_dir['SPECS'] + + # Spec file goes into 'dist_dir' if '--spec-only specified', + # build/rpm. otherwise. + spec_path = os.path.join(spec_dir, + "%s.spec" % self.distribution.get_name()) + self.execute(write_file, + (spec_path, + self._make_spec_file()), + "writing '%s'" % spec_path) + + if self.spec_only: # stop if requested + return + + # Make a source distribution and copy to SOURCES directory with + # optional icon. + saved_dist_files = self.distribution.dist_files[:] + sdist = self.reinitialize_command('sdist') + if self.use_bzip2: + sdist.formats = ['bztar'] + else: + sdist.formats = ['gztar'] + self.run_command('sdist') + self.distribution.dist_files = saved_dist_files + + source = sdist.get_archive_files()[0] + source_dir = rpm_dir['SOURCES'] + self.copy_file(source, source_dir) + + if self.icon: + if os.path.exists(self.icon): + self.copy_file(self.icon, source_dir) + else: + raise DistutilsFileError( + "icon file '%s' does not exist" % self.icon) + + # build package + log.info("building RPMs") + rpm_cmd = ['rpmbuild'] + + if self.source_only: # what kind of RPMs? + rpm_cmd.append('-bs') + elif self.binary_only: + rpm_cmd.append('-bb') + else: + rpm_cmd.append('-ba') + rpm_cmd.extend(['--define', '__python %s' % self.python]) + if self.rpm3_mode: + rpm_cmd.extend(['--define', + '_topdir %s' % os.path.abspath(self.rpm_base)]) + if not self.keep_temp: + rpm_cmd.append('--clean') + + if self.quiet: + rpm_cmd.append('--quiet') + + rpm_cmd.append(spec_path) + # Determine the binary rpm names that should be built out of this spec + # file + # Note that some of these may not be really built (if the file + # list is empty) + nvr_string = "%{name}-%{version}-%{release}" + src_rpm = nvr_string + ".src.rpm" + non_src_rpm = "%{arch}/" + nvr_string + ".%{arch}.rpm" + q_cmd = r"rpm -q --qf '%s %s\n' --specfile '%s'" % ( + src_rpm, non_src_rpm, spec_path) + + out = os.popen(q_cmd) + try: + binary_rpms = [] + source_rpm = None + while True: + line = out.readline() + if not line: + break + l = line.strip().split() + assert(len(l) == 2) + binary_rpms.append(l[1]) + # The source rpm is named after the first entry in the spec file + if source_rpm is None: + source_rpm = l[0] + + status = out.close() + if status: + raise DistutilsExecError("Failed to execute: %s" % repr(q_cmd)) + + finally: + out.close() + + self.spawn(rpm_cmd) + + if not self.dry_run: + if self.distribution.has_ext_modules(): + pyversion = get_python_version() + else: + pyversion = 'any' + + if not self.binary_only: + srpm = os.path.join(rpm_dir['SRPMS'], source_rpm) + assert(os.path.exists(srpm)) + self.move_file(srpm, self.dist_dir) + filename = os.path.join(self.dist_dir, source_rpm) + self.distribution.dist_files.append( + ('bdist_rpm', pyversion, filename)) + + if not self.source_only: + for rpm in binary_rpms: + rpm = os.path.join(rpm_dir['RPMS'], rpm) + if os.path.exists(rpm): + self.move_file(rpm, self.dist_dir) + filename = os.path.join(self.dist_dir, + os.path.basename(rpm)) + self.distribution.dist_files.append( + ('bdist_rpm', pyversion, filename)) + + def _dist_path(self, path): + return os.path.join(self.dist_dir, os.path.basename(path)) + + def _make_spec_file(self): + """Generate the text of an RPM spec file and return it as a + list of strings (one per line). + """ + # definitions and headers + spec_file = [ + '%define name ' + self.distribution.get_name(), + '%define version ' + self.distribution.get_version().replace('-','_'), + '%define unmangled_version ' + self.distribution.get_version(), + '%define release ' + self.release.replace('-','_'), + '', + 'Summary: ' + self.distribution.get_description(), + ] + + # Workaround for #14443 which affects some RPM based systems such as + # RHEL6 (and probably derivatives) + vendor_hook = subprocess.getoutput('rpm --eval %{__os_install_post}') + # Generate a potential replacement value for __os_install_post (whilst + # normalizing the whitespace to simplify the test for whether the + # invocation of brp-python-bytecompile passes in __python): + vendor_hook = '\n'.join([' %s \\' % line.strip() + for line in vendor_hook.splitlines()]) + problem = "brp-python-bytecompile \\\n" + fixed = "brp-python-bytecompile %{__python} \\\n" + fixed_hook = vendor_hook.replace(problem, fixed) + if fixed_hook != vendor_hook: + spec_file.append('# Workaround for http://bugs.python.org/issue14443') + spec_file.append('%define __os_install_post ' + fixed_hook + '\n') + + # put locale summaries into spec file + # XXX not supported for now (hard to put a dictionary + # in a config file -- arg!) + #for locale in self.summaries.keys(): + # spec_file.append('Summary(%s): %s' % (locale, + # self.summaries[locale])) + + spec_file.extend([ + 'Name: %{name}', + 'Version: %{version}', + 'Release: %{release}',]) + + # XXX yuck! this filename is available from the "sdist" command, + # but only after it has run: and we create the spec file before + # running "sdist", in case of --spec-only. + if self.use_bzip2: + spec_file.append('Source0: %{name}-%{unmangled_version}.tar.bz2') + else: + spec_file.append('Source0: %{name}-%{unmangled_version}.tar.gz') + + spec_file.extend([ + 'License: ' + self.distribution.get_license(), + 'Group: ' + self.group, + 'BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot', + 'Prefix: %{_prefix}', ]) + + if not self.force_arch: + # noarch if no extension modules + if not self.distribution.has_ext_modules(): + spec_file.append('BuildArch: noarch') + else: + spec_file.append( 'BuildArch: %s' % self.force_arch ) + + for field in ('Vendor', + 'Packager', + 'Provides', + 'Requires', + 'Conflicts', + 'Obsoletes', + ): + val = getattr(self, field.lower()) + if isinstance(val, list): + spec_file.append('%s: %s' % (field, ' '.join(val))) + elif val is not None: + spec_file.append('%s: %s' % (field, val)) + + + if self.distribution.get_url() != 'UNKNOWN': + spec_file.append('Url: ' + self.distribution.get_url()) + + if self.distribution_name: + spec_file.append('Distribution: ' + self.distribution_name) + + if self.build_requires: + spec_file.append('BuildRequires: ' + + ' '.join(self.build_requires)) + + if self.icon: + spec_file.append('Icon: ' + os.path.basename(self.icon)) + + if self.no_autoreq: + spec_file.append('AutoReq: 0') + + spec_file.extend([ + '', + '%description', + self.distribution.get_long_description() + ]) + + # put locale descriptions into spec file + # XXX again, suppressed because config file syntax doesn't + # easily support this ;-( + #for locale in self.descriptions.keys(): + # spec_file.extend([ + # '', + # '%description -l ' + locale, + # self.descriptions[locale], + # ]) + + # rpm scripts + # figure out default build script + def_setup_call = "%s %s" % (self.python,os.path.basename(sys.argv[0])) + def_build = "%s build" % def_setup_call + if self.use_rpm_opt_flags: + def_build = 'env CFLAGS="$RPM_OPT_FLAGS" ' + def_build + + # insert contents of files + + # XXX this is kind of misleading: user-supplied options are files + # that we open and interpolate into the spec file, but the defaults + # are just text that we drop in as-is. Hmmm. + + install_cmd = ('%s install -O1 --root=$RPM_BUILD_ROOT ' + '--record=INSTALLED_FILES') % def_setup_call + + script_options = [ + ('prep', 'prep_script', "%setup -n %{name}-%{unmangled_version}"), + ('build', 'build_script', def_build), + ('install', 'install_script', install_cmd), + ('clean', 'clean_script', "rm -rf $RPM_BUILD_ROOT"), + ('verifyscript', 'verify_script', None), + ('pre', 'pre_install', None), + ('post', 'post_install', None), + ('preun', 'pre_uninstall', None), + ('postun', 'post_uninstall', None), + ] + + for (rpm_opt, attr, default) in script_options: + # Insert contents of file referred to, if no file is referred to + # use 'default' as contents of script + val = getattr(self, attr) + if val or default: + spec_file.extend([ + '', + '%' + rpm_opt,]) + if val: + with open(val) as f: + spec_file.extend(f.read().split('\n')) + else: + spec_file.append(default) + + + # files section + spec_file.extend([ + '', + '%files -f INSTALLED_FILES', + '%defattr(-,root,root)', + ]) + + if self.doc_files: + spec_file.append('%doc ' + ' '.join(self.doc_files)) + + if self.changelog: + spec_file.extend([ + '', + '%changelog',]) + spec_file.extend(self.changelog) + + return spec_file + + def _format_changelog(self, changelog): + """Format the changelog correctly and convert it to a list of strings + """ + if not changelog: + return changelog + new_changelog = [] + for line in changelog.strip().split('\n'): + line = line.strip() + if line[0] == '*': + new_changelog.extend(['', line]) + elif line[0] == '-': + new_changelog.append(line) + else: + new_changelog.append(' ' + line) + + # strip trailing newline inserted by first changelog entry + if not new_changelog[0]: + del new_changelog[0] + + return new_changelog diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_wininst.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_wininst.py new file mode 100644 index 0000000000000000000000000000000000000000..0e9ddaa21419e9581392d170a51dfcf53203d5e8 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/bdist_wininst.py @@ -0,0 +1,377 @@ +"""distutils.command.bdist_wininst + +Implements the Distutils 'bdist_wininst' command: create a windows installer +exe-program.""" + +import os +import sys +import warnings +from distutils.core import Command +from distutils.util import get_platform +from distutils.dir_util import remove_tree +from distutils.errors import * +from distutils.sysconfig import get_python_version +from distutils import log + +class bdist_wininst(Command): + + description = "create an executable installer for MS Windows" + + user_options = [('bdist-dir=', None, + "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('target-version=', None, + "require a specific python version" + + " on the target system"), + ('no-target-compile', 'c', + "do not compile .py to .pyc on the target system"), + ('no-target-optimize', 'o', + "do not compile .py to .pyo (optimized) " + "on the target system"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('bitmap=', 'b', + "bitmap to use for the installer instead of python-powered logo"), + ('title=', 't', + "title to display on the installer background instead of default"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('install-script=', None, + "basename of installation script to be run after " + "installation or before deinstallation"), + ('pre-install-script=', None, + "Fully qualified filename of a script to be run before " + "any files are installed. This script need not be in the " + "distribution"), + ('user-access-control=', None, + "specify Vista's UAC handling - 'none'/default=no " + "handling, 'auto'=use UAC if target Python installed for " + "all users, 'force'=always use UAC"), + ] + + boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', + 'skip-build'] + + # bpo-10945: bdist_wininst requires mbcs encoding only available on Windows + _unsupported = (sys.platform != "win32") + + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + warnings.warn("bdist_wininst command is deprecated since Python 3.8, " + "use bdist_wheel (wheel packages) instead", + DeprecationWarning, 2) + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.keep_temp = 0 + self.no_target_compile = 0 + self.no_target_optimize = 0 + self.target_version = None + self.dist_dir = None + self.bitmap = None + self.title = None + self.skip_build = None + self.install_script = None + self.pre_install_script = None + self.user_access_control = None + + + def finalize_options(self): + self.set_undefined_options('bdist', ('skip_build', 'skip_build')) + + if self.bdist_dir is None: + if self.skip_build and self.plat_name: + # If build is skipped and plat_name is overridden, bdist will + # not see the correct 'plat_name' - so set that up manually. + bdist = self.distribution.get_command_obj('bdist') + bdist.plat_name = self.plat_name + # next the command will be initialized using that name + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'wininst') + + if not self.target_version: + self.target_version = "" + + if not self.skip_build and self.distribution.has_ext_modules(): + short_version = get_python_version() + if self.target_version and self.target_version != short_version: + raise DistutilsOptionError( + "target version can only be %s, or the '--skip-build'" \ + " option must be specified" % (short_version,)) + self.target_version = short_version + + self.set_undefined_options('bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ) + + if self.install_script: + for script in self.distribution.scripts: + if self.install_script == os.path.basename(script): + break + else: + raise DistutilsOptionError( + "install_script '%s' not found in scripts" + % self.install_script) + + def run(self): + if (sys.platform != "win32" and + (self.distribution.has_ext_modules() or + self.distribution.has_c_libraries())): + raise DistutilsPlatformError \ + ("distribution contains extensions and/or C libraries; " + "must be compiled on a Windows 32 platform") + + if not self.skip_build: + self.run_command('build') + + install = self.reinitialize_command('install', reinit_subcommands=1) + install.root = self.bdist_dir + install.skip_build = self.skip_build + install.warn_dir = 0 + install.plat_name = self.plat_name + + install_lib = self.reinitialize_command('install_lib') + # we do not want to include pyc or pyo files + install_lib.compile = 0 + install_lib.optimize = 0 + + if self.distribution.has_ext_modules(): + # If we are building an installer for a Python version other + # than the one we are currently running, then we need to ensure + # our build_lib reflects the other Python version rather than ours. + # Note that for target_version!=sys.version, we must have skipped the + # build step, so there is no issue with enforcing the build of this + # version. + target_version = self.target_version + if not target_version: + assert self.skip_build, "Should have already checked this" + target_version = '%d.%d' % sys.version_info[:2] + plat_specifier = ".%s-%s" % (self.plat_name, target_version) + build = self.get_finalized_command('build') + build.build_lib = os.path.join(build.build_base, + 'lib' + plat_specifier) + + # Use a custom scheme for the zip-file, because we have to decide + # at installation time which scheme to use. + for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): + value = key.upper() + if key == 'headers': + value = value + '/Include/$dist_name' + setattr(install, + 'install_' + key, + value) + + log.info("installing to %s", self.bdist_dir) + install.ensure_finalized() + + # avoid warning of 'install_lib' about installing + # into a directory not in sys.path + sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) + + install.run() + + del sys.path[0] + + # And make an archive relative to the root of the + # pseudo-installation tree. + from tempfile import mktemp + archive_basename = mktemp() + fullname = self.distribution.get_fullname() + arcname = self.make_archive(archive_basename, "zip", + root_dir=self.bdist_dir) + # create an exe containing the zip-file + self.create_exe(arcname, fullname, self.bitmap) + if self.distribution.has_ext_modules(): + pyversion = get_python_version() + else: + pyversion = 'any' + self.distribution.dist_files.append(('bdist_wininst', pyversion, + self.get_installer_filename(fullname))) + # remove the zip-file again + log.debug("removing temporary file '%s'", arcname) + os.remove(arcname) + + if not self.keep_temp: + remove_tree(self.bdist_dir, dry_run=self.dry_run) + + def get_inidata(self): + # Return data describing the installation. + lines = [] + metadata = self.distribution.metadata + + # Write the [metadata] section. + lines.append("[metadata]") + + # 'info' will be displayed in the installer's dialog box, + # describing the items to be installed. + info = (metadata.long_description or '') + '\n' + + # Escape newline characters + def escape(s): + return s.replace("\n", "\\n") + + for name in ["author", "author_email", "description", "maintainer", + "maintainer_email", "name", "url", "version"]: + data = getattr(metadata, name, "") + if data: + info = info + ("\n %s: %s" % \ + (name.capitalize(), escape(data))) + lines.append("%s=%s" % (name, escape(data))) + + # The [setup] section contains entries controlling + # the installer runtime. + lines.append("\n[Setup]") + if self.install_script: + lines.append("install_script=%s" % self.install_script) + lines.append("info=%s" % escape(info)) + lines.append("target_compile=%d" % (not self.no_target_compile)) + lines.append("target_optimize=%d" % (not self.no_target_optimize)) + if self.target_version: + lines.append("target_version=%s" % self.target_version) + if self.user_access_control: + lines.append("user_access_control=%s" % self.user_access_control) + + title = self.title or self.distribution.get_fullname() + lines.append("title=%s" % escape(title)) + import time + import distutils + build_info = "Built %s with distutils-%s" % \ + (time.ctime(time.time()), distutils.__version__) + lines.append("build_info=%s" % build_info) + return "\n".join(lines) + + def create_exe(self, arcname, fullname, bitmap=None): + import struct + + self.mkpath(self.dist_dir) + + cfgdata = self.get_inidata() + + installer_name = self.get_installer_filename(fullname) + self.announce("creating %s" % installer_name) + + if bitmap: + with open(bitmap, "rb") as f: + bitmapdata = f.read() + bitmaplen = len(bitmapdata) + else: + bitmaplen = 0 + + with open(installer_name, "wb") as file: + file.write(self.get_exe_bytes()) + if bitmap: + file.write(bitmapdata) + + # Convert cfgdata from unicode to ascii, mbcs encoded + if isinstance(cfgdata, str): + cfgdata = cfgdata.encode("mbcs") + + # Append the pre-install script + cfgdata = cfgdata + b"\0" + if self.pre_install_script: + # We need to normalize newlines, so we open in text mode and + # convert back to bytes. "latin-1" simply avoids any possible + # failures. + with open(self.pre_install_script, "r", + encoding="latin-1") as script: + script_data = script.read().encode("latin-1") + cfgdata = cfgdata + script_data + b"\n\0" + else: + # empty pre-install script + cfgdata = cfgdata + b"\0" + file.write(cfgdata) + + # The 'magic number' 0x1234567B is used to make sure that the + # binary layout of 'cfgdata' is what the wininst.exe binary + # expects. If the layout changes, increment that number, make + # the corresponding changes to the wininst.exe sources, and + # recompile them. + header = struct.pack("' under the base build directory. We only use one of + # them for a given distribution, though -- + if self.build_purelib is None: + self.build_purelib = os.path.join(self.build_base, 'lib') + if self.build_platlib is None: + self.build_platlib = os.path.join(self.build_base, + 'lib' + plat_specifier) + + # 'build_lib' is the actual directory that we will use for this + # particular module distribution -- if user didn't supply it, pick + # one of 'build_purelib' or 'build_platlib'. + if self.build_lib is None: + if self.distribution.has_ext_modules(): + self.build_lib = self.build_platlib + else: + self.build_lib = self.build_purelib + + # 'build_temp' -- temporary directory for compiler turds, + # "build/temp." + if self.build_temp is None: + self.build_temp = os.path.join(self.build_base, + 'temp' + plat_specifier) + if self.build_scripts is None: + self.build_scripts = os.path.join(self.build_base, + 'scripts-%d.%d' % sys.version_info[:2]) + + if self.executable is None and sys.executable: + self.executable = os.path.normpath(sys.executable) + + if isinstance(self.parallel, str): + try: + self.parallel = int(self.parallel) + except ValueError: + raise DistutilsOptionError("parallel should be an integer") + + def run(self): + # Run all relevant sub-commands. This will be some subset of: + # - build_py - pure Python modules + # - build_clib - standalone C libraries + # - build_ext - Python extensions + # - build_scripts - (Python) scripts + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + + # -- Predicates for the sub-command list --------------------------- + + def has_pure_modules(self): + return self.distribution.has_pure_modules() + + def has_c_libraries(self): + return self.distribution.has_c_libraries() + + def has_ext_modules(self): + return self.distribution.has_ext_modules() + + def has_scripts(self): + return self.distribution.has_scripts() + + + sub_commands = [('build_py', has_pure_modules), + ('build_clib', has_c_libraries), + ('build_ext', has_ext_modules), + ('build_scripts', has_scripts), + ] diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/build_clib.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_clib.py new file mode 100644 index 0000000000000000000000000000000000000000..3e20ef23cd81e0d4fb54898f2b642882d3d0d5ef --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_clib.py @@ -0,0 +1,209 @@ +"""distutils.command.build_clib + +Implements the Distutils 'build_clib' command, to build a C/C++ library +that is included in the module distribution and needed by an extension +module.""" + + +# XXX this module has *lots* of code ripped-off quite transparently from +# build_ext.py -- not surprisingly really, as the work required to build +# a static library from a collection of C source files is not really all +# that different from what's required to build a shared object file from +# a collection of C source files. Nevertheless, I haven't done the +# necessary refactoring to account for the overlap in code between the +# two modules, mainly because a number of subtle details changed in the +# cut 'n paste. Sigh. + +import os +from distutils.core import Command +from distutils.errors import * +from distutils.sysconfig import customize_compiler +from distutils import log + +def show_compilers(): + from distutils.ccompiler import show_compilers + show_compilers() + + +class build_clib(Command): + + description = "build C/C++ libraries used by Python extensions" + + user_options = [ + ('build-clib=', 'b', + "directory to build C/C++ libraries to"), + ('build-temp=', 't', + "directory to put temporary build by-products"), + ('debug', 'g', + "compile with debugging information"), + ('force', 'f', + "forcibly build everything (ignore file timestamps)"), + ('compiler=', 'c', + "specify the compiler type"), + ] + + boolean_options = ['debug', 'force'] + + help_options = [ + ('help-compiler', None, + "list available compilers", show_compilers), + ] + + def initialize_options(self): + self.build_clib = None + self.build_temp = None + + # List of libraries to build + self.libraries = None + + # Compilation options for all libraries + self.include_dirs = None + self.define = None + self.undef = None + self.debug = None + self.force = 0 + self.compiler = None + + + def finalize_options(self): + # This might be confusing: both build-clib and build-temp default + # to build-temp as defined by the "build" command. This is because + # I think that C libraries are really just temporary build + # by-products, at least from the point of view of building Python + # extensions -- but I want to keep my options open. + self.set_undefined_options('build', + ('build_temp', 'build_clib'), + ('build_temp', 'build_temp'), + ('compiler', 'compiler'), + ('debug', 'debug'), + ('force', 'force')) + + self.libraries = self.distribution.libraries + if self.libraries: + self.check_library_list(self.libraries) + + if self.include_dirs is None: + self.include_dirs = self.distribution.include_dirs or [] + if isinstance(self.include_dirs, str): + self.include_dirs = self.include_dirs.split(os.pathsep) + + # XXX same as for build_ext -- what about 'self.define' and + # 'self.undef' ? + + + def run(self): + if not self.libraries: + return + + # Yech -- this is cut 'n pasted from build_ext.py! + from distutils.ccompiler import new_compiler + self.compiler = new_compiler(compiler=self.compiler, + dry_run=self.dry_run, + force=self.force) + customize_compiler(self.compiler) + + if self.include_dirs is not None: + self.compiler.set_include_dirs(self.include_dirs) + if self.define is not None: + # 'define' option is a list of (name,value) tuples + for (name,value) in self.define: + self.compiler.define_macro(name, value) + if self.undef is not None: + for macro in self.undef: + self.compiler.undefine_macro(macro) + + self.build_libraries(self.libraries) + + + def check_library_list(self, libraries): + """Ensure that the list of libraries is valid. + + `library` is presumably provided as a command option 'libraries'. + This method checks that it is a list of 2-tuples, where the tuples + are (library_name, build_info_dict). + + Raise DistutilsSetupError if the structure is invalid anywhere; + just returns otherwise. + """ + if not isinstance(libraries, list): + raise DistutilsSetupError( + "'libraries' option must be a list of tuples") + + for lib in libraries: + if not isinstance(lib, tuple) and len(lib) != 2: + raise DistutilsSetupError( + "each element of 'libraries' must a 2-tuple") + + name, build_info = lib + + if not isinstance(name, str): + raise DistutilsSetupError( + "first element of each tuple in 'libraries' " + "must be a string (the library name)") + + if '/' in name or (os.sep != '/' and os.sep in name): + raise DistutilsSetupError("bad library name '%s': " + "may not contain directory separators" % lib[0]) + + if not isinstance(build_info, dict): + raise DistutilsSetupError( + "second element of each tuple in 'libraries' " + "must be a dictionary (build info)") + + + def get_library_names(self): + # Assume the library list is valid -- 'check_library_list()' is + # called from 'finalize_options()', so it should be! + if not self.libraries: + return None + + lib_names = [] + for (lib_name, build_info) in self.libraries: + lib_names.append(lib_name) + return lib_names + + + def get_source_files(self): + self.check_library_list(self.libraries) + filenames = [] + for (lib_name, build_info) in self.libraries: + sources = build_info.get('sources') + if sources is None or not isinstance(sources, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % lib_name) + + filenames.extend(sources) + return filenames + + + def build_libraries(self, libraries): + for (lib_name, build_info) in libraries: + sources = build_info.get('sources') + if sources is None or not isinstance(sources, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % lib_name) + sources = list(sources) + + log.info("building '%s' library", lib_name) + + # First, compile the source code to object files in the library + # directory. (This should probably change to putting object + # files in a temporary build directory.) + macros = build_info.get('macros') + include_dirs = build_info.get('include_dirs') + objects = self.compiler.compile(sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug) + + # Now "link" the object files together into a static library. + # (On Unix at least, this isn't really linking -- it just + # builds an archive. Whatever.) + self.compiler.create_static_lib(objects, lib_name, + output_dir=self.build_clib, + debug=self.debug) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/build_ext.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_ext.py new file mode 100644 index 0000000000000000000000000000000000000000..22628baf90f1ae93033d2f7d06c7c116b695a5ee --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_ext.py @@ -0,0 +1,757 @@ +"""distutils.command.build_ext + +Implements the Distutils 'build_ext' command, for building extension +modules (currently limited to C extensions, should accommodate C++ +extensions ASAP).""" + +import contextlib +import os +import re +import sys +from distutils.core import Command +from distutils.errors import * +from distutils.sysconfig import customize_compiler, get_python_version +from distutils.sysconfig import get_config_h_filename +from distutils.dep_util import newer_group +from distutils.extension import Extension +from distutils.util import get_platform +from distutils import log +from . import py37compat + +from site import USER_BASE + +# An extension name is just a dot-separated list of Python NAMEs (ie. +# the same as a fully-qualified module name). +extension_name_re = re.compile \ + (r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$') + + +def show_compilers (): + from distutils.ccompiler import show_compilers + show_compilers() + + +class build_ext(Command): + + description = "build C/C++ extensions (compile/link to build directory)" + + # XXX thoughts on how to deal with complex command-line options like + # these, i.e. how to make it so fancy_getopt can suck them off the + # command line and make it look like setup.py defined the appropriate + # lists of tuples of what-have-you. + # - each command needs a callback to process its command-line options + # - Command.__init__() needs access to its share of the whole + # command line (must ultimately come from + # Distribution.parse_command_line()) + # - it then calls the current command class' option-parsing + # callback to deal with weird options like -D, which have to + # parse the option text and churn out some custom data + # structure + # - that data structure (in this case, a list of 2-tuples) + # will then be present in the command object by the time + # we get to finalize_options() (i.e. the constructor + # takes care of both command-line and client options + # in between initialize_options() and finalize_options()) + + sep_by = " (separated by '%s')" % os.pathsep + user_options = [ + ('build-lib=', 'b', + "directory for compiled extension modules"), + ('build-temp=', 't', + "directory for temporary files (build by-products)"), + ('plat-name=', 'p', + "platform name to cross-compile for, if supported " + "(default: %s)" % get_platform()), + ('inplace', 'i', + "ignore build-lib and put compiled extensions into the source " + + "directory alongside your pure Python modules"), + ('include-dirs=', 'I', + "list of directories to search for header files" + sep_by), + ('define=', 'D', + "C preprocessor macros to define"), + ('undef=', 'U', + "C preprocessor macros to undefine"), + ('libraries=', 'l', + "external C libraries to link with"), + ('library-dirs=', 'L', + "directories to search for external C libraries" + sep_by), + ('rpath=', 'R', + "directories to search for shared C libraries at runtime"), + ('link-objects=', 'O', + "extra explicit link objects to include in the link"), + ('debug', 'g', + "compile/link with debugging information"), + ('force', 'f', + "forcibly build everything (ignore file timestamps)"), + ('compiler=', 'c', + "specify the compiler type"), + ('parallel=', 'j', + "number of parallel build jobs"), + ('swig-cpp', None, + "make SWIG create C++ files (default is C)"), + ('swig-opts=', None, + "list of SWIG command line options"), + ('swig=', None, + "path to the SWIG executable"), + ('user', None, + "add user include, library and rpath") + ] + + boolean_options = ['inplace', 'debug', 'force', 'swig-cpp', 'user'] + + help_options = [ + ('help-compiler', None, + "list available compilers", show_compilers), + ] + + def initialize_options(self): + self.extensions = None + self.build_lib = None + self.plat_name = None + self.build_temp = None + self.inplace = 0 + self.package = None + + self.include_dirs = None + self.define = None + self.undef = None + self.libraries = None + self.library_dirs = None + self.rpath = None + self.link_objects = None + self.debug = None + self.force = None + self.compiler = None + self.swig = None + self.swig_cpp = None + self.swig_opts = None + self.user = None + self.parallel = None + + def finalize_options(self): + from distutils import sysconfig + + self.set_undefined_options('build', + ('build_lib', 'build_lib'), + ('build_temp', 'build_temp'), + ('compiler', 'compiler'), + ('debug', 'debug'), + ('force', 'force'), + ('parallel', 'parallel'), + ('plat_name', 'plat_name'), + ) + + if self.package is None: + self.package = self.distribution.ext_package + + self.extensions = self.distribution.ext_modules + + # Make sure Python's include directories (for Python.h, pyconfig.h, + # etc.) are in the include search path. + py_include = sysconfig.get_python_inc() + plat_py_include = sysconfig.get_python_inc(plat_specific=1) + if self.include_dirs is None: + self.include_dirs = self.distribution.include_dirs or [] + if isinstance(self.include_dirs, str): + self.include_dirs = self.include_dirs.split(os.pathsep) + + # If in a virtualenv, add its include directory + # Issue 16116 + if sys.exec_prefix != sys.base_exec_prefix: + self.include_dirs.append(os.path.join(sys.exec_prefix, 'include')) + + # Put the Python "system" include dir at the end, so that + # any local include dirs take precedence. + self.include_dirs.extend(py_include.split(os.path.pathsep)) + if plat_py_include != py_include: + self.include_dirs.extend( + plat_py_include.split(os.path.pathsep)) + + self.ensure_string_list('libraries') + self.ensure_string_list('link_objects') + + # Life is easier if we're not forever checking for None, so + # simplify these options to empty lists if unset + if self.libraries is None: + self.libraries = [] + if self.library_dirs is None: + self.library_dirs = [] + elif isinstance(self.library_dirs, str): + self.library_dirs = self.library_dirs.split(os.pathsep) + + if self.rpath is None: + self.rpath = [] + elif isinstance(self.rpath, str): + self.rpath = self.rpath.split(os.pathsep) + + # for extensions under windows use different directories + # for Release and Debug builds. + # also Python's library directory must be appended to library_dirs + if os.name == 'nt': + # the 'libs' directory is for binary installs - we assume that + # must be the *native* platform. But we don't really support + # cross-compiling via a binary install anyway, so we let it go. + self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs')) + if sys.base_exec_prefix != sys.prefix: # Issue 16116 + self.library_dirs.append(os.path.join(sys.base_exec_prefix, 'libs')) + if self.debug: + self.build_temp = os.path.join(self.build_temp, "Debug") + else: + self.build_temp = os.path.join(self.build_temp, "Release") + + # Append the source distribution include and library directories, + # this allows distutils on windows to work in the source tree + self.include_dirs.append(os.path.dirname(get_config_h_filename())) + _sys_home = getattr(sys, '_home', None) + if _sys_home: + self.library_dirs.append(_sys_home) + + # Use the .lib files for the correct architecture + if self.plat_name == 'win32': + suffix = 'win32' + else: + # win-amd64 + suffix = self.plat_name[4:] + new_lib = os.path.join(sys.exec_prefix, 'PCbuild') + if suffix: + new_lib = os.path.join(new_lib, suffix) + self.library_dirs.append(new_lib) + + # For extensions under Cygwin, Python's library directory must be + # appended to library_dirs + if sys.platform[:6] == 'cygwin': + if not sysconfig.python_build: + # building third party extensions + self.library_dirs.append(os.path.join(sys.prefix, "lib", + "python" + get_python_version(), + "config")) + else: + # building python standard extensions + self.library_dirs.append('.') + + # For building extensions with a shared Python library, + # Python's library directory must be appended to library_dirs + # See Issues: #1600860, #4366 + if (sysconfig.get_config_var('Py_ENABLE_SHARED')): + if not sysconfig.python_build: + # building third party extensions + self.library_dirs.append(sysconfig.get_config_var('LIBDIR')) + else: + # building python standard extensions + self.library_dirs.append('.') + + # The argument parsing will result in self.define being a string, but + # it has to be a list of 2-tuples. All the preprocessor symbols + # specified by the 'define' option will be set to '1'. Multiple + # symbols can be separated with commas. + + if self.define: + defines = self.define.split(',') + self.define = [(symbol, '1') for symbol in defines] + + # The option for macros to undefine is also a string from the + # option parsing, but has to be a list. Multiple symbols can also + # be separated with commas here. + if self.undef: + self.undef = self.undef.split(',') + + if self.swig_opts is None: + self.swig_opts = [] + else: + self.swig_opts = self.swig_opts.split(' ') + + # Finally add the user include and library directories if requested + if self.user: + user_include = os.path.join(USER_BASE, "include") + user_lib = os.path.join(USER_BASE, "lib") + if os.path.isdir(user_include): + self.include_dirs.append(user_include) + if os.path.isdir(user_lib): + self.library_dirs.append(user_lib) + self.rpath.append(user_lib) + + if isinstance(self.parallel, str): + try: + self.parallel = int(self.parallel) + except ValueError: + raise DistutilsOptionError("parallel should be an integer") + + def run(self): + from distutils.ccompiler import new_compiler + + # 'self.extensions', as supplied by setup.py, is a list of + # Extension instances. See the documentation for Extension (in + # distutils.extension) for details. + # + # For backwards compatibility with Distutils 0.8.2 and earlier, we + # also allow the 'extensions' list to be a list of tuples: + # (ext_name, build_info) + # where build_info is a dictionary containing everything that + # Extension instances do except the name, with a few things being + # differently named. We convert these 2-tuples to Extension + # instances as needed. + + if not self.extensions: + return + + # If we were asked to build any C/C++ libraries, make sure that the + # directory where we put them is in the library search path for + # linking extensions. + if self.distribution.has_c_libraries(): + build_clib = self.get_finalized_command('build_clib') + self.libraries.extend(build_clib.get_library_names() or []) + self.library_dirs.append(build_clib.build_clib) + + # Setup the CCompiler object that we'll use to do all the + # compiling and linking + self.compiler = new_compiler(compiler=self.compiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force) + customize_compiler(self.compiler) + # If we are cross-compiling, init the compiler now (if we are not + # cross-compiling, init would not hurt, but people may rely on + # late initialization of compiler even if they shouldn't...) + if os.name == 'nt' and self.plat_name != get_platform(): + self.compiler.initialize(self.plat_name) + + # And make sure that any compile/link-related options (which might + # come from the command-line or from the setup script) are set in + # that CCompiler object -- that way, they automatically apply to + # all compiling and linking done here. + if self.include_dirs is not None: + self.compiler.set_include_dirs(self.include_dirs) + if self.define is not None: + # 'define' option is a list of (name,value) tuples + for (name, value) in self.define: + self.compiler.define_macro(name, value) + if self.undef is not None: + for macro in self.undef: + self.compiler.undefine_macro(macro) + if self.libraries is not None: + self.compiler.set_libraries(self.libraries) + if self.library_dirs is not None: + self.compiler.set_library_dirs(self.library_dirs) + if self.rpath is not None: + self.compiler.set_runtime_library_dirs(self.rpath) + if self.link_objects is not None: + self.compiler.set_link_objects(self.link_objects) + + # Now actually compile and link everything. + self.build_extensions() + + def check_extensions_list(self, extensions): + """Ensure that the list of extensions (presumably provided as a + command option 'extensions') is valid, i.e. it is a list of + Extension objects. We also support the old-style list of 2-tuples, + where the tuples are (ext_name, build_info), which are converted to + Extension instances here. + + Raise DistutilsSetupError if the structure is invalid anywhere; + just returns otherwise. + """ + if not isinstance(extensions, list): + raise DistutilsSetupError( + "'ext_modules' option must be a list of Extension instances") + + for i, ext in enumerate(extensions): + if isinstance(ext, Extension): + continue # OK! (assume type-checking done + # by Extension constructor) + + if not isinstance(ext, tuple) or len(ext) != 2: + raise DistutilsSetupError( + "each element of 'ext_modules' option must be an " + "Extension instance or 2-tuple") + + ext_name, build_info = ext + + log.warn("old-style (ext_name, build_info) tuple found in " + "ext_modules for extension '%s' " + "-- please convert to Extension instance", ext_name) + + if not (isinstance(ext_name, str) and + extension_name_re.match(ext_name)): + raise DistutilsSetupError( + "first element of each tuple in 'ext_modules' " + "must be the extension name (a string)") + + if not isinstance(build_info, dict): + raise DistutilsSetupError( + "second element of each tuple in 'ext_modules' " + "must be a dictionary (build info)") + + # OK, the (ext_name, build_info) dict is type-safe: convert it + # to an Extension instance. + ext = Extension(ext_name, build_info['sources']) + + # Easy stuff: one-to-one mapping from dict elements to + # instance attributes. + for key in ('include_dirs', 'library_dirs', 'libraries', + 'extra_objects', 'extra_compile_args', + 'extra_link_args'): + val = build_info.get(key) + if val is not None: + setattr(ext, key, val) + + # Medium-easy stuff: same syntax/semantics, different names. + ext.runtime_library_dirs = build_info.get('rpath') + if 'def_file' in build_info: + log.warn("'def_file' element of build info dict " + "no longer supported") + + # Non-trivial stuff: 'macros' split into 'define_macros' + # and 'undef_macros'. + macros = build_info.get('macros') + if macros: + ext.define_macros = [] + ext.undef_macros = [] + for macro in macros: + if not (isinstance(macro, tuple) and len(macro) in (1, 2)): + raise DistutilsSetupError( + "'macros' element of build info dict " + "must be 1- or 2-tuple") + if len(macro) == 1: + ext.undef_macros.append(macro[0]) + elif len(macro) == 2: + ext.define_macros.append(macro) + + extensions[i] = ext + + def get_source_files(self): + self.check_extensions_list(self.extensions) + filenames = [] + + # Wouldn't it be neat if we knew the names of header files too... + for ext in self.extensions: + filenames.extend(ext.sources) + return filenames + + def get_outputs(self): + # Sanity check the 'extensions' list -- can't assume this is being + # done in the same run as a 'build_extensions()' call (in fact, we + # can probably assume that it *isn't*!). + self.check_extensions_list(self.extensions) + + # And build the list of output (built) filenames. Note that this + # ignores the 'inplace' flag, and assumes everything goes in the + # "build" tree. + outputs = [] + for ext in self.extensions: + outputs.append(self.get_ext_fullpath(ext.name)) + return outputs + + def build_extensions(self): + # First, sanity-check the 'extensions' list + self.check_extensions_list(self.extensions) + if self.parallel: + self._build_extensions_parallel() + else: + self._build_extensions_serial() + + def _build_extensions_parallel(self): + workers = self.parallel + if self.parallel is True: + workers = os.cpu_count() # may return None + try: + from concurrent.futures import ThreadPoolExecutor + except ImportError: + workers = None + + if workers is None: + self._build_extensions_serial() + return + + with ThreadPoolExecutor(max_workers=workers) as executor: + futures = [executor.submit(self.build_extension, ext) + for ext in self.extensions] + for ext, fut in zip(self.extensions, futures): + with self._filter_build_errors(ext): + fut.result() + + def _build_extensions_serial(self): + for ext in self.extensions: + with self._filter_build_errors(ext): + self.build_extension(ext) + + @contextlib.contextmanager + def _filter_build_errors(self, ext): + try: + yield + except (CCompilerError, DistutilsError, CompileError) as e: + if not ext.optional: + raise + self.warn('building extension "%s" failed: %s' % + (ext.name, e)) + + def build_extension(self, ext): + sources = ext.sources + if sources is None or not isinstance(sources, (list, tuple)): + raise DistutilsSetupError( + "in 'ext_modules' option (extension '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % ext.name) + # sort to make the resulting .so file build reproducible + sources = sorted(sources) + + ext_path = self.get_ext_fullpath(ext.name) + depends = sources + ext.depends + if not (self.force or newer_group(depends, ext_path, 'newer')): + log.debug("skipping '%s' extension (up-to-date)", ext.name) + return + else: + log.info("building '%s' extension", ext.name) + + # First, scan the sources for SWIG definition files (.i), run + # SWIG on 'em to create .c files, and modify the sources list + # accordingly. + sources = self.swig_sources(sources, ext) + + # Next, compile the source code to object files. + + # XXX not honouring 'define_macros' or 'undef_macros' -- the + # CCompiler API needs to change to accommodate this, and I + # want to do one thing at a time! + + # Two possible sources for extra compiler arguments: + # - 'extra_compile_args' in Extension object + # - CFLAGS environment variable (not particularly + # elegant, but people seem to expect it and I + # guess it's useful) + # The environment variable should take precedence, and + # any sensible compiler will give precedence to later + # command line args. Hence we combine them in order: + extra_args = ext.extra_compile_args or [] + + macros = ext.define_macros[:] + for undef in ext.undef_macros: + macros.append((undef,)) + + objects = self.compiler.compile(sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=ext.include_dirs, + debug=self.debug, + extra_postargs=extra_args, + depends=ext.depends) + + # XXX outdated variable, kept here in case third-part code + # needs it. + self._built_objects = objects[:] + + # Now link the object files together into a "shared object" -- + # of course, first we have to figure out all the other things + # that go into the mix. + if ext.extra_objects: + objects.extend(ext.extra_objects) + extra_args = ext.extra_link_args or [] + + # Detect target language, if not provided + language = ext.language or self.compiler.detect_language(sources) + + self.compiler.link_shared_object( + objects, ext_path, + libraries=self.get_libraries(ext), + library_dirs=ext.library_dirs, + runtime_library_dirs=ext.runtime_library_dirs, + extra_postargs=extra_args, + export_symbols=self.get_export_symbols(ext), + debug=self.debug, + build_temp=self.build_temp, + target_lang=language) + + def swig_sources(self, sources, extension): + """Walk the list of source files in 'sources', looking for SWIG + interface (.i) files. Run SWIG on all that are found, and + return a modified 'sources' list with SWIG source files replaced + by the generated C (or C++) files. + """ + new_sources = [] + swig_sources = [] + swig_targets = {} + + # XXX this drops generated C/C++ files into the source tree, which + # is fine for developers who want to distribute the generated + # source -- but there should be an option to put SWIG output in + # the temp dir. + + if self.swig_cpp: + log.warn("--swig-cpp is deprecated - use --swig-opts=-c++") + + if self.swig_cpp or ('-c++' in self.swig_opts) or \ + ('-c++' in extension.swig_opts): + target_ext = '.cpp' + else: + target_ext = '.c' + + for source in sources: + (base, ext) = os.path.splitext(source) + if ext == ".i": # SWIG interface file + new_sources.append(base + '_wrap' + target_ext) + swig_sources.append(source) + swig_targets[source] = new_sources[-1] + else: + new_sources.append(source) + + if not swig_sources: + return new_sources + + swig = self.swig or self.find_swig() + swig_cmd = [swig, "-python"] + swig_cmd.extend(self.swig_opts) + if self.swig_cpp: + swig_cmd.append("-c++") + + # Do not override commandline arguments + if not self.swig_opts: + for o in extension.swig_opts: + swig_cmd.append(o) + + for source in swig_sources: + target = swig_targets[source] + log.info("swigging %s to %s", source, target) + self.spawn(swig_cmd + ["-o", target, source]) + + return new_sources + + def find_swig(self): + """Return the name of the SWIG executable. On Unix, this is + just "swig" -- it should be in the PATH. Tries a bit harder on + Windows. + """ + if os.name == "posix": + return "swig" + elif os.name == "nt": + # Look for SWIG in its standard installation directory on + # Windows (or so I presume!). If we find it there, great; + # if not, act like Unix and assume it's in the PATH. + for vers in ("1.3", "1.2", "1.1"): + fn = os.path.join("c:\\swig%s" % vers, "swig.exe") + if os.path.isfile(fn): + return fn + else: + return "swig.exe" + else: + raise DistutilsPlatformError( + "I don't know how to find (much less run) SWIG " + "on platform '%s'" % os.name) + + # -- Name generators ----------------------------------------------- + # (extension names, filenames, whatever) + def get_ext_fullpath(self, ext_name): + """Returns the path of the filename for a given extension. + + The file is located in `build_lib` or directly in the package + (inplace option). + """ + fullname = self.get_ext_fullname(ext_name) + modpath = fullname.split('.') + filename = self.get_ext_filename(modpath[-1]) + + if not self.inplace: + # no further work needed + # returning : + # build_dir/package/path/filename + filename = os.path.join(*modpath[:-1]+[filename]) + return os.path.join(self.build_lib, filename) + + # the inplace option requires to find the package directory + # using the build_py command for that + package = '.'.join(modpath[0:-1]) + build_py = self.get_finalized_command('build_py') + package_dir = os.path.abspath(build_py.get_package_dir(package)) + + # returning + # package_dir/filename + return os.path.join(package_dir, filename) + + def get_ext_fullname(self, ext_name): + """Returns the fullname of a given extension name. + + Adds the `package.` prefix""" + if self.package is None: + return ext_name + else: + return self.package + '.' + ext_name + + def get_ext_filename(self, ext_name): + r"""Convert the name of an extension (eg. "foo.bar") into the name + of the file from which it will be loaded (eg. "foo/bar.so", or + "foo\bar.pyd"). + """ + from distutils.sysconfig import get_config_var + ext_path = ext_name.split('.') + ext_suffix = get_config_var('EXT_SUFFIX') + return os.path.join(*ext_path) + ext_suffix + + def get_export_symbols(self, ext): + """Return the list of symbols that a shared extension has to + export. This either uses 'ext.export_symbols' or, if it's not + provided, "PyInit_" + module_name. Only relevant on Windows, where + the .pyd file (DLL) must export the module "PyInit_" function. + """ + name = ext.name.split('.')[-1] + try: + # Unicode module name support as defined in PEP-489 + # https://www.python.org/dev/peps/pep-0489/#export-hook-name + name.encode('ascii') + except UnicodeEncodeError: + suffix = 'U_' + name.encode('punycode').replace(b'-', b'_').decode('ascii') + else: + suffix = "_" + name + + initfunc_name = "PyInit" + suffix + if initfunc_name not in ext.export_symbols: + ext.export_symbols.append(initfunc_name) + return ext.export_symbols + + def get_libraries(self, ext): + """Return the list of libraries to link against when building a + shared extension. On most platforms, this is just 'ext.libraries'; + on Windows, we add the Python library (eg. python20.dll). + """ + # The python library is always needed on Windows. For MSVC, this + # is redundant, since the library is mentioned in a pragma in + # pyconfig.h that MSVC groks. The other Windows compilers all seem + # to need it mentioned explicitly, though, so that's what we do. + # Append '_d' to the python import library on debug builds. + if sys.platform == "win32": + from distutils._msvccompiler import MSVCCompiler + if not isinstance(self.compiler, MSVCCompiler): + template = "python%d%d" + if self.debug: + template = template + '_d' + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + # don't extend ext.libraries, it may be shared with other + # extensions, it is a reference to the original list + return ext.libraries + [pythonlib] + else: + # On Android only the main executable and LD_PRELOADs are considered + # to be RTLD_GLOBAL, all the dependencies of the main executable + # remain RTLD_LOCAL and so the shared libraries must be linked with + # libpython when python is built with a shared python library (issue + # bpo-21536). + # On Cygwin (and if required, other POSIX-like platforms based on + # Windows like MinGW) it is simply necessary that all symbols in + # shared libraries are resolved at link time. + from distutils.sysconfig import get_config_var + link_libpython = False + if get_config_var('Py_ENABLE_SHARED'): + # A native build on an Android device or on Cygwin + if hasattr(sys, 'getandroidapilevel'): + link_libpython = True + elif sys.platform == 'cygwin': + link_libpython = True + elif '_PYTHON_HOST_PLATFORM' in os.environ: + # We are cross-compiling for one of the relevant platforms + if get_config_var('ANDROID_API_LEVEL') != 0: + link_libpython = True + elif get_config_var('MACHDEP') == 'cygwin': + link_libpython = True + + if link_libpython: + ldversion = get_config_var('LDVERSION') + return ext.libraries + ['python' + ldversion] + + return ext.libraries + py37compat.pythonlib() diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/build_py.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_py.py new file mode 100644 index 0000000000000000000000000000000000000000..7ef9bcefdec05490393466f032548f24d41ea0b8 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_py.py @@ -0,0 +1,392 @@ +"""distutils.command.build_py + +Implements the Distutils 'build_py' command.""" + +import os +import importlib.util +import sys +import glob + +from distutils.core import Command +from distutils.errors import * +from distutils.util import convert_path +from distutils import log + +class build_py (Command): + + description = "\"build\" pure Python modules (copy to build directory)" + + user_options = [ + ('build-lib=', 'd', "directory to \"build\" (copy) to"), + ('compile', 'c', "compile .py to .pyc"), + ('no-compile', None, "don't compile .py files [default]"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ('force', 'f', "forcibly build everything (ignore file timestamps)"), + ] + + boolean_options = ['compile', 'force'] + negative_opt = {'no-compile' : 'compile'} + + def initialize_options(self): + self.build_lib = None + self.py_modules = None + self.package = None + self.package_data = None + self.package_dir = None + self.compile = 0 + self.optimize = 0 + self.force = None + + def finalize_options(self): + self.set_undefined_options('build', + ('build_lib', 'build_lib'), + ('force', 'force')) + + # Get the distribution options that are aliases for build_py + # options -- list of packages and list of modules. + self.packages = self.distribution.packages + self.py_modules = self.distribution.py_modules + self.package_data = self.distribution.package_data + self.package_dir = {} + if self.distribution.package_dir: + for name, path in self.distribution.package_dir.items(): + self.package_dir[name] = convert_path(path) + self.data_files = self.get_data_files() + + # Ick, copied straight from install_lib.py (fancy_getopt needs a + # type system! Hell, *everything* needs a type system!!!) + if not isinstance(self.optimize, int): + try: + self.optimize = int(self.optimize) + assert 0 <= self.optimize <= 2 + except (ValueError, AssertionError): + raise DistutilsOptionError("optimize must be 0, 1, or 2") + + def run(self): + # XXX copy_file by default preserves atime and mtime. IMHO this is + # the right thing to do, but perhaps it should be an option -- in + # particular, a site administrator might want installed files to + # reflect the time of installation rather than the last + # modification time before the installed release. + + # XXX copy_file by default preserves mode, which appears to be the + # wrong thing to do: if a file is read-only in the working + # directory, we want it to be installed read/write so that the next + # installation of the same module distribution can overwrite it + # without problems. (This might be a Unix-specific issue.) Thus + # we turn off 'preserve_mode' when copying to the build directory, + # since the build directory is supposed to be exactly what the + # installation will look like (ie. we preserve mode when + # installing). + + # Two options control which modules will be installed: 'packages' + # and 'py_modules'. The former lets us work with whole packages, not + # specifying individual modules at all; the latter is for + # specifying modules one-at-a-time. + + if self.py_modules: + self.build_modules() + if self.packages: + self.build_packages() + self.build_package_data() + + self.byte_compile(self.get_outputs(include_bytecode=0)) + + def get_data_files(self): + """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" + data = [] + if not self.packages: + return data + for package in self.packages: + # Locate package source directory + src_dir = self.get_package_dir(package) + + # Compute package build directory + build_dir = os.path.join(*([self.build_lib] + package.split('.'))) + + # Length of path to strip from found files + plen = 0 + if src_dir: + plen = len(src_dir)+1 + + # Strip directory from globbed filenames + filenames = [ + file[plen:] for file in self.find_data_files(package, src_dir) + ] + data.append((package, src_dir, build_dir, filenames)) + return data + + def find_data_files(self, package, src_dir): + """Return filenames for package's data files in 'src_dir'""" + globs = (self.package_data.get('', []) + + self.package_data.get(package, [])) + files = [] + for pattern in globs: + # Each pattern has to be converted to a platform-specific path + filelist = glob.glob(os.path.join(glob.escape(src_dir), convert_path(pattern))) + # Files that match more than one pattern are only added once + files.extend([fn for fn in filelist if fn not in files + and os.path.isfile(fn)]) + return files + + def build_package_data(self): + """Copy data files into build directory""" + lastdir = None + for package, src_dir, build_dir, filenames in self.data_files: + for filename in filenames: + target = os.path.join(build_dir, filename) + self.mkpath(os.path.dirname(target)) + self.copy_file(os.path.join(src_dir, filename), target, + preserve_mode=False) + + def get_package_dir(self, package): + """Return the directory, relative to the top of the source + distribution, where package 'package' should be found + (at least according to the 'package_dir' option, if any).""" + path = package.split('.') + + if not self.package_dir: + if path: + return os.path.join(*path) + else: + return '' + else: + tail = [] + while path: + try: + pdir = self.package_dir['.'.join(path)] + except KeyError: + tail.insert(0, path[-1]) + del path[-1] + else: + tail.insert(0, pdir) + return os.path.join(*tail) + else: + # Oops, got all the way through 'path' without finding a + # match in package_dir. If package_dir defines a directory + # for the root (nameless) package, then fallback on it; + # otherwise, we might as well have not consulted + # package_dir at all, as we just use the directory implied + # by 'tail' (which should be the same as the original value + # of 'path' at this point). + pdir = self.package_dir.get('') + if pdir is not None: + tail.insert(0, pdir) + + if tail: + return os.path.join(*tail) + else: + return '' + + def check_package(self, package, package_dir): + # Empty dir name means current directory, which we can probably + # assume exists. Also, os.path.exists and isdir don't know about + # my "empty string means current dir" convention, so we have to + # circumvent them. + if package_dir != "": + if not os.path.exists(package_dir): + raise DistutilsFileError( + "package directory '%s' does not exist" % package_dir) + if not os.path.isdir(package_dir): + raise DistutilsFileError( + "supposed package directory '%s' exists, " + "but is not a directory" % package_dir) + + # Require __init__.py for all but the "root package" + if package: + init_py = os.path.join(package_dir, "__init__.py") + if os.path.isfile(init_py): + return init_py + else: + log.warn(("package init file '%s' not found " + + "(or not a regular file)"), init_py) + + # Either not in a package at all (__init__.py not expected), or + # __init__.py doesn't exist -- so don't return the filename. + return None + + def check_module(self, module, module_file): + if not os.path.isfile(module_file): + log.warn("file %s (for module %s) not found", module_file, module) + return False + else: + return True + + def find_package_modules(self, package, package_dir): + self.check_package(package, package_dir) + module_files = glob.glob(os.path.join(glob.escape(package_dir), "*.py")) + modules = [] + setup_script = os.path.abspath(self.distribution.script_name) + + for f in module_files: + abs_f = os.path.abspath(f) + if abs_f != setup_script: + module = os.path.splitext(os.path.basename(f))[0] + modules.append((package, module, f)) + else: + self.debug_print("excluding %s" % setup_script) + return modules + + def find_modules(self): + """Finds individually-specified Python modules, ie. those listed by + module name in 'self.py_modules'. Returns a list of tuples (package, + module_base, filename): 'package' is a tuple of the path through + package-space to the module; 'module_base' is the bare (no + packages, no dots) module name, and 'filename' is the path to the + ".py" file (relative to the distribution root) that implements the + module. + """ + # Map package names to tuples of useful info about the package: + # (package_dir, checked) + # package_dir - the directory where we'll find source files for + # this package + # checked - true if we have checked that the package directory + # is valid (exists, contains __init__.py, ... ?) + packages = {} + + # List of (package, module, filename) tuples to return + modules = [] + + # We treat modules-in-packages almost the same as toplevel modules, + # just the "package" for a toplevel is empty (either an empty + # string or empty list, depending on context). Differences: + # - don't check for __init__.py in directory for empty package + for module in self.py_modules: + path = module.split('.') + package = '.'.join(path[0:-1]) + module_base = path[-1] + + try: + (package_dir, checked) = packages[package] + except KeyError: + package_dir = self.get_package_dir(package) + checked = 0 + + if not checked: + init_py = self.check_package(package, package_dir) + packages[package] = (package_dir, 1) + if init_py: + modules.append((package, "__init__", init_py)) + + # XXX perhaps we should also check for just .pyc files + # (so greedy closed-source bastards can distribute Python + # modules too) + module_file = os.path.join(package_dir, module_base + ".py") + if not self.check_module(module, module_file): + continue + + modules.append((package, module_base, module_file)) + + return modules + + def find_all_modules(self): + """Compute the list of all modules that will be built, whether + they are specified one-module-at-a-time ('self.py_modules') or + by whole packages ('self.packages'). Return a list of tuples + (package, module, module_file), just like 'find_modules()' and + 'find_package_modules()' do.""" + modules = [] + if self.py_modules: + modules.extend(self.find_modules()) + if self.packages: + for package in self.packages: + package_dir = self.get_package_dir(package) + m = self.find_package_modules(package, package_dir) + modules.extend(m) + return modules + + def get_source_files(self): + return [module[-1] for module in self.find_all_modules()] + + def get_module_outfile(self, build_dir, package, module): + outfile_path = [build_dir] + list(package) + [module + ".py"] + return os.path.join(*outfile_path) + + def get_outputs(self, include_bytecode=1): + modules = self.find_all_modules() + outputs = [] + for (package, module, module_file) in modules: + package = package.split('.') + filename = self.get_module_outfile(self.build_lib, package, module) + outputs.append(filename) + if include_bytecode: + if self.compile: + outputs.append(importlib.util.cache_from_source( + filename, optimization='')) + if self.optimize > 0: + outputs.append(importlib.util.cache_from_source( + filename, optimization=self.optimize)) + + outputs += [ + os.path.join(build_dir, filename) + for package, src_dir, build_dir, filenames in self.data_files + for filename in filenames + ] + + return outputs + + def build_module(self, module, module_file, package): + if isinstance(package, str): + package = package.split('.') + elif not isinstance(package, (list, tuple)): + raise TypeError( + "'package' must be a string (dot-separated), list, or tuple") + + # Now put the module source file into the "build" area -- this is + # easy, we just copy it somewhere under self.build_lib (the build + # directory for Python source). + outfile = self.get_module_outfile(self.build_lib, package, module) + dir = os.path.dirname(outfile) + self.mkpath(dir) + return self.copy_file(module_file, outfile, preserve_mode=0) + + def build_modules(self): + modules = self.find_modules() + for (package, module, module_file) in modules: + # Now "build" the module -- ie. copy the source file to + # self.build_lib (the build directory for Python source). + # (Actually, it gets copied to the directory for this package + # under self.build_lib.) + self.build_module(module, module_file, package) + + def build_packages(self): + for package in self.packages: + # Get list of (package, module, module_file) tuples based on + # scanning the package directory. 'package' is only included + # in the tuple so that 'find_modules()' and + # 'find_package_tuples()' have a consistent interface; it's + # ignored here (apart from a sanity check). Also, 'module' is + # the *unqualified* module name (ie. no dots, no package -- we + # already know its package!), and 'module_file' is the path to + # the .py file, relative to the current directory + # (ie. including 'package_dir'). + package_dir = self.get_package_dir(package) + modules = self.find_package_modules(package, package_dir) + + # Now loop over the modules we found, "building" each one (just + # copy it to self.build_lib). + for (package_, module, module_file) in modules: + assert package == package_ + self.build_module(module, module_file, package) + + def byte_compile(self, files): + if sys.dont_write_bytecode: + self.warn('byte-compiling is disabled, skipping.') + return + + from distutils.util import byte_compile + prefix = self.build_lib + if prefix[-1] != os.sep: + prefix = prefix + os.sep + + # XXX this code is essentially the same as the 'byte_compile() + # method of the "install_lib" command, except for the determination + # of the 'prefix' string. Hmmm. + if self.compile: + byte_compile(files, optimize=0, + force=self.force, prefix=prefix, dry_run=self.dry_run) + if self.optimize > 0: + byte_compile(files, optimize=self.optimize, + force=self.force, prefix=prefix, dry_run=self.dry_run) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/build_scripts.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_scripts.py new file mode 100644 index 0000000000000000000000000000000000000000..e3312cf0caa2a8f4e6afd99435442fa01dd8cf65 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/build_scripts.py @@ -0,0 +1,152 @@ +"""distutils.command.build_scripts + +Implements the Distutils 'build_scripts' command.""" + +import os, re +from stat import ST_MODE +from distutils import sysconfig +from distutils.core import Command +from distutils.dep_util import newer +from distutils.util import convert_path +from distutils import log +import tokenize + +# check if Python is called on the first line with this expression +first_line_re = re.compile(b'^#!.*python[0-9.]*([ \t].*)?$') + +class build_scripts(Command): + + description = "\"build\" scripts (copy and fixup #! line)" + + user_options = [ + ('build-dir=', 'd', "directory to \"build\" (copy) to"), + ('force', 'f', "forcibly build everything (ignore file timestamps"), + ('executable=', 'e', "specify final destination interpreter path"), + ] + + boolean_options = ['force'] + + + def initialize_options(self): + self.build_dir = None + self.scripts = None + self.force = None + self.executable = None + self.outfiles = None + + def finalize_options(self): + self.set_undefined_options('build', + ('build_scripts', 'build_dir'), + ('force', 'force'), + ('executable', 'executable')) + self.scripts = self.distribution.scripts + + def get_source_files(self): + return self.scripts + + def run(self): + if not self.scripts: + return + self.copy_scripts() + + + def copy_scripts(self): + r"""Copy each script listed in 'self.scripts'; if it's marked as a + Python script in the Unix way (first line matches 'first_line_re', + ie. starts with "\#!" and contains "python"), then adjust the first + line to refer to the current Python interpreter as we copy. + """ + self.mkpath(self.build_dir) + outfiles = [] + updated_files = [] + for script in self.scripts: + adjust = False + script = convert_path(script) + outfile = os.path.join(self.build_dir, os.path.basename(script)) + outfiles.append(outfile) + + if not self.force and not newer(script, outfile): + log.debug("not copying %s (up-to-date)", script) + continue + + # Always open the file, but ignore failures in dry-run mode -- + # that way, we'll get accurate feedback if we can read the + # script. + try: + f = open(script, "rb") + except OSError: + if not self.dry_run: + raise + f = None + else: + encoding, lines = tokenize.detect_encoding(f.readline) + f.seek(0) + first_line = f.readline() + if not first_line: + self.warn("%s is an empty file (skipping)" % script) + continue + + match = first_line_re.match(first_line) + if match: + adjust = True + post_interp = match.group(1) or b'' + + if adjust: + log.info("copying and adjusting %s -> %s", script, + self.build_dir) + updated_files.append(outfile) + if not self.dry_run: + if not sysconfig.python_build: + executable = self.executable + else: + executable = os.path.join( + sysconfig.get_config_var("BINDIR"), + "python%s%s" % (sysconfig.get_config_var("VERSION"), + sysconfig.get_config_var("EXE"))) + executable = os.fsencode(executable) + shebang = b"#!" + executable + post_interp + b"\n" + # Python parser starts to read a script using UTF-8 until + # it gets a #coding:xxx cookie. The shebang has to be the + # first line of a file, the #coding:xxx cookie cannot be + # written before. So the shebang has to be decodable from + # UTF-8. + try: + shebang.decode('utf-8') + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from utf-8".format(shebang)) + # If the script is encoded to a custom encoding (use a + # #coding:xxx cookie), the shebang has to be decodable from + # the script encoding too. + try: + shebang.decode(encoding) + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from the script encoding ({})" + .format(shebang, encoding)) + with open(outfile, "wb") as outf: + outf.write(shebang) + outf.writelines(f.readlines()) + if f: + f.close() + else: + if f: + f.close() + updated_files.append(outfile) + self.copy_file(script, outfile) + + if os.name == 'posix': + for file in outfiles: + if self.dry_run: + log.info("changing mode of %s", file) + else: + oldmode = os.stat(file)[ST_MODE] & 0o7777 + newmode = (oldmode | 0o555) & 0o7777 + if newmode != oldmode: + log.info("changing mode of %s from %o to %o", + file, oldmode, newmode) + os.chmod(file, newmode) + # XXX should we modify self.outfiles? + return outfiles, updated_files diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/check.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/check.py new file mode 100644 index 0000000000000000000000000000000000000000..ada250064678ee3ddfbc29244a45ca64d527659c --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/check.py @@ -0,0 +1,148 @@ +"""distutils.command.check + +Implements the Distutils 'check' command. +""" +from distutils.core import Command +from distutils.errors import DistutilsSetupError + +try: + # docutils is installed + from docutils.utils import Reporter + from docutils.parsers.rst import Parser + from docutils import frontend + from docutils import nodes + + class SilentReporter(Reporter): + + def __init__(self, source, report_level, halt_level, stream=None, + debug=0, encoding='ascii', error_handler='replace'): + self.messages = [] + Reporter.__init__(self, source, report_level, halt_level, stream, + debug, encoding, error_handler) + + def system_message(self, level, message, *children, **kwargs): + self.messages.append((level, message, children, kwargs)) + return nodes.system_message(message, level=level, + type=self.levels[level], + *children, **kwargs) + + HAS_DOCUTILS = True +except Exception: + # Catch all exceptions because exceptions besides ImportError probably + # indicate that docutils is not ported to Py3k. + HAS_DOCUTILS = False + +class check(Command): + """This command checks the meta-data of the package. + """ + description = ("perform some checks on the package") + user_options = [('metadata', 'm', 'Verify meta-data'), + ('restructuredtext', 'r', + ('Checks if long string meta-data syntax ' + 'are reStructuredText-compliant')), + ('strict', 's', + 'Will exit with an error if a check fails')] + + boolean_options = ['metadata', 'restructuredtext', 'strict'] + + def initialize_options(self): + """Sets default values for options.""" + self.restructuredtext = 0 + self.metadata = 1 + self.strict = 0 + self._warnings = 0 + + def finalize_options(self): + pass + + def warn(self, msg): + """Counts the number of warnings that occurs.""" + self._warnings += 1 + return Command.warn(self, msg) + + def run(self): + """Runs the command.""" + # perform the various tests + if self.metadata: + self.check_metadata() + if self.restructuredtext: + if HAS_DOCUTILS: + self.check_restructuredtext() + elif self.strict: + raise DistutilsSetupError('The docutils package is needed.') + + # let's raise an error in strict mode, if we have at least + # one warning + if self.strict and self._warnings > 0: + raise DistutilsSetupError('Please correct your package.') + + def check_metadata(self): + """Ensures that all required elements of meta-data are supplied. + + Required fields: + name, version, URL + + Recommended fields: + (author and author_email) or (maintainer and maintainer_email)) + + Warns if any are missing. + """ + metadata = self.distribution.metadata + + missing = [] + for attr in ('name', 'version', 'url'): + if not (hasattr(metadata, attr) and getattr(metadata, attr)): + missing.append(attr) + + if missing: + self.warn("missing required meta-data: %s" % ', '.join(missing)) + if metadata.author: + if not metadata.author_email: + self.warn("missing meta-data: if 'author' supplied, " + + "'author_email' should be supplied too") + elif metadata.maintainer: + if not metadata.maintainer_email: + self.warn("missing meta-data: if 'maintainer' supplied, " + + "'maintainer_email' should be supplied too") + else: + self.warn("missing meta-data: either (author and author_email) " + + "or (maintainer and maintainer_email) " + + "should be supplied") + + def check_restructuredtext(self): + """Checks if the long string fields are reST-compliant.""" + data = self.distribution.get_long_description() + for warning in self._check_rst_data(data): + line = warning[-1].get('line') + if line is None: + warning = warning[1] + else: + warning = '%s (line %s)' % (warning[1], line) + self.warn(warning) + + def _check_rst_data(self, data): + """Returns warnings when the provided data doesn't compile.""" + # the include and csv_table directives need this to be a path + source_path = self.distribution.script_name or 'setup.py' + parser = Parser() + settings = frontend.OptionParser(components=(Parser,)).get_default_values() + settings.tab_width = 4 + settings.pep_references = None + settings.rfc_references = None + reporter = SilentReporter(source_path, + settings.report_level, + settings.halt_level, + stream=settings.warning_stream, + debug=settings.debug, + encoding=settings.error_encoding, + error_handler=settings.error_encoding_error_handler) + + document = nodes.document(settings, reporter, source=source_path) + document.note_source(source_path, -1) + try: + parser.parse(data, document) + except AttributeError as e: + reporter.messages.append( + (-1, 'Could not finish the parsing: %s.' % e, '', {})) + + return reporter.messages diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/clean.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/clean.py new file mode 100644 index 0000000000000000000000000000000000000000..0cb270166211fe2b24b6ec636f632a77a5ca6b8f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/clean.py @@ -0,0 +1,76 @@ +"""distutils.command.clean + +Implements the Distutils 'clean' command.""" + +# contributed by Bastian Kleineidam , added 2000-03-18 + +import os +from distutils.core import Command +from distutils.dir_util import remove_tree +from distutils import log + +class clean(Command): + + description = "clean up temporary files from 'build' command" + user_options = [ + ('build-base=', 'b', + "base build directory (default: 'build.build-base')"), + ('build-lib=', None, + "build directory for all modules (default: 'build.build-lib')"), + ('build-temp=', 't', + "temporary build directory (default: 'build.build-temp')"), + ('build-scripts=', None, + "build directory for scripts (default: 'build.build-scripts')"), + ('bdist-base=', None, + "temporary directory for built distributions"), + ('all', 'a', + "remove all build output, not just temporary by-products") + ] + + boolean_options = ['all'] + + def initialize_options(self): + self.build_base = None + self.build_lib = None + self.build_temp = None + self.build_scripts = None + self.bdist_base = None + self.all = None + + def finalize_options(self): + self.set_undefined_options('build', + ('build_base', 'build_base'), + ('build_lib', 'build_lib'), + ('build_scripts', 'build_scripts'), + ('build_temp', 'build_temp')) + self.set_undefined_options('bdist', + ('bdist_base', 'bdist_base')) + + def run(self): + # remove the build/temp. directory (unless it's already + # gone) + if os.path.exists(self.build_temp): + remove_tree(self.build_temp, dry_run=self.dry_run) + else: + log.debug("'%s' does not exist -- can't clean it", + self.build_temp) + + if self.all: + # remove build directories + for directory in (self.build_lib, + self.bdist_base, + self.build_scripts): + if os.path.exists(directory): + remove_tree(directory, dry_run=self.dry_run) + else: + log.warn("'%s' does not exist -- can't clean it", + directory) + + # just for the heck of it, try to remove the base build directory: + # we might have emptied it right now, but if not we don't care + if not self.dry_run: + try: + os.rmdir(self.build_base) + log.info("removing '%s'", self.build_base) + except OSError: + pass diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/config.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/config.py new file mode 100644 index 0000000000000000000000000000000000000000..aeda408e731979bf5884e4830fed142a70bfb25e --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/config.py @@ -0,0 +1,344 @@ +"""distutils.command.config + +Implements the Distutils 'config' command, a (mostly) empty command class +that exists mainly to be sub-classed by specific module distributions and +applications. The idea is that while every "config" command is different, +at least they're all named the same, and users always see "config" in the +list of standard commands. Also, this is a good place to put common +configure-like tasks: "try to compile this C code", or "figure out where +this header file lives". +""" + +import os, re + +from distutils.core import Command +from distutils.errors import DistutilsExecError +from distutils.sysconfig import customize_compiler +from distutils import log + +LANG_EXT = {"c": ".c", "c++": ".cxx"} + +class config(Command): + + description = "prepare to build" + + user_options = [ + ('compiler=', None, + "specify the compiler type"), + ('cc=', None, + "specify the compiler executable"), + ('include-dirs=', 'I', + "list of directories to search for header files"), + ('define=', 'D', + "C preprocessor macros to define"), + ('undef=', 'U', + "C preprocessor macros to undefine"), + ('libraries=', 'l', + "external C libraries to link with"), + ('library-dirs=', 'L', + "directories to search for external C libraries"), + + ('noisy', None, + "show every action (compile, link, run, ...) taken"), + ('dump-source', None, + "dump generated source files before attempting to compile them"), + ] + + + # The three standard command methods: since the "config" command + # does nothing by default, these are empty. + + def initialize_options(self): + self.compiler = None + self.cc = None + self.include_dirs = None + self.libraries = None + self.library_dirs = None + + # maximal output for now + self.noisy = 1 + self.dump_source = 1 + + # list of temporary files generated along-the-way that we have + # to clean at some point + self.temp_files = [] + + def finalize_options(self): + if self.include_dirs is None: + self.include_dirs = self.distribution.include_dirs or [] + elif isinstance(self.include_dirs, str): + self.include_dirs = self.include_dirs.split(os.pathsep) + + if self.libraries is None: + self.libraries = [] + elif isinstance(self.libraries, str): + self.libraries = [self.libraries] + + if self.library_dirs is None: + self.library_dirs = [] + elif isinstance(self.library_dirs, str): + self.library_dirs = self.library_dirs.split(os.pathsep) + + def run(self): + pass + + # Utility methods for actual "config" commands. The interfaces are + # loosely based on Autoconf macros of similar names. Sub-classes + # may use these freely. + + def _check_compiler(self): + """Check that 'self.compiler' really is a CCompiler object; + if not, make it one. + """ + # We do this late, and only on-demand, because this is an expensive + # import. + from distutils.ccompiler import CCompiler, new_compiler + if not isinstance(self.compiler, CCompiler): + self.compiler = new_compiler(compiler=self.compiler, + dry_run=self.dry_run, force=1) + customize_compiler(self.compiler) + if self.include_dirs: + self.compiler.set_include_dirs(self.include_dirs) + if self.libraries: + self.compiler.set_libraries(self.libraries) + if self.library_dirs: + self.compiler.set_library_dirs(self.library_dirs) + + def _gen_temp_sourcefile(self, body, headers, lang): + filename = "_configtest" + LANG_EXT[lang] + with open(filename, "w") as file: + if headers: + for header in headers: + file.write("#include <%s>\n" % header) + file.write("\n") + file.write(body) + if body[-1] != "\n": + file.write("\n") + return filename + + def _preprocess(self, body, headers, include_dirs, lang): + src = self._gen_temp_sourcefile(body, headers, lang) + out = "_configtest.i" + self.temp_files.extend([src, out]) + self.compiler.preprocess(src, out, include_dirs=include_dirs) + return (src, out) + + def _compile(self, body, headers, include_dirs, lang): + src = self._gen_temp_sourcefile(body, headers, lang) + if self.dump_source: + dump_file(src, "compiling '%s':" % src) + (obj,) = self.compiler.object_filenames([src]) + self.temp_files.extend([src, obj]) + self.compiler.compile([src], include_dirs=include_dirs) + return (src, obj) + + def _link(self, body, headers, include_dirs, libraries, library_dirs, + lang): + (src, obj) = self._compile(body, headers, include_dirs, lang) + prog = os.path.splitext(os.path.basename(src))[0] + self.compiler.link_executable([obj], prog, + libraries=libraries, + library_dirs=library_dirs, + target_lang=lang) + + if self.compiler.exe_extension is not None: + prog = prog + self.compiler.exe_extension + self.temp_files.append(prog) + + return (src, obj, prog) + + def _clean(self, *filenames): + if not filenames: + filenames = self.temp_files + self.temp_files = [] + log.info("removing: %s", ' '.join(filenames)) + for filename in filenames: + try: + os.remove(filename) + except OSError: + pass + + + # XXX these ignore the dry-run flag: what to do, what to do? even if + # you want a dry-run build, you still need some sort of configuration + # info. My inclination is to make it up to the real config command to + # consult 'dry_run', and assume a default (minimal) configuration if + # true. The problem with trying to do it here is that you'd have to + # return either true or false from all the 'try' methods, neither of + # which is correct. + + # XXX need access to the header search path and maybe default macros. + + def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"): + """Construct a source file from 'body' (a string containing lines + of C/C++ code) and 'headers' (a list of header files to include) + and run it through the preprocessor. Return true if the + preprocessor succeeded, false if there were any errors. + ('body' probably isn't of much use, but what the heck.) + """ + from distutils.ccompiler import CompileError + self._check_compiler() + ok = True + try: + self._preprocess(body, headers, include_dirs, lang) + except CompileError: + ok = False + + self._clean() + return ok + + def search_cpp(self, pattern, body=None, headers=None, include_dirs=None, + lang="c"): + """Construct a source file (just like 'try_cpp()'), run it through + the preprocessor, and return true if any line of the output matches + 'pattern'. 'pattern' should either be a compiled regex object or a + string containing a regex. If both 'body' and 'headers' are None, + preprocesses an empty file -- which can be useful to determine the + symbols the preprocessor and compiler set by default. + """ + self._check_compiler() + src, out = self._preprocess(body, headers, include_dirs, lang) + + if isinstance(pattern, str): + pattern = re.compile(pattern) + + with open(out) as file: + match = False + while True: + line = file.readline() + if line == '': + break + if pattern.search(line): + match = True + break + + self._clean() + return match + + def try_compile(self, body, headers=None, include_dirs=None, lang="c"): + """Try to compile a source file built from 'body' and 'headers'. + Return true on success, false otherwise. + """ + from distutils.ccompiler import CompileError + self._check_compiler() + try: + self._compile(body, headers, include_dirs, lang) + ok = True + except CompileError: + ok = False + + log.info(ok and "success!" or "failure.") + self._clean() + return ok + + def try_link(self, body, headers=None, include_dirs=None, libraries=None, + library_dirs=None, lang="c"): + """Try to compile and link a source file, built from 'body' and + 'headers', to executable form. Return true on success, false + otherwise. + """ + from distutils.ccompiler import CompileError, LinkError + self._check_compiler() + try: + self._link(body, headers, include_dirs, + libraries, library_dirs, lang) + ok = True + except (CompileError, LinkError): + ok = False + + log.info(ok and "success!" or "failure.") + self._clean() + return ok + + def try_run(self, body, headers=None, include_dirs=None, libraries=None, + library_dirs=None, lang="c"): + """Try to compile, link to an executable, and run a program + built from 'body' and 'headers'. Return true on success, false + otherwise. + """ + from distutils.ccompiler import CompileError, LinkError + self._check_compiler() + try: + src, obj, exe = self._link(body, headers, include_dirs, + libraries, library_dirs, lang) + self.spawn([exe]) + ok = True + except (CompileError, LinkError, DistutilsExecError): + ok = False + + log.info(ok and "success!" or "failure.") + self._clean() + return ok + + + # -- High-level methods -------------------------------------------- + # (these are the ones that are actually likely to be useful + # when implementing a real-world config command!) + + def check_func(self, func, headers=None, include_dirs=None, + libraries=None, library_dirs=None, decl=0, call=0): + """Determine if function 'func' is available by constructing a + source file that refers to 'func', and compiles and links it. + If everything succeeds, returns true; otherwise returns false. + + The constructed source file starts out by including the header + files listed in 'headers'. If 'decl' is true, it then declares + 'func' (as "int func()"); you probably shouldn't supply 'headers' + and set 'decl' true in the same call, or you might get errors about + a conflicting declarations for 'func'. Finally, the constructed + 'main()' function either references 'func' or (if 'call' is true) + calls it. 'libraries' and 'library_dirs' are used when + linking. + """ + self._check_compiler() + body = [] + if decl: + body.append("int %s ();" % func) + body.append("int main () {") + if call: + body.append(" %s();" % func) + else: + body.append(" %s;" % func) + body.append("}") + body = "\n".join(body) + "\n" + + return self.try_link(body, headers, include_dirs, + libraries, library_dirs) + + def check_lib(self, library, library_dirs=None, headers=None, + include_dirs=None, other_libraries=[]): + """Determine if 'library' is available to be linked against, + without actually checking that any particular symbols are provided + by it. 'headers' will be used in constructing the source file to + be compiled, but the only effect of this is to check if all the + header files listed are available. Any libraries listed in + 'other_libraries' will be included in the link, in case 'library' + has symbols that depend on other libraries. + """ + self._check_compiler() + return self.try_link("int main (void) { }", headers, include_dirs, + [library] + other_libraries, library_dirs) + + def check_header(self, header, include_dirs=None, library_dirs=None, + lang="c"): + """Determine if the system header file named by 'header_file' + exists and can be found by the preprocessor; return true if so, + false otherwise. + """ + return self.try_cpp(body="/* No body */", headers=[header], + include_dirs=include_dirs) + +def dump_file(filename, head=None): + """Dumps a file content into log.info. + + If head is not None, will be dumped before the file content. + """ + if head is None: + log.info('%s', filename) + else: + log.info(head) + file = open(filename) + try: + log.info(file.read()) + finally: + file.close() diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/install.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/install.py new file mode 100644 index 0000000000000000000000000000000000000000..866e2d597151da71af52803b39e62aa0bfc360a9 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/install.py @@ -0,0 +1,678 @@ +"""distutils.command.install + +Implements the Distutils 'install' command.""" + +import sys +import os + +from distutils import log +from distutils.core import Command +from distutils.debug import DEBUG +from distutils.sysconfig import get_config_vars +from distutils.errors import DistutilsPlatformError +from distutils.file_util import write_file +from distutils.util import convert_path, subst_vars, change_root +from distutils.util import get_platform +from distutils.errors import DistutilsOptionError + +from site import USER_BASE +from site import USER_SITE +HAS_USER_SITE = True + +WINDOWS_SCHEME = { + 'purelib': '$base/Lib/site-packages', + 'platlib': '$base/Lib/site-packages', + 'headers': '$base/Include/$dist_name', + 'scripts': '$base/Scripts', + 'data' : '$base', +} + +INSTALL_SCHEMES = { + 'unix_prefix': { + 'purelib': '$base/lib/python$py_version_short/site-packages', + 'platlib': '$platbase/$platlibdir/python$py_version_short/site-packages', + 'headers': '$base/include/python$py_version_short$abiflags/$dist_name', + 'scripts': '$base/bin', + 'data' : '$base', + }, + 'unix_home': { + 'purelib': '$base/lib/python', + 'platlib': '$base/$platlibdir/python', + 'headers': '$base/include/python/$dist_name', + 'scripts': '$base/bin', + 'data' : '$base', + }, + 'nt': WINDOWS_SCHEME, + 'pypy': { + 'purelib': '$base/site-packages', + 'platlib': '$base/site-packages', + 'headers': '$base/include/$dist_name', + 'scripts': '$base/bin', + 'data' : '$base', + }, + 'pypy_nt': { + 'purelib': '$base/site-packages', + 'platlib': '$base/site-packages', + 'headers': '$base/include/$dist_name', + 'scripts': '$base/Scripts', + 'data' : '$base', + }, + } + +# user site schemes +if HAS_USER_SITE: + INSTALL_SCHEMES['nt_user'] = { + 'purelib': '$usersite', + 'platlib': '$usersite', + 'headers': '$userbase/Python$py_version_nodot/Include/$dist_name', + 'scripts': '$userbase/Python$py_version_nodot/Scripts', + 'data' : '$userbase', + } + + INSTALL_SCHEMES['unix_user'] = { + 'purelib': '$usersite', + 'platlib': '$usersite', + 'headers': + '$userbase/include/python$py_version_short$abiflags/$dist_name', + 'scripts': '$userbase/bin', + 'data' : '$userbase', + } + +# The keys to an installation scheme; if any new types of files are to be +# installed, be sure to add an entry to every installation scheme above, +# and to SCHEME_KEYS here. +SCHEME_KEYS = ('purelib', 'platlib', 'headers', 'scripts', 'data') + + +class install(Command): + + description = "install everything from build directory" + + user_options = [ + # Select installation scheme and set base director(y|ies) + ('prefix=', None, + "installation prefix"), + ('exec-prefix=', None, + "(Unix only) prefix for platform-specific files"), + ('home=', None, + "(Unix only) home directory to install under"), + + # Or, just set the base director(y|ies) + ('install-base=', None, + "base installation directory (instead of --prefix or --home)"), + ('install-platbase=', None, + "base installation directory for platform-specific files " + + "(instead of --exec-prefix or --home)"), + ('root=', None, + "install everything relative to this alternate root directory"), + + # Or, explicitly set the installation scheme + ('install-purelib=', None, + "installation directory for pure Python module distributions"), + ('install-platlib=', None, + "installation directory for non-pure module distributions"), + ('install-lib=', None, + "installation directory for all module distributions " + + "(overrides --install-purelib and --install-platlib)"), + + ('install-headers=', None, + "installation directory for C/C++ headers"), + ('install-scripts=', None, + "installation directory for Python scripts"), + ('install-data=', None, + "installation directory for data files"), + + # Byte-compilation options -- see install_lib.py for details, as + # these are duplicated from there (but only install_lib does + # anything with them). + ('compile', 'c', "compile .py to .pyc [default]"), + ('no-compile', None, "don't compile .py files"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + + # Miscellaneous control options + ('force', 'f', + "force installation (overwrite any existing files)"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + + # Where to install documentation (eventually!) + #('doc-format=', None, "format of documentation to generate"), + #('install-man=', None, "directory for Unix man pages"), + #('install-html=', None, "directory for HTML documentation"), + #('install-info=', None, "directory for GNU info files"), + + ('record=', None, + "filename in which to record list of installed files"), + ] + + boolean_options = ['compile', 'force', 'skip-build'] + + if HAS_USER_SITE: + user_options.append(('user', None, + "install in user site-package '%s'" % USER_SITE)) + boolean_options.append('user') + + negative_opt = {'no-compile' : 'compile'} + + + def initialize_options(self): + """Initializes options.""" + # High-level options: these select both an installation base + # and scheme. + self.prefix = None + self.exec_prefix = None + self.home = None + self.user = 0 + + # These select only the installation base; it's up to the user to + # specify the installation scheme (currently, that means supplying + # the --install-{platlib,purelib,scripts,data} options). + self.install_base = None + self.install_platbase = None + self.root = None + + # These options are the actual installation directories; if not + # supplied by the user, they are filled in using the installation + # scheme implied by prefix/exec-prefix/home and the contents of + # that installation scheme. + self.install_purelib = None # for pure module distributions + self.install_platlib = None # non-pure (dists w/ extensions) + self.install_headers = None # for C/C++ headers + self.install_lib = None # set to either purelib or platlib + self.install_scripts = None + self.install_data = None + self.install_userbase = USER_BASE + self.install_usersite = USER_SITE + + self.compile = None + self.optimize = None + + # Deprecated + # These two are for putting non-packagized distributions into their + # own directory and creating a .pth file if it makes sense. + # 'extra_path' comes from the setup file; 'install_path_file' can + # be turned off if it makes no sense to install a .pth file. (But + # better to install it uselessly than to guess wrong and not + # install it when it's necessary and would be used!) Currently, + # 'install_path_file' is always true unless some outsider meddles + # with it. + self.extra_path = None + self.install_path_file = 1 + + # 'force' forces installation, even if target files are not + # out-of-date. 'skip_build' skips running the "build" command, + # handy if you know it's not necessary. 'warn_dir' (which is *not* + # a user option, it's just there so the bdist_* commands can turn + # it off) determines whether we warn about installing to a + # directory not in sys.path. + self.force = 0 + self.skip_build = 0 + self.warn_dir = 1 + + # These are only here as a conduit from the 'build' command to the + # 'install_*' commands that do the real work. ('build_base' isn't + # actually used anywhere, but it might be useful in future.) They + # are not user options, because if the user told the install + # command where the build directory is, that wouldn't affect the + # build command. + self.build_base = None + self.build_lib = None + + # Not defined yet because we don't know anything about + # documentation yet. + #self.install_man = None + #self.install_html = None + #self.install_info = None + + self.record = None + + + # -- Option finalizing methods ------------------------------------- + # (This is rather more involved than for most commands, + # because this is where the policy for installing third- + # party Python modules on various platforms given a wide + # array of user input is decided. Yes, it's quite complex!) + + def finalize_options(self): + """Finalizes options.""" + # This method (and its helpers, like 'finalize_unix()', + # 'finalize_other()', and 'select_scheme()') is where the default + # installation directories for modules, extension modules, and + # anything else we care to install from a Python module + # distribution. Thus, this code makes a pretty important policy + # statement about how third-party stuff is added to a Python + # installation! Note that the actual work of installation is done + # by the relatively simple 'install_*' commands; they just take + # their orders from the installation directory options determined + # here. + + # Check for errors/inconsistencies in the options; first, stuff + # that's wrong on any platform. + + if ((self.prefix or self.exec_prefix or self.home) and + (self.install_base or self.install_platbase)): + raise DistutilsOptionError( + "must supply either prefix/exec-prefix/home or " + + "install-base/install-platbase -- not both") + + if self.home and (self.prefix or self.exec_prefix): + raise DistutilsOptionError( + "must supply either home or prefix/exec-prefix -- not both") + + if self.user and (self.prefix or self.exec_prefix or self.home or + self.install_base or self.install_platbase): + raise DistutilsOptionError("can't combine user with prefix, " + "exec_prefix/home, or install_(plat)base") + + # Next, stuff that's wrong (or dubious) only on certain platforms. + if os.name != "posix": + if self.exec_prefix: + self.warn("exec-prefix option ignored on this platform") + self.exec_prefix = None + + # Now the interesting logic -- so interesting that we farm it out + # to other methods. The goal of these methods is to set the final + # values for the install_{lib,scripts,data,...} options, using as + # input a heady brew of prefix, exec_prefix, home, install_base, + # install_platbase, user-supplied versions of + # install_{purelib,platlib,lib,scripts,data,...}, and the + # INSTALL_SCHEME dictionary above. Phew! + + self.dump_dirs("pre-finalize_{unix,other}") + + if os.name == 'posix': + self.finalize_unix() + else: + self.finalize_other() + + self.dump_dirs("post-finalize_{unix,other}()") + + # Expand configuration variables, tilde, etc. in self.install_base + # and self.install_platbase -- that way, we can use $base or + # $platbase in the other installation directories and not worry + # about needing recursive variable expansion (shudder). + + py_version = sys.version.split()[0] + (prefix, exec_prefix) = get_config_vars('prefix', 'exec_prefix') + try: + abiflags = sys.abiflags + except AttributeError: + # sys.abiflags may not be defined on all platforms. + abiflags = '' + self.config_vars = {'dist_name': self.distribution.get_name(), + 'dist_version': self.distribution.get_version(), + 'dist_fullname': self.distribution.get_fullname(), + 'py_version': py_version, + 'py_version_short': '%d.%d' % sys.version_info[:2], + 'py_version_nodot': '%d%d' % sys.version_info[:2], + 'sys_prefix': prefix, + 'prefix': prefix, + 'sys_exec_prefix': exec_prefix, + 'exec_prefix': exec_prefix, + 'abiflags': abiflags, + 'platlibdir': getattr(sys, 'platlibdir', 'lib'), + } + + if HAS_USER_SITE: + self.config_vars['userbase'] = self.install_userbase + self.config_vars['usersite'] = self.install_usersite + + self.expand_basedirs() + + self.dump_dirs("post-expand_basedirs()") + + # Now define config vars for the base directories so we can expand + # everything else. + self.config_vars['base'] = self.install_base + self.config_vars['platbase'] = self.install_platbase + + if DEBUG: + from pprint import pprint + print("config vars:") + pprint(self.config_vars) + + # Expand "~" and configuration variables in the installation + # directories. + self.expand_dirs() + + self.dump_dirs("post-expand_dirs()") + + # Create directories in the home dir: + if self.user: + self.create_home_path() + + # Pick the actual directory to install all modules to: either + # install_purelib or install_platlib, depending on whether this + # module distribution is pure or not. Of course, if the user + # already specified install_lib, use their selection. + if self.install_lib is None: + if self.distribution.has_ext_modules(): # has extensions: non-pure + self.install_lib = self.install_platlib + else: + self.install_lib = self.install_purelib + + + # Convert directories from Unix /-separated syntax to the local + # convention. + self.convert_paths('lib', 'purelib', 'platlib', + 'scripts', 'data', 'headers', + 'userbase', 'usersite') + + # Deprecated + # Well, we're not actually fully completely finalized yet: we still + # have to deal with 'extra_path', which is the hack for allowing + # non-packagized module distributions (hello, Numerical Python!) to + # get their own directories. + self.handle_extra_path() + self.install_libbase = self.install_lib # needed for .pth file + self.install_lib = os.path.join(self.install_lib, self.extra_dirs) + + # If a new root directory was supplied, make all the installation + # dirs relative to it. + if self.root is not None: + self.change_roots('libbase', 'lib', 'purelib', 'platlib', + 'scripts', 'data', 'headers') + + self.dump_dirs("after prepending root") + + # Find out the build directories, ie. where to install from. + self.set_undefined_options('build', + ('build_base', 'build_base'), + ('build_lib', 'build_lib')) + + # Punt on doc directories for now -- after all, we're punting on + # documentation completely! + + def dump_dirs(self, msg): + """Dumps the list of user options.""" + if not DEBUG: + return + from distutils.fancy_getopt import longopt_xlate + log.debug(msg + ":") + for opt in self.user_options: + opt_name = opt[0] + if opt_name[-1] == "=": + opt_name = opt_name[0:-1] + if opt_name in self.negative_opt: + opt_name = self.negative_opt[opt_name] + opt_name = opt_name.translate(longopt_xlate) + val = not getattr(self, opt_name) + else: + opt_name = opt_name.translate(longopt_xlate) + val = getattr(self, opt_name) + log.debug(" %s: %s", opt_name, val) + + def finalize_unix(self): + """Finalizes options for posix platforms.""" + if self.install_base is not None or self.install_platbase is not None: + if ((self.install_lib is None and + self.install_purelib is None and + self.install_platlib is None) or + self.install_headers is None or + self.install_scripts is None or + self.install_data is None): + raise DistutilsOptionError( + "install-base or install-platbase supplied, but " + "installation scheme is incomplete") + return + + if self.user: + if self.install_userbase is None: + raise DistutilsPlatformError( + "User base directory is not specified") + self.install_base = self.install_platbase = self.install_userbase + self.select_scheme("unix_user") + elif self.home is not None: + self.install_base = self.install_platbase = self.home + self.select_scheme("unix_home") + else: + if self.prefix is None: + if self.exec_prefix is not None: + raise DistutilsOptionError( + "must not supply exec-prefix without prefix") + + self.prefix = os.path.normpath(sys.prefix) + self.exec_prefix = os.path.normpath(sys.exec_prefix) + + else: + if self.exec_prefix is None: + self.exec_prefix = self.prefix + + self.install_base = self.prefix + self.install_platbase = self.exec_prefix + self.select_scheme("unix_prefix") + + def finalize_other(self): + """Finalizes options for non-posix platforms""" + if self.user: + if self.install_userbase is None: + raise DistutilsPlatformError( + "User base directory is not specified") + self.install_base = self.install_platbase = self.install_userbase + self.select_scheme(os.name + "_user") + elif self.home is not None: + self.install_base = self.install_platbase = self.home + self.select_scheme("unix_home") + else: + if self.prefix is None: + self.prefix = os.path.normpath(sys.prefix) + + self.install_base = self.install_platbase = self.prefix + try: + self.select_scheme(os.name) + except KeyError: + raise DistutilsPlatformError( + "I don't know how to install stuff on '%s'" % os.name) + + def select_scheme(self, name): + """Sets the install directories by applying the install schemes.""" + # it's the caller's problem if they supply a bad name! + if (hasattr(sys, 'pypy_version_info') and + sys.version_info < (3, 8) and + not name.endswith(('_user', '_home'))): + if os.name == 'nt': + name = 'pypy_nt' + else: + name = 'pypy' + scheme = INSTALL_SCHEMES[name] + for key in SCHEME_KEYS: + attrname = 'install_' + key + if getattr(self, attrname) is None: + setattr(self, attrname, scheme[key]) + + def _expand_attrs(self, attrs): + for attr in attrs: + val = getattr(self, attr) + if val is not None: + if os.name == 'posix' or os.name == 'nt': + val = os.path.expanduser(val) + val = subst_vars(val, self.config_vars) + setattr(self, attr, val) + + def expand_basedirs(self): + """Calls `os.path.expanduser` on install_base, install_platbase and + root.""" + self._expand_attrs(['install_base', 'install_platbase', 'root']) + + def expand_dirs(self): + """Calls `os.path.expanduser` on install dirs.""" + self._expand_attrs(['install_purelib', 'install_platlib', + 'install_lib', 'install_headers', + 'install_scripts', 'install_data',]) + + def convert_paths(self, *names): + """Call `convert_path` over `names`.""" + for name in names: + attr = "install_" + name + setattr(self, attr, convert_path(getattr(self, attr))) + + def handle_extra_path(self): + """Set `path_file` and `extra_dirs` using `extra_path`.""" + if self.extra_path is None: + self.extra_path = self.distribution.extra_path + + if self.extra_path is not None: + log.warn( + "Distribution option extra_path is deprecated. " + "See issue27919 for details." + ) + if isinstance(self.extra_path, str): + self.extra_path = self.extra_path.split(',') + + if len(self.extra_path) == 1: + path_file = extra_dirs = self.extra_path[0] + elif len(self.extra_path) == 2: + path_file, extra_dirs = self.extra_path + else: + raise DistutilsOptionError( + "'extra_path' option must be a list, tuple, or " + "comma-separated string with 1 or 2 elements") + + # convert to local form in case Unix notation used (as it + # should be in setup scripts) + extra_dirs = convert_path(extra_dirs) + else: + path_file = None + extra_dirs = '' + + # XXX should we warn if path_file and not extra_dirs? (in which + # case the path file would be harmless but pointless) + self.path_file = path_file + self.extra_dirs = extra_dirs + + def change_roots(self, *names): + """Change the install directories pointed by name using root.""" + for name in names: + attr = "install_" + name + setattr(self, attr, change_root(self.root, getattr(self, attr))) + + def create_home_path(self): + """Create directories under ~.""" + if not self.user: + return + home = convert_path(os.path.expanduser("~")) + for name, path in self.config_vars.items(): + if path.startswith(home) and not os.path.isdir(path): + self.debug_print("os.makedirs('%s', 0o700)" % path) + os.makedirs(path, 0o700) + + # -- Command execution methods ------------------------------------- + + def run(self): + """Runs the command.""" + # Obviously have to build before we can install + if not self.skip_build: + self.run_command('build') + # If we built for any other platform, we can't install. + build_plat = self.distribution.get_command_obj('build').plat_name + # check warn_dir - it is a clue that the 'install' is happening + # internally, and not to sys.path, so we don't check the platform + # matches what we are running. + if self.warn_dir and build_plat != get_platform(): + raise DistutilsPlatformError("Can't install when " + "cross-compiling") + + # Run all sub-commands (at least those that need to be run) + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + if self.path_file: + self.create_path_file() + + # write list of installed files, if requested. + if self.record: + outputs = self.get_outputs() + if self.root: # strip any package prefix + root_len = len(self.root) + for counter in range(len(outputs)): + outputs[counter] = outputs[counter][root_len:] + self.execute(write_file, + (self.record, outputs), + "writing list of installed files to '%s'" % + self.record) + + sys_path = map(os.path.normpath, sys.path) + sys_path = map(os.path.normcase, sys_path) + install_lib = os.path.normcase(os.path.normpath(self.install_lib)) + if (self.warn_dir and + not (self.path_file and self.install_path_file) and + install_lib not in sys_path): + log.debug(("modules installed to '%s', which is not in " + "Python's module search path (sys.path) -- " + "you'll have to change the search path yourself"), + self.install_lib) + + def create_path_file(self): + """Creates the .pth file""" + filename = os.path.join(self.install_libbase, + self.path_file + ".pth") + if self.install_path_file: + self.execute(write_file, + (filename, [self.extra_dirs]), + "creating %s" % filename) + else: + self.warn("path file '%s' not created" % filename) + + + # -- Reporting methods --------------------------------------------- + + def get_outputs(self): + """Assembles the outputs of all the sub-commands.""" + outputs = [] + for cmd_name in self.get_sub_commands(): + cmd = self.get_finalized_command(cmd_name) + # Add the contents of cmd.get_outputs(), ensuring + # that outputs doesn't contain duplicate entries + for filename in cmd.get_outputs(): + if filename not in outputs: + outputs.append(filename) + + if self.path_file and self.install_path_file: + outputs.append(os.path.join(self.install_libbase, + self.path_file + ".pth")) + + return outputs + + def get_inputs(self): + """Returns the inputs of all the sub-commands""" + # XXX gee, this looks familiar ;-( + inputs = [] + for cmd_name in self.get_sub_commands(): + cmd = self.get_finalized_command(cmd_name) + inputs.extend(cmd.get_inputs()) + + return inputs + + # -- Predicates for sub-command list ------------------------------- + + def has_lib(self): + """Returns true if the current distribution has any Python + modules to install.""" + return (self.distribution.has_pure_modules() or + self.distribution.has_ext_modules()) + + def has_headers(self): + """Returns true if the current distribution has any headers to + install.""" + return self.distribution.has_headers() + + def has_scripts(self): + """Returns true if the current distribution has any scripts to. + install.""" + return self.distribution.has_scripts() + + def has_data(self): + """Returns true if the current distribution has any data to. + install.""" + return self.distribution.has_data_files() + + # 'sub_commands': a list of commands this command might have to run to + # get its work done. See cmd.py for more info. + sub_commands = [('install_lib', has_lib), + ('install_headers', has_headers), + ('install_scripts', has_scripts), + ('install_data', has_data), + ('install_egg_info', lambda self:True), + ] diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/install_data.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_data.py new file mode 100644 index 0000000000000000000000000000000000000000..947cd76a99e5fdde049b2b6b713ba273ea4309d5 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_data.py @@ -0,0 +1,79 @@ +"""distutils.command.install_data + +Implements the Distutils 'install_data' command, for installing +platform-independent data files.""" + +# contributed by Bastian Kleineidam + +import os +from distutils.core import Command +from distutils.util import change_root, convert_path + +class install_data(Command): + + description = "install data files" + + user_options = [ + ('install-dir=', 'd', + "base directory for installing data files " + "(default: installation base dir)"), + ('root=', None, + "install everything relative to this alternate root directory"), + ('force', 'f', "force installation (overwrite existing files)"), + ] + + boolean_options = ['force'] + + def initialize_options(self): + self.install_dir = None + self.outfiles = [] + self.root = None + self.force = 0 + self.data_files = self.distribution.data_files + self.warn_dir = 1 + + def finalize_options(self): + self.set_undefined_options('install', + ('install_data', 'install_dir'), + ('root', 'root'), + ('force', 'force'), + ) + + def run(self): + self.mkpath(self.install_dir) + for f in self.data_files: + if isinstance(f, str): + # it's a simple file, so copy it + f = convert_path(f) + if self.warn_dir: + self.warn("setup script did not provide a directory for " + "'%s' -- installing right in '%s'" % + (f, self.install_dir)) + (out, _) = self.copy_file(f, self.install_dir) + self.outfiles.append(out) + else: + # it's a tuple with path to install to and a list of files + dir = convert_path(f[0]) + if not os.path.isabs(dir): + dir = os.path.join(self.install_dir, dir) + elif self.root: + dir = change_root(self.root, dir) + self.mkpath(dir) + + if f[1] == []: + # If there are no files listed, the user must be + # trying to create an empty directory, so add the + # directory to the list of output files. + self.outfiles.append(dir) + else: + # Copy files, adding them to the list of output files. + for data in f[1]: + data = convert_path(data) + (out, _) = self.copy_file(data, dir) + self.outfiles.append(out) + + def get_inputs(self): + return self.data_files or [] + + def get_outputs(self): + return self.outfiles diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/install_egg_info.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_egg_info.py new file mode 100644 index 0000000000000000000000000000000000000000..0ddc7367cc608dac2cfb408a08c8b442278a8207 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_egg_info.py @@ -0,0 +1,77 @@ +"""distutils.command.install_egg_info + +Implements the Distutils 'install_egg_info' command, for installing +a package's PKG-INFO metadata.""" + + +from distutils.cmd import Command +from distutils import log, dir_util +import os, sys, re + +class install_egg_info(Command): + """Install an .egg-info file for the package""" + + description = "Install package's PKG-INFO metadata as an .egg-info file" + user_options = [ + ('install-dir=', 'd', "directory to install to"), + ] + + def initialize_options(self): + self.install_dir = None + + def finalize_options(self): + self.set_undefined_options('install_lib',('install_dir','install_dir')) + basename = "%s-%s-py%d.%d.egg-info" % ( + to_filename(safe_name(self.distribution.get_name())), + to_filename(safe_version(self.distribution.get_version())), + *sys.version_info[:2] + ) + self.target = os.path.join(self.install_dir, basename) + self.outputs = [self.target] + + def run(self): + target = self.target + if os.path.isdir(target) and not os.path.islink(target): + dir_util.remove_tree(target, dry_run=self.dry_run) + elif os.path.exists(target): + self.execute(os.unlink,(self.target,),"Removing "+target) + elif not os.path.isdir(self.install_dir): + self.execute(os.makedirs, (self.install_dir,), + "Creating "+self.install_dir) + log.info("Writing %s", target) + if not self.dry_run: + with open(target, 'w', encoding='UTF-8') as f: + self.distribution.metadata.write_pkg_file(f) + + def get_outputs(self): + return self.outputs + + +# The following routines are taken from setuptools' pkg_resources module and +# can be replaced by importing them from pkg_resources once it is included +# in the stdlib. + +def safe_name(name): + """Convert an arbitrary string to a standard distribution name + + Any runs of non-alphanumeric/. characters are replaced with a single '-'. + """ + return re.sub('[^A-Za-z0-9.]+', '-', name) + + +def safe_version(version): + """Convert an arbitrary string to a standard version string + + Spaces become dots, and all other non-alphanumeric characters become + dashes, with runs of multiple dashes condensed to a single dash. + """ + version = version.replace(' ','.') + return re.sub('[^A-Za-z0-9.]+', '-', version) + + +def to_filename(name): + """Convert a project or version name to its filename-escaped form + + Any '-' characters are currently replaced with '_'. + """ + return name.replace('-','_') diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/install_headers.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_headers.py new file mode 100644 index 0000000000000000000000000000000000000000..9bb0b18dc0d809dbc03d9ca355818b3bb0af573b --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_headers.py @@ -0,0 +1,47 @@ +"""distutils.command.install_headers + +Implements the Distutils 'install_headers' command, to install C/C++ header +files to the Python include directory.""" + +from distutils.core import Command + + +# XXX force is never used +class install_headers(Command): + + description = "install C/C++ header files" + + user_options = [('install-dir=', 'd', + "directory to install header files to"), + ('force', 'f', + "force installation (overwrite existing files)"), + ] + + boolean_options = ['force'] + + def initialize_options(self): + self.install_dir = None + self.force = 0 + self.outfiles = [] + + def finalize_options(self): + self.set_undefined_options('install', + ('install_headers', 'install_dir'), + ('force', 'force')) + + + def run(self): + headers = self.distribution.headers + if not headers: + return + + self.mkpath(self.install_dir) + for header in headers: + (out, _) = self.copy_file(header, self.install_dir) + self.outfiles.append(out) + + def get_inputs(self): + return self.distribution.headers or [] + + def get_outputs(self): + return self.outfiles diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/install_lib.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_lib.py new file mode 100644 index 0000000000000000000000000000000000000000..6154cf09431f72258638a927c1e360fd42c31ff3 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_lib.py @@ -0,0 +1,217 @@ +"""distutils.command.install_lib + +Implements the Distutils 'install_lib' command +(install all Python modules).""" + +import os +import importlib.util +import sys + +from distutils.core import Command +from distutils.errors import DistutilsOptionError + + +# Extension for Python source files. +PYTHON_SOURCE_EXTENSION = ".py" + +class install_lib(Command): + + description = "install all Python modules (extensions and pure Python)" + + # The byte-compilation options are a tad confusing. Here are the + # possible scenarios: + # 1) no compilation at all (--no-compile --no-optimize) + # 2) compile .pyc only (--compile --no-optimize; default) + # 3) compile .pyc and "opt-1" .pyc (--compile --optimize) + # 4) compile "opt-1" .pyc only (--no-compile --optimize) + # 5) compile .pyc and "opt-2" .pyc (--compile --optimize-more) + # 6) compile "opt-2" .pyc only (--no-compile --optimize-more) + # + # The UI for this is two options, 'compile' and 'optimize'. + # 'compile' is strictly boolean, and only decides whether to + # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and + # decides both whether to generate .pyc files and what level of + # optimization to use. + + user_options = [ + ('install-dir=', 'd', "directory to install to"), + ('build-dir=','b', "build directory (where to install from)"), + ('force', 'f', "force installation (overwrite existing files)"), + ('compile', 'c', "compile .py to .pyc [default]"), + ('no-compile', None, "don't compile .py files"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ('skip-build', None, "skip the build steps"), + ] + + boolean_options = ['force', 'compile', 'skip-build'] + negative_opt = {'no-compile' : 'compile'} + + def initialize_options(self): + # let the 'install' command dictate our installation directory + self.install_dir = None + self.build_dir = None + self.force = 0 + self.compile = None + self.optimize = None + self.skip_build = None + + def finalize_options(self): + # Get all the information we need to install pure Python modules + # from the umbrella 'install' command -- build (source) directory, + # install (target) directory, and whether to compile .py files. + self.set_undefined_options('install', + ('build_lib', 'build_dir'), + ('install_lib', 'install_dir'), + ('force', 'force'), + ('compile', 'compile'), + ('optimize', 'optimize'), + ('skip_build', 'skip_build'), + ) + + if self.compile is None: + self.compile = True + if self.optimize is None: + self.optimize = False + + if not isinstance(self.optimize, int): + try: + self.optimize = int(self.optimize) + if self.optimize not in (0, 1, 2): + raise AssertionError + except (ValueError, AssertionError): + raise DistutilsOptionError("optimize must be 0, 1, or 2") + + def run(self): + # Make sure we have built everything we need first + self.build() + + # Install everything: simply dump the entire contents of the build + # directory to the installation directory (that's the beauty of + # having a build directory!) + outfiles = self.install() + + # (Optionally) compile .py to .pyc + if outfiles is not None and self.distribution.has_pure_modules(): + self.byte_compile(outfiles) + + # -- Top-level worker functions ------------------------------------ + # (called from 'run()') + + def build(self): + if not self.skip_build: + if self.distribution.has_pure_modules(): + self.run_command('build_py') + if self.distribution.has_ext_modules(): + self.run_command('build_ext') + + def install(self): + if os.path.isdir(self.build_dir): + outfiles = self.copy_tree(self.build_dir, self.install_dir) + else: + self.warn("'%s' does not exist -- no Python modules to install" % + self.build_dir) + return + return outfiles + + def byte_compile(self, files): + if sys.dont_write_bytecode: + self.warn('byte-compiling is disabled, skipping.') + return + + from distutils.util import byte_compile + + # Get the "--root" directory supplied to the "install" command, + # and use it as a prefix to strip off the purported filename + # encoded in bytecode files. This is far from complete, but it + # should at least generate usable bytecode in RPM distributions. + install_root = self.get_finalized_command('install').root + + if self.compile: + byte_compile(files, optimize=0, + force=self.force, prefix=install_root, + dry_run=self.dry_run) + if self.optimize > 0: + byte_compile(files, optimize=self.optimize, + force=self.force, prefix=install_root, + verbose=self.verbose, dry_run=self.dry_run) + + + # -- Utility methods ----------------------------------------------- + + def _mutate_outputs(self, has_any, build_cmd, cmd_option, output_dir): + if not has_any: + return [] + + build_cmd = self.get_finalized_command(build_cmd) + build_files = build_cmd.get_outputs() + build_dir = getattr(build_cmd, cmd_option) + + prefix_len = len(build_dir) + len(os.sep) + outputs = [] + for file in build_files: + outputs.append(os.path.join(output_dir, file[prefix_len:])) + + return outputs + + def _bytecode_filenames(self, py_filenames): + bytecode_files = [] + for py_file in py_filenames: + # Since build_py handles package data installation, the + # list of outputs can contain more than just .py files. + # Make sure we only report bytecode for the .py files. + ext = os.path.splitext(os.path.normcase(py_file))[1] + if ext != PYTHON_SOURCE_EXTENSION: + continue + if self.compile: + bytecode_files.append(importlib.util.cache_from_source( + py_file, optimization='')) + if self.optimize > 0: + bytecode_files.append(importlib.util.cache_from_source( + py_file, optimization=self.optimize)) + + return bytecode_files + + + # -- External interface -------------------------------------------- + # (called by outsiders) + + def get_outputs(self): + """Return the list of files that would be installed if this command + were actually run. Not affected by the "dry-run" flag or whether + modules have actually been built yet. + """ + pure_outputs = \ + self._mutate_outputs(self.distribution.has_pure_modules(), + 'build_py', 'build_lib', + self.install_dir) + if self.compile: + bytecode_outputs = self._bytecode_filenames(pure_outputs) + else: + bytecode_outputs = [] + + ext_outputs = \ + self._mutate_outputs(self.distribution.has_ext_modules(), + 'build_ext', 'build_lib', + self.install_dir) + + return pure_outputs + bytecode_outputs + ext_outputs + + def get_inputs(self): + """Get the list of files that are input to this command, ie. the + files that get installed as they are named in the build tree. + The files in this list correspond one-to-one to the output + filenames returned by 'get_outputs()'. + """ + inputs = [] + + if self.distribution.has_pure_modules(): + build_py = self.get_finalized_command('build_py') + inputs.extend(build_py.get_outputs()) + + if self.distribution.has_ext_modules(): + build_ext = self.get_finalized_command('build_ext') + inputs.extend(build_ext.get_outputs()) + + return inputs diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/install_scripts.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_scripts.py new file mode 100644 index 0000000000000000000000000000000000000000..31a1130ee549371dffc668e515d2ae5d91799aac --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/install_scripts.py @@ -0,0 +1,60 @@ +"""distutils.command.install_scripts + +Implements the Distutils 'install_scripts' command, for installing +Python scripts.""" + +# contributed by Bastian Kleineidam + +import os +from distutils.core import Command +from distutils import log +from stat import ST_MODE + + +class install_scripts(Command): + + description = "install scripts (Python or otherwise)" + + user_options = [ + ('install-dir=', 'd', "directory to install scripts to"), + ('build-dir=','b', "build directory (where to install from)"), + ('force', 'f', "force installation (overwrite existing files)"), + ('skip-build', None, "skip the build steps"), + ] + + boolean_options = ['force', 'skip-build'] + + def initialize_options(self): + self.install_dir = None + self.force = 0 + self.build_dir = None + self.skip_build = None + + def finalize_options(self): + self.set_undefined_options('build', ('build_scripts', 'build_dir')) + self.set_undefined_options('install', + ('install_scripts', 'install_dir'), + ('force', 'force'), + ('skip_build', 'skip_build'), + ) + + def run(self): + if not self.skip_build: + self.run_command('build_scripts') + self.outfiles = self.copy_tree(self.build_dir, self.install_dir) + if os.name == 'posix': + # Set the executable bits (owner, group, and world) on + # all the scripts we just installed. + for file in self.get_outputs(): + if self.dry_run: + log.info("changing mode of %s", file) + else: + mode = ((os.stat(file)[ST_MODE]) | 0o555) & 0o7777 + log.info("changing mode of %s to %o", file, mode) + os.chmod(file, mode) + + def get_inputs(self): + return self.distribution.scripts or [] + + def get_outputs(self): + return self.outfiles or [] diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/py37compat.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/py37compat.py new file mode 100644 index 0000000000000000000000000000000000000000..754715a5084a9e4f04544ac8a4426d0871a0eb88 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/py37compat.py @@ -0,0 +1,30 @@ +import sys + + +def _pythonlib_compat(): + """ + On Python 3.7 and earlier, distutils would include the Python + library. See pypa/distutils#9. + """ + from distutils import sysconfig + if not sysconfig.get_config_var('Py_ENABLED_SHARED'): + return + + yield 'python{}.{}{}'.format( + sys.hexversion >> 24, + (sys.hexversion >> 16) & 0xff, + sysconfig.get_config_var('ABIFLAGS'), + ) + + +def compose(f1, f2): + return lambda *args, **kwargs: f1(f2(*args, **kwargs)) + + +pythonlib = ( + compose(list, _pythonlib_compat) + if sys.version_info < (3, 8) + and sys.platform != 'darwin' + and sys.platform[:3] != 'aix' + else list +) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/register.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/register.py new file mode 100644 index 0000000000000000000000000000000000000000..0fac94e9e54905688d0e359fc5a9b96b703afab5 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/register.py @@ -0,0 +1,304 @@ +"""distutils.command.register + +Implements the Distutils 'register' command (register with the repository). +""" + +# created 2002/10/21, Richard Jones + +import getpass +import io +import urllib.parse, urllib.request +from warnings import warn + +from distutils.core import PyPIRCCommand +from distutils.errors import * +from distutils import log + +class register(PyPIRCCommand): + + description = ("register the distribution with the Python package index") + user_options = PyPIRCCommand.user_options + [ + ('list-classifiers', None, + 'list the valid Trove classifiers'), + ('strict', None , + 'Will stop the registering if the meta-data are not fully compliant') + ] + boolean_options = PyPIRCCommand.boolean_options + [ + 'verify', 'list-classifiers', 'strict'] + + sub_commands = [('check', lambda self: True)] + + def initialize_options(self): + PyPIRCCommand.initialize_options(self) + self.list_classifiers = 0 + self.strict = 0 + + def finalize_options(self): + PyPIRCCommand.finalize_options(self) + # setting options for the `check` subcommand + check_options = {'strict': ('register', self.strict), + 'restructuredtext': ('register', 1)} + self.distribution.command_options['check'] = check_options + + def run(self): + self.finalize_options() + self._set_config() + + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + if self.dry_run: + self.verify_metadata() + elif self.list_classifiers: + self.classifiers() + else: + self.send_metadata() + + def check_metadata(self): + """Deprecated API.""" + warn("distutils.command.register.check_metadata is deprecated, \ + use the check command instead", PendingDeprecationWarning) + check = self.distribution.get_command_obj('check') + check.ensure_finalized() + check.strict = self.strict + check.restructuredtext = 1 + check.run() + + def _set_config(self): + ''' Reads the configuration file and set attributes. + ''' + config = self._read_pypirc() + if config != {}: + self.username = config['username'] + self.password = config['password'] + self.repository = config['repository'] + self.realm = config['realm'] + self.has_config = True + else: + if self.repository not in ('pypi', self.DEFAULT_REPOSITORY): + raise ValueError('%s not found in .pypirc' % self.repository) + if self.repository == 'pypi': + self.repository = self.DEFAULT_REPOSITORY + self.has_config = False + + def classifiers(self): + ''' Fetch the list of classifiers from the server. + ''' + url = self.repository+'?:action=list_classifiers' + response = urllib.request.urlopen(url) + log.info(self._read_pypi_response(response)) + + def verify_metadata(self): + ''' Send the metadata to the package index server to be checked. + ''' + # send the info to the server and report the result + (code, result) = self.post_to_server(self.build_post_data('verify')) + log.info('Server response (%s): %s', code, result) + + def send_metadata(self): + ''' Send the metadata to the package index server. + + Well, do the following: + 1. figure who the user is, and then + 2. send the data as a Basic auth'ed POST. + + First we try to read the username/password from $HOME/.pypirc, + which is a ConfigParser-formatted file with a section + [distutils] containing username and password entries (both + in clear text). Eg: + + [distutils] + index-servers = + pypi + + [pypi] + username: fred + password: sekrit + + Otherwise, to figure who the user is, we offer the user three + choices: + + 1. use existing login, + 2. register as a new user, or + 3. set the password to a random string and email the user. + + ''' + # see if we can short-cut and get the username/password from the + # config + if self.has_config: + choice = '1' + username = self.username + password = self.password + else: + choice = 'x' + username = password = '' + + # get the user's login info + choices = '1 2 3 4'.split() + while choice not in choices: + self.announce('''\ +We need to know who you are, so please choose either: + 1. use your existing login, + 2. register as a new user, + 3. have the server generate a new password for you (and email it to you), or + 4. quit +Your selection [default 1]: ''', log.INFO) + choice = input() + if not choice: + choice = '1' + elif choice not in choices: + print('Please choose one of the four options!') + + if choice == '1': + # get the username and password + while not username: + username = input('Username: ') + while not password: + password = getpass.getpass('Password: ') + + # set up the authentication + auth = urllib.request.HTTPPasswordMgr() + host = urllib.parse.urlparse(self.repository)[1] + auth.add_password(self.realm, host, username, password) + # send the info to the server and report the result + code, result = self.post_to_server(self.build_post_data('submit'), + auth) + self.announce('Server response (%s): %s' % (code, result), + log.INFO) + + # possibly save the login + if code == 200: + if self.has_config: + # sharing the password in the distribution instance + # so the upload command can reuse it + self.distribution.password = password + else: + self.announce(('I can store your PyPI login so future ' + 'submissions will be faster.'), log.INFO) + self.announce('(the login will be stored in %s)' % \ + self._get_rc_file(), log.INFO) + choice = 'X' + while choice.lower() not in 'yn': + choice = input('Save your login (y/N)?') + if not choice: + choice = 'n' + if choice.lower() == 'y': + self._store_pypirc(username, password) + + elif choice == '2': + data = {':action': 'user'} + data['name'] = data['password'] = data['email'] = '' + data['confirm'] = None + while not data['name']: + data['name'] = input('Username: ') + while data['password'] != data['confirm']: + while not data['password']: + data['password'] = getpass.getpass('Password: ') + while not data['confirm']: + data['confirm'] = getpass.getpass(' Confirm: ') + if data['password'] != data['confirm']: + data['password'] = '' + data['confirm'] = None + print("Password and confirm don't match!") + while not data['email']: + data['email'] = input(' EMail: ') + code, result = self.post_to_server(data) + if code != 200: + log.info('Server response (%s): %s', code, result) + else: + log.info('You will receive an email shortly.') + log.info(('Follow the instructions in it to ' + 'complete registration.')) + elif choice == '3': + data = {':action': 'password_reset'} + data['email'] = '' + while not data['email']: + data['email'] = input('Your email address: ') + code, result = self.post_to_server(data) + log.info('Server response (%s): %s', code, result) + + def build_post_data(self, action): + # figure the data to send - the metadata plus some additional + # information used by the package server + meta = self.distribution.metadata + data = { + ':action': action, + 'metadata_version' : '1.0', + 'name': meta.get_name(), + 'version': meta.get_version(), + 'summary': meta.get_description(), + 'home_page': meta.get_url(), + 'author': meta.get_contact(), + 'author_email': meta.get_contact_email(), + 'license': meta.get_licence(), + 'description': meta.get_long_description(), + 'keywords': meta.get_keywords(), + 'platform': meta.get_platforms(), + 'classifiers': meta.get_classifiers(), + 'download_url': meta.get_download_url(), + # PEP 314 + 'provides': meta.get_provides(), + 'requires': meta.get_requires(), + 'obsoletes': meta.get_obsoletes(), + } + if data['provides'] or data['requires'] or data['obsoletes']: + data['metadata_version'] = '1.1' + return data + + def post_to_server(self, data, auth=None): + ''' Post a query to the server, and return a string response. + ''' + if 'name' in data: + self.announce('Registering %s to %s' % (data['name'], + self.repository), + log.INFO) + # Build up the MIME payload for the urllib2 POST data + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = '\n--' + boundary + end_boundary = sep_boundary + '--' + body = io.StringIO() + for key, value in data.items(): + # handle multiple entries for the same name + if type(value) not in (type([]), type( () )): + value = [value] + for value in value: + value = str(value) + body.write(sep_boundary) + body.write('\nContent-Disposition: form-data; name="%s"'%key) + body.write("\n\n") + body.write(value) + if value and value[-1] == '\r': + body.write('\n') # write an extra newline (lurve Macs) + body.write(end_boundary) + body.write("\n") + body = body.getvalue().encode("utf-8") + + # build the Request + headers = { + 'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary, + 'Content-length': str(len(body)) + } + req = urllib.request.Request(self.repository, body, headers) + + # handle HTTP and include the Basic Auth handler + opener = urllib.request.build_opener( + urllib.request.HTTPBasicAuthHandler(password_mgr=auth) + ) + data = '' + try: + result = opener.open(req) + except urllib.error.HTTPError as e: + if self.show_response: + data = e.fp.read() + result = e.code, e.msg + except urllib.error.URLError as e: + result = 500, str(e) + else: + if self.show_response: + data = self._read_pypi_response(result) + result = 200, 'OK' + if self.show_response: + msg = '\n'.join(('-' * 75, data, '-' * 75)) + self.announce(msg, log.INFO) + return result diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/sdist.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/sdist.py new file mode 100644 index 0000000000000000000000000000000000000000..b4996fcb1d276c48ad5637992c313e98a2bd9d99 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/sdist.py @@ -0,0 +1,494 @@ +"""distutils.command.sdist + +Implements the Distutils 'sdist' command (create a source distribution).""" + +import os +import sys +from glob import glob +from warnings import warn + +from distutils.core import Command +from distutils import dir_util +from distutils import file_util +from distutils import archive_util +from distutils.text_file import TextFile +from distutils.filelist import FileList +from distutils import log +from distutils.util import convert_path +from distutils.errors import DistutilsTemplateError, DistutilsOptionError + + +def show_formats(): + """Print all possible values for the 'formats' option (used by + the "--help-formats" command-line option). + """ + from distutils.fancy_getopt import FancyGetopt + from distutils.archive_util import ARCHIVE_FORMATS + formats = [] + for format in ARCHIVE_FORMATS.keys(): + formats.append(("formats=" + format, None, + ARCHIVE_FORMATS[format][2])) + formats.sort() + FancyGetopt(formats).print_help( + "List of available source distribution formats:") + + +class sdist(Command): + + description = "create a source distribution (tarball, zip file, etc.)" + + def checking_metadata(self): + """Callable used for the check sub-command. + + Placed here so user_options can view it""" + return self.metadata_check + + user_options = [ + ('template=', 't', + "name of manifest template file [default: MANIFEST.in]"), + ('manifest=', 'm', + "name of manifest file [default: MANIFEST]"), + ('use-defaults', None, + "include the default file set in the manifest " + "[default; disable with --no-defaults]"), + ('no-defaults', None, + "don't include the default file set"), + ('prune', None, + "specifically exclude files/directories that should not be " + "distributed (build tree, RCS/CVS dirs, etc.) " + "[default; disable with --no-prune]"), + ('no-prune', None, + "don't automatically exclude anything"), + ('manifest-only', 'o', + "just regenerate the manifest and then stop " + "(implies --force-manifest)"), + ('force-manifest', 'f', + "forcibly regenerate the manifest and carry on as usual. " + "Deprecated: now the manifest is always regenerated."), + ('formats=', None, + "formats for source distribution (comma-separated list)"), + ('keep-temp', 'k', + "keep the distribution tree around after creating " + + "archive file(s)"), + ('dist-dir=', 'd', + "directory to put the source distribution archive(s) in " + "[default: dist]"), + ('metadata-check', None, + "Ensure that all required elements of meta-data " + "are supplied. Warn if any missing. [default]"), + ('owner=', 'u', + "Owner name used when creating a tar file [default: current user]"), + ('group=', 'g', + "Group name used when creating a tar file [default: current group]"), + ] + + boolean_options = ['use-defaults', 'prune', + 'manifest-only', 'force-manifest', + 'keep-temp', 'metadata-check'] + + help_options = [ + ('help-formats', None, + "list available distribution formats", show_formats), + ] + + negative_opt = {'no-defaults': 'use-defaults', + 'no-prune': 'prune' } + + sub_commands = [('check', checking_metadata)] + + READMES = ('README', 'README.txt', 'README.rst') + + def initialize_options(self): + # 'template' and 'manifest' are, respectively, the names of + # the manifest template and manifest file. + self.template = None + self.manifest = None + + # 'use_defaults': if true, we will include the default file set + # in the manifest + self.use_defaults = 1 + self.prune = 1 + + self.manifest_only = 0 + self.force_manifest = 0 + + self.formats = ['gztar'] + self.keep_temp = 0 + self.dist_dir = None + + self.archive_files = None + self.metadata_check = 1 + self.owner = None + self.group = None + + def finalize_options(self): + if self.manifest is None: + self.manifest = "MANIFEST" + if self.template is None: + self.template = "MANIFEST.in" + + self.ensure_string_list('formats') + + bad_format = archive_util.check_archive_formats(self.formats) + if bad_format: + raise DistutilsOptionError( + "unknown archive format '%s'" % bad_format) + + if self.dist_dir is None: + self.dist_dir = "dist" + + def run(self): + # 'filelist' contains the list of files that will make up the + # manifest + self.filelist = FileList() + + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + # Do whatever it takes to get the list of files to process + # (process the manifest template, read an existing manifest, + # whatever). File list is accumulated in 'self.filelist'. + self.get_file_list() + + # If user just wanted us to regenerate the manifest, stop now. + if self.manifest_only: + return + + # Otherwise, go ahead and create the source distribution tarball, + # or zipfile, or whatever. + self.make_distribution() + + def check_metadata(self): + """Deprecated API.""" + warn("distutils.command.sdist.check_metadata is deprecated, \ + use the check command instead", PendingDeprecationWarning) + check = self.distribution.get_command_obj('check') + check.ensure_finalized() + check.run() + + def get_file_list(self): + """Figure out the list of files to include in the source + distribution, and put it in 'self.filelist'. This might involve + reading the manifest template (and writing the manifest), or just + reading the manifest, or just using the default file set -- it all + depends on the user's options. + """ + # new behavior when using a template: + # the file list is recalculated every time because + # even if MANIFEST.in or setup.py are not changed + # the user might have added some files in the tree that + # need to be included. + # + # This makes --force the default and only behavior with templates. + template_exists = os.path.isfile(self.template) + if not template_exists and self._manifest_is_not_generated(): + self.read_manifest() + self.filelist.sort() + self.filelist.remove_duplicates() + return + + if not template_exists: + self.warn(("manifest template '%s' does not exist " + + "(using default file list)") % + self.template) + self.filelist.findall() + + if self.use_defaults: + self.add_defaults() + + if template_exists: + self.read_template() + + if self.prune: + self.prune_file_list() + + self.filelist.sort() + self.filelist.remove_duplicates() + self.write_manifest() + + def add_defaults(self): + """Add all the default files to self.filelist: + - README or README.txt + - setup.py + - test/test*.py + - all pure Python modules mentioned in setup script + - all files pointed by package_data (build_py) + - all files defined in data_files. + - all files defined as scripts. + - all C sources listed as part of extensions or C libraries + in the setup script (doesn't catch C headers!) + Warns if (README or README.txt) or setup.py are missing; everything + else is optional. + """ + self._add_defaults_standards() + self._add_defaults_optional() + self._add_defaults_python() + self._add_defaults_data_files() + self._add_defaults_ext() + self._add_defaults_c_libs() + self._add_defaults_scripts() + + @staticmethod + def _cs_path_exists(fspath): + """ + Case-sensitive path existence check + + >>> sdist._cs_path_exists(__file__) + True + >>> sdist._cs_path_exists(__file__.upper()) + False + """ + if not os.path.exists(fspath): + return False + # make absolute so we always have a directory + abspath = os.path.abspath(fspath) + directory, filename = os.path.split(abspath) + return filename in os.listdir(directory) + + def _add_defaults_standards(self): + standards = [self.READMES, self.distribution.script_name] + for fn in standards: + if isinstance(fn, tuple): + alts = fn + got_it = False + for fn in alts: + if self._cs_path_exists(fn): + got_it = True + self.filelist.append(fn) + break + + if not got_it: + self.warn("standard file not found: should have one of " + + ', '.join(alts)) + else: + if self._cs_path_exists(fn): + self.filelist.append(fn) + else: + self.warn("standard file '%s' not found" % fn) + + def _add_defaults_optional(self): + optional = ['test/test*.py', 'setup.cfg'] + for pattern in optional: + files = filter(os.path.isfile, glob(pattern)) + self.filelist.extend(files) + + def _add_defaults_python(self): + # build_py is used to get: + # - python modules + # - files defined in package_data + build_py = self.get_finalized_command('build_py') + + # getting python files + if self.distribution.has_pure_modules(): + self.filelist.extend(build_py.get_source_files()) + + # getting package_data files + # (computed in build_py.data_files by build_py.finalize_options) + for pkg, src_dir, build_dir, filenames in build_py.data_files: + for filename in filenames: + self.filelist.append(os.path.join(src_dir, filename)) + + def _add_defaults_data_files(self): + # getting distribution.data_files + if self.distribution.has_data_files(): + for item in self.distribution.data_files: + if isinstance(item, str): + # plain file + item = convert_path(item) + if os.path.isfile(item): + self.filelist.append(item) + else: + # a (dirname, filenames) tuple + dirname, filenames = item + for f in filenames: + f = convert_path(f) + if os.path.isfile(f): + self.filelist.append(f) + + def _add_defaults_ext(self): + if self.distribution.has_ext_modules(): + build_ext = self.get_finalized_command('build_ext') + self.filelist.extend(build_ext.get_source_files()) + + def _add_defaults_c_libs(self): + if self.distribution.has_c_libraries(): + build_clib = self.get_finalized_command('build_clib') + self.filelist.extend(build_clib.get_source_files()) + + def _add_defaults_scripts(self): + if self.distribution.has_scripts(): + build_scripts = self.get_finalized_command('build_scripts') + self.filelist.extend(build_scripts.get_source_files()) + + def read_template(self): + """Read and parse manifest template file named by self.template. + + (usually "MANIFEST.in") The parsing and processing is done by + 'self.filelist', which updates itself accordingly. + """ + log.info("reading manifest template '%s'", self.template) + template = TextFile(self.template, strip_comments=1, skip_blanks=1, + join_lines=1, lstrip_ws=1, rstrip_ws=1, + collapse_join=1) + + try: + while True: + line = template.readline() + if line is None: # end of file + break + + try: + self.filelist.process_template_line(line) + # the call above can raise a DistutilsTemplateError for + # malformed lines, or a ValueError from the lower-level + # convert_path function + except (DistutilsTemplateError, ValueError) as msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() + + def prune_file_list(self): + """Prune off branches that might slip into the file list as created + by 'read_template()', but really don't belong there: + * the build tree (typically "build") + * the release tree itself (only an issue if we ran "sdist" + previously with --keep-temp, or it aborted) + * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories + """ + build = self.get_finalized_command('build') + base_dir = self.distribution.get_fullname() + + self.filelist.exclude_pattern(None, prefix=build.build_base) + self.filelist.exclude_pattern(None, prefix=base_dir) + + if sys.platform == 'win32': + seps = r'/|\\' + else: + seps = '/' + + vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', + '_darcs'] + vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps) + self.filelist.exclude_pattern(vcs_ptrn, is_regex=1) + + def write_manifest(self): + """Write the file list in 'self.filelist' (presumably as filled in + by 'add_defaults()' and 'read_template()') to the manifest file + named by 'self.manifest'. + """ + if self._manifest_is_not_generated(): + log.info("not writing to manually maintained " + "manifest file '%s'" % self.manifest) + return + + content = self.filelist.files[:] + content.insert(0, '# file GENERATED by distutils, do NOT edit') + self.execute(file_util.write_file, (self.manifest, content), + "writing manifest file '%s'" % self.manifest) + + def _manifest_is_not_generated(self): + # check for special comment used in 3.1.3 and higher + if not os.path.isfile(self.manifest): + return False + + fp = open(self.manifest) + try: + first_line = fp.readline() + finally: + fp.close() + return first_line != '# file GENERATED by distutils, do NOT edit\n' + + def read_manifest(self): + """Read the manifest file (named by 'self.manifest') and use it to + fill in 'self.filelist', the list of files to include in the source + distribution. + """ + log.info("reading manifest file '%s'", self.manifest) + with open(self.manifest) as manifest: + for line in manifest: + # ignore comments and blank lines + line = line.strip() + if line.startswith('#') or not line: + continue + self.filelist.append(line) + + def make_release_tree(self, base_dir, files): + """Create the directory tree that will become the source + distribution archive. All directories implied by the filenames in + 'files' are created under 'base_dir', and then we hard link or copy + (if hard linking is unavailable) those files into place. + Essentially, this duplicates the developer's source tree, but in a + directory named after the distribution, containing only the files + to be distributed. + """ + # Create all the directories under 'base_dir' necessary to + # put 'files' there; the 'mkpath()' is just so we don't die + # if the manifest happens to be empty. + self.mkpath(base_dir) + dir_util.create_tree(base_dir, files, dry_run=self.dry_run) + + # And walk over the list of files, either making a hard link (if + # os.link exists) to each one that doesn't already exist in its + # corresponding location under 'base_dir', or copying each file + # that's out-of-date in 'base_dir'. (Usually, all files will be + # out-of-date, because by default we blow away 'base_dir' when + # we're done making the distribution archives.) + + if hasattr(os, 'link'): # can make hard links on this system + link = 'hard' + msg = "making hard links in %s..." % base_dir + else: # nope, have to copy + link = None + msg = "copying files to %s..." % base_dir + + if not files: + log.warn("no files to distribute -- empty manifest?") + else: + log.info(msg) + for file in files: + if not os.path.isfile(file): + log.warn("'%s' not a regular file -- skipping", file) + else: + dest = os.path.join(base_dir, file) + self.copy_file(file, dest, link=link) + + self.distribution.metadata.write_pkg_info(base_dir) + + def make_distribution(self): + """Create the source distribution(s). First, we create the release + tree with 'make_release_tree()'; then, we create all required + archive files (according to 'self.formats') from the release tree. + Finally, we clean up by blowing away the release tree (unless + 'self.keep_temp' is true). The list of archive files created is + stored so it can be retrieved later by 'get_archive_files()'. + """ + # Don't warn about missing meta-data here -- should be (and is!) + # done elsewhere. + base_dir = self.distribution.get_fullname() + base_name = os.path.join(self.dist_dir, base_dir) + + self.make_release_tree(base_dir, self.filelist.files) + archive_files = [] # remember names of files we create + # tar archive must be created last to avoid overwrite and remove + if 'tar' in self.formats: + self.formats.append(self.formats.pop(self.formats.index('tar'))) + + for fmt in self.formats: + file = self.make_archive(base_name, fmt, base_dir=base_dir, + owner=self.owner, group=self.group) + archive_files.append(file) + self.distribution.dist_files.append(('sdist', '', file)) + + self.archive_files = archive_files + + if not self.keep_temp: + dir_util.remove_tree(base_dir, dry_run=self.dry_run) + + def get_archive_files(self): + """Return the list of archive files created when the command + was run, or None if the command hasn't run yet. + """ + return self.archive_files diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/command/upload.py b/MLPY/Lib/site-packages/setuptools/_distutils/command/upload.py new file mode 100644 index 0000000000000000000000000000000000000000..95e9fda186fc8f5b884215f7bea251b515e72cae --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/command/upload.py @@ -0,0 +1,214 @@ +""" +distutils.command.upload + +Implements the Distutils 'upload' subcommand (upload package to a package +index). +""" + +import os +import io +import hashlib +from base64 import standard_b64encode +from urllib.request import urlopen, Request, HTTPError +from urllib.parse import urlparse +from distutils.errors import DistutilsError, DistutilsOptionError +from distutils.core import PyPIRCCommand +from distutils.spawn import spawn +from distutils import log + + +# PyPI Warehouse supports MD5, SHA256, and Blake2 (blake2-256) +# https://bugs.python.org/issue40698 +_FILE_CONTENT_DIGESTS = { + "md5_digest": getattr(hashlib, "md5", None), + "sha256_digest": getattr(hashlib, "sha256", None), + "blake2_256_digest": getattr(hashlib, "blake2b", None), +} + + +class upload(PyPIRCCommand): + + description = "upload binary package to PyPI" + + user_options = PyPIRCCommand.user_options + [ + ('sign', 's', + 'sign files to upload using gpg'), + ('identity=', 'i', 'GPG identity used to sign files'), + ] + + boolean_options = PyPIRCCommand.boolean_options + ['sign'] + + def initialize_options(self): + PyPIRCCommand.initialize_options(self) + self.username = '' + self.password = '' + self.show_response = 0 + self.sign = False + self.identity = None + + def finalize_options(self): + PyPIRCCommand.finalize_options(self) + if self.identity and not self.sign: + raise DistutilsOptionError( + "Must use --sign for --identity to have meaning" + ) + config = self._read_pypirc() + if config != {}: + self.username = config['username'] + self.password = config['password'] + self.repository = config['repository'] + self.realm = config['realm'] + + # getting the password from the distribution + # if previously set by the register command + if not self.password and self.distribution.password: + self.password = self.distribution.password + + def run(self): + if not self.distribution.dist_files: + msg = ("Must create and upload files in one command " + "(e.g. setup.py sdist upload)") + raise DistutilsOptionError(msg) + for command, pyversion, filename in self.distribution.dist_files: + self.upload_file(command, pyversion, filename) + + def upload_file(self, command, pyversion, filename): + # Makes sure the repository URL is compliant + schema, netloc, url, params, query, fragments = \ + urlparse(self.repository) + if params or query or fragments: + raise AssertionError("Incompatible url %s" % self.repository) + + if schema not in ('http', 'https'): + raise AssertionError("unsupported schema " + schema) + + # Sign if requested + if self.sign: + gpg_args = ["gpg", "--detach-sign", "-a", filename] + if self.identity: + gpg_args[2:2] = ["--local-user", self.identity] + spawn(gpg_args, + dry_run=self.dry_run) + + # Fill in the data - send all the meta-data in case we need to + # register a new release + f = open(filename,'rb') + try: + content = f.read() + finally: + f.close() + + meta = self.distribution.metadata + data = { + # action + ':action': 'file_upload', + 'protocol_version': '1', + + # identify release + 'name': meta.get_name(), + 'version': meta.get_version(), + + # file content + 'content': (os.path.basename(filename),content), + 'filetype': command, + 'pyversion': pyversion, + + # additional meta-data + 'metadata_version': '1.0', + 'summary': meta.get_description(), + 'home_page': meta.get_url(), + 'author': meta.get_contact(), + 'author_email': meta.get_contact_email(), + 'license': meta.get_licence(), + 'description': meta.get_long_description(), + 'keywords': meta.get_keywords(), + 'platform': meta.get_platforms(), + 'classifiers': meta.get_classifiers(), + 'download_url': meta.get_download_url(), + # PEP 314 + 'provides': meta.get_provides(), + 'requires': meta.get_requires(), + 'obsoletes': meta.get_obsoletes(), + } + + data['comment'] = '' + + # file content digests + for digest_name, digest_cons in _FILE_CONTENT_DIGESTS.items(): + if digest_cons is None: + continue + try: + data[digest_name] = digest_cons(content).hexdigest() + except ValueError: + # hash digest not available or blocked by security policy + pass + + if self.sign: + with open(filename + ".asc", "rb") as f: + data['gpg_signature'] = (os.path.basename(filename) + ".asc", + f.read()) + + # set up the authentication + user_pass = (self.username + ":" + self.password).encode('ascii') + # The exact encoding of the authentication string is debated. + # Anyway PyPI only accepts ascii for both username or password. + auth = "Basic " + standard_b64encode(user_pass).decode('ascii') + + # Build up the MIME payload for the POST data + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = b'\r\n--' + boundary.encode('ascii') + end_boundary = sep_boundary + b'--\r\n' + body = io.BytesIO() + for key, value in data.items(): + title = '\r\nContent-Disposition: form-data; name="%s"' % key + # handle multiple entries for the same name + if not isinstance(value, list): + value = [value] + for value in value: + if type(value) is tuple: + title += '; filename="%s"' % value[0] + value = value[1] + else: + value = str(value).encode('utf-8') + body.write(sep_boundary) + body.write(title.encode('utf-8')) + body.write(b"\r\n\r\n") + body.write(value) + body.write(end_boundary) + body = body.getvalue() + + msg = "Submitting %s to %s" % (filename, self.repository) + self.announce(msg, log.INFO) + + # build the Request + headers = { + 'Content-type': 'multipart/form-data; boundary=%s' % boundary, + 'Content-length': str(len(body)), + 'Authorization': auth, + } + + request = Request(self.repository, data=body, + headers=headers) + # send the data + try: + result = urlopen(request) + status = result.getcode() + reason = result.msg + except HTTPError as e: + status = e.code + reason = e.msg + except OSError as e: + self.announce(str(e), log.ERROR) + raise + + if status == 200: + self.announce('Server response (%s): %s' % (status, reason), + log.INFO) + if self.show_response: + text = self._read_pypi_response(result) + msg = '\n'.join(('-' * 75, text, '-' * 75)) + self.announce(msg, log.INFO) + else: + msg = 'Upload failed (%s): %s' % (status, reason) + self.announce(msg, log.ERROR) + raise DistutilsError(msg) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/config.py b/MLPY/Lib/site-packages/setuptools/_distutils/config.py new file mode 100644 index 0000000000000000000000000000000000000000..2171abd6969f6823454d704c5eea3e278bbe8005 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/config.py @@ -0,0 +1,130 @@ +"""distutils.pypirc + +Provides the PyPIRCCommand class, the base class for the command classes +that uses .pypirc in the distutils.command package. +""" +import os +from configparser import RawConfigParser + +from distutils.cmd import Command + +DEFAULT_PYPIRC = """\ +[distutils] +index-servers = + pypi + +[pypi] +username:%s +password:%s +""" + +class PyPIRCCommand(Command): + """Base command that knows how to handle the .pypirc file + """ + DEFAULT_REPOSITORY = 'https://upload.pypi.org/legacy/' + DEFAULT_REALM = 'pypi' + repository = None + realm = None + + user_options = [ + ('repository=', 'r', + "url of repository [default: %s]" % \ + DEFAULT_REPOSITORY), + ('show-response', None, + 'display full response text from server')] + + boolean_options = ['show-response'] + + def _get_rc_file(self): + """Returns rc file path.""" + return os.path.join(os.path.expanduser('~'), '.pypirc') + + def _store_pypirc(self, username, password): + """Creates a default .pypirc file.""" + rc = self._get_rc_file() + with os.fdopen(os.open(rc, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as f: + f.write(DEFAULT_PYPIRC % (username, password)) + + def _read_pypirc(self): + """Reads the .pypirc file.""" + rc = self._get_rc_file() + if os.path.exists(rc): + self.announce('Using PyPI login from %s' % rc) + repository = self.repository or self.DEFAULT_REPOSITORY + + config = RawConfigParser() + config.read(rc) + sections = config.sections() + if 'distutils' in sections: + # let's get the list of servers + index_servers = config.get('distutils', 'index-servers') + _servers = [server.strip() for server in + index_servers.split('\n') + if server.strip() != ''] + if _servers == []: + # nothing set, let's try to get the default pypi + if 'pypi' in sections: + _servers = ['pypi'] + else: + # the file is not properly defined, returning + # an empty dict + return {} + for server in _servers: + current = {'server': server} + current['username'] = config.get(server, 'username') + + # optional params + for key, default in (('repository', + self.DEFAULT_REPOSITORY), + ('realm', self.DEFAULT_REALM), + ('password', None)): + if config.has_option(server, key): + current[key] = config.get(server, key) + else: + current[key] = default + + # work around people having "repository" for the "pypi" + # section of their config set to the HTTP (rather than + # HTTPS) URL + if (server == 'pypi' and + repository in (self.DEFAULT_REPOSITORY, 'pypi')): + current['repository'] = self.DEFAULT_REPOSITORY + return current + + if (current['server'] == repository or + current['repository'] == repository): + return current + elif 'server-login' in sections: + # old format + server = 'server-login' + if config.has_option(server, 'repository'): + repository = config.get(server, 'repository') + else: + repository = self.DEFAULT_REPOSITORY + return {'username': config.get(server, 'username'), + 'password': config.get(server, 'password'), + 'repository': repository, + 'server': server, + 'realm': self.DEFAULT_REALM} + + return {} + + def _read_pypi_response(self, response): + """Read and decode a PyPI HTTP response.""" + import cgi + content_type = response.getheader('content-type', 'text/plain') + encoding = cgi.parse_header(content_type)[1].get('charset', 'ascii') + return response.read().decode(encoding) + + def initialize_options(self): + """Initialize options.""" + self.repository = None + self.realm = None + self.show_response = 0 + + def finalize_options(self): + """Finalizes options.""" + if self.repository is None: + self.repository = self.DEFAULT_REPOSITORY + if self.realm is None: + self.realm = self.DEFAULT_REALM diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/core.py b/MLPY/Lib/site-packages/setuptools/_distutils/core.py new file mode 100644 index 0000000000000000000000000000000000000000..d603d4a45a73ee4f373fbd1ef934738bda0a1991 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/core.py @@ -0,0 +1,234 @@ +"""distutils.core + +The only module that needs to be imported to use the Distutils; provides +the 'setup' function (which is to be called from the setup script). Also +indirectly provides the Distribution and Command classes, although they are +really defined in distutils.dist and distutils.cmd. +""" + +import os +import sys + +from distutils.debug import DEBUG +from distutils.errors import * + +# Mainly import these so setup scripts can "from distutils.core import" them. +from distutils.dist import Distribution +from distutils.cmd import Command +from distutils.config import PyPIRCCommand +from distutils.extension import Extension + +# This is a barebones help message generated displayed when the user +# runs the setup script with no arguments at all. More useful help +# is generated with various --help options: global help, list commands, +# and per-command help. +USAGE = """\ +usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] + or: %(script)s --help [cmd1 cmd2 ...] + or: %(script)s --help-commands + or: %(script)s cmd --help +""" + +def gen_usage (script_name): + script = os.path.basename(script_name) + return USAGE % vars() + + +# Some mild magic to control the behaviour of 'setup()' from 'run_setup()'. +_setup_stop_after = None +_setup_distribution = None + +# Legal keyword arguments for the setup() function +setup_keywords = ('distclass', 'script_name', 'script_args', 'options', + 'name', 'version', 'author', 'author_email', + 'maintainer', 'maintainer_email', 'url', 'license', + 'description', 'long_description', 'keywords', + 'platforms', 'classifiers', 'download_url', + 'requires', 'provides', 'obsoletes', + ) + +# Legal keyword arguments for the Extension constructor +extension_keywords = ('name', 'sources', 'include_dirs', + 'define_macros', 'undef_macros', + 'library_dirs', 'libraries', 'runtime_library_dirs', + 'extra_objects', 'extra_compile_args', 'extra_link_args', + 'swig_opts', 'export_symbols', 'depends', 'language') + +def setup (**attrs): + """The gateway to the Distutils: do everything your setup script needs + to do, in a highly flexible and user-driven way. Briefly: create a + Distribution instance; find and parse config files; parse the command + line; run each Distutils command found there, customized by the options + supplied to 'setup()' (as keyword arguments), in config files, and on + the command line. + + The Distribution instance might be an instance of a class supplied via + the 'distclass' keyword argument to 'setup'; if no such class is + supplied, then the Distribution class (in dist.py) is instantiated. + All other arguments to 'setup' (except for 'cmdclass') are used to set + attributes of the Distribution instance. + + The 'cmdclass' argument, if supplied, is a dictionary mapping command + names to command classes. Each command encountered on the command line + will be turned into a command class, which is in turn instantiated; any + class found in 'cmdclass' is used in place of the default, which is + (for command 'foo_bar') class 'foo_bar' in module + 'distutils.command.foo_bar'. The command class must provide a + 'user_options' attribute which is a list of option specifiers for + 'distutils.fancy_getopt'. Any command-line options between the current + and the next command are used to set attributes of the current command + object. + + When the entire command-line has been successfully parsed, calls the + 'run()' method on each command object in turn. This method will be + driven entirely by the Distribution object (which each command object + has a reference to, thanks to its constructor), and the + command-specific options that became attributes of each command + object. + """ + + global _setup_stop_after, _setup_distribution + + # Determine the distribution class -- either caller-supplied or + # our Distribution (see below). + klass = attrs.get('distclass') + if klass: + del attrs['distclass'] + else: + klass = Distribution + + if 'script_name' not in attrs: + attrs['script_name'] = os.path.basename(sys.argv[0]) + if 'script_args' not in attrs: + attrs['script_args'] = sys.argv[1:] + + # Create the Distribution instance, using the remaining arguments + # (ie. everything except distclass) to initialize it + try: + _setup_distribution = dist = klass(attrs) + except DistutilsSetupError as msg: + if 'name' not in attrs: + raise SystemExit("error in setup command: %s" % msg) + else: + raise SystemExit("error in %s setup command: %s" % \ + (attrs['name'], msg)) + + if _setup_stop_after == "init": + return dist + + # Find and parse the config file(s): they will override options from + # the setup script, but be overridden by the command line. + dist.parse_config_files() + + if DEBUG: + print("options (after parsing config files):") + dist.dump_option_dicts() + + if _setup_stop_after == "config": + return dist + + # Parse the command line and override config files; any + # command-line errors are the end user's fault, so turn them into + # SystemExit to suppress tracebacks. + try: + ok = dist.parse_command_line() + except DistutilsArgError as msg: + raise SystemExit(gen_usage(dist.script_name) + "\nerror: %s" % msg) + + if DEBUG: + print("options (after parsing command line):") + dist.dump_option_dicts() + + if _setup_stop_after == "commandline": + return dist + + # And finally, run all the commands found on the command line. + if ok: + try: + dist.run_commands() + except KeyboardInterrupt: + raise SystemExit("interrupted") + except OSError as exc: + if DEBUG: + sys.stderr.write("error: %s\n" % (exc,)) + raise + else: + raise SystemExit("error: %s" % (exc,)) + + except (DistutilsError, + CCompilerError) as msg: + if DEBUG: + raise + else: + raise SystemExit("error: " + str(msg)) + + return dist + +# setup () + + +def run_setup (script_name, script_args=None, stop_after="run"): + """Run a setup script in a somewhat controlled environment, and + return the Distribution instance that drives things. This is useful + if you need to find out the distribution meta-data (passed as + keyword args from 'script' to 'setup()', or the contents of the + config files or command-line. + + 'script_name' is a file that will be read and run with 'exec()'; + 'sys.argv[0]' will be replaced with 'script' for the duration of the + call. 'script_args' is a list of strings; if supplied, + 'sys.argv[1:]' will be replaced by 'script_args' for the duration of + the call. + + 'stop_after' tells 'setup()' when to stop processing; possible + values: + init + stop after the Distribution instance has been created and + populated with the keyword arguments to 'setup()' + config + stop after config files have been parsed (and their data + stored in the Distribution instance) + commandline + stop after the command-line ('sys.argv[1:]' or 'script_args') + have been parsed (and the data stored in the Distribution) + run [default] + stop after all commands have been run (the same as if 'setup()' + had been called in the usual way + + Returns the Distribution instance, which provides all information + used to drive the Distutils. + """ + if stop_after not in ('init', 'config', 'commandline', 'run'): + raise ValueError("invalid value for 'stop_after': %r" % (stop_after,)) + + global _setup_stop_after, _setup_distribution + _setup_stop_after = stop_after + + save_argv = sys.argv.copy() + g = {'__file__': script_name} + try: + try: + sys.argv[0] = script_name + if script_args is not None: + sys.argv[1:] = script_args + with open(script_name, 'rb') as f: + exec(f.read(), g) + finally: + sys.argv = save_argv + _setup_stop_after = None + except SystemExit: + # Hmm, should we do something if exiting with a non-zero code + # (ie. error)? + pass + + if _setup_distribution is None: + raise RuntimeError(("'distutils.core.setup()' was never called -- " + "perhaps '%s' is not a Distutils setup script?") % \ + script_name) + + # I wonder if the setup script's namespace -- g and l -- would be of + # any interest to callers? + #print "_setup_distribution:", _setup_distribution + return _setup_distribution + +# run_setup () diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py b/MLPY/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py new file mode 100644 index 0000000000000000000000000000000000000000..f1c38e390cf2fd246b7fc85ca41ef91aff3daec6 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py @@ -0,0 +1,414 @@ +"""distutils.cygwinccompiler + +Provides the CygwinCCompiler class, a subclass of UnixCCompiler that +handles the Cygwin port of the GNU C compiler to Windows. It also contains +the Mingw32CCompiler class which handles the mingw32 port of GCC (same as +cygwin in no-cygwin mode). +""" + +# problems: +# +# * if you use a msvc compiled python version (1.5.2) +# 1. you have to insert a __GNUC__ section in its config.h +# 2. you have to generate an import library for its dll +# - create a def-file for python??.dll +# - create an import library using +# dlltool --dllname python15.dll --def python15.def \ +# --output-lib libpython15.a +# +# see also http://starship.python.net/crew/kernr/mingw32/Notes.html +# +# * We put export_symbols in a def-file, and don't use +# --export-all-symbols because it doesn't worked reliable in some +# tested configurations. And because other windows compilers also +# need their symbols specified this no serious problem. +# +# tested configurations: +# +# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works +# (after patching python's config.h and for C++ some other include files) +# see also http://starship.python.net/crew/kernr/mingw32/Notes.html +# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works +# (ld doesn't support -shared, so we use dllwrap) +# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now +# - its dllwrap doesn't work, there is a bug in binutils 2.10.90 +# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html +# - using gcc -mdll instead dllwrap doesn't work without -static because +# it tries to link against dlls instead their import libraries. (If +# it finds the dll first.) +# By specifying -static we force ld to link against the import libraries, +# this is windows standard and there are normally not the necessary symbols +# in the dlls. +# *** only the version of June 2000 shows these problems +# * cygwin gcc 3.2/ld 2.13.90 works +# (ld supports -shared) +# * mingw gcc 3.2/ld 2.13 works +# (ld supports -shared) +# * llvm-mingw with Clang 11 works +# (lld supports -shared) + +import os +import sys +import copy +from subprocess import Popen, PIPE, check_output +import re + +from distutils.unixccompiler import UnixCCompiler +from distutils.file_util import write_file +from distutils.errors import (DistutilsExecError, CCompilerError, + CompileError, UnknownFileError) +from distutils.version import LooseVersion +from distutils.spawn import find_executable + +def get_msvcr(): + """Include the appropriate MSVC runtime library if Python was built + with MSVC 7.0 or later. + """ + msc_pos = sys.version.find('MSC v.') + if msc_pos != -1: + msc_ver = sys.version[msc_pos+6:msc_pos+10] + if msc_ver == '1300': + # MSVC 7.0 + return ['msvcr70'] + elif msc_ver == '1310': + # MSVC 7.1 + return ['msvcr71'] + elif msc_ver == '1400': + # VS2005 / MSVC 8.0 + return ['msvcr80'] + elif msc_ver == '1500': + # VS2008 / MSVC 9.0 + return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] + else: + raise ValueError("Unknown MS Compiler version %s " % msc_ver) + + +class CygwinCCompiler(UnixCCompiler): + """ Handles the Cygwin port of the GNU C compiler to Windows. + """ + compiler_type = 'cygwin' + obj_extension = ".o" + static_lib_extension = ".a" + shared_lib_extension = ".dll" + static_lib_format = "lib%s%s" + shared_lib_format = "%s%s" + exe_extension = ".exe" + + def __init__(self, verbose=0, dry_run=0, force=0): + + UnixCCompiler.__init__(self, verbose, dry_run, force) + + status, details = check_config_h() + self.debug_print("Python's GCC status: %s (details: %s)" % + (status, details)) + if status is not CONFIG_H_OK: + self.warn( + "Python's pyconfig.h doesn't seem to support your compiler. " + "Reason: %s. " + "Compiling may fail because of undefined preprocessor macros." + % details) + + self.cc = os.environ.get('CC', 'gcc') + self.cxx = os.environ.get('CXX', 'g++') + + if ('gcc' in self.cc): # Start gcc workaround + self.gcc_version, self.ld_version, self.dllwrap_version = \ + get_versions() + self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % + (self.gcc_version, + self.ld_version, + self.dllwrap_version) ) + + # ld_version >= "2.10.90" and < "2.13" should also be able to use + # gcc -mdll instead of dllwrap + # Older dllwraps had own version numbers, newer ones use the + # same as the rest of binutils ( also ld ) + # dllwrap 2.10.90 is buggy + if self.ld_version >= "2.10.90": + self.linker_dll = self.cc + else: + self.linker_dll = "dllwrap" + + # ld_version >= "2.13" support -shared so use it instead of + # -mdll -static + if self.ld_version >= "2.13": + shared_option = "-shared" + else: + shared_option = "-mdll -static" + else: # Assume linker is up to date + self.linker_dll = self.cc + shared_option = "-shared" + + self.set_executables(compiler='%s -mcygwin -O -Wall' % self.cc, + compiler_so='%s -mcygwin -mdll -O -Wall' % self.cc, + compiler_cxx='%s -mcygwin -O -Wall' % self.cxx, + linker_exe='%s -mcygwin' % self.cc, + linker_so=('%s -mcygwin %s' % + (self.linker_dll, shared_option))) + + # cygwin and mingw32 need different sets of libraries + if ('gcc' in self.cc and self.gcc_version == "2.91.57"): + # cygwin shouldn't need msvcrt, but without the dlls will crash + # (gcc version 2.91.57) -- perhaps something about initialization + self.dll_libraries=["msvcrt"] + self.warn( + "Consider upgrading to a newer version of gcc") + else: + # Include the appropriate MSVC runtime library if Python was built + # with MSVC 7.0 or later. + self.dll_libraries = get_msvcr() + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + """Compiles the source by spawning GCC and windres if needed.""" + if ext == '.rc' or ext == '.res': + # gcc needs '.res' and '.rc' compiled to object files !!! + try: + self.spawn(["windres", "-i", src, "-o", obj]) + except DistutilsExecError as msg: + raise CompileError(msg) + else: # for other files use the C-compiler + try: + self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + + extra_postargs) + except DistutilsExecError as msg: + raise CompileError(msg) + + def link(self, target_desc, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=0, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + """Link the objects.""" + # use separate copies, so we can modify the lists + extra_preargs = copy.copy(extra_preargs or []) + libraries = copy.copy(libraries or []) + objects = copy.copy(objects or []) + + # Additional libraries + libraries.extend(self.dll_libraries) + + # handle export symbols by creating a def-file + # with executables this only works with gcc/ld as linker + if ((export_symbols is not None) and + (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): + # (The linker doesn't do anything if output is up-to-date. + # So it would probably better to check if we really need this, + # but for this we had to insert some unchanged parts of + # UnixCCompiler, and this is not what we want.) + + # we want to put some files in the same directory as the + # object files are, build_temp doesn't help much + # where are the object files + temp_dir = os.path.dirname(objects[0]) + # name of dll to give the helper files the same base name + (dll_name, dll_extension) = os.path.splitext( + os.path.basename(output_filename)) + + # generate the filenames for these files + def_file = os.path.join(temp_dir, dll_name + ".def") + lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a") + + # Generate .def file + contents = [ + "LIBRARY %s" % os.path.basename(output_filename), + "EXPORTS"] + for sym in export_symbols: + contents.append(sym) + self.execute(write_file, (def_file, contents), + "writing %s" % def_file) + + # next add options for def-file and to creating import libraries + + # dllwrap uses different options than gcc/ld + if self.linker_dll == "dllwrap": + extra_preargs.extend(["--output-lib", lib_file]) + # for dllwrap we have to use a special option + extra_preargs.extend(["--def", def_file]) + # we use gcc/ld here and can be sure ld is >= 2.9.10 + else: + # doesn't work: bfd_close build\...\libfoo.a: Invalid operation + #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file]) + # for gcc/ld the def-file is specified as any object files + objects.append(def_file) + + #end: if ((export_symbols is not None) and + # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): + + # who wants symbols and a many times larger output file + # should explicitly switch the debug mode on + # otherwise we let dllwrap/ld strip the output file + # (On my machine: 10KiB < stripped_file < ??100KiB + # unstripped_file = stripped_file + XXX KiB + # ( XXX=254 for a typical python extension)) + if not debug: + extra_preargs.append("-s") + + UnixCCompiler.link(self, target_desc, objects, output_filename, + output_dir, libraries, library_dirs, + runtime_library_dirs, + None, # export_symbols, we do this in our def-file + debug, extra_preargs, extra_postargs, build_temp, + target_lang) + + # -- Miscellaneous methods ----------------------------------------- + + def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): + """Adds supports for rc and res files.""" + if output_dir is None: + output_dir = '' + obj_names = [] + for src_name in source_filenames: + # use normcase to make sure '.rc' is really '.rc' and not '.RC' + base, ext = os.path.splitext(os.path.normcase(src_name)) + if ext not in (self.src_extensions + ['.rc','.res']): + raise UnknownFileError("unknown file type '%s' (from '%s')" % \ + (ext, src_name)) + if strip_dir: + base = os.path.basename (base) + if ext in ('.res', '.rc'): + # these need to be compiled to object files + obj_names.append (os.path.join(output_dir, + base + ext + self.obj_extension)) + else: + obj_names.append (os.path.join(output_dir, + base + self.obj_extension)) + return obj_names + +# the same as cygwin plus some additional parameters +class Mingw32CCompiler(CygwinCCompiler): + """ Handles the Mingw32 port of the GNU C compiler to Windows. + """ + compiler_type = 'mingw32' + + def __init__(self, verbose=0, dry_run=0, force=0): + + CygwinCCompiler.__init__ (self, verbose, dry_run, force) + + # ld_version >= "2.13" support -shared so use it instead of + # -mdll -static + if ('gcc' in self.cc and self.ld_version < "2.13"): + shared_option = "-mdll -static" + else: + shared_option = "-shared" + + # A real mingw32 doesn't need to specify a different entry point, + # but cygwin 2.91.57 in no-cygwin-mode needs it. + if ('gcc' in self.cc and self.gcc_version <= "2.91.57"): + entry_point = '--entry _DllMain@12' + else: + entry_point = '' + + if is_cygwincc(self.cc): + raise CCompilerError( + 'Cygwin gcc cannot be used with --compiler=mingw32') + + self.set_executables(compiler='%s -O -Wall' % self.cc, + compiler_so='%s -mdll -O -Wall' % self.cc, + compiler_cxx='%s -O -Wall' % self.cxx, + linker_exe='%s' % self.cc, + linker_so='%s %s %s' + % (self.linker_dll, shared_option, + entry_point)) + # Maybe we should also append -mthreads, but then the finished + # dlls need another dll (mingwm10.dll see Mingw32 docs) + # (-mthreads: Support thread-safe exception handling on `Mingw32') + + # no additional libraries needed + self.dll_libraries=[] + + # Include the appropriate MSVC runtime library if Python was built + # with MSVC 7.0 or later. + self.dll_libraries = get_msvcr() + +# Because these compilers aren't configured in Python's pyconfig.h file by +# default, we should at least warn the user if he is using an unmodified +# version. + +CONFIG_H_OK = "ok" +CONFIG_H_NOTOK = "not ok" +CONFIG_H_UNCERTAIN = "uncertain" + +def check_config_h(): + """Check if the current Python installation appears amenable to building + extensions with GCC. + + Returns a tuple (status, details), where 'status' is one of the following + constants: + + - CONFIG_H_OK: all is well, go ahead and compile + - CONFIG_H_NOTOK: doesn't look good + - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h + + 'details' is a human-readable string explaining the situation. + + Note there are two ways to conclude "OK": either 'sys.version' contains + the string "GCC" (implying that this Python was built with GCC), or the + installed "pyconfig.h" contains the string "__GNUC__". + """ + + # XXX since this function also checks sys.version, it's not strictly a + # "pyconfig.h" check -- should probably be renamed... + + from distutils import sysconfig + + # if sys.version contains GCC then python was compiled with GCC, and the + # pyconfig.h file should be OK + if "GCC" in sys.version: + return CONFIG_H_OK, "sys.version mentions 'GCC'" + + # Clang would also work + if "Clang" in sys.version: + return CONFIG_H_OK, "sys.version mentions 'Clang'" + + # let's see if __GNUC__ is mentioned in python.h + fn = sysconfig.get_config_h_filename() + try: + config_h = open(fn) + try: + if "__GNUC__" in config_h.read(): + return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn + else: + return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn + finally: + config_h.close() + except OSError as exc: + return (CONFIG_H_UNCERTAIN, + "couldn't read '%s': %s" % (fn, exc.strerror)) + +RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)') + +def _find_exe_version(cmd): + """Find the version of an executable by running `cmd` in the shell. + + If the command is not found, or the output does not match + `RE_VERSION`, returns None. + """ + executable = cmd.split()[0] + if find_executable(executable) is None: + return None + out = Popen(cmd, shell=True, stdout=PIPE).stdout + try: + out_string = out.read() + finally: + out.close() + result = RE_VERSION.search(out_string) + if result is None: + return None + # LooseVersion works with strings + # so we need to decode our bytes + return LooseVersion(result.group(1).decode()) + +def get_versions(): + """ Try to find out the versions of gcc, ld and dllwrap. + + If not possible it returns None for it. + """ + commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version'] + return tuple([_find_exe_version(cmd) for cmd in commands]) + +def is_cygwincc(cc): + '''Try to determine if the compiler that would be used is from cygwin.''' + out_string = check_output([cc, '-dumpmachine']) + return out_string.strip().endswith(b'cygwin') diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/debug.py b/MLPY/Lib/site-packages/setuptools/_distutils/debug.py new file mode 100644 index 0000000000000000000000000000000000000000..daf1660f0d821143e388d37532a39ddfd2ca0347 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/debug.py @@ -0,0 +1,5 @@ +import os + +# If DISTUTILS_DEBUG is anything other than the empty string, we run in +# debug mode. +DEBUG = os.environ.get('DISTUTILS_DEBUG') diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/dep_util.py b/MLPY/Lib/site-packages/setuptools/_distutils/dep_util.py new file mode 100644 index 0000000000000000000000000000000000000000..d74f5e4e92f3edeb5a2868ac049973eef7b245cb --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/dep_util.py @@ -0,0 +1,92 @@ +"""distutils.dep_util + +Utility functions for simple, timestamp-based dependency of files +and groups of files; also, function based entirely on such +timestamp dependency analysis.""" + +import os +from distutils.errors import DistutilsFileError + + +def newer (source, target): + """Return true if 'source' exists and is more recently modified than + 'target', or if 'source' exists and 'target' doesn't. Return false if + both exist and 'target' is the same age or younger than 'source'. + Raise DistutilsFileError if 'source' does not exist. + """ + if not os.path.exists(source): + raise DistutilsFileError("file '%s' does not exist" % + os.path.abspath(source)) + if not os.path.exists(target): + return 1 + + from stat import ST_MTIME + mtime1 = os.stat(source)[ST_MTIME] + mtime2 = os.stat(target)[ST_MTIME] + + return mtime1 > mtime2 + +# newer () + + +def newer_pairwise (sources, targets): + """Walk two filename lists in parallel, testing if each source is newer + than its corresponding target. Return a pair of lists (sources, + targets) where source is newer than target, according to the semantics + of 'newer()'. + """ + if len(sources) != len(targets): + raise ValueError("'sources' and 'targets' must be same length") + + # build a pair of lists (sources, targets) where source is newer + n_sources = [] + n_targets = [] + for i in range(len(sources)): + if newer(sources[i], targets[i]): + n_sources.append(sources[i]) + n_targets.append(targets[i]) + + return (n_sources, n_targets) + +# newer_pairwise () + + +def newer_group (sources, target, missing='error'): + """Return true if 'target' is out-of-date with respect to any file + listed in 'sources'. In other words, if 'target' exists and is newer + than every file in 'sources', return false; otherwise return true. + 'missing' controls what we do when a source file is missing; the + default ("error") is to blow up with an OSError from inside 'stat()'; + if it is "ignore", we silently drop any missing source files; if it is + "newer", any missing source files make us assume that 'target' is + out-of-date (this is handy in "dry-run" mode: it'll make you pretend to + carry out commands that wouldn't work because inputs are missing, but + that doesn't matter because you're not actually going to run the + commands). + """ + # If the target doesn't even exist, then it's definitely out-of-date. + if not os.path.exists(target): + return 1 + + # Otherwise we have to find out the hard way: if *any* source file + # is more recent than 'target', then 'target' is out-of-date and + # we can immediately return true. If we fall through to the end + # of the loop, then 'target' is up-to-date and we return false. + from stat import ST_MTIME + target_mtime = os.stat(target)[ST_MTIME] + for source in sources: + if not os.path.exists(source): + if missing == 'error': # blow up when we stat() the file + pass + elif missing == 'ignore': # missing source dropped from + continue # target's dependency list + elif missing == 'newer': # missing source means target is + return 1 # out-of-date + + source_mtime = os.stat(source)[ST_MTIME] + if source_mtime > target_mtime: + return 1 + else: + return 0 + +# newer_group () diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/dir_util.py b/MLPY/Lib/site-packages/setuptools/_distutils/dir_util.py new file mode 100644 index 0000000000000000000000000000000000000000..d5cd8e3e24f46a8d4610717d76fb3ef9ad80b643 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/dir_util.py @@ -0,0 +1,210 @@ +"""distutils.dir_util + +Utility functions for manipulating directories and directory trees.""" + +import os +import errno +from distutils.errors import DistutilsFileError, DistutilsInternalError +from distutils import log + +# cache for by mkpath() -- in addition to cheapening redundant calls, +# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode +_path_created = {} + +# I don't use os.makedirs because a) it's new to Python 1.5.2, and +# b) it blows up if the directory already exists (I want to silently +# succeed in that case). +def mkpath(name, mode=0o777, verbose=1, dry_run=0): + """Create a directory and any missing ancestor directories. + + If the directory already exists (or if 'name' is the empty string, which + means the current directory, which of course exists), then do nothing. + Raise DistutilsFileError if unable to create some directory along the way + (eg. some sub-path exists, but is a file rather than a directory). + If 'verbose' is true, print a one-line summary of each mkdir to stdout. + Return the list of directories actually created. + """ + + global _path_created + + # Detect a common bug -- name is None + if not isinstance(name, str): + raise DistutilsInternalError( + "mkpath: 'name' must be a string (got %r)" % (name,)) + + # XXX what's the better way to handle verbosity? print as we create + # each directory in the path (the current behaviour), or only announce + # the creation of the whole path? (quite easy to do the latter since + # we're not using a recursive algorithm) + + name = os.path.normpath(name) + created_dirs = [] + if os.path.isdir(name) or name == '': + return created_dirs + if _path_created.get(os.path.abspath(name)): + return created_dirs + + (head, tail) = os.path.split(name) + tails = [tail] # stack of lone dirs to create + + while head and tail and not os.path.isdir(head): + (head, tail) = os.path.split(head) + tails.insert(0, tail) # push next higher dir onto stack + + # now 'head' contains the deepest directory that already exists + # (that is, the child of 'head' in 'name' is the highest directory + # that does *not* exist) + for d in tails: + #print "head = %s, d = %s: " % (head, d), + head = os.path.join(head, d) + abs_head = os.path.abspath(head) + + if _path_created.get(abs_head): + continue + + if verbose >= 1: + log.info("creating %s", head) + + if not dry_run: + try: + os.mkdir(head, mode) + except OSError as exc: + if not (exc.errno == errno.EEXIST and os.path.isdir(head)): + raise DistutilsFileError( + "could not create '%s': %s" % (head, exc.args[-1])) + created_dirs.append(head) + + _path_created[abs_head] = 1 + return created_dirs + +def create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0): + """Create all the empty directories under 'base_dir' needed to put 'files' + there. + + 'base_dir' is just the name of a directory which doesn't necessarily + exist yet; 'files' is a list of filenames to be interpreted relative to + 'base_dir'. 'base_dir' + the directory portion of every file in 'files' + will be created if it doesn't already exist. 'mode', 'verbose' and + 'dry_run' flags are as for 'mkpath()'. + """ + # First get the list of directories to create + need_dir = set() + for file in files: + need_dir.add(os.path.join(base_dir, os.path.dirname(file))) + + # Now create them + for dir in sorted(need_dir): + mkpath(dir, mode, verbose=verbose, dry_run=dry_run) + +def copy_tree(src, dst, preserve_mode=1, preserve_times=1, + preserve_symlinks=0, update=0, verbose=1, dry_run=0): + """Copy an entire directory tree 'src' to a new location 'dst'. + + Both 'src' and 'dst' must be directory names. If 'src' is not a + directory, raise DistutilsFileError. If 'dst' does not exist, it is + created with 'mkpath()'. The end result of the copy is that every + file in 'src' is copied to 'dst', and directories under 'src' are + recursively copied to 'dst'. Return the list of files that were + copied or might have been copied, using their output name. The + return value is unaffected by 'update' or 'dry_run': it is simply + the list of all files under 'src', with the names changed to be + under 'dst'. + + 'preserve_mode' and 'preserve_times' are the same as for + 'copy_file'; note that they only apply to regular files, not to + directories. If 'preserve_symlinks' is true, symlinks will be + copied as symlinks (on platforms that support them!); otherwise + (the default), the destination of the symlink will be copied. + 'update' and 'verbose' are the same as for 'copy_file'. + """ + from distutils.file_util import copy_file + + if not dry_run and not os.path.isdir(src): + raise DistutilsFileError( + "cannot copy tree '%s': not a directory" % src) + try: + names = os.listdir(src) + except OSError as e: + if dry_run: + names = [] + else: + raise DistutilsFileError( + "error listing files in '%s': %s" % (src, e.strerror)) + + if not dry_run: + mkpath(dst, verbose=verbose) + + outputs = [] + + for n in names: + src_name = os.path.join(src, n) + dst_name = os.path.join(dst, n) + + if n.startswith('.nfs'): + # skip NFS rename files + continue + + if preserve_symlinks and os.path.islink(src_name): + link_dest = os.readlink(src_name) + if verbose >= 1: + log.info("linking %s -> %s", dst_name, link_dest) + if not dry_run: + os.symlink(link_dest, dst_name) + outputs.append(dst_name) + + elif os.path.isdir(src_name): + outputs.extend( + copy_tree(src_name, dst_name, preserve_mode, + preserve_times, preserve_symlinks, update, + verbose=verbose, dry_run=dry_run)) + else: + copy_file(src_name, dst_name, preserve_mode, + preserve_times, update, verbose=verbose, + dry_run=dry_run) + outputs.append(dst_name) + + return outputs + +def _build_cmdtuple(path, cmdtuples): + """Helper for remove_tree().""" + for f in os.listdir(path): + real_f = os.path.join(path,f) + if os.path.isdir(real_f) and not os.path.islink(real_f): + _build_cmdtuple(real_f, cmdtuples) + else: + cmdtuples.append((os.remove, real_f)) + cmdtuples.append((os.rmdir, path)) + +def remove_tree(directory, verbose=1, dry_run=0): + """Recursively remove an entire directory tree. + + Any errors are ignored (apart from being reported to stdout if 'verbose' + is true). + """ + global _path_created + + if verbose >= 1: + log.info("removing '%s' (and everything under it)", directory) + if dry_run: + return + cmdtuples = [] + _build_cmdtuple(directory, cmdtuples) + for cmd in cmdtuples: + try: + cmd[0](cmd[1]) + # remove dir from cache if it's already there + abspath = os.path.abspath(cmd[1]) + if abspath in _path_created: + del _path_created[abspath] + except OSError as exc: + log.warn("error removing %s: %s", directory, exc) + +def ensure_relative(path): + """Take the full path 'path', and make it a relative path. + + This is useful to make 'path' the second argument to os.path.join(). + """ + drive, path = os.path.splitdrive(path) + if path[0:1] == os.sep: + path = drive + path[1:] + return path diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/dist.py b/MLPY/Lib/site-packages/setuptools/_distutils/dist.py new file mode 100644 index 0000000000000000000000000000000000000000..37db4d6cd7539940d5629ae1f426526a4d8d1d6f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/dist.py @@ -0,0 +1,1257 @@ +"""distutils.dist + +Provides the Distribution class, which represents the module distribution +being built/installed/distributed. +""" + +import sys +import os +import re +from email import message_from_file + +try: + import warnings +except ImportError: + warnings = None + +from distutils.errors import * +from distutils.fancy_getopt import FancyGetopt, translate_longopt +from distutils.util import check_environ, strtobool, rfc822_escape +from distutils import log +from distutils.debug import DEBUG + +# Regex to define acceptable Distutils command names. This is not *quite* +# the same as a Python NAME -- I don't allow leading underscores. The fact +# that they're very similar is no coincidence; the default naming scheme is +# to look for a Python module named after the command. +command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') + + +def _ensure_list(value, fieldname): + if isinstance(value, str): + # a string containing comma separated values is okay. It will + # be converted to a list by Distribution.finalize_options(). + pass + elif not isinstance(value, list): + # passing a tuple or an iterator perhaps, warn and convert + typename = type(value).__name__ + msg = "Warning: '{fieldname}' should be a list, got type '{typename}'" + msg = msg.format(**locals()) + log.log(log.WARN, msg) + value = list(value) + return value + + +class Distribution: + """The core of the Distutils. Most of the work hiding behind 'setup' + is really done within a Distribution instance, which farms the work out + to the Distutils commands specified on the command line. + + Setup scripts will almost never instantiate Distribution directly, + unless the 'setup()' function is totally inadequate to their needs. + However, it is conceivable that a setup script might wish to subclass + Distribution for some specialized purpose, and then pass the subclass + to 'setup()' as the 'distclass' keyword argument. If so, it is + necessary to respect the expectations that 'setup' has of Distribution. + See the code for 'setup()', in core.py, for details. + """ + + # 'global_options' describes the command-line options that may be + # supplied to the setup script prior to any actual commands. + # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of + # these global options. This list should be kept to a bare minimum, + # since every global option is also valid as a command option -- and we + # don't want to pollute the commands with too many options that they + # have minimal control over. + # The fourth entry for verbose means that it can be repeated. + global_options = [ + ('verbose', 'v', "run verbosely (default)", 1), + ('quiet', 'q', "run quietly (turns verbosity off)"), + ('dry-run', 'n', "don't actually do anything"), + ('help', 'h', "show detailed help message"), + ('no-user-cfg', None, + 'ignore pydistutils.cfg in your home directory'), + ] + + # 'common_usage' is a short (2-3 line) string describing the common + # usage of the setup script. + common_usage = """\ +Common commands: (see '--help-commands' for more) + + setup.py build will build the package underneath 'build/' + setup.py install will install the package +""" + + # options that are not propagated to the commands + display_options = [ + ('help-commands', None, + "list all available commands"), + ('name', None, + "print package name"), + ('version', 'V', + "print package version"), + ('fullname', None, + "print -"), + ('author', None, + "print the author's name"), + ('author-email', None, + "print the author's email address"), + ('maintainer', None, + "print the maintainer's name"), + ('maintainer-email', None, + "print the maintainer's email address"), + ('contact', None, + "print the maintainer's name if known, else the author's"), + ('contact-email', None, + "print the maintainer's email address if known, else the author's"), + ('url', None, + "print the URL for this package"), + ('license', None, + "print the license of the package"), + ('licence', None, + "alias for --license"), + ('description', None, + "print the package description"), + ('long-description', None, + "print the long package description"), + ('platforms', None, + "print the list of platforms"), + ('classifiers', None, + "print the list of classifiers"), + ('keywords', None, + "print the list of keywords"), + ('provides', None, + "print the list of packages/modules provided"), + ('requires', None, + "print the list of packages/modules required"), + ('obsoletes', None, + "print the list of packages/modules made obsolete") + ] + display_option_names = [translate_longopt(x[0]) for x in display_options] + + # negative options are options that exclude other options + negative_opt = {'quiet': 'verbose'} + + # -- Creation/initialization methods ------------------------------- + + def __init__(self, attrs=None): + """Construct a new Distribution instance: initialize all the + attributes of a Distribution, and then use 'attrs' (a dictionary + mapping attribute names to values) to assign some of those + attributes their "real" values. (Any attributes not mentioned in + 'attrs' will be assigned to some null value: 0, None, an empty list + or dictionary, etc.) Most importantly, initialize the + 'command_obj' attribute to the empty dictionary; this will be + filled in with real command objects by 'parse_command_line()'. + """ + + # Default values for our command-line options + self.verbose = 1 + self.dry_run = 0 + self.help = 0 + for attr in self.display_option_names: + setattr(self, attr, 0) + + # Store the distribution meta-data (name, version, author, and so + # forth) in a separate object -- we're getting to have enough + # information here (and enough command-line options) that it's + # worth it. Also delegate 'get_XXX()' methods to the 'metadata' + # object in a sneaky and underhanded (but efficient!) way. + self.metadata = DistributionMetadata() + for basename in self.metadata._METHOD_BASENAMES: + method_name = "get_" + basename + setattr(self, method_name, getattr(self.metadata, method_name)) + + # 'cmdclass' maps command names to class objects, so we + # can 1) quickly figure out which class to instantiate when + # we need to create a new command object, and 2) have a way + # for the setup script to override command classes + self.cmdclass = {} + + # 'command_packages' is a list of packages in which commands + # are searched for. The factory for command 'foo' is expected + # to be named 'foo' in the module 'foo' in one of the packages + # named here. This list is searched from the left; an error + # is raised if no named package provides the command being + # searched for. (Always access using get_command_packages().) + self.command_packages = None + + # 'script_name' and 'script_args' are usually set to sys.argv[0] + # and sys.argv[1:], but they can be overridden when the caller is + # not necessarily a setup script run from the command-line. + self.script_name = None + self.script_args = None + + # 'command_options' is where we store command options between + # parsing them (from config files, the command-line, etc.) and when + # they are actually needed -- ie. when the command in question is + # instantiated. It is a dictionary of dictionaries of 2-tuples: + # command_options = { command_name : { option : (source, value) } } + self.command_options = {} + + # 'dist_files' is the list of (command, pyversion, file) that + # have been created by any dist commands run so far. This is + # filled regardless of whether the run is dry or not. pyversion + # gives sysconfig.get_python_version() if the dist file is + # specific to a Python version, 'any' if it is good for all + # Python versions on the target platform, and '' for a source + # file. pyversion should not be used to specify minimum or + # maximum required Python versions; use the metainfo for that + # instead. + self.dist_files = [] + + # These options are really the business of various commands, rather + # than of the Distribution itself. We provide aliases for them in + # Distribution as a convenience to the developer. + self.packages = None + self.package_data = {} + self.package_dir = None + self.py_modules = None + self.libraries = None + self.headers = None + self.ext_modules = None + self.ext_package = None + self.include_dirs = None + self.extra_path = None + self.scripts = None + self.data_files = None + self.password = '' + + # And now initialize bookkeeping stuff that can't be supplied by + # the caller at all. 'command_obj' maps command names to + # Command instances -- that's how we enforce that every command + # class is a singleton. + self.command_obj = {} + + # 'have_run' maps command names to boolean values; it keeps track + # of whether we have actually run a particular command, to make it + # cheap to "run" a command whenever we think we might need to -- if + # it's already been done, no need for expensive filesystem + # operations, we just check the 'have_run' dictionary and carry on. + # It's only safe to query 'have_run' for a command class that has + # been instantiated -- a false value will be inserted when the + # command object is created, and replaced with a true value when + # the command is successfully run. Thus it's probably best to use + # '.get()' rather than a straight lookup. + self.have_run = {} + + # Now we'll use the attrs dictionary (ultimately, keyword args from + # the setup script) to possibly override any or all of these + # distribution options. + + if attrs: + # Pull out the set of command options and work on them + # specifically. Note that this order guarantees that aliased + # command options will override any supplied redundantly + # through the general options dictionary. + options = attrs.get('options') + if options is not None: + del attrs['options'] + for (command, cmd_options) in options.items(): + opt_dict = self.get_option_dict(command) + for (opt, val) in cmd_options.items(): + opt_dict[opt] = ("setup script", val) + + if 'licence' in attrs: + attrs['license'] = attrs['licence'] + del attrs['licence'] + msg = "'licence' distribution option is deprecated; use 'license'" + if warnings is not None: + warnings.warn(msg) + else: + sys.stderr.write(msg + "\n") + + # Now work on the rest of the attributes. Any attribute that's + # not already defined is invalid! + for (key, val) in attrs.items(): + if hasattr(self.metadata, "set_" + key): + getattr(self.metadata, "set_" + key)(val) + elif hasattr(self.metadata, key): + setattr(self.metadata, key, val) + elif hasattr(self, key): + setattr(self, key, val) + else: + msg = "Unknown distribution option: %s" % repr(key) + warnings.warn(msg) + + # no-user-cfg is handled before other command line args + # because other args override the config files, and this + # one is needed before we can load the config files. + # If attrs['script_args'] wasn't passed, assume false. + # + # This also make sure we just look at the global options + self.want_user_cfg = True + + if self.script_args is not None: + for arg in self.script_args: + if not arg.startswith('-'): + break + if arg == '--no-user-cfg': + self.want_user_cfg = False + break + + self.finalize_options() + + def get_option_dict(self, command): + """Get the option dictionary for a given command. If that + command's option dictionary hasn't been created yet, then create it + and return the new dictionary; otherwise, return the existing + option dictionary. + """ + dict = self.command_options.get(command) + if dict is None: + dict = self.command_options[command] = {} + return dict + + def dump_option_dicts(self, header=None, commands=None, indent=""): + from pprint import pformat + + if commands is None: # dump all command option dicts + commands = sorted(self.command_options.keys()) + + if header is not None: + self.announce(indent + header) + indent = indent + " " + + if not commands: + self.announce(indent + "no commands known yet") + return + + for cmd_name in commands: + opt_dict = self.command_options.get(cmd_name) + if opt_dict is None: + self.announce(indent + + "no option dict for '%s' command" % cmd_name) + else: + self.announce(indent + + "option dict for '%s' command:" % cmd_name) + out = pformat(opt_dict) + for line in out.split('\n'): + self.announce(indent + " " + line) + + # -- Config file finding/parsing methods --------------------------- + + def find_config_files(self): + """Find as many configuration files as should be processed for this + platform, and return a list of filenames in the order in which they + should be parsed. The filenames returned are guaranteed to exist + (modulo nasty race conditions). + + There are three possible config files: distutils.cfg in the + Distutils installation directory (ie. where the top-level + Distutils __inst__.py file lives), a file in the user's home + directory named .pydistutils.cfg on Unix and pydistutils.cfg + on Windows/Mac; and setup.cfg in the current directory. + + The file in the user's home directory can be disabled with the + --no-user-cfg option. + """ + files = [] + check_environ() + + # Where to look for the system-wide Distutils config file + sys_dir = os.path.dirname(sys.modules['distutils'].__file__) + + # Look for the system config file + sys_file = os.path.join(sys_dir, "distutils.cfg") + if os.path.isfile(sys_file): + files.append(sys_file) + + # What to call the per-user config file + if os.name == 'posix': + user_filename = ".pydistutils.cfg" + else: + user_filename = "pydistutils.cfg" + + # And look for the user config file + if self.want_user_cfg: + user_file = os.path.join(os.path.expanduser('~'), user_filename) + if os.path.isfile(user_file): + files.append(user_file) + + # All platforms support local setup.cfg + local_file = "setup.cfg" + if os.path.isfile(local_file): + files.append(local_file) + + if DEBUG: + self.announce("using config files: %s" % ', '.join(files)) + + return files + + def parse_config_files(self, filenames=None): + from configparser import ConfigParser + + # Ignore install directory options if we have a venv + if sys.prefix != sys.base_prefix: + ignore_options = [ + 'install-base', 'install-platbase', 'install-lib', + 'install-platlib', 'install-purelib', 'install-headers', + 'install-scripts', 'install-data', 'prefix', 'exec-prefix', + 'home', 'user', 'root'] + else: + ignore_options = [] + + ignore_options = frozenset(ignore_options) + + if filenames is None: + filenames = self.find_config_files() + + if DEBUG: + self.announce("Distribution.parse_config_files():") + + parser = ConfigParser() + for filename in filenames: + if DEBUG: + self.announce(" reading %s" % filename) + parser.read(filename) + for section in parser.sections(): + options = parser.options(section) + opt_dict = self.get_option_dict(section) + + for opt in options: + if opt != '__name__' and opt not in ignore_options: + val = parser.get(section,opt) + opt = opt.replace('-', '_') + opt_dict[opt] = (filename, val) + + # Make the ConfigParser forget everything (so we retain + # the original filenames that options come from) + parser.__init__() + + # If there was a "global" section in the config file, use it + # to set Distribution options. + + if 'global' in self.command_options: + for (opt, (src, val)) in self.command_options['global'].items(): + alias = self.negative_opt.get(opt) + try: + if alias: + setattr(self, alias, not strtobool(val)) + elif opt in ('verbose', 'dry_run'): # ugh! + setattr(self, opt, strtobool(val)) + else: + setattr(self, opt, val) + except ValueError as msg: + raise DistutilsOptionError(msg) + + # -- Command-line parsing methods ---------------------------------- + + def parse_command_line(self): + """Parse the setup script's command line, taken from the + 'script_args' instance attribute (which defaults to 'sys.argv[1:]' + -- see 'setup()' in core.py). This list is first processed for + "global options" -- options that set attributes of the Distribution + instance. Then, it is alternately scanned for Distutils commands + and options for that command. Each new command terminates the + options for the previous command. The allowed options for a + command are determined by the 'user_options' attribute of the + command class -- thus, we have to be able to load command classes + in order to parse the command line. Any error in that 'options' + attribute raises DistutilsGetoptError; any error on the + command-line raises DistutilsArgError. If no Distutils commands + were found on the command line, raises DistutilsArgError. Return + true if command-line was successfully parsed and we should carry + on with executing commands; false if no errors but we shouldn't + execute commands (currently, this only happens if user asks for + help). + """ + # + # We now have enough information to show the Macintosh dialog + # that allows the user to interactively specify the "command line". + # + toplevel_options = self._get_toplevel_options() + + # We have to parse the command line a bit at a time -- global + # options, then the first command, then its options, and so on -- + # because each command will be handled by a different class, and + # the options that are valid for a particular class aren't known + # until we have loaded the command class, which doesn't happen + # until we know what the command is. + + self.commands = [] + parser = FancyGetopt(toplevel_options + self.display_options) + parser.set_negative_aliases(self.negative_opt) + parser.set_aliases({'licence': 'license'}) + args = parser.getopt(args=self.script_args, object=self) + option_order = parser.get_option_order() + log.set_verbosity(self.verbose) + + # for display options we return immediately + if self.handle_display_options(option_order): + return + while args: + args = self._parse_command_opts(parser, args) + if args is None: # user asked for help (and got it) + return + + # Handle the cases of --help as a "global" option, ie. + # "setup.py --help" and "setup.py --help command ...". For the + # former, we show global options (--verbose, --dry-run, etc.) + # and display-only options (--name, --version, etc.); for the + # latter, we omit the display-only options and show help for + # each command listed on the command line. + if self.help: + self._show_help(parser, + display_options=len(self.commands) == 0, + commands=self.commands) + return + + # Oops, no commands found -- an end-user error + if not self.commands: + raise DistutilsArgError("no commands supplied") + + # All is well: return true + return True + + def _get_toplevel_options(self): + """Return the non-display options recognized at the top level. + + This includes options that are recognized *only* at the top + level as well as options recognized for commands. + """ + return self.global_options + [ + ("command-packages=", None, + "list of packages that provide distutils commands"), + ] + + def _parse_command_opts(self, parser, args): + """Parse the command-line options for a single command. + 'parser' must be a FancyGetopt instance; 'args' must be the list + of arguments, starting with the current command (whose options + we are about to parse). Returns a new version of 'args' with + the next command at the front of the list; will be the empty + list if there are no more commands on the command line. Returns + None if the user asked for help on this command. + """ + # late import because of mutual dependence between these modules + from distutils.cmd import Command + + # Pull the current command from the head of the command line + command = args[0] + if not command_re.match(command): + raise SystemExit("invalid command name '%s'" % command) + self.commands.append(command) + + # Dig up the command class that implements this command, so we + # 1) know that it's a valid command, and 2) know which options + # it takes. + try: + cmd_class = self.get_command_class(command) + except DistutilsModuleError as msg: + raise DistutilsArgError(msg) + + # Require that the command class be derived from Command -- want + # to be sure that the basic "command" interface is implemented. + if not issubclass(cmd_class, Command): + raise DistutilsClassError( + "command class %s must subclass Command" % cmd_class) + + # Also make sure that the command object provides a list of its + # known options. + if not (hasattr(cmd_class, 'user_options') and + isinstance(cmd_class.user_options, list)): + msg = ("command class %s must provide " + "'user_options' attribute (a list of tuples)") + raise DistutilsClassError(msg % cmd_class) + + # If the command class has a list of negative alias options, + # merge it in with the global negative aliases. + negative_opt = self.negative_opt + if hasattr(cmd_class, 'negative_opt'): + negative_opt = negative_opt.copy() + negative_opt.update(cmd_class.negative_opt) + + # Check for help_options in command class. They have a different + # format (tuple of four) so we need to preprocess them here. + if (hasattr(cmd_class, 'help_options') and + isinstance(cmd_class.help_options, list)): + help_options = fix_help_options(cmd_class.help_options) + else: + help_options = [] + + # All commands support the global options too, just by adding + # in 'global_options'. + parser.set_option_table(self.global_options + + cmd_class.user_options + + help_options) + parser.set_negative_aliases(negative_opt) + (args, opts) = parser.getopt(args[1:]) + if hasattr(opts, 'help') and opts.help: + self._show_help(parser, display_options=0, commands=[cmd_class]) + return + + if (hasattr(cmd_class, 'help_options') and + isinstance(cmd_class.help_options, list)): + help_option_found=0 + for (help_option, short, desc, func) in cmd_class.help_options: + if hasattr(opts, parser.get_attr_name(help_option)): + help_option_found=1 + if callable(func): + func() + else: + raise DistutilsClassError( + "invalid help function %r for help option '%s': " + "must be a callable object (function, etc.)" + % (func, help_option)) + + if help_option_found: + return + + # Put the options from the command-line into their official + # holding pen, the 'command_options' dictionary. + opt_dict = self.get_option_dict(command) + for (name, value) in vars(opts).items(): + opt_dict[name] = ("command line", value) + + return args + + def finalize_options(self): + """Set final values for all the options on the Distribution + instance, analogous to the .finalize_options() method of Command + objects. + """ + for attr in ('keywords', 'platforms'): + value = getattr(self.metadata, attr) + if value is None: + continue + if isinstance(value, str): + value = [elm.strip() for elm in value.split(',')] + setattr(self.metadata, attr, value) + + def _show_help(self, parser, global_options=1, display_options=1, + commands=[]): + """Show help for the setup script command-line in the form of + several lists of command-line options. 'parser' should be a + FancyGetopt instance; do not expect it to be returned in the + same state, as its option table will be reset to make it + generate the correct help text. + + If 'global_options' is true, lists the global options: + --verbose, --dry-run, etc. If 'display_options' is true, lists + the "display-only" options: --name, --version, etc. Finally, + lists per-command help for every command name or command class + in 'commands'. + """ + # late import because of mutual dependence between these modules + from distutils.core import gen_usage + from distutils.cmd import Command + + if global_options: + if display_options: + options = self._get_toplevel_options() + else: + options = self.global_options + parser.set_option_table(options) + parser.print_help(self.common_usage + "\nGlobal options:") + print('') + + if display_options: + parser.set_option_table(self.display_options) + parser.print_help( + "Information display options (just display " + + "information, ignore any commands)") + print('') + + for command in self.commands: + if isinstance(command, type) and issubclass(command, Command): + klass = command + else: + klass = self.get_command_class(command) + if (hasattr(klass, 'help_options') and + isinstance(klass.help_options, list)): + parser.set_option_table(klass.user_options + + fix_help_options(klass.help_options)) + else: + parser.set_option_table(klass.user_options) + parser.print_help("Options for '%s' command:" % klass.__name__) + print('') + + print(gen_usage(self.script_name)) + + def handle_display_options(self, option_order): + """If there were any non-global "display-only" options + (--help-commands or the metadata display options) on the command + line, display the requested info and return true; else return + false. + """ + from distutils.core import gen_usage + + # User just wants a list of commands -- we'll print it out and stop + # processing now (ie. if they ran "setup --help-commands foo bar", + # we ignore "foo bar"). + if self.help_commands: + self.print_commands() + print('') + print(gen_usage(self.script_name)) + return 1 + + # If user supplied any of the "display metadata" options, then + # display that metadata in the order in which the user supplied the + # metadata options. + any_display_options = 0 + is_display_option = {} + for option in self.display_options: + is_display_option[option[0]] = 1 + + for (opt, val) in option_order: + if val and is_display_option.get(opt): + opt = translate_longopt(opt) + value = getattr(self.metadata, "get_"+opt)() + if opt in ['keywords', 'platforms']: + print(','.join(value)) + elif opt in ('classifiers', 'provides', 'requires', + 'obsoletes'): + print('\n'.join(value)) + else: + print(value) + any_display_options = 1 + + return any_display_options + + def print_command_list(self, commands, header, max_length): + """Print a subset of the list of all commands -- used by + 'print_commands()'. + """ + print(header + ":") + + for cmd in commands: + klass = self.cmdclass.get(cmd) + if not klass: + klass = self.get_command_class(cmd) + try: + description = klass.description + except AttributeError: + description = "(no description available)" + + print(" %-*s %s" % (max_length, cmd, description)) + + def print_commands(self): + """Print out a help message listing all available commands with a + description of each. The list is divided into "standard commands" + (listed in distutils.command.__all__) and "extra commands" + (mentioned in self.cmdclass, but not a standard command). The + descriptions come from the command class attribute + 'description'. + """ + import distutils.command + std_commands = distutils.command.__all__ + is_std = {} + for cmd in std_commands: + is_std[cmd] = 1 + + extra_commands = [] + for cmd in self.cmdclass.keys(): + if not is_std.get(cmd): + extra_commands.append(cmd) + + max_length = 0 + for cmd in (std_commands + extra_commands): + if len(cmd) > max_length: + max_length = len(cmd) + + self.print_command_list(std_commands, + "Standard commands", + max_length) + if extra_commands: + print() + self.print_command_list(extra_commands, + "Extra commands", + max_length) + + def get_command_list(self): + """Get a list of (command, description) tuples. + The list is divided into "standard commands" (listed in + distutils.command.__all__) and "extra commands" (mentioned in + self.cmdclass, but not a standard command). The descriptions come + from the command class attribute 'description'. + """ + # Currently this is only used on Mac OS, for the Mac-only GUI + # Distutils interface (by Jack Jansen) + import distutils.command + std_commands = distutils.command.__all__ + is_std = {} + for cmd in std_commands: + is_std[cmd] = 1 + + extra_commands = [] + for cmd in self.cmdclass.keys(): + if not is_std.get(cmd): + extra_commands.append(cmd) + + rv = [] + for cmd in (std_commands + extra_commands): + klass = self.cmdclass.get(cmd) + if not klass: + klass = self.get_command_class(cmd) + try: + description = klass.description + except AttributeError: + description = "(no description available)" + rv.append((cmd, description)) + return rv + + # -- Command class/object methods ---------------------------------- + + def get_command_packages(self): + """Return a list of packages from which commands are loaded.""" + pkgs = self.command_packages + if not isinstance(pkgs, list): + if pkgs is None: + pkgs = '' + pkgs = [pkg.strip() for pkg in pkgs.split(',') if pkg != ''] + if "distutils.command" not in pkgs: + pkgs.insert(0, "distutils.command") + self.command_packages = pkgs + return pkgs + + def get_command_class(self, command): + """Return the class that implements the Distutils command named by + 'command'. First we check the 'cmdclass' dictionary; if the + command is mentioned there, we fetch the class object from the + dictionary and return it. Otherwise we load the command module + ("distutils.command." + command) and fetch the command class from + the module. The loaded class is also stored in 'cmdclass' + to speed future calls to 'get_command_class()'. + + Raises DistutilsModuleError if the expected module could not be + found, or if that module does not define the expected class. + """ + klass = self.cmdclass.get(command) + if klass: + return klass + + for pkgname in self.get_command_packages(): + module_name = "%s.%s" % (pkgname, command) + klass_name = command + + try: + __import__(module_name) + module = sys.modules[module_name] + except ImportError: + continue + + try: + klass = getattr(module, klass_name) + except AttributeError: + raise DistutilsModuleError( + "invalid command '%s' (no class '%s' in module '%s')" + % (command, klass_name, module_name)) + + self.cmdclass[command] = klass + return klass + + raise DistutilsModuleError("invalid command '%s'" % command) + + def get_command_obj(self, command, create=1): + """Return the command object for 'command'. Normally this object + is cached on a previous call to 'get_command_obj()'; if no command + object for 'command' is in the cache, then we either create and + return it (if 'create' is true) or return None. + """ + cmd_obj = self.command_obj.get(command) + if not cmd_obj and create: + if DEBUG: + self.announce("Distribution.get_command_obj(): " + "creating '%s' command object" % command) + + klass = self.get_command_class(command) + cmd_obj = self.command_obj[command] = klass(self) + self.have_run[command] = 0 + + # Set any options that were supplied in config files + # or on the command line. (NB. support for error + # reporting is lame here: any errors aren't reported + # until 'finalize_options()' is called, which means + # we won't report the source of the error.) + options = self.command_options.get(command) + if options: + self._set_command_options(cmd_obj, options) + + return cmd_obj + + def _set_command_options(self, command_obj, option_dict=None): + """Set the options for 'command_obj' from 'option_dict'. Basically + this means copying elements of a dictionary ('option_dict') to + attributes of an instance ('command'). + + 'command_obj' must be a Command instance. If 'option_dict' is not + supplied, uses the standard option dictionary for this command + (from 'self.command_options'). + """ + command_name = command_obj.get_command_name() + if option_dict is None: + option_dict = self.get_option_dict(command_name) + + if DEBUG: + self.announce(" setting options for '%s' command:" % command_name) + for (option, (source, value)) in option_dict.items(): + if DEBUG: + self.announce(" %s = %s (from %s)" % (option, value, + source)) + try: + bool_opts = [translate_longopt(o) + for o in command_obj.boolean_options] + except AttributeError: + bool_opts = [] + try: + neg_opt = command_obj.negative_opt + except AttributeError: + neg_opt = {} + + try: + is_string = isinstance(value, str) + if option in neg_opt and is_string: + setattr(command_obj, neg_opt[option], not strtobool(value)) + elif option in bool_opts and is_string: + setattr(command_obj, option, strtobool(value)) + elif hasattr(command_obj, option): + setattr(command_obj, option, value) + else: + raise DistutilsOptionError( + "error in %s: command '%s' has no such option '%s'" + % (source, command_name, option)) + except ValueError as msg: + raise DistutilsOptionError(msg) + + def reinitialize_command(self, command, reinit_subcommands=0): + """Reinitializes a command to the state it was in when first + returned by 'get_command_obj()': ie., initialized but not yet + finalized. This provides the opportunity to sneak option + values in programmatically, overriding or supplementing + user-supplied values from the config files and command line. + You'll have to re-finalize the command object (by calling + 'finalize_options()' or 'ensure_finalized()') before using it for + real. + + 'command' should be a command name (string) or command object. If + 'reinit_subcommands' is true, also reinitializes the command's + sub-commands, as declared by the 'sub_commands' class attribute (if + it has one). See the "install" command for an example. Only + reinitializes the sub-commands that actually matter, ie. those + whose test predicates return true. + + Returns the reinitialized command object. + """ + from distutils.cmd import Command + if not isinstance(command, Command): + command_name = command + command = self.get_command_obj(command_name) + else: + command_name = command.get_command_name() + + if not command.finalized: + return command + command.initialize_options() + command.finalized = 0 + self.have_run[command_name] = 0 + self._set_command_options(command) + + if reinit_subcommands: + for sub in command.get_sub_commands(): + self.reinitialize_command(sub, reinit_subcommands) + + return command + + # -- Methods that operate on the Distribution ---------------------- + + def announce(self, msg, level=log.INFO): + log.log(level, msg) + + def run_commands(self): + """Run each command that was seen on the setup script command line. + Uses the list of commands found and cache of command objects + created by 'get_command_obj()'. + """ + for cmd in self.commands: + self.run_command(cmd) + + # -- Methods that operate on its Commands -------------------------- + + def run_command(self, command): + """Do whatever it takes to run a command (including nothing at all, + if the command has already been run). Specifically: if we have + already created and run the command named by 'command', return + silently without doing anything. If the command named by 'command' + doesn't even have a command object yet, create one. Then invoke + 'run()' on that command object (or an existing one). + """ + # Already been here, done that? then return silently. + if self.have_run.get(command): + return + + log.info("running %s", command) + cmd_obj = self.get_command_obj(command) + cmd_obj.ensure_finalized() + cmd_obj.run() + self.have_run[command] = 1 + + # -- Distribution query methods ------------------------------------ + + def has_pure_modules(self): + return len(self.packages or self.py_modules or []) > 0 + + def has_ext_modules(self): + return self.ext_modules and len(self.ext_modules) > 0 + + def has_c_libraries(self): + return self.libraries and len(self.libraries) > 0 + + def has_modules(self): + return self.has_pure_modules() or self.has_ext_modules() + + def has_headers(self): + return self.headers and len(self.headers) > 0 + + def has_scripts(self): + return self.scripts and len(self.scripts) > 0 + + def has_data_files(self): + return self.data_files and len(self.data_files) > 0 + + def is_pure(self): + return (self.has_pure_modules() and + not self.has_ext_modules() and + not self.has_c_libraries()) + + # -- Metadata query methods ---------------------------------------- + + # If you're looking for 'get_name()', 'get_version()', and so forth, + # they are defined in a sneaky way: the constructor binds self.get_XXX + # to self.metadata.get_XXX. The actual code is in the + # DistributionMetadata class, below. + +class DistributionMetadata: + """Dummy class to hold the distribution meta-data: name, version, + author, and so forth. + """ + + _METHOD_BASENAMES = ("name", "version", "author", "author_email", + "maintainer", "maintainer_email", "url", + "license", "description", "long_description", + "keywords", "platforms", "fullname", "contact", + "contact_email", "classifiers", "download_url", + # PEP 314 + "provides", "requires", "obsoletes", + ) + + def __init__(self, path=None): + if path is not None: + self.read_pkg_file(open(path)) + else: + self.name = None + self.version = None + self.author = None + self.author_email = None + self.maintainer = None + self.maintainer_email = None + self.url = None + self.license = None + self.description = None + self.long_description = None + self.keywords = None + self.platforms = None + self.classifiers = None + self.download_url = None + # PEP 314 + self.provides = None + self.requires = None + self.obsoletes = None + + def read_pkg_file(self, file): + """Reads the metadata values from a file object.""" + msg = message_from_file(file) + + def _read_field(name): + value = msg[name] + if value == 'UNKNOWN': + return None + return value + + def _read_list(name): + values = msg.get_all(name, None) + if values == []: + return None + return values + + metadata_version = msg['metadata-version'] + self.name = _read_field('name') + self.version = _read_field('version') + self.description = _read_field('summary') + # we are filling author only. + self.author = _read_field('author') + self.maintainer = None + self.author_email = _read_field('author-email') + self.maintainer_email = None + self.url = _read_field('home-page') + self.license = _read_field('license') + + if 'download-url' in msg: + self.download_url = _read_field('download-url') + else: + self.download_url = None + + self.long_description = _read_field('description') + self.description = _read_field('summary') + + if 'keywords' in msg: + self.keywords = _read_field('keywords').split(',') + + self.platforms = _read_list('platform') + self.classifiers = _read_list('classifier') + + # PEP 314 - these fields only exist in 1.1 + if metadata_version == '1.1': + self.requires = _read_list('requires') + self.provides = _read_list('provides') + self.obsoletes = _read_list('obsoletes') + else: + self.requires = None + self.provides = None + self.obsoletes = None + + def write_pkg_info(self, base_dir): + """Write the PKG-INFO file into the release tree. + """ + with open(os.path.join(base_dir, 'PKG-INFO'), 'w', + encoding='UTF-8') as pkg_info: + self.write_pkg_file(pkg_info) + + def write_pkg_file(self, file): + """Write the PKG-INFO format data to a file object. + """ + version = '1.0' + if (self.provides or self.requires or self.obsoletes or + self.classifiers or self.download_url): + version = '1.1' + + file.write('Metadata-Version: %s\n' % version) + file.write('Name: %s\n' % self.get_name()) + file.write('Version: %s\n' % self.get_version()) + file.write('Summary: %s\n' % self.get_description()) + file.write('Home-page: %s\n' % self.get_url()) + file.write('Author: %s\n' % self.get_contact()) + file.write('Author-email: %s\n' % self.get_contact_email()) + file.write('License: %s\n' % self.get_license()) + if self.download_url: + file.write('Download-URL: %s\n' % self.download_url) + + long_desc = rfc822_escape(self.get_long_description()) + file.write('Description: %s\n' % long_desc) + + keywords = ','.join(self.get_keywords()) + if keywords: + file.write('Keywords: %s\n' % keywords) + + self._write_list(file, 'Platform', self.get_platforms()) + self._write_list(file, 'Classifier', self.get_classifiers()) + + # PEP 314 + self._write_list(file, 'Requires', self.get_requires()) + self._write_list(file, 'Provides', self.get_provides()) + self._write_list(file, 'Obsoletes', self.get_obsoletes()) + + def _write_list(self, file, name, values): + for value in values: + file.write('%s: %s\n' % (name, value)) + + # -- Metadata query methods ---------------------------------------- + + def get_name(self): + return self.name or "UNKNOWN" + + def get_version(self): + return self.version or "0.0.0" + + def get_fullname(self): + return "%s-%s" % (self.get_name(), self.get_version()) + + def get_author(self): + return self.author or "UNKNOWN" + + def get_author_email(self): + return self.author_email or "UNKNOWN" + + def get_maintainer(self): + return self.maintainer or "UNKNOWN" + + def get_maintainer_email(self): + return self.maintainer_email or "UNKNOWN" + + def get_contact(self): + return self.maintainer or self.author or "UNKNOWN" + + def get_contact_email(self): + return self.maintainer_email or self.author_email or "UNKNOWN" + + def get_url(self): + return self.url or "UNKNOWN" + + def get_license(self): + return self.license or "UNKNOWN" + get_licence = get_license + + def get_description(self): + return self.description or "UNKNOWN" + + def get_long_description(self): + return self.long_description or "UNKNOWN" + + def get_keywords(self): + return self.keywords or [] + + def set_keywords(self, value): + self.keywords = _ensure_list(value, 'keywords') + + def get_platforms(self): + return self.platforms or ["UNKNOWN"] + + def set_platforms(self, value): + self.platforms = _ensure_list(value, 'platforms') + + def get_classifiers(self): + return self.classifiers or [] + + def set_classifiers(self, value): + self.classifiers = _ensure_list(value, 'classifiers') + + def get_download_url(self): + return self.download_url or "UNKNOWN" + + # PEP 314 + def get_requires(self): + return self.requires or [] + + def set_requires(self, value): + import distutils.versionpredicate + for v in value: + distutils.versionpredicate.VersionPredicate(v) + self.requires = list(value) + + def get_provides(self): + return self.provides or [] + + def set_provides(self, value): + value = [v.strip() for v in value] + for v in value: + import distutils.versionpredicate + distutils.versionpredicate.split_provision(v) + self.provides = value + + def get_obsoletes(self): + return self.obsoletes or [] + + def set_obsoletes(self, value): + import distutils.versionpredicate + for v in value: + distutils.versionpredicate.VersionPredicate(v) + self.obsoletes = list(value) + +def fix_help_options(options): + """Convert a 4-tuple 'help_options' list as found in various command + classes to the 3-tuple form required by FancyGetopt. + """ + new_options = [] + for help_tuple in options: + new_options.append(help_tuple[0:3]) + return new_options diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/errors.py b/MLPY/Lib/site-packages/setuptools/_distutils/errors.py new file mode 100644 index 0000000000000000000000000000000000000000..8b93059e19faa9f821ffad1b8a298e7301fe8ab2 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/errors.py @@ -0,0 +1,97 @@ +"""distutils.errors + +Provides exceptions used by the Distutils modules. Note that Distutils +modules may raise standard exceptions; in particular, SystemExit is +usually raised for errors that are obviously the end-user's fault +(eg. bad command-line arguments). + +This module is safe to use in "from ... import *" mode; it only exports +symbols whose names start with "Distutils" and end with "Error".""" + +class DistutilsError (Exception): + """The root of all Distutils evil.""" + pass + +class DistutilsModuleError (DistutilsError): + """Unable to load an expected module, or to find an expected class + within some module (in particular, command modules and classes).""" + pass + +class DistutilsClassError (DistutilsError): + """Some command class (or possibly distribution class, if anyone + feels a need to subclass Distribution) is found not to be holding + up its end of the bargain, ie. implementing some part of the + "command "interface.""" + pass + +class DistutilsGetoptError (DistutilsError): + """The option table provided to 'fancy_getopt()' is bogus.""" + pass + +class DistutilsArgError (DistutilsError): + """Raised by fancy_getopt in response to getopt.error -- ie. an + error in the command line usage.""" + pass + +class DistutilsFileError (DistutilsError): + """Any problems in the filesystem: expected file not found, etc. + Typically this is for problems that we detect before OSError + could be raised.""" + pass + +class DistutilsOptionError (DistutilsError): + """Syntactic/semantic errors in command options, such as use of + mutually conflicting options, or inconsistent options, + badly-spelled values, etc. No distinction is made between option + values originating in the setup script, the command line, config + files, or what-have-you -- but if we *know* something originated in + the setup script, we'll raise DistutilsSetupError instead.""" + pass + +class DistutilsSetupError (DistutilsError): + """For errors that can be definitely blamed on the setup script, + such as invalid keyword arguments to 'setup()'.""" + pass + +class DistutilsPlatformError (DistutilsError): + """We don't know how to do something on the current platform (but + we do know how to do it on some platform) -- eg. trying to compile + C files on a platform not supported by a CCompiler subclass.""" + pass + +class DistutilsExecError (DistutilsError): + """Any problems executing an external program (such as the C + compiler, when compiling C files).""" + pass + +class DistutilsInternalError (DistutilsError): + """Internal inconsistencies or impossibilities (obviously, this + should never be seen if the code is working!).""" + pass + +class DistutilsTemplateError (DistutilsError): + """Syntax error in a file list template.""" + +class DistutilsByteCompileError(DistutilsError): + """Byte compile error.""" + +# Exception classes used by the CCompiler implementation classes +class CCompilerError (Exception): + """Some compile/link operation failed.""" + +class PreprocessError (CCompilerError): + """Failure to preprocess one or more C/C++ files.""" + +class CompileError (CCompilerError): + """Failure to compile one or more C/C++ source files.""" + +class LibError (CCompilerError): + """Failure to create a static library from one or more C/C++ object + files.""" + +class LinkError (CCompilerError): + """Failure to link one or more C/C++ object files into an executable + or shared library file.""" + +class UnknownFileError (CCompilerError): + """Attempt to process an unknown file type.""" diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/extension.py b/MLPY/Lib/site-packages/setuptools/_distutils/extension.py new file mode 100644 index 0000000000000000000000000000000000000000..c507da360aa3d9ccff7a6ed0249ddf03df521c39 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/extension.py @@ -0,0 +1,240 @@ +"""distutils.extension + +Provides the Extension class, used to describe C/C++ extension +modules in setup scripts.""" + +import os +import warnings + +# This class is really only used by the "build_ext" command, so it might +# make sense to put it in distutils.command.build_ext. However, that +# module is already big enough, and I want to make this class a bit more +# complex to simplify some common cases ("foo" module in "foo.c") and do +# better error-checking ("foo.c" actually exists). +# +# Also, putting this in build_ext.py means every setup script would have to +# import that large-ish module (indirectly, through distutils.core) in +# order to do anything. + +class Extension: + """Just a collection of attributes that describes an extension + module and everything needed to build it (hopefully in a portable + way, but there are hooks that let you be as unportable as you need). + + Instance attributes: + name : string + the full name of the extension, including any packages -- ie. + *not* a filename or pathname, but Python dotted name + sources : [string] + list of source filenames, relative to the distribution root + (where the setup script lives), in Unix form (slash-separated) + for portability. Source files may be C, C++, SWIG (.i), + platform-specific resource files, or whatever else is recognized + by the "build_ext" command as source for a Python extension. + include_dirs : [string] + list of directories to search for C/C++ header files (in Unix + form for portability) + define_macros : [(name : string, value : string|None)] + list of macros to define; each macro is defined using a 2-tuple, + where 'value' is either the string to define it to or None to + define it without a particular value (equivalent of "#define + FOO" in source or -DFOO on Unix C compiler command line) + undef_macros : [string] + list of macros to undefine explicitly + library_dirs : [string] + list of directories to search for C/C++ libraries at link time + libraries : [string] + list of library names (not filenames or paths) to link against + runtime_library_dirs : [string] + list of directories to search for C/C++ libraries at run time + (for shared extensions, this is when the extension is loaded) + extra_objects : [string] + list of extra files to link with (eg. object files not implied + by 'sources', static library that must be explicitly specified, + binary resource files, etc.) + extra_compile_args : [string] + any extra platform- and compiler-specific information to use + when compiling the source files in 'sources'. For platforms and + compilers where "command line" makes sense, this is typically a + list of command-line arguments, but for other platforms it could + be anything. + extra_link_args : [string] + any extra platform- and compiler-specific information to use + when linking object files together to create the extension (or + to create a new static Python interpreter). Similar + interpretation as for 'extra_compile_args'. + export_symbols : [string] + list of symbols to be exported from a shared extension. Not + used on all platforms, and not generally necessary for Python + extensions, which typically export exactly one symbol: "init" + + extension_name. + swig_opts : [string] + any extra options to pass to SWIG if a source file has the .i + extension. + depends : [string] + list of files that the extension depends on + language : string + extension language (i.e. "c", "c++", "objc"). Will be detected + from the source extensions if not provided. + optional : boolean + specifies that a build failure in the extension should not abort the + build process, but simply not install the failing extension. + """ + + # When adding arguments to this constructor, be sure to update + # setup_keywords in core.py. + def __init__(self, name, sources, + include_dirs=None, + define_macros=None, + undef_macros=None, + library_dirs=None, + libraries=None, + runtime_library_dirs=None, + extra_objects=None, + extra_compile_args=None, + extra_link_args=None, + export_symbols=None, + swig_opts = None, + depends=None, + language=None, + optional=None, + **kw # To catch unknown keywords + ): + if not isinstance(name, str): + raise AssertionError("'name' must be a string") + if not (isinstance(sources, list) and + all(isinstance(v, str) for v in sources)): + raise AssertionError("'sources' must be a list of strings") + + self.name = name + self.sources = sources + self.include_dirs = include_dirs or [] + self.define_macros = define_macros or [] + self.undef_macros = undef_macros or [] + self.library_dirs = library_dirs or [] + self.libraries = libraries or [] + self.runtime_library_dirs = runtime_library_dirs or [] + self.extra_objects = extra_objects or [] + self.extra_compile_args = extra_compile_args or [] + self.extra_link_args = extra_link_args or [] + self.export_symbols = export_symbols or [] + self.swig_opts = swig_opts or [] + self.depends = depends or [] + self.language = language + self.optional = optional + + # If there are unknown keyword options, warn about them + if len(kw) > 0: + options = [repr(option) for option in kw] + options = ', '.join(sorted(options)) + msg = "Unknown Extension options: %s" % options + warnings.warn(msg) + + def __repr__(self): + return '<%s.%s(%r) at %#x>' % ( + self.__class__.__module__, + self.__class__.__qualname__, + self.name, + id(self)) + + +def read_setup_file(filename): + """Reads a Setup file and returns Extension instances.""" + from distutils.sysconfig import (parse_makefile, expand_makefile_vars, + _variable_rx) + + from distutils.text_file import TextFile + from distutils.util import split_quoted + + # First pass over the file to gather "VAR = VALUE" assignments. + vars = parse_makefile(filename) + + # Second pass to gobble up the real content: lines of the form + # ... [ ...] [ ...] [ ...] + file = TextFile(filename, + strip_comments=1, skip_blanks=1, join_lines=1, + lstrip_ws=1, rstrip_ws=1) + try: + extensions = [] + + while True: + line = file.readline() + if line is None: # eof + break + if _variable_rx.match(line): # VAR=VALUE, handled in first pass + continue + + if line[0] == line[-1] == "*": + file.warn("'%s' lines not handled yet" % line) + continue + + line = expand_makefile_vars(line, vars) + words = split_quoted(line) + + # NB. this parses a slightly different syntax than the old + # makesetup script: here, there must be exactly one extension per + # line, and it must be the first word of the line. I have no idea + # why the old syntax supported multiple extensions per line, as + # they all wind up being the same. + + module = words[0] + ext = Extension(module, []) + append_next_word = None + + for word in words[1:]: + if append_next_word is not None: + append_next_word.append(word) + append_next_word = None + continue + + suffix = os.path.splitext(word)[1] + switch = word[0:2] ; value = word[2:] + + if suffix in (".c", ".cc", ".cpp", ".cxx", ".c++", ".m", ".mm"): + # hmm, should we do something about C vs. C++ sources? + # or leave it up to the CCompiler implementation to + # worry about? + ext.sources.append(word) + elif switch == "-I": + ext.include_dirs.append(value) + elif switch == "-D": + equals = value.find("=") + if equals == -1: # bare "-DFOO" -- no value + ext.define_macros.append((value, None)) + else: # "-DFOO=blah" + ext.define_macros.append((value[0:equals], + value[equals+2:])) + elif switch == "-U": + ext.undef_macros.append(value) + elif switch == "-C": # only here 'cause makesetup has it! + ext.extra_compile_args.append(word) + elif switch == "-l": + ext.libraries.append(value) + elif switch == "-L": + ext.library_dirs.append(value) + elif switch == "-R": + ext.runtime_library_dirs.append(value) + elif word == "-rpath": + append_next_word = ext.runtime_library_dirs + elif word == "-Xlinker": + append_next_word = ext.extra_link_args + elif word == "-Xcompiler": + append_next_word = ext.extra_compile_args + elif switch == "-u": + ext.extra_link_args.append(word) + if not value: + append_next_word = ext.extra_link_args + elif suffix in (".a", ".so", ".sl", ".o", ".dylib"): + # NB. a really faithful emulation of makesetup would + # append a .o file to extra_objects only if it + # had a slash in it; otherwise, it would s/.o/.c/ + # and append it to sources. Hmmmm. + ext.extra_objects.append(word) + else: + file.warn("unrecognized argument '%s'" % word) + + extensions.append(ext) + finally: + file.close() + + return extensions diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/fancy_getopt.py b/MLPY/Lib/site-packages/setuptools/_distutils/fancy_getopt.py new file mode 100644 index 0000000000000000000000000000000000000000..7d170dd27731a5c0d3065e017a061b8c3607e982 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/fancy_getopt.py @@ -0,0 +1,457 @@ +"""distutils.fancy_getopt + +Wrapper around the standard getopt module that provides the following +additional features: + * short and long options are tied together + * options have help strings, so fancy_getopt could potentially + create a complete usage summary + * options set attributes of a passed-in object +""" + +import sys, string, re +import getopt +from distutils.errors import * + +# Much like command_re in distutils.core, this is close to but not quite +# the same as a Python NAME -- except, in the spirit of most GNU +# utilities, we use '-' in place of '_'. (The spirit of LISP lives on!) +# The similarities to NAME are again not a coincidence... +longopt_pat = r'[a-zA-Z](?:[a-zA-Z0-9-]*)' +longopt_re = re.compile(r'^%s$' % longopt_pat) + +# For recognizing "negative alias" options, eg. "quiet=!verbose" +neg_alias_re = re.compile("^(%s)=!(%s)$" % (longopt_pat, longopt_pat)) + +# This is used to translate long options to legitimate Python identifiers +# (for use as attributes of some object). +longopt_xlate = str.maketrans('-', '_') + +class FancyGetopt: + """Wrapper around the standard 'getopt()' module that provides some + handy extra functionality: + * short and long options are tied together + * options have help strings, and help text can be assembled + from them + * options set attributes of a passed-in object + * boolean options can have "negative aliases" -- eg. if + --quiet is the "negative alias" of --verbose, then "--quiet" + on the command line sets 'verbose' to false + """ + + def __init__(self, option_table=None): + # The option table is (currently) a list of tuples. The + # tuples may have 3 or four values: + # (long_option, short_option, help_string [, repeatable]) + # if an option takes an argument, its long_option should have '=' + # appended; short_option should just be a single character, no ':' + # in any case. If a long_option doesn't have a corresponding + # short_option, short_option should be None. All option tuples + # must have long options. + self.option_table = option_table + + # 'option_index' maps long option names to entries in the option + # table (ie. those 3-tuples). + self.option_index = {} + if self.option_table: + self._build_index() + + # 'alias' records (duh) alias options; {'foo': 'bar'} means + # --foo is an alias for --bar + self.alias = {} + + # 'negative_alias' keeps track of options that are the boolean + # opposite of some other option + self.negative_alias = {} + + # These keep track of the information in the option table. We + # don't actually populate these structures until we're ready to + # parse the command-line, since the 'option_table' passed in here + # isn't necessarily the final word. + self.short_opts = [] + self.long_opts = [] + self.short2long = {} + self.attr_name = {} + self.takes_arg = {} + + # And 'option_order' is filled up in 'getopt()'; it records the + # original order of options (and their values) on the command-line, + # but expands short options, converts aliases, etc. + self.option_order = [] + + def _build_index(self): + self.option_index.clear() + for option in self.option_table: + self.option_index[option[0]] = option + + def set_option_table(self, option_table): + self.option_table = option_table + self._build_index() + + def add_option(self, long_option, short_option=None, help_string=None): + if long_option in self.option_index: + raise DistutilsGetoptError( + "option conflict: already an option '%s'" % long_option) + else: + option = (long_option, short_option, help_string) + self.option_table.append(option) + self.option_index[long_option] = option + + def has_option(self, long_option): + """Return true if the option table for this parser has an + option with long name 'long_option'.""" + return long_option in self.option_index + + def get_attr_name(self, long_option): + """Translate long option name 'long_option' to the form it + has as an attribute of some object: ie., translate hyphens + to underscores.""" + return long_option.translate(longopt_xlate) + + def _check_alias_dict(self, aliases, what): + assert isinstance(aliases, dict) + for (alias, opt) in aliases.items(): + if alias not in self.option_index: + raise DistutilsGetoptError(("invalid %s '%s': " + "option '%s' not defined") % (what, alias, alias)) + if opt not in self.option_index: + raise DistutilsGetoptError(("invalid %s '%s': " + "aliased option '%s' not defined") % (what, alias, opt)) + + def set_aliases(self, alias): + """Set the aliases for this option parser.""" + self._check_alias_dict(alias, "alias") + self.alias = alias + + def set_negative_aliases(self, negative_alias): + """Set the negative aliases for this option parser. + 'negative_alias' should be a dictionary mapping option names to + option names, both the key and value must already be defined + in the option table.""" + self._check_alias_dict(negative_alias, "negative alias") + self.negative_alias = negative_alias + + def _grok_option_table(self): + """Populate the various data structures that keep tabs on the + option table. Called by 'getopt()' before it can do anything + worthwhile. + """ + self.long_opts = [] + self.short_opts = [] + self.short2long.clear() + self.repeat = {} + + for option in self.option_table: + if len(option) == 3: + long, short, help = option + repeat = 0 + elif len(option) == 4: + long, short, help, repeat = option + else: + # the option table is part of the code, so simply + # assert that it is correct + raise ValueError("invalid option tuple: %r" % (option,)) + + # Type- and value-check the option names + if not isinstance(long, str) or len(long) < 2: + raise DistutilsGetoptError(("invalid long option '%s': " + "must be a string of length >= 2") % long) + + if (not ((short is None) or + (isinstance(short, str) and len(short) == 1))): + raise DistutilsGetoptError("invalid short option '%s': " + "must a single character or None" % short) + + self.repeat[long] = repeat + self.long_opts.append(long) + + if long[-1] == '=': # option takes an argument? + if short: short = short + ':' + long = long[0:-1] + self.takes_arg[long] = 1 + else: + # Is option is a "negative alias" for some other option (eg. + # "quiet" == "!verbose")? + alias_to = self.negative_alias.get(long) + if alias_to is not None: + if self.takes_arg[alias_to]: + raise DistutilsGetoptError( + "invalid negative alias '%s': " + "aliased option '%s' takes a value" + % (long, alias_to)) + + self.long_opts[-1] = long # XXX redundant?! + self.takes_arg[long] = 0 + + # If this is an alias option, make sure its "takes arg" flag is + # the same as the option it's aliased to. + alias_to = self.alias.get(long) + if alias_to is not None: + if self.takes_arg[long] != self.takes_arg[alias_to]: + raise DistutilsGetoptError( + "invalid alias '%s': inconsistent with " + "aliased option '%s' (one of them takes a value, " + "the other doesn't" + % (long, alias_to)) + + # Now enforce some bondage on the long option name, so we can + # later translate it to an attribute name on some object. Have + # to do this a bit late to make sure we've removed any trailing + # '='. + if not longopt_re.match(long): + raise DistutilsGetoptError( + "invalid long option name '%s' " + "(must be letters, numbers, hyphens only" % long) + + self.attr_name[long] = self.get_attr_name(long) + if short: + self.short_opts.append(short) + self.short2long[short[0]] = long + + def getopt(self, args=None, object=None): + """Parse command-line options in args. Store as attributes on object. + + If 'args' is None or not supplied, uses 'sys.argv[1:]'. If + 'object' is None or not supplied, creates a new OptionDummy + object, stores option values there, and returns a tuple (args, + object). If 'object' is supplied, it is modified in place and + 'getopt()' just returns 'args'; in both cases, the returned + 'args' is a modified copy of the passed-in 'args' list, which + is left untouched. + """ + if args is None: + args = sys.argv[1:] + if object is None: + object = OptionDummy() + created_object = True + else: + created_object = False + + self._grok_option_table() + + short_opts = ' '.join(self.short_opts) + try: + opts, args = getopt.getopt(args, short_opts, self.long_opts) + except getopt.error as msg: + raise DistutilsArgError(msg) + + for opt, val in opts: + if len(opt) == 2 and opt[0] == '-': # it's a short option + opt = self.short2long[opt[1]] + else: + assert len(opt) > 2 and opt[:2] == '--' + opt = opt[2:] + + alias = self.alias.get(opt) + if alias: + opt = alias + + if not self.takes_arg[opt]: # boolean option? + assert val == '', "boolean option can't have value" + alias = self.negative_alias.get(opt) + if alias: + opt = alias + val = 0 + else: + val = 1 + + attr = self.attr_name[opt] + # The only repeating option at the moment is 'verbose'. + # It has a negative option -q quiet, which should set verbose = 0. + if val and self.repeat.get(attr) is not None: + val = getattr(object, attr, 0) + 1 + setattr(object, attr, val) + self.option_order.append((opt, val)) + + # for opts + if created_object: + return args, object + else: + return args + + def get_option_order(self): + """Returns the list of (option, value) tuples processed by the + previous run of 'getopt()'. Raises RuntimeError if + 'getopt()' hasn't been called yet. + """ + if self.option_order is None: + raise RuntimeError("'getopt()' hasn't been called yet") + else: + return self.option_order + + def generate_help(self, header=None): + """Generate help text (a list of strings, one per suggested line of + output) from the option table for this FancyGetopt object. + """ + # Blithely assume the option table is good: probably wouldn't call + # 'generate_help()' unless you've already called 'getopt()'. + + # First pass: determine maximum length of long option names + max_opt = 0 + for option in self.option_table: + long = option[0] + short = option[1] + l = len(long) + if long[-1] == '=': + l = l - 1 + if short is not None: + l = l + 5 # " (-x)" where short == 'x' + if l > max_opt: + max_opt = l + + opt_width = max_opt + 2 + 2 + 2 # room for indent + dashes + gutter + + # Typical help block looks like this: + # --foo controls foonabulation + # Help block for longest option looks like this: + # --flimflam set the flim-flam level + # and with wrapped text: + # --flimflam set the flim-flam level (must be between + # 0 and 100, except on Tuesdays) + # Options with short names will have the short name shown (but + # it doesn't contribute to max_opt): + # --foo (-f) controls foonabulation + # If adding the short option would make the left column too wide, + # we push the explanation off to the next line + # --flimflam (-l) + # set the flim-flam level + # Important parameters: + # - 2 spaces before option block start lines + # - 2 dashes for each long option name + # - min. 2 spaces between option and explanation (gutter) + # - 5 characters (incl. space) for short option name + + # Now generate lines of help text. (If 80 columns were good enough + # for Jesus, then 78 columns are good enough for me!) + line_width = 78 + text_width = line_width - opt_width + big_indent = ' ' * opt_width + if header: + lines = [header] + else: + lines = ['Option summary:'] + + for option in self.option_table: + long, short, help = option[:3] + text = wrap_text(help, text_width) + if long[-1] == '=': + long = long[0:-1] + + # Case 1: no short option at all (makes life easy) + if short is None: + if text: + lines.append(" --%-*s %s" % (max_opt, long, text[0])) + else: + lines.append(" --%-*s " % (max_opt, long)) + + # Case 2: we have a short option, so we have to include it + # just after the long option + else: + opt_names = "%s (-%s)" % (long, short) + if text: + lines.append(" --%-*s %s" % + (max_opt, opt_names, text[0])) + else: + lines.append(" --%-*s" % opt_names) + + for l in text[1:]: + lines.append(big_indent + l) + return lines + + def print_help(self, header=None, file=None): + if file is None: + file = sys.stdout + for line in self.generate_help(header): + file.write(line + "\n") + + +def fancy_getopt(options, negative_opt, object, args): + parser = FancyGetopt(options) + parser.set_negative_aliases(negative_opt) + return parser.getopt(args, object) + + +WS_TRANS = {ord(_wschar) : ' ' for _wschar in string.whitespace} + +def wrap_text(text, width): + """wrap_text(text : string, width : int) -> [string] + + Split 'text' into multiple lines of no more than 'width' characters + each, and return the list of strings that results. + """ + if text is None: + return [] + if len(text) <= width: + return [text] + + text = text.expandtabs() + text = text.translate(WS_TRANS) + chunks = re.split(r'( +|-+)', text) + chunks = [ch for ch in chunks if ch] # ' - ' results in empty strings + lines = [] + + while chunks: + cur_line = [] # list of chunks (to-be-joined) + cur_len = 0 # length of current line + + while chunks: + l = len(chunks[0]) + if cur_len + l <= width: # can squeeze (at least) this chunk in + cur_line.append(chunks[0]) + del chunks[0] + cur_len = cur_len + l + else: # this line is full + # drop last chunk if all space + if cur_line and cur_line[-1][0] == ' ': + del cur_line[-1] + break + + if chunks: # any chunks left to process? + # if the current line is still empty, then we had a single + # chunk that's too big too fit on a line -- so we break + # down and break it up at the line width + if cur_len == 0: + cur_line.append(chunks[0][0:width]) + chunks[0] = chunks[0][width:] + + # all-whitespace chunks at the end of a line can be discarded + # (and we know from the re.split above that if a chunk has + # *any* whitespace, it is *all* whitespace) + if chunks[0][0] == ' ': + del chunks[0] + + # and store this line in the list-of-all-lines -- as a single + # string, of course! + lines.append(''.join(cur_line)) + + return lines + + +def translate_longopt(opt): + """Convert a long option name to a valid Python identifier by + changing "-" to "_". + """ + return opt.translate(longopt_xlate) + + +class OptionDummy: + """Dummy class just used as a place to hold command-line option + values as instance attributes.""" + + def __init__(self, options=[]): + """Create a new OptionDummy instance. The attributes listed in + 'options' will be initialized to None.""" + for opt in options: + setattr(self, opt, None) + + +if __name__ == "__main__": + text = """\ +Tra-la-la, supercalifragilisticexpialidocious. +How *do* you spell that odd word, anyways? +(Someone ask Mary -- she'll know [or she'll +say, "How should I know?"].)""" + + for w in (10, 20, 30, 40): + print("width: %d" % w) + print("\n".join(wrap_text(text, w))) + print() diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/file_util.py b/MLPY/Lib/site-packages/setuptools/_distutils/file_util.py new file mode 100644 index 0000000000000000000000000000000000000000..b3fee35a6cce812ad856d3b84332e73fd1973420 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/file_util.py @@ -0,0 +1,238 @@ +"""distutils.file_util + +Utility functions for operating on single files. +""" + +import os +from distutils.errors import DistutilsFileError +from distutils import log + +# for generating verbose output in 'copy_file()' +_copy_action = { None: 'copying', + 'hard': 'hard linking', + 'sym': 'symbolically linking' } + + +def _copy_file_contents(src, dst, buffer_size=16*1024): + """Copy the file 'src' to 'dst'; both must be filenames. Any error + opening either file, reading from 'src', or writing to 'dst', raises + DistutilsFileError. Data is read/written in chunks of 'buffer_size' + bytes (default 16k). No attempt is made to handle anything apart from + regular files. + """ + # Stolen from shutil module in the standard library, but with + # custom error-handling added. + fsrc = None + fdst = None + try: + try: + fsrc = open(src, 'rb') + except OSError as e: + raise DistutilsFileError("could not open '%s': %s" % (src, e.strerror)) + + if os.path.exists(dst): + try: + os.unlink(dst) + except OSError as e: + raise DistutilsFileError( + "could not delete '%s': %s" % (dst, e.strerror)) + + try: + fdst = open(dst, 'wb') + except OSError as e: + raise DistutilsFileError( + "could not create '%s': %s" % (dst, e.strerror)) + + while True: + try: + buf = fsrc.read(buffer_size) + except OSError as e: + raise DistutilsFileError( + "could not read from '%s': %s" % (src, e.strerror)) + + if not buf: + break + + try: + fdst.write(buf) + except OSError as e: + raise DistutilsFileError( + "could not write to '%s': %s" % (dst, e.strerror)) + finally: + if fdst: + fdst.close() + if fsrc: + fsrc.close() + +def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0, + link=None, verbose=1, dry_run=0): + """Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src' is + copied there with the same name; otherwise, it must be a filename. (If + the file exists, it will be ruthlessly clobbered.) If 'preserve_mode' + is true (the default), the file's mode (type and permission bits, or + whatever is analogous on the current platform) is copied. If + 'preserve_times' is true (the default), the last-modified and + last-access times are copied as well. If 'update' is true, 'src' will + only be copied if 'dst' does not exist, or if 'dst' does exist but is + older than 'src'. + + 'link' allows you to make hard links (os.link) or symbolic links + (os.symlink) instead of copying: set it to "hard" or "sym"; if it is + None (the default), files are copied. Don't set 'link' on systems that + don't support it: 'copy_file()' doesn't check if hard or symbolic + linking is available. If hardlink fails, falls back to + _copy_file_contents(). + + Under Mac OS, uses the native file copy function in macostools; on + other systems, uses '_copy_file_contents()' to copy file contents. + + Return a tuple (dest_name, copied): 'dest_name' is the actual name of + the output file, and 'copied' is true if the file was copied (or would + have been copied, if 'dry_run' true). + """ + # XXX if the destination file already exists, we clobber it if + # copying, but blow up if linking. Hmmm. And I don't know what + # macostools.copyfile() does. Should definitely be consistent, and + # should probably blow up if destination exists and we would be + # changing it (ie. it's not already a hard/soft link to src OR + # (not update) and (src newer than dst). + + from distutils.dep_util import newer + from stat import ST_ATIME, ST_MTIME, ST_MODE, S_IMODE + + if not os.path.isfile(src): + raise DistutilsFileError( + "can't copy '%s': doesn't exist or not a regular file" % src) + + if os.path.isdir(dst): + dir = dst + dst = os.path.join(dst, os.path.basename(src)) + else: + dir = os.path.dirname(dst) + + if update and not newer(src, dst): + if verbose >= 1: + log.debug("not copying %s (output up-to-date)", src) + return (dst, 0) + + try: + action = _copy_action[link] + except KeyError: + raise ValueError("invalid value '%s' for 'link' argument" % link) + + if verbose >= 1: + if os.path.basename(dst) == os.path.basename(src): + log.info("%s %s -> %s", action, src, dir) + else: + log.info("%s %s -> %s", action, src, dst) + + if dry_run: + return (dst, 1) + + # If linking (hard or symbolic), use the appropriate system call + # (Unix only, of course, but that's the caller's responsibility) + elif link == 'hard': + if not (os.path.exists(dst) and os.path.samefile(src, dst)): + try: + os.link(src, dst) + return (dst, 1) + except OSError: + # If hard linking fails, fall back on copying file + # (some special filesystems don't support hard linking + # even under Unix, see issue #8876). + pass + elif link == 'sym': + if not (os.path.exists(dst) and os.path.samefile(src, dst)): + os.symlink(src, dst) + return (dst, 1) + + # Otherwise (non-Mac, not linking), copy the file contents and + # (optionally) copy the times and mode. + _copy_file_contents(src, dst) + if preserve_mode or preserve_times: + st = os.stat(src) + + # According to David Ascher , utime() should be done + # before chmod() (at least under NT). + if preserve_times: + os.utime(dst, (st[ST_ATIME], st[ST_MTIME])) + if preserve_mode: + os.chmod(dst, S_IMODE(st[ST_MODE])) + + return (dst, 1) + + +# XXX I suspect this is Unix-specific -- need porting help! +def move_file (src, dst, + verbose=1, + dry_run=0): + + """Move a file 'src' to 'dst'. If 'dst' is a directory, the file will + be moved into it with the same name; otherwise, 'src' is just renamed + to 'dst'. Return the new full name of the file. + + Handles cross-device moves on Unix using 'copy_file()'. What about + other systems??? + """ + from os.path import exists, isfile, isdir, basename, dirname + import errno + + if verbose >= 1: + log.info("moving %s -> %s", src, dst) + + if dry_run: + return dst + + if not isfile(src): + raise DistutilsFileError("can't move '%s': not a regular file" % src) + + if isdir(dst): + dst = os.path.join(dst, basename(src)) + elif exists(dst): + raise DistutilsFileError( + "can't move '%s': destination '%s' already exists" % + (src, dst)) + + if not isdir(dirname(dst)): + raise DistutilsFileError( + "can't move '%s': destination '%s' not a valid path" % + (src, dst)) + + copy_it = False + try: + os.rename(src, dst) + except OSError as e: + (num, msg) = e.args + if num == errno.EXDEV: + copy_it = True + else: + raise DistutilsFileError( + "couldn't move '%s' to '%s': %s" % (src, dst, msg)) + + if copy_it: + copy_file(src, dst, verbose=verbose) + try: + os.unlink(src) + except OSError as e: + (num, msg) = e.args + try: + os.unlink(dst) + except OSError: + pass + raise DistutilsFileError( + "couldn't move '%s' to '%s' by copy/delete: " + "delete '%s' failed: %s" + % (src, dst, src, msg)) + return dst + + +def write_file (filename, contents): + """Create a file with the specified name and write 'contents' (a + sequence of strings without line terminators) to it. + """ + f = open(filename, "w") + try: + for line in contents: + f.write(line + "\n") + finally: + f.close() diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/filelist.py b/MLPY/Lib/site-packages/setuptools/_distutils/filelist.py new file mode 100644 index 0000000000000000000000000000000000000000..82a77384dcbc56690494ad4549ef859071d90af2 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/filelist.py @@ -0,0 +1,355 @@ +"""distutils.filelist + +Provides the FileList class, used for poking about the filesystem +and building lists of files. +""" + +import os +import re +import fnmatch +import functools + +from distutils.util import convert_path +from distutils.errors import DistutilsTemplateError, DistutilsInternalError +from distutils import log + + +class FileList: + """A list of files built by on exploring the filesystem and filtered by + applying various patterns to what we find there. + + Instance attributes: + dir + directory from which files will be taken -- only used if + 'allfiles' not supplied to constructor + files + list of filenames currently being built/filtered/manipulated + allfiles + complete list of files under consideration (ie. without any + filtering applied) + """ + + def __init__(self, warn=None, debug_print=None): + # ignore argument to FileList, but keep them for backwards + # compatibility + self.allfiles = None + self.files = [] + + def set_allfiles(self, allfiles): + self.allfiles = allfiles + + def findall(self, dir=os.curdir): + self.allfiles = findall(dir) + + def debug_print(self, msg): + """Print 'msg' to stdout if the global DEBUG (taken from the + DISTUTILS_DEBUG environment variable) flag is true. + """ + from distutils.debug import DEBUG + if DEBUG: + print(msg) + + # Collection methods + + def append(self, item): + self.files.append(item) + + def extend(self, items): + self.files.extend(items) + + def sort(self): + # Not a strict lexical sort! + sortable_files = sorted(map(os.path.split, self.files)) + self.files = [] + for sort_tuple in sortable_files: + self.files.append(os.path.join(*sort_tuple)) + + # Other miscellaneous utility methods + + def remove_duplicates(self): + # Assumes list has been sorted! + for i in range(len(self.files) - 1, 0, -1): + if self.files[i] == self.files[i - 1]: + del self.files[i] + + # "File template" methods + + def _parse_template_line(self, line): + words = line.split() + action = words[0] + + patterns = dir = dir_pattern = None + + if action in ('include', 'exclude', + 'global-include', 'global-exclude'): + if len(words) < 2: + raise DistutilsTemplateError( + "'%s' expects ..." % action) + patterns = [convert_path(w) for w in words[1:]] + elif action in ('recursive-include', 'recursive-exclude'): + if len(words) < 3: + raise DistutilsTemplateError( + "'%s' expects ..." % action) + dir = convert_path(words[1]) + patterns = [convert_path(w) for w in words[2:]] + elif action in ('graft', 'prune'): + if len(words) != 2: + raise DistutilsTemplateError( + "'%s' expects a single " % action) + dir_pattern = convert_path(words[1]) + else: + raise DistutilsTemplateError("unknown action '%s'" % action) + + return (action, patterns, dir, dir_pattern) + + def process_template_line(self, line): + # Parse the line: split it up, make sure the right number of words + # is there, and return the relevant words. 'action' is always + # defined: it's the first word of the line. Which of the other + # three are defined depends on the action; it'll be either + # patterns, (dir and patterns), or (dir_pattern). + (action, patterns, dir, dir_pattern) = self._parse_template_line(line) + + # OK, now we know that the action is valid and we have the + # right number of words on the line for that action -- so we + # can proceed with minimal error-checking. + if action == 'include': + self.debug_print("include " + ' '.join(patterns)) + for pattern in patterns: + if not self.include_pattern(pattern, anchor=1): + log.warn("warning: no files found matching '%s'", + pattern) + + elif action == 'exclude': + self.debug_print("exclude " + ' '.join(patterns)) + for pattern in patterns: + if not self.exclude_pattern(pattern, anchor=1): + log.warn(("warning: no previously-included files " + "found matching '%s'"), pattern) + + elif action == 'global-include': + self.debug_print("global-include " + ' '.join(patterns)) + for pattern in patterns: + if not self.include_pattern(pattern, anchor=0): + log.warn(("warning: no files found matching '%s' " + "anywhere in distribution"), pattern) + + elif action == 'global-exclude': + self.debug_print("global-exclude " + ' '.join(patterns)) + for pattern in patterns: + if not self.exclude_pattern(pattern, anchor=0): + log.warn(("warning: no previously-included files matching " + "'%s' found anywhere in distribution"), + pattern) + + elif action == 'recursive-include': + self.debug_print("recursive-include %s %s" % + (dir, ' '.join(patterns))) + for pattern in patterns: + if not self.include_pattern(pattern, prefix=dir): + msg = ( + "warning: no files found matching '%s' " + "under directory '%s'" + ) + log.warn(msg, pattern, dir) + + elif action == 'recursive-exclude': + self.debug_print("recursive-exclude %s %s" % + (dir, ' '.join(patterns))) + for pattern in patterns: + if not self.exclude_pattern(pattern, prefix=dir): + log.warn(("warning: no previously-included files matching " + "'%s' found under directory '%s'"), + pattern, dir) + + elif action == 'graft': + self.debug_print("graft " + dir_pattern) + if not self.include_pattern(None, prefix=dir_pattern): + log.warn("warning: no directories found matching '%s'", + dir_pattern) + + elif action == 'prune': + self.debug_print("prune " + dir_pattern) + if not self.exclude_pattern(None, prefix=dir_pattern): + log.warn(("no previously-included directories found " + "matching '%s'"), dir_pattern) + else: + raise DistutilsInternalError( + "this cannot happen: invalid action '%s'" % action) + + # Filtering/selection methods + + def include_pattern(self, pattern, anchor=1, prefix=None, is_regex=0): + """Select strings (presumably filenames) from 'self.files' that + match 'pattern', a Unix-style wildcard (glob) pattern. Patterns + are not quite the same as implemented by the 'fnmatch' module: '*' + and '?' match non-special characters, where "special" is platform- + dependent: slash on Unix; colon, slash, and backslash on + DOS/Windows; and colon on Mac OS. + + If 'anchor' is true (the default), then the pattern match is more + stringent: "*.py" will match "foo.py" but not "foo/bar.py". If + 'anchor' is false, both of these will match. + + If 'prefix' is supplied, then only filenames starting with 'prefix' + (itself a pattern) and ending with 'pattern', with anything in between + them, will match. 'anchor' is ignored in this case. + + If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and + 'pattern' is assumed to be either a string containing a regex or a + regex object -- no translation is done, the regex is just compiled + and used as-is. + + Selected strings will be added to self.files. + + Return True if files are found, False otherwise. + """ + # XXX docstring lying about what the special chars are? + files_found = False + pattern_re = translate_pattern(pattern, anchor, prefix, is_regex) + self.debug_print("include_pattern: applying regex r'%s'" % + pattern_re.pattern) + + # delayed loading of allfiles list + if self.allfiles is None: + self.findall() + + for name in self.allfiles: + if pattern_re.search(name): + self.debug_print(" adding " + name) + self.files.append(name) + files_found = True + return files_found + + def exclude_pattern( + self, pattern, anchor=1, prefix=None, is_regex=0): + """Remove strings (presumably filenames) from 'files' that match + 'pattern'. Other parameters are the same as for + 'include_pattern()', above. + The list 'self.files' is modified in place. + Return True if files are found, False otherwise. + """ + files_found = False + pattern_re = translate_pattern(pattern, anchor, prefix, is_regex) + self.debug_print("exclude_pattern: applying regex r'%s'" % + pattern_re.pattern) + for i in range(len(self.files)-1, -1, -1): + if pattern_re.search(self.files[i]): + self.debug_print(" removing " + self.files[i]) + del self.files[i] + files_found = True + return files_found + + +# Utility functions + +def _find_all_simple(path): + """ + Find all files under 'path' + """ + all_unique = _UniqueDirs.filter(os.walk(path, followlinks=True)) + results = ( + os.path.join(base, file) + for base, dirs, files in all_unique + for file in files + ) + return filter(os.path.isfile, results) + + +class _UniqueDirs(set): + """ + Exclude previously-seen dirs from walk results, + avoiding infinite recursion. + Ref https://bugs.python.org/issue44497. + """ + def __call__(self, walk_item): + """ + Given an item from an os.walk result, determine + if the item represents a unique dir for this instance + and if not, prevent further traversal. + """ + base, dirs, files = walk_item + stat = os.stat(base) + candidate = stat.st_dev, stat.st_ino + found = candidate in self + if found: + del dirs[:] + self.add(candidate) + return not found + + @classmethod + def filter(cls, items): + return filter(cls(), items) + + +def findall(dir=os.curdir): + """ + Find all files under 'dir' and return the list of full filenames. + Unless dir is '.', return full filenames with dir prepended. + """ + files = _find_all_simple(dir) + if dir == os.curdir: + make_rel = functools.partial(os.path.relpath, start=dir) + files = map(make_rel, files) + return list(files) + + +def glob_to_re(pattern): + """Translate a shell-like glob pattern to a regular expression; return + a string containing the regex. Differs from 'fnmatch.translate()' in + that '*' does not match "special characters" (which are + platform-specific). + """ + pattern_re = fnmatch.translate(pattern) + + # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which + # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, + # and by extension they shouldn't match such "special characters" under + # any OS. So change all non-escaped dots in the RE to match any + # character except the special characters (currently: just os.sep). + sep = os.sep + if os.sep == '\\': + # we're using a regex to manipulate a regex, so we need + # to escape the backslash twice + sep = r'\\\\' + escaped = r'\1[^%s]' % sep + pattern_re = re.sub(r'((?= self.threshold: + if args: + msg = msg % args + if level in (WARN, ERROR, FATAL): + stream = sys.stderr + else: + stream = sys.stdout + try: + stream.write('%s\n' % msg) + except UnicodeEncodeError: + # emulate backslashreplace error handler + encoding = stream.encoding + msg = msg.encode(encoding, "backslashreplace").decode(encoding) + stream.write('%s\n' % msg) + stream.flush() + + def log(self, level, msg, *args): + self._log(level, msg, args) + + def debug(self, msg, *args): + self._log(DEBUG, msg, args) + + def info(self, msg, *args): + self._log(INFO, msg, args) + + def warn(self, msg, *args): + self._log(WARN, msg, args) + + def error(self, msg, *args): + self._log(ERROR, msg, args) + + def fatal(self, msg, *args): + self._log(FATAL, msg, args) + +_global_log = Log() +log = _global_log.log +debug = _global_log.debug +info = _global_log.info +warn = _global_log.warn +error = _global_log.error +fatal = _global_log.fatal + +def set_threshold(level): + # return the old threshold for use from tests + old = _global_log.threshold + _global_log.threshold = level + return old + +def set_verbosity(v): + if v <= 0: + set_threshold(WARN) + elif v == 1: + set_threshold(INFO) + elif v >= 2: + set_threshold(DEBUG) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/msvc9compiler.py b/MLPY/Lib/site-packages/setuptools/_distutils/msvc9compiler.py new file mode 100644 index 0000000000000000000000000000000000000000..a1b3b02ff0a94b0611a4ca44345d42a226d15ee5 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/msvc9compiler.py @@ -0,0 +1,788 @@ +"""distutils.msvc9compiler + +Contains MSVCCompiler, an implementation of the abstract CCompiler class +for the Microsoft Visual Studio 2008. + +The module is compatible with VS 2005 and VS 2008. You can find legacy support +for older versions of VS in distutils.msvccompiler. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) +# ported to VS2005 and VS 2008 by Christian Heimes + +import os +import subprocess +import sys +import re + +from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ + CompileError, LibError, LinkError +from distutils.ccompiler import CCompiler, gen_lib_options +from distutils import log +from distutils.util import get_platform + +import winreg + +RegOpenKeyEx = winreg.OpenKeyEx +RegEnumKey = winreg.EnumKey +RegEnumValue = winreg.EnumValue +RegError = winreg.error + +HKEYS = (winreg.HKEY_USERS, + winreg.HKEY_CURRENT_USER, + winreg.HKEY_LOCAL_MACHINE, + winreg.HKEY_CLASSES_ROOT) + +NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32) +if NATIVE_WIN64: + # Visual C++ is a 32-bit application, so we need to look in + # the corresponding registry branch, if we're running a + # 64-bit Python on Win64 + VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f" + WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows" + NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework" +else: + VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f" + WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows" + NET_BASE = r"Software\Microsoft\.NETFramework" + +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is +# the param to cross-compile on x86 targeting amd64.) +PLAT_TO_VCVARS = { + 'win32' : 'x86', + 'win-amd64' : 'amd64', +} + +class Reg: + """Helper class to read values from the registry + """ + + def get_value(cls, path, key): + for base in HKEYS: + d = cls.read_values(base, path) + if d and key in d: + return d[key] + raise KeyError(key) + get_value = classmethod(get_value) + + def read_keys(cls, base, key): + """Return list of registry keys.""" + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + L = [] + i = 0 + while True: + try: + k = RegEnumKey(handle, i) + except RegError: + break + L.append(k) + i += 1 + return L + read_keys = classmethod(read_keys) + + def read_values(cls, base, key): + """Return dict of registry keys and values. + + All names are converted to lowercase. + """ + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + d = {} + i = 0 + while True: + try: + name, value, type = RegEnumValue(handle, i) + except RegError: + break + name = name.lower() + d[cls.convert_mbcs(name)] = cls.convert_mbcs(value) + i += 1 + return d + read_values = classmethod(read_values) + + def convert_mbcs(s): + dec = getattr(s, "decode", None) + if dec is not None: + try: + s = dec("mbcs") + except UnicodeError: + pass + return s + convert_mbcs = staticmethod(convert_mbcs) + +class MacroExpander: + + def __init__(self, version): + self.macros = {} + self.vsbase = VS_BASE % version + self.load_macros(version) + + def set_macro(self, macro, path, key): + self.macros["$(%s)" % macro] = Reg.get_value(path, key) + + def load_macros(self, version): + self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir") + self.set_macro("FrameworkDir", NET_BASE, "installroot") + try: + if version >= 8.0: + self.set_macro("FrameworkSDKDir", NET_BASE, + "sdkinstallrootv2.0") + else: + raise KeyError("sdkinstallrootv2.0") + except KeyError: + raise DistutilsPlatformError( + """Python was built with Visual Studio 2008; +extensions must be built with a compiler than can generate compatible binaries. +Visual Studio 2008 was not found on this system. If you have Cygwin installed, +you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") + + if version >= 9.0: + self.set_macro("FrameworkVersion", self.vsbase, "clr version") + self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder") + else: + p = r"Software\Microsoft\NET Framework Setup\Product" + for base in HKEYS: + try: + h = RegOpenKeyEx(base, p) + except RegError: + continue + key = RegEnumKey(h, 0) + d = Reg.get_value(base, r"%s\%s" % (p, key)) + self.macros["$(FrameworkVersion)"] = d["version"] + + def sub(self, s): + for k, v in self.macros.items(): + s = s.replace(k, v) + return s + +def get_build_version(): + """Return the version of MSVC that was used to build Python. + + For Python 2.3 and up, the version number is included in + sys.version. For earlier versions, assume the compiler is MSVC 6. + """ + prefix = "MSC v." + i = sys.version.find(prefix) + if i == -1: + return 6 + i = i + len(prefix) + s, rest = sys.version[i:].split(" ", 1) + majorVersion = int(s[:-2]) - 6 + if majorVersion >= 13: + # v13 was skipped and should be v14 + majorVersion += 1 + minorVersion = int(s[2:3]) / 10.0 + # I don't think paths are affected by minor version in version 6 + if majorVersion == 6: + minorVersion = 0 + if majorVersion >= 6: + return majorVersion + minorVersion + # else we don't know what version of the compiler this is + return None + +def normalize_and_reduce_paths(paths): + """Return a list of normalized paths with duplicates removed. + + The current order of paths is maintained. + """ + # Paths are normalized so things like: /a and /a/ aren't both preserved. + reduced_paths = [] + for p in paths: + np = os.path.normpath(p) + # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. + if np not in reduced_paths: + reduced_paths.append(np) + return reduced_paths + +def removeDuplicates(variable): + """Remove duplicate values of an environment variable. + """ + oldList = variable.split(os.pathsep) + newList = [] + for i in oldList: + if i not in newList: + newList.append(i) + newVariable = os.pathsep.join(newList) + return newVariable + +def find_vcvarsall(version): + """Find the vcvarsall.bat file + + At first it tries to find the productdir of VS 2008 in the registry. If + that fails it falls back to the VS90COMNTOOLS env var. + """ + vsbase = VS_BASE % version + try: + productdir = Reg.get_value(r"%s\Setup\VC" % vsbase, + "productdir") + except KeyError: + log.debug("Unable to find productdir in registry") + productdir = None + + if not productdir or not os.path.isdir(productdir): + toolskey = "VS%0.f0COMNTOOLS" % version + toolsdir = os.environ.get(toolskey, None) + + if toolsdir and os.path.isdir(toolsdir): + productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC") + productdir = os.path.abspath(productdir) + if not os.path.isdir(productdir): + log.debug("%s is not a valid directory" % productdir) + return None + else: + log.debug("Env var %s is not set or invalid" % toolskey) + if not productdir: + log.debug("No productdir found") + return None + vcvarsall = os.path.join(productdir, "vcvarsall.bat") + if os.path.isfile(vcvarsall): + return vcvarsall + log.debug("Unable to find vcvarsall.bat") + return None + +def query_vcvarsall(version, arch="x86"): + """Launch vcvarsall.bat and read the settings from its environment + """ + vcvarsall = find_vcvarsall(version) + interesting = {"include", "lib", "libpath", "path"} + result = {} + + if vcvarsall is None: + raise DistutilsPlatformError("Unable to find vcvarsall.bat") + log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version) + popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + try: + stdout, stderr = popen.communicate() + if popen.wait() != 0: + raise DistutilsPlatformError(stderr.decode("mbcs")) + + stdout = stdout.decode("mbcs") + for line in stdout.split("\n"): + line = Reg.convert_mbcs(line) + if '=' not in line: + continue + line = line.strip() + key, value = line.split('=', 1) + key = key.lower() + if key in interesting: + if value.endswith(os.pathsep): + value = value[:-1] + result[key] = removeDuplicates(value) + + finally: + popen.stdout.close() + popen.stderr.close() + + if len(result) != len(interesting): + raise ValueError(str(list(result.keys()))) + + return result + +# More globals +VERSION = get_build_version() +if VERSION < 8.0: + raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION) +# MACROS = MacroExpander(VERSION) + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + compiler_type = 'msvc' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__ (self, verbose, dry_run, force) + self.__version = VERSION + self.__root = r"Software\Microsoft\VisualStudio" + # self.__macros = MACROS + self.__paths = [] + # target platform (.plat_name is consistent with 'bdist') + self.plat_name = None + self.__arch = None # deprecated name + self.initialized = False + + def initialize(self, plat_name=None): + # multi-init means we would need to check platform same each time... + assert not self.initialized, "don't init multiple times" + if plat_name is None: + plat_name = get_platform() + # sanity check for platforms to prevent obscure errors later. + ok_plats = 'win32', 'win-amd64' + if plat_name not in ok_plats: + raise DistutilsPlatformError("--plat-name must be one of %s" % + (ok_plats,)) + + if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): + # Assume that the SDK set up everything alright; don't try to be + # smarter + self.cc = "cl.exe" + self.linker = "link.exe" + self.lib = "lib.exe" + self.rc = "rc.exe" + self.mc = "mc.exe" + else: + # On x86, 'vcvars32.bat amd64' creates an env that doesn't work; + # to cross compile, you use 'x86_amd64'. + # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross + # compile use 'x86' (ie, it runs the x86 compiler directly) + if plat_name == get_platform() or plat_name == 'win32': + # native build or cross-compile to win32 + plat_spec = PLAT_TO_VCVARS[plat_name] + else: + # cross compile from win32 -> some 64bit + plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \ + PLAT_TO_VCVARS[plat_name] + + vc_env = query_vcvarsall(VERSION, plat_spec) + + self.__paths = vc_env['path'].split(os.pathsep) + os.environ['lib'] = vc_env['lib'] + os.environ['include'] = vc_env['include'] + + if len(self.__paths) == 0: + raise DistutilsPlatformError("Python was built with %s, " + "and extensions need to be built with the same " + "version of the compiler, but it isn't installed." + % self.__product) + + self.cc = self.find_exe("cl.exe") + self.linker = self.find_exe("link.exe") + self.lib = self.find_exe("lib.exe") + self.rc = self.find_exe("rc.exe") # resource compiler + self.mc = self.find_exe("mc.exe") # message compiler + #self.set_path_env_var('lib') + #self.set_path_env_var('include') + + # extend the MSVC path with the current path + try: + for p in os.environ['path'].split(';'): + self.__paths.append(p) + except KeyError: + pass + self.__paths = normalize_and_reduce_paths(self.__paths) + os.environ['path'] = ";".join(self.__paths) + + self.preprocess_options = None + if self.__arch == "x86": + self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', + '/Z7', '/D_DEBUG'] + else: + # Win64 + self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GS-' , + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', + '/Z7', '/D_DEBUG'] + + self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] + if self.__version >= 7: + self.ldflags_shared_debug = [ + '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG' + ] + self.ldflags_static = [ '/nologo'] + + self.initialized = True + + # -- Worker methods ------------------------------------------------ + + def object_filenames(self, + source_filenames, + strip_dir=0, + output_dir=''): + # Copied from ccompiler.py, extended to return .res as 'object'-file + # for .rc input file + if output_dir is None: output_dir = '' + obj_names = [] + for src_name in source_filenames: + (base, ext) = os.path.splitext (src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / + if ext not in self.src_extensions: + # Better to raise an exception instead of silently continuing + # and later complain about sources and targets having + # different lengths + raise CompileError ("Don't know how to compile %s" % src_name) + if strip_dir: + base = os.path.basename (base) + if ext in self._rc_extensions: + obj_names.append (os.path.join (output_dir, + base + self.res_extension)) + elif ext in self._mc_extensions: + obj_names.append (os.path.join (output_dir, + base + self.res_extension)) + else: + obj_names.append (os.path.join (output_dir, + base + self.obj_extension)) + return obj_names + + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=0, + extra_preargs=None, extra_postargs=None, depends=None): + + if not self.initialized: + self.initialize() + compile_info = self._setup_compile(output_dir, macros, include_dirs, + sources, depends, extra_postargs) + macros, objects, extra_postargs, pp_opts, build = compile_info + + compile_opts = extra_preargs or [] + compile_opts.append ('/c') + if debug: + compile_opts.extend(self.compile_options_debug) + else: + compile_opts.extend(self.compile_options) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + if debug: + # pass the full pathname to MSVC in debug mode, + # this allows the debugger to find the source file + # without asking the user to browse for it + src = os.path.abspath(src) + + if ext in self._c_extensions: + input_opt = "/Tc" + src + elif ext in self._cpp_extensions: + input_opt = "/Tp" + src + elif ext in self._rc_extensions: + # compile .RC to .RES file + input_opt = src + output_opt = "/fo" + obj + try: + self.spawn([self.rc] + pp_opts + + [output_opt] + [input_opt]) + except DistutilsExecError as msg: + raise CompileError(msg) + continue + elif ext in self._mc_extensions: + # Compile .MC to .RC file to .RES file. + # * '-h dir' specifies the directory for the + # generated include file + # * '-r dir' specifies the target directory of the + # generated RC file and the binary message resource + # it includes + # + # For now (since there are no options to change this), + # we use the source-directory for the include file and + # the build directory for the RC file and message + # resources. This works at least for win32all. + h_dir = os.path.dirname(src) + rc_dir = os.path.dirname(obj) + try: + # first compile .MC to .RC and .H file + self.spawn([self.mc] + + ['-h', h_dir, '-r', rc_dir] + [src]) + base, _ = os.path.splitext (os.path.basename (src)) + rc_file = os.path.join (rc_dir, base + '.rc') + # then compile .RC to .RES file + self.spawn([self.rc] + + ["/fo" + obj] + [rc_file]) + + except DistutilsExecError as msg: + raise CompileError(msg) + continue + else: + # how to handle this file? + raise CompileError("Don't know how to compile %s to %s" + % (src, obj)) + + output_opt = "/Fo" + obj + try: + self.spawn([self.cc] + compile_opts + pp_opts + + [input_opt, output_opt] + + extra_postargs) + except DistutilsExecError as msg: + raise CompileError(msg) + + return objects + + + def create_static_lib(self, + objects, + output_libname, + output_dir=None, + debug=0, + target_lang=None): + + if not self.initialized: + self.initialize() + (objects, output_dir) = self._fix_object_args(objects, output_dir) + output_filename = self.library_filename(output_libname, + output_dir=output_dir) + + if self._need_link(objects, output_filename): + lib_args = objects + ['/OUT:' + output_filename] + if debug: + pass # XXX what goes here? + try: + self.spawn([self.lib] + lib_args) + except DistutilsExecError as msg: + raise LibError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + + def link(self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + + if not self.initialized: + self.initialize() + (objects, output_dir) = self._fix_object_args(objects, output_dir) + fixed_args = self._fix_lib_args(libraries, library_dirs, + runtime_library_dirs) + (libraries, library_dirs, runtime_library_dirs) = fixed_args + + if runtime_library_dirs: + self.warn ("I don't know what to do with 'runtime_library_dirs': " + + str (runtime_library_dirs)) + + lib_opts = gen_lib_options(self, + library_dirs, runtime_library_dirs, + libraries) + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + if target_desc == CCompiler.EXECUTABLE: + if debug: + ldflags = self.ldflags_shared_debug[1:] + else: + ldflags = self.ldflags_shared[1:] + else: + if debug: + ldflags = self.ldflags_shared_debug + else: + ldflags = self.ldflags_shared + + export_opts = [] + for sym in (export_symbols or []): + export_opts.append("/EXPORT:" + sym) + + ld_args = (ldflags + lib_opts + export_opts + + objects + ['/OUT:' + output_filename]) + + # The MSVC linker generates .lib and .exp files, which cannot be + # suppressed by any linker switches. The .lib files may even be + # needed! Make sure they are generated in the temporary build + # directory. Since they have different names for debug and release + # builds, they can go into the same directory. + build_temp = os.path.dirname(objects[0]) + if export_symbols is not None: + (dll_name, dll_ext) = os.path.splitext( + os.path.basename(output_filename)) + implib_file = os.path.join( + build_temp, + self.library_filename(dll_name)) + ld_args.append ('/IMPLIB:' + implib_file) + + self.manifest_setup_ldargs(output_filename, build_temp, ld_args) + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + self.mkpath(os.path.dirname(output_filename)) + try: + self.spawn([self.linker] + ld_args) + except DistutilsExecError as msg: + raise LinkError(msg) + + # embed the manifest + # XXX - this is somewhat fragile - if mt.exe fails, distutils + # will still consider the DLL up-to-date, but it will not have a + # manifest. Maybe we should link to a temp file? OTOH, that + # implies a build environment error that shouldn't go undetected. + mfinfo = self.manifest_get_embed_info(target_desc, ld_args) + if mfinfo is not None: + mffilename, mfid = mfinfo + out_arg = '-outputresource:%s;%s' % (output_filename, mfid) + try: + self.spawn(['mt.exe', '-nologo', '-manifest', + mffilename, out_arg]) + except DistutilsExecError as msg: + raise LinkError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + def manifest_setup_ldargs(self, output_filename, build_temp, ld_args): + # If we need a manifest at all, an embedded manifest is recommended. + # See MSDN article titled + # "How to: Embed a Manifest Inside a C/C++ Application" + # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx) + # Ask the linker to generate the manifest in the temp dir, so + # we can check it, and possibly embed it, later. + temp_manifest = os.path.join( + build_temp, + os.path.basename(output_filename) + ".manifest") + ld_args.append('/MANIFESTFILE:' + temp_manifest) + + def manifest_get_embed_info(self, target_desc, ld_args): + # If a manifest should be embedded, return a tuple of + # (manifest_filename, resource_id). Returns None if no manifest + # should be embedded. See http://bugs.python.org/issue7833 for why + # we want to avoid any manifest for extension modules if we can) + for arg in ld_args: + if arg.startswith("/MANIFESTFILE:"): + temp_manifest = arg.split(":", 1)[1] + break + else: + # no /MANIFESTFILE so nothing to do. + return None + if target_desc == CCompiler.EXECUTABLE: + # by default, executables always get the manifest with the + # CRT referenced. + mfid = 1 + else: + # Extension modules try and avoid any manifest if possible. + mfid = 2 + temp_manifest = self._remove_visual_c_ref(temp_manifest) + if temp_manifest is None: + return None + return temp_manifest, mfid + + def _remove_visual_c_ref(self, manifest_file): + try: + # Remove references to the Visual C runtime, so they will + # fall through to the Visual C dependency of Python.exe. + # This way, when installed for a restricted user (e.g. + # runtimes are not in WinSxS folder, but in Python's own + # folder), the runtimes do not need to be in every folder + # with .pyd's. + # Returns either the filename of the modified manifest or + # None if no manifest should be embedded. + manifest_f = open(manifest_file) + try: + manifest_buf = manifest_f.read() + finally: + manifest_f.close() + pattern = re.compile( + r"""|)""", + re.DOTALL) + manifest_buf = re.sub(pattern, "", manifest_buf) + pattern = r"\s*" + manifest_buf = re.sub(pattern, "", manifest_buf) + # Now see if any other assemblies are referenced - if not, we + # don't want a manifest embedded. + pattern = re.compile( + r"""|)""", re.DOTALL) + if re.search(pattern, manifest_buf) is None: + return None + + manifest_f = open(manifest_file, 'w') + try: + manifest_f.write(manifest_buf) + return manifest_file + finally: + manifest_f.close() + except OSError: + pass + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "/LIBPATH:" + dir + + def runtime_library_dir_option(self, dir): + raise DistutilsPlatformError( + "don't know how to set runtime library search path for MSVC++") + + def library_option(self, lib): + return self.library_filename(lib) + + + def find_library_file(self, dirs, lib, debug=0): + # Prefer a debugging library if found (and requested), but deal + # with it if we don't have one. + if debug: + try_names = [lib + "_d", lib] + else: + try_names = [lib] + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename (name)) + if os.path.exists(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None + + # Helper methods for using the MSVC registry settings + + def find_exe(self, exe): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + for p in self.__paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + # didn't find it; try existing path + for p in os.environ['Path'].split(';'): + fn = os.path.join(os.path.abspath(p),exe) + if os.path.isfile(fn): + return fn + + return exe diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/msvccompiler.py b/MLPY/Lib/site-packages/setuptools/_distutils/msvccompiler.py new file mode 100644 index 0000000000000000000000000000000000000000..2d447b857d34c8e8ed1e16b48e7d1d6a7e5c293a --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/msvccompiler.py @@ -0,0 +1,643 @@ +"""distutils.msvccompiler + +Contains MSVCCompiler, an implementation of the abstract CCompiler class +for the Microsoft Visual Studio. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) + +import sys, os +from distutils.errors import \ + DistutilsExecError, DistutilsPlatformError, \ + CompileError, LibError, LinkError +from distutils.ccompiler import \ + CCompiler, gen_lib_options +from distutils import log + +_can_read_reg = False +try: + import winreg + + _can_read_reg = True + hkey_mod = winreg + + RegOpenKeyEx = winreg.OpenKeyEx + RegEnumKey = winreg.EnumKey + RegEnumValue = winreg.EnumValue + RegError = winreg.error + +except ImportError: + try: + import win32api + import win32con + _can_read_reg = True + hkey_mod = win32con + + RegOpenKeyEx = win32api.RegOpenKeyEx + RegEnumKey = win32api.RegEnumKey + RegEnumValue = win32api.RegEnumValue + RegError = win32api.error + except ImportError: + log.info("Warning: Can't read registry to find the " + "necessary compiler setting\n" + "Make sure that Python modules winreg, " + "win32api or win32con are installed.") + pass + +if _can_read_reg: + HKEYS = (hkey_mod.HKEY_USERS, + hkey_mod.HKEY_CURRENT_USER, + hkey_mod.HKEY_LOCAL_MACHINE, + hkey_mod.HKEY_CLASSES_ROOT) + +def read_keys(base, key): + """Return list of registry keys.""" + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + L = [] + i = 0 + while True: + try: + k = RegEnumKey(handle, i) + except RegError: + break + L.append(k) + i += 1 + return L + +def read_values(base, key): + """Return dict of registry keys and values. + + All names are converted to lowercase. + """ + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + d = {} + i = 0 + while True: + try: + name, value, type = RegEnumValue(handle, i) + except RegError: + break + name = name.lower() + d[convert_mbcs(name)] = convert_mbcs(value) + i += 1 + return d + +def convert_mbcs(s): + dec = getattr(s, "decode", None) + if dec is not None: + try: + s = dec("mbcs") + except UnicodeError: + pass + return s + +class MacroExpander: + def __init__(self, version): + self.macros = {} + self.load_macros(version) + + def set_macro(self, macro, path, key): + for base in HKEYS: + d = read_values(base, path) + if d: + self.macros["$(%s)" % macro] = d[key] + break + + def load_macros(self, version): + vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version + self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir") + net = r"Software\Microsoft\.NETFramework" + self.set_macro("FrameworkDir", net, "installroot") + try: + if version > 7.0: + self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") + else: + self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") + except KeyError as exc: # + raise DistutilsPlatformError( + """Python was built with Visual Studio 2003; +extensions must be built with a compiler than can generate compatible binaries. +Visual Studio 2003 was not found on this system. If you have Cygwin installed, +you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") + + p = r"Software\Microsoft\NET Framework Setup\Product" + for base in HKEYS: + try: + h = RegOpenKeyEx(base, p) + except RegError: + continue + key = RegEnumKey(h, 0) + d = read_values(base, r"%s\%s" % (p, key)) + self.macros["$(FrameworkVersion)"] = d["version"] + + def sub(self, s): + for k, v in self.macros.items(): + s = s.replace(k, v) + return s + +def get_build_version(): + """Return the version of MSVC that was used to build Python. + + For Python 2.3 and up, the version number is included in + sys.version. For earlier versions, assume the compiler is MSVC 6. + """ + prefix = "MSC v." + i = sys.version.find(prefix) + if i == -1: + return 6 + i = i + len(prefix) + s, rest = sys.version[i:].split(" ", 1) + majorVersion = int(s[:-2]) - 6 + if majorVersion >= 13: + # v13 was skipped and should be v14 + majorVersion += 1 + minorVersion = int(s[2:3]) / 10.0 + # I don't think paths are affected by minor version in version 6 + if majorVersion == 6: + minorVersion = 0 + if majorVersion >= 6: + return majorVersion + minorVersion + # else we don't know what version of the compiler this is + return None + +def get_build_architecture(): + """Return the processor architecture. + + Possible results are "Intel" or "AMD64". + """ + + prefix = " bit (" + i = sys.version.find(prefix) + if i == -1: + return "Intel" + j = sys.version.find(")", i) + return sys.version[i+len(prefix):j] + +def normalize_and_reduce_paths(paths): + """Return a list of normalized paths with duplicates removed. + + The current order of paths is maintained. + """ + # Paths are normalized so things like: /a and /a/ aren't both preserved. + reduced_paths = [] + for p in paths: + np = os.path.normpath(p) + # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. + if np not in reduced_paths: + reduced_paths.append(np) + return reduced_paths + + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + compiler_type = 'msvc' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__ (self, verbose, dry_run, force) + self.__version = get_build_version() + self.__arch = get_build_architecture() + if self.__arch == "Intel": + # x86 + if self.__version >= 7: + self.__root = r"Software\Microsoft\VisualStudio" + self.__macros = MacroExpander(self.__version) + else: + self.__root = r"Software\Microsoft\Devstudio" + self.__product = "Visual Studio version %s" % self.__version + else: + # Win64. Assume this was built with the platform SDK + self.__product = "Microsoft SDK compiler %s" % (self.__version + 6) + + self.initialized = False + + def initialize(self): + self.__paths = [] + if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): + # Assume that the SDK set up everything alright; don't try to be + # smarter + self.cc = "cl.exe" + self.linker = "link.exe" + self.lib = "lib.exe" + self.rc = "rc.exe" + self.mc = "mc.exe" + else: + self.__paths = self.get_msvc_paths("path") + + if len(self.__paths) == 0: + raise DistutilsPlatformError("Python was built with %s, " + "and extensions need to be built with the same " + "version of the compiler, but it isn't installed." + % self.__product) + + self.cc = self.find_exe("cl.exe") + self.linker = self.find_exe("link.exe") + self.lib = self.find_exe("lib.exe") + self.rc = self.find_exe("rc.exe") # resource compiler + self.mc = self.find_exe("mc.exe") # message compiler + self.set_path_env_var('lib') + self.set_path_env_var('include') + + # extend the MSVC path with the current path + try: + for p in os.environ['path'].split(';'): + self.__paths.append(p) + except KeyError: + pass + self.__paths = normalize_and_reduce_paths(self.__paths) + os.environ['path'] = ";".join(self.__paths) + + self.preprocess_options = None + if self.__arch == "Intel": + self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GX' , + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX', + '/Z7', '/D_DEBUG'] + else: + # Win64 + self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GS-' , + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', + '/Z7', '/D_DEBUG'] + + self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] + if self.__version >= 7: + self.ldflags_shared_debug = [ + '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG' + ] + else: + self.ldflags_shared_debug = [ + '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG' + ] + self.ldflags_static = [ '/nologo'] + + self.initialized = True + + # -- Worker methods ------------------------------------------------ + + def object_filenames(self, + source_filenames, + strip_dir=0, + output_dir=''): + # Copied from ccompiler.py, extended to return .res as 'object'-file + # for .rc input file + if output_dir is None: output_dir = '' + obj_names = [] + for src_name in source_filenames: + (base, ext) = os.path.splitext (src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / + if ext not in self.src_extensions: + # Better to raise an exception instead of silently continuing + # and later complain about sources and targets having + # different lengths + raise CompileError ("Don't know how to compile %s" % src_name) + if strip_dir: + base = os.path.basename (base) + if ext in self._rc_extensions: + obj_names.append (os.path.join (output_dir, + base + self.res_extension)) + elif ext in self._mc_extensions: + obj_names.append (os.path.join (output_dir, + base + self.res_extension)) + else: + obj_names.append (os.path.join (output_dir, + base + self.obj_extension)) + return obj_names + + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=0, + extra_preargs=None, extra_postargs=None, depends=None): + + if not self.initialized: + self.initialize() + compile_info = self._setup_compile(output_dir, macros, include_dirs, + sources, depends, extra_postargs) + macros, objects, extra_postargs, pp_opts, build = compile_info + + compile_opts = extra_preargs or [] + compile_opts.append ('/c') + if debug: + compile_opts.extend(self.compile_options_debug) + else: + compile_opts.extend(self.compile_options) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + if debug: + # pass the full pathname to MSVC in debug mode, + # this allows the debugger to find the source file + # without asking the user to browse for it + src = os.path.abspath(src) + + if ext in self._c_extensions: + input_opt = "/Tc" + src + elif ext in self._cpp_extensions: + input_opt = "/Tp" + src + elif ext in self._rc_extensions: + # compile .RC to .RES file + input_opt = src + output_opt = "/fo" + obj + try: + self.spawn([self.rc] + pp_opts + + [output_opt] + [input_opt]) + except DistutilsExecError as msg: + raise CompileError(msg) + continue + elif ext in self._mc_extensions: + # Compile .MC to .RC file to .RES file. + # * '-h dir' specifies the directory for the + # generated include file + # * '-r dir' specifies the target directory of the + # generated RC file and the binary message resource + # it includes + # + # For now (since there are no options to change this), + # we use the source-directory for the include file and + # the build directory for the RC file and message + # resources. This works at least for win32all. + h_dir = os.path.dirname(src) + rc_dir = os.path.dirname(obj) + try: + # first compile .MC to .RC and .H file + self.spawn([self.mc] + + ['-h', h_dir, '-r', rc_dir] + [src]) + base, _ = os.path.splitext (os.path.basename (src)) + rc_file = os.path.join (rc_dir, base + '.rc') + # then compile .RC to .RES file + self.spawn([self.rc] + + ["/fo" + obj] + [rc_file]) + + except DistutilsExecError as msg: + raise CompileError(msg) + continue + else: + # how to handle this file? + raise CompileError("Don't know how to compile %s to %s" + % (src, obj)) + + output_opt = "/Fo" + obj + try: + self.spawn([self.cc] + compile_opts + pp_opts + + [input_opt, output_opt] + + extra_postargs) + except DistutilsExecError as msg: + raise CompileError(msg) + + return objects + + + def create_static_lib(self, + objects, + output_libname, + output_dir=None, + debug=0, + target_lang=None): + + if not self.initialized: + self.initialize() + (objects, output_dir) = self._fix_object_args(objects, output_dir) + output_filename = self.library_filename(output_libname, + output_dir=output_dir) + + if self._need_link(objects, output_filename): + lib_args = objects + ['/OUT:' + output_filename] + if debug: + pass # XXX what goes here? + try: + self.spawn([self.lib] + lib_args) + except DistutilsExecError as msg: + raise LibError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + + def link(self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + + if not self.initialized: + self.initialize() + (objects, output_dir) = self._fix_object_args(objects, output_dir) + fixed_args = self._fix_lib_args(libraries, library_dirs, + runtime_library_dirs) + (libraries, library_dirs, runtime_library_dirs) = fixed_args + + if runtime_library_dirs: + self.warn ("I don't know what to do with 'runtime_library_dirs': " + + str (runtime_library_dirs)) + + lib_opts = gen_lib_options(self, + library_dirs, runtime_library_dirs, + libraries) + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + if target_desc == CCompiler.EXECUTABLE: + if debug: + ldflags = self.ldflags_shared_debug[1:] + else: + ldflags = self.ldflags_shared[1:] + else: + if debug: + ldflags = self.ldflags_shared_debug + else: + ldflags = self.ldflags_shared + + export_opts = [] + for sym in (export_symbols or []): + export_opts.append("/EXPORT:" + sym) + + ld_args = (ldflags + lib_opts + export_opts + + objects + ['/OUT:' + output_filename]) + + # The MSVC linker generates .lib and .exp files, which cannot be + # suppressed by any linker switches. The .lib files may even be + # needed! Make sure they are generated in the temporary build + # directory. Since they have different names for debug and release + # builds, they can go into the same directory. + if export_symbols is not None: + (dll_name, dll_ext) = os.path.splitext( + os.path.basename(output_filename)) + implib_file = os.path.join( + os.path.dirname(objects[0]), + self.library_filename(dll_name)) + ld_args.append ('/IMPLIB:' + implib_file) + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + self.mkpath(os.path.dirname(output_filename)) + try: + self.spawn([self.linker] + ld_args) + except DistutilsExecError as msg: + raise LinkError(msg) + + else: + log.debug("skipping %s (up-to-date)", output_filename) + + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "/LIBPATH:" + dir + + def runtime_library_dir_option(self, dir): + raise DistutilsPlatformError( + "don't know how to set runtime library search path for MSVC++") + + def library_option(self, lib): + return self.library_filename(lib) + + + def find_library_file(self, dirs, lib, debug=0): + # Prefer a debugging library if found (and requested), but deal + # with it if we don't have one. + if debug: + try_names = [lib + "_d", lib] + else: + try_names = [lib] + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename (name)) + if os.path.exists(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None + + # Helper methods for using the MSVC registry settings + + def find_exe(self, exe): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + for p in self.__paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + # didn't find it; try existing path + for p in os.environ['Path'].split(';'): + fn = os.path.join(os.path.abspath(p),exe) + if os.path.isfile(fn): + return fn + + return exe + + def get_msvc_paths(self, path, platform='x86'): + """Get a list of devstudio directories (include, lib or path). + + Return a list of strings. The list will be empty if unable to + access the registry or appropriate registry keys not found. + """ + if not _can_read_reg: + return [] + + path = path + " dirs" + if self.__version >= 7: + key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" + % (self.__root, self.__version)) + else: + key = (r"%s\6.0\Build System\Components\Platforms" + r"\Win32 (%s)\Directories" % (self.__root, platform)) + + for base in HKEYS: + d = read_values(base, key) + if d: + if self.__version >= 7: + return self.__macros.sub(d[path]).split(";") + else: + return d[path].split(";") + # MSVC 6 seems to create the registry entries we need only when + # the GUI is run. + if self.__version == 6: + for base in HKEYS: + if read_values(base, r"%s\6.0" % self.__root) is not None: + self.warn("It seems you have Visual Studio 6 installed, " + "but the expected registry settings are not present.\n" + "You must at least run the Visual Studio GUI once " + "so that these entries are created.") + break + return [] + + def set_path_env_var(self, name): + """Set environment variable 'name' to an MSVC path type value. + + This is equivalent to a SET command prior to execution of spawned + commands. + """ + + if name == "lib": + p = self.get_msvc_paths("library") + else: + p = self.get_msvc_paths(name) + if p: + os.environ[name] = ';'.join(p) + + +if get_build_version() >= 8.0: + log.debug("Importing new compiler from distutils.msvc9compiler") + OldMSVCCompiler = MSVCCompiler + from distutils.msvc9compiler import MSVCCompiler + # get_build_architecture not really relevant now we support cross-compile + from distutils.msvc9compiler import MacroExpander diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/py35compat.py b/MLPY/Lib/site-packages/setuptools/_distutils/py35compat.py new file mode 100644 index 0000000000000000000000000000000000000000..79b2e7f38c1c07472dd8dd968b4e9b4de5422d76 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/py35compat.py @@ -0,0 +1,19 @@ +import sys +import subprocess + + +def __optim_args_from_interpreter_flags(): + """Return a list of command-line arguments reproducing the current + optimization settings in sys.flags.""" + args = [] + value = sys.flags.optimize + if value > 0: + args.append("-" + "O" * value) + return args + + +_optim_args_from_interpreter_flags = getattr( + subprocess, + "_optim_args_from_interpreter_flags", + __optim_args_from_interpreter_flags, +) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/py38compat.py b/MLPY/Lib/site-packages/setuptools/_distutils/py38compat.py new file mode 100644 index 0000000000000000000000000000000000000000..7dbe8cef54a692c49e5fd01ddb5d01b224ee2d6d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/py38compat.py @@ -0,0 +1,7 @@ +def aix_platform(osname, version, release): + try: + import _aix_support + return _aix_support.aix_platform() + except ImportError: + pass + return "%s-%s.%s" % (osname, version, release) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/spawn.py b/MLPY/Lib/site-packages/setuptools/_distutils/spawn.py new file mode 100644 index 0000000000000000000000000000000000000000..6e1c89f1f235b29809bfacb6df2cf00f2215a47f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/spawn.py @@ -0,0 +1,106 @@ +"""distutils.spawn + +Provides the 'spawn()' function, a front-end to various platform- +specific functions for launching another program in a sub-process. +Also provides the 'find_executable()' to search the path for a given +executable name. +""" + +import sys +import os +import subprocess + +from distutils.errors import DistutilsPlatformError, DistutilsExecError +from distutils.debug import DEBUG +from distutils import log + + +def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None): + """Run another program, specified as a command list 'cmd', in a new process. + + 'cmd' is just the argument list for the new process, ie. + cmd[0] is the program to run and cmd[1:] are the rest of its arguments. + There is no way to run a program with a name different from that of its + executable. + + If 'search_path' is true (the default), the system's executable + search path will be used to find the program; otherwise, cmd[0] + must be the exact path to the executable. If 'dry_run' is true, + the command will not actually be run. + + Raise DistutilsExecError if running the program fails in any way; just + return on success. + """ + # cmd is documented as a list, but just in case some code passes a tuple + # in, protect our %-formatting code against horrible death + cmd = list(cmd) + + log.info(subprocess.list2cmdline(cmd)) + if dry_run: + return + + if search_path: + executable = find_executable(cmd[0]) + if executable is not None: + cmd[0] = executable + + env = env if env is not None else dict(os.environ) + + if sys.platform == 'darwin': + from distutils.util import MACOSX_VERSION_VAR, get_macosx_target_ver + macosx_target_ver = get_macosx_target_ver() + if macosx_target_ver: + env[MACOSX_VERSION_VAR] = macosx_target_ver + + try: + proc = subprocess.Popen(cmd, env=env) + proc.wait() + exitcode = proc.returncode + except OSError as exc: + if not DEBUG: + cmd = cmd[0] + raise DistutilsExecError( + "command %r failed: %s" % (cmd, exc.args[-1])) from exc + + if exitcode: + if not DEBUG: + cmd = cmd[0] + raise DistutilsExecError( + "command %r failed with exit code %s" % (cmd, exitcode)) + + +def find_executable(executable, path=None): + """Tries to find 'executable' in the directories listed in 'path'. + + A string listing directories separated by 'os.pathsep'; defaults to + os.environ['PATH']. Returns the complete filename or None if not found. + """ + _, ext = os.path.splitext(executable) + if (sys.platform == 'win32') and (ext != '.exe'): + executable = executable + '.exe' + + if os.path.isfile(executable): + return executable + + if path is None: + path = os.environ.get('PATH', None) + if path is None: + try: + path = os.confstr("CS_PATH") + except (AttributeError, ValueError): + # os.confstr() or CS_PATH is not available + path = os.defpath + # bpo-35755: Don't use os.defpath if the PATH environment variable is + # set to an empty string + + # PATH='' doesn't match, whereas PATH=':' looks in the current directory + if not path: + return None + + paths = path.split(os.pathsep) + for p in paths: + f = os.path.join(p, executable) + if os.path.isfile(f): + # the file exists, we have a shot at spawn working + return f + return None diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/sysconfig.py b/MLPY/Lib/site-packages/setuptools/_distutils/sysconfig.py new file mode 100644 index 0000000000000000000000000000000000000000..8832b3ecebf8966796df4663d33ae6b57a4c4f7d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/sysconfig.py @@ -0,0 +1,578 @@ +"""Provide access to Python's configuration information. The specific +configuration variables available depend heavily on the platform and +configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. + +Written by: Fred L. Drake, Jr. +Email: +""" + +import _imp +import os +import re +import sys + +from .errors import DistutilsPlatformError + +IS_PYPY = '__pypy__' in sys.builtin_module_names + +# These are needed in a couple of spots, so just compute them once. +PREFIX = os.path.normpath(sys.prefix) +EXEC_PREFIX = os.path.normpath(sys.exec_prefix) +BASE_PREFIX = os.path.normpath(sys.base_prefix) +BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) + +# Path to the base directory of the project. On Windows the binary may +# live in project/PCbuild/win32 or project/PCbuild/amd64. +# set for cross builds +if "_PYTHON_PROJECT_BASE" in os.environ: + project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"]) +else: + if sys.executable: + project_base = os.path.dirname(os.path.abspath(sys.executable)) + else: + # sys.executable can be empty if argv[0] has been changed and Python is + # unable to retrieve the real program name + project_base = os.getcwd() + + +# python_build: (Boolean) if true, we're either building Python or +# building an extension with an un-installed Python, so we use +# different (hard-wired) directories. +def _is_python_source_dir(d): + for fn in ("Setup", "Setup.local"): + if os.path.isfile(os.path.join(d, "Modules", fn)): + return True + return False + +_sys_home = getattr(sys, '_home', None) + +if os.name == 'nt': + def _fix_pcbuild(d): + if d and os.path.normcase(d).startswith( + os.path.normcase(os.path.join(PREFIX, "PCbuild"))): + return PREFIX + return d + project_base = _fix_pcbuild(project_base) + _sys_home = _fix_pcbuild(_sys_home) + +def _python_build(): + if _sys_home: + return _is_python_source_dir(_sys_home) + return _is_python_source_dir(project_base) + +python_build = _python_build() + + +# Calculate the build qualifier flags if they are defined. Adding the flags +# to the include and lib directories only makes sense for an installation, not +# an in-source build. +build_flags = '' +try: + if not python_build: + build_flags = sys.abiflags +except AttributeError: + # It's not a configure-based build, so the sys module doesn't have + # this attribute, which is fine. + pass + +def get_python_version(): + """Return a string containing the major and minor Python version, + leaving off the patchlevel. Sample return values could be '1.5' + or '2.2'. + """ + return '%d.%d' % sys.version_info[:2] + + +def get_python_inc(plat_specific=0, prefix=None): + """Return the directory containing installed Python header files. + + If 'plat_specific' is false (the default), this is the path to the + non-platform-specific header files, i.e. Python.h and so on; + otherwise, this is the path to platform-specific header files + (namely pyconfig.h). + + If 'prefix' is supplied, use it instead of sys.base_prefix or + sys.base_exec_prefix -- i.e., ignore 'plat_specific'. + """ + if prefix is None: + prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX + if os.name == "posix": + if IS_PYPY and sys.version_info < (3, 8): + return os.path.join(prefix, 'include') + if python_build: + # Assume the executable is in the build directory. The + # pyconfig.h file should be in the same directory. Since + # the build directory may not be the source directory, we + # must use "srcdir" from the makefile to find the "Include" + # directory. + if plat_specific: + return _sys_home or project_base + else: + incdir = os.path.join(get_config_var('srcdir'), 'Include') + return os.path.normpath(incdir) + implementation = 'pypy' if IS_PYPY else 'python' + python_dir = implementation + get_python_version() + build_flags + return os.path.join(prefix, "include", python_dir) + elif os.name == "nt": + if python_build: + # Include both the include and PC dir to ensure we can find + # pyconfig.h + return (os.path.join(prefix, "include") + os.path.pathsep + + os.path.join(prefix, "PC")) + return os.path.join(prefix, "include") + else: + raise DistutilsPlatformError( + "I don't know where Python installs its C header files " + "on platform '%s'" % os.name) + + +def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): + """Return the directory containing the Python library (standard or + site additions). + + If 'plat_specific' is true, return the directory containing + platform-specific modules, i.e. any module from a non-pure-Python + module distribution; otherwise, return the platform-shared library + directory. If 'standard_lib' is true, return the directory + containing standard Python library modules; otherwise, return the + directory for site-specific modules. + + If 'prefix' is supplied, use it instead of sys.base_prefix or + sys.base_exec_prefix -- i.e., ignore 'plat_specific'. + """ + + if IS_PYPY and sys.version_info < (3, 8): + # PyPy-specific schema + if prefix is None: + prefix = PREFIX + if standard_lib: + return os.path.join(prefix, "lib-python", sys.version[0]) + return os.path.join(prefix, 'site-packages') + + if prefix is None: + if standard_lib: + prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX + else: + prefix = plat_specific and EXEC_PREFIX or PREFIX + + if os.name == "posix": + if plat_specific or standard_lib: + # Platform-specific modules (any module from a non-pure-Python + # module distribution) or standard Python library modules. + libdir = getattr(sys, "platlibdir", "lib") + else: + # Pure Python + libdir = "lib" + implementation = 'pypy' if IS_PYPY else 'python' + libpython = os.path.join(prefix, libdir, + implementation + get_python_version()) + if standard_lib: + return libpython + else: + return os.path.join(libpython, "site-packages") + elif os.name == "nt": + if standard_lib: + return os.path.join(prefix, "Lib") + else: + return os.path.join(prefix, "Lib", "site-packages") + else: + raise DistutilsPlatformError( + "I don't know where Python installs its library " + "on platform '%s'" % os.name) + + + +def customize_compiler(compiler): + """Do any platform-specific customization of a CCompiler instance. + + Mainly needed on Unix, so we can plug in the information that + varies across Unices and is stored in Python's Makefile. + """ + if compiler.compiler_type == "unix": + if sys.platform == "darwin": + # Perform first-time customization of compiler-related + # config vars on OS X now that we know we need a compiler. + # This is primarily to support Pythons from binary + # installers. The kind and paths to build tools on + # the user system may vary significantly from the system + # that Python itself was built on. Also the user OS + # version and build tools may not support the same set + # of CPU architectures for universal builds. + global _config_vars + # Use get_config_var() to ensure _config_vars is initialized. + if not get_config_var('CUSTOMIZED_OSX_COMPILER'): + import _osx_support + _osx_support.customize_compiler(_config_vars) + _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' + + (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ + get_config_vars('CC', 'CXX', 'CFLAGS', + 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') + + if 'CC' in os.environ: + newcc = os.environ['CC'] + if('LDSHARED' not in os.environ + and ldshared.startswith(cc)): + # If CC is overridden, use that as the default + # command for LDSHARED as well + ldshared = newcc + ldshared[len(cc):] + cc = newcc + if 'CXX' in os.environ: + cxx = os.environ['CXX'] + if 'LDSHARED' in os.environ: + ldshared = os.environ['LDSHARED'] + if 'CPP' in os.environ: + cpp = os.environ['CPP'] + else: + cpp = cc + " -E" # not always + if 'LDFLAGS' in os.environ: + ldshared = ldshared + ' ' + os.environ['LDFLAGS'] + if 'CFLAGS' in os.environ: + cflags = cflags + ' ' + os.environ['CFLAGS'] + ldshared = ldshared + ' ' + os.environ['CFLAGS'] + if 'CPPFLAGS' in os.environ: + cpp = cpp + ' ' + os.environ['CPPFLAGS'] + cflags = cflags + ' ' + os.environ['CPPFLAGS'] + ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] + if 'AR' in os.environ: + ar = os.environ['AR'] + if 'ARFLAGS' in os.environ: + archiver = ar + ' ' + os.environ['ARFLAGS'] + else: + archiver = ar + ' ' + ar_flags + + cc_cmd = cc + ' ' + cflags + compiler.set_executables( + preprocessor=cpp, + compiler=cc_cmd, + compiler_so=cc_cmd + ' ' + ccshared, + compiler_cxx=cxx, + linker_so=ldshared, + linker_exe=cc, + archiver=archiver) + + if 'RANLIB' in os.environ and compiler.executables.get('ranlib', None): + compiler.set_executables(ranlib=os.environ['RANLIB']) + + compiler.shared_lib_extension = shlib_suffix + + +def get_config_h_filename(): + """Return full pathname of installed pyconfig.h file.""" + if python_build: + if os.name == "nt": + inc_dir = os.path.join(_sys_home or project_base, "PC") + else: + inc_dir = _sys_home or project_base + else: + inc_dir = get_python_inc(plat_specific=1) + + return os.path.join(inc_dir, 'pyconfig.h') + + +def get_makefile_filename(): + """Return full pathname of installed Makefile from the Python build.""" + if python_build: + return os.path.join(_sys_home or project_base, "Makefile") + lib_dir = get_python_lib(plat_specific=0, standard_lib=1) + config_file = 'config-{}{}'.format(get_python_version(), build_flags) + if hasattr(sys.implementation, '_multiarch'): + config_file += '-%s' % sys.implementation._multiarch + return os.path.join(lib_dir, config_file, 'Makefile') + + +def parse_config_h(fp, g=None): + """Parse a config.h-style file. + + A dictionary containing name/value pairs is returned. If an + optional dictionary is passed in as the second argument, it is + used instead of a new dictionary. + """ + if g is None: + g = {} + define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") + undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") + # + while True: + line = fp.readline() + if not line: + break + m = define_rx.match(line) + if m: + n, v = m.group(1, 2) + try: v = int(v) + except ValueError: pass + g[n] = v + else: + m = undef_rx.match(line) + if m: + g[m.group(1)] = 0 + return g + + +# Regexes needed for parsing Makefile (and similar syntaxes, +# like old-style Setup files). +_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") +_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") +_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") + +def parse_makefile(fn, g=None): + """Parse a Makefile-style file. + + A dictionary containing name/value pairs is returned. If an + optional dictionary is passed in as the second argument, it is + used instead of a new dictionary. + """ + from distutils.text_file import TextFile + fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape") + + if g is None: + g = {} + done = {} + notdone = {} + + while True: + line = fp.readline() + if line is None: # eof + break + m = _variable_rx.match(line) + if m: + n, v = m.group(1, 2) + v = v.strip() + # `$$' is a literal `$' in make + tmpv = v.replace('$$', '') + + if "$" in tmpv: + notdone[n] = v + else: + try: + v = int(v) + except ValueError: + # insert literal `$' + done[n] = v.replace('$$', '$') + else: + done[n] = v + + # Variables with a 'PY_' prefix in the makefile. These need to + # be made available without that prefix through sysconfig. + # Special care is needed to ensure that variable expansion works, even + # if the expansion uses the name without a prefix. + renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') + + # do variable interpolation here + while notdone: + for name in list(notdone): + value = notdone[name] + m = _findvar1_rx.search(value) or _findvar2_rx.search(value) + if m: + n = m.group(1) + found = True + if n in done: + item = str(done[n]) + elif n in notdone: + # get it on a subsequent round + found = False + elif n in os.environ: + # do it like make: fall back to environment + item = os.environ[n] + + elif n in renamed_variables: + if name.startswith('PY_') and name[3:] in renamed_variables: + item = "" + + elif 'PY_' + n in notdone: + found = False + + else: + item = str(done['PY_' + n]) + else: + done[n] = item = "" + if found: + after = value[m.end():] + value = value[:m.start()] + item + after + if "$" in after: + notdone[name] = value + else: + try: value = int(value) + except ValueError: + done[name] = value.strip() + else: + done[name] = value + del notdone[name] + + if name.startswith('PY_') \ + and name[3:] in renamed_variables: + + name = name[3:] + if name not in done: + done[name] = value + else: + # bogus variable reference; just drop it since we can't deal + del notdone[name] + + fp.close() + + # strip spurious spaces + for k, v in done.items(): + if isinstance(v, str): + done[k] = v.strip() + + # save the results in the global dictionary + g.update(done) + return g + + +def expand_makefile_vars(s, vars): + """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in + 'string' according to 'vars' (a dictionary mapping variable names to + values). Variables not present in 'vars' are silently expanded to the + empty string. The variable values in 'vars' should not contain further + variable expansions; if 'vars' is the output of 'parse_makefile()', + you're fine. Returns a variable-expanded version of 's'. + """ + + # This algorithm does multiple expansion, so if vars['foo'] contains + # "${bar}", it will expand ${foo} to ${bar}, and then expand + # ${bar}... and so forth. This is fine as long as 'vars' comes from + # 'parse_makefile()', which takes care of such expansions eagerly, + # according to make's variable expansion semantics. + + while True: + m = _findvar1_rx.search(s) or _findvar2_rx.search(s) + if m: + (beg, end) = m.span() + s = s[0:beg] + vars.get(m.group(1)) + s[end:] + else: + break + return s + + +_config_vars = None + +def _init_posix(): + """Initialize the module as appropriate for POSIX systems.""" + # _sysconfigdata is generated at build time, see the sysconfig module + name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME', + '_sysconfigdata_{abi}_{platform}_{multiarch}'.format( + abi=sys.abiflags, + platform=sys.platform, + multiarch=getattr(sys.implementation, '_multiarch', ''), + )) + try: + _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) + except ImportError: + # Python 3.5 and pypy 7.3.1 + _temp = __import__( + '_sysconfigdata', globals(), locals(), ['build_time_vars'], 0) + build_time_vars = _temp.build_time_vars + global _config_vars + _config_vars = {} + _config_vars.update(build_time_vars) + + +def _init_nt(): + """Initialize the module as appropriate for NT""" + g = {} + # set basic install directories + g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) + g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) + + # XXX hmmm.. a normal install puts include files here + g['INCLUDEPY'] = get_python_inc(plat_specific=0) + + g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] + g['EXE'] = ".exe" + g['VERSION'] = get_python_version().replace(".", "") + g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) + + global _config_vars + _config_vars = g + + +def get_config_vars(*args): + """With no arguments, return a dictionary of all configuration + variables relevant for the current platform. Generally this includes + everything needed to build extensions and install both pure modules and + extensions. On Unix, this means every variable defined in Python's + installed Makefile; on Windows it's a much smaller set. + + With arguments, return a list of values that result from looking up + each argument in the configuration variable dictionary. + """ + global _config_vars + if _config_vars is None: + func = globals().get("_init_" + os.name) + if func: + func() + else: + _config_vars = {} + + # Normalized versions of prefix and exec_prefix are handy to have; + # in fact, these are the standard versions used most places in the + # Distutils. + _config_vars['prefix'] = PREFIX + _config_vars['exec_prefix'] = EXEC_PREFIX + + if not IS_PYPY: + # For backward compatibility, see issue19555 + SO = _config_vars.get('EXT_SUFFIX') + if SO is not None: + _config_vars['SO'] = SO + + # Always convert srcdir to an absolute path + srcdir = _config_vars.get('srcdir', project_base) + if os.name == 'posix': + if python_build: + # If srcdir is a relative path (typically '.' or '..') + # then it should be interpreted relative to the directory + # containing Makefile. + base = os.path.dirname(get_makefile_filename()) + srcdir = os.path.join(base, srcdir) + else: + # srcdir is not meaningful since the installation is + # spread about the filesystem. We choose the + # directory containing the Makefile since we know it + # exists. + srcdir = os.path.dirname(get_makefile_filename()) + _config_vars['srcdir'] = os.path.abspath(os.path.normpath(srcdir)) + + # Convert srcdir into an absolute path if it appears necessary. + # Normally it is relative to the build directory. However, during + # testing, for example, we might be running a non-installed python + # from a different directory. + if python_build and os.name == "posix": + base = project_base + if (not os.path.isabs(_config_vars['srcdir']) and + base != os.getcwd()): + # srcdir is relative and we are not in the same directory + # as the executable. Assume executable is in the build + # directory and make srcdir absolute. + srcdir = os.path.join(base, _config_vars['srcdir']) + _config_vars['srcdir'] = os.path.normpath(srcdir) + + # OS X platforms require special customization to handle + # multi-architecture, multi-os-version installers + if sys.platform == 'darwin': + import _osx_support + _osx_support.customize_config_vars(_config_vars) + + if args: + vals = [] + for name in args: + vals.append(_config_vars.get(name)) + return vals + else: + return _config_vars + +def get_config_var(name): + """Return the value of a single variable using the dictionary + returned by 'get_config_vars()'. Equivalent to + get_config_vars().get(name) + """ + if name == 'SO': + import warnings + warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2) + return get_config_vars().get(name) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/text_file.py b/MLPY/Lib/site-packages/setuptools/_distutils/text_file.py new file mode 100644 index 0000000000000000000000000000000000000000..93abad38f434d7ecf8d208cdefc310bd73a5a673 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/text_file.py @@ -0,0 +1,286 @@ +"""text_file + +provides the TextFile class, which gives an interface to text files +that (optionally) takes care of stripping comments, ignoring blank +lines, and joining lines with backslashes.""" + +import sys, io + + +class TextFile: + """Provides a file-like object that takes care of all the things you + commonly want to do when processing a text file that has some + line-by-line syntax: strip comments (as long as "#" is your + comment character), skip blank lines, join adjacent lines by + escaping the newline (ie. backslash at end of line), strip + leading and/or trailing whitespace. All of these are optional + and independently controllable. + + Provides a 'warn()' method so you can generate warning messages that + report physical line number, even if the logical line in question + spans multiple physical lines. Also provides 'unreadline()' for + implementing line-at-a-time lookahead. + + Constructor is called as: + + TextFile (filename=None, file=None, **options) + + It bombs (RuntimeError) if both 'filename' and 'file' are None; + 'filename' should be a string, and 'file' a file object (or + something that provides 'readline()' and 'close()' methods). It is + recommended that you supply at least 'filename', so that TextFile + can include it in warning messages. If 'file' is not supplied, + TextFile creates its own using 'io.open()'. + + The options are all boolean, and affect the value returned by + 'readline()': + strip_comments [default: true] + strip from "#" to end-of-line, as well as any whitespace + leading up to the "#" -- unless it is escaped by a backslash + lstrip_ws [default: false] + strip leading whitespace from each line before returning it + rstrip_ws [default: true] + strip trailing whitespace (including line terminator!) from + each line before returning it + skip_blanks [default: true} + skip lines that are empty *after* stripping comments and + whitespace. (If both lstrip_ws and rstrip_ws are false, + then some lines may consist of solely whitespace: these will + *not* be skipped, even if 'skip_blanks' is true.) + join_lines [default: false] + if a backslash is the last non-newline character on a line + after stripping comments and whitespace, join the following line + to it to form one "logical line"; if N consecutive lines end + with a backslash, then N+1 physical lines will be joined to + form one logical line. + collapse_join [default: false] + strip leading whitespace from lines that are joined to their + predecessor; only matters if (join_lines and not lstrip_ws) + errors [default: 'strict'] + error handler used to decode the file content + + Note that since 'rstrip_ws' can strip the trailing newline, the + semantics of 'readline()' must differ from those of the builtin file + object's 'readline()' method! In particular, 'readline()' returns + None for end-of-file: an empty string might just be a blank line (or + an all-whitespace line), if 'rstrip_ws' is true but 'skip_blanks' is + not.""" + + default_options = { 'strip_comments': 1, + 'skip_blanks': 1, + 'lstrip_ws': 0, + 'rstrip_ws': 1, + 'join_lines': 0, + 'collapse_join': 0, + 'errors': 'strict', + } + + def __init__(self, filename=None, file=None, **options): + """Construct a new TextFile object. At least one of 'filename' + (a string) and 'file' (a file-like object) must be supplied. + They keyword argument options are described above and affect + the values returned by 'readline()'.""" + if filename is None and file is None: + raise RuntimeError("you must supply either or both of 'filename' and 'file'") + + # set values for all options -- either from client option hash + # or fallback to default_options + for opt in self.default_options.keys(): + if opt in options: + setattr(self, opt, options[opt]) + else: + setattr(self, opt, self.default_options[opt]) + + # sanity check client option hash + for opt in options.keys(): + if opt not in self.default_options: + raise KeyError("invalid TextFile option '%s'" % opt) + + if file is None: + self.open(filename) + else: + self.filename = filename + self.file = file + self.current_line = 0 # assuming that file is at BOF! + + # 'linebuf' is a stack of lines that will be emptied before we + # actually read from the file; it's only populated by an + # 'unreadline()' operation + self.linebuf = [] + + def open(self, filename): + """Open a new file named 'filename'. This overrides both the + 'filename' and 'file' arguments to the constructor.""" + self.filename = filename + self.file = io.open(self.filename, 'r', errors=self.errors) + self.current_line = 0 + + def close(self): + """Close the current file and forget everything we know about it + (filename, current line number).""" + file = self.file + self.file = None + self.filename = None + self.current_line = None + file.close() + + def gen_error(self, msg, line=None): + outmsg = [] + if line is None: + line = self.current_line + outmsg.append(self.filename + ", ") + if isinstance(line, (list, tuple)): + outmsg.append("lines %d-%d: " % tuple(line)) + else: + outmsg.append("line %d: " % line) + outmsg.append(str(msg)) + return "".join(outmsg) + + def error(self, msg, line=None): + raise ValueError("error: " + self.gen_error(msg, line)) + + def warn(self, msg, line=None): + """Print (to stderr) a warning message tied to the current logical + line in the current file. If the current logical line in the + file spans multiple physical lines, the warning refers to the + whole range, eg. "lines 3-5". If 'line' supplied, it overrides + the current line number; it may be a list or tuple to indicate a + range of physical lines, or an integer for a single physical + line.""" + sys.stderr.write("warning: " + self.gen_error(msg, line) + "\n") + + def readline(self): + """Read and return a single logical line from the current file (or + from an internal buffer if lines have previously been "unread" + with 'unreadline()'). If the 'join_lines' option is true, this + may involve reading multiple physical lines concatenated into a + single string. Updates the current line number, so calling + 'warn()' after 'readline()' emits a warning about the physical + line(s) just read. Returns None on end-of-file, since the empty + string can occur if 'rstrip_ws' is true but 'strip_blanks' is + not.""" + # If any "unread" lines waiting in 'linebuf', return the top + # one. (We don't actually buffer read-ahead data -- lines only + # get put in 'linebuf' if the client explicitly does an + # 'unreadline()'. + if self.linebuf: + line = self.linebuf[-1] + del self.linebuf[-1] + return line + + buildup_line = '' + + while True: + # read the line, make it None if EOF + line = self.file.readline() + if line == '': + line = None + + if self.strip_comments and line: + + # Look for the first "#" in the line. If none, never + # mind. If we find one and it's the first character, or + # is not preceded by "\", then it starts a comment -- + # strip the comment, strip whitespace before it, and + # carry on. Otherwise, it's just an escaped "#", so + # unescape it (and any other escaped "#"'s that might be + # lurking in there) and otherwise leave the line alone. + + pos = line.find("#") + if pos == -1: # no "#" -- no comments + pass + + # It's definitely a comment -- either "#" is the first + # character, or it's elsewhere and unescaped. + elif pos == 0 or line[pos-1] != "\\": + # Have to preserve the trailing newline, because it's + # the job of a later step (rstrip_ws) to remove it -- + # and if rstrip_ws is false, we'd better preserve it! + # (NB. this means that if the final line is all comment + # and has no trailing newline, we will think that it's + # EOF; I think that's OK.) + eol = (line[-1] == '\n') and '\n' or '' + line = line[0:pos] + eol + + # If all that's left is whitespace, then skip line + # *now*, before we try to join it to 'buildup_line' -- + # that way constructs like + # hello \\ + # # comment that should be ignored + # there + # result in "hello there". + if line.strip() == "": + continue + else: # it's an escaped "#" + line = line.replace("\\#", "#") + + # did previous line end with a backslash? then accumulate + if self.join_lines and buildup_line: + # oops: end of file + if line is None: + self.warn("continuation line immediately precedes " + "end-of-file") + return buildup_line + + if self.collapse_join: + line = line.lstrip() + line = buildup_line + line + + # careful: pay attention to line number when incrementing it + if isinstance(self.current_line, list): + self.current_line[1] = self.current_line[1] + 1 + else: + self.current_line = [self.current_line, + self.current_line + 1] + # just an ordinary line, read it as usual + else: + if line is None: # eof + return None + + # still have to be careful about incrementing the line number! + if isinstance(self.current_line, list): + self.current_line = self.current_line[1] + 1 + else: + self.current_line = self.current_line + 1 + + # strip whitespace however the client wants (leading and + # trailing, or one or the other, or neither) + if self.lstrip_ws and self.rstrip_ws: + line = line.strip() + elif self.lstrip_ws: + line = line.lstrip() + elif self.rstrip_ws: + line = line.rstrip() + + # blank line (whether we rstrip'ed or not)? skip to next line + # if appropriate + if (line == '' or line == '\n') and self.skip_blanks: + continue + + if self.join_lines: + if line[-1] == '\\': + buildup_line = line[:-1] + continue + + if line[-2:] == '\\\n': + buildup_line = line[0:-2] + '\n' + continue + + # well, I guess there's some actual content there: return it + return line + + def readlines(self): + """Read and return the list of all logical lines remaining in the + current file.""" + lines = [] + while True: + line = self.readline() + if line is None: + return lines + lines.append(line) + + def unreadline(self, line): + """Push 'line' (a string) onto an internal buffer that will be + checked by future 'readline()' calls. Handy for implementing + a parser with line-at-a-time lookahead.""" + self.linebuf.append(line) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/unixccompiler.py b/MLPY/Lib/site-packages/setuptools/_distutils/unixccompiler.py new file mode 100644 index 0000000000000000000000000000000000000000..349cc1642b74c398b9b53f5616d3f0a023dab03a --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/unixccompiler.py @@ -0,0 +1,332 @@ +"""distutils.unixccompiler + +Contains the UnixCCompiler class, a subclass of CCompiler that handles +the "typical" Unix-style command-line C compiler: + * macros defined with -Dname[=value] + * macros undefined with -Uname + * include search directories specified with -Idir + * libraries specified with -lllib + * library search directories specified with -Ldir + * compile handled by 'cc' (or similar) executable with -c option: + compiles .c to .o + * link static library handled by 'ar' command (possibly with 'ranlib') + * link shared library handled by 'cc -shared' +""" + +import os, sys, re, shlex + +from distutils import sysconfig +from distutils.dep_util import newer +from distutils.ccompiler import \ + CCompiler, gen_preprocess_options, gen_lib_options +from distutils.errors import \ + DistutilsExecError, CompileError, LibError, LinkError +from distutils import log + +if sys.platform == 'darwin': + import _osx_support + +# XXX Things not currently handled: +# * optimization/debug/warning flags; we just use whatever's in Python's +# Makefile and live with it. Is this adequate? If not, we might +# have to have a bunch of subclasses GNUCCompiler, SGICCompiler, +# SunCCompiler, and I suspect down that road lies madness. +# * even if we don't know a warning flag from an optimization flag, +# we need some way for outsiders to feed preprocessor/compiler/linker +# flags in to us -- eg. a sysadmin might want to mandate certain flags +# via a site config file, or a user might want to set something for +# compiling this module distribution only via the setup.py command +# line, whatever. As long as these options come from something on the +# current system, they can be as system-dependent as they like, and we +# should just happily stuff them into the preprocessor/compiler/linker +# options and carry on. + + +class UnixCCompiler(CCompiler): + + compiler_type = 'unix' + + # These are used by CCompiler in two places: the constructor sets + # instance attributes 'preprocessor', 'compiler', etc. from them, and + # 'set_executable()' allows any of these to be set. The defaults here + # are pretty generic; they will probably have to be set by an outsider + # (eg. using information discovered by the sysconfig about building + # Python extensions). + executables = {'preprocessor' : None, + 'compiler' : ["cc"], + 'compiler_so' : ["cc"], + 'compiler_cxx' : ["cc"], + 'linker_so' : ["cc", "-shared"], + 'linker_exe' : ["cc"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : None, + } + + if sys.platform[:6] == "darwin": + executables['ranlib'] = ["ranlib"] + + # Needed for the filename generation methods provided by the base + # class, CCompiler. NB. whoever instantiates/uses a particular + # UnixCCompiler instance should set 'shared_lib_ext' -- we set a + # reasonable common default here, but it's not necessarily used on all + # Unices! + + src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] + obj_extension = ".o" + static_lib_extension = ".a" + shared_lib_extension = ".so" + dylib_lib_extension = ".dylib" + xcode_stub_lib_extension = ".tbd" + static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" + xcode_stub_lib_format = dylib_lib_format + if sys.platform == "cygwin": + exe_extension = ".exe" + + def preprocess(self, source, output_file=None, macros=None, + include_dirs=None, extra_preargs=None, extra_postargs=None): + fixed_args = self._fix_compile_args(None, macros, include_dirs) + ignore, macros, include_dirs = fixed_args + pp_opts = gen_preprocess_options(macros, include_dirs) + pp_args = self.preprocessor + pp_opts + if output_file: + pp_args.extend(['-o', output_file]) + if extra_preargs: + pp_args[:0] = extra_preargs + if extra_postargs: + pp_args.extend(extra_postargs) + pp_args.append(source) + + # We need to preprocess: either we're being forced to, or we're + # generating output to stdout, or there's a target output file and + # the source file is newer than the target (or the target doesn't + # exist). + if self.force or output_file is None or newer(source, output_file): + if output_file: + self.mkpath(os.path.dirname(output_file)) + try: + self.spawn(pp_args) + except DistutilsExecError as msg: + raise CompileError(msg) + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + compiler_so = self.compiler_so + if sys.platform == 'darwin': + compiler_so = _osx_support.compiler_fixup(compiler_so, + cc_args + extra_postargs) + try: + self.spawn(compiler_so + cc_args + [src, '-o', obj] + + extra_postargs) + except DistutilsExecError as msg: + raise CompileError(msg) + + def create_static_lib(self, objects, output_libname, + output_dir=None, debug=0, target_lang=None): + objects, output_dir = self._fix_object_args(objects, output_dir) + + output_filename = \ + self.library_filename(output_libname, output_dir=output_dir) + + if self._need_link(objects, output_filename): + self.mkpath(os.path.dirname(output_filename)) + self.spawn(self.archiver + + [output_filename] + + objects + self.objects) + + # Not many Unices required ranlib anymore -- SunOS 4.x is, I + # think the only major Unix that does. Maybe we need some + # platform intelligence here to skip ranlib if it's not + # needed -- or maybe Python's configure script took care of + # it for us, hence the check for leading colon. + if self.ranlib: + try: + self.spawn(self.ranlib + [output_filename]) + except DistutilsExecError as msg: + raise LibError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + def link(self, target_desc, objects, + output_filename, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=0, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + objects, output_dir = self._fix_object_args(objects, output_dir) + fixed_args = self._fix_lib_args(libraries, library_dirs, + runtime_library_dirs) + libraries, library_dirs, runtime_library_dirs = fixed_args + + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, + libraries) + if not isinstance(output_dir, (str, type(None))): + raise TypeError("'output_dir' must be a string or None") + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + ld_args = (objects + self.objects + + lib_opts + ['-o', output_filename]) + if debug: + ld_args[:0] = ['-g'] + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + self.mkpath(os.path.dirname(output_filename)) + try: + if target_desc == CCompiler.EXECUTABLE: + linker = self.linker_exe[:] + else: + linker = self.linker_so[:] + if target_lang == "c++" and self.compiler_cxx: + # skip over environment variable settings if /usr/bin/env + # is used to set up the linker's environment. + # This is needed on OSX. Note: this assumes that the + # normal and C++ compiler have the same environment + # settings. + i = 0 + if os.path.basename(linker[0]) == "env": + i = 1 + while '=' in linker[i]: + i += 1 + + if os.path.basename(linker[i]) == 'ld_so_aix': + # AIX platforms prefix the compiler with the ld_so_aix + # script, so we need to adjust our linker index + offset = 1 + else: + offset = 0 + + linker[i+offset] = self.compiler_cxx[i] + + if sys.platform == 'darwin': + linker = _osx_support.compiler_fixup(linker, ld_args) + + self.spawn(linker + ld_args) + except DistutilsExecError as msg: + raise LinkError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "-L" + dir + + def _is_gcc(self, compiler_name): + return "gcc" in compiler_name or "g++" in compiler_name + + def runtime_library_dir_option(self, dir): + # XXX Hackish, at the very least. See Python bug #445902: + # http://sourceforge.net/tracker/index.php + # ?func=detail&aid=445902&group_id=5470&atid=105470 + # Linkers on different platforms need different options to + # specify that directories need to be added to the list of + # directories searched for dependencies when a dynamic library + # is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to + # be told to pass the -R option through to the linker, whereas + # other compilers and gcc on other systems just know this. + # Other compilers may need something slightly different. At + # this time, there's no way to determine this information from + # the configuration data stored in the Python installation, so + # we use this hack. + compiler = os.path.basename(shlex.split(sysconfig.get_config_var("CC"))[0]) + if sys.platform[:6] == "darwin": + from distutils.util import get_macosx_target_ver, split_version + macosx_target_ver = get_macosx_target_ver() + if macosx_target_ver and split_version(macosx_target_ver) >= [10, 5]: + return "-Wl,-rpath," + dir + else: # no support for -rpath on earlier macOS versions + return "-L" + dir + elif sys.platform[:7] == "freebsd": + return "-Wl,-rpath=" + dir + elif sys.platform[:5] == "hp-ux": + if self._is_gcc(compiler): + return ["-Wl,+s", "-L" + dir] + return ["+s", "-L" + dir] + else: + if self._is_gcc(compiler): + # gcc on non-GNU systems does not need -Wl, but can + # use it anyway. Since distutils has always passed in + # -Wl whenever gcc was used in the past it is probably + # safest to keep doing so. + if sysconfig.get_config_var("GNULD") == "yes": + # GNU ld needs an extra option to get a RUNPATH + # instead of just an RPATH. + return "-Wl,--enable-new-dtags,-R" + dir + else: + return "-Wl,-R" + dir + else: + # No idea how --enable-new-dtags would be passed on to + # ld if this system was using GNU ld. Don't know if a + # system like this even exists. + return "-R" + dir + + def library_option(self, lib): + return "-l" + lib + + def find_library_file(self, dirs, lib, debug=0): + shared_f = self.library_filename(lib, lib_type='shared') + dylib_f = self.library_filename(lib, lib_type='dylib') + xcode_stub_f = self.library_filename(lib, lib_type='xcode_stub') + static_f = self.library_filename(lib, lib_type='static') + + if sys.platform == 'darwin': + # On OSX users can specify an alternate SDK using + # '-isysroot', calculate the SDK root if it is specified + # (and use it further on) + # + # Note that, as of Xcode 7, Apple SDKs may contain textual stub + # libraries with .tbd extensions rather than the normal .dylib + # shared libraries installed in /. The Apple compiler tool + # chain handles this transparently but it can cause problems + # for programs that are being built with an SDK and searching + # for specific libraries. Callers of find_library_file need to + # keep in mind that the base filename of the returned SDK library + # file might have a different extension from that of the library + # file installed on the running system, for example: + # /Applications/Xcode.app/Contents/Developer/Platforms/ + # MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/ + # usr/lib/libedit.tbd + # vs + # /usr/lib/libedit.dylib + cflags = sysconfig.get_config_var('CFLAGS') + m = re.search(r'-isysroot\s*(\S+)', cflags) + if m is None: + sysroot = '/' + else: + sysroot = m.group(1) + + + + for dir in dirs: + shared = os.path.join(dir, shared_f) + dylib = os.path.join(dir, dylib_f) + static = os.path.join(dir, static_f) + xcode_stub = os.path.join(dir, xcode_stub_f) + + if sys.platform == 'darwin' and ( + dir.startswith('/System/') or ( + dir.startswith('/usr/') and not dir.startswith('/usr/local/'))): + + shared = os.path.join(sysroot, dir[1:], shared_f) + dylib = os.path.join(sysroot, dir[1:], dylib_f) + static = os.path.join(sysroot, dir[1:], static_f) + xcode_stub = os.path.join(sysroot, dir[1:], xcode_stub_f) + + # We're second-guessing the linker here, with not much hard + # data to go on: GCC seems to prefer the shared library, so I'm + # assuming that *all* Unix C compilers do. And of course I'm + # ignoring even GCC's "-static" option. So sue me. + if os.path.exists(dylib): + return dylib + elif os.path.exists(xcode_stub): + return xcode_stub + elif os.path.exists(shared): + return shared + elif os.path.exists(static): + return static + + # Oops, didn't find it in *any* of 'dirs' + return None diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/util.py b/MLPY/Lib/site-packages/setuptools/_distutils/util.py new file mode 100644 index 0000000000000000000000000000000000000000..64f06dd4bce4d634946bb836d56eff78196e0b6d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/util.py @@ -0,0 +1,535 @@ +"""distutils.util + +Miscellaneous utility functions -- anything that doesn't fit into +one of the other *util.py modules. +""" + +import os +import re +import importlib.util +import string +import sys +from distutils.errors import DistutilsPlatformError +from distutils.dep_util import newer +from distutils.spawn import spawn +from distutils import log +from distutils.errors import DistutilsByteCompileError +from .py35compat import _optim_args_from_interpreter_flags + + +def get_host_platform(): + """Return a string that identifies the current platform. This is used mainly to + distinguish platform-specific build directories and platform-specific built + distributions. Typically includes the OS name and version and the + architecture (as supplied by 'os.uname()'), although the exact information + included depends on the OS; eg. on Linux, the kernel version isn't + particularly important. + + Examples of returned values: + linux-i586 + linux-alpha (?) + solaris-2.6-sun4u + + Windows will return one of: + win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) + win32 (all others - specifically, sys.platform is returned) + + For other non-POSIX platforms, currently just returns 'sys.platform'. + + """ + if os.name == 'nt': + if 'amd64' in sys.version.lower(): + return 'win-amd64' + if '(arm)' in sys.version.lower(): + return 'win-arm32' + if '(arm64)' in sys.version.lower(): + return 'win-arm64' + return sys.platform + + # Set for cross builds explicitly + if "_PYTHON_HOST_PLATFORM" in os.environ: + return os.environ["_PYTHON_HOST_PLATFORM"] + + if os.name != "posix" or not hasattr(os, 'uname'): + # XXX what about the architecture? NT is Intel or Alpha, + # Mac OS is M68k or PPC, etc. + return sys.platform + + # Try to distinguish various flavours of Unix + + (osname, host, release, version, machine) = os.uname() + + # Convert the OS name to lowercase, remove '/' characters, and translate + # spaces (for "Power Macintosh") + osname = osname.lower().replace('/', '') + machine = machine.replace(' ', '_') + machine = machine.replace('/', '-') + + if osname[:5] == "linux": + # At least on Linux/Intel, 'machine' is the processor -- + # i386, etc. + # XXX what about Alpha, SPARC, etc? + return "%s-%s" % (osname, machine) + elif osname[:5] == "sunos": + if release[0] >= "5": # SunOS 5 == Solaris 2 + osname = "solaris" + release = "%d.%s" % (int(release[0]) - 3, release[2:]) + # We can't use "platform.architecture()[0]" because a + # bootstrap problem. We use a dict to get an error + # if some suspicious happens. + bitness = {2147483647:"32bit", 9223372036854775807:"64bit"} + machine += ".%s" % bitness[sys.maxsize] + # fall through to standard osname-release-machine representation + elif osname[:3] == "aix": + from .py38compat import aix_platform + return aix_platform(osname, version, release) + elif osname[:6] == "cygwin": + osname = "cygwin" + rel_re = re.compile (r'[\d.]+', re.ASCII) + m = rel_re.match(release) + if m: + release = m.group() + elif osname[:6] == "darwin": + import _osx_support, distutils.sysconfig + osname, release, machine = _osx_support.get_platform_osx( + distutils.sysconfig.get_config_vars(), + osname, release, machine) + + return "%s-%s-%s" % (osname, release, machine) + +def get_platform(): + if os.name == 'nt': + TARGET_TO_PLAT = { + 'x86' : 'win32', + 'x64' : 'win-amd64', + 'arm' : 'win-arm32', + 'arm64': 'win-arm64', + } + return TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) or get_host_platform() + else: + return get_host_platform() + + +if sys.platform == 'darwin': + _syscfg_macosx_ver = None # cache the version pulled from sysconfig +MACOSX_VERSION_VAR = 'MACOSX_DEPLOYMENT_TARGET' + +def _clear_cached_macosx_ver(): + """For testing only. Do not call.""" + global _syscfg_macosx_ver + _syscfg_macosx_ver = None + +def get_macosx_target_ver_from_syscfg(): + """Get the version of macOS latched in the Python interpreter configuration. + Returns the version as a string or None if can't obtain one. Cached.""" + global _syscfg_macosx_ver + if _syscfg_macosx_ver is None: + from distutils import sysconfig + ver = sysconfig.get_config_var(MACOSX_VERSION_VAR) or '' + if ver: + _syscfg_macosx_ver = ver + return _syscfg_macosx_ver + +def get_macosx_target_ver(): + """Return the version of macOS for which we are building. + + The target version defaults to the version in sysconfig latched at time + the Python interpreter was built, unless overriden by an environment + variable. If neither source has a value, then None is returned""" + + syscfg_ver = get_macosx_target_ver_from_syscfg() + env_ver = os.environ.get(MACOSX_VERSION_VAR) + + if env_ver: + # Validate overriden version against sysconfig version, if have both. + # Ensure that the deployment target of the build process is not less + # than 10.3 if the interpreter was built for 10.3 or later. This + # ensures extension modules are built with correct compatibility + # values, specifically LDSHARED which can use + # '-undefined dynamic_lookup' which only works on >= 10.3. + if syscfg_ver and split_version(syscfg_ver) >= [10, 3] and \ + split_version(env_ver) < [10, 3]: + my_msg = ('$' + MACOSX_VERSION_VAR + ' mismatch: ' + 'now "%s" but "%s" during configure; ' + 'must use 10.3 or later' + % (env_ver, syscfg_ver)) + raise DistutilsPlatformError(my_msg) + return env_ver + return syscfg_ver + + +def split_version(s): + """Convert a dot-separated string into a list of numbers for comparisons""" + return [int(n) for n in s.split('.')] + + +def convert_path (pathname): + """Return 'pathname' as a name that will work on the native filesystem, + i.e. split it on '/' and put it back together again using the current + directory separator. Needed because filenames in the setup script are + always supplied in Unix style, and have to be converted to the local + convention before we can actually use them in the filesystem. Raises + ValueError on non-Unix-ish systems if 'pathname' either starts or + ends with a slash. + """ + if os.sep == '/': + return pathname + if not pathname: + return pathname + if pathname[0] == '/': + raise ValueError("path '%s' cannot be absolute" % pathname) + if pathname[-1] == '/': + raise ValueError("path '%s' cannot end with '/'" % pathname) + + paths = pathname.split('/') + while '.' in paths: + paths.remove('.') + if not paths: + return os.curdir + return os.path.join(*paths) + +# convert_path () + + +def change_root (new_root, pathname): + """Return 'pathname' with 'new_root' prepended. If 'pathname' is + relative, this is equivalent to "os.path.join(new_root,pathname)". + Otherwise, it requires making 'pathname' relative and then joining the + two, which is tricky on DOS/Windows and Mac OS. + """ + if os.name == 'posix': + if not os.path.isabs(pathname): + return os.path.join(new_root, pathname) + else: + return os.path.join(new_root, pathname[1:]) + + elif os.name == 'nt': + (drive, path) = os.path.splitdrive(pathname) + if path[0] == '\\': + path = path[1:] + return os.path.join(new_root, path) + + else: + raise DistutilsPlatformError("nothing known about platform '%s'" % os.name) + + +_environ_checked = 0 +def check_environ (): + """Ensure that 'os.environ' has all the environment variables we + guarantee that users can use in config files, command-line options, + etc. Currently this includes: + HOME - user's home directory (Unix only) + PLAT - description of the current platform, including hardware + and OS (see 'get_platform()') + """ + global _environ_checked + if _environ_checked: + return + + if os.name == 'posix' and 'HOME' not in os.environ: + try: + import pwd + os.environ['HOME'] = pwd.getpwuid(os.getuid())[5] + except (ImportError, KeyError): + # bpo-10496: if the current user identifier doesn't exist in the + # password database, do nothing + pass + + if 'PLAT' not in os.environ: + os.environ['PLAT'] = get_platform() + + _environ_checked = 1 + + +def subst_vars (s, local_vars): + """Perform shell/Perl-style variable substitution on 'string'. Every + occurrence of '$' followed by a name is considered a variable, and + variable is substituted by the value found in the 'local_vars' + dictionary, or in 'os.environ' if it's not in 'local_vars'. + 'os.environ' is first checked/augmented to guarantee that it contains + certain values: see 'check_environ()'. Raise ValueError for any + variables not found in either 'local_vars' or 'os.environ'. + """ + check_environ() + def _subst (match, local_vars=local_vars): + var_name = match.group(1) + if var_name in local_vars: + return str(local_vars[var_name]) + else: + return os.environ[var_name] + + try: + return re.sub(r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, s) + except KeyError as var: + raise ValueError("invalid variable '$%s'" % var) + +# subst_vars () + + +def grok_environment_error (exc, prefix="error: "): + # Function kept for backward compatibility. + # Used to try clever things with EnvironmentErrors, + # but nowadays str(exception) produces good messages. + return prefix + str(exc) + + +# Needed by 'split_quoted()' +_wordchars_re = _squote_re = _dquote_re = None +def _init_regex(): + global _wordchars_re, _squote_re, _dquote_re + _wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace) + _squote_re = re.compile(r"'(?:[^'\\]|\\.)*'") + _dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"') + +def split_quoted (s): + """Split a string up according to Unix shell-like rules for quotes and + backslashes. In short: words are delimited by spaces, as long as those + spaces are not escaped by a backslash, or inside a quoted string. + Single and double quotes are equivalent, and the quote characters can + be backslash-escaped. The backslash is stripped from any two-character + escape sequence, leaving only the escaped character. The quote + characters are stripped from any quoted string. Returns a list of + words. + """ + + # This is a nice algorithm for splitting up a single string, since it + # doesn't require character-by-character examination. It was a little + # bit of a brain-bender to get it working right, though... + if _wordchars_re is None: _init_regex() + + s = s.strip() + words = [] + pos = 0 + + while s: + m = _wordchars_re.match(s, pos) + end = m.end() + if end == len(s): + words.append(s[:end]) + break + + if s[end] in string.whitespace: # unescaped, unquoted whitespace: now + words.append(s[:end]) # we definitely have a word delimiter + s = s[end:].lstrip() + pos = 0 + + elif s[end] == '\\': # preserve whatever is being escaped; + # will become part of the current word + s = s[:end] + s[end+1:] + pos = end+1 + + else: + if s[end] == "'": # slurp singly-quoted string + m = _squote_re.match(s, end) + elif s[end] == '"': # slurp doubly-quoted string + m = _dquote_re.match(s, end) + else: + raise RuntimeError("this can't happen (bad char '%c')" % s[end]) + + if m is None: + raise ValueError("bad string (mismatched %s quotes?)" % s[end]) + + (beg, end) = m.span() + s = s[:beg] + s[beg+1:end-1] + s[end:] + pos = m.end() - 2 + + if pos >= len(s): + words.append(s) + break + + return words + +# split_quoted () + + +def execute (func, args, msg=None, verbose=0, dry_run=0): + """Perform some action that affects the outside world (eg. by + writing to the filesystem). Such actions are special because they + are disabled by the 'dry_run' flag. This method takes care of all + that bureaucracy for you; all you have to do is supply the + function to call and an argument tuple for it (to embody the + "external action" being performed), and an optional message to + print. + """ + if msg is None: + msg = "%s%r" % (func.__name__, args) + if msg[-2:] == ',)': # correct for singleton tuple + msg = msg[0:-2] + ')' + + log.info(msg) + if not dry_run: + func(*args) + + +def strtobool (val): + """Convert a string representation of truth to true (1) or false (0). + + True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values + are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if + 'val' is anything else. + """ + val = val.lower() + if val in ('y', 'yes', 't', 'true', 'on', '1'): + return 1 + elif val in ('n', 'no', 'f', 'false', 'off', '0'): + return 0 + else: + raise ValueError("invalid truth value %r" % (val,)) + + +def byte_compile (py_files, + optimize=0, force=0, + prefix=None, base_dir=None, + verbose=1, dry_run=0, + direct=None): + """Byte-compile a collection of Python source files to .pyc + files in a __pycache__ subdirectory. 'py_files' is a list + of files to compile; any files that don't end in ".py" are silently + skipped. 'optimize' must be one of the following: + 0 - don't optimize + 1 - normal optimization (like "python -O") + 2 - extra optimization (like "python -OO") + If 'force' is true, all files are recompiled regardless of + timestamps. + + The source filename encoded in each bytecode file defaults to the + filenames listed in 'py_files'; you can modify these with 'prefix' and + 'basedir'. 'prefix' is a string that will be stripped off of each + source filename, and 'base_dir' is a directory name that will be + prepended (after 'prefix' is stripped). You can supply either or both + (or neither) of 'prefix' and 'base_dir', as you wish. + + If 'dry_run' is true, doesn't actually do anything that would + affect the filesystem. + + Byte-compilation is either done directly in this interpreter process + with the standard py_compile module, or indirectly by writing a + temporary script and executing it. Normally, you should let + 'byte_compile()' figure out to use direct compilation or not (see + the source for details). The 'direct' flag is used by the script + generated in indirect mode; unless you know what you're doing, leave + it set to None. + """ + + # Late import to fix a bootstrap issue: _posixsubprocess is built by + # setup.py, but setup.py uses distutils. + import subprocess + + # nothing is done if sys.dont_write_bytecode is True + if sys.dont_write_bytecode: + raise DistutilsByteCompileError('byte-compiling is disabled.') + + # First, if the caller didn't force us into direct or indirect mode, + # figure out which mode we should be in. We take a conservative + # approach: choose direct mode *only* if the current interpreter is + # in debug mode and optimize is 0. If we're not in debug mode (-O + # or -OO), we don't know which level of optimization this + # interpreter is running with, so we can't do direct + # byte-compilation and be certain that it's the right thing. Thus, + # always compile indirectly if the current interpreter is in either + # optimize mode, or if either optimization level was requested by + # the caller. + if direct is None: + direct = (__debug__ and optimize == 0) + + # "Indirect" byte-compilation: write a temporary script and then + # run it with the appropriate flags. + if not direct: + try: + from tempfile import mkstemp + (script_fd, script_name) = mkstemp(".py") + except ImportError: + from tempfile import mktemp + (script_fd, script_name) = None, mktemp(".py") + log.info("writing byte-compilation script '%s'", script_name) + if not dry_run: + if script_fd is not None: + script = os.fdopen(script_fd, "w") + else: + script = open(script_name, "w") + + with script: + script.write("""\ +from distutils.util import byte_compile +files = [ +""") + + # XXX would be nice to write absolute filenames, just for + # safety's sake (script should be more robust in the face of + # chdir'ing before running it). But this requires abspath'ing + # 'prefix' as well, and that breaks the hack in build_lib's + # 'byte_compile()' method that carefully tacks on a trailing + # slash (os.sep really) to make sure the prefix here is "just + # right". This whole prefix business is rather delicate -- the + # problem is that it's really a directory, but I'm treating it + # as a dumb string, so trailing slashes and so forth matter. + + #py_files = map(os.path.abspath, py_files) + #if prefix: + # prefix = os.path.abspath(prefix) + + script.write(",\n".join(map(repr, py_files)) + "]\n") + script.write(""" +byte_compile(files, optimize=%r, force=%r, + prefix=%r, base_dir=%r, + verbose=%r, dry_run=0, + direct=1) +""" % (optimize, force, prefix, base_dir, verbose)) + + cmd = [sys.executable] + cmd.extend(_optim_args_from_interpreter_flags()) + cmd.append(script_name) + spawn(cmd, dry_run=dry_run) + execute(os.remove, (script_name,), "removing %s" % script_name, + dry_run=dry_run) + + # "Direct" byte-compilation: use the py_compile module to compile + # right here, right now. Note that the script generated in indirect + # mode simply calls 'byte_compile()' in direct mode, a weird sort of + # cross-process recursion. Hey, it works! + else: + from py_compile import compile + + for file in py_files: + if file[-3:] != ".py": + # This lets us be lazy and not filter filenames in + # the "install_lib" command. + continue + + # Terminology from the py_compile module: + # cfile - byte-compiled file + # dfile - purported source filename (same as 'file' by default) + if optimize >= 0: + opt = '' if optimize == 0 else optimize + cfile = importlib.util.cache_from_source( + file, optimization=opt) + else: + cfile = importlib.util.cache_from_source(file) + dfile = file + if prefix: + if file[:len(prefix)] != prefix: + raise ValueError("invalid prefix: filename %r doesn't start with %r" + % (file, prefix)) + dfile = dfile[len(prefix):] + if base_dir: + dfile = os.path.join(base_dir, dfile) + + cfile_base = os.path.basename(cfile) + if direct: + if force or newer(file, cfile): + log.info("byte-compiling %s to %s", file, cfile_base) + if not dry_run: + compile(file, cfile, dfile) + else: + log.debug("skipping byte-compilation of %s to %s", + file, cfile_base) + +# byte_compile () + +def rfc822_escape (header): + """Return a version of the string escaped for inclusion in an + RFC-822 header, by ensuring there are 8 spaces space after each newline. + """ + lines = header.split('\n') + sep = '\n' + 8 * ' ' + return sep.join(lines) diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/version.py b/MLPY/Lib/site-packages/setuptools/_distutils/version.py new file mode 100644 index 0000000000000000000000000000000000000000..c33bebaed26aeead3a97b48dcd4f34308ca3976e --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/version.py @@ -0,0 +1,347 @@ +# +# distutils/version.py +# +# Implements multiple version numbering conventions for the +# Python Module Distribution Utilities. +# +# $Id$ +# + +"""Provides classes to represent module version numbers (one class for +each style of version numbering). There are currently two such classes +implemented: StrictVersion and LooseVersion. + +Every version number class implements the following interface: + * the 'parse' method takes a string and parses it to some internal + representation; if the string is an invalid version number, + 'parse' raises a ValueError exception + * the class constructor takes an optional string argument which, + if supplied, is passed to 'parse' + * __str__ reconstructs the string that was passed to 'parse' (or + an equivalent string -- ie. one that will generate an equivalent + version number instance) + * __repr__ generates Python code to recreate the version number instance + * _cmp compares the current instance with either another instance + of the same class or a string (which will be parsed to an instance + of the same class, thus must follow the same rules) +""" + +import re + +class Version: + """Abstract base class for version numbering classes. Just provides + constructor (__init__) and reproducer (__repr__), because those + seem to be the same for all version numbering classes; and route + rich comparisons to _cmp. + """ + + def __init__ (self, vstring=None): + if vstring: + self.parse(vstring) + + def __repr__ (self): + return "%s ('%s')" % (self.__class__.__name__, str(self)) + + def __eq__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c == 0 + + def __lt__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c < 0 + + def __le__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c <= 0 + + def __gt__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c > 0 + + def __ge__(self, other): + c = self._cmp(other) + if c is NotImplemented: + return c + return c >= 0 + + +# Interface for version-number classes -- must be implemented +# by the following classes (the concrete ones -- Version should +# be treated as an abstract class). +# __init__ (string) - create and take same action as 'parse' +# (string parameter is optional) +# parse (string) - convert a string representation to whatever +# internal representation is appropriate for +# this style of version numbering +# __str__ (self) - convert back to a string; should be very similar +# (if not identical to) the string supplied to parse +# __repr__ (self) - generate Python code to recreate +# the instance +# _cmp (self, other) - compare two version numbers ('other' may +# be an unparsed version string, or another +# instance of your version class) + + +class StrictVersion (Version): + + """Version numbering for anal retentives and software idealists. + Implements the standard interface for version number classes as + described above. A version number consists of two or three + dot-separated numeric components, with an optional "pre-release" tag + on the end. The pre-release tag consists of the letter 'a' or 'b' + followed by a number. If the numeric components of two version + numbers are equal, then one with a pre-release tag will always + be deemed earlier (lesser) than one without. + + The following are valid version numbers (shown in the order that + would be obtained by sorting according to the supplied cmp function): + + 0.4 0.4.0 (these two are equivalent) + 0.4.1 + 0.5a1 + 0.5b3 + 0.5 + 0.9.6 + 1.0 + 1.0.4a3 + 1.0.4b1 + 1.0.4 + + The following are examples of invalid version numbers: + + 1 + 2.7.2.2 + 1.3.a4 + 1.3pl1 + 1.3c4 + + The rationale for this version numbering system will be explained + in the distutils documentation. + """ + + version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', + re.VERBOSE | re.ASCII) + + + def parse (self, vstring): + match = self.version_re.match(vstring) + if not match: + raise ValueError("invalid version number '%s'" % vstring) + + (major, minor, patch, prerelease, prerelease_num) = \ + match.group(1, 2, 4, 5, 6) + + if patch: + self.version = tuple(map(int, [major, minor, patch])) + else: + self.version = tuple(map(int, [major, minor])) + (0,) + + if prerelease: + self.prerelease = (prerelease[0], int(prerelease_num)) + else: + self.prerelease = None + + + def __str__ (self): + + if self.version[2] == 0: + vstring = '.'.join(map(str, self.version[0:2])) + else: + vstring = '.'.join(map(str, self.version)) + + if self.prerelease: + vstring = vstring + self.prerelease[0] + str(self.prerelease[1]) + + return vstring + + + def _cmp (self, other): + if isinstance(other, str): + other = StrictVersion(other) + elif not isinstance(other, StrictVersion): + return NotImplemented + + if self.version != other.version: + # numeric versions don't match + # prerelease stuff doesn't matter + if self.version < other.version: + return -1 + else: + return 1 + + # have to compare prerelease + # case 1: neither has prerelease; they're equal + # case 2: self has prerelease, other doesn't; other is greater + # case 3: self doesn't have prerelease, other does: self is greater + # case 4: both have prerelease: must compare them! + + if (not self.prerelease and not other.prerelease): + return 0 + elif (self.prerelease and not other.prerelease): + return -1 + elif (not self.prerelease and other.prerelease): + return 1 + elif (self.prerelease and other.prerelease): + if self.prerelease == other.prerelease: + return 0 + elif self.prerelease < other.prerelease: + return -1 + else: + return 1 + else: + assert False, "never get here" + +# end class StrictVersion + + +# The rules according to Greg Stein: +# 1) a version number has 1 or more numbers separated by a period or by +# sequences of letters. If only periods, then these are compared +# left-to-right to determine an ordering. +# 2) sequences of letters are part of the tuple for comparison and are +# compared lexicographically +# 3) recognize the numeric components may have leading zeroes +# +# The LooseVersion class below implements these rules: a version number +# string is split up into a tuple of integer and string components, and +# comparison is a simple tuple comparison. This means that version +# numbers behave in a predictable and obvious way, but a way that might +# not necessarily be how people *want* version numbers to behave. There +# wouldn't be a problem if people could stick to purely numeric version +# numbers: just split on period and compare the numbers as tuples. +# However, people insist on putting letters into their version numbers; +# the most common purpose seems to be: +# - indicating a "pre-release" version +# ('alpha', 'beta', 'a', 'b', 'pre', 'p') +# - indicating a post-release patch ('p', 'pl', 'patch') +# but of course this can't cover all version number schemes, and there's +# no way to know what a programmer means without asking him. +# +# The problem is what to do with letters (and other non-numeric +# characters) in a version number. The current implementation does the +# obvious and predictable thing: keep them as strings and compare +# lexically within a tuple comparison. This has the desired effect if +# an appended letter sequence implies something "post-release": +# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002". +# +# However, if letters in a version number imply a pre-release version, +# the "obvious" thing isn't correct. Eg. you would expect that +# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison +# implemented here, this just isn't so. +# +# Two possible solutions come to mind. The first is to tie the +# comparison algorithm to a particular set of semantic rules, as has +# been done in the StrictVersion class above. This works great as long +# as everyone can go along with bondage and discipline. Hopefully a +# (large) subset of Python module programmers will agree that the +# particular flavour of bondage and discipline provided by StrictVersion +# provides enough benefit to be worth using, and will submit their +# version numbering scheme to its domination. The free-thinking +# anarchists in the lot will never give in, though, and something needs +# to be done to accommodate them. +# +# Perhaps a "moderately strict" version class could be implemented that +# lets almost anything slide (syntactically), and makes some heuristic +# assumptions about non-digits in version number strings. This could +# sink into special-case-hell, though; if I was as talented and +# idiosyncratic as Larry Wall, I'd go ahead and implement a class that +# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is +# just as happy dealing with things like "2g6" and "1.13++". I don't +# think I'm smart enough to do it right though. +# +# In any case, I've coded the test suite for this module (see +# ../test/test_version.py) specifically to fail on things like comparing +# "1.2a2" and "1.2". That's not because the *code* is doing anything +# wrong, it's because the simple, obvious design doesn't match my +# complicated, hairy expectations for real-world version numbers. It +# would be a snap to fix the test suite to say, "Yep, LooseVersion does +# the Right Thing" (ie. the code matches the conception). But I'd rather +# have a conception that matches common notions about version numbers. + +class LooseVersion (Version): + + """Version numbering for anarchists and software realists. + Implements the standard interface for version number classes as + described above. A version number consists of a series of numbers, + separated by either periods or strings of letters. When comparing + version numbers, the numeric components will be compared + numerically, and the alphabetic components lexically. The following + are all valid version numbers, in no particular order: + + 1.5.1 + 1.5.2b2 + 161 + 3.10a + 8.02 + 3.4j + 1996.07.12 + 3.2.pl0 + 3.1.1.6 + 2g6 + 11g + 0.960923 + 2.2beta29 + 1.13++ + 5.5.kw + 2.0b1pl0 + + In fact, there is no such thing as an invalid version number under + this scheme; the rules for comparison are simple and predictable, + but may not always give the results you want (for some definition + of "want"). + """ + + component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) + + def __init__ (self, vstring=None): + if vstring: + self.parse(vstring) + + + def parse (self, vstring): + # I've given up on thinking I can reconstruct the version string + # from the parsed tuple -- so I just store the string here for + # use by __str__ + self.vstring = vstring + components = [x for x in self.component_re.split(vstring) + if x and x != '.'] + for i, obj in enumerate(components): + try: + components[i] = int(obj) + except ValueError: + pass + + self.version = components + + + def __str__ (self): + return self.vstring + + + def __repr__ (self): + return "LooseVersion ('%s')" % str(self) + + + def _cmp (self, other): + if isinstance(other, str): + other = LooseVersion(other) + elif not isinstance(other, LooseVersion): + return NotImplemented + + if self.version == other.version: + return 0 + if self.version < other.version: + return -1 + if self.version > other.version: + return 1 + + +# end class LooseVersion diff --git a/MLPY/Lib/site-packages/setuptools/_distutils/versionpredicate.py b/MLPY/Lib/site-packages/setuptools/_distutils/versionpredicate.py new file mode 100644 index 0000000000000000000000000000000000000000..062c98f2489951a9b215c5f02d7cdb71605ec1b3 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_distutils/versionpredicate.py @@ -0,0 +1,166 @@ +"""Module for parsing and testing package version predicate strings. +""" +import re +import distutils.version +import operator + + +re_validPackage = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)", + re.ASCII) +# (package) (rest) + +re_paren = re.compile(r"^\s*\((.*)\)\s*$") # (list) inside of parentheses +re_splitComparison = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$") +# (comp) (version) + + +def splitUp(pred): + """Parse a single version comparison. + + Return (comparison string, StrictVersion) + """ + res = re_splitComparison.match(pred) + if not res: + raise ValueError("bad package restriction syntax: %r" % pred) + comp, verStr = res.groups() + return (comp, distutils.version.StrictVersion(verStr)) + +compmap = {"<": operator.lt, "<=": operator.le, "==": operator.eq, + ">": operator.gt, ">=": operator.ge, "!=": operator.ne} + +class VersionPredicate: + """Parse and test package version predicates. + + >>> v = VersionPredicate('pyepat.abc (>1.0, <3333.3a1, !=1555.1b3)') + + The `name` attribute provides the full dotted name that is given:: + + >>> v.name + 'pyepat.abc' + + The str() of a `VersionPredicate` provides a normalized + human-readable version of the expression:: + + >>> print(v) + pyepat.abc (> 1.0, < 3333.3a1, != 1555.1b3) + + The `satisfied_by()` method can be used to determine with a given + version number is included in the set described by the version + restrictions:: + + >>> v.satisfied_by('1.1') + True + >>> v.satisfied_by('1.4') + True + >>> v.satisfied_by('1.0') + False + >>> v.satisfied_by('4444.4') + False + >>> v.satisfied_by('1555.1b3') + False + + `VersionPredicate` is flexible in accepting extra whitespace:: + + >>> v = VersionPredicate(' pat( == 0.1 ) ') + >>> v.name + 'pat' + >>> v.satisfied_by('0.1') + True + >>> v.satisfied_by('0.2') + False + + If any version numbers passed in do not conform to the + restrictions of `StrictVersion`, a `ValueError` is raised:: + + >>> v = VersionPredicate('p1.p2.p3.p4(>=1.0, <=1.3a1, !=1.2zb3)') + Traceback (most recent call last): + ... + ValueError: invalid version number '1.2zb3' + + It the module or package name given does not conform to what's + allowed as a legal module or package name, `ValueError` is + raised:: + + >>> v = VersionPredicate('foo-bar') + Traceback (most recent call last): + ... + ValueError: expected parenthesized list: '-bar' + + >>> v = VersionPredicate('foo bar (12.21)') + Traceback (most recent call last): + ... + ValueError: expected parenthesized list: 'bar (12.21)' + + """ + + def __init__(self, versionPredicateStr): + """Parse a version predicate string. + """ + # Fields: + # name: package name + # pred: list of (comparison string, StrictVersion) + + versionPredicateStr = versionPredicateStr.strip() + if not versionPredicateStr: + raise ValueError("empty package restriction") + match = re_validPackage.match(versionPredicateStr) + if not match: + raise ValueError("bad package name in %r" % versionPredicateStr) + self.name, paren = match.groups() + paren = paren.strip() + if paren: + match = re_paren.match(paren) + if not match: + raise ValueError("expected parenthesized list: %r" % paren) + str = match.groups()[0] + self.pred = [splitUp(aPred) for aPred in str.split(",")] + if not self.pred: + raise ValueError("empty parenthesized list in %r" + % versionPredicateStr) + else: + self.pred = [] + + def __str__(self): + if self.pred: + seq = [cond + " " + str(ver) for cond, ver in self.pred] + return self.name + " (" + ", ".join(seq) + ")" + else: + return self.name + + def satisfied_by(self, version): + """True if version is compatible with all the predicates in self. + The parameter version must be acceptable to the StrictVersion + constructor. It may be either a string or StrictVersion. + """ + for cond, ver in self.pred: + if not compmap[cond](version, ver): + return False + return True + + +_provision_rx = None + +def split_provision(value): + """Return the name and optional version number of a provision. + + The version number, if given, will be returned as a `StrictVersion` + instance, otherwise it will be `None`. + + >>> split_provision('mypkg') + ('mypkg', None) + >>> split_provision(' mypkg( 1.2 ) ') + ('mypkg', StrictVersion ('1.2')) + """ + global _provision_rx + if _provision_rx is None: + _provision_rx = re.compile( + r"([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$", + re.ASCII) + value = value.strip() + m = _provision_rx.match(value) + if not m: + raise ValueError("illegal provides specification: %r" % value) + ver = m.group(2) or None + if ver: + ver = distutils.version.StrictVersion(ver) + return m.group(1), ver diff --git a/MLPY/Lib/site-packages/setuptools/_imp.py b/MLPY/Lib/site-packages/setuptools/_imp.py new file mode 100644 index 0000000000000000000000000000000000000000..47efd792b3cd04f0646adf7d3ef1811d201f8873 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_imp.py @@ -0,0 +1,82 @@ +""" +Re-implementation of find_module and get_frozen_object +from the deprecated imp module. +""" + +import os +import importlib.util +import importlib.machinery + +from .py34compat import module_from_spec + + +PY_SOURCE = 1 +PY_COMPILED = 2 +C_EXTENSION = 3 +C_BUILTIN = 6 +PY_FROZEN = 7 + + +def find_spec(module, paths): + finder = ( + importlib.machinery.PathFinder().find_spec + if isinstance(paths, list) else + importlib.util.find_spec + ) + return finder(module, paths) + + +def find_module(module, paths=None): + """Just like 'imp.find_module()', but with package support""" + spec = find_spec(module, paths) + if spec is None: + raise ImportError("Can't find %s" % module) + if not spec.has_location and hasattr(spec, 'submodule_search_locations'): + spec = importlib.util.spec_from_loader('__init__.py', spec.loader) + + kind = -1 + file = None + static = isinstance(spec.loader, type) + if spec.origin == 'frozen' or static and issubclass( + spec.loader, importlib.machinery.FrozenImporter): + kind = PY_FROZEN + path = None # imp compabilty + suffix = mode = '' # imp compatibility + elif spec.origin == 'built-in' or static and issubclass( + spec.loader, importlib.machinery.BuiltinImporter): + kind = C_BUILTIN + path = None # imp compabilty + suffix = mode = '' # imp compatibility + elif spec.has_location: + path = spec.origin + suffix = os.path.splitext(path)[1] + mode = 'r' if suffix in importlib.machinery.SOURCE_SUFFIXES else 'rb' + + if suffix in importlib.machinery.SOURCE_SUFFIXES: + kind = PY_SOURCE + elif suffix in importlib.machinery.BYTECODE_SUFFIXES: + kind = PY_COMPILED + elif suffix in importlib.machinery.EXTENSION_SUFFIXES: + kind = C_EXTENSION + + if kind in {PY_SOURCE, PY_COMPILED}: + file = open(path, mode) + else: + path = None + suffix = mode = '' + + return file, path, (suffix, mode, kind) + + +def get_frozen_object(module, paths=None): + spec = find_spec(module, paths) + if not spec: + raise ImportError("Can't find %s" % module) + return spec.loader.get_code(module) + + +def get_module(module, paths, info): + spec = find_spec(module, paths) + if not spec: + raise ImportError("Can't find %s" % module) + return module_from_spec(spec) diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/__init__.py b/MLPY/Lib/site-packages/setuptools/_vendor/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..077b70edac097f1f01a274cde99e2dfe490a159d Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/ordered_set.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/ordered_set.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88bd8d2c2ce64266482b5bde14be83d50c8fac77 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/ordered_set.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c1775360cf29487f02abbdfd7a55cd670529503 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__init__.py b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..19a169fc30183db91f931ad6ad04fbc0e16559b3 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__init__.py @@ -0,0 +1,4 @@ +from .more import * # noqa +from .recipes import * # noqa + +__version__ = '8.8.0' diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b3385f98f21d5bf757d067afa95f8cc7cb7b6e4 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14256da06791076cdfd87345c65087aecd4afa9f Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78267158e6485345e76bf60abe4149f64c71c60d Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/more.py b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/more.py new file mode 100644 index 0000000000000000000000000000000000000000..0f7d282aa5df08f3e2692bf1e51dfaaea60ae4ea --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/more.py @@ -0,0 +1,3825 @@ +import warnings + +from collections import Counter, defaultdict, deque, abc +from collections.abc import Sequence +from concurrent.futures import ThreadPoolExecutor +from functools import partial, reduce, wraps +from heapq import merge, heapify, heapreplace, heappop +from itertools import ( + chain, + compress, + count, + cycle, + dropwhile, + groupby, + islice, + repeat, + starmap, + takewhile, + tee, + zip_longest, +) +from math import exp, factorial, floor, log +from queue import Empty, Queue +from random import random, randrange, uniform +from operator import itemgetter, mul, sub, gt, lt +from sys import hexversion, maxsize +from time import monotonic + +from .recipes import ( + consume, + flatten, + pairwise, + powerset, + take, + unique_everseen, +) + +__all__ = [ + 'AbortThread', + 'adjacent', + 'always_iterable', + 'always_reversible', + 'bucket', + 'callback_iter', + 'chunked', + 'circular_shifts', + 'collapse', + 'collate', + 'consecutive_groups', + 'consumer', + 'countable', + 'count_cycle', + 'mark_ends', + 'difference', + 'distinct_combinations', + 'distinct_permutations', + 'distribute', + 'divide', + 'exactly_n', + 'filter_except', + 'first', + 'groupby_transform', + 'ilen', + 'interleave_longest', + 'interleave', + 'intersperse', + 'islice_extended', + 'iterate', + 'ichunked', + 'is_sorted', + 'last', + 'locate', + 'lstrip', + 'make_decorator', + 'map_except', + 'map_reduce', + 'nth_or_last', + 'nth_permutation', + 'nth_product', + 'numeric_range', + 'one', + 'only', + 'padded', + 'partitions', + 'set_partitions', + 'peekable', + 'repeat_last', + 'replace', + 'rlocate', + 'rstrip', + 'run_length', + 'sample', + 'seekable', + 'SequenceView', + 'side_effect', + 'sliced', + 'sort_together', + 'split_at', + 'split_after', + 'split_before', + 'split_when', + 'split_into', + 'spy', + 'stagger', + 'strip', + 'substrings', + 'substrings_indexes', + 'time_limited', + 'unique_to_each', + 'unzip', + 'windowed', + 'with_iter', + 'UnequalIterablesError', + 'zip_equal', + 'zip_offset', + 'windowed_complete', + 'all_unique', + 'value_chain', + 'product_index', + 'combination_index', + 'permutation_index', +] + +_marker = object() + + +def chunked(iterable, n, strict=False): + """Break *iterable* into lists of length *n*: + + >>> list(chunked([1, 2, 3, 4, 5, 6], 3)) + [[1, 2, 3], [4, 5, 6]] + + By the default, the last yielded list will have fewer than *n* elements + if the length of *iterable* is not divisible by *n*: + + >>> list(chunked([1, 2, 3, 4, 5, 6, 7, 8], 3)) + [[1, 2, 3], [4, 5, 6], [7, 8]] + + To use a fill-in value instead, see the :func:`grouper` recipe. + + If the length of *iterable* is not divisible by *n* and *strict* is + ``True``, then ``ValueError`` will be raised before the last + list is yielded. + + """ + iterator = iter(partial(take, n, iter(iterable)), []) + if strict: + + def ret(): + for chunk in iterator: + if len(chunk) != n: + raise ValueError('iterable is not divisible by n.') + yield chunk + + return iter(ret()) + else: + return iterator + + +def first(iterable, default=_marker): + """Return the first item of *iterable*, or *default* if *iterable* is + empty. + + >>> first([0, 1, 2, 3]) + 0 + >>> first([], 'some default') + 'some default' + + If *default* is not provided and there are no items in the iterable, + raise ``ValueError``. + + :func:`first` is useful when you have a generator of expensive-to-retrieve + values and want any arbitrary one. It is marginally shorter than + ``next(iter(iterable), default)``. + + """ + try: + return next(iter(iterable)) + except StopIteration as e: + if default is _marker: + raise ValueError( + 'first() was called on an empty iterable, and no ' + 'default value was provided.' + ) from e + return default + + +def last(iterable, default=_marker): + """Return the last item of *iterable*, or *default* if *iterable* is + empty. + + >>> last([0, 1, 2, 3]) + 3 + >>> last([], 'some default') + 'some default' + + If *default* is not provided and there are no items in the iterable, + raise ``ValueError``. + """ + try: + if isinstance(iterable, Sequence): + return iterable[-1] + # Work around https://bugs.python.org/issue38525 + elif hasattr(iterable, '__reversed__') and (hexversion != 0x030800F0): + return next(reversed(iterable)) + else: + return deque(iterable, maxlen=1)[-1] + except (IndexError, TypeError, StopIteration): + if default is _marker: + raise ValueError( + 'last() was called on an empty iterable, and no default was ' + 'provided.' + ) + return default + + +def nth_or_last(iterable, n, default=_marker): + """Return the nth or the last item of *iterable*, + or *default* if *iterable* is empty. + + >>> nth_or_last([0, 1, 2, 3], 2) + 2 + >>> nth_or_last([0, 1], 2) + 1 + >>> nth_or_last([], 0, 'some default') + 'some default' + + If *default* is not provided and there are no items in the iterable, + raise ``ValueError``. + """ + return last(islice(iterable, n + 1), default=default) + + +class peekable: + """Wrap an iterator to allow lookahead and prepending elements. + + Call :meth:`peek` on the result to get the value that will be returned + by :func:`next`. This won't advance the iterator: + + >>> p = peekable(['a', 'b']) + >>> p.peek() + 'a' + >>> next(p) + 'a' + + Pass :meth:`peek` a default value to return that instead of raising + ``StopIteration`` when the iterator is exhausted. + + >>> p = peekable([]) + >>> p.peek('hi') + 'hi' + + peekables also offer a :meth:`prepend` method, which "inserts" items + at the head of the iterable: + + >>> p = peekable([1, 2, 3]) + >>> p.prepend(10, 11, 12) + >>> next(p) + 10 + >>> p.peek() + 11 + >>> list(p) + [11, 12, 1, 2, 3] + + peekables can be indexed. Index 0 is the item that will be returned by + :func:`next`, index 1 is the item after that, and so on: + The values up to the given index will be cached. + + >>> p = peekable(['a', 'b', 'c', 'd']) + >>> p[0] + 'a' + >>> p[1] + 'b' + >>> next(p) + 'a' + + Negative indexes are supported, but be aware that they will cache the + remaining items in the source iterator, which may require significant + storage. + + To check whether a peekable is exhausted, check its truth value: + + >>> p = peekable(['a', 'b']) + >>> if p: # peekable has items + ... list(p) + ['a', 'b'] + >>> if not p: # peekable is exhausted + ... list(p) + [] + + """ + + def __init__(self, iterable): + self._it = iter(iterable) + self._cache = deque() + + def __iter__(self): + return self + + def __bool__(self): + try: + self.peek() + except StopIteration: + return False + return True + + def peek(self, default=_marker): + """Return the item that will be next returned from ``next()``. + + Return ``default`` if there are no items left. If ``default`` is not + provided, raise ``StopIteration``. + + """ + if not self._cache: + try: + self._cache.append(next(self._it)) + except StopIteration: + if default is _marker: + raise + return default + return self._cache[0] + + def prepend(self, *items): + """Stack up items to be the next ones returned from ``next()`` or + ``self.peek()``. The items will be returned in + first in, first out order:: + + >>> p = peekable([1, 2, 3]) + >>> p.prepend(10, 11, 12) + >>> next(p) + 10 + >>> list(p) + [11, 12, 1, 2, 3] + + It is possible, by prepending items, to "resurrect" a peekable that + previously raised ``StopIteration``. + + >>> p = peekable([]) + >>> next(p) + Traceback (most recent call last): + ... + StopIteration + >>> p.prepend(1) + >>> next(p) + 1 + >>> next(p) + Traceback (most recent call last): + ... + StopIteration + + """ + self._cache.extendleft(reversed(items)) + + def __next__(self): + if self._cache: + return self._cache.popleft() + + return next(self._it) + + def _get_slice(self, index): + # Normalize the slice's arguments + step = 1 if (index.step is None) else index.step + if step > 0: + start = 0 if (index.start is None) else index.start + stop = maxsize if (index.stop is None) else index.stop + elif step < 0: + start = -1 if (index.start is None) else index.start + stop = (-maxsize - 1) if (index.stop is None) else index.stop + else: + raise ValueError('slice step cannot be zero') + + # If either the start or stop index is negative, we'll need to cache + # the rest of the iterable in order to slice from the right side. + if (start < 0) or (stop < 0): + self._cache.extend(self._it) + # Otherwise we'll need to find the rightmost index and cache to that + # point. + else: + n = min(max(start, stop) + 1, maxsize) + cache_len = len(self._cache) + if n >= cache_len: + self._cache.extend(islice(self._it, n - cache_len)) + + return list(self._cache)[index] + + def __getitem__(self, index): + if isinstance(index, slice): + return self._get_slice(index) + + cache_len = len(self._cache) + if index < 0: + self._cache.extend(self._it) + elif index >= cache_len: + self._cache.extend(islice(self._it, index + 1 - cache_len)) + + return self._cache[index] + + +def collate(*iterables, **kwargs): + """Return a sorted merge of the items from each of several already-sorted + *iterables*. + + >>> list(collate('ACDZ', 'AZ', 'JKL')) + ['A', 'A', 'C', 'D', 'J', 'K', 'L', 'Z', 'Z'] + + Works lazily, keeping only the next value from each iterable in memory. Use + :func:`collate` to, for example, perform a n-way mergesort of items that + don't fit in memory. + + If a *key* function is specified, the iterables will be sorted according + to its result: + + >>> key = lambda s: int(s) # Sort by numeric value, not by string + >>> list(collate(['1', '10'], ['2', '11'], key=key)) + ['1', '2', '10', '11'] + + + If the *iterables* are sorted in descending order, set *reverse* to + ``True``: + + >>> list(collate([5, 3, 1], [4, 2, 0], reverse=True)) + [5, 4, 3, 2, 1, 0] + + If the elements of the passed-in iterables are out of order, you might get + unexpected results. + + On Python 3.5+, this function is an alias for :func:`heapq.merge`. + + """ + warnings.warn( + "collate is no longer part of more_itertools, use heapq.merge", + DeprecationWarning, + ) + return merge(*iterables, **kwargs) + + +def consumer(func): + """Decorator that automatically advances a PEP-342-style "reverse iterator" + to its first yield point so you don't have to call ``next()`` on it + manually. + + >>> @consumer + ... def tally(): + ... i = 0 + ... while True: + ... print('Thing number %s is %s.' % (i, (yield))) + ... i += 1 + ... + >>> t = tally() + >>> t.send('red') + Thing number 0 is red. + >>> t.send('fish') + Thing number 1 is fish. + + Without the decorator, you would have to call ``next(t)`` before + ``t.send()`` could be used. + + """ + + @wraps(func) + def wrapper(*args, **kwargs): + gen = func(*args, **kwargs) + next(gen) + return gen + + return wrapper + + +def ilen(iterable): + """Return the number of items in *iterable*. + + >>> ilen(x for x in range(1000000) if x % 3 == 0) + 333334 + + This consumes the iterable, so handle with care. + + """ + # This approach was selected because benchmarks showed it's likely the + # fastest of the known implementations at the time of writing. + # See GitHub tracker: #236, #230. + counter = count() + deque(zip(iterable, counter), maxlen=0) + return next(counter) + + +def iterate(func, start): + """Return ``start``, ``func(start)``, ``func(func(start))``, ... + + >>> from itertools import islice + >>> list(islice(iterate(lambda x: 2*x, 1), 10)) + [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] + + """ + while True: + yield start + start = func(start) + + +def with_iter(context_manager): + """Wrap an iterable in a ``with`` statement, so it closes once exhausted. + + For example, this will close the file when the iterator is exhausted:: + + upper_lines = (line.upper() for line in with_iter(open('foo'))) + + Any context manager which returns an iterable is a candidate for + ``with_iter``. + + """ + with context_manager as iterable: + yield from iterable + + +def one(iterable, too_short=None, too_long=None): + """Return the first item from *iterable*, which is expected to contain only + that item. Raise an exception if *iterable* is empty or has more than one + item. + + :func:`one` is useful for ensuring that an iterable contains only one item. + For example, it can be used to retrieve the result of a database query + that is expected to return a single row. + + If *iterable* is empty, ``ValueError`` will be raised. You may specify a + different exception with the *too_short* keyword: + + >>> it = [] + >>> one(it) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + ValueError: too many items in iterable (expected 1)' + >>> too_short = IndexError('too few items') + >>> one(it, too_short=too_short) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + IndexError: too few items + + Similarly, if *iterable* contains more than one item, ``ValueError`` will + be raised. You may specify a different exception with the *too_long* + keyword: + + >>> it = ['too', 'many'] + >>> one(it) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + ValueError: Expected exactly one item in iterable, but got 'too', + 'many', and perhaps more. + >>> too_long = RuntimeError + >>> one(it, too_long=too_long) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + RuntimeError + + Note that :func:`one` attempts to advance *iterable* twice to ensure there + is only one item. See :func:`spy` or :func:`peekable` to check iterable + contents less destructively. + + """ + it = iter(iterable) + + try: + first_value = next(it) + except StopIteration as e: + raise ( + too_short or ValueError('too few items in iterable (expected 1)') + ) from e + + try: + second_value = next(it) + except StopIteration: + pass + else: + msg = ( + 'Expected exactly one item in iterable, but got {!r}, {!r}, ' + 'and perhaps more.'.format(first_value, second_value) + ) + raise too_long or ValueError(msg) + + return first_value + + +def distinct_permutations(iterable, r=None): + """Yield successive distinct permutations of the elements in *iterable*. + + >>> sorted(distinct_permutations([1, 0, 1])) + [(0, 1, 1), (1, 0, 1), (1, 1, 0)] + + Equivalent to ``set(permutations(iterable))``, except duplicates are not + generated and thrown away. For larger input sequences this is much more + efficient. + + Duplicate permutations arise when there are duplicated elements in the + input iterable. The number of items returned is + `n! / (x_1! * x_2! * ... * x_n!)`, where `n` is the total number of + items input, and each `x_i` is the count of a distinct item in the input + sequence. + + If *r* is given, only the *r*-length permutations are yielded. + + >>> sorted(distinct_permutations([1, 0, 1], r=2)) + [(0, 1), (1, 0), (1, 1)] + >>> sorted(distinct_permutations(range(3), r=2)) + [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] + + """ + # Algorithm: https://w.wiki/Qai + def _full(A): + while True: + # Yield the permutation we have + yield tuple(A) + + # Find the largest index i such that A[i] < A[i + 1] + for i in range(size - 2, -1, -1): + if A[i] < A[i + 1]: + break + # If no such index exists, this permutation is the last one + else: + return + + # Find the largest index j greater than j such that A[i] < A[j] + for j in range(size - 1, i, -1): + if A[i] < A[j]: + break + + # Swap the value of A[i] with that of A[j], then reverse the + # sequence from A[i + 1] to form the new permutation + A[i], A[j] = A[j], A[i] + A[i + 1 :] = A[: i - size : -1] # A[i + 1:][::-1] + + # Algorithm: modified from the above + def _partial(A, r): + # Split A into the first r items and the last r items + head, tail = A[:r], A[r:] + right_head_indexes = range(r - 1, -1, -1) + left_tail_indexes = range(len(tail)) + + while True: + # Yield the permutation we have + yield tuple(head) + + # Starting from the right, find the first index of the head with + # value smaller than the maximum value of the tail - call it i. + pivot = tail[-1] + for i in right_head_indexes: + if head[i] < pivot: + break + pivot = head[i] + else: + return + + # Starting from the left, find the first value of the tail + # with a value greater than head[i] and swap. + for j in left_tail_indexes: + if tail[j] > head[i]: + head[i], tail[j] = tail[j], head[i] + break + # If we didn't find one, start from the right and find the first + # index of the head with a value greater than head[i] and swap. + else: + for j in right_head_indexes: + if head[j] > head[i]: + head[i], head[j] = head[j], head[i] + break + + # Reverse head[i + 1:] and swap it with tail[:r - (i + 1)] + tail += head[: i - r : -1] # head[i + 1:][::-1] + i += 1 + head[i:], tail[:] = tail[: r - i], tail[r - i :] + + items = sorted(iterable) + + size = len(items) + if r is None: + r = size + + if 0 < r <= size: + return _full(items) if (r == size) else _partial(items, r) + + return iter(() if r else ((),)) + + +def intersperse(e, iterable, n=1): + """Intersperse filler element *e* among the items in *iterable*, leaving + *n* items between each filler element. + + >>> list(intersperse('!', [1, 2, 3, 4, 5])) + [1, '!', 2, '!', 3, '!', 4, '!', 5] + + >>> list(intersperse(None, [1, 2, 3, 4, 5], n=2)) + [1, 2, None, 3, 4, None, 5] + + """ + if n == 0: + raise ValueError('n must be > 0') + elif n == 1: + # interleave(repeat(e), iterable) -> e, x_0, e, e, x_1, e, x_2... + # islice(..., 1, None) -> x_0, e, e, x_1, e, x_2... + return islice(interleave(repeat(e), iterable), 1, None) + else: + # interleave(filler, chunks) -> [e], [x_0, x_1], [e], [x_2, x_3]... + # islice(..., 1, None) -> [x_0, x_1], [e], [x_2, x_3]... + # flatten(...) -> x_0, x_1, e, x_2, x_3... + filler = repeat([e]) + chunks = chunked(iterable, n) + return flatten(islice(interleave(filler, chunks), 1, None)) + + +def unique_to_each(*iterables): + """Return the elements from each of the input iterables that aren't in the + other input iterables. + + For example, suppose you have a set of packages, each with a set of + dependencies:: + + {'pkg_1': {'A', 'B'}, 'pkg_2': {'B', 'C'}, 'pkg_3': {'B', 'D'}} + + If you remove one package, which dependencies can also be removed? + + If ``pkg_1`` is removed, then ``A`` is no longer necessary - it is not + associated with ``pkg_2`` or ``pkg_3``. Similarly, ``C`` is only needed for + ``pkg_2``, and ``D`` is only needed for ``pkg_3``:: + + >>> unique_to_each({'A', 'B'}, {'B', 'C'}, {'B', 'D'}) + [['A'], ['C'], ['D']] + + If there are duplicates in one input iterable that aren't in the others + they will be duplicated in the output. Input order is preserved:: + + >>> unique_to_each("mississippi", "missouri") + [['p', 'p'], ['o', 'u', 'r']] + + It is assumed that the elements of each iterable are hashable. + + """ + pool = [list(it) for it in iterables] + counts = Counter(chain.from_iterable(map(set, pool))) + uniques = {element for element in counts if counts[element] == 1} + return [list(filter(uniques.__contains__, it)) for it in pool] + + +def windowed(seq, n, fillvalue=None, step=1): + """Return a sliding window of width *n* over the given iterable. + + >>> all_windows = windowed([1, 2, 3, 4, 5], 3) + >>> list(all_windows) + [(1, 2, 3), (2, 3, 4), (3, 4, 5)] + + When the window is larger than the iterable, *fillvalue* is used in place + of missing values: + + >>> list(windowed([1, 2, 3], 4)) + [(1, 2, 3, None)] + + Each window will advance in increments of *step*: + + >>> list(windowed([1, 2, 3, 4, 5, 6], 3, fillvalue='!', step=2)) + [(1, 2, 3), (3, 4, 5), (5, 6, '!')] + + To slide into the iterable's items, use :func:`chain` to add filler items + to the left: + + >>> iterable = [1, 2, 3, 4] + >>> n = 3 + >>> padding = [None] * (n - 1) + >>> list(windowed(chain(padding, iterable), 3)) + [(None, None, 1), (None, 1, 2), (1, 2, 3), (2, 3, 4)] + """ + if n < 0: + raise ValueError('n must be >= 0') + if n == 0: + yield tuple() + return + if step < 1: + raise ValueError('step must be >= 1') + + window = deque(maxlen=n) + i = n + for _ in map(window.append, seq): + i -= 1 + if not i: + i = step + yield tuple(window) + + size = len(window) + if size < n: + yield tuple(chain(window, repeat(fillvalue, n - size))) + elif 0 < i < min(step, n): + window += (fillvalue,) * i + yield tuple(window) + + +def substrings(iterable): + """Yield all of the substrings of *iterable*. + + >>> [''.join(s) for s in substrings('more')] + ['m', 'o', 'r', 'e', 'mo', 'or', 're', 'mor', 'ore', 'more'] + + Note that non-string iterables can also be subdivided. + + >>> list(substrings([0, 1, 2])) + [(0,), (1,), (2,), (0, 1), (1, 2), (0, 1, 2)] + + """ + # The length-1 substrings + seq = [] + for item in iter(iterable): + seq.append(item) + yield (item,) + seq = tuple(seq) + item_count = len(seq) + + # And the rest + for n in range(2, item_count + 1): + for i in range(item_count - n + 1): + yield seq[i : i + n] + + +def substrings_indexes(seq, reverse=False): + """Yield all substrings and their positions in *seq* + + The items yielded will be a tuple of the form ``(substr, i, j)``, where + ``substr == seq[i:j]``. + + This function only works for iterables that support slicing, such as + ``str`` objects. + + >>> for item in substrings_indexes('more'): + ... print(item) + ('m', 0, 1) + ('o', 1, 2) + ('r', 2, 3) + ('e', 3, 4) + ('mo', 0, 2) + ('or', 1, 3) + ('re', 2, 4) + ('mor', 0, 3) + ('ore', 1, 4) + ('more', 0, 4) + + Set *reverse* to ``True`` to yield the same items in the opposite order. + + + """ + r = range(1, len(seq) + 1) + if reverse: + r = reversed(r) + return ( + (seq[i : i + L], i, i + L) for L in r for i in range(len(seq) - L + 1) + ) + + +class bucket: + """Wrap *iterable* and return an object that buckets it iterable into + child iterables based on a *key* function. + + >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3'] + >>> s = bucket(iterable, key=lambda x: x[0]) # Bucket by 1st character + >>> sorted(list(s)) # Get the keys + ['a', 'b', 'c'] + >>> a_iterable = s['a'] + >>> next(a_iterable) + 'a1' + >>> next(a_iterable) + 'a2' + >>> list(s['b']) + ['b1', 'b2', 'b3'] + + The original iterable will be advanced and its items will be cached until + they are used by the child iterables. This may require significant storage. + + By default, attempting to select a bucket to which no items belong will + exhaust the iterable and cache all values. + If you specify a *validator* function, selected buckets will instead be + checked against it. + + >>> from itertools import count + >>> it = count(1, 2) # Infinite sequence of odd numbers + >>> key = lambda x: x % 10 # Bucket by last digit + >>> validator = lambda x: x in {1, 3, 5, 7, 9} # Odd digits only + >>> s = bucket(it, key=key, validator=validator) + >>> 2 in s + False + >>> list(s[2]) + [] + + """ + + def __init__(self, iterable, key, validator=None): + self._it = iter(iterable) + self._key = key + self._cache = defaultdict(deque) + self._validator = validator or (lambda x: True) + + def __contains__(self, value): + if not self._validator(value): + return False + + try: + item = next(self[value]) + except StopIteration: + return False + else: + self._cache[value].appendleft(item) + + return True + + def _get_values(self, value): + """ + Helper to yield items from the parent iterator that match *value*. + Items that don't match are stored in the local cache as they + are encountered. + """ + while True: + # If we've cached some items that match the target value, emit + # the first one and evict it from the cache. + if self._cache[value]: + yield self._cache[value].popleft() + # Otherwise we need to advance the parent iterator to search for + # a matching item, caching the rest. + else: + while True: + try: + item = next(self._it) + except StopIteration: + return + item_value = self._key(item) + if item_value == value: + yield item + break + elif self._validator(item_value): + self._cache[item_value].append(item) + + def __iter__(self): + for item in self._it: + item_value = self._key(item) + if self._validator(item_value): + self._cache[item_value].append(item) + + yield from self._cache.keys() + + def __getitem__(self, value): + if not self._validator(value): + return iter(()) + + return self._get_values(value) + + +def spy(iterable, n=1): + """Return a 2-tuple with a list containing the first *n* elements of + *iterable*, and an iterator with the same items as *iterable*. + This allows you to "look ahead" at the items in the iterable without + advancing it. + + There is one item in the list by default: + + >>> iterable = 'abcdefg' + >>> head, iterable = spy(iterable) + >>> head + ['a'] + >>> list(iterable) + ['a', 'b', 'c', 'd', 'e', 'f', 'g'] + + You may use unpacking to retrieve items instead of lists: + + >>> (head,), iterable = spy('abcdefg') + >>> head + 'a' + >>> (first, second), iterable = spy('abcdefg', 2) + >>> first + 'a' + >>> second + 'b' + + The number of items requested can be larger than the number of items in + the iterable: + + >>> iterable = [1, 2, 3, 4, 5] + >>> head, iterable = spy(iterable, 10) + >>> head + [1, 2, 3, 4, 5] + >>> list(iterable) + [1, 2, 3, 4, 5] + + """ + it = iter(iterable) + head = take(n, it) + + return head.copy(), chain(head, it) + + +def interleave(*iterables): + """Return a new iterable yielding from each iterable in turn, + until the shortest is exhausted. + + >>> list(interleave([1, 2, 3], [4, 5], [6, 7, 8])) + [1, 4, 6, 2, 5, 7] + + For a version that doesn't terminate after the shortest iterable is + exhausted, see :func:`interleave_longest`. + + """ + return chain.from_iterable(zip(*iterables)) + + +def interleave_longest(*iterables): + """Return a new iterable yielding from each iterable in turn, + skipping any that are exhausted. + + >>> list(interleave_longest([1, 2, 3], [4, 5], [6, 7, 8])) + [1, 4, 6, 2, 5, 7, 3, 8] + + This function produces the same output as :func:`roundrobin`, but may + perform better for some inputs (in particular when the number of iterables + is large). + + """ + i = chain.from_iterable(zip_longest(*iterables, fillvalue=_marker)) + return (x for x in i if x is not _marker) + + +def collapse(iterable, base_type=None, levels=None): + """Flatten an iterable with multiple levels of nesting (e.g., a list of + lists of tuples) into non-iterable types. + + >>> iterable = [(1, 2), ([3, 4], [[5], [6]])] + >>> list(collapse(iterable)) + [1, 2, 3, 4, 5, 6] + + Binary and text strings are not considered iterable and + will not be collapsed. + + To avoid collapsing other types, specify *base_type*: + + >>> iterable = ['ab', ('cd', 'ef'), ['gh', 'ij']] + >>> list(collapse(iterable, base_type=tuple)) + ['ab', ('cd', 'ef'), 'gh', 'ij'] + + Specify *levels* to stop flattening after a certain level: + + >>> iterable = [('a', ['b']), ('c', ['d'])] + >>> list(collapse(iterable)) # Fully flattened + ['a', 'b', 'c', 'd'] + >>> list(collapse(iterable, levels=1)) # Only one level flattened + ['a', ['b'], 'c', ['d']] + + """ + + def walk(node, level): + if ( + ((levels is not None) and (level > levels)) + or isinstance(node, (str, bytes)) + or ((base_type is not None) and isinstance(node, base_type)) + ): + yield node + return + + try: + tree = iter(node) + except TypeError: + yield node + return + else: + for child in tree: + yield from walk(child, level + 1) + + yield from walk(iterable, 0) + + +def side_effect(func, iterable, chunk_size=None, before=None, after=None): + """Invoke *func* on each item in *iterable* (or on each *chunk_size* group + of items) before yielding the item. + + `func` must be a function that takes a single argument. Its return value + will be discarded. + + *before* and *after* are optional functions that take no arguments. They + will be executed before iteration starts and after it ends, respectively. + + `side_effect` can be used for logging, updating progress bars, or anything + that is not functionally "pure." + + Emitting a status message: + + >>> from more_itertools import consume + >>> func = lambda item: print('Received {}'.format(item)) + >>> consume(side_effect(func, range(2))) + Received 0 + Received 1 + + Operating on chunks of items: + + >>> pair_sums = [] + >>> func = lambda chunk: pair_sums.append(sum(chunk)) + >>> list(side_effect(func, [0, 1, 2, 3, 4, 5], 2)) + [0, 1, 2, 3, 4, 5] + >>> list(pair_sums) + [1, 5, 9] + + Writing to a file-like object: + + >>> from io import StringIO + >>> from more_itertools import consume + >>> f = StringIO() + >>> func = lambda x: print(x, file=f) + >>> before = lambda: print(u'HEADER', file=f) + >>> after = f.close + >>> it = [u'a', u'b', u'c'] + >>> consume(side_effect(func, it, before=before, after=after)) + >>> f.closed + True + + """ + try: + if before is not None: + before() + + if chunk_size is None: + for item in iterable: + func(item) + yield item + else: + for chunk in chunked(iterable, chunk_size): + func(chunk) + yield from chunk + finally: + if after is not None: + after() + + +def sliced(seq, n, strict=False): + """Yield slices of length *n* from the sequence *seq*. + + >>> list(sliced((1, 2, 3, 4, 5, 6), 3)) + [(1, 2, 3), (4, 5, 6)] + + By the default, the last yielded slice will have fewer than *n* elements + if the length of *seq* is not divisible by *n*: + + >>> list(sliced((1, 2, 3, 4, 5, 6, 7, 8), 3)) + [(1, 2, 3), (4, 5, 6), (7, 8)] + + If the length of *seq* is not divisible by *n* and *strict* is + ``True``, then ``ValueError`` will be raised before the last + slice is yielded. + + This function will only work for iterables that support slicing. + For non-sliceable iterables, see :func:`chunked`. + + """ + iterator = takewhile(len, (seq[i : i + n] for i in count(0, n))) + if strict: + + def ret(): + for _slice in iterator: + if len(_slice) != n: + raise ValueError("seq is not divisible by n.") + yield _slice + + return iter(ret()) + else: + return iterator + + +def split_at(iterable, pred, maxsplit=-1, keep_separator=False): + """Yield lists of items from *iterable*, where each list is delimited by + an item where callable *pred* returns ``True``. + + >>> list(split_at('abcdcba', lambda x: x == 'b')) + [['a'], ['c', 'd', 'c'], ['a']] + + >>> list(split_at(range(10), lambda n: n % 2 == 1)) + [[0], [2], [4], [6], [8], []] + + At most *maxsplit* splits are done. If *maxsplit* is not specified or -1, + then there is no limit on the number of splits: + + >>> list(split_at(range(10), lambda n: n % 2 == 1, maxsplit=2)) + [[0], [2], [4, 5, 6, 7, 8, 9]] + + By default, the delimiting items are not included in the output. + The include them, set *keep_separator* to ``True``. + + >>> list(split_at('abcdcba', lambda x: x == 'b', keep_separator=True)) + [['a'], ['b'], ['c', 'd', 'c'], ['b'], ['a']] + + """ + if maxsplit == 0: + yield list(iterable) + return + + buf = [] + it = iter(iterable) + for item in it: + if pred(item): + yield buf + if keep_separator: + yield [item] + if maxsplit == 1: + yield list(it) + return + buf = [] + maxsplit -= 1 + else: + buf.append(item) + yield buf + + +def split_before(iterable, pred, maxsplit=-1): + """Yield lists of items from *iterable*, where each list ends just before + an item for which callable *pred* returns ``True``: + + >>> list(split_before('OneTwo', lambda s: s.isupper())) + [['O', 'n', 'e'], ['T', 'w', 'o']] + + >>> list(split_before(range(10), lambda n: n % 3 == 0)) + [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] + + At most *maxsplit* splits are done. If *maxsplit* is not specified or -1, + then there is no limit on the number of splits: + + >>> list(split_before(range(10), lambda n: n % 3 == 0, maxsplit=2)) + [[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]] + """ + if maxsplit == 0: + yield list(iterable) + return + + buf = [] + it = iter(iterable) + for item in it: + if pred(item) and buf: + yield buf + if maxsplit == 1: + yield [item] + list(it) + return + buf = [] + maxsplit -= 1 + buf.append(item) + if buf: + yield buf + + +def split_after(iterable, pred, maxsplit=-1): + """Yield lists of items from *iterable*, where each list ends with an + item where callable *pred* returns ``True``: + + >>> list(split_after('one1two2', lambda s: s.isdigit())) + [['o', 'n', 'e', '1'], ['t', 'w', 'o', '2']] + + >>> list(split_after(range(10), lambda n: n % 3 == 0)) + [[0], [1, 2, 3], [4, 5, 6], [7, 8, 9]] + + At most *maxsplit* splits are done. If *maxsplit* is not specified or -1, + then there is no limit on the number of splits: + + >>> list(split_after(range(10), lambda n: n % 3 == 0, maxsplit=2)) + [[0], [1, 2, 3], [4, 5, 6, 7, 8, 9]] + + """ + if maxsplit == 0: + yield list(iterable) + return + + buf = [] + it = iter(iterable) + for item in it: + buf.append(item) + if pred(item) and buf: + yield buf + if maxsplit == 1: + yield list(it) + return + buf = [] + maxsplit -= 1 + if buf: + yield buf + + +def split_when(iterable, pred, maxsplit=-1): + """Split *iterable* into pieces based on the output of *pred*. + *pred* should be a function that takes successive pairs of items and + returns ``True`` if the iterable should be split in between them. + + For example, to find runs of increasing numbers, split the iterable when + element ``i`` is larger than element ``i + 1``: + + >>> list(split_when([1, 2, 3, 3, 2, 5, 2, 4, 2], lambda x, y: x > y)) + [[1, 2, 3, 3], [2, 5], [2, 4], [2]] + + At most *maxsplit* splits are done. If *maxsplit* is not specified or -1, + then there is no limit on the number of splits: + + >>> list(split_when([1, 2, 3, 3, 2, 5, 2, 4, 2], + ... lambda x, y: x > y, maxsplit=2)) + [[1, 2, 3, 3], [2, 5], [2, 4, 2]] + + """ + if maxsplit == 0: + yield list(iterable) + return + + it = iter(iterable) + try: + cur_item = next(it) + except StopIteration: + return + + buf = [cur_item] + for next_item in it: + if pred(cur_item, next_item): + yield buf + if maxsplit == 1: + yield [next_item] + list(it) + return + buf = [] + maxsplit -= 1 + + buf.append(next_item) + cur_item = next_item + + yield buf + + +def split_into(iterable, sizes): + """Yield a list of sequential items from *iterable* of length 'n' for each + integer 'n' in *sizes*. + + >>> list(split_into([1,2,3,4,5,6], [1,2,3])) + [[1], [2, 3], [4, 5, 6]] + + If the sum of *sizes* is smaller than the length of *iterable*, then the + remaining items of *iterable* will not be returned. + + >>> list(split_into([1,2,3,4,5,6], [2,3])) + [[1, 2], [3, 4, 5]] + + If the sum of *sizes* is larger than the length of *iterable*, fewer items + will be returned in the iteration that overruns *iterable* and further + lists will be empty: + + >>> list(split_into([1,2,3,4], [1,2,3,4])) + [[1], [2, 3], [4], []] + + When a ``None`` object is encountered in *sizes*, the returned list will + contain items up to the end of *iterable* the same way that itertools.slice + does: + + >>> list(split_into([1,2,3,4,5,6,7,8,9,0], [2,3,None])) + [[1, 2], [3, 4, 5], [6, 7, 8, 9, 0]] + + :func:`split_into` can be useful for grouping a series of items where the + sizes of the groups are not uniform. An example would be where in a row + from a table, multiple columns represent elements of the same feature + (e.g. a point represented by x,y,z) but, the format is not the same for + all columns. + """ + # convert the iterable argument into an iterator so its contents can + # be consumed by islice in case it is a generator + it = iter(iterable) + + for size in sizes: + if size is None: + yield list(it) + return + else: + yield list(islice(it, size)) + + +def padded(iterable, fillvalue=None, n=None, next_multiple=False): + """Yield the elements from *iterable*, followed by *fillvalue*, such that + at least *n* items are emitted. + + >>> list(padded([1, 2, 3], '?', 5)) + [1, 2, 3, '?', '?'] + + If *next_multiple* is ``True``, *fillvalue* will be emitted until the + number of items emitted is a multiple of *n*:: + + >>> list(padded([1, 2, 3, 4], n=3, next_multiple=True)) + [1, 2, 3, 4, None, None] + + If *n* is ``None``, *fillvalue* will be emitted indefinitely. + + """ + it = iter(iterable) + if n is None: + yield from chain(it, repeat(fillvalue)) + elif n < 1: + raise ValueError('n must be at least 1') + else: + item_count = 0 + for item in it: + yield item + item_count += 1 + + remaining = (n - item_count) % n if next_multiple else n - item_count + for _ in range(remaining): + yield fillvalue + + +def repeat_last(iterable, default=None): + """After the *iterable* is exhausted, keep yielding its last element. + + >>> list(islice(repeat_last(range(3)), 5)) + [0, 1, 2, 2, 2] + + If the iterable is empty, yield *default* forever:: + + >>> list(islice(repeat_last(range(0), 42), 5)) + [42, 42, 42, 42, 42] + + """ + item = _marker + for item in iterable: + yield item + final = default if item is _marker else item + yield from repeat(final) + + +def distribute(n, iterable): + """Distribute the items from *iterable* among *n* smaller iterables. + + >>> group_1, group_2 = distribute(2, [1, 2, 3, 4, 5, 6]) + >>> list(group_1) + [1, 3, 5] + >>> list(group_2) + [2, 4, 6] + + If the length of *iterable* is not evenly divisible by *n*, then the + length of the returned iterables will not be identical: + + >>> children = distribute(3, [1, 2, 3, 4, 5, 6, 7]) + >>> [list(c) for c in children] + [[1, 4, 7], [2, 5], [3, 6]] + + If the length of *iterable* is smaller than *n*, then the last returned + iterables will be empty: + + >>> children = distribute(5, [1, 2, 3]) + >>> [list(c) for c in children] + [[1], [2], [3], [], []] + + This function uses :func:`itertools.tee` and may require significant + storage. If you need the order items in the smaller iterables to match the + original iterable, see :func:`divide`. + + """ + if n < 1: + raise ValueError('n must be at least 1') + + children = tee(iterable, n) + return [islice(it, index, None, n) for index, it in enumerate(children)] + + +def stagger(iterable, offsets=(-1, 0, 1), longest=False, fillvalue=None): + """Yield tuples whose elements are offset from *iterable*. + The amount by which the `i`-th item in each tuple is offset is given by + the `i`-th item in *offsets*. + + >>> list(stagger([0, 1, 2, 3])) + [(None, 0, 1), (0, 1, 2), (1, 2, 3)] + >>> list(stagger(range(8), offsets=(0, 2, 4))) + [(0, 2, 4), (1, 3, 5), (2, 4, 6), (3, 5, 7)] + + By default, the sequence will end when the final element of a tuple is the + last item in the iterable. To continue until the first element of a tuple + is the last item in the iterable, set *longest* to ``True``:: + + >>> list(stagger([0, 1, 2, 3], longest=True)) + [(None, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, None), (3, None, None)] + + By default, ``None`` will be used to replace offsets beyond the end of the + sequence. Specify *fillvalue* to use some other value. + + """ + children = tee(iterable, len(offsets)) + + return zip_offset( + *children, offsets=offsets, longest=longest, fillvalue=fillvalue + ) + + +class UnequalIterablesError(ValueError): + def __init__(self, details=None): + msg = 'Iterables have different lengths' + if details is not None: + msg += (': index 0 has length {}; index {} has length {}').format( + *details + ) + + super().__init__(msg) + + +def _zip_equal_generator(iterables): + for combo in zip_longest(*iterables, fillvalue=_marker): + for val in combo: + if val is _marker: + raise UnequalIterablesError() + yield combo + + +def zip_equal(*iterables): + """``zip`` the input *iterables* together, but raise + ``UnequalIterablesError`` if they aren't all the same length. + + >>> it_1 = range(3) + >>> it_2 = iter('abc') + >>> list(zip_equal(it_1, it_2)) + [(0, 'a'), (1, 'b'), (2, 'c')] + + >>> it_1 = range(3) + >>> it_2 = iter('abcd') + >>> list(zip_equal(it_1, it_2)) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + more_itertools.more.UnequalIterablesError: Iterables have different + lengths + + """ + if hexversion >= 0x30A00A6: + warnings.warn( + ( + 'zip_equal will be removed in a future version of ' + 'more-itertools. Use the builtin zip function with ' + 'strict=True instead.' + ), + DeprecationWarning, + ) + # Check whether the iterables are all the same size. + try: + first_size = len(iterables[0]) + for i, it in enumerate(iterables[1:], 1): + size = len(it) + if size != first_size: + break + else: + # If we didn't break out, we can use the built-in zip. + return zip(*iterables) + + # If we did break out, there was a mismatch. + raise UnequalIterablesError(details=(first_size, i, size)) + # If any one of the iterables didn't have a length, start reading + # them until one runs out. + except TypeError: + return _zip_equal_generator(iterables) + + +def zip_offset(*iterables, offsets, longest=False, fillvalue=None): + """``zip`` the input *iterables* together, but offset the `i`-th iterable + by the `i`-th item in *offsets*. + + >>> list(zip_offset('0123', 'abcdef', offsets=(0, 1))) + [('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e')] + + This can be used as a lightweight alternative to SciPy or pandas to analyze + data sets in which some series have a lead or lag relationship. + + By default, the sequence will end when the shortest iterable is exhausted. + To continue until the longest iterable is exhausted, set *longest* to + ``True``. + + >>> list(zip_offset('0123', 'abcdef', offsets=(0, 1), longest=True)) + [('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e'), (None, 'f')] + + By default, ``None`` will be used to replace offsets beyond the end of the + sequence. Specify *fillvalue* to use some other value. + + """ + if len(iterables) != len(offsets): + raise ValueError("Number of iterables and offsets didn't match") + + staggered = [] + for it, n in zip(iterables, offsets): + if n < 0: + staggered.append(chain(repeat(fillvalue, -n), it)) + elif n > 0: + staggered.append(islice(it, n, None)) + else: + staggered.append(it) + + if longest: + return zip_longest(*staggered, fillvalue=fillvalue) + + return zip(*staggered) + + +def sort_together(iterables, key_list=(0,), key=None, reverse=False): + """Return the input iterables sorted together, with *key_list* as the + priority for sorting. All iterables are trimmed to the length of the + shortest one. + + This can be used like the sorting function in a spreadsheet. If each + iterable represents a column of data, the key list determines which + columns are used for sorting. + + By default, all iterables are sorted using the ``0``-th iterable:: + + >>> iterables = [(4, 3, 2, 1), ('a', 'b', 'c', 'd')] + >>> sort_together(iterables) + [(1, 2, 3, 4), ('d', 'c', 'b', 'a')] + + Set a different key list to sort according to another iterable. + Specifying multiple keys dictates how ties are broken:: + + >>> iterables = [(3, 1, 2), (0, 1, 0), ('c', 'b', 'a')] + >>> sort_together(iterables, key_list=(1, 2)) + [(2, 3, 1), (0, 0, 1), ('a', 'c', 'b')] + + To sort by a function of the elements of the iterable, pass a *key* + function. Its arguments are the elements of the iterables corresponding to + the key list:: + + >>> names = ('a', 'b', 'c') + >>> lengths = (1, 2, 3) + >>> widths = (5, 2, 1) + >>> def area(length, width): + ... return length * width + >>> sort_together([names, lengths, widths], key_list=(1, 2), key=area) + [('c', 'b', 'a'), (3, 2, 1), (1, 2, 5)] + + Set *reverse* to ``True`` to sort in descending order. + + >>> sort_together([(1, 2, 3), ('c', 'b', 'a')], reverse=True) + [(3, 2, 1), ('a', 'b', 'c')] + + """ + if key is None: + # if there is no key function, the key argument to sorted is an + # itemgetter + key_argument = itemgetter(*key_list) + else: + # if there is a key function, call it with the items at the offsets + # specified by the key function as arguments + key_list = list(key_list) + if len(key_list) == 1: + # if key_list contains a single item, pass the item at that offset + # as the only argument to the key function + key_offset = key_list[0] + key_argument = lambda zipped_items: key(zipped_items[key_offset]) + else: + # if key_list contains multiple items, use itemgetter to return a + # tuple of items, which we pass as *args to the key function + get_key_items = itemgetter(*key_list) + key_argument = lambda zipped_items: key( + *get_key_items(zipped_items) + ) + + return list( + zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse)) + ) + + +def unzip(iterable): + """The inverse of :func:`zip`, this function disaggregates the elements + of the zipped *iterable*. + + The ``i``-th iterable contains the ``i``-th element from each element + of the zipped iterable. The first element is used to to determine the + length of the remaining elements. + + >>> iterable = [('a', 1), ('b', 2), ('c', 3), ('d', 4)] + >>> letters, numbers = unzip(iterable) + >>> list(letters) + ['a', 'b', 'c', 'd'] + >>> list(numbers) + [1, 2, 3, 4] + + This is similar to using ``zip(*iterable)``, but it avoids reading + *iterable* into memory. Note, however, that this function uses + :func:`itertools.tee` and thus may require significant storage. + + """ + head, iterable = spy(iter(iterable)) + if not head: + # empty iterable, e.g. zip([], [], []) + return () + # spy returns a one-length iterable as head + head = head[0] + iterables = tee(iterable, len(head)) + + def itemgetter(i): + def getter(obj): + try: + return obj[i] + except IndexError: + # basically if we have an iterable like + # iter([(1, 2, 3), (4, 5), (6,)]) + # the second unzipped iterable would fail at the third tuple + # since it would try to access tup[1] + # same with the third unzipped iterable and the second tuple + # to support these "improperly zipped" iterables, + # we create a custom itemgetter + # which just stops the unzipped iterables + # at first length mismatch + raise StopIteration + + return getter + + return tuple(map(itemgetter(i), it) for i, it in enumerate(iterables)) + + +def divide(n, iterable): + """Divide the elements from *iterable* into *n* parts, maintaining + order. + + >>> group_1, group_2 = divide(2, [1, 2, 3, 4, 5, 6]) + >>> list(group_1) + [1, 2, 3] + >>> list(group_2) + [4, 5, 6] + + If the length of *iterable* is not evenly divisible by *n*, then the + length of the returned iterables will not be identical: + + >>> children = divide(3, [1, 2, 3, 4, 5, 6, 7]) + >>> [list(c) for c in children] + [[1, 2, 3], [4, 5], [6, 7]] + + If the length of the iterable is smaller than n, then the last returned + iterables will be empty: + + >>> children = divide(5, [1, 2, 3]) + >>> [list(c) for c in children] + [[1], [2], [3], [], []] + + This function will exhaust the iterable before returning and may require + significant storage. If order is not important, see :func:`distribute`, + which does not first pull the iterable into memory. + + """ + if n < 1: + raise ValueError('n must be at least 1') + + try: + iterable[:0] + except TypeError: + seq = tuple(iterable) + else: + seq = iterable + + q, r = divmod(len(seq), n) + + ret = [] + stop = 0 + for i in range(1, n + 1): + start = stop + stop += q + 1 if i <= r else q + ret.append(iter(seq[start:stop])) + + return ret + + +def always_iterable(obj, base_type=(str, bytes)): + """If *obj* is iterable, return an iterator over its items:: + + >>> obj = (1, 2, 3) + >>> list(always_iterable(obj)) + [1, 2, 3] + + If *obj* is not iterable, return a one-item iterable containing *obj*:: + + >>> obj = 1 + >>> list(always_iterable(obj)) + [1] + + If *obj* is ``None``, return an empty iterable: + + >>> obj = None + >>> list(always_iterable(None)) + [] + + By default, binary and text strings are not considered iterable:: + + >>> obj = 'foo' + >>> list(always_iterable(obj)) + ['foo'] + + If *base_type* is set, objects for which ``isinstance(obj, base_type)`` + returns ``True`` won't be considered iterable. + + >>> obj = {'a': 1} + >>> list(always_iterable(obj)) # Iterate over the dict's keys + ['a'] + >>> list(always_iterable(obj, base_type=dict)) # Treat dicts as a unit + [{'a': 1}] + + Set *base_type* to ``None`` to avoid any special handling and treat objects + Python considers iterable as iterable: + + >>> obj = 'foo' + >>> list(always_iterable(obj, base_type=None)) + ['f', 'o', 'o'] + """ + if obj is None: + return iter(()) + + if (base_type is not None) and isinstance(obj, base_type): + return iter((obj,)) + + try: + return iter(obj) + except TypeError: + return iter((obj,)) + + +def adjacent(predicate, iterable, distance=1): + """Return an iterable over `(bool, item)` tuples where the `item` is + drawn from *iterable* and the `bool` indicates whether + that item satisfies the *predicate* or is adjacent to an item that does. + + For example, to find whether items are adjacent to a ``3``:: + + >>> list(adjacent(lambda x: x == 3, range(6))) + [(False, 0), (False, 1), (True, 2), (True, 3), (True, 4), (False, 5)] + + Set *distance* to change what counts as adjacent. For example, to find + whether items are two places away from a ``3``: + + >>> list(adjacent(lambda x: x == 3, range(6), distance=2)) + [(False, 0), (True, 1), (True, 2), (True, 3), (True, 4), (True, 5)] + + This is useful for contextualizing the results of a search function. + For example, a code comparison tool might want to identify lines that + have changed, but also surrounding lines to give the viewer of the diff + context. + + The predicate function will only be called once for each item in the + iterable. + + See also :func:`groupby_transform`, which can be used with this function + to group ranges of items with the same `bool` value. + + """ + # Allow distance=0 mainly for testing that it reproduces results with map() + if distance < 0: + raise ValueError('distance must be at least 0') + + i1, i2 = tee(iterable) + padding = [False] * distance + selected = chain(padding, map(predicate, i1), padding) + adjacent_to_selected = map(any, windowed(selected, 2 * distance + 1)) + return zip(adjacent_to_selected, i2) + + +def groupby_transform(iterable, keyfunc=None, valuefunc=None, reducefunc=None): + """An extension of :func:`itertools.groupby` that can apply transformations + to the grouped data. + + * *keyfunc* is a function computing a key value for each item in *iterable* + * *valuefunc* is a function that transforms the individual items from + *iterable* after grouping + * *reducefunc* is a function that transforms each group of items + + >>> iterable = 'aAAbBBcCC' + >>> keyfunc = lambda k: k.upper() + >>> valuefunc = lambda v: v.lower() + >>> reducefunc = lambda g: ''.join(g) + >>> list(groupby_transform(iterable, keyfunc, valuefunc, reducefunc)) + [('A', 'aaa'), ('B', 'bbb'), ('C', 'ccc')] + + Each optional argument defaults to an identity function if not specified. + + :func:`groupby_transform` is useful when grouping elements of an iterable + using a separate iterable as the key. To do this, :func:`zip` the iterables + and pass a *keyfunc* that extracts the first element and a *valuefunc* + that extracts the second element:: + + >>> from operator import itemgetter + >>> keys = [0, 0, 1, 1, 1, 2, 2, 2, 3] + >>> values = 'abcdefghi' + >>> iterable = zip(keys, values) + >>> grouper = groupby_transform(iterable, itemgetter(0), itemgetter(1)) + >>> [(k, ''.join(g)) for k, g in grouper] + [(0, 'ab'), (1, 'cde'), (2, 'fgh'), (3, 'i')] + + Note that the order of items in the iterable is significant. + Only adjacent items are grouped together, so if you don't want any + duplicate groups, you should sort the iterable by the key function. + + """ + ret = groupby(iterable, keyfunc) + if valuefunc: + ret = ((k, map(valuefunc, g)) for k, g in ret) + if reducefunc: + ret = ((k, reducefunc(g)) for k, g in ret) + + return ret + + +class numeric_range(abc.Sequence, abc.Hashable): + """An extension of the built-in ``range()`` function whose arguments can + be any orderable numeric type. + + With only *stop* specified, *start* defaults to ``0`` and *step* + defaults to ``1``. The output items will match the type of *stop*: + + >>> list(numeric_range(3.5)) + [0.0, 1.0, 2.0, 3.0] + + With only *start* and *stop* specified, *step* defaults to ``1``. The + output items will match the type of *start*: + + >>> from decimal import Decimal + >>> start = Decimal('2.1') + >>> stop = Decimal('5.1') + >>> list(numeric_range(start, stop)) + [Decimal('2.1'), Decimal('3.1'), Decimal('4.1')] + + With *start*, *stop*, and *step* specified the output items will match + the type of ``start + step``: + + >>> from fractions import Fraction + >>> start = Fraction(1, 2) # Start at 1/2 + >>> stop = Fraction(5, 2) # End at 5/2 + >>> step = Fraction(1, 2) # Count by 1/2 + >>> list(numeric_range(start, stop, step)) + [Fraction(1, 2), Fraction(1, 1), Fraction(3, 2), Fraction(2, 1)] + + If *step* is zero, ``ValueError`` is raised. Negative steps are supported: + + >>> list(numeric_range(3, -1, -1.0)) + [3.0, 2.0, 1.0, 0.0] + + Be aware of the limitations of floating point numbers; the representation + of the yielded numbers may be surprising. + + ``datetime.datetime`` objects can be used for *start* and *stop*, if *step* + is a ``datetime.timedelta`` object: + + >>> import datetime + >>> start = datetime.datetime(2019, 1, 1) + >>> stop = datetime.datetime(2019, 1, 3) + >>> step = datetime.timedelta(days=1) + >>> items = iter(numeric_range(start, stop, step)) + >>> next(items) + datetime.datetime(2019, 1, 1, 0, 0) + >>> next(items) + datetime.datetime(2019, 1, 2, 0, 0) + + """ + + _EMPTY_HASH = hash(range(0, 0)) + + def __init__(self, *args): + argc = len(args) + if argc == 1: + (self._stop,) = args + self._start = type(self._stop)(0) + self._step = type(self._stop - self._start)(1) + elif argc == 2: + self._start, self._stop = args + self._step = type(self._stop - self._start)(1) + elif argc == 3: + self._start, self._stop, self._step = args + elif argc == 0: + raise TypeError( + 'numeric_range expected at least ' + '1 argument, got {}'.format(argc) + ) + else: + raise TypeError( + 'numeric_range expected at most ' + '3 arguments, got {}'.format(argc) + ) + + self._zero = type(self._step)(0) + if self._step == self._zero: + raise ValueError('numeric_range() arg 3 must not be zero') + self._growing = self._step > self._zero + self._init_len() + + def __bool__(self): + if self._growing: + return self._start < self._stop + else: + return self._start > self._stop + + def __contains__(self, elem): + if self._growing: + if self._start <= elem < self._stop: + return (elem - self._start) % self._step == self._zero + else: + if self._start >= elem > self._stop: + return (self._start - elem) % (-self._step) == self._zero + + return False + + def __eq__(self, other): + if isinstance(other, numeric_range): + empty_self = not bool(self) + empty_other = not bool(other) + if empty_self or empty_other: + return empty_self and empty_other # True if both empty + else: + return ( + self._start == other._start + and self._step == other._step + and self._get_by_index(-1) == other._get_by_index(-1) + ) + else: + return False + + def __getitem__(self, key): + if isinstance(key, int): + return self._get_by_index(key) + elif isinstance(key, slice): + step = self._step if key.step is None else key.step * self._step + + if key.start is None or key.start <= -self._len: + start = self._start + elif key.start >= self._len: + start = self._stop + else: # -self._len < key.start < self._len + start = self._get_by_index(key.start) + + if key.stop is None or key.stop >= self._len: + stop = self._stop + elif key.stop <= -self._len: + stop = self._start + else: # -self._len < key.stop < self._len + stop = self._get_by_index(key.stop) + + return numeric_range(start, stop, step) + else: + raise TypeError( + 'numeric range indices must be ' + 'integers or slices, not {}'.format(type(key).__name__) + ) + + def __hash__(self): + if self: + return hash((self._start, self._get_by_index(-1), self._step)) + else: + return self._EMPTY_HASH + + def __iter__(self): + values = (self._start + (n * self._step) for n in count()) + if self._growing: + return takewhile(partial(gt, self._stop), values) + else: + return takewhile(partial(lt, self._stop), values) + + def __len__(self): + return self._len + + def _init_len(self): + if self._growing: + start = self._start + stop = self._stop + step = self._step + else: + start = self._stop + stop = self._start + step = -self._step + distance = stop - start + if distance <= self._zero: + self._len = 0 + else: # distance > 0 and step > 0: regular euclidean division + q, r = divmod(distance, step) + self._len = int(q) + int(r != self._zero) + + def __reduce__(self): + return numeric_range, (self._start, self._stop, self._step) + + def __repr__(self): + if self._step == 1: + return "numeric_range({}, {})".format( + repr(self._start), repr(self._stop) + ) + else: + return "numeric_range({}, {}, {})".format( + repr(self._start), repr(self._stop), repr(self._step) + ) + + def __reversed__(self): + return iter( + numeric_range( + self._get_by_index(-1), self._start - self._step, -self._step + ) + ) + + def count(self, value): + return int(value in self) + + def index(self, value): + if self._growing: + if self._start <= value < self._stop: + q, r = divmod(value - self._start, self._step) + if r == self._zero: + return int(q) + else: + if self._start >= value > self._stop: + q, r = divmod(self._start - value, -self._step) + if r == self._zero: + return int(q) + + raise ValueError("{} is not in numeric range".format(value)) + + def _get_by_index(self, i): + if i < 0: + i += self._len + if i < 0 or i >= self._len: + raise IndexError("numeric range object index out of range") + return self._start + i * self._step + + +def count_cycle(iterable, n=None): + """Cycle through the items from *iterable* up to *n* times, yielding + the number of completed cycles along with each item. If *n* is omitted the + process repeats indefinitely. + + >>> list(count_cycle('AB', 3)) + [(0, 'A'), (0, 'B'), (1, 'A'), (1, 'B'), (2, 'A'), (2, 'B')] + + """ + iterable = tuple(iterable) + if not iterable: + return iter(()) + counter = count() if n is None else range(n) + return ((i, item) for i in counter for item in iterable) + + +def mark_ends(iterable): + """Yield 3-tuples of the form ``(is_first, is_last, item)``. + + >>> list(mark_ends('ABC')) + [(True, False, 'A'), (False, False, 'B'), (False, True, 'C')] + + Use this when looping over an iterable to take special action on its first + and/or last items: + + >>> iterable = ['Header', 100, 200, 'Footer'] + >>> total = 0 + >>> for is_first, is_last, item in mark_ends(iterable): + ... if is_first: + ... continue # Skip the header + ... if is_last: + ... continue # Skip the footer + ... total += item + >>> print(total) + 300 + """ + it = iter(iterable) + + try: + b = next(it) + except StopIteration: + return + + try: + for i in count(): + a = b + b = next(it) + yield i == 0, False, a + + except StopIteration: + yield i == 0, True, a + + +def locate(iterable, pred=bool, window_size=None): + """Yield the index of each item in *iterable* for which *pred* returns + ``True``. + + *pred* defaults to :func:`bool`, which will select truthy items: + + >>> list(locate([0, 1, 1, 0, 1, 0, 0])) + [1, 2, 4] + + Set *pred* to a custom function to, e.g., find the indexes for a particular + item. + + >>> list(locate(['a', 'b', 'c', 'b'], lambda x: x == 'b')) + [1, 3] + + If *window_size* is given, then the *pred* function will be called with + that many items. This enables searching for sub-sequences: + + >>> iterable = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3] + >>> pred = lambda *args: args == (1, 2, 3) + >>> list(locate(iterable, pred=pred, window_size=3)) + [1, 5, 9] + + Use with :func:`seekable` to find indexes and then retrieve the associated + items: + + >>> from itertools import count + >>> from more_itertools import seekable + >>> source = (3 * n + 1 if (n % 2) else n // 2 for n in count()) + >>> it = seekable(source) + >>> pred = lambda x: x > 100 + >>> indexes = locate(it, pred=pred) + >>> i = next(indexes) + >>> it.seek(i) + >>> next(it) + 106 + + """ + if window_size is None: + return compress(count(), map(pred, iterable)) + + if window_size < 1: + raise ValueError('window size must be at least 1') + + it = windowed(iterable, window_size, fillvalue=_marker) + return compress(count(), starmap(pred, it)) + + +def lstrip(iterable, pred): + """Yield the items from *iterable*, but strip any from the beginning + for which *pred* returns ``True``. + + For example, to remove a set of items from the start of an iterable: + + >>> iterable = (None, False, None, 1, 2, None, 3, False, None) + >>> pred = lambda x: x in {None, False, ''} + >>> list(lstrip(iterable, pred)) + [1, 2, None, 3, False, None] + + This function is analogous to to :func:`str.lstrip`, and is essentially + an wrapper for :func:`itertools.dropwhile`. + + """ + return dropwhile(pred, iterable) + + +def rstrip(iterable, pred): + """Yield the items from *iterable*, but strip any from the end + for which *pred* returns ``True``. + + For example, to remove a set of items from the end of an iterable: + + >>> iterable = (None, False, None, 1, 2, None, 3, False, None) + >>> pred = lambda x: x in {None, False, ''} + >>> list(rstrip(iterable, pred)) + [None, False, None, 1, 2, None, 3] + + This function is analogous to :func:`str.rstrip`. + + """ + cache = [] + cache_append = cache.append + cache_clear = cache.clear + for x in iterable: + if pred(x): + cache_append(x) + else: + yield from cache + cache_clear() + yield x + + +def strip(iterable, pred): + """Yield the items from *iterable*, but strip any from the + beginning and end for which *pred* returns ``True``. + + For example, to remove a set of items from both ends of an iterable: + + >>> iterable = (None, False, None, 1, 2, None, 3, False, None) + >>> pred = lambda x: x in {None, False, ''} + >>> list(strip(iterable, pred)) + [1, 2, None, 3] + + This function is analogous to :func:`str.strip`. + + """ + return rstrip(lstrip(iterable, pred), pred) + + +class islice_extended: + """An extension of :func:`itertools.islice` that supports negative values + for *stop*, *start*, and *step*. + + >>> iterable = iter('abcdefgh') + >>> list(islice_extended(iterable, -4, -1)) + ['e', 'f', 'g'] + + Slices with negative values require some caching of *iterable*, but this + function takes care to minimize the amount of memory required. + + For example, you can use a negative step with an infinite iterator: + + >>> from itertools import count + >>> list(islice_extended(count(), 110, 99, -2)) + [110, 108, 106, 104, 102, 100] + + You can also use slice notation directly: + + >>> iterable = map(str, count()) + >>> it = islice_extended(iterable)[10:20:2] + >>> list(it) + ['10', '12', '14', '16', '18'] + + """ + + def __init__(self, iterable, *args): + it = iter(iterable) + if args: + self._iterable = _islice_helper(it, slice(*args)) + else: + self._iterable = it + + def __iter__(self): + return self + + def __next__(self): + return next(self._iterable) + + def __getitem__(self, key): + if isinstance(key, slice): + return islice_extended(_islice_helper(self._iterable, key)) + + raise TypeError('islice_extended.__getitem__ argument must be a slice') + + +def _islice_helper(it, s): + start = s.start + stop = s.stop + if s.step == 0: + raise ValueError('step argument must be a non-zero integer or None.') + step = s.step or 1 + + if step > 0: + start = 0 if (start is None) else start + + if start < 0: + # Consume all but the last -start items + cache = deque(enumerate(it, 1), maxlen=-start) + len_iter = cache[-1][0] if cache else 0 + + # Adjust start to be positive + i = max(len_iter + start, 0) + + # Adjust stop to be positive + if stop is None: + j = len_iter + elif stop >= 0: + j = min(stop, len_iter) + else: + j = max(len_iter + stop, 0) + + # Slice the cache + n = j - i + if n <= 0: + return + + for index, item in islice(cache, 0, n, step): + yield item + elif (stop is not None) and (stop < 0): + # Advance to the start position + next(islice(it, start, start), None) + + # When stop is negative, we have to carry -stop items while + # iterating + cache = deque(islice(it, -stop), maxlen=-stop) + + for index, item in enumerate(it): + cached_item = cache.popleft() + if index % step == 0: + yield cached_item + cache.append(item) + else: + # When both start and stop are positive we have the normal case + yield from islice(it, start, stop, step) + else: + start = -1 if (start is None) else start + + if (stop is not None) and (stop < 0): + # Consume all but the last items + n = -stop - 1 + cache = deque(enumerate(it, 1), maxlen=n) + len_iter = cache[-1][0] if cache else 0 + + # If start and stop are both negative they are comparable and + # we can just slice. Otherwise we can adjust start to be negative + # and then slice. + if start < 0: + i, j = start, stop + else: + i, j = min(start - len_iter, -1), None + + for index, item in list(cache)[i:j:step]: + yield item + else: + # Advance to the stop position + if stop is not None: + m = stop + 1 + next(islice(it, m, m), None) + + # stop is positive, so if start is negative they are not comparable + # and we need the rest of the items. + if start < 0: + i = start + n = None + # stop is None and start is positive, so we just need items up to + # the start index. + elif stop is None: + i = None + n = start + 1 + # Both stop and start are positive, so they are comparable. + else: + i = None + n = start - stop + if n <= 0: + return + + cache = list(islice(it, n)) + + yield from cache[i::step] + + +def always_reversible(iterable): + """An extension of :func:`reversed` that supports all iterables, not + just those which implement the ``Reversible`` or ``Sequence`` protocols. + + >>> print(*always_reversible(x for x in range(3))) + 2 1 0 + + If the iterable is already reversible, this function returns the + result of :func:`reversed()`. If the iterable is not reversible, + this function will cache the remaining items in the iterable and + yield them in reverse order, which may require significant storage. + """ + try: + return reversed(iterable) + except TypeError: + return reversed(list(iterable)) + + +def consecutive_groups(iterable, ordering=lambda x: x): + """Yield groups of consecutive items using :func:`itertools.groupby`. + The *ordering* function determines whether two items are adjacent by + returning their position. + + By default, the ordering function is the identity function. This is + suitable for finding runs of numbers: + + >>> iterable = [1, 10, 11, 12, 20, 30, 31, 32, 33, 40] + >>> for group in consecutive_groups(iterable): + ... print(list(group)) + [1] + [10, 11, 12] + [20] + [30, 31, 32, 33] + [40] + + For finding runs of adjacent letters, try using the :meth:`index` method + of a string of letters: + + >>> from string import ascii_lowercase + >>> iterable = 'abcdfgilmnop' + >>> ordering = ascii_lowercase.index + >>> for group in consecutive_groups(iterable, ordering): + ... print(list(group)) + ['a', 'b', 'c', 'd'] + ['f', 'g'] + ['i'] + ['l', 'm', 'n', 'o', 'p'] + + Each group of consecutive items is an iterator that shares it source with + *iterable*. When an an output group is advanced, the previous group is + no longer available unless its elements are copied (e.g., into a ``list``). + + >>> iterable = [1, 2, 11, 12, 21, 22] + >>> saved_groups = [] + >>> for group in consecutive_groups(iterable): + ... saved_groups.append(list(group)) # Copy group elements + >>> saved_groups + [[1, 2], [11, 12], [21, 22]] + + """ + for k, g in groupby( + enumerate(iterable), key=lambda x: x[0] - ordering(x[1]) + ): + yield map(itemgetter(1), g) + + +def difference(iterable, func=sub, *, initial=None): + """This function is the inverse of :func:`itertools.accumulate`. By default + it will compute the first difference of *iterable* using + :func:`operator.sub`: + + >>> from itertools import accumulate + >>> iterable = accumulate([0, 1, 2, 3, 4]) # produces 0, 1, 3, 6, 10 + >>> list(difference(iterable)) + [0, 1, 2, 3, 4] + + *func* defaults to :func:`operator.sub`, but other functions can be + specified. They will be applied as follows:: + + A, B, C, D, ... --> A, func(B, A), func(C, B), func(D, C), ... + + For example, to do progressive division: + + >>> iterable = [1, 2, 6, 24, 120] + >>> func = lambda x, y: x // y + >>> list(difference(iterable, func)) + [1, 2, 3, 4, 5] + + If the *initial* keyword is set, the first element will be skipped when + computing successive differences. + + >>> it = [10, 11, 13, 16] # from accumulate([1, 2, 3], initial=10) + >>> list(difference(it, initial=10)) + [1, 2, 3] + + """ + a, b = tee(iterable) + try: + first = [next(b)] + except StopIteration: + return iter([]) + + if initial is not None: + first = [] + + return chain(first, starmap(func, zip(b, a))) + + +class SequenceView(Sequence): + """Return a read-only view of the sequence object *target*. + + :class:`SequenceView` objects are analogous to Python's built-in + "dictionary view" types. They provide a dynamic view of a sequence's items, + meaning that when the sequence updates, so does the view. + + >>> seq = ['0', '1', '2'] + >>> view = SequenceView(seq) + >>> view + SequenceView(['0', '1', '2']) + >>> seq.append('3') + >>> view + SequenceView(['0', '1', '2', '3']) + + Sequence views support indexing, slicing, and length queries. They act + like the underlying sequence, except they don't allow assignment: + + >>> view[1] + '1' + >>> view[1:-1] + ['1', '2'] + >>> len(view) + 4 + + Sequence views are useful as an alternative to copying, as they don't + require (much) extra storage. + + """ + + def __init__(self, target): + if not isinstance(target, Sequence): + raise TypeError + self._target = target + + def __getitem__(self, index): + return self._target[index] + + def __len__(self): + return len(self._target) + + def __repr__(self): + return '{}({})'.format(self.__class__.__name__, repr(self._target)) + + +class seekable: + """Wrap an iterator to allow for seeking backward and forward. This + progressively caches the items in the source iterable so they can be + re-visited. + + Call :meth:`seek` with an index to seek to that position in the source + iterable. + + To "reset" an iterator, seek to ``0``: + + >>> from itertools import count + >>> it = seekable((str(n) for n in count())) + >>> next(it), next(it), next(it) + ('0', '1', '2') + >>> it.seek(0) + >>> next(it), next(it), next(it) + ('0', '1', '2') + >>> next(it) + '3' + + You can also seek forward: + + >>> it = seekable((str(n) for n in range(20))) + >>> it.seek(10) + >>> next(it) + '10' + >>> it.seek(20) # Seeking past the end of the source isn't a problem + >>> list(it) + [] + >>> it.seek(0) # Resetting works even after hitting the end + >>> next(it), next(it), next(it) + ('0', '1', '2') + + Call :meth:`peek` to look ahead one item without advancing the iterator: + + >>> it = seekable('1234') + >>> it.peek() + '1' + >>> list(it) + ['1', '2', '3', '4'] + >>> it.peek(default='empty') + 'empty' + + Before the iterator is at its end, calling :func:`bool` on it will return + ``True``. After it will return ``False``: + + >>> it = seekable('5678') + >>> bool(it) + True + >>> list(it) + ['5', '6', '7', '8'] + >>> bool(it) + False + + You may view the contents of the cache with the :meth:`elements` method. + That returns a :class:`SequenceView`, a view that updates automatically: + + >>> it = seekable((str(n) for n in range(10))) + >>> next(it), next(it), next(it) + ('0', '1', '2') + >>> elements = it.elements() + >>> elements + SequenceView(['0', '1', '2']) + >>> next(it) + '3' + >>> elements + SequenceView(['0', '1', '2', '3']) + + By default, the cache grows as the source iterable progresses, so beware of + wrapping very large or infinite iterables. Supply *maxlen* to limit the + size of the cache (this of course limits how far back you can seek). + + >>> from itertools import count + >>> it = seekable((str(n) for n in count()), maxlen=2) + >>> next(it), next(it), next(it), next(it) + ('0', '1', '2', '3') + >>> list(it.elements()) + ['2', '3'] + >>> it.seek(0) + >>> next(it), next(it), next(it), next(it) + ('2', '3', '4', '5') + >>> next(it) + '6' + + """ + + def __init__(self, iterable, maxlen=None): + self._source = iter(iterable) + if maxlen is None: + self._cache = [] + else: + self._cache = deque([], maxlen) + self._index = None + + def __iter__(self): + return self + + def __next__(self): + if self._index is not None: + try: + item = self._cache[self._index] + except IndexError: + self._index = None + else: + self._index += 1 + return item + + item = next(self._source) + self._cache.append(item) + return item + + def __bool__(self): + try: + self.peek() + except StopIteration: + return False + return True + + def peek(self, default=_marker): + try: + peeked = next(self) + except StopIteration: + if default is _marker: + raise + return default + if self._index is None: + self._index = len(self._cache) + self._index -= 1 + return peeked + + def elements(self): + return SequenceView(self._cache) + + def seek(self, index): + self._index = index + remainder = index - len(self._cache) + if remainder > 0: + consume(self, remainder) + + +class run_length: + """ + :func:`run_length.encode` compresses an iterable with run-length encoding. + It yields groups of repeated items with the count of how many times they + were repeated: + + >>> uncompressed = 'abbcccdddd' + >>> list(run_length.encode(uncompressed)) + [('a', 1), ('b', 2), ('c', 3), ('d', 4)] + + :func:`run_length.decode` decompresses an iterable that was previously + compressed with run-length encoding. It yields the items of the + decompressed iterable: + + >>> compressed = [('a', 1), ('b', 2), ('c', 3), ('d', 4)] + >>> list(run_length.decode(compressed)) + ['a', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd'] + + """ + + @staticmethod + def encode(iterable): + return ((k, ilen(g)) for k, g in groupby(iterable)) + + @staticmethod + def decode(iterable): + return chain.from_iterable(repeat(k, n) for k, n in iterable) + + +def exactly_n(iterable, n, predicate=bool): + """Return ``True`` if exactly ``n`` items in the iterable are ``True`` + according to the *predicate* function. + + >>> exactly_n([True, True, False], 2) + True + >>> exactly_n([True, True, False], 1) + False + >>> exactly_n([0, 1, 2, 3, 4, 5], 3, lambda x: x < 3) + True + + The iterable will be advanced until ``n + 1`` truthy items are encountered, + so avoid calling it on infinite iterables. + + """ + return len(take(n + 1, filter(predicate, iterable))) == n + + +def circular_shifts(iterable): + """Return a list of circular shifts of *iterable*. + + >>> circular_shifts(range(4)) + [(0, 1, 2, 3), (1, 2, 3, 0), (2, 3, 0, 1), (3, 0, 1, 2)] + """ + lst = list(iterable) + return take(len(lst), windowed(cycle(lst), len(lst))) + + +def make_decorator(wrapping_func, result_index=0): + """Return a decorator version of *wrapping_func*, which is a function that + modifies an iterable. *result_index* is the position in that function's + signature where the iterable goes. + + This lets you use itertools on the "production end," i.e. at function + definition. This can augment what the function returns without changing the + function's code. + + For example, to produce a decorator version of :func:`chunked`: + + >>> from more_itertools import chunked + >>> chunker = make_decorator(chunked, result_index=0) + >>> @chunker(3) + ... def iter_range(n): + ... return iter(range(n)) + ... + >>> list(iter_range(9)) + [[0, 1, 2], [3, 4, 5], [6, 7, 8]] + + To only allow truthy items to be returned: + + >>> truth_serum = make_decorator(filter, result_index=1) + >>> @truth_serum(bool) + ... def boolean_test(): + ... return [0, 1, '', ' ', False, True] + ... + >>> list(boolean_test()) + [1, ' ', True] + + The :func:`peekable` and :func:`seekable` wrappers make for practical + decorators: + + >>> from more_itertools import peekable + >>> peekable_function = make_decorator(peekable) + >>> @peekable_function() + ... def str_range(*args): + ... return (str(x) for x in range(*args)) + ... + >>> it = str_range(1, 20, 2) + >>> next(it), next(it), next(it) + ('1', '3', '5') + >>> it.peek() + '7' + >>> next(it) + '7' + + """ + # See https://sites.google.com/site/bbayles/index/decorator_factory for + # notes on how this works. + def decorator(*wrapping_args, **wrapping_kwargs): + def outer_wrapper(f): + def inner_wrapper(*args, **kwargs): + result = f(*args, **kwargs) + wrapping_args_ = list(wrapping_args) + wrapping_args_.insert(result_index, result) + return wrapping_func(*wrapping_args_, **wrapping_kwargs) + + return inner_wrapper + + return outer_wrapper + + return decorator + + +def map_reduce(iterable, keyfunc, valuefunc=None, reducefunc=None): + """Return a dictionary that maps the items in *iterable* to categories + defined by *keyfunc*, transforms them with *valuefunc*, and + then summarizes them by category with *reducefunc*. + + *valuefunc* defaults to the identity function if it is unspecified. + If *reducefunc* is unspecified, no summarization takes place: + + >>> keyfunc = lambda x: x.upper() + >>> result = map_reduce('abbccc', keyfunc) + >>> sorted(result.items()) + [('A', ['a']), ('B', ['b', 'b']), ('C', ['c', 'c', 'c'])] + + Specifying *valuefunc* transforms the categorized items: + + >>> keyfunc = lambda x: x.upper() + >>> valuefunc = lambda x: 1 + >>> result = map_reduce('abbccc', keyfunc, valuefunc) + >>> sorted(result.items()) + [('A', [1]), ('B', [1, 1]), ('C', [1, 1, 1])] + + Specifying *reducefunc* summarizes the categorized items: + + >>> keyfunc = lambda x: x.upper() + >>> valuefunc = lambda x: 1 + >>> reducefunc = sum + >>> result = map_reduce('abbccc', keyfunc, valuefunc, reducefunc) + >>> sorted(result.items()) + [('A', 1), ('B', 2), ('C', 3)] + + You may want to filter the input iterable before applying the map/reduce + procedure: + + >>> all_items = range(30) + >>> items = [x for x in all_items if 10 <= x <= 20] # Filter + >>> keyfunc = lambda x: x % 2 # Evens map to 0; odds to 1 + >>> categories = map_reduce(items, keyfunc=keyfunc) + >>> sorted(categories.items()) + [(0, [10, 12, 14, 16, 18, 20]), (1, [11, 13, 15, 17, 19])] + >>> summaries = map_reduce(items, keyfunc=keyfunc, reducefunc=sum) + >>> sorted(summaries.items()) + [(0, 90), (1, 75)] + + Note that all items in the iterable are gathered into a list before the + summarization step, which may require significant storage. + + The returned object is a :obj:`collections.defaultdict` with the + ``default_factory`` set to ``None``, such that it behaves like a normal + dictionary. + + """ + valuefunc = (lambda x: x) if (valuefunc is None) else valuefunc + + ret = defaultdict(list) + for item in iterable: + key = keyfunc(item) + value = valuefunc(item) + ret[key].append(value) + + if reducefunc is not None: + for key, value_list in ret.items(): + ret[key] = reducefunc(value_list) + + ret.default_factory = None + return ret + + +def rlocate(iterable, pred=bool, window_size=None): + """Yield the index of each item in *iterable* for which *pred* returns + ``True``, starting from the right and moving left. + + *pred* defaults to :func:`bool`, which will select truthy items: + + >>> list(rlocate([0, 1, 1, 0, 1, 0, 0])) # Truthy at 1, 2, and 4 + [4, 2, 1] + + Set *pred* to a custom function to, e.g., find the indexes for a particular + item: + + >>> iterable = iter('abcb') + >>> pred = lambda x: x == 'b' + >>> list(rlocate(iterable, pred)) + [3, 1] + + If *window_size* is given, then the *pred* function will be called with + that many items. This enables searching for sub-sequences: + + >>> iterable = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3] + >>> pred = lambda *args: args == (1, 2, 3) + >>> list(rlocate(iterable, pred=pred, window_size=3)) + [9, 5, 1] + + Beware, this function won't return anything for infinite iterables. + If *iterable* is reversible, ``rlocate`` will reverse it and search from + the right. Otherwise, it will search from the left and return the results + in reverse order. + + See :func:`locate` to for other example applications. + + """ + if window_size is None: + try: + len_iter = len(iterable) + return (len_iter - i - 1 for i in locate(reversed(iterable), pred)) + except TypeError: + pass + + return reversed(list(locate(iterable, pred, window_size))) + + +def replace(iterable, pred, substitutes, count=None, window_size=1): + """Yield the items from *iterable*, replacing the items for which *pred* + returns ``True`` with the items from the iterable *substitutes*. + + >>> iterable = [1, 1, 0, 1, 1, 0, 1, 1] + >>> pred = lambda x: x == 0 + >>> substitutes = (2, 3) + >>> list(replace(iterable, pred, substitutes)) + [1, 1, 2, 3, 1, 1, 2, 3, 1, 1] + + If *count* is given, the number of replacements will be limited: + + >>> iterable = [1, 1, 0, 1, 1, 0, 1, 1, 0] + >>> pred = lambda x: x == 0 + >>> substitutes = [None] + >>> list(replace(iterable, pred, substitutes, count=2)) + [1, 1, None, 1, 1, None, 1, 1, 0] + + Use *window_size* to control the number of items passed as arguments to + *pred*. This allows for locating and replacing subsequences. + + >>> iterable = [0, 1, 2, 5, 0, 1, 2, 5] + >>> window_size = 3 + >>> pred = lambda *args: args == (0, 1, 2) # 3 items passed to pred + >>> substitutes = [3, 4] # Splice in these items + >>> list(replace(iterable, pred, substitutes, window_size=window_size)) + [3, 4, 5, 3, 4, 5] + + """ + if window_size < 1: + raise ValueError('window_size must be at least 1') + + # Save the substitutes iterable, since it's used more than once + substitutes = tuple(substitutes) + + # Add padding such that the number of windows matches the length of the + # iterable + it = chain(iterable, [_marker] * (window_size - 1)) + windows = windowed(it, window_size) + + n = 0 + for w in windows: + # If the current window matches our predicate (and we haven't hit + # our maximum number of replacements), splice in the substitutes + # and then consume the following windows that overlap with this one. + # For example, if the iterable is (0, 1, 2, 3, 4...) + # and the window size is 2, we have (0, 1), (1, 2), (2, 3)... + # If the predicate matches on (0, 1), we need to zap (0, 1) and (1, 2) + if pred(*w): + if (count is None) or (n < count): + n += 1 + yield from substitutes + consume(windows, window_size - 1) + continue + + # If there was no match (or we've reached the replacement limit), + # yield the first item from the window. + if w and (w[0] is not _marker): + yield w[0] + + +def partitions(iterable): + """Yield all possible order-preserving partitions of *iterable*. + + >>> iterable = 'abc' + >>> for part in partitions(iterable): + ... print([''.join(p) for p in part]) + ['abc'] + ['a', 'bc'] + ['ab', 'c'] + ['a', 'b', 'c'] + + This is unrelated to :func:`partition`. + + """ + sequence = list(iterable) + n = len(sequence) + for i in powerset(range(1, n)): + yield [sequence[i:j] for i, j in zip((0,) + i, i + (n,))] + + +def set_partitions(iterable, k=None): + """ + Yield the set partitions of *iterable* into *k* parts. Set partitions are + not order-preserving. + + >>> iterable = 'abc' + >>> for part in set_partitions(iterable, 2): + ... print([''.join(p) for p in part]) + ['a', 'bc'] + ['ab', 'c'] + ['b', 'ac'] + + + If *k* is not given, every set partition is generated. + + >>> iterable = 'abc' + >>> for part in set_partitions(iterable): + ... print([''.join(p) for p in part]) + ['abc'] + ['a', 'bc'] + ['ab', 'c'] + ['b', 'ac'] + ['a', 'b', 'c'] + + """ + L = list(iterable) + n = len(L) + if k is not None: + if k < 1: + raise ValueError( + "Can't partition in a negative or zero number of groups" + ) + elif k > n: + return + + def set_partitions_helper(L, k): + n = len(L) + if k == 1: + yield [L] + elif n == k: + yield [[s] for s in L] + else: + e, *M = L + for p in set_partitions_helper(M, k - 1): + yield [[e], *p] + for p in set_partitions_helper(M, k): + for i in range(len(p)): + yield p[:i] + [[e] + p[i]] + p[i + 1 :] + + if k is None: + for k in range(1, n + 1): + yield from set_partitions_helper(L, k) + else: + yield from set_partitions_helper(L, k) + + +class time_limited: + """ + Yield items from *iterable* until *limit_seconds* have passed. + If the time limit expires before all items have been yielded, the + ``timed_out`` parameter will be set to ``True``. + + >>> from time import sleep + >>> def generator(): + ... yield 1 + ... yield 2 + ... sleep(0.2) + ... yield 3 + >>> iterable = time_limited(0.1, generator()) + >>> list(iterable) + [1, 2] + >>> iterable.timed_out + True + + Note that the time is checked before each item is yielded, and iteration + stops if the time elapsed is greater than *limit_seconds*. If your time + limit is 1 second, but it takes 2 seconds to generate the first item from + the iterable, the function will run for 2 seconds and not yield anything. + + """ + + def __init__(self, limit_seconds, iterable): + if limit_seconds < 0: + raise ValueError('limit_seconds must be positive') + self.limit_seconds = limit_seconds + self._iterable = iter(iterable) + self._start_time = monotonic() + self.timed_out = False + + def __iter__(self): + return self + + def __next__(self): + item = next(self._iterable) + if monotonic() - self._start_time > self.limit_seconds: + self.timed_out = True + raise StopIteration + + return item + + +def only(iterable, default=None, too_long=None): + """If *iterable* has only one item, return it. + If it has zero items, return *default*. + If it has more than one item, raise the exception given by *too_long*, + which is ``ValueError`` by default. + + >>> only([], default='missing') + 'missing' + >>> only([1]) + 1 + >>> only([1, 2]) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + ValueError: Expected exactly one item in iterable, but got 1, 2, + and perhaps more.' + >>> only([1, 2], too_long=TypeError) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + TypeError + + Note that :func:`only` attempts to advance *iterable* twice to ensure there + is only one item. See :func:`spy` or :func:`peekable` to check + iterable contents less destructively. + """ + it = iter(iterable) + first_value = next(it, default) + + try: + second_value = next(it) + except StopIteration: + pass + else: + msg = ( + 'Expected exactly one item in iterable, but got {!r}, {!r}, ' + 'and perhaps more.'.format(first_value, second_value) + ) + raise too_long or ValueError(msg) + + return first_value + + +def ichunked(iterable, n): + """Break *iterable* into sub-iterables with *n* elements each. + :func:`ichunked` is like :func:`chunked`, but it yields iterables + instead of lists. + + If the sub-iterables are read in order, the elements of *iterable* + won't be stored in memory. + If they are read out of order, :func:`itertools.tee` is used to cache + elements as necessary. + + >>> from itertools import count + >>> all_chunks = ichunked(count(), 4) + >>> c_1, c_2, c_3 = next(all_chunks), next(all_chunks), next(all_chunks) + >>> list(c_2) # c_1's elements have been cached; c_3's haven't been + [4, 5, 6, 7] + >>> list(c_1) + [0, 1, 2, 3] + >>> list(c_3) + [8, 9, 10, 11] + + """ + source = iter(iterable) + + while True: + # Check to see whether we're at the end of the source iterable + item = next(source, _marker) + if item is _marker: + return + + # Clone the source and yield an n-length slice + source, it = tee(chain([item], source)) + yield islice(it, n) + + # Advance the source iterable + consume(source, n) + + +def distinct_combinations(iterable, r): + """Yield the distinct combinations of *r* items taken from *iterable*. + + >>> list(distinct_combinations([0, 0, 1], 2)) + [(0, 0), (0, 1)] + + Equivalent to ``set(combinations(iterable))``, except duplicates are not + generated and thrown away. For larger input sequences this is much more + efficient. + + """ + if r < 0: + raise ValueError('r must be non-negative') + elif r == 0: + yield () + return + pool = tuple(iterable) + generators = [unique_everseen(enumerate(pool), key=itemgetter(1))] + current_combo = [None] * r + level = 0 + while generators: + try: + cur_idx, p = next(generators[-1]) + except StopIteration: + generators.pop() + level -= 1 + continue + current_combo[level] = p + if level + 1 == r: + yield tuple(current_combo) + else: + generators.append( + unique_everseen( + enumerate(pool[cur_idx + 1 :], cur_idx + 1), + key=itemgetter(1), + ) + ) + level += 1 + + +def filter_except(validator, iterable, *exceptions): + """Yield the items from *iterable* for which the *validator* function does + not raise one of the specified *exceptions*. + + *validator* is called for each item in *iterable*. + It should be a function that accepts one argument and raises an exception + if that item is not valid. + + >>> iterable = ['1', '2', 'three', '4', None] + >>> list(filter_except(int, iterable, ValueError, TypeError)) + ['1', '2', '4'] + + If an exception other than one given by *exceptions* is raised by + *validator*, it is raised like normal. + """ + for item in iterable: + try: + validator(item) + except exceptions: + pass + else: + yield item + + +def map_except(function, iterable, *exceptions): + """Transform each item from *iterable* with *function* and yield the + result, unless *function* raises one of the specified *exceptions*. + + *function* is called to transform each item in *iterable*. + It should be a accept one argument. + + >>> iterable = ['1', '2', 'three', '4', None] + >>> list(map_except(int, iterable, ValueError, TypeError)) + [1, 2, 4] + + If an exception other than one given by *exceptions* is raised by + *function*, it is raised like normal. + """ + for item in iterable: + try: + yield function(item) + except exceptions: + pass + + +def _sample_unweighted(iterable, k): + # Implementation of "Algorithm L" from the 1994 paper by Kim-Hung Li: + # "Reservoir-Sampling Algorithms of Time Complexity O(n(1+log(N/n)))". + + # Fill up the reservoir (collection of samples) with the first `k` samples + reservoir = take(k, iterable) + + # Generate random number that's the largest in a sample of k U(0,1) numbers + # Largest order statistic: https://en.wikipedia.org/wiki/Order_statistic + W = exp(log(random()) / k) + + # The number of elements to skip before changing the reservoir is a random + # number with a geometric distribution. Sample it using random() and logs. + next_index = k + floor(log(random()) / log(1 - W)) + + for index, element in enumerate(iterable, k): + + if index == next_index: + reservoir[randrange(k)] = element + # The new W is the largest in a sample of k U(0, `old_W`) numbers + W *= exp(log(random()) / k) + next_index += floor(log(random()) / log(1 - W)) + 1 + + return reservoir + + +def _sample_weighted(iterable, k, weights): + # Implementation of "A-ExpJ" from the 2006 paper by Efraimidis et al. : + # "Weighted random sampling with a reservoir". + + # Log-transform for numerical stability for weights that are small/large + weight_keys = (log(random()) / weight for weight in weights) + + # Fill up the reservoir (collection of samples) with the first `k` + # weight-keys and elements, then heapify the list. + reservoir = take(k, zip(weight_keys, iterable)) + heapify(reservoir) + + # The number of jumps before changing the reservoir is a random variable + # with an exponential distribution. Sample it using random() and logs. + smallest_weight_key, _ = reservoir[0] + weights_to_skip = log(random()) / smallest_weight_key + + for weight, element in zip(weights, iterable): + if weight >= weights_to_skip: + # The notation here is consistent with the paper, but we store + # the weight-keys in log-space for better numerical stability. + smallest_weight_key, _ = reservoir[0] + t_w = exp(weight * smallest_weight_key) + r_2 = uniform(t_w, 1) # generate U(t_w, 1) + weight_key = log(r_2) / weight + heapreplace(reservoir, (weight_key, element)) + smallest_weight_key, _ = reservoir[0] + weights_to_skip = log(random()) / smallest_weight_key + else: + weights_to_skip -= weight + + # Equivalent to [element for weight_key, element in sorted(reservoir)] + return [heappop(reservoir)[1] for _ in range(k)] + + +def sample(iterable, k, weights=None): + """Return a *k*-length list of elements chosen (without replacement) + from the *iterable*. Like :func:`random.sample`, but works on iterables + of unknown length. + + >>> iterable = range(100) + >>> sample(iterable, 5) # doctest: +SKIP + [81, 60, 96, 16, 4] + + An iterable with *weights* may also be given: + + >>> iterable = range(100) + >>> weights = (i * i + 1 for i in range(100)) + >>> sampled = sample(iterable, 5, weights=weights) # doctest: +SKIP + [79, 67, 74, 66, 78] + + The algorithm can also be used to generate weighted random permutations. + The relative weight of each item determines the probability that it + appears late in the permutation. + + >>> data = "abcdefgh" + >>> weights = range(1, len(data) + 1) + >>> sample(data, k=len(data), weights=weights) # doctest: +SKIP + ['c', 'a', 'b', 'e', 'g', 'd', 'h', 'f'] + """ + if k == 0: + return [] + + iterable = iter(iterable) + if weights is None: + return _sample_unweighted(iterable, k) + else: + weights = iter(weights) + return _sample_weighted(iterable, k, weights) + + +def is_sorted(iterable, key=None, reverse=False): + """Returns ``True`` if the items of iterable are in sorted order, and + ``False`` otherwise. *key* and *reverse* have the same meaning that they do + in the built-in :func:`sorted` function. + + >>> is_sorted(['1', '2', '3', '4', '5'], key=int) + True + >>> is_sorted([5, 4, 3, 1, 2], reverse=True) + False + + The function returns ``False`` after encountering the first out-of-order + item. If there are no out-of-order items, the iterable is exhausted. + """ + + compare = lt if reverse else gt + it = iterable if (key is None) else map(key, iterable) + return not any(starmap(compare, pairwise(it))) + + +class AbortThread(BaseException): + pass + + +class callback_iter: + """Convert a function that uses callbacks to an iterator. + + Let *func* be a function that takes a `callback` keyword argument. + For example: + + >>> def func(callback=None): + ... for i, c in [(1, 'a'), (2, 'b'), (3, 'c')]: + ... if callback: + ... callback(i, c) + ... return 4 + + + Use ``with callback_iter(func)`` to get an iterator over the parameters + that are delivered to the callback. + + >>> with callback_iter(func) as it: + ... for args, kwargs in it: + ... print(args) + (1, 'a') + (2, 'b') + (3, 'c') + + The function will be called in a background thread. The ``done`` property + indicates whether it has completed execution. + + >>> it.done + True + + If it completes successfully, its return value will be available + in the ``result`` property. + + >>> it.result + 4 + + Notes: + + * If the function uses some keyword argument besides ``callback``, supply + *callback_kwd*. + * If it finished executing, but raised an exception, accessing the + ``result`` property will raise the same exception. + * If it hasn't finished executing, accessing the ``result`` + property from within the ``with`` block will raise ``RuntimeError``. + * If it hasn't finished executing, accessing the ``result`` property from + outside the ``with`` block will raise a + ``more_itertools.AbortThread`` exception. + * Provide *wait_seconds* to adjust how frequently the it is polled for + output. + + """ + + def __init__(self, func, callback_kwd='callback', wait_seconds=0.1): + self._func = func + self._callback_kwd = callback_kwd + self._aborted = False + self._future = None + self._wait_seconds = wait_seconds + self._executor = ThreadPoolExecutor(max_workers=1) + self._iterator = self._reader() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self._aborted = True + self._executor.shutdown() + + def __iter__(self): + return self + + def __next__(self): + return next(self._iterator) + + @property + def done(self): + if self._future is None: + return False + return self._future.done() + + @property + def result(self): + if not self.done: + raise RuntimeError('Function has not yet completed') + + return self._future.result() + + def _reader(self): + q = Queue() + + def callback(*args, **kwargs): + if self._aborted: + raise AbortThread('canceled by user') + + q.put((args, kwargs)) + + self._future = self._executor.submit( + self._func, **{self._callback_kwd: callback} + ) + + while True: + try: + item = q.get(timeout=self._wait_seconds) + except Empty: + pass + else: + q.task_done() + yield item + + if self._future.done(): + break + + remaining = [] + while True: + try: + item = q.get_nowait() + except Empty: + break + else: + q.task_done() + remaining.append(item) + q.join() + yield from remaining + + +def windowed_complete(iterable, n): + """ + Yield ``(beginning, middle, end)`` tuples, where: + + * Each ``middle`` has *n* items from *iterable* + * Each ``beginning`` has the items before the ones in ``middle`` + * Each ``end`` has the items after the ones in ``middle`` + + >>> iterable = range(7) + >>> n = 3 + >>> for beginning, middle, end in windowed_complete(iterable, n): + ... print(beginning, middle, end) + () (0, 1, 2) (3, 4, 5, 6) + (0,) (1, 2, 3) (4, 5, 6) + (0, 1) (2, 3, 4) (5, 6) + (0, 1, 2) (3, 4, 5) (6,) + (0, 1, 2, 3) (4, 5, 6) () + + Note that *n* must be at least 0 and most equal to the length of + *iterable*. + + This function will exhaust the iterable and may require significant + storage. + """ + if n < 0: + raise ValueError('n must be >= 0') + + seq = tuple(iterable) + size = len(seq) + + if n > size: + raise ValueError('n must be <= len(seq)') + + for i in range(size - n + 1): + beginning = seq[:i] + middle = seq[i : i + n] + end = seq[i + n :] + yield beginning, middle, end + + +def all_unique(iterable, key=None): + """ + Returns ``True`` if all the elements of *iterable* are unique (no two + elements are equal). + + >>> all_unique('ABCB') + False + + If a *key* function is specified, it will be used to make comparisons. + + >>> all_unique('ABCb') + True + >>> all_unique('ABCb', str.lower) + False + + The function returns as soon as the first non-unique element is + encountered. Iterables with a mix of hashable and unhashable items can + be used, but the function will be slower for unhashable items. + """ + seenset = set() + seenset_add = seenset.add + seenlist = [] + seenlist_add = seenlist.append + for element in map(key, iterable) if key else iterable: + try: + if element in seenset: + return False + seenset_add(element) + except TypeError: + if element in seenlist: + return False + seenlist_add(element) + return True + + +def nth_product(index, *args): + """Equivalent to ``list(product(*args))[index]``. + + The products of *args* can be ordered lexicographically. + :func:`nth_product` computes the product at sort position *index* without + computing the previous products. + + >>> nth_product(8, range(2), range(2), range(2), range(2)) + (1, 0, 0, 0) + + ``IndexError`` will be raised if the given *index* is invalid. + """ + pools = list(map(tuple, reversed(args))) + ns = list(map(len, pools)) + + c = reduce(mul, ns) + + if index < 0: + index += c + + if not 0 <= index < c: + raise IndexError + + result = [] + for pool, n in zip(pools, ns): + result.append(pool[index % n]) + index //= n + + return tuple(reversed(result)) + + +def nth_permutation(iterable, r, index): + """Equivalent to ``list(permutations(iterable, r))[index]``` + + The subsequences of *iterable* that are of length *r* where order is + important can be ordered lexicographically. :func:`nth_permutation` + computes the subsequence at sort position *index* directly, without + computing the previous subsequences. + + >>> nth_permutation('ghijk', 2, 5) + ('h', 'i') + + ``ValueError`` will be raised If *r* is negative or greater than the length + of *iterable*. + ``IndexError`` will be raised if the given *index* is invalid. + """ + pool = list(iterable) + n = len(pool) + + if r is None or r == n: + r, c = n, factorial(n) + elif not 0 <= r < n: + raise ValueError + else: + c = factorial(n) // factorial(n - r) + + if index < 0: + index += c + + if not 0 <= index < c: + raise IndexError + + if c == 0: + return tuple() + + result = [0] * r + q = index * factorial(n) // c if r < n else index + for d in range(1, n + 1): + q, i = divmod(q, d) + if 0 <= n - d < r: + result[n - d] = i + if q == 0: + break + + return tuple(map(pool.pop, result)) + + +def value_chain(*args): + """Yield all arguments passed to the function in the same order in which + they were passed. If an argument itself is iterable then iterate over its + values. + + >>> list(value_chain(1, 2, 3, [4, 5, 6])) + [1, 2, 3, 4, 5, 6] + + Binary and text strings are not considered iterable and are emitted + as-is: + + >>> list(value_chain('12', '34', ['56', '78'])) + ['12', '34', '56', '78'] + + + Multiple levels of nesting are not flattened. + + """ + for value in args: + if isinstance(value, (str, bytes)): + yield value + continue + try: + yield from value + except TypeError: + yield value + + +def product_index(element, *args): + """Equivalent to ``list(product(*args)).index(element)`` + + The products of *args* can be ordered lexicographically. + :func:`product_index` computes the first index of *element* without + computing the previous products. + + >>> product_index([8, 2], range(10), range(5)) + 42 + + ``ValueError`` will be raised if the given *element* isn't in the product + of *args*. + """ + index = 0 + + for x, pool in zip_longest(element, args, fillvalue=_marker): + if x is _marker or pool is _marker: + raise ValueError('element is not a product of args') + + pool = tuple(pool) + index = index * len(pool) + pool.index(x) + + return index + + +def combination_index(element, iterable): + """Equivalent to ``list(combinations(iterable, r)).index(element)`` + + The subsequences of *iterable* that are of length *r* can be ordered + lexicographically. :func:`combination_index` computes the index of the + first *element*, without computing the previous combinations. + + >>> combination_index('adf', 'abcdefg') + 10 + + ``ValueError`` will be raised if the given *element* isn't one of the + combinations of *iterable*. + """ + element = enumerate(element) + k, y = next(element, (None, None)) + if k is None: + return 0 + + indexes = [] + pool = enumerate(iterable) + for n, x in pool: + if x == y: + indexes.append(n) + tmp, y = next(element, (None, None)) + if tmp is None: + break + else: + k = tmp + else: + raise ValueError('element is not a combination of iterable') + + n, _ = last(pool, default=(n, None)) + + # Python versiosn below 3.8 don't have math.comb + index = 1 + for i, j in enumerate(reversed(indexes), start=1): + j = n - j + if i <= j: + index += factorial(j) // (factorial(i) * factorial(j - i)) + + return factorial(n + 1) // (factorial(k + 1) * factorial(n - k)) - index + + +def permutation_index(element, iterable): + """Equivalent to ``list(permutations(iterable, r)).index(element)``` + + The subsequences of *iterable* that are of length *r* where order is + important can be ordered lexicographically. :func:`permutation_index` + computes the index of the first *element* directly, without computing + the previous permutations. + + >>> permutation_index([1, 3, 2], range(5)) + 19 + + ``ValueError`` will be raised if the given *element* isn't one of the + permutations of *iterable*. + """ + index = 0 + pool = list(iterable) + for i, x in zip(range(len(pool), -1, -1), element): + r = pool.index(x) + index = index * i + r + del pool[r] + + return index + + +class countable: + """Wrap *iterable* and keep a count of how many items have been consumed. + + The ``items_seen`` attribute starts at ``0`` and increments as the iterable + is consumed: + + >>> iterable = map(str, range(10)) + >>> it = countable(iterable) + >>> it.items_seen + 0 + >>> next(it), next(it) + ('0', '1') + >>> list(it) + ['2', '3', '4', '5', '6', '7', '8', '9'] + >>> it.items_seen + 10 + """ + + def __init__(self, iterable): + self._it = iter(iterable) + self.items_seen = 0 + + def __iter__(self): + return self + + def __next__(self): + item = next(self._it) + self.items_seen += 1 + + return item diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/recipes.py b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/recipes.py new file mode 100644 index 0000000000000000000000000000000000000000..521abd7c2ca633f90a5ba13a8060c5c3d0c32205 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/more_itertools/recipes.py @@ -0,0 +1,620 @@ +"""Imported from the recipes section of the itertools documentation. + +All functions taken from the recipes section of the itertools library docs +[1]_. +Some backward-compatible usability improvements have been made. + +.. [1] http://docs.python.org/library/itertools.html#recipes + +""" +import warnings +from collections import deque +from itertools import ( + chain, + combinations, + count, + cycle, + groupby, + islice, + repeat, + starmap, + tee, + zip_longest, +) +import operator +from random import randrange, sample, choice + +__all__ = [ + 'all_equal', + 'consume', + 'convolve', + 'dotproduct', + 'first_true', + 'flatten', + 'grouper', + 'iter_except', + 'ncycles', + 'nth', + 'nth_combination', + 'padnone', + 'pad_none', + 'pairwise', + 'partition', + 'powerset', + 'prepend', + 'quantify', + 'random_combination_with_replacement', + 'random_combination', + 'random_permutation', + 'random_product', + 'repeatfunc', + 'roundrobin', + 'tabulate', + 'tail', + 'take', + 'unique_everseen', + 'unique_justseen', +] + + +def take(n, iterable): + """Return first *n* items of the iterable as a list. + + >>> take(3, range(10)) + [0, 1, 2] + + If there are fewer than *n* items in the iterable, all of them are + returned. + + >>> take(10, range(3)) + [0, 1, 2] + + """ + return list(islice(iterable, n)) + + +def tabulate(function, start=0): + """Return an iterator over the results of ``func(start)``, + ``func(start + 1)``, ``func(start + 2)``... + + *func* should be a function that accepts one integer argument. + + If *start* is not specified it defaults to 0. It will be incremented each + time the iterator is advanced. + + >>> square = lambda x: x ** 2 + >>> iterator = tabulate(square, -3) + >>> take(4, iterator) + [9, 4, 1, 0] + + """ + return map(function, count(start)) + + +def tail(n, iterable): + """Return an iterator over the last *n* items of *iterable*. + + >>> t = tail(3, 'ABCDEFG') + >>> list(t) + ['E', 'F', 'G'] + + """ + return iter(deque(iterable, maxlen=n)) + + +def consume(iterator, n=None): + """Advance *iterable* by *n* steps. If *n* is ``None``, consume it + entirely. + + Efficiently exhausts an iterator without returning values. Defaults to + consuming the whole iterator, but an optional second argument may be + provided to limit consumption. + + >>> i = (x for x in range(10)) + >>> next(i) + 0 + >>> consume(i, 3) + >>> next(i) + 4 + >>> consume(i) + >>> next(i) + Traceback (most recent call last): + File "", line 1, in + StopIteration + + If the iterator has fewer items remaining than the provided limit, the + whole iterator will be consumed. + + >>> i = (x for x in range(3)) + >>> consume(i, 5) + >>> next(i) + Traceback (most recent call last): + File "", line 1, in + StopIteration + + """ + # Use functions that consume iterators at C speed. + if n is None: + # feed the entire iterator into a zero-length deque + deque(iterator, maxlen=0) + else: + # advance to the empty slice starting at position n + next(islice(iterator, n, n), None) + + +def nth(iterable, n, default=None): + """Returns the nth item or a default value. + + >>> l = range(10) + >>> nth(l, 3) + 3 + >>> nth(l, 20, "zebra") + 'zebra' + + """ + return next(islice(iterable, n, None), default) + + +def all_equal(iterable): + """ + Returns ``True`` if all the elements are equal to each other. + + >>> all_equal('aaaa') + True + >>> all_equal('aaab') + False + + """ + g = groupby(iterable) + return next(g, True) and not next(g, False) + + +def quantify(iterable, pred=bool): + """Return the how many times the predicate is true. + + >>> quantify([True, False, True]) + 2 + + """ + return sum(map(pred, iterable)) + + +def pad_none(iterable): + """Returns the sequence of elements and then returns ``None`` indefinitely. + + >>> take(5, pad_none(range(3))) + [0, 1, 2, None, None] + + Useful for emulating the behavior of the built-in :func:`map` function. + + See also :func:`padded`. + + """ + return chain(iterable, repeat(None)) + + +padnone = pad_none + + +def ncycles(iterable, n): + """Returns the sequence elements *n* times + + >>> list(ncycles(["a", "b"], 3)) + ['a', 'b', 'a', 'b', 'a', 'b'] + + """ + return chain.from_iterable(repeat(tuple(iterable), n)) + + +def dotproduct(vec1, vec2): + """Returns the dot product of the two iterables. + + >>> dotproduct([10, 10], [20, 20]) + 400 + + """ + return sum(map(operator.mul, vec1, vec2)) + + +def flatten(listOfLists): + """Return an iterator flattening one level of nesting in a list of lists. + + >>> list(flatten([[0, 1], [2, 3]])) + [0, 1, 2, 3] + + See also :func:`collapse`, which can flatten multiple levels of nesting. + + """ + return chain.from_iterable(listOfLists) + + +def repeatfunc(func, times=None, *args): + """Call *func* with *args* repeatedly, returning an iterable over the + results. + + If *times* is specified, the iterable will terminate after that many + repetitions: + + >>> from operator import add + >>> times = 4 + >>> args = 3, 5 + >>> list(repeatfunc(add, times, *args)) + [8, 8, 8, 8] + + If *times* is ``None`` the iterable will not terminate: + + >>> from random import randrange + >>> times = None + >>> args = 1, 11 + >>> take(6, repeatfunc(randrange, times, *args)) # doctest:+SKIP + [2, 4, 8, 1, 8, 4] + + """ + if times is None: + return starmap(func, repeat(args)) + return starmap(func, repeat(args, times)) + + +def _pairwise(iterable): + """Returns an iterator of paired items, overlapping, from the original + + >>> take(4, pairwise(count())) + [(0, 1), (1, 2), (2, 3), (3, 4)] + + On Python 3.10 and above, this is an alias for :func:`itertools.pairwise`. + + """ + a, b = tee(iterable) + next(b, None) + yield from zip(a, b) + + +try: + from itertools import pairwise as itertools_pairwise +except ImportError: + pairwise = _pairwise +else: + + def pairwise(iterable): + yield from itertools_pairwise(iterable) + + pairwise.__doc__ = _pairwise.__doc__ + + +def grouper(iterable, n, fillvalue=None): + """Collect data into fixed-length chunks or blocks. + + >>> list(grouper('ABCDEFG', 3, 'x')) + [('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')] + + """ + if isinstance(iterable, int): + warnings.warn( + "grouper expects iterable as first parameter", DeprecationWarning + ) + n, iterable = iterable, n + args = [iter(iterable)] * n + return zip_longest(fillvalue=fillvalue, *args) + + +def roundrobin(*iterables): + """Yields an item from each iterable, alternating between them. + + >>> list(roundrobin('ABC', 'D', 'EF')) + ['A', 'D', 'E', 'B', 'F', 'C'] + + This function produces the same output as :func:`interleave_longest`, but + may perform better for some inputs (in particular when the number of + iterables is small). + + """ + # Recipe credited to George Sakkis + pending = len(iterables) + nexts = cycle(iter(it).__next__ for it in iterables) + while pending: + try: + for next in nexts: + yield next() + except StopIteration: + pending -= 1 + nexts = cycle(islice(nexts, pending)) + + +def partition(pred, iterable): + """ + Returns a 2-tuple of iterables derived from the input iterable. + The first yields the items that have ``pred(item) == False``. + The second yields the items that have ``pred(item) == True``. + + >>> is_odd = lambda x: x % 2 != 0 + >>> iterable = range(10) + >>> even_items, odd_items = partition(is_odd, iterable) + >>> list(even_items), list(odd_items) + ([0, 2, 4, 6, 8], [1, 3, 5, 7, 9]) + + If *pred* is None, :func:`bool` is used. + + >>> iterable = [0, 1, False, True, '', ' '] + >>> false_items, true_items = partition(None, iterable) + >>> list(false_items), list(true_items) + ([0, False, ''], [1, True, ' ']) + + """ + if pred is None: + pred = bool + + evaluations = ((pred(x), x) for x in iterable) + t1, t2 = tee(evaluations) + return ( + (x for (cond, x) in t1 if not cond), + (x for (cond, x) in t2 if cond), + ) + + +def powerset(iterable): + """Yields all possible subsets of the iterable. + + >>> list(powerset([1, 2, 3])) + [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)] + + :func:`powerset` will operate on iterables that aren't :class:`set` + instances, so repeated elements in the input will produce repeated elements + in the output. Use :func:`unique_everseen` on the input to avoid generating + duplicates: + + >>> seq = [1, 1, 0] + >>> list(powerset(seq)) + [(), (1,), (1,), (0,), (1, 1), (1, 0), (1, 0), (1, 1, 0)] + >>> from more_itertools import unique_everseen + >>> list(powerset(unique_everseen(seq))) + [(), (1,), (0,), (1, 0)] + + """ + s = list(iterable) + return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1)) + + +def unique_everseen(iterable, key=None): + """ + Yield unique elements, preserving order. + + >>> list(unique_everseen('AAAABBBCCDAABBB')) + ['A', 'B', 'C', 'D'] + >>> list(unique_everseen('ABBCcAD', str.lower)) + ['A', 'B', 'C', 'D'] + + Sequences with a mix of hashable and unhashable items can be used. + The function will be slower (i.e., `O(n^2)`) for unhashable items. + + Remember that ``list`` objects are unhashable - you can use the *key* + parameter to transform the list to a tuple (which is hashable) to + avoid a slowdown. + + >>> iterable = ([1, 2], [2, 3], [1, 2]) + >>> list(unique_everseen(iterable)) # Slow + [[1, 2], [2, 3]] + >>> list(unique_everseen(iterable, key=tuple)) # Faster + [[1, 2], [2, 3]] + + Similary, you may want to convert unhashable ``set`` objects with + ``key=frozenset``. For ``dict`` objects, + ``key=lambda x: frozenset(x.items())`` can be used. + + """ + seenset = set() + seenset_add = seenset.add + seenlist = [] + seenlist_add = seenlist.append + use_key = key is not None + + for element in iterable: + k = key(element) if use_key else element + try: + if k not in seenset: + seenset_add(k) + yield element + except TypeError: + if k not in seenlist: + seenlist_add(k) + yield element + + +def unique_justseen(iterable, key=None): + """Yields elements in order, ignoring serial duplicates + + >>> list(unique_justseen('AAAABBBCCDAABBB')) + ['A', 'B', 'C', 'D', 'A', 'B'] + >>> list(unique_justseen('ABBCcAD', str.lower)) + ['A', 'B', 'C', 'A', 'D'] + + """ + return map(next, map(operator.itemgetter(1), groupby(iterable, key))) + + +def iter_except(func, exception, first=None): + """Yields results from a function repeatedly until an exception is raised. + + Converts a call-until-exception interface to an iterator interface. + Like ``iter(func, sentinel)``, but uses an exception instead of a sentinel + to end the loop. + + >>> l = [0, 1, 2] + >>> list(iter_except(l.pop, IndexError)) + [2, 1, 0] + + """ + try: + if first is not None: + yield first() + while 1: + yield func() + except exception: + pass + + +def first_true(iterable, default=None, pred=None): + """ + Returns the first true value in the iterable. + + If no true value is found, returns *default* + + If *pred* is not None, returns the first item for which + ``pred(item) == True`` . + + >>> first_true(range(10)) + 1 + >>> first_true(range(10), pred=lambda x: x > 5) + 6 + >>> first_true(range(10), default='missing', pred=lambda x: x > 9) + 'missing' + + """ + return next(filter(pred, iterable), default) + + +def random_product(*args, repeat=1): + """Draw an item at random from each of the input iterables. + + >>> random_product('abc', range(4), 'XYZ') # doctest:+SKIP + ('c', 3, 'Z') + + If *repeat* is provided as a keyword argument, that many items will be + drawn from each iterable. + + >>> random_product('abcd', range(4), repeat=2) # doctest:+SKIP + ('a', 2, 'd', 3) + + This equivalent to taking a random selection from + ``itertools.product(*args, **kwarg)``. + + """ + pools = [tuple(pool) for pool in args] * repeat + return tuple(choice(pool) for pool in pools) + + +def random_permutation(iterable, r=None): + """Return a random *r* length permutation of the elements in *iterable*. + + If *r* is not specified or is ``None``, then *r* defaults to the length of + *iterable*. + + >>> random_permutation(range(5)) # doctest:+SKIP + (3, 4, 0, 1, 2) + + This equivalent to taking a random selection from + ``itertools.permutations(iterable, r)``. + + """ + pool = tuple(iterable) + r = len(pool) if r is None else r + return tuple(sample(pool, r)) + + +def random_combination(iterable, r): + """Return a random *r* length subsequence of the elements in *iterable*. + + >>> random_combination(range(5), 3) # doctest:+SKIP + (2, 3, 4) + + This equivalent to taking a random selection from + ``itertools.combinations(iterable, r)``. + + """ + pool = tuple(iterable) + n = len(pool) + indices = sorted(sample(range(n), r)) + return tuple(pool[i] for i in indices) + + +def random_combination_with_replacement(iterable, r): + """Return a random *r* length subsequence of elements in *iterable*, + allowing individual elements to be repeated. + + >>> random_combination_with_replacement(range(3), 5) # doctest:+SKIP + (0, 0, 1, 2, 2) + + This equivalent to taking a random selection from + ``itertools.combinations_with_replacement(iterable, r)``. + + """ + pool = tuple(iterable) + n = len(pool) + indices = sorted(randrange(n) for i in range(r)) + return tuple(pool[i] for i in indices) + + +def nth_combination(iterable, r, index): + """Equivalent to ``list(combinations(iterable, r))[index]``. + + The subsequences of *iterable* that are of length *r* can be ordered + lexicographically. :func:`nth_combination` computes the subsequence at + sort position *index* directly, without computing the previous + subsequences. + + >>> nth_combination(range(5), 3, 5) + (0, 3, 4) + + ``ValueError`` will be raised If *r* is negative or greater than the length + of *iterable*. + ``IndexError`` will be raised if the given *index* is invalid. + """ + pool = tuple(iterable) + n = len(pool) + if (r < 0) or (r > n): + raise ValueError + + c = 1 + k = min(r, n - r) + for i in range(1, k + 1): + c = c * (n - k + i) // i + + if index < 0: + index += c + + if (index < 0) or (index >= c): + raise IndexError + + result = [] + while r: + c, n, r = c * r // n, n - 1, r - 1 + while index >= c: + index -= c + c, n = c * (n - r) // n, n - 1 + result.append(pool[-1 - n]) + + return tuple(result) + + +def prepend(value, iterator): + """Yield *value*, followed by the elements in *iterator*. + + >>> value = '0' + >>> iterator = ['1', '2', '3'] + >>> list(prepend(value, iterator)) + ['0', '1', '2', '3'] + + To prepend multiple values, see :func:`itertools.chain` + or :func:`value_chain`. + + """ + return chain([value], iterator) + + +def convolve(signal, kernel): + """Convolve the iterable *signal* with the iterable *kernel*. + + >>> signal = (1, 2, 3, 4, 5) + >>> kernel = [3, 2, 1] + >>> list(convolve(signal, kernel)) + [3, 8, 14, 20, 26, 14, 5] + + Note: the input arguments are not interchangeable, as the *kernel* + is immediately consumed and stored. + + """ + kernel = tuple(kernel)[::-1] + n = len(kernel) + window = deque([0], maxlen=n) * n + for x in chain(signal, repeat(0, n - 1)): + window.append(x) + yield sum(map(operator.mul, kernel, window)) diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/ordered_set.py b/MLPY/Lib/site-packages/setuptools/_vendor/ordered_set.py new file mode 100644 index 0000000000000000000000000000000000000000..14876000de895a609d5b9f3de39c3c8fc44ef1fc --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/ordered_set.py @@ -0,0 +1,488 @@ +""" +An OrderedSet is a custom MutableSet that remembers its order, so that every +entry has an index that can be looked up. + +Based on a recipe originally posted to ActiveState Recipes by Raymond Hettiger, +and released under the MIT license. +""" +import itertools as it +from collections import deque + +try: + # Python 3 + from collections.abc import MutableSet, Sequence +except ImportError: + # Python 2.7 + from collections import MutableSet, Sequence + +SLICE_ALL = slice(None) +__version__ = "3.1" + + +def is_iterable(obj): + """ + Are we being asked to look up a list of things, instead of a single thing? + We check for the `__iter__` attribute so that this can cover types that + don't have to be known by this module, such as NumPy arrays. + + Strings, however, should be considered as atomic values to look up, not + iterables. The same goes for tuples, since they are immutable and therefore + valid entries. + + We don't need to check for the Python 2 `unicode` type, because it doesn't + have an `__iter__` attribute anyway. + """ + return ( + hasattr(obj, "__iter__") + and not isinstance(obj, str) + and not isinstance(obj, tuple) + ) + + +class OrderedSet(MutableSet, Sequence): + """ + An OrderedSet is a custom MutableSet that remembers its order, so that + every entry has an index that can be looked up. + + Example: + >>> OrderedSet([1, 1, 2, 3, 2]) + OrderedSet([1, 2, 3]) + """ + + def __init__(self, iterable=None): + self.items = [] + self.map = {} + if iterable is not None: + self |= iterable + + def __len__(self): + """ + Returns the number of unique elements in the ordered set + + Example: + >>> len(OrderedSet([])) + 0 + >>> len(OrderedSet([1, 2])) + 2 + """ + return len(self.items) + + def __getitem__(self, index): + """ + Get the item at a given index. + + If `index` is a slice, you will get back that slice of items, as a + new OrderedSet. + + If `index` is a list or a similar iterable, you'll get a list of + items corresponding to those indices. This is similar to NumPy's + "fancy indexing". The result is not an OrderedSet because you may ask + for duplicate indices, and the number of elements returned should be + the number of elements asked for. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset[1] + 2 + """ + if isinstance(index, slice) and index == SLICE_ALL: + return self.copy() + elif is_iterable(index): + return [self.items[i] for i in index] + elif hasattr(index, "__index__") or isinstance(index, slice): + result = self.items[index] + if isinstance(result, list): + return self.__class__(result) + else: + return result + else: + raise TypeError("Don't know how to index an OrderedSet by %r" % index) + + def copy(self): + """ + Return a shallow copy of this object. + + Example: + >>> this = OrderedSet([1, 2, 3]) + >>> other = this.copy() + >>> this == other + True + >>> this is other + False + """ + return self.__class__(self) + + def __getstate__(self): + if len(self) == 0: + # The state can't be an empty list. + # We need to return a truthy value, or else __setstate__ won't be run. + # + # This could have been done more gracefully by always putting the state + # in a tuple, but this way is backwards- and forwards- compatible with + # previous versions of OrderedSet. + return (None,) + else: + return list(self) + + def __setstate__(self, state): + if state == (None,): + self.__init__([]) + else: + self.__init__(state) + + def __contains__(self, key): + """ + Test if the item is in this ordered set + + Example: + >>> 1 in OrderedSet([1, 3, 2]) + True + >>> 5 in OrderedSet([1, 3, 2]) + False + """ + return key in self.map + + def add(self, key): + """ + Add `key` as an item to this OrderedSet, then return its index. + + If `key` is already in the OrderedSet, return the index it already + had. + + Example: + >>> oset = OrderedSet() + >>> oset.append(3) + 0 + >>> print(oset) + OrderedSet([3]) + """ + if key not in self.map: + self.map[key] = len(self.items) + self.items.append(key) + return self.map[key] + + append = add + + def update(self, sequence): + """ + Update the set with the given iterable sequence, then return the index + of the last element inserted. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.update([3, 1, 5, 1, 4]) + 4 + >>> print(oset) + OrderedSet([1, 2, 3, 5, 4]) + """ + item_index = None + try: + for item in sequence: + item_index = self.add(item) + except TypeError: + raise ValueError( + "Argument needs to be an iterable, got %s" % type(sequence) + ) + return item_index + + def index(self, key): + """ + Get the index of a given entry, raising an IndexError if it's not + present. + + `key` can be an iterable of entries that is not a string, in which case + this returns a list of indices. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.index(2) + 1 + """ + if is_iterable(key): + return [self.index(subkey) for subkey in key] + return self.map[key] + + # Provide some compatibility with pd.Index + get_loc = index + get_indexer = index + + def pop(self): + """ + Remove and return the last element from the set. + + Raises KeyError if the set is empty. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.pop() + 3 + """ + if not self.items: + raise KeyError("Set is empty") + + elem = self.items[-1] + del self.items[-1] + del self.map[elem] + return elem + + def discard(self, key): + """ + Remove an element. Do not raise an exception if absent. + + The MutableSet mixin uses this to implement the .remove() method, which + *does* raise an error when asked to remove a non-existent item. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.discard(2) + >>> print(oset) + OrderedSet([1, 3]) + >>> oset.discard(2) + >>> print(oset) + OrderedSet([1, 3]) + """ + if key in self: + i = self.map[key] + del self.items[i] + del self.map[key] + for k, v in self.map.items(): + if v >= i: + self.map[k] = v - 1 + + def clear(self): + """ + Remove all items from this OrderedSet. + """ + del self.items[:] + self.map.clear() + + def __iter__(self): + """ + Example: + >>> list(iter(OrderedSet([1, 2, 3]))) + [1, 2, 3] + """ + return iter(self.items) + + def __reversed__(self): + """ + Example: + >>> list(reversed(OrderedSet([1, 2, 3]))) + [3, 2, 1] + """ + return reversed(self.items) + + def __repr__(self): + if not self: + return "%s()" % (self.__class__.__name__,) + return "%s(%r)" % (self.__class__.__name__, list(self)) + + def __eq__(self, other): + """ + Returns true if the containers have the same items. If `other` is a + Sequence, then order is checked, otherwise it is ignored. + + Example: + >>> oset = OrderedSet([1, 3, 2]) + >>> oset == [1, 3, 2] + True + >>> oset == [1, 2, 3] + False + >>> oset == [2, 3] + False + >>> oset == OrderedSet([3, 2, 1]) + False + """ + # In Python 2 deque is not a Sequence, so treat it as one for + # consistent behavior with Python 3. + if isinstance(other, (Sequence, deque)): + # Check that this OrderedSet contains the same elements, in the + # same order, as the other object. + return list(self) == list(other) + try: + other_as_set = set(other) + except TypeError: + # If `other` can't be converted into a set, it's not equal. + return False + else: + return set(self) == other_as_set + + def union(self, *sets): + """ + Combines all unique items. + Each items order is defined by its first appearance. + + Example: + >>> oset = OrderedSet.union(OrderedSet([3, 1, 4, 1, 5]), [1, 3], [2, 0]) + >>> print(oset) + OrderedSet([3, 1, 4, 5, 2, 0]) + >>> oset.union([8, 9]) + OrderedSet([3, 1, 4, 5, 2, 0, 8, 9]) + >>> oset | {10} + OrderedSet([3, 1, 4, 5, 2, 0, 10]) + """ + cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet + containers = map(list, it.chain([self], sets)) + items = it.chain.from_iterable(containers) + return cls(items) + + def __and__(self, other): + # the parent implementation of this is backwards + return self.intersection(other) + + def intersection(self, *sets): + """ + Returns elements in common between all sets. Order is defined only + by the first set. + + Example: + >>> oset = OrderedSet.intersection(OrderedSet([0, 1, 2, 3]), [1, 2, 3]) + >>> print(oset) + OrderedSet([1, 2, 3]) + >>> oset.intersection([2, 4, 5], [1, 2, 3, 4]) + OrderedSet([2]) + >>> oset.intersection() + OrderedSet([1, 2, 3]) + """ + cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet + if sets: + common = set.intersection(*map(set, sets)) + items = (item for item in self if item in common) + else: + items = self + return cls(items) + + def difference(self, *sets): + """ + Returns all elements that are in this set but not the others. + + Example: + >>> OrderedSet([1, 2, 3]).difference(OrderedSet([2])) + OrderedSet([1, 3]) + >>> OrderedSet([1, 2, 3]).difference(OrderedSet([2]), OrderedSet([3])) + OrderedSet([1]) + >>> OrderedSet([1, 2, 3]) - OrderedSet([2]) + OrderedSet([1, 3]) + >>> OrderedSet([1, 2, 3]).difference() + OrderedSet([1, 2, 3]) + """ + cls = self.__class__ + if sets: + other = set.union(*map(set, sets)) + items = (item for item in self if item not in other) + else: + items = self + return cls(items) + + def issubset(self, other): + """ + Report whether another set contains this set. + + Example: + >>> OrderedSet([1, 2, 3]).issubset({1, 2}) + False + >>> OrderedSet([1, 2, 3]).issubset({1, 2, 3, 4}) + True + >>> OrderedSet([1, 2, 3]).issubset({1, 4, 3, 5}) + False + """ + if len(self) > len(other): # Fast check for obvious cases + return False + return all(item in other for item in self) + + def issuperset(self, other): + """ + Report whether this set contains another set. + + Example: + >>> OrderedSet([1, 2]).issuperset([1, 2, 3]) + False + >>> OrderedSet([1, 2, 3, 4]).issuperset({1, 2, 3}) + True + >>> OrderedSet([1, 4, 3, 5]).issuperset({1, 2, 3}) + False + """ + if len(self) < len(other): # Fast check for obvious cases + return False + return all(item in self for item in other) + + def symmetric_difference(self, other): + """ + Return the symmetric difference of two OrderedSets as a new set. + That is, the new set will contain all elements that are in exactly + one of the sets. + + Their order will be preserved, with elements from `self` preceding + elements from `other`. + + Example: + >>> this = OrderedSet([1, 4, 3, 5, 7]) + >>> other = OrderedSet([9, 7, 1, 3, 2]) + >>> this.symmetric_difference(other) + OrderedSet([4, 5, 9, 2]) + """ + cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet + diff1 = cls(self).difference(other) + diff2 = cls(other).difference(self) + return diff1.union(diff2) + + def _update_items(self, items): + """ + Replace the 'items' list of this OrderedSet with a new one, updating + self.map accordingly. + """ + self.items = items + self.map = {item: idx for (idx, item) in enumerate(items)} + + def difference_update(self, *sets): + """ + Update this OrderedSet to remove items from one or more other sets. + + Example: + >>> this = OrderedSet([1, 2, 3]) + >>> this.difference_update(OrderedSet([2, 4])) + >>> print(this) + OrderedSet([1, 3]) + + >>> this = OrderedSet([1, 2, 3, 4, 5]) + >>> this.difference_update(OrderedSet([2, 4]), OrderedSet([1, 4, 6])) + >>> print(this) + OrderedSet([3, 5]) + """ + items_to_remove = set() + for other in sets: + items_to_remove |= set(other) + self._update_items([item for item in self.items if item not in items_to_remove]) + + def intersection_update(self, other): + """ + Update this OrderedSet to keep only items in another set, preserving + their order in this set. + + Example: + >>> this = OrderedSet([1, 4, 3, 5, 7]) + >>> other = OrderedSet([9, 7, 1, 3, 2]) + >>> this.intersection_update(other) + >>> print(this) + OrderedSet([1, 3, 7]) + """ + other = set(other) + self._update_items([item for item in self.items if item in other]) + + def symmetric_difference_update(self, other): + """ + Update this OrderedSet to remove items from another set, then + add items from the other set that were not present in this set. + + Example: + >>> this = OrderedSet([1, 4, 3, 5, 7]) + >>> other = OrderedSet([9, 7, 1, 3, 2]) + >>> this.symmetric_difference_update(other) + >>> print(this) + OrderedSet([4, 5, 9, 2]) + """ + items_to_add = [item for item in other if item not in self] + items_to_remove = set(other) + self._update_items( + [item for item in self.items if item not in items_to_remove] + items_to_add + ) diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__about__.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__about__.py new file mode 100644 index 0000000000000000000000000000000000000000..4d998578d7b5d39ae1cd5ce8832e7cd85ed2a1d1 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__about__.py @@ -0,0 +1,27 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", +] + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "20.4" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD-2-Clause or Apache-2.0" +__copyright__ = "Copyright 2014-2019 %s" % __author__ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__init__.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a0cf67df5245be16a020ca048832e180f7ce8661 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__init__.py @@ -0,0 +1,26 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +from .__about__ import ( + __author__, + __copyright__, + __email__, + __license__, + __summary__, + __title__, + __uri__, + __version__, +) + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", +] diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a201cf5604e890852b009f404ef1c0d48c9ceec Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c191391002074757ec54ab9e82f7db920299c1c Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3028882eecf4546f69b554b3ed5dc6713c560ed Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf245bbcbdf44506c41108f7fe08dbe1dead2509 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_typing.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_typing.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19907336b342c738f1cfb4ec106f1c5d7da5f86e Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_typing.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b0fee6595f0be49c6ff3f2331c4ec6cbf5aaa24 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f338fb7f6f5a22c504093bf50f1f83460b82c0d0 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90202a3ec1192746fd14ef493774787adc2d4d48 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3f8c12fbc9da42ec94c69503bf1bdc72df6f686 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04fec2a5fd902a4a8e555cd1435f372b943c0148 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2cd1e4079999f97c79a9a74f9b49c510a3f65826 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_compat.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_compat.py new file mode 100644 index 0000000000000000000000000000000000000000..e54bd4ede8761df5882a3354bc22bdee7a5e8a8b --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_compat.py @@ -0,0 +1,38 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import sys + +from ._typing import TYPE_CHECKING + +if TYPE_CHECKING: # pragma: no cover + from typing import Any, Dict, Tuple, Type + + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +# flake8: noqa + +if PY3: + string_types = (str,) +else: + string_types = (basestring,) + + +def with_metaclass(meta, *bases): + # type: (Type[Any], Tuple[Type[Any], ...]) -> Any + """ + Create a base class with a metaclass. + """ + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): # type: ignore + def __new__(cls, name, this_bases, d): + # type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any + return meta(name, bases, d) + + return type.__new__(metaclass, "temporary_class", (), {}) diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_structures.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_structures.py new file mode 100644 index 0000000000000000000000000000000000000000..800d5c5588c99dc216cdea5084da440efb641945 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_structures.py @@ -0,0 +1,86 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + + +class InfinityType(object): + def __repr__(self): + # type: () -> str + return "Infinity" + + def __hash__(self): + # type: () -> int + return hash(repr(self)) + + def __lt__(self, other): + # type: (object) -> bool + return False + + def __le__(self, other): + # type: (object) -> bool + return False + + def __eq__(self, other): + # type: (object) -> bool + return isinstance(other, self.__class__) + + def __ne__(self, other): + # type: (object) -> bool + return not isinstance(other, self.__class__) + + def __gt__(self, other): + # type: (object) -> bool + return True + + def __ge__(self, other): + # type: (object) -> bool + return True + + def __neg__(self): + # type: (object) -> NegativeInfinityType + return NegativeInfinity + + +Infinity = InfinityType() + + +class NegativeInfinityType(object): + def __repr__(self): + # type: () -> str + return "-Infinity" + + def __hash__(self): + # type: () -> int + return hash(repr(self)) + + def __lt__(self, other): + # type: (object) -> bool + return True + + def __le__(self, other): + # type: (object) -> bool + return True + + def __eq__(self, other): + # type: (object) -> bool + return isinstance(other, self.__class__) + + def __ne__(self, other): + # type: (object) -> bool + return not isinstance(other, self.__class__) + + def __gt__(self, other): + # type: (object) -> bool + return False + + def __ge__(self, other): + # type: (object) -> bool + return False + + def __neg__(self): + # type: (object) -> InfinityType + return Infinity + + +NegativeInfinity = NegativeInfinityType() diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_typing.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_typing.py new file mode 100644 index 0000000000000000000000000000000000000000..77a8b9185a07d0338e652810f48757dfe9e0c90c --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/_typing.py @@ -0,0 +1,48 @@ +"""For neatly implementing static typing in packaging. + +`mypy` - the static type analysis tool we use - uses the `typing` module, which +provides core functionality fundamental to mypy's functioning. + +Generally, `typing` would be imported at runtime and used in that fashion - +it acts as a no-op at runtime and does not have any run-time overhead by +design. + +As it turns out, `typing` is not vendorable - it uses separate sources for +Python 2/Python 3. Thus, this codebase can not expect it to be present. +To work around this, mypy allows the typing import to be behind a False-y +optional to prevent it from running at runtime and type-comments can be used +to remove the need for the types to be accessible directly during runtime. + +This module provides the False-y guard in a nicely named fashion so that a +curious maintainer can reach here to read this. + +In packaging, all static-typing related imports should be guarded as follows: + + from packaging._typing import TYPE_CHECKING + + if TYPE_CHECKING: + from typing import ... + +Ref: https://github.com/python/mypy/issues/3216 +""" + +__all__ = ["TYPE_CHECKING", "cast"] + +# The TYPE_CHECKING constant defined by the typing module is False at runtime +# but True while type checking. +if False: # pragma: no cover + from typing import TYPE_CHECKING +else: + TYPE_CHECKING = False + +# typing's cast syntax requires calling typing.cast at runtime, but we don't +# want to import typing at runtime. Here, we inform the type checkers that +# we're importing `typing.cast` as `cast` and re-implement typing.cast's +# runtime behavior in a block that is ignored by type checkers. +if TYPE_CHECKING: # pragma: no cover + # not executed at runtime + from typing import cast +else: + # executed at runtime + def cast(type_, value): # noqa + return value diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/markers.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/markers.py new file mode 100644 index 0000000000000000000000000000000000000000..03fbdfcc944ef6f969744134957a428d19c743ca --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/markers.py @@ -0,0 +1,328 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import operator +import os +import platform +import sys + +from setuptools.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd +from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString +from setuptools.extern.pyparsing import Literal as L # noqa + +from ._compat import string_types +from ._typing import TYPE_CHECKING +from .specifiers import Specifier, InvalidSpecifier + +if TYPE_CHECKING: # pragma: no cover + from typing import Any, Callable, Dict, List, Optional, Tuple, Union + + Operator = Callable[[str, str], bool] + + +__all__ = [ + "InvalidMarker", + "UndefinedComparison", + "UndefinedEnvironmentName", + "Marker", + "default_environment", +] + + +class InvalidMarker(ValueError): + """ + An invalid marker was found, users should refer to PEP 508. + """ + + +class UndefinedComparison(ValueError): + """ + An invalid operation was attempted on a value that doesn't support it. + """ + + +class UndefinedEnvironmentName(ValueError): + """ + A name was attempted to be used that does not exist inside of the + environment. + """ + + +class Node(object): + def __init__(self, value): + # type: (Any) -> None + self.value = value + + def __str__(self): + # type: () -> str + return str(self.value) + + def __repr__(self): + # type: () -> str + return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) + + def serialize(self): + # type: () -> str + raise NotImplementedError + + +class Variable(Node): + def serialize(self): + # type: () -> str + return str(self) + + +class Value(Node): + def serialize(self): + # type: () -> str + return '"{0}"'.format(self) + + +class Op(Node): + def serialize(self): + # type: () -> str + return str(self) + + +VARIABLE = ( + L("implementation_version") + | L("platform_python_implementation") + | L("implementation_name") + | L("python_full_version") + | L("platform_release") + | L("platform_version") + | L("platform_machine") + | L("platform_system") + | L("python_version") + | L("sys_platform") + | L("os_name") + | L("os.name") # PEP-345 + | L("sys.platform") # PEP-345 + | L("platform.version") # PEP-345 + | L("platform.machine") # PEP-345 + | L("platform.python_implementation") # PEP-345 + | L("python_implementation") # undocumented setuptools legacy + | L("extra") # PEP-508 +) +ALIASES = { + "os.name": "os_name", + "sys.platform": "sys_platform", + "platform.version": "platform_version", + "platform.machine": "platform_machine", + "platform.python_implementation": "platform_python_implementation", + "python_implementation": "platform_python_implementation", +} +VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) + +VERSION_CMP = ( + L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<") +) + +MARKER_OP = VERSION_CMP | L("not in") | L("in") +MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) + +MARKER_VALUE = QuotedString("'") | QuotedString('"') +MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) + +BOOLOP = L("and") | L("or") + +MARKER_VAR = VARIABLE | MARKER_VALUE + +MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) +MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) + +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() + +MARKER_EXPR = Forward() +MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) +MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) + +MARKER = stringStart + MARKER_EXPR + stringEnd + + +def _coerce_parse_result(results): + # type: (Union[ParseResults, List[Any]]) -> List[Any] + if isinstance(results, ParseResults): + return [_coerce_parse_result(i) for i in results] + else: + return results + + +def _format_marker(marker, first=True): + # type: (Union[List[str], Tuple[Node, ...], str], Optional[bool]) -> str + + assert isinstance(marker, (list, tuple, string_types)) + + # Sometimes we have a structure like [[...]] which is a single item list + # where the single item is itself it's own list. In that case we want skip + # the rest of this function so that we don't get extraneous () on the + # outside. + if ( + isinstance(marker, list) + and len(marker) == 1 + and isinstance(marker[0], (list, tuple)) + ): + return _format_marker(marker[0]) + + if isinstance(marker, list): + inner = (_format_marker(m, first=False) for m in marker) + if first: + return " ".join(inner) + else: + return "(" + " ".join(inner) + ")" + elif isinstance(marker, tuple): + return " ".join([m.serialize() for m in marker]) + else: + return marker + + +_operators = { + "in": lambda lhs, rhs: lhs in rhs, + "not in": lambda lhs, rhs: lhs not in rhs, + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + "!=": operator.ne, + ">=": operator.ge, + ">": operator.gt, +} # type: Dict[str, Operator] + + +def _eval_op(lhs, op, rhs): + # type: (str, Op, str) -> bool + try: + spec = Specifier("".join([op.serialize(), rhs])) + except InvalidSpecifier: + pass + else: + return spec.contains(lhs) + + oper = _operators.get(op.serialize()) # type: Optional[Operator] + if oper is None: + raise UndefinedComparison( + "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) + ) + + return oper(lhs, rhs) + + +class Undefined(object): + pass + + +_undefined = Undefined() + + +def _get_env(environment, name): + # type: (Dict[str, str], str) -> str + value = environment.get(name, _undefined) # type: Union[str, Undefined] + + if isinstance(value, Undefined): + raise UndefinedEnvironmentName( + "{0!r} does not exist in evaluation environment.".format(name) + ) + + return value + + +def _evaluate_markers(markers, environment): + # type: (List[Any], Dict[str, str]) -> bool + groups = [[]] # type: List[List[bool]] + + for marker in markers: + assert isinstance(marker, (list, tuple, string_types)) + + if isinstance(marker, list): + groups[-1].append(_evaluate_markers(marker, environment)) + elif isinstance(marker, tuple): + lhs, op, rhs = marker + + if isinstance(lhs, Variable): + lhs_value = _get_env(environment, lhs.value) + rhs_value = rhs.value + else: + lhs_value = lhs.value + rhs_value = _get_env(environment, rhs.value) + + groups[-1].append(_eval_op(lhs_value, op, rhs_value)) + else: + assert marker in ["and", "or"] + if marker == "or": + groups.append([]) + + return any(all(item) for item in groups) + + +def format_full_version(info): + # type: (sys._version_info) -> str + version = "{0.major}.{0.minor}.{0.micro}".format(info) + kind = info.releaselevel + if kind != "final": + version += kind[0] + str(info.serial) + return version + + +def default_environment(): + # type: () -> Dict[str, str] + if hasattr(sys, "implementation"): + # Ignoring the `sys.implementation` reference for type checking due to + # mypy not liking that the attribute doesn't exist in Python 2.7 when + # run with the `--py27` flag. + iver = format_full_version(sys.implementation.version) # type: ignore + implementation_name = sys.implementation.name # type: ignore + else: + iver = "0" + implementation_name = "" + + return { + "implementation_name": implementation_name, + "implementation_version": iver, + "os_name": os.name, + "platform_machine": platform.machine(), + "platform_release": platform.release(), + "platform_system": platform.system(), + "platform_version": platform.version(), + "python_full_version": platform.python_version(), + "platform_python_implementation": platform.python_implementation(), + "python_version": ".".join(platform.python_version_tuple()[:2]), + "sys_platform": sys.platform, + } + + +class Marker(object): + def __init__(self, marker): + # type: (str) -> None + try: + self._markers = _coerce_parse_result(MARKER.parseString(marker)) + except ParseException as e: + err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( + marker, marker[e.loc : e.loc + 8] + ) + raise InvalidMarker(err_str) + + def __str__(self): + # type: () -> str + return _format_marker(self._markers) + + def __repr__(self): + # type: () -> str + return "".format(str(self)) + + def evaluate(self, environment=None): + # type: (Optional[Dict[str, str]]) -> bool + """Evaluate a marker. + + Return the boolean from evaluating the given marker against the + environment. environment is an optional argument to override all or + part of the determined environment. + + The environment is determined from the current Python process. + """ + current_environment = default_environment() + if environment is not None: + current_environment.update(environment) + + return _evaluate_markers(self._markers, current_environment) diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/requirements.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/requirements.py new file mode 100644 index 0000000000000000000000000000000000000000..5d50c7d7e20c8b390edc0e6a2c362161641117d4 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/requirements.py @@ -0,0 +1,145 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import string +import re + +from setuptools.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine +from setuptools.extern.pyparsing import Literal as L # noqa +from urllib import parse as urlparse + +from ._typing import TYPE_CHECKING +from .markers import MARKER_EXPR, Marker +from .specifiers import LegacySpecifier, Specifier, SpecifierSet + +if TYPE_CHECKING: # pragma: no cover + from typing import List + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +ALPHANUM = Word(string.ascii_letters + string.digits) + +LBRACKET = L("[").suppress() +RBRACKET = L("]").suppress() +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() +COMMA = L(",").suppress() +SEMICOLON = L(";").suppress() +AT = L("@").suppress() + +PUNCTUATION = Word("-_.") +IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) +IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) + +NAME = IDENTIFIER("name") +EXTRA = IDENTIFIER + +URI = Regex(r"[^ ]+")("url") +URL = AT + URI + +EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) +EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") + +VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) +VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) + +VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY +VERSION_MANY = Combine( + VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False +)("_raw_spec") +_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) +_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "") + +VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") +VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) + +MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") +MARKER_EXPR.setParseAction( + lambda s, l, t: Marker(s[t._original_start : t._original_end]) +) +MARKER_SEPARATOR = SEMICOLON +MARKER = MARKER_SEPARATOR + MARKER_EXPR + +VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) +URL_AND_MARKER = URL + Optional(MARKER) + +NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) + +REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd +# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see +# issue #104 +REQUIREMENT.parseString("x[]") + + +class Requirement(object): + """Parse a requirement. + + Parse a given requirement string into its parts, such as name, specifier, + URL, and extras. Raises InvalidRequirement on a badly-formed requirement + string. + """ + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string): + # type: (str) -> None + try: + req = REQUIREMENT.parseString(requirement_string) + except ParseException as e: + raise InvalidRequirement( + 'Parse error at "{0!r}": {1}'.format( + requirement_string[e.loc : e.loc + 8], e.msg + ) + ) + + self.name = req.name + if req.url: + parsed_url = urlparse.urlparse(req.url) + if parsed_url.scheme == "file": + if urlparse.urlunparse(parsed_url) != req.url: + raise InvalidRequirement("Invalid URL given") + elif not (parsed_url.scheme and parsed_url.netloc) or ( + not parsed_url.scheme and not parsed_url.netloc + ): + raise InvalidRequirement("Invalid URL: {0}".format(req.url)) + self.url = req.url + else: + self.url = None + self.extras = set(req.extras.asList() if req.extras else []) + self.specifier = SpecifierSet(req.specifier) + self.marker = req.marker if req.marker else None + + def __str__(self): + # type: () -> str + parts = [self.name] # type: List[str] + + if self.extras: + parts.append("[{0}]".format(",".join(sorted(self.extras)))) + + if self.specifier: + parts.append(str(self.specifier)) + + if self.url: + parts.append("@ {0}".format(self.url)) + if self.marker: + parts.append(" ") + + if self.marker: + parts.append("; {0}".format(self.marker)) + + return "".join(parts) + + def __repr__(self): + # type: () -> str + return "".format(str(self)) diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/specifiers.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/specifiers.py new file mode 100644 index 0000000000000000000000000000000000000000..fe09bb1dbb22f7670d33fe4b86ac45e207cc7eb1 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/specifiers.py @@ -0,0 +1,863 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import abc +import functools +import itertools +import re + +from ._compat import string_types, with_metaclass +from ._typing import TYPE_CHECKING +from .utils import canonicalize_version +from .version import Version, LegacyVersion, parse + +if TYPE_CHECKING: # pragma: no cover + from typing import ( + List, + Dict, + Union, + Iterable, + Iterator, + Optional, + Callable, + Tuple, + FrozenSet, + ) + + ParsedVersion = Union[Version, LegacyVersion] + UnparsedVersion = Union[Version, LegacyVersion, str] + CallableOperator = Callable[[ParsedVersion, str], bool] + + +class InvalidSpecifier(ValueError): + """ + An invalid specifier was found, users should refer to PEP 440. + """ + + +class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): # type: ignore + @abc.abstractmethod + def __str__(self): + # type: () -> str + """ + Returns the str representation of this Specifier like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self): + # type: () -> int + """ + Returns a hash value for this Specifier like object. + """ + + @abc.abstractmethod + def __eq__(self, other): + # type: (object) -> bool + """ + Returns a boolean representing whether or not the two Specifier like + objects are equal. + """ + + @abc.abstractmethod + def __ne__(self, other): + # type: (object) -> bool + """ + Returns a boolean representing whether or not the two Specifier like + objects are not equal. + """ + + @abc.abstractproperty + def prereleases(self): + # type: () -> Optional[bool] + """ + Returns whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @prereleases.setter + def prereleases(self, value): + # type: (bool) -> None + """ + Sets whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @abc.abstractmethod + def contains(self, item, prereleases=None): + # type: (str, Optional[bool]) -> bool + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter(self, iterable, prereleases=None): + # type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion] + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class _IndividualSpecifier(BaseSpecifier): + + _operators = {} # type: Dict[str, str] + + def __init__(self, spec="", prereleases=None): + # type: (str, Optional[bool]) -> None + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) + + self._spec = ( + match.group("operator").strip(), + match.group("version").strip(), + ) # type: Tuple[str, str] + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + def __repr__(self): + # type: () -> str + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre) + + def __str__(self): + # type: () -> str + return "{0}{1}".format(*self._spec) + + @property + def _canonical_spec(self): + # type: () -> Tuple[str, Union[Version, str]] + return self._spec[0], canonicalize_version(self._spec[1]) + + def __hash__(self): + # type: () -> int + return hash(self._canonical_spec) + + def __eq__(self, other): + # type: (object) -> bool + if isinstance(other, string_types): + try: + other = self.__class__(str(other)) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._canonical_spec == other._canonical_spec + + def __ne__(self, other): + # type: (object) -> bool + if isinstance(other, string_types): + try: + other = self.__class__(str(other)) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec != other._spec + + def _get_operator(self, op): + # type: (str) -> CallableOperator + operator_callable = getattr( + self, "_compare_{0}".format(self._operators[op]) + ) # type: CallableOperator + return operator_callable + + def _coerce_version(self, version): + # type: (UnparsedVersion) -> ParsedVersion + if not isinstance(version, (LegacyVersion, Version)): + version = parse(version) + return version + + @property + def operator(self): + # type: () -> str + return self._spec[0] + + @property + def version(self): + # type: () -> str + return self._spec[1] + + @property + def prereleases(self): + # type: () -> Optional[bool] + return self._prereleases + + @prereleases.setter + def prereleases(self, value): + # type: (bool) -> None + self._prereleases = value + + def __contains__(self, item): + # type: (str) -> bool + return self.contains(item) + + def contains(self, item, prereleases=None): + # type: (UnparsedVersion, Optional[bool]) -> bool + + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version or LegacyVersion, this allows us to have + # a shortcut for ``"2.0" in Specifier(">=2") + normalized_item = self._coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if normalized_item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + operator_callable = self._get_operator(self.operator) # type: CallableOperator + return operator_callable(normalized_item, self.version) + + def filter(self, iterable, prereleases=None): + # type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion] + + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = self._coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later incase nothing + # else matches this specifier. + if parsed_version.is_prerelease and not ( + prereleases or self.prereleases + ): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the beginning. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +class LegacySpecifier(_IndividualSpecifier): + + _regex_str = r""" + (?P(==|!=|<=|>=|<|>)) + \s* + (?P + [^,;\s)]* # Since this is a "legacy" specifier, and the version + # string can be just about anything, we match everything + # except for whitespace, a semi-colon for marker support, + # a closing paren since versions can be enclosed in + # them, and a comma since it's a version separator. + ) + """ + + _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + } + + def _coerce_version(self, version): + # type: (Union[ParsedVersion, str]) -> LegacyVersion + if not isinstance(version, LegacyVersion): + version = LegacyVersion(str(version)) + return version + + def _compare_equal(self, prospective, spec): + # type: (LegacyVersion, str) -> bool + return prospective == self._coerce_version(spec) + + def _compare_not_equal(self, prospective, spec): + # type: (LegacyVersion, str) -> bool + return prospective != self._coerce_version(spec) + + def _compare_less_than_equal(self, prospective, spec): + # type: (LegacyVersion, str) -> bool + return prospective <= self._coerce_version(spec) + + def _compare_greater_than_equal(self, prospective, spec): + # type: (LegacyVersion, str) -> bool + return prospective >= self._coerce_version(spec) + + def _compare_less_than(self, prospective, spec): + # type: (LegacyVersion, str) -> bool + return prospective < self._coerce_version(spec) + + def _compare_greater_than(self, prospective, spec): + # type: (LegacyVersion, str) -> bool + return prospective > self._coerce_version(spec) + + +def _require_version_compare( + fn # type: (Callable[[Specifier, ParsedVersion, str], bool]) +): + # type: (...) -> Callable[[Specifier, ParsedVersion, str], bool] + @functools.wraps(fn) + def wrapped(self, prospective, spec): + # type: (Specifier, ParsedVersion, str) -> bool + if not isinstance(prospective, Version): + return False + return fn(self, prospective, spec) + + return wrapped + + +class Specifier(_IndividualSpecifier): + + _regex_str = r""" + (?P(~=|==|!=|<=|>=|<|>|===)) + (?P + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s]* # We just match everything, except for whitespace + # since we are only testing for strict identity. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + + # You cannot use a wild card and a dev or local version + # together so group them with a | and make them optional. + (?: + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + | + \.\* # Wild card syntax of .* + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + @_require_version_compare + def _compare_compatible(self, prospective, spec): + # type: (ParsedVersion, str) -> bool + + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore post and dev releases and we want to treat the pre-release as + # it's own separate segment. + prefix = ".".join( + list( + itertools.takewhile( + lambda x: (not x.startswith("post") and not x.startswith("dev")), + _version_split(spec), + ) + )[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( + prospective, prefix + ) + + @_require_version_compare + def _compare_equal(self, prospective, spec): + # type: (ParsedVersion, str) -> bool + + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # In the case of prefix matching we want to ignore local segment. + prospective = Version(prospective.public) + # Split the spec out by dots, and pretend that there is an implicit + # dot in between a release segment and a pre-release segment. + split_spec = _version_split(spec[:-2]) # Remove the trailing .* + + # Split the prospective version out by dots, and pretend that there + # is an implicit dot in between a release segment and a pre-release + # segment. + split_prospective = _version_split(str(prospective)) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + shortened_prospective = split_prospective[: len(split_spec)] + + # Pad out our two sides with zeros so that they both equal the same + # length. + padded_spec, padded_prospective = _pad_version( + split_spec, shortened_prospective + ) + + return padded_prospective == padded_spec + else: + # Convert our spec string into a Version + spec_version = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec_version.local: + prospective = Version(prospective.public) + + return prospective == spec_version + + @_require_version_compare + def _compare_not_equal(self, prospective, spec): + # type: (ParsedVersion, str) -> bool + return not self._compare_equal(prospective, spec) + + @_require_version_compare + def _compare_less_than_equal(self, prospective, spec): + # type: (ParsedVersion, str) -> bool + + # NB: Local version identifiers are NOT permitted in the version + # specifier, so local version labels can be universally removed from + # the prospective version. + return Version(prospective.public) <= Version(spec) + + @_require_version_compare + def _compare_greater_than_equal(self, prospective, spec): + # type: (ParsedVersion, str) -> bool + + # NB: Local version identifiers are NOT permitted in the version + # specifier, so local version labels can be universally removed from + # the prospective version. + return Version(prospective.public) >= Version(spec) + + @_require_version_compare + def _compare_less_than(self, prospective, spec_str): + # type: (ParsedVersion, str) -> bool + + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec_str) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + @_require_version_compare + def _compare_greater_than(self, prospective, spec_str): + # type: (ParsedVersion, str) -> bool + + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec_str) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is technically greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective, spec): + # type: (Version, str) -> bool + return str(prospective).lower() == str(spec).lower() + + @property + def prereleases(self): + # type: () -> bool + + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "==="]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if parse(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value): + # type: (bool) -> None + self._prereleases = value + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version): + # type: (str) -> List[str] + result = [] # type: List[str] + for item in version.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _pad_version(left, right): + # type: (List[str], List[str]) -> Tuple[List[str], List[str]] + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split[0]) :]) + right_split.append(right[len(right_split[0]) :]) + + # Insert our padding + left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) + right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) + + return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) + + +class SpecifierSet(BaseSpecifier): + def __init__(self, specifiers="", prereleases=None): + # type: (str, Optional[bool]) -> None + + # Split on , to break each individual specifier into it's own item, and + # strip each item to remove leading/trailing whitespace. + split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Parsed each individual specifier, attempting first to make it a + # Specifier and falling back to a LegacySpecifier. + parsed = set() + for specifier in split_specifiers: + try: + parsed.add(Specifier(specifier)) + except InvalidSpecifier: + parsed.add(LegacySpecifier(specifier)) + + # Turn our parsed specifiers into a frozen set and save them for later. + self._specs = frozenset(parsed) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + def __repr__(self): + # type: () -> str + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "".format(str(self), pre) + + def __str__(self): + # type: () -> str + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self): + # type: () -> int + return hash(self._specs) + + def __and__(self, other): + # type: (Union[SpecifierSet, str]) -> SpecifierSet + if isinstance(other, string_types): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease " + "overrides." + ) + + return specifier + + def __eq__(self, other): + # type: (object) -> bool + if isinstance(other, (string_types, _IndividualSpecifier)): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __ne__(self, other): + # type: (object) -> bool + if isinstance(other, (string_types, _IndividualSpecifier)): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs != other._specs + + def __len__(self): + # type: () -> int + return len(self._specs) + + def __iter__(self): + # type: () -> Iterator[FrozenSet[_IndividualSpecifier]] + return iter(self._specs) + + @property + def prereleases(self): + # type: () -> Optional[bool] + + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value): + # type: (bool) -> None + self._prereleases = value + + def __contains__(self, item): + # type: (Union[ParsedVersion, str]) -> bool + return self.contains(item) + + def contains(self, item, prereleases=None): + # type: (Union[ParsedVersion, str], Optional[bool]) -> bool + + # Ensure that our item is a Version or LegacyVersion instance. + if not isinstance(item, (LegacyVersion, Version)): + item = parse(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all(s.contains(item, prereleases=prereleases) for s in self._specs) + + def filter( + self, + iterable, # type: Iterable[Union[ParsedVersion, str]] + prereleases=None, # type: Optional[bool] + ): + # type: (...) -> Iterable[Union[ParsedVersion, str]] + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iterable + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases, and which will filter out LegacyVersion in general. + else: + filtered = [] # type: List[Union[ParsedVersion, str]] + found_prereleases = [] # type: List[Union[ParsedVersion, str]] + + for item in iterable: + # Ensure that we some kind of Version class for this item. + if not isinstance(item, (LegacyVersion, Version)): + parsed_version = parse(item) + else: + parsed_version = item + + # Filter out any item which is parsed as a LegacyVersion + if isinstance(parsed_version, LegacyVersion): + continue + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return found_prereleases + + return filtered diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/tags.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/tags.py new file mode 100644 index 0000000000000000000000000000000000000000..9064910b8bafe2d60ce5fca8897226f5e0fb8f8f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/tags.py @@ -0,0 +1,751 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import + +import distutils.util + +try: + from importlib.machinery import EXTENSION_SUFFIXES +except ImportError: # pragma: no cover + import imp + + EXTENSION_SUFFIXES = [x[0] for x in imp.get_suffixes()] + del imp +import logging +import os +import platform +import re +import struct +import sys +import sysconfig +import warnings + +from ._typing import TYPE_CHECKING, cast + +if TYPE_CHECKING: # pragma: no cover + from typing import ( + Dict, + FrozenSet, + IO, + Iterable, + Iterator, + List, + Optional, + Sequence, + Tuple, + Union, + ) + + PythonVersion = Sequence[int] + MacVersion = Tuple[int, int] + GlibcVersion = Tuple[int, int] + + +logger = logging.getLogger(__name__) + +INTERPRETER_SHORT_NAMES = { + "python": "py", # Generic. + "cpython": "cp", + "pypy": "pp", + "ironpython": "ip", + "jython": "jy", +} # type: Dict[str, str] + + +_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 + + +class Tag(object): + """ + A representation of the tag triple for a wheel. + + Instances are considered immutable and thus are hashable. Equality checking + is also supported. + """ + + __slots__ = ["_interpreter", "_abi", "_platform"] + + def __init__(self, interpreter, abi, platform): + # type: (str, str, str) -> None + self._interpreter = interpreter.lower() + self._abi = abi.lower() + self._platform = platform.lower() + + @property + def interpreter(self): + # type: () -> str + return self._interpreter + + @property + def abi(self): + # type: () -> str + return self._abi + + @property + def platform(self): + # type: () -> str + return self._platform + + def __eq__(self, other): + # type: (object) -> bool + if not isinstance(other, Tag): + return NotImplemented + + return ( + (self.platform == other.platform) + and (self.abi == other.abi) + and (self.interpreter == other.interpreter) + ) + + def __hash__(self): + # type: () -> int + return hash((self._interpreter, self._abi, self._platform)) + + def __str__(self): + # type: () -> str + return "{}-{}-{}".format(self._interpreter, self._abi, self._platform) + + def __repr__(self): + # type: () -> str + return "<{self} @ {self_id}>".format(self=self, self_id=id(self)) + + +def parse_tag(tag): + # type: (str) -> FrozenSet[Tag] + """ + Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. + + Returning a set is required due to the possibility that the tag is a + compressed tag set. + """ + tags = set() + interpreters, abis, platforms = tag.split("-") + for interpreter in interpreters.split("."): + for abi in abis.split("."): + for platform_ in platforms.split("."): + tags.add(Tag(interpreter, abi, platform_)) + return frozenset(tags) + + +def _warn_keyword_parameter(func_name, kwargs): + # type: (str, Dict[str, bool]) -> bool + """ + Backwards-compatibility with Python 2.7 to allow treating 'warn' as keyword-only. + """ + if not kwargs: + return False + elif len(kwargs) > 1 or "warn" not in kwargs: + kwargs.pop("warn", None) + arg = next(iter(kwargs.keys())) + raise TypeError( + "{}() got an unexpected keyword argument {!r}".format(func_name, arg) + ) + return kwargs["warn"] + + +def _get_config_var(name, warn=False): + # type: (str, bool) -> Union[int, str, None] + value = sysconfig.get_config_var(name) + if value is None and warn: + logger.debug( + "Config variable '%s' is unset, Python ABI tag may be incorrect", name + ) + return value + + +def _normalize_string(string): + # type: (str) -> str + return string.replace(".", "_").replace("-", "_") + + +def _abi3_applies(python_version): + # type: (PythonVersion) -> bool + """ + Determine if the Python version supports abi3. + + PEP 384 was first implemented in Python 3.2. + """ + return len(python_version) > 1 and tuple(python_version) >= (3, 2) + + +def _cpython_abis(py_version, warn=False): + # type: (PythonVersion, bool) -> List[str] + py_version = tuple(py_version) # To allow for version comparison. + abis = [] + version = _version_nodot(py_version[:2]) + debug = pymalloc = ucs4 = "" + with_debug = _get_config_var("Py_DEBUG", warn) + has_refcount = hasattr(sys, "gettotalrefcount") + # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled + # extension modules is the best option. + # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 + has_ext = "_d.pyd" in EXTENSION_SUFFIXES + if with_debug or (with_debug is None and (has_refcount or has_ext)): + debug = "d" + if py_version < (3, 8): + with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) + if with_pymalloc or with_pymalloc is None: + pymalloc = "m" + if py_version < (3, 3): + unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) + if unicode_size == 4 or ( + unicode_size is None and sys.maxunicode == 0x10FFFF + ): + ucs4 = "u" + elif debug: + # Debug builds can also load "normal" extension modules. + # We can also assume no UCS-4 or pymalloc requirement. + abis.append("cp{version}".format(version=version)) + abis.insert( + 0, + "cp{version}{debug}{pymalloc}{ucs4}".format( + version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 + ), + ) + return abis + + +def cpython_tags( + python_version=None, # type: Optional[PythonVersion] + abis=None, # type: Optional[Iterable[str]] + platforms=None, # type: Optional[Iterable[str]] + **kwargs # type: bool +): + # type: (...) -> Iterator[Tag] + """ + Yields the tags for a CPython interpreter. + + The tags consist of: + - cp-- + - cp-abi3- + - cp-none- + - cp-abi3- # Older Python versions down to 3.2. + + If python_version only specifies a major version then user-provided ABIs and + the 'none' ABItag will be used. + + If 'abi3' or 'none' are specified in 'abis' then they will be yielded at + their normal position and not at the beginning. + """ + warn = _warn_keyword_parameter("cpython_tags", kwargs) + if not python_version: + python_version = sys.version_info[:2] + + interpreter = "cp{}".format(_version_nodot(python_version[:2])) + + if abis is None: + if len(python_version) > 1: + abis = _cpython_abis(python_version, warn) + else: + abis = [] + abis = list(abis) + # 'abi3' and 'none' are explicitly handled later. + for explicit_abi in ("abi3", "none"): + try: + abis.remove(explicit_abi) + except ValueError: + pass + + platforms = list(platforms or _platform_tags()) + for abi in abis: + for platform_ in platforms: + yield Tag(interpreter, abi, platform_) + if _abi3_applies(python_version): + for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms): + yield tag + for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms): + yield tag + + if _abi3_applies(python_version): + for minor_version in range(python_version[1] - 1, 1, -1): + for platform_ in platforms: + interpreter = "cp{version}".format( + version=_version_nodot((python_version[0], minor_version)) + ) + yield Tag(interpreter, "abi3", platform_) + + +def _generic_abi(): + # type: () -> Iterator[str] + abi = sysconfig.get_config_var("SOABI") + if abi: + yield _normalize_string(abi) + + +def generic_tags( + interpreter=None, # type: Optional[str] + abis=None, # type: Optional[Iterable[str]] + platforms=None, # type: Optional[Iterable[str]] + **kwargs # type: bool +): + # type: (...) -> Iterator[Tag] + """ + Yields the tags for a generic interpreter. + + The tags consist of: + - -- + + The "none" ABI will be added if it was not explicitly provided. + """ + warn = _warn_keyword_parameter("generic_tags", kwargs) + if not interpreter: + interp_name = interpreter_name() + interp_version = interpreter_version(warn=warn) + interpreter = "".join([interp_name, interp_version]) + if abis is None: + abis = _generic_abi() + platforms = list(platforms or _platform_tags()) + abis = list(abis) + if "none" not in abis: + abis.append("none") + for abi in abis: + for platform_ in platforms: + yield Tag(interpreter, abi, platform_) + + +def _py_interpreter_range(py_version): + # type: (PythonVersion) -> Iterator[str] + """ + Yields Python versions in descending order. + + After the latest version, the major-only version will be yielded, and then + all previous versions of that major version. + """ + if len(py_version) > 1: + yield "py{version}".format(version=_version_nodot(py_version[:2])) + yield "py{major}".format(major=py_version[0]) + if len(py_version) > 1: + for minor in range(py_version[1] - 1, -1, -1): + yield "py{version}".format(version=_version_nodot((py_version[0], minor))) + + +def compatible_tags( + python_version=None, # type: Optional[PythonVersion] + interpreter=None, # type: Optional[str] + platforms=None, # type: Optional[Iterable[str]] +): + # type: (...) -> Iterator[Tag] + """ + Yields the sequence of tags that are compatible with a specific version of Python. + + The tags consist of: + - py*-none- + - -none-any # ... if `interpreter` is provided. + - py*-none-any + """ + if not python_version: + python_version = sys.version_info[:2] + platforms = list(platforms or _platform_tags()) + for version in _py_interpreter_range(python_version): + for platform_ in platforms: + yield Tag(version, "none", platform_) + if interpreter: + yield Tag(interpreter, "none", "any") + for version in _py_interpreter_range(python_version): + yield Tag(version, "none", "any") + + +def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER): + # type: (str, bool) -> str + if not is_32bit: + return arch + + if arch.startswith("ppc"): + return "ppc" + + return "i386" + + +def _mac_binary_formats(version, cpu_arch): + # type: (MacVersion, str) -> List[str] + formats = [cpu_arch] + if cpu_arch == "x86_64": + if version < (10, 4): + return [] + formats.extend(["intel", "fat64", "fat32"]) + + elif cpu_arch == "i386": + if version < (10, 4): + return [] + formats.extend(["intel", "fat32", "fat"]) + + elif cpu_arch == "ppc64": + # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? + if version > (10, 5) or version < (10, 4): + return [] + formats.append("fat64") + + elif cpu_arch == "ppc": + if version > (10, 6): + return [] + formats.extend(["fat32", "fat"]) + + formats.append("universal") + return formats + + +def mac_platforms(version=None, arch=None): + # type: (Optional[MacVersion], Optional[str]) -> Iterator[str] + """ + Yields the platform tags for a macOS system. + + The `version` parameter is a two-item tuple specifying the macOS version to + generate platform tags for. The `arch` parameter is the CPU architecture to + generate platform tags for. Both parameters default to the appropriate value + for the current system. + """ + version_str, _, cpu_arch = platform.mac_ver() # type: ignore + if version is None: + version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2]))) + else: + version = version + if arch is None: + arch = _mac_arch(cpu_arch) + else: + arch = arch + for minor_version in range(version[1], -1, -1): + compat_version = version[0], minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield "macosx_{major}_{minor}_{binary_format}".format( + major=compat_version[0], + minor=compat_version[1], + binary_format=binary_format, + ) + + +# From PEP 513. +def _is_manylinux_compatible(name, glibc_version): + # type: (str, GlibcVersion) -> bool + # Check for presence of _manylinux module. + try: + import _manylinux # noqa + + return bool(getattr(_manylinux, name + "_compatible")) + except (ImportError, AttributeError): + # Fall through to heuristic check below. + pass + + return _have_compatible_glibc(*glibc_version) + + +def _glibc_version_string(): + # type: () -> Optional[str] + # Returns glibc version string, or None if not using glibc. + return _glibc_version_string_confstr() or _glibc_version_string_ctypes() + + +def _glibc_version_string_confstr(): + # type: () -> Optional[str] + """ + Primary implementation of glibc_version_string using os.confstr. + """ + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module. + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183 + try: + # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". + version_string = os.confstr( # type: ignore[attr-defined] # noqa: F821 + "CS_GNU_LIBC_VERSION" + ) + assert version_string is not None + _, version = version_string.split() # type: Tuple[str, str] + except (AssertionError, AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def _glibc_version_string_ctypes(): + # type: () -> Optional[str] + """ + Fallback implementation of glibc_version_string using ctypes. + """ + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + # + # Note: typeshed is wrong here so we are ignoring this line. + process_namespace = ctypes.CDLL(None) # type: ignore + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str = gnu_get_libc_version() # type: str + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +# Separated out from have_compatible_glibc for easier unit testing. +def _check_glibc_version(version_str, required_major, minimum_minor): + # type: (str, int, int) -> bool + # Parse string and check against requested version. + # + # We use a regexp instead of str.split because we want to discard any + # random junk that might come after the minor version -- this might happen + # in patched/forked versions of glibc (e.g. Linaro's version of glibc + # uses version strings like "2.20-2014.11"). See gh-3588. + m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) + if not m: + warnings.warn( + "Expected glibc version with 2 components major.minor," + " got: %s" % version_str, + RuntimeWarning, + ) + return False + return ( + int(m.group("major")) == required_major + and int(m.group("minor")) >= minimum_minor + ) + + +def _have_compatible_glibc(required_major, minimum_minor): + # type: (int, int) -> bool + version_str = _glibc_version_string() + if version_str is None: + return False + return _check_glibc_version(version_str, required_major, minimum_minor) + + +# Python does not provide platform information at sufficient granularity to +# identify the architecture of the running executable in some cases, so we +# determine it dynamically by reading the information from the running +# process. This only applies on Linux, which uses the ELF format. +class _ELFFileHeader(object): + # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header + class _InvalidELFFileHeader(ValueError): + """ + An invalid ELF file header was found. + """ + + ELF_MAGIC_NUMBER = 0x7F454C46 + ELFCLASS32 = 1 + ELFCLASS64 = 2 + ELFDATA2LSB = 1 + ELFDATA2MSB = 2 + EM_386 = 3 + EM_S390 = 22 + EM_ARM = 40 + EM_X86_64 = 62 + EF_ARM_ABIMASK = 0xFF000000 + EF_ARM_ABI_VER5 = 0x05000000 + EF_ARM_ABI_FLOAT_HARD = 0x00000400 + + def __init__(self, file): + # type: (IO[bytes]) -> None + def unpack(fmt): + # type: (str) -> int + try: + (result,) = struct.unpack( + fmt, file.read(struct.calcsize(fmt)) + ) # type: (int, ) + except struct.error: + raise _ELFFileHeader._InvalidELFFileHeader() + return result + + self.e_ident_magic = unpack(">I") + if self.e_ident_magic != self.ELF_MAGIC_NUMBER: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_class = unpack("B") + if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_data = unpack("B") + if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_version = unpack("B") + self.e_ident_osabi = unpack("B") + self.e_ident_abiversion = unpack("B") + self.e_ident_pad = file.read(7) + format_h = "H" + format_i = "I" + format_q = "Q" + format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q + self.e_type = unpack(format_h) + self.e_machine = unpack(format_h) + self.e_version = unpack(format_i) + self.e_entry = unpack(format_p) + self.e_phoff = unpack(format_p) + self.e_shoff = unpack(format_p) + self.e_flags = unpack(format_i) + self.e_ehsize = unpack(format_h) + self.e_phentsize = unpack(format_h) + self.e_phnum = unpack(format_h) + self.e_shentsize = unpack(format_h) + self.e_shnum = unpack(format_h) + self.e_shstrndx = unpack(format_h) + + +def _get_elf_header(): + # type: () -> Optional[_ELFFileHeader] + try: + with open(sys.executable, "rb") as f: + elf_header = _ELFFileHeader(f) + except (IOError, OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): + return None + return elf_header + + +def _is_linux_armhf(): + # type: () -> bool + # hard-float ABI can be detected from the ELF header of the running + # process + # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_ARM + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABIMASK + ) == elf_header.EF_ARM_ABI_VER5 + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD + ) == elf_header.EF_ARM_ABI_FLOAT_HARD + return result + + +def _is_linux_i686(): + # type: () -> bool + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_386 + return result + + +def _have_compatible_manylinux_abi(arch): + # type: (str) -> bool + if arch == "armv7l": + return _is_linux_armhf() + if arch == "i686": + return _is_linux_i686() + return True + + +def _linux_platforms(is_32bit=_32_BIT_INTERPRETER): + # type: (bool) -> Iterator[str] + linux = _normalize_string(distutils.util.get_platform()) + if is_32bit: + if linux == "linux_x86_64": + linux = "linux_i686" + elif linux == "linux_aarch64": + linux = "linux_armv7l" + manylinux_support = [] + _, arch = linux.split("_", 1) + if _have_compatible_manylinux_abi(arch): + if arch in {"x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"}: + manylinux_support.append( + ("manylinux2014", (2, 17)) + ) # CentOS 7 w/ glibc 2.17 (PEP 599) + if arch in {"x86_64", "i686"}: + manylinux_support.append( + ("manylinux2010", (2, 12)) + ) # CentOS 6 w/ glibc 2.12 (PEP 571) + manylinux_support.append( + ("manylinux1", (2, 5)) + ) # CentOS 5 w/ glibc 2.5 (PEP 513) + manylinux_support_iter = iter(manylinux_support) + for name, glibc_version in manylinux_support_iter: + if _is_manylinux_compatible(name, glibc_version): + yield linux.replace("linux", name) + break + # Support for a later manylinux implies support for an earlier version. + for name, _ in manylinux_support_iter: + yield linux.replace("linux", name) + yield linux + + +def _generic_platforms(): + # type: () -> Iterator[str] + yield _normalize_string(distutils.util.get_platform()) + + +def _platform_tags(): + # type: () -> Iterator[str] + """ + Provides the platform tags for this installation. + """ + if platform.system() == "Darwin": + return mac_platforms() + elif platform.system() == "Linux": + return _linux_platforms() + else: + return _generic_platforms() + + +def interpreter_name(): + # type: () -> str + """ + Returns the name of the running interpreter. + """ + try: + name = sys.implementation.name # type: ignore + except AttributeError: # pragma: no cover + # Python 2.7 compatibility. + name = platform.python_implementation().lower() + return INTERPRETER_SHORT_NAMES.get(name) or name + + +def interpreter_version(**kwargs): + # type: (bool) -> str + """ + Returns the version of the running interpreter. + """ + warn = _warn_keyword_parameter("interpreter_version", kwargs) + version = _get_config_var("py_version_nodot", warn=warn) + if version: + version = str(version) + else: + version = _version_nodot(sys.version_info[:2]) + return version + + +def _version_nodot(version): + # type: (PythonVersion) -> str + if any(v >= 10 for v in version): + sep = "_" + else: + sep = "" + return sep.join(map(str, version)) + + +def sys_tags(**kwargs): + # type: (bool) -> Iterator[Tag] + """ + Returns the sequence of tag triples for the running interpreter. + + The order of the sequence corresponds to priority order for the + interpreter, from most to least important. + """ + warn = _warn_keyword_parameter("sys_tags", kwargs) + + interp_name = interpreter_name() + if interp_name == "cp": + for tag in cpython_tags(warn=warn): + yield tag + else: + for tag in generic_tags(): + yield tag + + for tag in compatible_tags(): + yield tag diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/utils.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..19579c1a0fa38c088a7cbb80950d0c85f5514cca --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/utils.py @@ -0,0 +1,65 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import re + +from ._typing import TYPE_CHECKING, cast +from .version import InvalidVersion, Version + +if TYPE_CHECKING: # pragma: no cover + from typing import NewType, Union + + NormalizedName = NewType("NormalizedName", str) + +_canonicalize_regex = re.compile(r"[-_.]+") + + +def canonicalize_name(name): + # type: (str) -> NormalizedName + # This is taken from PEP 503. + value = _canonicalize_regex.sub("-", name).lower() + return cast("NormalizedName", value) + + +def canonicalize_version(_version): + # type: (str) -> Union[Version, str] + """ + This is very similar to Version.__str__, but has one subtle difference + with the way it handles the release segment. + """ + + try: + version = Version(_version) + except InvalidVersion: + # Legacy versions cannot be normalized + return _version + + parts = [] + + # Epoch + if version.epoch != 0: + parts.append("{0}!".format(version.epoch)) + + # Release segment + # NB: This strips trailing '.0's to normalize + parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release))) + + # Pre-release + if version.pre is not None: + parts.append("".join(str(x) for x in version.pre)) + + # Post-release + if version.post is not None: + parts.append(".post{0}".format(version.post)) + + # Development release + if version.dev is not None: + parts.append(".dev{0}".format(version.dev)) + + # Local version segment + if version.local is not None: + parts.append("+{0}".format(version.local)) + + return "".join(parts) diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/packaging/version.py b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/version.py new file mode 100644 index 0000000000000000000000000000000000000000..00371e86a87edfc5f8d1d1352360bfae0cce8e65 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/_vendor/packaging/version.py @@ -0,0 +1,535 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import collections +import itertools +import re + +from ._structures import Infinity, NegativeInfinity +from ._typing import TYPE_CHECKING + +if TYPE_CHECKING: # pragma: no cover + from typing import Callable, Iterator, List, Optional, SupportsInt, Tuple, Union + + from ._structures import InfinityType, NegativeInfinityType + + InfiniteTypes = Union[InfinityType, NegativeInfinityType] + PrePostDevType = Union[InfiniteTypes, Tuple[str, int]] + SubLocalType = Union[InfiniteTypes, int, str] + LocalType = Union[ + NegativeInfinityType, + Tuple[ + Union[ + SubLocalType, + Tuple[SubLocalType, str], + Tuple[NegativeInfinityType, SubLocalType], + ], + ..., + ], + ] + CmpKey = Tuple[ + int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType + ] + LegacyCmpKey = Tuple[int, Tuple[str, ...]] + VersionComparisonMethod = Callable[ + [Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool + ] + +__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"] + + +_Version = collections.namedtuple( + "_Version", ["epoch", "release", "dev", "pre", "post", "local"] +) + + +def parse(version): + # type: (str) -> Union[LegacyVersion, Version] + """ + Parse the given version string and return either a :class:`Version` object + or a :class:`LegacyVersion` object depending on if the given version is + a valid PEP 440 version or a legacy version. + """ + try: + return Version(version) + except InvalidVersion: + return LegacyVersion(version) + + +class InvalidVersion(ValueError): + """ + An invalid version was found, users should refer to PEP 440. + """ + + +class _BaseVersion(object): + _key = None # type: Union[CmpKey, LegacyCmpKey] + + def __hash__(self): + # type: () -> int + return hash(self._key) + + def __lt__(self, other): + # type: (_BaseVersion) -> bool + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + # type: (_BaseVersion) -> bool + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + # type: (object) -> bool + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + # type: (_BaseVersion) -> bool + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + # type: (_BaseVersion) -> bool + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + # type: (object) -> bool + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + # type: (object, VersionComparisonMethod) -> Union[bool, NotImplemented] + if not isinstance(other, _BaseVersion): + return NotImplemented + + return method(self._key, other._key) + + +class LegacyVersion(_BaseVersion): + def __init__(self, version): + # type: (str) -> None + self._version = str(version) + self._key = _legacy_cmpkey(self._version) + + def __str__(self): + # type: () -> str + return self._version + + def __repr__(self): + # type: () -> str + return "".format(repr(str(self))) + + @property + def public(self): + # type: () -> str + return self._version + + @property + def base_version(self): + # type: () -> str + return self._version + + @property + def epoch(self): + # type: () -> int + return -1 + + @property + def release(self): + # type: () -> None + return None + + @property + def pre(self): + # type: () -> None + return None + + @property + def post(self): + # type: () -> None + return None + + @property + def dev(self): + # type: () -> None + return None + + @property + def local(self): + # type: () -> None + return None + + @property + def is_prerelease(self): + # type: () -> bool + return False + + @property + def is_postrelease(self): + # type: () -> bool + return False + + @property + def is_devrelease(self): + # type: () -> bool + return False + + +_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE) + +_legacy_version_replacement_map = { + "pre": "c", + "preview": "c", + "-": "final-", + "rc": "c", + "dev": "@", +} + + +def _parse_version_parts(s): + # type: (str) -> Iterator[str] + for part in _legacy_version_component_re.split(s): + part = _legacy_version_replacement_map.get(part, part) + + if not part or part == ".": + continue + + if part[:1] in "0123456789": + # pad for numeric comparison + yield part.zfill(8) + else: + yield "*" + part + + # ensure that alpha/beta/candidate are before final + yield "*final" + + +def _legacy_cmpkey(version): + # type: (str) -> LegacyCmpKey + + # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch + # greater than or equal to 0. This will effectively put the LegacyVersion, + # which uses the defacto standard originally implemented by setuptools, + # as before all PEP 440 versions. + epoch = -1 + + # This scheme is taken from pkg_resources.parse_version setuptools prior to + # it's adoption of the packaging library. + parts = [] # type: List[str] + for part in _parse_version_parts(version.lower()): + if part.startswith("*"): + # remove "-" before a prerelease tag + if part < "*final": + while parts and parts[-1] == "*final-": + parts.pop() + + # remove trailing zeros from each series of numeric parts + while parts and parts[-1] == "00000000": + parts.pop() + + parts.append(part) + + return epoch, tuple(parts) + + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +VERSION_PATTERN = r""" + v? + (?: + (?:(?P[0-9]+)!)? # epoch + (?P[0-9]+(?:\.[0-9]+)*) # release segment + (?P
                                          # pre-release
+            [-_\.]?
+            (?P(a|b|c|rc|alpha|beta|pre|preview))
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+        (?P                                         # post release
+            (?:-(?P[0-9]+))
+            |
+            (?:
+                [-_\.]?
+                (?Ppost|rev|r)
+                [-_\.]?
+                (?P[0-9]+)?
+            )
+        )?
+        (?P                                          # dev release
+            [-_\.]?
+            (?Pdev)
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+    )
+    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
+"""
+
+
+class Version(_BaseVersion):
+
+    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
+
+    def __init__(self, version):
+        # type: (str) -> None
+
+        # Validate the version and parse it into pieces
+        match = self._regex.search(version)
+        if not match:
+            raise InvalidVersion("Invalid version: '{0}'".format(version))
+
+        # Store the parsed out pieces of the version
+        self._version = _Version(
+            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
+            release=tuple(int(i) for i in match.group("release").split(".")),
+            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
+            post=_parse_letter_version(
+                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
+            ),
+            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
+            local=_parse_local_version(match.group("local")),
+        )
+
+        # Generate a key which will be used for sorting
+        self._key = _cmpkey(
+            self._version.epoch,
+            self._version.release,
+            self._version.pre,
+            self._version.post,
+            self._version.dev,
+            self._version.local,
+        )
+
+    def __repr__(self):
+        # type: () -> str
+        return "".format(repr(str(self)))
+
+    def __str__(self):
+        # type: () -> str
+        parts = []
+
+        # Epoch
+        if self.epoch != 0:
+            parts.append("{0}!".format(self.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self.release))
+
+        # Pre-release
+        if self.pre is not None:
+            parts.append("".join(str(x) for x in self.pre))
+
+        # Post-release
+        if self.post is not None:
+            parts.append(".post{0}".format(self.post))
+
+        # Development release
+        if self.dev is not None:
+            parts.append(".dev{0}".format(self.dev))
+
+        # Local version segment
+        if self.local is not None:
+            parts.append("+{0}".format(self.local))
+
+        return "".join(parts)
+
+    @property
+    def epoch(self):
+        # type: () -> int
+        _epoch = self._version.epoch  # type: int
+        return _epoch
+
+    @property
+    def release(self):
+        # type: () -> Tuple[int, ...]
+        _release = self._version.release  # type: Tuple[int, ...]
+        return _release
+
+    @property
+    def pre(self):
+        # type: () -> Optional[Tuple[str, int]]
+        _pre = self._version.pre  # type: Optional[Tuple[str, int]]
+        return _pre
+
+    @property
+    def post(self):
+        # type: () -> Optional[Tuple[str, int]]
+        return self._version.post[1] if self._version.post else None
+
+    @property
+    def dev(self):
+        # type: () -> Optional[Tuple[str, int]]
+        return self._version.dev[1] if self._version.dev else None
+
+    @property
+    def local(self):
+        # type: () -> Optional[str]
+        if self._version.local:
+            return ".".join(str(x) for x in self._version.local)
+        else:
+            return None
+
+    @property
+    def public(self):
+        # type: () -> str
+        return str(self).split("+", 1)[0]
+
+    @property
+    def base_version(self):
+        # type: () -> str
+        parts = []
+
+        # Epoch
+        if self.epoch != 0:
+            parts.append("{0}!".format(self.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self.release))
+
+        return "".join(parts)
+
+    @property
+    def is_prerelease(self):
+        # type: () -> bool
+        return self.dev is not None or self.pre is not None
+
+    @property
+    def is_postrelease(self):
+        # type: () -> bool
+        return self.post is not None
+
+    @property
+    def is_devrelease(self):
+        # type: () -> bool
+        return self.dev is not None
+
+    @property
+    def major(self):
+        # type: () -> int
+        return self.release[0] if len(self.release) >= 1 else 0
+
+    @property
+    def minor(self):
+        # type: () -> int
+        return self.release[1] if len(self.release) >= 2 else 0
+
+    @property
+    def micro(self):
+        # type: () -> int
+        return self.release[2] if len(self.release) >= 3 else 0
+
+
+def _parse_letter_version(
+    letter,  # type: str
+    number,  # type: Union[str, bytes, SupportsInt]
+):
+    # type: (...) -> Optional[Tuple[str, int]]
+
+    if letter:
+        # We consider there to be an implicit 0 in a pre-release if there is
+        # not a numeral associated with it.
+        if number is None:
+            number = 0
+
+        # We normalize any letters to their lower case form
+        letter = letter.lower()
+
+        # We consider some words to be alternate spellings of other words and
+        # in those cases we want to normalize the spellings to our preferred
+        # spelling.
+        if letter == "alpha":
+            letter = "a"
+        elif letter == "beta":
+            letter = "b"
+        elif letter in ["c", "pre", "preview"]:
+            letter = "rc"
+        elif letter in ["rev", "r"]:
+            letter = "post"
+
+        return letter, int(number)
+    if not letter and number:
+        # We assume if we are given a number, but we are not given a letter
+        # then this is using the implicit post release syntax (e.g. 1.0-1)
+        letter = "post"
+
+        return letter, int(number)
+
+    return None
+
+
+_local_version_separators = re.compile(r"[\._-]")
+
+
+def _parse_local_version(local):
+    # type: (str) -> Optional[LocalType]
+    """
+    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
+    """
+    if local is not None:
+        return tuple(
+            part.lower() if not part.isdigit() else int(part)
+            for part in _local_version_separators.split(local)
+        )
+    return None
+
+
+def _cmpkey(
+    epoch,  # type: int
+    release,  # type: Tuple[int, ...]
+    pre,  # type: Optional[Tuple[str, int]]
+    post,  # type: Optional[Tuple[str, int]]
+    dev,  # type: Optional[Tuple[str, int]]
+    local,  # type: Optional[Tuple[SubLocalType]]
+):
+    # type: (...) -> CmpKey
+
+    # When we compare a release version, we want to compare it with all of the
+    # trailing zeros removed. So we'll use a reverse the list, drop all the now
+    # leading zeros until we come to something non zero, then take the rest
+    # re-reverse it back into the correct order and make it a tuple and use
+    # that for our sorting key.
+    _release = tuple(
+        reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
+    )
+
+    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
+    # We'll do this by abusing the pre segment, but we _only_ want to do this
+    # if there is not a pre or a post segment. If we have one of those then
+    # the normal sorting rules will handle this case correctly.
+    if pre is None and post is None and dev is not None:
+        _pre = NegativeInfinity  # type: PrePostDevType
+    # Versions without a pre-release (except as noted above) should sort after
+    # those with one.
+    elif pre is None:
+        _pre = Infinity
+    else:
+        _pre = pre
+
+    # Versions without a post segment should sort before those with one.
+    if post is None:
+        _post = NegativeInfinity  # type: PrePostDevType
+
+    else:
+        _post = post
+
+    # Versions without a development segment should sort after those with one.
+    if dev is None:
+        _dev = Infinity  # type: PrePostDevType
+
+    else:
+        _dev = dev
+
+    if local is None:
+        # Versions without a local segment should sort before those with one.
+        _local = NegativeInfinity  # type: LocalType
+    else:
+        # Versions with a local segment need that segment parsed to implement
+        # the sorting rules in PEP440.
+        # - Alpha numeric segments sort before numeric segments
+        # - Alpha numeric segments sort lexicographically
+        # - Numeric segments sort numerically
+        # - Shorter versions sort before longer versions when the prefixes
+        #   match exactly
+        _local = tuple(
+            (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
+        )
+
+    return epoch, _release, _pre, _post, _dev, _local
diff --git a/MLPY/Lib/site-packages/setuptools/_vendor/pyparsing.py b/MLPY/Lib/site-packages/setuptools/_vendor/pyparsing.py
new file mode 100644
index 0000000000000000000000000000000000000000..4cae78838708b07f76357f938289fce8a200e98e
--- /dev/null
+++ b/MLPY/Lib/site-packages/setuptools/_vendor/pyparsing.py
@@ -0,0 +1,5742 @@
+# module pyparsing.py
+#
+# Copyright (c) 2003-2018  Paul T. McGuire
+#
+# 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.
+#
+
+__doc__ = \
+"""
+pyparsing module - Classes and methods to define and execute parsing grammars
+=============================================================================
+
+The pyparsing module is an alternative approach to creating and executing simple grammars,
+vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
+don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
+provides a library of classes that you use to construct the grammar directly in Python.
+
+Here is a program to parse "Hello, World!" (or any greeting of the form 
+C{", !"}), built up using L{Word}, L{Literal}, and L{And} elements 
+(L{'+'} operator gives L{And} expressions, strings are auto-converted to
+L{Literal} expressions)::
+
+    from pyparsing import Word, alphas
+
+    # define grammar of a greeting
+    greet = Word(alphas) + "," + Word(alphas) + "!"
+
+    hello = "Hello, World!"
+    print (hello, "->", greet.parseString(hello))
+
+The program outputs the following::
+
+    Hello, World! -> ['Hello', ',', 'World', '!']
+
+The Python representation of the grammar is quite readable, owing to the self-explanatory
+class names, and the use of '+', '|' and '^' operators.
+
+The L{ParseResults} object returned from L{ParserElement.parseString} can be accessed as a nested list, a dictionary, or an
+object with named attributes.
+
+The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
+ - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
+ - quoted strings
+ - embedded comments
+
+
+Getting Started -
+-----------------
+Visit the classes L{ParserElement} and L{ParseResults} to see the base classes that most other pyparsing
+classes inherit from. Use the docstrings for examples of how to:
+ - construct literal match expressions from L{Literal} and L{CaselessLiteral} classes
+ - construct character word-group expressions using the L{Word} class
+ - see how to create repetitive expressions using L{ZeroOrMore} and L{OneOrMore} classes
+ - use L{'+'}, L{'|'}, L{'^'}, and L{'&'} operators to combine simple expressions into more complex ones
+ - associate names with your parsed results using L{ParserElement.setResultsName}
+ - find some helpful expression short-cuts like L{delimitedList} and L{oneOf}
+ - find more useful common expressions in the L{pyparsing_common} namespace class
+"""
+
+__version__ = "2.2.1"
+__versionTime__ = "18 Sep 2018 00:49 UTC"
+__author__ = "Paul McGuire "
+
+import string
+from weakref import ref as wkref
+import copy
+import sys
+import warnings
+import re
+import sre_constants
+import collections
+import pprint
+import traceback
+import types
+from datetime import datetime
+
+try:
+    from _thread import RLock
+except ImportError:
+    from threading import RLock
+
+try:
+    # Python 3
+    from collections.abc import Iterable
+    from collections.abc import MutableMapping
+except ImportError:
+    # Python 2.7
+    from collections import Iterable
+    from collections import MutableMapping
+
+try:
+    from collections import OrderedDict as _OrderedDict
+except ImportError:
+    try:
+        from ordereddict import OrderedDict as _OrderedDict
+    except ImportError:
+        _OrderedDict = None
+
+#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
+
+__all__ = [
+'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
+'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
+'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
+'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
+'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
+'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 
+'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
+'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
+'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
+'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums',
+'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno',
+'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
+'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
+'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 
+'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
+'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
+'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass',
+'CloseMatch', 'tokenMap', 'pyparsing_common',
+]
+
+system_version = tuple(sys.version_info)[:3]
+PY_3 = system_version[0] == 3
+if PY_3:
+    _MAX_INT = sys.maxsize
+    basestring = str
+    unichr = chr
+    _ustr = str
+
+    # build list of single arg builtins, that can be used as parse actions
+    singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max]
+
+else:
+    _MAX_INT = sys.maxint
+    range = xrange
+
+    def _ustr(obj):
+        """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
+           str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
+           then < returns the unicode object | encodes it with the default encoding | ... >.
+        """
+        if isinstance(obj,unicode):
+            return obj
+
+        try:
+            # If this works, then _ustr(obj) has the same behaviour as str(obj), so
+            # it won't break any existing code.
+            return str(obj)
+
+        except UnicodeEncodeError:
+            # Else encode it
+            ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace')
+            xmlcharref = Regex(r'&#\d+;')
+            xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:])
+            return xmlcharref.transformString(ret)
+
+    # build list of single arg builtins, tolerant of Python version, that can be used as parse actions
+    singleArgBuiltins = []
+    import __builtin__
+    for fname in "sum len sorted reversed list tuple set any all min max".split():
+        try:
+            singleArgBuiltins.append(getattr(__builtin__,fname))
+        except AttributeError:
+            continue
+            
+_generatorType = type((y for y in range(1)))
+ 
+def _xml_escape(data):
+    """Escape &, <, >, ", ', etc. in a string of data."""
+
+    # ampersand must be replaced first
+    from_symbols = '&><"\''
+    to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split())
+    for from_,to_ in zip(from_symbols, to_symbols):
+        data = data.replace(from_, to_)
+    return data
+
+class _Constants(object):
+    pass
+
+alphas     = string.ascii_uppercase + string.ascii_lowercase
+nums       = "0123456789"
+hexnums    = nums + "ABCDEFabcdef"
+alphanums  = alphas + nums
+_bslash    = chr(92)
+printables = "".join(c for c in string.printable if c not in string.whitespace)
+
+class ParseBaseException(Exception):
+    """base exception class for all parsing runtime exceptions"""
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, pstr, loc=0, msg=None, elem=None ):
+        self.loc = loc
+        if msg is None:
+            self.msg = pstr
+            self.pstr = ""
+        else:
+            self.msg = msg
+            self.pstr = pstr
+        self.parserElement = elem
+        self.args = (pstr, loc, msg)
+
+    @classmethod
+    def _from_exception(cls, pe):
+        """
+        internal factory method to simplify creating one type of ParseException 
+        from another - avoids having __init__ signature conflicts among subclasses
+        """
+        return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement)
+
+    def __getattr__( self, aname ):
+        """supported attributes by name are:
+            - lineno - returns the line number of the exception text
+            - col - returns the column number of the exception text
+            - line - returns the line containing the exception text
+        """
+        if( aname == "lineno" ):
+            return lineno( self.loc, self.pstr )
+        elif( aname in ("col", "column") ):
+            return col( self.loc, self.pstr )
+        elif( aname == "line" ):
+            return line( self.loc, self.pstr )
+        else:
+            raise AttributeError(aname)
+
+    def __str__( self ):
+        return "%s (at char %d), (line:%d, col:%d)" % \
+                ( self.msg, self.loc, self.lineno, self.column )
+    def __repr__( self ):
+        return _ustr(self)
+    def markInputline( self, markerString = ">!<" ):
+        """Extracts the exception line from the input string, and marks
+           the location of the exception with a special symbol.
+        """
+        line_str = self.line
+        line_column = self.column - 1
+        if markerString:
+            line_str = "".join((line_str[:line_column],
+                                markerString, line_str[line_column:]))
+        return line_str.strip()
+    def __dir__(self):
+        return "lineno col line".split() + dir(type(self))
+
+class ParseException(ParseBaseException):
+    """
+    Exception thrown when parse expressions don't match class;
+    supported attributes by name are:
+     - lineno - returns the line number of the exception text
+     - col - returns the column number of the exception text
+     - line - returns the line containing the exception text
+        
+    Example::
+        try:
+            Word(nums).setName("integer").parseString("ABC")
+        except ParseException as pe:
+            print(pe)
+            print("column: {}".format(pe.col))
+            
+    prints::
+       Expected integer (at char 0), (line:1, col:1)
+        column: 1
+    """
+    pass
+
+class ParseFatalException(ParseBaseException):
+    """user-throwable exception thrown when inconsistent parse content
+       is found; stops all parsing immediately"""
+    pass
+
+class ParseSyntaxException(ParseFatalException):
+    """just like L{ParseFatalException}, but thrown internally when an
+       L{ErrorStop} ('-' operator) indicates that parsing is to stop 
+       immediately because an unbacktrackable syntax error has been found"""
+    pass
+
+#~ class ReparseException(ParseBaseException):
+    #~ """Experimental class - parse actions can raise this exception to cause
+       #~ pyparsing to reparse the input string:
+        #~ - with a modified input string, and/or
+        #~ - with a modified start location
+       #~ Set the values of the ReparseException in the constructor, and raise the
+       #~ exception in a parse action to cause pyparsing to use the new string/location.
+       #~ Setting the values as None causes no change to be made.
+       #~ """
+    #~ def __init_( self, newstring, restartLoc ):
+        #~ self.newParseText = newstring
+        #~ self.reparseLoc = restartLoc
+
+class RecursiveGrammarException(Exception):
+    """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive"""
+    def __init__( self, parseElementList ):
+        self.parseElementTrace = parseElementList
+
+    def __str__( self ):
+        return "RecursiveGrammarException: %s" % self.parseElementTrace
+
+class _ParseResultsWithOffset(object):
+    def __init__(self,p1,p2):
+        self.tup = (p1,p2)
+    def __getitem__(self,i):
+        return self.tup[i]
+    def __repr__(self):
+        return repr(self.tup[0])
+    def setOffset(self,i):
+        self.tup = (self.tup[0],i)
+
+class ParseResults(object):
+    """
+    Structured parse results, to provide multiple means of access to the parsed data:
+       - as a list (C{len(results)})
+       - by list index (C{results[0], results[1]}, etc.)
+       - by attribute (C{results.} - see L{ParserElement.setResultsName})
+
+    Example::
+        integer = Word(nums)
+        date_str = (integer.setResultsName("year") + '/' 
+                        + integer.setResultsName("month") + '/' 
+                        + integer.setResultsName("day"))
+        # equivalent form:
+        # date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+
+        # parseString returns a ParseResults object
+        result = date_str.parseString("1999/12/31")
+
+        def test(s, fn=repr):
+            print("%s -> %s" % (s, fn(eval(s))))
+        test("list(result)")
+        test("result[0]")
+        test("result['month']")
+        test("result.day")
+        test("'month' in result")
+        test("'minutes' in result")
+        test("result.dump()", str)
+    prints::
+        list(result) -> ['1999', '/', '12', '/', '31']
+        result[0] -> '1999'
+        result['month'] -> '12'
+        result.day -> '31'
+        'month' in result -> True
+        'minutes' in result -> False
+        result.dump() -> ['1999', '/', '12', '/', '31']
+        - day: 31
+        - month: 12
+        - year: 1999
+    """
+    def __new__(cls, toklist=None, name=None, asList=True, modal=True ):
+        if isinstance(toklist, cls):
+            return toklist
+        retobj = object.__new__(cls)
+        retobj.__doinit = True
+        return retobj
+
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ):
+        if self.__doinit:
+            self.__doinit = False
+            self.__name = None
+            self.__parent = None
+            self.__accumNames = {}
+            self.__asList = asList
+            self.__modal = modal
+            if toklist is None:
+                toklist = []
+            if isinstance(toklist, list):
+                self.__toklist = toklist[:]
+            elif isinstance(toklist, _generatorType):
+                self.__toklist = list(toklist)
+            else:
+                self.__toklist = [toklist]
+            self.__tokdict = dict()
+
+        if name is not None and name:
+            if not modal:
+                self.__accumNames[name] = 0
+            if isinstance(name,int):
+                name = _ustr(name) # will always return a str, but use _ustr for consistency
+            self.__name = name
+            if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])):
+                if isinstance(toklist,basestring):
+                    toklist = [ toklist ]
+                if asList:
+                    if isinstance(toklist,ParseResults):
+                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)
+                    else:
+                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
+                    self[name].__name = name
+                else:
+                    try:
+                        self[name] = toklist[0]
+                    except (KeyError,TypeError,IndexError):
+                        self[name] = toklist
+
+    def __getitem__( self, i ):
+        if isinstance( i, (int,slice) ):
+            return self.__toklist[i]
+        else:
+            if i not in self.__accumNames:
+                return self.__tokdict[i][-1][0]
+            else:
+                return ParseResults([ v[0] for v in self.__tokdict[i] ])
+
+    def __setitem__( self, k, v, isinstance=isinstance ):
+        if isinstance(v,_ParseResultsWithOffset):
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
+            sub = v[0]
+        elif isinstance(k,(int,slice)):
+            self.__toklist[k] = v
+            sub = v
+        else:
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
+            sub = v
+        if isinstance(sub,ParseResults):
+            sub.__parent = wkref(self)
+
+    def __delitem__( self, i ):
+        if isinstance(i,(int,slice)):
+            mylen = len( self.__toklist )
+            del self.__toklist[i]
+
+            # convert int to slice
+            if isinstance(i, int):
+                if i < 0:
+                    i += mylen
+                i = slice(i, i+1)
+            # get removed indices
+            removed = list(range(*i.indices(mylen)))
+            removed.reverse()
+            # fixup indices in token dictionary
+            for name,occurrences in self.__tokdict.items():
+                for j in removed:
+                    for k, (value, position) in enumerate(occurrences):
+                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
+        else:
+            del self.__tokdict[i]
+
+    def __contains__( self, k ):
+        return k in self.__tokdict
+
+    def __len__( self ): return len( self.__toklist )
+    def __bool__(self): return ( not not self.__toklist )
+    __nonzero__ = __bool__
+    def __iter__( self ): return iter( self.__toklist )
+    def __reversed__( self ): return iter( self.__toklist[::-1] )
+    def _iterkeys( self ):
+        if hasattr(self.__tokdict, "iterkeys"):
+            return self.__tokdict.iterkeys()
+        else:
+            return iter(self.__tokdict)
+
+    def _itervalues( self ):
+        return (self[k] for k in self._iterkeys())
+            
+    def _iteritems( self ):
+        return ((k, self[k]) for k in self._iterkeys())
+
+    if PY_3:
+        keys = _iterkeys       
+        """Returns an iterator of all named result keys (Python 3.x only)."""
+
+        values = _itervalues
+        """Returns an iterator of all named result values (Python 3.x only)."""
+
+        items = _iteritems
+        """Returns an iterator of all named result key-value tuples (Python 3.x only)."""
+
+    else:
+        iterkeys = _iterkeys
+        """Returns an iterator of all named result keys (Python 2.x only)."""
+
+        itervalues = _itervalues
+        """Returns an iterator of all named result values (Python 2.x only)."""
+
+        iteritems = _iteritems
+        """Returns an iterator of all named result key-value tuples (Python 2.x only)."""
+
+        def keys( self ):
+            """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x)."""
+            return list(self.iterkeys())
+
+        def values( self ):
+            """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x)."""
+            return list(self.itervalues())
+                
+        def items( self ):
+            """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x)."""
+            return list(self.iteritems())
+
+    def haskeys( self ):
+        """Since keys() returns an iterator, this method is helpful in bypassing
+           code that looks for the existence of any defined results names."""
+        return bool(self.__tokdict)
+        
+    def pop( self, *args, **kwargs):
+        """
+        Removes and returns item at specified index (default=C{last}).
+        Supports both C{list} and C{dict} semantics for C{pop()}. If passed no
+        argument or an integer argument, it will use C{list} semantics
+        and pop tokens from the list of parsed tokens. If passed a 
+        non-integer argument (most likely a string), it will use C{dict}
+        semantics and pop the corresponding value from any defined 
+        results names. A second default return value argument is 
+        supported, just as in C{dict.pop()}.
+
+        Example::
+            def remove_first(tokens):
+                tokens.pop(0)
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']
+            print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321']
+
+            label = Word(alphas)
+            patt = label("LABEL") + OneOrMore(Word(nums))
+            print(patt.parseString("AAB 123 321").dump())
+
+            # Use pop() in a parse action to remove named result (note that corresponding value is not
+            # removed from list form of results)
+            def remove_LABEL(tokens):
+                tokens.pop("LABEL")
+                return tokens
+            patt.addParseAction(remove_LABEL)
+            print(patt.parseString("AAB 123 321").dump())
+        prints::
+            ['AAB', '123', '321']
+            - LABEL: AAB
+
+            ['AAB', '123', '321']
+        """
+        if not args:
+            args = [-1]
+        for k,v in kwargs.items():
+            if k == 'default':
+                args = (args[0], v)
+            else:
+                raise TypeError("pop() got an unexpected keyword argument '%s'" % k)
+        if (isinstance(args[0], int) or 
+                        len(args) == 1 or 
+                        args[0] in self):
+            index = args[0]
+            ret = self[index]
+            del self[index]
+            return ret
+        else:
+            defaultvalue = args[1]
+            return defaultvalue
+
+    def get(self, key, defaultValue=None):
+        """
+        Returns named result matching the given key, or if there is no
+        such name, then returns the given C{defaultValue} or C{None} if no
+        C{defaultValue} is specified.
+
+        Similar to C{dict.get()}.
+        
+        Example::
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           
+
+            result = date_str.parseString("1999/12/31")
+            print(result.get("year")) # -> '1999'
+            print(result.get("hour", "not specified")) # -> 'not specified'
+            print(result.get("hour")) # -> None
+        """
+        if key in self:
+            return self[key]
+        else:
+            return defaultValue
+
+    def insert( self, index, insStr ):
+        """
+        Inserts new element at location index in the list of parsed tokens.
+        
+        Similar to C{list.insert()}.
+
+        Example::
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']
+
+            # use a parse action to insert the parse location in the front of the parsed results
+            def insert_locn(locn, tokens):
+                tokens.insert(0, locn)
+            print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321']
+        """
+        self.__toklist.insert(index, insStr)
+        # fixup indices in token dictionary
+        for name,occurrences in self.__tokdict.items():
+            for k, (value, position) in enumerate(occurrences):
+                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
+
+    def append( self, item ):
+        """
+        Add single element to end of ParseResults list of elements.
+
+        Example::
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']
+            
+            # use a parse action to compute the sum of the parsed integers, and add it to the end
+            def append_sum(tokens):
+                tokens.append(sum(map(int, tokens)))
+            print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444]
+        """
+        self.__toklist.append(item)
+
+    def extend( self, itemseq ):
+        """
+        Add sequence of elements to end of ParseResults list of elements.
+
+        Example::
+            patt = OneOrMore(Word(alphas))
+            
+            # use a parse action to append the reverse of the matched strings, to make a palindrome
+            def make_palindrome(tokens):
+                tokens.extend(reversed([t[::-1] for t in tokens]))
+                return ''.join(tokens)
+            print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl'
+        """
+        if isinstance(itemseq, ParseResults):
+            self += itemseq
+        else:
+            self.__toklist.extend(itemseq)
+
+    def clear( self ):
+        """
+        Clear all elements and results names.
+        """
+        del self.__toklist[:]
+        self.__tokdict.clear()
+
+    def __getattr__( self, name ):
+        try:
+            return self[name]
+        except KeyError:
+            return ""
+            
+        if name in self.__tokdict:
+            if name not in self.__accumNames:
+                return self.__tokdict[name][-1][0]
+            else:
+                return ParseResults([ v[0] for v in self.__tokdict[name] ])
+        else:
+            return ""
+
+    def __add__( self, other ):
+        ret = self.copy()
+        ret += other
+        return ret
+
+    def __iadd__( self, other ):
+        if other.__tokdict:
+            offset = len(self.__toklist)
+            addoffset = lambda a: offset if a<0 else a+offset
+            otheritems = other.__tokdict.items()
+            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
+                                for (k,vlist) in otheritems for v in vlist]
+            for k,v in otherdictitems:
+                self[k] = v
+                if isinstance(v[0],ParseResults):
+                    v[0].__parent = wkref(self)
+            
+        self.__toklist += other.__toklist
+        self.__accumNames.update( other.__accumNames )
+        return self
+
+    def __radd__(self, other):
+        if isinstance(other,int) and other == 0:
+            # useful for merging many ParseResults using sum() builtin
+            return self.copy()
+        else:
+            # this may raise a TypeError - so be it
+            return other + self
+        
+    def __repr__( self ):
+        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
+
+    def __str__( self ):
+        return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']'
+
+    def _asStringList( self, sep='' ):
+        out = []
+        for item in self.__toklist:
+            if out and sep:
+                out.append(sep)
+            if isinstance( item, ParseResults ):
+                out += item._asStringList()
+            else:
+                out.append( _ustr(item) )
+        return out
+
+    def asList( self ):
+        """
+        Returns the parse results as a nested list of matching tokens, all converted to strings.
+
+        Example::
+            patt = OneOrMore(Word(alphas))
+            result = patt.parseString("sldkj lsdkj sldkj")
+            # even though the result prints in string-like form, it is actually a pyparsing ParseResults
+            print(type(result), result) # ->  ['sldkj', 'lsdkj', 'sldkj']
+            
+            # Use asList() to create an actual list
+            result_list = result.asList()
+            print(type(result_list), result_list) # ->  ['sldkj', 'lsdkj', 'sldkj']
+        """
+        return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist]
+
+    def asDict( self ):
+        """
+        Returns the named parse results as a nested dictionary.
+
+        Example::
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+            
+            result = date_str.parseString('12/31/1999')
+            print(type(result), repr(result)) # ->  (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]})
+            
+            result_dict = result.asDict()
+            print(type(result_dict), repr(result_dict)) # ->  {'day': '1999', 'year': '12', 'month': '31'}
+
+            # even though a ParseResults supports dict-like access, sometime you just need to have a dict
+            import json
+            print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable
+            print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"}
+        """
+        if PY_3:
+            item_fn = self.items
+        else:
+            item_fn = self.iteritems
+            
+        def toItem(obj):
+            if isinstance(obj, ParseResults):
+                if obj.haskeys():
+                    return obj.asDict()
+                else:
+                    return [toItem(v) for v in obj]
+            else:
+                return obj
+                
+        return dict((k,toItem(v)) for k,v in item_fn())
+
+    def copy( self ):
+        """
+        Returns a new copy of a C{ParseResults} object.
+        """
+        ret = ParseResults( self.__toklist )
+        ret.__tokdict = self.__tokdict.copy()
+        ret.__parent = self.__parent
+        ret.__accumNames.update( self.__accumNames )
+        ret.__name = self.__name
+        return ret
+
+    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
+        """
+        (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names.
+        """
+        nl = "\n"
+        out = []
+        namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items()
+                                                            for v in vlist)
+        nextLevelIndent = indent + "  "
+
+        # collapse out indents if formatting is not desired
+        if not formatted:
+            indent = ""
+            nextLevelIndent = ""
+            nl = ""
+
+        selfTag = None
+        if doctag is not None:
+            selfTag = doctag
+        else:
+            if self.__name:
+                selfTag = self.__name
+
+        if not selfTag:
+            if namedItemsOnly:
+                return ""
+            else:
+                selfTag = "ITEM"
+
+        out += [ nl, indent, "<", selfTag, ">" ]
+
+        for i,res in enumerate(self.__toklist):
+            if isinstance(res,ParseResults):
+                if i in namedItems:
+                    out += [ res.asXML(namedItems[i],
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+                else:
+                    out += [ res.asXML(None,
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+            else:
+                # individual token, see if there is a name for it
+                resTag = None
+                if i in namedItems:
+                    resTag = namedItems[i]
+                if not resTag:
+                    if namedItemsOnly:
+                        continue
+                    else:
+                        resTag = "ITEM"
+                xmlBodyText = _xml_escape(_ustr(res))
+                out += [ nl, nextLevelIndent, "<", resTag, ">",
+                                                xmlBodyText,
+                                                "" ]
+
+        out += [ nl, indent, "" ]
+        return "".join(out)
+
+    def __lookup(self,sub):
+        for k,vlist in self.__tokdict.items():
+            for v,loc in vlist:
+                if sub is v:
+                    return k
+        return None
+
+    def getName(self):
+        r"""
+        Returns the results name for this token expression. Useful when several 
+        different expressions might match at a particular location.
+
+        Example::
+            integer = Word(nums)
+            ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d")
+            house_number_expr = Suppress('#') + Word(nums, alphanums)
+            user_data = (Group(house_number_expr)("house_number") 
+                        | Group(ssn_expr)("ssn")
+                        | Group(integer)("age"))
+            user_info = OneOrMore(user_data)
+            
+            result = user_info.parseString("22 111-22-3333 #221B")
+            for item in result:
+                print(item.getName(), ':', item[0])
+        prints::
+            age : 22
+            ssn : 111-22-3333
+            house_number : 221B
+        """
+        if self.__name:
+            return self.__name
+        elif self.__parent:
+            par = self.__parent()
+            if par:
+                return par.__lookup(self)
+            else:
+                return None
+        elif (len(self) == 1 and
+               len(self.__tokdict) == 1 and
+               next(iter(self.__tokdict.values()))[0][1] in (0,-1)):
+            return next(iter(self.__tokdict.keys()))
+        else:
+            return None
+
+    def dump(self, indent='', depth=0, full=True):
+        """
+        Diagnostic method for listing out the contents of a C{ParseResults}.
+        Accepts an optional C{indent} argument so that this string can be embedded
+        in a nested display of other data.
+
+        Example::
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+            
+            result = date_str.parseString('12/31/1999')
+            print(result.dump())
+        prints::
+            ['12', '/', '31', '/', '1999']
+            - day: 1999
+            - month: 31
+            - year: 12
+        """
+        out = []
+        NL = '\n'
+        out.append( indent+_ustr(self.asList()) )
+        if full:
+            if self.haskeys():
+                items = sorted((str(k), v) for k,v in self.items())
+                for k,v in items:
+                    if out:
+                        out.append(NL)
+                    out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
+                    if isinstance(v,ParseResults):
+                        if v:
+                            out.append( v.dump(indent,depth+1) )
+                        else:
+                            out.append(_ustr(v))
+                    else:
+                        out.append(repr(v))
+            elif any(isinstance(vv,ParseResults) for vv in self):
+                v = self
+                for i,vv in enumerate(v):
+                    if isinstance(vv,ParseResults):
+                        out.append("\n%s%s[%d]:\n%s%s%s" % (indent,('  '*(depth)),i,indent,('  '*(depth+1)),vv.dump(indent,depth+1) ))
+                    else:
+                        out.append("\n%s%s[%d]:\n%s%s%s" % (indent,('  '*(depth)),i,indent,('  '*(depth+1)),_ustr(vv)))
+            
+        return "".join(out)
+
+    def pprint(self, *args, **kwargs):
+        """
+        Pretty-printer for parsed results as a list, using the C{pprint} module.
+        Accepts additional positional or keyword args as defined for the 
+        C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint})
+
+        Example::
+            ident = Word(alphas, alphanums)
+            num = Word(nums)
+            func = Forward()
+            term = ident | num | Group('(' + func + ')')
+            func <<= ident + Group(Optional(delimitedList(term)))
+            result = func.parseString("fna a,b,(fnb c,d,200),100")
+            result.pprint(width=40)
+        prints::
+            ['fna',
+             ['a',
+              'b',
+              ['(', 'fnb', ['c', 'd', '200'], ')'],
+              '100']]
+        """
+        pprint.pprint(self.asList(), *args, **kwargs)
+
+    # add support for pickle protocol
+    def __getstate__(self):
+        return ( self.__toklist,
+                 ( self.__tokdict.copy(),
+                   self.__parent is not None and self.__parent() or None,
+                   self.__accumNames,
+                   self.__name ) )
+
+    def __setstate__(self,state):
+        self.__toklist = state[0]
+        (self.__tokdict,
+         par,
+         inAccumNames,
+         self.__name) = state[1]
+        self.__accumNames = {}
+        self.__accumNames.update(inAccumNames)
+        if par is not None:
+            self.__parent = wkref(par)
+        else:
+            self.__parent = None
+
+    def __getnewargs__(self):
+        return self.__toklist, self.__name, self.__asList, self.__modal
+
+    def __dir__(self):
+        return (dir(type(self)) + list(self.keys()))
+
+MutableMapping.register(ParseResults)
+
+def col (loc,strg):
+    """Returns current column within a string, counting newlines as line separators.
+   The first column is number 1.
+
+   Note: the default parsing behavior is to expand tabs in the input string
+   before starting the parsing process.  See L{I{ParserElement.parseString}} for more information
+   on parsing strings containing C{}s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    s = strg
+    return 1 if 0} for more information
+   on parsing strings containing C{}s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    return strg.count("\n",0,loc) + 1
+
+def line( loc, strg ):
+    """Returns the line of text containing loc within a string, counting newlines as line separators.
+       """
+    lastCR = strg.rfind("\n", 0, loc)
+    nextCR = strg.find("\n", loc)
+    if nextCR >= 0:
+        return strg[lastCR+1:nextCR]
+    else:
+        return strg[lastCR+1:]
+
+def _defaultStartDebugAction( instring, loc, expr ):
+    print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))
+
+def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
+    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
+
+def _defaultExceptionDebugAction( instring, loc, expr, exc ):
+    print ("Exception raised:" + _ustr(exc))
+
+def nullDebugAction(*args):
+    """'Do-nothing' debug action, to suppress debugging output during parsing."""
+    pass
+
+# Only works on Python 3.x - nonlocal is toxic to Python 2 installs
+#~ 'decorator to trim function calls to match the arity of the target'
+#~ def _trim_arity(func, maxargs=3):
+    #~ if func in singleArgBuiltins:
+        #~ return lambda s,l,t: func(t)
+    #~ limit = 0
+    #~ foundArity = False
+    #~ def wrapper(*args):
+        #~ nonlocal limit,foundArity
+        #~ while 1:
+            #~ try:
+                #~ ret = func(*args[limit:])
+                #~ foundArity = True
+                #~ return ret
+            #~ except TypeError:
+                #~ if limit == maxargs or foundArity:
+                    #~ raise
+                #~ limit += 1
+                #~ continue
+    #~ return wrapper
+
+# this version is Python 2.x-3.x cross-compatible
+'decorator to trim function calls to match the arity of the target'
+def _trim_arity(func, maxargs=2):
+    if func in singleArgBuiltins:
+        return lambda s,l,t: func(t)
+    limit = [0]
+    foundArity = [False]
+    
+    # traceback return data structure changed in Py3.5 - normalize back to plain tuples
+    if system_version[:2] >= (3,5):
+        def extract_stack(limit=0):
+            # special handling for Python 3.5.0 - extra deep call stack by 1
+            offset = -3 if system_version == (3,5,0) else -2
+            frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset]
+            return [frame_summary[:2]]
+        def extract_tb(tb, limit=0):
+            frames = traceback.extract_tb(tb, limit=limit)
+            frame_summary = frames[-1]
+            return [frame_summary[:2]]
+    else:
+        extract_stack = traceback.extract_stack
+        extract_tb = traceback.extract_tb
+    
+    # synthesize what would be returned by traceback.extract_stack at the call to 
+    # user's parse action 'func', so that we don't incur call penalty at parse time
+    
+    LINE_DIFF = 6
+    # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND 
+    # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!!
+    this_line = extract_stack(limit=2)[-1]
+    pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF)
+
+    def wrapper(*args):
+        while 1:
+            try:
+                ret = func(*args[limit[0]:])
+                foundArity[0] = True
+                return ret
+            except TypeError:
+                # re-raise TypeErrors if they did not come from our arity testing
+                if foundArity[0]:
+                    raise
+                else:
+                    try:
+                        tb = sys.exc_info()[-1]
+                        if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth:
+                            raise
+                    finally:
+                        del tb
+
+                if limit[0] <= maxargs:
+                    limit[0] += 1
+                    continue
+                raise
+
+    # copy func name to wrapper for sensible debug output
+    func_name = ""
+    try:
+        func_name = getattr(func, '__name__', 
+                            getattr(func, '__class__').__name__)
+    except Exception:
+        func_name = str(func)
+    wrapper.__name__ = func_name
+
+    return wrapper
+
+class ParserElement(object):
+    """Abstract base level parser element class."""
+    DEFAULT_WHITE_CHARS = " \n\t\r"
+    verbose_stacktrace = False
+
+    @staticmethod
+    def setDefaultWhitespaceChars( chars ):
+        r"""
+        Overrides the default whitespace chars
+
+        Example::
+            # default whitespace chars are space,  and newline
+            OneOrMore(Word(alphas)).parseString("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']
+            
+            # change to just treat newline as significant
+            ParserElement.setDefaultWhitespaceChars(" \t")
+            OneOrMore(Word(alphas)).parseString("abc def\nghi jkl")  # -> ['abc', 'def']
+        """
+        ParserElement.DEFAULT_WHITE_CHARS = chars
+
+    @staticmethod
+    def inlineLiteralsUsing(cls):
+        """
+        Set class to be used for inclusion of string literals into a parser.
+        
+        Example::
+            # default literal class used is Literal
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           
+
+            date_str.parseString("1999/12/31")  # -> ['1999', '/', '12', '/', '31']
+
+
+            # change to Suppress
+            ParserElement.inlineLiteralsUsing(Suppress)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           
+
+            date_str.parseString("1999/12/31")  # -> ['1999', '12', '31']
+        """
+        ParserElement._literalStringClass = cls
+
+    def __init__( self, savelist=False ):
+        self.parseAction = list()
+        self.failAction = None
+        #~ self.name = ""  # don't define self.name, let subclasses try/except upcall
+        self.strRepr = None
+        self.resultsName = None
+        self.saveAsList = savelist
+        self.skipWhitespace = True
+        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        self.copyDefaultWhiteChars = True
+        self.mayReturnEmpty = False # used when checking for left-recursion
+        self.keepTabs = False
+        self.ignoreExprs = list()
+        self.debug = False
+        self.streamlined = False
+        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
+        self.errmsg = ""
+        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
+        self.debugActions = ( None, None, None ) #custom debug actions
+        self.re = None
+        self.callPreparse = True # used to avoid redundant calls to preParse
+        self.callDuringTry = False
+
+    def copy( self ):
+        """
+        Make a copy of this C{ParserElement}.  Useful for defining different parse actions
+        for the same parsing pattern, using copies of the original parse element.
+        
+        Example::
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))
+            integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K")
+            integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")
+            
+            print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M"))
+        prints::
+            [5120, 100, 655360, 268435456]
+        Equivalent form of C{expr.copy()} is just C{expr()}::
+            integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")
+        """
+        cpy = copy.copy( self )
+        cpy.parseAction = self.parseAction[:]
+        cpy.ignoreExprs = self.ignoreExprs[:]
+        if self.copyDefaultWhiteChars:
+            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        return cpy
+
+    def setName( self, name ):
+        """
+        Define name for this expression, makes debugging and exception messages clearer.
+        
+        Example::
+            Word(nums).parseString("ABC")  # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1)
+            Word(nums).setName("integer").parseString("ABC")  # -> Exception: Expected integer (at char 0), (line:1, col:1)
+        """
+        self.name = name
+        self.errmsg = "Expected " + self.name
+        if hasattr(self,"exception"):
+            self.exception.msg = self.errmsg
+        return self
+
+    def setResultsName( self, name, listAllMatches=False ):
+        """
+        Define name for referencing matching tokens as a nested attribute
+        of the returned parse results.
+        NOTE: this returns a *copy* of the original C{ParserElement} object;
+        this is so that the client can define a basic element, such as an
+        integer, and reference it in multiple places with different names.
+
+        You can also set results names using the abbreviated syntax,
+        C{expr("name")} in place of C{expr.setResultsName("name")} - 
+        see L{I{__call__}<__call__>}.
+
+        Example::
+            date_str = (integer.setResultsName("year") + '/' 
+                        + integer.setResultsName("month") + '/' 
+                        + integer.setResultsName("day"))
+
+            # equivalent form:
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+        """
+        newself = self.copy()
+        if name.endswith("*"):
+            name = name[:-1]
+            listAllMatches=True
+        newself.resultsName = name
+        newself.modalResults = not listAllMatches
+        return newself
+
+    def setBreak(self,breakFlag = True):
+        """Method to invoke the Python pdb debugger when this element is
+           about to be parsed. Set C{breakFlag} to True to enable, False to
+           disable.
+        """
+        if breakFlag:
+            _parseMethod = self._parse
+            def breaker(instring, loc, doActions=True, callPreParse=True):
+                import pdb
+                pdb.set_trace()
+                return _parseMethod( instring, loc, doActions, callPreParse )
+            breaker._originalParseMethod = _parseMethod
+            self._parse = breaker
+        else:
+            if hasattr(self._parse,"_originalParseMethod"):
+                self._parse = self._parse._originalParseMethod
+        return self
+
+    def setParseAction( self, *fns, **kwargs ):
+        """
+        Define one or more actions to perform when successfully matching parse element definition.
+        Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},
+        C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:
+         - s   = the original string being parsed (see note below)
+         - loc = the location of the matching substring
+         - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object
+        If the functions in fns modify the tokens, they can return them as the return
+        value from fn, and the modified list of tokens will replace the original.
+        Otherwise, fn does not need to return any value.
+
+        Optional keyword arguments:
+         - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing
+
+        Note: the default parsing behavior is to expand tabs in the input string
+        before starting the parsing process.  See L{I{parseString}} for more information
+        on parsing strings containing C{}s, and suggested methods to maintain a
+        consistent view of the parsed string, the parse location, and line and column
+        positions within the parsed string.
+        
+        Example::
+            integer = Word(nums)
+            date_str = integer + '/' + integer + '/' + integer
+
+            date_str.parseString("1999/12/31")  # -> ['1999', '/', '12', '/', '31']
+
+            # use parse action to convert to ints at parse time
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))
+            date_str = integer + '/' + integer + '/' + integer
+
+            # note that integer fields are now ints, not strings
+            date_str.parseString("1999/12/31")  # -> [1999, '/', 12, '/', 31]
+        """
+        self.parseAction = list(map(_trim_arity, list(fns)))
+        self.callDuringTry = kwargs.get("callDuringTry", False)
+        return self
+
+    def addParseAction( self, *fns, **kwargs ):
+        """
+        Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}}.
+        
+        See examples in L{I{copy}}.
+        """
+        self.parseAction += list(map(_trim_arity, list(fns)))
+        self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False)
+        return self
+
+    def addCondition(self, *fns, **kwargs):
+        """Add a boolean predicate function to expression's list of parse actions. See 
+        L{I{setParseAction}} for function call signatures. Unlike C{setParseAction}, 
+        functions passed to C{addCondition} need to return boolean success/fail of the condition.
+
+        Optional keyword arguments:
+         - message = define a custom message to be used in the raised exception
+         - fatal   = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException
+         
+        Example::
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))
+            year_int = integer.copy()
+            year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later")
+            date_str = year_int + '/' + integer + '/' + integer
+
+            result = date_str.parseString("1999/12/31")  # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1)
+        """
+        msg = kwargs.get("message", "failed user-defined condition")
+        exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException
+        for fn in fns:
+            def pa(s,l,t):
+                if not bool(_trim_arity(fn)(s,l,t)):
+                    raise exc_type(s,l,msg)
+            self.parseAction.append(pa)
+        self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False)
+        return self
+
+    def setFailAction( self, fn ):
+        """Define action to perform if parsing fails at this expression.
+           Fail acton fn is a callable function that takes the arguments
+           C{fn(s,loc,expr,err)} where:
+            - s = string being parsed
+            - loc = location where expression match was attempted and failed
+            - expr = the parse expression that failed
+            - err = the exception thrown
+           The function returns no value.  It may throw C{L{ParseFatalException}}
+           if it is desired to stop parsing immediately."""
+        self.failAction = fn
+        return self
+
+    def _skipIgnorables( self, instring, loc ):
+        exprsFound = True
+        while exprsFound:
+            exprsFound = False
+            for e in self.ignoreExprs:
+                try:
+                    while 1:
+                        loc,dummy = e._parse( instring, loc )
+                        exprsFound = True
+                except ParseException:
+                    pass
+        return loc
+
+    def preParse( self, instring, loc ):
+        if self.ignoreExprs:
+            loc = self._skipIgnorables( instring, loc )
+
+        if self.skipWhitespace:
+            wt = self.whiteChars
+            instrlen = len(instring)
+            while loc < instrlen and instring[loc] in wt:
+                loc += 1
+
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        return loc, []
+
+    def postParse( self, instring, loc, tokenlist ):
+        return tokenlist
+
+    #~ @profile
+    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
+        debugging = ( self.debug ) #and doActions )
+
+        if debugging or self.failAction:
+            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
+            if (self.debugActions[0] ):
+                self.debugActions[0]( instring, loc, self )
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = preloc
+            try:
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            except ParseBaseException as err:
+                #~ print ("Exception raised:", err)
+                if self.debugActions[2]:
+                    self.debugActions[2]( instring, tokensStart, self, err )
+                if self.failAction:
+                    self.failAction( instring, tokensStart, self, err )
+                raise
+        else:
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = preloc
+            if self.mayIndexError or preloc >= len(instring):
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            else:
+                loc,tokens = self.parseImpl( instring, preloc, doActions )
+
+        tokens = self.postParse( instring, loc, tokens )
+
+        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
+        if self.parseAction and (doActions or self.callDuringTry):
+            if debugging:
+                try:
+                    for fn in self.parseAction:
+                        tokens = fn( instring, tokensStart, retTokens )
+                        if tokens is not None:
+                            retTokens = ParseResults( tokens,
+                                                      self.resultsName,
+                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                      modal=self.modalResults )
+                except ParseBaseException as err:
+                    #~ print "Exception raised in user parse action:", err
+                    if (self.debugActions[2] ):
+                        self.debugActions[2]( instring, tokensStart, self, err )
+                    raise
+            else:
+                for fn in self.parseAction:
+                    tokens = fn( instring, tokensStart, retTokens )
+                    if tokens is not None:
+                        retTokens = ParseResults( tokens,
+                                                  self.resultsName,
+                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                  modal=self.modalResults )
+        if debugging:
+            #~ print ("Matched",self,"->",retTokens.asList())
+            if (self.debugActions[1] ):
+                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
+
+        return loc, retTokens
+
+    def tryParse( self, instring, loc ):
+        try:
+            return self._parse( instring, loc, doActions=False )[0]
+        except ParseFatalException:
+            raise ParseException( instring, loc, self.errmsg, self)
+    
+    def canParseNext(self, instring, loc):
+        try:
+            self.tryParse(instring, loc)
+        except (ParseException, IndexError):
+            return False
+        else:
+            return True
+
+    class _UnboundedCache(object):
+        def __init__(self):
+            cache = {}
+            self.not_in_cache = not_in_cache = object()
+
+            def get(self, key):
+                return cache.get(key, not_in_cache)
+
+            def set(self, key, value):
+                cache[key] = value
+
+            def clear(self):
+                cache.clear()
+                
+            def cache_len(self):
+                return len(cache)
+
+            self.get = types.MethodType(get, self)
+            self.set = types.MethodType(set, self)
+            self.clear = types.MethodType(clear, self)
+            self.__len__ = types.MethodType(cache_len, self)
+
+    if _OrderedDict is not None:
+        class _FifoCache(object):
+            def __init__(self, size):
+                self.not_in_cache = not_in_cache = object()
+
+                cache = _OrderedDict()
+
+                def get(self, key):
+                    return cache.get(key, not_in_cache)
+
+                def set(self, key, value):
+                    cache[key] = value
+                    while len(cache) > size:
+                        try:
+                            cache.popitem(False)
+                        except KeyError:
+                            pass
+
+                def clear(self):
+                    cache.clear()
+
+                def cache_len(self):
+                    return len(cache)
+
+                self.get = types.MethodType(get, self)
+                self.set = types.MethodType(set, self)
+                self.clear = types.MethodType(clear, self)
+                self.__len__ = types.MethodType(cache_len, self)
+
+    else:
+        class _FifoCache(object):
+            def __init__(self, size):
+                self.not_in_cache = not_in_cache = object()
+
+                cache = {}
+                key_fifo = collections.deque([], size)
+
+                def get(self, key):
+                    return cache.get(key, not_in_cache)
+
+                def set(self, key, value):
+                    cache[key] = value
+                    while len(key_fifo) > size:
+                        cache.pop(key_fifo.popleft(), None)
+                    key_fifo.append(key)
+
+                def clear(self):
+                    cache.clear()
+                    key_fifo.clear()
+
+                def cache_len(self):
+                    return len(cache)
+
+                self.get = types.MethodType(get, self)
+                self.set = types.MethodType(set, self)
+                self.clear = types.MethodType(clear, self)
+                self.__len__ = types.MethodType(cache_len, self)
+
+    # argument cache for optimizing repeated calls when backtracking through recursive expressions
+    packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail
+    packrat_cache_lock = RLock()
+    packrat_cache_stats = [0, 0]
+
+    # this method gets repeatedly called during backtracking with the same arguments -
+    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
+    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
+        HIT, MISS = 0, 1
+        lookup = (self, instring, loc, callPreParse, doActions)
+        with ParserElement.packrat_cache_lock:
+            cache = ParserElement.packrat_cache
+            value = cache.get(lookup)
+            if value is cache.not_in_cache:
+                ParserElement.packrat_cache_stats[MISS] += 1
+                try:
+                    value = self._parseNoCache(instring, loc, doActions, callPreParse)
+                except ParseBaseException as pe:
+                    # cache a copy of the exception, without the traceback
+                    cache.set(lookup, pe.__class__(*pe.args))
+                    raise
+                else:
+                    cache.set(lookup, (value[0], value[1].copy()))
+                    return value
+            else:
+                ParserElement.packrat_cache_stats[HIT] += 1
+                if isinstance(value, Exception):
+                    raise value
+                return (value[0], value[1].copy())
+
+    _parse = _parseNoCache
+
+    @staticmethod
+    def resetCache():
+        ParserElement.packrat_cache.clear()
+        ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats)
+
+    _packratEnabled = False
+    @staticmethod
+    def enablePackrat(cache_size_limit=128):
+        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
+           Repeated parse attempts at the same string location (which happens
+           often in many complex grammars) can immediately return a cached value,
+           instead of re-executing parsing/validating code.  Memoizing is done of
+           both valid results and parsing exceptions.
+           
+           Parameters:
+            - cache_size_limit - (default=C{128}) - if an integer value is provided
+              will limit the size of the packrat cache; if None is passed, then
+              the cache size will be unbounded; if 0 is passed, the cache will
+              be effectively disabled.
+            
+           This speedup may break existing programs that use parse actions that
+           have side-effects.  For this reason, packrat parsing is disabled when
+           you first import pyparsing.  To activate the packrat feature, your
+           program must call the class method C{ParserElement.enablePackrat()}.  If
+           your program uses C{psyco} to "compile as you go", you must call
+           C{enablePackrat} before calling C{psyco.full()}.  If you do not do this,
+           Python will crash.  For best results, call C{enablePackrat()} immediately
+           after importing pyparsing.
+           
+           Example::
+               import pyparsing
+               pyparsing.ParserElement.enablePackrat()
+        """
+        if not ParserElement._packratEnabled:
+            ParserElement._packratEnabled = True
+            if cache_size_limit is None:
+                ParserElement.packrat_cache = ParserElement._UnboundedCache()
+            else:
+                ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit)
+            ParserElement._parse = ParserElement._parseCache
+
+    def parseString( self, instring, parseAll=False ):
+        """
+        Execute the parse expression with the given string.
+        This is the main interface to the client code, once the complete
+        expression has been built.
+
+        If you want the grammar to require that the entire input string be
+        successfully parsed, then set C{parseAll} to True (equivalent to ending
+        the grammar with C{L{StringEnd()}}).
+
+        Note: C{parseString} implicitly calls C{expandtabs()} on the input string,
+        in order to report proper column numbers in parse actions.
+        If the input string contains tabs and
+        the grammar uses parse actions that use the C{loc} argument to index into the
+        string being parsed, you can ensure you have a consistent view of the input
+        string by:
+         - calling C{parseWithTabs} on your grammar before calling C{parseString}
+           (see L{I{parseWithTabs}})
+         - define your parse action using the full C{(s,loc,toks)} signature, and
+           reference the input string using the parse action's C{s} argument
+         - explicitly expand the tabs in your input string before calling
+           C{parseString}
+        
+        Example::
+            Word('a').parseString('aaaaabaaa')  # -> ['aaaaa']
+            Word('a').parseString('aaaaabaaa', parseAll=True)  # -> Exception: Expected end of text
+        """
+        ParserElement.resetCache()
+        if not self.streamlined:
+            self.streamline()
+            #~ self.saveAsList = True
+        for e in self.ignoreExprs:
+            e.streamline()
+        if not self.keepTabs:
+            instring = instring.expandtabs()
+        try:
+            loc, tokens = self._parse( instring, 0 )
+            if parseAll:
+                loc = self.preParse( instring, loc )
+                se = Empty() + StringEnd()
+                se._parse( instring, loc )
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+        else:
+            return tokens
+
+    def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ):
+        """
+        Scan the input string for expression matches.  Each match will return the
+        matching tokens, start location, and end location.  May be called with optional
+        C{maxMatches} argument, to clip scanning after 'n' matches are found.  If
+        C{overlap} is specified, then overlapping matches will be reported.
+
+        Note that the start and end locations are reported relative to the string
+        being parsed.  See L{I{parseString}} for more information on parsing
+        strings with embedded tabs.
+
+        Example::
+            source = "sldjf123lsdjjkf345sldkjf879lkjsfd987"
+            print(source)
+            for tokens,start,end in Word(alphas).scanString(source):
+                print(' '*start + '^'*(end-start))
+                print(' '*start + tokens[0])
+        
+        prints::
+        
+            sldjf123lsdjjkf345sldkjf879lkjsfd987
+            ^^^^^
+            sldjf
+                    ^^^^^^^
+                    lsdjjkf
+                              ^^^^^^
+                              sldkjf
+                                       ^^^^^^
+                                       lkjsfd
+        """
+        if not self.streamlined:
+            self.streamline()
+        for e in self.ignoreExprs:
+            e.streamline()
+
+        if not self.keepTabs:
+            instring = _ustr(instring).expandtabs()
+        instrlen = len(instring)
+        loc = 0
+        preparseFn = self.preParse
+        parseFn = self._parse
+        ParserElement.resetCache()
+        matches = 0
+        try:
+            while loc <= instrlen and matches < maxMatches:
+                try:
+                    preloc = preparseFn( instring, loc )
+                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
+                except ParseException:
+                    loc = preloc+1
+                else:
+                    if nextLoc > loc:
+                        matches += 1
+                        yield tokens, preloc, nextLoc
+                        if overlap:
+                            nextloc = preparseFn( instring, loc )
+                            if nextloc > loc:
+                                loc = nextLoc
+                            else:
+                                loc += 1
+                        else:
+                            loc = nextLoc
+                    else:
+                        loc = preloc+1
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def transformString( self, instring ):
+        """
+        Extension to C{L{scanString}}, to modify matching text with modified tokens that may
+        be returned from a parse action.  To use C{transformString}, define a grammar and
+        attach a parse action to it that modifies the returned token list.
+        Invoking C{transformString()} on a target string will then scan for matches,
+        and replace the matched text patterns according to the logic in the parse
+        action.  C{transformString()} returns the resulting transformed string.
+        
+        Example::
+            wd = Word(alphas)
+            wd.setParseAction(lambda toks: toks[0].title())
+            
+            print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york."))
+        Prints::
+            Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York.
+        """
+        out = []
+        lastE = 0
+        # force preservation of s, to minimize unwanted transformation of string, and to
+        # keep string locs straight between transformString and scanString
+        self.keepTabs = True
+        try:
+            for t,s,e in self.scanString( instring ):
+                out.append( instring[lastE:s] )
+                if t:
+                    if isinstance(t,ParseResults):
+                        out += t.asList()
+                    elif isinstance(t,list):
+                        out += t
+                    else:
+                        out.append(t)
+                lastE = e
+            out.append(instring[lastE:])
+            out = [o for o in out if o]
+            return "".join(map(_ustr,_flatten(out)))
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def searchString( self, instring, maxMatches=_MAX_INT ):
+        """
+        Another extension to C{L{scanString}}, simplifying the access to the tokens found
+        to match the given parse expression.  May be called with optional
+        C{maxMatches} argument, to clip searching after 'n' matches are found.
+        
+        Example::
+            # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters
+            cap_word = Word(alphas.upper(), alphas.lower())
+            
+            print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))
+
+            # the sum() builtin can be used to merge results into a single ParseResults object
+            print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")))
+        prints::
+            [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']]
+            ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity']
+        """
+        try:
+            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False):
+        """
+        Generator method to split a string using the given expression as a separator.
+        May be called with optional C{maxsplit} argument, to limit the number of splits;
+        and the optional C{includeSeparators} argument (default=C{False}), if the separating
+        matching text should be included in the split results.
+        
+        Example::        
+            punc = oneOf(list(".,;:/-!?"))
+            print(list(punc.split("This, this?, this sentence, is badly punctuated!")))
+        prints::
+            ['This', ' this', '', ' this sentence', ' is badly punctuated', '']
+        """
+        splits = 0
+        last = 0
+        for t,s,e in self.scanString(instring, maxMatches=maxsplit):
+            yield instring[last:s]
+            if includeSeparators:
+                yield t[0]
+            last = e
+        yield instring[last:]
+
+    def __add__(self, other ):
+        """
+        Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement
+        converts them to L{Literal}s by default.
+        
+        Example::
+            greet = Word(alphas) + "," + Word(alphas) + "!"
+            hello = "Hello, World!"
+            print (hello, "->", greet.parseString(hello))
+        Prints::
+            Hello, World! -> ['Hello', ',', 'World', '!']
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return And( [ self, other ] )
+
+    def __radd__(self, other ):
+        """
+        Implementation of + operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other + self
+
+    def __sub__(self, other):
+        """
+        Implementation of - operator, returns C{L{And}} with error stop
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return self + And._ErrorStop() + other
+
+    def __rsub__(self, other ):
+        """
+        Implementation of - operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other - self
+
+    def __mul__(self,other):
+        """
+        Implementation of * operator, allows use of C{expr * 3} in place of
+        C{expr + expr + expr}.  Expressions may also me multiplied by a 2-integer
+        tuple, similar to C{{min,max}} multipliers in regular expressions.  Tuples
+        may also include C{None} as in:
+         - C{expr*(n,None)} or C{expr*(n,)} is equivalent
+              to C{expr*n + L{ZeroOrMore}(expr)}
+              (read as "at least n instances of C{expr}")
+         - C{expr*(None,n)} is equivalent to C{expr*(0,n)}
+              (read as "0 to n instances of C{expr}")
+         - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)}
+         - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)}
+
+        Note that C{expr*(None,n)} does not raise an exception if
+        more than n exprs exist in the input stream; that is,
+        C{expr*(None,n)} does not enforce a maximum number of expr
+        occurrences.  If this behavior is desired, then write
+        C{expr*(None,n) + ~expr}
+        """
+        if isinstance(other,int):
+            minElements, optElements = other,0
+        elif isinstance(other,tuple):
+            other = (other + (None, None))[:2]
+            if other[0] is None:
+                other = (0, other[1])
+            if isinstance(other[0],int) and other[1] is None:
+                if other[0] == 0:
+                    return ZeroOrMore(self)
+                if other[0] == 1:
+                    return OneOrMore(self)
+                else:
+                    return self*other[0] + ZeroOrMore(self)
+            elif isinstance(other[0],int) and isinstance(other[1],int):
+                minElements, optElements = other
+                optElements -= minElements
+            else:
+                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
+        else:
+            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
+
+        if minElements < 0:
+            raise ValueError("cannot multiply ParserElement by negative value")
+        if optElements < 0:
+            raise ValueError("second tuple value must be greater or equal to first tuple value")
+        if minElements == optElements == 0:
+            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
+
+        if (optElements):
+            def makeOptionalList(n):
+                if n>1:
+                    return Optional(self + makeOptionalList(n-1))
+                else:
+                    return Optional(self)
+            if minElements:
+                if minElements == 1:
+                    ret = self + makeOptionalList(optElements)
+                else:
+                    ret = And([self]*minElements) + makeOptionalList(optElements)
+            else:
+                ret = makeOptionalList(optElements)
+        else:
+            if minElements == 1:
+                ret = self
+            else:
+                ret = And([self]*minElements)
+        return ret
+
+    def __rmul__(self, other):
+        return self.__mul__(other)
+
+    def __or__(self, other ):
+        """
+        Implementation of | operator - returns C{L{MatchFirst}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return MatchFirst( [ self, other ] )
+
+    def __ror__(self, other ):
+        """
+        Implementation of | operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other | self
+
+    def __xor__(self, other ):
+        """
+        Implementation of ^ operator - returns C{L{Or}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Or( [ self, other ] )
+
+    def __rxor__(self, other ):
+        """
+        Implementation of ^ operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other ^ self
+
+    def __and__(self, other ):
+        """
+        Implementation of & operator - returns C{L{Each}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Each( [ self, other ] )
+
+    def __rand__(self, other ):
+        """
+        Implementation of & operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other & self
+
+    def __invert__( self ):
+        """
+        Implementation of ~ operator - returns C{L{NotAny}}
+        """
+        return NotAny( self )
+
+    def __call__(self, name=None):
+        """
+        Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}.
+        
+        If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be
+        passed as C{True}.
+           
+        If C{name} is omitted, same as calling C{L{copy}}.
+
+        Example::
+            # these are equivalent
+            userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
+            userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")             
+        """
+        if name is not None:
+            return self.setResultsName(name)
+        else:
+            return self.copy()
+
+    def suppress( self ):
+        """
+        Suppresses the output of this C{ParserElement}; useful to keep punctuation from
+        cluttering up returned output.
+        """
+        return Suppress( self )
+
+    def leaveWhitespace( self ):
+        """
+        Disables the skipping of whitespace before matching the characters in the
+        C{ParserElement}'s defined pattern.  This is normally only used internally by
+        the pyparsing module, but may be needed in some whitespace-sensitive grammars.
+        """
+        self.skipWhitespace = False
+        return self
+
+    def setWhitespaceChars( self, chars ):
+        """
+        Overrides the default whitespace chars
+        """
+        self.skipWhitespace = True
+        self.whiteChars = chars
+        self.copyDefaultWhiteChars = False
+        return self
+
+    def parseWithTabs( self ):
+        """
+        Overrides default behavior to expand C{}s to spaces before parsing the input string.
+        Must be called before C{parseString} when the input grammar contains elements that
+        match C{} characters.
+        """
+        self.keepTabs = True
+        return self
+
+    def ignore( self, other ):
+        """
+        Define expression to be ignored (e.g., comments) while doing pattern
+        matching; may be called repeatedly, to define multiple comment or other
+        ignorable patterns.
+        
+        Example::
+            patt = OneOrMore(Word(alphas))
+            patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj']
+            
+            patt.ignore(cStyleComment)
+            patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd']
+        """
+        if isinstance(other, basestring):
+            other = Suppress(other)
+
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                self.ignoreExprs.append(other)
+        else:
+            self.ignoreExprs.append( Suppress( other.copy() ) )
+        return self
+
+    def setDebugActions( self, startAction, successAction, exceptionAction ):
+        """
+        Enable display of debugging messages while doing pattern matching.
+        """
+        self.debugActions = (startAction or _defaultStartDebugAction,
+                             successAction or _defaultSuccessDebugAction,
+                             exceptionAction or _defaultExceptionDebugAction)
+        self.debug = True
+        return self
+
+    def setDebug( self, flag=True ):
+        """
+        Enable display of debugging messages while doing pattern matching.
+        Set C{flag} to True to enable, False to disable.
+
+        Example::
+            wd = Word(alphas).setName("alphaword")
+            integer = Word(nums).setName("numword")
+            term = wd | integer
+            
+            # turn on debugging for wd
+            wd.setDebug()
+
+            OneOrMore(term).parseString("abc 123 xyz 890")
+        
+        prints::
+            Match alphaword at loc 0(1,1)
+            Matched alphaword -> ['abc']
+            Match alphaword at loc 3(1,4)
+            Exception raised:Expected alphaword (at char 4), (line:1, col:5)
+            Match alphaword at loc 7(1,8)
+            Matched alphaword -> ['xyz']
+            Match alphaword at loc 11(1,12)
+            Exception raised:Expected alphaword (at char 12), (line:1, col:13)
+            Match alphaword at loc 15(1,16)
+            Exception raised:Expected alphaword (at char 15), (line:1, col:16)
+
+        The output shown is that produced by the default debug actions - custom debug actions can be
+        specified using L{setDebugActions}. Prior to attempting
+        to match the C{wd} expression, the debugging message C{"Match  at loc (,)"}
+        is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"}
+        message is shown. Also note the use of L{setName} to assign a human-readable name to the expression,
+        which makes debugging and exception messages easier to understand - for instance, the default
+        name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}.
+        """
+        if flag:
+            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
+        else:
+            self.debug = False
+        return self
+
+    def __str__( self ):
+        return self.name
+
+    def __repr__( self ):
+        return _ustr(self)
+
+    def streamline( self ):
+        self.streamlined = True
+        self.strRepr = None
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        pass
+
+    def validate( self, validateTrace=[] ):
+        """
+        Check defined expressions for valid structure, check for infinite recursive definitions.
+        """
+        self.checkRecursion( [] )
+
+    def parseFile( self, file_or_filename, parseAll=False ):
+        """
+        Execute the parse expression on the given file or filename.
+        If a filename is specified (instead of a file object),
+        the entire file is opened, read, and closed before parsing.
+        """
+        try:
+            file_contents = file_or_filename.read()
+        except AttributeError:
+            with open(file_or_filename, "r") as f:
+                file_contents = f.read()
+        try:
+            return self.parseString(file_contents, parseAll)
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def __eq__(self,other):
+        if isinstance(other, ParserElement):
+            return self is other or vars(self) == vars(other)
+        elif isinstance(other, basestring):
+            return self.matches(other)
+        else:
+            return super(ParserElement,self)==other
+
+    def __ne__(self,other):
+        return not (self == other)
+
+    def __hash__(self):
+        return hash(id(self))
+
+    def __req__(self,other):
+        return self == other
+
+    def __rne__(self,other):
+        return not (self == other)
+
+    def matches(self, testString, parseAll=True):
+        """
+        Method for quick testing of a parser against a test string. Good for simple 
+        inline microtests of sub expressions while building up larger parser.
+           
+        Parameters:
+         - testString - to test against this expression for a match
+         - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests
+            
+        Example::
+            expr = Word(nums)
+            assert expr.matches("100")
+        """
+        try:
+            self.parseString(_ustr(testString), parseAll=parseAll)
+            return True
+        except ParseBaseException:
+            return False
+                
+    def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False):
+        """
+        Execute the parse expression on a series of test strings, showing each
+        test, the parsed results or where the parse failed. Quick and easy way to
+        run a parse expression against a list of sample strings.
+           
+        Parameters:
+         - tests - a list of separate test strings, or a multiline string of test strings
+         - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests           
+         - comment - (default=C{'#'}) - expression for indicating embedded comments in the test 
+              string; pass None to disable comment filtering
+         - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline;
+              if False, only dump nested list
+         - printResults - (default=C{True}) prints test output to stdout
+         - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing
+
+        Returns: a (success, results) tuple, where success indicates that all tests succeeded
+        (or failed if C{failureTests} is True), and the results contain a list of lines of each 
+        test's output
+        
+        Example::
+            number_expr = pyparsing_common.number.copy()
+
+            result = number_expr.runTests('''
+                # unsigned integer
+                100
+                # negative integer
+                -100
+                # float with scientific notation
+                6.02e23
+                # integer with scientific notation
+                1e-12
+                ''')
+            print("Success" if result[0] else "Failed!")
+
+            result = number_expr.runTests('''
+                # stray character
+                100Z
+                # missing leading digit before '.'
+                -.100
+                # too many '.'
+                3.14.159
+                ''', failureTests=True)
+            print("Success" if result[0] else "Failed!")
+        prints::
+            # unsigned integer
+            100
+            [100]
+
+            # negative integer
+            -100
+            [-100]
+
+            # float with scientific notation
+            6.02e23
+            [6.02e+23]
+
+            # integer with scientific notation
+            1e-12
+            [1e-12]
+
+            Success
+            
+            # stray character
+            100Z
+               ^
+            FAIL: Expected end of text (at char 3), (line:1, col:4)
+
+            # missing leading digit before '.'
+            -.100
+            ^
+            FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1)
+
+            # too many '.'
+            3.14.159
+                ^
+            FAIL: Expected end of text (at char 4), (line:1, col:5)
+
+            Success
+
+        Each test string must be on a single line. If you want to test a string that spans multiple
+        lines, create a test like this::
+
+            expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines")
+        
+        (Note that this is a raw string literal, you must include the leading 'r'.)
+        """
+        if isinstance(tests, basestring):
+            tests = list(map(str.strip, tests.rstrip().splitlines()))
+        if isinstance(comment, basestring):
+            comment = Literal(comment)
+        allResults = []
+        comments = []
+        success = True
+        for t in tests:
+            if comment is not None and comment.matches(t, False) or comments and not t:
+                comments.append(t)
+                continue
+            if not t:
+                continue
+            out = ['\n'.join(comments), t]
+            comments = []
+            try:
+                t = t.replace(r'\n','\n')
+                result = self.parseString(t, parseAll=parseAll)
+                out.append(result.dump(full=fullDump))
+                success = success and not failureTests
+            except ParseBaseException as pe:
+                fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else ""
+                if '\n' in t:
+                    out.append(line(pe.loc, t))
+                    out.append(' '*(col(pe.loc,t)-1) + '^' + fatal)
+                else:
+                    out.append(' '*pe.loc + '^' + fatal)
+                out.append("FAIL: " + str(pe))
+                success = success and failureTests
+                result = pe
+            except Exception as exc:
+                out.append("FAIL-EXCEPTION: " + str(exc))
+                success = success and failureTests
+                result = exc
+
+            if printResults:
+                if fullDump:
+                    out.append('')
+                print('\n'.join(out))
+
+            allResults.append((t, result))
+        
+        return success, allResults
+
+        
+class Token(ParserElement):
+    """
+    Abstract C{ParserElement} subclass, for defining atomic matching patterns.
+    """
+    def __init__( self ):
+        super(Token,self).__init__( savelist=False )
+
+
+class Empty(Token):
+    """
+    An empty token, will always match.
+    """
+    def __init__( self ):
+        super(Empty,self).__init__()
+        self.name = "Empty"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+
+class NoMatch(Token):
+    """
+    A token that will never match.
+    """
+    def __init__( self ):
+        super(NoMatch,self).__init__()
+        self.name = "NoMatch"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.errmsg = "Unmatchable token"
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        raise ParseException(instring, loc, self.errmsg, self)
+
+
+class Literal(Token):
+    """
+    Token to exactly match a specified string.
+    
+    Example::
+        Literal('blah').parseString('blah')  # -> ['blah']
+        Literal('blah').parseString('blahfooblah')  # -> ['blah']
+        Literal('blah').parseString('bla')  # -> Exception: Expected "blah"
+    
+    For case-insensitive matching, use L{CaselessLiteral}.
+    
+    For keyword matching (force word break before and after the matched string),
+    use L{Keyword} or L{CaselessKeyword}.
+    """
+    def __init__( self, matchString ):
+        super(Literal,self).__init__()
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Literal; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+            self.__class__ = Empty
+        self.name = '"%s"' % _ustr(self.match)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        self.mayIndexError = False
+
+    # Performance tuning: this routine gets called a *lot*
+    # if this is a single character match string  and the first character matches,
+    # short-circuit as quickly as possible, and avoid calling startswith
+    #~ @profile
+    def parseImpl( self, instring, loc, doActions=True ):
+        if (instring[loc] == self.firstMatchChar and
+            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
+            return loc+self.matchLen, self.match
+        raise ParseException(instring, loc, self.errmsg, self)
+_L = Literal
+ParserElement._literalStringClass = Literal
+
+class Keyword(Token):
+    """
+    Token to exactly match a specified string as a keyword, that is, it must be
+    immediately followed by a non-keyword character.  Compare with C{L{Literal}}:
+     - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}.
+     - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'}
+    Accepts two optional constructor arguments in addition to the keyword string:
+     - C{identChars} is a string of characters that would be valid identifier characters,
+          defaulting to all alphanumerics + "_" and "$"
+     - C{caseless} allows case-insensitive matching, default is C{False}.
+       
+    Example::
+        Keyword("start").parseString("start")  # -> ['start']
+        Keyword("start").parseString("starting")  # -> Exception
+
+    For case-insensitive matching, use L{CaselessKeyword}.
+    """
+    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
+
+    def __init__( self, matchString, identChars=None, caseless=False ):
+        super(Keyword,self).__init__()
+        if identChars is None:
+            identChars = Keyword.DEFAULT_KEYWORD_CHARS
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Keyword; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+        self.name = '"%s"' % self.match
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        self.mayIndexError = False
+        self.caseless = caseless
+        if caseless:
+            self.caselessmatch = matchString.upper()
+            identChars = identChars.upper()
+        self.identChars = set(identChars)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.caseless:
+            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
+                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        else:
+            if (instring[loc] == self.firstMatchChar and
+                (self.matchLen==1 or instring.startswith(self.match,loc)) and
+                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
+                (loc == 0 or instring[loc-1] not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        raise ParseException(instring, loc, self.errmsg, self)
+
+    def copy(self):
+        c = super(Keyword,self).copy()
+        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
+        return c
+
+    @staticmethod
+    def setDefaultKeywordChars( chars ):
+        """Overrides the default Keyword chars
+        """
+        Keyword.DEFAULT_KEYWORD_CHARS = chars
+
+class CaselessLiteral(Literal):
+    """
+    Token to match a specified string, ignoring case of letters.
+    Note: the matched results will always be in the case of the given
+    match string, NOT the case of the input text.
+
+    Example::
+        OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD']
+        
+    (Contrast with example for L{CaselessKeyword}.)
+    """
+    def __init__( self, matchString ):
+        super(CaselessLiteral,self).__init__( matchString.upper() )
+        # Preserve the defining literal.
+        self.returnString = matchString
+        self.name = "'%s'" % self.returnString
+        self.errmsg = "Expected " + self.name
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[ loc:loc+self.matchLen ].upper() == self.match:
+            return loc+self.matchLen, self.returnString
+        raise ParseException(instring, loc, self.errmsg, self)
+
+class CaselessKeyword(Keyword):
+    """
+    Caseless version of L{Keyword}.
+
+    Example::
+        OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD']
+        
+    (Contrast with example for L{CaselessLiteral}.)
+    """
+    def __init__( self, matchString, identChars=None ):
+        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
+            return loc+self.matchLen, self.match
+        raise ParseException(instring, loc, self.errmsg, self)
+
+class CloseMatch(Token):
+    """
+    A variation on L{Literal} which matches "close" matches, that is, 
+    strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters:
+     - C{match_string} - string to be matched
+     - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match
+    
+    The results from a successful parse will contain the matched text from the input string and the following named results:
+     - C{mismatches} - a list of the positions within the match_string where mismatches were found
+     - C{original} - the original match_string used to compare against the input string
+    
+    If C{mismatches} is an empty list, then the match was an exact match.
+    
+    Example::
+        patt = CloseMatch("ATCATCGAATGGA")
+        patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']})
+        patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1)
+
+        # exact match
+        patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']})
+
+        # close match allowing up to 2 mismatches
+        patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2)
+        patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']})
+    """
+    def __init__(self, match_string, maxMismatches=1):
+        super(CloseMatch,self).__init__()
+        self.name = match_string
+        self.match_string = match_string
+        self.maxMismatches = maxMismatches
+        self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches)
+        self.mayIndexError = False
+        self.mayReturnEmpty = False
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        start = loc
+        instrlen = len(instring)
+        maxloc = start + len(self.match_string)
+
+        if maxloc <= instrlen:
+            match_string = self.match_string
+            match_stringloc = 0
+            mismatches = []
+            maxMismatches = self.maxMismatches
+
+            for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)):
+                src,mat = s_m
+                if src != mat:
+                    mismatches.append(match_stringloc)
+                    if len(mismatches) > maxMismatches:
+                        break
+            else:
+                loc = match_stringloc + 1
+                results = ParseResults([instring[start:loc]])
+                results['original'] = self.match_string
+                results['mismatches'] = mismatches
+                return loc, results
+
+        raise ParseException(instring, loc, self.errmsg, self)
+
+
+class Word(Token):
+    """
+    Token for matching words composed of allowed character sets.
+    Defined with string containing all allowed initial characters,
+    an optional string containing allowed body characters (if omitted,
+    defaults to the initial character set), and an optional minimum,
+    maximum, and/or exact length.  The default value for C{min} is 1 (a
+    minimum value < 1 is not valid); the default values for C{max} and C{exact}
+    are 0, meaning no maximum or exact length restriction. An optional
+    C{excludeChars} parameter can list characters that might be found in 
+    the input C{bodyChars} string; useful to define a word of all printables
+    except for one or two characters, for instance.
+    
+    L{srange} is useful for defining custom character set strings for defining 
+    C{Word} expressions, using range notation from regular expression character sets.
+    
+    A common mistake is to use C{Word} to match a specific literal string, as in 
+    C{Word("Address")}. Remember that C{Word} uses the string argument to define
+    I{sets} of matchable characters. This expression would match "Add", "AAA",
+    "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'.
+    To match an exact literal string, use L{Literal} or L{Keyword}.
+
+    pyparsing includes helper strings for building Words:
+     - L{alphas}
+     - L{nums}
+     - L{alphanums}
+     - L{hexnums}
+     - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.)
+     - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.)
+     - L{printables} (any non-whitespace character)
+
+    Example::
+        # a word composed of digits
+        integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9"))
+        
+        # a word with a leading capital, and zero or more lowercase
+        capital_word = Word(alphas.upper(), alphas.lower())
+
+        # hostnames are alphanumeric, with leading alpha, and '-'
+        hostname = Word(alphas, alphanums+'-')
+        
+        # roman numeral (not a strict parser, accepts invalid mix of characters)
+        roman = Word("IVXLCDM")
+        
+        # any string of non-whitespace characters, except for ','
+        csv_value = Word(printables, excludeChars=",")
+    """
+    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ):
+        super(Word,self).__init__()
+        if excludeChars:
+            initChars = ''.join(c for c in initChars if c not in excludeChars)
+            if bodyChars:
+                bodyChars = ''.join(c for c in bodyChars if c not in excludeChars)
+        self.initCharsOrig = initChars
+        self.initChars = set(initChars)
+        if bodyChars :
+            self.bodyCharsOrig = bodyChars
+            self.bodyChars = set(bodyChars)
+        else:
+            self.bodyCharsOrig = initChars
+            self.bodyChars = set(initChars)
+
+        self.maxSpecified = max > 0
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayIndexError = False
+        self.asKeyword = asKeyword
+
+        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
+            if self.bodyCharsOrig == self.initCharsOrig:
+                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
+            elif len(self.initCharsOrig) == 1:
+                self.reString = "%s[%s]*" % \
+                                      (re.escape(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            else:
+                self.reString = "[%s][%s]*" % \
+                                      (_escapeRegexRangeChars(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            if self.asKeyword:
+                self.reString = r"\b"+self.reString+r"\b"
+            try:
+                self.re = re.compile( self.reString )
+            except Exception:
+                self.re = None
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.re:
+            result = self.re.match(instring,loc)
+            if not result:
+                raise ParseException(instring, loc, self.errmsg, self)
+
+            loc = result.end()
+            return loc, result.group()
+
+        if not(instring[ loc ] in self.initChars):
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        start = loc
+        loc += 1
+        instrlen = len(instring)
+        bodychars = self.bodyChars
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, instrlen )
+        while loc < maxloc and instring[loc] in bodychars:
+            loc += 1
+
+        throwException = False
+        if loc - start < self.minLen:
+            throwException = True
+        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
+            throwException = True
+        if self.asKeyword:
+            if (start>0 and instring[start-1] in bodychars) or (loc4:
+                    return s[:4]+"..."
+                else:
+                    return s
+
+            if ( self.initCharsOrig != self.bodyCharsOrig ):
+                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
+            else:
+                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
+
+        return self.strRepr
+
+
+class Regex(Token):
+    r"""
+    Token for matching strings that match a given regular expression.
+    Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
+    If the given regex contains named groups (defined using C{(?P...)}), these will be preserved as 
+    named parse results.
+
+    Example::
+        realnum = Regex(r"[+-]?\d+\.\d*")
+        date = Regex(r'(?P\d{4})-(?P\d\d?)-(?P\d\d?)')
+        # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression
+        roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")
+    """
+    compiledREtype = type(re.compile("[A-Z]"))
+    def __init__( self, pattern, flags=0):
+        """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags."""
+        super(Regex,self).__init__()
+
+        if isinstance(pattern, basestring):
+            if not pattern:
+                warnings.warn("null string passed to Regex; use Empty() instead",
+                        SyntaxWarning, stacklevel=2)
+
+            self.pattern = pattern
+            self.flags = flags
+
+            try:
+                self.re = re.compile(self.pattern, self.flags)
+                self.reString = self.pattern
+            except sre_constants.error:
+                warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
+                    SyntaxWarning, stacklevel=2)
+                raise
+
+        elif isinstance(pattern, Regex.compiledREtype):
+            self.re = pattern
+            self.pattern = \
+            self.reString = str(pattern)
+            self.flags = flags
+            
+        else:
+            raise ValueError("Regex may only be constructed with a string or a compiled RE object")
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = self.re.match(instring,loc)
+        if not result:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        loc = result.end()
+        d = result.groupdict()
+        ret = ParseResults(result.group())
+        if d:
+            for k in d:
+                ret[k] = d[k]
+        return loc,ret
+
+    def __str__( self ):
+        try:
+            return super(Regex,self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "Re:(%s)" % repr(self.pattern)
+
+        return self.strRepr
+
+
+class QuotedString(Token):
+    r"""
+    Token for matching strings that are delimited by quoting characters.
+    
+    Defined with the following parameters:
+        - quoteChar - string of one or more characters defining the quote delimiting string
+        - escChar - character to escape quotes, typically backslash (default=C{None})
+        - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None})
+        - multiline - boolean indicating whether quotes can span multiple lines (default=C{False})
+        - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True})
+        - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar)
+        - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True})
+
+    Example::
+        qs = QuotedString('"')
+        print(qs.searchString('lsjdf "This is the quote" sldjf'))
+        complex_qs = QuotedString('{{', endQuoteChar='}}')
+        print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf'))
+        sql_qs = QuotedString('"', escQuote='""')
+        print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf'))
+    prints::
+        [['This is the quote']]
+        [['This is the "quote"']]
+        [['This is the quote with "embedded" quotes']]
+    """
+    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True):
+        super(QuotedString,self).__init__()
+
+        # remove white space from quote chars - wont work anyway
+        quoteChar = quoteChar.strip()
+        if not quoteChar:
+            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+            raise SyntaxError()
+
+        if endQuoteChar is None:
+            endQuoteChar = quoteChar
+        else:
+            endQuoteChar = endQuoteChar.strip()
+            if not endQuoteChar:
+                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+                raise SyntaxError()
+
+        self.quoteChar = quoteChar
+        self.quoteCharLen = len(quoteChar)
+        self.firstQuoteChar = quoteChar[0]
+        self.endQuoteChar = endQuoteChar
+        self.endQuoteCharLen = len(endQuoteChar)
+        self.escChar = escChar
+        self.escQuote = escQuote
+        self.unquoteResults = unquoteResults
+        self.convertWhitespaceEscapes = convertWhitespaceEscapes
+
+        if multiline:
+            self.flags = re.MULTILINE | re.DOTALL
+            self.pattern = r'%s(?:[^%s%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        else:
+            self.flags = 0
+            self.pattern = r'%s(?:[^%s\n\r%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        if len(self.endQuoteChar) > 1:
+            self.pattern += (
+                '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
+                                               _escapeRegexRangeChars(self.endQuoteChar[i]))
+                                    for i in range(len(self.endQuoteChar)-1,0,-1)) + ')'
+                )
+        if escQuote:
+            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
+        if escChar:
+            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
+            self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
+        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
+
+        try:
+            self.re = re.compile(self.pattern, self.flags)
+            self.reString = self.pattern
+        except sre_constants.error:
+            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
+                SyntaxWarning, stacklevel=2)
+            raise
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
+        if not result:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        loc = result.end()
+        ret = result.group()
+
+        if self.unquoteResults:
+
+            # strip off quotes
+            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
+
+            if isinstance(ret,basestring):
+                # replace escaped whitespace
+                if '\\' in ret and self.convertWhitespaceEscapes:
+                    ws_map = {
+                        r'\t' : '\t',
+                        r'\n' : '\n',
+                        r'\f' : '\f',
+                        r'\r' : '\r',
+                    }
+                    for wslit,wschar in ws_map.items():
+                        ret = ret.replace(wslit, wschar)
+
+                # replace escaped characters
+                if self.escChar:
+                    ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret)
+
+                # replace escaped quotes
+                if self.escQuote:
+                    ret = ret.replace(self.escQuote, self.endQuoteChar)
+
+        return loc, ret
+
+    def __str__( self ):
+        try:
+            return super(QuotedString,self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
+
+        return self.strRepr
+
+
+class CharsNotIn(Token):
+    """
+    Token for matching words composed of characters I{not} in a given set (will
+    include whitespace in matched characters if not listed in the provided exclusion set - see example).
+    Defined with string containing all disallowed characters, and an optional
+    minimum, maximum, and/or exact length.  The default value for C{min} is 1 (a
+    minimum value < 1 is not valid); the default values for C{max} and C{exact}
+    are 0, meaning no maximum or exact length restriction.
+
+    Example::
+        # define a comma-separated-value as anything that is not a ','
+        csv_value = CharsNotIn(',')
+        print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213"))
+    prints::
+        ['dkls', 'lsdkjf', 's12 34', '@!#', '213']
+    """
+    def __init__( self, notChars, min=1, max=0, exact=0 ):
+        super(CharsNotIn,self).__init__()
+        self.skipWhitespace = False
+        self.notChars = notChars
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = ( self.minLen == 0 )
+        self.mayIndexError = False
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[loc] in self.notChars:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        start = loc
+        loc += 1
+        notchars = self.notChars
+        maxlen = min( start+self.maxLen, len(instring) )
+        while loc < maxlen and \
+              (instring[loc] not in notchars):
+            loc += 1
+
+        if loc - start < self.minLen:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        return loc, instring[start:loc]
+
+    def __str__( self ):
+        try:
+            return super(CharsNotIn, self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None:
+            if len(self.notChars) > 4:
+                self.strRepr = "!W:(%s...)" % self.notChars[:4]
+            else:
+                self.strRepr = "!W:(%s)" % self.notChars
+
+        return self.strRepr
+
+class White(Token):
+    """
+    Special matching class for matching whitespace.  Normally, whitespace is ignored
+    by pyparsing grammars.  This class is included when some whitespace structures
+    are significant.  Define with a string containing the whitespace characters to be
+    matched; default is C{" \\t\\r\\n"}.  Also takes optional C{min}, C{max}, and C{exact} arguments,
+    as defined for the C{L{Word}} class.
+    """
+    whiteStrs = {
+        " " : "",
+        "\t": "",
+        "\n": "",
+        "\r": "",
+        "\f": "",
+        }
+    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
+        super(White,self).__init__()
+        self.matchWhite = ws
+        self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) )
+        #~ self.leaveWhitespace()
+        self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite))
+        self.mayReturnEmpty = True
+        self.errmsg = "Expected " + self.name
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if not(instring[ loc ] in self.matchWhite):
+            raise ParseException(instring, loc, self.errmsg, self)
+        start = loc
+        loc += 1
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, len(instring) )
+        while loc < maxloc and instring[loc] in self.matchWhite:
+            loc += 1
+
+        if loc - start < self.minLen:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        return loc, instring[start:loc]
+
+
+class _PositionToken(Token):
+    def __init__( self ):
+        super(_PositionToken,self).__init__()
+        self.name=self.__class__.__name__
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+class GoToColumn(_PositionToken):
+    """
+    Token to advance to a specific column of input text; useful for tabular report scraping.
+    """
+    def __init__( self, colno ):
+        super(GoToColumn,self).__init__()
+        self.col = colno
+
+    def preParse( self, instring, loc ):
+        if col(loc,instring) != self.col:
+            instrlen = len(instring)
+            if self.ignoreExprs:
+                loc = self._skipIgnorables( instring, loc )
+            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
+                loc += 1
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        thiscol = col( loc, instring )
+        if thiscol > self.col:
+            raise ParseException( instring, loc, "Text not in expected column", self )
+        newloc = loc + self.col - thiscol
+        ret = instring[ loc: newloc ]
+        return newloc, ret
+
+
+class LineStart(_PositionToken):
+    """
+    Matches if current position is at the beginning of a line within the parse string
+    
+    Example::
+    
+        test = '''\
+        AAA this line
+        AAA and this line
+          AAA but not this one
+        B AAA and definitely not this one
+        '''
+
+        for t in (LineStart() + 'AAA' + restOfLine).searchString(test):
+            print(t)
+    
+    Prints::
+        ['AAA', ' this line']
+        ['AAA', ' and this line']    
+
+    """
+    def __init__( self ):
+        super(LineStart,self).__init__()
+        self.errmsg = "Expected start of line"
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if col(loc, instring) == 1:
+            return loc, []
+        raise ParseException(instring, loc, self.errmsg, self)
+
+class LineEnd(_PositionToken):
+    """
+    Matches if current position is at the end of a line within the parse string
+    """
+    def __init__( self ):
+        super(LineEnd,self).__init__()
+        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
+        self.errmsg = "Expected end of line"
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc len(instring):
+            return loc, []
+        else:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+class WordStart(_PositionToken):
+    """
+    Matches if the current position is at the beginning of a Word, and
+    is not preceded by any character in a given set of C{wordChars}
+    (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
+    use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of
+    the string being parsed, or at the beginning of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordStart,self).__init__()
+        self.wordChars = set(wordChars)
+        self.errmsg = "Not at the start of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        if loc != 0:
+            if (instring[loc-1] in self.wordChars or
+                instring[loc] not in self.wordChars):
+                raise ParseException(instring, loc, self.errmsg, self)
+        return loc, []
+
+class WordEnd(_PositionToken):
+    """
+    Matches if the current position is at the end of a Word, and
+    is not followed by any character in a given set of C{wordChars}
+    (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
+    use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of
+    the string being parsed, or at the end of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordEnd,self).__init__()
+        self.wordChars = set(wordChars)
+        self.skipWhitespace = False
+        self.errmsg = "Not at the end of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        instrlen = len(instring)
+        if instrlen>0 and loc maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+            else:
+                # save match among all matches, to retry longest to shortest
+                matches.append((loc2, e))
+
+        if matches:
+            matches.sort(key=lambda x: -x[0])
+            for _,e in matches:
+                try:
+                    return e._parse( instring, loc, doActions )
+                except ParseException as err:
+                    err.__traceback__ = None
+                    if err.loc > maxExcLoc:
+                        maxException = err
+                        maxExcLoc = err.loc
+
+        if maxException is not None:
+            maxException.msg = self.errmsg
+            raise maxException
+        else:
+            raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+
+    def __ixor__(self, other ):
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        return self.append( other ) #Or( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class MatchFirst(ParseExpression):
+    """
+    Requires that at least one C{ParseExpression} is found.
+    If two expressions match, the first one listed is the one that will match.
+    May be constructed using the C{'|'} operator.
+
+    Example::
+        # construct MatchFirst using '|' operator
+        
+        # watch the order of expressions to match
+        number = Word(nums) | Combine(Word(nums) + '.' + Word(nums))
+        print(number.searchString("123 3.1416 789")) #  Fail! -> [['123'], ['3'], ['1416'], ['789']]
+
+        # put more selective expression first
+        number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums)
+        print(number.searchString("123 3.1416 789")) #  Better -> [['123'], ['3.1416'], ['789']]
+    """
+    def __init__( self, exprs, savelist = False ):
+        super(MatchFirst,self).__init__(exprs, savelist)
+        if self.exprs:
+            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
+        else:
+            self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        maxExcLoc = -1
+        maxException = None
+        for e in self.exprs:
+            try:
+                ret = e._parse( instring, loc, doActions )
+                return ret
+            except ParseException as err:
+                if err.loc > maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+
+        # only got here if no expression matched, raise exception for match that made it the furthest
+        else:
+            if maxException is not None:
+                maxException.msg = self.errmsg
+                raise maxException
+            else:
+                raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+    def __ior__(self, other ):
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        return self.append( other ) #MatchFirst( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class Each(ParseExpression):
+    """
+    Requires all given C{ParseExpression}s to be found, but in any order.
+    Expressions may be separated by whitespace.
+    May be constructed using the C{'&'} operator.
+
+    Example::
+        color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN")
+        shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON")
+        integer = Word(nums)
+        shape_attr = "shape:" + shape_type("shape")
+        posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn")
+        color_attr = "color:" + color("color")
+        size_attr = "size:" + integer("size")
+
+        # use Each (using operator '&') to accept attributes in any order 
+        # (shape and posn are required, color and size are optional)
+        shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr)
+
+        shape_spec.runTests('''
+            shape: SQUARE color: BLACK posn: 100, 120
+            shape: CIRCLE size: 50 color: BLUE posn: 50,80
+            color:GREEN size:20 shape:TRIANGLE posn:20,40
+            '''
+            )
+    prints::
+        shape: SQUARE color: BLACK posn: 100, 120
+        ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']]
+        - color: BLACK
+        - posn: ['100', ',', '120']
+          - x: 100
+          - y: 120
+        - shape: SQUARE
+
+
+        shape: CIRCLE size: 50 color: BLUE posn: 50,80
+        ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']]
+        - color: BLUE
+        - posn: ['50', ',', '80']
+          - x: 50
+          - y: 80
+        - shape: CIRCLE
+        - size: 50
+
+
+        color: GREEN size: 20 shape: TRIANGLE posn: 20,40
+        ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']]
+        - color: GREEN
+        - posn: ['20', ',', '40']
+          - x: 20
+          - y: 40
+        - shape: TRIANGLE
+        - size: 20
+    """
+    def __init__( self, exprs, savelist = True ):
+        super(Each,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
+        self.skipWhitespace = True
+        self.initExprGroups = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.initExprGroups:
+            self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional))
+            opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
+            opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)]
+            self.optionals = opt1 + opt2
+            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
+            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
+            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
+            self.required += self.multirequired
+            self.initExprGroups = False
+        tmpLoc = loc
+        tmpReqd = self.required[:]
+        tmpOpt  = self.optionals[:]
+        matchOrder = []
+
+        keepMatching = True
+        while keepMatching:
+            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
+            failed = []
+            for e in tmpExprs:
+                try:
+                    tmpLoc = e.tryParse( instring, tmpLoc )
+                except ParseException:
+                    failed.append(e)
+                else:
+                    matchOrder.append(self.opt1map.get(id(e),e))
+                    if e in tmpReqd:
+                        tmpReqd.remove(e)
+                    elif e in tmpOpt:
+                        tmpOpt.remove(e)
+            if len(failed) == len(tmpExprs):
+                keepMatching = False
+
+        if tmpReqd:
+            missing = ", ".join(_ustr(e) for e in tmpReqd)
+            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
+
+        # add any unmatched Optionals, in case they have default values defined
+        matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt]
+
+        resultlist = []
+        for e in matchOrder:
+            loc,results = e._parse(instring,loc,doActions)
+            resultlist.append(results)
+
+        finalResults = sum(resultlist, ParseResults([]))
+        return loc, finalResults
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class ParseElementEnhance(ParserElement):
+    """
+    Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens.
+    """
+    def __init__( self, expr, savelist=False ):
+        super(ParseElementEnhance,self).__init__(savelist)
+        if isinstance( expr, basestring ):
+            if issubclass(ParserElement._literalStringClass, Token):
+                expr = ParserElement._literalStringClass(expr)
+            else:
+                expr = ParserElement._literalStringClass(Literal(expr))
+        self.expr = expr
+        self.strRepr = None
+        if expr is not None:
+            self.mayIndexError = expr.mayIndexError
+            self.mayReturnEmpty = expr.mayReturnEmpty
+            self.setWhitespaceChars( expr.whiteChars )
+            self.skipWhitespace = expr.skipWhitespace
+            self.saveAsList = expr.saveAsList
+            self.callPreparse = expr.callPreparse
+            self.ignoreExprs.extend(expr.ignoreExprs)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.expr is not None:
+            return self.expr._parse( instring, loc, doActions, callPreParse=False )
+        else:
+            raise ParseException("",loc,self.errmsg,self)
+
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        self.expr = self.expr.copy()
+        if self.expr is not None:
+            self.expr.leaveWhitespace()
+        return self
+
+    def ignore( self, other ):
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                super( ParseElementEnhance, self).ignore( other )
+                if self.expr is not None:
+                    self.expr.ignore( self.ignoreExprs[-1] )
+        else:
+            super( ParseElementEnhance, self).ignore( other )
+            if self.expr is not None:
+                self.expr.ignore( self.ignoreExprs[-1] )
+        return self
+
+    def streamline( self ):
+        super(ParseElementEnhance,self).streamline()
+        if self.expr is not None:
+            self.expr.streamline()
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        if self in parseElementList:
+            raise RecursiveGrammarException( parseElementList+[self] )
+        subRecCheckList = parseElementList[:] + [ self ]
+        if self.expr is not None:
+            self.expr.checkRecursion( subRecCheckList )
+
+    def validate( self, validateTrace=[] ):
+        tmp = validateTrace[:]+[self]
+        if self.expr is not None:
+            self.expr.validate(tmp)
+        self.checkRecursion( [] )
+
+    def __str__( self ):
+        try:
+            return super(ParseElementEnhance,self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None and self.expr is not None:
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
+        return self.strRepr
+
+
+class FollowedBy(ParseElementEnhance):
+    """
+    Lookahead matching of the given parse expression.  C{FollowedBy}
+    does I{not} advance the parsing position within the input string, it only
+    verifies that the specified parse expression matches at the current
+    position.  C{FollowedBy} always returns a null token list.
+
+    Example::
+        # use FollowedBy to match a label only if it is followed by a ':'
+        data_word = Word(alphas)
+        label = data_word + FollowedBy(':')
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        
+        OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint()
+    prints::
+        [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']]
+    """
+    def __init__( self, expr ):
+        super(FollowedBy,self).__init__(expr)
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        self.expr.tryParse( instring, loc )
+        return loc, []
+
+
+class NotAny(ParseElementEnhance):
+    """
+    Lookahead to disallow matching with the given parse expression.  C{NotAny}
+    does I{not} advance the parsing position within the input string, it only
+    verifies that the specified parse expression does I{not} match at the current
+    position.  Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny}
+    always returns a null token list.  May be constructed using the '~' operator.
+
+    Example::
+        
+    """
+    def __init__( self, expr ):
+        super(NotAny,self).__init__(expr)
+        #~ self.leaveWhitespace()
+        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
+        self.mayReturnEmpty = True
+        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.expr.canParseNext(instring, loc):
+            raise ParseException(instring, loc, self.errmsg, self)
+        return loc, []
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "~{" + _ustr(self.expr) + "}"
+
+        return self.strRepr
+
+class _MultipleMatch(ParseElementEnhance):
+    def __init__( self, expr, stopOn=None):
+        super(_MultipleMatch, self).__init__(expr)
+        self.saveAsList = True
+        ender = stopOn
+        if isinstance(ender, basestring):
+            ender = ParserElement._literalStringClass(ender)
+        self.not_ender = ~ender if ender is not None else None
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        self_expr_parse = self.expr._parse
+        self_skip_ignorables = self._skipIgnorables
+        check_ender = self.not_ender is not None
+        if check_ender:
+            try_not_ender = self.not_ender.tryParse
+        
+        # must be at least one (but first see if we are the stopOn sentinel;
+        # if so, fail)
+        if check_ender:
+            try_not_ender(instring, loc)
+        loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False )
+        try:
+            hasIgnoreExprs = (not not self.ignoreExprs)
+            while 1:
+                if check_ender:
+                    try_not_ender(instring, loc)
+                if hasIgnoreExprs:
+                    preloc = self_skip_ignorables( instring, loc )
+                else:
+                    preloc = loc
+                loc, tmptokens = self_expr_parse( instring, preloc, doActions )
+                if tmptokens or tmptokens.haskeys():
+                    tokens += tmptokens
+        except (ParseException,IndexError):
+            pass
+
+        return loc, tokens
+        
+class OneOrMore(_MultipleMatch):
+    """
+    Repetition of one or more of the given expression.
+    
+    Parameters:
+     - expr - expression that must match one or more times
+     - stopOn - (default=C{None}) - expression for a terminating sentinel
+          (only required if the sentinel would ordinarily match the repetition 
+          expression)          
+
+    Example::
+        data_word = Word(alphas)
+        label = data_word + FollowedBy(':')
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))
+
+        text = "shape: SQUARE posn: upper left color: BLACK"
+        OneOrMore(attr_expr).parseString(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
+
+        # use stopOn attribute for OneOrMore to avoid reading label string as part of the data
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']]
+        
+        # could also be written as
+        (attr_expr * (1,)).parseString(text).pprint()
+    """
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + _ustr(self.expr) + "}..."
+
+        return self.strRepr
+
+class ZeroOrMore(_MultipleMatch):
+    """
+    Optional repetition of zero or more of the given expression.
+    
+    Parameters:
+     - expr - expression that must match zero or more times
+     - stopOn - (default=C{None}) - expression for a terminating sentinel
+          (only required if the sentinel would ordinarily match the repetition 
+          expression)          
+
+    Example: similar to L{OneOrMore}
+    """
+    def __init__( self, expr, stopOn=None):
+        super(ZeroOrMore,self).__init__(expr, stopOn=stopOn)
+        self.mayReturnEmpty = True
+        
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            return super(ZeroOrMore, self).parseImpl(instring, loc, doActions)
+        except (ParseException,IndexError):
+            return loc, []
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]..."
+
+        return self.strRepr
+
+class _NullToken(object):
+    def __bool__(self):
+        return False
+    __nonzero__ = __bool__
+    def __str__(self):
+        return ""
+
+_optionalNotMatched = _NullToken()
+class Optional(ParseElementEnhance):
+    """
+    Optional matching of the given expression.
+
+    Parameters:
+     - expr - expression that must match zero or more times
+     - default (optional) - value to be returned if the optional expression is not found.
+
+    Example::
+        # US postal code can be a 5-digit zip, plus optional 4-digit qualifier
+        zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4)))
+        zip.runTests('''
+            # traditional ZIP code
+            12345
+            
+            # ZIP+4 form
+            12101-0001
+            
+            # invalid ZIP
+            98765-
+            ''')
+    prints::
+        # traditional ZIP code
+        12345
+        ['12345']
+
+        # ZIP+4 form
+        12101-0001
+        ['12101-0001']
+
+        # invalid ZIP
+        98765-
+             ^
+        FAIL: Expected end of text (at char 5), (line:1, col:6)
+    """
+    def __init__( self, expr, default=_optionalNotMatched ):
+        super(Optional,self).__init__( expr, savelist=False )
+        self.saveAsList = self.expr.saveAsList
+        self.defaultValue = default
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+        except (ParseException,IndexError):
+            if self.defaultValue is not _optionalNotMatched:
+                if self.expr.resultsName:
+                    tokens = ParseResults([ self.defaultValue ])
+                    tokens[self.expr.resultsName] = self.defaultValue
+                else:
+                    tokens = [ self.defaultValue ]
+            else:
+                tokens = []
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]"
+
+        return self.strRepr
+
+class SkipTo(ParseElementEnhance):
+    """
+    Token for skipping over all undefined text until the matched expression is found.
+
+    Parameters:
+     - expr - target expression marking the end of the data to be skipped
+     - include - (default=C{False}) if True, the target expression is also parsed 
+          (the skipped text and target expression are returned as a 2-element list).
+     - ignore - (default=C{None}) used to define grammars (typically quoted strings and 
+          comments) that might contain false matches to the target expression
+     - failOn - (default=C{None}) define expressions that are not allowed to be 
+          included in the skipped test; if found before the target expression is found, 
+          the SkipTo is not a match
+
+    Example::
+        report = '''
+            Outstanding Issues Report - 1 Jan 2000
+
+               # | Severity | Description                               |  Days Open
+            -----+----------+-------------------------------------------+-----------
+             101 | Critical | Intermittent system crash                 |          6
+              94 | Cosmetic | Spelling error on Login ('log|n')         |         14
+              79 | Minor    | System slow when running too many reports |         47
+            '''
+        integer = Word(nums)
+        SEP = Suppress('|')
+        # use SkipTo to simply match everything up until the next SEP
+        # - ignore quoted strings, so that a '|' character inside a quoted string does not match
+        # - parse action will call token.strip() for each matched token, i.e., the description body
+        string_data = SkipTo(SEP, ignore=quotedString)
+        string_data.setParseAction(tokenMap(str.strip))
+        ticket_expr = (integer("issue_num") + SEP 
+                      + string_data("sev") + SEP 
+                      + string_data("desc") + SEP 
+                      + integer("days_open"))
+        
+        for tkt in ticket_expr.searchString(report):
+            print tkt.dump()
+    prints::
+        ['101', 'Critical', 'Intermittent system crash', '6']
+        - days_open: 6
+        - desc: Intermittent system crash
+        - issue_num: 101
+        - sev: Critical
+        ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14']
+        - days_open: 14
+        - desc: Spelling error on Login ('log|n')
+        - issue_num: 94
+        - sev: Cosmetic
+        ['79', 'Minor', 'System slow when running too many reports', '47']
+        - days_open: 47
+        - desc: System slow when running too many reports
+        - issue_num: 79
+        - sev: Minor
+    """
+    def __init__( self, other, include=False, ignore=None, failOn=None ):
+        super( SkipTo, self ).__init__( other )
+        self.ignoreExpr = ignore
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.includeMatch = include
+        self.asList = False
+        if isinstance(failOn, basestring):
+            self.failOn = ParserElement._literalStringClass(failOn)
+        else:
+            self.failOn = failOn
+        self.errmsg = "No match found for "+_ustr(self.expr)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        startloc = loc
+        instrlen = len(instring)
+        expr = self.expr
+        expr_parse = self.expr._parse
+        self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None
+        self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None
+        
+        tmploc = loc
+        while tmploc <= instrlen:
+            if self_failOn_canParseNext is not None:
+                # break if failOn expression matches
+                if self_failOn_canParseNext(instring, tmploc):
+                    break
+                    
+            if self_ignoreExpr_tryParse is not None:
+                # advance past ignore expressions
+                while 1:
+                    try:
+                        tmploc = self_ignoreExpr_tryParse(instring, tmploc)
+                    except ParseBaseException:
+                        break
+            
+            try:
+                expr_parse(instring, tmploc, doActions=False, callPreParse=False)
+            except (ParseException, IndexError):
+                # no match, advance loc in string
+                tmploc += 1
+            else:
+                # matched skipto expr, done
+                break
+
+        else:
+            # ran off the end of the input string without matching skipto expr, fail
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        # build up return values
+        loc = tmploc
+        skiptext = instring[startloc:loc]
+        skipresult = ParseResults(skiptext)
+        
+        if self.includeMatch:
+            loc, mat = expr_parse(instring,loc,doActions,callPreParse=False)
+            skipresult += mat
+
+        return loc, skipresult
+
+class Forward(ParseElementEnhance):
+    """
+    Forward declaration of an expression to be defined later -
+    used for recursive grammars, such as algebraic infix notation.
+    When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator.
+
+    Note: take care when assigning to C{Forward} not to overlook precedence of operators.
+    Specifically, '|' has a lower precedence than '<<', so that::
+        fwdExpr << a | b | c
+    will actually be evaluated as::
+        (fwdExpr << a) | b | c
+    thereby leaving b and c out as parseable alternatives.  It is recommended that you
+    explicitly group the values inserted into the C{Forward}::
+        fwdExpr << (a | b | c)
+    Converting to use the '<<=' operator instead will avoid this problem.
+
+    See L{ParseResults.pprint} for an example of a recursive parser created using
+    C{Forward}.
+    """
+    def __init__( self, other=None ):
+        super(Forward,self).__init__( other, savelist=False )
+
+    def __lshift__( self, other ):
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass(other)
+        self.expr = other
+        self.strRepr = None
+        self.mayIndexError = self.expr.mayIndexError
+        self.mayReturnEmpty = self.expr.mayReturnEmpty
+        self.setWhitespaceChars( self.expr.whiteChars )
+        self.skipWhitespace = self.expr.skipWhitespace
+        self.saveAsList = self.expr.saveAsList
+        self.ignoreExprs.extend(self.expr.ignoreExprs)
+        return self
+        
+    def __ilshift__(self, other):
+        return self << other
+    
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        return self
+
+    def streamline( self ):
+        if not self.streamlined:
+            self.streamlined = True
+            if self.expr is not None:
+                self.expr.streamline()
+        return self
+
+    def validate( self, validateTrace=[] ):
+        if self not in validateTrace:
+            tmp = validateTrace[:]+[self]
+            if self.expr is not None:
+                self.expr.validate(tmp)
+        self.checkRecursion([])
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+        return self.__class__.__name__ + ": ..."
+
+        # stubbed out for now - creates awful memory and perf issues
+        self._revertClass = self.__class__
+        self.__class__ = _ForwardNoRecurse
+        try:
+            if self.expr is not None:
+                retString = _ustr(self.expr)
+            else:
+                retString = "None"
+        finally:
+            self.__class__ = self._revertClass
+        return self.__class__.__name__ + ": " + retString
+
+    def copy(self):
+        if self.expr is not None:
+            return super(Forward,self).copy()
+        else:
+            ret = Forward()
+            ret <<= self
+            return ret
+
+class _ForwardNoRecurse(Forward):
+    def __str__( self ):
+        return "..."
+
+class TokenConverter(ParseElementEnhance):
+    """
+    Abstract subclass of C{ParseExpression}, for converting parsed results.
+    """
+    def __init__( self, expr, savelist=False ):
+        super(TokenConverter,self).__init__( expr )#, savelist )
+        self.saveAsList = False
+
+class Combine(TokenConverter):
+    """
+    Converter to concatenate all matching tokens to a single string.
+    By default, the matching patterns must also be contiguous in the input string;
+    this can be disabled by specifying C{'adjacent=False'} in the constructor.
+
+    Example::
+        real = Word(nums) + '.' + Word(nums)
+        print(real.parseString('3.1416')) # -> ['3', '.', '1416']
+        # will also erroneously match the following
+        print(real.parseString('3. 1416')) # -> ['3', '.', '1416']
+
+        real = Combine(Word(nums) + '.' + Word(nums))
+        print(real.parseString('3.1416')) # -> ['3.1416']
+        # no match when there are internal spaces
+        print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...)
+    """
+    def __init__( self, expr, joinString="", adjacent=True ):
+        super(Combine,self).__init__( expr )
+        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
+        if adjacent:
+            self.leaveWhitespace()
+        self.adjacent = adjacent
+        self.skipWhitespace = True
+        self.joinString = joinString
+        self.callPreparse = True
+
+    def ignore( self, other ):
+        if self.adjacent:
+            ParserElement.ignore(self, other)
+        else:
+            super( Combine, self).ignore( other )
+        return self
+
+    def postParse( self, instring, loc, tokenlist ):
+        retToks = tokenlist.copy()
+        del retToks[:]
+        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
+
+        if self.resultsName and retToks.haskeys():
+            return [ retToks ]
+        else:
+            return retToks
+
+class Group(TokenConverter):
+    """
+    Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions.
+
+    Example::
+        ident = Word(alphas)
+        num = Word(nums)
+        term = ident | num
+        func = ident + Optional(delimitedList(term))
+        print(func.parseString("fn a,b,100"))  # -> ['fn', 'a', 'b', '100']
+
+        func = ident + Group(Optional(delimitedList(term)))
+        print(func.parseString("fn a,b,100"))  # -> ['fn', ['a', 'b', '100']]
+    """
+    def __init__( self, expr ):
+        super(Group,self).__init__( expr )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        return [ tokenlist ]
+
+class Dict(TokenConverter):
+    """
+    Converter to return a repetitive expression as a list, but also as a dictionary.
+    Each element can also be referenced using the first token in the expression as its key.
+    Useful for tabular report scraping when the first column can be used as a item key.
+
+    Example::
+        data_word = Word(alphas)
+        label = data_word + FollowedBy(':')
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))
+
+        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
+        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        
+        # print attributes as plain groups
+        print(OneOrMore(attr_expr).parseString(text).dump())
+        
+        # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names
+        result = Dict(OneOrMore(Group(attr_expr))).parseString(text)
+        print(result.dump())
+        
+        # access named fields as dict entries, or output as dict
+        print(result['shape'])        
+        print(result.asDict())
+    prints::
+        ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap']
+
+        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]
+        - color: light blue
+        - posn: upper left
+        - shape: SQUARE
+        - texture: burlap
+        SQUARE
+        {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'}
+    See more examples at L{ParseResults} of accessing fields by results name.
+    """
+    def __init__( self, expr ):
+        super(Dict,self).__init__( expr )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        for i,tok in enumerate(tokenlist):
+            if len(tok) == 0:
+                continue
+            ikey = tok[0]
+            if isinstance(ikey,int):
+                ikey = _ustr(tok[0]).strip()
+            if len(tok)==1:
+                tokenlist[ikey] = _ParseResultsWithOffset("",i)
+            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
+                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
+            else:
+                dictvalue = tok.copy() #ParseResults(i)
+                del dictvalue[0]
+                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()):
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
+                else:
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
+
+        if self.resultsName:
+            return [ tokenlist ]
+        else:
+            return tokenlist
+
+
+class Suppress(TokenConverter):
+    """
+    Converter for ignoring the results of a parsed expression.
+
+    Example::
+        source = "a, b, c,d"
+        wd = Word(alphas)
+        wd_list1 = wd + ZeroOrMore(',' + wd)
+        print(wd_list1.parseString(source))
+
+        # often, delimiters that are useful during parsing are just in the
+        # way afterward - use Suppress to keep them out of the parsed output
+        wd_list2 = wd + ZeroOrMore(Suppress(',') + wd)
+        print(wd_list2.parseString(source))
+    prints::
+        ['a', ',', 'b', ',', 'c', ',', 'd']
+        ['a', 'b', 'c', 'd']
+    (See also L{delimitedList}.)
+    """
+    def postParse( self, instring, loc, tokenlist ):
+        return []
+
+    def suppress( self ):
+        return self
+
+
+class OnlyOnce(object):
+    """
+    Wrapper for parse actions, to ensure they are only called once.
+    """
+    def __init__(self, methodCall):
+        self.callable = _trim_arity(methodCall)
+        self.called = False
+    def __call__(self,s,l,t):
+        if not self.called:
+            results = self.callable(s,l,t)
+            self.called = True
+            return results
+        raise ParseException(s,l,"")
+    def reset(self):
+        self.called = False
+
+def traceParseAction(f):
+    """
+    Decorator for debugging parse actions. 
+    
+    When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".}
+    When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised.
+
+    Example::
+        wd = Word(alphas)
+
+        @traceParseAction
+        def remove_duplicate_chars(tokens):
+            return ''.join(sorted(set(''.join(tokens))))
+
+        wds = OneOrMore(wd).setParseAction(remove_duplicate_chars)
+        print(wds.parseString("slkdjs sld sldd sdlf sdljf"))
+    prints::
+        >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {}))
+        <3:
+            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
+        sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) )
+        try:
+            ret = f(*paArgs)
+        except Exception as exc:
+            sys.stderr.write( "< ['aa', 'bb', 'cc']
+        delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE']
+    """
+    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
+    if combine:
+        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
+    else:
+        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
+
+def countedArray( expr, intExpr=None ):
+    """
+    Helper to define a counted list of expressions.
+    This helper defines a pattern of the form::
+        integer expr expr expr...
+    where the leading integer tells how many expr expressions follow.
+    The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
+    
+    If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value.
+
+    Example::
+        countedArray(Word(alphas)).parseString('2 ab cd ef')  # -> ['ab', 'cd']
+
+        # in this parser, the leading integer value is given in binary,
+        # '10' indicating that 2 values are in the array
+        binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2))
+        countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef')  # -> ['ab', 'cd']
+    """
+    arrayExpr = Forward()
+    def countFieldParseAction(s,l,t):
+        n = t[0]
+        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
+        return []
+    if intExpr is None:
+        intExpr = Word(nums).setParseAction(lambda t:int(t[0]))
+    else:
+        intExpr = intExpr.copy()
+    intExpr.setName("arrayLen")
+    intExpr.addParseAction(countFieldParseAction, callDuringTry=True)
+    return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...')
+
+def _flatten(L):
+    ret = []
+    for i in L:
+        if isinstance(i,list):
+            ret.extend(_flatten(i))
+        else:
+            ret.append(i)
+    return ret
+
+def matchPreviousLiteral(expr):
+    """
+    Helper to define an expression that is indirectly defined from
+    the tokens matched in a previous expression, that is, it looks
+    for a 'repeat' of a previous expression.  For example::
+        first = Word(nums)
+        second = matchPreviousLiteral(first)
+        matchExpr = first + ":" + second
+    will match C{"1:1"}, but not C{"1:2"}.  Because this matches a
+    previous literal, will also match the leading C{"1:1"} in C{"1:10"}.
+    If this is not desired, use C{matchPreviousExpr}.
+    Do I{not} use with packrat parsing enabled.
+    """
+    rep = Forward()
+    def copyTokenToRepeater(s,l,t):
+        if t:
+            if len(t) == 1:
+                rep << t[0]
+            else:
+                # flatten t tokens
+                tflat = _flatten(t.asList())
+                rep << And(Literal(tt) for tt in tflat)
+        else:
+            rep << Empty()
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    rep.setName('(prev) ' + _ustr(expr))
+    return rep
+
+def matchPreviousExpr(expr):
+    """
+    Helper to define an expression that is indirectly defined from
+    the tokens matched in a previous expression, that is, it looks
+    for a 'repeat' of a previous expression.  For example::
+        first = Word(nums)
+        second = matchPreviousExpr(first)
+        matchExpr = first + ":" + second
+    will match C{"1:1"}, but not C{"1:2"}.  Because this matches by
+    expressions, will I{not} match the leading C{"1:1"} in C{"1:10"};
+    the expressions are evaluated first, and then compared, so
+    C{"1"} is compared with C{"10"}.
+    Do I{not} use with packrat parsing enabled.
+    """
+    rep = Forward()
+    e2 = expr.copy()
+    rep <<= e2
+    def copyTokenToRepeater(s,l,t):
+        matchTokens = _flatten(t.asList())
+        def mustMatchTheseTokens(s,l,t):
+            theseTokens = _flatten(t.asList())
+            if  theseTokens != matchTokens:
+                raise ParseException("",0,"")
+        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    rep.setName('(prev) ' + _ustr(expr))
+    return rep
+
+def _escapeRegexRangeChars(s):
+    #~  escape these chars: ^-]
+    for c in r"\^-]":
+        s = s.replace(c,_bslash+c)
+    s = s.replace("\n",r"\n")
+    s = s.replace("\t",r"\t")
+    return _ustr(s)
+
+def oneOf( strs, caseless=False, useRegex=True ):
+    """
+    Helper to quickly define a set of alternative Literals, and makes sure to do
+    longest-first testing when there is a conflict, regardless of the input order,
+    but returns a C{L{MatchFirst}} for best performance.
+
+    Parameters:
+     - strs - a string of space-delimited literals, or a collection of string literals
+     - caseless - (default=C{False}) - treat all literals as caseless
+     - useRegex - (default=C{True}) - as an optimization, will generate a Regex
+          object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or
+          if creating a C{Regex} raises an exception)
+
+    Example::
+        comp_oper = oneOf("< = > <= >= !=")
+        var = Word(alphas)
+        number = Word(nums)
+        term = var | number
+        comparison_expr = term + comp_oper + term
+        print(comparison_expr.searchString("B = 12  AA=23 B<=AA AA>12"))
+    prints::
+        [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']]
+    """
+    if caseless:
+        isequal = ( lambda a,b: a.upper() == b.upper() )
+        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
+        parseElementClass = CaselessLiteral
+    else:
+        isequal = ( lambda a,b: a == b )
+        masks = ( lambda a,b: b.startswith(a) )
+        parseElementClass = Literal
+
+    symbols = []
+    if isinstance(strs,basestring):
+        symbols = strs.split()
+    elif isinstance(strs, Iterable):
+        symbols = list(strs)
+    else:
+        warnings.warn("Invalid argument to oneOf, expected string or iterable",
+                SyntaxWarning, stacklevel=2)
+    if not symbols:
+        return NoMatch()
+
+    i = 0
+    while i < len(symbols)-1:
+        cur = symbols[i]
+        for j,other in enumerate(symbols[i+1:]):
+            if ( isequal(other, cur) ):
+                del symbols[i+j+1]
+                break
+            elif ( masks(cur, other) ):
+                del symbols[i+j+1]
+                symbols.insert(i,other)
+                cur = other
+                break
+        else:
+            i += 1
+
+    if not caseless and useRegex:
+        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
+        try:
+            if len(symbols)==len("".join(symbols)):
+                return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols))
+            else:
+                return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols))
+        except Exception:
+            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
+                    SyntaxWarning, stacklevel=2)
+
+
+    # last resort, just use MatchFirst
+    return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols))
+
+def dictOf( key, value ):
+    """
+    Helper to easily and clearly define a dictionary by specifying the respective patterns
+    for the key and value.  Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens
+    in the proper order.  The key pattern can include delimiting markers or punctuation,
+    as long as they are suppressed, thereby leaving the significant key text.  The value
+    pattern can include named results, so that the C{Dict} results can include named token
+    fields.
+
+    Example::
+        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
+        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        print(OneOrMore(attr_expr).parseString(text).dump())
+        
+        attr_label = label
+        attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)
+
+        # similar to Dict, but simpler call format
+        result = dictOf(attr_label, attr_value).parseString(text)
+        print(result.dump())
+        print(result['shape'])
+        print(result.shape)  # object attribute access works too
+        print(result.asDict())
+    prints::
+        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]
+        - color: light blue
+        - posn: upper left
+        - shape: SQUARE
+        - texture: burlap
+        SQUARE
+        SQUARE
+        {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'}
+    """
+    return Dict( ZeroOrMore( Group ( key + value ) ) )
+
+def originalTextFor(expr, asString=True):
+    """
+    Helper to return the original, untokenized text for a given expression.  Useful to
+    restore the parsed fields of an HTML start tag into the raw tag text itself, or to
+    revert separate tokens with intervening whitespace back to the original matching
+    input text. By default, returns astring containing the original parsed text.  
+       
+    If the optional C{asString} argument is passed as C{False}, then the return value is a 
+    C{L{ParseResults}} containing any results names that were originally matched, and a 
+    single token containing the original matched text from the input string.  So if 
+    the expression passed to C{L{originalTextFor}} contains expressions with defined
+    results names, you must set C{asString} to C{False} if you want to preserve those
+    results name values.
+
+    Example::
+        src = "this is test  bold text  normal text "
+        for tag in ("b","i"):
+            opener,closer = makeHTMLTags(tag)
+            patt = originalTextFor(opener + SkipTo(closer) + closer)
+            print(patt.searchString(src)[0])
+    prints::
+        [' bold text ']
+        ['text']
+    """
+    locMarker = Empty().setParseAction(lambda s,loc,t: loc)
+    endlocMarker = locMarker.copy()
+    endlocMarker.callPreparse = False
+    matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end")
+    if asString:
+        extractText = lambda s,l,t: s[t._original_start:t._original_end]
+    else:
+        def extractText(s,l,t):
+            t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]]
+    matchExpr.setParseAction(extractText)
+    matchExpr.ignoreExprs = expr.ignoreExprs
+    return matchExpr
+
+def ungroup(expr): 
+    """
+    Helper to undo pyparsing's default grouping of And expressions, even
+    if all but one are non-empty.
+    """
+    return TokenConverter(expr).setParseAction(lambda t:t[0])
+
+def locatedExpr(expr):
+    """
+    Helper to decorate a returned token with its starting and ending locations in the input string.
+    This helper adds the following results names:
+     - locn_start = location where matched expression begins
+     - locn_end = location where matched expression ends
+     - value = the actual parsed results
+
+    Be careful if the input text contains C{} characters, you may want to call
+    C{L{ParserElement.parseWithTabs}}
+
+    Example::
+        wd = Word(alphas)
+        for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"):
+            print(match)
+    prints::
+        [[0, 'ljsdf', 5]]
+        [[8, 'lksdjjf', 15]]
+        [[18, 'lkkjj', 23]]
+    """
+    locator = Empty().setParseAction(lambda s,l,t: l)
+    return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end"))
+
+
+# convenience constants for positional expressions
+empty       = Empty().setName("empty")
+lineStart   = LineStart().setName("lineStart")
+lineEnd     = LineEnd().setName("lineEnd")
+stringStart = StringStart().setName("stringStart")
+stringEnd   = StringEnd().setName("stringEnd")
+
+_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
+_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16)))
+_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8)))
+_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1)
+_charRange = Group(_singleChar + Suppress("-") + _singleChar)
+_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
+
+def srange(s):
+    r"""
+    Helper to easily define string ranges for use in Word construction.  Borrows
+    syntax from regexp '[]' string range definitions::
+        srange("[0-9]")   -> "0123456789"
+        srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
+        srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
+    The input string must be enclosed in []'s, and the returned string is the expanded
+    character set joined into a single string.
+    The values enclosed in the []'s may be:
+     - a single character
+     - an escaped character with a leading backslash (such as C{\-} or C{\]})
+     - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) 
+         (C{\0x##} is also supported for backwards compatibility) 
+     - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character)
+     - a range of any of the above, separated by a dash (C{'a-z'}, etc.)
+     - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.)
+    """
+    _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1))
+    try:
+        return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body)
+    except Exception:
+        return ""
+
+def matchOnlyAtCol(n):
+    """
+    Helper method for defining parse actions that require matching at a specific
+    column in the input text.
+    """
+    def verifyCol(strg,locn,toks):
+        if col(locn,strg) != n:
+            raise ParseException(strg,locn,"matched token not at column %d" % n)
+    return verifyCol
+
+def replaceWith(replStr):
+    """
+    Helper method for common parse actions that simply return a literal value.  Especially
+    useful when used with C{L{transformString}()}.
+
+    Example::
+        num = Word(nums).setParseAction(lambda toks: int(toks[0]))
+        na = oneOf("N/A NA").setParseAction(replaceWith(math.nan))
+        term = na | num
+        
+        OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234]
+    """
+    return lambda s,l,t: [replStr]
+
+def removeQuotes(s,l,t):
+    """
+    Helper parse action for removing quotation marks from parsed quoted strings.
+
+    Example::
+        # by default, quotation marks are included in parsed results
+        quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"]
+
+        # use removeQuotes to strip quotation marks from parsed results
+        quotedString.setParseAction(removeQuotes)
+        quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"]
+    """
+    return t[0][1:-1]
+
+def tokenMap(func, *args):
+    """
+    Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional 
+    args are passed, they are forwarded to the given function as additional arguments after
+    the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the
+    parsed data to an integer using base 16.
+
+    Example (compare the last to example in L{ParserElement.transformString}::
+        hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16))
+        hex_ints.runTests('''
+            00 11 22 aa FF 0a 0d 1a
+            ''')
+        
+        upperword = Word(alphas).setParseAction(tokenMap(str.upper))
+        OneOrMore(upperword).runTests('''
+            my kingdom for a horse
+            ''')
+
+        wd = Word(alphas).setParseAction(tokenMap(str.title))
+        OneOrMore(wd).setParseAction(' '.join).runTests('''
+            now is the winter of our discontent made glorious summer by this sun of york
+            ''')
+    prints::
+        00 11 22 aa FF 0a 0d 1a
+        [0, 17, 34, 170, 255, 10, 13, 26]
+
+        my kingdom for a horse
+        ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE']
+
+        now is the winter of our discontent made glorious summer by this sun of york
+        ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York']
+    """
+    def pa(s,l,t):
+        return [func(tokn, *args) for tokn in t]
+
+    try:
+        func_name = getattr(func, '__name__', 
+                            getattr(func, '__class__').__name__)
+    except Exception:
+        func_name = str(func)
+    pa.__name__ = func_name
+
+    return pa
+
+upcaseTokens = tokenMap(lambda t: _ustr(t).upper())
+"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}"""
+
+downcaseTokens = tokenMap(lambda t: _ustr(t).lower())
+"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}"""
+    
+def _makeTags(tagStr, xml):
+    """Internal helper to construct opening and closing tag expressions, given a tag name"""
+    if isinstance(tagStr,basestring):
+        resname = tagStr
+        tagStr = Keyword(tagStr, caseless=not xml)
+    else:
+        resname = tagStr.name
+
+    tagAttrName = Word(alphas,alphanums+"_-:")
+    if (xml):
+        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
+        openTag = Suppress("<") + tagStr("tag") + \
+                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    else:
+        printablesLessRAbrack = "".join(c for c in printables if c not in ">")
+        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
+        openTag = Suppress("<") + tagStr("tag") + \
+                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
+                Optional( Suppress("=") + tagAttrValue ) ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    closeTag = Combine(_L("")
+
+    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname)
+    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % resname)
+    openTag.tag = resname
+    closeTag.tag = resname
+    return openTag, closeTag
+
+def makeHTMLTags(tagStr):
+    """
+    Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches
+    tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values.
+
+    Example::
+        text = 'More info at the pyparsing wiki page'
+        # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple
+        a,a_end = makeHTMLTags("A")
+        link_expr = a + SkipTo(a_end)("link_text") + a_end
+        
+        for link in link_expr.searchString(text):
+            # attributes in the  tag (like "href" shown here) are also accessible as named results
+            print(link.link_text, '->', link.href)
+    prints::
+        pyparsing -> http://pyparsing.wikispaces.com
+    """
+    return _makeTags( tagStr, False )
+
+def makeXMLTags(tagStr):
+    """
+    Helper to construct opening and closing tag expressions for XML, given a tag name. Matches
+    tags only in the given upper/lower case.
+
+    Example: similar to L{makeHTMLTags}
+    """
+    return _makeTags( tagStr, True )
+
+def withAttribute(*args,**attrDict):
+    """
+    Helper to create a validating parse action to be used with start tags created
+    with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag
+    with a required attribute value, to avoid false matches on common tags such as
+    C{} or C{
}. + + Call C{withAttribute} with a series of attribute names and values. Specify the list + of filter attributes names and values as: + - keyword arguments, as in C{(align="right")}, or + - as an explicit dict with C{**} operator, when an attribute name is also a Python + reserved word, as in C{**{"class":"Customer", "align":"right"}} + - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) + For attribute names with a namespace prefix, you must use the second form. Attribute + names are matched insensitive to upper/lower case. + + If just testing for C{class} (with or without a namespace), use C{L{withClass}}. + + To verify that the attribute exists, but without specifying a value, pass + C{withAttribute.ANY_VALUE} as the value. + + Example:: + html = ''' +
+ Some text +
1 4 0 1 0
+
1,3 2,3 1,1
+
this has no type
+
+ + ''' + div,div_end = makeHTMLTags("div") + + # only match div tag having a type attribute with value "grid" + div_grid = div().setParseAction(withAttribute(type="grid")) + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + # construct a match with any div tag having a type attribute, regardless of the value + div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + if args: + attrs = args[:] + else: + attrs = attrDict.items() + attrs = [(k,v) for k,v in attrs] + def pa(s,l,tokens): + for attrName,attrValue in attrs: + if attrName not in tokens: + raise ParseException(s,l,"no matching attribute " + attrName) + if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: + raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % + (attrName, tokens[attrName], attrValue)) + return pa +withAttribute.ANY_VALUE = object() + +def withClass(classname, namespace=''): + """ + Simplified version of C{L{withAttribute}} when matching on a div class - made + difficult because C{class} is a reserved word in Python. + + Example:: + html = ''' +
+ Some text +
1 4 0 1 0
+
1,3 2,3 1,1
+
this <div> has no class
+
+ + ''' + div,div_end = makeHTMLTags("div") + div_grid = div().setParseAction(withClass("grid")) + + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + classattr = "%s:class" % namespace if namespace else "class" + return withAttribute(**{classattr : classname}) + +opAssoc = _Constants() +opAssoc.LEFT = object() +opAssoc.RIGHT = object() + +def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): + """ + Helper method for constructing grammars of expressions made up of + operators working in a precedence hierarchy. Operators may be unary or + binary, left- or right-associative. Parse actions can also be attached + to operator expressions. The generated parser will also recognize the use + of parentheses to override operator precedences (see example below). + + Note: if you define a deep operator list, you may see performance issues + when using infixNotation. See L{ParserElement.enablePackrat} for a + mechanism to potentially improve your parser performance. + + Parameters: + - baseExpr - expression representing the most basic element for the nested + - opList - list of tuples, one for each operator precedence level in the + expression grammar; each tuple is of the form + (opExpr, numTerms, rightLeftAssoc, parseAction), where: + - opExpr is the pyparsing expression for the operator; + may also be a string, which will be converted to a Literal; + if numTerms is 3, opExpr is a tuple of two expressions, for the + two operators separating the 3 terms + - numTerms is the number of terms for this operator (must + be 1, 2, or 3) + - rightLeftAssoc is the indicator whether the operator is + right or left associative, using the pyparsing-defined + constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. + - parseAction is the parse action to be associated with + expressions matching this operator expression (the + parse action tuple member may be omitted); if the parse action + is passed a tuple or list of functions, this is equivalent to + calling C{setParseAction(*fn)} (L{ParserElement.setParseAction}) + - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) + - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) + + Example:: + # simple example of four-function arithmetic with ints and variable names + integer = pyparsing_common.signed_integer + varname = pyparsing_common.identifier + + arith_expr = infixNotation(integer | varname, + [ + ('-', 1, opAssoc.RIGHT), + (oneOf('* /'), 2, opAssoc.LEFT), + (oneOf('+ -'), 2, opAssoc.LEFT), + ]) + + arith_expr.runTests(''' + 5+3*6 + (5+3)*6 + -2--11 + ''', fullDump=False) + prints:: + 5+3*6 + [[5, '+', [3, '*', 6]]] + + (5+3)*6 + [[[5, '+', 3], '*', 6]] + + -2--11 + [[['-', 2], '-', ['-', 11]]] + """ + ret = Forward() + lastExpr = baseExpr | ( lpar + ret + rpar ) + for i,operDef in enumerate(opList): + opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] + termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr + if arity == 3: + if opExpr is None or len(opExpr) != 2: + raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") + opExpr1, opExpr2 = opExpr + thisExpr = Forward().setName(termName) + if rightLeftAssoc == opAssoc.LEFT: + if arity == 1: + matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) + else: + matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ + Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + elif rightLeftAssoc == opAssoc.RIGHT: + if arity == 1: + # try to avoid LR with this extra test + if not isinstance(opExpr, Optional): + opExpr = Optional(opExpr) + matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) + else: + matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ + Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + else: + raise ValueError("operator must indicate right or left associativity") + if pa: + if isinstance(pa, (tuple, list)): + matchExpr.setParseAction(*pa) + else: + matchExpr.setParseAction(pa) + thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) + lastExpr = thisExpr + ret <<= lastExpr + return ret + +operatorPrecedence = infixNotation +"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" + +dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") +sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") +quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| + Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") +unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") + +def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): + """ + Helper method for defining nested lists enclosed in opening and closing + delimiters ("(" and ")" are the default). + + Parameters: + - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression + - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression + - content - expression for items within the nested lists (default=C{None}) + - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) + + If an expression is not provided for the content argument, the nested + expression will capture all whitespace-delimited content between delimiters + as a list of separate values. + + Use the C{ignoreExpr} argument to define expressions that may contain + opening or closing characters that should not be treated as opening + or closing characters for nesting, such as quotedString or a comment + expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. + The default is L{quotedString}, but if no expressions are to be ignored, + then pass C{None} for this argument. + + Example:: + data_type = oneOf("void int short long char float double") + decl_data_type = Combine(data_type + Optional(Word('*'))) + ident = Word(alphas+'_', alphanums+'_') + number = pyparsing_common.number + arg = Group(decl_data_type + ident) + LPAR,RPAR = map(Suppress, "()") + + code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) + + c_function = (decl_data_type("type") + + ident("name") + + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + + code_body("body")) + c_function.ignore(cStyleComment) + + source_code = ''' + int is_odd(int x) { + return (x%2); + } + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { + return (10+ord(hchar)-ord('A')); + } + } + ''' + for func in c_function.searchString(source_code): + print("%(name)s (%(type)s) args: %(args)s" % func) + + prints:: + is_odd (int) args: [['int', 'x']] + dec_to_hex (int) args: [['char', 'hchar']] + """ + if opener == closer: + raise ValueError("opening and closing strings cannot be the same") + if content is None: + if isinstance(opener,basestring) and isinstance(closer,basestring): + if len(opener) == 1 and len(closer)==1: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS + ).setParseAction(lambda t:t[0].strip())) + else: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + ~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + raise ValueError("opening and closing arguments must be strings if no content expression is given") + ret = Forward() + if ignoreExpr is not None: + ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) + else: + ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) + ret.setName('nested %s%s expression' % (opener,closer)) + return ret + +def indentedBlock(blockStatementExpr, indentStack, indent=True): + """ + Helper method for defining space-delimited indentation blocks, such as + those used to define block statements in Python source code. + + Parameters: + - blockStatementExpr - expression defining syntax of statement that + is repeated within the indented block + - indentStack - list created by caller to manage indentation stack + (multiple statementWithIndentedBlock expressions within a single grammar + should share a common indentStack) + - indent - boolean indicating whether block must be indented beyond the + the current level; set to False for block of left-most statements + (default=C{True}) + + A valid block must contain at least one C{blockStatement}. + + Example:: + data = ''' + def A(z): + A1 + B = 100 + G = A2 + A2 + A3 + B + def BB(a,b,c): + BB1 + def BBA(): + bba1 + bba2 + bba3 + C + D + def spam(x,y): + def eggs(z): + pass + ''' + + + indentStack = [1] + stmt = Forward() + + identifier = Word(alphas, alphanums) + funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") + func_body = indentedBlock(stmt, indentStack) + funcDef = Group( funcDecl + func_body ) + + rvalue = Forward() + funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") + rvalue << (funcCall | identifier | Word(nums)) + assignment = Group(identifier + "=" + rvalue) + stmt << ( funcDef | assignment | identifier ) + + module_body = OneOrMore(stmt) + + parseTree = module_body.parseString(data) + parseTree.pprint() + prints:: + [['def', + 'A', + ['(', 'z', ')'], + ':', + [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], + 'B', + ['def', + 'BB', + ['(', 'a', 'b', 'c', ')'], + ':', + [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], + 'C', + 'D', + ['def', + 'spam', + ['(', 'x', 'y', ')'], + ':', + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + """ + def checkPeerIndent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if curCol != indentStack[-1]: + if curCol > indentStack[-1]: + raise ParseFatalException(s,l,"illegal nesting") + raise ParseException(s,l,"not a peer entry") + + def checkSubIndent(s,l,t): + curCol = col(l,s) + if curCol > indentStack[-1]: + indentStack.append( curCol ) + else: + raise ParseException(s,l,"not a subentry") + + def checkUnindent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): + raise ParseException(s,l,"not an unindent") + indentStack.pop() + + NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) + INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') + PEER = Empty().setParseAction(checkPeerIndent).setName('') + UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') + if indent: + smExpr = Group( Optional(NL) + + #~ FollowedBy(blockStatementExpr) + + INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) + else: + smExpr = Group( Optional(NL) + + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) + blockStatementExpr.ignore(_bslash + LineEnd()) + return smExpr.setName('indented block') + +alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") +punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") + +anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) +_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) +commonHTMLEntity = Regex('&(?P' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") +def replaceHTMLEntity(t): + """Helper parser action to replace common HTML entities with their special characters""" + return _htmlEntityMap.get(t.entity) + +# it's easy to get these comment structures wrong - they're very common, so may as well make them available +cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") +"Comment of the form C{/* ... */}" + +htmlComment = Regex(r"").setName("HTML comment") +"Comment of the form C{}" + +restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") +dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") +"Comment of the form C{// ... (to end of line)}" + +cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") +"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" + +javaStyleComment = cppStyleComment +"Same as C{L{cppStyleComment}}" + +pythonStyleComment = Regex(r"#.*").setName("Python style comment") +"Comment of the form C{# ... (to end of line)}" + +_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + + Optional( Word(" \t") + + ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") +commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") +"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. + This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" + +# some other useful expressions - using lower-case class name since we are really using this as a namespace +class pyparsing_common: + """ + Here are some common low-level expressions that may be useful in jump-starting parser development: + - numeric forms (L{integers}, L{reals}, L{scientific notation}) + - common L{programming identifiers} + - network addresses (L{MAC}, L{IPv4}, L{IPv6}) + - ISO8601 L{dates} and L{datetime} + - L{UUID} + - L{comma-separated list} + Parse actions: + - C{L{convertToInteger}} + - C{L{convertToFloat}} + - C{L{convertToDate}} + - C{L{convertToDatetime}} + - C{L{stripHTMLTags}} + - C{L{upcaseTokens}} + - C{L{downcaseTokens}} + + Example:: + pyparsing_common.number.runTests(''' + # any int or real number, returned as the appropriate type + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.fnumber.runTests(''' + # any int or real number, returned as float + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.hex_integer.runTests(''' + # hex numbers + 100 + FF + ''') + + pyparsing_common.fraction.runTests(''' + # fractions + 1/2 + -3/4 + ''') + + pyparsing_common.mixed_integer.runTests(''' + # mixed fractions + 1 + 1/2 + -3/4 + 1-3/4 + ''') + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(''' + # uuid + 12345678-1234-5678-1234-567812345678 + ''') + prints:: + # any int or real number, returned as the appropriate type + 100 + [100] + + -100 + [-100] + + +100 + [100] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # any int or real number, returned as float + 100 + [100.0] + + -100 + [-100.0] + + +100 + [100.0] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # hex numbers + 100 + [256] + + FF + [255] + + # fractions + 1/2 + [0.5] + + -3/4 + [-0.75] + + # mixed fractions + 1 + [1] + + 1/2 + [0.5] + + -3/4 + [-0.75] + + 1-3/4 + [1.75] + + # uuid + 12345678-1234-5678-1234-567812345678 + [UUID('12345678-1234-5678-1234-567812345678')] + """ + + convertToInteger = tokenMap(int) + """ + Parse action for converting parsed integers to Python int + """ + + convertToFloat = tokenMap(float) + """ + Parse action for converting parsed numbers to Python float + """ + + integer = Word(nums).setName("integer").setParseAction(convertToInteger) + """expression that parses an unsigned integer, returns an int""" + + hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) + """expression that parses a hexadecimal integer, returns an int""" + + signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + """expression that parses an integer with optional leading sign, returns an int""" + + fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") + """fractional expression of an integer divided by an integer, returns a float""" + fraction.addParseAction(lambda t: t[0]/t[-1]) + + mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") + """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" + mixed_integer.addParseAction(sum) + + real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) + """expression that parses a floating point number and returns a float""" + + sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) + """expression that parses a floating point number with optional scientific notation and returns a float""" + + # streamlining this expression makes the docs nicer-looking + number = (sci_real | real | signed_integer).streamline() + """any numeric expression, returns the corresponding Python type""" + + fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) + """any int or real number, returned as float""" + + identifier = Word(alphas+'_', alphanums+'_').setName("identifier") + """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" + + ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") + "IPv4 address (C{0.0.0.0 - 255.255.255.255})" + + _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") + _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") + _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") + _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) + _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") + ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") + "IPv6 address (long, short, or mixed form)" + + mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") + "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" + + @staticmethod + def convertToDate(fmt="%Y-%m-%d"): + """ + Helper to create a parse action for converting parsed date string to Python datetime.date + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) + + Example:: + date_expr = pyparsing_common.iso8601_date.copy() + date_expr.setParseAction(pyparsing_common.convertToDate()) + print(date_expr.parseString("1999-12-31")) + prints:: + [datetime.date(1999, 12, 31)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt).date() + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + @staticmethod + def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): + """ + Helper to create a parse action for converting parsed datetime string to Python datetime.datetime + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) + + Example:: + dt_expr = pyparsing_common.iso8601_datetime.copy() + dt_expr.setParseAction(pyparsing_common.convertToDatetime()) + print(dt_expr.parseString("1999-12-31T23:59:59.999")) + prints:: + [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt) + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + iso8601_date = Regex(r'(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?').setName("ISO8601 date") + "ISO8601 date (C{yyyy-mm-dd})" + + iso8601_datetime = Regex(r'(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") + "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" + + uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") + "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" + + _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() + @staticmethod + def stripHTMLTags(s, l, tokens): + """ + Parse action to remove HTML tags from web page HTML source + + Example:: + # strip HTML links from normal text + text = 'More info at the
pyparsing wiki page' + td,td_end = makeHTMLTags("TD") + table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end + + print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' + """ + return pyparsing_common._html_stripper.transformString(tokens[0]) + + _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') + + Optional( White(" \t") ) ) ).streamline().setName("commaItem") + comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") + """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" + + upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) + """Parse action to convert tokens to upper case.""" + + downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower())) + """Parse action to convert tokens to lower case.""" + + +if __name__ == "__main__": + + selectToken = CaselessLiteral("select") + fromToken = CaselessLiteral("from") + + ident = Word(alphas, alphanums + "_$") + + columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + columnNameList = Group(delimitedList(columnName)).setName("columns") + columnSpec = ('*' | columnNameList) + + tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + tableNameList = Group(delimitedList(tableName)).setName("tables") + + simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") + + # demo runTests method, including embedded comments in test string + simpleSQL.runTests(""" + # '*' as column list and dotted table name + select * from SYS.XYZZY + + # caseless match on "SELECT", and casts back to "select" + SELECT * from XYZZY, ABC + + # list of column names, and mixed case SELECT keyword + Select AA,BB,CC from Sys.dual + + # multiple tables + Select A, B, C from Sys.dual, Table2 + + # invalid SELECT keyword - should fail + Xelect A, B, C from Sys.dual + + # incomplete command - should fail + Select + + # invalid column name - should fail + Select ^^^ frox Sys.dual + + """) + + pyparsing_common.number.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + # any int or real number, returned as float + pyparsing_common.fnumber.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + pyparsing_common.hex_integer.runTests(""" + 100 + FF + """) + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(""" + 12345678-1234-5678-1234-567812345678 + """) diff --git a/MLPY/Lib/site-packages/setuptools/archive_util.py b/MLPY/Lib/site-packages/setuptools/archive_util.py new file mode 100644 index 0000000000000000000000000000000000000000..0f70284822f50098e21ad439550cdbd4d298d011 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/archive_util.py @@ -0,0 +1,205 @@ +"""Utilities for extracting common archive formats""" + +import zipfile +import tarfile +import os +import shutil +import posixpath +import contextlib +from distutils.errors import DistutilsError + +from pkg_resources import ensure_directory + +__all__ = [ + "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", + "UnrecognizedFormat", "extraction_drivers", "unpack_directory", +] + + +class UnrecognizedFormat(DistutilsError): + """Couldn't recognize the archive type""" + + +def default_filter(src, dst): + """The default progress/filter callback; returns True for all files""" + return dst + + +def unpack_archive( + filename, extract_dir, progress_filter=default_filter, + drivers=None): + """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat`` + + `progress_filter` is a function taking two arguments: a source path + internal to the archive ('/'-separated), and a filesystem path where it + will be extracted. The callback must return the desired extract path + (which may be the same as the one passed in), or else ``None`` to skip + that file or directory. The callback can thus be used to report on the + progress of the extraction, as well as to filter the items extracted or + alter their extraction paths. + + `drivers`, if supplied, must be a non-empty sequence of functions with the + same signature as this function (minus the `drivers` argument), that raise + ``UnrecognizedFormat`` if they do not support extracting the designated + archive type. The `drivers` are tried in sequence until one is found that + does not raise an error, or until all are exhausted (in which case + ``UnrecognizedFormat`` is raised). If you do not supply a sequence of + drivers, the module's ``extraction_drivers`` constant will be used, which + means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that + order. + """ + for driver in drivers or extraction_drivers: + try: + driver(filename, extract_dir, progress_filter) + except UnrecognizedFormat: + continue + else: + return + else: + raise UnrecognizedFormat( + "Not a recognized archive type: %s" % filename + ) + + +def unpack_directory(filename, extract_dir, progress_filter=default_filter): + """"Unpack" a directory, using the same interface as for archives + + Raises ``UnrecognizedFormat`` if `filename` is not a directory + """ + if not os.path.isdir(filename): + raise UnrecognizedFormat("%s is not a directory" % filename) + + paths = { + filename: ('', extract_dir), + } + for base, dirs, files in os.walk(filename): + src, dst = paths[base] + for d in dirs: + paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d) + for f in files: + target = os.path.join(dst, f) + target = progress_filter(src + f, target) + if not target: + # skip non-files + continue + ensure_directory(target) + f = os.path.join(base, f) + shutil.copyfile(f, target) + shutil.copystat(f, target) + + +def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): + """Unpack zip `filename` to `extract_dir` + + Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined + by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation + of the `progress_filter` argument. + """ + + if not zipfile.is_zipfile(filename): + raise UnrecognizedFormat("%s is not a zip file" % (filename,)) + + with zipfile.ZipFile(filename) as z: + for info in z.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name.split('/'): + continue + + target = os.path.join(extract_dir, *name.split('/')) + target = progress_filter(name, target) + if not target: + continue + if name.endswith('/'): + # directory + ensure_directory(target) + else: + # file + ensure_directory(target) + data = z.read(info.filename) + with open(target, 'wb') as f: + f.write(data) + unix_attributes = info.external_attr >> 16 + if unix_attributes: + os.chmod(target, unix_attributes) + + +def _resolve_tar_file_or_dir(tar_obj, tar_member_obj): + """Resolve any links and extract link targets as normal files.""" + while tar_member_obj is not None and ( + tar_member_obj.islnk() or tar_member_obj.issym()): + linkpath = tar_member_obj.linkname + if tar_member_obj.issym(): + base = posixpath.dirname(tar_member_obj.name) + linkpath = posixpath.join(base, linkpath) + linkpath = posixpath.normpath(linkpath) + tar_member_obj = tar_obj._getmember(linkpath) + + is_file_or_dir = ( + tar_member_obj is not None and + (tar_member_obj.isfile() or tar_member_obj.isdir()) + ) + if is_file_or_dir: + return tar_member_obj + + raise LookupError('Got unknown file type') + + +def _iter_open_tar(tar_obj, extract_dir, progress_filter): + """Emit member-destination pairs from a tar archive.""" + # don't do any chowning! + tar_obj.chown = lambda *args: None + + with contextlib.closing(tar_obj): + for member in tar_obj: + name = member.name + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name.split('/'): + continue + + prelim_dst = os.path.join(extract_dir, *name.split('/')) + + try: + member = _resolve_tar_file_or_dir(tar_obj, member) + except LookupError: + continue + + final_dst = progress_filter(name, prelim_dst) + if not final_dst: + continue + + if final_dst.endswith(os.sep): + final_dst = final_dst[:-1] + + yield member, final_dst + + +def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + + Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined + by ``tarfile.open()``). See ``unpack_archive()`` for an explanation + of the `progress_filter` argument. + """ + try: + tarobj = tarfile.open(filename) + except tarfile.TarError as e: + raise UnrecognizedFormat( + "%s is not a compressed or uncompressed tar file" % (filename,) + ) from e + + for member, final_dst in _iter_open_tar( + tarobj, extract_dir, progress_filter, + ): + try: + # XXX Ugh + tarobj._extract_member(member, final_dst) + except tarfile.ExtractError: + # chown/chmod/mkfifo/mknode/makedev failed + pass + + return True + + +extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile diff --git a/MLPY/Lib/site-packages/setuptools/build_meta.py b/MLPY/Lib/site-packages/setuptools/build_meta.py new file mode 100644 index 0000000000000000000000000000000000000000..9dfb2f24b52e4d4a806b26fe99ad9a316fcc5631 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/build_meta.py @@ -0,0 +1,281 @@ +"""A PEP 517 interface to setuptools + +Previously, when a user or a command line tool (let's call it a "frontend") +needed to make a request of setuptools to take a certain action, for +example, generating a list of installation requirements, the frontend would +would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line. + +PEP 517 defines a different method of interfacing with setuptools. Rather +than calling "setup.py" directly, the frontend should: + + 1. Set the current directory to the directory with a setup.py file + 2. Import this module into a safe python interpreter (one in which + setuptools can potentially set global variables or crash hard). + 3. Call one of the functions defined in PEP 517. + +What each function does is defined in PEP 517. However, here is a "casual" +definition of the functions (this definition should not be relied on for +bug reports or API stability): + + - `build_wheel`: build a wheel in the folder and return the basename + - `get_requires_for_build_wheel`: get the `setup_requires` to build + - `prepare_metadata_for_build_wheel`: get the `install_requires` + - `build_sdist`: build an sdist in the folder and return the basename + - `get_requires_for_build_sdist`: get the `setup_requires` to build + +Again, this is not a formal definition! Just a "taste" of the module. +""" + +import io +import os +import sys +import tokenize +import shutil +import contextlib +import tempfile + +import setuptools +import distutils + +from pkg_resources import parse_requirements + +__all__ = ['get_requires_for_build_sdist', + 'get_requires_for_build_wheel', + 'prepare_metadata_for_build_wheel', + 'build_wheel', + 'build_sdist', + '__legacy__', + 'SetupRequirementsError'] + + +class SetupRequirementsError(BaseException): + def __init__(self, specifiers): + self.specifiers = specifiers + + +class Distribution(setuptools.dist.Distribution): + def fetch_build_eggs(self, specifiers): + specifier_list = list(map(str, parse_requirements(specifiers))) + + raise SetupRequirementsError(specifier_list) + + @classmethod + @contextlib.contextmanager + def patch(cls): + """ + Replace + distutils.dist.Distribution with this class + for the duration of this context. + """ + orig = distutils.core.Distribution + distutils.core.Distribution = cls + try: + yield + finally: + distutils.core.Distribution = orig + + +@contextlib.contextmanager +def no_install_setup_requires(): + """Temporarily disable installing setup_requires + + Under PEP 517, the backend reports build dependencies to the frontend, + and the frontend is responsible for ensuring they're installed. + So setuptools (acting as a backend) should not try to install them. + """ + orig = setuptools._install_setup_requires + setuptools._install_setup_requires = lambda attrs: None + try: + yield + finally: + setuptools._install_setup_requires = orig + + +def _get_immediate_subdirectories(a_dir): + return [name for name in os.listdir(a_dir) + if os.path.isdir(os.path.join(a_dir, name))] + + +def _file_with_extension(directory, extension): + matching = ( + f for f in os.listdir(directory) + if f.endswith(extension) + ) + try: + file, = matching + except ValueError: + raise ValueError( + 'No distribution was found. Ensure that `setup.py` ' + 'is not empty and that it calls `setup()`.') + return file + + +def _open_setup_script(setup_script): + if not os.path.exists(setup_script): + # Supply a default setup.py + return io.StringIO(u"from setuptools import setup; setup()") + + return getattr(tokenize, 'open', open)(setup_script) + + +class _BuildMetaBackend(object): + + def _fix_config(self, config_settings): + config_settings = config_settings or {} + config_settings.setdefault('--global-option', []) + return config_settings + + def _get_build_requires(self, config_settings, requirements): + config_settings = self._fix_config(config_settings) + + sys.argv = sys.argv[:1] + ['egg_info'] + \ + config_settings["--global-option"] + try: + with Distribution.patch(): + self.run_setup() + except SetupRequirementsError as e: + requirements += e.specifiers + + return requirements + + def run_setup(self, setup_script='setup.py'): + # Note that we can reuse our build directory between calls + # Correctness comes first, then optimization later + __file__ = setup_script + __name__ = '__main__' + + with _open_setup_script(__file__) as f: + code = f.read().replace(r'\r\n', r'\n') + + exec(compile(code, __file__, 'exec'), locals()) + + def get_requires_for_build_wheel(self, config_settings=None): + config_settings = self._fix_config(config_settings) + return self._get_build_requires( + config_settings, requirements=['wheel']) + + def get_requires_for_build_sdist(self, config_settings=None): + config_settings = self._fix_config(config_settings) + return self._get_build_requires(config_settings, requirements=[]) + + def prepare_metadata_for_build_wheel(self, metadata_directory, + config_settings=None): + sys.argv = sys.argv[:1] + [ + 'dist_info', '--egg-base', metadata_directory] + with no_install_setup_requires(): + self.run_setup() + + dist_info_directory = metadata_directory + while True: + dist_infos = [f for f in os.listdir(dist_info_directory) + if f.endswith('.dist-info')] + + if ( + len(dist_infos) == 0 and + len(_get_immediate_subdirectories(dist_info_directory)) == 1 + ): + + dist_info_directory = os.path.join( + dist_info_directory, os.listdir(dist_info_directory)[0]) + continue + + assert len(dist_infos) == 1 + break + + # PEP 517 requires that the .dist-info directory be placed in the + # metadata_directory. To comply, we MUST copy the directory to the root + if dist_info_directory != metadata_directory: + shutil.move( + os.path.join(dist_info_directory, dist_infos[0]), + metadata_directory) + shutil.rmtree(dist_info_directory, ignore_errors=True) + + return dist_infos[0] + + def _build_with_temp_dir(self, setup_command, result_extension, + result_directory, config_settings): + config_settings = self._fix_config(config_settings) + result_directory = os.path.abspath(result_directory) + + # Build in a temporary directory, then copy to the target. + os.makedirs(result_directory, exist_ok=True) + with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir: + sys.argv = (sys.argv[:1] + setup_command + + ['--dist-dir', tmp_dist_dir] + + config_settings["--global-option"]) + with no_install_setup_requires(): + self.run_setup() + + result_basename = _file_with_extension( + tmp_dist_dir, result_extension) + result_path = os.path.join(result_directory, result_basename) + if os.path.exists(result_path): + # os.rename will fail overwriting on non-Unix. + os.remove(result_path) + os.rename(os.path.join(tmp_dist_dir, result_basename), result_path) + + return result_basename + + def build_wheel(self, wheel_directory, config_settings=None, + metadata_directory=None): + return self._build_with_temp_dir(['bdist_wheel'], '.whl', + wheel_directory, config_settings) + + def build_sdist(self, sdist_directory, config_settings=None): + return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], + '.tar.gz', sdist_directory, + config_settings) + + +class _BuildMetaLegacyBackend(_BuildMetaBackend): + """Compatibility backend for setuptools + + This is a version of setuptools.build_meta that endeavors + to maintain backwards + compatibility with pre-PEP 517 modes of invocation. It + exists as a temporary + bridge between the old packaging mechanism and the new + packaging mechanism, + and will eventually be removed. + """ + def run_setup(self, setup_script='setup.py'): + # In order to maintain compatibility with scripts assuming that + # the setup.py script is in a directory on the PYTHONPATH, inject + # '' into sys.path. (pypa/setuptools#1642) + sys_path = list(sys.path) # Save the original path + + script_dir = os.path.dirname(os.path.abspath(setup_script)) + if script_dir not in sys.path: + sys.path.insert(0, script_dir) + + # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to + # get the directory of the source code. They expect it to refer to the + # setup.py script. + sys_argv_0 = sys.argv[0] + sys.argv[0] = setup_script + + try: + super(_BuildMetaLegacyBackend, + self).run_setup(setup_script=setup_script) + finally: + # While PEP 517 frontends should be calling each hook in a fresh + # subprocess according to the standard (and thus it should not be + # strictly necessary to restore the old sys.path), we'll restore + # the original path so that the path manipulation does not persist + # within the hook after run_setup is called. + sys.path[:] = sys_path + sys.argv[0] = sys_argv_0 + + +# The primary backend +_BACKEND = _BuildMetaBackend() + +get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel +get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist +prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel +build_wheel = _BACKEND.build_wheel +build_sdist = _BACKEND.build_sdist + + +# The legacy backend +__legacy__ = _BuildMetaLegacyBackend() diff --git a/MLPY/Lib/site-packages/setuptools/cli-32.exe b/MLPY/Lib/site-packages/setuptools/cli-32.exe new file mode 100644 index 0000000000000000000000000000000000000000..b1487b7819e7286577a043c7726fbe0ca1543083 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/cli-32.exe differ diff --git a/MLPY/Lib/site-packages/setuptools/cli-64.exe b/MLPY/Lib/site-packages/setuptools/cli-64.exe new file mode 100644 index 0000000000000000000000000000000000000000..675e6bf3743f3d3011c238657e7128ee9960ef7f Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/cli-64.exe differ diff --git a/MLPY/Lib/site-packages/setuptools/cli.exe b/MLPY/Lib/site-packages/setuptools/cli.exe new file mode 100644 index 0000000000000000000000000000000000000000..b1487b7819e7286577a043c7726fbe0ca1543083 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/cli.exe differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__init__.py b/MLPY/Lib/site-packages/setuptools/command/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b966dcea57a2072f98b96dbba75ceb26bd26d2dd --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/__init__.py @@ -0,0 +1,8 @@ +from distutils.command.bdist import bdist +import sys + +if 'egg' not in bdist.format_commands: + bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") + bdist.format_commands.append('egg') + +del bdist, sys diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e62b4c2e7532be87c6cdb0d091de284c094bf6e2 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/alias.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/alias.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9b02da53ea7d33bc9495b5650ccc4e2b98c9650 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/alias.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b4ff8770671b330ad44102983203644fc158278 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..758a6ea854668686e44f3b01c40ba117e13dd912 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_clib.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_clib.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6128a05bafc62c477c707761bbae92b430976c76 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_clib.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_ext.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_ext.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2fcadf88da263d0fd2d38f5552cc6852c6b2ee2d Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_ext.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_py.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_py.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbbafbc06efa852bc7e622c0b7c3b7584a01afc2 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/build_py.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/develop.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/develop.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b6a1a21582580e710402a383ff8ee039eec3a6d Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/develop.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/dist_info.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/dist_info.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..807da68b8e8a9f1b14eb4be58216358da190c9f5 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/dist_info.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/easy_install.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/easy_install.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4dc506ed8ee7b422cab6354b81deb234b39c76af Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/easy_install.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/egg_info.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/egg_info.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b37ef4e4bad3935ef51d2e3b6108060d9f0b481 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/egg_info.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/install.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..667af5e6aef98f9b71d72fc50ca09056fd124ede Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33bdd8dd0f213821178e51dfe5c90c58b5a4f032 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_lib.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_lib.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea46ff27ae4a1f7ea0f75a073ada7db276189968 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_lib.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_scripts.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_scripts.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b506f38fcbbb64032d2545d65fcd41320257702 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/install_scripts.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/py36compat.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/py36compat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..314422605482bd5b5146a6b3857f22b62430818a Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/py36compat.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/register.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/register.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de8623f41a58c8a94f956bd8ff9bc688c2f11dba Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/register.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/rotate.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/rotate.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cdc071f2e7d0e1e1cb361fb144ca7dbb92c8df6d Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/rotate.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/saveopts.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/saveopts.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af61a5512ee151b17d38472a93d8817ed8c61f3e Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/saveopts.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/sdist.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/sdist.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64b7abeb6c9206ed98c9608e437acc69c362a795 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/sdist.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/setopt.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/setopt.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..763f56ab65eb2325938df4c82bb577a1584e6a73 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/setopt.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/test.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/test.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..902728877faceb62c2e53f5b013e49ae41b8347f Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/test.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/upload.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/upload.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e8a90aa22158e5fb25edbce049fcdca1b416a0f Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/upload.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/__pycache__/upload_docs.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/command/__pycache__/upload_docs.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59dcb55892195558e789b9c592a262c5f9f43aa0 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/command/__pycache__/upload_docs.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/command/alias.py b/MLPY/Lib/site-packages/setuptools/command/alias.py new file mode 100644 index 0000000000000000000000000000000000000000..452a9244ea6766d8cf94425fb583583ef740baee --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/alias.py @@ -0,0 +1,78 @@ +from distutils.errors import DistutilsOptionError + +from setuptools.command.setopt import edit_config, option_base, config_file + + +def shquote(arg): + """Quote an argument for later parsing by shlex.split()""" + for c in '"', "'", "\\", "#": + if c in arg: + return repr(arg) + if arg.split() != [arg]: + return repr(arg) + return arg + + +class alias(option_base): + """Define a shortcut that invokes one or more commands""" + + description = "define a shortcut to invoke one or more commands" + command_consumes_arguments = True + + user_options = [ + ('remove', 'r', 'remove (unset) the alias'), + ] + option_base.user_options + + boolean_options = option_base.boolean_options + ['remove'] + + def initialize_options(self): + option_base.initialize_options(self) + self.args = None + self.remove = None + + def finalize_options(self): + option_base.finalize_options(self) + if self.remove and len(self.args) != 1: + raise DistutilsOptionError( + "Must specify exactly one argument (the alias name) when " + "using --remove" + ) + + def run(self): + aliases = self.distribution.get_option_dict('aliases') + + if not self.args: + print("Command Aliases") + print("---------------") + for alias in aliases: + print("setup.py alias", format_alias(alias, aliases)) + return + + elif len(self.args) == 1: + alias, = self.args + if self.remove: + command = None + elif alias in aliases: + print("setup.py alias", format_alias(alias, aliases)) + return + else: + print("No alias definition found for %r" % alias) + return + else: + alias = self.args[0] + command = ' '.join(map(shquote, self.args[1:])) + + edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run) + + +def format_alias(name, aliases): + source, command = aliases[name] + if source == config_file('global'): + source = '--global-config ' + elif source == config_file('user'): + source = '--user-config ' + elif source == config_file('local'): + source = '' + else: + source = '--filename=%r' % source + return source + name + ' ' + command diff --git a/MLPY/Lib/site-packages/setuptools/command/bdist_egg.py b/MLPY/Lib/site-packages/setuptools/command/bdist_egg.py new file mode 100644 index 0000000000000000000000000000000000000000..e6b1609f7babcd4439376c0d826978f7a66dfa3f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/bdist_egg.py @@ -0,0 +1,456 @@ +"""setuptools.command.bdist_egg + +Build .egg distributions""" + +from distutils.dir_util import remove_tree, mkpath +from distutils import log +from types import CodeType +import sys +import os +import re +import textwrap +import marshal + +from pkg_resources import get_build_platform, Distribution, ensure_directory +from setuptools.extension import Library +from setuptools import Command + +from sysconfig import get_path, get_python_version + + +def _get_purelib(): + return get_path("purelib") + + +def strip_module(filename): + if '.' in filename: + filename = os.path.splitext(filename)[0] + if filename.endswith('module'): + filename = filename[:-6] + return filename + + +def sorted_walk(dir): + """Do os.walk in a reproducible way, + independent of indeterministic filesystem readdir order + """ + for base, dirs, files in os.walk(dir): + dirs.sort() + files.sort() + yield base, dirs, files + + +def write_stub(resource, pyfile): + _stub_template = textwrap.dedent(""" + def __bootstrap__(): + global __bootstrap__, __loader__, __file__ + import sys, pkg_resources, importlib.util + __file__ = pkg_resources.resource_filename(__name__, %r) + __loader__ = None; del __bootstrap__, __loader__ + spec = importlib.util.spec_from_file_location(__name__,__file__) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + __bootstrap__() + """).lstrip() + with open(pyfile, 'w') as f: + f.write(_stub_template % resource) + + +class bdist_egg(Command): + description = "create an \"egg\" distribution" + + user_options = [ + ('bdist-dir=', 'b', + "temporary directory for creating the distribution"), + ('plat-name=', 'p', "platform name to embed in generated filenames " + "(default: %s)" % get_build_platform()), + ('exclude-source-files', None, + "remove all .py files from the generated egg"), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ] + + boolean_options = [ + 'keep-temp', 'skip-build', 'exclude-source-files' + ] + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.keep_temp = 0 + self.dist_dir = None + self.skip_build = 0 + self.egg_output = None + self.exclude_source_files = None + + def finalize_options(self): + ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info") + self.egg_info = ei_cmd.egg_info + + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'egg') + + if self.plat_name is None: + self.plat_name = get_build_platform() + + self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) + + if self.egg_output is None: + + # Compute filename of the output egg + basename = Distribution( + None, None, ei_cmd.egg_name, ei_cmd.egg_version, + get_python_version(), + self.distribution.has_ext_modules() and self.plat_name + ).egg_name() + + self.egg_output = os.path.join(self.dist_dir, basename + '.egg') + + def do_install_data(self): + # Hack for packages that install data to install's --install-lib + self.get_finalized_command('install').install_lib = self.bdist_dir + + site_packages = os.path.normcase(os.path.realpath(_get_purelib())) + old, self.distribution.data_files = self.distribution.data_files, [] + + for item in old: + if isinstance(item, tuple) and len(item) == 2: + if os.path.isabs(item[0]): + realpath = os.path.realpath(item[0]) + normalized = os.path.normcase(realpath) + if normalized == site_packages or normalized.startswith( + site_packages + os.sep + ): + item = realpath[len(site_packages) + 1:], item[1] + # XXX else: raise ??? + self.distribution.data_files.append(item) + + try: + log.info("installing package data to %s", self.bdist_dir) + self.call_command('install_data', force=0, root=None) + finally: + self.distribution.data_files = old + + def get_outputs(self): + return [self.egg_output] + + def call_command(self, cmdname, **kw): + """Invoke reinitialized command `cmdname` with keyword args""" + for dirname in INSTALL_DIRECTORY_ATTRS: + kw.setdefault(dirname, self.bdist_dir) + kw.setdefault('skip_build', self.skip_build) + kw.setdefault('dry_run', self.dry_run) + cmd = self.reinitialize_command(cmdname, **kw) + self.run_command(cmdname) + return cmd + + def run(self): # noqa: C901 # is too complex (14) # FIXME + # Generate metadata first + self.run_command("egg_info") + # We run install_lib before install_data, because some data hacks + # pull their data path from the install_lib command. + log.info("installing library code to %s", self.bdist_dir) + instcmd = self.get_finalized_command('install') + old_root = instcmd.root + instcmd.root = None + if self.distribution.has_c_libraries() and not self.skip_build: + self.run_command('build_clib') + cmd = self.call_command('install_lib', warn_dir=0) + instcmd.root = old_root + + all_outputs, ext_outputs = self.get_ext_outputs() + self.stubs = [] + to_compile = [] + for (p, ext_name) in enumerate(ext_outputs): + filename, ext = os.path.splitext(ext_name) + pyfile = os.path.join(self.bdist_dir, strip_module(filename) + + '.py') + self.stubs.append(pyfile) + log.info("creating stub loader for %s", ext_name) + if not self.dry_run: + write_stub(os.path.basename(ext_name), pyfile) + to_compile.append(pyfile) + ext_outputs[p] = ext_name.replace(os.sep, '/') + + if to_compile: + cmd.byte_compile(to_compile) + if self.distribution.data_files: + self.do_install_data() + + # Make the EGG-INFO directory + archive_root = self.bdist_dir + egg_info = os.path.join(archive_root, 'EGG-INFO') + self.mkpath(egg_info) + if self.distribution.scripts: + script_dir = os.path.join(egg_info, 'scripts') + log.info("installing scripts to %s", script_dir) + self.call_command('install_scripts', install_dir=script_dir, + no_ep=1) + + self.copy_metadata_to(egg_info) + native_libs = os.path.join(egg_info, "native_libs.txt") + if all_outputs: + log.info("writing %s", native_libs) + if not self.dry_run: + ensure_directory(native_libs) + libs_file = open(native_libs, 'wt') + libs_file.write('\n'.join(all_outputs)) + libs_file.write('\n') + libs_file.close() + elif os.path.isfile(native_libs): + log.info("removing %s", native_libs) + if not self.dry_run: + os.unlink(native_libs) + + write_safety_flag( + os.path.join(archive_root, 'EGG-INFO'), self.zip_safe() + ) + + if os.path.exists(os.path.join(self.egg_info, 'depends.txt')): + log.warn( + "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n" + "Use the install_requires/extras_require setup() args instead." + ) + + if self.exclude_source_files: + self.zap_pyfiles() + + # Make the archive + make_zipfile(self.egg_output, archive_root, verbose=self.verbose, + dry_run=self.dry_run, mode=self.gen_header()) + if not self.keep_temp: + remove_tree(self.bdist_dir, dry_run=self.dry_run) + + # Add to 'Distribution.dist_files' so that the "upload" command works + getattr(self.distribution, 'dist_files', []).append( + ('bdist_egg', get_python_version(), self.egg_output)) + + def zap_pyfiles(self): + log.info("Removing .py files from temporary directory") + for base, dirs, files in walk_egg(self.bdist_dir): + for name in files: + path = os.path.join(base, name) + + if name.endswith('.py'): + log.debug("Deleting %s", path) + os.unlink(path) + + if base.endswith('__pycache__'): + path_old = path + + pattern = r'(?P.+)\.(?P[^.]+)\.pyc' + m = re.match(pattern, name) + path_new = os.path.join( + base, os.pardir, m.group('name') + '.pyc') + log.info( + "Renaming file from [%s] to [%s]" + % (path_old, path_new)) + try: + os.remove(path_new) + except OSError: + pass + os.rename(path_old, path_new) + + def zip_safe(self): + safe = getattr(self.distribution, 'zip_safe', None) + if safe is not None: + return safe + log.warn("zip_safe flag not set; analyzing archive contents...") + return analyze_egg(self.bdist_dir, self.stubs) + + def gen_header(self): + return 'w' + + def copy_metadata_to(self, target_dir): + "Copy metadata (egg info) to the target_dir" + # normalize the path (so that a forward-slash in egg_info will + # match using startswith below) + norm_egg_info = os.path.normpath(self.egg_info) + prefix = os.path.join(norm_egg_info, '') + for path in self.ei_cmd.filelist.files: + if path.startswith(prefix): + target = os.path.join(target_dir, path[len(prefix):]) + ensure_directory(target) + self.copy_file(path, target) + + def get_ext_outputs(self): + """Get a list of relative paths to C extensions in the output distro""" + + all_outputs = [] + ext_outputs = [] + + paths = {self.bdist_dir: ''} + for base, dirs, files in sorted_walk(self.bdist_dir): + for filename in files: + if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: + all_outputs.append(paths[base] + filename) + for filename in dirs: + paths[os.path.join(base, filename)] = (paths[base] + + filename + '/') + + if self.distribution.has_ext_modules(): + build_cmd = self.get_finalized_command('build_ext') + for ext in build_cmd.extensions: + if isinstance(ext, Library): + continue + fullname = build_cmd.get_ext_fullname(ext.name) + filename = build_cmd.get_ext_filename(fullname) + if not os.path.basename(filename).startswith('dl-'): + if os.path.exists(os.path.join(self.bdist_dir, filename)): + ext_outputs.append(filename) + + return all_outputs, ext_outputs + + +NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split()) + + +def walk_egg(egg_dir): + """Walk an unpacked egg's contents, skipping the metadata directory""" + walker = sorted_walk(egg_dir) + base, dirs, files = next(walker) + if 'EGG-INFO' in dirs: + dirs.remove('EGG-INFO') + yield base, dirs, files + for bdf in walker: + yield bdf + + +def analyze_egg(egg_dir, stubs): + # check for existing flag in EGG-INFO + for flag, fn in safety_flags.items(): + if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)): + return flag + if not can_scan(): + return False + safe = True + for base, dirs, files in walk_egg(egg_dir): + for name in files: + if name.endswith('.py') or name.endswith('.pyw'): + continue + elif name.endswith('.pyc') or name.endswith('.pyo'): + # always scan, even if we already know we're not safe + safe = scan_module(egg_dir, base, name, stubs) and safe + return safe + + +def write_safety_flag(egg_dir, safe): + # Write or remove zip safety flag file(s) + for flag, fn in safety_flags.items(): + fn = os.path.join(egg_dir, fn) + if os.path.exists(fn): + if safe is None or bool(safe) != flag: + os.unlink(fn) + elif safe is not None and bool(safe) == flag: + f = open(fn, 'wt') + f.write('\n') + f.close() + + +safety_flags = { + True: 'zip-safe', + False: 'not-zip-safe', +} + + +def scan_module(egg_dir, base, name, stubs): + """Check whether module possibly uses unsafe-for-zipfile stuff""" + + filename = os.path.join(base, name) + if filename[:-1] in stubs: + return True # Extension module + pkg = base[len(egg_dir) + 1:].replace(os.sep, '.') + module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] + if sys.version_info < (3, 7): + skip = 12 # skip magic & date & file size + else: + skip = 16 # skip magic & reserved? & date & file size + f = open(filename, 'rb') + f.read(skip) + code = marshal.load(f) + f.close() + safe = True + symbols = dict.fromkeys(iter_symbols(code)) + for bad in ['__file__', '__path__']: + if bad in symbols: + log.warn("%s: module references %s", module, bad) + safe = False + if 'inspect' in symbols: + for bad in [ + 'getsource', 'getabsfile', 'getsourcefile', 'getfile' + 'getsourcelines', 'findsource', 'getcomments', 'getframeinfo', + 'getinnerframes', 'getouterframes', 'stack', 'trace' + ]: + if bad in symbols: + log.warn("%s: module MAY be using inspect.%s", module, bad) + safe = False + return safe + + +def iter_symbols(code): + """Yield names and strings used by `code` and its nested code objects""" + for name in code.co_names: + yield name + for const in code.co_consts: + if isinstance(const, str): + yield const + elif isinstance(const, CodeType): + for name in iter_symbols(const): + yield name + + +def can_scan(): + if not sys.platform.startswith('java') and sys.platform != 'cli': + # CPython, PyPy, etc. + return True + log.warn("Unable to analyze compiled code on this platform.") + log.warn("Please ask the author to include a 'zip_safe'" + " setting (either True or False) in the package's setup.py") + + +# Attribute names of options for commands that might need to be convinced to +# install to the egg build directory + +INSTALL_DIRECTORY_ATTRS = [ + 'install_lib', 'install_dir', 'install_data', 'install_base' +] + + +def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, + mode='w'): + """Create a zip file from all the files under 'base_dir'. The output + zip file will be named 'base_dir' + ".zip". Uses either the "zipfile" + Python module (if available) or the InfoZIP "zip" utility (if installed + and found on the default search path). If neither tool is available, + raises DistutilsExecError. Returns the name of the output zip file. + """ + import zipfile + + mkpath(os.path.dirname(zip_filename), dry_run=dry_run) + log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir) + + def visit(z, dirname, names): + for name in names: + path = os.path.normpath(os.path.join(dirname, name)) + if os.path.isfile(path): + p = path[len(base_dir) + 1:] + if not dry_run: + z.write(path, p) + log.debug("adding '%s'", p) + + compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED + if not dry_run: + z = zipfile.ZipFile(zip_filename, mode, compression=compression) + for dirname, dirs, files in sorted_walk(base_dir): + visit(z, dirname, files) + z.close() + else: + for dirname, dirs, files in sorted_walk(base_dir): + visit(None, dirname, files) + return zip_filename diff --git a/MLPY/Lib/site-packages/setuptools/command/bdist_rpm.py b/MLPY/Lib/site-packages/setuptools/command/bdist_rpm.py new file mode 100644 index 0000000000000000000000000000000000000000..98bf5dea8468bf1728f18d97d1b9a43be33fdf20 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/bdist_rpm.py @@ -0,0 +1,40 @@ +import distutils.command.bdist_rpm as orig +import warnings + +from setuptools import SetuptoolsDeprecationWarning + + +class bdist_rpm(orig.bdist_rpm): + """ + Override the default bdist_rpm behavior to do the following: + + 1. Run egg_info to ensure the name and version are properly calculated. + 2. Always run 'install' using --single-version-externally-managed to + disable eggs in RPM distributions. + """ + + def run(self): + warnings.warn( + "bdist_rpm is deprecated and will be removed in a future " + "version. Use bdist_wheel (wheel packages) instead.", + SetuptoolsDeprecationWarning, + ) + + # ensure distro name is up-to-date + self.run_command('egg_info') + + orig.bdist_rpm.run(self) + + def _make_spec_file(self): + spec = orig.bdist_rpm._make_spec_file(self) + spec = [ + line.replace( + "setup.py install ", + "setup.py install --single-version-externally-managed " + ).replace( + "%setup", + "%setup -n %{name}-%{unmangled_version}" + ) + for line in spec + ] + return spec diff --git a/MLPY/Lib/site-packages/setuptools/command/build_clib.py b/MLPY/Lib/site-packages/setuptools/command/build_clib.py new file mode 100644 index 0000000000000000000000000000000000000000..67ce2444ea69a0bbdfab0bda8c2aa14951187096 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/build_clib.py @@ -0,0 +1,101 @@ +import distutils.command.build_clib as orig +from distutils.errors import DistutilsSetupError +from distutils import log +from setuptools.dep_util import newer_pairwise_group + + +class build_clib(orig.build_clib): + """ + Override the default build_clib behaviour to do the following: + + 1. Implement a rudimentary timestamp-based dependency system + so 'compile()' doesn't run every time. + 2. Add more keys to the 'build_info' dictionary: + * obj_deps - specify dependencies for each object compiled. + this should be a dictionary mapping a key + with the source filename to a list of + dependencies. Use an empty string for global + dependencies. + * cflags - specify a list of additional flags to pass to + the compiler. + """ + + def build_libraries(self, libraries): + for (lib_name, build_info) in libraries: + sources = build_info.get('sources') + if sources is None or not isinstance(sources, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % lib_name) + sources = list(sources) + + log.info("building '%s' library", lib_name) + + # Make sure everything is the correct type. + # obj_deps should be a dictionary of keys as sources + # and a list/tuple of files that are its dependencies. + obj_deps = build_info.get('obj_deps', dict()) + if not isinstance(obj_deps, dict): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'obj_deps' must be a dictionary of " + "type 'source: list'" % lib_name) + dependencies = [] + + # Get the global dependencies that are specified by the '' key. + # These will go into every source's dependency list. + global_deps = obj_deps.get('', list()) + if not isinstance(global_deps, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'obj_deps' must be a dictionary of " + "type 'source: list'" % lib_name) + + # Build the list to be used by newer_pairwise_group + # each source will be auto-added to its dependencies. + for source in sources: + src_deps = [source] + src_deps.extend(global_deps) + extra_deps = obj_deps.get(source, list()) + if not isinstance(extra_deps, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'obj_deps' must be a dictionary of " + "type 'source: list'" % lib_name) + src_deps.extend(extra_deps) + dependencies.append(src_deps) + + expected_objects = self.compiler.object_filenames( + sources, + output_dir=self.build_temp, + ) + + if ( + newer_pairwise_group(dependencies, expected_objects) + != ([], []) + ): + # First, compile the source code to object files in the library + # directory. (This should probably change to putting object + # files in a temporary build directory.) + macros = build_info.get('macros') + include_dirs = build_info.get('include_dirs') + cflags = build_info.get('cflags') + self.compiler.compile( + sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + extra_postargs=cflags, + debug=self.debug + ) + + # Now "link" the object files together into a static library. + # (On Unix at least, this isn't really linking -- it just + # builds an archive. Whatever.) + self.compiler.create_static_lib( + expected_objects, + lib_name, + output_dir=self.build_clib, + debug=self.debug + ) diff --git a/MLPY/Lib/site-packages/setuptools/command/build_ext.py b/MLPY/Lib/site-packages/setuptools/command/build_ext.py new file mode 100644 index 0000000000000000000000000000000000000000..c59eff8bbf7bf9f3ec79e9f2ffbc426e2233df5c --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/build_ext.py @@ -0,0 +1,328 @@ +import os +import sys +import itertools +from importlib.machinery import EXTENSION_SUFFIXES +from distutils.command.build_ext import build_ext as _du_build_ext +from distutils.file_util import copy_file +from distutils.ccompiler import new_compiler +from distutils.sysconfig import customize_compiler, get_config_var +from distutils.errors import DistutilsError +from distutils import log + +from setuptools.extension import Library + +try: + # Attempt to use Cython for building extensions, if available + from Cython.Distutils.build_ext import build_ext as _build_ext + # Additionally, assert that the compiler module will load + # also. Ref #1229. + __import__('Cython.Compiler.Main') +except ImportError: + _build_ext = _du_build_ext + +# make sure _config_vars is initialized +get_config_var("LDSHARED") +from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa + + +def _customize_compiler_for_shlib(compiler): + if sys.platform == "darwin": + # building .dylib requires additional compiler flags on OSX; here we + # temporarily substitute the pyconfig.h variables so that distutils' + # 'customize_compiler' uses them before we build the shared libraries. + tmp = _CONFIG_VARS.copy() + try: + # XXX Help! I don't have any idea whether these are right... + _CONFIG_VARS['LDSHARED'] = ( + "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup") + _CONFIG_VARS['CCSHARED'] = " -dynamiclib" + _CONFIG_VARS['SO'] = ".dylib" + customize_compiler(compiler) + finally: + _CONFIG_VARS.clear() + _CONFIG_VARS.update(tmp) + else: + customize_compiler(compiler) + + +have_rtld = False +use_stubs = False +libtype = 'shared' + +if sys.platform == "darwin": + use_stubs = True +elif os.name != 'nt': + try: + import dl + use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') + except ImportError: + pass + + +def if_dl(s): + return s if have_rtld else '' + + +def get_abi3_suffix(): + """Return the file extension for an abi3-compliant Extension()""" + for suffix in EXTENSION_SUFFIXES: + if '.abi3' in suffix: # Unix + return suffix + elif suffix == '.pyd': # Windows + return suffix + + +class build_ext(_build_ext): + def run(self): + """Build extensions in build directory, then copy if --inplace""" + old_inplace, self.inplace = self.inplace, 0 + _build_ext.run(self) + self.inplace = old_inplace + if old_inplace: + self.copy_extensions_to_source() + + def copy_extensions_to_source(self): + build_py = self.get_finalized_command('build_py') + for ext in self.extensions: + fullname = self.get_ext_fullname(ext.name) + filename = self.get_ext_filename(fullname) + modpath = fullname.split('.') + package = '.'.join(modpath[:-1]) + package_dir = build_py.get_package_dir(package) + dest_filename = os.path.join(package_dir, + os.path.basename(filename)) + src_filename = os.path.join(self.build_lib, filename) + + # Always copy, even if source is older than destination, to ensure + # that the right extensions for the current Python/platform are + # used. + copy_file( + src_filename, dest_filename, verbose=self.verbose, + dry_run=self.dry_run + ) + if ext._needs_stub: + self.write_stub(package_dir or os.curdir, ext, True) + + def get_ext_filename(self, fullname): + so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX') + if so_ext: + filename = os.path.join(*fullname.split('.')) + so_ext + else: + filename = _build_ext.get_ext_filename(self, fullname) + so_ext = get_config_var('EXT_SUFFIX') + + if fullname in self.ext_map: + ext = self.ext_map[fullname] + use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix() + if use_abi3: + filename = filename[:-len(so_ext)] + so_ext = get_abi3_suffix() + filename = filename + so_ext + if isinstance(ext, Library): + fn, ext = os.path.splitext(filename) + return self.shlib_compiler.library_filename(fn, libtype) + elif use_stubs and ext._links_to_dynamic: + d, fn = os.path.split(filename) + return os.path.join(d, 'dl-' + fn) + return filename + + def initialize_options(self): + _build_ext.initialize_options(self) + self.shlib_compiler = None + self.shlibs = [] + self.ext_map = {} + + def finalize_options(self): + _build_ext.finalize_options(self) + self.extensions = self.extensions or [] + self.check_extensions_list(self.extensions) + self.shlibs = [ext for ext in self.extensions + if isinstance(ext, Library)] + if self.shlibs: + self.setup_shlib_compiler() + for ext in self.extensions: + ext._full_name = self.get_ext_fullname(ext.name) + for ext in self.extensions: + fullname = ext._full_name + self.ext_map[fullname] = ext + + # distutils 3.1 will also ask for module names + # XXX what to do with conflicts? + self.ext_map[fullname.split('.')[-1]] = ext + + ltd = self.shlibs and self.links_to_dynamic(ext) or False + ns = ltd and use_stubs and not isinstance(ext, Library) + ext._links_to_dynamic = ltd + ext._needs_stub = ns + filename = ext._file_name = self.get_ext_filename(fullname) + libdir = os.path.dirname(os.path.join(self.build_lib, filename)) + if ltd and libdir not in ext.library_dirs: + ext.library_dirs.append(libdir) + if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs: + ext.runtime_library_dirs.append(os.curdir) + + def setup_shlib_compiler(self): + compiler = self.shlib_compiler = new_compiler( + compiler=self.compiler, dry_run=self.dry_run, force=self.force + ) + _customize_compiler_for_shlib(compiler) + + if self.include_dirs is not None: + compiler.set_include_dirs(self.include_dirs) + if self.define is not None: + # 'define' option is a list of (name,value) tuples + for (name, value) in self.define: + compiler.define_macro(name, value) + if self.undef is not None: + for macro in self.undef: + compiler.undefine_macro(macro) + if self.libraries is not None: + compiler.set_libraries(self.libraries) + if self.library_dirs is not None: + compiler.set_library_dirs(self.library_dirs) + if self.rpath is not None: + compiler.set_runtime_library_dirs(self.rpath) + if self.link_objects is not None: + compiler.set_link_objects(self.link_objects) + + # hack so distutils' build_extension() builds a library instead + compiler.link_shared_object = link_shared_object.__get__(compiler) + + def get_export_symbols(self, ext): + if isinstance(ext, Library): + return ext.export_symbols + return _build_ext.get_export_symbols(self, ext) + + def build_extension(self, ext): + ext._convert_pyx_sources_to_lang() + _compiler = self.compiler + try: + if isinstance(ext, Library): + self.compiler = self.shlib_compiler + _build_ext.build_extension(self, ext) + if ext._needs_stub: + cmd = self.get_finalized_command('build_py').build_lib + self.write_stub(cmd, ext) + finally: + self.compiler = _compiler + + def links_to_dynamic(self, ext): + """Return true if 'ext' links to a dynamic lib in the same package""" + # XXX this should check to ensure the lib is actually being built + # XXX as dynamic, and not just using a locally-found version or a + # XXX static-compiled version + libnames = dict.fromkeys([lib._full_name for lib in self.shlibs]) + pkg = '.'.join(ext._full_name.split('.')[:-1] + ['']) + return any(pkg + libname in libnames for libname in ext.libraries) + + def get_outputs(self): + return _build_ext.get_outputs(self) + self.__get_stubs_outputs() + + def __get_stubs_outputs(self): + # assemble the base name for each extension that needs a stub + ns_ext_bases = ( + os.path.join(self.build_lib, *ext._full_name.split('.')) + for ext in self.extensions + if ext._needs_stub + ) + # pair each base with the extension + pairs = itertools.product(ns_ext_bases, self.__get_output_extensions()) + return list(base + fnext for base, fnext in pairs) + + def __get_output_extensions(self): + yield '.py' + yield '.pyc' + if self.get_finalized_command('build_py').optimize: + yield '.pyo' + + def write_stub(self, output_dir, ext, compile=False): + log.info("writing stub loader for %s to %s", ext._full_name, + output_dir) + stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) + + '.py') + if compile and os.path.exists(stub_file): + raise DistutilsError(stub_file + " already exists! Please delete.") + if not self.dry_run: + f = open(stub_file, 'w') + f.write( + '\n'.join([ + "def __bootstrap__():", + " global __bootstrap__, __file__, __loader__", + " import sys, os, pkg_resources, importlib.util" + + if_dl(", dl"), + " __file__ = pkg_resources.resource_filename" + "(__name__,%r)" + % os.path.basename(ext._file_name), + " del __bootstrap__", + " if '__loader__' in globals():", + " del __loader__", + if_dl(" old_flags = sys.getdlopenflags()"), + " old_dir = os.getcwd()", + " try:", + " os.chdir(os.path.dirname(__file__))", + if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), + " spec = importlib.util.spec_from_file_location(", + " __name__, __file__)", + " mod = importlib.util.module_from_spec(spec)", + " spec.loader.exec_module(mod)", + " finally:", + if_dl(" sys.setdlopenflags(old_flags)"), + " os.chdir(old_dir)", + "__bootstrap__()", + "" # terminal \n + ]) + ) + f.close() + if compile: + from distutils.util import byte_compile + + byte_compile([stub_file], optimize=0, + force=True, dry_run=self.dry_run) + optimize = self.get_finalized_command('install_lib').optimize + if optimize > 0: + byte_compile([stub_file], optimize=optimize, + force=True, dry_run=self.dry_run) + if os.path.exists(stub_file) and not self.dry_run: + os.unlink(stub_file) + + +if use_stubs or os.name == 'nt': + # Build shared libraries + # + def link_shared_object( + self, objects, output_libname, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, export_symbols=None, + debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, + target_lang=None): + self.link( + self.SHARED_LIBRARY, objects, output_libname, + output_dir, libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, extra_preargs, extra_postargs, + build_temp, target_lang + ) +else: + # Build static libraries everywhere else + libtype = 'static' + + def link_shared_object( + self, objects, output_libname, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, export_symbols=None, + debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, + target_lang=None): + # XXX we need to either disallow these attrs on Library instances, + # or warn/abort here if set, or something... + # libraries=None, library_dirs=None, runtime_library_dirs=None, + # export_symbols=None, extra_preargs=None, extra_postargs=None, + # build_temp=None + + assert output_dir is None # distutils build_ext doesn't pass this + output_dir, filename = os.path.split(output_libname) + basename, ext = os.path.splitext(filename) + if self.library_filename("x").startswith('lib'): + # strip 'lib' prefix; this is kludgy if some platform uses + # a different prefix + basename = basename[3:] + + self.create_static_lib( + objects, basename, output_dir, debug, target_lang + ) diff --git a/MLPY/Lib/site-packages/setuptools/command/build_py.py b/MLPY/Lib/site-packages/setuptools/command/build_py.py new file mode 100644 index 0000000000000000000000000000000000000000..6a61543342ce1dc9f0aa4f6176754a433f15bf74 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/build_py.py @@ -0,0 +1,232 @@ +from glob import glob +from distutils.util import convert_path +import distutils.command.build_py as orig +import os +import fnmatch +import textwrap +import io +import distutils.errors +import itertools +import stat +from setuptools.extern.more_itertools import unique_everseen + + +def make_writable(target): + os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE) + + +class build_py(orig.build_py): + """Enhanced 'build_py' command that includes data files with packages + + The data files are specified via a 'package_data' argument to 'setup()'. + See 'setuptools.dist.Distribution' for more details. + + Also, this version of the 'build_py' command allows you to specify both + 'py_modules' and 'packages' in the same setup operation. + """ + + def finalize_options(self): + orig.build_py.finalize_options(self) + self.package_data = self.distribution.package_data + self.exclude_package_data = self.distribution.exclude_package_data or {} + if 'data_files' in self.__dict__: + del self.__dict__['data_files'] + self.__updated_files = [] + + def run(self): + """Build modules, packages, and copy data files to build directory""" + if not self.py_modules and not self.packages: + return + + if self.py_modules: + self.build_modules() + + if self.packages: + self.build_packages() + self.build_package_data() + + # Only compile actual .py files, using our base class' idea of what our + # output files are. + self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0)) + + def __getattr__(self, attr): + "lazily compute data files" + if attr == 'data_files': + self.data_files = self._get_data_files() + return self.data_files + return orig.build_py.__getattr__(self, attr) + + def build_module(self, module, module_file, package): + outfile, copied = orig.build_py.build_module(self, module, module_file, package) + if copied: + self.__updated_files.append(outfile) + return outfile, copied + + def _get_data_files(self): + """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" + self.analyze_manifest() + return list(map(self._get_pkg_data_files, self.packages or ())) + + def _get_pkg_data_files(self, package): + # Locate package source directory + src_dir = self.get_package_dir(package) + + # Compute package build directory + build_dir = os.path.join(*([self.build_lib] + package.split('.'))) + + # Strip directory from globbed filenames + filenames = [ + os.path.relpath(file, src_dir) + for file in self.find_data_files(package, src_dir) + ] + return package, src_dir, build_dir, filenames + + def find_data_files(self, package, src_dir): + """Return filenames for package's data files in 'src_dir'""" + patterns = self._get_platform_patterns( + self.package_data, + package, + src_dir, + ) + globs_expanded = map(glob, patterns) + # flatten the expanded globs into an iterable of matches + globs_matches = itertools.chain.from_iterable(globs_expanded) + glob_files = filter(os.path.isfile, globs_matches) + files = itertools.chain( + self.manifest_files.get(package, []), + glob_files, + ) + return self.exclude_data_files(package, src_dir, files) + + def build_package_data(self): + """Copy data files into build directory""" + for package, src_dir, build_dir, filenames in self.data_files: + for filename in filenames: + target = os.path.join(build_dir, filename) + self.mkpath(os.path.dirname(target)) + srcfile = os.path.join(src_dir, filename) + outf, copied = self.copy_file(srcfile, target) + make_writable(target) + srcfile = os.path.abspath(srcfile) + + def analyze_manifest(self): + self.manifest_files = mf = {} + if not self.distribution.include_package_data: + return + src_dirs = {} + for package in self.packages or (): + # Locate package source directory + src_dirs[assert_relative(self.get_package_dir(package))] = package + + self.run_command('egg_info') + ei_cmd = self.get_finalized_command('egg_info') + for path in ei_cmd.filelist.files: + d, f = os.path.split(assert_relative(path)) + prev = None + oldf = f + while d and d != prev and d not in src_dirs: + prev = d + d, df = os.path.split(d) + f = os.path.join(df, f) + if d in src_dirs: + if path.endswith('.py') and f == oldf: + continue # it's a module, not data + mf.setdefault(src_dirs[d], []).append(path) + + def get_data_files(self): + pass # Lazily compute data files in _get_data_files() function. + + def check_package(self, package, package_dir): + """Check namespace packages' __init__ for declare_namespace""" + try: + return self.packages_checked[package] + except KeyError: + pass + + init_py = orig.build_py.check_package(self, package, package_dir) + self.packages_checked[package] = init_py + + if not init_py or not self.distribution.namespace_packages: + return init_py + + for pkg in self.distribution.namespace_packages: + if pkg == package or pkg.startswith(package + '.'): + break + else: + return init_py + + with io.open(init_py, 'rb') as f: + contents = f.read() + if b'declare_namespace' not in contents: + raise distutils.errors.DistutilsError( + "Namespace package problem: %s is a namespace package, but " + "its\n__init__.py does not call declare_namespace()! Please " + 'fix it.\n(See the setuptools manual under ' + '"Namespace Packages" for details.)\n"' % (package,) + ) + return init_py + + def initialize_options(self): + self.packages_checked = {} + orig.build_py.initialize_options(self) + + def get_package_dir(self, package): + res = orig.build_py.get_package_dir(self, package) + if self.distribution.src_root is not None: + return os.path.join(self.distribution.src_root, res) + return res + + def exclude_data_files(self, package, src_dir, files): + """Filter filenames for package's data files in 'src_dir'""" + files = list(files) + patterns = self._get_platform_patterns( + self.exclude_package_data, + package, + src_dir, + ) + match_groups = (fnmatch.filter(files, pattern) for pattern in patterns) + # flatten the groups of matches into an iterable of matches + matches = itertools.chain.from_iterable(match_groups) + bad = set(matches) + keepers = (fn for fn in files if fn not in bad) + # ditch dupes + return list(unique_everseen(keepers)) + + @staticmethod + def _get_platform_patterns(spec, package, src_dir): + """ + yield platform-specific path patterns (suitable for glob + or fn_match) from a glob-based spec (such as + self.package_data or self.exclude_package_data) + matching package in src_dir. + """ + raw_patterns = itertools.chain( + spec.get('', []), + spec.get(package, []), + ) + return ( + # Each pattern has to be converted to a platform-specific path + os.path.join(src_dir, convert_path(pattern)) + for pattern in raw_patterns + ) + + +def assert_relative(path): + if not os.path.isabs(path): + return path + from distutils.errors import DistutilsSetupError + + msg = ( + textwrap.dedent( + """ + Error: setup script specifies an absolute path: + + %s + + setup() arguments must *always* be /-separated paths relative to the + setup.py directory, *never* absolute paths. + """ + ).lstrip() + % path + ) + raise DistutilsSetupError(msg) diff --git a/MLPY/Lib/site-packages/setuptools/command/develop.py b/MLPY/Lib/site-packages/setuptools/command/develop.py new file mode 100644 index 0000000000000000000000000000000000000000..24fb0a7c81bc665844d5d307eee2d720079c039f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/develop.py @@ -0,0 +1,193 @@ +from distutils.util import convert_path +from distutils import log +from distutils.errors import DistutilsError, DistutilsOptionError +import os +import glob +import io + +import pkg_resources +from setuptools.command.easy_install import easy_install +from setuptools import namespaces +import setuptools + + +class develop(namespaces.DevelopInstaller, easy_install): + """Set up package for development""" + + description = "install package in 'development mode'" + + user_options = easy_install.user_options + [ + ("uninstall", "u", "Uninstall this source package"), + ("egg-path=", None, "Set the path to be used in the .egg-link file"), + ] + + boolean_options = easy_install.boolean_options + ['uninstall'] + + command_consumes_arguments = False # override base + + def run(self): + if self.uninstall: + self.multi_version = True + self.uninstall_link() + self.uninstall_namespaces() + else: + self.install_for_development() + self.warn_deprecated_options() + + def initialize_options(self): + self.uninstall = None + self.egg_path = None + easy_install.initialize_options(self) + self.setup_path = None + self.always_copy_from = '.' # always copy eggs installed in curdir + + def finalize_options(self): + ei = self.get_finalized_command("egg_info") + if ei.broken_egg_info: + template = "Please rename %r to %r before using 'develop'" + args = ei.egg_info, ei.broken_egg_info + raise DistutilsError(template % args) + self.args = [ei.egg_name] + + easy_install.finalize_options(self) + self.expand_basedirs() + self.expand_dirs() + # pick up setup-dir .egg files only: no .egg-info + self.package_index.scan(glob.glob('*.egg')) + + egg_link_fn = ei.egg_name + '.egg-link' + self.egg_link = os.path.join(self.install_dir, egg_link_fn) + self.egg_base = ei.egg_base + if self.egg_path is None: + self.egg_path = os.path.abspath(ei.egg_base) + + target = pkg_resources.normalize_path(self.egg_base) + egg_path = pkg_resources.normalize_path( + os.path.join(self.install_dir, self.egg_path) + ) + if egg_path != target: + raise DistutilsOptionError( + "--egg-path must be a relative path from the install" + " directory to " + target + ) + + # Make a distribution for the package's source + self.dist = pkg_resources.Distribution( + target, + pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)), + project_name=ei.egg_name, + ) + + self.setup_path = self._resolve_setup_path( + self.egg_base, + self.install_dir, + self.egg_path, + ) + + @staticmethod + def _resolve_setup_path(egg_base, install_dir, egg_path): + """ + Generate a path from egg_base back to '.' where the + setup script resides and ensure that path points to the + setup path from $install_dir/$egg_path. + """ + path_to_setup = egg_base.replace(os.sep, '/').rstrip('/') + if path_to_setup != os.curdir: + path_to_setup = '../' * (path_to_setup.count('/') + 1) + resolved = pkg_resources.normalize_path( + os.path.join(install_dir, egg_path, path_to_setup) + ) + if resolved != pkg_resources.normalize_path(os.curdir): + raise DistutilsOptionError( + "Can't get a consistent path to setup script from" + " installation directory", + resolved, + pkg_resources.normalize_path(os.curdir), + ) + return path_to_setup + + def install_for_development(self): + self.run_command('egg_info') + + # Build extensions in-place + self.reinitialize_command('build_ext', inplace=1) + self.run_command('build_ext') + + if setuptools.bootstrap_install_from: + self.easy_install(setuptools.bootstrap_install_from) + setuptools.bootstrap_install_from = None + + self.install_namespaces() + + # create an .egg-link in the installation dir, pointing to our egg + log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) + if not self.dry_run: + with open(self.egg_link, "w") as f: + f.write(self.egg_path + "\n" + self.setup_path) + # postprocess the installed distro, fixing up .pth, installing scripts, + # and handling requirements + self.process_distribution(None, self.dist, not self.no_deps) + + def uninstall_link(self): + if os.path.exists(self.egg_link): + log.info("Removing %s (link to %s)", self.egg_link, self.egg_base) + egg_link_file = open(self.egg_link) + contents = [line.rstrip() for line in egg_link_file] + egg_link_file.close() + if contents not in ([self.egg_path], [self.egg_path, self.setup_path]): + log.warn("Link points to %s: uninstall aborted", contents) + return + if not self.dry_run: + os.unlink(self.egg_link) + if not self.dry_run: + self.update_pth(self.dist) # remove any .pth link to us + if self.distribution.scripts: + # XXX should also check for entry point scripts! + log.warn("Note: you must uninstall or replace scripts manually!") + + def install_egg_scripts(self, dist): + if dist is not self.dist: + # Installing a dependency, so fall back to normal behavior + return easy_install.install_egg_scripts(self, dist) + + # create wrapper scripts in the script dir, pointing to dist.scripts + + # new-style... + self.install_wrapper_scripts(dist) + + # ...and old-style + for script_name in self.distribution.scripts or []: + script_path = os.path.abspath(convert_path(script_name)) + script_name = os.path.basename(script_path) + with io.open(script_path) as strm: + script_text = strm.read() + self.install_script(dist, script_name, script_text, script_path) + + def install_wrapper_scripts(self, dist): + dist = VersionlessRequirement(dist) + return easy_install.install_wrapper_scripts(self, dist) + + +class VersionlessRequirement: + """ + Adapt a pkg_resources.Distribution to simply return the project + name as the 'requirement' so that scripts will work across + multiple versions. + + >>> from pkg_resources import Distribution + >>> dist = Distribution(project_name='foo', version='1.0') + >>> str(dist.as_requirement()) + 'foo==1.0' + >>> adapted_dist = VersionlessRequirement(dist) + >>> str(adapted_dist.as_requirement()) + 'foo' + """ + + def __init__(self, dist): + self.__dist = dist + + def __getattr__(self, name): + return getattr(self.__dist, name) + + def as_requirement(self): + return self.project_name diff --git a/MLPY/Lib/site-packages/setuptools/command/dist_info.py b/MLPY/Lib/site-packages/setuptools/command/dist_info.py new file mode 100644 index 0000000000000000000000000000000000000000..c45258fa03a3ddd6a73db4514365f8741d16ca86 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/dist_info.py @@ -0,0 +1,36 @@ +""" +Create a dist_info directory +As defined in the wheel specification +""" + +import os + +from distutils.core import Command +from distutils import log + + +class dist_info(Command): + + description = 'create a .dist-info directory' + + user_options = [ + ('egg-base=', 'e', "directory containing .egg-info directories" + " (default: top of the source tree)"), + ] + + def initialize_options(self): + self.egg_base = None + + def finalize_options(self): + pass + + def run(self): + egg_info = self.get_finalized_command('egg_info') + egg_info.egg_base = self.egg_base + egg_info.finalize_options() + egg_info.run() + dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info' + log.info("creating '{}'".format(os.path.abspath(dist_info_dir))) + + bdist_wheel = self.get_finalized_command('bdist_wheel') + bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir) diff --git a/MLPY/Lib/site-packages/setuptools/command/easy_install.py b/MLPY/Lib/site-packages/setuptools/command/easy_install.py new file mode 100644 index 0000000000000000000000000000000000000000..5e0f97cfea5484ea1ea139e0f4b8e8553b80b00d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/easy_install.py @@ -0,0 +1,2290 @@ +""" +Easy Install +------------ + +A tool for doing automatic download/extract/build of distutils-based Python +packages. For detailed documentation, see the accompanying EasyInstall.txt +file, or visit the `EasyInstall home page`__. + +__ https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html + +""" + +from glob import glob +from distutils.util import get_platform +from distutils.util import convert_path, subst_vars +from distutils.errors import ( + DistutilsArgError, DistutilsOptionError, + DistutilsError, DistutilsPlatformError, +) +from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS +from distutils import log, dir_util +from distutils.command.build_scripts import first_line_re +from distutils.spawn import find_executable +import sys +import os +import zipimport +import shutil +import tempfile +import zipfile +import re +import stat +import random +import textwrap +import warnings +import site +import struct +import contextlib +import subprocess +import shlex +import io +import configparser + + +from sysconfig import get_config_vars, get_path + +from setuptools import SetuptoolsDeprecationWarning + +from setuptools import Command +from setuptools.sandbox import run_setup +from setuptools.command import setopt +from setuptools.archive_util import unpack_archive +from setuptools.package_index import ( + PackageIndex, parse_requirement_arg, URL_SCHEME, +) +from setuptools.command import bdist_egg, egg_info +from setuptools.wheel import Wheel +from pkg_resources import ( + yield_lines, normalize_path, resource_string, ensure_directory, + get_distribution, find_distributions, Environment, Requirement, + Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, + VersionConflict, DEVELOP_DIST, +) +import pkg_resources + +# Turn on PEP440Warnings +warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) + +__all__ = [ + 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', + 'get_exe_prefixes', +] + + +def is_64bit(): + return struct.calcsize("P") == 8 + + +def samefile(p1, p2): + """ + Determine if two paths reference the same file. + + Augments os.path.samefile to work on Windows and + suppresses errors if the path doesn't exist. + """ + both_exist = os.path.exists(p1) and os.path.exists(p2) + use_samefile = hasattr(os.path, 'samefile') and both_exist + if use_samefile: + return os.path.samefile(p1, p2) + norm_p1 = os.path.normpath(os.path.normcase(p1)) + norm_p2 = os.path.normpath(os.path.normcase(p2)) + return norm_p1 == norm_p2 + + +def _to_bytes(s): + return s.encode('utf8') + + +def isascii(s): + try: + s.encode('ascii') + return True + except UnicodeError: + return False + + +def _one_liner(text): + return textwrap.dedent(text).strip().replace('\n', '; ') + + +class easy_install(Command): + """Manage a download/build/install process""" + description = "Find/get/install Python packages" + command_consumes_arguments = True + + user_options = [ + ('prefix=', None, "installation prefix"), + ("zip-ok", "z", "install package as a zipfile"), + ("multi-version", "m", "make apps have to require() a version"), + ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"), + ("install-dir=", "d", "install package to DIR"), + ("script-dir=", "s", "install scripts to DIR"), + ("exclude-scripts", "x", "Don't install scripts"), + ("always-copy", "a", "Copy all needed packages to install dir"), + ("index-url=", "i", "base URL of Python Package Index"), + ("find-links=", "f", "additional URL(s) to search for packages"), + ("build-directory=", "b", + "download/extract/build in DIR; keep the results"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ('record=', None, + "filename in which to record list of installed files"), + ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), + ('site-dirs=', 'S', "list of directories where .pth files work"), + ('editable', 'e', "Install specified packages in editable form"), + ('no-deps', 'N', "don't install dependencies"), + ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), + ('local-snapshots-ok', 'l', + "allow building eggs from local checkouts"), + ('version', None, "print version information and exit"), + ('no-find-links', None, + "Don't load find-links defined in packages being installed"), + ('user', None, "install in user site-package '%s'" % site.USER_SITE) + ] + boolean_options = [ + 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', + 'editable', + 'no-deps', 'local-snapshots-ok', 'version', + 'user' + ] + + negative_opt = {'always-unzip': 'zip-ok'} + create_index = PackageIndex + + def initialize_options(self): + # the --user option seems to be an opt-in one, + # so the default should be False. + self.user = 0 + self.zip_ok = self.local_snapshots_ok = None + self.install_dir = self.script_dir = self.exclude_scripts = None + self.index_url = None + self.find_links = None + self.build_directory = None + self.args = None + self.optimize = self.record = None + self.upgrade = self.always_copy = self.multi_version = None + self.editable = self.no_deps = self.allow_hosts = None + self.root = self.prefix = self.no_report = None + self.version = None + self.install_purelib = None # for pure module distributions + self.install_platlib = None # non-pure (dists w/ extensions) + self.install_headers = None # for C/C++ headers + self.install_lib = None # set to either purelib or platlib + self.install_scripts = None + self.install_data = None + self.install_base = None + self.install_platbase = None + if site.ENABLE_USER_SITE: + self.install_userbase = site.USER_BASE + self.install_usersite = site.USER_SITE + else: + self.install_userbase = None + self.install_usersite = None + self.no_find_links = None + + # Options not specifiable via command line + self.package_index = None + self.pth_file = self.always_copy_from = None + self.site_dirs = None + self.installed_projects = {} + # Always read easy_install options, even if we are subclassed, or have + # an independent instance created. This ensures that defaults will + # always come from the standard configuration file(s)' "easy_install" + # section, even if this is a "develop" or "install" command, or some + # other embedding. + self._dry_run = None + self.verbose = self.distribution.verbose + self.distribution._set_command_options( + self, self.distribution.get_option_dict('easy_install') + ) + + def delete_blockers(self, blockers): + extant_blockers = ( + filename for filename in blockers + if os.path.exists(filename) or os.path.islink(filename) + ) + list(map(self._delete_path, extant_blockers)) + + def _delete_path(self, path): + log.info("Deleting %s", path) + if self.dry_run: + return + + is_tree = os.path.isdir(path) and not os.path.islink(path) + remover = rmtree if is_tree else os.unlink + remover(path) + + @staticmethod + def _render_version(): + """ + Render the Setuptools version and installation details, then exit. + """ + ver = '{}.{}'.format(*sys.version_info) + dist = get_distribution('setuptools') + tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})' + print(tmpl.format(**locals())) + raise SystemExit() + + def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME + self.version and self._render_version() + + py_version = sys.version.split()[0] + prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix') + + self.config_vars = { + 'dist_name': self.distribution.get_name(), + 'dist_version': self.distribution.get_version(), + 'dist_fullname': self.distribution.get_fullname(), + 'py_version': py_version, + 'py_version_short': py_version[0:3], + 'py_version_nodot': py_version[0] + py_version[2], + 'sys_prefix': prefix, + 'prefix': prefix, + 'sys_exec_prefix': exec_prefix, + 'exec_prefix': exec_prefix, + # Only python 3.2+ has abiflags + 'abiflags': getattr(sys, 'abiflags', ''), + } + + if site.ENABLE_USER_SITE: + self.config_vars['userbase'] = self.install_userbase + self.config_vars['usersite'] = self.install_usersite + + elif self.user: + log.warn("WARNING: The user site-packages directory is disabled.") + + self._fix_install_dir_for_user_site() + + self.expand_basedirs() + self.expand_dirs() + + self._expand( + 'install_dir', 'script_dir', 'build_directory', + 'site_dirs', + ) + # If a non-default installation directory was specified, default the + # script directory to match it. + if self.script_dir is None: + self.script_dir = self.install_dir + + if self.no_find_links is None: + self.no_find_links = False + + # Let install_dir get set by install_lib command, which in turn + # gets its info from the install command, and takes into account + # --prefix and --home and all that other crud. + self.set_undefined_options( + 'install_lib', ('install_dir', 'install_dir') + ) + # Likewise, set default script_dir from 'install_scripts.install_dir' + self.set_undefined_options( + 'install_scripts', ('install_dir', 'script_dir') + ) + + if self.user and self.install_purelib: + self.install_dir = self.install_purelib + self.script_dir = self.install_scripts + # default --record from the install command + self.set_undefined_options('install', ('record', 'record')) + # Should this be moved to the if statement below? It's not used + # elsewhere + normpath = map(normalize_path, sys.path) + self.all_site_dirs = get_site_dirs() + if self.site_dirs is not None: + site_dirs = [ + os.path.expanduser(s.strip()) for s in + self.site_dirs.split(',') + ] + for d in site_dirs: + if not os.path.isdir(d): + log.warn("%s (in --site-dirs) does not exist", d) + elif normalize_path(d) not in normpath: + raise DistutilsOptionError( + d + " (in --site-dirs) is not on sys.path" + ) + else: + self.all_site_dirs.append(normalize_path(d)) + if not self.editable: + self.check_site_dir() + self.index_url = self.index_url or "https://pypi.org/simple/" + self.shadow_path = self.all_site_dirs[:] + for path_item in self.install_dir, normalize_path(self.script_dir): + if path_item not in self.shadow_path: + self.shadow_path.insert(0, path_item) + + if self.allow_hosts is not None: + hosts = [s.strip() for s in self.allow_hosts.split(',')] + else: + hosts = ['*'] + if self.package_index is None: + self.package_index = self.create_index( + self.index_url, search_path=self.shadow_path, hosts=hosts, + ) + self.local_index = Environment(self.shadow_path + sys.path) + + if self.find_links is not None: + if isinstance(self.find_links, str): + self.find_links = self.find_links.split() + else: + self.find_links = [] + if self.local_snapshots_ok: + self.package_index.scan_egg_links(self.shadow_path + sys.path) + if not self.no_find_links: + self.package_index.add_find_links(self.find_links) + self.set_undefined_options('install_lib', ('optimize', 'optimize')) + if not isinstance(self.optimize, int): + try: + self.optimize = int(self.optimize) + if not (0 <= self.optimize <= 2): + raise ValueError + except ValueError as e: + raise DistutilsOptionError( + "--optimize must be 0, 1, or 2" + ) from e + + if self.editable and not self.build_directory: + raise DistutilsArgError( + "Must specify a build directory (-b) when using --editable" + ) + if not self.args: + raise DistutilsArgError( + "No urls, filenames, or requirements specified (see --help)") + + self.outputs = [] + + def _fix_install_dir_for_user_site(self): + """ + Fix the install_dir if "--user" was used. + """ + if not self.user or not site.ENABLE_USER_SITE: + return + + self.create_home_path() + if self.install_userbase is None: + msg = "User base directory is not specified" + raise DistutilsPlatformError(msg) + self.install_base = self.install_platbase = self.install_userbase + scheme_name = os.name.replace('posix', 'unix') + '_user' + self.select_scheme(scheme_name) + + def _expand_attrs(self, attrs): + for attr in attrs: + val = getattr(self, attr) + if val is not None: + if os.name == 'posix' or os.name == 'nt': + val = os.path.expanduser(val) + val = subst_vars(val, self.config_vars) + setattr(self, attr, val) + + def expand_basedirs(self): + """Calls `os.path.expanduser` on install_base, install_platbase and + root.""" + self._expand_attrs(['install_base', 'install_platbase', 'root']) + + def expand_dirs(self): + """Calls `os.path.expanduser` on install dirs.""" + dirs = [ + 'install_purelib', + 'install_platlib', + 'install_lib', + 'install_headers', + 'install_scripts', + 'install_data', + ] + self._expand_attrs(dirs) + + def run(self, show_deprecation=True): + if show_deprecation: + self.announce( + "WARNING: The easy_install command is deprecated " + "and will be removed in a future version.", + log.WARN, + ) + if self.verbose != self.distribution.verbose: + log.set_verbosity(self.verbose) + try: + for spec in self.args: + self.easy_install(spec, not self.no_deps) + if self.record: + outputs = self.outputs + if self.root: # strip any package prefix + root_len = len(self.root) + for counter in range(len(outputs)): + outputs[counter] = outputs[counter][root_len:] + from distutils import file_util + + self.execute( + file_util.write_file, (self.record, outputs), + "writing list of installed files to '%s'" % + self.record + ) + self.warn_deprecated_options() + finally: + log.set_verbosity(self.distribution.verbose) + + def pseudo_tempname(self): + """Return a pseudo-tempname base in the install directory. + This code is intentionally naive; if a malicious party can write to + the target directory you're already in deep doodoo. + """ + try: + pid = os.getpid() + except Exception: + pid = random.randint(0, sys.maxsize) + return os.path.join(self.install_dir, "test-easy-install-%s" % pid) + + def warn_deprecated_options(self): + pass + + def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME + """Verify that self.install_dir is .pth-capable dir, if needed""" + + instdir = normalize_path(self.install_dir) + pth_file = os.path.join(instdir, 'easy-install.pth') + + if not os.path.exists(instdir): + try: + os.makedirs(instdir) + except (OSError, IOError): + self.cant_write_to_target() + + # Is it a configured, PYTHONPATH, implicit, or explicit site dir? + is_site_dir = instdir in self.all_site_dirs + + if not is_site_dir and not self.multi_version: + # No? Then directly test whether it does .pth file processing + is_site_dir = self.check_pth_processing() + else: + # make sure we can write to target dir + testfile = self.pseudo_tempname() + '.write-test' + test_exists = os.path.exists(testfile) + try: + if test_exists: + os.unlink(testfile) + open(testfile, 'w').close() + os.unlink(testfile) + except (OSError, IOError): + self.cant_write_to_target() + + if not is_site_dir and not self.multi_version: + # Can't install non-multi to non-site dir with easy_install + pythonpath = os.environ.get('PYTHONPATH', '') + log.warn(self.__no_default_msg, self.install_dir, pythonpath) + + if is_site_dir: + if self.pth_file is None: + self.pth_file = PthDistributions(pth_file, self.all_site_dirs) + else: + self.pth_file = None + + if self.multi_version and not os.path.exists(pth_file): + self.pth_file = None # don't create a .pth file + self.install_dir = instdir + + __cant_write_msg = textwrap.dedent(""" + can't create or remove files in install directory + + The following error occurred while trying to add or remove files in the + installation directory: + + %s + + The installation directory you specified (via --install-dir, --prefix, or + the distutils default setting) was: + + %s + """).lstrip() # noqa + + __not_exists_id = textwrap.dedent(""" + This directory does not currently exist. Please create it and try again, or + choose a different installation directory (using the -d or --install-dir + option). + """).lstrip() # noqa + + __access_msg = textwrap.dedent(""" + Perhaps your account does not have write access to this directory? If the + installation directory is a system-owned directory, you may need to sign in + as the administrator or "root" account. If you do not have administrative + access to this machine, you may wish to choose a different installation + directory, preferably one that is listed in your PYTHONPATH environment + variable. + + For information on other options, you may wish to consult the + documentation at: + + https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html + + Please make the appropriate changes for your system and try again. + """).lstrip() # noqa + + def cant_write_to_target(self): + msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,) + + if not os.path.exists(self.install_dir): + msg += '\n' + self.__not_exists_id + else: + msg += '\n' + self.__access_msg + raise DistutilsError(msg) + + def check_pth_processing(self): + """Empirically verify whether .pth files are supported in inst. dir""" + instdir = self.install_dir + log.info("Checking .pth file support in %s", instdir) + pth_file = self.pseudo_tempname() + ".pth" + ok_file = pth_file + '.ok' + ok_exists = os.path.exists(ok_file) + tmpl = _one_liner(""" + import os + f = open({ok_file!r}, 'w') + f.write('OK') + f.close() + """) + '\n' + try: + if ok_exists: + os.unlink(ok_file) + dirname = os.path.dirname(ok_file) + os.makedirs(dirname, exist_ok=True) + f = open(pth_file, 'w') + except (OSError, IOError): + self.cant_write_to_target() + else: + try: + f.write(tmpl.format(**locals())) + f.close() + f = None + executable = sys.executable + if os.name == 'nt': + dirname, basename = os.path.split(executable) + alt = os.path.join(dirname, 'pythonw.exe') + use_alt = ( + basename.lower() == 'python.exe' and + os.path.exists(alt) + ) + if use_alt: + # use pythonw.exe to avoid opening a console window + executable = alt + + from distutils.spawn import spawn + + spawn([executable, '-E', '-c', 'pass'], 0) + + if os.path.exists(ok_file): + log.info( + "TEST PASSED: %s appears to support .pth files", + instdir + ) + return True + finally: + if f: + f.close() + if os.path.exists(ok_file): + os.unlink(ok_file) + if os.path.exists(pth_file): + os.unlink(pth_file) + if not self.multi_version: + log.warn("TEST FAILED: %s does NOT support .pth files", instdir) + return False + + def install_egg_scripts(self, dist): + """Write all the scripts for `dist`, unless scripts are excluded""" + if not self.exclude_scripts and dist.metadata_isdir('scripts'): + for script_name in dist.metadata_listdir('scripts'): + if dist.metadata_isdir('scripts/' + script_name): + # The "script" is a directory, likely a Python 3 + # __pycache__ directory, so skip it. + continue + self.install_script( + dist, script_name, + dist.get_metadata('scripts/' + script_name) + ) + self.install_wrapper_scripts(dist) + + def add_output(self, path): + if os.path.isdir(path): + for base, dirs, files in os.walk(path): + for filename in files: + self.outputs.append(os.path.join(base, filename)) + else: + self.outputs.append(path) + + def not_editable(self, spec): + if self.editable: + raise DistutilsArgError( + "Invalid argument %r: you can't use filenames or URLs " + "with --editable (except via the --find-links option)." + % (spec,) + ) + + def check_editable(self, spec): + if not self.editable: + return + + if os.path.exists(os.path.join(self.build_directory, spec.key)): + raise DistutilsArgError( + "%r already exists in %s; can't do a checkout there" % + (spec.key, self.build_directory) + ) + + @contextlib.contextmanager + def _tmpdir(self): + tmpdir = tempfile.mkdtemp(prefix=u"easy_install-") + try: + # cast to str as workaround for #709 and #710 and #712 + yield str(tmpdir) + finally: + os.path.exists(tmpdir) and rmtree(tmpdir) + + def easy_install(self, spec, deps=False): + with self._tmpdir() as tmpdir: + if not isinstance(spec, Requirement): + if URL_SCHEME(spec): + # It's a url, download it to tmpdir and process + self.not_editable(spec) + dl = self.package_index.download(spec, tmpdir) + return self.install_item(None, dl, tmpdir, deps, True) + + elif os.path.exists(spec): + # Existing file or directory, just process it directly + self.not_editable(spec) + return self.install_item(None, spec, tmpdir, deps, True) + else: + spec = parse_requirement_arg(spec) + + self.check_editable(spec) + dist = self.package_index.fetch_distribution( + spec, tmpdir, self.upgrade, self.editable, + not self.always_copy, self.local_index + ) + if dist is None: + msg = "Could not find suitable distribution for %r" % spec + if self.always_copy: + msg += " (--always-copy skips system and development eggs)" + raise DistutilsError(msg) + elif dist.precedence == DEVELOP_DIST: + # .egg-info dists don't need installing, just process deps + self.process_distribution(spec, dist, deps, "Using") + return dist + else: + return self.install_item(spec, dist.location, tmpdir, deps) + + def install_item(self, spec, download, tmpdir, deps, install_needed=False): + + # Installation is also needed if file in tmpdir or is not an egg + install_needed = install_needed or self.always_copy + install_needed = install_needed or os.path.dirname(download) == tmpdir + install_needed = install_needed or not download.endswith('.egg') + install_needed = install_needed or ( + self.always_copy_from is not None and + os.path.dirname(normalize_path(download)) == + normalize_path(self.always_copy_from) + ) + + if spec and not install_needed: + # at this point, we know it's a local .egg, we just don't know if + # it's already installed. + for dist in self.local_index[spec.project_name]: + if dist.location == download: + break + else: + install_needed = True # it's not in the local index + + log.info("Processing %s", os.path.basename(download)) + + if install_needed: + dists = self.install_eggs(spec, download, tmpdir) + for dist in dists: + self.process_distribution(spec, dist, deps) + else: + dists = [self.egg_distribution(download)] + self.process_distribution(spec, dists[0], deps, "Using") + + if spec is not None: + for dist in dists: + if dist in spec: + return dist + + def select_scheme(self, name): + """Sets the install directories by applying the install schemes.""" + # it's the caller's problem if they supply a bad name! + scheme = INSTALL_SCHEMES[name] + for key in SCHEME_KEYS: + attrname = 'install_' + key + if getattr(self, attrname) is None: + setattr(self, attrname, scheme[key]) + + # FIXME: 'easy_install.process_distribution' is too complex (12) + def process_distribution( # noqa: C901 + self, requirement, dist, deps=True, *info, + ): + self.update_pth(dist) + self.package_index.add(dist) + if dist in self.local_index[dist.key]: + self.local_index.remove(dist) + self.local_index.add(dist) + self.install_egg_scripts(dist) + self.installed_projects[dist.key] = dist + log.info(self.installation_report(requirement, dist, *info)) + if (dist.has_metadata('dependency_links.txt') and + not self.no_find_links): + self.package_index.add_find_links( + dist.get_metadata_lines('dependency_links.txt') + ) + if not deps and not self.always_copy: + return + elif requirement is not None and dist.key != requirement.key: + log.warn("Skipping dependencies for %s", dist) + return # XXX this is not the distribution we were looking for + elif requirement is None or dist not in requirement: + # if we wound up with a different version, resolve what we've got + distreq = dist.as_requirement() + requirement = Requirement(str(distreq)) + log.info("Processing dependencies for %s", requirement) + try: + distros = WorkingSet([]).resolve( + [requirement], self.local_index, self.easy_install + ) + except DistributionNotFound as e: + raise DistutilsError(str(e)) from e + except VersionConflict as e: + raise DistutilsError(e.report()) from e + if self.always_copy or self.always_copy_from: + # Force all the relevant distros to be copied or activated + for dist in distros: + if dist.key not in self.installed_projects: + self.easy_install(dist.as_requirement()) + log.info("Finished processing dependencies for %s", requirement) + + def should_unzip(self, dist): + if self.zip_ok is not None: + return not self.zip_ok + if dist.has_metadata('not-zip-safe'): + return True + if not dist.has_metadata('zip-safe'): + return True + return False + + def maybe_move(self, spec, dist_filename, setup_base): + dst = os.path.join(self.build_directory, spec.key) + if os.path.exists(dst): + msg = ( + "%r already exists in %s; build directory %s will not be kept" + ) + log.warn(msg, spec.key, self.build_directory, setup_base) + return setup_base + if os.path.isdir(dist_filename): + setup_base = dist_filename + else: + if os.path.dirname(dist_filename) == setup_base: + os.unlink(dist_filename) # get it out of the tmp dir + contents = os.listdir(setup_base) + if len(contents) == 1: + dist_filename = os.path.join(setup_base, contents[0]) + if os.path.isdir(dist_filename): + # if the only thing there is a directory, move it instead + setup_base = dist_filename + ensure_directory(dst) + shutil.move(setup_base, dst) + return dst + + def install_wrapper_scripts(self, dist): + if self.exclude_scripts: + return + for args in ScriptWriter.best().get_args(dist): + self.write_script(*args) + + def install_script(self, dist, script_name, script_text, dev_path=None): + """Generate a legacy script wrapper and install it""" + spec = str(dist.as_requirement()) + is_script = is_python_script(script_text, script_name) + + if is_script: + body = self._load_template(dev_path) % locals() + script_text = ScriptWriter.get_header(script_text) + body + self.write_script(script_name, _to_bytes(script_text), 'b') + + @staticmethod + def _load_template(dev_path): + """ + There are a couple of template scripts in the package. This + function loads one of them and prepares it for use. + """ + # See https://github.com/pypa/setuptools/issues/134 for info + # on script file naming and downstream issues with SVR4 + name = 'script.tmpl' + if dev_path: + name = name.replace('.tmpl', ' (dev).tmpl') + + raw_bytes = resource_string('setuptools', name) + return raw_bytes.decode('utf-8') + + def write_script(self, script_name, contents, mode="t", blockers=()): + """Write an executable file to the scripts directory""" + self.delete_blockers( # clean up old .py/.pyw w/o a script + [os.path.join(self.script_dir, x) for x in blockers] + ) + log.info("Installing %s script to %s", script_name, self.script_dir) + target = os.path.join(self.script_dir, script_name) + self.add_output(target) + + if self.dry_run: + return + + mask = current_umask() + ensure_directory(target) + if os.path.exists(target): + os.unlink(target) + with open(target, "w" + mode) as f: + f.write(contents) + chmod(target, 0o777 - mask) + + def install_eggs(self, spec, dist_filename, tmpdir): + # .egg dirs or files are already built, so just return them + installer_map = { + '.egg': self.install_egg, + '.exe': self.install_exe, + '.whl': self.install_wheel, + } + try: + install_dist = installer_map[ + dist_filename.lower()[-4:] + ] + except KeyError: + pass + else: + return [install_dist(dist_filename, tmpdir)] + + # Anything else, try to extract and build + setup_base = tmpdir + if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'): + unpack_archive(dist_filename, tmpdir, self.unpack_progress) + elif os.path.isdir(dist_filename): + setup_base = os.path.abspath(dist_filename) + + if (setup_base.startswith(tmpdir) # something we downloaded + and self.build_directory and spec is not None): + setup_base = self.maybe_move(spec, dist_filename, setup_base) + + # Find the setup.py file + setup_script = os.path.join(setup_base, 'setup.py') + + if not os.path.exists(setup_script): + setups = glob(os.path.join(setup_base, '*', 'setup.py')) + if not setups: + raise DistutilsError( + "Couldn't find a setup script in %s" % + os.path.abspath(dist_filename) + ) + if len(setups) > 1: + raise DistutilsError( + "Multiple setup scripts in %s" % + os.path.abspath(dist_filename) + ) + setup_script = setups[0] + + # Now run it, and return the result + if self.editable: + log.info(self.report_editable(spec, setup_script)) + return [] + else: + return self.build_and_install(setup_script, setup_base) + + def egg_distribution(self, egg_path): + if os.path.isdir(egg_path): + metadata = PathMetadata(egg_path, os.path.join(egg_path, + 'EGG-INFO')) + else: + metadata = EggMetadata(zipimport.zipimporter(egg_path)) + return Distribution.from_filename(egg_path, metadata=metadata) + + # FIXME: 'easy_install.install_egg' is too complex (11) + def install_egg(self, egg_path, tmpdir): # noqa: C901 + destination = os.path.join( + self.install_dir, + os.path.basename(egg_path), + ) + destination = os.path.abspath(destination) + if not self.dry_run: + ensure_directory(destination) + + dist = self.egg_distribution(egg_path) + if not samefile(egg_path, destination): + if os.path.isdir(destination) and not os.path.islink(destination): + dir_util.remove_tree(destination, dry_run=self.dry_run) + elif os.path.exists(destination): + self.execute( + os.unlink, + (destination,), + "Removing " + destination, + ) + try: + new_dist_is_zipped = False + if os.path.isdir(egg_path): + if egg_path.startswith(tmpdir): + f, m = shutil.move, "Moving" + else: + f, m = shutil.copytree, "Copying" + elif self.should_unzip(dist): + self.mkpath(destination) + f, m = self.unpack_and_compile, "Extracting" + else: + new_dist_is_zipped = True + if egg_path.startswith(tmpdir): + f, m = shutil.move, "Moving" + else: + f, m = shutil.copy2, "Copying" + self.execute( + f, + (egg_path, destination), + (m + " %s to %s") % ( + os.path.basename(egg_path), + os.path.dirname(destination) + ), + ) + update_dist_caches( + destination, + fix_zipimporter_caches=new_dist_is_zipped, + ) + except Exception: + update_dist_caches(destination, fix_zipimporter_caches=False) + raise + + self.add_output(destination) + return self.egg_distribution(destination) + + def install_exe(self, dist_filename, tmpdir): + # See if it's valid, get data + cfg = extract_wininst_cfg(dist_filename) + if cfg is None: + raise DistutilsError( + "%s is not a valid distutils Windows .exe" % dist_filename + ) + # Create a dummy distribution object until we build the real distro + dist = Distribution( + None, + project_name=cfg.get('metadata', 'name'), + version=cfg.get('metadata', 'version'), platform=get_platform(), + ) + + # Convert the .exe to an unpacked egg + egg_path = os.path.join(tmpdir, dist.egg_name() + '.egg') + dist.location = egg_path + egg_tmp = egg_path + '.tmp' + _egg_info = os.path.join(egg_tmp, 'EGG-INFO') + pkg_inf = os.path.join(_egg_info, 'PKG-INFO') + ensure_directory(pkg_inf) # make sure EGG-INFO dir exists + dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX + self.exe_to_egg(dist_filename, egg_tmp) + + # Write EGG-INFO/PKG-INFO + if not os.path.exists(pkg_inf): + f = open(pkg_inf, 'w') + f.write('Metadata-Version: 1.0\n') + for k, v in cfg.items('metadata'): + if k != 'target_version': + f.write('%s: %s\n' % (k.replace('_', '-').title(), v)) + f.close() + script_dir = os.path.join(_egg_info, 'scripts') + # delete entry-point scripts to avoid duping + self.delete_blockers([ + os.path.join(script_dir, args[0]) + for args in ScriptWriter.get_args(dist) + ]) + # Build .egg file from tmpdir + bdist_egg.make_zipfile( + egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run, + ) + # install the .egg + return self.install_egg(egg_path, tmpdir) + + # FIXME: 'easy_install.exe_to_egg' is too complex (12) + def exe_to_egg(self, dist_filename, egg_tmp): # noqa: C901 + """Extract a bdist_wininst to the directories an egg would use""" + # Check for .pth file and set up prefix translations + prefixes = get_exe_prefixes(dist_filename) + to_compile = [] + native_libs = [] + top_level = {} + + def process(src, dst): + s = src.lower() + for old, new in prefixes: + if s.startswith(old): + src = new + src[len(old):] + parts = src.split('/') + dst = os.path.join(egg_tmp, *parts) + dl = dst.lower() + if dl.endswith('.pyd') or dl.endswith('.dll'): + parts[-1] = bdist_egg.strip_module(parts[-1]) + top_level[os.path.splitext(parts[0])[0]] = 1 + native_libs.append(src) + elif dl.endswith('.py') and old != 'SCRIPTS/': + top_level[os.path.splitext(parts[0])[0]] = 1 + to_compile.append(dst) + return dst + if not src.endswith('.pth'): + log.warn("WARNING: can't process %s", src) + return None + + # extract, tracking .pyd/.dll->native_libs and .py -> to_compile + unpack_archive(dist_filename, egg_tmp, process) + stubs = [] + for res in native_libs: + if res.lower().endswith('.pyd'): # create stubs for .pyd's + parts = res.split('/') + resource = parts[-1] + parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py' + pyfile = os.path.join(egg_tmp, *parts) + to_compile.append(pyfile) + stubs.append(pyfile) + bdist_egg.write_stub(resource, pyfile) + self.byte_compile(to_compile) # compile .py's + bdist_egg.write_safety_flag( + os.path.join(egg_tmp, 'EGG-INFO'), + bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag + + for name in 'top_level', 'native_libs': + if locals()[name]: + txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt') + if not os.path.exists(txt): + f = open(txt, 'w') + f.write('\n'.join(locals()[name]) + '\n') + f.close() + + def install_wheel(self, wheel_path, tmpdir): + wheel = Wheel(wheel_path) + assert wheel.is_compatible() + destination = os.path.join(self.install_dir, wheel.egg_name()) + destination = os.path.abspath(destination) + if not self.dry_run: + ensure_directory(destination) + if os.path.isdir(destination) and not os.path.islink(destination): + dir_util.remove_tree(destination, dry_run=self.dry_run) + elif os.path.exists(destination): + self.execute( + os.unlink, + (destination,), + "Removing " + destination, + ) + try: + self.execute( + wheel.install_as_egg, + (destination,), + ("Installing %s to %s") % ( + os.path.basename(wheel_path), + os.path.dirname(destination) + ), + ) + finally: + update_dist_caches(destination, fix_zipimporter_caches=False) + self.add_output(destination) + return self.egg_distribution(destination) + + __mv_warning = textwrap.dedent(""" + Because this distribution was installed --multi-version, before you can + import modules from this package in an application, you will need to + 'import pkg_resources' and then use a 'require()' call similar to one of + these examples, in order to select the desired version: + + pkg_resources.require("%(name)s") # latest installed version + pkg_resources.require("%(name)s==%(version)s") # this exact version + pkg_resources.require("%(name)s>=%(version)s") # this version or higher + """).lstrip() # noqa + + __id_warning = textwrap.dedent(""" + Note also that the installation directory must be on sys.path at runtime for + this to work. (e.g. by being the application's script directory, by being on + PYTHONPATH, or by being added to sys.path by your code.) + """) # noqa + + def installation_report(self, req, dist, what="Installed"): + """Helpful installation message for display to package users""" + msg = "\n%(what)s %(eggloc)s%(extras)s" + if self.multi_version and not self.no_report: + msg += '\n' + self.__mv_warning + if self.install_dir not in map(normalize_path, sys.path): + msg += '\n' + self.__id_warning + + eggloc = dist.location + name = dist.project_name + version = dist.version + extras = '' # TODO: self.report_extras(req, dist) + return msg % locals() + + __editable_msg = textwrap.dedent(""" + Extracted editable version of %(spec)s to %(dirname)s + + If it uses setuptools in its setup script, you can activate it in + "development" mode by going to that directory and running:: + + %(python)s setup.py develop + + See the setuptools documentation for the "develop" command for more info. + """).lstrip() # noqa + + def report_editable(self, spec, setup_script): + dirname = os.path.dirname(setup_script) + python = sys.executable + return '\n' + self.__editable_msg % locals() + + def run_setup(self, setup_script, setup_base, args): + sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg) + sys.modules.setdefault('distutils.command.egg_info', egg_info) + + args = list(args) + if self.verbose > 2: + v = 'v' * (self.verbose - 1) + args.insert(0, '-' + v) + elif self.verbose < 2: + args.insert(0, '-q') + if self.dry_run: + args.insert(0, '-n') + log.info( + "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args) + ) + try: + run_setup(setup_script, args) + except SystemExit as v: + raise DistutilsError( + "Setup script exited with %s" % (v.args[0],) + ) from v + + def build_and_install(self, setup_script, setup_base): + args = ['bdist_egg', '--dist-dir'] + + dist_dir = tempfile.mkdtemp( + prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) + ) + try: + self._set_fetcher_options(os.path.dirname(setup_script)) + args.append(dist_dir) + + self.run_setup(setup_script, setup_base, args) + all_eggs = Environment([dist_dir]) + eggs = [] + for key in all_eggs: + for dist in all_eggs[key]: + eggs.append(self.install_egg(dist.location, setup_base)) + if not eggs and not self.dry_run: + log.warn("No eggs found in %s (setup script problem?)", + dist_dir) + return eggs + finally: + rmtree(dist_dir) + log.set_verbosity(self.verbose) # restore our log verbosity + + def _set_fetcher_options(self, base): + """ + When easy_install is about to run bdist_egg on a source dist, that + source dist might have 'setup_requires' directives, requiring + additional fetching. Ensure the fetcher options given to easy_install + are available to that command as well. + """ + # find the fetch options from easy_install and write them out + # to the setup.cfg file. + ei_opts = self.distribution.get_option_dict('easy_install').copy() + fetch_directives = ( + 'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts', + ) + fetch_options = {} + for key, val in ei_opts.items(): + if key not in fetch_directives: + continue + fetch_options[key] = val[1] + # create a settings dictionary suitable for `edit_config` + settings = dict(easy_install=fetch_options) + cfg_filename = os.path.join(base, 'setup.cfg') + setopt.edit_config(cfg_filename, settings) + + def update_pth(self, dist): # noqa: C901 # is too complex (11) # FIXME + if self.pth_file is None: + return + + for d in self.pth_file[dist.key]: # drop old entries + if not self.multi_version and d.location == dist.location: + continue + + log.info("Removing %s from easy-install.pth file", d) + self.pth_file.remove(d) + if d.location in self.shadow_path: + self.shadow_path.remove(d.location) + + if not self.multi_version: + if dist.location in self.pth_file.paths: + log.info( + "%s is already the active version in easy-install.pth", + dist, + ) + else: + log.info("Adding %s to easy-install.pth file", dist) + self.pth_file.add(dist) # add new entry + if dist.location not in self.shadow_path: + self.shadow_path.append(dist.location) + + if self.dry_run: + return + + self.pth_file.save() + + if dist.key != 'setuptools': + return + + # Ensure that setuptools itself never becomes unavailable! + # XXX should this check for latest version? + filename = os.path.join(self.install_dir, 'setuptools.pth') + if os.path.islink(filename): + os.unlink(filename) + with open(filename, 'wt') as f: + f.write(self.pth_file.make_relative(dist.location) + '\n') + + def unpack_progress(self, src, dst): + # Progress filter for unpacking + log.debug("Unpacking %s to %s", src, dst) + return dst # only unpack-and-compile skips files for dry run + + def unpack_and_compile(self, egg_path, destination): + to_compile = [] + to_chmod = [] + + def pf(src, dst): + if dst.endswith('.py') and not src.startswith('EGG-INFO/'): + to_compile.append(dst) + elif dst.endswith('.dll') or dst.endswith('.so'): + to_chmod.append(dst) + self.unpack_progress(src, dst) + return not self.dry_run and dst or None + + unpack_archive(egg_path, destination, pf) + self.byte_compile(to_compile) + if not self.dry_run: + for f in to_chmod: + mode = ((os.stat(f)[stat.ST_MODE]) | 0o555) & 0o7755 + chmod(f, mode) + + def byte_compile(self, to_compile): + if sys.dont_write_bytecode: + return + + from distutils.util import byte_compile + + try: + # try to make the byte compile messages quieter + log.set_verbosity(self.verbose - 1) + + byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) + if self.optimize: + byte_compile( + to_compile, optimize=self.optimize, force=1, + dry_run=self.dry_run, + ) + finally: + log.set_verbosity(self.verbose) # restore original verbosity + + __no_default_msg = textwrap.dedent(""" + bad install directory or PYTHONPATH + + You are attempting to install a package to a directory that is not + on PYTHONPATH and which Python does not read ".pth" files from. The + installation directory you specified (via --install-dir, --prefix, or + the distutils default setting) was: + + %s + + and your PYTHONPATH environment variable currently contains: + + %r + + Here are some of your options for correcting the problem: + + * You can choose a different installation directory, i.e., one that is + on PYTHONPATH or supports .pth files + + * You can add the installation directory to the PYTHONPATH environment + variable. (It must then also be on PYTHONPATH whenever you run + Python and want to use the package(s) you are installing.) + + * You can set up the installation directory to support ".pth" files by + using one of the approaches described here: + + https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html#custom-installation-locations + + + Please make the appropriate changes for your system and try again. + """).strip() + + def create_home_path(self): + """Create directories under ~.""" + if not self.user: + return + home = convert_path(os.path.expanduser("~")) + for name, path in self.config_vars.items(): + if path.startswith(home) and not os.path.isdir(path): + self.debug_print("os.makedirs('%s', 0o700)" % path) + os.makedirs(path, 0o700) + + INSTALL_SCHEMES = dict( + posix=dict( + install_dir='$base/lib/python$py_version_short/site-packages', + script_dir='$base/bin', + ), + ) + + DEFAULT_SCHEME = dict( + install_dir='$base/Lib/site-packages', + script_dir='$base/Scripts', + ) + + def _expand(self, *attrs): + config_vars = self.get_finalized_command('install').config_vars + + if self.prefix: + # Set default install_dir/scripts from --prefix + config_vars = config_vars.copy() + config_vars['base'] = self.prefix + scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME) + for attr, val in scheme.items(): + if getattr(self, attr, None) is None: + setattr(self, attr, val) + + from distutils.util import subst_vars + + for attr in attrs: + val = getattr(self, attr) + if val is not None: + val = subst_vars(val, config_vars) + if os.name == 'posix': + val = os.path.expanduser(val) + setattr(self, attr, val) + + +def _pythonpath(): + items = os.environ.get('PYTHONPATH', '').split(os.pathsep) + return filter(None, items) + + +def get_site_dirs(): + """ + Return a list of 'site' dirs + """ + + sitedirs = [] + + # start with PYTHONPATH + sitedirs.extend(_pythonpath()) + + prefixes = [sys.prefix] + if sys.exec_prefix != sys.prefix: + prefixes.append(sys.exec_prefix) + for prefix in prefixes: + if not prefix: + continue + + if sys.platform in ('os2emx', 'riscos'): + sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) + elif os.sep == '/': + sitedirs.extend([ + os.path.join( + prefix, + "lib", + "python{}.{}".format(*sys.version_info), + "site-packages", + ), + os.path.join(prefix, "lib", "site-python"), + ]) + else: + sitedirs.extend([ + prefix, + os.path.join(prefix, "lib", "site-packages"), + ]) + if sys.platform != 'darwin': + continue + + # for framework builds *only* we add the standard Apple + # locations. Currently only per-user, but /Library and + # /Network/Library could be added too + if 'Python.framework' not in prefix: + continue + + home = os.environ.get('HOME') + if not home: + continue + + home_sp = os.path.join( + home, + 'Library', + 'Python', + '{}.{}'.format(*sys.version_info), + 'site-packages', + ) + sitedirs.append(home_sp) + lib_paths = get_path('purelib'), get_path('platlib') + + sitedirs.extend(s for s in lib_paths if s not in sitedirs) + + if site.ENABLE_USER_SITE: + sitedirs.append(site.USER_SITE) + + with contextlib.suppress(AttributeError): + sitedirs.extend(site.getsitepackages()) + + sitedirs = list(map(normalize_path, sitedirs)) + + return sitedirs + + +def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME + """Yield sys.path directories that might contain "old-style" packages""" + + seen = {} + + for dirname in inputs: + dirname = normalize_path(dirname) + if dirname in seen: + continue + + seen[dirname] = 1 + if not os.path.isdir(dirname): + continue + + files = os.listdir(dirname) + yield dirname, files + + for name in files: + if not name.endswith('.pth'): + # We only care about the .pth files + continue + if name in ('easy-install.pth', 'setuptools.pth'): + # Ignore .pth files that we control + continue + + # Read the .pth file + f = open(os.path.join(dirname, name)) + lines = list(yield_lines(f)) + f.close() + + # Yield existing non-dupe, non-import directory lines from it + for line in lines: + if line.startswith("import"): + continue + + line = normalize_path(line.rstrip()) + if line in seen: + continue + + seen[line] = 1 + if not os.path.isdir(line): + continue + + yield line, os.listdir(line) + + +def extract_wininst_cfg(dist_filename): + """Extract configuration data from a bdist_wininst .exe + + Returns a configparser.RawConfigParser, or None + """ + f = open(dist_filename, 'rb') + try: + endrec = zipfile._EndRecData(f) + if endrec is None: + return None + + prepended = (endrec[9] - endrec[5]) - endrec[6] + if prepended < 12: # no wininst data here + return None + f.seek(prepended - 12) + + tag, cfglen, bmlen = struct.unpack("egg path translations for a given .exe file""" + + prefixes = [ + ('PURELIB/', ''), + ('PLATLIB/pywin32_system32', ''), + ('PLATLIB/', ''), + ('SCRIPTS/', 'EGG-INFO/scripts/'), + ('DATA/lib/site-packages', ''), + ] + z = zipfile.ZipFile(exe_filename) + try: + for info in z.infolist(): + name = info.filename + parts = name.split('/') + if len(parts) == 3 and parts[2] == 'PKG-INFO': + if parts[1].endswith('.egg-info'): + prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/')) + break + if len(parts) != 2 or not name.endswith('.pth'): + continue + if name.endswith('-nspkg.pth'): + continue + if parts[0].upper() in ('PURELIB', 'PLATLIB'): + contents = z.read(name).decode() + for pth in yield_lines(contents): + pth = pth.strip().replace('\\', '/') + if not pth.startswith('import'): + prefixes.append((('%s/%s/' % (parts[0], pth)), '')) + finally: + z.close() + prefixes = [(x.lower(), y) for x, y in prefixes] + prefixes.sort() + prefixes.reverse() + return prefixes + + +class PthDistributions(Environment): + """A .pth file with Distribution paths in it""" + + dirty = False + + def __init__(self, filename, sitedirs=()): + self.filename = filename + self.sitedirs = list(map(normalize_path, sitedirs)) + self.basedir = normalize_path(os.path.dirname(self.filename)) + self._load() + Environment.__init__(self, [], None, None) + for path in yield_lines(self.paths): + list(map(self.add, find_distributions(path, True))) + + def _load(self): + self.paths = [] + saw_import = False + seen = dict.fromkeys(self.sitedirs) + if os.path.isfile(self.filename): + f = open(self.filename, 'rt') + for line in f: + if line.startswith('import'): + saw_import = True + continue + path = line.rstrip() + self.paths.append(path) + if not path.strip() or path.strip().startswith('#'): + continue + # skip non-existent paths, in case somebody deleted a package + # manually, and duplicate paths as well + path = self.paths[-1] = normalize_path( + os.path.join(self.basedir, path) + ) + if not os.path.exists(path) or path in seen: + self.paths.pop() # skip it + self.dirty = True # we cleaned up, so we're dirty now :) + continue + seen[path] = 1 + f.close() + + if self.paths and not saw_import: + self.dirty = True # ensure anything we touch has import wrappers + while self.paths and not self.paths[-1].strip(): + self.paths.pop() + + def save(self): + """Write changed .pth file back to disk""" + if not self.dirty: + return + + rel_paths = list(map(self.make_relative, self.paths)) + if rel_paths: + log.debug("Saving %s", self.filename) + lines = self._wrap_lines(rel_paths) + data = '\n'.join(lines) + '\n' + + if os.path.islink(self.filename): + os.unlink(self.filename) + with open(self.filename, 'wt') as f: + f.write(data) + + elif os.path.exists(self.filename): + log.debug("Deleting empty %s", self.filename) + os.unlink(self.filename) + + self.dirty = False + + @staticmethod + def _wrap_lines(lines): + return lines + + def add(self, dist): + """Add `dist` to the distribution map""" + new_path = ( + dist.location not in self.paths and ( + dist.location not in self.sitedirs or + # account for '.' being in PYTHONPATH + dist.location == os.getcwd() + ) + ) + if new_path: + self.paths.append(dist.location) + self.dirty = True + Environment.add(self, dist) + + def remove(self, dist): + """Remove `dist` from the distribution map""" + while dist.location in self.paths: + self.paths.remove(dist.location) + self.dirty = True + Environment.remove(self, dist) + + def make_relative(self, path): + npath, last = os.path.split(normalize_path(path)) + baselen = len(self.basedir) + parts = [last] + sep = os.altsep == '/' and '/' or os.sep + while len(npath) >= baselen: + if npath == self.basedir: + parts.append(os.curdir) + parts.reverse() + return sep.join(parts) + npath, last = os.path.split(npath) + parts.append(last) + else: + return path + + +class RewritePthDistributions(PthDistributions): + @classmethod + def _wrap_lines(cls, lines): + yield cls.prelude + for line in lines: + yield line + yield cls.postlude + + prelude = _one_liner(""" + import sys + sys.__plen = len(sys.path) + """) + postlude = _one_liner(""" + import sys + new = sys.path[sys.__plen:] + del sys.path[sys.__plen:] + p = getattr(sys, '__egginsert', 0) + sys.path[p:p] = new + sys.__egginsert = p + len(new) + """) + + +if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite': + PthDistributions = RewritePthDistributions + + +def _first_line_re(): + """ + Return a regular expression based on first_line_re suitable for matching + strings. + """ + if isinstance(first_line_re.pattern, str): + return first_line_re + + # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern. + return re.compile(first_line_re.pattern.decode()) + + +def auto_chmod(func, arg, exc): + if func in [os.unlink, os.remove] and os.name == 'nt': + chmod(arg, stat.S_IWRITE) + return func(arg) + et, ev, _ = sys.exc_info() + # TODO: This code doesn't make sense. What is it trying to do? + raise (ev[0], ev[1] + (" %s %s" % (func, arg))) + + +def update_dist_caches(dist_path, fix_zipimporter_caches): + """ + Fix any globally cached `dist_path` related data + + `dist_path` should be a path of a newly installed egg distribution (zipped + or unzipped). + + sys.path_importer_cache contains finder objects that have been cached when + importing data from the original distribution. Any such finders need to be + cleared since the replacement distribution might be packaged differently, + e.g. a zipped egg distribution might get replaced with an unzipped egg + folder or vice versa. Having the old finders cached may then cause Python + to attempt loading modules from the replacement distribution using an + incorrect loader. + + zipimport.zipimporter objects are Python loaders charged with importing + data packaged inside zip archives. If stale loaders referencing the + original distribution, are left behind, they can fail to load modules from + the replacement distribution. E.g. if an old zipimport.zipimporter instance + is used to load data from a new zipped egg archive, it may cause the + operation to attempt to locate the requested data in the wrong location - + one indicated by the original distribution's zip archive directory + information. Such an operation may then fail outright, e.g. report having + read a 'bad local file header', or even worse, it may fail silently & + return invalid data. + + zipimport._zip_directory_cache contains cached zip archive directory + information for all existing zipimport.zipimporter instances and all such + instances connected to the same archive share the same cached directory + information. + + If asked, and the underlying Python implementation allows it, we can fix + all existing zipimport.zipimporter instances instead of having to track + them down and remove them one by one, by updating their shared cached zip + archive directory information. This, of course, assumes that the + replacement distribution is packaged as a zipped egg. + + If not asked to fix existing zipimport.zipimporter instances, we still do + our best to clear any remaining zipimport.zipimporter related cached data + that might somehow later get used when attempting to load data from the new + distribution and thus cause such load operations to fail. Note that when + tracking down such remaining stale data, we can not catch every conceivable + usage from here, and we clear only those that we know of and have found to + cause problems if left alive. Any remaining caches should be updated by + whomever is in charge of maintaining them, i.e. they should be ready to + handle us replacing their zip archives with new distributions at runtime. + + """ + # There are several other known sources of stale zipimport.zipimporter + # instances that we do not clear here, but might if ever given a reason to + # do so: + # * Global setuptools pkg_resources.working_set (a.k.a. 'master working + # set') may contain distributions which may in turn contain their + # zipimport.zipimporter loaders. + # * Several zipimport.zipimporter loaders held by local variables further + # up the function call stack when running the setuptools installation. + # * Already loaded modules may have their __loader__ attribute set to the + # exact loader instance used when importing them. Python 3.4 docs state + # that this information is intended mostly for introspection and so is + # not expected to cause us problems. + normalized_path = normalize_path(dist_path) + _uncache(normalized_path, sys.path_importer_cache) + if fix_zipimporter_caches: + _replace_zip_directory_cache_data(normalized_path) + else: + # Here, even though we do not want to fix existing and now stale + # zipimporter cache information, we still want to remove it. Related to + # Python's zip archive directory information cache, we clear each of + # its stale entries in two phases: + # 1. Clear the entry so attempting to access zip archive information + # via any existing stale zipimport.zipimporter instances fails. + # 2. Remove the entry from the cache so any newly constructed + # zipimport.zipimporter instances do not end up using old stale + # zip archive directory information. + # This whole stale data removal step does not seem strictly necessary, + # but has been left in because it was done before we started replacing + # the zip archive directory information cache content if possible, and + # there are no relevant unit tests that we can depend on to tell us if + # this is really needed. + _remove_and_clear_zip_directory_cache_data(normalized_path) + + +def _collect_zipimporter_cache_entries(normalized_path, cache): + """ + Return zipimporter cache entry keys related to a given normalized path. + + Alternative path spellings (e.g. those using different character case or + those using alternative path separators) related to the same path are + included. Any sub-path entries are included as well, i.e. those + corresponding to zip archives embedded in other zip archives. + + """ + result = [] + prefix_len = len(normalized_path) + for p in cache: + np = normalize_path(p) + if (np.startswith(normalized_path) and + np[prefix_len:prefix_len + 1] in (os.sep, '')): + result.append(p) + return result + + +def _update_zipimporter_cache(normalized_path, cache, updater=None): + """ + Update zipimporter cache data for a given normalized path. + + Any sub-path entries are processed as well, i.e. those corresponding to zip + archives embedded in other zip archives. + + Given updater is a callable taking a cache entry key and the original entry + (after already removing the entry from the cache), and expected to update + the entry and possibly return a new one to be inserted in its place. + Returning None indicates that the entry should not be replaced with a new + one. If no updater is given, the cache entries are simply removed without + any additional processing, the same as if the updater simply returned None. + + """ + for p in _collect_zipimporter_cache_entries(normalized_path, cache): + # N.B. pypy's custom zipimport._zip_directory_cache implementation does + # not support the complete dict interface: + # * Does not support item assignment, thus not allowing this function + # to be used only for removing existing cache entries. + # * Does not support the dict.pop() method, forcing us to use the + # get/del patterns instead. For more detailed information see the + # following links: + # https://github.com/pypa/setuptools/issues/202#issuecomment-202913420 + # http://bit.ly/2h9itJX + old_entry = cache[p] + del cache[p] + new_entry = updater and updater(p, old_entry) + if new_entry is not None: + cache[p] = new_entry + + +def _uncache(normalized_path, cache): + _update_zipimporter_cache(normalized_path, cache) + + +def _remove_and_clear_zip_directory_cache_data(normalized_path): + def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): + old_entry.clear() + + _update_zipimporter_cache( + normalized_path, zipimport._zip_directory_cache, + updater=clear_and_remove_cached_zip_archive_directory_data) + + +# PyPy Python implementation does not allow directly writing to the +# zipimport._zip_directory_cache and so prevents us from attempting to correct +# its content. The best we can do there is clear the problematic cache content +# and have PyPy repopulate it as needed. The downside is that if there are any +# stale zipimport.zipimporter instances laying around, attempting to use them +# will fail due to not having its zip archive directory information available +# instead of being automatically corrected to use the new correct zip archive +# directory information. +if '__pypy__' in sys.builtin_module_names: + _replace_zip_directory_cache_data = \ + _remove_and_clear_zip_directory_cache_data +else: + + def _replace_zip_directory_cache_data(normalized_path): + def replace_cached_zip_archive_directory_data(path, old_entry): + # N.B. In theory, we could load the zip directory information just + # once for all updated path spellings, and then copy it locally and + # update its contained path strings to contain the correct + # spelling, but that seems like a way too invasive move (this cache + # structure is not officially documented anywhere and could in + # theory change with new Python releases) for no significant + # benefit. + old_entry.clear() + zipimport.zipimporter(path) + old_entry.update(zipimport._zip_directory_cache[path]) + return old_entry + + _update_zipimporter_cache( + normalized_path, zipimport._zip_directory_cache, + updater=replace_cached_zip_archive_directory_data) + + +def is_python(text, filename=''): + "Is this string a valid Python script?" + try: + compile(text, filename, 'exec') + except (SyntaxError, TypeError): + return False + else: + return True + + +def is_sh(executable): + """Determine if the specified executable is a .sh (contains a #! line)""" + try: + with io.open(executable, encoding='latin-1') as fp: + magic = fp.read(2) + except (OSError, IOError): + return executable + return magic == '#!' + + +def nt_quote_arg(arg): + """Quote a command line argument according to Windows parsing rules""" + return subprocess.list2cmdline([arg]) + + +def is_python_script(script_text, filename): + """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. + """ + if filename.endswith('.py') or filename.endswith('.pyw'): + return True # extension says it's Python + if is_python(script_text, filename): + return True # it's syntactically valid Python + if script_text.startswith('#!'): + # It begins with a '#!' line, so check if 'python' is in it somewhere + return 'python' in script_text.splitlines()[0].lower() + + return False # Not any Python I can recognize + + +try: + from os import chmod as _chmod +except ImportError: + # Jython compatibility + def _chmod(*args): + pass + + +def chmod(path, mode): + log.debug("changing mode of %s to %o", path, mode) + try: + _chmod(path, mode) + except os.error as e: + log.debug("chmod failed: %s", e) + + +class CommandSpec(list): + """ + A command spec for a #! header, specified as a list of arguments akin to + those passed to Popen. + """ + + options = [] + split_args = dict() + + @classmethod + def best(cls): + """ + Choose the best CommandSpec class based on environmental conditions. + """ + return cls + + @classmethod + def _sys_executable(cls): + _default = os.path.normpath(sys.executable) + return os.environ.get('__PYVENV_LAUNCHER__', _default) + + @classmethod + def from_param(cls, param): + """ + Construct a CommandSpec from a parameter to build_scripts, which may + be None. + """ + if isinstance(param, cls): + return param + if isinstance(param, list): + return cls(param) + if param is None: + return cls.from_environment() + # otherwise, assume it's a string. + return cls.from_string(param) + + @classmethod + def from_environment(cls): + return cls([cls._sys_executable()]) + + @classmethod + def from_string(cls, string): + """ + Construct a command spec from a simple string representing a command + line parseable by shlex.split. + """ + items = shlex.split(string, **cls.split_args) + return cls(items) + + def install_options(self, script_text): + self.options = shlex.split(self._extract_options(script_text)) + cmdline = subprocess.list2cmdline(self) + if not isascii(cmdline): + self.options[:0] = ['-x'] + + @staticmethod + def _extract_options(orig_script): + """ + Extract any options from the first line of the script. + """ + first = (orig_script + '\n').splitlines()[0] + match = _first_line_re().match(first) + options = match.group(1) or '' if match else '' + return options.strip() + + def as_header(self): + return self._render(self + list(self.options)) + + @staticmethod + def _strip_quotes(item): + _QUOTES = '"\'' + for q in _QUOTES: + if item.startswith(q) and item.endswith(q): + return item[1:-1] + return item + + @staticmethod + def _render(items): + cmdline = subprocess.list2cmdline( + CommandSpec._strip_quotes(item.strip()) for item in items) + return '#!' + cmdline + '\n' + + +# For pbr compat; will be removed in a future version. +sys_executable = CommandSpec._sys_executable() + + +class WindowsCommandSpec(CommandSpec): + split_args = dict(posix=False) + + +class ScriptWriter: + """ + Encapsulates behavior around writing entry point scripts for console and + gui apps. + """ + + template = textwrap.dedent(r""" + # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r + import re + import sys + + # for compatibility with easy_install; see #2198 + __requires__ = %(spec)r + + try: + from importlib.metadata import distribution + except ImportError: + try: + from importlib_metadata import distribution + except ImportError: + from pkg_resources import load_entry_point + + + def importlib_load_entry_point(spec, group, name): + dist_name, _, _ = spec.partition('==') + matches = ( + entry_point + for entry_point in distribution(dist_name).entry_points + if entry_point.group == group and entry_point.name == name + ) + return next(matches).load() + + + globals().setdefault('load_entry_point', importlib_load_entry_point) + + + if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(load_entry_point(%(spec)r, %(group)r, %(name)r)()) + """).lstrip() + + command_spec_class = CommandSpec + + @classmethod + def get_script_args(cls, dist, executable=None, wininst=False): + # for backward compatibility + warnings.warn("Use get_args", EasyInstallDeprecationWarning) + writer = (WindowsScriptWriter if wininst else ScriptWriter).best() + header = cls.get_script_header("", executable, wininst) + return writer.get_args(dist, header) + + @classmethod + def get_script_header(cls, script_text, executable=None, wininst=False): + # for backward compatibility + warnings.warn( + "Use get_header", EasyInstallDeprecationWarning, stacklevel=2) + if wininst: + executable = "python.exe" + return cls.get_header(script_text, executable) + + @classmethod + def get_args(cls, dist, header=None): + """ + Yield write_script() argument tuples for a distribution's + console_scripts and gui_scripts entry points. + """ + if header is None: + header = cls.get_header() + spec = str(dist.as_requirement()) + for type_ in 'console', 'gui': + group = type_ + '_scripts' + for name, ep in dist.get_entry_map(group).items(): + cls._ensure_safe_name(name) + script_text = cls.template % locals() + args = cls._get_script_args(type_, name, header, script_text) + for res in args: + yield res + + @staticmethod + def _ensure_safe_name(name): + """ + Prevent paths in *_scripts entry point names. + """ + has_path_sep = re.search(r'[\\/]', name) + if has_path_sep: + raise ValueError("Path separators not allowed in script names") + + @classmethod + def get_writer(cls, force_windows): + # for backward compatibility + warnings.warn("Use best", EasyInstallDeprecationWarning) + return WindowsScriptWriter.best() if force_windows else cls.best() + + @classmethod + def best(cls): + """ + Select the best ScriptWriter for this environment. + """ + if sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt'): + return WindowsScriptWriter.best() + else: + return cls + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + # Simply write the stub with no extension. + yield (name, header + script_text) + + @classmethod + def get_header(cls, script_text="", executable=None): + """Create a #! line, getting options (if any) from script_text""" + cmd = cls.command_spec_class.best().from_param(executable) + cmd.install_options(script_text) + return cmd.as_header() + + +class WindowsScriptWriter(ScriptWriter): + command_spec_class = WindowsCommandSpec + + @classmethod + def get_writer(cls): + # for backward compatibility + warnings.warn("Use best", EasyInstallDeprecationWarning) + return cls.best() + + @classmethod + def best(cls): + """ + Select the best ScriptWriter suitable for Windows + """ + writer_lookup = dict( + executable=WindowsExecutableLauncherWriter, + natural=cls, + ) + # for compatibility, use the executable launcher by default + launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable') + return writer_lookup[launcher] + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + "For Windows, add a .py extension" + ext = dict(console='.pya', gui='.pyw')[type_] + if ext not in os.environ['PATHEXT'].lower().split(';'): + msg = ( + "{ext} not listed in PATHEXT; scripts will not be " + "recognized as executables." + ).format(**locals()) + warnings.warn(msg, UserWarning) + old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] + old.remove(ext) + header = cls._adjust_header(type_, header) + blockers = [name + x for x in old] + yield name + ext, header + script_text, 't', blockers + + @classmethod + def _adjust_header(cls, type_, orig_header): + """ + Make sure 'pythonw' is used for gui and 'python' is used for + console (regardless of what sys.executable is). + """ + pattern = 'pythonw.exe' + repl = 'python.exe' + if type_ == 'gui': + pattern, repl = repl, pattern + pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE) + new_header = pattern_ob.sub(string=orig_header, repl=repl) + return new_header if cls._use_header(new_header) else orig_header + + @staticmethod + def _use_header(new_header): + """ + Should _adjust_header use the replaced header? + + On non-windows systems, always use. On + Windows systems, only use the replaced header if it resolves + to an executable on the system. + """ + clean_header = new_header[2:-1].strip('"') + return sys.platform != 'win32' or find_executable(clean_header) + + +class WindowsExecutableLauncherWriter(WindowsScriptWriter): + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + """ + For Windows, add a .py extension and an .exe launcher + """ + if type_ == 'gui': + launcher_type = 'gui' + ext = '-script.pyw' + old = ['.pyw'] + else: + launcher_type = 'cli' + ext = '-script.py' + old = ['.py', '.pyc', '.pyo'] + hdr = cls._adjust_header(type_, header) + blockers = [name + x for x in old] + yield (name + ext, hdr + script_text, 't', blockers) + yield ( + name + '.exe', get_win_launcher(launcher_type), + 'b' # write in binary mode + ) + if not is_64bit(): + # install a manifest for the launcher to prevent Windows + # from detecting it as an installer (which it will for + # launchers like easy_install.exe). Consider only + # adding a manifest for launchers detected as installers. + # See Distribute #143 for details. + m_name = name + '.exe.manifest' + yield (m_name, load_launcher_manifest(name), 't') + + +# for backward-compatibility +get_script_args = ScriptWriter.get_script_args +get_script_header = ScriptWriter.get_script_header + + +def get_win_launcher(type): + """ + Load the Windows launcher (executable) suitable for launching a script. + + `type` should be either 'cli' or 'gui' + + Returns the executable as a byte string. + """ + launcher_fn = '%s.exe' % type + if is_64bit(): + launcher_fn = launcher_fn.replace(".", "-64.") + else: + launcher_fn = launcher_fn.replace(".", "-32.") + return resource_string('setuptools', launcher_fn) + + +def load_launcher_manifest(name): + manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml') + return manifest.decode('utf-8') % vars() + + +def rmtree(path, ignore_errors=False, onerror=auto_chmod): + return shutil.rmtree(path, ignore_errors, onerror) + + +def current_umask(): + tmp = os.umask(0o022) + os.umask(tmp) + return tmp + + +class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning): + """ + Warning for EasyInstall deprecations, bypassing suppression. + """ diff --git a/MLPY/Lib/site-packages/setuptools/command/egg_info.py b/MLPY/Lib/site-packages/setuptools/command/egg_info.py new file mode 100644 index 0000000000000000000000000000000000000000..18b81340a7f74b2762db3b2db6b1ab1414df01ca --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/egg_info.py @@ -0,0 +1,734 @@ +"""setuptools.command.egg_info + +Create a distribution's .egg-info directory and contents""" + +from distutils.filelist import FileList as _FileList +from distutils.errors import DistutilsInternalError +from distutils.util import convert_path +from distutils import log +import distutils.errors +import distutils.filelist +import functools +import os +import re +import sys +import io +import warnings +import time +import collections + +from setuptools import Command +from setuptools.command.sdist import sdist +from setuptools.command.sdist import walk_revctrl +from setuptools.command.setopt import edit_config +from setuptools.command import bdist_egg +from pkg_resources import ( + parse_requirements, safe_name, parse_version, + safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) +import setuptools.unicode_utils as unicode_utils +from setuptools.glob import glob + +from setuptools.extern import packaging +from setuptools import SetuptoolsDeprecationWarning + + +def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME + """ + Translate a file path glob like '*.txt' in to a regular expression. + This differs from fnmatch.translate which allows wildcards to match + directory separators. It also knows about '**/' which matches any number of + directories. + """ + pat = '' + + # This will split on '/' within [character classes]. This is deliberate. + chunks = glob.split(os.path.sep) + + sep = re.escape(os.sep) + valid_char = '[^%s]' % (sep,) + + for c, chunk in enumerate(chunks): + last_chunk = c == len(chunks) - 1 + + # Chunks that are a literal ** are globstars. They match anything. + if chunk == '**': + if last_chunk: + # Match anything if this is the last component + pat += '.*' + else: + # Match '(name/)*' + pat += '(?:%s+%s)*' % (valid_char, sep) + continue # Break here as the whole path component has been handled + + # Find any special characters in the remainder + i = 0 + chunk_len = len(chunk) + while i < chunk_len: + char = chunk[i] + if char == '*': + # Match any number of name characters + pat += valid_char + '*' + elif char == '?': + # Match a name character + pat += valid_char + elif char == '[': + # Character class + inner_i = i + 1 + # Skip initial !/] chars + if inner_i < chunk_len and chunk[inner_i] == '!': + inner_i = inner_i + 1 + if inner_i < chunk_len and chunk[inner_i] == ']': + inner_i = inner_i + 1 + + # Loop till the closing ] is found + while inner_i < chunk_len and chunk[inner_i] != ']': + inner_i = inner_i + 1 + + if inner_i >= chunk_len: + # Got to the end of the string without finding a closing ] + # Do not treat this as a matching group, but as a literal [ + pat += re.escape(char) + else: + # Grab the insides of the [brackets] + inner = chunk[i + 1:inner_i] + char_class = '' + + # Class negation + if inner[0] == '!': + char_class = '^' + inner = inner[1:] + + char_class += re.escape(inner) + pat += '[%s]' % (char_class,) + + # Skip to the end ] + i = inner_i + else: + pat += re.escape(char) + i += 1 + + # Join each chunk with the dir separator + if not last_chunk: + pat += sep + + pat += r'\Z' + return re.compile(pat, flags=re.MULTILINE | re.DOTALL) + + +class InfoCommon: + tag_build = None + tag_date = None + + @property + def name(self): + return safe_name(self.distribution.get_name()) + + def tagged_version(self): + return safe_version(self._maybe_tag(self.distribution.get_version())) + + def _maybe_tag(self, version): + """ + egg_info may be called more than once for a distribution, + in which case the version string already contains all tags. + """ + return ( + version if self.vtags and version.endswith(self.vtags) + else version + self.vtags + ) + + def tags(self): + version = '' + if self.tag_build: + version += self.tag_build + if self.tag_date: + version += time.strftime("-%Y%m%d") + return version + vtags = property(tags) + + +class egg_info(InfoCommon, Command): + description = "create a distribution's .egg-info directory" + + user_options = [ + ('egg-base=', 'e', "directory containing .egg-info directories" + " (default: top of the source tree)"), + ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), + ('tag-build=', 'b', "Specify explicit tag to add to version number"), + ('no-date', 'D', "Don't include date stamp [default]"), + ] + + boolean_options = ['tag-date'] + negative_opt = { + 'no-date': 'tag-date', + } + + def initialize_options(self): + self.egg_base = None + self.egg_name = None + self.egg_info = None + self.egg_version = None + self.broken_egg_info = False + + #################################### + # allow the 'tag_svn_revision' to be detected and + # set, supporting sdists built on older Setuptools. + @property + def tag_svn_revision(self): + pass + + @tag_svn_revision.setter + def tag_svn_revision(self, value): + pass + #################################### + + def save_version_info(self, filename): + """ + Materialize the value of date into the + build tag. Install build keys in a deterministic order + to avoid arbitrary reordering on subsequent builds. + """ + egg_info = collections.OrderedDict() + # follow the order these keys would have been added + # when PYTHONHASHSEED=0 + egg_info['tag_build'] = self.tags() + egg_info['tag_date'] = 0 + edit_config(filename, dict(egg_info=egg_info)) + + def finalize_options(self): + # Note: we need to capture the current value returned + # by `self.tagged_version()`, so we can later update + # `self.distribution.metadata.version` without + # repercussions. + self.egg_name = self.name + self.egg_version = self.tagged_version() + parsed_version = parse_version(self.egg_version) + + try: + is_version = isinstance(parsed_version, packaging.version.Version) + spec = ( + "%s==%s" if is_version else "%s===%s" + ) + list( + parse_requirements(spec % (self.egg_name, self.egg_version)) + ) + except ValueError as e: + raise distutils.errors.DistutilsOptionError( + "Invalid distribution name or version syntax: %s-%s" % + (self.egg_name, self.egg_version) + ) from e + + if self.egg_base is None: + dirs = self.distribution.package_dir + self.egg_base = (dirs or {}).get('', os.curdir) + + self.ensure_dirname('egg_base') + self.egg_info = to_filename(self.egg_name) + '.egg-info' + if self.egg_base != os.curdir: + self.egg_info = os.path.join(self.egg_base, self.egg_info) + if '-' in self.egg_name: + self.check_broken_egg_info() + + # Set package version for the benefit of dumber commands + # (e.g. sdist, bdist_wininst, etc.) + # + self.distribution.metadata.version = self.egg_version + + # If we bootstrapped around the lack of a PKG-INFO, as might be the + # case in a fresh checkout, make sure that any special tags get added + # to the version info + # + pd = self.distribution._patched_dist + if pd is not None and pd.key == self.egg_name.lower(): + pd._version = self.egg_version + pd._parsed_version = parse_version(self.egg_version) + self.distribution._patched_dist = None + + def write_or_delete_file(self, what, filename, data, force=False): + """Write `data` to `filename` or delete if empty + + If `data` is non-empty, this routine is the same as ``write_file()``. + If `data` is empty but not ``None``, this is the same as calling + ``delete_file(filename)`. If `data` is ``None``, then this is a no-op + unless `filename` exists, in which case a warning is issued about the + orphaned file (if `force` is false), or deleted (if `force` is true). + """ + if data: + self.write_file(what, filename, data) + elif os.path.exists(filename): + if data is None and not force: + log.warn( + "%s not set in setup(), but %s exists", what, filename + ) + return + else: + self.delete_file(filename) + + def write_file(self, what, filename, data): + """Write `data` to `filename` (if not a dry run) after announcing it + + `what` is used in a log message to identify what is being written + to the file. + """ + log.info("writing %s to %s", what, filename) + data = data.encode("utf-8") + if not self.dry_run: + f = open(filename, 'wb') + f.write(data) + f.close() + + def delete_file(self, filename): + """Delete `filename` (if not a dry run) after announcing it""" + log.info("deleting %s", filename) + if not self.dry_run: + os.unlink(filename) + + def run(self): + self.mkpath(self.egg_info) + os.utime(self.egg_info, None) + installer = self.distribution.fetch_build_egg + for ep in iter_entry_points('egg_info.writers'): + ep.require(installer=installer) + writer = ep.resolve() + writer(self, ep.name, os.path.join(self.egg_info, ep.name)) + + # Get rid of native_libs.txt if it was put there by older bdist_egg + nl = os.path.join(self.egg_info, "native_libs.txt") + if os.path.exists(nl): + self.delete_file(nl) + + self.find_sources() + + def find_sources(self): + """Generate SOURCES.txt manifest file""" + manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") + mm = manifest_maker(self.distribution) + mm.manifest = manifest_filename + mm.run() + self.filelist = mm.filelist + + def check_broken_egg_info(self): + bei = self.egg_name + '.egg-info' + if self.egg_base != os.curdir: + bei = os.path.join(self.egg_base, bei) + if os.path.exists(bei): + log.warn( + "-" * 78 + '\n' + "Note: Your current .egg-info directory has a '-' in its name;" + '\nthis will not work correctly with "setup.py develop".\n\n' + 'Please rename %s to %s to correct this problem.\n' + '-' * 78, + bei, self.egg_info + ) + self.broken_egg_info = self.egg_info + self.egg_info = bei # make it work for now + + +class FileList(_FileList): + # Implementations of the various MANIFEST.in commands + + def process_template_line(self, line): + # Parse the line: split it up, make sure the right number of words + # is there, and return the relevant words. 'action' is always + # defined: it's the first word of the line. Which of the other + # three are defined depends on the action; it'll be either + # patterns, (dir and patterns), or (dir_pattern). + (action, patterns, dir, dir_pattern) = self._parse_template_line(line) + + action_map = { + 'include': self.include, + 'exclude': self.exclude, + 'global-include': self.global_include, + 'global-exclude': self.global_exclude, + 'recursive-include': functools.partial( + self.recursive_include, dir, + ), + 'recursive-exclude': functools.partial( + self.recursive_exclude, dir, + ), + 'graft': self.graft, + 'prune': self.prune, + } + log_map = { + 'include': "warning: no files found matching '%s'", + 'exclude': ( + "warning: no previously-included files found " + "matching '%s'" + ), + 'global-include': ( + "warning: no files found matching '%s' " + "anywhere in distribution" + ), + 'global-exclude': ( + "warning: no previously-included files matching " + "'%s' found anywhere in distribution" + ), + 'recursive-include': ( + "warning: no files found matching '%s' " + "under directory '%s'" + ), + 'recursive-exclude': ( + "warning: no previously-included files matching " + "'%s' found under directory '%s'" + ), + 'graft': "warning: no directories found matching '%s'", + 'prune': "no previously-included directories found matching '%s'", + } + + try: + process_action = action_map[action] + except KeyError: + raise DistutilsInternalError( + "this cannot happen: invalid action '{action!s}'". + format(action=action), + ) + + # OK, now we know that the action is valid and we have the + # right number of words on the line for that action -- so we + # can proceed with minimal error-checking. + + action_is_recursive = action.startswith('recursive-') + if action in {'graft', 'prune'}: + patterns = [dir_pattern] + extra_log_args = (dir, ) if action_is_recursive else () + log_tmpl = log_map[action] + + self.debug_print( + ' '.join( + [action] + + ([dir] if action_is_recursive else []) + + patterns, + ) + ) + for pattern in patterns: + if not process_action(pattern): + log.warn(log_tmpl, pattern, *extra_log_args) + + def _remove_files(self, predicate): + """ + Remove all files from the file list that match the predicate. + Return True if any matching files were removed + """ + found = False + for i in range(len(self.files) - 1, -1, -1): + if predicate(self.files[i]): + self.debug_print(" removing " + self.files[i]) + del self.files[i] + found = True + return found + + def include(self, pattern): + """Include files that match 'pattern'.""" + found = [f for f in glob(pattern) if not os.path.isdir(f)] + self.extend(found) + return bool(found) + + def exclude(self, pattern): + """Exclude files that match 'pattern'.""" + match = translate_pattern(pattern) + return self._remove_files(match.match) + + def recursive_include(self, dir, pattern): + """ + Include all files anywhere in 'dir/' that match the pattern. + """ + full_pattern = os.path.join(dir, '**', pattern) + found = [f for f in glob(full_pattern, recursive=True) + if not os.path.isdir(f)] + self.extend(found) + return bool(found) + + def recursive_exclude(self, dir, pattern): + """ + Exclude any file anywhere in 'dir/' that match the pattern. + """ + match = translate_pattern(os.path.join(dir, '**', pattern)) + return self._remove_files(match.match) + + def graft(self, dir): + """Include all files from 'dir/'.""" + found = [ + item + for match_dir in glob(dir) + for item in distutils.filelist.findall(match_dir) + ] + self.extend(found) + return bool(found) + + def prune(self, dir): + """Filter out files from 'dir/'.""" + match = translate_pattern(os.path.join(dir, '**')) + return self._remove_files(match.match) + + def global_include(self, pattern): + """ + Include all files anywhere in the current directory that match the + pattern. This is very inefficient on large file trees. + """ + if self.allfiles is None: + self.findall() + match = translate_pattern(os.path.join('**', pattern)) + found = [f for f in self.allfiles if match.match(f)] + self.extend(found) + return bool(found) + + def global_exclude(self, pattern): + """ + Exclude all files anywhere that match the pattern. + """ + match = translate_pattern(os.path.join('**', pattern)) + return self._remove_files(match.match) + + def append(self, item): + if item.endswith('\r'): # Fix older sdists built on Windows + item = item[:-1] + path = convert_path(item) + + if self._safe_path(path): + self.files.append(path) + + def extend(self, paths): + self.files.extend(filter(self._safe_path, paths)) + + def _repair(self): + """ + Replace self.files with only safe paths + + Because some owners of FileList manipulate the underlying + ``files`` attribute directly, this method must be called to + repair those paths. + """ + self.files = list(filter(self._safe_path, self.files)) + + def _safe_path(self, path): + enc_warn = "'%s' not %s encodable -- skipping" + + # To avoid accidental trans-codings errors, first to unicode + u_path = unicode_utils.filesys_decode(path) + if u_path is None: + log.warn("'%s' in unexpected encoding -- skipping" % path) + return False + + # Must ensure utf-8 encodability + utf8_path = unicode_utils.try_encode(u_path, "utf-8") + if utf8_path is None: + log.warn(enc_warn, path, 'utf-8') + return False + + try: + # accept is either way checks out + if os.path.exists(u_path) or os.path.exists(utf8_path): + return True + # this will catch any encode errors decoding u_path + except UnicodeEncodeError: + log.warn(enc_warn, path, sys.getfilesystemencoding()) + + +class manifest_maker(sdist): + template = "MANIFEST.in" + + def initialize_options(self): + self.use_defaults = 1 + self.prune = 1 + self.manifest_only = 1 + self.force_manifest = 1 + + def finalize_options(self): + pass + + def run(self): + self.filelist = FileList() + if not os.path.exists(self.manifest): + self.write_manifest() # it must exist so it'll get in the list + self.add_defaults() + if os.path.exists(self.template): + self.read_template() + self.add_license_files() + self.prune_file_list() + self.filelist.sort() + self.filelist.remove_duplicates() + self.write_manifest() + + def _manifest_normalize(self, path): + path = unicode_utils.filesys_decode(path) + return path.replace(os.sep, '/') + + def write_manifest(self): + """ + Write the file list in 'self.filelist' to the manifest file + named by 'self.manifest'. + """ + self.filelist._repair() + + # Now _repairs should encodability, but not unicode + files = [self._manifest_normalize(f) for f in self.filelist.files] + msg = "writing manifest file '%s'" % self.manifest + self.execute(write_file, (self.manifest, files), msg) + + def warn(self, msg): + if not self._should_suppress_warning(msg): + sdist.warn(self, msg) + + @staticmethod + def _should_suppress_warning(msg): + """ + suppress missing-file warnings from sdist + """ + return re.match(r"standard file .*not found", msg) + + def add_defaults(self): + sdist.add_defaults(self) + self.filelist.append(self.template) + self.filelist.append(self.manifest) + rcfiles = list(walk_revctrl()) + if rcfiles: + self.filelist.extend(rcfiles) + elif os.path.exists(self.manifest): + self.read_manifest() + + if os.path.exists("setup.py"): + # setup.py should be included by default, even if it's not + # the script called to create the sdist + self.filelist.append("setup.py") + + ei_cmd = self.get_finalized_command('egg_info') + self.filelist.graft(ei_cmd.egg_info) + + def add_license_files(self): + license_files = self.distribution.metadata.license_files or [] + for lf in license_files: + log.info("adding license file '%s'", lf) + pass + self.filelist.extend(license_files) + + def prune_file_list(self): + build = self.get_finalized_command('build') + base_dir = self.distribution.get_fullname() + self.filelist.prune(build.build_base) + self.filelist.prune(base_dir) + sep = re.escape(os.sep) + self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, + is_regex=1) + + +def write_file(filename, contents): + """Create a file with the specified name and write 'contents' (a + sequence of strings without line terminators) to it. + """ + contents = "\n".join(contents) + + # assuming the contents has been vetted for utf-8 encoding + contents = contents.encode("utf-8") + + with open(filename, "wb") as f: # always write POSIX-style manifest + f.write(contents) + + +def write_pkg_info(cmd, basename, filename): + log.info("writing %s", filename) + if not cmd.dry_run: + metadata = cmd.distribution.metadata + metadata.version, oldver = cmd.egg_version, metadata.version + metadata.name, oldname = cmd.egg_name, metadata.name + + try: + # write unescaped data to PKG-INFO, so older pkg_resources + # can still parse it + metadata.write_pkg_info(cmd.egg_info) + finally: + metadata.name, metadata.version = oldname, oldver + + safe = getattr(cmd.distribution, 'zip_safe', None) + + bdist_egg.write_safety_flag(cmd.egg_info, safe) + + +def warn_depends_obsolete(cmd, basename, filename): + if os.path.exists(filename): + log.warn( + "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" + "Use the install_requires/extras_require setup() args instead." + ) + + +def _write_requirements(stream, reqs): + lines = yield_lines(reqs or ()) + + def append_cr(line): + return line + '\n' + lines = map(append_cr, lines) + stream.writelines(lines) + + +def write_requirements(cmd, basename, filename): + dist = cmd.distribution + data = io.StringIO() + _write_requirements(data, dist.install_requires) + extras_require = dist.extras_require or {} + for extra in sorted(extras_require): + data.write('\n[{extra}]\n'.format(**vars())) + _write_requirements(data, extras_require[extra]) + cmd.write_or_delete_file("requirements", filename, data.getvalue()) + + +def write_setup_requirements(cmd, basename, filename): + data = io.StringIO() + _write_requirements(data, cmd.distribution.setup_requires) + cmd.write_or_delete_file("setup-requirements", filename, data.getvalue()) + + +def write_toplevel_names(cmd, basename, filename): + pkgs = dict.fromkeys( + [ + k.split('.', 1)[0] + for k in cmd.distribution.iter_distribution_names() + ] + ) + cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n') + + +def overwrite_arg(cmd, basename, filename): + write_arg(cmd, basename, filename, True) + + +def write_arg(cmd, basename, filename, force=False): + argname = os.path.splitext(basename)[0] + value = getattr(cmd.distribution, argname, None) + if value is not None: + value = '\n'.join(value) + '\n' + cmd.write_or_delete_file(argname, filename, value, force) + + +def write_entries(cmd, basename, filename): + ep = cmd.distribution.entry_points + + if isinstance(ep, str) or ep is None: + data = ep + elif ep is not None: + data = [] + for section, contents in sorted(ep.items()): + if not isinstance(contents, str): + contents = EntryPoint.parse_group(section, contents) + contents = '\n'.join(sorted(map(str, contents.values()))) + data.append('[%s]\n%s\n\n' % (section, contents)) + data = ''.join(data) + + cmd.write_or_delete_file('entry points', filename, data, True) + + +def get_pkg_info_revision(): + """ + Get a -r### off of PKG-INFO Version in case this is an sdist of + a subversion revision. + """ + warnings.warn( + "get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning) + if os.path.exists('PKG-INFO'): + with io.open('PKG-INFO') as f: + for line in f: + match = re.match(r"Version:.*-r(\d+)\s*$", line) + if match: + return int(match.group(1)) + return 0 + + +class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning): + """Deprecated behavior warning for EggInfo, bypassing suppression.""" diff --git a/MLPY/Lib/site-packages/setuptools/command/install.py b/MLPY/Lib/site-packages/setuptools/command/install.py new file mode 100644 index 0000000000000000000000000000000000000000..72b9a3e424707633c7e31a347170f358cfa3f87a --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/install.py @@ -0,0 +1,125 @@ +from distutils.errors import DistutilsArgError +import inspect +import glob +import warnings +import platform +import distutils.command.install as orig + +import setuptools + +# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for +# now. See https://github.com/pypa/setuptools/issues/199/ +_install = orig.install + + +class install(orig.install): + """Use easy_install to install the package, w/dependencies""" + + user_options = orig.install.user_options + [ + ('old-and-unmanageable', None, "Try not to use this!"), + ('single-version-externally-managed', None, + "used by system package builders to create 'flat' eggs"), + ] + boolean_options = orig.install.boolean_options + [ + 'old-and-unmanageable', 'single-version-externally-managed', + ] + new_commands = [ + ('install_egg_info', lambda self: True), + ('install_scripts', lambda self: True), + ] + _nc = dict(new_commands) + + def initialize_options(self): + orig.install.initialize_options(self) + self.old_and_unmanageable = None + self.single_version_externally_managed = None + + def finalize_options(self): + orig.install.finalize_options(self) + if self.root: + self.single_version_externally_managed = True + elif self.single_version_externally_managed: + if not self.root and not self.record: + raise DistutilsArgError( + "You must specify --record or --root when building system" + " packages" + ) + + def handle_extra_path(self): + if self.root or self.single_version_externally_managed: + # explicit backward-compatibility mode, allow extra_path to work + return orig.install.handle_extra_path(self) + + # Ignore extra_path when installing an egg (or being run by another + # command without --root or --single-version-externally-managed + self.path_file = None + self.extra_dirs = '' + + def run(self): + # Explicit request for old-style install? Just do it + if self.old_and_unmanageable or self.single_version_externally_managed: + return orig.install.run(self) + + if not self._called_from_setup(inspect.currentframe()): + # Run in backward-compatibility mode to support bdist_* commands. + orig.install.run(self) + else: + self.do_egg_install() + + @staticmethod + def _called_from_setup(run_frame): + """ + Attempt to detect whether run() was called from setup() or by another + command. If called by setup(), the parent caller will be the + 'run_command' method in 'distutils.dist', and *its* caller will be + the 'run_commands' method. If called any other way, the + immediate caller *might* be 'run_command', but it won't have been + called by 'run_commands'. Return True in that case or if a call stack + is unavailable. Return False otherwise. + """ + if run_frame is None: + msg = "Call stack not available. bdist_* commands may fail." + warnings.warn(msg) + if platform.python_implementation() == 'IronPython': + msg = "For best results, pass -X:Frames to enable call stack." + warnings.warn(msg) + return True + res = inspect.getouterframes(run_frame)[2] + caller, = res[:1] + info = inspect.getframeinfo(caller) + caller_module = caller.f_globals.get('__name__', '') + return ( + caller_module == 'distutils.dist' + and info.function == 'run_commands' + ) + + def do_egg_install(self): + + easy_install = self.distribution.get_command_class('easy_install') + + cmd = easy_install( + self.distribution, args="x", root=self.root, record=self.record, + ) + cmd.ensure_finalized() # finalize before bdist_egg munges install cmd + cmd.always_copy_from = '.' # make sure local-dir eggs get installed + + # pick up setup-dir .egg files only: no .egg-info + cmd.package_index.scan(glob.glob('*.egg')) + + self.run_command('bdist_egg') + args = [self.distribution.get_command_obj('bdist_egg').egg_output] + + if setuptools.bootstrap_install_from: + # Bootstrap self-installation of setuptools + args.insert(0, setuptools.bootstrap_install_from) + + cmd.args = args + cmd.run(show_deprecation=False) + setuptools.bootstrap_install_from = None + + +# XXX Python 3.1 doesn't see _nc if this is inside the class +install.sub_commands = ( + [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] + + install.new_commands +) diff --git a/MLPY/Lib/site-packages/setuptools/command/install_egg_info.py b/MLPY/Lib/site-packages/setuptools/command/install_egg_info.py new file mode 100644 index 0000000000000000000000000000000000000000..edc4718b686203312cea4487a30d8f7801f49b08 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/install_egg_info.py @@ -0,0 +1,62 @@ +from distutils import log, dir_util +import os + +from setuptools import Command +from setuptools import namespaces +from setuptools.archive_util import unpack_archive +import pkg_resources + + +class install_egg_info(namespaces.Installer, Command): + """Install an .egg-info directory for the package""" + + description = "Install an .egg-info directory for the package" + + user_options = [ + ('install-dir=', 'd', "directory to install to"), + ] + + def initialize_options(self): + self.install_dir = None + + def finalize_options(self): + self.set_undefined_options('install_lib', + ('install_dir', 'install_dir')) + ei_cmd = self.get_finalized_command("egg_info") + basename = pkg_resources.Distribution( + None, None, ei_cmd.egg_name, ei_cmd.egg_version + ).egg_name() + '.egg-info' + self.source = ei_cmd.egg_info + self.target = os.path.join(self.install_dir, basename) + self.outputs = [] + + def run(self): + self.run_command('egg_info') + if os.path.isdir(self.target) and not os.path.islink(self.target): + dir_util.remove_tree(self.target, dry_run=self.dry_run) + elif os.path.exists(self.target): + self.execute(os.unlink, (self.target,), "Removing " + self.target) + if not self.dry_run: + pkg_resources.ensure_directory(self.target) + self.execute( + self.copytree, (), "Copying %s to %s" % (self.source, self.target) + ) + self.install_namespaces() + + def get_outputs(self): + return self.outputs + + def copytree(self): + # Copy the .egg-info tree to site-packages + def skimmer(src, dst): + # filter out source-control directories; note that 'src' is always + # a '/'-separated path, regardless of platform. 'dst' is a + # platform-specific path. + for skip in '.svn/', 'CVS/': + if src.startswith(skip) or '/' + skip in src: + return None + self.outputs.append(dst) + log.debug("Copying %s to %s", src, dst) + return dst + + unpack_archive(self.source, self.target, skimmer) diff --git a/MLPY/Lib/site-packages/setuptools/command/install_lib.py b/MLPY/Lib/site-packages/setuptools/command/install_lib.py new file mode 100644 index 0000000000000000000000000000000000000000..2e9d8757a582b1dcdb47a34c35c6cfb3ed23ba90 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/install_lib.py @@ -0,0 +1,122 @@ +import os +import sys +from itertools import product, starmap +import distutils.command.install_lib as orig + + +class install_lib(orig.install_lib): + """Don't add compiled flags to filenames of non-Python files""" + + def run(self): + self.build() + outfiles = self.install() + if outfiles is not None: + # always compile, in case we have any extension stubs to deal with + self.byte_compile(outfiles) + + def get_exclusions(self): + """ + Return a collections.Sized collections.Container of paths to be + excluded for single_version_externally_managed installations. + """ + all_packages = ( + pkg + for ns_pkg in self._get_SVEM_NSPs() + for pkg in self._all_packages(ns_pkg) + ) + + excl_specs = product(all_packages, self._gen_exclusion_paths()) + return set(starmap(self._exclude_pkg_path, excl_specs)) + + def _exclude_pkg_path(self, pkg, exclusion_path): + """ + Given a package name and exclusion path within that package, + compute the full exclusion path. + """ + parts = pkg.split('.') + [exclusion_path] + return os.path.join(self.install_dir, *parts) + + @staticmethod + def _all_packages(pkg_name): + """ + >>> list(install_lib._all_packages('foo.bar.baz')) + ['foo.bar.baz', 'foo.bar', 'foo'] + """ + while pkg_name: + yield pkg_name + pkg_name, sep, child = pkg_name.rpartition('.') + + def _get_SVEM_NSPs(self): + """ + Get namespace packages (list) but only for + single_version_externally_managed installations and empty otherwise. + """ + # TODO: is it necessary to short-circuit here? i.e. what's the cost + # if get_finalized_command is called even when namespace_packages is + # False? + if not self.distribution.namespace_packages: + return [] + + install_cmd = self.get_finalized_command('install') + svem = install_cmd.single_version_externally_managed + + return self.distribution.namespace_packages if svem else [] + + @staticmethod + def _gen_exclusion_paths(): + """ + Generate file paths to be excluded for namespace packages (bytecode + cache files). + """ + # always exclude the package module itself + yield '__init__.py' + + yield '__init__.pyc' + yield '__init__.pyo' + + if not hasattr(sys, 'implementation'): + return + + base = os.path.join( + '__pycache__', '__init__.' + sys.implementation.cache_tag) + yield base + '.pyc' + yield base + '.pyo' + yield base + '.opt-1.pyc' + yield base + '.opt-2.pyc' + + def copy_tree( + self, infile, outfile, + preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 + ): + assert preserve_mode and preserve_times and not preserve_symlinks + exclude = self.get_exclusions() + + if not exclude: + return orig.install_lib.copy_tree(self, infile, outfile) + + # Exclude namespace package __init__.py* files from the output + + from setuptools.archive_util import unpack_directory + from distutils import log + + outfiles = [] + + def pf(src, dst): + if dst in exclude: + log.warn("Skipping installation of %s (namespace package)", + dst) + return False + + log.info("copying %s -> %s", src, os.path.dirname(dst)) + outfiles.append(dst) + return dst + + unpack_directory(infile, outfile, pf) + return outfiles + + def get_outputs(self): + outputs = orig.install_lib.get_outputs(self) + exclude = self.get_exclusions() + if exclude: + return [f for f in outputs if f not in exclude] + return outputs diff --git a/MLPY/Lib/site-packages/setuptools/command/install_scripts.py b/MLPY/Lib/site-packages/setuptools/command/install_scripts.py new file mode 100644 index 0000000000000000000000000000000000000000..9cd8eb06277f449599a7b4babe74e1adab33bdc2 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/install_scripts.py @@ -0,0 +1,69 @@ +from distutils import log +import distutils.command.install_scripts as orig +from distutils.errors import DistutilsModuleError +import os +import sys + +from pkg_resources import Distribution, PathMetadata, ensure_directory + + +class install_scripts(orig.install_scripts): + """Do normal script install, plus any egg_info wrapper scripts""" + + def initialize_options(self): + orig.install_scripts.initialize_options(self) + self.no_ep = False + + def run(self): + import setuptools.command.easy_install as ei + + self.run_command("egg_info") + if self.distribution.scripts: + orig.install_scripts.run(self) # run first to set up self.outfiles + else: + self.outfiles = [] + if self.no_ep: + # don't install entry point scripts into .egg file! + return + + ei_cmd = self.get_finalized_command("egg_info") + dist = Distribution( + ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), + ei_cmd.egg_name, ei_cmd.egg_version, + ) + bs_cmd = self.get_finalized_command('build_scripts') + exec_param = getattr(bs_cmd, 'executable', None) + try: + bw_cmd = self.get_finalized_command("bdist_wininst") + is_wininst = getattr(bw_cmd, '_is_running', False) + except (ImportError, DistutilsModuleError): + is_wininst = False + writer = ei.ScriptWriter + if is_wininst: + exec_param = "python.exe" + writer = ei.WindowsScriptWriter + if exec_param == sys.executable: + # In case the path to the Python executable contains a space, wrap + # it so it's not split up. + exec_param = [exec_param] + # resolve the writer to the environment + writer = writer.best() + cmd = writer.command_spec_class.best().from_param(exec_param) + for args in writer.get_args(dist, cmd.as_header()): + self.write_script(*args) + + def write_script(self, script_name, contents, mode="t", *ignored): + """Write an executable file to the scripts directory""" + from setuptools.command.easy_install import chmod, current_umask + + log.info("Installing %s script to %s", script_name, self.install_dir) + target = os.path.join(self.install_dir, script_name) + self.outfiles.append(target) + + mask = current_umask() + if not self.dry_run: + ensure_directory(target) + f = open(target, "w" + mode) + f.write(contents) + f.close() + chmod(target, 0o777 - mask) diff --git a/MLPY/Lib/site-packages/setuptools/command/launcher manifest.xml b/MLPY/Lib/site-packages/setuptools/command/launcher manifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..5972a96d8ded85cc14147ffc1400ec67c3b5a578 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/launcher manifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/MLPY/Lib/site-packages/setuptools/command/py36compat.py b/MLPY/Lib/site-packages/setuptools/command/py36compat.py new file mode 100644 index 0000000000000000000000000000000000000000..343547a4d316e48144ba6bdf342dcc24cd6cb6cd --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/py36compat.py @@ -0,0 +1,134 @@ +import os +from glob import glob +from distutils.util import convert_path +from distutils.command import sdist + + +class sdist_add_defaults: + """ + Mix-in providing forward-compatibility for functionality as found in + distutils on Python 3.7. + + Do not edit the code in this class except to update functionality + as implemented in distutils. Instead, override in the subclass. + """ + + def add_defaults(self): + """Add all the default files to self.filelist: + - README or README.txt + - setup.py + - test/test*.py + - all pure Python modules mentioned in setup script + - all files pointed by package_data (build_py) + - all files defined in data_files. + - all files defined as scripts. + - all C sources listed as part of extensions or C libraries + in the setup script (doesn't catch C headers!) + Warns if (README or README.txt) or setup.py are missing; everything + else is optional. + """ + self._add_defaults_standards() + self._add_defaults_optional() + self._add_defaults_python() + self._add_defaults_data_files() + self._add_defaults_ext() + self._add_defaults_c_libs() + self._add_defaults_scripts() + + @staticmethod + def _cs_path_exists(fspath): + """ + Case-sensitive path existence check + + >>> sdist_add_defaults._cs_path_exists(__file__) + True + >>> sdist_add_defaults._cs_path_exists(__file__.upper()) + False + """ + if not os.path.exists(fspath): + return False + # make absolute so we always have a directory + abspath = os.path.abspath(fspath) + directory, filename = os.path.split(abspath) + return filename in os.listdir(directory) + + def _add_defaults_standards(self): + standards = [self.READMES, self.distribution.script_name] + for fn in standards: + if isinstance(fn, tuple): + alts = fn + got_it = False + for fn in alts: + if self._cs_path_exists(fn): + got_it = True + self.filelist.append(fn) + break + + if not got_it: + self.warn("standard file not found: should have one of " + + ', '.join(alts)) + else: + if self._cs_path_exists(fn): + self.filelist.append(fn) + else: + self.warn("standard file '%s' not found" % fn) + + def _add_defaults_optional(self): + optional = ['test/test*.py', 'setup.cfg'] + for pattern in optional: + files = filter(os.path.isfile, glob(pattern)) + self.filelist.extend(files) + + def _add_defaults_python(self): + # build_py is used to get: + # - python modules + # - files defined in package_data + build_py = self.get_finalized_command('build_py') + + # getting python files + if self.distribution.has_pure_modules(): + self.filelist.extend(build_py.get_source_files()) + + # getting package_data files + # (computed in build_py.data_files by build_py.finalize_options) + for pkg, src_dir, build_dir, filenames in build_py.data_files: + for filename in filenames: + self.filelist.append(os.path.join(src_dir, filename)) + + def _add_defaults_data_files(self): + # getting distribution.data_files + if self.distribution.has_data_files(): + for item in self.distribution.data_files: + if isinstance(item, str): + # plain file + item = convert_path(item) + if os.path.isfile(item): + self.filelist.append(item) + else: + # a (dirname, filenames) tuple + dirname, filenames = item + for f in filenames: + f = convert_path(f) + if os.path.isfile(f): + self.filelist.append(f) + + def _add_defaults_ext(self): + if self.distribution.has_ext_modules(): + build_ext = self.get_finalized_command('build_ext') + self.filelist.extend(build_ext.get_source_files()) + + def _add_defaults_c_libs(self): + if self.distribution.has_c_libraries(): + build_clib = self.get_finalized_command('build_clib') + self.filelist.extend(build_clib.get_source_files()) + + def _add_defaults_scripts(self): + if self.distribution.has_scripts(): + build_scripts = self.get_finalized_command('build_scripts') + self.filelist.extend(build_scripts.get_source_files()) + + +if hasattr(sdist.sdist, '_add_defaults_standards'): + # disable the functionality already available upstream + class sdist_add_defaults: # noqa + pass diff --git a/MLPY/Lib/site-packages/setuptools/command/register.py b/MLPY/Lib/site-packages/setuptools/command/register.py new file mode 100644 index 0000000000000000000000000000000000000000..b8266b9a60f8c363ba35f7b73befd7c9c7cb4abc --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/register.py @@ -0,0 +1,18 @@ +from distutils import log +import distutils.command.register as orig + +from setuptools.errors import RemovedCommandError + + +class register(orig.register): + """Formerly used to register packages on PyPI.""" + + def run(self): + msg = ( + "The register command has been removed, use twine to upload " + + "instead (https://pypi.org/p/twine)" + ) + + self.announce("ERROR: " + msg, log.ERROR) + + raise RemovedCommandError(msg) diff --git a/MLPY/Lib/site-packages/setuptools/command/rotate.py b/MLPY/Lib/site-packages/setuptools/command/rotate.py new file mode 100644 index 0000000000000000000000000000000000000000..74795ba922bb376e24858760e63dc9124ef22b9f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/rotate.py @@ -0,0 +1,64 @@ +from distutils.util import convert_path +from distutils import log +from distutils.errors import DistutilsOptionError +import os +import shutil + +from setuptools import Command + + +class rotate(Command): + """Delete older distributions""" + + description = "delete older distributions, keeping N newest files" + user_options = [ + ('match=', 'm', "patterns to match (required)"), + ('dist-dir=', 'd', "directory where the distributions are"), + ('keep=', 'k', "number of matching distributions to keep"), + ] + + boolean_options = [] + + def initialize_options(self): + self.match = None + self.dist_dir = None + self.keep = None + + def finalize_options(self): + if self.match is None: + raise DistutilsOptionError( + "Must specify one or more (comma-separated) match patterns " + "(e.g. '.zip' or '.egg')" + ) + if self.keep is None: + raise DistutilsOptionError("Must specify number of files to keep") + try: + self.keep = int(self.keep) + except ValueError as e: + raise DistutilsOptionError("--keep must be an integer") from e + if isinstance(self.match, str): + self.match = [ + convert_path(p.strip()) for p in self.match.split(',') + ] + self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) + + def run(self): + self.run_command("egg_info") + from glob import glob + + for pattern in self.match: + pattern = self.distribution.get_name() + '*' + pattern + files = glob(os.path.join(self.dist_dir, pattern)) + files = [(os.path.getmtime(f), f) for f in files] + files.sort() + files.reverse() + + log.info("%d file(s) matching %s", len(files), pattern) + files = files[self.keep:] + for (t, f) in files: + log.info("Deleting %s", f) + if not self.dry_run: + if os.path.isdir(f): + shutil.rmtree(f) + else: + os.unlink(f) diff --git a/MLPY/Lib/site-packages/setuptools/command/saveopts.py b/MLPY/Lib/site-packages/setuptools/command/saveopts.py new file mode 100644 index 0000000000000000000000000000000000000000..611cec552867a6d50b7edd700c86c7396d906ea2 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/saveopts.py @@ -0,0 +1,22 @@ +from setuptools.command.setopt import edit_config, option_base + + +class saveopts(option_base): + """Save command-line options to a file""" + + description = "save supplied options to setup.cfg or other config file" + + def run(self): + dist = self.distribution + settings = {} + + for cmd in dist.command_options: + + if cmd == 'saveopts': + continue # don't save our own options! + + for opt, (src, val) in dist.get_option_dict(cmd).items(): + if src == "command line": + settings.setdefault(cmd, {})[opt] = val + + edit_config(self.filename, settings, self.dry_run) diff --git a/MLPY/Lib/site-packages/setuptools/command/sdist.py b/MLPY/Lib/site-packages/setuptools/command/sdist.py new file mode 100644 index 0000000000000000000000000000000000000000..4a014283c8650112323007992fe702702707ad66 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/sdist.py @@ -0,0 +1,189 @@ +from distutils import log +import distutils.command.sdist as orig +import os +import sys +import io +import contextlib + +from .py36compat import sdist_add_defaults + +import pkg_resources + +_default_revctrl = list + + +def walk_revctrl(dirname=''): + """Find all files under revision control""" + for ep in pkg_resources.iter_entry_points('setuptools.file_finders'): + for item in ep.load()(dirname): + yield item + + +class sdist(sdist_add_defaults, orig.sdist): + """Smart sdist that finds anything supported by revision control""" + + user_options = [ + ('formats=', None, + "formats for source distribution (comma-separated list)"), + ('keep-temp', 'k', + "keep the distribution tree around after creating " + + "archive file(s)"), + ('dist-dir=', 'd', + "directory to put the source distribution archive(s) in " + "[default: dist]"), + ] + + negative_opt = {} + + README_EXTENSIONS = ['', '.rst', '.txt', '.md'] + READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS) + + def run(self): + self.run_command('egg_info') + ei_cmd = self.get_finalized_command('egg_info') + self.filelist = ei_cmd.filelist + self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt')) + self.check_readme() + + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + self.make_distribution() + + dist_files = getattr(self.distribution, 'dist_files', []) + for file in self.archive_files: + data = ('sdist', '', file) + if data not in dist_files: + dist_files.append(data) + + def initialize_options(self): + orig.sdist.initialize_options(self) + + self._default_to_gztar() + + def _default_to_gztar(self): + # only needed on Python prior to 3.6. + if sys.version_info >= (3, 6, 0, 'beta', 1): + return + self.formats = ['gztar'] + + def make_distribution(self): + """ + Workaround for #516 + """ + with self._remove_os_link(): + orig.sdist.make_distribution(self) + + @staticmethod + @contextlib.contextmanager + def _remove_os_link(): + """ + In a context, remove and restore os.link if it exists + """ + + class NoValue: + pass + + orig_val = getattr(os, 'link', NoValue) + try: + del os.link + except Exception: + pass + try: + yield + finally: + if orig_val is not NoValue: + setattr(os, 'link', orig_val) + + def _add_defaults_optional(self): + super()._add_defaults_optional() + if os.path.isfile('pyproject.toml'): + self.filelist.append('pyproject.toml') + + def _add_defaults_python(self): + """getting python files""" + if self.distribution.has_pure_modules(): + build_py = self.get_finalized_command('build_py') + self.filelist.extend(build_py.get_source_files()) + self._add_data_files(self._safe_data_files(build_py)) + + def _safe_data_files(self, build_py): + """ + Extracting data_files from build_py is known to cause + infinite recursion errors when `include_package_data` + is enabled, so suppress it in that case. + """ + if self.distribution.include_package_data: + return () + return build_py.data_files + + def _add_data_files(self, data_files): + """ + Add data files as found in build_py.data_files. + """ + self.filelist.extend( + os.path.join(src_dir, name) + for _, src_dir, _, filenames in data_files + for name in filenames + ) + + def _add_defaults_data_files(self): + try: + super()._add_defaults_data_files() + except TypeError: + log.warn("data_files contains unexpected objects") + + def check_readme(self): + for f in self.READMES: + if os.path.exists(f): + return + else: + self.warn( + "standard file not found: should have one of " + + ', '.join(self.READMES) + ) + + def make_release_tree(self, base_dir, files): + orig.sdist.make_release_tree(self, base_dir, files) + + # Save any egg_info command line options used to create this sdist + dest = os.path.join(base_dir, 'setup.cfg') + if hasattr(os, 'link') and os.path.exists(dest): + # unlink and re-copy, since it might be hard-linked, and + # we don't want to change the source version + os.unlink(dest) + self.copy_file('setup.cfg', dest) + + self.get_finalized_command('egg_info').save_version_info(dest) + + def _manifest_is_not_generated(self): + # check for special comment used in 2.7.1 and higher + if not os.path.isfile(self.manifest): + return False + + with io.open(self.manifest, 'rb') as fp: + first_line = fp.readline() + return (first_line != + '# file GENERATED by distutils, do NOT edit\n'.encode()) + + def read_manifest(self): + """Read the manifest file (named by 'self.manifest') and use it to + fill in 'self.filelist', the list of files to include in the source + distribution. + """ + log.info("reading manifest file '%s'", self.manifest) + manifest = open(self.manifest, 'rb') + for line in manifest: + # The manifest must contain UTF-8. See #303. + try: + line = line.decode('UTF-8') + except UnicodeDecodeError: + log.warn("%r not UTF-8 decodable -- skipping" % line) + continue + # ignore comments and blank lines + line = line.strip() + if line.startswith('#') or not line: + continue + self.filelist.append(line) + manifest.close() diff --git a/MLPY/Lib/site-packages/setuptools/command/setopt.py b/MLPY/Lib/site-packages/setuptools/command/setopt.py new file mode 100644 index 0000000000000000000000000000000000000000..6358c0451b2d0036e3821d897fb6f7ab436ee4a9 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/setopt.py @@ -0,0 +1,149 @@ +from distutils.util import convert_path +from distutils import log +from distutils.errors import DistutilsOptionError +import distutils +import os +import configparser + +from setuptools import Command + +__all__ = ['config_file', 'edit_config', 'option_base', 'setopt'] + + +def config_file(kind="local"): + """Get the filename of the distutils, local, global, or per-user config + + `kind` must be one of "local", "global", or "user" + """ + if kind == 'local': + return 'setup.cfg' + if kind == 'global': + return os.path.join( + os.path.dirname(distutils.__file__), 'distutils.cfg' + ) + if kind == 'user': + dot = os.name == 'posix' and '.' or '' + return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot)) + raise ValueError( + "config_file() type must be 'local', 'global', or 'user'", kind + ) + + +def edit_config(filename, settings, dry_run=False): + """Edit a configuration file to include `settings` + + `settings` is a dictionary of dictionaries or ``None`` values, keyed by + command/section name. A ``None`` value means to delete the entire section, + while a dictionary lists settings to be changed or deleted in that section. + A setting of ``None`` means to delete that setting. + """ + log.debug("Reading configuration from %s", filename) + opts = configparser.RawConfigParser() + opts.optionxform = lambda x: x + opts.read([filename]) + for section, options in settings.items(): + if options is None: + log.info("Deleting section [%s] from %s", section, filename) + opts.remove_section(section) + else: + if not opts.has_section(section): + log.debug("Adding new section [%s] to %s", section, filename) + opts.add_section(section) + for option, value in options.items(): + if value is None: + log.debug( + "Deleting %s.%s from %s", + section, option, filename + ) + opts.remove_option(section, option) + if not opts.options(section): + log.info("Deleting empty [%s] section from %s", + section, filename) + opts.remove_section(section) + else: + log.debug( + "Setting %s.%s to %r in %s", + section, option, value, filename + ) + opts.set(section, option, value) + + log.info("Writing %s", filename) + if not dry_run: + with open(filename, 'w') as f: + opts.write(f) + + +class option_base(Command): + """Abstract base class for commands that mess with config files""" + + user_options = [ + ('global-config', 'g', + "save options to the site-wide distutils.cfg file"), + ('user-config', 'u', + "save options to the current user's pydistutils.cfg file"), + ('filename=', 'f', + "configuration file to use (default=setup.cfg)"), + ] + + boolean_options = [ + 'global-config', 'user-config', + ] + + def initialize_options(self): + self.global_config = None + self.user_config = None + self.filename = None + + def finalize_options(self): + filenames = [] + if self.global_config: + filenames.append(config_file('global')) + if self.user_config: + filenames.append(config_file('user')) + if self.filename is not None: + filenames.append(self.filename) + if not filenames: + filenames.append(config_file('local')) + if len(filenames) > 1: + raise DistutilsOptionError( + "Must specify only one configuration file option", + filenames + ) + self.filename, = filenames + + +class setopt(option_base): + """Save command-line options to a file""" + + description = "set an option in setup.cfg or another config file" + + user_options = [ + ('command=', 'c', 'command to set an option for'), + ('option=', 'o', 'option to set'), + ('set-value=', 's', 'value of the option'), + ('remove', 'r', 'remove (unset) the value'), + ] + option_base.user_options + + boolean_options = option_base.boolean_options + ['remove'] + + def initialize_options(self): + option_base.initialize_options(self) + self.command = None + self.option = None + self.set_value = None + self.remove = None + + def finalize_options(self): + option_base.finalize_options(self) + if self.command is None or self.option is None: + raise DistutilsOptionError("Must specify --command *and* --option") + if self.set_value is None and not self.remove: + raise DistutilsOptionError("Must specify --set-value or --remove") + + def run(self): + edit_config( + self.filename, { + self.command: {self.option.replace('-', '_'): self.set_value} + }, + self.dry_run + ) diff --git a/MLPY/Lib/site-packages/setuptools/command/test.py b/MLPY/Lib/site-packages/setuptools/command/test.py new file mode 100644 index 0000000000000000000000000000000000000000..4a389e4d071d3753f14a8b74338def21f6b54299 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/test.py @@ -0,0 +1,252 @@ +import os +import operator +import sys +import contextlib +import itertools +import unittest +from distutils.errors import DistutilsError, DistutilsOptionError +from distutils import log +from unittest import TestLoader + +from pkg_resources import ( + resource_listdir, + resource_exists, + normalize_path, + working_set, + evaluate_marker, + add_activation_listener, + require, + EntryPoint, +) +from setuptools import Command +from setuptools.extern.more_itertools import unique_everseen + + +class ScanningLoader(TestLoader): + def __init__(self): + TestLoader.__init__(self) + self._visited = set() + + def loadTestsFromModule(self, module, pattern=None): + """Return a suite of all tests cases contained in the given module + + If the module is a package, load tests from all the modules in it. + If the module has an ``additional_tests`` function, call it and add + the return value to the tests. + """ + if module in self._visited: + return None + self._visited.add(module) + + tests = [] + tests.append(TestLoader.loadTestsFromModule(self, module)) + + if hasattr(module, "additional_tests"): + tests.append(module.additional_tests()) + + if hasattr(module, '__path__'): + for file in resource_listdir(module.__name__, ''): + if file.endswith('.py') and file != '__init__.py': + submodule = module.__name__ + '.' + file[:-3] + else: + if resource_exists(module.__name__, file + '/__init__.py'): + submodule = module.__name__ + '.' + file + else: + continue + tests.append(self.loadTestsFromName(submodule)) + + if len(tests) != 1: + return self.suiteClass(tests) + else: + return tests[0] # don't create a nested suite for only one return + + +# adapted from jaraco.classes.properties:NonDataProperty +class NonDataProperty: + def __init__(self, fget): + self.fget = fget + + def __get__(self, obj, objtype=None): + if obj is None: + return self + return self.fget(obj) + + +class test(Command): + """Command to run unit tests after in-place build""" + + description = "run unit tests after in-place build (deprecated)" + + user_options = [ + ('test-module=', 'm', "Run 'test_suite' in specified module"), + ( + 'test-suite=', + 's', + "Run single test, case or suite (e.g. 'module.test_suite')", + ), + ('test-runner=', 'r', "Test runner to use"), + ] + + def initialize_options(self): + self.test_suite = None + self.test_module = None + self.test_loader = None + self.test_runner = None + + def finalize_options(self): + + if self.test_suite and self.test_module: + msg = "You may specify a module or a suite, but not both" + raise DistutilsOptionError(msg) + + if self.test_suite is None: + if self.test_module is None: + self.test_suite = self.distribution.test_suite + else: + self.test_suite = self.test_module + ".test_suite" + + if self.test_loader is None: + self.test_loader = getattr(self.distribution, 'test_loader', None) + if self.test_loader is None: + self.test_loader = "setuptools.command.test:ScanningLoader" + if self.test_runner is None: + self.test_runner = getattr(self.distribution, 'test_runner', None) + + @NonDataProperty + def test_args(self): + return list(self._test_args()) + + def _test_args(self): + if not self.test_suite and sys.version_info >= (2, 7): + yield 'discover' + if self.verbose: + yield '--verbose' + if self.test_suite: + yield self.test_suite + + def with_project_on_sys_path(self, func): + """ + Backward compatibility for project_on_sys_path context. + """ + with self.project_on_sys_path(): + func() + + @contextlib.contextmanager + def project_on_sys_path(self, include_dists=[]): + self.run_command('egg_info') + + # Build extensions in-place + self.reinitialize_command('build_ext', inplace=1) + self.run_command('build_ext') + + ei_cmd = self.get_finalized_command("egg_info") + + old_path = sys.path[:] + old_modules = sys.modules.copy() + + try: + project_path = normalize_path(ei_cmd.egg_base) + sys.path.insert(0, project_path) + working_set.__init__() + add_activation_listener(lambda dist: dist.activate()) + require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) + with self.paths_on_pythonpath([project_path]): + yield + finally: + sys.path[:] = old_path + sys.modules.clear() + sys.modules.update(old_modules) + working_set.__init__() + + @staticmethod + @contextlib.contextmanager + def paths_on_pythonpath(paths): + """ + Add the indicated paths to the head of the PYTHONPATH environment + variable so that subprocesses will also see the packages at + these paths. + + Do this in a context that restores the value on exit. + """ + nothing = object() + orig_pythonpath = os.environ.get('PYTHONPATH', nothing) + current_pythonpath = os.environ.get('PYTHONPATH', '') + try: + prefix = os.pathsep.join(unique_everseen(paths)) + to_join = filter(None, [prefix, current_pythonpath]) + new_path = os.pathsep.join(to_join) + if new_path: + os.environ['PYTHONPATH'] = new_path + yield + finally: + if orig_pythonpath is nothing: + os.environ.pop('PYTHONPATH', None) + else: + os.environ['PYTHONPATH'] = orig_pythonpath + + @staticmethod + def install_dists(dist): + """ + Install the requirements indicated by self.distribution and + return an iterable of the dists that were built. + """ + ir_d = dist.fetch_build_eggs(dist.install_requires) + tr_d = dist.fetch_build_eggs(dist.tests_require or []) + er_d = dist.fetch_build_eggs( + v + for k, v in dist.extras_require.items() + if k.startswith(':') and evaluate_marker(k[1:]) + ) + return itertools.chain(ir_d, tr_d, er_d) + + def run(self): + self.announce( + "WARNING: Testing via this command is deprecated and will be " + "removed in a future version. Users looking for a generic test " + "entry point independent of test runner are encouraged to use " + "tox.", + log.WARN, + ) + + installed_dists = self.install_dists(self.distribution) + + cmd = ' '.join(self._argv) + if self.dry_run: + self.announce('skipping "%s" (dry run)' % cmd) + return + + self.announce('running "%s"' % cmd) + + paths = map(operator.attrgetter('location'), installed_dists) + with self.paths_on_pythonpath(paths): + with self.project_on_sys_path(): + self.run_tests() + + def run_tests(self): + test = unittest.main( + None, + None, + self._argv, + testLoader=self._resolve_as_ep(self.test_loader), + testRunner=self._resolve_as_ep(self.test_runner), + exit=False, + ) + if not test.result.wasSuccessful(): + msg = 'Test failed: %s' % test.result + self.announce(msg, log.ERROR) + raise DistutilsError(msg) + + @property + def _argv(self): + return ['unittest'] + self.test_args + + @staticmethod + def _resolve_as_ep(val): + """ + Load the indicated attribute value, called, as a as if it were + specified as an entry point. + """ + if val is None: + return + parsed = EntryPoint.parse("x=" + val) + return parsed.resolve()() diff --git a/MLPY/Lib/site-packages/setuptools/command/upload.py b/MLPY/Lib/site-packages/setuptools/command/upload.py new file mode 100644 index 0000000000000000000000000000000000000000..ec7f81e22772511d668e5ab92f625db33259e803 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/upload.py @@ -0,0 +1,17 @@ +from distutils import log +from distutils.command import upload as orig + +from setuptools.errors import RemovedCommandError + + +class upload(orig.upload): + """Formerly used to upload packages to PyPI.""" + + def run(self): + msg = ( + "The upload command has been removed, use twine to upload " + + "instead (https://pypi.org/p/twine)" + ) + + self.announce("ERROR: " + msg, log.ERROR) + raise RemovedCommandError(msg) diff --git a/MLPY/Lib/site-packages/setuptools/command/upload_docs.py b/MLPY/Lib/site-packages/setuptools/command/upload_docs.py new file mode 100644 index 0000000000000000000000000000000000000000..845bff4421f8700eb6e1bf719b0639185e6ed0b1 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/command/upload_docs.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +"""upload_docs + +Implements a Distutils 'upload_docs' subcommand (upload documentation to +sites other than PyPi such as devpi). +""" + +from base64 import standard_b64encode +from distutils import log +from distutils.errors import DistutilsOptionError +import os +import socket +import zipfile +import tempfile +import shutil +import itertools +import functools +import http.client +import urllib.parse + +from pkg_resources import iter_entry_points +from .upload import upload + + +def _encode(s): + return s.encode('utf-8', 'surrogateescape') + + +class upload_docs(upload): + # override the default repository as upload_docs isn't + # supported by Warehouse (and won't be). + DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi/' + + description = 'Upload documentation to sites other than PyPi such as devpi' + + user_options = [ + ('repository=', 'r', + "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), + ('show-response', None, + 'display full response text from server'), + ('upload-dir=', None, 'directory to upload'), + ] + boolean_options = upload.boolean_options + + def has_sphinx(self): + if self.upload_dir is None: + for ep in iter_entry_points('distutils.commands', 'build_sphinx'): + return True + + sub_commands = [('build_sphinx', has_sphinx)] + + def initialize_options(self): + upload.initialize_options(self) + self.upload_dir = None + self.target_dir = None + + def finalize_options(self): + upload.finalize_options(self) + if self.upload_dir is None: + if self.has_sphinx(): + build_sphinx = self.get_finalized_command('build_sphinx') + self.target_dir = dict(build_sphinx.builder_target_dirs)['html'] + else: + build = self.get_finalized_command('build') + self.target_dir = os.path.join(build.build_base, 'docs') + else: + self.ensure_dirname('upload_dir') + self.target_dir = self.upload_dir + if 'pypi.python.org' in self.repository: + log.warn("Upload_docs command is deprecated for PyPi. Use RTD instead.") + self.announce('Using upload directory %s' % self.target_dir) + + def create_zipfile(self, filename): + zip_file = zipfile.ZipFile(filename, "w") + try: + self.mkpath(self.target_dir) # just in case + for root, dirs, files in os.walk(self.target_dir): + if root == self.target_dir and not files: + tmpl = "no files found in upload directory '%s'" + raise DistutilsOptionError(tmpl % self.target_dir) + for name in files: + full = os.path.join(root, name) + relative = root[len(self.target_dir):].lstrip(os.path.sep) + dest = os.path.join(relative, name) + zip_file.write(full, dest) + finally: + zip_file.close() + + def run(self): + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + tmp_dir = tempfile.mkdtemp() + name = self.distribution.metadata.get_name() + zip_file = os.path.join(tmp_dir, "%s.zip" % name) + try: + self.create_zipfile(zip_file) + self.upload_file(zip_file) + finally: + shutil.rmtree(tmp_dir) + + @staticmethod + def _build_part(item, sep_boundary): + key, values = item + title = '\nContent-Disposition: form-data; name="%s"' % key + # handle multiple entries for the same name + if not isinstance(values, list): + values = [values] + for value in values: + if isinstance(value, tuple): + title += '; filename="%s"' % value[0] + value = value[1] + else: + value = _encode(value) + yield sep_boundary + yield _encode(title) + yield b"\n\n" + yield value + if value and value[-1:] == b'\r': + yield b'\n' # write an extra newline (lurve Macs) + + @classmethod + def _build_multipart(cls, data): + """ + Build up the MIME payload for the POST data + """ + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = b'\n--' + boundary.encode('ascii') + end_boundary = sep_boundary + b'--' + end_items = end_boundary, b"\n", + builder = functools.partial( + cls._build_part, + sep_boundary=sep_boundary, + ) + part_groups = map(builder, data.items()) + parts = itertools.chain.from_iterable(part_groups) + body_items = itertools.chain(parts, end_items) + content_type = 'multipart/form-data; boundary=%s' % boundary + return b''.join(body_items), content_type + + def upload_file(self, filename): + with open(filename, 'rb') as f: + content = f.read() + meta = self.distribution.metadata + data = { + ':action': 'doc_upload', + 'name': meta.get_name(), + 'content': (os.path.basename(filename), content), + } + # set up the authentication + credentials = _encode(self.username + ':' + self.password) + credentials = standard_b64encode(credentials).decode('ascii') + auth = "Basic " + credentials + + body, ct = self._build_multipart(data) + + msg = "Submitting documentation to %s" % (self.repository) + self.announce(msg, log.INFO) + + # build the Request + # We can't use urllib2 since we need to send the Basic + # auth right with the first request + schema, netloc, url, params, query, fragments = \ + urllib.parse.urlparse(self.repository) + assert not params and not query and not fragments + if schema == 'http': + conn = http.client.HTTPConnection(netloc) + elif schema == 'https': + conn = http.client.HTTPSConnection(netloc) + else: + raise AssertionError("unsupported schema " + schema) + + data = '' + try: + conn.connect() + conn.putrequest("POST", url) + content_type = ct + conn.putheader('Content-type', content_type) + conn.putheader('Content-length', str(len(body))) + conn.putheader('Authorization', auth) + conn.endheaders() + conn.send(body) + except socket.error as e: + self.announce(str(e), log.ERROR) + return + + r = conn.getresponse() + if r.status == 200: + msg = 'Server response (%s): %s' % (r.status, r.reason) + self.announce(msg, log.INFO) + elif r.status == 301: + location = r.getheader('Location') + if location is None: + location = 'https://pythonhosted.org/%s/' % meta.get_name() + msg = 'Upload successful. Visit %s' % location + self.announce(msg, log.INFO) + else: + msg = 'Upload failed (%s): %s' % (r.status, r.reason) + self.announce(msg, log.ERROR) + if self.show_response: + print('-' * 75, r.read(), '-' * 75) diff --git a/MLPY/Lib/site-packages/setuptools/config.py b/MLPY/Lib/site-packages/setuptools/config.py new file mode 100644 index 0000000000000000000000000000000000000000..e3e44c25b8c9deae33144ef101f2b49f2d301f5f --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/config.py @@ -0,0 +1,749 @@ +import ast +import io +import os +import sys + +import warnings +import functools +import importlib +from collections import defaultdict +from functools import partial +from functools import wraps +from glob import iglob +import contextlib + +from distutils.errors import DistutilsOptionError, DistutilsFileError +from setuptools.extern.packaging.version import LegacyVersion, parse +from setuptools.extern.packaging.specifiers import SpecifierSet + + +class StaticModule: + """ + Attempt to load the module by the name + """ + + def __init__(self, name): + spec = importlib.util.find_spec(name) + with open(spec.origin) as strm: + src = strm.read() + module = ast.parse(src) + vars(self).update(locals()) + del self.self + + def __getattr__(self, attr): + try: + return next( + ast.literal_eval(statement.value) + for statement in self.module.body + if isinstance(statement, ast.Assign) + for target in statement.targets + if isinstance(target, ast.Name) and target.id == attr + ) + except Exception as e: + raise AttributeError( + "{self.name} has no attribute {attr}".format(**locals()) + ) from e + + +@contextlib.contextmanager +def patch_path(path): + """ + Add path to front of sys.path for the duration of the context. + """ + try: + sys.path.insert(0, path) + yield + finally: + sys.path.remove(path) + + +def read_configuration(filepath, find_others=False, ignore_option_errors=False): + """Read given configuration file and returns options from it as a dict. + + :param str|unicode filepath: Path to configuration file + to get options from. + + :param bool find_others: Whether to search for other configuration files + which could be on in various places. + + :param bool ignore_option_errors: Whether to silently ignore + options, values of which could not be resolved (e.g. due to exceptions + in directives such as file:, attr:, etc.). + If False exceptions are propagated as expected. + + :rtype: dict + """ + from setuptools.dist import Distribution, _Distribution + + filepath = os.path.abspath(filepath) + + if not os.path.isfile(filepath): + raise DistutilsFileError('Configuration file %s does not exist.' % filepath) + + current_directory = os.getcwd() + os.chdir(os.path.dirname(filepath)) + + try: + dist = Distribution() + + filenames = dist.find_config_files() if find_others else [] + if filepath not in filenames: + filenames.append(filepath) + + _Distribution.parse_config_files(dist, filenames=filenames) + + handlers = parse_configuration( + dist, dist.command_options, ignore_option_errors=ignore_option_errors + ) + + finally: + os.chdir(current_directory) + + return configuration_to_dict(handlers) + + +def _get_option(target_obj, key): + """ + Given a target object and option key, get that option from + the target object, either through a get_{key} method or + from an attribute directly. + """ + getter_name = 'get_{key}'.format(**locals()) + by_attribute = functools.partial(getattr, target_obj, key) + getter = getattr(target_obj, getter_name, by_attribute) + return getter() + + +def configuration_to_dict(handlers): + """Returns configuration data gathered by given handlers as a dict. + + :param list[ConfigHandler] handlers: Handlers list, + usually from parse_configuration() + + :rtype: dict + """ + config_dict = defaultdict(dict) + + for handler in handlers: + for option in handler.set_options: + value = _get_option(handler.target_obj, option) + config_dict[handler.section_prefix][option] = value + + return config_dict + + +def parse_configuration(distribution, command_options, ignore_option_errors=False): + """Performs additional parsing of configuration options + for a distribution. + + Returns a list of used option handlers. + + :param Distribution distribution: + :param dict command_options: + :param bool ignore_option_errors: Whether to silently ignore + options, values of which could not be resolved (e.g. due to exceptions + in directives such as file:, attr:, etc.). + If False exceptions are propagated as expected. + :rtype: list + """ + options = ConfigOptionsHandler(distribution, command_options, ignore_option_errors) + options.parse() + + meta = ConfigMetadataHandler( + distribution.metadata, + command_options, + ignore_option_errors, + distribution.package_dir, + ) + meta.parse() + + return meta, options + + +class ConfigHandler: + """Handles metadata supplied in configuration files.""" + + section_prefix = None + """Prefix for config sections handled by this handler. + Must be provided by class heirs. + + """ + + aliases = {} + """Options aliases. + For compatibility with various packages. E.g.: d2to1 and pbr. + Note: `-` in keys is replaced with `_` by config parser. + + """ + + def __init__(self, target_obj, options, ignore_option_errors=False): + sections = {} + + section_prefix = self.section_prefix + for section_name, section_options in options.items(): + if not section_name.startswith(section_prefix): + continue + + section_name = section_name.replace(section_prefix, '').strip('.') + sections[section_name] = section_options + + self.ignore_option_errors = ignore_option_errors + self.target_obj = target_obj + self.sections = sections + self.set_options = [] + + @property + def parsers(self): + """Metadata item name to parser function mapping.""" + raise NotImplementedError( + '%s must provide .parsers property' % self.__class__.__name__ + ) + + def __setitem__(self, option_name, value): + unknown = tuple() + target_obj = self.target_obj + + # Translate alias into real name. + option_name = self.aliases.get(option_name, option_name) + + current_value = getattr(target_obj, option_name, unknown) + + if current_value is unknown: + raise KeyError(option_name) + + if current_value: + # Already inhabited. Skipping. + return + + skip_option = False + parser = self.parsers.get(option_name) + if parser: + try: + value = parser(value) + + except Exception: + skip_option = True + if not self.ignore_option_errors: + raise + + if skip_option: + return + + setter = getattr(target_obj, 'set_%s' % option_name, None) + if setter is None: + setattr(target_obj, option_name, value) + else: + setter(value) + + self.set_options.append(option_name) + + @classmethod + def _parse_list(cls, value, separator=','): + """Represents value as a list. + + Value is split either by separator (defaults to comma) or by lines. + + :param value: + :param separator: List items separator character. + :rtype: list + """ + if isinstance(value, list): # _get_parser_compound case + return value + + if '\n' in value: + value = value.splitlines() + else: + value = value.split(separator) + + return [chunk.strip() for chunk in value if chunk.strip()] + + @classmethod + def _parse_list_glob(cls, value, separator=','): + """Equivalent to _parse_list() but expands any glob patterns using glob(). + + However, unlike with glob() calls, the results remain relative paths. + + :param value: + :param separator: List items separator character. + :rtype: list + """ + glob_characters = ('*', '?', '[', ']', '{', '}') + values = cls._parse_list(value, separator=separator) + expanded_values = [] + for value in values: + + # Has globby characters? + if any(char in value for char in glob_characters): + # then expand the glob pattern while keeping paths *relative*: + expanded_values.extend(sorted( + os.path.relpath(path, os.getcwd()) + for path in iglob(os.path.abspath(value)))) + + else: + # take the value as-is: + expanded_values.append(value) + + return expanded_values + + @classmethod + def _parse_dict(cls, value): + """Represents value as a dict. + + :param value: + :rtype: dict + """ + separator = '=' + result = {} + for line in cls._parse_list(value): + key, sep, val = line.partition(separator) + if sep != separator: + raise DistutilsOptionError( + 'Unable to parse option value to dict: %s' % value + ) + result[key.strip()] = val.strip() + + return result + + @classmethod + def _parse_bool(cls, value): + """Represents value as boolean. + + :param value: + :rtype: bool + """ + value = value.lower() + return value in ('1', 'true', 'yes') + + @classmethod + def _exclude_files_parser(cls, key): + """Returns a parser function to make sure field inputs + are not files. + + Parses a value after getting the key so error messages are + more informative. + + :param key: + :rtype: callable + """ + + def parser(value): + exclude_directive = 'file:' + if value.startswith(exclude_directive): + raise ValueError( + 'Only strings are accepted for the {0} field, ' + 'files are not accepted'.format(key) + ) + return value + + return parser + + @classmethod + def _parse_file(cls, value): + """Represents value as a string, allowing including text + from nearest files using `file:` directive. + + Directive is sandboxed and won't reach anything outside + directory with setup.py. + + Examples: + file: README.rst, CHANGELOG.md, src/file.txt + + :param str value: + :rtype: str + """ + include_directive = 'file:' + + if not isinstance(value, str): + return value + + if not value.startswith(include_directive): + return value + + spec = value[len(include_directive) :] + filepaths = (os.path.abspath(path.strip()) for path in spec.split(',')) + return '\n'.join( + cls._read_file(path) + for path in filepaths + if (cls._assert_local(path) or True) and os.path.isfile(path) + ) + + @staticmethod + def _assert_local(filepath): + if not filepath.startswith(os.getcwd()): + raise DistutilsOptionError('`file:` directive can not access %s' % filepath) + + @staticmethod + def _read_file(filepath): + with io.open(filepath, encoding='utf-8') as f: + return f.read() + + @classmethod + def _parse_attr(cls, value, package_dir=None): + """Represents value as a module attribute. + + Examples: + attr: package.attr + attr: package.module.attr + + :param str value: + :rtype: str + """ + attr_directive = 'attr:' + if not value.startswith(attr_directive): + return value + + attrs_path = value.replace(attr_directive, '').strip().split('.') + attr_name = attrs_path.pop() + + module_name = '.'.join(attrs_path) + module_name = module_name or '__init__' + + parent_path = os.getcwd() + if package_dir: + if attrs_path[0] in package_dir: + # A custom path was specified for the module we want to import + custom_path = package_dir[attrs_path[0]] + parts = custom_path.rsplit('/', 1) + if len(parts) > 1: + parent_path = os.path.join(os.getcwd(), parts[0]) + module_name = parts[1] + else: + module_name = custom_path + elif '' in package_dir: + # A custom parent directory was specified for all root modules + parent_path = os.path.join(os.getcwd(), package_dir['']) + + with patch_path(parent_path): + try: + # attempt to load value statically + return getattr(StaticModule(module_name), attr_name) + except Exception: + # fallback to simple import + module = importlib.import_module(module_name) + + return getattr(module, attr_name) + + @classmethod + def _get_parser_compound(cls, *parse_methods): + """Returns parser function to represents value as a list. + + Parses a value applying given methods one after another. + + :param parse_methods: + :rtype: callable + """ + + def parse(value): + parsed = value + + for method in parse_methods: + parsed = method(parsed) + + return parsed + + return parse + + @classmethod + def _parse_section_to_dict(cls, section_options, values_parser=None): + """Parses section options into a dictionary. + + Optionally applies a given parser to values. + + :param dict section_options: + :param callable values_parser: + :rtype: dict + """ + value = {} + values_parser = values_parser or (lambda val: val) + for key, (_, val) in section_options.items(): + value[key] = values_parser(val) + return value + + def parse_section(self, section_options): + """Parses configuration file section. + + :param dict section_options: + """ + for (name, (_, value)) in section_options.items(): + try: + self[name] = value + + except KeyError: + pass # Keep silent for a new option may appear anytime. + + def parse(self): + """Parses configuration file items from one + or more related sections. + + """ + for section_name, section_options in self.sections.items(): + + method_postfix = '' + if section_name: # [section.option] variant + method_postfix = '_%s' % section_name + + section_parser_method = getattr( + self, + # Dots in section names are translated into dunderscores. + ('parse_section%s' % method_postfix).replace('.', '__'), + None, + ) + + if section_parser_method is None: + raise DistutilsOptionError( + 'Unsupported distribution option section: [%s.%s]' + % (self.section_prefix, section_name) + ) + + section_parser_method(section_options) + + def _deprecated_config_handler(self, func, msg, warning_class): + """this function will wrap around parameters that are deprecated + + :param msg: deprecation message + :param warning_class: class of warning exception to be raised + :param func: function to be wrapped around + """ + + @wraps(func) + def config_handler(*args, **kwargs): + warnings.warn(msg, warning_class) + return func(*args, **kwargs) + + return config_handler + + +class ConfigMetadataHandler(ConfigHandler): + + section_prefix = 'metadata' + + aliases = { + 'home_page': 'url', + 'summary': 'description', + 'classifier': 'classifiers', + 'platform': 'platforms', + } + + strict_mode = False + """We need to keep it loose, to be partially compatible with + `pbr` and `d2to1` packages which also uses `metadata` section. + + """ + + def __init__( + self, target_obj, options, ignore_option_errors=False, package_dir=None + ): + super(ConfigMetadataHandler, self).__init__( + target_obj, options, ignore_option_errors + ) + self.package_dir = package_dir + + @property + def parsers(self): + """Metadata item name to parser function mapping.""" + parse_list = self._parse_list + parse_file = self._parse_file + parse_dict = self._parse_dict + exclude_files_parser = self._exclude_files_parser + + return { + 'platforms': parse_list, + 'keywords': parse_list, + 'provides': parse_list, + 'requires': self._deprecated_config_handler( + parse_list, + "The requires parameter is deprecated, please use " + "install_requires for runtime dependencies.", + DeprecationWarning, + ), + 'obsoletes': parse_list, + 'classifiers': self._get_parser_compound(parse_file, parse_list), + 'license': exclude_files_parser('license'), + 'license_file': self._deprecated_config_handler( + exclude_files_parser('license_file'), + "The license_file parameter is deprecated, " + "use license_files instead.", + DeprecationWarning, + ), + 'license_files': parse_list, + 'description': parse_file, + 'long_description': parse_file, + 'version': self._parse_version, + 'project_urls': parse_dict, + } + + def _parse_version(self, value): + """Parses `version` option value. + + :param value: + :rtype: str + + """ + version = self._parse_file(value) + + if version != value: + version = version.strip() + # Be strict about versions loaded from file because it's easy to + # accidentally include newlines and other unintended content + if isinstance(parse(version), LegacyVersion): + tmpl = ( + 'Version loaded from {value} does not ' + 'comply with PEP 440: {version}' + ) + raise DistutilsOptionError(tmpl.format(**locals())) + + return version + + version = self._parse_attr(value, self.package_dir) + + if callable(version): + version = version() + + if not isinstance(version, str): + if hasattr(version, '__iter__'): + version = '.'.join(map(str, version)) + else: + version = '%s' % version + + return version + + +class ConfigOptionsHandler(ConfigHandler): + + section_prefix = 'options' + + @property + def parsers(self): + """Metadata item name to parser function mapping.""" + parse_list = self._parse_list + parse_list_semicolon = partial(self._parse_list, separator=';') + parse_bool = self._parse_bool + parse_dict = self._parse_dict + parse_cmdclass = self._parse_cmdclass + + return { + 'zip_safe': parse_bool, + 'include_package_data': parse_bool, + 'package_dir': parse_dict, + 'scripts': parse_list, + 'eager_resources': parse_list, + 'dependency_links': parse_list, + 'namespace_packages': parse_list, + 'install_requires': parse_list_semicolon, + 'setup_requires': parse_list_semicolon, + 'tests_require': parse_list_semicolon, + 'packages': self._parse_packages, + 'entry_points': self._parse_file, + 'py_modules': parse_list, + 'python_requires': SpecifierSet, + 'cmdclass': parse_cmdclass, + } + + def _parse_cmdclass(self, value): + def resolve_class(qualified_class_name): + idx = qualified_class_name.rfind('.') + class_name = qualified_class_name[idx + 1 :] + pkg_name = qualified_class_name[:idx] + + module = __import__(pkg_name) + + return getattr(module, class_name) + + return {k: resolve_class(v) for k, v in self._parse_dict(value).items()} + + def _parse_packages(self, value): + """Parses `packages` option value. + + :param value: + :rtype: list + """ + find_directives = ['find:', 'find_namespace:'] + trimmed_value = value.strip() + + if trimmed_value not in find_directives: + return self._parse_list(value) + + findns = trimmed_value == find_directives[1] + + # Read function arguments from a dedicated section. + find_kwargs = self.parse_section_packages__find( + self.sections.get('packages.find', {}) + ) + + if findns: + from setuptools import find_namespace_packages as find_packages + else: + from setuptools import find_packages + + return find_packages(**find_kwargs) + + def parse_section_packages__find(self, section_options): + """Parses `packages.find` configuration file section. + + To be used in conjunction with _parse_packages(). + + :param dict section_options: + """ + section_data = self._parse_section_to_dict(section_options, self._parse_list) + + valid_keys = ['where', 'include', 'exclude'] + + find_kwargs = dict( + [(k, v) for k, v in section_data.items() if k in valid_keys and v] + ) + + where = find_kwargs.get('where') + if where is not None: + find_kwargs['where'] = where[0] # cast list to single val + + return find_kwargs + + def parse_section_entry_points(self, section_options): + """Parses `entry_points` configuration file section. + + :param dict section_options: + """ + parsed = self._parse_section_to_dict(section_options, self._parse_list) + self['entry_points'] = parsed + + def _parse_package_data(self, section_options): + parsed = self._parse_section_to_dict(section_options, self._parse_list) + + root = parsed.get('*') + if root: + parsed[''] = root + del parsed['*'] + + return parsed + + def parse_section_package_data(self, section_options): + """Parses `package_data` configuration file section. + + :param dict section_options: + """ + self['package_data'] = self._parse_package_data(section_options) + + def parse_section_exclude_package_data(self, section_options): + """Parses `exclude_package_data` configuration file section. + + :param dict section_options: + """ + self['exclude_package_data'] = self._parse_package_data(section_options) + + def parse_section_extras_require(self, section_options): + """Parses `extras_require` configuration file section. + + :param dict section_options: + """ + parse_list = partial(self._parse_list, separator=';') + self['extras_require'] = self._parse_section_to_dict( + section_options, parse_list + ) + + def parse_section_data_files(self, section_options): + """Parses `data_files` configuration file section. + + :param dict section_options: + """ + parsed = self._parse_section_to_dict(section_options, self._parse_list_glob) + self['data_files'] = [(k, v) for k, v in parsed.items()] diff --git a/MLPY/Lib/site-packages/setuptools/dep_util.py b/MLPY/Lib/site-packages/setuptools/dep_util.py new file mode 100644 index 0000000000000000000000000000000000000000..521eb716a5ebbcbc2c59654c4e71c3f0ff1abf26 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/dep_util.py @@ -0,0 +1,25 @@ +from distutils.dep_util import newer_group + + +# yes, this is was almost entirely copy-pasted from +# 'newer_pairwise()', this is just another convenience +# function. +def newer_pairwise_group(sources_groups, targets): + """Walk both arguments in parallel, testing if each source group is newer + than its corresponding target. Returns a pair of lists (sources_groups, + targets) where sources is newer than target, according to the semantics + of 'newer_group()'. + """ + if len(sources_groups) != len(targets): + raise ValueError( + "'sources_group' and 'targets' must be the same length") + + # build a pair of lists (sources_groups, targets) where source is newer + n_sources = [] + n_targets = [] + for i in range(len(sources_groups)): + if newer_group(sources_groups[i], targets[i]): + n_sources.append(sources_groups[i]) + n_targets.append(targets[i]) + + return n_sources, n_targets diff --git a/MLPY/Lib/site-packages/setuptools/depends.py b/MLPY/Lib/site-packages/setuptools/depends.py new file mode 100644 index 0000000000000000000000000000000000000000..8be6928a31feca4549a6ec789a8db751d5bb8c97 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/depends.py @@ -0,0 +1,175 @@ +import sys +import marshal +import contextlib +import dis +from distutils.version import StrictVersion + +from ._imp import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE +from . import _imp + + +__all__ = [ + 'Require', 'find_module', 'get_module_constant', 'extract_constant' +] + + +class Require: + """A prerequisite to building or installing a distribution""" + + def __init__( + self, name, requested_version, module, homepage='', + attribute=None, format=None): + + if format is None and requested_version is not None: + format = StrictVersion + + if format is not None: + requested_version = format(requested_version) + if attribute is None: + attribute = '__version__' + + self.__dict__.update(locals()) + del self.self + + def full_name(self): + """Return full package/distribution name, w/version""" + if self.requested_version is not None: + return '%s-%s' % (self.name, self.requested_version) + return self.name + + def version_ok(self, version): + """Is 'version' sufficiently up-to-date?""" + return self.attribute is None or self.format is None or \ + str(version) != "unknown" and version >= self.requested_version + + def get_version(self, paths=None, default="unknown"): + """Get version number of installed module, 'None', or 'default' + + Search 'paths' for module. If not found, return 'None'. If found, + return the extracted version attribute, or 'default' if no version + attribute was specified, or the value cannot be determined without + importing the module. The version is formatted according to the + requirement's version format (if any), unless it is 'None' or the + supplied 'default'. + """ + + if self.attribute is None: + try: + f, p, i = find_module(self.module, paths) + if f: + f.close() + return default + except ImportError: + return None + + v = get_module_constant(self.module, self.attribute, default, paths) + + if v is not None and v is not default and self.format is not None: + return self.format(v) + + return v + + def is_present(self, paths=None): + """Return true if dependency is present on 'paths'""" + return self.get_version(paths) is not None + + def is_current(self, paths=None): + """Return true if dependency is present and up-to-date on 'paths'""" + version = self.get_version(paths) + if version is None: + return False + return self.version_ok(version) + + +def maybe_close(f): + @contextlib.contextmanager + def empty(): + yield + return + if not f: + return empty() + + return contextlib.closing(f) + + +def get_module_constant(module, symbol, default=-1, paths=None): + """Find 'module' by searching 'paths', and extract 'symbol' + + Return 'None' if 'module' does not exist on 'paths', or it does not define + 'symbol'. If the module defines 'symbol' as a constant, return the + constant. Otherwise, return 'default'.""" + + try: + f, path, (suffix, mode, kind) = info = find_module(module, paths) + except ImportError: + # Module doesn't exist + return None + + with maybe_close(f): + if kind == PY_COMPILED: + f.read(8) # skip magic & date + code = marshal.load(f) + elif kind == PY_FROZEN: + code = _imp.get_frozen_object(module, paths) + elif kind == PY_SOURCE: + code = compile(f.read(), path, 'exec') + else: + # Not something we can parse; we'll have to import it. :( + imported = _imp.get_module(module, paths, info) + return getattr(imported, symbol, None) + + return extract_constant(code, symbol, default) + + +def extract_constant(code, symbol, default=-1): + """Extract the constant value of 'symbol' from 'code' + + If the name 'symbol' is bound to a constant value by the Python code + object 'code', return that value. If 'symbol' is bound to an expression, + return 'default'. Otherwise, return 'None'. + + Return value is based on the first assignment to 'symbol'. 'symbol' must + be a global, or at least a non-"fast" local in the code block. That is, + only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol' + must be present in 'code.co_names'. + """ + if symbol not in code.co_names: + # name's not there, can't possibly be an assignment + return None + + name_idx = list(code.co_names).index(symbol) + + STORE_NAME = 90 + STORE_GLOBAL = 97 + LOAD_CONST = 100 + + const = default + + for byte_code in dis.Bytecode(code): + op = byte_code.opcode + arg = byte_code.arg + + if op == LOAD_CONST: + const = code.co_consts[arg] + elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL): + return const + else: + const = default + + +def _update_globals(): + """ + Patch the globals to remove the objects not available on some platforms. + + XXX it'd be better to test assertions about bytecode instead. + """ + + if not sys.platform.startswith('java') and sys.platform != 'cli': + return + incompatible = 'extract_constant', 'get_module_constant' + for name in incompatible: + del globals()[name] + __all__.remove(name) + + +_update_globals() diff --git a/MLPY/Lib/site-packages/setuptools/dist.py b/MLPY/Lib/site-packages/setuptools/dist.py new file mode 100644 index 0000000000000000000000000000000000000000..8e2111a52ba7d5dc2a361d03303d93261c25abd5 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/dist.py @@ -0,0 +1,1150 @@ +# -*- coding: utf-8 -*- +__all__ = ['Distribution'] + +import io +import sys +import re +import os +import warnings +import numbers +import distutils.log +import distutils.core +import distutils.cmd +import distutils.dist +import distutils.command +from distutils.util import strtobool +from distutils.debug import DEBUG +from distutils.fancy_getopt import translate_longopt +from glob import iglob +import itertools +import textwrap +from typing import List, Optional, TYPE_CHECKING + +from collections import defaultdict +from email import message_from_file + +from distutils.errors import DistutilsOptionError, DistutilsSetupError +from distutils.util import rfc822_escape +from distutils.version import StrictVersion + +from setuptools.extern import packaging +from setuptools.extern import ordered_set +from setuptools.extern.more_itertools import unique_everseen + +from . import SetuptoolsDeprecationWarning + +import setuptools +import setuptools.command +from setuptools import windows_support +from setuptools.monkey import get_unpatched +from setuptools.config import parse_configuration +import pkg_resources + +if TYPE_CHECKING: + from email.message import Message + +__import__('setuptools.extern.packaging.specifiers') +__import__('setuptools.extern.packaging.version') + + +def _get_unpatched(cls): + warnings.warn("Do not call this function", DistDeprecationWarning) + return get_unpatched(cls) + + +def get_metadata_version(self): + mv = getattr(self, 'metadata_version', None) + if mv is None: + mv = StrictVersion('2.1') + self.metadata_version = mv + return mv + + +def rfc822_unescape(content: str) -> str: + """Reverse RFC-822 escaping by removing leading whitespaces from content.""" + lines = content.splitlines() + if len(lines) == 1: + return lines[0].lstrip() + return '\n'.join((lines[0].lstrip(), textwrap.dedent('\n'.join(lines[1:])))) + + +def _read_field_from_msg(msg: "Message", field: str) -> Optional[str]: + """Read Message header field.""" + value = msg[field] + if value == 'UNKNOWN': + return None + return value + + +def _read_field_unescaped_from_msg(msg: "Message", field: str) -> Optional[str]: + """Read Message header field and apply rfc822_unescape.""" + value = _read_field_from_msg(msg, field) + if value is None: + return value + return rfc822_unescape(value) + + +def _read_list_from_msg(msg: "Message", field: str) -> Optional[List[str]]: + """Read Message header field and return all results as list.""" + values = msg.get_all(field, None) + if values == []: + return None + return values + + +def _read_payload_from_msg(msg: "Message") -> Optional[str]: + value = msg.get_payload().strip() + if value == 'UNKNOWN': + return None + return value + + +def read_pkg_file(self, file): + """Reads the metadata values from a file object.""" + msg = message_from_file(file) + + self.metadata_version = StrictVersion(msg['metadata-version']) + self.name = _read_field_from_msg(msg, 'name') + self.version = _read_field_from_msg(msg, 'version') + self.description = _read_field_from_msg(msg, 'summary') + # we are filling author only. + self.author = _read_field_from_msg(msg, 'author') + self.maintainer = None + self.author_email = _read_field_from_msg(msg, 'author-email') + self.maintainer_email = None + self.url = _read_field_from_msg(msg, 'home-page') + self.license = _read_field_unescaped_from_msg(msg, 'license') + + if 'download-url' in msg: + self.download_url = _read_field_from_msg(msg, 'download-url') + else: + self.download_url = None + + self.long_description = _read_field_unescaped_from_msg(msg, 'description') + if self.long_description is None and self.metadata_version >= StrictVersion('2.1'): + self.long_description = _read_payload_from_msg(msg) + self.description = _read_field_from_msg(msg, 'summary') + + if 'keywords' in msg: + self.keywords = _read_field_from_msg(msg, 'keywords').split(',') + + self.platforms = _read_list_from_msg(msg, 'platform') + self.classifiers = _read_list_from_msg(msg, 'classifier') + + # PEP 314 - these fields only exist in 1.1 + if self.metadata_version == StrictVersion('1.1'): + self.requires = _read_list_from_msg(msg, 'requires') + self.provides = _read_list_from_msg(msg, 'provides') + self.obsoletes = _read_list_from_msg(msg, 'obsoletes') + else: + self.requires = None + self.provides = None + self.obsoletes = None + + self.license_files = _read_list_from_msg(msg, 'license-file') + + +def single_line(val): + # quick and dirty validation for description pypa/setuptools#1390 + if '\n' in val: + # TODO after 2021-07-31: Replace with `raise ValueError("newlines not allowed")` + warnings.warn("newlines not allowed and will break in the future") + val = val.replace('\n', ' ') + return val + + +# Based on Python 3.5 version +def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME + """Write the PKG-INFO format data to a file object.""" + version = self.get_metadata_version() + + def write_field(key, value): + file.write("%s: %s\n" % (key, value)) + + write_field('Metadata-Version', str(version)) + write_field('Name', self.get_name()) + write_field('Version', self.get_version()) + write_field('Summary', single_line(self.get_description())) + write_field('Home-page', self.get_url()) + + optional_fields = ( + ('Author', 'author'), + ('Author-email', 'author_email'), + ('Maintainer', 'maintainer'), + ('Maintainer-email', 'maintainer_email'), + ) + + for field, attr in optional_fields: + attr_val = getattr(self, attr, None) + if attr_val is not None: + write_field(field, attr_val) + + license = rfc822_escape(self.get_license()) + write_field('License', license) + if self.download_url: + write_field('Download-URL', self.download_url) + for project_url in self.project_urls.items(): + write_field('Project-URL', '%s, %s' % project_url) + + keywords = ','.join(self.get_keywords()) + if keywords: + write_field('Keywords', keywords) + + for platform in self.get_platforms(): + write_field('Platform', platform) + + self._write_list(file, 'Classifier', self.get_classifiers()) + + # PEP 314 + self._write_list(file, 'Requires', self.get_requires()) + self._write_list(file, 'Provides', self.get_provides()) + self._write_list(file, 'Obsoletes', self.get_obsoletes()) + + # Setuptools specific for PEP 345 + if hasattr(self, 'python_requires'): + write_field('Requires-Python', self.python_requires) + + # PEP 566 + if self.long_description_content_type: + write_field('Description-Content-Type', self.long_description_content_type) + if self.provides_extras: + for extra in self.provides_extras: + write_field('Provides-Extra', extra) + + self._write_list(file, 'License-File', self.license_files or []) + + file.write("\n%s\n\n" % self.get_long_description()) + + +sequence = tuple, list + + +def check_importable(dist, attr, value): + try: + ep = pkg_resources.EntryPoint.parse('x=' + value) + assert not ep.extras + except (TypeError, ValueError, AttributeError, AssertionError) as e: + raise DistutilsSetupError( + "%r must be importable 'module:attrs' string (got %r)" % (attr, value) + ) from e + + +def assert_string_list(dist, attr, value): + """Verify that value is a string list""" + try: + # verify that value is a list or tuple to exclude unordered + # or single-use iterables + assert isinstance(value, (list, tuple)) + # verify that elements of value are strings + assert ''.join(value) != value + except (TypeError, ValueError, AttributeError, AssertionError) as e: + raise DistutilsSetupError( + "%r must be a list of strings (got %r)" % (attr, value) + ) from e + + +def check_nsp(dist, attr, value): + """Verify that namespace packages are valid""" + ns_packages = value + assert_string_list(dist, attr, ns_packages) + for nsp in ns_packages: + if not dist.has_contents_for(nsp): + raise DistutilsSetupError( + "Distribution contains no modules or packages for " + + "namespace package %r" % nsp + ) + parent, sep, child = nsp.rpartition('.') + if parent and parent not in ns_packages: + distutils.log.warn( + "WARNING: %r is declared as a package namespace, but %r" + " is not: please correct this in setup.py", + nsp, + parent, + ) + + +def check_extras(dist, attr, value): + """Verify that extras_require mapping is valid""" + try: + list(itertools.starmap(_check_extra, value.items())) + except (TypeError, ValueError, AttributeError) as e: + raise DistutilsSetupError( + "'extras_require' must be a dictionary whose values are " + "strings or lists of strings containing valid project/version " + "requirement specifiers." + ) from e + + +def _check_extra(extra, reqs): + name, sep, marker = extra.partition(':') + if marker and pkg_resources.invalid_marker(marker): + raise DistutilsSetupError("Invalid environment marker: " + marker) + list(pkg_resources.parse_requirements(reqs)) + + +def assert_bool(dist, attr, value): + """Verify that value is True, False, 0, or 1""" + if bool(value) != value: + tmpl = "{attr!r} must be a boolean value (got {value!r})" + raise DistutilsSetupError(tmpl.format(attr=attr, value=value)) + + +def invalid_unless_false(dist, attr, value): + if not value: + warnings.warn(f"{attr} is ignored.", DistDeprecationWarning) + return + raise DistutilsSetupError(f"{attr} is invalid.") + + +def check_requirements(dist, attr, value): + """Verify that install_requires is a valid requirements list""" + try: + list(pkg_resources.parse_requirements(value)) + if isinstance(value, (dict, set)): + raise TypeError("Unordered types are not allowed") + except (TypeError, ValueError) as error: + tmpl = ( + "{attr!r} must be a string or list of strings " + "containing valid project/version requirement specifiers; {error}" + ) + raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error + + +def check_specifier(dist, attr, value): + """Verify that value is a valid version specifier""" + try: + packaging.specifiers.SpecifierSet(value) + except (packaging.specifiers.InvalidSpecifier, AttributeError) as error: + tmpl = ( + "{attr!r} must be a string " "containing valid version specifiers; {error}" + ) + raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error + + +def check_entry_points(dist, attr, value): + """Verify that entry_points map is parseable""" + try: + pkg_resources.EntryPoint.parse_map(value) + except ValueError as e: + raise DistutilsSetupError(e) from e + + +def check_test_suite(dist, attr, value): + if not isinstance(value, str): + raise DistutilsSetupError("test_suite must be a string") + + +def check_package_data(dist, attr, value): + """Verify that value is a dictionary of package names to glob lists""" + if not isinstance(value, dict): + raise DistutilsSetupError( + "{!r} must be a dictionary mapping package names to lists of " + "string wildcard patterns".format(attr) + ) + for k, v in value.items(): + if not isinstance(k, str): + raise DistutilsSetupError( + "keys of {!r} dict must be strings (got {!r})".format(attr, k) + ) + assert_string_list(dist, 'values of {!r} dict'.format(attr), v) + + +def check_packages(dist, attr, value): + for pkgname in value: + if not re.match(r'\w+(\.\w+)*', pkgname): + distutils.log.warn( + "WARNING: %r not a valid package name; please use only " + ".-separated package names in setup.py", + pkgname, + ) + + +_Distribution = get_unpatched(distutils.core.Distribution) + + +class Distribution(_Distribution): + """Distribution with support for tests and package data + + This is an enhanced version of 'distutils.dist.Distribution' that + effectively adds the following new optional keyword arguments to 'setup()': + + 'install_requires' -- a string or sequence of strings specifying project + versions that the distribution requires when installed, in the format + used by 'pkg_resources.require()'. They will be installed + automatically when the package is installed. If you wish to use + packages that are not available in PyPI, or want to give your users an + alternate download location, you can add a 'find_links' option to the + '[easy_install]' section of your project's 'setup.cfg' file, and then + setuptools will scan the listed web pages for links that satisfy the + requirements. + + 'extras_require' -- a dictionary mapping names of optional "extras" to the + additional requirement(s) that using those extras incurs. For example, + this:: + + extras_require = dict(reST = ["docutils>=0.3", "reSTedit"]) + + indicates that the distribution can optionally provide an extra + capability called "reST", but it can only be used if docutils and + reSTedit are installed. If the user installs your package using + EasyInstall and requests one of your extras, the corresponding + additional requirements will be installed if needed. + + 'test_suite' -- the name of a test suite to run for the 'test' command. + If the user runs 'python setup.py test', the package will be installed, + and the named test suite will be run. The format is the same as + would be used on a 'unittest.py' command line. That is, it is the + dotted name of an object to import and call to generate a test suite. + + 'package_data' -- a dictionary mapping package names to lists of filenames + or globs to use to find data files contained in the named packages. + If the dictionary has filenames or globs listed under '""' (the empty + string), those names will be searched for in every package, in addition + to any names for the specific package. Data files found using these + names/globs will be installed along with the package, in the same + location as the package. Note that globs are allowed to reference + the contents of non-package subdirectories, as long as you use '/' as + a path separator. (Globs are automatically converted to + platform-specific paths at runtime.) + + In addition to these new keywords, this class also has several new methods + for manipulating the distribution's contents. For example, the 'include()' + and 'exclude()' methods can be thought of as in-place add and subtract + commands that add or remove packages, modules, extensions, and so on from + the distribution. + """ + + _DISTUTILS_UNSUPPORTED_METADATA = { + 'long_description_content_type': lambda: None, + 'project_urls': dict, + 'provides_extras': ordered_set.OrderedSet, + 'license_file': lambda: None, + 'license_files': lambda: None, + } + + _patched_dist = None + + def patch_missing_pkg_info(self, attrs): + # Fake up a replacement for the data that would normally come from + # PKG-INFO, but which might not yet be built if this is a fresh + # checkout. + # + if not attrs or 'name' not in attrs or 'version' not in attrs: + return + key = pkg_resources.safe_name(str(attrs['name'])).lower() + dist = pkg_resources.working_set.by_key.get(key) + if dist is not None and not dist.has_metadata('PKG-INFO'): + dist._version = pkg_resources.safe_version(str(attrs['version'])) + self._patched_dist = dist + + def __init__(self, attrs=None): + have_package_data = hasattr(self, "package_data") + if not have_package_data: + self.package_data = {} + attrs = attrs or {} + self.dist_files = [] + # Filter-out setuptools' specific options. + self.src_root = attrs.pop("src_root", None) + self.patch_missing_pkg_info(attrs) + self.dependency_links = attrs.pop('dependency_links', []) + self.setup_requires = attrs.pop('setup_requires', []) + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + vars(self).setdefault(ep.name, None) + _Distribution.__init__( + self, + { + k: v + for k, v in attrs.items() + if k not in self._DISTUTILS_UNSUPPORTED_METADATA + }, + ) + + self._set_metadata_defaults(attrs) + + self.metadata.version = self._normalize_version( + self._validate_version(self.metadata.version) + ) + self._finalize_requires() + + def _set_metadata_defaults(self, attrs): + """ + Fill-in missing metadata fields not supported by distutils. + Some fields may have been set by other tools (e.g. pbr). + Those fields (vars(self.metadata)) take precedence to + supplied attrs. + """ + for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items(): + vars(self.metadata).setdefault(option, attrs.get(option, default())) + + @staticmethod + def _normalize_version(version): + if isinstance(version, setuptools.sic) or version is None: + return version + + normalized = str(packaging.version.Version(version)) + if version != normalized: + tmpl = "Normalizing '{version}' to '{normalized}'" + warnings.warn(tmpl.format(**locals())) + return normalized + return version + + @staticmethod + def _validate_version(version): + if isinstance(version, numbers.Number): + # Some people apparently take "version number" too literally :) + version = str(version) + + if version is not None: + try: + packaging.version.Version(version) + except (packaging.version.InvalidVersion, TypeError): + warnings.warn( + "The version specified (%r) is an invalid version, this " + "may not work as expected with newer versions of " + "setuptools, pip, and PyPI. Please see PEP 440 for more " + "details." % version + ) + return setuptools.sic(version) + return version + + def _finalize_requires(self): + """ + Set `metadata.python_requires` and fix environment markers + in `install_requires` and `extras_require`. + """ + if getattr(self, 'python_requires', None): + self.metadata.python_requires = self.python_requires + + if getattr(self, 'extras_require', None): + for extra in self.extras_require.keys(): + # Since this gets called multiple times at points where the + # keys have become 'converted' extras, ensure that we are only + # truly adding extras we haven't seen before here. + extra = extra.split(':')[0] + if extra: + self.metadata.provides_extras.add(extra) + + self._convert_extras_requirements() + self._move_install_requirements_markers() + + def _convert_extras_requirements(self): + """ + Convert requirements in `extras_require` of the form + `"extra": ["barbazquux; {marker}"]` to + `"extra:{marker}": ["barbazquux"]`. + """ + spec_ext_reqs = getattr(self, 'extras_require', None) or {} + self._tmp_extras_require = defaultdict(list) + for section, v in spec_ext_reqs.items(): + # Do not strip empty sections. + self._tmp_extras_require[section] + for r in pkg_resources.parse_requirements(v): + suffix = self._suffix_for(r) + self._tmp_extras_require[section + suffix].append(r) + + @staticmethod + def _suffix_for(req): + """ + For a requirement, return the 'extras_require' suffix for + that requirement. + """ + return ':' + str(req.marker) if req.marker else '' + + def _move_install_requirements_markers(self): + """ + Move requirements in `install_requires` that are using environment + markers `extras_require`. + """ + + # divide the install_requires into two sets, simple ones still + # handled by install_requires and more complex ones handled + # by extras_require. + + def is_simple_req(req): + return not req.marker + + spec_inst_reqs = getattr(self, 'install_requires', None) or () + inst_reqs = list(pkg_resources.parse_requirements(spec_inst_reqs)) + simple_reqs = filter(is_simple_req, inst_reqs) + complex_reqs = itertools.filterfalse(is_simple_req, inst_reqs) + self.install_requires = list(map(str, simple_reqs)) + + for r in complex_reqs: + self._tmp_extras_require[':' + str(r.marker)].append(r) + self.extras_require = dict( + (k, [str(r) for r in map(self._clean_req, v)]) + for k, v in self._tmp_extras_require.items() + ) + + def _clean_req(self, req): + """ + Given a Requirement, remove environment markers and return it. + """ + req.marker = None + return req + + def _finalize_license_files(self): + """Compute names of all license files which should be included.""" + license_files: Optional[List[str]] = self.metadata.license_files + patterns: List[str] = license_files if license_files else [] + + license_file: Optional[str] = self.metadata.license_file + if license_file and license_file not in patterns: + patterns.append(license_file) + + if license_files is None and license_file is None: + # Default patterns match the ones wheel uses + # See https://wheel.readthedocs.io/en/stable/user_guide.html + # -> 'Including license files in the generated wheel file' + patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') + + self.metadata.license_files = list( + unique_everseen(self._expand_patterns(patterns)) + ) + + @staticmethod + def _expand_patterns(patterns): + """ + >>> list(Distribution._expand_patterns(['LICENSE'])) + ['LICENSE'] + >>> list(Distribution._expand_patterns(['setup.cfg', 'LIC*'])) + ['setup.cfg', 'LICENSE'] + """ + return ( + path + for pattern in patterns + for path in sorted(iglob(pattern)) + if not path.endswith('~') and os.path.isfile(path) + ) + + # FIXME: 'Distribution._parse_config_files' is too complex (14) + def _parse_config_files(self, filenames=None): # noqa: C901 + """ + Adapted from distutils.dist.Distribution.parse_config_files, + this method provides the same functionality in subtly-improved + ways. + """ + from configparser import ConfigParser + + # Ignore install directory options if we have a venv + ignore_options = ( + [] + if sys.prefix == sys.base_prefix + else [ + 'install-base', + 'install-platbase', + 'install-lib', + 'install-platlib', + 'install-purelib', + 'install-headers', + 'install-scripts', + 'install-data', + 'prefix', + 'exec-prefix', + 'home', + 'user', + 'root', + ] + ) + + ignore_options = frozenset(ignore_options) + + if filenames is None: + filenames = self.find_config_files() + + if DEBUG: + self.announce("Distribution.parse_config_files():") + + parser = ConfigParser() + parser.optionxform = str + for filename in filenames: + with io.open(filename, encoding='utf-8') as reader: + if DEBUG: + self.announce(" reading {filename}".format(**locals())) + parser.read_file(reader) + for section in parser.sections(): + options = parser.options(section) + opt_dict = self.get_option_dict(section) + + for opt in options: + if opt == '__name__' or opt in ignore_options: + continue + + val = parser.get(section, opt) + opt = self.warn_dash_deprecation(opt, section) + opt = self.make_option_lowercase(opt, section) + opt_dict[opt] = (filename, val) + + # Make the ConfigParser forget everything (so we retain + # the original filenames that options come from) + parser.__init__() + + if 'global' not in self.command_options: + return + + # If there was a "global" section in the config file, use it + # to set Distribution options. + + for (opt, (src, val)) in self.command_options['global'].items(): + alias = self.negative_opt.get(opt) + if alias: + val = not strtobool(val) + elif opt in ('verbose', 'dry_run'): # ugh! + val = strtobool(val) + + try: + setattr(self, alias or opt, val) + except ValueError as e: + raise DistutilsOptionError(e) from e + + def warn_dash_deprecation(self, opt, section): + if section in ( + 'options.extras_require', + 'options.data_files', + ): + return opt + + underscore_opt = opt.replace('-', '_') + commands = distutils.command.__all__ + self._setuptools_commands() + if ( + not section.startswith('options') + and section != 'metadata' + and section not in commands + ): + return underscore_opt + + if '-' in opt: + warnings.warn( + "Usage of dash-separated '%s' will not be supported in future " + "versions. Please use the underscore name '%s' instead" + % (opt, underscore_opt) + ) + return underscore_opt + + def _setuptools_commands(self): + try: + dist = pkg_resources.get_distribution('setuptools') + return list(dist.get_entry_map('distutils.commands')) + except pkg_resources.DistributionNotFound: + # during bootstrapping, distribution doesn't exist + return [] + + def make_option_lowercase(self, opt, section): + if section != 'metadata' or opt.islower(): + return opt + + lowercase_opt = opt.lower() + warnings.warn( + "Usage of uppercase key '%s' in '%s' will be deprecated in future " + "versions. Please use lowercase '%s' instead" + % (opt, section, lowercase_opt) + ) + return lowercase_opt + + # FIXME: 'Distribution._set_command_options' is too complex (14) + def _set_command_options(self, command_obj, option_dict=None): # noqa: C901 + """ + Set the options for 'command_obj' from 'option_dict'. Basically + this means copying elements of a dictionary ('option_dict') to + attributes of an instance ('command'). + + 'command_obj' must be a Command instance. If 'option_dict' is not + supplied, uses the standard option dictionary for this command + (from 'self.command_options'). + + (Adopted from distutils.dist.Distribution._set_command_options) + """ + command_name = command_obj.get_command_name() + if option_dict is None: + option_dict = self.get_option_dict(command_name) + + if DEBUG: + self.announce(" setting options for '%s' command:" % command_name) + for (option, (source, value)) in option_dict.items(): + if DEBUG: + self.announce(" %s = %s (from %s)" % (option, value, source)) + try: + bool_opts = [translate_longopt(o) for o in command_obj.boolean_options] + except AttributeError: + bool_opts = [] + try: + neg_opt = command_obj.negative_opt + except AttributeError: + neg_opt = {} + + try: + is_string = isinstance(value, str) + if option in neg_opt and is_string: + setattr(command_obj, neg_opt[option], not strtobool(value)) + elif option in bool_opts and is_string: + setattr(command_obj, option, strtobool(value)) + elif hasattr(command_obj, option): + setattr(command_obj, option, value) + else: + raise DistutilsOptionError( + "error in %s: command '%s' has no such option '%s'" + % (source, command_name, option) + ) + except ValueError as e: + raise DistutilsOptionError(e) from e + + def parse_config_files(self, filenames=None, ignore_option_errors=False): + """Parses configuration files from various levels + and loads configuration. + + """ + self._parse_config_files(filenames=filenames) + + parse_configuration( + self, self.command_options, ignore_option_errors=ignore_option_errors + ) + self._finalize_requires() + self._finalize_license_files() + + def fetch_build_eggs(self, requires): + """Resolve pre-setup requirements""" + resolved_dists = pkg_resources.working_set.resolve( + pkg_resources.parse_requirements(requires), + installer=self.fetch_build_egg, + replace_conflicting=True, + ) + for dist in resolved_dists: + pkg_resources.working_set.add(dist, replace=True) + return resolved_dists + + def finalize_options(self): + """ + Allow plugins to apply arbitrary operations to the + distribution. Each hook may optionally define a 'order' + to influence the order of execution. Smaller numbers + go first and the default is 0. + """ + group = 'setuptools.finalize_distribution_options' + + def by_order(hook): + return getattr(hook, 'order', 0) + + defined = pkg_resources.iter_entry_points(group) + filtered = itertools.filterfalse(self._removed, defined) + loaded = map(lambda e: e.load(), filtered) + for ep in sorted(loaded, key=by_order): + ep(self) + + @staticmethod + def _removed(ep): + """ + When removing an entry point, if metadata is loaded + from an older version of Setuptools, that removed + entry point will attempt to be loaded and will fail. + See #2765 for more details. + """ + removed = { + # removed 2021-09-05 + '2to3_doctests', + } + return ep.name in removed + + def _finalize_setup_keywords(self): + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + value = getattr(self, ep.name, None) + if value is not None: + ep.require(installer=self.fetch_build_egg) + ep.load()(self, ep.name, value) + + def get_egg_cache_dir(self): + egg_cache_dir = os.path.join(os.curdir, '.eggs') + if not os.path.exists(egg_cache_dir): + os.mkdir(egg_cache_dir) + windows_support.hide_file(egg_cache_dir) + readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt') + with open(readme_txt_filename, 'w') as f: + f.write( + 'This directory contains eggs that were downloaded ' + 'by setuptools to build, test, and run plug-ins.\n\n' + ) + f.write( + 'This directory caches those eggs to prevent ' + 'repeated downloads.\n\n' + ) + f.write('However, it is safe to delete this directory.\n\n') + + return egg_cache_dir + + def fetch_build_egg(self, req): + """Fetch an egg needed for building""" + from setuptools.installer import fetch_build_egg + + return fetch_build_egg(self, req) + + def get_command_class(self, command): + """Pluggable version of get_command_class()""" + if command in self.cmdclass: + return self.cmdclass[command] + + eps = pkg_resources.iter_entry_points('distutils.commands', command) + for ep in eps: + ep.require(installer=self.fetch_build_egg) + self.cmdclass[command] = cmdclass = ep.load() + return cmdclass + else: + return _Distribution.get_command_class(self, command) + + def print_commands(self): + for ep in pkg_resources.iter_entry_points('distutils.commands'): + if ep.name not in self.cmdclass: + # don't require extras as the commands won't be invoked + cmdclass = ep.resolve() + self.cmdclass[ep.name] = cmdclass + return _Distribution.print_commands(self) + + def get_command_list(self): + for ep in pkg_resources.iter_entry_points('distutils.commands'): + if ep.name not in self.cmdclass: + # don't require extras as the commands won't be invoked + cmdclass = ep.resolve() + self.cmdclass[ep.name] = cmdclass + return _Distribution.get_command_list(self) + + def include(self, **attrs): + """Add items to distribution that are named in keyword arguments + + For example, 'dist.include(py_modules=["x"])' would add 'x' to + the distribution's 'py_modules' attribute, if it was not already + there. + + Currently, this method only supports inclusion for attributes that are + lists or tuples. If you need to add support for adding to other + attributes in this or a subclass, you can add an '_include_X' method, + where 'X' is the name of the attribute. The method will be called with + the value passed to 'include()'. So, 'dist.include(foo={"bar":"baz"})' + will try to call 'dist._include_foo({"bar":"baz"})', which can then + handle whatever special inclusion logic is needed. + """ + for k, v in attrs.items(): + include = getattr(self, '_include_' + k, None) + if include: + include(v) + else: + self._include_misc(k, v) + + def exclude_package(self, package): + """Remove packages, modules, and extensions in named package""" + + pfx = package + '.' + if self.packages: + self.packages = [ + p for p in self.packages if p != package and not p.startswith(pfx) + ] + + if self.py_modules: + self.py_modules = [ + p for p in self.py_modules if p != package and not p.startswith(pfx) + ] + + if self.ext_modules: + self.ext_modules = [ + p + for p in self.ext_modules + if p.name != package and not p.name.startswith(pfx) + ] + + def has_contents_for(self, package): + """Return true if 'exclude_package(package)' would do something""" + + pfx = package + '.' + + for p in self.iter_distribution_names(): + if p == package or p.startswith(pfx): + return True + + def _exclude_misc(self, name, value): + """Handle 'exclude()' for list/tuple attrs without a special handler""" + if not isinstance(value, sequence): + raise DistutilsSetupError( + "%s: setting must be a list or tuple (%r)" % (name, value) + ) + try: + old = getattr(self, name) + except AttributeError as e: + raise DistutilsSetupError("%s: No such distribution setting" % name) from e + if old is not None and not isinstance(old, sequence): + raise DistutilsSetupError( + name + ": this setting cannot be changed via include/exclude" + ) + elif old: + setattr(self, name, [item for item in old if item not in value]) + + def _include_misc(self, name, value): + """Handle 'include()' for list/tuple attrs without a special handler""" + + if not isinstance(value, sequence): + raise DistutilsSetupError("%s: setting must be a list (%r)" % (name, value)) + try: + old = getattr(self, name) + except AttributeError as e: + raise DistutilsSetupError("%s: No such distribution setting" % name) from e + if old is None: + setattr(self, name, value) + elif not isinstance(old, sequence): + raise DistutilsSetupError( + name + ": this setting cannot be changed via include/exclude" + ) + else: + new = [item for item in value if item not in old] + setattr(self, name, old + new) + + def exclude(self, **attrs): + """Remove items from distribution that are named in keyword arguments + + For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from + the distribution's 'py_modules' attribute. Excluding packages uses + the 'exclude_package()' method, so all of the package's contained + packages, modules, and extensions are also excluded. + + Currently, this method only supports exclusion from attributes that are + lists or tuples. If you need to add support for excluding from other + attributes in this or a subclass, you can add an '_exclude_X' method, + where 'X' is the name of the attribute. The method will be called with + the value passed to 'exclude()'. So, 'dist.exclude(foo={"bar":"baz"})' + will try to call 'dist._exclude_foo({"bar":"baz"})', which can then + handle whatever special exclusion logic is needed. + """ + for k, v in attrs.items(): + exclude = getattr(self, '_exclude_' + k, None) + if exclude: + exclude(v) + else: + self._exclude_misc(k, v) + + def _exclude_packages(self, packages): + if not isinstance(packages, sequence): + raise DistutilsSetupError( + "packages: setting must be a list or tuple (%r)" % (packages,) + ) + list(map(self.exclude_package, packages)) + + def _parse_command_opts(self, parser, args): + # Remove --with-X/--without-X options when processing command args + self.global_options = self.__class__.global_options + self.negative_opt = self.__class__.negative_opt + + # First, expand any aliases + command = args[0] + aliases = self.get_option_dict('aliases') + while command in aliases: + src, alias = aliases[command] + del aliases[command] # ensure each alias can expand only once! + import shlex + + args[:1] = shlex.split(alias, True) + command = args[0] + + nargs = _Distribution._parse_command_opts(self, parser, args) + + # Handle commands that want to consume all remaining arguments + cmd_class = self.get_command_class(command) + if getattr(cmd_class, 'command_consumes_arguments', None): + self.get_option_dict(command)['args'] = ("command line", nargs) + if nargs is not None: + return [] + + return nargs + + def get_cmdline_options(self): + """Return a '{cmd: {opt:val}}' map of all command-line options + + Option names are all long, but do not include the leading '--', and + contain dashes rather than underscores. If the option doesn't take + an argument (e.g. '--quiet'), the 'val' is 'None'. + + Note that options provided by config files are intentionally excluded. + """ + + d = {} + + for cmd, opts in self.command_options.items(): + + for opt, (src, val) in opts.items(): + + if src != "command line": + continue + + opt = opt.replace('_', '-') + + if val == 0: + cmdobj = self.get_command_obj(cmd) + neg_opt = self.negative_opt.copy() + neg_opt.update(getattr(cmdobj, 'negative_opt', {})) + for neg, pos in neg_opt.items(): + if pos == opt: + opt = neg + val = None + break + else: + raise AssertionError("Shouldn't be able to get here") + + elif val == 1: + val = None + + d.setdefault(cmd, {})[opt] = val + + return d + + def iter_distribution_names(self): + """Yield all packages, modules, and extension names in distribution""" + + for pkg in self.packages or (): + yield pkg + + for module in self.py_modules or (): + yield module + + for ext in self.ext_modules or (): + if isinstance(ext, tuple): + name, buildinfo = ext + else: + name = ext.name + if name.endswith('module'): + name = name[:-6] + yield name + + def handle_display_options(self, option_order): + """If there were any non-global "display-only" options + (--help-commands or the metadata display options) on the command + line, display the requested info and return true; else return + false. + """ + import sys + + if self.help_commands: + return _Distribution.handle_display_options(self, option_order) + + # Stdout may be StringIO (e.g. in tests) + if not isinstance(sys.stdout, io.TextIOWrapper): + return _Distribution.handle_display_options(self, option_order) + + # Don't wrap stdout if utf-8 is already the encoding. Provides + # workaround for #334. + if sys.stdout.encoding.lower() in ('utf-8', 'utf8'): + return _Distribution.handle_display_options(self, option_order) + + # Print metadata in UTF-8 no matter the platform + encoding = sys.stdout.encoding + errors = sys.stdout.errors + newline = sys.platform != 'win32' and '\n' or None + line_buffering = sys.stdout.line_buffering + + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), 'utf-8', errors, newline, line_buffering + ) + try: + return _Distribution.handle_display_options(self, option_order) + finally: + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), encoding, errors, newline, line_buffering + ) + + +class DistDeprecationWarning(SetuptoolsDeprecationWarning): + """Class for warning about deprecations in dist in + setuptools. Not ignored by default, unlike DeprecationWarning.""" diff --git a/MLPY/Lib/site-packages/setuptools/errors.py b/MLPY/Lib/site-packages/setuptools/errors.py new file mode 100644 index 0000000000000000000000000000000000000000..2701747f56cc77845159f2c5fee2d0ce114259af --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/errors.py @@ -0,0 +1,16 @@ +"""setuptools.errors + +Provides exceptions used by setuptools modules. +""" + +from distutils.errors import DistutilsError + + +class RemovedCommandError(DistutilsError, RuntimeError): + """Error used for commands that have been removed in setuptools. + + Since ``setuptools`` is built on ``distutils``, simply removing a command + from ``setuptools`` will make the behavior fall back to ``distutils``; this + error is raised if a command exists in ``distutils`` but has been actively + removed in ``setuptools``. + """ diff --git a/MLPY/Lib/site-packages/setuptools/extension.py b/MLPY/Lib/site-packages/setuptools/extension.py new file mode 100644 index 0000000000000000000000000000000000000000..1820722a494b1744a406e364bc3dc3aefc7dd059 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/extension.py @@ -0,0 +1,55 @@ +import re +import functools +import distutils.core +import distutils.errors +import distutils.extension + +from .monkey import get_unpatched + + +def _have_cython(): + """ + Return True if Cython can be imported. + """ + cython_impl = 'Cython.Distutils.build_ext' + try: + # from (cython_impl) import build_ext + __import__(cython_impl, fromlist=['build_ext']).build_ext + return True + except Exception: + pass + return False + + +# for compatibility +have_pyrex = _have_cython + +_Extension = get_unpatched(distutils.core.Extension) + + +class Extension(_Extension): + """Extension that uses '.c' files in place of '.pyx' files""" + + def __init__(self, name, sources, *args, **kw): + # The *args is needed for compatibility as calls may use positional + # arguments. py_limited_api may be set only via keyword. + self.py_limited_api = kw.pop("py_limited_api", False) + _Extension.__init__(self, name, sources, *args, **kw) + + def _convert_pyx_sources_to_lang(self): + """ + Replace sources with .pyx extensions to sources with the target + language extension. This mechanism allows language authors to supply + pre-converted sources but to prefer the .pyx sources. + """ + if _have_cython(): + # the build has Cython, so allow it to compile the .pyx files + return + lang = self.language or '' + target_ext = '.cpp' if lang.lower() == 'c++' else '.c' + sub = functools.partial(re.sub, '.pyx$', target_ext) + self.sources = list(map(sub, self.sources)) + + +class Library(Extension): + """Just like a regular Extension, but built as a library instead""" diff --git a/MLPY/Lib/site-packages/setuptools/extern/__init__.py b/MLPY/Lib/site-packages/setuptools/extern/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..baca1afabe94f3cf7a9309d8f11258a94fb19f06 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/extern/__init__.py @@ -0,0 +1,73 @@ +import importlib.util +import sys + + +class VendorImporter: + """ + A PEP 302 meta path importer for finding optionally-vendored + or otherwise naturally-installed packages from root_name. + """ + + def __init__(self, root_name, vendored_names=(), vendor_pkg=None): + self.root_name = root_name + self.vendored_names = set(vendored_names) + self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor') + + @property + def search_path(self): + """ + Search first the vendor package then as a natural package. + """ + yield self.vendor_pkg + '.' + yield '' + + def _module_matches_namespace(self, fullname): + """Figure out if the target module is vendored.""" + root, base, target = fullname.partition(self.root_name + '.') + return not root and any(map(target.startswith, self.vendored_names)) + + def load_module(self, fullname): + """ + Iterate over the search path to locate and load fullname. + """ + root, base, target = fullname.partition(self.root_name + '.') + for prefix in self.search_path: + try: + extant = prefix + target + __import__(extant) + mod = sys.modules[extant] + sys.modules[fullname] = mod + return mod + except ImportError: + pass + else: + raise ImportError( + "The '{target}' package is required; " + "normally this is bundled with this package so if you get " + "this warning, consult the packager of your " + "distribution.".format(**locals()) + ) + + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + + def find_spec(self, fullname, path=None, target=None): + """Return a module spec for vendored names.""" + return ( + importlib.util.spec_from_loader(fullname, self) + if self._module_matches_namespace(fullname) else None + ) + + def install(self): + """ + Install this importer into sys.meta_path if not already present. + """ + if self not in sys.meta_path: + sys.meta_path.append(self) + + +names = 'packaging', 'pyparsing', 'ordered_set', 'more_itertools', +VendorImporter(__name__, names, 'setuptools._vendor').install() diff --git a/MLPY/Lib/site-packages/setuptools/extern/__pycache__/__init__.cpython-39.pyc b/MLPY/Lib/site-packages/setuptools/extern/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c1c213270ee6c9724360de68c69bd0351fcce80 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/extern/__pycache__/__init__.cpython-39.pyc differ diff --git a/MLPY/Lib/site-packages/setuptools/glob.py b/MLPY/Lib/site-packages/setuptools/glob.py new file mode 100644 index 0000000000000000000000000000000000000000..87062b8187fa4f74a8c4edbaa60bd9a8b2d506a4 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/glob.py @@ -0,0 +1,167 @@ +""" +Filename globbing utility. Mostly a copy of `glob` from Python 3.5. + +Changes include: + * `yield from` and PEP3102 `*` removed. + * Hidden files are not ignored. +""" + +import os +import re +import fnmatch + +__all__ = ["glob", "iglob", "escape"] + + +def glob(pathname, recursive=False): + """Return a list of paths matching a pathname pattern. + + The pattern may contain simple shell-style wildcards a la + fnmatch. However, unlike fnmatch, filenames starting with a + dot are special cases that are not matched by '*' and '?' + patterns. + + If recursive is true, the pattern '**' will match any files and + zero or more directories and subdirectories. + """ + return list(iglob(pathname, recursive=recursive)) + + +def iglob(pathname, recursive=False): + """Return an iterator which yields the paths matching a pathname pattern. + + The pattern may contain simple shell-style wildcards a la + fnmatch. However, unlike fnmatch, filenames starting with a + dot are special cases that are not matched by '*' and '?' + patterns. + + If recursive is true, the pattern '**' will match any files and + zero or more directories and subdirectories. + """ + it = _iglob(pathname, recursive) + if recursive and _isrecursive(pathname): + s = next(it) # skip empty string + assert not s + return it + + +def _iglob(pathname, recursive): + dirname, basename = os.path.split(pathname) + glob_in_dir = glob2 if recursive and _isrecursive(basename) else glob1 + + if not has_magic(pathname): + if basename: + if os.path.lexists(pathname): + yield pathname + else: + # Patterns ending with a slash should match only directories + if os.path.isdir(dirname): + yield pathname + return + + if not dirname: + yield from glob_in_dir(dirname, basename) + return + # `os.path.split()` returns the argument itself as a dirname if it is a + # drive or UNC path. Prevent an infinite recursion if a drive or UNC path + # contains magic characters (i.e. r'\\?\C:'). + if dirname != pathname and has_magic(dirname): + dirs = _iglob(dirname, recursive) + else: + dirs = [dirname] + if not has_magic(basename): + glob_in_dir = glob0 + for dirname in dirs: + for name in glob_in_dir(dirname, basename): + yield os.path.join(dirname, name) + + +# These 2 helper functions non-recursively glob inside a literal directory. +# They return a list of basenames. `glob1` accepts a pattern while `glob0` +# takes a literal basename (so it only has to check for its existence). + + +def glob1(dirname, pattern): + if not dirname: + if isinstance(pattern, bytes): + dirname = os.curdir.encode('ASCII') + else: + dirname = os.curdir + try: + names = os.listdir(dirname) + except OSError: + return [] + return fnmatch.filter(names, pattern) + + +def glob0(dirname, basename): + if not basename: + # `os.path.split()` returns an empty basename for paths ending with a + # directory separator. 'q*x/' should match only directories. + if os.path.isdir(dirname): + return [basename] + else: + if os.path.lexists(os.path.join(dirname, basename)): + return [basename] + return [] + + +# This helper function recursively yields relative pathnames inside a literal +# directory. + + +def glob2(dirname, pattern): + assert _isrecursive(pattern) + yield pattern[:0] + for x in _rlistdir(dirname): + yield x + + +# Recursively yields relative pathnames inside a literal directory. +def _rlistdir(dirname): + if not dirname: + if isinstance(dirname, bytes): + dirname = os.curdir.encode('ASCII') + else: + dirname = os.curdir + try: + names = os.listdir(dirname) + except os.error: + return + for x in names: + yield x + path = os.path.join(dirname, x) if dirname else x + for y in _rlistdir(path): + yield os.path.join(x, y) + + +magic_check = re.compile('([*?[])') +magic_check_bytes = re.compile(b'([*?[])') + + +def has_magic(s): + if isinstance(s, bytes): + match = magic_check_bytes.search(s) + else: + match = magic_check.search(s) + return match is not None + + +def _isrecursive(pattern): + if isinstance(pattern, bytes): + return pattern == b'**' + else: + return pattern == '**' + + +def escape(pathname): + """Escape all special characters. + """ + # Escaping is done by wrapping any of "*?[" between square brackets. + # Metacharacters do not work in the drive part and shouldn't be escaped. + drive, pathname = os.path.splitdrive(pathname) + if isinstance(pathname, bytes): + pathname = magic_check_bytes.sub(br'[\1]', pathname) + else: + pathname = magic_check.sub(r'[\1]', pathname) + return drive + pathname diff --git a/MLPY/Lib/site-packages/setuptools/gui-32.exe b/MLPY/Lib/site-packages/setuptools/gui-32.exe new file mode 100644 index 0000000000000000000000000000000000000000..f8d3509653ba8f80ca7f3aa7f95616142ba83a94 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/gui-32.exe differ diff --git a/MLPY/Lib/site-packages/setuptools/gui-64.exe b/MLPY/Lib/site-packages/setuptools/gui-64.exe new file mode 100644 index 0000000000000000000000000000000000000000..330c51a5dde15a0bb610a48cd0ca11770c914dae Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/gui-64.exe differ diff --git a/MLPY/Lib/site-packages/setuptools/gui.exe b/MLPY/Lib/site-packages/setuptools/gui.exe new file mode 100644 index 0000000000000000000000000000000000000000..f8d3509653ba8f80ca7f3aa7f95616142ba83a94 Binary files /dev/null and b/MLPY/Lib/site-packages/setuptools/gui.exe differ diff --git a/MLPY/Lib/site-packages/setuptools/installer.py b/MLPY/Lib/site-packages/setuptools/installer.py new file mode 100644 index 0000000000000000000000000000000000000000..57e2b587aae05167540abdd2b53c7b5bcac298f0 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/installer.py @@ -0,0 +1,97 @@ +import glob +import os +import subprocess +import sys +import tempfile +from distutils import log +from distutils.errors import DistutilsError + +import pkg_resources +from setuptools.wheel import Wheel + + +def _fixup_find_links(find_links): + """Ensure find-links option end-up being a list of strings.""" + if isinstance(find_links, str): + return find_links.split() + assert isinstance(find_links, (tuple, list)) + return find_links + + +def fetch_build_egg(dist, req): # noqa: C901 # is too complex (16) # FIXME + """Fetch an egg needed for building. + + Use pip/wheel to fetch/build a wheel.""" + # Warn if wheel is not available + try: + pkg_resources.get_distribution('wheel') + except pkg_resources.DistributionNotFound: + dist.announce('WARNING: The wheel package is not available.', log.WARN) + # Ignore environment markers; if supplied, it is required. + req = strip_marker(req) + # Take easy_install options into account, but do not override relevant + # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll + # take precedence. + opts = dist.get_option_dict('easy_install') + if 'allow_hosts' in opts: + raise DistutilsError('the `allow-hosts` option is not supported ' + 'when using pip to install requirements.') + quiet = 'PIP_QUIET' not in os.environ and 'PIP_VERBOSE' not in os.environ + if 'PIP_INDEX_URL' in os.environ: + index_url = None + elif 'index_url' in opts: + index_url = opts['index_url'][1] + else: + index_url = None + find_links = ( + _fixup_find_links(opts['find_links'][1])[:] if 'find_links' in opts + else [] + ) + if dist.dependency_links: + find_links.extend(dist.dependency_links) + eggs_dir = os.path.realpath(dist.get_egg_cache_dir()) + environment = pkg_resources.Environment() + for egg_dist in pkg_resources.find_distributions(eggs_dir): + if egg_dist in req and environment.can_add(egg_dist): + return egg_dist + with tempfile.TemporaryDirectory() as tmpdir: + cmd = [ + sys.executable, '-m', 'pip', + '--disable-pip-version-check', + 'wheel', '--no-deps', + '-w', tmpdir, + ] + if quiet: + cmd.append('--quiet') + if index_url is not None: + cmd.extend(('--index-url', index_url)) + for link in find_links or []: + cmd.extend(('--find-links', link)) + # If requirement is a PEP 508 direct URL, directly pass + # the URL to pip, as `req @ url` does not work on the + # command line. + cmd.append(req.url or str(req)) + try: + subprocess.check_call(cmd) + except subprocess.CalledProcessError as e: + raise DistutilsError(str(e)) from e + wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0]) + dist_location = os.path.join(eggs_dir, wheel.egg_name()) + wheel.install_as_egg(dist_location) + dist_metadata = pkg_resources.PathMetadata( + dist_location, os.path.join(dist_location, 'EGG-INFO')) + dist = pkg_resources.Distribution.from_filename( + dist_location, metadata=dist_metadata) + return dist + + +def strip_marker(req): + """ + Return a new requirement without the environment marker to avoid + calling pip with something like `babel; extra == "i18n"`, which + would always be ignored. + """ + # create a copy to avoid mutating the input + req = pkg_resources.Requirement.parse(str(req)) + req.marker = None + return req diff --git a/MLPY/Lib/site-packages/setuptools/launch.py b/MLPY/Lib/site-packages/setuptools/launch.py new file mode 100644 index 0000000000000000000000000000000000000000..0208fdf33b640cd9791359d74673bb90cfb87f96 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/launch.py @@ -0,0 +1,36 @@ +""" +Launch the Python script on the command line after +setuptools is bootstrapped via import. +""" + +# Note that setuptools gets imported implicitly by the +# invocation of this script using python -m setuptools.launch + +import tokenize +import sys + + +def run(): + """ + Run the script in sys.argv[1] as if it had + been invoked naturally. + """ + __builtins__ + script_name = sys.argv[1] + namespace = dict( + __file__=script_name, + __name__='__main__', + __doc__=None, + ) + sys.argv[:] = sys.argv[1:] + + open_ = getattr(tokenize, 'open', open) + with open_(script_name) as fid: + script = fid.read() + norm_script = script.replace('\\r\\n', '\\n') + code = compile(norm_script, script_name, 'exec') + exec(code, namespace) + + +if __name__ == '__main__': + run() diff --git a/MLPY/Lib/site-packages/setuptools/monkey.py b/MLPY/Lib/site-packages/setuptools/monkey.py new file mode 100644 index 0000000000000000000000000000000000000000..fb36dc1a97a9f1f2a52c25fb6b872a7afa640be7 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/monkey.py @@ -0,0 +1,177 @@ +""" +Monkey patching of distutils. +""" + +import sys +import distutils.filelist +import platform +import types +import functools +from importlib import import_module +import inspect + +import setuptools + +__all__ = [] +""" +Everything is private. Contact the project team +if you think you need this functionality. +""" + + +def _get_mro(cls): + """ + Returns the bases classes for cls sorted by the MRO. + + Works around an issue on Jython where inspect.getmro will not return all + base classes if multiple classes share the same name. Instead, this + function will return a tuple containing the class itself, and the contents + of cls.__bases__. See https://github.com/pypa/setuptools/issues/1024. + """ + if platform.python_implementation() == "Jython": + return (cls,) + cls.__bases__ + return inspect.getmro(cls) + + +def get_unpatched(item): + lookup = ( + get_unpatched_class if isinstance(item, type) else + get_unpatched_function if isinstance(item, types.FunctionType) else + lambda item: None + ) + return lookup(item) + + +def get_unpatched_class(cls): + """Protect against re-patching the distutils if reloaded + + Also ensures that no other distutils extension monkeypatched the distutils + first. + """ + external_bases = ( + cls + for cls in _get_mro(cls) + if not cls.__module__.startswith('setuptools') + ) + base = next(external_bases) + if not base.__module__.startswith('distutils'): + msg = "distutils has already been patched by %r" % cls + raise AssertionError(msg) + return base + + +def patch_all(): + # we can't patch distutils.cmd, alas + distutils.core.Command = setuptools.Command + + has_issue_12885 = sys.version_info <= (3, 5, 3) + + if has_issue_12885: + # fix findall bug in distutils (http://bugs.python.org/issue12885) + distutils.filelist.findall = setuptools.findall + + needs_warehouse = ( + sys.version_info < (2, 7, 13) + or + (3, 4) < sys.version_info < (3, 4, 6) + or + (3, 5) < sys.version_info <= (3, 5, 3) + ) + + if needs_warehouse: + warehouse = 'https://upload.pypi.org/legacy/' + distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse + + _patch_distribution_metadata() + + # Install Distribution throughout the distutils + for module in distutils.dist, distutils.core, distutils.cmd: + module.Distribution = setuptools.dist.Distribution + + # Install the patched Extension + distutils.core.Extension = setuptools.extension.Extension + distutils.extension.Extension = setuptools.extension.Extension + if 'distutils.command.build_ext' in sys.modules: + sys.modules['distutils.command.build_ext'].Extension = ( + setuptools.extension.Extension + ) + + patch_for_msvc_specialized_compiler() + + +def _patch_distribution_metadata(): + """Patch write_pkg_file and read_pkg_file for higher metadata standards""" + for attr in ('write_pkg_file', 'read_pkg_file', 'get_metadata_version'): + new_val = getattr(setuptools.dist, attr) + setattr(distutils.dist.DistributionMetadata, attr, new_val) + + +def patch_func(replacement, target_mod, func_name): + """ + Patch func_name in target_mod with replacement + + Important - original must be resolved by name to avoid + patching an already patched function. + """ + original = getattr(target_mod, func_name) + + # set the 'unpatched' attribute on the replacement to + # point to the original. + vars(replacement).setdefault('unpatched', original) + + # replace the function in the original module + setattr(target_mod, func_name, replacement) + + +def get_unpatched_function(candidate): + return getattr(candidate, 'unpatched') + + +def patch_for_msvc_specialized_compiler(): + """ + Patch functions in distutils to use standalone Microsoft Visual C++ + compilers. + """ + # import late to avoid circular imports on Python < 3.5 + msvc = import_module('setuptools.msvc') + + if platform.system() != 'Windows': + # Compilers only available on Microsoft Windows + return + + def patch_params(mod_name, func_name): + """ + Prepare the parameters for patch_func to patch indicated function. + """ + repl_prefix = 'msvc9_' if 'msvc9' in mod_name else 'msvc14_' + repl_name = repl_prefix + func_name.lstrip('_') + repl = getattr(msvc, repl_name) + mod = import_module(mod_name) + if not hasattr(mod, func_name): + raise ImportError(func_name) + return repl, mod, func_name + + # Python 2.7 to 3.4 + msvc9 = functools.partial(patch_params, 'distutils.msvc9compiler') + + # Python 3.5+ + msvc14 = functools.partial(patch_params, 'distutils._msvccompiler') + + try: + # Patch distutils.msvc9compiler + patch_func(*msvc9('find_vcvarsall')) + patch_func(*msvc9('query_vcvarsall')) + except ImportError: + pass + + try: + # Patch distutils._msvccompiler._get_vc_env + patch_func(*msvc14('_get_vc_env')) + except ImportError: + pass + + try: + # Patch distutils._msvccompiler.gen_lib_options for Numpy + patch_func(*msvc14('gen_lib_options')) + except ImportError: + pass diff --git a/MLPY/Lib/site-packages/setuptools/msvc.py b/MLPY/Lib/site-packages/setuptools/msvc.py new file mode 100644 index 0000000000000000000000000000000000000000..281ea1c2af6b0eb5f02ecc6d115f2d6884be74b5 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/msvc.py @@ -0,0 +1,1805 @@ +""" +Improved support for Microsoft Visual C++ compilers. + +Known supported compilers: +-------------------------- +Microsoft Visual C++ 9.0: + Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) + Microsoft Windows SDK 6.1 (x86, x64, ia64) + Microsoft Windows SDK 7.0 (x86, x64, ia64) + +Microsoft Visual C++ 10.0: + Microsoft Windows SDK 7.1 (x86, x64, ia64) + +Microsoft Visual C++ 14.X: + Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) + Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) + Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64) + +This may also support compilers shipped with compatible Visual Studio versions. +""" + +import json +from io import open +from os import listdir, pathsep +from os.path import join, isfile, isdir, dirname +import sys +import contextlib +import platform +import itertools +import subprocess +import distutils.errors +from setuptools.extern.packaging.version import LegacyVersion +from setuptools.extern.more_itertools import unique_everseen + +from .monkey import get_unpatched + +if platform.system() == 'Windows': + import winreg + from os import environ +else: + # Mock winreg and environ so the module can be imported on this platform. + + class winreg: + HKEY_USERS = None + HKEY_CURRENT_USER = None + HKEY_LOCAL_MACHINE = None + HKEY_CLASSES_ROOT = None + + environ = dict() + +_msvc9_suppress_errors = ( + # msvc9compiler isn't available on some platforms + ImportError, + + # msvc9compiler raises DistutilsPlatformError in some + # environments. See #1118. + distutils.errors.DistutilsPlatformError, +) + +try: + from distutils.msvc9compiler import Reg +except _msvc9_suppress_errors: + pass + + +def msvc9_find_vcvarsall(version): + """ + Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone + compiler build for Python + (VCForPython / Microsoft Visual C++ Compiler for Python 2.7). + + Fall back to original behavior when the standalone compiler is not + available. + + Redirect the path of "vcvarsall.bat". + + Parameters + ---------- + version: float + Required Microsoft Visual C++ version. + + Return + ------ + str + vcvarsall.bat path + """ + vc_base = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f' + key = vc_base % ('', version) + try: + # Per-user installs register the compiler path here + productdir = Reg.get_value(key, "installdir") + except KeyError: + try: + # All-user installs on a 64-bit system register here + key = vc_base % ('Wow6432Node\\', version) + productdir = Reg.get_value(key, "installdir") + except KeyError: + productdir = None + + if productdir: + vcvarsall = join(productdir, "vcvarsall.bat") + if isfile(vcvarsall): + return vcvarsall + + return get_unpatched(msvc9_find_vcvarsall)(version) + + +def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): + """ + Patched "distutils.msvc9compiler.query_vcvarsall" for support extra + Microsoft Visual C++ 9.0 and 10.0 compilers. + + Set environment without use of "vcvarsall.bat". + + Parameters + ---------- + ver: float + Required Microsoft Visual C++ version. + arch: str + Target architecture. + + Return + ------ + dict + environment + """ + # Try to get environment from vcvarsall.bat (Classical way) + try: + orig = get_unpatched(msvc9_query_vcvarsall) + return orig(ver, arch, *args, **kwargs) + except distutils.errors.DistutilsPlatformError: + # Pass error if Vcvarsall.bat is missing + pass + except ValueError: + # Pass error if environment not set after executing vcvarsall.bat + pass + + # If error, try to set environment directly + try: + return EnvironmentInfo(arch, ver).return_env() + except distutils.errors.DistutilsPlatformError as exc: + _augment_exception(exc, ver, arch) + raise + + +def _msvc14_find_vc2015(): + """Python 3.8 "distutils/_msvccompiler.py" backport""" + try: + key = winreg.OpenKey( + winreg.HKEY_LOCAL_MACHINE, + r"Software\Microsoft\VisualStudio\SxS\VC7", + 0, + winreg.KEY_READ | winreg.KEY_WOW64_32KEY + ) + except OSError: + return None, None + + best_version = 0 + best_dir = None + with key: + for i in itertools.count(): + try: + v, vc_dir, vt = winreg.EnumValue(key, i) + except OSError: + break + if v and vt == winreg.REG_SZ and isdir(vc_dir): + try: + version = int(float(v)) + except (ValueError, TypeError): + continue + if version >= 14 and version > best_version: + best_version, best_dir = version, vc_dir + return best_version, best_dir + + +def _msvc14_find_vc2017(): + """Python 3.8 "distutils/_msvccompiler.py" backport + + Returns "15, path" based on the result of invoking vswhere.exe + If no install is found, returns "None, None" + + The version is returned to avoid unnecessarily changing the function + result. It may be ignored when the path is not None. + + If vswhere.exe is not available, by definition, VS 2017 is not + installed. + """ + root = environ.get("ProgramFiles(x86)") or environ.get("ProgramFiles") + if not root: + return None, None + + try: + path = subprocess.check_output([ + join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), + "-latest", + "-prerelease", + "-requiresAny", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-requires", "Microsoft.VisualStudio.Workload.WDExpress", + "-property", "installationPath", + "-products", "*", + ]).decode(encoding="mbcs", errors="strict").strip() + except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): + return None, None + + path = join(path, "VC", "Auxiliary", "Build") + if isdir(path): + return 15, path + + return None, None + + +PLAT_SPEC_TO_RUNTIME = { + 'x86': 'x86', + 'x86_amd64': 'x64', + 'x86_arm': 'arm', + 'x86_arm64': 'arm64' +} + + +def _msvc14_find_vcvarsall(plat_spec): + """Python 3.8 "distutils/_msvccompiler.py" backport""" + _, best_dir = _msvc14_find_vc2017() + vcruntime = None + + if plat_spec in PLAT_SPEC_TO_RUNTIME: + vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec] + else: + vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86' + + if best_dir: + vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**", + vcruntime_plat, "Microsoft.VC14*.CRT", + "vcruntime140.dll") + try: + import glob + vcruntime = glob.glob(vcredist, recursive=True)[-1] + except (ImportError, OSError, LookupError): + vcruntime = None + + if not best_dir: + best_version, best_dir = _msvc14_find_vc2015() + if best_version: + vcruntime = join(best_dir, 'redist', vcruntime_plat, + "Microsoft.VC140.CRT", "vcruntime140.dll") + + if not best_dir: + return None, None + + vcvarsall = join(best_dir, "vcvarsall.bat") + if not isfile(vcvarsall): + return None, None + + if not vcruntime or not isfile(vcruntime): + vcruntime = None + + return vcvarsall, vcruntime + + +def _msvc14_get_vc_env(plat_spec): + """Python 3.8 "distutils/_msvccompiler.py" backport""" + if "DISTUTILS_USE_SDK" in environ: + return { + key.lower(): value + for key, value in environ.items() + } + + vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec) + if not vcvarsall: + raise distutils.errors.DistutilsPlatformError( + "Unable to find vcvarsall.bat" + ) + + try: + out = subprocess.check_output( + 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec), + stderr=subprocess.STDOUT, + ).decode('utf-16le', errors='replace') + except subprocess.CalledProcessError as exc: + raise distutils.errors.DistutilsPlatformError( + "Error executing {}".format(exc.cmd) + ) from exc + + env = { + key.lower(): value + for key, _, value in + (line.partition('=') for line in out.splitlines()) + if key and value + } + + if vcruntime: + env['py_vcruntime_redist'] = vcruntime + return env + + +def msvc14_get_vc_env(plat_spec): + """ + Patched "distutils._msvccompiler._get_vc_env" for support extra + Microsoft Visual C++ 14.X compilers. + + Set environment without use of "vcvarsall.bat". + + Parameters + ---------- + plat_spec: str + Target architecture. + + Return + ------ + dict + environment + """ + + # Always use backport from CPython 3.8 + try: + return _msvc14_get_vc_env(plat_spec) + except distutils.errors.DistutilsPlatformError as exc: + _augment_exception(exc, 14.0) + raise + + +def msvc14_gen_lib_options(*args, **kwargs): + """ + Patched "distutils._msvccompiler.gen_lib_options" for fix + compatibility between "numpy.distutils" and "distutils._msvccompiler" + (for Numpy < 1.11.2) + """ + if "numpy.distutils" in sys.modules: + import numpy as np + if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): + return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) + return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs) + + +def _augment_exception(exc, version, arch=''): + """ + Add details to the exception message to help guide the user + as to what action will resolve it. + """ + # Error if MSVC++ directory not found or environment not set + message = exc.args[0] + + if "vcvarsall" in message.lower() or "visual c" in message.lower(): + # Special error message if MSVC++ not installed + tmpl = 'Microsoft Visual C++ {version:0.1f} or greater is required.' + message = tmpl.format(**locals()) + msdownload = 'www.microsoft.com/download/details.aspx?id=%d' + if version == 9.0: + if arch.lower().find('ia64') > -1: + # For VC++ 9.0, if IA64 support is needed, redirect user + # to Windows SDK 7.0. + # Note: No download link available from Microsoft. + message += ' Get it with "Microsoft Windows SDK 7.0"' + else: + # For VC++ 9.0 redirect user to Vc++ for Python 2.7 : + # This redirection link is maintained by Microsoft. + # Contact vspython@microsoft.com if it needs updating. + message += ' Get it from http://aka.ms/vcpython27' + elif version == 10.0: + # For VC++ 10.0 Redirect user to Windows SDK 7.1 + message += ' Get it with "Microsoft Windows SDK 7.1": ' + message += msdownload % 8279 + elif version >= 14.0: + # For VC++ 14.X Redirect user to latest Visual C++ Build Tools + message += (' Get it with "Microsoft C++ Build Tools": ' + r'https://visualstudio.microsoft.com' + r'/visual-cpp-build-tools/') + + exc.args = (message, ) + + +class PlatformInfo: + """ + Current and Target Architectures information. + + Parameters + ---------- + arch: str + Target architecture. + """ + current_cpu = environ.get('processor_architecture', '').lower() + + def __init__(self, arch): + self.arch = arch.lower().replace('x64', 'amd64') + + @property + def target_cpu(self): + """ + Return Target CPU architecture. + + Return + ------ + str + Target CPU + """ + return self.arch[self.arch.find('_') + 1:] + + def target_is_x86(self): + """ + Return True if target CPU is x86 32 bits.. + + Return + ------ + bool + CPU is x86 32 bits + """ + return self.target_cpu == 'x86' + + def current_is_x86(self): + """ + Return True if current CPU is x86 32 bits.. + + Return + ------ + bool + CPU is x86 32 bits + """ + return self.current_cpu == 'x86' + + def current_dir(self, hidex86=False, x64=False): + """ + Current platform specific subfolder. + + Parameters + ---------- + hidex86: bool + return '' and not '\x86' if architecture is x86. + x64: bool + return '\x64' and not '\amd64' if architecture is amd64. + + Return + ------ + str + subfolder: '\target', or '' (see hidex86 parameter) + """ + return ( + '' if (self.current_cpu == 'x86' and hidex86) else + r'\x64' if (self.current_cpu == 'amd64' and x64) else + r'\%s' % self.current_cpu + ) + + def target_dir(self, hidex86=False, x64=False): + r""" + Target platform specific subfolder. + + Parameters + ---------- + hidex86: bool + return '' and not '\x86' if architecture is x86. + x64: bool + return '\x64' and not '\amd64' if architecture is amd64. + + Return + ------ + str + subfolder: '\current', or '' (see hidex86 parameter) + """ + return ( + '' if (self.target_cpu == 'x86' and hidex86) else + r'\x64' if (self.target_cpu == 'amd64' and x64) else + r'\%s' % self.target_cpu + ) + + def cross_dir(self, forcex86=False): + r""" + Cross platform specific subfolder. + + Parameters + ---------- + forcex86: bool + Use 'x86' as current architecture even if current architecture is + not x86. + + Return + ------ + str + subfolder: '' if target architecture is current architecture, + '\current_target' if not. + """ + current = 'x86' if forcex86 else self.current_cpu + return ( + '' if self.target_cpu == current else + self.target_dir().replace('\\', '\\%s_' % current) + ) + + +class RegistryInfo: + """ + Microsoft Visual Studio related registry information. + + Parameters + ---------- + platform_info: PlatformInfo + "PlatformInfo" instance. + """ + HKEYS = (winreg.HKEY_USERS, + winreg.HKEY_CURRENT_USER, + winreg.HKEY_LOCAL_MACHINE, + winreg.HKEY_CLASSES_ROOT) + + def __init__(self, platform_info): + self.pi = platform_info + + @property + def visualstudio(self): + """ + Microsoft Visual Studio root registry key. + + Return + ------ + str + Registry key + """ + return 'VisualStudio' + + @property + def sxs(self): + """ + Microsoft Visual Studio SxS registry key. + + Return + ------ + str + Registry key + """ + return join(self.visualstudio, 'SxS') + + @property + def vc(self): + """ + Microsoft Visual C++ VC7 registry key. + + Return + ------ + str + Registry key + """ + return join(self.sxs, 'VC7') + + @property + def vs(self): + """ + Microsoft Visual Studio VS7 registry key. + + Return + ------ + str + Registry key + """ + return join(self.sxs, 'VS7') + + @property + def vc_for_python(self): + """ + Microsoft Visual C++ for Python registry key. + + Return + ------ + str + Registry key + """ + return r'DevDiv\VCForPython' + + @property + def microsoft_sdk(self): + """ + Microsoft SDK registry key. + + Return + ------ + str + Registry key + """ + return 'Microsoft SDKs' + + @property + def windows_sdk(self): + """ + Microsoft Windows/Platform SDK registry key. + + Return + ------ + str + Registry key + """ + return join(self.microsoft_sdk, 'Windows') + + @property + def netfx_sdk(self): + """ + Microsoft .NET Framework SDK registry key. + + Return + ------ + str + Registry key + """ + return join(self.microsoft_sdk, 'NETFXSDK') + + @property + def windows_kits_roots(self): + """ + Microsoft Windows Kits Roots registry key. + + Return + ------ + str + Registry key + """ + return r'Windows Kits\Installed Roots' + + def microsoft(self, key, x86=False): + """ + Return key in Microsoft software registry. + + Parameters + ---------- + key: str + Registry key path where look. + x86: str + Force x86 software registry. + + Return + ------ + str + Registry key + """ + node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node' + return join('Software', node64, 'Microsoft', key) + + def lookup(self, key, name): + """ + Look for values in registry in Microsoft software registry. + + Parameters + ---------- + key: str + Registry key path where look. + name: str + Value name to find. + + Return + ------ + str + value + """ + key_read = winreg.KEY_READ + openkey = winreg.OpenKey + closekey = winreg.CloseKey + ms = self.microsoft + for hkey in self.HKEYS: + bkey = None + try: + bkey = openkey(hkey, ms(key), 0, key_read) + except (OSError, IOError): + if not self.pi.current_is_x86(): + try: + bkey = openkey(hkey, ms(key, True), 0, key_read) + except (OSError, IOError): + continue + else: + continue + try: + return winreg.QueryValueEx(bkey, name)[0] + except (OSError, IOError): + pass + finally: + if bkey: + closekey(bkey) + + +class SystemInfo: + """ + Microsoft Windows and Visual Studio related system information. + + Parameters + ---------- + registry_info: RegistryInfo + "RegistryInfo" instance. + vc_ver: float + Required Microsoft Visual C++ version. + """ + + # Variables and properties in this class use originals CamelCase variables + # names from Microsoft source files for more easy comparison. + WinDir = environ.get('WinDir', '') + ProgramFiles = environ.get('ProgramFiles', '') + ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles) + + def __init__(self, registry_info, vc_ver=None): + self.ri = registry_info + self.pi = self.ri.pi + + self.known_vs_paths = self.find_programdata_vs_vers() + + # Except for VS15+, VC version is aligned with VS version + self.vs_ver = self.vc_ver = ( + vc_ver or self._find_latest_available_vs_ver()) + + def _find_latest_available_vs_ver(self): + """ + Find the latest VC version + + Return + ------ + float + version + """ + reg_vc_vers = self.find_reg_vs_vers() + + if not (reg_vc_vers or self.known_vs_paths): + raise distutils.errors.DistutilsPlatformError( + 'No Microsoft Visual C++ version found') + + vc_vers = set(reg_vc_vers) + vc_vers.update(self.known_vs_paths) + return sorted(vc_vers)[-1] + + def find_reg_vs_vers(self): + """ + Find Microsoft Visual Studio versions available in registry. + + Return + ------ + list of float + Versions + """ + ms = self.ri.microsoft + vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs) + vs_vers = [] + for hkey, key in itertools.product(self.ri.HKEYS, vckeys): + try: + bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ) + except (OSError, IOError): + continue + with bkey: + subkeys, values, _ = winreg.QueryInfoKey(bkey) + for i in range(values): + with contextlib.suppress(ValueError): + ver = float(winreg.EnumValue(bkey, i)[0]) + if ver not in vs_vers: + vs_vers.append(ver) + for i in range(subkeys): + with contextlib.suppress(ValueError): + ver = float(winreg.EnumKey(bkey, i)) + if ver not in vs_vers: + vs_vers.append(ver) + return sorted(vs_vers) + + def find_programdata_vs_vers(self): + r""" + Find Visual studio 2017+ versions from information in + "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances". + + Return + ------ + dict + float version as key, path as value. + """ + vs_versions = {} + instances_dir = \ + r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances' + + try: + hashed_names = listdir(instances_dir) + + except (OSError, IOError): + # Directory not exists with all Visual Studio versions + return vs_versions + + for name in hashed_names: + try: + # Get VS installation path from "state.json" file + state_path = join(instances_dir, name, 'state.json') + with open(state_path, 'rt', encoding='utf-8') as state_file: + state = json.load(state_file) + vs_path = state['installationPath'] + + # Raises OSError if this VS installation does not contain VC + listdir(join(vs_path, r'VC\Tools\MSVC')) + + # Store version and path + vs_versions[self._as_float_version( + state['installationVersion'])] = vs_path + + except (OSError, IOError, KeyError): + # Skip if "state.json" file is missing or bad format + continue + + return vs_versions + + @staticmethod + def _as_float_version(version): + """ + Return a string version as a simplified float version (major.minor) + + Parameters + ---------- + version: str + Version. + + Return + ------ + float + version + """ + return float('.'.join(version.split('.')[:2])) + + @property + def VSInstallDir(self): + """ + Microsoft Visual Studio directory. + + Return + ------ + str + path + """ + # Default path + default = join(self.ProgramFilesx86, + 'Microsoft Visual Studio %0.1f' % self.vs_ver) + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default + + @property + def VCInstallDir(self): + """ + Microsoft Visual C++ directory. + + Return + ------ + str + path + """ + path = self._guess_vc() or self._guess_vc_legacy() + + if not isdir(path): + msg = 'Microsoft Visual C++ directory not found' + raise distutils.errors.DistutilsPlatformError(msg) + + return path + + def _guess_vc(self): + """ + Locate Visual C++ for VS2017+. + + Return + ------ + str + path + """ + if self.vs_ver <= 14.0: + return '' + + try: + # First search in known VS paths + vs_dir = self.known_vs_paths[self.vs_ver] + except KeyError: + # Else, search with path from registry + vs_dir = self.VSInstallDir + + guess_vc = join(vs_dir, r'VC\Tools\MSVC') + + # Subdir with VC exact version as name + try: + # Update the VC version with real one instead of VS version + vc_ver = listdir(guess_vc)[-1] + self.vc_ver = self._as_float_version(vc_ver) + return join(guess_vc, vc_ver) + except (OSError, IOError, IndexError): + return '' + + def _guess_vc_legacy(self): + """ + Locate Visual C++ for versions prior to 2017. + + Return + ------ + str + path + """ + default = join(self.ProgramFilesx86, + r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver) + + # Try to get "VC++ for Python" path from registry as default path + reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver) + python_vc = self.ri.lookup(reg_path, 'installdir') + default_vc = join(python_vc, 'VC') if python_vc else default + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc + + @property + def WindowsSdkVersion(self): + """ + Microsoft Windows SDK versions for specified MSVC++ version. + + Return + ------ + tuple of str + versions + """ + if self.vs_ver <= 9.0: + return '7.0', '6.1', '6.0a' + elif self.vs_ver == 10.0: + return '7.1', '7.0a' + elif self.vs_ver == 11.0: + return '8.0', '8.0a' + elif self.vs_ver == 12.0: + return '8.1', '8.1a' + elif self.vs_ver >= 14.0: + return '10.0', '8.1' + + @property + def WindowsSdkLastVersion(self): + """ + Microsoft Windows SDK last version. + + Return + ------ + str + version + """ + return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib')) + + @property # noqa: C901 + def WindowsSdkDir(self): # noqa: C901 # is too complex (12) # FIXME + """ + Microsoft Windows SDK directory. + + Return + ------ + str + path + """ + sdkdir = '' + for ver in self.WindowsSdkVersion: + # Try to get it from registry + loc = join(self.ri.windows_sdk, 'v%s' % ver) + sdkdir = self.ri.lookup(loc, 'installationfolder') + if sdkdir: + break + if not sdkdir or not isdir(sdkdir): + # Try to get "VC++ for Python" version from registry + path = join(self.ri.vc_for_python, '%0.1f' % self.vc_ver) + install_base = self.ri.lookup(path, 'installdir') + if install_base: + sdkdir = join(install_base, 'WinSDK') + if not sdkdir or not isdir(sdkdir): + # If fail, use default new path + for ver in self.WindowsSdkVersion: + intver = ver[:ver.rfind('.')] + path = r'Microsoft SDKs\Windows Kits\%s' % intver + d = join(self.ProgramFiles, path) + if isdir(d): + sdkdir = d + if not sdkdir or not isdir(sdkdir): + # If fail, use default old path + for ver in self.WindowsSdkVersion: + path = r'Microsoft SDKs\Windows\v%s' % ver + d = join(self.ProgramFiles, path) + if isdir(d): + sdkdir = d + if not sdkdir: + # If fail, use Platform SDK + sdkdir = join(self.VCInstallDir, 'PlatformSDK') + return sdkdir + + @property + def WindowsSDKExecutablePath(self): + """ + Microsoft Windows SDK executable directory. + + Return + ------ + str + path + """ + # Find WinSDK NetFx Tools registry dir name + if self.vs_ver <= 11.0: + netfxver = 35 + arch = '' + else: + netfxver = 40 + hidex86 = True if self.vs_ver <= 12.0 else False + arch = self.pi.current_dir(x64=True, hidex86=hidex86) + fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-')) + + # list all possibles registry paths + regpaths = [] + if self.vs_ver >= 14.0: + for ver in self.NetFxSdkVersion: + regpaths += [join(self.ri.netfx_sdk, ver, fx)] + + for ver in self.WindowsSdkVersion: + regpaths += [join(self.ri.windows_sdk, 'v%sA' % ver, fx)] + + # Return installation folder from the more recent path + for path in regpaths: + execpath = self.ri.lookup(path, 'installationfolder') + if execpath: + return execpath + + @property + def FSharpInstallDir(self): + """ + Microsoft Visual F# directory. + + Return + ------ + str + path + """ + path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver) + return self.ri.lookup(path, 'productdir') or '' + + @property + def UniversalCRTSdkDir(self): + """ + Microsoft Universal CRT SDK directory. + + Return + ------ + str + path + """ + # Set Kit Roots versions for specified MSVC++ version + vers = ('10', '81') if self.vs_ver >= 14.0 else () + + # Find path of the more recent Kit + for ver in vers: + sdkdir = self.ri.lookup(self.ri.windows_kits_roots, + 'kitsroot%s' % ver) + if sdkdir: + return sdkdir or '' + + @property + def UniversalCRTSdkLastVersion(self): + """ + Microsoft Universal C Runtime SDK last version. + + Return + ------ + str + version + """ + return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib')) + + @property + def NetFxSdkVersion(self): + """ + Microsoft .NET Framework SDK versions. + + Return + ------ + tuple of str + versions + """ + # Set FxSdk versions for specified VS version + return (('4.7.2', '4.7.1', '4.7', + '4.6.2', '4.6.1', '4.6', + '4.5.2', '4.5.1', '4.5') + if self.vs_ver >= 14.0 else ()) + + @property + def NetFxSdkDir(self): + """ + Microsoft .NET Framework SDK directory. + + Return + ------ + str + path + """ + sdkdir = '' + for ver in self.NetFxSdkVersion: + loc = join(self.ri.netfx_sdk, ver) + sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder') + if sdkdir: + break + return sdkdir + + @property + def FrameworkDir32(self): + """ + Microsoft .NET Framework 32bit directory. + + Return + ------ + str + path + """ + # Default path + guess_fw = join(self.WinDir, r'Microsoft.NET\Framework') + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw + + @property + def FrameworkDir64(self): + """ + Microsoft .NET Framework 64bit directory. + + Return + ------ + str + path + """ + # Default path + guess_fw = join(self.WinDir, r'Microsoft.NET\Framework64') + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw + + @property + def FrameworkVersion32(self): + """ + Microsoft .NET Framework 32bit versions. + + Return + ------ + tuple of str + versions + """ + return self._find_dot_net_versions(32) + + @property + def FrameworkVersion64(self): + """ + Microsoft .NET Framework 64bit versions. + + Return + ------ + tuple of str + versions + """ + return self._find_dot_net_versions(64) + + def _find_dot_net_versions(self, bits): + """ + Find Microsoft .NET Framework versions. + + Parameters + ---------- + bits: int + Platform number of bits: 32 or 64. + + Return + ------ + tuple of str + versions + """ + # Find actual .NET version in registry + reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) + dot_net_dir = getattr(self, 'FrameworkDir%d' % bits) + ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or '' + + # Set .NET versions for specified MSVC++ version + if self.vs_ver >= 12.0: + return ver, 'v4.0' + elif self.vs_ver >= 10.0: + return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5' + elif self.vs_ver == 9.0: + return 'v3.5', 'v2.0.50727' + elif self.vs_ver == 8.0: + return 'v3.0', 'v2.0.50727' + + @staticmethod + def _use_last_dir_name(path, prefix=''): + """ + Return name of the last dir in path or '' if no dir found. + + Parameters + ---------- + path: str + Use dirs in this path + prefix: str + Use only dirs starting by this prefix + + Return + ------ + str + name + """ + matching_dirs = ( + dir_name + for dir_name in reversed(listdir(path)) + if isdir(join(path, dir_name)) and + dir_name.startswith(prefix) + ) + return next(matching_dirs, None) or '' + + +class EnvironmentInfo: + """ + Return environment variables for specified Microsoft Visual C++ version + and platform : Lib, Include, Path and libpath. + + This function is compatible with Microsoft Visual C++ 9.0 to 14.X. + + Script created by analysing Microsoft environment configuration files like + "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ... + + Parameters + ---------- + arch: str + Target architecture. + vc_ver: float + Required Microsoft Visual C++ version. If not set, autodetect the last + version. + vc_min_ver: float + Minimum Microsoft Visual C++ version. + """ + + # Variables and properties in this class use originals CamelCase variables + # names from Microsoft source files for more easy comparison. + + def __init__(self, arch, vc_ver=None, vc_min_ver=0): + self.pi = PlatformInfo(arch) + self.ri = RegistryInfo(self.pi) + self.si = SystemInfo(self.ri, vc_ver) + + if self.vc_ver < vc_min_ver: + err = 'No suitable Microsoft Visual C++ version found' + raise distutils.errors.DistutilsPlatformError(err) + + @property + def vs_ver(self): + """ + Microsoft Visual Studio. + + Return + ------ + float + version + """ + return self.si.vs_ver + + @property + def vc_ver(self): + """ + Microsoft Visual C++ version. + + Return + ------ + float + version + """ + return self.si.vc_ver + + @property + def VSTools(self): + """ + Microsoft Visual Studio Tools. + + Return + ------ + list of str + paths + """ + paths = [r'Common7\IDE', r'Common7\Tools'] + + if self.vs_ver >= 14.0: + arch_subdir = self.pi.current_dir(hidex86=True, x64=True) + paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow'] + paths += [r'Team Tools\Performance Tools'] + paths += [r'Team Tools\Performance Tools%s' % arch_subdir] + + return [join(self.si.VSInstallDir, path) for path in paths] + + @property + def VCIncludes(self): + """ + Microsoft Visual C++ & Microsoft Foundation Class Includes. + + Return + ------ + list of str + paths + """ + return [join(self.si.VCInstallDir, 'Include'), + join(self.si.VCInstallDir, r'ATLMFC\Include')] + + @property + def VCLibraries(self): + """ + Microsoft Visual C++ & Microsoft Foundation Class Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver >= 15.0: + arch_subdir = self.pi.target_dir(x64=True) + else: + arch_subdir = self.pi.target_dir(hidex86=True) + paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir] + + if self.vs_ver >= 14.0: + paths += [r'Lib\store%s' % arch_subdir] + + return [join(self.si.VCInstallDir, path) for path in paths] + + @property + def VCStoreRefs(self): + """ + Microsoft Visual C++ store references Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0: + return [] + return [join(self.si.VCInstallDir, r'Lib\store\references')] + + @property + def VCTools(self): + """ + Microsoft Visual C++ Tools. + + Return + ------ + list of str + paths + """ + si = self.si + tools = [join(si.VCInstallDir, 'VCPackages')] + + forcex86 = True if self.vs_ver <= 10.0 else False + arch_subdir = self.pi.cross_dir(forcex86) + if arch_subdir: + tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)] + + if self.vs_ver == 14.0: + path = 'Bin%s' % self.pi.current_dir(hidex86=True) + tools += [join(si.VCInstallDir, path)] + + elif self.vs_ver >= 15.0: + host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else + r'bin\HostX64%s') + tools += [join( + si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] + + if self.pi.current_cpu != self.pi.target_cpu: + tools += [join( + si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))] + + else: + tools += [join(si.VCInstallDir, 'Bin')] + + return tools + + @property + def OSLibraries(self): + """ + Microsoft Windows SDK Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver <= 10.0: + arch_subdir = self.pi.target_dir(hidex86=True, x64=True) + return [join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)] + + else: + arch_subdir = self.pi.target_dir(x64=True) + lib = join(self.si.WindowsSdkDir, 'lib') + libver = self._sdk_subdir + return [join(lib, '%sum%s' % (libver, arch_subdir))] + + @property + def OSIncludes(self): + """ + Microsoft Windows SDK Include. + + Return + ------ + list of str + paths + """ + include = join(self.si.WindowsSdkDir, 'include') + + if self.vs_ver <= 10.0: + return [include, join(include, 'gl')] + + else: + if self.vs_ver >= 14.0: + sdkver = self._sdk_subdir + else: + sdkver = '' + return [join(include, '%sshared' % sdkver), + join(include, '%sum' % sdkver), + join(include, '%swinrt' % sdkver)] + + @property + def OSLibpath(self): + """ + Microsoft Windows SDK Libraries Paths. + + Return + ------ + list of str + paths + """ + ref = join(self.si.WindowsSdkDir, 'References') + libpath = [] + + if self.vs_ver <= 9.0: + libpath += self.OSLibraries + + if self.vs_ver >= 11.0: + libpath += [join(ref, r'CommonConfiguration\Neutral')] + + if self.vs_ver >= 14.0: + libpath += [ + ref, + join(self.si.WindowsSdkDir, 'UnionMetadata'), + join( + ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), + join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'), + join( + ref, 'Windows.Networking.Connectivity.WwanContract', + '1.0.0.0'), + join( + self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs', + '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration', + 'neutral'), + ] + return libpath + + @property + def SdkTools(self): + """ + Microsoft Windows SDK Tools. + + Return + ------ + list of str + paths + """ + return list(self._sdk_tools()) + + def _sdk_tools(self): + """ + Microsoft Windows SDK Tools paths generator. + + Return + ------ + generator of str + paths + """ + if self.vs_ver < 15.0: + bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86' + yield join(self.si.WindowsSdkDir, bin_dir) + + if not self.pi.current_is_x86(): + arch_subdir = self.pi.current_dir(x64=True) + path = 'Bin%s' % arch_subdir + yield join(self.si.WindowsSdkDir, path) + + if self.vs_ver in (10.0, 11.0): + if self.pi.target_is_x86(): + arch_subdir = '' + else: + arch_subdir = self.pi.current_dir(hidex86=True, x64=True) + path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir + yield join(self.si.WindowsSdkDir, path) + + elif self.vs_ver >= 15.0: + path = join(self.si.WindowsSdkDir, 'Bin') + arch_subdir = self.pi.current_dir(x64=True) + sdkver = self.si.WindowsSdkLastVersion + yield join(path, '%s%s' % (sdkver, arch_subdir)) + + if self.si.WindowsSDKExecutablePath: + yield self.si.WindowsSDKExecutablePath + + @property + def _sdk_subdir(self): + """ + Microsoft Windows SDK version subdir. + + Return + ------ + str + subdir + """ + ucrtver = self.si.WindowsSdkLastVersion + return ('%s\\' % ucrtver) if ucrtver else '' + + @property + def SdkSetup(self): + """ + Microsoft Windows SDK Setup. + + Return + ------ + list of str + paths + """ + if self.vs_ver > 9.0: + return [] + + return [join(self.si.WindowsSdkDir, 'Setup')] + + @property + def FxTools(self): + """ + Microsoft .NET Framework Tools. + + Return + ------ + list of str + paths + """ + pi = self.pi + si = self.si + + if self.vs_ver <= 10.0: + include32 = True + include64 = not pi.target_is_x86() and not pi.current_is_x86() + else: + include32 = pi.target_is_x86() or pi.current_is_x86() + include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64' + + tools = [] + if include32: + tools += [join(si.FrameworkDir32, ver) + for ver in si.FrameworkVersion32] + if include64: + tools += [join(si.FrameworkDir64, ver) + for ver in si.FrameworkVersion64] + return tools + + @property + def NetFxSDKLibraries(self): + """ + Microsoft .Net Framework SDK Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0 or not self.si.NetFxSdkDir: + return [] + + arch_subdir = self.pi.target_dir(x64=True) + return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)] + + @property + def NetFxSDKIncludes(self): + """ + Microsoft .Net Framework SDK Includes. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0 or not self.si.NetFxSdkDir: + return [] + + return [join(self.si.NetFxSdkDir, r'include\um')] + + @property + def VsTDb(self): + """ + Microsoft Visual Studio Team System Database. + + Return + ------ + list of str + paths + """ + return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')] + + @property + def MSBuild(self): + """ + Microsoft Build Engine. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 12.0: + return [] + elif self.vs_ver < 15.0: + base_path = self.si.ProgramFilesx86 + arch_subdir = self.pi.current_dir(hidex86=True) + else: + base_path = self.si.VSInstallDir + arch_subdir = '' + + path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir) + build = [join(base_path, path)] + + if self.vs_ver >= 15.0: + # Add Roslyn C# & Visual Basic Compiler + build += [join(base_path, path, 'Roslyn')] + + return build + + @property + def HTMLHelpWorkshop(self): + """ + Microsoft HTML Help Workshop. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 11.0: + return [] + + return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')] + + @property + def UCRTLibraries(self): + """ + Microsoft Universal C Runtime SDK Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0: + return [] + + arch_subdir = self.pi.target_dir(x64=True) + lib = join(self.si.UniversalCRTSdkDir, 'lib') + ucrtver = self._ucrt_subdir + return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] + + @property + def UCRTIncludes(self): + """ + Microsoft Universal C Runtime SDK Include. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0: + return [] + + include = join(self.si.UniversalCRTSdkDir, 'include') + return [join(include, '%sucrt' % self._ucrt_subdir)] + + @property + def _ucrt_subdir(self): + """ + Microsoft Universal C Runtime SDK version subdir. + + Return + ------ + str + subdir + """ + ucrtver = self.si.UniversalCRTSdkLastVersion + return ('%s\\' % ucrtver) if ucrtver else '' + + @property + def FSharp(self): + """ + Microsoft Visual F#. + + Return + ------ + list of str + paths + """ + if 11.0 > self.vs_ver > 12.0: + return [] + + return [self.si.FSharpInstallDir] + + @property + def VCRuntimeRedist(self): + """ + Microsoft Visual C++ runtime redistributable dll. + + Return + ------ + str + path + """ + vcruntime = 'vcruntime%d0.dll' % self.vc_ver + arch_subdir = self.pi.target_dir(x64=True).strip('\\') + + # Installation prefixes candidates + prefixes = [] + tools_path = self.si.VCInstallDir + redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist')) + if isdir(redist_path): + # Redist version may not be exactly the same as tools + redist_path = join(redist_path, listdir(redist_path)[-1]) + prefixes += [redist_path, join(redist_path, 'onecore')] + + prefixes += [join(tools_path, 'redist')] # VS14 legacy path + + # CRT directory + crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10), + # Sometime store in directory with VS version instead of VC + 'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10)) + + # vcruntime path + for prefix, crt_dir in itertools.product(prefixes, crt_dirs): + path = join(prefix, arch_subdir, crt_dir, vcruntime) + if isfile(path): + return path + + def return_env(self, exists=True): + """ + Return environment dict. + + Parameters + ---------- + exists: bool + It True, only return existing paths. + + Return + ------ + dict + environment + """ + env = dict( + include=self._build_paths('include', + [self.VCIncludes, + self.OSIncludes, + self.UCRTIncludes, + self.NetFxSDKIncludes], + exists), + lib=self._build_paths('lib', + [self.VCLibraries, + self.OSLibraries, + self.FxTools, + self.UCRTLibraries, + self.NetFxSDKLibraries], + exists), + libpath=self._build_paths('libpath', + [self.VCLibraries, + self.FxTools, + self.VCStoreRefs, + self.OSLibpath], + exists), + path=self._build_paths('path', + [self.VCTools, + self.VSTools, + self.VsTDb, + self.SdkTools, + self.SdkSetup, + self.FxTools, + self.MSBuild, + self.HTMLHelpWorkshop, + self.FSharp], + exists), + ) + if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist): + env['py_vcruntime_redist'] = self.VCRuntimeRedist + return env + + def _build_paths(self, name, spec_path_lists, exists): + """ + Given an environment variable name and specified paths, + return a pathsep-separated string of paths containing + unique, extant, directories from those paths and from + the environment variable. Raise an error if no paths + are resolved. + + Parameters + ---------- + name: str + Environment variable name + spec_path_lists: list of str + Paths + exists: bool + It True, only return existing paths. + + Return + ------ + str + Pathsep-separated paths + """ + # flatten spec_path_lists + spec_paths = itertools.chain.from_iterable(spec_path_lists) + env_paths = environ.get(name, '').split(pathsep) + paths = itertools.chain(spec_paths, env_paths) + extant_paths = list(filter(isdir, paths)) if exists else paths + if not extant_paths: + msg = "%s environment variable is empty" % name.upper() + raise distutils.errors.DistutilsPlatformError(msg) + unique_paths = unique_everseen(extant_paths) + return pathsep.join(unique_paths) diff --git a/MLPY/Lib/site-packages/setuptools/namespaces.py b/MLPY/Lib/site-packages/setuptools/namespaces.py new file mode 100644 index 0000000000000000000000000000000000000000..44939e1c6d40539eb8173bf1527db926c5a54658 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/namespaces.py @@ -0,0 +1,107 @@ +import os +from distutils import log +import itertools + + +flatten = itertools.chain.from_iterable + + +class Installer: + + nspkg_ext = '-nspkg.pth' + + def install_namespaces(self): + nsp = self._get_all_ns_packages() + if not nsp: + return + filename, ext = os.path.splitext(self._get_target()) + filename += self.nspkg_ext + self.outputs.append(filename) + log.info("Installing %s", filename) + lines = map(self._gen_nspkg_line, nsp) + + if self.dry_run: + # always generate the lines, even in dry run + list(lines) + return + + with open(filename, 'wt') as f: + f.writelines(lines) + + def uninstall_namespaces(self): + filename, ext = os.path.splitext(self._get_target()) + filename += self.nspkg_ext + if not os.path.exists(filename): + return + log.info("Removing %s", filename) + os.remove(filename) + + def _get_target(self): + return self.target + + _nspkg_tmpl = ( + "import sys, types, os", + "has_mfs = sys.version_info > (3, 5)", + "p = os.path.join(%(root)s, *%(pth)r)", + "importlib = has_mfs and __import__('importlib.util')", + "has_mfs and __import__('importlib.machinery')", + ( + "m = has_mfs and " + "sys.modules.setdefault(%(pkg)r, " + "importlib.util.module_from_spec(" + "importlib.machinery.PathFinder.find_spec(%(pkg)r, " + "[os.path.dirname(p)])))" + ), + ( + "m = m or " + "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))" + ), + "mp = (m or []) and m.__dict__.setdefault('__path__',[])", + "(p not in mp) and mp.append(p)", + ) + "lines for the namespace installer" + + _nspkg_tmpl_multi = ( + 'm and setattr(sys.modules[%(parent)r], %(child)r, m)', + ) + "additional line(s) when a parent package is indicated" + + def _get_root(self): + return "sys._getframe(1).f_locals['sitedir']" + + def _gen_nspkg_line(self, pkg): + pth = tuple(pkg.split('.')) + root = self._get_root() + tmpl_lines = self._nspkg_tmpl + parent, sep, child = pkg.rpartition('.') + if parent: + tmpl_lines += self._nspkg_tmpl_multi + return ';'.join(tmpl_lines) % locals() + '\n' + + def _get_all_ns_packages(self): + """Return sorted list of all package namespaces""" + pkgs = self.distribution.namespace_packages or [] + return sorted(flatten(map(self._pkg_names, pkgs))) + + @staticmethod + def _pkg_names(pkg): + """ + Given a namespace package, yield the components of that + package. + + >>> names = Installer._pkg_names('a.b.c') + >>> set(names) == set(['a', 'a.b', 'a.b.c']) + True + """ + parts = pkg.split('.') + while parts: + yield '.'.join(parts) + parts.pop() + + +class DevelopInstaller(Installer): + def _get_root(self): + return repr(str(self.egg_path)) + + def _get_target(self): + return self.egg_link diff --git a/MLPY/Lib/site-packages/setuptools/package_index.py b/MLPY/Lib/site-packages/setuptools/package_index.py new file mode 100644 index 0000000000000000000000000000000000000000..d818f44ade082e2e11a3f954ee28bf046ba5cf2d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/package_index.py @@ -0,0 +1,1119 @@ +"""PyPI and direct package downloading""" +import sys +import os +import re +import io +import shutil +import socket +import base64 +import hashlib +import itertools +import warnings +import configparser +import html +import http.client +import urllib.parse +import urllib.request +import urllib.error +from functools import wraps + +import setuptools +from pkg_resources import ( + CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST, + Environment, find_distributions, safe_name, safe_version, + to_filename, Requirement, DEVELOP_DIST, EGG_DIST, +) +from distutils import log +from distutils.errors import DistutilsError +from fnmatch import translate +from setuptools.wheel import Wheel +from setuptools.extern.more_itertools import unique_everseen + + +EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.+!]+)$') +HREF = re.compile(r"""href\s*=\s*['"]?([^'"> ]+)""", re.I) +PYPI_MD5 = re.compile( + r'([^<]+)\n\s+\(md5\)' +) +URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match +EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split() + +__all__ = [ + 'PackageIndex', 'distros_for_url', 'parse_bdist_wininst', + 'interpret_distro_name', +] + +_SOCKET_TIMEOUT = 15 + +_tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}" +user_agent = _tmpl.format( + py_major='{}.{}'.format(*sys.version_info), setuptools=setuptools) + + +def parse_requirement_arg(spec): + try: + return Requirement.parse(spec) + except ValueError as e: + raise DistutilsError( + "Not a URL, existing file, or requirement spec: %r" % (spec,) + ) from e + + +def parse_bdist_wininst(name): + """Return (base,pyversion) or (None,None) for possible .exe name""" + + lower = name.lower() + base, py_ver, plat = None, None, None + + if lower.endswith('.exe'): + if lower.endswith('.win32.exe'): + base = name[:-10] + plat = 'win32' + elif lower.startswith('.win32-py', -16): + py_ver = name[-7:-4] + base = name[:-16] + plat = 'win32' + elif lower.endswith('.win-amd64.exe'): + base = name[:-14] + plat = 'win-amd64' + elif lower.startswith('.win-amd64-py', -20): + py_ver = name[-7:-4] + base = name[:-20] + plat = 'win-amd64' + return base, py_ver, plat + + +def egg_info_for_url(url): + parts = urllib.parse.urlparse(url) + scheme, server, path, parameters, query, fragment = parts + base = urllib.parse.unquote(path.split('/')[-1]) + if server == 'sourceforge.net' and base == 'download': # XXX Yuck + base = urllib.parse.unquote(path.split('/')[-2]) + if '#' in base: + base, fragment = base.split('#', 1) + return base, fragment + + +def distros_for_url(url, metadata=None): + """Yield egg or source distribution objects that might be found at a URL""" + base, fragment = egg_info_for_url(url) + for dist in distros_for_location(url, base, metadata): + yield dist + if fragment: + match = EGG_FRAGMENT.match(fragment) + if match: + for dist in interpret_distro_name( + url, match.group(1), metadata, precedence=CHECKOUT_DIST + ): + yield dist + + +def distros_for_location(location, basename, metadata=None): + """Yield egg or source distribution objects based on basename""" + if basename.endswith('.egg.zip'): + basename = basename[:-4] # strip the .zip + if basename.endswith('.egg') and '-' in basename: + # only one, unambiguous interpretation + return [Distribution.from_location(location, basename, metadata)] + if basename.endswith('.whl') and '-' in basename: + wheel = Wheel(basename) + if not wheel.is_compatible(): + return [] + return [Distribution( + location=location, + project_name=wheel.project_name, + version=wheel.version, + # Increase priority over eggs. + precedence=EGG_DIST + 1, + )] + if basename.endswith('.exe'): + win_base, py_ver, platform = parse_bdist_wininst(basename) + if win_base is not None: + return interpret_distro_name( + location, win_base, metadata, py_ver, BINARY_DIST, platform + ) + # Try source distro extensions (.zip, .tgz, etc.) + # + for ext in EXTENSIONS: + if basename.endswith(ext): + basename = basename[:-len(ext)] + return interpret_distro_name(location, basename, metadata) + return [] # no extension matched + + +def distros_for_filename(filename, metadata=None): + """Yield possible egg or source distribution objects based on a filename""" + return distros_for_location( + normalize_path(filename), os.path.basename(filename), metadata + ) + + +def interpret_distro_name( + location, basename, metadata, py_version=None, precedence=SOURCE_DIST, + platform=None +): + """Generate alternative interpretations of a source distro name + + Note: if `location` is a filesystem filename, you should call + ``pkg_resources.normalize_path()`` on it before passing it to this + routine! + """ + # Generate alternative interpretations of a source distro name + # Because some packages are ambiguous as to name/versions split + # e.g. "adns-python-1.1.0", "egenix-mx-commercial", etc. + # So, we generate each possible interpretation (e.g. "adns, python-1.1.0" + # "adns-python, 1.1.0", and "adns-python-1.1.0, no version"). In practice, + # the spurious interpretations should be ignored, because in the event + # there's also an "adns" package, the spurious "python-1.1.0" version will + # compare lower than any numeric version number, and is therefore unlikely + # to match a request for it. It's still a potential problem, though, and + # in the long run PyPI and the distutils should go for "safe" names and + # versions in distribution archive names (sdist and bdist). + + parts = basename.split('-') + if not py_version and any(re.match(r'py\d\.\d$', p) for p in parts[2:]): + # it is a bdist_dumb, not an sdist -- bail out + return + + for p in range(1, len(parts) + 1): + yield Distribution( + location, metadata, '-'.join(parts[:p]), '-'.join(parts[p:]), + py_version=py_version, precedence=precedence, + platform=platform + ) + + +def unique_values(func): + """ + Wrap a function returning an iterable such that the resulting iterable + only ever yields unique items. + """ + + @wraps(func) + def wrapper(*args, **kwargs): + return unique_everseen(func(*args, **kwargs)) + + return wrapper + + +REL = re.compile(r"""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I) +# this line is here to fix emacs' cruddy broken syntax highlighting + + +@unique_values +def find_external_links(url, page): + """Find rel="homepage" and rel="download" links in `page`, yielding URLs""" + + for match in REL.finditer(page): + tag, rel = match.groups() + rels = set(map(str.strip, rel.lower().split(','))) + if 'homepage' in rels or 'download' in rels: + for match in HREF.finditer(tag): + yield urllib.parse.urljoin(url, htmldecode(match.group(1))) + + for tag in ("Home Page", "Download URL"): + pos = page.find(tag) + if pos != -1: + match = HREF.search(page, pos) + if match: + yield urllib.parse.urljoin(url, htmldecode(match.group(1))) + + +class ContentChecker: + """ + A null content checker that defines the interface for checking content + """ + + def feed(self, block): + """ + Feed a block of data to the hash. + """ + return + + def is_valid(self): + """ + Check the hash. Return False if validation fails. + """ + return True + + def report(self, reporter, template): + """ + Call reporter with information about the checker (hash name) + substituted into the template. + """ + return + + +class HashChecker(ContentChecker): + pattern = re.compile( + r'(?Psha1|sha224|sha384|sha256|sha512|md5)=' + r'(?P[a-f0-9]+)' + ) + + def __init__(self, hash_name, expected): + self.hash_name = hash_name + self.hash = hashlib.new(hash_name) + self.expected = expected + + @classmethod + def from_url(cls, url): + "Construct a (possibly null) ContentChecker from a URL" + fragment = urllib.parse.urlparse(url)[-1] + if not fragment: + return ContentChecker() + match = cls.pattern.search(fragment) + if not match: + return ContentChecker() + return cls(**match.groupdict()) + + def feed(self, block): + self.hash.update(block) + + def is_valid(self): + return self.hash.hexdigest() == self.expected + + def report(self, reporter, template): + msg = template % self.hash_name + return reporter(msg) + + +class PackageIndex(Environment): + """A distribution index that scans web pages for download URLs""" + + def __init__( + self, index_url="https://pypi.org/simple/", hosts=('*',), + ca_bundle=None, verify_ssl=True, *args, **kw + ): + Environment.__init__(self, *args, **kw) + self.index_url = index_url + "/" [:not index_url.endswith('/')] + self.scanned_urls = {} + self.fetched_urls = {} + self.package_pages = {} + self.allows = re.compile('|'.join(map(translate, hosts))).match + self.to_scan = [] + self.opener = urllib.request.urlopen + + # FIXME: 'PackageIndex.process_url' is too complex (14) + def process_url(self, url, retrieve=False): # noqa: C901 + """Evaluate a URL as a possible download, and maybe retrieve it""" + if url in self.scanned_urls and not retrieve: + return + self.scanned_urls[url] = True + if not URL_SCHEME(url): + self.process_filename(url) + return + else: + dists = list(distros_for_url(url)) + if dists: + if not self.url_ok(url): + return + self.debug("Found link: %s", url) + + if dists or not retrieve or url in self.fetched_urls: + list(map(self.add, dists)) + return # don't need the actual page + + if not self.url_ok(url): + self.fetched_urls[url] = True + return + + self.info("Reading %s", url) + self.fetched_urls[url] = True # prevent multiple fetch attempts + tmpl = "Download error on %s: %%s -- Some packages may not be found!" + f = self.open_url(url, tmpl % url) + if f is None: + return + if isinstance(f, urllib.error.HTTPError) and f.code == 401: + self.info("Authentication error: %s" % f.msg) + self.fetched_urls[f.url] = True + if 'html' not in f.headers.get('content-type', '').lower(): + f.close() # not html, we can't process it + return + + base = f.url # handle redirects + page = f.read() + if not isinstance(page, str): + # In Python 3 and got bytes but want str. + if isinstance(f, urllib.error.HTTPError): + # Errors have no charset, assume latin1: + charset = 'latin-1' + else: + charset = f.headers.get_param('charset') or 'latin-1' + page = page.decode(charset, "ignore") + f.close() + for match in HREF.finditer(page): + link = urllib.parse.urljoin(base, htmldecode(match.group(1))) + self.process_url(link) + if url.startswith(self.index_url) and getattr(f, 'code', None) != 404: + page = self.process_index(url, page) + + def process_filename(self, fn, nested=False): + # process filenames or directories + if not os.path.exists(fn): + self.warn("Not found: %s", fn) + return + + if os.path.isdir(fn) and not nested: + path = os.path.realpath(fn) + for item in os.listdir(path): + self.process_filename(os.path.join(path, item), True) + + dists = distros_for_filename(fn) + if dists: + self.debug("Found: %s", fn) + list(map(self.add, dists)) + + def url_ok(self, url, fatal=False): + s = URL_SCHEME(url) + is_file = s and s.group(1).lower() == 'file' + if is_file or self.allows(urllib.parse.urlparse(url)[1]): + return True + msg = ( + "\nNote: Bypassing %s (disallowed host; see " + "http://bit.ly/2hrImnY for details).\n") + if fatal: + raise DistutilsError(msg % url) + else: + self.warn(msg, url) + + def scan_egg_links(self, search_path): + dirs = filter(os.path.isdir, search_path) + egg_links = ( + (path, entry) + for path in dirs + for entry in os.listdir(path) + if entry.endswith('.egg-link') + ) + list(itertools.starmap(self.scan_egg_link, egg_links)) + + def scan_egg_link(self, path, entry): + with open(os.path.join(path, entry)) as raw_lines: + # filter non-empty lines + lines = list(filter(None, map(str.strip, raw_lines))) + + if len(lines) != 2: + # format is not recognized; punt + return + + egg_path, setup_path = lines + + for dist in find_distributions(os.path.join(path, egg_path)): + dist.location = os.path.join(path, *lines) + dist.precedence = SOURCE_DIST + self.add(dist) + + def _scan(self, link): + # Process a URL to see if it's for a package page + NO_MATCH_SENTINEL = None, None + if not link.startswith(self.index_url): + return NO_MATCH_SENTINEL + + parts = list(map( + urllib.parse.unquote, link[len(self.index_url):].split('/') + )) + if len(parts) != 2 or '#' in parts[1]: + return NO_MATCH_SENTINEL + + # it's a package page, sanitize and index it + pkg = safe_name(parts[0]) + ver = safe_version(parts[1]) + self.package_pages.setdefault(pkg.lower(), {})[link] = True + return to_filename(pkg), to_filename(ver) + + def process_index(self, url, page): + """Process the contents of a PyPI page""" + + # process an index page into the package-page index + for match in HREF.finditer(page): + try: + self._scan(urllib.parse.urljoin(url, htmldecode(match.group(1)))) + except ValueError: + pass + + pkg, ver = self._scan(url) # ensure this page is in the page index + if not pkg: + return "" # no sense double-scanning non-package pages + + # process individual package page + for new_url in find_external_links(url, page): + # Process the found URL + base, frag = egg_info_for_url(new_url) + if base.endswith('.py') and not frag: + if ver: + new_url += '#egg=%s-%s' % (pkg, ver) + else: + self.need_version_info(url) + self.scan_url(new_url) + + return PYPI_MD5.sub( + lambda m: '%s' % m.group(1, 3, 2), page + ) + + def need_version_info(self, url): + self.scan_all( + "Page at %s links to .py file(s) without version info; an index " + "scan is required.", url + ) + + def scan_all(self, msg=None, *args): + if self.index_url not in self.fetched_urls: + if msg: + self.warn(msg, *args) + self.info( + "Scanning index of all packages (this may take a while)" + ) + self.scan_url(self.index_url) + + def find_packages(self, requirement): + self.scan_url(self.index_url + requirement.unsafe_name + '/') + + if not self.package_pages.get(requirement.key): + # Fall back to safe version of the name + self.scan_url(self.index_url + requirement.project_name + '/') + + if not self.package_pages.get(requirement.key): + # We couldn't find the target package, so search the index page too + self.not_found_in_index(requirement) + + for url in list(self.package_pages.get(requirement.key, ())): + # scan each page that might be related to the desired package + self.scan_url(url) + + def obtain(self, requirement, installer=None): + self.prescan() + self.find_packages(requirement) + for dist in self[requirement.key]: + if dist in requirement: + return dist + self.debug("%s does not match %s", requirement, dist) + return super(PackageIndex, self).obtain(requirement, installer) + + def check_hash(self, checker, filename, tfp): + """ + checker is a ContentChecker + """ + checker.report( + self.debug, + "Validating %%s checksum for %s" % filename) + if not checker.is_valid(): + tfp.close() + os.unlink(filename) + raise DistutilsError( + "%s validation failed for %s; " + "possible download problem?" + % (checker.hash.name, os.path.basename(filename)) + ) + + def add_find_links(self, urls): + """Add `urls` to the list that will be prescanned for searches""" + for url in urls: + if ( + self.to_scan is None # if we have already "gone online" + or not URL_SCHEME(url) # or it's a local file/directory + or url.startswith('file:') + or list(distros_for_url(url)) # or a direct package link + ): + # then go ahead and process it now + self.scan_url(url) + else: + # otherwise, defer retrieval till later + self.to_scan.append(url) + + def prescan(self): + """Scan urls scheduled for prescanning (e.g. --find-links)""" + if self.to_scan: + list(map(self.scan_url, self.to_scan)) + self.to_scan = None # from now on, go ahead and process immediately + + def not_found_in_index(self, requirement): + if self[requirement.key]: # we've seen at least one distro + meth, msg = self.info, "Couldn't retrieve index page for %r" + else: # no distros seen for this name, might be misspelled + meth, msg = ( + self.warn, + "Couldn't find index page for %r (maybe misspelled?)") + meth(msg, requirement.unsafe_name) + self.scan_all() + + def download(self, spec, tmpdir): + """Locate and/or download `spec` to `tmpdir`, returning a local path + + `spec` may be a ``Requirement`` object, or a string containing a URL, + an existing local filename, or a project/version requirement spec + (i.e. the string form of a ``Requirement`` object). If it is the URL + of a .py file with an unambiguous ``#egg=name-version`` tag (i.e., one + that escapes ``-`` as ``_`` throughout), a trivial ``setup.py`` is + automatically created alongside the downloaded file. + + If `spec` is a ``Requirement`` object or a string containing a + project/version requirement spec, this method returns the location of + a matching distribution (possibly after downloading it to `tmpdir`). + If `spec` is a locally existing file or directory name, it is simply + returned unchanged. If `spec` is a URL, it is downloaded to a subpath + of `tmpdir`, and the local filename is returned. Various errors may be + raised if a problem occurs during downloading. + """ + if not isinstance(spec, Requirement): + scheme = URL_SCHEME(spec) + if scheme: + # It's a url, download it to tmpdir + found = self._download_url(scheme.group(1), spec, tmpdir) + base, fragment = egg_info_for_url(spec) + if base.endswith('.py'): + found = self.gen_setup(found, fragment, tmpdir) + return found + elif os.path.exists(spec): + # Existing file or directory, just return it + return spec + else: + spec = parse_requirement_arg(spec) + return getattr(self.fetch_distribution(spec, tmpdir), 'location', None) + + def fetch_distribution( # noqa: C901 # is too complex (14) # FIXME + self, requirement, tmpdir, force_scan=False, source=False, + develop_ok=False, local_index=None): + """Obtain a distribution suitable for fulfilling `requirement` + + `requirement` must be a ``pkg_resources.Requirement`` instance. + If necessary, or if the `force_scan` flag is set, the requirement is + searched for in the (online) package index as well as the locally + installed packages. If a distribution matching `requirement` is found, + the returned distribution's ``location`` is the value you would have + gotten from calling the ``download()`` method with the matching + distribution's URL or filename. If no matching distribution is found, + ``None`` is returned. + + If the `source` flag is set, only source distributions and source + checkout links will be considered. Unless the `develop_ok` flag is + set, development and system eggs (i.e., those using the ``.egg-info`` + format) will be ignored. + """ + # process a Requirement + self.info("Searching for %s", requirement) + skipped = {} + dist = None + + def find(req, env=None): + if env is None: + env = self + # Find a matching distribution; may be called more than once + + for dist in env[req.key]: + + if dist.precedence == DEVELOP_DIST and not develop_ok: + if dist not in skipped: + self.warn( + "Skipping development or system egg: %s", dist, + ) + skipped[dist] = 1 + continue + + test = ( + dist in req + and (dist.precedence <= SOURCE_DIST or not source) + ) + if test: + loc = self.download(dist.location, tmpdir) + dist.download_location = loc + if os.path.exists(dist.download_location): + return dist + + if force_scan: + self.prescan() + self.find_packages(requirement) + dist = find(requirement) + + if not dist and local_index is not None: + dist = find(requirement, local_index) + + if dist is None: + if self.to_scan is not None: + self.prescan() + dist = find(requirement) + + if dist is None and not force_scan: + self.find_packages(requirement) + dist = find(requirement) + + if dist is None: + self.warn( + "No local packages or working download links found for %s%s", + (source and "a source distribution of " or ""), + requirement, + ) + else: + self.info("Best match: %s", dist) + return dist.clone(location=dist.download_location) + + def fetch(self, requirement, tmpdir, force_scan=False, source=False): + """Obtain a file suitable for fulfilling `requirement` + + DEPRECATED; use the ``fetch_distribution()`` method now instead. For + backward compatibility, this routine is identical but returns the + ``location`` of the downloaded distribution instead of a distribution + object. + """ + dist = self.fetch_distribution(requirement, tmpdir, force_scan, source) + if dist is not None: + return dist.location + return None + + def gen_setup(self, filename, fragment, tmpdir): + match = EGG_FRAGMENT.match(fragment) + dists = match and [ + d for d in + interpret_distro_name(filename, match.group(1), None) if d.version + ] or [] + + if len(dists) == 1: # unambiguous ``#egg`` fragment + basename = os.path.basename(filename) + + # Make sure the file has been downloaded to the temp dir. + if os.path.dirname(filename) != tmpdir: + dst = os.path.join(tmpdir, basename) + from setuptools.command.easy_install import samefile + if not samefile(filename, dst): + shutil.copy2(filename, dst) + filename = dst + + with open(os.path.join(tmpdir, 'setup.py'), 'w') as file: + file.write( + "from setuptools import setup\n" + "setup(name=%r, version=%r, py_modules=[%r])\n" + % ( + dists[0].project_name, dists[0].version, + os.path.splitext(basename)[0] + ) + ) + return filename + + elif match: + raise DistutilsError( + "Can't unambiguously interpret project/version identifier %r; " + "any dashes in the name or version should be escaped using " + "underscores. %r" % (fragment, dists) + ) + else: + raise DistutilsError( + "Can't process plain .py files without an '#egg=name-version'" + " suffix to enable automatic setup script generation." + ) + + dl_blocksize = 8192 + + def _download_to(self, url, filename): + self.info("Downloading %s", url) + # Download the file + fp = None + try: + checker = HashChecker.from_url(url) + fp = self.open_url(url) + if isinstance(fp, urllib.error.HTTPError): + raise DistutilsError( + "Can't download %s: %s %s" % (url, fp.code, fp.msg) + ) + headers = fp.info() + blocknum = 0 + bs = self.dl_blocksize + size = -1 + if "content-length" in headers: + # Some servers return multiple Content-Length headers :( + sizes = headers.get_all('Content-Length') + size = max(map(int, sizes)) + self.reporthook(url, filename, blocknum, bs, size) + with open(filename, 'wb') as tfp: + while True: + block = fp.read(bs) + if block: + checker.feed(block) + tfp.write(block) + blocknum += 1 + self.reporthook(url, filename, blocknum, bs, size) + else: + break + self.check_hash(checker, filename, tfp) + return headers + finally: + if fp: + fp.close() + + def reporthook(self, url, filename, blocknum, blksize, size): + pass # no-op + + # FIXME: + def open_url(self, url, warning=None): # noqa: C901 # is too complex (12) + if url.startswith('file:'): + return local_open(url) + try: + return open_with_auth(url, self.opener) + except (ValueError, http.client.InvalidURL) as v: + msg = ' '.join([str(arg) for arg in v.args]) + if warning: + self.warn(warning, msg) + else: + raise DistutilsError('%s %s' % (url, msg)) from v + except urllib.error.HTTPError as v: + return v + except urllib.error.URLError as v: + if warning: + self.warn(warning, v.reason) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v.reason)) from v + except http.client.BadStatusLine as v: + if warning: + self.warn(warning, v.line) + else: + raise DistutilsError( + '%s returned a bad status line. The server might be ' + 'down, %s' % + (url, v.line) + ) from v + except (http.client.HTTPException, socket.error) as v: + if warning: + self.warn(warning, v) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v)) from v + + def _download_url(self, scheme, url, tmpdir): + # Determine download filename + # + name, fragment = egg_info_for_url(url) + if name: + while '..' in name: + name = name.replace('..', '.').replace('\\', '_') + else: + name = "__downloaded__" # default if URL has no path contents + + if name.endswith('.egg.zip'): + name = name[:-4] # strip the extra .zip before download + + filename = os.path.join(tmpdir, name) + + # Download the file + # + if scheme == 'svn' or scheme.startswith('svn+'): + return self._download_svn(url, filename) + elif scheme == 'git' or scheme.startswith('git+'): + return self._download_git(url, filename) + elif scheme.startswith('hg+'): + return self._download_hg(url, filename) + elif scheme == 'file': + return urllib.request.url2pathname(urllib.parse.urlparse(url)[2]) + else: + self.url_ok(url, True) # raises error if not allowed + return self._attempt_download(url, filename) + + def scan_url(self, url): + self.process_url(url, True) + + def _attempt_download(self, url, filename): + headers = self._download_to(url, filename) + if 'html' in headers.get('content-type', '').lower(): + return self._download_html(url, headers, filename) + else: + return filename + + def _download_html(self, url, headers, filename): + file = open(filename) + for line in file: + if line.strip(): + # Check for a subversion index page + if re.search(r'([^- ]+ - )?Revision \d+:', line): + # it's a subversion index page: + file.close() + os.unlink(filename) + return self._download_svn(url, filename) + break # not an index page + file.close() + os.unlink(filename) + raise DistutilsError("Unexpected HTML page found at " + url) + + def _download_svn(self, url, filename): + warnings.warn("SVN download support is deprecated", UserWarning) + url = url.split('#', 1)[0] # remove any fragment for svn's sake + creds = '' + if url.lower().startswith('svn:') and '@' in url: + scheme, netloc, path, p, q, f = urllib.parse.urlparse(url) + if not netloc and path.startswith('//') and '/' in path[2:]: + netloc, path = path[2:].split('/', 1) + auth, host = _splituser(netloc) + if auth: + if ':' in auth: + user, pw = auth.split(':', 1) + creds = " --username=%s --password=%s" % (user, pw) + else: + creds = " --username=" + auth + netloc = host + parts = scheme, netloc, url, p, q, f + url = urllib.parse.urlunparse(parts) + self.info("Doing subversion checkout from %s to %s", url, filename) + os.system("svn checkout%s -q %s %s" % (creds, url, filename)) + return filename + + @staticmethod + def _vcs_split_rev_from_url(url, pop_prefix=False): + scheme, netloc, path, query, frag = urllib.parse.urlsplit(url) + + scheme = scheme.split('+', 1)[-1] + + # Some fragment identification fails + path = path.split('#', 1)[0] + + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + + # Also, discard fragment + url = urllib.parse.urlunsplit((scheme, netloc, path, query, '')) + + return url, rev + + def _download_git(self, url, filename): + filename = filename.split('#', 1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing git clone from %s to %s", url, filename) + os.system("git clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Checking out %s", rev) + os.system("git -C %s checkout --quiet %s" % ( + filename, + rev, + )) + + return filename + + def _download_hg(self, url, filename): + filename = filename.split('#', 1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing hg clone from %s to %s", url, filename) + os.system("hg clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Updating to %s", rev) + os.system("hg --cwd %s up -C -r %s -q" % ( + filename, + rev, + )) + + return filename + + def debug(self, msg, *args): + log.debug(msg, *args) + + def info(self, msg, *args): + log.info(msg, *args) + + def warn(self, msg, *args): + log.warn(msg, *args) + + +# This pattern matches a character entity reference (a decimal numeric +# references, a hexadecimal numeric reference, or a named reference). +entity_sub = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub + + +def decode_entity(match): + what = match.group(0) + return html.unescape(what) + + +def htmldecode(text): + """ + Decode HTML entities in the given text. + + >>> htmldecode( + ... 'https://../package_name-0.1.2.tar.gz' + ... '?tokena=A&tokenb=B">package_name-0.1.2.tar.gz') + 'https://../package_name-0.1.2.tar.gz?tokena=A&tokenb=B">package_name-0.1.2.tar.gz' + """ + return entity_sub(decode_entity, text) + + +def socket_timeout(timeout=15): + def _socket_timeout(func): + def _socket_timeout(*args, **kwargs): + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + try: + return func(*args, **kwargs) + finally: + socket.setdefaulttimeout(old_timeout) + + return _socket_timeout + + return _socket_timeout + + +def _encode_auth(auth): + """ + Encode auth from a URL suitable for an HTTP header. + >>> str(_encode_auth('username%3Apassword')) + 'dXNlcm5hbWU6cGFzc3dvcmQ=' + + Long auth strings should not cause a newline to be inserted. + >>> long_auth = 'username:' + 'password'*10 + >>> chr(10) in str(_encode_auth(long_auth)) + False + """ + auth_s = urllib.parse.unquote(auth) + # convert to bytes + auth_bytes = auth_s.encode() + encoded_bytes = base64.b64encode(auth_bytes) + # convert back to a string + encoded = encoded_bytes.decode() + # strip the trailing carriage return + return encoded.replace('\n', '') + + +class Credential: + """ + A username/password pair. Use like a namedtuple. + """ + + def __init__(self, username, password): + self.username = username + self.password = password + + def __iter__(self): + yield self.username + yield self.password + + def __str__(self): + return '%(username)s:%(password)s' % vars(self) + + +class PyPIConfig(configparser.RawConfigParser): + def __init__(self): + """ + Load from ~/.pypirc + """ + defaults = dict.fromkeys(['username', 'password', 'repository'], '') + configparser.RawConfigParser.__init__(self, defaults) + + rc = os.path.join(os.path.expanduser('~'), '.pypirc') + if os.path.exists(rc): + self.read(rc) + + @property + def creds_by_repository(self): + sections_with_repositories = [ + section for section in self.sections() + if self.get(section, 'repository').strip() + ] + + return dict(map(self._get_repo_cred, sections_with_repositories)) + + def _get_repo_cred(self, section): + repo = self.get(section, 'repository').strip() + return repo, Credential( + self.get(section, 'username').strip(), + self.get(section, 'password').strip(), + ) + + def find_credential(self, url): + """ + If the URL indicated appears to be a repository defined in this + config, return the credential for that repository. + """ + for repository, cred in self.creds_by_repository.items(): + if url.startswith(repository): + return cred + + +def open_with_auth(url, opener=urllib.request.urlopen): + """Open a urllib2 request, handling HTTP authentication""" + + parsed = urllib.parse.urlparse(url) + scheme, netloc, path, params, query, frag = parsed + + # Double scheme does not raise on macOS as revealed by a + # failing test. We would expect "nonnumeric port". Refs #20. + if netloc.endswith(':'): + raise http.client.InvalidURL("nonnumeric port: ''") + + if scheme in ('http', 'https'): + auth, address = _splituser(netloc) + else: + auth = None + + if not auth: + cred = PyPIConfig().find_credential(url) + if cred: + auth = str(cred) + info = cred.username, url + log.info('Authenticating as %s for %s (from .pypirc)', *info) + + if auth: + auth = "Basic " + _encode_auth(auth) + parts = scheme, address, path, params, query, frag + new_url = urllib.parse.urlunparse(parts) + request = urllib.request.Request(new_url) + request.add_header("Authorization", auth) + else: + request = urllib.request.Request(url) + + request.add_header('User-Agent', user_agent) + fp = opener(request) + + if auth: + # Put authentication info back into request URL if same host, + # so that links found on the page will work + s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url) + if s2 == scheme and h2 == address: + parts = s2, netloc, path2, param2, query2, frag2 + fp.url = urllib.parse.urlunparse(parts) + + return fp + + +# copy of urllib.parse._splituser from Python 3.8 +def _splituser(host): + """splituser('user[:passwd]@host[:port]') + --> 'user[:passwd]', 'host[:port]'.""" + user, delim, host = host.rpartition('@') + return (user if delim else None), host + + +# adding a timeout to avoid freezing package_index +open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth) + + +def fix_sf_url(url): + return url # backward compatibility + + +def local_open(url): + """Read a local path, with special support for directories""" + scheme, server, path, param, query, frag = urllib.parse.urlparse(url) + filename = urllib.request.url2pathname(path) + if os.path.isfile(filename): + return urllib.request.urlopen(url) + elif path.endswith('/') and os.path.isdir(filename): + files = [] + for f in os.listdir(filename): + filepath = os.path.join(filename, f) + if f == 'index.html': + with open(filepath, 'r') as fp: + body = fp.read() + break + elif os.path.isdir(filepath): + f += '/' + files.append('<a href="{name}">{name}</a>'.format(name=f)) + else: + tmpl = ( + "<html><head><title>{url}" + "{files}") + body = tmpl.format(url=url, files='\n'.join(files)) + status, message = 200, "OK" + else: + status, message, body = 404, "Path not found", "Not found" + + headers = {'content-type': 'text/html'} + body_stream = io.StringIO(body) + return urllib.error.HTTPError(url, status, message, headers, body_stream) diff --git a/MLPY/Lib/site-packages/setuptools/py34compat.py b/MLPY/Lib/site-packages/setuptools/py34compat.py new file mode 100644 index 0000000000000000000000000000000000000000..3ad917222a4e5bb93fe1c9e8fe1713bcab3630b6 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/py34compat.py @@ -0,0 +1,13 @@ +import importlib + +try: + import importlib.util +except ImportError: + pass + + +try: + module_from_spec = importlib.util.module_from_spec +except AttributeError: + def module_from_spec(spec): + return spec.loader.load_module(spec.name) diff --git a/MLPY/Lib/site-packages/setuptools/sandbox.py b/MLPY/Lib/site-packages/setuptools/sandbox.py new file mode 100644 index 0000000000000000000000000000000000000000..034fc80d20ea4a59d77af6f808dbcfc3b87612c3 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/sandbox.py @@ -0,0 +1,530 @@ +import os +import sys +import tempfile +import operator +import functools +import itertools +import re +import contextlib +import pickle +import textwrap +import builtins + +import pkg_resources +from distutils.errors import DistutilsError +from pkg_resources import working_set + +if sys.platform.startswith('java'): + import org.python.modules.posix.PosixModule as _os +else: + _os = sys.modules[os.name] +try: + _file = file +except NameError: + _file = None +_open = open + + +__all__ = [ + "AbstractSandbox", + "DirectorySandbox", + "SandboxViolation", + "run_setup", +] + + +def _execfile(filename, globals, locals=None): + """ + Python 3 implementation of execfile. + """ + mode = 'rb' + with open(filename, mode) as stream: + script = stream.read() + if locals is None: + locals = globals + code = compile(script, filename, 'exec') + exec(code, globals, locals) + + +@contextlib.contextmanager +def save_argv(repl=None): + saved = sys.argv[:] + if repl is not None: + sys.argv[:] = repl + try: + yield saved + finally: + sys.argv[:] = saved + + +@contextlib.contextmanager +def save_path(): + saved = sys.path[:] + try: + yield saved + finally: + sys.path[:] = saved + + +@contextlib.contextmanager +def override_temp(replacement): + """ + Monkey-patch tempfile.tempdir with replacement, ensuring it exists + """ + os.makedirs(replacement, exist_ok=True) + + saved = tempfile.tempdir + + tempfile.tempdir = replacement + + try: + yield + finally: + tempfile.tempdir = saved + + +@contextlib.contextmanager +def pushd(target): + saved = os.getcwd() + os.chdir(target) + try: + yield saved + finally: + os.chdir(saved) + + +class UnpickleableException(Exception): + """ + An exception representing another Exception that could not be pickled. + """ + + @staticmethod + def dump(type, exc): + """ + Always return a dumped (pickled) type and exc. If exc can't be pickled, + wrap it in UnpickleableException first. + """ + try: + return pickle.dumps(type), pickle.dumps(exc) + except Exception: + # get UnpickleableException inside the sandbox + from setuptools.sandbox import UnpickleableException as cls + + return cls.dump(cls, cls(repr(exc))) + + +class ExceptionSaver: + """ + A Context Manager that will save an exception, serialized, and restore it + later. + """ + + def __enter__(self): + return self + + def __exit__(self, type, exc, tb): + if not exc: + return + + # dump the exception + self._saved = UnpickleableException.dump(type, exc) + self._tb = tb + + # suppress the exception + return True + + def resume(self): + "restore and re-raise any exception" + + if '_saved' not in vars(self): + return + + type, exc = map(pickle.loads, self._saved) + raise exc.with_traceback(self._tb) + + +@contextlib.contextmanager +def save_modules(): + """ + Context in which imported modules are saved. + + Translates exceptions internal to the context into the equivalent exception + outside the context. + """ + saved = sys.modules.copy() + with ExceptionSaver() as saved_exc: + yield saved + + sys.modules.update(saved) + # remove any modules imported since + del_modules = ( + mod_name + for mod_name in sys.modules + if mod_name not in saved + # exclude any encodings modules. See #285 + and not mod_name.startswith('encodings.') + ) + _clear_modules(del_modules) + + saved_exc.resume() + + +def _clear_modules(module_names): + for mod_name in list(module_names): + del sys.modules[mod_name] + + +@contextlib.contextmanager +def save_pkg_resources_state(): + saved = pkg_resources.__getstate__() + try: + yield saved + finally: + pkg_resources.__setstate__(saved) + + +@contextlib.contextmanager +def setup_context(setup_dir): + temp_dir = os.path.join(setup_dir, 'temp') + with save_pkg_resources_state(): + with save_modules(): + with save_path(): + hide_setuptools() + with save_argv(): + with override_temp(temp_dir): + with pushd(setup_dir): + # ensure setuptools commands are available + __import__('setuptools') + yield + + +_MODULES_TO_HIDE = { + 'setuptools', + 'distutils', + 'pkg_resources', + 'Cython', + '_distutils_hack', +} + + +def _needs_hiding(mod_name): + """ + >>> _needs_hiding('setuptools') + True + >>> _needs_hiding('pkg_resources') + True + >>> _needs_hiding('setuptools_plugin') + False + >>> _needs_hiding('setuptools.__init__') + True + >>> _needs_hiding('distutils') + True + >>> _needs_hiding('os') + False + >>> _needs_hiding('Cython') + True + """ + base_module = mod_name.split('.', 1)[0] + return base_module in _MODULES_TO_HIDE + + +def hide_setuptools(): + """ + Remove references to setuptools' modules from sys.modules to allow the + invocation to import the most appropriate setuptools. This technique is + necessary to avoid issues such as #315 where setuptools upgrading itself + would fail to find a function declared in the metadata. + """ + _distutils_hack = sys.modules.get('_distutils_hack', None) + if _distutils_hack is not None: + _distutils_hack.remove_shim() + + modules = filter(_needs_hiding, sys.modules) + _clear_modules(modules) + + +def run_setup(setup_script, args): + """Run a distutils setup script, sandboxed in its directory""" + setup_dir = os.path.abspath(os.path.dirname(setup_script)) + with setup_context(setup_dir): + try: + sys.argv[:] = [setup_script] + list(args) + sys.path.insert(0, setup_dir) + # reset to include setup dir, w/clean callback list + working_set.__init__() + working_set.callbacks.append(lambda dist: dist.activate()) + + with DirectorySandbox(setup_dir): + ns = dict(__file__=setup_script, __name__='__main__') + _execfile(setup_script, ns) + except SystemExit as v: + if v.args and v.args[0]: + raise + # Normal exit, just return + + +class AbstractSandbox: + """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts""" + + _active = False + + def __init__(self): + self._attrs = [ + name + for name in dir(_os) + if not name.startswith('_') and hasattr(self, name) + ] + + def _copy(self, source): + for name in self._attrs: + setattr(os, name, getattr(source, name)) + + def __enter__(self): + self._copy(self) + if _file: + builtins.file = self._file + builtins.open = self._open + self._active = True + + def __exit__(self, exc_type, exc_value, traceback): + self._active = False + if _file: + builtins.file = _file + builtins.open = _open + self._copy(_os) + + def run(self, func): + """Run 'func' under os sandboxing""" + with self: + return func() + + def _mk_dual_path_wrapper(name): + original = getattr(_os, name) + + def wrap(self, src, dst, *args, **kw): + if self._active: + src, dst = self._remap_pair(name, src, dst, *args, **kw) + return original(src, dst, *args, **kw) + + return wrap + + for name in ["rename", "link", "symlink"]: + if hasattr(_os, name): + locals()[name] = _mk_dual_path_wrapper(name) + + def _mk_single_path_wrapper(name, original=None): + original = original or getattr(_os, name) + + def wrap(self, path, *args, **kw): + if self._active: + path = self._remap_input(name, path, *args, **kw) + return original(path, *args, **kw) + + return wrap + + if _file: + _file = _mk_single_path_wrapper('file', _file) + _open = _mk_single_path_wrapper('open', _open) + for name in [ + "stat", + "listdir", + "chdir", + "open", + "chmod", + "chown", + "mkdir", + "remove", + "unlink", + "rmdir", + "utime", + "lchown", + "chroot", + "lstat", + "startfile", + "mkfifo", + "mknod", + "pathconf", + "access", + ]: + if hasattr(_os, name): + locals()[name] = _mk_single_path_wrapper(name) + + def _mk_single_with_return(name): + original = getattr(_os, name) + + def wrap(self, path, *args, **kw): + if self._active: + path = self._remap_input(name, path, *args, **kw) + return self._remap_output(name, original(path, *args, **kw)) + return original(path, *args, **kw) + + return wrap + + for name in ['readlink', 'tempnam']: + if hasattr(_os, name): + locals()[name] = _mk_single_with_return(name) + + def _mk_query(name): + original = getattr(_os, name) + + def wrap(self, *args, **kw): + retval = original(*args, **kw) + if self._active: + return self._remap_output(name, retval) + return retval + + return wrap + + for name in ['getcwd', 'tmpnam']: + if hasattr(_os, name): + locals()[name] = _mk_query(name) + + def _validate_path(self, path): + """Called to remap or validate any path, whether input or output""" + return path + + def _remap_input(self, operation, path, *args, **kw): + """Called for path inputs""" + return self._validate_path(path) + + def _remap_output(self, operation, path): + """Called for path outputs""" + return self._validate_path(path) + + def _remap_pair(self, operation, src, dst, *args, **kw): + """Called for path pairs like rename, link, and symlink operations""" + return ( + self._remap_input(operation + '-from', src, *args, **kw), + self._remap_input(operation + '-to', dst, *args, **kw), + ) + + +if hasattr(os, 'devnull'): + _EXCEPTIONS = [os.devnull] +else: + _EXCEPTIONS = [] + + +class DirectorySandbox(AbstractSandbox): + """Restrict operations to a single subdirectory - pseudo-chroot""" + + write_ops = dict.fromkeys( + [ + "open", + "chmod", + "chown", + "mkdir", + "remove", + "unlink", + "rmdir", + "utime", + "lchown", + "chroot", + "mkfifo", + "mknod", + "tempnam", + ] + ) + + _exception_patterns = [] + "exempt writing to paths that match the pattern" + + def __init__(self, sandbox, exceptions=_EXCEPTIONS): + self._sandbox = os.path.normcase(os.path.realpath(sandbox)) + self._prefix = os.path.join(self._sandbox, '') + self._exceptions = [ + os.path.normcase(os.path.realpath(path)) for path in exceptions + ] + AbstractSandbox.__init__(self) + + def _violation(self, operation, *args, **kw): + from setuptools.sandbox import SandboxViolation + + raise SandboxViolation(operation, args, kw) + + if _file: + + def _file(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("file", path, mode, *args, **kw) + return _file(path, mode, *args, **kw) + + def _open(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("open", path, mode, *args, **kw) + return _open(path, mode, *args, **kw) + + def tmpnam(self): + self._violation("tmpnam") + + def _ok(self, path): + active = self._active + try: + self._active = False + realpath = os.path.normcase(os.path.realpath(path)) + return ( + self._exempted(realpath) + or realpath == self._sandbox + or realpath.startswith(self._prefix) + ) + finally: + self._active = active + + def _exempted(self, filepath): + start_matches = ( + filepath.startswith(exception) for exception in self._exceptions + ) + pattern_matches = ( + re.match(pattern, filepath) for pattern in self._exception_patterns + ) + candidates = itertools.chain(start_matches, pattern_matches) + return any(candidates) + + def _remap_input(self, operation, path, *args, **kw): + """Called for path inputs""" + if operation in self.write_ops and not self._ok(path): + self._violation(operation, os.path.realpath(path), *args, **kw) + return path + + def _remap_pair(self, operation, src, dst, *args, **kw): + """Called for path pairs like rename, link, and symlink operations""" + if not self._ok(src) or not self._ok(dst): + self._violation(operation, src, dst, *args, **kw) + return (src, dst) + + def open(self, file, flags, mode=0o777, *args, **kw): + """Called for low-level os.open()""" + if flags & WRITE_FLAGS and not self._ok(file): + self._violation("os.open", file, flags, mode, *args, **kw) + return _os.open(file, flags, mode, *args, **kw) + + +WRITE_FLAGS = functools.reduce( + operator.or_, + [ + getattr(_os, a, 0) + for a in "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split() + ], +) + + +class SandboxViolation(DistutilsError): + """A setup script attempted to modify the filesystem outside the sandbox""" + + tmpl = textwrap.dedent( + """ + SandboxViolation: {cmd}{args!r} {kwargs} + + The package setup script has attempted to modify files on your system + that are not within the EasyInstall build area, and has been aborted. + + This package cannot be safely installed by EasyInstall, and may not + support alternate installation locations even if you run its setup + script by hand. Please inform the package's author and the EasyInstall + maintainers to find out if a fix or workaround is available. + """ + ).lstrip() + + def __str__(self): + cmd, args, kwargs = self.args + return self.tmpl.format(**locals()) diff --git a/MLPY/Lib/site-packages/setuptools/script (dev).tmpl b/MLPY/Lib/site-packages/setuptools/script (dev).tmpl new file mode 100644 index 0000000000000000000000000000000000000000..39a24b04888e79df51e2237577b303a2f901be63 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/script (dev).tmpl @@ -0,0 +1,6 @@ +# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r +__requires__ = %(spec)r +__import__('pkg_resources').require(%(spec)r) +__file__ = %(dev_path)r +with open(__file__) as f: + exec(compile(f.read(), __file__, 'exec')) diff --git a/MLPY/Lib/site-packages/setuptools/script.tmpl b/MLPY/Lib/site-packages/setuptools/script.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..ff5efbcab3b58063dd84787181c26a95fb663d94 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/script.tmpl @@ -0,0 +1,3 @@ +# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r +__requires__ = %(spec)r +__import__('pkg_resources').run_script(%(spec)r, %(script_name)r) diff --git a/MLPY/Lib/site-packages/setuptools/unicode_utils.py b/MLPY/Lib/site-packages/setuptools/unicode_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..e84e65e3e14152a2ba6e6e05d914f0e1bbef187b --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/unicode_utils.py @@ -0,0 +1,42 @@ +import unicodedata +import sys + + +# HFS Plus uses decomposed UTF-8 +def decompose(path): + if isinstance(path, str): + return unicodedata.normalize('NFD', path) + try: + path = path.decode('utf-8') + path = unicodedata.normalize('NFD', path) + path = path.encode('utf-8') + except UnicodeError: + pass # Not UTF-8 + return path + + +def filesys_decode(path): + """ + Ensure that the given path is decoded, + NONE when no expected encoding works + """ + + if isinstance(path, str): + return path + + fs_enc = sys.getfilesystemencoding() or 'utf-8' + candidates = fs_enc, 'utf-8' + + for enc in candidates: + try: + return path.decode(enc) + except UnicodeDecodeError: + continue + + +def try_encode(string, enc): + "turn unicode encoding into a functional routine" + try: + return string.encode(enc) + except UnicodeEncodeError: + return None diff --git a/MLPY/Lib/site-packages/setuptools/version.py b/MLPY/Lib/site-packages/setuptools/version.py new file mode 100644 index 0000000000000000000000000000000000000000..95e1869658566aac3060562d8cd5a6b647887d1e --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/version.py @@ -0,0 +1,6 @@ +import pkg_resources + +try: + __version__ = pkg_resources.get_distribution('setuptools').version +except Exception: + __version__ = 'unknown' diff --git a/MLPY/Lib/site-packages/setuptools/wheel.py b/MLPY/Lib/site-packages/setuptools/wheel.py new file mode 100644 index 0000000000000000000000000000000000000000..0be811af2c29e5ef697b63f329b882694c91c88d --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/wheel.py @@ -0,0 +1,213 @@ +"""Wheels support.""" + +from distutils.util import get_platform +from distutils import log +import email +import itertools +import os +import posixpath +import re +import zipfile + +import pkg_resources +import setuptools +from pkg_resources import parse_version +from setuptools.extern.packaging.tags import sys_tags +from setuptools.extern.packaging.utils import canonicalize_name +from setuptools.command.egg_info import write_requirements + + +WHEEL_NAME = re.compile( + r"""^(?P.+?)-(?P\d.*?) + ((-(?P\d.*?))?-(?P.+?)-(?P.+?)-(?P.+?) + )\.whl$""", + re.VERBOSE).match + +NAMESPACE_PACKAGE_INIT = \ + "__import__('pkg_resources').declare_namespace(__name__)\n" + + +def unpack(src_dir, dst_dir): + '''Move everything under `src_dir` to `dst_dir`, and delete the former.''' + for dirpath, dirnames, filenames in os.walk(src_dir): + subdir = os.path.relpath(dirpath, src_dir) + for f in filenames: + src = os.path.join(dirpath, f) + dst = os.path.join(dst_dir, subdir, f) + os.renames(src, dst) + for n, d in reversed(list(enumerate(dirnames))): + src = os.path.join(dirpath, d) + dst = os.path.join(dst_dir, subdir, d) + if not os.path.exists(dst): + # Directory does not exist in destination, + # rename it and prune it from os.walk list. + os.renames(src, dst) + del dirnames[n] + # Cleanup. + for dirpath, dirnames, filenames in os.walk(src_dir, topdown=True): + assert not filenames + os.rmdir(dirpath) + + +class Wheel: + + def __init__(self, filename): + match = WHEEL_NAME(os.path.basename(filename)) + if match is None: + raise ValueError('invalid wheel name: %r' % filename) + self.filename = filename + for k, v in match.groupdict().items(): + setattr(self, k, v) + + def tags(self): + '''List tags (py_version, abi, platform) supported by this wheel.''' + return itertools.product( + self.py_version.split('.'), + self.abi.split('.'), + self.platform.split('.'), + ) + + def is_compatible(self): + '''Is the wheel is compatible with the current platform?''' + supported_tags = set( + (t.interpreter, t.abi, t.platform) for t in sys_tags()) + return next((True for t in self.tags() if t in supported_tags), False) + + def egg_name(self): + return pkg_resources.Distribution( + project_name=self.project_name, version=self.version, + platform=(None if self.platform == 'any' else get_platform()), + ).egg_name() + '.egg' + + def get_dist_info(self, zf): + # find the correct name of the .dist-info dir in the wheel file + for member in zf.namelist(): + dirname = posixpath.dirname(member) + if (dirname.endswith('.dist-info') and + canonicalize_name(dirname).startswith( + canonicalize_name(self.project_name))): + return dirname + raise ValueError("unsupported wheel format. .dist-info not found") + + def install_as_egg(self, destination_eggdir): + '''Install wheel as an egg directory.''' + with zipfile.ZipFile(self.filename) as zf: + self._install_as_egg(destination_eggdir, zf) + + def _install_as_egg(self, destination_eggdir, zf): + dist_basename = '%s-%s' % (self.project_name, self.version) + dist_info = self.get_dist_info(zf) + dist_data = '%s.data' % dist_basename + egg_info = os.path.join(destination_eggdir, 'EGG-INFO') + + self._convert_metadata(zf, destination_eggdir, dist_info, egg_info) + self._move_data_entries(destination_eggdir, dist_data) + self._fix_namespace_packages(egg_info, destination_eggdir) + + @staticmethod + def _convert_metadata(zf, destination_eggdir, dist_info, egg_info): + def get_metadata(name): + with zf.open(posixpath.join(dist_info, name)) as fp: + value = fp.read().decode('utf-8') + return email.parser.Parser().parsestr(value) + + wheel_metadata = get_metadata('WHEEL') + # Check wheel format version is supported. + wheel_version = parse_version(wheel_metadata.get('Wheel-Version')) + wheel_v1 = ( + parse_version('1.0') <= wheel_version < parse_version('2.0dev0') + ) + if not wheel_v1: + raise ValueError( + 'unsupported wheel format version: %s' % wheel_version) + # Extract to target directory. + os.mkdir(destination_eggdir) + zf.extractall(destination_eggdir) + # Convert metadata. + dist_info = os.path.join(destination_eggdir, dist_info) + dist = pkg_resources.Distribution.from_location( + destination_eggdir, dist_info, + metadata=pkg_resources.PathMetadata(destination_eggdir, dist_info), + ) + + # Note: Evaluate and strip markers now, + # as it's difficult to convert back from the syntax: + # foobar; "linux" in sys_platform and extra == 'test' + def raw_req(req): + req.marker = None + return str(req) + install_requires = list(sorted(map(raw_req, dist.requires()))) + extras_require = { + extra: sorted( + req + for req in map(raw_req, dist.requires((extra,))) + if req not in install_requires + ) + for extra in dist.extras + } + os.rename(dist_info, egg_info) + os.rename( + os.path.join(egg_info, 'METADATA'), + os.path.join(egg_info, 'PKG-INFO'), + ) + setup_dist = setuptools.Distribution( + attrs=dict( + install_requires=install_requires, + extras_require=extras_require, + ), + ) + # Temporarily disable info traces. + log_threshold = log._global_log.threshold + log.set_threshold(log.WARN) + try: + write_requirements( + setup_dist.get_command_obj('egg_info'), + None, + os.path.join(egg_info, 'requires.txt'), + ) + finally: + log.set_threshold(log_threshold) + + @staticmethod + def _move_data_entries(destination_eggdir, dist_data): + """Move data entries to their correct location.""" + dist_data = os.path.join(destination_eggdir, dist_data) + dist_data_scripts = os.path.join(dist_data, 'scripts') + if os.path.exists(dist_data_scripts): + egg_info_scripts = os.path.join( + destination_eggdir, 'EGG-INFO', 'scripts') + os.mkdir(egg_info_scripts) + for entry in os.listdir(dist_data_scripts): + # Remove bytecode, as it's not properly handled + # during easy_install scripts install phase. + if entry.endswith('.pyc'): + os.unlink(os.path.join(dist_data_scripts, entry)) + else: + os.rename( + os.path.join(dist_data_scripts, entry), + os.path.join(egg_info_scripts, entry), + ) + os.rmdir(dist_data_scripts) + for subdir in filter(os.path.exists, ( + os.path.join(dist_data, d) + for d in ('data', 'headers', 'purelib', 'platlib') + )): + unpack(subdir, destination_eggdir) + if os.path.exists(dist_data): + os.rmdir(dist_data) + + @staticmethod + def _fix_namespace_packages(egg_info, destination_eggdir): + namespace_packages = os.path.join( + egg_info, 'namespace_packages.txt') + if os.path.exists(namespace_packages): + with open(namespace_packages) as fp: + namespace_packages = fp.read().split() + for mod in namespace_packages: + mod_dir = os.path.join(destination_eggdir, *mod.split('.')) + mod_init = os.path.join(mod_dir, '__init__.py') + if not os.path.exists(mod_dir): + os.mkdir(mod_dir) + if not os.path.exists(mod_init): + with open(mod_init, 'w') as fp: + fp.write(NAMESPACE_PACKAGE_INIT) diff --git a/MLPY/Lib/site-packages/setuptools/windows_support.py b/MLPY/Lib/site-packages/setuptools/windows_support.py new file mode 100644 index 0000000000000000000000000000000000000000..cb977cff9545ef5d48ad7cf13f2cbe1ebc3e7cd0 --- /dev/null +++ b/MLPY/Lib/site-packages/setuptools/windows_support.py @@ -0,0 +1,29 @@ +import platform +import ctypes + + +def windows_only(func): + if platform.system() != 'Windows': + return lambda *args, **kwargs: None + return func + + +@windows_only +def hide_file(path): + """ + Set the hidden attribute on a file or directory. + + From http://stackoverflow.com/questions/19622133/ + + `path` must be text. + """ + __import__('ctypes.wintypes') + SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW + SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD + SetFileAttributes.restype = ctypes.wintypes.BOOL + + FILE_ATTRIBUTE_HIDDEN = 0x02 + + ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN) + if not ret: + raise ctypes.WinError() diff --git a/MLPY/Lib/site-packages/six-1.16.0.dist-info/INSTALLER b/MLPY/Lib/site-packages/six-1.16.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/MLPY/Lib/site-packages/six-1.16.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/MLPY/Lib/site-packages/six-1.16.0.dist-info/LICENSE b/MLPY/Lib/site-packages/six-1.16.0.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..de6633112c1f9951fd688e1fb43457a1ec11d6d8 --- /dev/null +++ b/MLPY/Lib/site-packages/six-1.16.0.dist-info/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2010-2020 Benjamin Peterson + +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. diff --git a/MLPY/Lib/site-packages/six-1.16.0.dist-info/METADATA b/MLPY/Lib/site-packages/six-1.16.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..6d7525c2ebcfe25cb6787579bf5324da1fd6f28a --- /dev/null +++ b/MLPY/Lib/site-packages/six-1.16.0.dist-info/METADATA @@ -0,0 +1,49 @@ +Metadata-Version: 2.1 +Name: six +Version: 1.16.0 +Summary: Python 2 and 3 compatibility utilities +Home-page: https://github.com/benjaminp/six +Author: Benjamin Peterson +Author-email: benjamin@python.org +License: MIT +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.* + +.. image:: https://img.shields.io/pypi/v/six.svg + :target: https://pypi.org/project/six/ + :alt: six on PyPI + +.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master + :target: https://travis-ci.org/benjaminp/six + :alt: six on TravisCI + +.. image:: https://readthedocs.org/projects/six/badge/?version=latest + :target: https://six.readthedocs.io/ + :alt: six's documentation on Read the Docs + +.. image:: https://img.shields.io/badge/license-MIT-green.svg + :target: https://github.com/benjaminp/six/blob/master/LICENSE + :alt: MIT License badge + +Six is a Python 2 and 3 compatibility library. It provides utility functions +for smoothing over the differences between the Python versions with the goal of +writing Python code that is compatible on both Python versions. See the +documentation for more information on what is provided. + +Six supports Python 2.7 and 3.3+. It is contained in only one Python +file, so it can be easily copied into your project. (The copyright and license +notice must be retained.) + +Online documentation is at https://six.readthedocs.io/. + +Bugs can be reported to https://github.com/benjaminp/six. The code can also +be found there. + + diff --git a/MLPY/Lib/site-packages/six-1.16.0.dist-info/RECORD b/MLPY/Lib/site-packages/six-1.16.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..d8c0f6c00c7838dd034fd9d9bcb17b6043031552 --- /dev/null +++ b/MLPY/Lib/site-packages/six-1.16.0.dist-info/RECORD @@ -0,0 +1,8 @@ +__pycache__/six.cpython-39.pyc,, +six-1.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +six-1.16.0.dist-info/LICENSE,sha256=i7hQxWWqOJ_cFvOkaWWtI9gq3_YPI5P8J2K2MYXo5sk,1066 +six-1.16.0.dist-info/METADATA,sha256=VQcGIFCAEmfZcl77E5riPCN4v2TIsc_qtacnjxKHJoI,1795 +six-1.16.0.dist-info/RECORD,, +six-1.16.0.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +six-1.16.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4 +six.py,sha256=TOOfQi7nFGfMrIvtdr6wX4wyHH8M7aknmuLfo2cBBrM,34549 diff --git a/MLPY/Lib/site-packages/six-1.16.0.dist-info/WHEEL b/MLPY/Lib/site-packages/six-1.16.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..01b8fc7d4a10cb8b4f1d21f11d3398d07d6b3478 --- /dev/null +++ b/MLPY/Lib/site-packages/six-1.16.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/MLPY/Lib/site-packages/six-1.16.0.dist-info/top_level.txt b/MLPY/Lib/site-packages/six-1.16.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..ffe2fce498955b628014618b28c6bcf152466a4a --- /dev/null +++ b/MLPY/Lib/site-packages/six-1.16.0.dist-info/top_level.txt @@ -0,0 +1 @@ +six