Tue, 12 Jul 2022 16:26:22 +0200
pip Interface
- included a copy of pipdeptree and patched it to work with Python 3.11+
--- a/docs/changelog Mon Jul 11 17:56:42 2022 +0200 +++ b/docs/changelog Tue Jul 12 16:26:22 2022 +0200 @@ -10,6 +10,8 @@ generation process - Code Formatting -- added an interface to reformat Python source code with the 'Black' utility +- pip Interface + -- included a copy of pipdeptree and patched it to work with Python 3.11+ - setup Wizard -- added support for 'project_urls' -- added support for 'entry_points'
--- a/eric7.epj Mon Jul 11 17:56:42 2022 +0200 +++ b/eric7.epj Tue Jul 12 16:26:22 2022 +0200 @@ -61,7 +61,7 @@ "CopyrightMinFileSize": 0, "DocstringType": "eric", "EnabledCheckerCategories": "C, D, E, M, N, Y, W", - "ExcludeFiles": "*/ThirdParty/*, */coverage/*, */Ui_*.py, */Examples/*, */pycodestyle.py,*/pyflakes/checker.py,*/mccabe.py,*/eradicate.py,*/ast_unparse.py,*/piplicenses.py", + "ExcludeFiles": "*/ThirdParty/*, */coverage/*, */Ui_*.py, */Examples/*, */pycodestyle.py,*/pyflakes/checker.py,*/mccabe.py,*/eradicate.py,*/ast_unparse.py,*/piplicenses.py,*/pipdeptree.py", "ExcludeMessages": "C101,E203,E265,E266,E305,E402,M201,M301,M302,M303,M304,M305,M306,M307,M308,M311,M312,M313,M314,M315,M321,M701,M702,M811,M834,N802,N803,N807,N808,N821,W293,W503,Y119,Y401,Y402", "FixCodes": "", "FixIssues": false, @@ -963,6 +963,22 @@ "src/eric7/pixmaps" ], "OTHERTOOLSPARMS": { + "Black": { + "exclude": "/(\\.direnv|\\.eggs|\\.git|\\.hg|\\.mypy_cache|\\.nox|\\.tox|\\.venv|venv|\\.svn|_build|buck-out|build|dist|__pypackages__)/", + "extend-exclude": "/(\n\tExamples/\n\t| ThirdParty/\n\t| coverage/\n\t| Ui_.*\\.py\n\t| pycodestyle\\.py\n\t| pyflakes/checker\\.py\n\t| mccabe\\.py\n\t| eradicate\\.py\n\t| ast_unparse\\.py\n\t| piplicenses\\.py\n\t| pipdeptree\\.py\n)", + "force-exclude": "", + "line-length": 88, + "skip-magic-trailing-comma": false, + "skip-string-normalization": false, + "source": "dialog", + "target-version": [ + "py37", + "py38", + "py39", + "py310", + "py311" + ] + }, "CodeMetrics": { "ExcludeFiles": "Examples/*, */ThirdParty/*, */coverage/*, Ui_*.py" }, @@ -1308,6 +1324,7 @@ "src/eric7/PipInterface/PipPackagesWidget.py", "src/eric7/PipInterface/PipVulnerabilityChecker.py", "src/eric7/PipInterface/__init__.py", + "src/eric7/PipInterface/pipdeptree.py", "src/eric7/PipInterface/piplicenses.py", "src/eric7/PluginManager/PluginDetailsDialog.py", "src/eric7/PluginManager/PluginExceptions.py", @@ -2396,7 +2413,7 @@ "src/eric7/i18n/eric7_zh_CN.qm", "src/eric7/i18n/eric7_zh_CN.ts" ], - "TRANSLATIONSBINPATH": "", + "TRANSLATIONSBINPATH": ".", "UICPARAMS": { "Package": "", "PackagesRoot": "src/eric7", @@ -2444,4 +2461,4 @@ "VCSOTHERDATA": {}, "VERSION": "7.x" } -} \ No newline at end of file +}
--- a/pyproject.toml Mon Jul 11 17:56:42 2022 +0200 +++ b/pyproject.toml Tue Jul 12 16:26:22 2022 +0200 @@ -47,30 +47,29 @@ ] requires-python = ">=3.7, <3.12" dependencies = [ - "pip>=21.1", - "wheel", - "PyQt6>=6.2.0", - "PyQt6-Charts>=6.2.0", - "PyQt6-WebEngine>=6.2.0", - "PyQt6-QScintilla>=2.13.0", - "docutils", - "Markdown", - "pyyaml", - "tomlkit", - "chardet", - "asttokens", - "EditorConfig", - "Send2Trash", - "Pygments", - "parso", - "jedi", - "packaging", - "pipdeptree", - "cyclonedx-python-lib", - "cyclonedx-bom", - "trove-classifiers", - "black>=22.6.0", - "pywin32>=1.0;platform_system=='Windows'", + "pip>=21.1", + "wheel", + "PyQt6>=6.2.0", + "PyQt6-Charts>=6.2.0", + "PyQt6-WebEngine>=6.2.0", + "PyQt6-QScintilla>=2.13.0", + "docutils", + "Markdown", + "pyyaml", + "tomlkit", + "chardet", + "asttokens", + "EditorConfig", + "Send2Trash", + "Pygments", + "parso", + "jedi", + "packaging", + "cyclonedx-python-lib", + "cyclonedx-bom", + "trove-classifiers", + "black>=22.6.0", + "pywin32>=1.0;platform_system=='Windows'", ] dynamic = ["version"] @@ -128,36 +127,55 @@ [tool.setuptools.package-data] "*" = [ - "*.png", - "*.svg", - "*.xpm", - "*.ico", - "*.gif", - "*.icns", - "*.txt", - "*.md", - "*.rst", - "*.tmpl", - "*.html", - "*.qch", - "*.css", - "*.scss", - "*.qss", - "*.ehj", - "*.ethj", - "*.api", - "*.bas", - "*.dat", - "*.xbel", - "*.xml", - "*.js", - "*.json", - "*.desktop", + "*.png", + "*.svg", + "*.xpm", + "*.ico", + "*.gif", + "*.icns", + "*.txt", + "*.md", + "*.rst", + "*.tmpl", + "*.html", + "*.qch", + "*.css", + "*.scss", + "*.qss", + "*.ehj", + "*.ethj", + "*.api", + "*.bas", + "*.dat", + "*.xbel", + "*.xml", + "*.js", + "*.json", + "*.desktop", ] # complete translation files only "eric7.i18n" = [ - "eric7_de.qm", - "eric7_en.qm", - "eric7_es.qm", - "eric7_ru.qm", + "eric7_de.qm", + "eric7_en.qm", + "eric7_es.qm", + "eric7_ru.qm", ] + +[tool.black] +target-version = ["py37", "py38", "py39", "py310", "py311"] +line-length = 88 +extend-exclude = ''' +/( + Examples/ + | ThirdParty/ + | coverage/ + | Ui_.*\.py + | pycodestyle\.py + | pyflakes/checker\.py + | mccabe\.py + | eradicate\.py + | ast_unparse\.py + | piplicenses\.py + | pipdeptree\.py +) +'''
--- a/scripts/install.py Mon Jul 11 17:56:42 2022 +0200 +++ b/scripts/install.py Tue Jul 12 16:26:22 2022 +0200 @@ -1628,7 +1628,6 @@ "parso": ("parso", ""), "jedi": ("jedi", ""), "packaging": ("packaging", ""), - "pipdeptree": ("pipdeptree", ""), "cyclonedx-python-lib": ("cyclonedx", ""), "cyclonedx-bom": ("cyclonedx_py", ""), "trove-classifiers": ("trove_classifiers", ""),
--- a/src/eric7/APIs/Python3/eric7.api Mon Jul 11 17:56:42 2022 +0200 +++ b/src/eric7/APIs/Python3/eric7.api Tue Jul 12 16:26:22 2022 +0200 @@ -3189,6 +3189,54 @@ eric7.PipInterface.PipVulnerabilityChecker.VulnerabilityCheckError.FullDbUnavailable?7 eric7.PipInterface.PipVulnerabilityChecker.VulnerabilityCheckError.OK?7 eric7.PipInterface.PipVulnerabilityChecker.VulnerabilityCheckError.SummaryDbUnavailable?7 +eric7.PipInterface.pipdeptree.DistPackage.as_dict?4() +eric7.PipInterface.pipdeptree.DistPackage.as_parent_of?4(req) +eric7.PipInterface.pipdeptree.DistPackage.as_requirement?4() +eric7.PipInterface.pipdeptree.DistPackage.render_as_branch?4(frozen) +eric7.PipInterface.pipdeptree.DistPackage.render_as_root?4(frozen) +eric7.PipInterface.pipdeptree.DistPackage?1(obj, req=None) +eric7.PipInterface.pipdeptree.Package.frozen_repr?4() +eric7.PipInterface.pipdeptree.Package.render?4(parent=None, frozen=False) +eric7.PipInterface.pipdeptree.Package.render_as_branch?4(frozen) +eric7.PipInterface.pipdeptree.Package.render_as_root?4(frozen) +eric7.PipInterface.pipdeptree.Package?1(obj) +eric7.PipInterface.pipdeptree.PackageDAG.filter?4(include, exclude) +eric7.PipInterface.pipdeptree.PackageDAG.from_pkgs?4(pkgs) +eric7.PipInterface.pipdeptree.PackageDAG.get_children?4(node_key) +eric7.PipInterface.pipdeptree.PackageDAG.get_node_as_parent?4(node_key) +eric7.PipInterface.pipdeptree.PackageDAG.reverse?4() +eric7.PipInterface.pipdeptree.PackageDAG.sort?4() +eric7.PipInterface.pipdeptree.PackageDAG?1(m) +eric7.PipInterface.pipdeptree.ReqPackage.UNKNOWN_VERSION?7 +eric7.PipInterface.pipdeptree.ReqPackage.as_dict?4() +eric7.PipInterface.pipdeptree.ReqPackage.installed_version?4() +eric7.PipInterface.pipdeptree.ReqPackage.is_conflicting?4() +eric7.PipInterface.pipdeptree.ReqPackage.is_missing?4() +eric7.PipInterface.pipdeptree.ReqPackage.render_as_branch?4(frozen) +eric7.PipInterface.pipdeptree.ReqPackage.render_as_root?4(frozen) +eric7.PipInterface.pipdeptree.ReqPackage.version_spec?4() +eric7.PipInterface.pipdeptree.ReqPackage?1(obj, dist=None) +eric7.PipInterface.pipdeptree.ReversedPackageDAG.reverse?4() +eric7.PipInterface.pipdeptree._get_args?5() +eric7.PipInterface.pipdeptree.aux?4(node, parent=None, chain=None) +eric7.PipInterface.pipdeptree.aux?4(node, parent=None, indent=0, chain=None) +eric7.PipInterface.pipdeptree.conflicting_deps?4(tree) +eric7.PipInterface.pipdeptree.cyclic_deps?4(tree) +eric7.PipInterface.pipdeptree.dump_graphviz?4(tree, output_format='dot', is_reverse=False) +eric7.PipInterface.pipdeptree.flatten?7 +eric7.PipInterface.pipdeptree.frozen_req_from_dist?4(dist) +eric7.PipInterface.pipdeptree.get_installed_distributions?4(local_only=False, user_only=False) +eric7.PipInterface.pipdeptree.get_parser?4() +eric7.PipInterface.pipdeptree.guess_version?4(pkg_key, default='?') +eric7.PipInterface.pipdeptree.handle_non_host_target?4(args) +eric7.PipInterface.pipdeptree.main?4() +eric7.PipInterface.pipdeptree.print_graphviz?4(dump_output) +eric7.PipInterface.pipdeptree.render_conflicts_text?4(conflicts) +eric7.PipInterface.pipdeptree.render_cycles_text?4(cycles) +eric7.PipInterface.pipdeptree.render_json?4(tree, indent) +eric7.PipInterface.pipdeptree.render_json_tree?4(tree, indent) +eric7.PipInterface.pipdeptree.render_text?4(tree, list_all=True, frozen=False) +eric7.PipInterface.pipdeptree.sorted_tree?4(tree) eric7.PipInterface.piplicenses.CompatibleArgumentParser._verify_args?5(args: CustomNamespace) eric7.PipInterface.piplicenses.CompatibleArgumentParser.parse_args?4(args: Optional[Sequence[Text]] = None, namespace: CustomNamespace = None) eric7.PipInterface.piplicenses.CustomHelpFormatter._expand_help?5(action: argparse.Action)
--- a/src/eric7/APIs/Python3/eric7.bas Mon Jul 11 17:56:42 2022 +0200 +++ b/src/eric7/APIs/Python3/eric7.bas Tue Jul 12 16:26:22 2022 +0200 @@ -164,6 +164,7 @@ DiffReport StandardReport DiffWindow EricMainWindow DirectorySyncHandler SyncHandler +DistPackage Package DocstringMenuForEnterOnly QMenu DocumentationViewerWidget QWidget DotDesktopListSelectionDialog QDialog Ui_DotDesktopListSelectionDialog @@ -698,6 +699,7 @@ OpenSearchWriter QXmlStreamWriter OperaImporter BookmarksImporter OrderArg NoValueEnum +PackageDAG Mapping PackageDiagramBuilder UMLDiagramBuilder PackageItem UMLItem PackageModel UMLModel @@ -838,8 +840,10 @@ RefactoringPreviewDialog QDialog Ui_RefactoringPreviewDialog ReloadStopButton EricToolButton RemoveBookmarksCommand QUndoCommand +ReqPackage Package RestructuredTextProvider MarkupBase ReturnVisitor ast.NodeVisitor +ReversedPackageDAG PackageDAG SafariImporter BookmarksImporter SafeBrowsingAPIClient QObject SafeBrowsingCache QObject
--- a/src/eric7/Documentation/Help/source.qhp Mon Jul 11 17:56:42 2022 +0200 +++ b/src/eric7/Documentation/Help/source.qhp Tue Jul 12 16:26:22 2022 +0200 @@ -317,6 +317,7 @@ <section title="eric7.PipInterface.PipPackagesInputDialog" ref="eric7.PipInterface.PipPackagesInputDialog.html" /> <section title="eric7.PipInterface.PipPackagesWidget" ref="eric7.PipInterface.PipPackagesWidget.html" /> <section title="eric7.PipInterface.PipVulnerabilityChecker" ref="eric7.PipInterface.PipVulnerabilityChecker.html" /> + <section title="eric7.PipInterface.pipdeptree" ref="eric7.PipInterface.pipdeptree.html" /> <section title="eric7.PipInterface.piplicenses" ref="eric7.PipInterface.piplicenses.html" /> </section> <section title="eric7.PluginManager" ref="index-eric7.PluginManager.html"> @@ -3902,6 +3903,13 @@ <keyword name="DirectorySyncHandler.syncPasswords" id="DirectorySyncHandler.syncPasswords" ref="eric7.WebBrowser.Sync.DirectorySyncHandler.html#DirectorySyncHandler.syncPasswords" /> <keyword name="DirectorySyncHandler.syncSpeedDial" id="DirectorySyncHandler.syncSpeedDial" ref="eric7.WebBrowser.Sync.DirectorySyncHandler.html#DirectorySyncHandler.syncSpeedDial" /> <keyword name="DirectorySyncHandler.syncUserAgents" id="DirectorySyncHandler.syncUserAgents" ref="eric7.WebBrowser.Sync.DirectorySyncHandler.html#DirectorySyncHandler.syncUserAgents" /> + <keyword name="DistPackage" id="DistPackage" ref="eric7.PipInterface.pipdeptree.html#DistPackage" /> + <keyword name="DistPackage (Constructor)" id="DistPackage (Constructor)" ref="eric7.PipInterface.pipdeptree.html#DistPackage.__init__" /> + <keyword name="DistPackage.as_dict" id="DistPackage.as_dict" ref="eric7.PipInterface.pipdeptree.html#DistPackage.as_dict" /> + <keyword name="DistPackage.as_parent_of" id="DistPackage.as_parent_of" ref="eric7.PipInterface.pipdeptree.html#DistPackage.as_parent_of" /> + <keyword name="DistPackage.as_requirement" id="DistPackage.as_requirement" ref="eric7.PipInterface.pipdeptree.html#DistPackage.as_requirement" /> + <keyword name="DistPackage.render_as_branch" id="DistPackage.render_as_branch" ref="eric7.PipInterface.pipdeptree.html#DistPackage.render_as_branch" /> + <keyword name="DistPackage.render_as_root" id="DistPackage.render_as_root" ref="eric7.PipInterface.pipdeptree.html#DistPackage.render_as_root" /> <keyword name="DocStyle (Package)" id="DocStyle (Package)" ref="index-eric7.Plugins.CheckerPlugins.CodeStyleChecker.DocStyle.html" /> <keyword name="DocStyleChecker" id="DocStyleChecker" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.DocStyle.DocStyleChecker.html#DocStyleChecker" /> <keyword name="DocStyleChecker (Constructor)" id="DocStyleChecker (Constructor)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.DocStyle.DocStyleChecker.html#DocStyleChecker.__init__" /> @@ -11161,6 +11169,26 @@ <keyword name="PDFStyle" id="PDFStyle" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFStyle" /> <keyword name="PDFStyle (Constructor)" id="PDFStyle (Constructor)" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFStyle.__init__" /> <keyword name="Package" id="Package" ref="eric7.PipInterface.PipVulnerabilityChecker.html#Package" /> + <keyword name="Package" id="Package" ref="eric7.PipInterface.pipdeptree.html#Package" /> + <keyword name="Package (Constructor)" id="Package (Constructor)" ref="eric7.PipInterface.pipdeptree.html#Package.__init__" /> + <keyword name="Package.__getattr__" id="Package.__getattr__" ref="eric7.PipInterface.pipdeptree.html#Package.__getattr__" /> + <keyword name="Package.__lt__" id="Package.__lt__" ref="eric7.PipInterface.pipdeptree.html#Package.__lt__" /> + <keyword name="Package.__repr__" id="Package.__repr__" ref="eric7.PipInterface.pipdeptree.html#Package.__repr__" /> + <keyword name="Package.frozen_repr" id="Package.frozen_repr" ref="eric7.PipInterface.pipdeptree.html#Package.frozen_repr" /> + <keyword name="Package.render" id="Package.render" ref="eric7.PipInterface.pipdeptree.html#Package.render" /> + <keyword name="Package.render_as_branch" id="Package.render_as_branch" ref="eric7.PipInterface.pipdeptree.html#Package.render_as_branch" /> + <keyword name="Package.render_as_root" id="Package.render_as_root" ref="eric7.PipInterface.pipdeptree.html#Package.render_as_root" /> + <keyword name="PackageDAG" id="PackageDAG" ref="eric7.PipInterface.pipdeptree.html#PackageDAG" /> + <keyword name="PackageDAG (Constructor)" id="PackageDAG (Constructor)" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.__init__" /> + <keyword name="PackageDAG.__getitem__" id="PackageDAG.__getitem__" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.__getitem__" /> + <keyword name="PackageDAG.__iter__" id="PackageDAG.__iter__" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.__iter__" /> + <keyword name="PackageDAG.__len__" id="PackageDAG.__len__" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.__len__" /> + <keyword name="PackageDAG.filter" id="PackageDAG.filter" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.filter" /> + <keyword name="PackageDAG.from_pkgs" id="PackageDAG.from_pkgs" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.from_pkgs" /> + <keyword name="PackageDAG.get_children" id="PackageDAG.get_children" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.get_children" /> + <keyword name="PackageDAG.get_node_as_parent" id="PackageDAG.get_node_as_parent" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.get_node_as_parent" /> + <keyword name="PackageDAG.reverse" id="PackageDAG.reverse" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.reverse" /> + <keyword name="PackageDAG.sort" id="PackageDAG.sort" ref="eric7.PipInterface.pipdeptree.html#PackageDAG.sort" /> <keyword name="PackageDiagramBuilder" id="PackageDiagramBuilder" ref="eric7.Graphics.PackageDiagramBuilder.html#PackageDiagramBuilder" /> <keyword name="PackageDiagramBuilder (Constructor)" id="PackageDiagramBuilder (Constructor)" ref="eric7.Graphics.PackageDiagramBuilder.html#PackageDiagramBuilder.__init__" /> <keyword name="PackageDiagramBuilder (Module)" id="PackageDiagramBuilder (Module)" ref="eric7.Graphics.PackageDiagramBuilder.html" /> @@ -13252,6 +13280,15 @@ <keyword name="RemoveBookmarksCommand.redo" id="RemoveBookmarksCommand.redo" ref="eric7.WebBrowser.Bookmarks.BookmarksManager.html#RemoveBookmarksCommand.redo" /> <keyword name="RemoveBookmarksCommand.undo" id="RemoveBookmarksCommand.undo" ref="eric7.WebBrowser.Bookmarks.BookmarksManager.html#RemoveBookmarksCommand.undo" /> <keyword name="RepositoryInfoDialog (Module)" id="RepositoryInfoDialog (Module)" ref="eric7.VCS.RepositoryInfoDialog.html" /> + <keyword name="ReqPackage" id="ReqPackage" ref="eric7.PipInterface.pipdeptree.html#ReqPackage" /> + <keyword name="ReqPackage (Constructor)" id="ReqPackage (Constructor)" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.__init__" /> + <keyword name="ReqPackage.as_dict" id="ReqPackage.as_dict" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.as_dict" /> + <keyword name="ReqPackage.installed_version" id="ReqPackage.installed_version" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.installed_version" /> + <keyword name="ReqPackage.is_conflicting" id="ReqPackage.is_conflicting" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.is_conflicting" /> + <keyword name="ReqPackage.is_missing" id="ReqPackage.is_missing" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.is_missing" /> + <keyword name="ReqPackage.render_as_branch" id="ReqPackage.render_as_branch" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.render_as_branch" /> + <keyword name="ReqPackage.render_as_root" id="ReqPackage.render_as_root" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.render_as_root" /> + <keyword name="ReqPackage.version_spec" id="ReqPackage.version_spec" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.version_spec" /> <keyword name="RestructuredTextProvider" id="RestructuredTextProvider" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html#RestructuredTextProvider" /> <keyword name="RestructuredTextProvider (Constructor)" id="RestructuredTextProvider (Constructor)" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html#RestructuredTextProvider.__init__" /> <keyword name="RestructuredTextProvider (Module)" id="RestructuredTextProvider (Module)" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html" /> @@ -13310,6 +13347,8 @@ <keyword name="ReturnVisitor.visit_Return" id="ReturnVisitor.visit_Return" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Annotations.AnnotationsFunctionVisitor.html#ReturnVisitor.visit_Return" /> <keyword name="ReturnVisitor.visit_Return" id="ReturnVisitor.visit_Return" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Miscellaneous.MiscellaneousChecker.html#ReturnVisitor.visit_Return" /> <keyword name="ReturnVisitor.visit_While" id="ReturnVisitor.visit_While" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Miscellaneous.MiscellaneousChecker.html#ReturnVisitor.visit_While" /> + <keyword name="ReversedPackageDAG" id="ReversedPackageDAG" ref="eric7.PipInterface.pipdeptree.html#ReversedPackageDAG" /> + <keyword name="ReversedPackageDAG.reverse" id="ReversedPackageDAG.reverse" ref="eric7.PipInterface.pipdeptree.html#ReversedPackageDAG.reverse" /> <keyword name="SafariImporter" id="SafariImporter" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.SafariImporter.html#SafariImporter" /> <keyword name="SafariImporter (Constructor)" id="SafariImporter (Constructor)" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.SafariImporter.html#SafariImporter.__init__" /> <keyword name="SafariImporter (Module)" id="SafariImporter (Module)" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.SafariImporter.html" /> @@ -18255,6 +18294,7 @@ <keyword name="_evaluateAst" id="_evaluateAst" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.injectionSql.html#_evaluateAst" /> <keyword name="_evaluateShellCall" id="_evaluateShellCall" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.injectionShell.html#_evaluateShellCall" /> <keyword name="_get" id="_get" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.SecurityUtils.html#_get" /> + <keyword name="_get_args" id="_get_args" ref="eric7.PipInterface.pipdeptree.html#_get_args" /> <keyword name="_get_parameters" id="_get_parameters" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#_get_parameters" /> <keyword name="_getfullargs" id="_getfullargs" ref="eric7.DebugClients.Python.DebugUtilities.html#_getfullargs" /> <keyword name="_indent" id="_indent" ref="eric7.Utilities.ClassBrowsers.pyclbr.html#_indent" /> @@ -18284,6 +18324,8 @@ <keyword name="append_PKCS7_padding" id="append_PKCS7_padding" ref="eric7.Utilities.crypto.py3AES.html#append_PKCS7_padding" /> <keyword name="assert (Module)" id="assert (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.assert.html" /> <keyword name="ast_unparse (Module)" id="ast_unparse (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.html" /> + <keyword name="aux" id="aux" ref="eric7.PipInterface.pipdeptree.html#aux" /> + <keyword name="aux_1" id="aux_1" ref="eric7.PipInterface.pipdeptree.html#aux_1" /> <keyword name="awsHardcodedPassword (Module)" id="awsHardcodedPassword (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.awsHardcodedPassword.html" /> <keyword name="bare_except" id="bare_except" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#bare_except" /> <keyword name="blackListCalls (Module)" id="blackListCalls (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.blackListCalls.html" /> @@ -18357,6 +18399,7 @@ <keyword name="condaVersion" id="condaVersion" ref="eric7.CondaInterface.__init__.html#condaVersion" /> <keyword name="condaVersionStr" id="condaVersionStr" ref="eric7.CondaInterface.__init__.html#condaVersionStr" /> <keyword name="confirmOverwrite" id="confirmOverwrite" ref="eric7.EricWidgets.EricFileSaveConfirmDialog.html#confirmOverwrite" /> + <keyword name="conflicting_deps" id="conflicting_deps" ref="eric7.PipInterface.pipdeptree.html#conflicting_deps" /> <keyword name="containsSpace" id="containsSpace" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#containsSpace" /> <keyword name="continued_indentation" id="continued_indentation" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#continued_indentation" /> <keyword name="convertLineEnds" id="convertLineEnds" ref="eric7.Utilities.__init__.html#convertLineEnds" /> @@ -18478,6 +18521,7 @@ <keyword name="critical" id="critical" ref="eric7.EricWidgets.EricMessageBox.html#critical" /> <keyword name="crypto (Package)" id="crypto (Package)" ref="index-eric7.Utilities.crypto.html" /> <keyword name="cursors (Package)" id="cursors (Package)" ref="index-eric7.IconEditor.cursors.html" /> + <keyword name="cyclic_deps" id="cyclic_deps" ref="eric7.PipInterface.pipdeptree.html#cyclic_deps" /> <keyword name="data (Package)" id="data (Package)" ref="index-eric7.EricNetwork.data.html" /> <keyword name="data (Package)" id="data (Package)" ref="index-eric7.UI.data.html" /> <keyword name="data (Package)" id="data (Package)" ref="index-eric7.WebBrowser.data.html" /> @@ -18504,6 +18548,7 @@ <keyword name="doUpgrade" id="doUpgrade" ref="eric7.UI.upgrader.html#doUpgrade" /> <keyword name="drawPolygon" id="drawPolygon" ref="eric7.Snapshot.SnapshotFreehandGrabber.html#drawPolygon" /> <keyword name="drawRect" id="drawRect" ref="eric7.Snapshot.SnapshotRegionGrabber.html#drawRect" /> + <keyword name="dump_graphviz" id="dump_graphviz" ref="eric7.PipInterface.pipdeptree.html#dump_graphviz" /> <keyword name="editMessageFilters" id="editMessageFilters" ref="eric7.EricWidgets.EricErrorMessage.html#editMessageFilters" /> <keyword name="encode" id="encode" ref="eric7.Utilities.__init__.html#encode" /> <keyword name="encryptData" id="encryptData" ref="eric7.Utilities.crypto.py3AES.html#encryptData" /> @@ -18577,6 +18622,7 @@ <keyword name="formatTime" id="formatTime" ref="eric7.Plugins.VcsPlugins.vcsPySvn.SvnUtilities.html#formatTime" /> <keyword name="formatargvalues" id="formatargvalues" ref="eric7.DebugClients.Python.DebugUtilities.html#formatargvalues" /> <keyword name="fromNativeSeparators" id="fromNativeSeparators" ref="eric7.Utilities.__init__.html#fromNativeSeparators" /> + <keyword name="frozen_req_from_dist" id="frozen_req_from_dist" ref="eric7.PipInterface.pipdeptree.html#frozen_req_from_dist" /> <keyword name="fstat" id="fstat" ref="eric7.MicroPython.MicroPythonFileSystemUtilities.html#fstat" /> <keyword name="generalBindAllInterfaces (Module)" id="generalBindAllInterfaces (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.generalBindAllInterfaces.html" /> <keyword name="generalFilePermissions (Module)" id="generalFilePermissions (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.generalFilePermissions.html" /> @@ -18792,9 +18838,11 @@ <keyword name="get_class_members" id="get_class_members" ref="eric7.DebugClients.Python.FlexCompleter.html#get_class_members" /> <keyword name="get_coding" id="get_coding" ref="eric7.Utilities.__init__.html#get_coding" /> <keyword name="get_codingBytes" id="get_codingBytes" ref="eric7.Utilities.__init__.html#get_codingBytes" /> + <keyword name="get_installed_distributions" id="get_installed_distributions" ref="eric7.PipInterface.pipdeptree.html#get_installed_distributions" /> <keyword name="get_installed_distributions" id="get_installed_distributions" ref="eric7.PipInterface.piplicenses.html#get_installed_distributions" /> <keyword name="get_output_fields" id="get_output_fields" ref="eric7.PipInterface.piplicenses.html#get_output_fields" /> <keyword name="get_packages" id="get_packages" ref="eric7.PipInterface.piplicenses.html#get_packages" /> + <keyword name="get_parser" id="get_parser" ref="eric7.PipInterface.pipdeptree.html#get_parser" /> <keyword name="get_parser" id="get_parser" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#get_parser" /> <keyword name="get_pkg_included_file" id="get_pkg_included_file" ref="eric7.PipInterface.piplicenses.html#get_pkg_included_file" /> <keyword name="get_pkg_info" id="get_pkg_info" ref="eric7.PipInterface.piplicenses.html#get_pkg_info" /> @@ -18804,8 +18852,10 @@ <keyword name="getuser" id="getuser" ref="eric7.DebugClients.Python.getpass.html#getuser" /> <keyword name="git (Module)" id="git (Module)" ref="eric7.Plugins.VcsPlugins.vcsGit.git.html" /> <keyword name="gpg (Module)" id="gpg (Module)" ref="eric7.Plugins.VcsPlugins.vcsMercurial.GpgExtension.gpg.html" /> + <keyword name="guess_version" id="guess_version" ref="eric7.PipInterface.pipdeptree.html#guess_version" /> <keyword name="handleArgs" id="handleArgs" ref="eric7.Toolbox.Startup.html#handleArgs" /> <keyword name="handleSingleApplication" id="handleSingleApplication" ref="eric7.eric7.html#handleSingleApplication" /> + <keyword name="handle_non_host_target" id="handle_non_host_target" ref="eric7.PipInterface.pipdeptree.html#handle_non_host_target" /> <keyword name="hasEnvironmentEntry" id="hasEnvironmentEntry" ref="eric7.Utilities.__init__.html#hasEnvironmentEntry" /> <keyword name="hasEric6Configuration" id="hasEric6Configuration" ref="eric7.Preferences.__init__.html#hasEric6Configuration" /> <keyword name="hasShell" id="hasShell" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.injectionShell.html#hasShell" /> @@ -18905,6 +18955,7 @@ <keyword name="loadTranslatorForLocale" id="loadTranslatorForLocale" ref="eric7.Toolbox.Startup.html#loadTranslatorForLocale" /> <keyword name="loadTranslators" id="loadTranslators" ref="eric7.Toolbox.Startup.html#loadTranslators" /> <keyword name="lru_cache" id="lru_cache" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#lru_cache" /> + <keyword name="main" id="main" ref="eric7.PipInterface.pipdeptree.html#main" /> <keyword name="main" id="main" ref="eric7.PipInterface.piplicenses.html#main" /> <keyword name="main" id="main" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Miscellaneous.eradicate.html#main" /> <keyword name="main" id="main" ref="eric7.Plugins.VcsPlugins.vcsMercurial.HisteditExtension.HgHisteditEditor.html#main" /> @@ -18988,6 +19039,7 @@ <keyword name="patchQProcess" id="patchQProcess" ref="eric7.DebugClients.Python.QProcessExtension.html#patchQProcess" /> <keyword name="patchSubprocess" id="patchSubprocess" ref="eric7.DebugClients.Python.SubprocessExtension.html#patchSubprocess" /> <keyword name="pbkdf2" id="pbkdf2" ref="eric7.Utilities.crypto.py3PBKDF2.html#pbkdf2" /> + <keyword name="pipdeptree (Module)" id="pipdeptree (Module)" ref="eric7.PipInterface.pipdeptree.html" /> <keyword name="piplicenses (Module)" id="piplicenses (Module)" ref="eric7.PipInterface.piplicenses.html" /> <keyword name="pixmapFileToDataUrl" id="pixmapFileToDataUrl" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#pixmapFileToDataUrl" /> <keyword name="pixmapFromByteArray" id="pixmapFromByteArray" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#pixmapFromByteArray" /> @@ -19007,6 +19059,7 @@ <keyword name="prepareUninstall" id="prepareUninstall" ref="eric7.Plugins.PluginVcsSubversion.html#prepareUninstall" /> <keyword name="previewPix" id="previewPix" ref="eric7.Plugins.PluginVmListspace.html#previewPix" /> <keyword name="previewPix" id="previewPix" ref="eric7.Plugins.PluginVmTabview.html#previewPix" /> + <keyword name="print_graphviz" id="print_graphviz" ref="eric7.PipInterface.pipdeptree.html#print_graphviz" /> <keyword name="printerr" id="printerr" ref="eric7.DebugClients.Python.DebugBase.html#printerr" /> <keyword name="process_options" id="process_options" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#process_options" /> <keyword name="protoclbr (Module)" id="protoclbr (Module)" ref="eric7.Utilities.ClassBrowsers.protoclbr.html" /> @@ -19065,6 +19118,11 @@ <keyword name="removeQuotesFromArgs" id="removeQuotesFromArgs" ref="eric7.DebugClients.Python.DebugUtilities.html#removeQuotesFromArgs" /> <keyword name="removeSearchPath" id="removeSearchPath" ref="eric7.UI.PixmapCache.html#removeSearchPath" /> <keyword name="renderTabPreview" id="renderTabPreview" ref="eric7.WebBrowser.WebBrowserSnap.html#renderTabPreview" /> + <keyword name="render_conflicts_text" id="render_conflicts_text" ref="eric7.PipInterface.pipdeptree.html#render_conflicts_text" /> + <keyword name="render_cycles_text" id="render_cycles_text" ref="eric7.PipInterface.pipdeptree.html#render_cycles_text" /> + <keyword name="render_json" id="render_json" ref="eric7.PipInterface.pipdeptree.html#render_json" /> + <keyword name="render_json_tree" id="render_json_tree" ref="eric7.PipInterface.pipdeptree.html#render_json_tree" /> + <keyword name="render_text" id="render_text" ref="eric7.PipInterface.pipdeptree.html#render_text" /> <keyword name="resetInterface" id="resetInterface" ref="eric7.CondaInterface.__init__.html#resetInterface" /> <keyword name="resetLayout" id="resetLayout" ref="eric7.Preferences.__init__.html#resetLayout" /> <keyword name="resetParsedModule" id="resetParsedModule" ref="eric7.Utilities.ModuleParser.html#resetParsedModule" /> @@ -19160,6 +19218,7 @@ <keyword name="signatures" id="signatures" ref="eric7.Project.UicLoadUi6.html#signatures" /> <keyword name="simpleAppStartup" id="simpleAppStartup" ref="eric7.Toolbox.Startup.html#simpleAppStartup" /> <keyword name="sort" id="sort" ref="eric7.Graphics.GraphicsUtilities.html#sort" /> + <keyword name="sorted_tree" id="sorted_tree" ref="eric7.PipInterface.pipdeptree.html#sorted_tree" /> <keyword name="speedString" id="speedString" ref="eric7.WebBrowser.Download.DownloadUtilities.html#speedString" /> <keyword name="splitPath" id="splitPath" ref="eric7.Utilities.__init__.html#splitPath" /> <keyword name="sshNoHostKeyVerification (Module)" id="sshNoHostKeyVerification (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.sshNoHostKeyVerification.html" /> @@ -19514,6 +19573,7 @@ <file>eric7.PipInterface.PipPackagesInputDialog.html</file> <file>eric7.PipInterface.PipPackagesWidget.html</file> <file>eric7.PipInterface.PipVulnerabilityChecker.html</file> + <file>eric7.PipInterface.pipdeptree.html</file> <file>eric7.PipInterface.piplicenses.html</file> <file>eric7.PluginManager.PluginDetailsDialog.html</file> <file>eric7.PluginManager.PluginExceptions.html</file>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.PipInterface.pipdeptree.html Tue Jul 12 16:26:22 2022 +0200 @@ -0,0 +1,1012 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.PipInterface.pipdeptree</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.PipInterface.pipdeptree</h1> + +<p> +Copyright (c) 2015 Vineet Naik (naikvin@gmail.com) +</p> +<p> +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: +</p> +<p> +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. +</p> +<p> +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. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>__version__</td></tr><tr><td>flatten</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#DistPackage">DistPackage</a></td> +<td>Wrapper class for pkg_resources.Distribution instances</td> +</tr> +<tr> +<td><a href="#Package">Package</a></td> +<td>Abstract class for wrappers around objects that pip returns.</td> +</tr> +<tr> +<td><a href="#PackageDAG">PackageDAG</a></td> +<td>Representation of Package dependencies as directed acyclic graph using a dict (Mapping) as the underlying datastructure.</td> +</tr> +<tr> +<td><a href="#ReqPackage">ReqPackage</a></td> +<td>Wrapper class for Requirements instance</td> +</tr> +<tr> +<td><a href="#ReversedPackageDAG">ReversedPackageDAG</a></td> +<td>Representation of Package dependencies in the reverse order.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#_get_args">_get_args</a></td> +<td></td> +</tr> +<tr> +<td><a href="#aux">aux</a></td> +<td></td> +</tr> +<tr> +<td><a href="#aux_1">aux</a></td> +<td></td> +</tr> +<tr> +<td><a href="#conflicting_deps">conflicting_deps</a></td> +<td>Returns dependencies which are not present or conflict with the requirements of other packages.</td> +</tr> +<tr> +<td><a href="#cyclic_deps">cyclic_deps</a></td> +<td>Return cyclic dependencies as list of tuples</td> +</tr> +<tr> +<td><a href="#dump_graphviz">dump_graphviz</a></td> +<td>Output dependency graph as one of the supported GraphViz output formats.</td> +</tr> +<tr> +<td><a href="#frozen_req_from_dist">frozen_req_from_dist</a></td> +<td></td> +</tr> +<tr> +<td><a href="#get_installed_distributions">get_installed_distributions</a></td> +<td></td> +</tr> +<tr> +<td><a href="#get_parser">get_parser</a></td> +<td></td> +</tr> +<tr> +<td><a href="#guess_version">guess_version</a></td> +<td>Guess the version of a pkg when pip doesn't provide it</td> +</tr> +<tr> +<td><a href="#handle_non_host_target">handle_non_host_target</a></td> +<td></td> +</tr> +<tr> +<td><a href="#main">main</a></td> +<td></td> +</tr> +<tr> +<td><a href="#print_graphviz">print_graphviz</a></td> +<td>Dump the data generated by GraphViz to stdout.</td> +</tr> +<tr> +<td><a href="#render_conflicts_text">render_conflicts_text</a></td> +<td></td> +</tr> +<tr> +<td><a href="#render_cycles_text">render_cycles_text</a></td> +<td></td> +</tr> +<tr> +<td><a href="#render_json">render_json</a></td> +<td>Converts the tree into a flat json representation.</td> +</tr> +<tr> +<td><a href="#render_json_tree">render_json_tree</a></td> +<td>Converts the tree into a nested json representation.</td> +</tr> +<tr> +<td><a href="#render_text">render_text</a></td> +<td>Print tree as text on console</td> +</tr> +<tr> +<td><a href="#sorted_tree">sorted_tree</a></td> +<td>Sorts the dict representation of the tree</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="DistPackage" ID="DistPackage"></a> +<h2>DistPackage</h2> + +<p> +Wrapper class for pkg_resources.Distribution instances +</p> +<p> + :param obj: pkg_resources.Distribution to wrap over + :param req: optional ReqPackage object to associate this + DistPackage with. This is useful for displaying the + tree in reverse +</p> +<h3>Derived from</h3> +Package +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#DistPackage.__init__">DistPackage</a></td> +<td></td> +</tr> +<tr> +<td><a href="#DistPackage.as_dict">as_dict</a></td> +<td></td> +</tr> +<tr> +<td><a href="#DistPackage.as_parent_of">as_parent_of</a></td> +<td>Return a DistPackage instance associated to a requirement</td> +</tr> +<tr> +<td><a href="#DistPackage.as_requirement">as_requirement</a></td> +<td>Return a ReqPackage representation of this DistPackage</td> +</tr> +<tr> +<td><a href="#DistPackage.render_as_branch">render_as_branch</a></td> +<td></td> +</tr> +<tr> +<td><a href="#DistPackage.render_as_root">render_as_root</a></td> +<td></td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="DistPackage.__init__" ID="DistPackage.__init__"></a> +<h4>DistPackage (Constructor)</h4> +<b>DistPackage</b>(<i>obj, req=None</i>) + +<a NAME="DistPackage.as_dict" ID="DistPackage.as_dict"></a> +<h4>DistPackage.as_dict</h4> +<b>as_dict</b>(<i></i>) + +<a NAME="DistPackage.as_parent_of" ID="DistPackage.as_parent_of"></a> +<h4>DistPackage.as_parent_of</h4> +<b>as_parent_of</b>(<i>req</i>) + +<p> +Return a DistPackage instance associated to a requirement +</p> +<p> + This association is necessary for reversing the PackageDAG. +</p> +<p> + If `req` is None, and the `req` attribute of the current + instance is also None, then the same instance will be + returned. +</p> +<p> + :param ReqPackage req: the requirement to associate with + :returns: DistPackage instance +</p> +<p> + +</p> +<a NAME="DistPackage.as_requirement" ID="DistPackage.as_requirement"></a> +<h4>DistPackage.as_requirement</h4> +<b>as_requirement</b>(<i></i>) + +<p> +Return a ReqPackage representation of this DistPackage +</p> +<a NAME="DistPackage.render_as_branch" ID="DistPackage.render_as_branch"></a> +<h4>DistPackage.render_as_branch</h4> +<b>render_as_branch</b>(<i>frozen</i>) + +<a NAME="DistPackage.render_as_root" ID="DistPackage.render_as_root"></a> +<h4>DistPackage.render_as_root</h4> +<b>render_as_root</b>(<i>frozen</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="Package" ID="Package"></a> +<h2>Package</h2> + +<p> +Abstract class for wrappers around objects that pip returns. +</p> +<p> + This class needs to be subclassed with implementations for + `render_as_root` and `render_as_branch` methods. +</p> +<p> + +</p> +<h3>Derived from</h3> +object +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#Package.__init__">Package</a></td> +<td></td> +</tr> +<tr> +<td><a href="#Package.__getattr__">__getattr__</a></td> +<td></td> +</tr> +<tr> +<td><a href="#Package.__lt__">__lt__</a></td> +<td></td> +</tr> +<tr> +<td><a href="#Package.__repr__">__repr__</a></td> +<td></td> +</tr> +<tr> +<td><a href="#Package.render">render</a></td> +<td></td> +</tr> +<tr> +<td><a href="#Package.render_as_branch">render_as_branch</a></td> +<td></td> +</tr> +<tr> +<td><a href="#Package.render_as_root">render_as_root</a></td> +<td></td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> + +<tr> +<td><a href="#Package.frozen_repr">frozen_repr</a></td> +<td></td> +</tr> +</table> + +<a NAME="Package.__init__" ID="Package.__init__"></a> +<h4>Package (Constructor)</h4> +<b>Package</b>(<i>obj</i>) + +<a NAME="Package.__getattr__" ID="Package.__getattr__"></a> +<h4>Package.__getattr__</h4> +<b>__getattr__</b>(<i>key</i>) + +<a NAME="Package.__lt__" ID="Package.__lt__"></a> +<h4>Package.__lt__</h4> +<b>__lt__</b>(<i>rhs</i>) + +<a NAME="Package.__repr__" ID="Package.__repr__"></a> +<h4>Package.__repr__</h4> +<b>__repr__</b>(<i></i>) + +<a NAME="Package.render" ID="Package.render"></a> +<h4>Package.render</h4> +<b>render</b>(<i>parent=None, frozen=False</i>) + +<a NAME="Package.render_as_branch" ID="Package.render_as_branch"></a> +<h4>Package.render_as_branch</h4> +<b>render_as_branch</b>(<i>frozen</i>) + +<a NAME="Package.render_as_root" ID="Package.render_as_root"></a> +<h4>Package.render_as_root</h4> +<b>render_as_root</b>(<i>frozen</i>) + +<a NAME="Package.frozen_repr" ID="Package.frozen_repr"></a> +<h4>Package.frozen_repr (static)</h4> +<b>frozen_repr</b>(<i></i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="PackageDAG" ID="PackageDAG"></a> +<h2>PackageDAG</h2> + +<p> +Representation of Package dependencies as directed acyclic graph + using a dict (Mapping) as the underlying datastructure. +</p> +<p> + The nodes and their relationships (edges) are internally + stored using a map as follows, +</p> +<p> + {a: [b, c], + b: [d], + c: [d, e], + d: [e], + e: [], + f: [b], + g: [e, f]} +</p> +<p> + Here, node `a` has 2 children nodes `b` and `c`. Consider edge + direction from `a` -> `b` and `a` -> `c` respectively. +</p> +<p> + A node is expected to be an instance of a subclass of + `Package`. The keys are must be of class `DistPackage` and each + item in values must be of class `ReqPackage`. (See also + ReversedPackageDAG where the key and value types are + interchanged). +</p> +<p> + +</p> +<h3>Derived from</h3> +Mapping +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> + +<tr> +<td><a href="#PackageDAG.from_pkgs">from_pkgs</a></td> +<td></td> +</tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#PackageDAG.__init__">PackageDAG</a></td> +<td>Initialize the PackageDAG object</td> +</tr> +<tr> +<td><a href="#PackageDAG.__getitem__">__getitem__</a></td> +<td></td> +</tr> +<tr> +<td><a href="#PackageDAG.__iter__">__iter__</a></td> +<td></td> +</tr> +<tr> +<td><a href="#PackageDAG.__len__">__len__</a></td> +<td></td> +</tr> +<tr> +<td><a href="#PackageDAG.filter">filter</a></td> +<td>Filters nodes in a graph by given parameters</td> +</tr> +<tr> +<td><a href="#PackageDAG.get_children">get_children</a></td> +<td>Get child nodes for a node by it's key</td> +</tr> +<tr> +<td><a href="#PackageDAG.get_node_as_parent">get_node_as_parent</a></td> +<td>Get the node from the keys of the dict representing the DAG.</td> +</tr> +<tr> +<td><a href="#PackageDAG.reverse">reverse</a></td> +<td>Reverse the DAG, or turn it upside-down</td> +</tr> +<tr> +<td><a href="#PackageDAG.sort">sort</a></td> +<td>Return sorted tree in which the underlying _obj dict is an OrderedDict, sorted alphabetically by the keys</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="PackageDAG.from_pkgs" ID="PackageDAG.from_pkgs"></a> +<h4>PackageDAG.from_pkgs (class method)</h4> +<b>from_pkgs</b>(<i>pkgs</i>) + +<a NAME="PackageDAG.__init__" ID="PackageDAG.__init__"></a> +<h4>PackageDAG (Constructor)</h4> +<b>PackageDAG</b>(<i>m</i>) + +<p> +Initialize the PackageDAG object +</p> +<p> + :param dict m: dict of node objects (refer class docstring) + :returns: None + :rtype: NoneType +</p> +<p> + +</p> +<a NAME="PackageDAG.__getitem__" ID="PackageDAG.__getitem__"></a> +<h4>PackageDAG.__getitem__</h4> +<b>__getitem__</b>(<i>*args</i>) + +<a NAME="PackageDAG.__iter__" ID="PackageDAG.__iter__"></a> +<h4>PackageDAG.__iter__</h4> +<b>__iter__</b>(<i></i>) + +<a NAME="PackageDAG.__len__" ID="PackageDAG.__len__"></a> +<h4>PackageDAG.__len__</h4> +<b>__len__</b>(<i></i>) + +<a NAME="PackageDAG.filter" ID="PackageDAG.filter"></a> +<h4>PackageDAG.filter</h4> +<b>filter</b>(<i>include, exclude</i>) + +<p> +Filters nodes in a graph by given parameters +</p> +<p> + If a node is included, then all it's children are also + included. +</p> +<p> + :param set include: set of node keys to include (or None) + :param set exclude: set of node keys to exclude (or None) + :returns: filtered version of the graph + :rtype: PackageDAG +</p> +<p> + +</p> +<a NAME="PackageDAG.get_children" ID="PackageDAG.get_children"></a> +<h4>PackageDAG.get_children</h4> +<b>get_children</b>(<i>node_key</i>) + +<p> +Get child nodes for a node by it's key +</p> +<p> + :param str node_key: key of the node to get children of + :returns: list of child nodes + :rtype: ReqPackage[] +</p> +<p> + +</p> +<a NAME="PackageDAG.get_node_as_parent" ID="PackageDAG.get_node_as_parent"></a> +<h4>PackageDAG.get_node_as_parent</h4> +<b>get_node_as_parent</b>(<i>node_key</i>) + +<p> +Get the node from the keys of the dict representing the DAG. +</p> +<p> + This method is useful if the dict representing the DAG + contains different kind of objects in keys and values. Use + this method to lookup a node obj as a parent (from the keys of + the dict) given a node key. +</p> +<p> + :param node_key: identifier corresponding to key attr of node obj + :returns: node obj (as present in the keys of the dict) + :rtype: Object +</p> +<p> + +</p> +<a NAME="PackageDAG.reverse" ID="PackageDAG.reverse"></a> +<h4>PackageDAG.reverse</h4> +<b>reverse</b>(<i></i>) + +<p> +Reverse the DAG, or turn it upside-down +</p> +<p> + In other words, the directions of edges of the nodes in the + DAG will be reversed. +</p> +<p> + Note that this function purely works on the nodes in the + graph. This implies that to perform a combination of filtering + and reversing, the order in which `filter` and `reverse` + methods should be applied is important. For eg. if reverse is + called on a filtered graph, then only the filtered nodes and + it's children will be considered when reversing. On the other + hand, if filter is called on reversed DAG, then the definition + of "child" nodes is as per the reversed DAG. +</p> +<p> + :returns: DAG in the reversed form + :rtype: ReversedPackageDAG +</p> +<p> + +</p> +<a NAME="PackageDAG.sort" ID="PackageDAG.sort"></a> +<h4>PackageDAG.sort</h4> +<b>sort</b>(<i></i>) + +<p> +Return sorted tree in which the underlying _obj dict is an + OrderedDict, sorted alphabetically by the keys +</p> +<p> + :returns: Instance of same class with OrderedDict +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="ReqPackage" ID="ReqPackage"></a> +<h2>ReqPackage</h2> + +<p> +Wrapper class for Requirements instance +</p> +<p> + :param obj: The `Requirements` instance to wrap over + :param dist: optional `pkg_resources.Distribution` instance for + this requirement +</p> +<h3>Derived from</h3> +Package +<h3>Class Attributes</h3> + +<table> +<tr><td>UNKNOWN_VERSION</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#ReqPackage.__init__">ReqPackage</a></td> +<td></td> +</tr> +<tr> +<td><a href="#ReqPackage.as_dict">as_dict</a></td> +<td></td> +</tr> +<tr> +<td><a href="#ReqPackage.installed_version">installed_version</a></td> +<td></td> +</tr> +<tr> +<td><a href="#ReqPackage.is_conflicting">is_conflicting</a></td> +<td>If installed version conflicts with required version</td> +</tr> +<tr> +<td><a href="#ReqPackage.is_missing">is_missing</a></td> +<td></td> +</tr> +<tr> +<td><a href="#ReqPackage.render_as_branch">render_as_branch</a></td> +<td></td> +</tr> +<tr> +<td><a href="#ReqPackage.render_as_root">render_as_root</a></td> +<td></td> +</tr> +<tr> +<td><a href="#ReqPackage.version_spec">version_spec</a></td> +<td></td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="ReqPackage.__init__" ID="ReqPackage.__init__"></a> +<h4>ReqPackage (Constructor)</h4> +<b>ReqPackage</b>(<i>obj, dist=None</i>) + +<a NAME="ReqPackage.as_dict" ID="ReqPackage.as_dict"></a> +<h4>ReqPackage.as_dict</h4> +<b>as_dict</b>(<i></i>) + +<a NAME="ReqPackage.installed_version" ID="ReqPackage.installed_version"></a> +<h4>ReqPackage.installed_version</h4> +<b>installed_version</b>(<i></i>) + +<a NAME="ReqPackage.is_conflicting" ID="ReqPackage.is_conflicting"></a> +<h4>ReqPackage.is_conflicting</h4> +<b>is_conflicting</b>(<i></i>) + +<p> +If installed version conflicts with required version +</p> +<a NAME="ReqPackage.is_missing" ID="ReqPackage.is_missing"></a> +<h4>ReqPackage.is_missing</h4> +<b>is_missing</b>(<i></i>) + +<a NAME="ReqPackage.render_as_branch" ID="ReqPackage.render_as_branch"></a> +<h4>ReqPackage.render_as_branch</h4> +<b>render_as_branch</b>(<i>frozen</i>) + +<a NAME="ReqPackage.render_as_root" ID="ReqPackage.render_as_root"></a> +<h4>ReqPackage.render_as_root</h4> +<b>render_as_root</b>(<i>frozen</i>) + +<a NAME="ReqPackage.version_spec" ID="ReqPackage.version_spec"></a> +<h4>ReqPackage.version_spec</h4> +<b>version_spec</b>(<i></i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="ReversedPackageDAG" ID="ReversedPackageDAG"></a> +<h2>ReversedPackageDAG</h2> + +<p> +Representation of Package dependencies in the reverse + order. +</p> +<p> + Similar to it's super class `PackageDAG`, the underlying + datastructure is a dict, but here the keys are expected to be of + type `ReqPackage` and each item in the values of type + `DistPackage`. +</p> +<p> + Typically, this object will be obtained by calling + `PackageDAG.reverse`. +</p> +<p> + +</p> +<h3>Derived from</h3> +PackageDAG +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#ReversedPackageDAG.reverse">reverse</a></td> +<td>Reverse the already reversed DAG to get the PackageDAG again</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="ReversedPackageDAG.reverse" ID="ReversedPackageDAG.reverse"></a> +<h4>ReversedPackageDAG.reverse</h4> +<b>reverse</b>(<i></i>) + +<p> +Reverse the already reversed DAG to get the PackageDAG again +</p> +<p> + :returns: reverse of the reversed DAG + :rtype: PackageDAG +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="_get_args" ID="_get_args"></a> +<h2>_get_args</h2> +<b>_get_args</b>(<i></i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="aux" ID="aux"></a> +<h2>aux</h2> +<b>aux</b>(<i>node, parent=None, indent=0, chain=None</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="aux_1" ID="aux_1"></a> +<h2>aux</h2> +<b>aux</b>(<i>node, parent=None, chain=None</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="conflicting_deps" ID="conflicting_deps"></a> +<h2>conflicting_deps</h2> +<b>conflicting_deps</b>(<i>tree</i>) + +<p> +Returns dependencies which are not present or conflict with the + requirements of other packages. +</p> +<p> + e.g. will warn if pkg1 requires pkg2==2.0 and pkg2==1.0 is installed +</p> +<p> + :param tree: the requirements tree (dict) + :returns: dict of DistPackage -> list of unsatisfied/unknown ReqPackage + :rtype: dict +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="cyclic_deps" ID="cyclic_deps"></a> +<h2>cyclic_deps</h2> +<b>cyclic_deps</b>(<i>tree</i>) + +<p> +Return cyclic dependencies as list of tuples +</p> +<p> + :param PackageDAG pkgs: package tree/dag + :returns: list of tuples representing cyclic dependencies + :rtype: list +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="dump_graphviz" ID="dump_graphviz"></a> +<h2>dump_graphviz</h2> +<b>dump_graphviz</b>(<i>tree, output_format='dot', is_reverse=False</i>) + +<p> +Output dependency graph as one of the supported GraphViz output formats. +</p> +<p> + :param dict tree: dependency graph + :param string output_format: output format + :returns: representation of tree in the specified output format + :rtype: str or binary representation depending on the output format +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="frozen_req_from_dist" ID="frozen_req_from_dist"></a> +<h2>frozen_req_from_dist</h2> +<b>frozen_req_from_dist</b>(<i>dist</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="get_installed_distributions" ID="get_installed_distributions"></a> +<h2>get_installed_distributions</h2> +<b>get_installed_distributions</b>(<i>local_only=False, user_only=False</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="get_parser" ID="get_parser"></a> +<h2>get_parser</h2> +<b>get_parser</b>(<i></i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="guess_version" ID="guess_version"></a> +<h2>guess_version</h2> +<b>guess_version</b>(<i>pkg_key, default='?'</i>) + +<p> +Guess the version of a pkg when pip doesn't provide it +</p> +<p> + :param str pkg_key: key of the package + :param str default: default version to return if unable to find + :returns: version + :rtype: string +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="handle_non_host_target" ID="handle_non_host_target"></a> +<h2>handle_non_host_target</h2> +<b>handle_non_host_target</b>(<i>args</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="main" ID="main"></a> +<h2>main</h2> +<b>main</b>(<i></i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="print_graphviz" ID="print_graphviz"></a> +<h2>print_graphviz</h2> +<b>print_graphviz</b>(<i>dump_output</i>) + +<p> +Dump the data generated by GraphViz to stdout. +</p> +<p> + :param dump_output: The output from dump_graphviz +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="render_conflicts_text" ID="render_conflicts_text"></a> +<h2>render_conflicts_text</h2> +<b>render_conflicts_text</b>(<i>conflicts</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="render_cycles_text" ID="render_cycles_text"></a> +<h2>render_cycles_text</h2> +<b>render_cycles_text</b>(<i>cycles</i>) + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="render_json" ID="render_json"></a> +<h2>render_json</h2> +<b>render_json</b>(<i>tree, indent</i>) + +<p> +Converts the tree into a flat json representation. +</p> +<p> + The json repr will be a list of hashes, each hash having 2 fields: + - package + - dependencies: list of dependencies +</p> +<p> + :param dict tree: dependency tree + :param int indent: no. of spaces to indent json + :returns: json representation of the tree + :rtype: str +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="render_json_tree" ID="render_json_tree"></a> +<h2>render_json_tree</h2> +<b>render_json_tree</b>(<i>tree, indent</i>) + +<p> +Converts the tree into a nested json representation. +</p> +<p> + The json repr will be a list of hashes, each hash having the following fields: + - package_name + - key + - required_version + - installed_version + - dependencies: list of dependencies +</p> +<p> + :param dict tree: dependency tree + :param int indent: no. of spaces to indent json + :returns: json representation of the tree + :rtype: str +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="render_text" ID="render_text"></a> +<h2>render_text</h2> +<b>render_text</b>(<i>tree, list_all=True, frozen=False</i>) + +<p> +Print tree as text on console +</p> +<p> + :param dict tree: the package tree + :param bool list_all: whether to list all the pgks at the root + level or only those that are the + sub-dependencies + :param bool frozen: whether or not show the names of the pkgs in + the output that's favourable to pip --freeze + :returns: None +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="sorted_tree" ID="sorted_tree"></a> +<h2>sorted_tree</h2> +<b>sorted_tree</b>(<i>tree</i>) + +<p> +Sorts the dict representation of the tree +</p> +<p> + The root packages as well as the intermediate packages are sorted + in the alphabetical order of the package names. +</p> +<p> + :param dict tree: the pkg dependency tree obtained by calling + `construct_tree` function + :returns: sorted tree + :rtype: collections.OrderedDict +</p> +<p> + +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- a/src/eric7/Documentation/Source/index-eric7.PipInterface.html Mon Jul 11 17:56:42 2022 +0200 +++ b/src/eric7/Documentation/Source/index-eric7.PipInterface.html Tue Jul 12 16:26:22 2022 +0200 @@ -52,6 +52,10 @@ <td>Module implementing a Python package vulnerability checker.</td> </tr> <tr> +<td><a href="eric7.PipInterface.pipdeptree.html">pipdeptree</a></td> +<td>Copyright (c) 2015 Vineet Naik (naikvin@gmail.com)</td> +</tr> +<tr> <td><a href="eric7.PipInterface.piplicenses.html">piplicenses</a></td> <td>pip-licenses</td> </tr>
--- a/src/eric7/PipInterface/Pip.py Mon Jul 11 17:56:42 2022 +0200 +++ b/src/eric7/PipInterface/Pip.py Tue Jul 12 16:26:22 2022 +0200 @@ -943,10 +943,13 @@ if envName: interpreter = self.getVirtualenvInterpreter(envName) if interpreter: + from . import pipdeptree + with open(pipdeptree.__file__, "r") as f: + content = f.read() args = [ - "-m", "pipdeptree", + "-c", + content, "--json-tree", - "--python", interpreter, ] if localPackages: args.append("--local-only") @@ -956,7 +959,7 @@ args.append("--reverse") proc = QProcess() - proc.start(Globals.getPythonExecutable(), args) + proc.start(interpreter, args) if proc.waitForStarted(15000) and proc.waitForFinished(30000): output = str(proc.readAllStandardOutput(), Preferences.getSystem("IOEncoding"),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/PipInterface/pipdeptree.py Tue Jul 12 16:26:22 2022 +0200 @@ -0,0 +1,960 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Copyright (c) 2015 Vineet Naik (naikvin@gmail.com) + +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. +""" + +# +# Modified to be used within the eric-ide project. +# +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +from __future__ import print_function +import os +import inspect +import sys +import subprocess +from itertools import chain +from collections import defaultdict, deque +import argparse +import json +from importlib import import_module +import tempfile + +try: + from collections import OrderedDict +except ImportError: + from ordereddict import OrderedDict + +try: + from collections.abc import Mapping +except ImportError: + from collections import Mapping + +from pip._vendor import pkg_resources +try: + from pip._internal.operations.freeze import FrozenRequirement +except ImportError: + from pip import FrozenRequirement + + +__version__ = '2.2.1' + + +flatten = chain.from_iterable + + +def sorted_tree(tree): + """Sorts the dict representation of the tree + + The root packages as well as the intermediate packages are sorted + in the alphabetical order of the package names. + + :param dict tree: the pkg dependency tree obtained by calling + `construct_tree` function + :returns: sorted tree + :rtype: collections.OrderedDict + + """ + return OrderedDict([(k, sorted(v)) for k, v in sorted(tree.items())]) + + +def guess_version(pkg_key, default='?'): + """Guess the version of a pkg when pip doesn't provide it + + :param str pkg_key: key of the package + :param str default: default version to return if unable to find + :returns: version + :rtype: string + + """ + try: + m = import_module(pkg_key) + except ImportError: + return default + else: + v = getattr(m, '__version__', default) + if inspect.ismodule(v): + return getattr(v, '__version__', default) + else: + return v + + +def frozen_req_from_dist(dist): + # The `pip._internal.metadata` modules were introduced in 21.1.1 + # and the `pip._internal.operations.freeze.FrozenRequirement` + # class now expects dist to be a subclass of + # `pip._internal.metadata.BaseDistribution`, however the + # `pip._internal.utils.misc.get_installed_distributions` continues + # to return objects of type + # pip._vendor.pkg_resources.DistInfoDistribution. + # + # This is a hacky backward compatible (with older versions of pip) + # fix. + try: + from pip._internal import metadata + except ImportError: + pass + else: + dist = metadata.pkg_resources.Distribution(dist) + + try: + return FrozenRequirement.from_dist(dist) + except TypeError: + return FrozenRequirement.from_dist(dist, []) + + +class Package(object): + """Abstract class for wrappers around objects that pip returns. + + This class needs to be subclassed with implementations for + `render_as_root` and `render_as_branch` methods. + + """ + + def __init__(self, obj): + self._obj = obj + self.project_name = obj.project_name + self.key = obj.key + + def render_as_root(self, frozen): + return NotImplementedError + + def render_as_branch(self, frozen): + return NotImplementedError + + def render(self, parent=None, frozen=False): + if not parent: + return self.render_as_root(frozen) + else: + return self.render_as_branch(frozen) + + @staticmethod + def frozen_repr(obj): + fr = frozen_req_from_dist(obj) + return str(fr).strip() + + def __getattr__(self, key): + return getattr(self._obj, key) + + def __repr__(self): + return '<{0}("{1}")>'.format(self.__class__.__name__, self.key) + + def __lt__(self, rhs): + return self.key < rhs.key + + +class DistPackage(Package): + """Wrapper class for pkg_resources.Distribution instances + + :param obj: pkg_resources.Distribution to wrap over + :param req: optional ReqPackage object to associate this + DistPackage with. This is useful for displaying the + tree in reverse + """ + + def __init__(self, obj, req=None): + super(DistPackage, self).__init__(obj) + self.version_spec = None + self.req = req + + def render_as_root(self, frozen): + if not frozen: + return '{0}=={1}'.format(self.project_name, self.version) + else: + return self.__class__.frozen_repr(self._obj) + + def render_as_branch(self, frozen): + assert self.req is not None + if not frozen: + parent_ver_spec = self.req.version_spec + parent_str = self.req.project_name + if parent_ver_spec: + parent_str += parent_ver_spec + return ( + '{0}=={1} [requires: {2}]' + ).format(self.project_name, self.version, parent_str) + else: + return self.render_as_root(frozen) + + def as_requirement(self): + """Return a ReqPackage representation of this DistPackage""" + return ReqPackage(self._obj.as_requirement(), dist=self) + + def as_parent_of(self, req): + """Return a DistPackage instance associated to a requirement + + This association is necessary for reversing the PackageDAG. + + If `req` is None, and the `req` attribute of the current + instance is also None, then the same instance will be + returned. + + :param ReqPackage req: the requirement to associate with + :returns: DistPackage instance + + """ + if req is None and self.req is None: + return self + return self.__class__(self._obj, req) + + def as_dict(self): + return {'key': self.key, + 'package_name': self.project_name, + 'installed_version': self.version} + + +class ReqPackage(Package): + """Wrapper class for Requirements instance + + :param obj: The `Requirements` instance to wrap over + :param dist: optional `pkg_resources.Distribution` instance for + this requirement + """ + + UNKNOWN_VERSION = '?' + + def __init__(self, obj, dist=None): + super(ReqPackage, self).__init__(obj) + self.dist = dist + + @property + def version_spec(self): + specs = sorted(self._obj.specs, reverse=True) # `reverse` makes '>' prior to '<' + return ','.join([''.join(sp) for sp in specs]) if specs else None + + @property + def installed_version(self): + if not self.dist: + return guess_version(self.key, self.UNKNOWN_VERSION) + return self.dist.version + + @property + def is_missing(self): + return self.installed_version == self.UNKNOWN_VERSION + + def is_conflicting(self): + """If installed version conflicts with required version""" + # unknown installed version is also considered conflicting + if self.installed_version == self.UNKNOWN_VERSION: + return True + ver_spec = (self.version_spec if self.version_spec else '') + req_version_str = '{0}{1}'.format(self.project_name, ver_spec) + req_obj = pkg_resources.Requirement.parse(req_version_str) + return self.installed_version not in req_obj + + def render_as_root(self, frozen): + if not frozen: + return '{0}=={1}'.format(self.project_name, self.installed_version) + elif self.dist: + return self.__class__.frozen_repr(self.dist._obj) + else: + return self.project_name + + def render_as_branch(self, frozen): + if not frozen: + req_ver = self.version_spec if self.version_spec else 'Any' + return ( + '{0} [required: {1}, installed: {2}]' + ).format(self.project_name, req_ver, self.installed_version) + else: + return self.render_as_root(frozen) + + def as_dict(self): + return {'key': self.key, + 'package_name': self.project_name, + 'installed_version': self.installed_version, + 'required_version': self.version_spec} + + +class PackageDAG(Mapping): + """Representation of Package dependencies as directed acyclic graph + using a dict (Mapping) as the underlying datastructure. + + The nodes and their relationships (edges) are internally + stored using a map as follows, + + {a: [b, c], + b: [d], + c: [d, e], + d: [e], + e: [], + f: [b], + g: [e, f]} + + Here, node `a` has 2 children nodes `b` and `c`. Consider edge + direction from `a` -> `b` and `a` -> `c` respectively. + + A node is expected to be an instance of a subclass of + `Package`. The keys are must be of class `DistPackage` and each + item in values must be of class `ReqPackage`. (See also + ReversedPackageDAG where the key and value types are + interchanged). + + """ + + @classmethod + def from_pkgs(cls, pkgs): + pkgs = [DistPackage(p) for p in pkgs] + idx = {p.key: p for p in pkgs} + m = {p: [ReqPackage(r, idx.get(r.key)) + for r in p.requires()] + for p in pkgs} + return cls(m) + + def __init__(self, m): + """Initialize the PackageDAG object + + :param dict m: dict of node objects (refer class docstring) + :returns: None + :rtype: NoneType + + """ + self._obj = m + self._index = {p.key: p for p in list(self._obj)} + + def get_node_as_parent(self, node_key): + """Get the node from the keys of the dict representing the DAG. + + This method is useful if the dict representing the DAG + contains different kind of objects in keys and values. Use + this method to lookup a node obj as a parent (from the keys of + the dict) given a node key. + + :param node_key: identifier corresponding to key attr of node obj + :returns: node obj (as present in the keys of the dict) + :rtype: Object + + """ + try: + return self._index[node_key] + except KeyError: + return None + + def get_children(self, node_key): + """Get child nodes for a node by it's key + + :param str node_key: key of the node to get children of + :returns: list of child nodes + :rtype: ReqPackage[] + + """ + node = self.get_node_as_parent(node_key) + return self._obj[node] if node else [] + + def filter(self, include, exclude): + """Filters nodes in a graph by given parameters + + If a node is included, then all it's children are also + included. + + :param set include: set of node keys to include (or None) + :param set exclude: set of node keys to exclude (or None) + :returns: filtered version of the graph + :rtype: PackageDAG + + """ + # If neither of the filters are specified, short circuit + if include is None and exclude is None: + return self + + # Note: In following comparisons, we use lower cased values so + # that user may specify `key` or `project_name`. As per the + # documentation, `key` is simply + # `project_name.lower()`. Refer: + # https://setuptools.readthedocs.io/en/latest/pkg_resources.html#distribution-objects + if include: + include = set([s.lower() for s in include]) + if exclude: + exclude = set([s.lower() for s in exclude]) + else: + exclude = set([]) + + # Check for mutual exclusion of show_only and exclude sets + # after normalizing the values to lowercase + if include and exclude: + assert not (include & exclude) + + # Traverse the graph in a depth first manner and filter the + # nodes according to `show_only` and `exclude` sets + stack = deque() + m = {} + seen = set([]) + for node in self._obj.keys(): + if node.key in exclude: + continue + if include is None or node.key in include: + stack.append(node) + while True: + if len(stack) > 0: + n = stack.pop() + cldn = [c for c in self._obj[n] + if c.key not in exclude] + m[n] = cldn + seen.add(n.key) + for c in cldn: + if c.key not in seen: + cld_node = self.get_node_as_parent(c.key) + if cld_node: + stack.append(cld_node) + else: + # It means there's no root node + # corresponding to the child node + # ie. a dependency is missing + continue + else: + break + + return self.__class__(m) + + def reverse(self): + """Reverse the DAG, or turn it upside-down + + In other words, the directions of edges of the nodes in the + DAG will be reversed. + + Note that this function purely works on the nodes in the + graph. This implies that to perform a combination of filtering + and reversing, the order in which `filter` and `reverse` + methods should be applied is important. For eg. if reverse is + called on a filtered graph, then only the filtered nodes and + it's children will be considered when reversing. On the other + hand, if filter is called on reversed DAG, then the definition + of "child" nodes is as per the reversed DAG. + + :returns: DAG in the reversed form + :rtype: ReversedPackageDAG + + """ + m = defaultdict(list) + child_keys = set(r.key for r in flatten(self._obj.values())) + for k, vs in self._obj.items(): + for v in vs: + # if v is already added to the dict, then ensure that + # we are using the same object. This check is required + # as we're using array mutation + try: + node = [p for p in m.keys() if p.key == v.key][0] + except IndexError: + node = v + m[node].append(k.as_parent_of(v)) + if k.key not in child_keys: + m[k.as_requirement()] = [] + return ReversedPackageDAG(dict(m)) + + def sort(self): + """Return sorted tree in which the underlying _obj dict is an + OrderedDict, sorted alphabetically by the keys + + :returns: Instance of same class with OrderedDict + + """ + return self.__class__(sorted_tree(self._obj)) + + # Methods required by the abstract base class Mapping + def __getitem__(self, *args): + return self._obj.get(*args) + + def __iter__(self): + return self._obj.__iter__() + + def __len__(self): + return len(self._obj) + + +class ReversedPackageDAG(PackageDAG): + """Representation of Package dependencies in the reverse + order. + + Similar to it's super class `PackageDAG`, the underlying + datastructure is a dict, but here the keys are expected to be of + type `ReqPackage` and each item in the values of type + `DistPackage`. + + Typically, this object will be obtained by calling + `PackageDAG.reverse`. + + """ + + def reverse(self): + """Reverse the already reversed DAG to get the PackageDAG again + + :returns: reverse of the reversed DAG + :rtype: PackageDAG + + """ + m = defaultdict(list) + child_keys = set(r.key for r in flatten(self._obj.values())) + for k, vs in self._obj.items(): + for v in vs: + try: + node = [p for p in m.keys() if p.key == v.key][0] + except IndexError: + node = v.as_parent_of(None) + m[node].append(k) + if k.key not in child_keys: + m[k.dist] = [] + return PackageDAG(dict(m)) + + +def render_text(tree, list_all=True, frozen=False): + """Print tree as text on console + + :param dict tree: the package tree + :param bool list_all: whether to list all the pgks at the root + level or only those that are the + sub-dependencies + :param bool frozen: whether or not show the names of the pkgs in + the output that's favourable to pip --freeze + :returns: None + + """ + tree = tree.sort() + nodes = tree.keys() + branch_keys = set(r.key for r in flatten(tree.values())) + use_bullets = not frozen + + if not list_all: + nodes = [p for p in nodes if p.key not in branch_keys] + + def aux(node, parent=None, indent=0, chain=None): + chain = chain or [] + node_str = node.render(parent, frozen) + if parent: + prefix = ' '*indent + ('- ' if use_bullets else '') + node_str = prefix + node_str + result = [node_str] + children = [aux(c, node, indent=indent+2, + chain=chain+[c.project_name]) + for c in tree.get_children(node.key) + if c.project_name not in chain] + result += list(flatten(children)) + return result + + lines = flatten([aux(p) for p in nodes]) + print('\n'.join(lines)) + + +def render_json(tree, indent): + """Converts the tree into a flat json representation. + + The json repr will be a list of hashes, each hash having 2 fields: + - package + - dependencies: list of dependencies + + :param dict tree: dependency tree + :param int indent: no. of spaces to indent json + :returns: json representation of the tree + :rtype: str + + """ + tree = tree.sort() + return json.dumps([{'package': k.as_dict(), + 'dependencies': [v.as_dict() for v in vs]} + for k, vs in tree.items()], + indent=indent) + + +def render_json_tree(tree, indent): + """Converts the tree into a nested json representation. + + The json repr will be a list of hashes, each hash having the following fields: + - package_name + - key + - required_version + - installed_version + - dependencies: list of dependencies + + :param dict tree: dependency tree + :param int indent: no. of spaces to indent json + :returns: json representation of the tree + :rtype: str + + """ + tree = tree.sort() + branch_keys = set(r.key for r in flatten(tree.values())) + nodes = [p for p in tree.keys() if p.key not in branch_keys] + + def aux(node, parent=None, chain=None): + if chain is None: + chain = [node.project_name] + + d = node.as_dict() + if parent: + d['required_version'] = node.version_spec if node.version_spec else 'Any' + else: + d['required_version'] = d['installed_version'] + + d['dependencies'] = [ + aux(c, parent=node, chain=chain+[c.project_name]) + for c in tree.get_children(node.key) + if c.project_name not in chain + ] + + return d + + return json.dumps([aux(p) for p in nodes], indent=indent) + + +def dump_graphviz(tree, output_format='dot', is_reverse=False): + """Output dependency graph as one of the supported GraphViz output formats. + + :param dict tree: dependency graph + :param string output_format: output format + :returns: representation of tree in the specified output format + :rtype: str or binary representation depending on the output format + + """ + try: + from graphviz import Digraph + except ImportError: + print('graphviz is not available, but necessary for the output ' + 'option. Please install it.', file=sys.stderr) + sys.exit(1) + + try: + from graphviz import parameters + except ImportError: + from graphviz import backend + valid_formats = backend.FORMATS + print('Deprecation warning! Please upgrade graphviz to version >=0.18.0 ' + 'Support for older versions will be removed in upcoming release', + file=sys.stderr) + else: + valid_formats = parameters.FORMATS + + if output_format not in valid_formats: + print('{0} is not a supported output format.'.format(output_format), + file=sys.stderr) + print('Supported formats are: {0}'.format( + ', '.join(sorted(valid_formats))), file=sys.stderr) + sys.exit(1) + + graph = Digraph(format=output_format) + + if not is_reverse: + for pkg, deps in tree.items(): + pkg_label = '{0}\\n{1}'.format(pkg.project_name, pkg.version) + graph.node(pkg.key, label=pkg_label) + for dep in deps: + edge_label = dep.version_spec or 'any' + if dep.is_missing: + dep_label = '{0}\\n(missing)'.format(dep.project_name) + graph.node(dep.key, label=dep_label, style='dashed') + graph.edge(pkg.key, dep.key, style='dashed') + else: + graph.edge(pkg.key, dep.key, label=edge_label) + else: + for dep, parents in tree.items(): + dep_label = '{0}\\n{1}'.format(dep.project_name, + dep.installed_version) + graph.node(dep.key, label=dep_label) + for parent in parents: + # req reference of the dep associated with this + # particular parent package + req_ref = parent.req + edge_label = req_ref.version_spec or 'any' + graph.edge(dep.key, parent.key, label=edge_label) + + # Allow output of dot format, even if GraphViz isn't installed. + if output_format == 'dot': + return graph.source + + # As it's unknown if the selected output format is binary or not, try to + # decode it as UTF8 and only print it out in binary if that's not possible. + try: + return graph.pipe().decode('utf-8') + except UnicodeDecodeError: + return graph.pipe() + + +def print_graphviz(dump_output): + """Dump the data generated by GraphViz to stdout. + + :param dump_output: The output from dump_graphviz + """ + if hasattr(dump_output, 'encode'): + print(dump_output) + else: + with os.fdopen(sys.stdout.fileno(), 'wb') as bytestream: + bytestream.write(dump_output) + + +def conflicting_deps(tree): + """Returns dependencies which are not present or conflict with the + requirements of other packages. + + e.g. will warn if pkg1 requires pkg2==2.0 and pkg2==1.0 is installed + + :param tree: the requirements tree (dict) + :returns: dict of DistPackage -> list of unsatisfied/unknown ReqPackage + :rtype: dict + + """ + conflicting = defaultdict(list) + for p, rs in tree.items(): + for req in rs: + if req.is_conflicting(): + conflicting[p].append(req) + return conflicting + + +def render_conflicts_text(conflicts): + if conflicts: + print('Warning!!! Possibly conflicting dependencies found:', + file=sys.stderr) + # Enforce alphabetical order when listing conflicts + pkgs = sorted(conflicts.keys()) + for p in pkgs: + pkg = p.render_as_root(False) + print('* {}'.format(pkg), file=sys.stderr) + for req in conflicts[p]: + req_str = req.render_as_branch(False) + print(' - {}'.format(req_str), file=sys.stderr) + + +def cyclic_deps(tree): + """Return cyclic dependencies as list of tuples + + :param PackageDAG pkgs: package tree/dag + :returns: list of tuples representing cyclic dependencies + :rtype: list + + """ + index = {p.key: set([r.key for r in rs]) for p, rs in tree.items()} + cyclic = [] + for p, rs in tree.items(): + for r in rs: + if p.key in index.get(r.key, []): + p_as_dep_of_r = [x for x + in tree.get(tree.get_node_as_parent(r.key)) + if x.key == p.key][0] + cyclic.append((p, r, p_as_dep_of_r)) + return cyclic + + +def render_cycles_text(cycles): + if cycles: + print('Warning!! Cyclic dependencies found:', file=sys.stderr) + # List in alphabetical order of the dependency that's cycling + # (2nd item in the tuple) + cycles = sorted(cycles, key=lambda xs: xs[1].key) + for a, b, c in cycles: + print('* {0} => {1} => {2}'.format(a.project_name, + b.project_name, + c.project_name), + file=sys.stderr) + + +def get_parser(): + parser = argparse.ArgumentParser(description=( + 'Dependency tree of the installed python packages' + )) + parser.add_argument('-v', '--version', action='version', + version='{0}'.format(__version__)) + parser.add_argument('-f', '--freeze', action='store_true', + help='Print names so as to write freeze files') + parser.add_argument('--python', default=sys.executable, + help='Python to use to look for packages in it (default: where' + ' installed)') + parser.add_argument('-a', '--all', action='store_true', + help='list all deps at top level') + parser.add_argument('-l', '--local-only', + action='store_true', help=( + 'If in a virtualenv that has global access ' + 'do not show globally installed packages' + )) + parser.add_argument('-u', '--user-only', action='store_true', + help=( + 'Only show installations in the user site dir' + )) + parser.add_argument('-w', '--warn', action='store', dest='warn', + nargs='?', default='suppress', + choices=('silence', 'suppress', 'fail'), + help=( + 'Warning control. "suppress" will show warnings ' + 'but return 0 whether or not they are present. ' + '"silence" will not show warnings at all and ' + 'always return 0. "fail" will show warnings and ' + 'return 1 if any are present. The default is ' + '"suppress".' + )) + parser.add_argument('-r', '--reverse', action='store_true', + default=False, help=( + 'Shows the dependency tree in the reverse fashion ' + 'ie. the sub-dependencies are listed with the ' + 'list of packages that need them under them.' + )) + parser.add_argument('-p', '--packages', + help=( + 'Comma separated list of select packages to show ' + 'in the output. If set, --all will be ignored.' + )) + parser.add_argument('-e', '--exclude', + help=( + 'Comma separated list of select packages to exclude ' + 'from the output. If set, --all will be ignored.' + ), metavar='PACKAGES') + parser.add_argument('-j', '--json', action='store_true', default=False, + help=( + 'Display dependency tree as json. This will yield ' + '"raw" output that may be used by external tools. ' + 'This option overrides all other options.' + )) + parser.add_argument('--json-tree', action='store_true', default=False, + help=( + 'Display dependency tree as json which is nested ' + 'the same way as the plain text output printed by default. ' + 'This option overrides all other options (except --json).' + )) + parser.add_argument('--graph-output', dest='output_format', + help=( + 'Print a dependency graph in the specified output ' + 'format. Available are all formats supported by ' + 'GraphViz, e.g.: dot, jpeg, pdf, png, svg' + )) + return parser + + +def _get_args(): + parser = get_parser() + return parser.parse_args() + + +def handle_non_host_target(args): + of_python = os.path.abspath(args.python) + # if target is not current python re-invoke it under the actual host + if of_python != os.path.abspath(sys.executable): + # there's no way to guarantee that graphviz is available, so refuse + if args.output_format: + print("graphviz functionality is not supported when querying" + " non-host python", file=sys.stderr) + raise SystemExit(1) + argv = sys.argv[1:] # remove current python executable + for py_at, value in enumerate(argv): + if value == "--python": + del argv[py_at] + del argv[py_at] + elif value.startswith("--python"): + del argv[py_at] + # feed the file as argument, instead of file + # to avoid adding the file path to sys.path, that can affect result + file_path = inspect.getsourcefile(sys.modules[__name__]) + with open(file_path, 'rt') as file_handler: + content = file_handler.read() + cmd = [of_python, "-c", content] + cmd.extend(argv) + # invoke from an empty folder to avoid cwd altering sys.path + cwd = tempfile.mkdtemp() + try: + return subprocess.call(cmd, cwd=cwd) + finally: + os.removedirs(cwd) + return None + + +def get_installed_distributions(local_only=False, user_only=False): + try: + from pip._internal.metadata import get_environment + except ImportError: + # For backward compatibility with python ver. 2.7 and pip + # version 20.3.4 (latest pip version that works with python + # version 2.7) + from pip._internal.utils import misc + return misc.get_installed_distributions( + local_only=local_only, + user_only=user_only + ) + else: + dists = get_environment(None).iter_installed_distributions( + local_only=local_only, + skip=(), + user_only=user_only + ) + return [d._dist for d in dists] + + +def main(): + os.environ["_PIP_USE_IMPORTLIB_METADATA"] = "False" + # patched for 3.11+ compatibility + + args = _get_args() + result = handle_non_host_target(args) + if result is not None: + return result + + pkgs = get_installed_distributions(local_only=args.local_only, + user_only=args.user_only) + + tree = PackageDAG.from_pkgs(pkgs) + + is_text_output = not any([args.json, args.json_tree, args.output_format]) + + return_code = 0 + + # Before any reversing or filtering, show warnings to console + # about possibly conflicting or cyclic deps if found and warnings + # are enabled (ie. only if output is to be printed to console) + if is_text_output and args.warn != 'silence': + conflicts = conflicting_deps(tree) + if conflicts: + render_conflicts_text(conflicts) + print('-'*72, file=sys.stderr) + + cycles = cyclic_deps(tree) + if cycles: + render_cycles_text(cycles) + print('-'*72, file=sys.stderr) + + if args.warn == 'fail' and (conflicts or cycles): + return_code = 1 + + # Reverse the tree (if applicable) before filtering, thus ensuring + # that the filter will be applied on ReverseTree + if args.reverse: + tree = tree.reverse() + + show_only = set(args.packages.split(',')) if args.packages else None + exclude = set(args.exclude.split(',')) if args.exclude else None + + if show_only is not None or exclude is not None: + tree = tree.filter(show_only, exclude) + + if args.json: + print(render_json(tree, indent=4)) + elif args.json_tree: + print(render_json_tree(tree, indent=4)) + elif args.output_format: + output = dump_graphviz(tree, + output_format=args.output_format, + is_reverse=args.reverse) + print_graphviz(output) + else: + render_text(tree, args.all, args.freeze) + + return return_code + + +if __name__ == '__main__': + sys.exit(main())
--- a/src/eric7/PipInterface/piplicenses.py Mon Jul 11 17:56:42 2022 +0200 +++ b/src/eric7/PipInterface/piplicenses.py Tue Jul 12 16:26:22 2022 +0200 @@ -652,6 +652,9 @@ def main(): # pragma: no cover + os.environ["_PIP_USE_IMPORTLIB_METADATA"] = "False" + # patched for 3.11+ compatibility + parser = create_parser() args = parser.parse_args()