Skip to content

Commit ffb3aea

Browse files
authored
Merge pull request #258 from Xpirix/upgrade_to_qgis4_docs
Add migration guide for QGIS 4 and update plugin metadata handling
2 parents 0c42ad0 + a308da8 commit ffb3aea

File tree

11 files changed

+272
-2
lines changed

11 files changed

+272
-2
lines changed

qgis-app/docs.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,14 @@ def docs_security_scanning(request):
4444
"flatpages/docs_security_scanning.html",
4545
{},
4646
)
47+
48+
49+
def docs_migrate_qgis4(request):
50+
"""
51+
Renders the Migrate to QGIS 4 documentation page
52+
"""
53+
return render(
54+
request,
55+
"flatpages/docs_migrate_qgis4.html",
56+
{},
57+
)

qgis-app/plugins/templates/plugins/plugin_list.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,30 @@ <h2 class="title is-4">{% if title %}{{title}}{% else %}{% trans "All plugins" %
110110
{% endif %}
111111
</div>
112112
</div>
113+
{% if show_qgis4_migration_notice %}
114+
<div class="notification is-warning is-light mb-4">
115+
<span class="icon-text">
116+
<span class="icon"><i class="fas fa-info-circle"></i></span>
117+
<span><strong>{% trans "Is your plugin missing from this list?" %}</strong></span>
118+
</span>
119+
<p class="mt-2">
120+
{% blocktrans trimmed %}
121+
The <code>supportsQt6</code> metadata flag is <strong>deprecated</strong> and no longer used to
122+
determine QGIS 4 compatibility. Plugins are now listed here based on their
123+
<code>qgisMaximumVersion</code> field — plugins with <code>qgisMaximumVersion &ge; 4.0</code>
124+
are considered compatible with QGIS 4.
125+
{% endblocktrans %}
126+
</p>
127+
<p class="mt-1">
128+
{% url 'docs_migrate_qgis4' as migrate_url %}
129+
{% blocktrans trimmed with migrate_url=migrate_url %}
130+
If your plugin is not listed, please update your <code>metadata.txt</code> and set
131+
<code>qgisMaximumVersion = 4.99</code> (or higher).
132+
See our <a href="{{ migrate_url }}"><strong>Migrate to QGIS 4</strong></a> guide for full instructions.
133+
{% endblocktrans %}
134+
</p>
135+
</div>
136+
{% endif %}
113137
{# Filtered views menu #}
114138
{% if object_list.count %}
115139
<div class="mt-3 is-flex is-justify-content-space-between is-flex-wrap-wrap">

qgis-app/plugins/templates/plugins/plugin_sidebar.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@
109109
Security Scanning
110110
</a>
111111
</li>
112+
{% url 'docs_migrate_qgis4' as docs_migrate_qgis4_url %}
113+
<li class="has-child {% if request.path == docs_migrate_qgis4_url %}is-active{% endif %}">
114+
<a href="{{ docs_migrate_qgis4_url }}">
115+
Migrate to QGIS 4
116+
</a>
117+
</li>
112118
</ul>
113119
</li>
114120
<li>

qgis-app/plugins/tests/test_rename_plugin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class PluginRenameTestCase(TestCase):
1818
"fixtures/auth.json",
1919
]
2020

21+
@patch("plugins.tasks.generate_plugins_xml", new=do_nothing)
22+
@patch("plugins.validator._check_url_link", new=do_nothing)
2123
@override_settings(MEDIA_ROOT="api/tests")
2224
def setUp(self):
2325
self.client = Client()

qgis-app/plugins/tests/test_token_auth.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from unittest.mock import patch
23

34
from django.contrib.auth.models import User
45
from django.core.files.uploadedfile import SimpleUploadedFile
@@ -20,6 +21,8 @@ def do_nothing(*args, **kwargs):
2021
class UploadWithTokenTestCase(TestCase):
2122
fixtures = ["fixtures/auth.json"]
2223

24+
@patch("plugins.tasks.generate_plugins_xml", new=do_nothing)
25+
@patch("plugins.validator._check_url_link", new=do_nothing)
2326
@override_settings(MEDIA_ROOT="api/tests")
2427
def setUp(self):
2528
self.client = Client()
@@ -241,6 +244,8 @@ class APIResponseTestCase(TestCase):
241244

242245
fixtures = ["fixtures/auth.json"]
243246

247+
@patch("plugins.tasks.generate_plugins_xml", new=do_nothing)
248+
@patch("plugins.validator._check_url_link", new=do_nothing)
244249
@override_settings(MEDIA_ROOT="api/tests")
245250
def setUp(self):
246251
self.client = Client()
@@ -546,6 +551,8 @@ class EmptyPluginWithTokenTestCase(TestCase):
546551

547552
fixtures = ["fixtures/auth.json"]
548553

554+
@patch("plugins.tasks.generate_plugins_xml", new=do_nothing)
555+
@patch("plugins.validator._check_url_link", new=do_nothing)
549556
@override_settings(MEDIA_ROOT="api/tests")
550557
def setUp(self):
551558
self.client = Client()

qgis-app/plugins/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"description": _(
242242
f"List of approved plugins that are ready for QGIS {settings.NEW_QGIS_MAJOR_VERSION}."
243243
),
244+
"show_qgis4_migration_notice": True,
244245
},
245246
),
246247
name="new_qgis_ready_plugins",

