--- Begin Message ---
Source: python-debian
Version: 1.0.1
Severity: wishlist
Tags: patch
Hello.
The next concern after deb822.PkgRelation.parse_relations() is
probably to check that the relation holds in a given context. The
last commit enables callers to do that without depending on the
internal representation of arch and profiles restrictions.
The 6 first commits are suggestions inspired by 'debian/rules qa' and
lintian.
>From 4e7ba5499d0944df734f4f52dea4adeb8025be96 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <[email protected]>
Date: Thu, 6 Nov 2025 21:30:03 +0100
Subject: [PATCH 1/7] style: Remove trailing whitespaces in test_deb822.py
---
tests/test_deb822.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/tests/test_deb822.py b/tests/test_deb822.py
index 6a6e584..97623dd 100755
--- a/tests/test_deb822.py
+++ b/tests/test_deb822.py
@@ -143,7 +143,7 @@ Description: text-based mailreader supporting MIME, GPG, PGP and threading
Tag: interface::text-mode, made-of::lang:c, mail::imap, mail::pop, mail::user-agent, protocol::imap, protocol::ipv6, protocol::pop, protocol::ssl, role::sw:client, uitoolkit::ncurses, use::editing, works-with::mail
Task: mail-server
'''
-
+
PARSED_PACKAGE = deb822.Deb822Dict([
('Package', 'mutt'),
@@ -841,7 +841,7 @@ with open("test_deb822.pickle", "wb") as fh:
cls: Type[deb822.Deb822],
**kwargs: Any) -> None:
"""Ensure iter_paragraphs consistency"""
-
+
with open(filename, 'rb') as fh:
packages_content = fh.read()
@@ -968,7 +968,7 @@ with open("test_deb822.pickle", "wb") as fh:
for k, v in deb822_.items():
assert dict_[k] == v
-
+
def test_case_insensitive(self) -> None:
# PARSED_PACKAGE is a deb822.Deb822Dict object, so we can test
# it directly
@@ -998,7 +998,7 @@ with open("test_deb822.pickle", "wb") as fh:
with a newline (e.g. the control file Description field), then there
should be a space after the colon, as with non-multiline fields.
"""
-
+
# bad_re: match a line that starts with a "Field:", and ends in
# whitespace
bad_re = re.compile(r"^\S+:\s+$")
@@ -1010,7 +1010,7 @@ with open("test_deb822.pickle", "wb") as fh:
"after the colon in a multiline field " \
"starting with a newline"
-
+
control_paragraph = """Package: python-debian
Architecture: all
Depends: ${python:Depends}
@@ -1047,12 +1047,12 @@ Description: python modules to work with Debian-related data formats
d['Foo'] = 'bar'
d['Baz'] = ''
d['Another-Key'] = 'another value'
-
+
# Previous versions would raise an exception here -- this makes the
# test fail and gives useful information, so I won't try to wrap around
# it.
dumped = d.dump()
-
+
# May as well make sure the resulting string is what we want
expected = "Foo: bar\nBaz:\nAnother-Key: another value\n"
assert dumped == expected
--
2.47.3
>From 0d81af5066bac24d3fca2e67c428e7e998d9a06f Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <[email protected]>
Date: Thu, 6 Nov 2025 22:14:09 +0100
Subject: [PATCH 2/7] style: clean src/python_debian.egg-info/
---
debian/clean | 1 +
1 file changed, 1 insertion(+)
diff --git a/debian/clean b/debian/clean
index 3651b9c..714eafc 100644
--- a/debian/clean
+++ b/debian/clean
@@ -7,3 +7,4 @@ build/sphinx/
.mypy_cache/
src/debian/.mypy_cache/
.coverage
+src/python_debian.egg-info/
--
2.47.3
>From 1de870f52150693cbd51eab0ace24bb81ddf2de3 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <[email protected]>
Date: Thu, 6 Nov 2025 22:27:41 +0100
Subject: [PATCH 3/7] style: replace physical address to the FSF with an URL
---
debian/copyright | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/debian/copyright b/debian/copyright
index d1187b0..032123a 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -117,8 +117,7 @@ License: GPL-2+
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General Public License
version 2 can be found in `/usr/share/common-licenses/GPL-2'.
--
2.47.3
>From 495b78728d344bb13897c81a138101887ef4dec4 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <[email protected]>
Date: Thu, 6 Nov 2025 22:31:54 +0100
Subject: [PATCH 4/7] style: drop obsolete Rules-Requires-Root: no from
debian/control
---
debian/control | 1 -
1 file changed, 1 deletion(-)
diff --git a/debian/control b/debian/control
index 32be789..9d101b2 100644
--- a/debian/control
+++ b/debian/control
@@ -29,7 +29,6 @@ Standards-Version: 4.7.0
Vcs-Browser: https://salsa.debian.org/python-debian-team/python-debian
Vcs-Git: https://salsa.debian.org/python-debian-team/python-debian.git
Homepage: https://salsa.debian.org/python-debian-team/python-debian
-Rules-Requires-Root: no
Package: python3-debian
Architecture: all
--
2.47.3
>From ead04b68884de73f7ae5fcf77ed87dee5612b9ee Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <[email protected]>
Date: Thu, 6 Nov 2025 22:33:25 +0100
Subject: [PATCH 5/7] style: Update Standards-Version to 4.7.2
---
debian/control | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/debian/control b/debian/control
index 9d101b2..3986786 100644
--- a/debian/control
+++ b/debian/control
@@ -25,7 +25,7 @@ Build-Depends:
zstd <!nocheck>,
Build-Conflicts:
gpgv-from-sq,
-Standards-Version: 4.7.0
+Standards-Version: 4.7.2
Vcs-Browser: https://salsa.debian.org/python-debian-team/python-debian
Vcs-Git: https://salsa.debian.org/python-debian-team/python-debian.git
Homepage: https://salsa.debian.org/python-debian-team/python-debian
--
2.47.3
>From 058da4f4835ad594bf54842926e0f7a8ca36e488 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <[email protected]>
Date: Thu, 6 Nov 2025 21:32:47 +0100
Subject: [PATCH 6/7] style: replace collections.namedtuple with
typing.NamedTuple in deb822.py
---
src/debian/deb822.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/debian/deb822.py b/src/debian/deb822.py
index 1592ec9..4929583 100644
--- a/src/debian/deb822.py
+++ b/src/debian/deb822.py
@@ -257,6 +257,7 @@ from typing import (
List,
Mapping,
MutableMapping,
+ NamedTuple,
Optional,
overload,
Text,
@@ -1393,10 +1394,13 @@ class PkgRelation:
r'(?P<enabled>\!)?'
r'(?P<profile>[^\s]+)')
- ArchRestriction = collections.namedtuple('ArchRestriction',
- ['enabled', 'arch'])
- BuildRestriction = collections.namedtuple('BuildRestriction',
- ['enabled', 'profile'])
+ class ArchRestriction(NamedTuple):
+ enabled: bool
+ arch: str
+
+ class BuildRestriction(NamedTuple):
+ enabled: bool
+ profile: str
if TYPE_CHECKING:
class ParsedRelation(TypedDict):
--
2.47.3
>From a63e7044b93d56cc3d029912e7befcb657726fb1 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <[email protected]>
Date: Thu, 6 Nov 2025 21:28:36 +0100
Subject: [PATCH 7/7] Add deb822.PkgRelation.{holds_on_arch,
holds_with_profiles}
The next concern after parse_relations is probably to check that the
relation holds in a given context. Enable callers to do that without
depending on the internal representation of arch and profiles
restrictions.
---
src/debian/deb822.py | 27 +++++++++++++++++++++++++++
tests/test_deb822.py | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)
diff --git a/src/debian/deb822.py b/src/debian/deb822.py
index 4929583..b230e30 100644
--- a/src/debian/deb822.py
+++ b/src/debian/deb822.py
@@ -1487,6 +1487,33 @@ class PkgRelation:
cnf = map(cls.__pipe_sep_RE.split, tl_deps)
return [[parse_rel(or_dep) for or_dep in or_deps] for or_deps in cnf]
+ @staticmethod
+ def holds_on_arch(relation: ParsedRelation, arch: str) -> bool:
+ """Is relation active on the given architecture?
+
+ Check arch against a disjunction like [amd64 armel]
+ or a conjonction of exclusions like [!amd64 !armel].
+
+ Per policy, the list is non empty and ! affects all names or none."""
+ archs = relation["arch"]
+ return (archs is None
+ or archs[0].enabled == any(arch == a.arch for a in archs))
+
+ @staticmethod
+ def holds_with_profiles(
+ relation: ParsedRelation,
+ profiles: collections.abc.Container[str],
+ ) -> bool:
+ """Is relation active under the given profiles?
+
+ In the relation, '<a !b> <c>' requires that profiles
+ either contains a but not b, or contains c."""
+ restrictions = relation["restrictions"]
+ return (restrictions is None
+ or any(all(term.enabled == (term.profile in profiles)
+ for term in restriction_list)
+ for restriction_list in restrictions))
+
@staticmethod
def str(rels: List[List[PkgRelation.ParsedRelation]]) -> builtins.str:
"""Format to string structured inter-package relationships
diff --git a/tests/test_deb822.py b/tests/test_deb822.py
index 97623dd..a632e4f 100755
--- a/tests/test_deb822.py
+++ b/tests/test_deb822.py
@@ -1701,6 +1701,46 @@ class TestPkgRelations:
assert term == "native"
assert deb822.PkgRelation.str(rel) == r
+ def test_holds_on_arch(self) -> None:
+ A = "a" # the current architecture
+ for one_relation, expected in (
+ # no restriction
+ ("foo", True),
+ # architecture membership
+ ("foo [ a1 a a2]", True),
+ ("foo [ a1 a2]", False),
+ # architecture exclusions
+ ("foo [!a1 !a2]", True),
+ ("foo [!a1 !a !a2]", False),
+ ):
+ rel = deb822.PkgRelation.parse_relations(one_relation)[0][0]
+ got = deb822.PkgRelation.holds_on_arch(rel, A)
+ assert got == expected, one_relation
+
+ def test_holds_with_profiles(self) -> None:
+ P = ("p1", "p2") # the current profiles
+ for one_relation, expected in (
+ # no restriction
+ ("foo", True),
+ # profile membership
+ ("foo <p1>", True),
+ ("foo <p>", False),
+ # profile negation
+ ("foo <!p1>", False),
+ ("foo <!p>", True),
+ # profile conjunction
+ ("foo <p p1>", False),
+ ("foo <p1 p2>", True),
+ ("foo <p1 p2 p>", False),
+ # profile disjunction
+ ("foo <p> <p1>", True),
+ ("foo <p> <q>", False),
+ ("foo <p1> <p2>", True),
+ ):
+ rel = deb822.PkgRelation.parse_relations(one_relation)[0][0]
+ got = deb822.PkgRelation.holds_with_profiles(rel, P)
+ assert got == expected, one_relation
+
class TestVersionAccessor:
--
2.47.3
--- End Message ---