From 426b59be186a0db63aff45f634f5ead37e9fa9fc Mon Sep 17 00:00:00 2001 From: wayrk Date: Mon, 13 Jan 2020 21:41:36 +0300 Subject: [PATCH] winpython --- build/lib/winpython/__init__.py | 33 + build/lib/winpython/_vendor/qtpy/QtCore.py | 101 + .../lib/winpython/_vendor/qtpy/QtDesigner.py | 20 + build/lib/winpython/_vendor/qtpy/QtGui.py | 157 ++ build/lib/winpython/_vendor/qtpy/QtHelp.py | 24 + .../winpython/_vendor/qtpy/QtMultimedia.py | 17 + build/lib/winpython/_vendor/qtpy/QtNetwork.py | 25 + build/lib/winpython/_vendor/qtpy/QtOpenGL.py | 22 + .../winpython/_vendor/qtpy/QtPrintSupport.py | 28 + build/lib/winpython/_vendor/qtpy/QtSql.py | 24 + build/lib/winpython/_vendor/qtpy/QtSvg.py | 24 + build/lib/winpython/_vendor/qtpy/QtTest.py | 30 + .../_vendor/qtpy/QtWebEngineWidgets.py | 53 + build/lib/winpython/_vendor/qtpy/QtWidgets.py | 133 + build/lib/winpython/_vendor/qtpy/__init__.py | 191 ++ .../winpython/_vendor/qtpy/_patch/__init__.py | 0 .../_vendor/qtpy/_patch/qcombobox.py | 101 + .../_vendor/qtpy/_patch/qheaderview.py | 96 + build/lib/winpython/_vendor/qtpy/_version.py | 2 + build/lib/winpython/_vendor/qtpy/compat.py | 196 ++ build/lib/winpython/_vendor/qtpy/py3compat.py | 261 ++ .../winpython/_vendor/qtpy/tests/__init__.py | 0 .../winpython/_vendor/qtpy/tests/conftest.py | 71 + .../winpython/_vendor/qtpy/tests/runtests.py | 26 + .../winpython/_vendor/qtpy/tests/test_main.py | 82 + .../qtpy/tests/test_patch_qcombobox.py | 102 + .../qtpy/tests/test_patch_qheaderview.py | 98 + .../qtpy/tests/test_qdesktopservice_split.py | 41 + .../_vendor/qtpy/tests/test_qtcore.py | 10 + .../_vendor/qtpy/tests/test_qtdesigner.py | 28 + .../_vendor/qtpy/tests/test_qthelp.py | 22 + .../_vendor/qtpy/tests/test_qtmultimedia.py | 14 + .../_vendor/qtpy/tests/test_qtnetwork.py | 42 + .../_vendor/qtpy/tests/test_qtprintsupport.py | 18 + .../_vendor/qtpy/tests/test_qtsql.py | 24 + .../_vendor/qtpy/tests/test_qtsvg.py | 13 + .../_vendor/qtpy/tests/test_qttest.py | 9 + .../winpython/_vendor/qtpy/tests/test_uic.py | 83 + build/lib/winpython/_vendor/qtpy/uic.py | 228 ++ build/lib/winpython/associate.py | 387 +++ build/lib/winpython/config.py | 57 + build/lib/winpython/controlpanel.py | 1014 +++++++ build/lib/winpython/data/categories.ini | 30 + build/lib/winpython/data/packages.ini | 2412 +++++++++++++++++ build/lib/winpython/data/tools.ini | 47 + build/lib/winpython/disthelpers.py | 1130 ++++++++ build/lib/winpython/images/bug.png | Bin 0 -> 1659 bytes build/lib/winpython/images/winpython.svg | 444 +++ build/lib/winpython/py3compat.py | 268 ++ build/lib/winpython/qthelpers.py | 300 ++ build/lib/winpython/utils.py | 794 ++++++ build/lib/winpython/wppm.py | 860 ++++++ build/scripts-2.7/register_python | 26 + build/scripts-2.7/register_python.bat | 2 + dist/winpython-2.2.20191222-py2.7.egg | Bin 0 -> 190179 bytes winpython.egg-info/PKG-INFO | 25 + winpython.egg-info/SOURCES.txt | 65 + winpython.egg-info/dependency_links.txt | 1 + winpython.egg-info/entry_points.txt | 4 + winpython.egg-info/top_level.txt | 1 + 60 files changed, 10316 insertions(+) create mode 100644 build/lib/winpython/__init__.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtCore.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtDesigner.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtGui.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtHelp.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtMultimedia.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtNetwork.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtOpenGL.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtPrintSupport.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtSql.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtSvg.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtTest.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtWebEngineWidgets.py create mode 100644 build/lib/winpython/_vendor/qtpy/QtWidgets.py create mode 100644 build/lib/winpython/_vendor/qtpy/__init__.py create mode 100644 build/lib/winpython/_vendor/qtpy/_patch/__init__.py create mode 100644 build/lib/winpython/_vendor/qtpy/_patch/qcombobox.py create mode 100644 build/lib/winpython/_vendor/qtpy/_patch/qheaderview.py create mode 100644 build/lib/winpython/_vendor/qtpy/_version.py create mode 100644 build/lib/winpython/_vendor/qtpy/compat.py create mode 100644 build/lib/winpython/_vendor/qtpy/py3compat.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/__init__.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/conftest.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/runtests.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_main.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_patch_qcombobox.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_patch_qheaderview.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qdesktopservice_split.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qtcore.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qtdesigner.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qthelp.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qtmultimedia.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qtnetwork.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qtprintsupport.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qtsql.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qtsvg.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_qttest.py create mode 100644 build/lib/winpython/_vendor/qtpy/tests/test_uic.py create mode 100644 build/lib/winpython/_vendor/qtpy/uic.py create mode 100644 build/lib/winpython/associate.py create mode 100644 build/lib/winpython/config.py create mode 100644 build/lib/winpython/controlpanel.py create mode 100644 build/lib/winpython/data/categories.ini create mode 100644 build/lib/winpython/data/packages.ini create mode 100644 build/lib/winpython/data/tools.ini create mode 100644 build/lib/winpython/disthelpers.py create mode 100644 build/lib/winpython/images/bug.png create mode 100644 build/lib/winpython/images/winpython.svg create mode 100644 build/lib/winpython/py3compat.py create mode 100644 build/lib/winpython/qthelpers.py create mode 100644 build/lib/winpython/utils.py create mode 100644 build/lib/winpython/wppm.py create mode 100644 build/scripts-2.7/register_python create mode 100644 build/scripts-2.7/register_python.bat create mode 100644 dist/winpython-2.2.20191222-py2.7.egg create mode 100644 winpython.egg-info/PKG-INFO create mode 100644 winpython.egg-info/SOURCES.txt create mode 100644 winpython.egg-info/dependency_links.txt create mode 100644 winpython.egg-info/entry_points.txt create mode 100644 winpython.egg-info/top_level.txt diff --git a/build/lib/winpython/__init__.py b/build/lib/winpython/__init__.py new file mode 100644 index 00000000..8ae1bf3f --- /dev/null +++ b/build/lib/winpython/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +""" +WinPython License Agreement (MIT License) +----------------------------------------- + +Copyright (c) 2012-2013 Pierre Raybaut +Copyright (c) 2014-2019+ The Winpython development team https://github.com/winpython/ + +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. +""" + +__version__ = '2.2.20191222' +__license__ = __doc__ +__project_url__ = 'http://winpython.github.io/' diff --git a/build/lib/winpython/_vendor/qtpy/QtCore.py b/build/lib/winpython/_vendor/qtpy/QtCore.py new file mode 100644 index 00000000..289fcac2 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtCore.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014-2015 Colin Duquesnoy +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides QtCore classes and functions. +""" + +from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError + + +if PYQT5: + from PyQt5.QtCore import * + from PyQt5.QtCore import pyqtSignal as Signal + from PyQt5.QtCore import pyqtSlot as Slot + from PyQt5.QtCore import pyqtProperty as Property + from PyQt5.QtCore import QT_VERSION_STR as __version__ + + # Those are imported from `import *` + del pyqtSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR +elif PYSIDE2: + from PySide2.QtCore import * + try: # may be limited to PySide-5.11a1 only + from PySide2.QtGui import QStringListModel + except: + pass +elif PYQT4: + from PyQt4.QtCore import * + # Those are things we inherited from Spyder that fix crazy crashes under + # some specific situations. (See #34) + from PyQt4.QtCore import QCoreApplication + from PyQt4.QtCore import Qt + from PyQt4.QtCore import pyqtSignal as Signal + from PyQt4.QtCore import pyqtSlot as Slot + from PyQt4.QtCore import pyqtProperty as Property + from PyQt4.QtGui import (QItemSelection, QItemSelectionModel, + QItemSelectionRange, QSortFilterProxyModel, + QStringListModel) + from PyQt4.QtCore import QT_VERSION_STR as __version__ + from PyQt4.QtCore import qInstallMsgHandler as qInstallMessageHandler + + # QDesktopServices has has been split into (QDesktopServices and + # QStandardPaths) in Qt5 + # This creates a dummy class that emulates QStandardPaths + from PyQt4.QtGui import QDesktopServices as _QDesktopServices + + class QStandardPaths(): + StandardLocation = _QDesktopServices.StandardLocation + displayName = _QDesktopServices.displayName + DesktopLocation = _QDesktopServices.DesktopLocation + DocumentsLocation = _QDesktopServices.DocumentsLocation + FontsLocation = _QDesktopServices.FontsLocation + ApplicationsLocation = _QDesktopServices.ApplicationsLocation + MusicLocation = _QDesktopServices.MusicLocation + MoviesLocation = _QDesktopServices.MoviesLocation + PicturesLocation = _QDesktopServices.PicturesLocation + TempLocation = _QDesktopServices.TempLocation + HomeLocation = _QDesktopServices.HomeLocation + DataLocation = _QDesktopServices.DataLocation + CacheLocation = _QDesktopServices.CacheLocation + writableLocation = _QDesktopServices.storageLocation + + # Those are imported from `import *` + del pyqtSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR, qInstallMsgHandler +elif PYSIDE: + from PySide.QtCore import * + from PySide.QtGui import (QItemSelection, QItemSelectionModel, + QItemSelectionRange, QSortFilterProxyModel, + QStringListModel) + from PySide.QtCore import qInstallMsgHandler as qInstallMessageHandler + del qInstallMsgHandler + + # QDesktopServices has has been split into (QDesktopServices and + # QStandardPaths) in Qt5 + # This creates a dummy class that emulates QStandardPaths + from PySide.QtGui import QDesktopServices as _QDesktopServices + + class QStandardPaths(): + StandardLocation = _QDesktopServices.StandardLocation + displayName = _QDesktopServices.displayName + DesktopLocation = _QDesktopServices.DesktopLocation + DocumentsLocation = _QDesktopServices.DocumentsLocation + FontsLocation = _QDesktopServices.FontsLocation + ApplicationsLocation = _QDesktopServices.ApplicationsLocation + MusicLocation = _QDesktopServices.MusicLocation + MoviesLocation = _QDesktopServices.MoviesLocation + PicturesLocation = _QDesktopServices.PicturesLocation + TempLocation = _QDesktopServices.TempLocation + HomeLocation = _QDesktopServices.HomeLocation + DataLocation = _QDesktopServices.DataLocation + CacheLocation = _QDesktopServices.CacheLocation + writableLocation = _QDesktopServices.storageLocation + + import PySide.QtCore + __version__ = PySide.QtCore.__version__ +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/QtDesigner.py b/build/lib/winpython/_vendor/qtpy/QtDesigner.py new file mode 100644 index 00000000..4aaafc81 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtDesigner.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014-2015 Colin Duquesnoy +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides QtDesigner classes and functions. +""" + +from . import PYQT5, PYQT4, PythonQtError + + +if PYQT5: + from PyQt5.QtDesigner import * +elif PYQT4: + from PyQt4.QtDesigner import * +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/QtGui.py b/build/lib/winpython/_vendor/qtpy/QtGui.py new file mode 100644 index 00000000..071be132 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtGui.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014-2015 Colin Duquesnoy +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides QtGui classes and functions. +.. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtGui are + exposed here. Therefore, you need to treat/use this package as if it were + the ``PyQt5.QtGui`` module. +""" +import warnings + +from . import PYQT5, PYQT4, PYSIDE, PYSIDE2, PythonQtError + + +if PYQT5: + from PyQt5.QtGui import * +elif PYSIDE2: + from PySide2.QtGui import * +elif PYQT4: + try: + # Older versions of PyQt4 do not provide these + from PyQt4.QtGui import (QGlyphRun, QMatrix2x2, QMatrix2x3, + QMatrix2x4, QMatrix3x2, QMatrix3x3, + QMatrix3x4, QMatrix4x2, QMatrix4x3, + QMatrix4x4, QTouchEvent, QQuaternion, + QRadialGradient, QRawFont, QStaticText, + QVector2D, QVector3D, QVector4D, + qFuzzyCompare) + except ImportError: + pass + from PyQt4.Qt import QKeySequence, QTextCursor + from PyQt4.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap, + QBrush, QClipboard, QCloseEvent, QColor, + QConicalGradient, QContextMenuEvent, QCursor, + QDoubleValidator, QDrag, + QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, + QDropEvent, QFileOpenEvent, QFocusEvent, QFont, + QFontDatabase, QFontInfo, QFontMetrics, + QFontMetricsF, QGradient, QHelpEvent, + QHideEvent, QHoverEvent, QIcon, QIconDragEvent, + QIconEngine, QImage, QImageIOHandler, QImageReader, + QImageWriter, QInputEvent, QInputMethodEvent, + QKeyEvent, QLinearGradient, + QMouseEvent, QMoveEvent, QMovie, + QPaintDevice, QPaintEngine, QPaintEngineState, + QPaintEvent, QPainter, QPainterPath, + QPainterPathStroker, QPalette, QPen, QPicture, + QPictureIO, QPixmap, QPixmapCache, QPolygon, + QPolygonF, QRegExpValidator, QRegion, QResizeEvent, + QSessionManager, QShortcutEvent, QShowEvent, + QStandardItem, QStandardItemModel, + QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, + QTextBlock, QTextBlockFormat, QTextBlockGroup, + QTextBlockUserData, QTextCharFormat, + QTextDocument, QTextDocumentFragment, + QTextDocumentWriter, QTextFormat, QTextFragment, + QTextFrame, QTextFrameFormat, QTextImageFormat, + QTextInlineObject, QTextItem, QTextLayout, + QTextLength, QTextLine, QTextList, QTextListFormat, + QTextObject, QTextObjectInterface, QTextOption, + QTextTable, QTextTableCell, QTextTableCellFormat, + QTextTableFormat, QTransform, + QValidator, QWhatsThisClickedEvent, QWheelEvent, + QWindowStateChangeEvent, qAlpha, qBlue, + qGray, qGreen, qIsGray, qRed, qRgb, + qRgba, QIntValidator) + + # QDesktopServices has has been split into (QDesktopServices and + # QStandardPaths) in Qt5 + # It only exposes QDesktopServices that are still in pyqt5 + from PyQt4.QtGui import QDesktopServices as _QDesktopServices + + class QDesktopServices(): + openUrl = _QDesktopServices.openUrl + setUrlHandler = _QDesktopServices.setUrlHandler + unsetUrlHandler = _QDesktopServices.unsetUrlHandler + + def __getattr__(self, name): + attr = getattr(_QDesktopServices, name) + + new_name = name + if name == 'storageLocation': + new_name = 'writableLocation' + warnings.warn(("Warning QDesktopServices.{} is deprecated in Qt5" + "we recommend you use QDesktopServices.{} instead").format(name, new_name), + DeprecationWarning) + return attr + QDesktopServices = QDesktopServices() + +elif PYSIDE: + from PySide.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap, + QBrush, QClipboard, QCloseEvent, QColor, + QConicalGradient, QContextMenuEvent, QCursor, + QDoubleValidator, QDrag, + QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, + QDropEvent, QFileOpenEvent, QFocusEvent, QFont, + QFontDatabase, QFontInfo, QFontMetrics, + QFontMetricsF, QGradient, QHelpEvent, + QHideEvent, QHoverEvent, QIcon, QIconDragEvent, + QIconEngine, QImage, QImageIOHandler, QImageReader, + QImageWriter, QInputEvent, QInputMethodEvent, + QKeyEvent, QKeySequence, QLinearGradient, + QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, + QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3, + QMatrix4x4, QMouseEvent, QMoveEvent, QMovie, + QPaintDevice, QPaintEngine, QPaintEngineState, + QPaintEvent, QPainter, QPainterPath, + QPainterPathStroker, QPalette, QPen, QPicture, + QPictureIO, QPixmap, QPixmapCache, QPolygon, + QPolygonF, QQuaternion, QRadialGradient, + QRegExpValidator, QRegion, QResizeEvent, + QSessionManager, QShortcutEvent, QShowEvent, + QStandardItem, QStandardItemModel, + QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, + QTextBlock, QTextBlockFormat, QTextBlockGroup, + QTextBlockUserData, QTextCharFormat, QTextCursor, + QTextDocument, QTextDocumentFragment, + QTextFormat, QTextFragment, + QTextFrame, QTextFrameFormat, QTextImageFormat, + QTextInlineObject, QTextItem, QTextLayout, + QTextLength, QTextLine, QTextList, QTextListFormat, + QTextObject, QTextObjectInterface, QTextOption, + QTextTable, QTextTableCell, QTextTableCellFormat, + QTextTableFormat, QTouchEvent, QTransform, + QValidator, QVector2D, QVector3D, QVector4D, + QWhatsThisClickedEvent, QWheelEvent, + QWindowStateChangeEvent, qAlpha, qBlue, + qGray, qGreen, qIsGray, qRed, qRgb, qRgba, + QIntValidator) + # QDesktopServices has has been split into (QDesktopServices and + # QStandardPaths) in Qt5 + # It only exposes QDesktopServices that are still in pyqt5 + from PySide.QtGui import QDesktopServices as _QDesktopServices + + class QDesktopServices(): + openUrl = _QDesktopServices.openUrl + setUrlHandler = _QDesktopServices.setUrlHandler + unsetUrlHandler = _QDesktopServices.unsetUrlHandler + + def __getattr__(self, name): + attr = getattr(_QDesktopServices, name) + + new_name = name + if name == 'storageLocation': + new_name = 'writableLocation' + warnings.warn(("Warning QDesktopServices.{} is deprecated in Qt5" + "we recommend you use QDesktopServices.{} instead").format(name, new_name), + DeprecationWarning) + return attr + QDesktopServices = QDesktopServices() +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/QtHelp.py b/build/lib/winpython/_vendor/qtpy/QtHelp.py new file mode 100644 index 00000000..ca9d93dd --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtHelp.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +"""QtHelp Wrapper.""" + +import warnings + +from . import PYQT5 +from . import PYQT4 +from . import PYSIDE +from . import PYSIDE2 + +if PYQT5: + from PyQt5.QtHelp import * +elif PYSIDE2: + from PySide2.QtHelp import * +elif PYQT4: + from PyQt4.QtHelp import * +elif PYSIDE: + from PySide.QtHelp import * diff --git a/build/lib/winpython/_vendor/qtpy/QtMultimedia.py b/build/lib/winpython/_vendor/qtpy/QtMultimedia.py new file mode 100644 index 00000000..9015ece9 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtMultimedia.py @@ -0,0 +1,17 @@ +import warnings + +from . import PYQT5 +from . import PYQT4 +from . import PYSIDE +from . import PYSIDE2 + +if PYQT5: + from PyQt5.QtMultimedia import * +elif PYSIDE2: + from PySide2.QtMultimedia import * +elif PYQT4: + from PyQt4.QtMultimedia import * + from PyQt4.QtGui import QSound +elif PYSIDE: + from PySide.QtMultimedia import * + from PySide.QtGui import QSound diff --git a/build/lib/winpython/_vendor/qtpy/QtNetwork.py b/build/lib/winpython/_vendor/qtpy/QtNetwork.py new file mode 100644 index 00000000..49faded7 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtNetwork.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014-2015 Colin Duquesnoy +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides QtNetwork classes and functions. +""" + +from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError + + +if PYQT5: + from PyQt5.QtNetwork import * +elif PYSIDE2: + from PySide2.QtNetwork import * +elif PYQT4: + from PyQt4.QtNetwork import * +elif PYSIDE: + from PySide.QtNetwork import * +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/QtOpenGL.py b/build/lib/winpython/_vendor/qtpy/QtOpenGL.py new file mode 100644 index 00000000..ef62171a --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtOpenGL.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# ----------------------------------------------------------------------------- +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) +# ----------------------------------------------------------------------------- +"""Provides QtOpenGL classes and functions.""" + +# Local imports +from . import PYQT4, PYQT5, PYSIDE, PythonQtError + +if PYQT5: + from PyQt5.QtOpenGL import * +elif PYQT4: + from PyQt4.QtOpenGL import * +elif PYSIDE: + from PySide.QtOpenGL import * +else: + raise PythonQtError('No Qt bindings could be found') + +del PYQT4, PYQT5, PYSIDE diff --git a/build/lib/winpython/_vendor/qtpy/QtPrintSupport.py b/build/lib/winpython/_vendor/qtpy/QtPrintSupport.py new file mode 100644 index 00000000..b821d411 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtPrintSupport.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides QtPrintSupport classes and functions. +""" + +from . import PYQT5, PYQT4,PYSIDE2, PYSIDE, PythonQtError + + +if PYQT5: + from PyQt5.QtPrintSupport import * +elif PYSIDE2: + from PySide2.QtPrintSupport import * +elif PYQT4: + from PyQt4.QtGui import (QAbstractPrintDialog, QPageSetupDialog, + QPrintDialog, QPrintEngine, QPrintPreviewDialog, + QPrintPreviewWidget, QPrinter, QPrinterInfo) +elif PYSIDE: + from PySide.QtGui import (QAbstractPrintDialog, QPageSetupDialog, + QPrintDialog, QPrintEngine, QPrintPreviewDialog, + QPrintPreviewWidget, QPrinter, QPrinterInfo) +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/QtSql.py b/build/lib/winpython/_vendor/qtpy/QtSql.py new file mode 100644 index 00000000..98520bef --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtSql.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# ----------------------------------------------------------------------------- +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) +# ----------------------------------------------------------------------------- +"""Provides QtSql classes and functions.""" + +# Local imports +from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError + +if PYQT5: + from PyQt5.QtSql import * +elif PYSIDE2: + from PySide2.QtSql import * +elif PYQT4: + from PyQt4.QtSql import * +elif PYSIDE: + from PySide.QtSql import * +else: + raise PythonQtError('No Qt bindings could be found') + +del PYQT4, PYQT5, PYSIDE, PYSIDE2 diff --git a/build/lib/winpython/_vendor/qtpy/QtSvg.py b/build/lib/winpython/_vendor/qtpy/QtSvg.py new file mode 100644 index 00000000..edc075ea --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtSvg.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# ----------------------------------------------------------------------------- +# Copyright © 2009- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) +# ----------------------------------------------------------------------------- +"""Provides QtSvg classes and functions.""" + +# Local imports +from . import PYQT4, PYSIDE2, PYQT5, PYSIDE, PythonQtError + +if PYQT5: + from PyQt5.QtSvg import * +elif PYSIDE2: + from PySide2.QtSvg import * +elif PYQT4: + from PyQt4.QtSvg import * +elif PYSIDE: + from PySide.QtSvg import * +else: + raise PythonQtError('No Qt bindings could be found') + +del PYQT4, PYQT5, PYSIDE, PYSIDE2 diff --git a/build/lib/winpython/_vendor/qtpy/QtTest.py b/build/lib/winpython/_vendor/qtpy/QtTest.py new file mode 100644 index 00000000..cca5e192 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtTest.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014-2015 Colin Duquesnoy +# Copyright © 2009- The Spyder Developmet Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides QtTest and functions +""" + +from . import PYQT5,PYSIDE2, PYQT4, PYSIDE, PythonQtError + + +if PYQT5: + from PyQt5.QtTest import QTest +elif PYSIDE2: + from PySide2.QtTest import QTest +elif PYQT4: + from PyQt4.QtTest import QTest as OldQTest + + class QTest(OldQTest): + @staticmethod + def qWaitForWindowActive(QWidget): + OldQTest.qWaitForWindowShown(QWidget) +elif PYSIDE: + from PySide.QtTest import QTest +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/QtWebEngineWidgets.py b/build/lib/winpython/_vendor/qtpy/QtWebEngineWidgets.py new file mode 100644 index 00000000..c5577a22 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtWebEngineWidgets.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014-2015 Colin Duquesnoy +# Copyright © 2009- The Spyder development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides QtWebEngineWidgets classes and functions. +""" + +from . import PYQT5,PYSIDE2, PYQT4, PYSIDE, PythonQtError + + +# To test if we are using WebEngine or WebKit +WEBENGINE = True + + +if PYQT5: + try: + from PyQt5.QtWebEngineWidgets import QWebEnginePage + from PyQt5.QtWebEngineWidgets import QWebEngineView + from PyQt5.QtWebEngineWidgets import QWebEngineSettings + except ImportError: + from PyQt5.QtWebKitWidgets import QWebPage as QWebEnginePage + from PyQt5.QtWebKitWidgets import QWebView as QWebEngineView + from PyQt5.QtWebKit import QWebSettings as QWebEngineSettings + WEBENGINE = False +elif PYSIDE2: + try: + from PySide2.QtWebEngineWidgets import QWebEnginePage + from PySide2.QtWebEngineWidgets import QWebEngineView + # Current PySide2 wheels seem to be missing this. + # from PySide2.QtWebEngineWidgets import QWebEngineSettings + except ImportError: + from PySide2.QtWebKitWidgets import QWebPage as QWebEnginePage + from PySide2.QtWebKitWidgets import QWebView as QWebEngineView + # Current PySide2 wheels seem to be missing this. + # from PySide2.QtWebKit import QWebSettings as QWebEngineSettings + WEBENGINE = False +elif PYQT4: + from PyQt4.QtWebKit import QWebPage as QWebEnginePage + from PyQt4.QtWebKit import QWebView as QWebEngineView + from PyQt4.QtWebKit import QWebSettings as QWebEngineSettings + WEBENGINE = False +elif PYSIDE: + from PySide.QtWebKit import QWebPage as QWebEnginePage + from PySide.QtWebKit import QWebView as QWebEngineView + from PySide.QtWebKit import QWebSettings as QWebEngineSettings + WEBENGINE = False +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/QtWidgets.py b/build/lib/winpython/_vendor/qtpy/QtWidgets.py new file mode 100644 index 00000000..739f9ce1 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/QtWidgets.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014-2015 Colin Duquesnoy +# Copyright © 2009- The Spyder Developmet Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +Provides widget classes and functions. +.. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtWidgets + are exposed here. Therefore, you need to treat/use this package as if it + were the ``PyQt5.QtWidgets`` module. +""" + +from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError +from ._patch.qcombobox import patch_qcombobox +from ._patch.qheaderview import introduce_renamed_methods_qheaderview + + +if PYQT5: + from PyQt5.QtWidgets import * +elif PYSIDE2: + from PySide2.QtWidgets import * +elif PYQT4: + from PyQt4.QtGui import * + QStyleOptionViewItem = QStyleOptionViewItemV4 + del QStyleOptionViewItemV4 + + # These objects belong to QtGui + try: + # Older versions of PyQt4 do not provide these + del (QGlyphRun, + QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, + QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, + QQuaternion, QRadialGradient, QRawFont, QRegExpValidator, + QStaticText, QTouchEvent, QVector2D, QVector3D, QVector4D, + qFuzzyCompare) + except NameError: + pass + del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, + QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, + QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent, + QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, + QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, + QFontMetricsF, QGradient, QHelpEvent, QHideEvent, + QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, + QImageIOHandler, QImageReader, QImageWriter, QInputEvent, + QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient, + QMouseEvent, QMoveEvent, QMovie, QPaintDevice, QPaintEngine, + QPaintEngineState, QPaintEvent, QPainter, QPainterPath, + QPainterPathStroker, QPalette, QPen, QPicture, QPictureIO, QPixmap, + QPixmapCache, QPolygon, QPolygonF, + QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, + QStandardItem, QStandardItemModel, QStatusTipEvent, + QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, + QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor, + QTextDocument, QTextDocumentFragment, QTextDocumentWriter, + QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, + QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, + QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, + QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, + QTextTableCellFormat, QTextTableFormat, QTransform, + QValidator, QWhatsThisClickedEvent, + QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, + qGray, qGreen, qIsGray, qRed, qRgb, qRgba, QIntValidator, + QStringListModel) + + # These objects belong to QtPrintSupport + del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, + QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) + + # These objects belong to QtCore + del (QItemSelection, QItemSelectionModel, QItemSelectionRange, + QSortFilterProxyModel) + + # Patch QComboBox to allow Python objects to be passed to userData + patch_qcombobox(QComboBox) + + # QHeaderView: renamed methods + introduce_renamed_methods_qheaderview(QHeaderView) + +elif PYSIDE: + from PySide.QtGui import * + QStyleOptionViewItem = QStyleOptionViewItemV4 + del QStyleOptionViewItemV4 + + # These objects belong to QtGui + del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, + QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, + QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent, + QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, + QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, + QFontMetricsF, QGradient, QHelpEvent, QHideEvent, + QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, + QImageIOHandler, QImageReader, QImageWriter, QInputEvent, + QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient, + QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, + QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QMouseEvent, + QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState, + QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette, + QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon, + QPolygonF, QQuaternion, QRadialGradient, QRegExpValidator, + QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, + QStandardItem, QStandardItemModel, QStatusTipEvent, + QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, + QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor, + QTextDocument, QTextDocumentFragment, + QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, + QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, + QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, + QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, + QTextTableCellFormat, QTextTableFormat, QTouchEvent, QTransform, + QValidator, QVector2D, QVector3D, QVector4D, QWhatsThisClickedEvent, + QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qGray, qGreen, + qIsGray, qRed, qRgb, qRgba, QIntValidator, QStringListModel) + + # These objects belong to QtPrintSupport + del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, + QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) + + # These objects belong to QtCore + del (QItemSelection, QItemSelectionModel, QItemSelectionRange, + QSortFilterProxyModel) + + # Patch QComboBox to allow Python objects to be passed to userData + patch_qcombobox(QComboBox) + + # QHeaderView: renamed methods + introduce_renamed_methods_qheaderview(QHeaderView) + +else: + raise PythonQtError('No Qt bindings could be found') diff --git a/build/lib/winpython/_vendor/qtpy/__init__.py b/build/lib/winpython/_vendor/qtpy/__init__.py new file mode 100644 index 00000000..54ad5486 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/__init__.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009- The Spyder Development Team +# Copyright © 2014-2015 Colin Duquesnoy +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) + +""" +**QtPy** is a shim over the various Python Qt bindings. It is used to write +Qt binding indenpendent libraries or applications. + +If one of the APIs has already been imported, then it will be used. + +Otherwise, the shim will automatically select the first available API (PyQt5, +PySide2, PyQt4 and finally PySide); in that case, you can force the use of one +specific bindings (e.g. if your application is using one specific bindings and +you need to use library that use QtPy) by setting up the ``QT_API`` environment +variable. + +PyQt5 +===== + +For PyQt5, you don't have to set anything as it will be used automatically:: + + >>> from qtpy import QtGui, QtWidgets, QtCore + >>> print(QtWidgets.QWidget) + + +PySide2 +====== + +Set the QT_API environment variable to 'pyside2' before importing other +packages:: + + >>> import os + >>> os.environ['QT_API'] = 'pyside2' + >>> from qtpy import QtGui, QtWidgets, QtCore + >>> print(QtWidgets.QWidget) + +PyQt4 +===== + +Set the ``QT_API`` environment variable to 'pyqt' before importing any python +package:: + + >>> import os + >>> os.environ['QT_API'] = 'pyqt' + >>> from qtpy import QtGui, QtWidgets, QtCore + >>> print(QtWidgets.QWidget) + +PySide +====== + +Set the QT_API environment variable to 'pyside' before importing other +packages:: + + >>> import os + >>> os.environ['QT_API'] = 'pyside' + >>> from qtpy import QtGui, QtWidgets, QtCore + >>> print(QtWidgets.QWidget) + +""" + +import os +import sys +import warnings + +# Version of QtPy +from ._version import __version__ + + +class PythonQtError(Exception): + """Error raise if no bindings could be selected""" + pass + + +class PythonQtWarning(Warning): + """Warning if some features are not implemented in a binding.""" + pass + + +# Qt API environment variable name +QT_API = 'QT_API' + +# Names of the expected PyQt5 api +PYQT5_API = ['pyqt5'] + +# Names of the expected PyQt4 api +PYQT4_API = [ + 'pyqt', # name used in IPython.qt + 'pyqt4' # pyqode.qt original name +] + +# Names of the expected PySide api +PYSIDE_API = ['pyside'] + +# Names of the expected PySide2 api +PYSIDE2_API = ['pyside2'] + +# Setting a default value for QT_API +os.environ.setdefault(QT_API, 'pyqt5') + +API = os.environ[QT_API].lower() +initial_api = API +assert API in (PYQT5_API + PYQT4_API + PYSIDE_API + PYSIDE2_API) + +is_old_pyqt = is_pyqt46 = False +PYQT5 = True +PYQT4 = PYSIDE = PYSIDE2 = False + + +if 'PyQt5' in sys.modules: + API = 'pyqt5' +elif 'PySide2' in sys.modules: + API = 'pyside2' +elif 'PyQt4' in sys.modules: + API = 'pyqt4' +elif 'PySide' in sys.modules: + API = 'pyside' + + +if API in PYQT5_API: + try: + from PyQt5.QtCore import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore + from PyQt5.QtCore import QT_VERSION_STR as QT_VERSION # analysis:ignore + PYSIDE_VERSION = None + except ImportError: + API = os.environ['QT_API'] = 'pyside2' + +if API in PYSIDE2_API: + try: + from PySide2 import __version__ as PYSIDE_VERSION # analysis:ignore + from PySide2.QtCore import __version__ as QT_VERSION # analysis:ignore + + PYQT_VERSION = None + PYQT5 = False + PYSIDE2 = True + except ImportError: + API = os.environ['QT_API'] = 'pyqt' + +if API in PYQT4_API: + try: + import sip + try: + sip.setapi('QString', 2) + sip.setapi('QVariant', 2) + sip.setapi('QDate', 2) + sip.setapi('QDateTime', 2) + sip.setapi('QTextStream', 2) + sip.setapi('QTime', 2) + sip.setapi('QUrl', 2) + except (AttributeError, ValueError): + # PyQt < v4.6 + pass + from PyQt4.Qt import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore + from PyQt4.Qt import QT_VERSION_STR as QT_VERSION # analysis:ignore + PYSIDE_VERSION = None + PYQT5 = False + PYQT4 = True + except ImportError: + API = os.environ['QT_API'] = 'pyside' + else: + is_old_pyqt = PYQT_VERSION.startswith(('4.4', '4.5', '4.6', '4.7')) + is_pyqt46 = PYQT_VERSION.startswith('4.6') + +if API in PYSIDE_API: + try: + from PySide import __version__ as PYSIDE_VERSION # analysis:ignore + from PySide.QtCore import __version__ as QT_VERSION # analysis:ignore + PYQT_VERSION = None + PYQT5 = PYSIDE2 = False + PYSIDE = True + except ImportError: + raise PythonQtError('No Qt bindings could be found') + +# If a correct API name is passed to QT_API and it could not be found, +# switches to another and informs through the warning +if API != initial_api: + warnings.warn('Selected binding "{}" could not be found, ' + 'using "{}"'.format(initial_api, API), RuntimeWarning) + +API_NAME = {'pyqt5': 'PyQt5', 'pyqt': 'PyQt4', 'pyqt4': 'PyQt4', + 'pyside': 'PySide', 'pyside2':'PySide2'}[API] + +if PYQT4: + import sip + try: + API_NAME += (" (API v{0})".format(sip.getapi('QString'))) + except AttributeError: + pass diff --git a/build/lib/winpython/_vendor/qtpy/_patch/__init__.py b/build/lib/winpython/_vendor/qtpy/_patch/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/build/lib/winpython/_vendor/qtpy/_patch/qcombobox.py b/build/lib/winpython/_vendor/qtpy/_patch/qcombobox.py new file mode 100644 index 00000000..d3e98bed --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/_patch/qcombobox.py @@ -0,0 +1,101 @@ +# The code below, as well as the associated test were adapted from +# qt-helpers, which was released under a 3-Clause BSD license: +# +# Copyright (c) 2015, Chris Beaumont and Thomas Robitaille +# +# 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 the name of the Glue project nor the names of its +# 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 COPYRIGHT HOLDER 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. + + +def patch_qcombobox(QComboBox): + """ + In PySide, using Python objects as userData in QComboBox causes + Segmentation faults under certain conditions. Even in cases where it + doesn't, findData does not work correctly. Likewise, findData also does not + work correctly with Python objects when using PyQt4. On the other hand, + PyQt5 deals with this case correctly. We therefore patch QComboBox when + using PyQt4 and PySide to avoid issues. + """ + + from ..QtGui import QIcon + from ..QtCore import Qt, QObject + + class userDataWrapper(): + """ + This class is used to wrap any userData object. If we don't do this, + then certain types of objects can cause segmentation faults or issues + depending on whether/how __getitem__ is defined. + """ + def __init__(self, data): + self.data = data + + _addItem = QComboBox.addItem + + def addItem(self, *args, **kwargs): + if len(args) == 3 or (not isinstance(args[0], QIcon) + and len(args) == 2): + args, kwargs['userData'] = args[:-1], args[-1] + if 'userData' in kwargs: + kwargs['userData'] = userDataWrapper(kwargs['userData']) + _addItem(self, *args, **kwargs) + + _insertItem = QComboBox.insertItem + + def insertItem(self, *args, **kwargs): + if len(args) == 4 or (not isinstance(args[1], QIcon) + and len(args) == 3): + args, kwargs['userData'] = args[:-1], args[-1] + if 'userData' in kwargs: + kwargs['userData'] = userDataWrapper(kwargs['userData']) + _insertItem(self, *args, **kwargs) + + _setItemData = QComboBox.setItemData + + def setItemData(self, index, value, role=Qt.UserRole): + value = userDataWrapper(value) + _setItemData(self, index, value, role=role) + + _itemData = QComboBox.itemData + + def itemData(self, index, role=Qt.UserRole): + userData = _itemData(self, index, role=role) + if isinstance(userData, userDataWrapper): + userData = userData.data + return userData + + def findData(self, value): + for i in range(self.count()): + if self.itemData(i) == value: + return i + return -1 + + QComboBox.addItem = addItem + QComboBox.insertItem = insertItem + QComboBox.setItemData = setItemData + QComboBox.itemData = itemData + QComboBox.findData = findData \ No newline at end of file diff --git a/build/lib/winpython/_vendor/qtpy/_patch/qheaderview.py b/build/lib/winpython/_vendor/qtpy/_patch/qheaderview.py new file mode 100644 index 00000000..b6baddbb --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/_patch/qheaderview.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# +# Copyright © The Spyder Development Team +# +# Licensed under the terms of the MIT License +# (see LICENSE.txt for details) +import warnings + +def introduce_renamed_methods_qheaderview(QHeaderView): + + _isClickable = QHeaderView.isClickable + def sectionsClickable(self): + """ + QHeaderView.sectionsClickable() -> bool + """ + return _isClickable(self) + QHeaderView.sectionsClickable = sectionsClickable + def isClickable(self): + warnings.warn('isClickable is only available in Qt4. Use ' + 'sectionsClickable instead.', stacklevel=2) + return _isClickable(self) + QHeaderView.isClickable = isClickable + + + _isMovable = QHeaderView.isMovable + def sectionsMovable(self): + """ + QHeaderView.sectionsMovable() -> bool + """ + return _isMovable(self) + QHeaderView.sectionsMovable = sectionsMovable + def isMovable(self): + warnings.warn('isMovable is only available in Qt4. Use ' + 'sectionsMovable instead.', stacklevel=2) + return _isMovable(self) + QHeaderView.isMovable = isMovable + + + _resizeMode = QHeaderView.resizeMode + def sectionResizeMode(self, logicalIndex): + """ + QHeaderView.sectionResizeMode(int) -> QHeaderView.ResizeMode + """ + return _resizeMode(self, logicalIndex) + QHeaderView.sectionResizeMode = sectionResizeMode + def resizeMode(self, logicalIndex): + warnings.warn('resizeMode is only available in Qt4. Use ' + 'sectionResizeMode instead.', stacklevel=2) + return _resizeMode(self, logicalIndex) + QHeaderView.resizeMode = resizeMode + + _setClickable = QHeaderView.setClickable + def setSectionsClickable(self, clickable): + """ + QHeaderView.setSectionsClickable(bool) + """ + return _setClickable(self, clickable) + QHeaderView.setSectionsClickable = setSectionsClickable + def setClickable(self, clickable): + warnings.warn('setClickable is only available in Qt4. Use ' + 'setSectionsClickable instead.', stacklevel=2) + return _setClickable(self, clickable) + QHeaderView.setClickable = setClickable + + + _setMovable = QHeaderView.setMovable + def setSectionsMovable(self, movable): + """ + QHeaderView.setSectionsMovable(bool) + """ + return _setMovable(self, movable) + QHeaderView.setSectionsMovable = setSectionsMovable + def setMovable(self, movable): + warnings.warn('setMovable is only available in Qt4. Use ' + 'setSectionsMovable instead.', stacklevel=2) + return _setMovable(self, movable) + QHeaderView.setMovable = setMovable + + + _setResizeMode = QHeaderView.setResizeMode + def setSectionResizeMode(self, *args): + """ + QHeaderView.setSectionResizeMode(QHeaderView.ResizeMode) + QHeaderView.setSectionResizeMode(int, QHeaderView.ResizeMode) + """ + _setResizeMode(self, *args) + QHeaderView.setSectionResizeMode = setSectionResizeMode + def setResizeMode(self, *args): + warnings.warn('setResizeMode is only available in Qt4. Use ' + 'setSectionResizeMode instead.', stacklevel=2) + _setResizeMode(self, *args) + QHeaderView.setResizeMode = setResizeMode + + + + diff --git a/build/lib/winpython/_vendor/qtpy/_version.py b/build/lib/winpython/_vendor/qtpy/_version.py new file mode 100644 index 00000000..3e2a74ac --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/_version.py @@ -0,0 +1,2 @@ +version_info = (1, 4, 2) +__version__ = '.'.join(map(str, version_info)) diff --git a/build/lib/winpython/_vendor/qtpy/compat.py b/build/lib/winpython/_vendor/qtpy/compat.py new file mode 100644 index 00000000..f5794548 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/compat.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009- The Spyder Development Team +# Licensed under the terms of the MIT License + +""" +Compatibility functions +""" + +from __future__ import print_function +import sys +import collections + +from . import PYQT4 +from .QtWidgets import QFileDialog +from .py3compat import is_text_string, to_text_string, TEXT_TYPES + + +# ============================================================================= +# QVariant conversion utilities +# ============================================================================= +PYQT_API_1 = False +if PYQT4: + import sip + try: + PYQT_API_1 = sip.getapi('QVariant') == 1 # PyQt API #1 + except AttributeError: + # PyQt =v4.4 (API #1 and #2) and PySide >=v1.0""" + # Calling QFileDialog static method + if sys.platform == "win32": + # On Windows platforms: redirect standard outputs + _temp1, _temp2 = sys.stdout, sys.stderr + sys.stdout, sys.stderr = None, None + try: + result = QFileDialog.getExistingDirectory(parent, caption, basedir, + options) + finally: + if sys.platform == "win32": + # On Windows platforms: restore standard outputs + sys.stdout, sys.stderr = _temp1, _temp2 + if not is_text_string(result): + # PyQt API #1 + result = to_text_string(result) + return result + + +def _qfiledialog_wrapper(attr, parent=None, caption='', basedir='', + filters='', selectedfilter='', options=None): + if options is None: + options = QFileDialog.Options(0) + try: + # PyQt =v4.6 + QString = None # analysis:ignore + tuple_returned = True + try: + # PyQt >=v4.6 + func = getattr(QFileDialog, attr+'AndFilter') + except AttributeError: + # PySide or PyQt =v4.6 + output, selectedfilter = result + else: + # PyQt =v4.4 (API #1 and #2) and PySide >=v1.0""" + return _qfiledialog_wrapper('getOpenFileName', parent=parent, + caption=caption, basedir=basedir, + filters=filters, selectedfilter=selectedfilter, + options=options) + + +def getopenfilenames(parent=None, caption='', basedir='', filters='', + selectedfilter='', options=None): + """Wrapper around QtGui.QFileDialog.getOpenFileNames static method + Returns a tuple (filenames, selectedfilter) -- when dialog box is canceled, + returns a tuple (empty list, empty string) + Compatible with PyQt >=v4.4 (API #1 and #2) and PySide >=v1.0""" + return _qfiledialog_wrapper('getOpenFileNames', parent=parent, + caption=caption, basedir=basedir, + filters=filters, selectedfilter=selectedfilter, + options=options) + + +def getsavefilename(parent=None, caption='', basedir='', filters='', + selectedfilter='', options=None): + """Wrapper around QtGui.QFileDialog.getSaveFileName static method + Returns a tuple (filename, selectedfilter) -- when dialog box is canceled, + returns a tuple of empty strings + Compatible with PyQt >=v4.4 (API #1 and #2) and PySide >=v1.0""" + return _qfiledialog_wrapper('getSaveFileName', parent=parent, + caption=caption, basedir=basedir, + filters=filters, selectedfilter=selectedfilter, + options=options) diff --git a/build/lib/winpython/_vendor/qtpy/py3compat.py b/build/lib/winpython/_vendor/qtpy/py3compat.py new file mode 100644 index 00000000..f6d0d4b7 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/py3compat.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012-2013 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see spyderlib/__init__.py for details) + +""" +spyderlib.py3compat +------------------- + +Transitional module providing compatibility functions intended to help +migrating from Python 2 to Python 3. + +This module should be fully compatible with: + * Python >=v2.6 + * Python 3 +""" + +from __future__ import print_function + +import sys +import os + +PY2 = sys.version[0] == '2' +PY3 = sys.version[0] == '3' + + +# ============================================================================= +# Data types +# ============================================================================= +if PY2: + # Python 2 + TEXT_TYPES = (str, unicode) + INT_TYPES = (int, long) +else: + # Python 3 + TEXT_TYPES = (str,) + INT_TYPES = (int,) +NUMERIC_TYPES = tuple(list(INT_TYPES) + [float, complex]) + + +# ============================================================================= +# Renamed/Reorganized modules +# ============================================================================= +if PY2: + # Python 2 + import __builtin__ as builtins + import ConfigParser as configparser + try: + import _winreg as winreg + except ImportError: + pass + from sys import maxint as maxsize + try: + import CStringIO as io + except ImportError: + import StringIO as io + try: + import cPickle as pickle + except ImportError: + import pickle + from UserDict import DictMixin as MutableMapping + import thread as _thread + import repr as reprlib +else: + # Python 3 + import builtins + import configparser + try: + import winreg + except ImportError: + pass + from sys import maxsize + import io + import pickle + from collections import MutableMapping + import _thread + import reprlib + + +# ============================================================================= +# Strings +# ============================================================================= +if PY2: + # Python 2 + import codecs + + def u(obj): + """Make unicode object""" + return codecs.unicode_escape_decode(obj)[0] +else: + # Python 3 + def u(obj): + """Return string as it is""" + return obj + + +def is_text_string(obj): + """Return True if `obj` is a text string, False if it is anything else, + like binary data (Python 3) or QString (Python 2, PyQt API #1)""" + if PY2: + # Python 2 + return isinstance(obj, basestring) + else: + # Python 3 + return isinstance(obj, str) + + +def is_binary_string(obj): + """Return True if `obj` is a binary string, False if it is anything else""" + if PY2: + # Python 2 + return isinstance(obj, str) + else: + # Python 3 + return isinstance(obj, bytes) + + +def is_string(obj): + """Return True if `obj` is a text or binary Python string object, + False if it is anything else, like a QString (Python 2, PyQt API #1)""" + return is_text_string(obj) or is_binary_string(obj) + + +def is_unicode(obj): + """Return True if `obj` is unicode""" + if PY2: + # Python 2 + return isinstance(obj, unicode) + else: + # Python 3 + return isinstance(obj, str) + + +def to_text_string(obj, encoding=None): + """Convert `obj` to (unicode) text string""" + if PY2: + # Python 2 + if encoding is None: + return unicode(obj) + else: + return unicode(obj, encoding) + else: + # Python 3 + if encoding is None: + return str(obj) + elif isinstance(obj, str): + # In case this function is not used properly, this could happen + return obj + else: + return str(obj, encoding) + + +def to_binary_string(obj, encoding=None): + """Convert `obj` to binary string (bytes in Python 3, str in Python 2)""" + if PY2: + # Python 2 + if encoding is None: + return str(obj) + else: + return obj.encode(encoding) + else: + # Python 3 + return bytes(obj, 'utf-8' if encoding is None else encoding) + + +# ============================================================================= +# Function attributes +# ============================================================================= +def get_func_code(func): + """Return function code object""" + if PY2: + # Python 2 + return func.func_code + else: + # Python 3 + return func.__code__ + + +def get_func_name(func): + """Return function name""" + if PY2: + # Python 2 + return func.func_name + else: + # Python 3 + return func.__name__ + + +def get_func_defaults(func): + """Return function default argument values""" + if PY2: + # Python 2 + return func.func_defaults + else: + # Python 3 + return func.__defaults__ + + +# ============================================================================= +# Special method attributes +# ============================================================================= +def get_meth_func(obj): + """Return method function object""" + if PY2: + # Python 2 + return obj.im_func + else: + # Python 3 + return obj.__func__ + + +def get_meth_class_inst(obj): + """Return method class instance""" + if PY2: + # Python 2 + return obj.im_self + else: + # Python 3 + return obj.__self__ + + +def get_meth_class(obj): + """Return method class""" + if PY2: + # Python 2 + return obj.im_class + else: + # Python 3 + return obj.__self__.__class__ + + +# ============================================================================= +# Misc. +# ============================================================================= +if PY2: + # Python 2 + input = raw_input + getcwd = os.getcwdu + cmp = cmp + import string + str_lower = string.lower + from itertools import izip_longest as zip_longest +else: + # Python 3 + input = input + getcwd = os.getcwd + + def cmp(a, b): + return (a > b) - (a < b) + str_lower = str.lower + from itertools import zip_longest + + +def qbytearray_to_str(qba): + """Convert QByteArray object to str in a way compatible with Python 2/3""" + return str(bytes(qba.toHex().data()).decode()) + + +if __name__ == '__main__': + pass diff --git a/build/lib/winpython/_vendor/qtpy/tests/__init__.py b/build/lib/winpython/_vendor/qtpy/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/build/lib/winpython/_vendor/qtpy/tests/conftest.py b/build/lib/winpython/_vendor/qtpy/tests/conftest.py new file mode 100644 index 00000000..c631886f --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/conftest.py @@ -0,0 +1,71 @@ +import os + + +def pytest_configure(config): + """ + This function gets run by py.test at the very start + """ + + if 'USE_QT_API' in os.environ: + os.environ['QT_API'] = os.environ['USE_QT_API'].lower() + + # We need to import qtpy here to make sure that the API versions get set + # straight away. + import qtpy + + +def pytest_report_header(config): + """ + This function is used by py.test to insert a customized header into the + test report. + """ + + versions = os.linesep + versions += 'PyQt4: ' + + try: + from PyQt4 import Qt + versions += "PyQt: {0} - Qt: {1}".format(Qt.PYQT_VERSION_STR, Qt.QT_VERSION_STR) + except ImportError: + versions += 'not installed' + except AttributeError: + versions += 'unknown version' + + versions += os.linesep + versions += 'PyQt5: ' + + try: + from PyQt5 import Qt + versions += "PyQt: {0} - Qt: {1}".format(Qt.PYQT_VERSION_STR, Qt.QT_VERSION_STR) + except ImportError: + versions += 'not installed' + except AttributeError: + versions += 'unknown version' + + versions += os.linesep + versions += 'PySide: ' + + try: + import PySide + from PySide import QtCore + versions += "PySide: {0} - Qt: {1}".format(PySide.__version__, QtCore.__version__) + except ImportError: + versions += 'not installed' + except AttributeError: + versions += 'unknown version' + + versions += os.linesep + versions += 'PySide2: ' + + try: + import PySide2 + from PySide2 import QtCore + versions += "PySide: {0} - Qt: {1}".format(PySide2.__version__, QtCore.__version__) + except ImportError: + versions += 'not installed' + except AttributeError: + versions += 'unknown version' + + versions += os.linesep + + return versions diff --git a/build/lib/winpython/_vendor/qtpy/tests/runtests.py b/build/lib/winpython/_vendor/qtpy/tests/runtests.py new file mode 100644 index 00000000..b54fbb45 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/runtests.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# ---------------------------------------------------------------------------- +# Copyright © 2015- The Spyder Development Team +# +# Licensed under the terms of the MIT License +# ---------------------------------------------------------------------------- + +"""File for running tests programmatically.""" + +# Standard library imports +import sys + +# Third party imports +import qtpy # to ensure that Qt4 uses API v2 +import pytest + + +def main(): + """Run pytest tests.""" + errno = pytest.main(['-x', 'qtpy', '-v', '-rw', '--durations=10', + '--cov=qtpy', '--cov-report=term-missing']) + sys.exit(errno) + +if __name__ == '__main__': + main() diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_main.py b/build/lib/winpython/_vendor/qtpy/tests/test_main.py new file mode 100644 index 00000000..2449249c --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_main.py @@ -0,0 +1,82 @@ +import os + +from qtpy import QtCore, QtGui, QtWidgets, QtWebEngineWidgets + + +def assert_pyside(): + """ + Make sure that we are using PySide + """ + import PySide + assert QtCore.QEvent is PySide.QtCore.QEvent + assert QtGui.QPainter is PySide.QtGui.QPainter + assert QtWidgets.QWidget is PySide.QtGui.QWidget + assert QtWebEngineWidgets.QWebEnginePage is PySide.QtWebKit.QWebPage + +def assert_pyside2(): + """ + Make sure that we are using PySide + """ + import PySide2 + assert QtCore.QEvent is PySide2.QtCore.QEvent + assert QtGui.QPainter is PySide2.QtGui.QPainter + assert QtWidgets.QWidget is PySide2.QtWidgets.QWidget + assert QtWebEngineWidgets.QWebEnginePage is PySide2.QtWebEngineWidgets.QWebEnginePage + +def assert_pyqt4(): + """ + Make sure that we are using PyQt4 + """ + import PyQt4 + assert QtCore.QEvent is PyQt4.QtCore.QEvent + assert QtGui.QPainter is PyQt4.QtGui.QPainter + assert QtWidgets.QWidget is PyQt4.QtGui.QWidget + assert QtWebEngineWidgets.QWebEnginePage is PyQt4.QtWebKit.QWebPage + + +def assert_pyqt5(): + """ + Make sure that we are using PyQt5 + """ + import PyQt5 + assert QtCore.QEvent is PyQt5.QtCore.QEvent + assert QtGui.QPainter is PyQt5.QtGui.QPainter + assert QtWidgets.QWidget is PyQt5.QtWidgets.QWidget + if QtWebEngineWidgets.WEBENGINE: + assert QtWebEngineWidgets.QWebEnginePage is PyQt5.QtWebEngineWidgets.QWebEnginePage + else: + assert QtWebEngineWidgets.QWebEnginePage is PyQt5.QtWebKitWidgets.QWebPage + + +def test_qt_api(): + """ + If QT_API is specified, we check that the correct Qt wrapper was used + """ + + QT_API = os.environ.get('QT_API', '').lower() + + if QT_API == 'pyside': + assert_pyside() + elif QT_API in ('pyqt', 'pyqt4'): + assert_pyqt4() + elif QT_API == 'pyqt5': + assert_pyqt5() + elif QT_API == 'pyside2': + assert_pyside2() + else: + # If the tests are run locally, USE_QT_API and QT_API may not be + # defined, but we still want to make sure qtpy is behaving sensibly. + # We should then be loading, in order of decreasing preference, PyQt5, + # PyQt4, and PySide. + try: + import PyQt5 + except ImportError: + try: + import PyQt4 + except ImportError: + import PySide + assert_pyside() + else: + assert_pyqt4() + else: + assert_pyqt5() diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_patch_qcombobox.py b/build/lib/winpython/_vendor/qtpy/tests/test_patch_qcombobox.py new file mode 100644 index 00000000..2e5e6fe3 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_patch_qcombobox.py @@ -0,0 +1,102 @@ +from __future__ import absolute_import + +import sys + +import pytest +from qtpy import PYSIDE2, QtGui, QtWidgets + + +PY3 = sys.version[0] == "3" + + +def get_qapp(icon_path=None): + qapp = QtWidgets.QApplication.instance() + if qapp is None: + qapp = QtWidgets.QApplication(['']) + return qapp + + +class Data(object): + """ + Test class to store in userData. The __getitem__ is needed in order to + reproduce the segmentation fault. + """ + def __getitem__(self, item): + raise ValueError("Failing") + + +@pytest.mark.skipif(PY3 or PYSIDE2, reason="It segfaults in Python 3 and PYSIDE2") +def test_patched_qcombobox(): + """ + In PySide, using Python objects as userData in QComboBox causes + Segmentation faults under certain conditions. Even in cases where it + doesn't, findData does not work correctly. Likewise, findData also + does not work correctly with Python objects when using PyQt4. On the + other hand, PyQt5 deals with this case correctly. We therefore patch + QComboBox when using PyQt4 and PySide to avoid issues. + """ + + app = get_qapp() + + data1 = Data() + data2 = Data() + data3 = Data() + data4 = Data() + data5 = Data() + data6 = Data() + + icon1 = QtGui.QIcon() + icon2 = QtGui.QIcon() + + widget = QtWidgets.QComboBox() + widget.addItem('a', data1) + widget.insertItem(0, 'b', data2) + widget.addItem('c', data1) + widget.setItemData(2, data3) + widget.addItem(icon1, 'd', data4) + widget.insertItem(3, icon2, 'e', data5) + widget.addItem(icon1, 'f') + widget.insertItem(5, icon2, 'g') + + widget.show() + + assert widget.findData(data1) == 1 + assert widget.findData(data2) == 0 + assert widget.findData(data3) == 2 + assert widget.findData(data4) == 4 + assert widget.findData(data5) == 3 + assert widget.findData(data6) == -1 + + assert widget.itemData(0) == data2 + assert widget.itemData(1) == data1 + assert widget.itemData(2) == data3 + assert widget.itemData(3) == data5 + assert widget.itemData(4) == data4 + assert widget.itemData(5) is None + assert widget.itemData(6) is None + + assert widget.itemText(0) == 'b' + assert widget.itemText(1) == 'a' + assert widget.itemText(2) == 'c' + assert widget.itemText(3) == 'e' + assert widget.itemText(4) == 'd' + assert widget.itemText(5) == 'g' + assert widget.itemText(6) == 'f' + + +def test_model_item(): + """ + This is a regression test for an issue that caused the call to item(0) + below to trigger segmentation faults in PySide. The issue is + non-deterministic when running the call once, so we include a loop to make + sure that we trigger the fault. + """ + app = get_qapp() + combo = QtWidgets.QComboBox() + label_data = [('a', None)] + for iter in range(10000): + combo.clear() + for i, (label, data) in enumerate(label_data): + combo.addItem(label, userData=data) + model = combo.model() + model.item(0) diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_patch_qheaderview.py b/build/lib/winpython/_vendor/qtpy/tests/test_patch_qheaderview.py new file mode 100644 index 00000000..17037f34 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_patch_qheaderview.py @@ -0,0 +1,98 @@ +from __future__ import absolute_import + +import sys + +import pytest +from qtpy import PYSIDE, PYSIDE2, PYQT4 +from qtpy.QtWidgets import QApplication +from qtpy.QtWidgets import QHeaderView +from qtpy.QtCore import Qt +from qtpy.QtCore import QAbstractListModel + + +PY3 = sys.version[0] == "3" + + +def get_qapp(icon_path=None): + qapp = QApplication.instance() + if qapp is None: + qapp = QApplication(['']) + return qapp + + +@pytest.mark.skipif(PY3 or PYSIDE2, reason="It fails on Python 3 and PySide2") +def test_patched_qheaderview(): + """ + This will test whether QHeaderView has the new methods introduced in Qt5. + It will then create an instance of QHeaderView and test that no exceptions + are raised and that some basic behaviour works. + """ + assert QHeaderView.sectionsClickable is not None + assert QHeaderView.sectionsMovable is not None + assert QHeaderView.sectionResizeMode is not None + assert QHeaderView.setSectionsClickable is not None + assert QHeaderView.setSectionsMovable is not None + assert QHeaderView.setSectionResizeMode is not None + + # setup a model and add it to a headerview + qapp = get_qapp() + headerview = QHeaderView(Qt.Horizontal) + class Model(QAbstractListModel): + pass + model = Model() + headerview.setModel(model) + assert headerview.count() == 1 + + # test it + assert isinstance(headerview.sectionsClickable(), bool) + assert isinstance(headerview.sectionsMovable(), bool) + if PYSIDE: + assert isinstance(headerview.sectionResizeMode(0), + QHeaderView.ResizeMode) + else: + assert isinstance(headerview.sectionResizeMode(0), int) + + headerview.setSectionsClickable(True) + assert headerview.sectionsClickable() == True + headerview.setSectionsClickable(False) + assert headerview.sectionsClickable() == False + + headerview.setSectionsMovable(True) + assert headerview.sectionsMovable() == True + headerview.setSectionsMovable(False) + assert headerview.sectionsMovable() == False + + headerview.setSectionResizeMode(QHeaderView.Interactive) + assert headerview.sectionResizeMode(0) == QHeaderView.Interactive + headerview.setSectionResizeMode(QHeaderView.Fixed) + assert headerview.sectionResizeMode(0) == QHeaderView.Fixed + headerview.setSectionResizeMode(QHeaderView.Stretch) + assert headerview.sectionResizeMode(0) == QHeaderView.Stretch + headerview.setSectionResizeMode(QHeaderView.ResizeToContents) + assert headerview.sectionResizeMode(0) == QHeaderView.ResizeToContents + + headerview.setSectionResizeMode(0, QHeaderView.Interactive) + assert headerview.sectionResizeMode(0) == QHeaderView.Interactive + headerview.setSectionResizeMode(0, QHeaderView.Fixed) + assert headerview.sectionResizeMode(0) == QHeaderView.Fixed + headerview.setSectionResizeMode(0, QHeaderView.Stretch) + assert headerview.sectionResizeMode(0) == QHeaderView.Stretch + headerview.setSectionResizeMode(0, QHeaderView.ResizeToContents) + assert headerview.sectionResizeMode(0) == QHeaderView.ResizeToContents + + # test that the old methods in Qt4 raise exceptions + if PYQT4 or PYSIDE: + with pytest.warns(UserWarning): + headerview.isClickable() + with pytest.warns(UserWarning): + headerview.isMovable() + with pytest.warns(UserWarning): + headerview.resizeMode(0) + with pytest.warns(UserWarning): + headerview.setClickable(True) + with pytest.warns(UserWarning): + headerview.setMovable(True) + with pytest.warns(UserWarning): + headerview.setResizeMode(0, QHeaderView.Interactive) + + diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qdesktopservice_split.py b/build/lib/winpython/_vendor/qtpy/tests/test_qdesktopservice_split.py new file mode 100644 index 00000000..472f2df1 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qdesktopservice_split.py @@ -0,0 +1,41 @@ +"""Test QDesktopServices split in Qt5.""" + +from __future__ import absolute_import + +import pytest +import warnings +from qtpy import PYQT4, PYSIDE + + +def test_qstandarpath(): + """Test the qtpy.QStandardPaths namespace""" + from qtpy.QtCore import QStandardPaths + + assert QStandardPaths.StandardLocation is not None + + # Attributes from QDesktopServices shouldn't be in QStandardPaths + with pytest.raises(AttributeError) as excinfo: + QStandardPaths.setUrlHandler + + +def test_qdesktopservice(): + """Test the qtpy.QDesktopServices namespace""" + from qtpy.QtGui import QDesktopServices + + assert QDesktopServices.setUrlHandler is not None + + +@pytest.mark.skipif(not (PYQT4 or PYSIDE), reason="Warning is only raised in old bindings") +def test_qdesktopservice_qt4_pyside(): + from qtpy.QtGui import QDesktopServices + # Attributes from QStandardPaths should raise a warning when imported + # from QDesktopServices + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + # Try to import QtHelp. + QDesktopServices.StandardLocation + + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) + assert "deprecated" in str(w[-1].message) diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qtcore.py b/build/lib/winpython/_vendor/qtpy/tests/test_qtcore.py new file mode 100644 index 00000000..8dc8f74a --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qtcore.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import + +import pytest +from qtpy import QtCore + +"""Test QtCore.""" + +def test_qtmsghandler(): + """Test the qtpy.QtMsgHandler""" + assert QtCore.qInstallMessageHandler is not None diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qtdesigner.py b/build/lib/winpython/_vendor/qtpy/tests/test_qtdesigner.py new file mode 100644 index 00000000..0327c6f7 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qtdesigner.py @@ -0,0 +1,28 @@ +from __future__ import absolute_import + +import pytest +from qtpy import PYSIDE2, PYSIDE + +@pytest.mark.skipif(PYSIDE2 or PYSIDE, reason="QtDesigner is not avalaible in PySide/PySide2") +def test_qtdesigner(): + from qtpy import QtDesigner + """Test the qtpy.QtDesigner namespace""" + assert QtDesigner.QAbstractExtensionFactory is not None + assert QtDesigner.QAbstractExtensionManager is not None + assert QtDesigner.QDesignerActionEditorInterface is not None + assert QtDesigner.QDesignerContainerExtension is not None + assert QtDesigner.QDesignerCustomWidgetCollectionInterface is not None + assert QtDesigner.QDesignerCustomWidgetInterface is not None + assert QtDesigner.QDesignerFormEditorInterface is not None + assert QtDesigner.QDesignerFormWindowCursorInterface is not None + assert QtDesigner.QDesignerFormWindowInterface is not None + assert QtDesigner.QDesignerFormWindowManagerInterface is not None + assert QtDesigner.QDesignerMemberSheetExtension is not None + assert QtDesigner.QDesignerObjectInspectorInterface is not None + assert QtDesigner.QDesignerPropertyEditorInterface is not None + assert QtDesigner.QDesignerPropertySheetExtension is not None + assert QtDesigner.QDesignerTaskMenuExtension is not None + assert QtDesigner.QDesignerWidgetBoxInterface is not None + assert QtDesigner.QExtensionFactory is not None + assert QtDesigner.QExtensionManager is not None + assert QtDesigner.QFormBuilder is not None \ No newline at end of file diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qthelp.py b/build/lib/winpython/_vendor/qtpy/tests/test_qthelp.py new file mode 100644 index 00000000..2b70ca75 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qthelp.py @@ -0,0 +1,22 @@ +"""Test for QtHelp namespace.""" + +from __future__ import absolute_import + +import pytest + + +def test_qthelp(): + """Test the qtpy.QtHelp namespace.""" + from qtpy import QtHelp + + assert QtHelp.QHelpContentItem is not None + assert QtHelp.QHelpContentModel is not None + assert QtHelp.QHelpContentWidget is not None + assert QtHelp.QHelpEngine is not None + assert QtHelp.QHelpEngineCore is not None + assert QtHelp.QHelpIndexModel is not None + assert QtHelp.QHelpIndexWidget is not None + assert QtHelp.QHelpSearchEngine is not None + assert QtHelp.QHelpSearchQuery is not None + assert QtHelp.QHelpSearchQueryWidget is not None + assert QtHelp.QHelpSearchResultWidget is not None diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qtmultimedia.py b/build/lib/winpython/_vendor/qtpy/tests/test_qtmultimedia.py new file mode 100644 index 00000000..02b415ff --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qtmultimedia.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import + +import pytest + + +def test_qtmultimedia(): + """Test the qtpy.QtMultimedia namespace""" + from qtpy import QtMultimedia + + assert QtMultimedia.QAbstractVideoBuffer is not None + assert QtMultimedia.QAudio is not None + assert QtMultimedia.QAudioDeviceInfo is not None + assert QtMultimedia.QAudioInput is not None + assert QtMultimedia.QSound is not None diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qtnetwork.py b/build/lib/winpython/_vendor/qtpy/tests/test_qtnetwork.py new file mode 100644 index 00000000..8f4b71f4 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qtnetwork.py @@ -0,0 +1,42 @@ +from __future__ import absolute_import + +import pytest +from qtpy import PYSIDE, PYSIDE2, QtNetwork + + +@pytest.mark.skipif(PYSIDE2 or PYSIDE, reason="It fails on PySide/PySide2") +def test_qtnetwork(): + """Test the qtpy.QtNetwork namespace""" + assert QtNetwork.QAbstractNetworkCache is not None + assert QtNetwork.QNetworkCacheMetaData is not None + assert QtNetwork.QHttpMultiPart is not None + assert QtNetwork.QHttpPart is not None + assert QtNetwork.QNetworkAccessManager is not None + assert QtNetwork.QNetworkCookie is not None + assert QtNetwork.QNetworkCookieJar is not None + assert QtNetwork.QNetworkDiskCache is not None + assert QtNetwork.QNetworkReply is not None + assert QtNetwork.QNetworkRequest is not None + assert QtNetwork.QNetworkConfigurationManager is not None + assert QtNetwork.QNetworkConfiguration is not None + assert QtNetwork.QNetworkSession is not None + assert QtNetwork.QAuthenticator is not None + assert QtNetwork.QHostAddress is not None + assert QtNetwork.QHostInfo is not None + assert QtNetwork.QNetworkAddressEntry is not None + assert QtNetwork.QNetworkInterface is not None + assert QtNetwork.QNetworkProxy is not None + assert QtNetwork.QNetworkProxyFactory is not None + assert QtNetwork.QNetworkProxyQuery is not None + assert QtNetwork.QAbstractSocket is not None + assert QtNetwork.QLocalServer is not None + assert QtNetwork.QLocalSocket is not None + assert QtNetwork.QTcpServer is not None + assert QtNetwork.QTcpSocket is not None + assert QtNetwork.QUdpSocket is not None + assert QtNetwork.QSslCertificate is not None + assert QtNetwork.QSslCipher is not None + assert QtNetwork.QSslConfiguration is not None + assert QtNetwork.QSslError is not None + assert QtNetwork.QSslKey is not None + assert QtNetwork.QSslSocket is not None diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qtprintsupport.py b/build/lib/winpython/_vendor/qtpy/tests/test_qtprintsupport.py new file mode 100644 index 00000000..2e8f7861 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qtprintsupport.py @@ -0,0 +1,18 @@ +from __future__ import absolute_import + +import pytest +from qtpy import QtPrintSupport + + +def test_qtprintsupport(): + """Test the qtpy.QtPrintSupport namespace""" + assert QtPrintSupport.QAbstractPrintDialog is not None + assert QtPrintSupport.QPageSetupDialog is not None + assert QtPrintSupport.QPrintDialog is not None + assert QtPrintSupport.QPrintPreviewDialog is not None + assert QtPrintSupport.QPrintEngine is not None + assert QtPrintSupport.QPrinter is not None + assert QtPrintSupport.QPrinterInfo is not None + assert QtPrintSupport.QPrintPreviewWidget is not None + + diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qtsql.py b/build/lib/winpython/_vendor/qtpy/tests/test_qtsql.py new file mode 100644 index 00000000..1e7404ff --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qtsql.py @@ -0,0 +1,24 @@ +from __future__ import absolute_import + +import pytest +from qtpy import QtSql + +def test_qtsql(): + """Test the qtpy.QtSql namespace""" + assert QtSql.QSqlDatabase is not None + assert QtSql.QSqlDriverCreatorBase is not None + assert QtSql.QSqlDriver is not None + assert QtSql.QSqlError is not None + assert QtSql.QSqlField is not None + assert QtSql.QSqlIndex is not None + assert QtSql.QSqlQuery is not None + assert QtSql.QSqlRecord is not None + assert QtSql.QSqlResult is not None + assert QtSql.QSqlQueryModel is not None + assert QtSql.QSqlRelationalDelegate is not None + assert QtSql.QSqlRelation is not None + assert QtSql.QSqlRelationalTableModel is not None + assert QtSql.QSqlTableModel is not None + + # Following modules are not (yet) part of any wrapper: + # QSqlDriverCreator, QSqlDriverPlugin diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qtsvg.py b/build/lib/winpython/_vendor/qtpy/tests/test_qtsvg.py new file mode 100644 index 00000000..74d8522e --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qtsvg.py @@ -0,0 +1,13 @@ +from __future__ import absolute_import + +import pytest + + +def test_qtsvg(): + """Test the qtpy.QtSvg namespace""" + from qtpy import QtSvg + + assert QtSvg.QGraphicsSvgItem is not None + assert QtSvg.QSvgGenerator is not None + assert QtSvg.QSvgRenderer is not None + assert QtSvg.QSvgWidget is not None diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_qttest.py b/build/lib/winpython/_vendor/qtpy/tests/test_qttest.py new file mode 100644 index 00000000..5d2ab9e1 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_qttest.py @@ -0,0 +1,9 @@ +from __future__ import absolute_import + +import pytest +from qtpy import QtTest + + +def test_qttest(): + """Test the qtpy.QtTest namespace""" + assert QtTest.QTest is not None diff --git a/build/lib/winpython/_vendor/qtpy/tests/test_uic.py b/build/lib/winpython/_vendor/qtpy/tests/test_uic.py new file mode 100644 index 00000000..1c50e9fe --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/tests/test_uic.py @@ -0,0 +1,83 @@ +import os +import sys +import contextlib + +import pytest +from qtpy import PYSIDE2, QtWidgets +from qtpy.QtWidgets import QComboBox +from qtpy import uic +from qtpy.uic import loadUi + + +QCOMBOBOX_SUBCLASS = """ +from qtpy.QtWidgets import QComboBox +class _QComboBoxSubclass(QComboBox): + pass +""" + +@contextlib.contextmanager +def enabled_qcombobox_subclass(tmpdir): + """ + Context manager that sets up a temporary module with a QComboBox subclass + and then removes it once we are done. + """ + + with open(tmpdir.join('qcombobox_subclass.py').strpath, 'w') as f: + f.write(QCOMBOBOX_SUBCLASS) + + sys.path.insert(0, tmpdir.strpath) + + yield + + sys.path.pop(0) + + +def get_qapp(icon_path=None): + """ + Helper function to return a QApplication instance + """ + qapp = QtWidgets.QApplication.instance() + if qapp is None: + qapp = QtWidgets.QApplication(['']) + return qapp + + +def test_load_ui(): + """ + Make sure that the patched loadUi function behaves as expected with a + simple .ui file. + """ + app = get_qapp() + ui = loadUi(os.path.join(os.path.dirname(__file__), 'test.ui')) + assert isinstance(ui.pushButton, QtWidgets.QPushButton) + assert isinstance(ui.comboBox, QComboBox) + + +def test_load_ui_custom_auto(tmpdir): + """ + Test that we can load a .ui file with custom widgets without having to + explicitly specify a dictionary of custom widgets, even in the case of + PySide. + """ + + app = get_qapp() + + with enabled_qcombobox_subclass(tmpdir): + from qcombobox_subclass import _QComboBoxSubclass + ui = loadUi(os.path.join(os.path.dirname(__file__), 'test_custom.ui')) + + assert isinstance(ui.pushButton, QtWidgets.QPushButton) + assert isinstance(ui.comboBox, _QComboBoxSubclass) + + +@pytest.mark.skipif(PYSIDE2, reason="It fails on PySide2") +def test_load_full_uic(): + """Test that we load the full uic objects for PyQt5 and PyQt4.""" + QT_API = os.environ.get('QT_API', '').lower() + if QT_API == 'pyside': + assert hasattr(uic, 'loadUi') + assert not hasattr(uic, 'loadUiType') + else: + objects = ['compileUi', 'compileUiDir', 'loadUi', 'loadUiType', + 'widgetPluginPath'] + assert all([hasattr(uic, o) for o in objects]) diff --git a/build/lib/winpython/_vendor/qtpy/uic.py b/build/lib/winpython/_vendor/qtpy/uic.py new file mode 100644 index 00000000..07d7a787 --- /dev/null +++ b/build/lib/winpython/_vendor/qtpy/uic.py @@ -0,0 +1,228 @@ +import os + +from . import PYSIDE, PYSIDE2, PYQT4, PYQT5 +from .QtWidgets import QComboBox + + +if PYQT5: + + from PyQt5.uic import * + +elif PYQT4: + + from PyQt4.uic import * + +else: + + __all__ = ['loadUi'] + + # In PySide, loadUi does not exist, so we define it using QUiLoader, and + # then make sure we expose that function. This is adapted from qt-helpers + # which was released under a 3-clause BSD license: + # qt-helpers - a common front-end to various Qt modules + # + # Copyright (c) 2015, Chris Beaumont and Thomas Robitaille + # + # 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 the name of the Glue project nor the names of its 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 COPYRIGHT HOLDER 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. + # + # Which itself was based on the solution at + # + # https://gist.github.com/cpbotha/1b42a20c8f3eb9bb7cb8 + # + # which was released under the MIT license: + # + # Copyright (c) 2011 Sebastian Wiesner + # Modifications by Charl Botha + # + # 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. + + if PYSIDE: + from PySide.QtCore import QMetaObject + from PySide.QtUiTools import QUiLoader + elif PYSIDE2: + from PySide2.QtCore import QMetaObject + from PySide2.QtUiTools import QUiLoader + + class UiLoader(QUiLoader): + """ + Subclass of :class:`~PySide.QtUiTools.QUiLoader` to create the user + interface in a base instance. + + Unlike :class:`~PySide.QtUiTools.QUiLoader` itself this class does not + create a new instance of the top-level widget, but creates the user + interface in an existing instance of the top-level class if needed. + + This mimics the behaviour of :func:`PyQt4.uic.loadUi`. + """ + + def __init__(self, baseinstance, customWidgets=None): + """ + Create a loader for the given ``baseinstance``. + + The user interface is created in ``baseinstance``, which must be an + instance of the top-level class in the user interface to load, or a + subclass thereof. + + ``customWidgets`` is a dictionary mapping from class name to class + object for custom widgets. Usually, this should be done by calling + registerCustomWidget on the QUiLoader, but with PySide 1.1.2 on + Ubuntu 12.04 x86_64 this causes a segfault. + + ``parent`` is the parent object of this loader. + """ + + QUiLoader.__init__(self, baseinstance) + + self.baseinstance = baseinstance + + if customWidgets is None: + self.customWidgets = {} + else: + self.customWidgets = customWidgets + + def createWidget(self, class_name, parent=None, name=''): + """ + Function that is called for each widget defined in ui file, + overridden here to populate baseinstance instead. + """ + + if parent is None and self.baseinstance: + # supposed to create the top-level widget, return the base + # instance instead + return self.baseinstance + + else: + + # For some reason, Line is not in the list of available + # widgets, but works fine, so we have to special case it here. + if class_name in self.availableWidgets() or class_name == 'Line': + # create a new widget for child widgets + widget = QUiLoader.createWidget(self, class_name, parent, name) + + else: + # If not in the list of availableWidgets, must be a custom + # widget. This will raise KeyError if the user has not + # supplied the relevant class_name in the dictionary or if + # customWidgets is empty. + try: + widget = self.customWidgets[class_name](parent) + except KeyError: + raise Exception('No custom widget ' + class_name + ' ' + 'found in customWidgets') + + if self.baseinstance: + # set an attribute for the new child widget on the base + # instance, just like PyQt4.uic.loadUi does. + setattr(self.baseinstance, name, widget) + + return widget + + def _get_custom_widgets(ui_file): + """ + This function is used to parse a ui file and look for the + section, then automatically load all the custom widget classes. + """ + + import sys + import importlib + from xml.etree.ElementTree import ElementTree + + # Parse the UI file + etree = ElementTree() + ui = etree.parse(ui_file) + + # Get the customwidgets section + custom_widgets = ui.find('customwidgets') + + if custom_widgets is None: + return {} + + custom_widget_classes = {} + + for custom_widget in custom_widgets.getchildren(): + + cw_class = custom_widget.find('class').text + cw_header = custom_widget.find('header').text + + module = importlib.import_module(cw_header) + + custom_widget_classes[cw_class] = getattr(module, cw_class) + + return custom_widget_classes + + def loadUi(uifile, baseinstance=None, workingDirectory=None): + """ + Dynamically load a user interface from the given ``uifile``. + + ``uifile`` is a string containing a file name of the UI file to load. + + If ``baseinstance`` is ``None``, the a new instance of the top-level + widget will be created. Otherwise, the user interface is created within + the given ``baseinstance``. In this case ``baseinstance`` must be an + instance of the top-level widget class in the UI file to load, or a + subclass thereof. In other words, if you've created a ``QMainWindow`` + interface in the designer, ``baseinstance`` must be a ``QMainWindow`` + or a subclass thereof, too. You cannot load a ``QMainWindow`` UI file + with a plain :class:`~PySide.QtGui.QWidget` as ``baseinstance``. + + :method:`~PySide.QtCore.QMetaObject.connectSlotsByName()` is called on + the created user interface, so you can implemented your slots according + to its conventions in your widget class. + + Return ``baseinstance``, if ``baseinstance`` is not ``None``. Otherwise + return the newly created instance of the user interface. + """ + + # We parse the UI file and import any required custom widgets + customWidgets = _get_custom_widgets(uifile) + + loader = UiLoader(baseinstance, customWidgets) + + if workingDirectory is not None: + loader.setWorkingDirectory(workingDirectory) + + widget = loader.load(uifile) + QMetaObject.connectSlotsByName(widget) + return widget diff --git a/build/lib/winpython/associate.py b/build/lib/winpython/associate.py new file mode 100644 index 00000000..74e6aee4 --- /dev/null +++ b/build/lib/winpython/associate.py @@ -0,0 +1,387 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see winpython/__init__.py for details) + +""" +Register a Python distribution + +Created on Tue Aug 21 21:46:30 2012 +""" + +from __future__ import print_function + +import sys +import os +import os.path as osp +import subprocess + + +# Local imports +from winpython.py3compat import winreg +from winpython import utils + +KEY_C = r"Software\Classes\%s" +KEY_C0 = KEY_C % r"Python.%sFile\shell" +KEY_C1 = KEY_C % r"Python.%sFile\shell\%s" +KEY_C2 = KEY_C1 + r"\command" +KEY_DROP0 = KEY_C % r"Python.%sFile\shellex" +KEY_DROP1 = KEY_C % r"Python.%sFile\shellex\DropHandler" +KEY_I = KEY_C % r"Python.%sFile\DefaultIcon" +KEY_D = KEY_C % r"Python.%sFile" +EWI = "Edit with IDLE" +EWS = "Edit with Spyder" + +KEY_S = r"Software\Python" +KEY_S0 = KEY_S + r"\PythonCore" +KEY_S1 = KEY_S0 + r"\%s" + + +def _get_shortcut_data(target, current=True): + wpgroup = utils.create_winpython_start_menu_folder( + current=current + ) + wpdir = osp.join(target, os.pardir) + data = [] + for name in os.listdir(wpdir): + bname, ext = osp.splitext(name) + if ext == '.exe': + data.append( + ( + osp.join(wpdir, name), + bname, + osp.join(wpgroup, bname), + ) + ) + return data + + +def register(target, current=True): + """Register a Python distribution in Windows registry""" + root = ( + winreg.HKEY_CURRENT_USER + if current + else winreg.HKEY_LOCAL_MACHINE + ) + + # Extensions + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C % ".py"), + "", + 0, + winreg.REG_SZ, + "Python.File", + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C % ".pyw"), + "", + 0, + winreg.REG_SZ, + "Python.NoConFile", + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C % ".pyc"), + "", + 0, + winreg.REG_SZ, + "Python.CompiledFile", + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C % ".pyo"), + "", + 0, + winreg.REG_SZ, + "Python.CompiledFile", + ) + + # MIME types + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C % ".py"), + "Content Type", + 0, + winreg.REG_SZ, + "text/plain", + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C % ".pyw"), + "Content Type", + 0, + winreg.REG_SZ, + "text/plain", + ) + + # Verbs + python = osp.abspath(osp.join(target, 'python.exe')) + pythonw = osp.abspath(osp.join(target, 'pythonw.exe')) + spyder = osp.abspath( + osp.join(target, os.pardir, 'Spyder.exe') + ) + if not osp.isfile(spyder): + spyder = '%s" "%s\Scripts\spyder' % ( + pythonw, + target, + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C2 % ("", "open")), + "", + 0, + winreg.REG_SZ, + '"%s" "%%1" %%*' % python, + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C2 % ("NoCon", "open")), + "", + 0, + winreg.REG_SZ, + '"%s" "%%1" %%*' % pythonw, + ) + winreg.SetValueEx( + winreg.CreateKey( + root, KEY_C2 % ("Compiled", "open") + ), + "", + 0, + winreg.REG_SZ, + '"%s" "%%1" %%*' % python, + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C2 % ("", EWI)), + "", + 0, + winreg.REG_SZ, + '"%s" "%s\Lib\idlelib\idle.pyw" -n -e "%%1"' + % (pythonw, target), + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C2 % ("NoCon", EWI)), + "", + 0, + winreg.REG_SZ, + '"%s" "%s\Lib\idlelib\idle.pyw" -n -e "%%1"' + % (pythonw, target), + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C2 % ("", EWS)), + "", + 0, + winreg.REG_SZ, + '"%s" "%%1"' % spyder, + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_C2 % ("NoCon", EWS)), + "", + 0, + winreg.REG_SZ, + '"%s" "%%1"' % spyder, + ) + + # Drop support + handler = "{60254CA5-953B-11CF-8C96-00AA00B8708C}" + for ftype in ("", "NoCon", "Compiled"): + winreg.SetValueEx( + winreg.CreateKey(root, KEY_DROP1 % ftype), + "", + 0, + winreg.REG_SZ, + handler, + ) + # Icons + dlls = osp.join(target, 'DLLs') + winreg.SetValueEx( + winreg.CreateKey(root, KEY_I % ""), + "", + 0, + winreg.REG_SZ, + r'%s\py.ico' % dlls, + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_I % "NoCon"), + "", + 0, + winreg.REG_SZ, + r'%s\py.ico' % dlls, + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_I % "Compiled"), + "", + 0, + winreg.REG_SZ, + r'%s\pyc.ico' % dlls, + ) + + # Descriptions + winreg.SetValueEx( + winreg.CreateKey(root, KEY_D % ""), + "", + 0, + winreg.REG_SZ, + "Python File", + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_D % "NoCon"), + "", + 0, + winreg.REG_SZ, + "Python File (no console)", + ) + winreg.SetValueEx( + winreg.CreateKey(root, KEY_D % "Compiled"), + "", + 0, + winreg.REG_SZ, + "Compiled Python File", + ) + + # PythonCore entries + short_version = utils.get_python_infos(target)[0] + long_version = utils.get_python_long_version(target) + key_core = (KEY_S1 % short_version) + r'\%s' + winreg.SetValueEx( + winreg.CreateKey(root, key_core % 'InstallPath'), + "", + 0, + winreg.REG_SZ, + target, + ) + winreg.SetValueEx( + winreg.CreateKey( + root, key_core % r'InstallPath\InstallGroup' + ), + "", + 0, + winreg.REG_SZ, + "Python %s" % short_version, + ) + winreg.SetValueEx( + winreg.CreateKey(root, key_core % 'Modules'), + "", + 0, + winreg.REG_SZ, + "", + ) + winreg.SetValueEx( + winreg.CreateKey(root, key_core % 'PythonPath'), + "", + 0, + winreg.REG_SZ, + r"%s\Lib;%s\DLLs" % (target, target), + ) + winreg.SetValueEx( + winreg.CreateKey( + root, + key_core % r'Help\Main Python Documentation', + ), + "", + 0, + winreg.REG_SZ, + r"%s\Doc\python%s.chm" % (target, long_version), + ) + + # Create start menu entries for all WinPython launchers + for path, desc, fname in _get_shortcut_data( + target, current=current + ): + utils.create_shortcut(path, desc, fname) + # Register the Python ActiveX Scripting client (requires pywin32) + axscript = osp.join( + target, + 'Lib', + 'site-packages', + 'win32comext', + 'axscript', + 'client', + 'pyscript.py', + ) + if osp.isfile(axscript): + subprocess.call( + '"%s" "%s"' % (python, axscript), cwd=target + ) + else: + print( + 'Unable to register ActiveX: please install pywin32', + file=sys.stderr, + ) + + +def unregister(target, current=True): + """Unregister a Python distribution in Windows registry""" + # Registry entries + root = ( + winreg.HKEY_CURRENT_USER + if current + else winreg.HKEY_LOCAL_MACHINE + ) + short_version = utils.get_python_infos(target)[0] + key_core = (KEY_S1 % short_version) + r'\%s' + for key in ( + # Drop support + KEY_DROP1 % "", + KEY_DROP1 % "NoCon", + KEY_DROP1 % "Compiled", + KEY_DROP0 % "", + KEY_DROP0 % "NoCon", + KEY_DROP0 % "Compiled", + # Icons + KEY_I % "NoCon", + KEY_I % "Compiled", + KEY_I % "", + # Edit with IDLE + KEY_C2 % ("", EWI), + KEY_C2 % ("NoCon", EWI), + KEY_C1 % ("", EWI), + KEY_C1 % ("NoCon", EWI), + # Edit with Spyder + KEY_C2 % ("", EWS), + KEY_C2 % ("NoCon", EWS), + KEY_C1 % ("", EWS), + KEY_C1 % ("NoCon", EWS), + # Verbs + KEY_C2 % ("", "open"), + KEY_C2 % ("NoCon", "open"), + KEY_C2 % ("Compiled", "open"), + KEY_C1 % ("", "open"), + KEY_C1 % ("NoCon", "open"), + KEY_C1 % ("Compiled", "open"), + KEY_C0 % "", + KEY_C0 % "NoCon", + KEY_C0 % "Compiled", + # Descriptions + KEY_D % "NoCon", + KEY_D % "Compiled", + KEY_D % "", + # PythonCore + key_core % r'InstallPath\InstallGroup', + key_core % 'InstallPath', + key_core % 'Modules', + key_core % 'PythonPath', + key_core % r'Help\Main Python Documentation', + key_core % 'Help', + KEY_S1 % short_version, + KEY_S0, + KEY_S, + ): + try: + print(key) + winreg.DeleteKey(root, key) + except WindowsError: + rootkey = ( + 'HKEY_CURRENT_USER' + if current + else 'HKEY_LOCAL_MACHINE' + ) + print( + r'Unable to remove %s\%s' % (rootkey, key), + file=sys.stderr, + ) + # Start menu shortcuts + for path, desc, fname in _get_shortcut_data( + target, current=current + ): + if osp.exists(fname): + os.remove(fname) + + +if __name__ == '__main__': + register(sys.prefix) + unregister(sys.prefix) diff --git a/build/lib/winpython/config.py b/build/lib/winpython/config.py new file mode 100644 index 00000000..53170cdb --- /dev/null +++ b/build/lib/winpython/config.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see winpython/__init__.py for details) + +""" +WinPython utilities configuration + +Created on Wed Aug 29 12:23:19 2012 +""" + +import sys +import os.path as osp + + +def get_module_path(modname): + """Return module *modname* base path""" + return osp.abspath( + osp.dirname(sys.modules[modname].__file__) + ) + + +def get_module_data_path( + modname, relpath=None, attr_name='DATAPATH' +): + """Return module *modname* data path + Note: relpath is ignored if module has an attribute named *attr_name* + + Handles py2exe/cx_Freeze distributions""" + datapath = getattr(sys.modules[modname], attr_name, '') + if datapath: + return datapath + else: + datapath = get_module_path(modname) + parentdir = osp.join(datapath, osp.pardir) + if osp.isfile(parentdir): + # Parent directory is not a directory but the 'library.zip' file: + # this is either a py2exe or a cx_Freeze distribution + datapath = osp.abspath( + osp.join( + osp.join(parentdir, osp.pardir), modname + ) + ) + if relpath is not None: + datapath = osp.abspath( + osp.join(datapath, relpath) + ) + return datapath + + +DATA_PATH = get_module_data_path( + 'winpython', relpath='data' +) +IMAGE_PATH = get_module_data_path( + 'winpython', relpath='images' +) diff --git a/build/lib/winpython/controlpanel.py b/build/lib/winpython/controlpanel.py new file mode 100644 index 00000000..26196132 --- /dev/null +++ b/build/lib/winpython/controlpanel.py @@ -0,0 +1,1014 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see winpython/__init__.py for details) + +""" +WinPython Package Manager GUI + +Created on Mon Aug 13 11:40:01 2012 +""" + +import os.path as osp +import os +import sys +import platform +import locale + +# winpython.qt becomes winpython._vendor.qtpy +from winpython._vendor.qtpy.QtWidgets import ( + QApplication, + QMainWindow, + QWidget, + QLineEdit, + QHBoxLayout, + QVBoxLayout, + QMessageBox, + QAbstractItemView, + QProgressDialog, + QTableView, + QPushButton, + QLabel, + QTabWidget, + QToolTip, +) + +from winpython._vendor.qtpy.QtGui import ( + QColor, + QDesktopServices, +) + +from winpython._vendor.qtpy.QtCore import ( + Qt, + QAbstractTableModel, + QModelIndex, + Signal, + QThread, + QTimer, + QUrl, +) +from winpython._vendor.qtpy.compat import ( + to_qvariant, + getopenfilenames, + getexistingdirectory, +) +import winpython._vendor.qtpy + +from winpython.qthelpers import ( + get_icon, + add_actions, + create_action, + keybinding, + get_std_icon, + action2button, + mimedata2url, +) + +# Local imports +from winpython import __version__, __project_url__ +from winpython import wppm, associate, utils +from winpython.py3compat import getcwd, to_text_string + + +COLUMNS = ACTION, CHECK, NAME, VERSION, DESCRIPTION = list( + range(5) +) + + +class PackagesModel(QAbstractTableModel): + # Signals after PyQt4 old SIGNAL removal + dataChanged = Signal(QModelIndex, QModelIndex) + + def __init__(self): + QAbstractTableModel.__init__(self) + self.packages = [] + self.checked = set() + self.actions = {} + + def sortByName(self): + self.packages = sorted( + self.packages, key=lambda x: x.name + ) + self.reset() + + def flags(self, index): + if not index.isValid(): + return Qt.ItemIsEnabled + column = index.column() + if column in (NAME, VERSION, ACTION, DESCRIPTION): + return Qt.ItemFlags( + QAbstractTableModel.flags(self, index) + ) + else: + return Qt.ItemFlags( + QAbstractTableModel.flags(self, index) + | Qt.ItemIsUserCheckable + | Qt.ItemIsEditable + ) + + def data(self, index, role=Qt.DisplayRole): + if not index.isValid() or not ( + 0 <= index.row() < len(self.packages) + ): + return to_qvariant() + package = self.packages[index.row()] + column = index.column() + if role == Qt.CheckStateRole and column == CHECK: + return to_qvariant(package in self.checked) + elif role == Qt.DisplayRole: + if column == NAME: + return to_qvariant(package.name) + elif column == VERSION: + return to_qvariant(package.version) + elif column == ACTION: + action = self.actions.get(package) + if action is not None: + return to_qvariant(action) + elif column == DESCRIPTION: + return to_qvariant(package.description) + elif role == Qt.TextAlignmentRole: + if column == ACTION: + return to_qvariant( + int(Qt.AlignRight | Qt.AlignVCenter) + ) + else: + return to_qvariant( + int(Qt.AlignLeft | Qt.AlignVCenter) + ) + elif role == Qt.BackgroundColorRole: + if package in self.checked: + color = QColor(Qt.darkGreen) + color.setAlphaF(0.1) + return to_qvariant(color) + else: + color = QColor(Qt.lightGray) + color.setAlphaF(0.3) + return to_qvariant(color) + return to_qvariant() + + def headerData( + self, section, orientation, role=Qt.DisplayRole + ): + if role == Qt.TextAlignmentRole: + if orientation == Qt.Horizontal: + return to_qvariant( + int(Qt.AlignHCenter | Qt.AlignVCenter) + ) + return to_qvariant( + int(Qt.AlignRight | Qt.AlignVCenter) + ) + if role != Qt.DisplayRole: + return to_qvariant() + if orientation == Qt.Horizontal: + if section == NAME: + return to_qvariant("Name") + elif section == VERSION: + return to_qvariant("Version") + elif section == ACTION: + return to_qvariant("Action") + elif section == DESCRIPTION: + return to_qvariant("Description") + return to_qvariant() + + def rowCount(self, index=QModelIndex()): + return len(self.packages) + + def columnCount(self, index=QModelIndex()): + return len(COLUMNS) + + def setData(self, index, value, role=Qt.EditRole): + if ( + index.isValid() + and 0 <= index.row() < len(self.packages) + and role == Qt.CheckStateRole + ): + package = self.packages[index.row()] + if package in self.checked: + self.checked.remove(package) + else: + self.checked.add(package) + # PyQt4 old SIGNAL: self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), + # PyQt4 old SIGNAL: index, index) + self.dataChanged.emit(index, index) + return True + return False + + +INSTALL_ACTION = 'Install' +REPAIR_ACTION = 'Repair (reinstall)' +NO_REPAIR_ACTION = 'None (Already installed)' +UPGRADE_ACTION = 'Upgrade from v' +NONE_ACTION = '-' + + +class PackagesTable(QTableView): + # Signals after PyQt4 old SIGNAL removal, to be emitted after package_added event + package_added = Signal() + + def __init__(self, parent, process, winname): + QTableView.__init__(self, parent) + assert process in ('install', 'uninstall') + self.process = process + self.model = PackagesModel() + self.setModel(self.model) + self.winname = winname + self.repair = False + self.resizeColumnToContents(0) + self.setAcceptDrops(process == 'install') + if process == 'uninstall': + self.hideColumn(0) + self.distribution = None + + self.setSelectionBehavior( + QAbstractItemView.SelectRows + ) + self.verticalHeader().hide() + self.setShowGrid(False) + + def reset_model(self): + # self.model.reset() is deprecated in Qt5 + self.model.beginResetModel() + self.model.endResetModel() + self.horizontalHeader().setStretchLastSection(True) + for colnb in (ACTION, CHECK, NAME, VERSION): + self.resizeColumnToContents(colnb) + + def get_selected_packages(self): + """Return selected packages""" + return [ + pack + for pack in self.model.packages + if pack in self.model.checked + ] + + def add_packages(self, fnames): + """Add packages""" + notsupported = [] + notcompatible = [] + dist = self.distribution + for fname in fnames: + bname = osp.basename(fname) + try: + package = wppm.Package(fname) + if package.is_compatible_with(dist): + self.add_package(package) + else: + notcompatible.append(bname) + except NotImplementedError: + notsupported.append(bname) + # PyQt4 old SIGNAL: self.emit(SIGNAL('package_added()')) + self.package_added.emit() + if notsupported: + QMessageBox.warning( + self, + "Warning", + "The following packages filenaming are not " + "recognized by %s:\n\n%s" + % (self.winname, "
".join(notsupported)), + QMessageBox.Ok, + ) + if notcompatible: + QMessageBox.warning( + self, + "Warning", + "The following packages " + "are not compatible with " + "Python %s %dbit:\n\n%s" + % ( + dist.version, + dist.architecture, + "
".join(notcompatible), + ), + QMessageBox.Ok, + ) + + def add_package(self, package): + for pack in self.model.packages: + if pack.name == package.name: + return + self.model.packages.append(package) + self.model.packages.sort(key=lambda x: x.name) + self.model.checked.add(package) + self.reset_model() + + def remove_package(self, package): + self.model.packages = [ + pack + for pack in self.model.packages + if pack.fname != package.fname + ] + if package in self.model.checked: + self.model.checked.remove(package) + if package in self.model.actions: + self.model.actions.pop(package) + self.reset_model() + + def refresh_distribution(self, dist): + self.distribution = dist + if self.process == 'install': + for package in self.model.packages: + pack = dist.find_package(package.name) + if pack is None: + action = INSTALL_ACTION + elif pack.version == package.version: + if self.repair: + action = REPAIR_ACTION + else: + action = NO_REPAIR_ACTION + else: + action = UPGRADE_ACTION + pack.version + self.model.actions[package] = action + else: + self.model.packages = ( + self.distribution.get_installed_packages() + ) + for package in self.model.packages: + self.model.actions[package] = NONE_ACTION + self.reset_model() + + def select_all(self): + allpk = set(self.model.packages) + if self.model.checked == allpk: + self.model.checked = set() + else: + self.model.checked = allpk + self.model.reset() + + def dragMoveEvent(self, event): + """Reimplement Qt method, just to avoid default drag'n drop + implementation of QTableView to handle events""" + event.acceptProposedAction() + + def dragEnterEvent(self, event): + """Reimplement Qt method + Inform Qt about the types of data that the widget accepts""" + source = event.mimeData() + if source.hasUrls() and mimedata2url(source): + event.acceptProposedAction() + + def dropEvent(self, event): + """Reimplement Qt method + Unpack dropped data and handle it""" + source = event.mimeData() + fnames = [ + path + for path in mimedata2url(source) + if osp.isfile(path) + ] + self.add_packages(fnames) + event.acceptProposedAction() + + +class DistributionSelector(QWidget): + """Python distribution selector widget""" + + TITLE = 'Select a Python distribution path' + + # Signals after PyQt4 old SIGNAL removal + selected_distribution = Signal(str) + + def __init__(self, parent): + super(DistributionSelector, self).__init__(parent) + self.browse_btn = None + self.label = None + self.line_edit = None + self.setup_widget() + + def set_distribution(self, path): + """Set distribution directory""" + self.line_edit.setText(path) + + def setup_widget(self): + """Setup workspace selector widget""" + self.label = QLabel() + self.line_edit = QLineEdit() + self.line_edit.setAlignment(Qt.AlignRight) + self.line_edit.setReadOnly(True) + # self.line_edit.setDisabled(True) + self.browse_btn = QPushButton( + get_std_icon('DirOpenIcon'), "", self + ) + self.browse_btn.setToolTip(self.TITLE) + # PyQt4 old SIGNAL:self.connect(self.browse_btn, SIGNAL("clicked()"), + # PyQt4 old SIGNAL: self.select_directory) + self.browse_btn.clicked.connect( + self.select_directory + ) + layout = QHBoxLayout() + layout.addWidget(self.label) + layout.addWidget(self.line_edit) + layout.addWidget(self.browse_btn) + layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(layout) + + def select_directory(self): + """Select directory""" + basedir = to_text_string(self.line_edit.text()) + if not osp.isdir(basedir): + basedir = getcwd() + while True: + directory = getexistingdirectory( + self, self.TITLE, basedir + ) + if not directory: + break + if not utils.is_python_distribution(directory): + QMessageBox.warning( + self, + self.TITLE, + "The following directory is not a Python distribution.", + QMessageBox.Ok, + ) + basedir = directory + continue + directory = osp.abspath(osp.normpath(directory)) + self.set_distribution(directory) + # PyQt4 old SIGNAL: self.emit(SIGNAL('selected_distribution(QString)'), directory) + self.selected_distribution.emit(directory) + break + + +class Thread(QThread): + """Installation/Uninstallation thread""" + + def __init__(self, parent): + QThread.__init__(self, parent) + self.callback = None + self.error = None + + def run(self): + try: + self.callback() + except Exception as error: + error_str = str(error) + fs_encoding = ( + sys.getfilesystemencoding() + or locale.getpreferredencoding() + ) + try: + error_str = error_str.decode(fs_encoding) + except ( + UnicodeError, + TypeError, + AttributeError, + ): + pass + self.error = error_str + + +def python_distribution_infos(): + """Return Python distribution infos (not selected distribution but + the one used to run this script)""" + winpyver = os.environ.get('WINPYVER') + if winpyver is None: + return 'Unknown Python distribution' + else: + return 'WinPython ' + winpyver + + +class PMWindow(QMainWindow): + NAME = 'WinPython Control Panel' + + def __init__(self): + QMainWindow.__init__(self) + self.setAttribute(Qt.WA_DeleteOnClose) + + self.distribution = None + + self.tabwidget = None + self.selector = None + self.table = None + self.untable = None + + self.basedir = None + + self.select_all_action = None + self.install_action = None + self.uninstall_action = None + self.remove_action = None + self.packages_icon = get_std_icon( + 'FileDialogContentsView' + ) + + self.setup_window() + + def _add_table(self, table, title, icon): + """Add table tab to main tab widget, return button layout""" + widget = QWidget() + tabvlayout = QVBoxLayout() + widget.setLayout(tabvlayout) + tabvlayout.addWidget(table) + btn_layout = QHBoxLayout() + tabvlayout.addLayout(btn_layout) + self.tabwidget.addTab(widget, icon, title) + return btn_layout + + def setup_window(self): + """Setup main window""" + self.setWindowTitle(self.NAME) + self.setWindowIcon(get_icon('winpython.svg')) + + self.selector = DistributionSelector(self) + # PyQt4 old SIGNAL: self.connect(self.selector, SIGNAL('selected_distribution(QString)'), + # PyQt4 old SIGNAL: self.distribution_changed) + self.selector.selected_distribution.connect( + self.distribution_changed + ) + + self.table = PackagesTable( + self, 'install', self.NAME + ) + # PyQt4 old SIGNAL:self.connect(self.table, SIGNAL('package_added()'), + # PyQt4 old SIGNAL: self.refresh_install_button) + self.table.package_added.connect( + self.refresh_install_button + ) + + # PyQt4 old SIGNAL: self.connect(self.table, SIGNAL("clicked(QModelIndex)"), + # PyQt4 old SIGNAL: lambda index: self.refresh_install_button()) + self.table.clicked.connect( + lambda index: self.refresh_install_button() + ) + + self.untable = PackagesTable( + self, 'uninstall', self.NAME + ) + # PyQt4 old SIGNAL:self.connect(self.untable, SIGNAL("clicked(QModelIndex)"), + # PyQt4 old SIGNAL: lambda index: self.refresh_uninstall_button()) + self.untable.clicked.connect( + lambda index: self.refresh_uninstall_button() + ) + + self.selector.set_distribution(sys.prefix) + self.distribution_changed(sys.prefix) + + self.tabwidget = QTabWidget() + # PyQt4 old SIGNAL:self.connect(self.tabwidget, SIGNAL('currentChanged(int)'), + # PyQt4 old SIGNAL: self.current_tab_changed) + self.tabwidget.currentChanged.connect( + self.current_tab_changed + ) + + btn_layout = self._add_table( + self.table, + "Install/upgrade packages", + get_std_icon("ArrowDown"), + ) + unbtn_layout = self._add_table( + self.untable, + "Uninstall packages", + get_std_icon("DialogResetButton"), + ) + + central_widget = QWidget() + vlayout = QVBoxLayout() + vlayout.addWidget(self.selector) + vlayout.addWidget(self.tabwidget) + central_widget.setLayout(vlayout) + self.setCentralWidget(central_widget) + + # Install tab + add_action = create_action( + self, + "&Add packages...", + icon=get_std_icon('DialogOpenButton'), + triggered=self.add_packages, + ) + self.remove_action = create_action( + self, + "Remove", + shortcut=keybinding('Delete'), + icon=get_std_icon('TrashIcon'), + triggered=self.remove_packages, + ) + self.remove_action.setEnabled(False) + self.select_all_action = create_action( + self, + "(Un)Select all", + shortcut=keybinding('SelectAll'), + icon=get_std_icon('DialogYesButton'), + triggered=self.table.select_all, + ) + self.install_action = create_action( + self, + "&Install packages", + icon=get_std_icon('DialogApplyButton'), + triggered=lambda: self.process_packages( + 'install' + ), + ) + self.install_action.setEnabled(False) + quit_action = create_action( + self, + "&Quit", + icon=get_std_icon('DialogCloseButton'), + triggered=self.close, + ) + packages_menu = self.menuBar().addMenu("&Packages") + add_actions( + packages_menu, + [ + add_action, + self.remove_action, + self.install_action, + None, + quit_action, + ], + ) + + # Uninstall tab + self.uninstall_action = create_action( + self, + "&Uninstall packages", + icon=get_std_icon('DialogCancelButton'), + triggered=lambda: self.process_packages( + 'uninstall' + ), + ) + self.uninstall_action.setEnabled(False) + + uninstall_btn = action2button( + self.uninstall_action, + autoraise=False, + text_beside_icon=True, + ) + + # Option menu + option_menu = self.menuBar().addMenu("&Options") + repair_action = create_action( + self, + "Repair packages", + tip="Reinstall packages even if version is unchanged", + toggled=self.toggle_repair, + ) + add_actions(option_menu, (repair_action,)) + + # Advanced menu + option_menu = self.menuBar().addMenu("&Advanced") + register_action = create_action( + self, + "Register distribution...", + tip="Register file extensions, icons and context menu", + triggered=self.register_distribution, + ) + unregister_action = create_action( + self, + "Unregister distribution...", + tip="Unregister file extensions, icons and context menu", + triggered=self.unregister_distribution, + ) + open_console_action = create_action( + self, + "Open console here", + triggered=lambda: os.startfile( + self.command_prompt_path + ), + ) + open_console_action.setEnabled( + osp.exists(self.command_prompt_path) + ) + add_actions( + option_menu, + ( + register_action, + unregister_action, + None, + open_console_action, + ), + ) + + # # View menu + # view_menu = self.menuBar().addMenu("&View") + # popmenu = self.createPopupMenu() + # add_actions(view_menu, popmenu.actions()) + + # Help menu + about_action = create_action( + self, + "About %s..." % self.NAME, + icon=get_std_icon('MessageBoxInformation'), + triggered=self.about, + ) + report_action = create_action( + self, + "Report issue...", + icon=get_icon('bug.png'), + triggered=self.report_issue, + ) + help_menu = self.menuBar().addMenu("?") + add_actions( + help_menu, [about_action, None, report_action] + ) + + # Status bar + status = self.statusBar() + status.setObjectName("StatusBar") + status.showMessage( + "Welcome to %s!" % self.NAME, 5000 + ) + + # Button layouts + for act in ( + add_action, + self.remove_action, + None, + self.select_all_action, + self.install_action, + ): + if act is None: + btn_layout.addStretch() + else: + btn_layout.addWidget( + action2button( + act, + autoraise=False, + text_beside_icon=True, + ) + ) + unbtn_layout.addWidget(uninstall_btn) + unbtn_layout.addStretch() + + self.resize(400, 500) + + def current_tab_changed(self, index): + """Current tab has just changed""" + if index == 0: + self.show_drop_tip() + + def refresh_install_button(self): + """Refresh install button enable state""" + self.table.refresh_distribution(self.distribution) + self.install_action.setEnabled( + len(self.get_packages_to_be_installed()) > 0 + ) + nbp = len(self.table.get_selected_packages()) + for act in ( + self.remove_action, + self.select_all_action, + ): + act.setEnabled(nbp > 0) + self.show_drop_tip() + + def show_drop_tip(self): + """Show drop tip on install table""" + callback = lambda: QToolTip.showText( + self.table.mapToGlobal(self.table.pos()), + 'Drop files here
' + 'Executable installers (distutils) or source packages', + self, + ) + QTimer.singleShot(500, callback) + + def refresh_uninstall_button(self): + """Refresh uninstall button enable state""" + nbp = len(self.untable.get_selected_packages()) + self.uninstall_action.setEnabled(nbp > 0) + + def toggle_repair(self, state): + """Toggle repair mode""" + self.table.repair = state + self.refresh_install_button() + + def register_distribution(self): + """Register distribution""" + answer = QMessageBox.warning( + self, + "Register distribution", + "This will associate file extensions, icons and " + "Windows explorer's context menu entries ('Edit with IDLE', ...) " + "with selected Python distribution in Windows registry. " + "
Shortcuts for all WinPython launchers will be installed " + "in WinPython Start menu group (replacing existing " + "shortcuts)." + "
If pywin32 is installed (it should be on any " + "WinPython distribution), the Python ActiveX Scripting client " + "will also be registered." + "