qgis-app/plugins/validator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,10 @@ def validator(package, is_new: bool = False):
375375

376376
metadata.append(("icon_file", icon_file))
377377

378+
# Check for deprecated supportsQt6 flag
379+
if "supportsQt6" in dict(metadata):
380+
metadata.append(("supportsQt6_deprecated", True))
381+
378382
# Transforms booleans flags (experimental)
379383
for flag in PLUGIN_BOOLEAN_METADATA:
380384
if flag in dict(metadata):
@@ -459,7 +463,7 @@ def validator(package, is_new: bool = False):
459463
checked_metadata = []
460464
for k, v in metadata:
461465
try:
462-
if not (k in PLUGIN_BOOLEAN_METADATA or k == "icon_file"):
466+
if not (k in PLUGIN_BOOLEAN_METADATA or k in ("icon_file", "supportsQt6_deprecated")):
463467
# v.decode('UTF-8')
464468
checked_metadata.append((k, v.strip()))
465469
else:

qgis-app/plugins/views.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,23 @@ def plugin_upload(request):
638638
)
639639
del form.cleaned_data["multiple_parent_folders"]
640640

641+
if form.cleaned_data.get("supportsQt6_deprecated"):
642+
messages.warning(
643+
request,
644+
mark_safe(
645+
_(
646+
"The <code>supportsQt6</code> flag in your plugin metadata is deprecated "
647+
"and is no longer used. QGIS 4 compatibility is now determined solely by "
648+
"the <code>qgisMaximumVersion</code> field. Please set "
649+
"<code>qgisMaximumVersion</code> to <code>4.99</code> (or higher) and "
650+
"remove <code>supportsQt6</code> from your metadata. "
651+
'See the <a href="/docs/migrate-qgis4">Migrate to QGIS 4</a> guide for more details.'
652+
)
653+
),
654+
fail_silently=True,
655+
)
656+
del form.cleaned_data["supportsQt6_deprecated"]
657+
641658
except (IntegrityError, ValidationError, DjangoUnicodeDecodeError) as e:
642659
connection.close()
643660
messages.error(request, e, fail_silently=True)
@@ -1633,6 +1650,29 @@ def _version_create(request, plugin, version):
16331650
)
16341651
del form.cleaned_data["multiple_parent_folders"]
16351652

1653+
if form.cleaned_data.get("supportsQt6_deprecated"):
1654+
qt6_warning_msg = mark_safe(
1655+
_(
1656+
"The <code>supportsQt6</code> flag in your plugin metadata is deprecated "
1657+
"and is no longer used. QGIS 4 compatibility is now determined solely by "
1658+
"the <code>qgisMaximumVersion</code> field. Please set "
1659+
"<code>qgisMaximumVersion</code> to <code>4.99</code> (or higher) and "
1660+
"remove <code>supportsQt6</code> from your metadata. "
1661+
'See the <a href="/docs/migrate-qgis4">Migrate to QGIS 4</a> guide for more details.'
1662+
)
1663+
)
1664+
response_data["warnings"] = response_data.get("warnings", [])
1665+
response_data["warnings"].append(
1666+
"The supportsQt6 flag is deprecated. See /docs/migrate-qgis4 for details."
1667+
)
1668+
if not is_api_request:
1669+
messages.warning(
1670+
request,
1671+
qt6_warning_msg,
1672+
fail_silently=True,
1673+
)
1674+
del form.cleaned_data["supportsQt6_deprecated"]
1675+
16361676
_main_plugin_update(request, new_object.plugin, form)
16371677
_check_optional_metadata(form, request)
16381678

