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( + ' + + + + + + + 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 00000000..4bd7e7d2 Binary files /dev/null and b/dist/winpython-2.2.20191222-py2.7.egg differ 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