Warning: the only way to undo this change is to " + "register another Python distribution to Windows registry." + "

Note: these actions are exactly the same as those " + "performed when installing Python with the official installer " + "for Windows.

Do you want to continue?", + QMessageBox.Yes | QMessageBox.No, + ) + if answer == QMessageBox.Yes: + associate.register(self.distribution.target) + + def unregister_distribution(self): + """Unregister distribution""" + answer = QMessageBox.warning( + self, + "Unregister distribution", + "This will remove file extensions associations, icons and " + "Windows explorer's context menu entries ('Edit with IDLE', ...) " + "with selected Python distribution in Windows registry. " + "
Shortcuts for all WinPython launchers will be removed " + "from WinPython Start menu group." + "
If pywin32 is installed (it should be on any " + "WinPython distribution), the Python ActiveX Scripting client " + "will also be unregistered." + "

Do you want to continue?", + QMessageBox.Yes | QMessageBox.No, + ) + if answer == QMessageBox.Yes: + associate.unregister(self.distribution.target) + + @property + def command_prompt_path(self): + return osp.join( + self.distribution.target, + osp.pardir, + "WinPython Command Prompt.exe", + ) + + def distribution_changed(self, path): + """Distribution path has just changed""" + for package in self.table.model.packages: + self.table.remove_package(package) + dist = wppm.Distribution(to_text_string(path)) + self.table.refresh_distribution(dist) + self.untable.refresh_distribution(dist) + self.distribution = dist + self.selector.label.setText( + 'Python %s %dbit:' + % (dist.version, dist.architecture) + ) + + def add_packages(self): + """Add packages""" + basedir = ( + self.basedir if self.basedir is not None else '' + ) + fnames, _selfilter = getopenfilenames( + parent=self, + basedir=basedir, + caption='Add packages', + filters='*.exe *.zip *.tar.gz *.whl', + ) + if fnames: + self.basedir = osp.dirname(fnames[0]) + self.table.add_packages(fnames) + + def get_packages_to_be_installed(self): + """Return packages to be installed""" + return [ + pack + for pack in self.table.get_selected_packages() + if self.table.model.actions[pack] + not in (NO_REPAIR_ACTION, NONE_ACTION) + ] + + def remove_packages(self): + """Remove selected packages""" + for package in self.table.get_selected_packages(): + self.table.remove_package(package) + + def process_packages(self, action): + """Install/uninstall packages""" + if action == 'install': + text, table = 'Installing', self.table + if not self.get_packages_to_be_installed(): + return + elif action == 'uninstall': + text, table = 'Uninstalling', self.untable + else: + raise AssertionError + packages = table.get_selected_packages() + if not packages: + return + func = getattr(self.distribution, action) + thread = Thread(self) + for widget in self.children(): + if isinstance(widget, QWidget): + widget.setEnabled(False) + try: + status = self.statusBar() + except AttributeError: + status = self.parent().statusBar() + progress = QProgressDialog( + self, Qt.FramelessWindowHint + ) + progress.setMaximum( + len(packages) + ) # old vicious bug:len(packages)-1 + for index, package in enumerate(packages): + progress.setValue(index) + progress.setLabelText( + "%s %s %s..." + % (text, package.name, package.version) + ) + QApplication.processEvents() + if progress.wasCanceled(): + break + if package in table.model.actions: + try: + thread.callback = lambda: func(package) + thread.start() + while thread.isRunning(): + QApplication.processEvents() + if progress.wasCanceled(): + status.setEnabled(True) + status.showMessage( + "Cancelling operation..." + ) + table.remove_package(package) + error = thread.error + except Exception as error: + error = to_text_string(error) + if error is not None: + pstr = ( + package.name + ' ' + package.version + ) + QMessageBox.critical( + self, + "Error", + "Unable to %s %s" + "

Error message:
%s" + % (action, pstr, error), + ) + progress.setValue(progress.maximum()) + status.clearMessage() + for widget in self.children(): + if isinstance(widget, QWidget): + widget.setEnabled(True) + thread = None + for table in (self.table, self.untable): + table.refresh_distribution(self.distribution) + + def report_issue(self): + + issue_template = """\ +Python distribution: %s +Control panel version: %s + +Python Version: %s +Qt Version: %s, %s %s + +What steps will reproduce the problem? +1. +2. +3. + +What is the expected output? What do you see instead? + + +Please provide any additional information below. +""" % ( + python_distribution_infos(), + __version__, + platform.python_version(), + winpython._vendor.qtpy.QtCore.__version__, + winpython.qt.API_NAME, + winpython._vendor.qtpy.__version__, + ) + + url = QUrl("%s/issues/entry" % __project_url__) + url.addQueryItem("comment", issue_template) + QDesktopServices.openUrl(url) + + def about(self): + """About this program""" + QMessageBox.about( + self, + "About %s" % self.NAME, + """%s %s +
Package Manager and Advanced Tasks +

