forked from qt-creator/qt-creator
Add pyproject.toml support for Python projects
This patch adds support for the standard Python project configuration file: pyproject.toml. It is intended to replace *.pyproject files. Task-number: QTCREATORBUG-22492 Task-number: PYSIDE-2714 Change-Id: I783ee7b49be23c61b0a501ef9bbd722cc652ad14 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Jaime Resano <Jaime.RESANO-AISA@qt.io>
This commit is contained in:
committed by
Jaime Resano
parent
69b9d6cb82
commit
2384da479c
@@ -4,6 +4,7 @@ add_qtc_plugin(Python
|
||||
SOURCES
|
||||
../../libs/3rdparty/toml11/toml.hpp
|
||||
pipsupport.cpp pipsupport.h
|
||||
pyprojecttoml.cpp pyprojecttoml.h
|
||||
pyside.cpp pyside.h
|
||||
pythonbuildconfiguration.cpp pythonbuildconfiguration.h
|
||||
pysideuicextracompiler.cpp pysideuicextracompiler.h
|
||||
|
@@ -49,6 +49,11 @@
|
||||
" <comment>Qt Creator Python project file</comment>",
|
||||
" <glob pattern='*.pyproject'/>",
|
||||
" </mime-type>",
|
||||
" <mime-type type='text/x-python-pyproject-toml'>",
|
||||
" <sub-class-of type='application/toml'/>",
|
||||
" <comment>Python TOML project file</comment>",
|
||||
" <glob pattern='pyproject.toml'/>",
|
||||
" </mime-type>",
|
||||
" <mime-type type='text/x-python3'>",
|
||||
" <comment>Python3 script</comment>",
|
||||
" <sub-class-of type='text/x-python'/>",
|
||||
|
269
src/plugins/python/pyprojecttoml.cpp
Normal file
269
src/plugins/python/pyprojecttoml.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "pyprojecttoml.h"
|
||||
#include "pythontr.h"
|
||||
|
||||
#include <3rdparty/toml11/toml.hpp>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
PyProjectTomlError PyProjectTomlError::ParseError(const std::string &description, int line)
|
||||
{
|
||||
return PyProjectTomlError(
|
||||
PyProjectTomlErrorType::ParsingError,
|
||||
Tr::tr("Parsing error: %1").arg(QString::fromUtf8(description)),
|
||||
line);
|
||||
}
|
||||
|
||||
PyProjectTomlError PyProjectTomlError::TypeError(
|
||||
const std::string &nodeName,
|
||||
const std::string &expectedType,
|
||||
const std::string &actualType,
|
||||
int line)
|
||||
{
|
||||
return PyProjectTomlError(
|
||||
PyProjectTomlErrorType::TypeError,
|
||||
Tr::tr("Type error: \"%1\" must be a \"%2\", not a \"%3\"")
|
||||
.arg(QString::fromUtf8(nodeName))
|
||||
.arg(QString::fromUtf8(expectedType))
|
||||
.arg(QString::fromUtf8(actualType)),
|
||||
line);
|
||||
}
|
||||
|
||||
PyProjectTomlError PyProjectTomlError::MissingNodeError(
|
||||
const std::string &nodeName, const std::string &key, int line)
|
||||
{
|
||||
return PyProjectTomlError(
|
||||
PyProjectTomlErrorType::MissingNode,
|
||||
Tr::tr("Missing node error: \"%1\" table must contain a \"%2\" node")
|
||||
.arg(QString::fromUtf8(nodeName))
|
||||
.arg(QString::fromUtf8(key)),
|
||||
line);
|
||||
}
|
||||
|
||||
PyProjectTomlError PyProjectTomlError::EmptyNodeError(const std::string &nodeName, int line)
|
||||
{
|
||||
return PyProjectTomlError(
|
||||
PyProjectTomlErrorType::EmptyNode,
|
||||
Tr::tr("Node \"%1\" is empty").arg(QString::fromUtf8(nodeName)),
|
||||
line);
|
||||
}
|
||||
|
||||
PyProjectTomlError PyProjectTomlError::FileNotFoundError(const std::string &filePath, int line)
|
||||
{
|
||||
return PyProjectTomlError(
|
||||
PyProjectTomlErrorType::FileNotFound,
|
||||
Tr::tr("File \"%1\" does not exist.").arg(QString::fromUtf8(filePath)),
|
||||
line);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns the value associated with a given key from a TOML table node, if it exists.
|
||||
The value can be a TOML table, array or primitive value.
|
||||
\tparam ExpectedType The type of the value to fetch. Must be a TOML value type.
|
||||
\param expectedTypeName The name of the expected type
|
||||
\param tableName The name of the table to fetch the value from
|
||||
\param table The table to fetch the value from
|
||||
\param key The key to fetch the value from. May be a dotted key.
|
||||
\return The value if found, otherwise an error string
|
||||
\note The \a expectedTypeName and \a tableName parameters are only used for error reporting
|
||||
*/
|
||||
template<typename ExpectedType>
|
||||
expected<ExpectedType, PyProjectTomlError> getNodeByKey(
|
||||
const std::string expectedTypeName,
|
||||
const std::string tableName,
|
||||
const toml::ordered_value &table,
|
||||
const std::string key)
|
||||
{
|
||||
// Edge case: Do not show the the root table errors in a specific line
|
||||
int nodeLine = tableName != "root" ? static_cast<int>(table.location().first_line_number())
|
||||
: -1;
|
||||
|
||||
if (!table.is_table()) {
|
||||
return make_unexpected(PyProjectTomlError::TypeError(
|
||||
tableName, "table", toml::to_string(table.type()), nodeLine));
|
||||
}
|
||||
|
||||
try {
|
||||
const auto &node = toml::find(table, key);
|
||||
return getNodeValue<ExpectedType>(expectedTypeName, key, node);
|
||||
} catch (const std::out_of_range &) {
|
||||
return make_unexpected(PyProjectTomlError::MissingNodeError(tableName, key, nodeLine));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Fetches a value of certain type from a TOML node by key if existing
|
||||
|
||||
\tparam ExpectedType The type of the value to fetch. Must be a TOML primitive value type.
|
||||
\param expectedTypeName The name of the expected type
|
||||
\param nodeName The name of the node to fetch the value from
|
||||
\param node The node to fetch the value from
|
||||
|
||||
\return The value if found, otherwise an error string
|
||||
|
||||
\note The \a expectedTypeName and \a nodeName parameters are only used for error reporting
|
||||
*/
|
||||
template<typename ExpectedType>
|
||||
expected<ExpectedType, PyProjectTomlError> getNodeValue(
|
||||
const std::string expectedTypeName, const std::string nodeName, const toml::ordered_value &node)
|
||||
{
|
||||
auto nodeLine = static_cast<int>(node.location().first_line_number());
|
||||
|
||||
if (node.is_empty())
|
||||
return make_unexpected(PyProjectTomlError::EmptyNodeError(nodeName, nodeLine));
|
||||
|
||||
if constexpr (std::is_same_v<ExpectedType, toml::table>) {
|
||||
if (!node.is_table())
|
||||
return make_unexpected(PyProjectTomlError::TypeError(
|
||||
nodeName, "table", toml::to_string(node.type()), nodeLine));
|
||||
return node.as_table();
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<ExpectedType, toml::array>) {
|
||||
if (!node.is_array())
|
||||
return make_unexpected(PyProjectTomlError::TypeError(
|
||||
nodeName, "array", toml::to_string(node.type()), nodeLine));
|
||||
return node.as_array();
|
||||
}
|
||||
|
||||
try {
|
||||
return toml::get<ExpectedType>(node);
|
||||
} catch (const toml::type_error &) {
|
||||
return make_unexpected(PyProjectTomlError::TypeError(
|
||||
nodeName, expectedTypeName, toml::to_string(node.type()), nodeLine));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
\brief Parses the given pyproject.toml file and returns a PyProjectTomlParseResult
|
||||
\param pyProjectTomlPath The path to the pyproject.toml file
|
||||
\returns A PyProjectTomlParseResult containing the errors found and the project information
|
||||
*/
|
||||
PyProjectTomlParseResult parsePyProjectToml(const FilePath &pyProjectTomlPath)
|
||||
{
|
||||
PyProjectTomlParseResult result;
|
||||
|
||||
const expected_str<QByteArray> fileContentsResult = pyProjectTomlPath.fileContents();
|
||||
if (!fileContentsResult) {
|
||||
result.errors << PyProjectTomlError::FileNotFoundError(
|
||||
pyProjectTomlPath.toUserOutput().toStdString(), -1);
|
||||
return result;
|
||||
}
|
||||
|
||||
QString pyProjectTomlContent = QString::fromUtf8(fileContentsResult.value());
|
||||
toml::ordered_value rootTable;
|
||||
try {
|
||||
rootTable = toml::parse_str<toml::ordered_type_config>(pyProjectTomlContent.toStdString());
|
||||
} catch (const toml::syntax_error &syntaxErrors) {
|
||||
for (const auto &error : syntaxErrors.errors()) {
|
||||
auto errorLine = static_cast<int>(error.locations().at(0).first.first_line_number());
|
||||
result.errors << PyProjectTomlError::ParseError(error.title(), errorLine);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto projectTable = getNodeByKey<toml::ordered_value>("table", "root", rootTable, "project");
|
||||
if (!projectTable) {
|
||||
result.errors << projectTable.error();
|
||||
return result;
|
||||
}
|
||||
|
||||
auto projectName = getNodeByKey<std::string>("table", "project", projectTable.value(), "name");
|
||||
if (!projectName) {
|
||||
result.errors << projectName.error();
|
||||
} else {
|
||||
result.projectName = QString::fromUtf8(projectName.value());
|
||||
}
|
||||
|
||||
auto toolTable = getNodeByKey<toml::ordered_value>("table", "root", rootTable, "tool");
|
||||
if (!toolTable) {
|
||||
result.errors << toolTable.error();
|
||||
return result;
|
||||
}
|
||||
|
||||
auto pysideTable
|
||||
= getNodeByKey<toml::ordered_value>("table", "tool", toolTable.value(), "pyside6-project");
|
||||
if (!pysideTable) {
|
||||
result.errors << pysideTable.error();
|
||||
return result;
|
||||
}
|
||||
|
||||
auto files
|
||||
= getNodeByKey<toml::ordered_array>("array", "pyside6-project", pysideTable.value(), "files");
|
||||
if (!files) {
|
||||
result.errors << files.error();
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto &filesArray = files.value();
|
||||
result.projectFiles.reserve(filesArray.size());
|
||||
|
||||
for (const auto &fileNode : filesArray) {
|
||||
auto possibleFile = getNodeValue<std::string>("string", "file", fileNode);
|
||||
if (!possibleFile) {
|
||||
result.errors << possibleFile.error();
|
||||
continue;
|
||||
}
|
||||
auto file = QString::fromUtf8(possibleFile.value());
|
||||
auto filePath = pyProjectTomlPath.parentDir().pathAppended(file);
|
||||
if (!filePath.exists()) {
|
||||
auto line = static_cast<int>(fileNode.location().first_line_number());
|
||||
result.errors << PyProjectTomlError::FileNotFoundError(possibleFile.value(), line);
|
||||
continue;
|
||||
}
|
||||
result.projectFiles.append(file);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Given an existing pyproject.toml file, update it with the given \a projectFiles.
|
||||
\return If successful, returns the new contents of the file. Otherwise, returns an error.
|
||||
*/
|
||||
expected_str<QString> updatePyProjectTomlContent(
|
||||
const QString &pyProjectTomlContent, const QStringList &projectFiles)
|
||||
{
|
||||
toml::ordered_value rootTable;
|
||||
try {
|
||||
rootTable = toml::parse_str<toml::ordered_type_config>(pyProjectTomlContent.toStdString());
|
||||
} catch (const toml::exception &error) {
|
||||
return make_unexpected(QString::fromUtf8(error.what()));
|
||||
}
|
||||
|
||||
auto &toolTable = rootTable["tool"];
|
||||
if (!toolTable.is_table()) {
|
||||
toolTable = toml::ordered_table{};
|
||||
}
|
||||
|
||||
auto &pysideTable = toolTable.as_table()["pyside6-project"];
|
||||
if (!pysideTable.is_table()) {
|
||||
pysideTable = toml::ordered_table{};
|
||||
}
|
||||
|
||||
std::vector<std::string> filesArray;
|
||||
filesArray.reserve(projectFiles.size());
|
||||
std::transform(
|
||||
projectFiles.begin(),
|
||||
projectFiles.end(),
|
||||
std::back_inserter(filesArray),
|
||||
[](const QString &file) { return file.toStdString(); });
|
||||
std::sort(filesArray.begin(), filesArray.end());
|
||||
|
||||
pysideTable["files"] = std::move(filesArray);
|
||||
|
||||
auto result = QString::fromUtf8(toml::format(rootTable));
|
||||
// For some reason, the TOML library adds two trailing newlines.
|
||||
while (result.endsWith("\n\n")) {
|
||||
result.chop(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Python::Internal
|
71
src/plugins/python/pyprojecttoml.h
Normal file
71
src/plugins/python/pyprojecttoml.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3rdparty/toml11/toml.hpp>
|
||||
#include <projectexplorer/buildsystem.h>
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
enum class PyProjectTomlErrorType { ParsingError, MissingNode, TypeError, EmptyNode, FileNotFound };
|
||||
|
||||
/*
|
||||
\brief Class representing a generic error found in a pyproject.toml file
|
||||
Not intended to be constructed directly, but rather calling one of the static factory methods
|
||||
to create an instance of this class with the appropriate \a description format.
|
||||
\sa PyProjectTomlParseResult
|
||||
*/
|
||||
struct PyProjectTomlError
|
||||
{
|
||||
PyProjectTomlErrorType type;
|
||||
QString description;
|
||||
int line;
|
||||
|
||||
PyProjectTomlError(PyProjectTomlErrorType type, const QString &description, int line = -1)
|
||||
: type(type)
|
||||
, description(description)
|
||||
, line(line)
|
||||
{}
|
||||
|
||||
bool operator==(const PyProjectTomlError &other) const
|
||||
{
|
||||
return type == other.type && description == other.description && line == other.line;
|
||||
}
|
||||
|
||||
static PyProjectTomlError ParseError(const std::string &description, int line = -1);
|
||||
static PyProjectTomlError TypeError(
|
||||
const std::string &nodeName,
|
||||
const std::string &expectedTypeName,
|
||||
const std::string &actualType,
|
||||
int line = -1);
|
||||
static PyProjectTomlError MissingNodeError(
|
||||
const std::string &nodeName, const std::string &key, int line = -1);
|
||||
static PyProjectTomlError EmptyNodeError(const std::string &nodeName, int line = -1);
|
||||
static PyProjectTomlError FileNotFoundError(const std::string &filePath, int line = -1);
|
||||
};
|
||||
|
||||
struct PyProjectTomlParseResult
|
||||
{
|
||||
QList<PyProjectTomlError> errors;
|
||||
QString projectName;
|
||||
QStringList projectFiles;
|
||||
};
|
||||
|
||||
template<typename ExpectedType>
|
||||
Utils::expected<ExpectedType, PyProjectTomlError> getNodeByKey(
|
||||
const std::string expectedTypeName,
|
||||
const std::string tableName,
|
||||
const toml::ordered_value &table,
|
||||
const std::string key);
|
||||
|
||||
template<typename ExpectedType>
|
||||
Utils::expected<ExpectedType, PyProjectTomlError> getNodeValue(
|
||||
const std::string expectedTypeName, const std::string nodeName, const toml::ordered_value &node);
|
||||
|
||||
PyProjectTomlParseResult parsePyProjectToml(const Utils::FilePath &pyProjectTomlPath);
|
||||
|
||||
Utils::expected_str<QString> updatePyProjectTomlContent(
|
||||
const QString &pyProjectTomlContent, const QStringList &projectFiles);
|
||||
|
||||
} // namespace Python::Internal
|
@@ -21,6 +21,8 @@ QtcPlugin {
|
||||
"../../libs/3rdparty/toml11/toml.hpp",
|
||||
"pipsupport.cpp",
|
||||
"pipsupport.h",
|
||||
"pyprojecttoml.cpp",
|
||||
"pyprojecttoml.h",
|
||||
"pyside.cpp",
|
||||
"pyside.h",
|
||||
"pythonbuildconfiguration.cpp",
|
||||
|
@@ -391,7 +391,8 @@ public:
|
||||
{
|
||||
registerBuildConfiguration<PythonBuildConfiguration>("Python.PySideBuildConfiguration");
|
||||
setSupportedProjectType(PythonProjectId);
|
||||
setSupportedProjectMimeTypeName(Constants::C_PY_PROJECT_MIME_TYPE);
|
||||
setSupportedProjectMimeTypeNames(
|
||||
{Constants::C_PY_PROJECT_MIME_TYPE, Constants::C_PY_PROJECT_MIME_TYPE_TOML});
|
||||
setBuildGenerator([](const Kit *k, const FilePath &projectPath, bool forSetup) {
|
||||
if (std::optional<Interpreter> python = PythonKitAspect::python(k)) {
|
||||
BuildInfo base;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pythonbuildsystem.h"
|
||||
|
||||
#include "pyprojecttoml.h"
|
||||
#include "pythonbuildconfiguration.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonproject.h"
|
||||
@@ -10,9 +11,11 @@
|
||||
|
||||
#include <coreplugin/documentmanager.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <coreplugin/textdocument.h>
|
||||
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
|
||||
@@ -216,28 +219,50 @@ void PythonBuildSystem::triggerParsing()
|
||||
emitBuildSystemUpdated();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Saves the build system configuration in the corresponding project file.
|
||||
Currently, three project file formats are supported: pyproject.toml, *.pyproject and the legacy
|
||||
*.pyqtc file.
|
||||
\returns true if the save was successful, false otherwise.
|
||||
*/
|
||||
bool PythonBuildSystem::save()
|
||||
{
|
||||
const FilePath filePath = projectFilePath();
|
||||
const QStringList rawList = Utils::transform(m_files, &FileEntry::rawEntry);
|
||||
const QStringList projectFiles = Utils::transform(m_files, &FileEntry::rawEntry);
|
||||
const FileChangeBlocker changeGuard(filePath);
|
||||
|
||||
QByteArray newContents;
|
||||
|
||||
// New project file
|
||||
if (filePath.endsWith(".pyproject")) {
|
||||
if (filePath.fileName() == "pyproject.toml") {
|
||||
Core::BaseTextDocument projectFile;
|
||||
QString pyProjectTomlContent;
|
||||
QString readingError;
|
||||
auto result = projectFile.read(filePath, &pyProjectTomlContent, &readingError);
|
||||
if (result != TextFileFormat::ReadSuccess) {
|
||||
MessageManager::writeDisrupting(readingError);
|
||||
return false;
|
||||
}
|
||||
auto newPyProjectToml = updatePyProjectTomlContent(pyProjectTomlContent, projectFiles);
|
||||
if (!newPyProjectToml) {
|
||||
MessageManager::writeDisrupting(newPyProjectToml.error());
|
||||
return false;
|
||||
}
|
||||
newContents = newPyProjectToml.value().toUtf8();
|
||||
} else if (filePath.endsWith(".pyproject")) {
|
||||
// *.pyproject project file
|
||||
expected_str<QByteArray> contents = filePath.fileContents();
|
||||
if (contents) {
|
||||
if (!contents) {
|
||||
MessageManager::writeDisrupting(contents.error());
|
||||
return false;
|
||||
}
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*contents);
|
||||
QJsonObject project = doc.object();
|
||||
project["files"] = QJsonArray::fromStringList(rawList);
|
||||
project["files"] = QJsonArray::fromStringList(projectFiles);
|
||||
doc.setObject(project);
|
||||
newContents = doc.toJson();
|
||||
} else {
|
||||
MessageManager::writeDisrupting(contents.error());
|
||||
}
|
||||
} else { // Old project file
|
||||
newContents = rawList.join('\n').toUtf8();
|
||||
// Old project file
|
||||
newContents = projectFiles.join('\n').toUtf8();
|
||||
}
|
||||
|
||||
const expected_str<qint64> writeResult = filePath.writeFileContents(newContents);
|
||||
@@ -326,14 +351,14 @@ void PythonBuildSystem::parse()
|
||||
QStringList qmlImportPaths;
|
||||
|
||||
const FilePath filePath = projectFilePath();
|
||||
// The PySide project file is JSON based
|
||||
if (filePath.endsWith(".pyproject")) {
|
||||
QString errorMessage;
|
||||
if (filePath.endsWith(".pyproject")) {
|
||||
// The PySide .pyproject file is JSON based
|
||||
files = readLinesJson(filePath, &errorMessage);
|
||||
if (!errorMessage.isEmpty())
|
||||
if (!errorMessage.isEmpty()) {
|
||||
MessageManager::writeFlashing(errorMessage);
|
||||
|
||||
errorMessage.clear();
|
||||
}
|
||||
qmlImportPaths = readImportPathsJson(filePath, &errorMessage);
|
||||
if (!errorMessage.isEmpty())
|
||||
MessageManager::writeFlashing(errorMessage);
|
||||
@@ -341,6 +366,20 @@ void PythonBuildSystem::parse()
|
||||
// To keep compatibility with PyQt we keep the compatibility with plain
|
||||
// text files as project files.
|
||||
files = readLines(filePath);
|
||||
} else if (filePath.fileName() == "pyproject.toml") {
|
||||
auto pyProjectTomlParseResult = parsePyProjectToml(filePath);
|
||||
|
||||
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
||||
for (const PyProjectTomlError &error : pyProjectTomlParseResult.errors) {
|
||||
TaskHub::addTask(
|
||||
BuildSystemTask(Task::TaskType::Error, error.description, filePath, error.line));
|
||||
}
|
||||
|
||||
if (!pyProjectTomlParseResult.projectName.isEmpty()) {
|
||||
project()->setDisplayName(pyProjectTomlParseResult.projectName);
|
||||
}
|
||||
|
||||
files = pyProjectTomlParseResult.projectFiles;
|
||||
}
|
||||
|
||||
m_files = processEntries(files);
|
||||
|
@@ -34,7 +34,7 @@ const char C_PY3_MIMETYPE[] = "text/x-python3";
|
||||
const char C_PY_MIME_ICON[] = "text-x-python";
|
||||
const char C_PY_PROJECT_MIME_TYPE[] = "text/x-python-project";
|
||||
const char C_PY_PROJECT_MIME_TYPE_LEGACY[] = "text/x-pyqt-project";
|
||||
|
||||
const char C_PY_PROJECT_MIME_TYPE_TOML[] = "text/x-python-pyproject-toml";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace Python
|
||||
|
@@ -146,12 +146,12 @@ void PythonEditorWidget::updateInterpretersSelector()
|
||||
};
|
||||
|
||||
const FilePath documentPath = textDocument()->filePath();
|
||||
Project *project = Utils::findOrDefault(ProjectManager::projects(),
|
||||
[documentPath](Project *project) {
|
||||
return project->mimeType()
|
||||
== Constants::C_PY_PROJECT_MIME_TYPE
|
||||
&& project->isKnownFile(documentPath);
|
||||
});
|
||||
const auto isPythonProject = [documentPath](Project *project) {
|
||||
return project->isKnownFile(documentPath) && (
|
||||
project->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE ||
|
||||
project->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE_TOML);
|
||||
};
|
||||
Project *project = Utils::findOrDefault(ProjectManager::projects(), isPythonProject);
|
||||
|
||||
if (project) {
|
||||
auto interpretersGroup = new QActionGroup(menu);
|
||||
|
@@ -92,8 +92,8 @@ class PythonPlugin final : public ExtensionSystem::IPlugin
|
||||
|
||||
setupPipSupport(this);
|
||||
|
||||
KitManager::setIrrelevantAspects(KitManager::irrelevantAspects()
|
||||
+ QSet<Id>{PythonKitAspect::id()});
|
||||
KitManager::setIrrelevantAspects(
|
||||
KitManager::irrelevantAspects() + QSet<Id>{PythonKitAspect::id()});
|
||||
|
||||
const auto issuesGenerator = [](const Kit *k) -> Tasks {
|
||||
if (!PythonKitAspect::python(k))
|
||||
@@ -106,6 +106,8 @@ class PythonPlugin final : public ExtensionSystem::IPlugin
|
||||
Constants::C_PY_PROJECT_MIME_TYPE, issuesGenerator);
|
||||
ProjectManager::registerProjectType<PythonProject>(
|
||||
Constants::C_PY_PROJECT_MIME_TYPE_LEGACY, issuesGenerator);
|
||||
ProjectManager::registerProjectType<PythonProject>(
|
||||
Constants::C_PY_PROJECT_MIME_TYPE_TOML, issuesGenerator);
|
||||
|
||||
auto oldHighlighter = Utils::Text::codeHighlighter();
|
||||
Utils::Text::setCodeHighlighter(
|
||||
@@ -134,6 +136,6 @@ class PythonPlugin final : public ExtensionSystem::IPlugin
|
||||
}
|
||||
};
|
||||
|
||||
} // Python::Internal
|
||||
} // namespace Python::Internal
|
||||
|
||||
#include "pythonplugin.moc"
|
||||
|
@@ -18,7 +18,7 @@ using namespace Utils;
|
||||
namespace Python::Internal {
|
||||
|
||||
PythonProject::PythonProject(const FilePath &fileName)
|
||||
: Project(Constants::C_PY_PROJECT_MIME_TYPE, fileName)
|
||||
: Project(Constants::C_PY_PROJECT_MIME_TYPE_TOML, fileName)
|
||||
{
|
||||
setId(PythonProjectId);
|
||||
setProjectLanguages(Context(ProjectExplorer::Constants::PYTHON_LANGUAGE_ID));
|
||||
@@ -45,4 +45,4 @@ QString PythonFileNode::displayName() const
|
||||
return m_displayName;
|
||||
}
|
||||
|
||||
} // Python::Internal
|
||||
} // namespace Python::Internal
|
||||
|
@@ -192,10 +192,13 @@ void setupPythonDebugWorker()
|
||||
void setupPythonOutputParser()
|
||||
{
|
||||
addOutputParserFactory([](Target *t) -> OutputLineParser * {
|
||||
if (t && t->project()->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE)
|
||||
if (!t)
|
||||
return nullptr;
|
||||
if (t->project()->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE
|
||||
|| t->project()->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE_TOML)
|
||||
return new PythonOutputLineParser;
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
} // Python::Internal
|
||||
} // namespace Python::Internal
|
||||
|
@@ -44,7 +44,8 @@ FilePath detectPython(const FilePath &documentPath)
|
||||
|
||||
FilePaths dirs = Environment::systemEnvironment().path();
|
||||
|
||||
if (project && project->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE) {
|
||||
if (project && (project->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE
|
||||
|| project->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE_TOML)) {
|
||||
if (auto bc = qobject_cast<PythonBuildConfiguration *>(project->activeBuildConfiguration()))
|
||||
return bc->python();
|
||||
if (const std::optional<Interpreter> python = PythonKitAspect::python(project->activeKit()))
|
||||
@@ -248,4 +249,4 @@ QString pythonVersion(const FilePath &python)
|
||||
return QString();
|
||||
}
|
||||
|
||||
} // Python::Internal
|
||||
} // namespace Python::Internal
|
||||
|
Reference in New Issue
Block a user