@@ -1775,6 +1815,29 @@ def _version_update(request, plugin, version, is_trusted=False):
17751815
)
17761816
del form.cleaned_data["multiple_parent_folders"]
17771817

1818+
if form.cleaned_data.get("supportsQt6_deprecated"):
1819+
qt6_warning_msg = mark_safe(
1820+
_(
1821+
"The <code>supportsQt6</code> flag in your plugin metadata is deprecated "
1822+
"and is no longer used. QGIS 4 compatibility is now determined solely by "
1823+
"the <code>qgisMaximumVersion</code> field. Please set "
1824+
"<code>qgisMaximumVersion</code> to <code>4.99</code> (or higher) and "
1825+
"remove <code>supportsQt6</code> from your metadata. "
1826+
'See the <a href="/docs/migrate-qgis4">Migrate to QGIS 4</a> guide for more details.'
1827+
)
1828+
)
1829+
response_data["warnings"] = response_data.get("warnings", [])
1830+
response_data["warnings"].append(
1831+
"The supportsQt6 flag is deprecated. See /docs/migrate-qgis4 for details."
1832+
)
1833+
if not is_api_request:
1834+
messages.warning(
1835+
request,
1836+
qt6_warning_msg,
1837+
fail_silently=True,
1838+
)
1839+
del form.cleaned_data["supportsQt6_deprecated"]
1840+
17781841
# Return JSON for API requests
17791842
if is_api_request:
17801843
return JsonResponse(response_data, status=200)