Copyright © 2012 Pierre Raybaut +
Licensed under the terms of the MIT License +

Created, developed and maintained by Pierre Raybaut +

WinPython at Github.io: downloads, bug reports, + discussions, etc.

+

This program is executed by:
+ %s
+ Python %s, Qt %s, %s qtpy %s""" + % ( + self.NAME, + __version__, + __project_url__, + python_distribution_infos(), + platform.python_version(), + winpython._vendor.qtpy.QtCore.__version__, + winpython._vendor.qtpy.API_NAME, + winpython._vendor.qtpy.__version__, + ), + ) + + +def main(test=False): + app = QApplication([]) + win = PMWindow() + win.show() + if test: + return app, win + else: + app.exec_() + + +def test(): + app, win = main(test=True) + print(sys.modules) + app.exec_() + + +if __name__ == "__main__": + main() diff --git a/build/lib/winpython/data/categories.ini b/build/lib/winpython/data/categories.ini new file mode 100644 index 00000000..b0b06840 --- /dev/null +++ b/build/lib/winpython/data/categories.ini @@ -0,0 +1,30 @@ +[misc] +description=Misc. + +[scientific] +description=Scientific + +[util] +description=Utilities + +[gui] +description=Graphical User Interfaces + +[plot] +description=2D and 3D Plotting + +[visu3d] +description=3D Visualization + +[improc] +description=Image Processing + +[dataproc] +description=Data Processing + +[deploy] +description=Installation/Deployment + +[docgen] +description=Documentation Generation + diff --git a/build/lib/winpython/data/packages.ini b/build/lib/winpython/data/packages.ini new file mode 100644 index 00000000..9b121c78 --- /dev/null +++ b/build/lib/winpython/data/packages.ini @@ -0,0 +1,2412 @@ + +[absl-py] +description=Abseil Python Common Libraries + +[adodbapi] +description=A pure Python package implementing PEP 249 DB-API using Microsoft ADO. + +[affine] +description=Matrices describing affine transformation of the plane. + +[aiodns] +description=Simple DNS resolver for asyncio + +[aiofiles] +description=File support for asyncio. + +[aiohttp] +description=http client/server for asyncio + +[aiosqlite] +description=asyncio bridge to the standard sqlite3 module + +[alabaster] +description=A configurable sidebar-enabled Sphinx theme + +[algopy] +description=Taylor Arithmetic Computation and Algorithmic Differentiation + +[altair] +description=High-level declarative visualization library for Python + +[altair_data_server] +description=A background data server for Altair charts. + +[altair_transform] +description=A python engine for evaluating Altair transforms. + +[altair_widgets] +description=Altair Widgets: An interactive visualization for statistical data for Python. + +[altgraph] +description=Python graph (network) package + +[amqp] +description=Low-level AMQP client for Python (fork of amqplib). + +[aniso8601] +description=A library for parsing ISO 8601 strings. + +[ansiwrap] +description=textwrap, but savvy to ANSI colors and styles + +[anyio] +description=High level compatibility layer for multiple asynchronous event loop implementations + +[anyjson] +description=Wraps the best available JSON implementation available in a common interface + +[apispec] +description=A pluggable API specification generator. Currently supports the OpenAPI specification (f.k.a. the Swagger specification). + +[apistar] +description=API documentation, validation, mocking, and clients. + +[aplus] +description=An implementation of the Promises/A+ specification and test suite in Python + +[appdirs] +description=A small Python module for determining appropriate " + "platform-specific dirs, e.g. a "user data dir". + +[apptools] +description=Enthought application tools + +[argcomplete] +description=Bash tab completion for argparse + +[argh] +description=An unobtrusive argparse wrapper with natural syntax + +[args] +description=Command Arguments for Humans. + +[asgiref] +description=ASGI specs, helper code, and adapters + +[asciitree] +description=Draws ASCII trees. + +[asn1crypto] +description=Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP + +[asteval] +description=Safe, minimalistic evaluator of python expression using ast module + +[astor] +description=Read/rewrite/write Python ASTs + +[astroid] +description=Rebuild a new abstract syntax tree from Python's ast (required for pylint) + +[astroml] +description=tools for machine learning and data mining in Astronomy + +[astropy] +description=Community-developed python astronomy tools + +[async_generator] +description=Async generators and context managers for Python 3.5+ + +[async_timeout] +description=Timeout context manager for asyncio programs + +[atomicwrites] +description=Powerful Python library for atomic file writes. + +[attrs] +description=Classes Without Boilerplate + +[autopep8] +description=A tool that automatically formats Python code to conform to the PEP 8 style guide + +[azureml_dataprep] +description=Azure ML Data Preparation SDK + +[babel] +description=Internationalization utilities + +[backcall] +description=Specifications for callback functions passed in to an API + +[backports_abc] +description=A backport of recent additions to the 'collections.abc' module. + +[backports.shutil_get_terminal_size] +description=A backport of the get_terminal_size function from Python 3.3's shutil. + +[backports.ssl_match_hostname] +description=The ssl.match_hostname() function from Python 3.4 + +[backports.weakref] +description=Backport of new features in Python's weakref module + +[bandit] +description=Security oriented static analyser for python code. + +[baresql] +description=playing SQL directly on Python datas + +[bcolz] +description=columnar and compressed data containers. + +[bcrypt] +description=Modern password hashing for your software and your servers + +[beautifulsoup4] +description=Screen-scraping library + +[billiard] +description=Python multiprocessing fork with improvements and bugfixes + +[binaryornot] +description=Ultra-lightweight pure Python package to check if a file is binary or text. + +[bitarray] +description=efficient arrays of booleans -- C extension + +[bkcharts] +description=High level chart types built on top of Bokeh + +[black] +description=The uncompromising code formatter. + +[blaze] +description=Blaze + +[bleach] +description=An easy whitelist-based HTML-sanitizing tool + +[blinker] +description=Fast, simple object-to-object and broadcast signaling + +[blosc] +description=Blosc data compressor + +[bloscpack] +description=Command line interface to and serialization format for Blosc + +[bokeh] +description=Statistical and novel interactive HTML plots for Python + +[boto3] +description=The AWS SDK for Python + +[botocore] +description=Low-level, data-driven core of boto 3. + +[bottle] +description=Fast and simple WSGI-framework for small web-applications. + +[bottleneck] +description=Fast NumPy array functions written in Cython + +[bqplot] +description=Interactive plotting for the Jupyter notebook, using d3.js and ipywidgets. + +[branca] +description=Generate complex HTML+JS pages with Python + +[brewer2mpl] +description=Connect colorbrewer2.org color maps to Python and matplotlib + +[brotli] +description=Python binding of the Brotli compression library + +[cachetools] +description=Extensible memoizing collections and decorators + +[cartopy] +description=A cartographic python library with matplotlib support for visualisation + +[castra] +description=On-disk partitioned store + +[cchardet] +description=Universal encoding detector. This library is faster than chardet. + +[cssselect] +description=cssselect parses CSS3 Selectors and translates them to XPath 1.0 + +[celery] +description=Distributed Task Queue. + +[celerite] +description=Scalable 1D Gaussian Processes + +[certifi] +description=Python package for providing Mozilla's CA Bundle. + +[ceodbc] +description=Python interface to ODBC + +[cffi] +description=Foreign Function Interface for Python calling C code. + +[cftime] +description=time-handling functionality from netcdf4-python + +[chainer] +description=A flexible framework of neural networks + +[chardet] +description=Universal encoding detector for Python 2 and 3 + +[click] +description=A simple wrapper around optparse for powerful command line utilities. + +[click_default_group] +description=Extends click.Group to invoke a command without explicit subcommand name + +[click_plugins] +description=An extension module for click to enable registering CLI commands via setuptools entry-points. + +[cligj] +description=Click params for commmand line interfaces to GeoJSON + +[clint] +description=Python Command Line Interface Tools + +[cloudpickle] +description=Extended pickling support for Python objects + +[clrmagic] +description=IPython cell magic to use .NET languages + +[cmarkgfm] +description=Minimal bindings to GitHub's fork of cmark + +[cntk] +description=The Microsoft Cognitive Toolkit + +[colorama] +description=Cross-platform colored terminal text + +[colorcet] +description=A set of useful perceptually uniform colormaps for plotting scientific data + +[coloredlogs] +description=Colored terminal output for Python's logging module + +[comtypes] +description=Pure Python COM package + +[commonmark] +description=Python parser for the CommonMark Markdown spec + +[cookiecutter] +description=A command-line utility that creates projects from cookiecutters (project templates). E.g. Python package projects, jQuery plugin projects. + +[configobj] +description=Config file reading, writing and validation. + +[configparser] +description=This library brings the updated configparser from Python 3.5 to Python 2.6-3.5. + +[contextily] +description=Context geo-tiles in Python + +[contextlib2] +description=Backports and enhancements for the contextlib module + +[contextvars] +description=PEP 567 Backport + +[convertdate] +description=Converts between Gregorian dates and other calendar systems + +[corner] +description=Make some beautiful corner plots of samples. + +[coverage] +description=Code coverage measurement for Python + +[cryptography] +description=cryptography is a package which provides cryptographic recipes and primitives to Python developers + +[cupy] +description=NumPy-like API accelerated with CUD + +[curio] +description=Curio - Concurrent I/O + +[cvxcanon] +description=common operations for convex optimization modeling tools. + +[cvxopt] +description=Convex optimization package + +[cvxpy] +description=A domain-specific language for modeling convex optimization problems in Python + +[cx_freeze] +description=Deployment tool which converts Python scripts into stand-alone Windows executables (i.e. target machine does not require Python or any other library to be installed) + +[cycler] +description=Composable style cycles + +[cymem] +description=Manage calls to calloc/free through Cython + +[cyordereddict] +description=Cython implementation of Python's collections.OrderedDict + +[cython] +description=Cython is a language that makes writing C extensions for the Python language as easy as Python + +[cytoolz] +description=Cython implementation of Toolz: High performance functional utilities + +[dash] +description=A Python framework for building reactive web-apps. Developed by Plotly. + +[dask] +description=Minimal task scheduling abstraction + +[dask_ml] +description=a library for distributed and parallel machine learning using dask + +[dask-searchcv] +description=Tools for doing hyperparameter search with Scikit-Learn and Dask + +[databases] +description=Async database support for Python. + +[dataclasses] +description=A backport of the dataclasses module for Python 3.6 + +[datafabric] +description=Distributed In-Memory system for analytics + +[datasette] +description=A tool for exploring and publishing data + +[datashader] +description=Data visualization toolchain based on aggregating into a grid + +[datashape] +description=A data description language + +[db.py] +description=a db package that doesn't suck + +[decorator] +description=Better living through Python with decorators + +[defusedxml] +description=XML bomb protection for Python stdlib modules + +[deprecated] +description=Python @deprecated decorator to deprecate old python classes, functions or methods. + +[descartes] +description=Use geometric objects as matplotlib paths and patches + +[diff_match_patch] +description=epackaging of Google's Diff Match and Patch libraries. Offers robust algorithms to perform the operations required for synchronizing plain text. + +[dill] +description=serialize all of python (almost) + +[discretize] +description=Discretization tools for finite volume and inverse problems + +[distribute] +description=Download, build, install, upgrade, and uninstall Python packages - easily + +[distributed] +description=Distributed computing + +[dm_sonnet] +description=Sonnet is a library for building neural networks in TensorFlow. + +[dnspython] +description=DNS toolkit + +[docopt] +description=Pythonic argument parser, that will make you smile + +[docrepr] +description=docrepr renders Python docstrings in HTML. + +[docutils] +description=Text processing system for processing plaintext documentation into useful formats, such as HTML or LaTeX (includes reStructuredText) + +[dopamine] +description=A library to use DopamineLabs machine learning API + +[dynd] +description=Python exposure of DyND + +[egenix-mx-base] +description=eGenix.com mx Base Distribution: mxDateTime, mxTextTools, mxProxy, mxBeeBase, mxURL, mxUID, mxStack, mxQueue and mxTools + +[ecos] +description=This is the Python package for ECOS: Embedded Cone Solver + +[edward] +description=A library for probabilistic modeling, inference, and criticism. Deep generative models, variational inference. Runs on TensorFlow. + +[emcee] +description=Kick ass affine-invariant ensemble MCMC sampling + +[enum34] +description=Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4 + +[entrypoints] +description=Discover and load entry points from installed packages + +[envisage] +description=Enthought extensible application framework + +[ephem] +description=Compute positions of the planets and stars + +[eradicate] +description=Removes commented-out code. + +[falcon] +description=An unladen web framework for building APIs and app backends. + +[fastcache] +description=C implementation of Python 3 functools.lru_cache + +[fastai] +description=fastai makes deep learning with PyTorch faster, more accurate, and easier + +[fastapi] +description=FastAPI framework, high performance, easy to learn, fast to code, ready for production + +[fasteners] +description=A python package that provides useful locks. + +[fastparquet] +description=Python support for Parquet file format + +[fastprogress] +description=A nested progress with plotting options for fastai + +[fastrlock] +description=A fast RLock implementation for CPython + +[fast-histogram] +description=Fast 1D and 2D histogram functions in Python + +[fbprophet] +description=Automatic Forecasting Procedure + +[feather-format] +description=Python interface to the Apache Arrow-based Feather File Format + +[fenics] +description=The FEniCS Project Python Metapackage + +[filelock] +description=A platform independent file lock. + +[fiona] +description=reads and writes spatial data files + +[flake8] +description=the modular source code checker: pep8, pyflakes and co + +[flask] +description=A microframework based on Werkzeug, Jinja2 and good intentions + +[flaskerize] +description=Python CLI build/dev tool for templated code generation and project modification. Think Angular schematics for Python. + +[flask_accepts] +description=Easy, opinionated Flask input/output handling mixing Marshmallow with Flask-RESTplus + +[flask-compress] +description=Compress responses in your Flask app with gzip. + +[flask-cors] +description=A Flask extension adding a decorator for CORS support + +[flask_restplus] +description=Fully featured framework for fast, easy and documented API development with Flask + +[flask-seasurf] +description=SeaSurf is a Flask extension for preventing cross-site request forgery (CSRF) + +[flexx] +description=Pure Python toolkit for creating GUI's using web technology. + +[flit] +description=Simplified packaging of Python modules + +[folium] +description=Make beautiful maps with Leaflet.js & Python + +[fonttools] +description=Tools to manipulate font files + +[formlayout] +description=Module for creating form dialogs/widgets to edit various type of parameters without having to write any GUI code + +[fs] +description=Python's filesystem abstraction layer + +[fsspec] +description=File-system specification + +[fuel] +description=Data pipeline framework for machine learning + +[funcsigs] +description=Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+ + +[functools32] +description=Backport of the functools module from Python 3.2.3 for use on 2.7 and PyPy. + +[future] +description=Clean single-source support for Python 3 and 2 + +[futures] +description=Backport of the concurrent.futures package from Python 3.2 + +[fuzzywuzzy] +description=Fuzzy string matching in python + +[gast] +description=Python AST that abstracts the underlying Python version + +[gdal] +description=Geospatial Data Abstraction Library + +[gensim] +description=Python framework for fast Vector Space Modelling + +[geoana] +description=Interactive geoscience (mostly) analytic functions. + +[geopy] +description=Python Geocoding Toolbox + +[geographiclib] +description=The geodesic routines from GeographicLib + +[geopandas] +description=Geographic pandas extensions + +[geoplot] +description=High-level geospatial data visualization library for Python + +[geoviews] +description=Stop plotting your data - annotate your data and let it visualize itself... on a map! + +[ggplot] +description=ggplot for python + +[ghost.py] +description=Webkit based webclient. + +[gin_config] +description=Gin-config: a lightweight configuration library for Python + +[gitdb2] +description=Git Object Database + +[gitpython] +description=Python Git Library + +[gmpy2] +description=GMP/MPIR, MPFR, and MPC interface to Python 2.6+ and 3.x + +[gnumath] +description=Extensible array functions that operate on xnd containers. + +[google_auth] +description=Google Authentication Library + +[google_auth_oauthlib] +description=Google Authentication Library + +[google-api-python-client] +description=Google API Client Library for Python + +[google_pasta] +description=pasta is an AST-based Python refactoring library + +[gr] +description=Python visualization framework + +[graphql_relay] +description=Relay implementation for Python + +[graphql_core] +description=GraphQL implementation for Python + +[graphviz] +description=Simple Python interface for Graphviz + +[graphene] +description=GraphQL Framework for Python + +[graphql-server-core] +description=GraphQL Server tools for powering your server + +[greenlet] +description=Lightweight in-process concurrent programming + +[gridmap] +description=Easily map Python functions onto a cluster using a DRMAA-compatible grid engine like Sun Grid Engine (SGE). + +[grpcio] +description=HTTP/2-based RPC framework + +[guidata] +description=Automatically generated graphical user interfaces for easy data set edition and display + +[guiqwt] +description=Efficient curve/image plotting and other GUI tools for scientific data processing software development + +[gym] +description=The OpenAI Gym: A toolkit for developing and comparing your reinforcement learning agents. + +[hdfs] +description=HdfsCLI: API and command line interface for HDFS. + +[heapdict] +description=a heap with decrease-key and increase-key operations + +[helpdev] +description=HelpDev - Extracts information about the Python environment easily. + +[holidays] +description=Generate and work with holidays in Python + +[holoviews] +description=Composable, declarative data structures for building complex visualizations easily. + +[hpack] +description=Pure-Python HPACK header compression + +[hvplot] +description=A high-level plotting API for pandas, dask, streamz and xarray built on HoloViews + +[html5lib] +description=HTML parser based on the WHATWG HTML specification + +[httplib2] +description=A comprehensive HTTP client library. + +[humanfriendly] +description=Human friendly output for text interfaces using Python + +[husl] +description=Human-friendly HSL (Hue-Saturation-Lightness) + +[hupper] +description=Integrated process monitor for developing and reloading daemons. + +[hypercorn] +description=A ASGI Server based on Hyper libraries and inspired by Gunicorn. + +[hyperframe] +description=HTTP/2 framing layer for Python + +[hypothesis] +description=A library for property based testing + +[h11] +description=A pure-Python, bring-your-own-I/O implementation of HTTP/1.1 + +[h2] +description=HTTP/2 framing layer for Python + +[h5py] +description=General-purpose Python interface to HDF5 files (unlike PyTables, h5py provides direct access to the full HDF5 C library) + +[ibis-framework] +description=Productivity-centric Python Big Data Framework + +[ipydatawidgets] +description=A set of widgets to help facilitate reuse of large datasets across widgets + +[idlex] +description=IDLE Extensions for Python + +[idna] +description=Internationalized Domain Names in Applications (IDNA) + +[imageio] +description=Library for reading and writing a wide range of image, video, scientific, and volumetric data formats. + +[imageio_ffmpeg] +description=FFMPEG wrapper for Python + +[imbalanced_learn] +description=Toolbox for imbalanced dataset in machine learning. + +[immutables] +description=A high-performance immutable mapping type for Python + +[imagesize] +description=Getting image size from png/jpeg/jpeg2000/gif file + +[importlib-metadata] +description=Read metadata from Python packages + +[intake] +description=Data input plugin and catalog system + +[ipycanvas] +description=Interactive Canvas in Jupyter + +[ipykernel] +description=IPython Kernel for Jupyter + +[ipyleaflet] +description=A Jupyter widget for dynamic Leaflet maps + +[ipympl] +description=Matplotlib Jupyter Extension + +[ipyparallel] +description=Interactive Parallel Computing with IPython + +[ipyscales] +description=A widget library for scales + +[ipython] +description=Enhanced Python shell + +[ipython-genutils] +description=Vestigial utilities from IPython + +[ipython-sql] +description=RDBMS access via IPython + +[ipyvega] +description=IPython/Jupy + +[ipyvolume] +description=3d plotting for Python in the Jupyter notebook based on IPython widgets using WebGL + +[ipyvuetify] +description=Jupyter widgets based on vuetify UI components + +[ipywebrtc] +description=WebRTC for Jupyter notebook/lab + +[ipywidgets] +description=IPython HTML widgets for Jupyter + +[isort] +description=A Python utility / library to sort Python imports. + +[itsdangerous] +description=Various helpers to pass trusted data to untrusted environments and back. + +[jedi] +description=An autocompletion tool for Python that can be used for text editors + +[jinja2] +description=Sandboxed template engine (provides a Django-like non-XML syntax and compiles templates into executable python code) + +[jmespath] +description=JSON Matching Expressions + +[joblib] +description=Lightweight pipelining: using Python functions as pipeline jobs. + +[jnius] +description=Access Java classes from Python + +[jplephem] +description=Use a JPL ephemeris to predict planet positions + +[jsonschema] +description=An implementation of JSON Schema validation for Python + +[json5] +description=A Python implementation of the JSON5 data format. + +[julia] +description=Python interface to the Julia language + +[jupyter] +description=Jupyter metapackage. Install all the Jupyter components in one go. + +[jupyter_echarts_pypkg] +description=Echarts pypi packages for jupyter and python + +[jupyterlab] +description=Jupyter lab environment notebook server extension + +[jupyterlab_launcher] +description=Jupyter Launcher + +[jupyterlab_sql] +description=SQL GUI for JupyterLab + +[jupyter_client] +description=Jupyter protocol implementation and client libraries + +[jupyter_console] +description=Jupyter terminal console + +[jupyter_core] +description=Jupyter core package. A base package on which Jupyter projects rely. + +[jupyterlab_pygments] +description=JupyterLab Pygments theme + +[jupyterlab_server] +description=JupyterLab Server + +[jupyter_server] +description=Jupyter Server + +[jupyter_sphinx] +description=Jupyter Sphinx Extensions + +[jupytext] +description=Jupyter notebooks as Markdown documents, Julia, Python or R scripts + +[kapteyn] +description=Python modules for astronomical applications + +[keras] +description=Theano-based Deep Learning library + +[keras-applications] +description=Reference implementations of popular deep learning models + +[keras-preprocessing] +description=Easy data preprocessing and data augmentation for deep learning models + +[keras-vis] +description=Neural network visualization toolkit for keras + +[keras_tuner] +description=Hyperparameter tuner for Keras + +[keyring] +description=Store and access your passwords safely. + +[kivy] +description=A software library for rapid development of hardware-accelerated multitouch applications. + +[kivy-garden] +description=Garden tool for kivy flowers. + +[kiwisolver] +description=an efficient implementation of the Cassowary constraint solving algorithm. + +[knack] +description=A Command-Line Interface framework + +[knit] +description=Python tool for defining and deploying YARN Applications + +[kombu] +description=Messaging library for Python. + +[lasagne] +description=neural network tools for Theano + +[lazy-object-proxy] +description=A fast and thorough lazy object proxy. + +[libpython] +description=The MinGW import library for Python + +[lightfm] +description=A Python implementation of LightFM, a hybrid recommendation algorithm. + +[lightning-python] +description=A Python client library for the Lightning data visualization server + +[llvmlite] +description=lightweight wrapper around basic LLVM functionality + +[llvmpy] +description=Python bindings for LLVM + +[lmfit] +description=Least-Squares Minimization with Bounds and Constraints + +[lml] +description=Load me later. A loading plugin management system. + +[lock] +description=spyder lock + +[locket] +description=File-based locks for Python for Linux and Windows + +[locket.py] +description=File-based locks for Python for Linux and Windows + +[logilab-astng] +description=Rebuild a new abstract syntax tree from Python's ast (required for pylint) + +[logilab-common] +description=Collection of low-level Python packages and modules used by Logilab projects (required for pylint) + +[logutils] +description=Logging utilities + +[loky] +description=Robust and reusable Executor for joblib + +[lunardate] +description=A Chinese Calendar Library in Pure Python + +[lxml] +description=Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API. + +[lz4] +description=LZ4 Bindings for Python + +[macholib] +description=Mach-O header analysis and editing + +[mahotas] +description=Computer Vision library + +[mako] +description=A super-fast templating language that borrows the best ideas from the existing templating languages. + +[mapclassify] +description=Classification schemes for choropleth mapping. + +[markdown] +description=Python implementation of Markdown. + +[markdown2] +description=A fast and complete Python implementation of Markdown + +[markupsafe] +description=Implements a XML/HTML/XHTML Markup safe string for Python + +[marshmallow] +description=A lightweight library for converting complex datatypes to and from native Python datatypes. + +[matplotlib] +description=2D plotting library (embeddable in GUIs created with PyQt) + +[mayavi] +description=The Mayavi scientific data 3-dimensional visualizer. + +[mccabe] +description=McCabe checker, plugin for flake8 + +[mercantile] +description=Web mercator XYZ tile utilities + +[metakernel] +description=Metakernel for Jupyter + +[mingwpy] +description=the python friendly windows compiler toolchain + +[mistune] +description=The fastest markdown parser in pure Python, inspired by marked. + +[mizani] +description=Scales for Python + +[mlxtend] +description=Machine Learning Library Extensions + +[mkl-service] +description=Python bindings to some MKL service functions + +[mlflow] +description=An ML Workflow Tool + +[mock] +description=Rolling backport of unittest.mock for all Pythons + +[modergnl] +description=Modern OpenGL binding for python + +[monotonic] +description=An implementation of time.monotonic() for Python 2 & < 3.3 + +[more-itertools] +description=More routines for operating on iterables, beyond itertools + +[moviepy] +description=Video editing with Python + +[mpldatacursor] +description=Interactive data cursors for Matplotlib + +[mpld3] +description=D3 Viewer for Matplotlib + +[mpl-scatter-density] +description=Fast scatter density plots for Matplotlib + +[mpmath] +description=Python library for arbitrary-precision floating-point arithmetic + +[msgpack] +description=MessagePack (de)serializer. + +[msgpack-numpy] +description=Numpy data serialization using msgpack + +[msgpack-python] +description=MessagePack (de)serializer. + +[multidict] +description=multidict implementation + +[multipledispatch] +description=A relatively sane approach to multiple dispatch in Python + +[multiprocess] +description=better multiprocessing and multithreading in python + +[murmurhash] +description=Cython bindings for MurmurHash2 + +[munch] +description=A dot-accessible dictionary (a la JavaScript objects). + +[mxbase] +description=eGenix.com mx Base Distribution: mxDateTime, mxTextTools, mxProxy, mxBeeBase, mxURL, mxUID, mxStack, mxQueue and mxTools + +[mypy] +description=Optional static typing for Python + +[mypy_extensions] +description=Experimental type system extensions for programs checked with the mypy typechecker. + +[mysql-connector-python] +description=MySQL driver written in Python + +[nbbrowserpdf] +description=LaTeX-free PDF generation from Jupyter Notebooks + +[nbconvert] +description=Converting Jupyter Notebooks + +[nbconvert_reportlab] +description=Convert notebooks to PDF using Reportlab + +[nbdime] +description=Tools for diffing and merging of Jupyter notebooks + +[nbformat] +description=The Jupyter Notebook format + +[nbgrader] +description=A system for assigning and grading notebooks. + +[nbpresent] +description=Next generation slides from Jupyter Notebooks + +[nbsphinx] +description=Jupyter Notebook Tools for Sphinx + +[ndtypes] +description=Dynamic types for data description and in-memory computations + +[netcdftime] +description=Time-handling functionality from netcdf4-python + +[netcdf4] +description=Provides an object-oriented python interface to the netCDF version 4 library + +[networkx] +description=Python package for creating and manipulating graphs and networks + +[nltk] +description=The Natural Language Toolkit (NLTK) is a Python package for natural language processing. + +[nose] +description=nose is a discovery-based unittest extension (e.g. NumPy test module is using nose) + +[notebook] +description=# Jupyter Notebook + +[nteract_on_jupyter] +description=Extension for the jupyter notebook server and nteract + +[numba] +description=compiling Python code using LLVM + +[numcodecs] +description=buffer compression and transformation codecs for use in data storage and communication applications + +[numdifftools] +description=Solves automatic numerical differentiation problems in one or more variables. + +[numexpr] +description=Fast evaluation of array expressions elementwise by using a vector-based virtual machine + +[numpy] +description=NumPy: multidimensional array processing for numbers, strings, records and objects (SciPy''s core module) + +[numpydoc] +description=Sphinx extension to support docstrings in Numpy format + +[nvidia-ml-py3] +description=Python Bindings for the NVIDIA Management Library + +[oauthlib] +description=A generic, spec-compliant, thorough implementation of the OAuth request-signing logic + +[oauth2client] +description=OAuth 2.0 client library + +[observations] +description=Tools for loading standard data sets in machine learning + +[octave_kernel] +description=A Jupyter kernel for Octave. + +[oct2py] +description=Python to GNU Octave bridge --> run m-files from python. + +[odo] +description=Data migration in Python + +[olefile] +description=Python package to parse, read and write Microsoft OLE2 files + +[opencv_python] +description=Open Source Computer Vision Library + +[openimageio] +description=a library for reading and writing images with emphasis on animation and visual effects. + +[openpyxl] +description=A Python library to read/write Excel 2007 xlsx/xlsm files + +[opt_einsum] +description=Optimizing numpys einsum function + +[orange] +description=a component-based data mining framework. + +[osqp] +description=the Operator Splitting QP Solver. + +[outcome] +description=Capture the outcome of Python function calls. + +[packaging] +description=Core utilities for Python packages + +[palettable] +description=Color palettes for Python + +[palladium] +description=Framework for setting up predictive analytics services + +[pandas] +description=Powerful data structures for data analysis, time series and statistics + +[pandasql] +description=sqldf for pandas + +[pandas-datareader] +description=Data readers extracted from the pandas codebase,should be compatible with recent pandas versions + +[pandas-ply] +description=functional data manipulation for pandas + +[pandocfilters] +description=Utilities for writing pandoc filters in python + +[panel] +description=A high-level Python toolkit for composing widgets and plots + +[papermill] +description=Parametrize and Run Jupyter Notebooks + +[param] +description=Declarative Python programming using Parameters. + +[parambokeh] +description=Declarative Python programming using Parameters. + +[paramnb] +description=Generate ipywidgets from Parameterized objects in the notebook + +[paramiko] +description=SSH2 protocol library + +[parse] +description=parse() is the opposite of format() + +[parso] +description=A Python Parser + +[partd] +description=Appendable key-value storage + +[passlib] +description=comprehensive password hashing framework supporting over 30 schemes + +[pathspec] +description=Utility library for gitignore style pattern matching of file paths. + +[pathtools] +description=File system general utilities + +[path.py] +description=A module wrapper for os.path + +[patsy] +description=Describing statistical models using symbolic formulas + +[pbr] +description=Python Build Reasonableness + +[pdfrw] +description=pure Python library that reads and writes PDFs + +[pdvega] +description=Pandas plotting interface to Vega and Vega-Lite + +[peewee] +description=a small, expressive ORM. + +[pefile] +description=Python PE parsing module + +[pep8] +description=Python style guide checker + +[perf] +description=Python module to generate and modify perf + +[performance] +description=Python benchmark suite + +[pexpect] +description=Pexpect allows easy control of interactive console applications. + +[pgmagick] +description=Yet Another Python wrapper for GraphicsMagick + +[pg8000] +description=PostgreSQL interface library + +[pkginfo] +description=Query metadatdata from sdists / bdists / installed packages. + +[picklable_itertools] +description=itertools. But picklable. Even on Python 2. + +[pickleshare] +description=Tiny 'shelve'-like database with concurrency support + +[pil] +description=Python Imaging Library - (basic) Image processing library + +[pillow] +description=Python Imaging Library (fork) + +[pint] +description=Physical quantities module + +[pip] +description=A tool for installing and managing Python packages + +[plotly] +description=Python plotting library for collaborative, interactive, publication-quality graphs. + +[plotnine] +description=A grammar of graphics for python + +[plotpy] +description=plotpy is a set of tools for curve and image plotting + +[pluggy] +description=plugin and hook calling mechanisms for python + +[ply] +description=Python Lex & Yacc + +[polygon2] +description=Polygon2 is a Python-2 package that handles polygonal shapes in 2D + +[polygon3] +description=Polygon3 is a Python-3 package that handles polygonal shapes in 2D + +[pomegranate] +description=Pomegranate is a graphical models library for Python, implemented in Cython for speed. + +[portalocker] +description=Wraps the portalocker recipe for easy usage + +[portpicker] +description=A library to choose unique available network ports. + +[poyo] +description=A lightweight YAML Parser for Python + +[ppci] +description=A compiler for ARM, X86, MSP430, xtensa and more implemented in pure Python + +[preshed] +description=Cython hash table that trusts the keys are pre-hashed + +[prettytable] +description=A simple Python library for easily displaying tabular data in a visually appealing ASCII table format. + +[prettytensor] +description=Pretty Tensor makes learning beautiful + +[priority] +description=A pure-Python implementation of the HTTP/2 priority tree + +[proglog] +description=Log and progress bar manager for console, notebooks, web... + +[progressbar] +description=Text progress bar library for Python. + +[progressbar2] +description=A Python Progressbar library to provide visual (yet text based) progress tolong running operations. + +[prometheus_client] +description=Python client for the Prometheus monitoring system. + +[promise] +description=Promises/A+ implementation for Python + +[properties] +description=an organizational aid and wrapper for validation and tab completion of class properties + +[prompt_toolkit] +description=Library for building powerful interactive command lines in Python + +[prospector] +description=python static analysis tool + +[protobuf] +description=Protocol Buffers - Google's data interchange format + +[pscript] +description=Python to JavaScript compiler + +[psutil] +description=Provides an interface for retrieving information on all running processes and system utilization (CPU, disk, memory, network) in a portable way + +[psycopg2] +description=Python-PostgreSQL Database Adapter + +[ptpython] +description=Python REPL build on top of prompt_toolkit + +[ptvsd] +description=Remote debugging server for Python support in Visual Studio and Visual Studio Code + +[ptyprocess] +description=Run a subprocess in a pseudo terminal + +[pulp] +description=PuLP is an LP modeler written in python. PuLP can generate MPS or LP files and call GLPK, COIN CLP/CBC, CPLEX, and GUROBI to solve linear problems + +[pweave] +description=Scientific reports with embedded python computations with reST, LaTeX or markdown + +[py] +description=library with cross-python path, ini-parsing, io, code, log facilities + +[pyct] +description=python package common tasks for users (e.g. copy examples, fetch data, ...) + +[pyarrow] +description=Python library for Apache Arrow + +[pyasn1] +description=ASN.1 types and codecs + +[pyasn1-modules] +description=A collection of ASN.1-based protocols modules + +[pyaudio] +description=Bindings for PortAudio v19, the cross-platform audio input/output stream library. + +[pybars3] +description=Handlebars.js templating for Python 3 and 2 + +[pybind11] +description=Seamless operability between C++11 and Python + +[pycares] +description=Python interface for c-ares + +[pycairo] +description=Python bindings for the cairo library + +[pycodestyle] +description=Python style guide checker + +[pycosat] +description=bindings to picosat (a SAT solver) + +[pycparser] +description=C parser in Python + +[pydantic] +description=Data validation and settings management using python 3.6 type hinting + +[pydicom] +description=Pure python package for working with DICOM files (medical imaging) + +[pydispatcher] +description=Multi-producer-multi-consumer signal dispatching mechanism + +[pydocstyle] +description=Python docstring style checker + +[pydot-ng] +description=Python interface to Graphviz's Dot + +[pyecharts] +description=Python echarts, make charting easier + +[pyecharts_javascripthon] +description=Embeded Python functions in pyecharts + +[pyecharts-jupyter-installer] +description=Install pyecharts extensions into jupyter + +[pyeda] +description=PyEDA is a Python library for electronic design automation. + +[pyepsg] +description=Easy access to the EPSG database via http://epsg.io/ + +[pyface] +description=Enthought traits-capable windowing framework + +[pyflakes] +description=passive checker of Python programs + +[pyflux] +description=Open source time series library for Python + +[pygame] +description=Pygame gives multimedia to python. + +[pygbm] +description=Experimental, numba-based Gradient Boosting Machines + +[pygit2] +description=Python bindings for libgit2. + +[pyglet] +description=Cross-platform windowing and multimedia library + +[pygments] +description=Generic syntax highlighter for general use in all kinds of software +url=http://pygments.org + +[pygraphviz] +description=Python interface to Graphviz graph drawing package + +[pyhdf] +description=Python interface to HDF4 files (Hierarchical Data Format version 4) +category=dataproc + +[PyHive] +description=PyHive is a collection of Python DB-API and SQLAlchemy interfaces for Presto and Hive. + +[pyinstaller] +description=PyInstaller bundles a Python application and all its dependencies into a single package. + +[pylama] +description=Code audit tool for python + +[pylearn2] +description=A Machine Learning library based on Theano + +[pylint] +description=Logilab code analysis module: analyzes Python source code looking for bugs and signs of poor quality + +[pylons] +description=Pylons Web Framework + +[pymatsolver] +description=pymatsolver: Matrix Solvers for Python + +[pymc] +description=Markov Chain Monte Carlo sampling toolkit. + +[pymc3] +description=Markov Chain Monte Carlo sampling toolkit. + +[pymeta3] +description=Pattern-matching language based on Meta for Python 3 and 2 + +[pymkl] +description=Python wrapper of Intel MKL routines + +[pymongo] +description=Python driver for MongoDB + +[pympler] +description=A development tool to measure, monitor and analyze the memory behavior of Python objects. + +[pynacl] +description=Python binding to the Networking and Cryptography (NaCl) library + +[pyodbc] +description=DB API Module for ODBC + +[pyomo] +description=Pyomo: Python Optimization Modeling Objects + +[pyopencl] +description=Python wrapper for OpenCL + +[pyopengl] +description=Cross platform Python binding to OpenGL and related APIs + +[pyopenssl] +description=Python wrapper module around the OpenSSL library + +[pypandoc] +description=Thin wrapper for pandoc. + +[pypdf2] +description=PDF toolkitPDF toolkit + +[pyparsing] +description=A Python Parsing Module + +[pyperf] +description=Python module to run and analyze benchmarks + +[pyproj] +description=Python interface to PROJ.4 library + +[pypiwin32] +description=Python for Windows Extensions + +[pyqt] +description=Cross-platform Application Framework: GUI, widgets, SQL, OpenGL, XML, Unicode... + +[pyqtchart] +description=Python bindings for the Qt Charts library + +[pyqtdatavisualization] +description=Python bindings for the Qt Data Visualization library + +[pyqtdeploy] +description=PyQt Application Deployment Tool + +[pyqtgraph] +description=Scientific Graphics and GUI Library for Python + +[pyqtpurchasing] +description=Python bindings for the Qt Purchasing library + +[pyqt4] +description=Python bindings for the Qt cross platform GUI toolkit +url=http://www.riverbankcomputing.co.uk/software/pyqt/intro + +[pyqt5] +description=Python bindings for the Qt cross platform GUI toolkit +url=http://www.riverbankcomputing.co.uk/software/pyqt/intro + +[pyqt5_sip] +description=Python extension module support for PyQt5 + +[pyqtdoc] +description=PyQtdoc installs Qt documentation for PyQt4 + +[pyqtdesignerplugins] +description=PyQtdesignerplugins installs Python Qt designer plugins (Matplotlib, guiqwt, etc.) for PyQt4 + +[pyqtwebengine] +description=Python bindings for the Qt 3D framework + +[pyqwt] +description=2D plotting library (set of Python bindings for the Qwt library featuring fast plotting) + +[pyramid] +description=The Pyramid Web Framework, a Pylons project + +[pyreadline] +description=IPython needs this module to display color text in Windows command window + +[pyroma] +description=Test your project's packaging friendliness + +[pyrro_ppl] +description=A Python library for probabilistic modeling and inference + +[pyrsistent] +description=Persistent/Functional/Immutable data structures + +[pysal] +description=A library of spatial analysis functions. + +[pyserial] +description=Library encapsulating the access for the serial port + +[pyshp] +description=Pure Python read/write support for ESRI Shapefile format + +[pyside] +description=Python binding of the cross-platform GUI toolkit Qt + +[pyside2] +description=Python binding of the cross-platform GUI toolkit Qt + +[pyspark] +description=Apache Spark Python API + +[pystache] +description=Mustache for Python + +[pystan] +description=Python interface to Stan, a package for Bayesian inference + +[pytest] +description=pytest: simple powerful testing with Python + +[pytest_runner] +description=Invoke py.test as distutils command with dependency resolution + +[python-crfsuite] +description=Python binding for CRFsuite + +[python-dateutil] +description=Powerful extensions to the standard datetime module + +[python-hdf4] +description=Python-HDF4: Python interface to the NCSA HDF4 library + +[python-igraph] +description=High performance graph data structures and algorithms + +[python_mimeparse] +description=An unladen web framework for building APIs and app backends. + +[python-qwt] +description=Qt plotting widgets for Python + +[python_jsonrpc_server] +description=JSON RPC 2.0 server library + +[python_language_server] +description=An implementation of the Language Server Protocol for Python + +[python_levenshtein] +description=Python extension for computing string edit distances and similarities + +[python_multipart] +description=A streaming multipart parser for Python + +[python_snappy] +description=Python library for the snappy compression library from Google + +[pythonnet] +description=.Net and Mono integration for Python + +[pythonqwt] +description=Qt plotting widgets for Python + +[python-twitter] +description=A Python wrapper around the Twitter API + +[python-zstandard] +description=Python bindings to the Zstandard (zstd) compression library + +[pythran] +description=Ahead of Time compiler for numeric kernels + +[pythreejs] +description=Interactive 3d graphics for the Jupyter notebook, using Three.js from Jupyter interactive widgets. + +[pytools] +description=A collection of tools for Python + +[pytorch_transformers] +description=Repository of pre-trained NLP Transformer models: BERT & RoBERTa, GPT & GPT-2, Transformer-XL, XLNet and XLM + +[pytz] +description=World Timezone Definitions for Python + +[pytzdata] +description=The Olson timezone database for Python. + +[PyUtilib] +description=PyUtilib: A collection of Python utilities + +[pyvisa] +description=Control all kinds of measurement equipment through various busses (GPIB, RS232, USB) + +[pyviz] +description=How to solve visualization problems with Python tools. + +[pyviz_comms] +description=Launch jobs, organize the output, and dissect the results + +[pywavelets] +description=Wavelet transforms module + +[pywin32] +description=Python library for Windows + +[pywin32_ctypes] +description=A (partial) reimplementation of pywin32 that is pure python (uses ctypes/cffi) + +[pywinpty] +description=Python bindings for the winpty library + +[pywinusb] +description=USB / HID windows helper library + +[pyyaml] +description=YAML parser and emitter for Python + +[pyzmq] +description=Lightweight and super-fast messaging based on ZeroMQ library (required for IPython Qt console) + +[pyzo] +description=the Python IDE for scientific computing + +[qdarkstyle] +description=A dark style sheet for QtWidgets application + +[qtawesome] +description=FontAwesome icons in PyQt and PySide applications + +[qtconsole] +description=Jupyter Qt console + +[qtpy] +description=Provides an abstraction layer on top of the various Qt bindings (PyQt5, PyQt4 and PySide) and additional custom QWidgets. + +[qscintilla] +description=Python bindings for the QScintilla programmers editor widget + +[quantecon] +description=A community based Python library for quantitative economics + +[quart] +description=A Python ASGI web microframework with the same API as Flask + +[quiver_engine] +description=Interactive per-layer visualization for convents in keras + +[radon] +description=Code Metrics in Python + +[rasterio] +description=Fast and direct raster I/O for use with Numpy and SciPy + +[readme_renderer] +description=a library for rendering "readme" descriptions for Warehouse + +[recommonmark] +description=A markdown parser for docutils + +[redis] +description=Python client for Redis key-value store + +[regex] +description=Alternative regular expression module, to replace re. + +[reportlab] +description=The PDF generation library + +[requests] +description=Requests is an Apache2 Licensed HTTP library, written in Python, for human beings. + +[requests_file] +description=File transport adapter for Requests + +[requests_ftp] +description=FTP Transport Adapter for Requests. + +[requests_threads] +description=Deferred Thread backend for Requests. + +[requests_toolbelt] +description=A utility belt for advanced users of python-requests + +[requests_oauthlib] +description=OAuthlib authentication support for Requests. + +[responder] +description=A sorta familiar HTTP framework. + +[rfc3986] +description=Validating URI References per RFC 3986 + +[rise] +description=Live Reveal.js Jupyter/IPython Slideshow Extension + +[rodeo] +description=an ide for data analysis in python + +[rope] +description=a python refactoring library... + +[rope_py3k] +description=a python refactoring library... + +[rpy2] +description=Python interface to the R language (embedded R) + +[rsa] +description=Pure-Python RSA implementation + +[rst2pdf] +description=Tool for transforming reStructuredText to PDF using ReportLab + +[rtree] +description=R-Tree spatial index for Python GIS + +[ruamel.yaml] +description=a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order + +[ruamel.yaml.clib] +description=C version of reader, parser and emitter for ruamel.yaml derived from libyaml + +[runipy] +description=Run IPython notebooks from the command line + +[rx] +description=Reactive Extensions (Rx) for Python + +[s3fs] +description=Convenient Filesystem interface over S3 + +[s3transfer] +description=An Amazon S3 Transfer Manager + +[sasl] +description=Cyrus-SASL bindings for Python + +[schemapi] +description=generate Python APIs from JSONSchema specifications + +[scidoc] +description=Scidoc installs scientific libraries documentation (NumPy, SciPy, ...) + +[scikits.audiolab] +description=Audio file I/O using NumPy arrays + +[scikits.timeseries] +description=Time series manipulation + +[scikit-fuzzy] +description=Fuzzy logic toolkit for SciPy + +[scikit-garden] +description=A garden for scikit-learn compatible trees + +[scikit-learn] +description=A set of Python modules for machine learning and data mining +category=scientific + +[scikit-image] +description=Image processing toolbox for SciPy +category=improc + +[scikit-neuralnetwork] +description=Deep neural networks without the learning cliff! A wrapper library compatible with scikit-learn. + +[scikit-optimize] +description=Sequential model-based optimization toolbox. + +[scilab2py] +description=Python to Scilab bridge + +[scilab_kernel] +description=A Scilab kernel for IPython + +[scipy] +description=SciPy: Scientific Library for Python (advanced math, signal processing, optimization, statistics, ...) + +[scrapy] +description=A high-level Python Screen Scraping framework + +[scs] +description=scs: splitting conic solver + +[seaborn] +description=statistical data visualization + +[semantic_version] +description=A library implementing the 'SemVer' scheme. + +[send2trash] +description=Send file to trash natively under Mac OS X, Windows and Linux. + +[service_identity] +description=Service identity verification for pyOpenSSL. + +[setuptools] +description=Download, build, install, upgrade, and uninstall Python packages - easily + +[setuptools_git] +description=Setuptools revision control system plugin for Git + +[sframe] +description=SFrame is an scalable, out-of-core dataframe, which allows you to work with datasets that are larger than the amount of RAM on your system. + +[sgp4] +description=Track earth satellite TLE orbits using up-to-date 2010 version of SGP4 + +[shapely] +description=Geometric objects, predicates, and operations + +[shiboken2] +description=Shiboken generates bindings for C++ libraries using CPython source code + +[simplegeneric] +description=Simple generic functions (similar to Python's own len(), pickle.dump(), etc.) + +[simplejson] +description=Simple, fast, extensible JSON (JavaScript Object Notation) encoder/decoder + +[simpy] +description=Event discrete, process based simulation for Python. + +[singledispatch] +description=This library brings functools.singledispatch from Python 3.4 to Python 2.6-3.3 + +[sip] +description=Python extension module generator for C and C++ libraries + +[six] +description=Python 2 and 3 compatibility utilities + +[sklearn-theano] +description=Scikit-learn compatible tools using theano + +[skll] +description=SciKit-Learn Laboratory makes it easier to run machinelearning experiments with scikit-learn. + +[skorch] +description=scikit-learn compatible neural network library for pytorch + +[skyfield] +description=Elegant astronomy for Python + +[smmap] +description=A pure python implementation of a sliding window memory map manager + +[smmap2] +description=A pure python implementation of a sliding window memory map manager + +[snakeviz] +description=An in-browser Python profile viewer + +[sniffio] +description=Sniff out which async library your code is running under + +[snowballstemmer] +description=This package provides 16 stemmer algorithms (15 + Poerter English stemmer) generated from Snowball algorithms. + +[snuggs] +description=Snuggs are s-expressions for Numpy + +[sortedcollections] +description=Python Sorted Collections + +[sortedcontainers] +description=Python Sorted Container Types: SortedList, SortedDict, and SortedSet + +[sounddevice] +description=Play and Record Sound with Python + +[soupsieve] +description=A CSS4 selector implementation for Beautiful Soup. + +[spacy] +description=Industrial-strength NLP + +[sparse] +description=sparse multidimensional arrays on top of NumPy and Scipy.sparse + +[sphinx] +description=Tool for generating documentation which uses reStructuredText as its markup language + +[sphinxcontrib_applehelp] +description=sphinx extension which outputs Apple help books + +[sphinxcontrib_devhelp] +description=sphinx extension which outputs Devhelp document + +[sphinxcontrib_htmlhelp] +description=sphinx extension which outputs html + +[sphinxcontrib_jsmath] +description=sphinx extension which renders display math in HTML via JavaScript + +[sphinxcontrib_qthelp] +description=sphinx extension which outputs QtHelp document + +[sphinxcontrib_websupport] +description=Sphinx API for Web Apps + +[sphinxcontrib_serializinghtml] +description=Sphinx API for Web Apps + +[sphinx_rtd_theme] +description=ReadTheDocs.org theme for Sphinx, 2013 version. + +[spyder] +description=The Scientific Python Development Environment: An IDE designed for interactive computing and data visualisation with a simple and intuitive user interface + +[spyder_kernels] +description=Jupyter kernels for the Spyder console + +[spyder_notebook] +description=Jupyter notebook integration with Spyder + +[spyder_reports] +description=Spyder plugin to render Markdown reports using Pweave as a backend + +[spyder_terminal] +description=Spyder plugin for displaying a virtual terminal (OS independent) inside the main Spyder window + +[spyder.line_profiler] +description=A plugin to run the Python line profiler from within the Spyder editor + +[spyder.memory_profiler] +description=A plugin to run the Python memory_profiler from within the Spyder editor + +[spyder.autopep8] +description=A plugin to run the autopep8 Python linter from within the Spyder editor + +[sqlalchemy] +description=SQL Toolkit and Object Relational Mapper + +[sqlite_bro] +description=a graphic SQLite Client in 1 Python file + +[sqlite_web] +description=Web-based SQLite database browser written in Python + +[sqlparse] +description=Non-validating SQL parser + +[starlette] +description=The little ASGI library that shines. + +[statsmodels] +description=Statistical computations and models for use with SciPy + +[stormhttp] +description=Performant asynchronous web application framework. + +[streamz] +description=Streams + +[supersmoother] +description=Python implementation of Friedman's Supersmoother + +[swifter] +description=efficiently applies any function to a pandas dataframe or series in the fastest available manner + +[sympy] +description=Symbolic Mathematics Library + +[tables] +description=Package based on HDF5 library for managing hierarchical datasets (extremely large amounts of data) + +[tabulate] +description=Pretty-print tabular data + +[tblib] +description=Traceback serialization library. + +[tb_nightly] +description=TensorBoard lets you watch Tensors Flow + +[tenacity] +description=Retry code until it succeeeds + +[tensorboard] +description=TensorBoard lets you watch Tensors Flow + +[tensorflow] +description=TensorFlow is an open source machine learning framework for everyone. + +[tensorflow_cpu] +description=TensorFlow is an open source machine learning framework for everyone. + +[tensorflow_estimator] +description=TensorFlow Estimator. + +[tensorflow-probability] +description=Probabilistic modeling and statistical inference in TensorFlow + +[tensorflow-tensorboard] +description=TensorBoard lets you watch Tensors Flow + +[termcolor] +description=ANSII Color formatting for output in terminal + +[terminado] +description=Terminals served to term.js using Tornado websockets + +[testfixtures] +description= a collection of helpers and mock objects that are useful when writing unit tests or doc tests. + +[testpath] +description=Test utilities for code working with files and commands + +[textwrap3] +description=textwrap from Python 3.6 backport (plus a few tweaks) + +[tf_estimator_nightly] +description=TensorFlow Estimator. + +[thinc] +description=Practical Machine Learning for NLP + +[theano] +description=Optimizing compiler for evaluating mathematical expressions on CPUs and GPUs. + +[thrift] +description= a software framework for scalable cross-language services development + +[thriftpy] +description=Pure python implementation of Apache Thrift. + +[thrift-sasl] +description=hrift SASL Python module that implements SASL transports for Thrift + +[toml] +description=Python Library for Tom's Obvious, Minimal Language + +[toolz] +description=List processing tools and functional utilities + +[torch] +description=a deep learning framework. + +[torchfile] +description=Torch7 binary serialized file parser + +[torchvision] +description=Datasets, Transforms and Models specific to Computer Vision + +[tornado] +description=Scalable, non-blocking web server and tools (required for IPython notebook) + +[tpot] +description=A Python tool that automatically creates and optimizes machine learning pipelines using genetic programming. + +[tqdm] +description=A Simple Python Progress Meter + +[traitlets] +description=Traitlets Python config system + +[traits] +description=Enthought explicitly typed attributes for Python + +[traitsui] +description=Enthought traits-capable user interfaces + +[traittypes] +description=Scipy trait types + +[trio] +description=An async/await-native I/O library for humans and snake people + +[trio_asyncio] +description=a re-implementation of the asyncio mainloop on top of Trio + +[ttfquery] +description=FontTools-based package for querying system fonts + +[tweepy] +description=Twitter library for python + +[twine] +description=Collection of utilities for interacting with PyPI + +[twisted] +description=Event-driven networking engine written in Python + +[twitter] +description=An API and command-line toolset for Twitter (twitter.com) + +[twython] +description=Actively maintained, pure Python wrapper for the Twitter API. Supports both normal and streaming Twitter APIs + +[typed_ast] +description=a fork of Python 2 and 3 ast modules with type comment support + +[typing] +description=Type Hints for Python + +[typing_extensions] +description=Backported and Experimental Type Hints for Python 3.5+ + +[tzlocal] +description=tzinfo object for the local timezone + +[uarray] +description=Universal array library + +[uncertainties] +description=Transparent calculations with uncertainties on the quantities involved (aka error propagation); fast calculation of derivatives + +[uritemplate] +description=URI templates + +[urllib3] +description=HTTP library with thread-safe connection pooling, file post, and more. + +[usjon] +description=Ultra fast JSON encoder and decoder for Python + +[uvicorn] +description=The lightning-fast ASGI server. + +[uvloop] +description=Fast implementation of asyncio event loop on top of libuv + +[vectormath] +description=vector math utilities for Python + +[vega] +description=An IPython/ Jupyter widget for Vega and Vega-Lite + +[vega_datasets] +description=A Python package for offline access to Vega datasets + +[vega3] +description=An IPython/ Jupyter widget for Vega 3 and Vega-Lite 2 + +[verboselogs] +description=Verbose logging level for Python's logging module + +[vispy] +description=Interactive visualization in Python + +[visdom] +description=A tool for visualizing live, rich data for Torch and Numpy + +[vitables] +description=Graphical tool for browsing and editing files in both HDF5 and PyTables formats + +[voila] +description=Serving read-only live Jupyter notebooks + +[voila-vuetify] +description=A vuetify template for voila + +[vpython] +description=A free, open-source module for producing real-time 3D scenes with Python + +[vtk] +description=Open-source software system for visualization, 3D graphics, volume rendering and image processing + +[watchdog] +description=Filesystem events monitoring + +[wcwidth] +description=Measures number of Terminal column cells of wide-character codes + +[webencodings] +description=Character encoding aliases for legacy web content + +[websockets] +description=An (asyncio) implementation of the WebSocket Protocol (RFC 6455 & 7692) + +[werkzeug] +description=The Swiss Army knife of Python web development + +[wheel] +description=A built-package format for Python. + +[wheelhouse-uploader] +description=Upload wheels to any cloud storage supported by Libcloud + +[whitenoise] +description=Radically simplified static file serving for WSGI applications + +[whichcraft] +description=cross-platform cross-python shutil.which functionality. + +[whoosh] +description=Fast, pure-Python full text indexing, search, and spell checking library. + +[widgetsnbextension] +description=IPython HTML widgets for Jupyter + +[winpython] +description=WinPython distribution tools, including WPPM (package manager) +url=http://winpython.github.io/ + +[winrt] +description=Access Windows Runtime APIs from Python + +[win-unicode-console] +description=Enable Unicode input and display when running Python from Windows console. + +[wordcloud] +description=A little word cloud generator + +[wpca] +description=Weighted Principal Component Analysis + +[wrapt] +description=A Python module for decorators, wrappers and monkey patching. + +[wsgiref] +description=WSGI (PEP 333) Reference Library + +[wsproto] +description=WebSockets state-machine based protocol implementation + +[w3lib] +description=Library of web-related functions + +[xarray] +description=N-D labeled arrays and datasets in Python + +[xlrd] +description=Extract data from Microsoft Excel spreadsheet files + +[xlsxwriter] +description=A Python module for creating Excel XLSX files. + +[xlwings] +description=Interact with Excel from Python and vice versa + +[xlwt] +description=Create spreadsheet files compatible with Microsoft Excel 97/2000/XP/2003 files, OpenOffice.org Calc, and Gnumeric + +[xnd] +description=General container that maps a wide range of Python values directly to memory + +[xonsh] +description=an exotic, usable shell + +[xray] +description=N-D labeled arrays and datasets in Python + +[yapf] +description=A formatter for Python code. + +[zarr] +description=A minimal implementation of chunked, compressed, N-dimensional arrays for Python. + +[zict] +description=Mutable mapping tools + +[zipp] +description=Backport of pathlib-compatible object wrapper for zip files + +[z3_solver] +description=an efficient SMT solver library + + diff --git a/build/lib/winpython/data/tools.ini b/build/lib/winpython/data/tools.ini new file mode 100644 index 00000000..78b2d052 --- /dev/null +++ b/build/lib/winpython/data/tools.ini @@ -0,0 +1,47 @@ +[gettext] +description=GNU gettext Win32 porting - the GNU translation tool (useful tools for pygettext, a standard library module) +url=https://sourceforge.net/projects/gettext + +[julia] +description=The Julia Langage +url=https://julialang.org/ + +[mingw32] +description=C/C++ and Fortran compilers (Mingwpy static toolchain version) +url=https://github.com/numpy/numpy/wiki/Mingw-static-toolchain + +[pandoc] +description=a universal document converter +url=https://pandoc.org/ + +[r] +description=The R Project for Statistical Computing +url=https://www.r-project.org + +[scite] +description=SCIntilla based Text Editor - Multilanguage, powerful and light-weight text editor +url=http://www.scintilla.org/SciTE.html + +[tortoisehg] +description=Set of graphical tools and a shell extension for the Mercurial distributed revision control system +url=https://tortoisehg.bitbucket.io/ + +[winmerge] +description=Open Source differencing and merging tool for Windows +url=http://winmerge.org + +[nodejs] +description=a JavaScript runtime built on Chrome's V8 JavaScript engine +url=https://nodejs.org + +[npmjs] +description=a package manager for JavaScript +url=https://www.npmjs.com/ + +[yarnpkg] +description=a package manager for JavaScriptFast, reliable, and secure dependency management +url=https://yarnpkg.com/lang/en/ + +[ffmpeg] +description=a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata +url=https://ffmpeg.org diff --git a/build/lib/winpython/disthelpers.py b/build/lib/winpython/disthelpers.py new file mode 100644 index 00000000..ae198c7f --- /dev/null +++ b/build/lib/winpython/disthelpers.py @@ -0,0 +1,1130 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009-2011 CEA +# Pierre Raybaut +# Licensed under the terms of the CECILL License +# (see guidata/__init__.py for details) + +# pylint: disable=W0613 + +""" +disthelpers +----------- + +The ``guidata.disthelpers`` module provides helper functions for Python +package distribution on Microsoft Windows platforms with ``py2exe`` or on +all platforms thanks to ``cx_Freeze``. +""" + +from __future__ import print_function + +import sys +import os +import os.path as osp +import shutil +import traceback +import atexit +import imp +from subprocess import Popen, PIPE +import warnings + +# ============================================================================== +# Module, scripts, programs +# ============================================================================== +def get_module_path(modname): + """Return module *modname* base path""" + module = sys.modules.get(modname, __import__(modname)) + return osp.abspath(osp.dirname(module.__file__)) + + +# ============================================================================== +# Dependency management +# ============================================================================== +def get_changeset(path, rev=None): + """Return Mercurial repository *path* revision number""" + args = ['hg', 'parent'] + if rev is not None: + args += ['--rev', str(rev)] + process = Popen( + args, stdout=PIPE, stderr=PIPE, cwd=path, shell=True + ) + try: + return ( + process.stdout.read().splitlines()[0].split()[1] + ) + except IndexError: + raise RuntimeError(process.stderr.read()) + + +def prepend_module_to_path(module_path): + """ + Prepend to sys.path module located in *module_path* + Return string with module infos: name, revision, changeset + + Use this function: + 1) In your application to import local frozen copies of internal libraries + 2) In your py2exe distributed package to add a text file containing the returned string + """ + if not osp.isdir(module_path): + # Assuming py2exe distribution + return + sys.path.insert(0, osp.abspath(module_path)) + changeset = get_changeset(module_path) + name = osp.basename(module_path) + prefix = "Prepending module to sys.path" + message = prefix + ( + "%s [revision %s]" % (name, changeset) + ).rjust(80 - len(prefix), ".") + print(message, file=sys.stderr) + if name in sys.modules: + sys.modules.pop(name) + nbsp = 0 + for modname in sys.modules.keys(): + if modname.startswith(name + '.'): + sys.modules.pop(modname) + nbsp += 1 + warning = '(removed %s from sys.modules' % name + if nbsp: + warning += ' and %d subpackages' % nbsp + warning += ')' + print(warning.rjust(80), file=sys.stderr) + return message + + +def prepend_modules_to_path(module_base_path): + """Prepend to sys.path all modules located in *module_base_path*""" + if not osp.isdir(module_base_path): + # Assuming py2exe distribution + return + fnames = [ + osp.join(module_base_path, name) + for name in os.listdir(module_base_path) + ] + messages = [ + prepend_module_to_path(dirname) + for dirname in fnames + if osp.isdir(dirname) + ] + return os.linesep.join(messages) + + +# ============================================================================== +# Distribution helpers +# ============================================================================== +def _remove_later(fname): + """Try to remove file later (at exit)""" + + def try_to_remove(fname): + if osp.exists(fname): + os.remove(fname) + + atexit.register(try_to_remove, osp.abspath(fname)) + + +def get_msvc_version(python_version): + """Return Microsoft Visual C++ version used to build this Python version""" + if python_version is None: + python_version = '2.7' + warnings.warn("assuming Python 2.7 target") + if python_version in ( + '2.6', + '2.7', + '3.0', + '3.1', + '3.2', + ): + # Python 2.6-2.7, 3.0-3.2 were built with Visual Studio 9.0.21022.8 + # (i.e. Visual C++ 2008, not Visual C++ 2008 SP1!) + return "9.0.21022.8" + elif python_version in ('3.3', '3.4'): + # Python 3.3+ were built with Visual Studio 10.0.30319.1 + # (i.e. Visual C++ 2010) + return '10.0' + elif python_version in ('3.5', '3.6'): + return '15.0' + elif python_version in ('3.7', '3.8'): + return '15.0' + else: + raise RuntimeError( + "Unsupported Python version %s" % python_version + ) + + +def get_msvc_dlls(msvc_version, architecture=None): + """Get the list of Microsoft Visual C++ DLLs associated to + architecture and Python version, create the manifest file. + + architecture: integer (32 or 64) -- if None, take the Python build arch + python_version: X.Y""" + current_architecture = ( + 64 if sys.maxsize > 2 ** 32 else 32 + ) + if architecture is None: + architecture = current_architecture + filelist = [] + + # simple vs2015 situation: nothing (system dll) + if msvc_version == '14.0': + return filelist + msvc_major = msvc_version.split('.')[0] + msvc_minor = msvc_version.split('.')[1] + + if msvc_major == '9': + key = "1fc8b3b9a1e18e3b" + atype = "" if architecture == 64 else "win32" + arch = "amd64" if architecture == 64 else "x86" + + groups = { + 'CRT': ( + 'msvcr90.dll', + 'msvcp90.dll', + 'msvcm90.dll', + ), + # 'OPENMP': ('vcomp90.dll',) + } + + for group, dll_list in groups.items(): + dlls = '' + for dll in dll_list: + dlls += ' %s' % ( + dll, + os.linesep, + ) + manifest = """ + + + + +%(dlls)s +""" % dict( + version=msvc_version, + key=key, + atype=atype, + arch=arch, + group=group, + dlls=dlls, + ) + + vc90man = "Microsoft.VC90.%s.manifest" % group + open(vc90man, 'w').write(manifest) + _remove_later(vc90man) + filelist += [vc90man] + + winsxs = osp.join( + os.environ['windir'], 'WinSxS' + ) + vcstr = '%s_Microsoft.VC90.%s_%s_%s' % ( + arch, + group, + key, + msvc_version, + ) + for fname in os.listdir(winsxs): + path = osp.join(winsxs, fname) + if osp.isdir( + path + ) and fname.lower().startswith( + vcstr.lower() + ): + for dllname in os.listdir(path): + filelist.append( + osp.join(path, dllname) + ) + break + else: + raise RuntimeError( + "Microsoft Visual C++ %s DLLs version %s " + "were not found" % (group, msvc_version) + ) + elif ( + msvc_major == '10' or msvc_major == '15' + ): # 15 for vs 2015 + namelist = [ + name % (msvc_major + msvc_minor) + for name in ( + 'msvcp%s.dll', + 'msvcr%s.dll', + 'vcomp%s.dll', + ) + ] + if msvc_major == '15': + namelist = [ + name % ('14' + msvc_minor) + for name in ( + 'vcruntime%s.dll', + 'msvcp%s.dll', + 'vccorlib%s.dll', + 'concrt%s.dll', + 'vcomp%s.dll', + ) + ] + windir = os.environ['windir'] + is_64bit_windows = osp.isdir( + osp.join(windir, "SysWOW64") + ) + + # Reminder: WoW64 (*W*indows 32-bit *o*n *W*indows *64*-bit) is a + # subsystem of the Windows operating system capable of running 32-bit + # applications and is included on all 64-bit versions of Windows + # (source: http://en.wikipedia.org/wiki/WoW64) + # + # In other words, "SysWOW64" contains 64-bit DLL and applications, + # whereas "System32" contains 64-bit DLL and applications on a 64-bit + # system. + sysdir = "System32" + if not is_64bit_windows and architecture == 64: + raise RuntimeError( + "Can't find 64-bit MSVC DLLs on a 32-bit OS" + ) + if is_64bit_windows and architecture == 32: + sysdir = "SysWOW64" + for dllname in namelist: + fname = osp.join(windir, sysdir, dllname) + print('searching', fname) + if osp.exists(fname): + filelist.append(fname) + else: + raise RuntimeError( + "Microsoft Visual C++ DLLs version %s " + "were not found" % msvc_version + ) + else: + raise RuntimeError( + "Unsupported MSVC version %s" % msvc_version + ) + return filelist + + +def create_msvc_data_files( + architecture=None, python_version=None, verbose=False +): + """Including Microsoft Visual C++ DLLs""" + msvc_version = get_msvc_version(python_version) + filelist = get_msvc_dlls( + msvc_version, architecture=architecture + ) + print(create_msvc_data_files.__doc__) + if verbose: + for name in filelist: + print(" ", name) + msvc_major = msvc_version.split('.')[0] + if msvc_major == '9': + return [("Microsoft.VC90.CRT", filelist)] + else: + return [("", filelist)] + + +def to_include_files(data_files): + """Convert data_files list to include_files list + + data_files: + * this is the ``py2exe`` data files format + * list of tuples (dest_dirname, (src_fname1, src_fname2, ...)) + + include_files: + * this is the ``cx_Freeze`` data files format + * list of tuples ((src_fname1, dst_fname1), + (src_fname2, dst_fname2), ...)) + """ + include_files = [] + for dest_dir, fnames in data_files: + for source_fname in fnames: + dest_fname = osp.join( + dest_dir, osp.basename(source_fname) + ) + include_files.append((source_fname, dest_fname)) + return include_files + + +def strip_version(version): + """Return version number with digits only + (Windows does not support strings in version numbers)""" + return ( + version.split('beta')[0] + .split('alpha')[0] + .split('rc')[0] + .split('dev')[0] + ) + + +def remove_dir(dirname): + """Remove directory *dirname* and all its contents + Print details about the operation (progress, success/failure)""" + print("Removing directory '%s'..." % dirname, end=' ') + try: + shutil.rmtree(dirname, ignore_errors=True) + print("OK") + except Exception: + print("Failed!") + traceback.print_exc() + + +class Distribution(object): + """Distribution object + + Help creating an executable using ``py2exe`` or ``cx_Freeze`` + """ + + DEFAULT_EXCLUDES = [ + 'Tkconstants', + 'Tkinter', + 'tcl', + 'tk', + 'wx', + '_imagingtk', + 'curses', + 'PIL._imagingtk', + 'ImageTk', + 'PIL.ImageTk', + 'FixTk', + 'bsddb', + 'email', + 'pywin.debugger', + 'pywin.debugger.dbgcon', + 'matplotlib', + ] + DEFAULT_INCLUDES = [] + DEFAULT_BIN_EXCLUDES = [ + 'MSVCP100.dll', + 'MSVCP90.dll', + 'w9xpopen.exe', + 'MSVCP80.dll', + 'MSVCR80.dll', + ] + DEFAULT_BIN_INCLUDES = [] + DEFAULT_BIN_PATH_INCLUDES = [] + DEFAULT_BIN_PATH_EXCLUDES = [] + + def __init__(self): + self.name = None + self.version = None + self.description = None + self.target_name = None + self._target_dir = None + self.icon = None + self.data_files = [] + self.includes = self.DEFAULT_INCLUDES + self.excludes = self.DEFAULT_EXCLUDES + self.bin_includes = self.DEFAULT_BIN_INCLUDES + self.bin_excludes = self.DEFAULT_BIN_EXCLUDES + self.bin_path_includes = ( + self.DEFAULT_BIN_PATH_INCLUDES + ) + self.bin_path_excludes = ( + self.DEFAULT_BIN_PATH_EXCLUDES + ) + self.msvc = os.name == 'nt' + self._py2exe_is_loaded = False + self._pyqt4_added = False + self._pyside_added = False + # Attributes relative to cx_Freeze: + self.executables = [] + + @property + def target_dir(self): + """Return target directory (default: 'dist')""" + dirname = self._target_dir + if dirname is None: + return 'dist' + else: + return dirname + + @target_dir.setter # analysis:ignore + def target_dir(self, value): + self._target_dir = value + + def setup( + self, + name, + version, + description, + script, + target_name=None, + target_dir=None, + icon=None, + data_files=None, + includes=None, + excludes=None, + bin_includes=None, + bin_excludes=None, + bin_path_includes=None, + bin_path_excludes=None, + msvc=None, + ): + """Setup distribution object + + Notes: + * bin_path_excludes is specific to cx_Freeze (ignored if it's None) + * if msvc is None, it's set to True by default on Windows + platforms, False on non-Windows platforms + """ + self.name = name + self.version = ( + strip_version(version) + if os.name == 'nt' + else version + ) + self.description = description + assert osp.isfile(script) + self.script = script + self.target_name = target_name + self.target_dir = target_dir + self.icon = icon + if data_files is not None: + self.data_files += data_files + if includes is not None: + self.includes += includes + if excludes is not None: + self.excludes += excludes + if bin_includes is not None: + self.bin_includes += bin_includes + if bin_excludes is not None: + self.bin_excludes += bin_excludes + if bin_path_includes is not None: + self.bin_path_includes += bin_path_includes + if bin_path_excludes is not None: + self.bin_path_excludes += bin_path_excludes + if msvc is not None: + self.msvc = msvc + if self.msvc: + try: + self.data_files += create_msvc_data_files() + except IOError: + print( + "Setting the msvc option to False " + "will avoid this error", + file=sys.stderr, + ) + raise + # cx_Freeze: + self.add_executable( + self.script, self.target_name, icon=self.icon + ) + + def add_text_data_file(self, filename, contents): + """Create temporary data file *filename* with *contents* + and add it to *data_files*""" + open(filename, 'wb').write(contents) + self.data_files += [("", (filename,))] + _remove_later(filename) + + def add_data_file(self, filename, destdir=''): + self.data_files += [(destdir, (filename,))] + + # ------ Adding packages + def add_pyqt4(self): + """Include module PyQt4 to the distribution""" + if self._pyqt4_added: + return + self._pyqt4_added = True + + self.includes += [ + 'sip', + 'PyQt4.Qt', + 'PyQt4.QtSvg', + 'PyQt4.QtNetwork', + ] + + import PyQt4 + + pyqt_path = osp.dirname(PyQt4.__file__) + + # Configuring PyQt4 + conf = os.linesep.join( + ["[Paths]", "Prefix = .", "Binaries = ."] + ) + self.add_text_data_file('qt.conf', conf) + + # Including plugins (.svg icons support, QtDesigner support, ...) + if self.msvc: + vc90man = "Microsoft.VC90.CRT.manifest" + pyqt_tmp = 'pyqt_tmp' + if osp.isdir(pyqt_tmp): + shutil.rmtree(pyqt_tmp) + os.mkdir(pyqt_tmp) + vc90man_pyqt = osp.join(pyqt_tmp, vc90man) + man = ( + open(vc90man, "r") + .read() + .replace( + '288*EP)cTWZLpIi`K$!zW1(i|?g@Tv9-ImfzxxKHy_up@Sbc{{rfAjqH321UGepL({|G*M~cRc zGsiZO6$K$Fh|du6JQsoh#N-WGR&D|U-)HPf65j(|S5;XS-|Rd6k5}}HIFX7egu-P= zlFaw+Yig8bSs56(a{j=XE50O6zOZc?Abdb#@vQ2EB#Z0^LwO7Sl>^5z7)vE7WJVdi zUK|KV!e83@=sL+LWwFfy54Ox{df>}-?S*{tOtDZp?YiEHyX#~3TBQPJaRS#ia4eJc ziyK=k&tEf=G2I)HNdTr%Ak}x7OXoV-`pgD*B3C-AN3@@AUiXl^vZeVh+wuMy(bZ)F zw4sq}O5Su^%4@3kKCt-ChmCxeVm8f|wM)wl%h{GGI>$af-{ai?$g{MobiDf}k39Wz zK5TCVMd85Ft_zp1n@j6z;%jHl{lczfGF3gEDPh|-*NZNGI7)fEI#O0WW8EKqyVH65 zjXze%lGt&!Z|uF+gMWL+aSBw`%$fvbk{89Hqutu<8r3r#m&(9m&5C;*@!|3DXJ=-g zo4aaF)%qPTAdIW@ocjdJcFEZ;K42>nPtJ%eztWp(-*+*6B%+Ac(hvpi*GA%hEv3^c9^~DlNO{S%J7O#Fh*uFbu z4w1`;#`4a0CT!mXP;A%5HZ8uj{EH)7zdHRTGm>CRck4%D_%u$w$Zz&#d1yK;ii|O} ze~iUpxU1U5Pml5Dc))i@EV`zZv!Wr^@Pp$c80%V9w**N&KS6?~Z4gRtqy0L3tEv!;rOoN)vFqD`=F#xR#^wYqMu;nj4w8bM?K& zjlbA?vyyYy#&A7{p@A#mYaaJ&C3WRvhN03sjwayT5>QJ}N`v7-&KFdgkT3bn3~3x} zu0kpcgC+|v5`OFOf%cVtk(~UPr7J-qng)5qUPJ?xltSw z6bJG}@NBSh;09p&VB1iP2Kc^DDDV&=jp1>le!Q;!LG-r=?*f4?xeZ?|&j=;3Rg??51sWCiv9rJ2zPIo~E87NGecJeY97u)zUrS>pMe z#lw{<^K=D07Qr)ZMy$Xqxxw~>rv|G-s%Tb)xI<}Juw*hD!%4s;IQCKgwt9pSA{#;1Xc$d45Z>JQh#J6SX(n zHMI>CGFPz;g`+w4tdhktTNPaOBzkQ~ND_f2u!Df6st_+#MQNI%NqQ zGl08x^Uho60YF%fq6(k$rJ!wkSQ?x!g8J728$GJvC=yZ-U|T+VJWNYmLrz4A)lZ?X zXUP72=k>ot1l^}TXbb*R^S?%Bpeh7Ph~0h3!XZ0&W;i6=SX{%a)R3oyP+}UICZW_s zk!oYa5*6f!uJWU|E*u(jY3m!fkZD}Fg3kmfijJg&ko5>J^mOijal-vsj~AF_WeOEj zbd)j`O%p_;GBL>`b$-Bk`ico>kXI=mR002ovPDHLk FV1ffvF8lxh literal 0 HcmV?d00001 diff --git a/build/lib/winpython/images/winpython.svg b/build/lib/winpython/images/winpython.svg new file mode 100644 index 00000000..c562c014 --- /dev/null +++ b/build/lib/winpython/images/winpython.svg @@ -0,0 +1,444 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/lib/winpython/py3compat.py b/build/lib/winpython/py3compat.py new file mode 100644 index 00000000..86578981 --- /dev/null +++ b/build/lib/winpython/py3compat.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012-2013 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see spyderlib/__init__.py for details) + +""" +spyderlib.py3compat +------------------- + +Transitional module providing compatibility functions intended to help +migrating from Python 2 to Python 3. + +This module should be fully compatible with: + * Python >=v2.6 + * Python 3 +""" + +from __future__ import print_function + +import sys +import os + +PY2 = sys.version[0] == '2' +PY3 = sys.version[0] == '3' + + +# ============================================================================== +# Data types +# ============================================================================== +if PY2: + # Python 2 + TEXT_TYPES = (str, unicode) + INT_TYPES = (int, long) +else: + # Python 3 + TEXT_TYPES = (str,) + INT_TYPES = (int,) +NUMERIC_TYPES = tuple(list(INT_TYPES) + [float, complex]) + + +# ============================================================================== +# Renamed/Reorganized modules +# ============================================================================== +if PY2: + # Python 2 + import __builtin__ as builtins + import ConfigParser as configparser + + try: + import _winreg as winreg + except ImportError: + pass + from sys import maxint as maxsize + + try: + import CStringIO as io + except ImportError: + import StringIO as io + try: + import cPickle as pickle + except ImportError: + import pickle + from UserDict import DictMixin as MutableMapping + import thread as _thread + import repr as reprlib +else: + # Python 3 + import builtins + import configparser + + try: + import winreg + except ImportError: + pass + from sys import maxsize + import io + import pickle + from collections import MutableMapping + import _thread + import reprlib +# ============================================================================== +# Strings +# ============================================================================== +if PY2: + # Python 2 + import codecs + + def u(obj): + """Make unicode object""" + return codecs.unicode_escape_decode(obj)[0] + + +else: + # Python 3 + def u(obj): + """Return string as it is""" + return obj + + +def is_text_string(obj): + """Return True if `obj` is a text string, False if it is anything else, + like binary data (Python 3) or QString (Python 2, PyQt API #1)""" + if PY2: + # Python 2 + return isinstance(obj, basestring) + else: + # Python 3 + return isinstance(obj, str) + + +def is_binary_string(obj): + """Return True if `obj` is a binary string, False if it is anything else""" + if PY2: + # Python 2 + return isinstance(obj, str) + else: + # Python 3 + return isinstance(obj, bytes) + + +def is_string(obj): + """Return True if `obj` is a text or binary Python string object, + False if it is anything else, like a QString (Python 2, PyQt API #1)""" + return is_text_string(obj) or is_binary_string(obj) + + +def is_unicode(obj): + """Return True if `obj` is unicode""" + if PY2: + # Python 2 + return isinstance(obj, unicode) + else: + # Python 3 + return isinstance(obj, str) + + +def to_text_string(obj, encoding=None): + """Convert `obj` to (unicode) text string""" + if PY2: + # Python 2 + if encoding is None: + return unicode(obj) + else: + return unicode(obj, encoding) + else: + # Python 3 + if encoding is None: + return str(obj) + elif isinstance(obj, str): + # In case this function is not used properly, this could happen + return obj + else: + return str(obj, encoding) + + +def to_binary_string(obj, encoding=None): + """Convert `obj` to binary string (bytes in Python 3, str in Python 2)""" + if PY2: + # Python 2 + if encoding is None: + return str(obj) + else: + return obj.encode(encoding) + else: + # Python 3 + return bytes( + obj, 'utf-8' if encoding is None else encoding + ) + + +# ============================================================================== +# Function attributes +# ============================================================================== +def get_func_code(func): + """Return function code object""" + if PY2: + # Python 2 + return func.func_code + else: + # Python 3 + return func.__code__ + + +def get_func_name(func): + """Return function name""" + if PY2: + # Python 2 + return func.func_name + else: + # Python 3 + return func.__name__ + + +def get_func_defaults(func): + """Return function default argument values""" + if PY2: + # Python 2 + return func.func_defaults + else: + # Python 3 + return func.__defaults__ + + +# ============================================================================== +# Special method attributes +# ============================================================================== +def get_meth_func(obj): + """Return method function object""" + if PY2: + # Python 2 + return obj.im_func + else: + # Python 3 + return obj.__func__ + + +def get_meth_class_inst(obj): + """Return method class instance""" + if PY2: + # Python 2 + return obj.im_self + else: + # Python 3 + return obj.__self__ + + +def get_meth_class(obj): + """Return method class""" + if PY2: + # Python 2 + return obj.im_class + else: + # Python 3 + return obj.__self__.__class__ + + +# ============================================================================== +# Misc. +# ============================================================================== +if PY2: + # Python 2 + input = raw_input + getcwd = os.getcwdu + cmp = cmp + import string + + str_lower = string.lower + from itertools import izip_longest as zip_longest +else: + # Python 3 + input = input + getcwd = os.getcwd + + def cmp(a, b): + return (a > b) - (a < b) + + str_lower = str.lower + from itertools import zip_longest + + +def qbytearray_to_str(qba): + """Convert QByteArray object to str in a way compatible with Python 2/3""" + return str(bytes(qba.toHex().data()).decode()) + + +if __name__ == '__main__': + pass diff --git a/build/lib/winpython/qthelpers.py b/build/lib/winpython/qthelpers.py new file mode 100644 index 00000000..a16a2505 --- /dev/null +++ b/build/lib/winpython/qthelpers.py @@ -0,0 +1,300 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009-2011 Pierre Raybaut +# Licensed under the terms of the MIT License +# (copied from Spyder source code [spyderlib.qt]) +# +# Qt5 migration would not have been possible without +# 2014-2015 Spyder Development Team work +# (MIT License too, same parent project) + +"""Qt utilities""" + +# winpython.qt becomes winpython._vendor.qtpy +from winpython._vendor.qtpy.QtWidgets import ( + QAction, + QStyle, + QWidget, + QApplication, + QLabel, + QVBoxLayout, + QHBoxLayout, + QLineEdit, + QMenu, + QToolButton, +) + +from winpython._vendor.qtpy.QtGui import ( + QIcon, + QKeyEvent, + QKeySequence, + QPixmap, +) + +from winpython._vendor.qtpy.QtCore import ( + Signal, + QObject, + Qt, + QLocale, + QTranslator, + QLibraryInfo, + QEvent, + Slot, +) +from winpython._vendor.qtpy.compat import ( + to_qvariant, + from_qvariant, +) + +import os +import re +import os.path as osp +import sys + +# Local import +from winpython import config +from winpython.py3compat import ( + is_text_string, + to_text_string, +) + + +def get_icon(name): + """Return QIcon from icon name""" + return QIcon(osp.join(config.IMAGE_PATH, name)) + + +class MacApplication(QApplication): + """Subclass to be able to open external files with our Mac app""" + + open_external_file = Signal(str) + + def __init__(self, *args): + QApplication.__init__(self, *args) + + def event(self, event): + if event.type() == QEvent.FileOpen: + fname = str(event.file()) + # PyQt4 old SIGNAL: self.emit(SIGNAL('open_external_file(QString)'), fname) + self.open_external_file.emit(fname) + return QApplication.event(self, event) + + +def qapplication(translate=True): + """Return QApplication instance + Creates it if it doesn't already exist""" + if ( + sys.platform == "darwin" + and 'Spyder.app' in __file__ + ): + SpyderApplication = MacApplication + else: + SpyderApplication = QApplication + app = SpyderApplication.instance() + if not app: + # Set Application name for Gnome 3 + # https://groups.google.com/forum/#!topic/pyside/24qxvwfrRDs + app = SpyderApplication(['Spyder']) + if translate: + install_translator(app) + return app + + +def file_uri(fname): + """Select the right file uri scheme according to the operating system""" + if os.name == 'nt': + # Local file + if re.search(r'^[a-zA-Z]:', fname): + return 'file:///' + fname + # UNC based path + else: + return 'file://' + fname + else: + return 'file://' + fname + + +QT_TRANSLATOR = None + + +def install_translator(qapp): + """Install Qt translator to the QApplication instance""" + global QT_TRANSLATOR + if QT_TRANSLATOR is None: + qt_translator = QTranslator() + if qt_translator.load( + "qt_" + QLocale.system().name(), + QLibraryInfo.location( + QLibraryInfo.TranslationsPath + ), + ): + QT_TRANSLATOR = ( + qt_translator + ) # Keep reference alive + if QT_TRANSLATOR is not None: + qapp.installTranslator(QT_TRANSLATOR) + + +def keybinding(attr): + """Return keybinding""" + ks = getattr(QKeySequence, attr) + return from_qvariant( + QKeySequence.keyBindings(ks)[0], str + ) + + +def _process_mime_path(path, extlist): + if path.startswith(r"file://"): + if os.name == 'nt': + # On Windows platforms, a local path reads: file:///c:/... + # and a UNC based path reads like: file://server/share + if path.startswith( + r"file:///" + ): # this is a local path + path = path[8:] + else: # this is a unc path + path = path[5:] + else: + path = path[7:] + if osp.exists(path): + if ( + extlist is None + or osp.splitext(path)[1] in extlist + ): + return path + + +def mimedata2url(source, extlist=None): + """ + Extract url list from MIME data + extlist: for example ('.py', '.pyw') + """ + pathlist = [] + if source.hasUrls(): + for url in source.urls(): + path = _process_mime_path( + to_text_string(url.toString()), extlist + ) + if path is not None: + pathlist.append(path) + elif source.hasText(): + for rawpath in to_text_string( + source.text() + ).splitlines(): + path = _process_mime_path(rawpath, extlist) + if path is not None: + pathlist.append(path) + if pathlist: + return pathlist + + +def action2button( + action, + autoraise=True, + text_beside_icon=False, + parent=None, +): + """Create a QToolButton directly from a QAction object""" + if parent is None: + parent = action.parent() + button = QToolButton(parent) + button.setDefaultAction(action) + button.setAutoRaise(autoraise) + if text_beside_icon: + button.setToolButtonStyle( + Qt.ToolButtonTextBesideIcon + ) + return button + + +def toggle_actions(actions, enable): + """Enable/disable actions""" + if actions is not None: + for action in actions: + if action is not None: + action.setEnabled(enable) + + +def create_action( + parent, + text, + shortcut=None, + icon=None, + tip=None, + toggled=None, + triggered=None, + data=None, + menurole=None, + context=Qt.WindowShortcut, +): + """Create a QAction""" + action = QAction(text, parent) + if triggered is not None: + # PyQt4 old SIGNAL: parent.connect(action, SIGNAL("triggered()"), triggered) + action.triggered.connect(triggered) + if toggled is not None: + # PyQt4 old SIGNAL: parent.connect(action, SIGNAL("toggled(bool)"), toggled) + action.toggled.connect(toggled) + action.setCheckable(True) + if icon is not None: + if is_text_string(icon): + icon = get_icon(icon) + action.setIcon(icon) + if shortcut is not None: + action.setShortcut(shortcut) + if tip is not None: + action.setToolTip(tip) + action.setStatusTip(tip) + if data is not None: + action.setData(to_qvariant(data)) + if menurole is not None: + action.setMenuRole(menurole) + # TODO: Hard-code all shortcuts and choose context=Qt.WidgetShortcut + # (this will avoid calling shortcuts from another dockwidget + # since the context thing doesn't work quite well with these widgets) + action.setShortcutContext(context) + return action + + +def add_actions(target, actions, insert_before=None): + """Add actions to a menu""" + previous_action = None + target_actions = list(target.actions()) + if target_actions: + previous_action = target_actions[-1] + if previous_action.isSeparator(): + previous_action = None + for action in actions: + if (action is None) and ( + previous_action is not None + ): + if insert_before is None: + target.addSeparator() + else: + target.insertSeparator(insert_before) + elif isinstance(action, QMenu): + if insert_before is None: + target.addMenu(action) + else: + target.insertMenu(insert_before, action) + elif isinstance(action, QAction): + if insert_before is None: + target.addAction(action) + else: + target.insertAction(insert_before, action) + previous_action = action + + +def get_std_icon(name, size=None): + """Get standard platform icon + Call 'show_std_icons()' for details""" + if not name.startswith('SP_'): + name = 'SP_' + name + icon = ( + QWidget() + .style() + .standardIcon(getattr(QStyle, name)) + ) + if size is None: + return icon + else: + return QIcon(icon.pixmap(size, size)) diff --git a/build/lib/winpython/utils.py b/build/lib/winpython/utils.py new file mode 100644 index 00000000..39079153 --- /dev/null +++ b/build/lib/winpython/utils.py @@ -0,0 +1,794 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see winpython/__init__.py for details) + +""" +WinPython utilities + +Created on Tue Aug 14 14:08:40 2012 +""" + +from __future__ import print_function + +import os +import os.path as osp +import subprocess +import re +import tarfile +import zipfile +import tempfile +import shutil +import atexit +import sys +import stat +import locale + +# Local imports +from winpython.py3compat import winreg + + +def onerror(function, path, excinfo): + """Error handler for `shutil.rmtree`. + + If the error is due to an access error (read-only file), it + attempts to add write permission and then retries. + If the error is for another reason, it re-raises the error. + + Usage: `shutil.rmtree(path, onerror=onerror)""" + if not os.access(path, os.W_OK): + # Is the error an access error? + os.chmod(path, stat.S_IWUSR) + function(path) + else: + raise + + +# Exact copy of 'spyderlib.utils.programs.is_program_installed' function +def is_program_installed(basename): + """Return program absolute path if installed in PATH + Otherwise, return None""" + for path in os.environ["PATH"].split(os.pathsep): + abspath = osp.join(path, basename) + if osp.isfile(abspath): + return abspath + + +# ============================================================================= +# Environment variables +# ============================================================================= +def get_env(name, current=True): + """Return HKCU/HKLM environment variable name and value + + For example, get_user_env('PATH') may returns: + ('Path', u'C:\\Program Files\\Intel\\WiFi\\bin\\')""" + root = ( + winreg.HKEY_CURRENT_USER + if current + else winreg.HKEY_LOCAL_MACHINE + ) + key = winreg.OpenKey(root, "Environment") + for index in range(0, winreg.QueryInfoKey(key)[1]): + try: + value = winreg.EnumValue(key, index) + if value[0].lower() == name.lower(): + # Return both value[0] and value[1] because value[0] could be + # different from name (lowercase/uppercase) + return value[0], value[1] + except: + break + + +def set_env(name, value, current=True): + """Set HKCU/HKLM environment variables""" + root = ( + winreg.HKEY_CURRENT_USER + if current + else winreg.HKEY_LOCAL_MACHINE + ) + key = winreg.OpenKey(root, "Environment") + try: + _x, key_type = winreg.QueryValueEx(key, name) + except WindowsError: + key_type = winreg.REG_EXPAND_SZ + key = winreg.OpenKey( + root, "Environment", 0, winreg.KEY_SET_VALUE + ) + winreg.SetValueEx(key, name, 0, key_type, value) + from win32gui import SendMessageTimeout + from win32con import ( + HWND_BROADCAST, + WM_SETTINGCHANGE, + SMTO_ABORTIFHUNG, + ) + + SendMessageTimeout( + HWND_BROADCAST, + WM_SETTINGCHANGE, + 0, + "Environment", + SMTO_ABORTIFHUNG, + 5000, + ) + + +# ============================================================================= +# Shortcuts, start menu +# ============================================================================= + + +def get_special_folder_path(path_name): + """Return special folder path""" + from win32com.shell import shell, shellcon + + for maybe in """ + CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA + CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY + CSIDL_DESKTOPDIRECTORY CSIDL_COMMON_STARTUP CSIDL_STARTUP + CSIDL_COMMON_PROGRAMS CSIDL_PROGRAMS CSIDL_PROGRAM_FILES_COMMON + CSIDL_PROGRAM_FILES CSIDL_FONTS""".split(): + if maybe == path_name: + csidl = getattr(shellcon, maybe) + return shell.SHGetSpecialFolderPath( + 0, csidl, False + ) + raise ValueError( + "%s is an unknown path ID" % (path_name,) + ) + + +def get_winpython_start_menu_folder(current=True): + """Return WinPython Start menu shortcuts folder""" + if current: + # non-admin install - always goes in this user's start menu. + folder = get_special_folder_path("CSIDL_PROGRAMS") + else: + try: + folder = get_special_folder_path( + "CSIDL_COMMON_PROGRAMS" + ) + except OSError: + # No CSIDL_COMMON_PROGRAMS on this platform + folder = get_special_folder_path( + "CSIDL_PROGRAMS" + ) + return osp.join(folder, 'WinPython') + + +def create_winpython_start_menu_folder(current=True): + """Create WinPython Start menu folder -- remove it if it already exists""" + path = get_winpython_start_menu_folder(current=current) + if osp.isdir(path): + try: + shutil.rmtree(path, onerror=onerror) + except WindowsError: + print( + "Directory %s could not be removed" % path, + file=sys.stderr, + ) + else: + os.mkdir(path) + return path + + +def create_shortcut( + path, + description, + filename, + arguments="", + workdir="", + iconpath="", + iconindex=0, +): + """Create Windows shortcut (.lnk file)""" + import pythoncom + from win32com.shell import shell + + ilink = pythoncom.CoCreateInstance( + shell.CLSID_ShellLink, + None, + pythoncom.CLSCTX_INPROC_SERVER, + shell.IID_IShellLink, + ) + ilink.SetPath(path) + ilink.SetDescription(description) + if arguments: + ilink.SetArguments(arguments) + if workdir: + ilink.SetWorkingDirectory(workdir) + if iconpath or iconindex: + ilink.SetIconLocation(iconpath, iconindex) + # now save it. + ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile) + if not filename.endswith('.lnk'): + filename += '.lnk' + ipf.Save(filename, 0) + + +# ============================================================================= +# Misc. +# ============================================================================= + + +def print_box(text): + """Print text in a box""" + line0 = "+" + ("-" * (len(text) + 2)) + "+" + line1 = "| " + text + " |" + print( + ("\n\n" + "\n".join([line0, line1, line0]) + "\n") + ) + + +def is_python_distribution(path): + """Return True if path is a Python distribution""" + # XXX: This test could be improved but it seems to be sufficient + return osp.isfile( + osp.join(path, 'python.exe') + ) and osp.isdir(osp.join(path, 'Lib', 'site-packages')) + + +# ============================================================================= +# Shell, Python queries +# ============================================================================= + + +def decode_fs_string(string): + """Convert string from file system charset to unicode""" + charset = sys.getfilesystemencoding() + if charset is None: + charset = locale.getpreferredencoding() + return string.decode(charset) + + +def exec_shell_cmd(args, path): + """Execute shell command (*args* is a list of arguments) in *path*""" + # print " ".join(args) + process = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=path, + shell=True, + ) + return decode_fs_string(process.stdout.read()) + + +def get_r_version(path): + """Return version of the R installed in *path*""" + return ( + exec_shell_cmd('dir ..\README.R*', path) + .splitlines()[-3] + .split("-")[-1] + ) + + +def get_julia_version(path): + """Return version of the Julia installed in *path*""" + return ( + exec_shell_cmd('julia.exe -v', path) + .splitlines()[0] + .split(" ")[-1] + ) + + +def get_nodejs_version(path): + """Return version of the Nodejs installed in *path*""" + return exec_shell_cmd('node -v', path).splitlines()[0] + + +def get_npmjs_version(path): + """Return version of the Nodejs installed in *path*""" + return exec_shell_cmd('npm -v', path).splitlines()[0] + + +def get_pandoc_version(path): + """Return version of the Pandoc executable in *path*""" + return ( + exec_shell_cmd('pandoc -v', path) + .splitlines()[0] + .split(" ")[-1] + ) + + +def python_query(cmd, path): + """Execute Python command using the Python interpreter located in *path*""" + return exec_shell_cmd( + 'python -c "%s"' % cmd, path + ).splitlines()[0] + + +def get_python_infos(path): + """Return (version, architecture) for the Python distribution located in + *path*. The version number is limited to MAJOR.MINOR, the architecture is + an integer: 32 or 64""" + is_64 = python_query( + 'import sys; print(sys.maxsize > 2**32)', path + ) + arch = {'True': 64, 'False': 32}.get(is_64, None) + ver = python_query( + "import sys; print('%d.%d' % (sys.version_info.major, " + "sys.version_info.minor))", + path, + ) + if re.match(r'([0-9]*)\.([0-9]*)', ver) is None: + ver = None + return ver, arch + + +def get_python_long_version(path): + """Return long version (X.Y.Z) for the Python distribution located in + *path*""" + ver = python_query( + "import sys; print('%d.%d.%d' % " + "(sys.version_info.major, sys.version_info.minor," + "sys.version_info.micro))", + path, + ) + if ( + re.match(r'([0-9]*)\.([0-9]*)\.([0-9]*)', ver) + is None + ): + ver = None + return ver + + +# ============================================================================= +# Patch chebang line (courtesy of Christoph Gohlke) +# ============================================================================= +def patch_shebang_line( + fname, pad=b' ', to_movable=True, targetdir="" +): + """Remove absolute path to python.exe in shebang lines, or re-add it""" + + import re + import sys + import os + + target_dir = targetdir # movable option + if to_movable == False: + target_dir = os.path.abspath(os.path.dirname(fname)) + target_dir = ( + os.path.abspath(os.path.join(target_dir, r'..')) + + '\\' + ) + executable = sys.executable + if sys.version_info[0] == 2: + shebang_line = re.compile( + r"(#!.*pythonw?\.exe)" + ) # Python2.7 + else: + shebang_line = re.compile( + b"(#!.*pythonw?\.exe)" + ) # Python3+ + target_dir = target_dir.encode('utf-8') + with open(fname, 'rb') as fh: + initial_content = fh.read() + fh.close + fh = None + content = shebang_line.split( + initial_content, maxsplit=1 + ) + if len(content) != 3: + return + exe = os.path.basename(content[1][2:]) + content[1] = ( + b'#!' + target_dir + exe + ) # + (pad * (len(content[1]) - len(exe) - 2)) + final_content = b''.join(content) + if initial_content == final_content: + return + try: + with open(fname, 'wb') as fo: + fo.write(final_content) + fo.close + fo = None + print("patched", fname) + except Exception: + print("failed to patch", fname) + + +# ============================================================================= +# Patch shebang line in .py files +# ============================================================================= +def patch_shebang_line_py( + fname, to_movable=True, targetdir="" +): + """Changes shebang line in '.py' file to relative or absolue path""" + import fileinput + import re + import sys + + if sys.version_info[0] == 2: + # Python 2.x doesn't create .py files for .exe files. So, Moving + # WinPython doesn't break running executable files. + return + if to_movable: + exec_path = '#!.\python.exe' + else: + exec_path = '#!' + sys.executable + for line in fileinput.input(fname, inplace=True): + if re.match('^#\!.*python\.exe$', line) is not None: + print(exec_path) + else: + print(line, end='') + + +# ============================================================================= +# Patch sourcefile (instead of forking packages) +# ============================================================================= +def patch_sourcefile( + fname, in_text, out_text, silent_mode=False +): + """Replace a string in a source file""" + import io + + if osp.isfile(fname) and not in_text == out_text: + with io.open(fname, 'r') as fh: + content = fh.read() + new_content = content.replace(in_text, out_text) + if not new_content == content: + if not silent_mode: + print( + "patching ", + fname, + "from", + in_text, + "to", + out_text, + ) + with io.open(fname, 'wt') as fh: + fh.write(new_content) + + +# ============================================================================= +# Patch sourcelines (instead of forking packages) +# ============================================================================= +def patch_sourcelines( + fname, + in_line_start, + out_line, + endline='\n', + silent_mode=False, +): + """Replace the middle of lines between in_line_start and endline """ + import io + import os.path as osp + + if osp.isfile(fname): + with io.open(fname, 'r') as fh: + contents = fh.readlines() + content = "".join(contents) + for l in range(len(contents)): + if contents[l].startswith(in_line_start): + begining, middle = ( + in_line_start, + contents[l][len(in_line_start) :], + ) + ending = "" + if middle.find(endline) > 0: + ending = endline + endline.join( + middle.split(endline)[1:] + ) + middle = middle.split(endline)[0] + middle = out_line + new_line = begining + middle + ending + if not new_line == contents[l]: + if not silent_mode: + print( + "patching ", + fname, + " from\n", + contents[l], + "\nto\n", + new_line, + ) + contents[l] = new_line + new_content = "".join(contents) + if not new_content == content: + # if not silent_mode: + # print("patching ", fname, "from", content, "to", new_content) + with io.open(fname, 'wt') as fh: + try: + fh.write(new_content) + except: + print( + "impossible to patch", + fname, + "from", + content, + "to", + new_content, + ) + + +# ============================================================================= +# Extract functions +# ============================================================================= +def _create_temp_dir(): + """Create a temporary directory and remove it at exit""" + tmpdir = tempfile.mkdtemp(prefix='wppm_') + atexit.register( + lambda path: shutil.rmtree(path, onerror=onerror), + tmpdir, + ) + return tmpdir + + +def extract_exe(fname, targetdir=None, verbose=False): + """Extract .exe archive to a temporary directory (if targetdir + is None). Return the temporary directory path""" + if targetdir is None: + targetdir = _create_temp_dir() + extract = '7z.exe' + assert is_program_installed(extract), ( + "Required program '%s' was not found" % extract + ) + bname = osp.basename(fname) + args = ['x', '-o%s' % targetdir, '-aos', bname] + if verbose: + retcode = subprocess.call( + [extract] + args, cwd=osp.dirname(fname) + ) + else: + p = subprocess.Popen( + [extract] + args, + cwd=osp.dirname(fname), + stdout=subprocess.PIPE, + ) + p.communicate() + p.stdout.close() + retcode = p.returncode + if retcode != 0: + raise RuntimeError( + "Failed to extract %s (return code: %d)" + % (fname, retcode) + ) + return targetdir + + +def extract_archive(fname, targetdir=None, verbose=False): + """Extract .zip, .exe (considered to be a zip archive) or .tar.gz archive + to a temporary directory (if targetdir is None). + Return the temporary directory path""" + if targetdir is None: + targetdir = _create_temp_dir() + else: + try: + os.mkdir(targetdir) + except: + pass + if osp.splitext(fname)[1] in ('.zip', '.exe'): + obj = zipfile.ZipFile(fname, mode="r") + elif fname.endswith('.tar.gz'): + obj = tarfile.open(fname, mode='r:gz') + else: + raise RuntimeError( + "Unsupported archive filename %s" % fname + ) + obj.extractall(path=targetdir) + return targetdir + + +WININST_PATTERN = r'([a-zA-Z0-9\-\_]*|[a-zA-Z\-\_\.]*)-([0-9\.\-]*[a-z]*[0-9]?)(-Qt-([0-9\.]+))?.(win32|win\-amd64)(-py([0-9\.]+))?(-setup)?\.exe' + +# SOURCE_PATTERN defines what an acceptable source package name is +# As of 2014-09-08 : +# - the wheel package format is accepte in source directory +# - the tricky regexp is tuned also to support the odd jolib naming : +# . joblib-0.8.3_r1-py2.py3-none-any.whl, +# . joblib-0.8.3-r1.tar.gz + +SOURCE_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z]*[\-]?[0-9]*)(\.zip|\.tar\.gz|\-(py[2-7]*|py[2-7]*\.py[2-7]*)\-none\-any\.whl)' + +# WHEELBIN_PATTERN defines what an acceptable binary wheel package is +# "cp([0-9]*)" to replace per cp(34) for python3.4 +# "win32|win\_amd64" to replace per "win\_amd64" for 64bit +WHEELBIN_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z0-9\+]*[0-9]?)-cp([0-9]*)\-[0-9|c|o|n|e|p|m]*\-(win32|win\_amd64)\.whl' + + +def get_source_package_infos(fname): + """Return a tuple (name, version) of the Python source package""" + if fname[-4:] == '.whl': + return osp.basename(fname).split("-")[:2] + match = re.match(SOURCE_PATTERN, osp.basename(fname)) + if match is not None: + return match.groups()[:2] + + +def build_wininst( + root, + python_exe=None, + copy_to=None, + architecture=None, + verbose=False, + installer='bdist_wininst', +): + """Build wininst installer from Python package located in *root* + and eventually copy it to *copy_to* folder. + Return wininst installer full path.""" + if python_exe is None: + python_exe = sys.executable + assert osp.isfile(python_exe) + cmd = [python_exe, 'setup.py', 'build'] + if architecture is not None: + archstr = ( + 'win32' if architecture == 32 else 'win-amd64' + ) + cmd += ['--plat-name=%s' % archstr] + cmd += [installer] + # root = a tmp dir in windows\tmp, + if verbose: + subprocess.call(cmd, cwd=root) + else: + p = subprocess.Popen( + cmd, + cwd=root, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + p.communicate() + p.stdout.close() + p.stderr.close() + distdir = osp.join(root, 'dist') + if not osp.isdir(distdir): + raise RuntimeError( + "Build failed: see package README file for further" + " details regarding installation requirements.\n\n" + "For more concrete debugging infos, please try to build " + "the package from the command line:\n" + "1. Open a WinPython command prompt\n" + "2. Change working directory to the appropriate folder\n" + "3. Type `python setup.py build install`" + ) + pattern = WININST_PATTERN.replace( + r'(win32|win\-amd64)', archstr + ) + for distname in os.listdir(distdir): + match = re.match(pattern, distname) + if match is not None: + break + # for wheels (winpython here) + match = re.match(SOURCE_PATTERN, distname) + if match is not None: + break + match = re.match(WHEELBIN_PATTERN, distname) + if match is not None: + break + else: + raise RuntimeError( + "Build failed: not a pure Python package? %s" + % distdir + ) + src_fname = osp.join(distdir, distname) + if copy_to is None: + return src_fname + else: + dst_fname = osp.join(copy_to, distname) + shutil.move(src_fname, dst_fname) + if verbose: + print( + ( + "Move: %s --> %s" + % (src_fname, (dst_fname)) + ) + ) + # remove tempo dir 'root' no more needed + shutil.rmtree(root, onerror=onerror) + return dst_fname + + +def direct_pip_install( + fname, + python_exe=None, + architecture=None, + verbose=False, + install_options=None, +): + """Direct install via pip !""" + copy_to = osp.dirname(fname) + + if python_exe is None: + python_exe = sys.executable + assert osp.isfile(python_exe) + myroot = os.path.dirname(python_exe) + + cmd = [python_exe, '-m', 'pip', 'install'] + if install_options: + cmd += install_options # typically ['--no-deps'] + print('pip install_options', install_options) + cmd += [fname] + + if verbose: + subprocess.call(cmd, cwd=myroot) + else: + p = subprocess.Popen( + cmd, + cwd=myroot, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + stdout, stderr = p.communicate() + the_log = "%s" % stdout + "\n %s" % stderr + + if ( + ' not find ' in the_log + or ' not found ' in the_log + ): + print("Failed to Install: \n %s \n" % fname) + print("msg: %s" % the_log) + raise RuntimeError + p.stdout.close() + p.stderr.close() + src_fname = fname + if copy_to is None: + return src_fname + else: + if verbose: + print("Installed %s" % src_fname) + return src_fname + + +def do_script( + this_script, + python_exe=None, + copy_to=None, + architecture=None, + verbose=False, + install_options=None, +): + """Execute a script (get-pip typically)""" + if python_exe is None: + python_exe = sys.executable + myroot = os.path.dirname(python_exe) + + # cmd = [python_exe, myroot + r'\Scripts\pip-script.py', 'install'] + cmd = [python_exe] + if install_options: + cmd += install_options # typically ['--no-deps'] + print('script install_options', install_options) + if this_script: + cmd += [this_script] + # print('build_wheel', myroot, cmd) + print("Executing ", cmd) + + if verbose: + subprocess.call(cmd, cwd=myroot) + else: + p = subprocess.Popen( + cmd, + cwd=myroot, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + p.communicate() + p.stdout.close() + p.stderr.close() + if verbose: + print("Executed " % cmd) + return 'ok' + + +if __name__ == '__main__': + + print_box("Test") + dname = sys.prefix + print((dname + ':', '\n', get_python_infos(dname))) + # dname = r'E:\winpython\sandbox\python-2.7.3' + # print dname+':', '\n', get_python_infos(dname) + + tmpdir = r'D:\Tests\winpython_tests' + if not osp.isdir(tmpdir): + os.mkdir(tmpdir) + print( + ( + extract_archive( + osp.join( + r'D:\WinP\bd37', + 'packages.win-amd64', + 'python-3.7.3.amd64.zip', + ), + tmpdir, + ) + ) + ) diff --git a/build/lib/winpython/wppm.py b/build/lib/winpython/wppm.py new file mode 100644 index 00000000..46d0c168 --- /dev/null +++ b/build/lib/winpython/wppm.py @@ -0,0 +1,860 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see winpython/__init__.py for details) + +""" +WinPython Package Manager + +Created on Fri Aug 03 14:32:26 2012 +""" + +from __future__ import print_function + +import os +import os.path as osp +import shutil +import re +import sys +import subprocess + +# Local imports +from winpython import utils +from winpython.config import DATA_PATH +from winpython.py3compat import configparser as cp + +# from former wppm separate script launcher +from argparse import ArgumentParser +from winpython import py3compat + + +# Workaround for installing PyVISA on Windows from source: +os.environ['HOME'] = os.environ['USERPROFILE'] + +# pep503 defines normalized package names: www.python.org/dev/peps/pep-0503 +def normalize(name): + return re.sub(r"[-_.]+", "-", name).lower() + + +def get_package_metadata(database, name): + """Extract infos (description, url) from the local database""" + # Note: we could use the PyPI database but this has been written on + # machine which is not connected to the internet + db = cp.ConfigParser() + db.readfp(open(osp.join(DATA_PATH, database))) + metadata = dict( + description='', + url='https://pypi.org/project/' + name, + ) + for key in metadata: + name1 = name.lower() + # wheel replace '-' per '_' in key + for name2 in ( + name1, + name1.split('-')[0], + name1.replace('-', '_'), + '-'.join(name1.split('_')), + normalize(name), + ): + try: + metadata[key] = db.get(name2, key) + break + except (cp.NoSectionError, cp.NoOptionError): + pass + return metadata + + +class BasePackage(object): + def __init__(self, fname): + self.fname = fname + self.name = None + self.version = None + self.architecture = None + self.pyversion = None + self.description = None + self.url = None + + def __str__(self): + text = "%s %s" % (self.name, self.version) + pytext = "" + if self.pyversion is not None: + pytext = " for Python %s" % self.pyversion + if self.architecture is not None: + if not pytext: + pytext = " for Python" + pytext += " %dbits" % self.architecture + text += "%s\n%s\nWebsite: %s\n[%s]" % ( + pytext, + self.description, + self.url, + osp.basename(self.fname), + ) + return text + + def is_compatible_with(self, distribution): + """Return True if package is compatible with distribution in terms of + architecture and Python version (if applyable)""" + iscomp = True + if self.architecture is not None: + # Source distributions (not yet supported though) + iscomp = ( + iscomp + and self.architecture + == distribution.architecture + ) + if self.pyversion is not None: + # Non-pure Python package + iscomp = ( + iscomp + and self.pyversion == distribution.version + ) + return iscomp + + def extract_optional_infos(self): + """Extract package optional infos (description, url) + from the package database""" + metadata = get_package_metadata( + 'packages.ini', self.name + ) + for key, value in list(metadata.items()): + setattr(self, key, value) + + +class Package(BasePackage): + def __init__(self, fname): + BasePackage.__init__(self, fname) + self.files = [] + self.extract_infos() + self.extract_optional_infos() + + def extract_infos(self): + """Extract package infos (name, version, architecture) + from filename (installer basename)""" + bname = osp.basename(self.fname) + if bname.endswith(('32.whl', '64.whl')): + # {name}[-{bloat}]-{version}-{python tag}-{abi tag}-{platform tag}.whl + # ['sounddevice','0.3.5','py2.py3.cp34.cp35','none','win32'] + # PyQt5-5.7.1-5.7.1-cp34.cp35.cp36-none-win_amd64.whl + bname2 = bname[:-4].split("-") + self.name = bname2[0] + self.version = '-'.join(list(bname2[1:-3])) + self.pywheel, abi, arch = bname2[-3:] + self.pyversion = ( + None + ) # Let's ignore this self.pywheel + # wheel arch is 'win32' or 'win_amd64' + self.architecture = ( + 32 if arch == 'win32' else 64 + ) + return + elif bname.endswith(('.zip', '.tar.gz', '.whl')): + # distutils sdist + infos = utils.get_source_package_infos(bname) + if infos is not None: + self.name, self.version = infos + return + raise NotImplementedError( + "Not supported package type %s" % bname + ) + + +class WininstPackage(BasePackage): + def __init__(self, fname, distribution): + BasePackage.__init__(self, fname) + self.logname = None + self.distribution = distribution + self.architecture = distribution.architecture + self.pyversion = distribution.version + self.extract_infos() + self.extract_optional_infos() + + def extract_infos(self): + """Extract package infos (name, version, architecture)""" + match = re.match( + r'Remove([a-zA-Z0-9\-\_\.]*)\.exe', self.fname + ) + if match is None: + return + self.name = match.groups()[0] + self.logname = '%s-wininst.log' % self.name + fd = open( + osp.join( + self.distribution.target, self.logname + ), + 'U', + ) + searchtxt = 'DisplayName=' + for line in fd.readlines(): + pos = line.find(searchtxt) + if pos != -1: + break + else: + return + fd.close() + match = re.match( + r'Python %s %s-([0-9\.]*)' + % (self.pyversion, self.name), + line[pos + len(searchtxt) :], + ) + if match is None: + return + self.version = match.groups()[0] + + def uninstall(self): + """Uninstall package""" + subprocess.call( + [self.fname, '-u', self.logname], + cwd=self.distribution.target, + ) + + +class Distribution(object): + def __init__( + self, target=None, verbose=False, indent=False + ): + self.target = target + self.verbose = verbose + self.indent = indent + + # if no target path given, take the current python interpreter one + if self.target is None: + self.target = os.path.dirname(sys.executable) + self.to_be_removed = ( + [] + ) # list of directories to be removed later + + self.version, self.architecture = utils.get_python_infos( + target + ) + + def clean_up(self): + """Remove directories which couldn't be removed when building""" + for path in self.to_be_removed: + try: + shutil.rmtree(path, onerror=utils.onerror) + except WindowsError: + print( + "Directory %s could not be removed" + % path, + file=sys.stderr, + ) + + def remove_directory(self, path): + """Try to remove directory -- on WindowsError, remove it later""" + try: + shutil.rmtree(path) + except WindowsError: + self.to_be_removed.append(path) + + def copy_files( + self, + package, + targetdir, + srcdir, + dstdir, + create_bat_files=False, + ): + """Add copy task""" + srcdir = osp.join(targetdir, srcdir) + if not osp.isdir(srcdir): + return + offset = len(srcdir) + len(os.pathsep) + for dirpath, dirnames, filenames in os.walk(srcdir): + for dname in dirnames: + t_dname = osp.join(dirpath, dname)[offset:] + src = osp.join(srcdir, t_dname) + dst = osp.join(dstdir, t_dname) + if self.verbose: + print("mkdir: %s" % dst) + full_dst = osp.join(self.target, dst) + if not osp.exists(full_dst): + os.mkdir(full_dst) + package.files.append(dst) + for fname in filenames: + t_fname = osp.join(dirpath, fname)[offset:] + src = osp.join(srcdir, t_fname) + if dirpath.endswith('_system32'): + # Files that should be copied in %WINDIR%\system32 + dst = fname + else: + dst = osp.join(dstdir, t_fname) + if self.verbose: + print("file: %s" % dst) + full_dst = osp.join(self.target, dst) + shutil.move(src, full_dst) + package.files.append(dst) + name, ext = osp.splitext(dst) + if create_bat_files and ext in ('', '.py'): + dst = name + '.bat' + if self.verbose: + print("file: %s" % dst) + full_dst = osp.join(self.target, dst) + fd = open(full_dst, 'w') + fd.write( + """@echo off +python "%~dpn0""" + + ext + + """" %*""" + ) + fd.close() + package.files.append(dst) + + def create_file(self, package, name, dstdir, contents): + """Generate data file -- path is relative to distribution root dir""" + dst = osp.join(dstdir, name) + if self.verbose: + print("create: %s" % dst) + full_dst = osp.join(self.target, dst) + open(full_dst, 'w').write(contents) + package.files.append(dst) + + def get_installed_packages(self): + """Return installed packages""" + + # Include package installed via pip (not via WPPM) + wppm = [] + try: + if ( + os.path.dirname(sys.executable) + == self.target + ): + # direct way: we interrogate ourself, using official API + import pkg_resources, imp + + imp.reload(pkg_resources) + pip_list = [ + (i.key, i.version) + for i in pkg_resources.working_set + ] + else: + # indirect way: we interrogate something else + cmdx = [ + osp.join(self.target, 'python.exe'), + '-c', + "import pip;from pip._internal.utils.misc import get_installed_distributions as pip_get_installed_distributions ;print('+!+'.join(['%s@+@%s@+@' % (i.key,i.version) for i in pip_get_installed_distributions()]))", + ] + p = subprocess.Popen( + cmdx, + shell=True, + stdout=subprocess.PIPE, + cwd=self.target, + ) + stdout, stderr = p.communicate() + start_at = ( + 2 if sys.version_info >= (3, 0) else 0 + ) + pip_list = [ + line.split("@+@")[:2] + for line in ("%s" % stdout)[ + start_at: + ].split("+!+") + ] + # there are only Packages installed with pip now + # create pip package list + wppm = [ + Package( + '%s-%s-py2.py3-none-any.whl' + % (i[0].replace('-', '_').lower(), i[1]) + ) + for i in pip_list + ] + except: + pass + return sorted( + wppm, key=lambda tup: tup.name.lower() + ) + + def find_package(self, name): + """Find installed package""" + for pack in self.get_installed_packages(): + if normalize(pack.name) == normalize(name): + return pack + + def uninstall_existing(self, package): + """Uninstall existing package (or package name)""" + if isinstance(package, str): + pack = self.find_package(package) + else: + pack = self.find_package(package.name) + if pack is not None: + self.uninstall(pack) + + def patch_all_shebang( + self, + to_movable=True, + max_exe_size=999999, + targetdir="", + ): + """make all python launchers relatives""" + import glob + import os + + for ffname in glob.glob( + r'%s\Scripts\*.exe' % self.target + ): + size = os.path.getsize(ffname) + if size <= max_exe_size: + utils.patch_shebang_line( + ffname, + to_movable=to_movable, + targetdir=targetdir, + ) + for ffname in glob.glob( + r'%s\Scripts\*.py' % self.target + ): + utils.patch_shebang_line_py( + ffname, + to_movable=to_movable, + targetdir=targetdir, + ) + + def install(self, package, install_options=None): + """Install package in distribution""" + assert package.is_compatible_with(self) + + # wheel addition + if package.fname.endswith( + ('.whl', '.tar.gz', '.zip') + ): + self.install_bdist_direct( + package, install_options=install_options + ) + self.handle_specific_packages(package) + # minimal post-install actions + self.patch_standard_packages(package.name) + + def do_pip_action( + self, actions=None, install_options=None + ): + """Do pip action in a distribution""" + my_list = install_options + if my_list is None: + my_list = [] + my_actions = actions + if my_actions is None: + my_actions = [] + executing = osp.join( + self.target, '..', 'scripts', 'env.bat' + ) + if osp.isfile(executing): + complement = [ + r'&&', + 'cd', + '/D', + self.target, + r'&&', + osp.join(self.target, 'python.exe'), + ] + complement += ['-m', 'pip'] + else: + executing = osp.join(self.target, 'python.exe') + complement = ['-m', 'pip'] + try: + fname = utils.do_script( + this_script=None, + python_exe=executing, + architecture=self.architecture, + verbose=self.verbose, + install_options=complement + + my_actions + + my_list, + ) + except RuntimeError: + if not self.verbose: + print("Failed!") + raise + + def patch_standard_packages( + self, package_name='', to_movable=True + ): + """patch Winpython packages in need""" + import filecmp + + # 'pywin32' minimal post-install (pywin32_postinstall.py do too much) + if ( + package_name.lower() == "pywin32" + or package_name == '' + ): + origin = self.target + ( + r"\Lib\site-packages\pywin32_system32" + ) + destin = self.target + if osp.isdir(origin): + for name in os.listdir(origin): + here, there = ( + osp.join(origin, name), + osp.join(destin, name), + ) + if not os.path.exists( + there + ) or not filecmp.cmp(here, there): + shutil.copyfile(here, there) + # 'pip' to do movable launchers (around line 100) !!!! + # rational: https://github.com/pypa/pip/issues/2328 + if ( + package_name.lower() == "pip" + or package_name == '' + ): + # ensure pip will create movable launchers + # sheb_mov1 = classic way up to WinPython 2016-01 + # sheb_mov2 = tried way, but doesn't work for pip (at least) + sheb_fix = " executable = get_executable()" + sheb_mov1 = " executable = os.path.join(os.path.basename(get_executable()))" + sheb_mov2 = " executable = os.path.join('..',os.path.basename(get_executable()))" + if to_movable: + utils.patch_sourcefile( + self.target + + r"\Lib\site-packages\pip\_vendor\distlib\scripts.py", + sheb_fix, + sheb_mov1, + ) + utils.patch_sourcefile( + self.target + + r"\Lib\site-packages\pip\_vendor\distlib\scripts.py", + sheb_mov2, + sheb_mov1, + ) + else: + utils.patch_sourcefile( + self.target + + r"\Lib\site-packages\pip\_vendor\distlib\scripts.py", + sheb_mov1, + sheb_fix, + ) + utils.patch_sourcefile( + self.target + + r"\Lib\site-packages\pip\_vendor\distlib\scripts.py", + sheb_mov2, + sheb_fix, + ) + # ensure pip wheel will register relative PATH in 'RECORD' files + # will be in standard pip 8.0.3 + utils.patch_sourcefile( + self.target + + (r"\Lib\site-packages\pip\wheel.py"), + " writer.writerow((f, h, l))", + " writer.writerow((normpath(f, lib_dir), h, l))", + ) + + # create movable launchers for previous package installations + self.patch_all_shebang(to_movable=to_movable) + if ( + package_name.lower() == "spyder" + or package_name == '' + ): + # spyder don't goes on internet without I ask + utils.patch_sourcefile( + self.target + + ( + r"\Lib\site-packages\spyderlib\config\main.py" + ), + "'check_updates_on_startup': True,", + "'check_updates_on_startup': False,", + ) + utils.patch_sourcefile( + self.target + + ( + r"\Lib\site-packages\spyder\config\main.py" + ), + "'check_updates_on_startup': True,", + "'check_updates_on_startup': False,", + ) + # workaround bad installers + if package_name.lower() == "numba": + self.create_pybat(['numba', 'pycc']) + else: + self.create_pybat(package_name.lower()) + + def create_pybat( + self, + names='', + contents=r"""@echo off +..\python "%~dpn0" %*""", + ): + """Create launcher batch script when missing""" + + scriptpy = osp.join( + self.target, 'Scripts' + ) # std Scripts of python + if not list(names) == names: + my_list = [ + f + for f in os.listdir(scriptpy) + if '.' not in f and f.startswith(names) + ] + else: + my_list = names + for name in my_list: + if osp.isdir(scriptpy) and osp.isfile( + osp.join(scriptpy, name) + ): + if not osp.isfile( + osp.join(scriptpy, name + '.exe') + ) and not osp.isfile( + osp.join(scriptpy, name + '.bat') + ): + fd = open( + osp.join(scriptpy, name + '.bat'), + 'w', + ) + fd.write(contents) + fd.close() + + def handle_specific_packages(self, package): + """Packages requiring additional configuration""" + if package.name.lower() in ( + 'pyqt4', + 'pyqt5', + 'pyside2', + ): + # Qt configuration file (where to find Qt) + name = 'qt.conf' + contents = """[Paths] +Prefix = . +Binaries = .""" + self.create_file( + package, + name, + osp.join( + 'Lib', 'site-packages', package.name + ), + contents, + ) + self.create_file( + package, + name, + '.', + contents.replace( + '.', + './Lib/site-packages/%s' % package.name, + ), + ) + # pyuic script + if package.name.lower() == 'pyqt5': + # see http://code.activestate.com/lists/python-list/666469/ + tmp_string = r'''@echo off +if "%WINPYDIR%"=="" call "%~dp0..\..\scripts\env.bat" +"%WINPYDIR%\python.exe" -m PyQt5.uic.pyuic %1 %2 %3 %4 %5 %6 %7 %8 %9''' + else: + tmp_string = r'''@echo off +if "%WINPYDIR%"=="" call "%~dp0..\..\scripts\env.bat" +"%WINPYDIR%\python.exe" "%WINPYDIR%\Lib\site-packages\package.name\uic\pyuic.py" %1 %2 %3 %4 %5 %6 %7 %8 %9''' + self.create_file( + package, + 'pyuic%s.bat' % package.name[-1], + 'Scripts', + tmp_string.replace( + 'package.name', package.name + ), + ) + # Adding missing __init__.py files (fixes Issue 8) + uic_path = osp.join( + 'Lib', 'site-packages', package.name, 'uic' + ) + for dirname in ('Loader', 'port_v2', 'port_v3'): + self.create_file( + package, + '__init__.py', + osp.join(uic_path, dirname), + '', + ) + + def _print(self, package, action): + """Print package-related action text (e.g. 'Installing') + indicating progress""" + text = " ".join( + [action, package.name, package.version] + ) + if self.verbose: + utils.print_box(text) + else: + if self.indent: + text = (' ' * 4) + text + print(text + '...', end=" ") + + def _print_done(self): + """Print OK at the end of a process""" + if not self.verbose: + print("OK") + + def uninstall(self, package): + """Uninstall package from distribution""" + self._print(package, "Uninstalling") + if not package.name == 'pip': + # trick to get true target (if not current) + this_executable_path = self.target + subprocess.call( + [ + this_executable_path + r'\python.exe', + '-m', + 'pip', + 'uninstall', + package.name, + '-y', + ], + cwd=this_executable_path, + ) + # no more legacy, no package are installed by old non-pip means + self._print_done() + + def install_bdist_direct( + self, package, install_options=None + ): + """Install a package directly !""" + self._print( + package, + "Installing %s" % package.fname.split(".")[-1], + ) + try: + fname = utils.direct_pip_install( + package.fname, + python_exe=osp.join( + self.target, 'python.exe' + ), + architecture=self.architecture, + verbose=self.verbose, + install_options=install_options, + ) + except RuntimeError: + if not self.verbose: + print("Failed!") + raise + package = Package(fname) + self._print_done() + + def install_script(self, script, install_options=None): + try: + fname = utils.do_script( + script, + python_exe=osp.join( + self.target, 'python.exe' + ), + architecture=self.architecture, + verbose=self.verbose, + install_options=install_options, + ) + except RuntimeError: + if not self.verbose: + print("Failed!") + raise + + +def main(test=False): + if test: + sbdir = osp.join( + osp.dirname(__file__), + os.pardir, + os.pardir, + os.pardir, + 'sandbox', + ) + tmpdir = osp.join(sbdir, 'tobedeleted') + + # fname = osp.join(tmpdir, 'scipy-0.10.1.win-amd64-py2.7.exe') + fname = osp.join( + sbdir, 'VTK-5.10.0-Qt-4.7.4.win32-py2.7.exe' + ) + print(Package(fname)) + sys.exit() + target = osp.join( + utils.BASE_DIR, + 'build', + 'winpython-2.7.3', + 'python-2.7.3', + ) + fname = osp.join( + utils.BASE_DIR, + 'packages.src', + 'docutils-0.9.1.tar.gz', + ) + + dist = Distribution(target, verbose=True) + pack = Package(fname) + print(pack.description) + # dist.install(pack) + # dist.uninstall(pack) + else: + + parser = ArgumentParser( + description="WinPython Package Manager: install, " + "uninstall or upgrade Python packages on a Windows " + "Python distribution like WinPython." + ) + parser.add_argument( + 'fname', + metavar='package', + type=str if py3compat.PY3 else unicode, + help='path to a Python package', + ) + parser.add_argument( + '-t', + '--target', + dest='target', + default=sys.prefix, + help='path to target Python distribution ' + '(default: "%s")' % sys.prefix, + ) + parser.add_argument( + '-i', + '--install', + dest='install', + action='store_const', + const=True, + default=False, + help='install package (this is the default action)', + ) + parser.add_argument( + '-u', + '--uninstall', + dest='uninstall', + action='store_const', + const=True, + default=False, + help='uninstall package', + ) + args = parser.parse_args() + + if args.install and args.uninstall: + raise RuntimeError( + "Incompatible arguments: --install and --uninstall" + ) + if not args.install and not args.uninstall: + args.install = True + if not osp.isfile(args.fname) and args.install: + raise IOError("File not found: %s" % args.fname) + if utils.is_python_distribution(args.target): + dist = Distribution(args.target) + try: + if args.uninstall: + package = dist.find_package(args.fname) + dist.uninstall(package) + else: + package = Package(args.fname) + if ( + args.install + and package.is_compatible_with(dist) + ): + dist.install(package) + else: + raise RuntimeError( + "Package is not compatible with Python " + "%s %dbit" + % ( + dist.version, + dist.architecture, + ) + ) + except NotImplementedError: + raise RuntimeError( + "Package is not (yet) supported by WPPM" + ) + else: + raise WindowsError( + "Invalid Python distribution %s" + % args.target + ) + + +if __name__ == '__main__': + main() diff --git a/build/scripts-2.7/register_python b/build/scripts-2.7/register_python new file mode 100644 index 00000000..19fd3a10 --- /dev/null +++ b/build/scripts-2.7/register_python @@ -0,0 +1,26 @@ +#!C:\Python27\python.exe +import sys +from winpython import associate, utils +from argparse import ArgumentParser + +parser = ArgumentParser(description="Register Python file extensions, icons "\ + "and Windows explorer context menu to a target "\ + "Python distribution.") +try: + str_type = unicode +except NameError: + str_type = str +parser.add_argument('--target', metavar='path', type=str, + default=sys.prefix, + help='path to the target Python distribution') +parser.add_argument('--all', dest='all', action='store_const', + const=True, default=False, + help='register to all users, requiring administrative '\ + 'privileges (default: register to current user only)') +args = parser.parse_args() + +print(args.target) +if utils.is_python_distribution(args.target): + associate.register(args.target, current=not args.all) +else: + raise WindowsError("Invalid Python distribution %s" % args.target) diff --git a/build/scripts-2.7/register_python.bat b/build/scripts-2.7/register_python.bat new file mode 100644 index 00000000..0aad2d46 --- /dev/null +++ b/build/scripts-2.7/register_python.bat @@ -0,0 +1,2 @@ +@echo off +python "%~dpn0" %* \ No newline at end of file diff --git a/dist/winpython-2.2.20191222-py2.7.egg b/dist/winpython-2.2.20191222-py2.7.egg new file mode 100644 index 0000000000000000000000000000000000000000..4bd7e7d28509617f5fc454dbd64762372ab975fc GIT binary patch literal 190179 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

6X8WUS;u>%xkR1-9kYby7$DRs?D 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 Q;13Kb7+6~i;A>$24>}dbQ~&?~ literal 0 HcmV?d00001 diff --git a/winpython.egg-info/PKG-INFO b/winpython.egg-info/PKG-INFO new file mode 100644 index 00000000..bd74a606 --- /dev/null +++ b/winpython.egg-info/PKG-INFO @@ -0,0 +1,25 @@ +Metadata-Version: 1.1 +Name: winpython +Version: 2.2.20191222 +Summary: WinPython distribution tools, including WPPM +Home-page: http://winpython.github.io/ +Author: Pierre Raybaut +Author-email: pierre.raybaut@gmail.com +License: MIT +Download-URL: http://winpython.github.io//files/winpython-2.2.20191222.zip +Description: WinPython is a portable distribution of the Python programming language + for Windows. It is a full-featured Python-based scientific environment, : + including a package manager, WPPM. +Keywords: PyQt5 PyQt4 PySide +Platform: any +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: MacOS +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: OS Independent +Classifier: Operating System :: POSIX +Classifier: Operating System :: Unix +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Development Status :: 5 - Production/Stable +Classifier: Topic :: Scientific/Engineering +Classifier: Topic :: Software Development :: Widget Sets diff --git a/winpython.egg-info/SOURCES.txt b/winpython.egg-info/SOURCES.txt new file mode 100644 index 00000000..3d8ce047 --- /dev/null +++ b/winpython.egg-info/SOURCES.txt @@ -0,0 +1,65 @@ +MANIFEST.in +README.rst +setup.cfg +setup.py +scripts/register_python +scripts/register_python.bat +tools/7z.dll +tools/7z.exe +winpython/__init__.py +winpython/associate.py +winpython/config.py +winpython/controlpanel.py +winpython/disthelpers.py +winpython/py3compat.py +winpython/qthelpers.py +winpython/utils.py +winpython/wppm.py +winpython.egg-info/PKG-INFO +winpython.egg-info/SOURCES.txt +winpython.egg-info/dependency_links.txt +winpython.egg-info/entry_points.txt +winpython.egg-info/top_level.txt +winpython/_vendor/qtpy/QtCore.py +winpython/_vendor/qtpy/QtDesigner.py +winpython/_vendor/qtpy/QtGui.py +winpython/_vendor/qtpy/QtHelp.py +winpython/_vendor/qtpy/QtMultimedia.py +winpython/_vendor/qtpy/QtNetwork.py +winpython/_vendor/qtpy/QtOpenGL.py +winpython/_vendor/qtpy/QtPrintSupport.py +winpython/_vendor/qtpy/QtSql.py +winpython/_vendor/qtpy/QtSvg.py +winpython/_vendor/qtpy/QtTest.py +winpython/_vendor/qtpy/QtWebEngineWidgets.py +winpython/_vendor/qtpy/QtWidgets.py +winpython/_vendor/qtpy/__init__.py +winpython/_vendor/qtpy/_version.py +winpython/_vendor/qtpy/compat.py +winpython/_vendor/qtpy/py3compat.py +winpython/_vendor/qtpy/uic.py +winpython/_vendor/qtpy/_patch/__init__.py +winpython/_vendor/qtpy/_patch/qcombobox.py +winpython/_vendor/qtpy/_patch/qheaderview.py +winpython/_vendor/qtpy/tests/__init__.py +winpython/_vendor/qtpy/tests/conftest.py +winpython/_vendor/qtpy/tests/runtests.py +winpython/_vendor/qtpy/tests/test_main.py +winpython/_vendor/qtpy/tests/test_patch_qcombobox.py +winpython/_vendor/qtpy/tests/test_patch_qheaderview.py +winpython/_vendor/qtpy/tests/test_qdesktopservice_split.py +winpython/_vendor/qtpy/tests/test_qtcore.py +winpython/_vendor/qtpy/tests/test_qtdesigner.py +winpython/_vendor/qtpy/tests/test_qthelp.py +winpython/_vendor/qtpy/tests/test_qtmultimedia.py +winpython/_vendor/qtpy/tests/test_qtnetwork.py +winpython/_vendor/qtpy/tests/test_qtprintsupport.py +winpython/_vendor/qtpy/tests/test_qtsql.py +winpython/_vendor/qtpy/tests/test_qtsvg.py +winpython/_vendor/qtpy/tests/test_qttest.py +winpython/_vendor/qtpy/tests/test_uic.py +winpython/data/categories.ini +winpython/data/packages.ini +winpython/data/tools.ini +winpython/images/bug.png +winpython/images/winpython.svg \ No newline at end of file diff --git a/winpython.egg-info/dependency_links.txt b/winpython.egg-info/dependency_links.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/winpython.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/winpython.egg-info/entry_points.txt b/winpython.egg-info/entry_points.txt new file mode 100644 index 00000000..a72fef56 --- /dev/null +++ b/winpython.egg-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] +wpcp = winpython.controlpanel:main +wppm = winpython.wppm:main + diff --git a/winpython.egg-info/top_level.txt b/winpython.egg-info/top_level.txt new file mode 100644 index 00000000..2846a7d4 --- /dev/null +++ b/winpython.egg-info/top_level.txt @@ -0,0 +1 @@ +winpython