qgis-app/static/style/scss/style.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,4 +541,9 @@ h6:hover > a.heading-anchor {
541541
gap: 8px;
542542
margin-bottom: 10px;
543543
}
544+
}
545+
546+
code {
547+
border-radius: 10px;
548+
padding: 2px 8px;
544549
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
{% extends 'flatpages/docs.html' %}
2+
{% load i18n %}
3+
4+
{% block content %}
5+
<div class="responsive-content">
6+
<h4>{% trans "Migrate Your Plugin to QGIS 4" %}</h4>
7+
8+
<div class="notification is-info is-light">
9+
<span class="icon-text">
10+
<span class="icon"><i class="fas fa-info-circle"></i></span>
11+
<span><strong>{% trans "TL;DR" %}</strong></span>
12+
</span>
13+
<p class="mt-1">
14+
{% blocktrans trimmed %}
15+
To make your plugin appear in the
16+
<a href="/plugins/new_qgis_ready/">QGIS 4 Ready Plugins</a> list, simply set
17+
<code>qgisMaximumVersion=4.99</code> (or higher) in your <code>metadata.txt</code>
18+
and remove the deprecated <code>supportsQt6</code> flag.
19+
{% endblocktrans %}
20+
</p>
21+
</div>
22+
23+
<h5>{% trans "Background" %}</h5>
24+
<p>
25+
{% blocktrans trimmed %}
26+
During the QGIS 4 pre-release period, a temporary metadata flag called
27+
<code>supportsQt6</code> was introduced to let plugin authors signal that their plugin
28+
was compatible with Qt 6 and QGIS 4. Plugin authors were encouraged to add
29+
<code>supportsQt6=True</code> to their <code>metadata.txt</code>.
30+
{% endblocktrans %}
31+
</p>
32+
<p>
33+
{% blocktrans trimmed %}
34+
Following the changes described in
35+
<a href="https://github.com/qgis/QGIS/pull/65146" target="_blank" rel="noopener">qgis/QGIS#65146</a>
36+
and <a href="https://github.com/qgis/QGIS/pull/65168" target="_blank" rel="noopener">qgis/QGIS#65168</a>,
37+
the <code>supportsQt6</code> flag has been <strong>removed from QGIS core</strong> and is
38+
<strong>no longer recognised</strong>. Declaring <code>supportsQt6=True</code> in your metadata has
39+
no effect and plugins that relied solely on this flag to appear in the QGIS 4 plugin list have been
40+
removed from that list.
41+
{% endblocktrans %}
42+
</p>
43+
44+
<h5>{% trans "The New Rule: qgisMaximumVersion" %}</h5>
45+
<p>
46+
{% blocktrans trimmed %}
47+
QGIS 4 compatibility is now determined exclusively by the <code>qgisMaximumVersion</code> field
48+
in <code class="is-size-7 has-text-weight-semibold">metadata.txt</code>. A plugin version is shown in the
49+
<a href="/plugins/new_qgis_ready/">QGIS 4 Ready Plugins</a> list when
50+
<code>qgisMaximumVersion &ge; 4.0</code>.
51+
{% endblocktrans %}
52+
</p>
53+
<p>{% trans "Examples:" %}</p>
54+
<div class="content">
55+
<ul>
56+
<li>
57+
<code>qgisMinimumVersion=3.22</code>, <code>qgisMaximumVersion=4.99</code>
58+
&rarr; {% trans "Listed for QGIS 3.22+ <strong>and</strong> QGIS 4.x" %}
59+
</li>
60+
<li>
61+
<code>qgisMinimumVersion=4.0</code>, <code>qgisMaximumVersion=4.99</code>
62+
&rarr; {% trans "Listed for QGIS 4.x only" %}
63+
</li>
64+
<li>
65+
<code>qgisMinimumVersion=3.22</code>, <code>qgisMaximumVersion=3.99</code>
66+
&rarr; {% trans "Not listed (QGIS 3 only)" %}
67+
</li>
68+
</ul>
69+
</div>
70+
71+
<h5>{% trans "How to Update Your Plugin" %}</h5>
72+
<div class="content">
73+
<ol>
74+
<li>
75+
<strong>{% trans "Update metadata.txt" %}</strong>
76+
<p>{% trans "Open your <code>metadata.txt</code> and make the following changes:" %}</p>
77+
<pre><code>[general]
78+
# Set qgisMaximumVersion to cover QGIS 4.x
79+
qgisMaximumVersion=4.99
80+
81+
# Remove or delete this line — it is no longer used:
82+
# supportsQt6=True</code></pre>
83+
</li>
84+
<li>
85+
<strong>{% trans "Verify Qt 6 / PyQGIS 4 compatibility" %}</strong>
86+
<p>
87+
{% blocktrans trimmed %}
88+
Before bumping <code>qgisMaximumVersion</code>, make sure your plugin actually works
89+
with QGIS 4. Key things to check:
90+
{% endblocktrans %}
91+
</p>
92+
<div class="content">
93+
<ul>
94+
<li>{% trans "Replace any deprecated Qt 5-only APIs with their Qt 6 equivalents." %}</li>
95+
<li>{% trans "Replace <code>PyQt5</code> imports with <code>PyQt6</code> (or use the QGIS-provided compatibility shim)." %}</li>
96+
<li>{% trans "Test your plugin with a QGIS 4 nightly or release build." %}</li>
97+
</ul>
98+
</div>
99+
</li>
100+
<li>
101+
<strong>{% trans "Upload a new version" %}</strong>
102+
<p>
103+
{% blocktrans trimmed %}
104+
Upload the updated plugin package on the
105+
<a href="/plugins/">QGIS Plugins repository</a>.
106+
Your plugin will appear in the
107+
<a href="/plugins/new_qgis_ready/">QGIS 4 Ready Plugins</a> list once the upload
108+
is approved.
109+
{% endblocktrans %}
110+
</p>
111+
</li>
112+
</ol>
113+
</div>
114+
115+
<h5>{% trans "Further Reading" %}</h5>
116+
<div class="content">
117+
<ul>
118+
<li>
119+
<a href="https://github.com/qgis/QGIS/wiki/Plugin-migration-to-be-compatible-with-Qt5-and-Qt6"
120+
target="_blank" rel="noopener">
121+
{% trans "QGIS Wiki: Plugin migration to be compatible with Qt5 and Qt6" %}
122+
</a>
123+
</li>
124+
<li>
125+
<a href="https://github.com/qgis/QGIS/pull/65146" target="_blank" rel="noopener">
126+
{% trans "GitHub PR #65146 – Remove supportsQt6 from QGIS core" %}
127+
</a>
128+
</li>
129+
<li>
130+
<a href="https://github.com/qgis/QGIS-Documentation/pull/10804" target="_blank" rel="noopener">
131+
{% trans "QGIS Documentation PR #10804 – Remove outdated supportsQt6 references" %}
132+
</a>
133+
</li>
134+
<li>
135+
<a href="https://plugins.qgis.org/plugins/new_qgis_ready/">
136+
{% trans "QGIS 4 Ready Plugins list" %}
137+
</a>
138+
</li>
139+
</ul>
140+
</div>
141+
</div>
142+
{% endblock %}

0 commit comments

Comments
 (0)