commit:     35cdb9c34b4008c82f0156250236d181e3d280b4
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Sun Oct 26 16:35:45 2025 +0000
Commit:     Brian Harring <ferringb <AT> gmail <DOT> com>
CommitDate: Fri Nov 21 22:23:17 2025 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcore.git/commit/?id=35cdb9c3

chore: convert restrictions to meta.Immutable

Signed-off-by: Brian Harring <ferringb <AT> gmail.com>

 src/pkgcore/ebuild/atom.py              | 56 +++++++++++-------------
 src/pkgcore/ebuild/conditionals.py      | 12 +++---
 src/pkgcore/restrictions/boolean.py     | 18 +++-----
 src/pkgcore/restrictions/delegated.py   |  3 +-
 src/pkgcore/restrictions/packages.py    | 23 +++++-----
 src/pkgcore/restrictions/restriction.py | 13 +++---
 src/pkgcore/restrictions/values.py      | 75 +++++++++++++--------------------
 src/pkgcore/scripts/pquery.py           |  6 +--
 8 files changed, 86 insertions(+), 120 deletions(-)

diff --git a/src/pkgcore/ebuild/atom.py b/src/pkgcore/ebuild/atom.py
index 8f82f4e9..3f6fdb0e 100644
--- a/src/pkgcore/ebuild/atom.py
+++ b/src/pkgcore/ebuild/atom.py
@@ -16,9 +16,8 @@ from ..restrictions import boolean, packages, restriction, 
values
 from ..restrictions.packages import AndRestriction as PkgAndRestriction
 from ..restrictions.packages import Conditional
 from ..restrictions.values import ContainmentMatch
-from . import cpv
+from . import cpv, errors, restricts
 from . import eapi as eapi_mod
-from . import errors, restricts
 
 # namespace compatibility...
 MalformedAtom = errors.MalformedAtom
@@ -95,7 +94,6 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
         if not atom:
             raise errors.MalformedAtom(atom)
 
-        sf = object.__setattr__
         orig_atom = atom
         override_kls = False
         use_start = atom.find("[")
@@ -116,7 +114,7 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
                 raise errors.MalformedAtom(orig_atom, "use restriction isn't 
completed")
             elif use_end != len(atom) - 1:
                 raise errors.MalformedAtom(orig_atom, "trailing garbage after 
use dep")
-            sf(self, "use", tuple(sorted(atom[use_start + 1 : 
use_end].split(","))))
+            self.use = tuple(sorted(atom[use_start + 1 : use_end].split(",")))
             for x in self.use:
                 # stripped purely for validation reasons
                 try:
@@ -152,10 +150,10 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
                 except IndexError:
                     raise errors.MalformedAtom(orig_atom, "empty use dep 
detected")
             if override_kls:
-                sf(self, "__class__", transitive_use_atom)
+                self.__class__ = transitive_use_atom
             atom = atom[0:use_start] + atom[use_end + 1 :]
         else:
-            sf(self, "use", None)
+            self.use = None
         if slot_start != -1:
             i2 = atom.find("::", slot_start)
             if i2 != -1:
@@ -173,9 +171,9 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
                         f"repo_id may contain only [a-Z0-9_-/], found 
{repo_id!r}",
                     )
                 atom = atom[:i2]
-                sf(self, "repo_id", repo_id)
+                self.repo_id = repo_id
             else:
-                sf(self, "repo_id", None)
+                self.repo_id = None
             # slot dep.
             slot = atom[slot_start + 1 :]
             slot_operator = subslot = None
@@ -230,17 +228,12 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
                 if len(slots) == 2:
                     slot, subslot = slots
 
-            sf(self, "slot_operator", slot_operator)
-            sf(self, "slot", slot)
-            sf(self, "subslot", subslot)
+            self.slot_operator, self.slot, self.subslot = slot_operator, slot, 
subslot
             atom = atom[:slot_start]
         else:
-            sf(self, "slot_operator", None)
-            sf(self, "slot", None)
-            sf(self, "subslot", None)
-            sf(self, "repo_id", None)
+            self.slot_operator = self.slot = self.subslot = self.repo_id = None
 
-        sf(self, "blocks", atom[0] == "!")
+        self.blocks = atom[0] == "!"
         if self.blocks:
             atom = atom[1:]
             # hackish/slow, but lstrip doesn't take a 'prune this many' arg
@@ -251,32 +244,32 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
                         f"strong blockers are not supported in EAPI {eapi}"
                     )
                 atom = atom[1:]
-                sf(self, "blocks_strongly", True)
+                self.blocks_strongly = True
             else:
-                sf(self, "blocks_strongly", False)
+                self.blocks_strongly = False
         else:
-            sf(self, "blocks_strongly", False)
+            self.blocks_strongly = False
 
         if atom[0] in ("<", ">"):
             if atom[1] == "=":
-                sf(self, "op", atom[:2])
+                self.op = atom[:2]
                 atom = atom[2:]
             else:
-                sf(self, "op", atom[0])
+                self.op = atom[0]
                 atom = atom[1:]
         elif atom[0] == "=":
             if atom[-1] == "*":
-                sf(self, "op", "=*")
+                self.op = "=*"
                 atom = atom[1:-1]
             else:
                 atom = atom[1:]
-                sf(self, "op", "=")
+                self.op = "="
         elif atom[0] == "~":
-            sf(self, "op", "~")
+            self.op = "~"
             atom = atom[1:]
         else:
-            sf(self, "op", "")
-        sf(self, "cpvstr", atom)
+            self.op = ""
+        self.cpvstr = atom
 
         if self.slot is not None and not eapi_obj.options.has_slot_deps:
             raise errors.MalformedAtom(
@@ -295,7 +288,7 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
                     orig_atom, f"repo_id atoms aren't supported for EAPI 
{eapi}"
                 )
         try:
-            sf(self, "_cpv", cpv.CPV(self.cpvstr, versioned=bool(self.op)))
+            self._cpv = cpv.CPV(self.cpvstr, versioned=bool(self.op))
         except errors.InvalidCPV as e:
             raise errors.MalformedAtom(orig_atom) from e
 
@@ -308,8 +301,9 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
                 )
         elif self.version is not None:
             raise errors.MalformedAtom(orig_atom, "versioned atom requires an 
operator")
-        sf(self, "_hash", hash(orig_atom))
-        sf(self, "negate_vers", negate_vers)
+
+        self._hash = hash(orig_atom)
+        self.negate_vers = negate_vers
 
     __getattr__ = klass.GetAttrProxy("_cpv")
     __dir__ = klass.DirProxy("_cpv")
@@ -362,7 +356,7 @@ class atom(boolean.AndRestriction, 
metaclass=klass.generic_equality):
         return [[self]]
 
     @property
-    def is_simple(self):
+    def is_simple(self) -> bool:
         return len(self.restrictions) == 2
 
     @klass.jit_attr
@@ -694,7 +688,7 @@ class transitive_use_atom(atom):
     __inst_caching__ = True
     _nontransitive_use_atom = atom
 
-    is_simple = False
+    is_simple = False  # type: ignore
 
     def _stripped_use(self):
         return str(self).split("[", 1)[0]

diff --git a/src/pkgcore/ebuild/conditionals.py 
b/src/pkgcore/ebuild/conditionals.py
index 80773974..7755ca9d 100644
--- a/src/pkgcore/ebuild/conditionals.py
+++ b/src/pkgcore/ebuild/conditionals.py
@@ -34,13 +34,11 @@ class DepSet(boolean.AndRestriction):
         node_conds=True,
         known_conditionals=None,
     ):
-        sf = object.__setattr__
-        sf(self, "_known_conditionals", known_conditionals)
-        sf(self, "element_class", element_class)
-        sf(self, "restrictions", restrictions)
-        sf(self, "_node_conds", node_conds)
-        sf(self, "type", restriction.package_type)
-        sf(self, "negate", False)
+        self._known_conditionals = known_conditionals
+        self.element_class = element_class
+        self.restrictions = restrictions
+        self._node_conds = node_conds
+        self.type, self.negate = restriction.package_type, False
 
     @classmethod
     def parse(

diff --git a/src/pkgcore/restrictions/boolean.py 
b/src/pkgcore/restrictions/boolean.py
index 26ec4d90..9d61ffbf 100644
--- a/src/pkgcore/restrictions/boolean.py
+++ b/src/pkgcore/restrictions/boolean.py
@@ -9,7 +9,7 @@ __all__ = ("AndRestriction", "OrRestriction")
 
 from itertools import islice
 
-from snakeoil.klass import cached_hash, generic_equality
+from snakeoil.klass import cached_hash, generic_equality, immutable
 
 from . import restriction
 
@@ -42,12 +42,10 @@ class base(restriction.base, metaclass=generic_equality):
         :keyword negate: should the logic be negated?
         """
 
-        sf = object.__setattr__
-
         node_type = kwds.pop("node_type", None)
 
-        sf(self, "type", node_type)
-        sf(self, "negate", kwds.pop("negate", False))
+        self.type = node_type
+        self.negate = kwds.pop("negate", False)
 
         if node_type is not None:
             try:
@@ -62,12 +60,9 @@ class base(restriction.base, metaclass=generic_equality):
                 )
 
         if kwds.pop("finalize", True):
-            if not isinstance(restrictions, tuple):
-                sf(self, "restrictions", tuple(restrictions))
-            else:
-                sf(self, "restrictions", restrictions)
+            self.restrictions = tuple(restrictions)
         else:
-            sf(self, "restrictions", list(restrictions))
+            self.restrictions = list(restrictions)
 
         if kwds:
             kwds.pop("disable_inst_caching", None)
@@ -123,9 +118,10 @@ class base(restriction.base, metaclass=generic_equality):
         except AttributeError:
             raise TypeError("%r is finalized" % self)
 
+    @immutable.Simple.__allow_mutation_wrapper__
     def finalize(self):
         """finalize the restriction instance, disallowing adding 
restrictions."""
-        object.__setattr__(self, "restrictions", tuple(self.restrictions))
+        self.restrictions = tuple(self.restrictions)
 
     def __repr__(self):
         return "<%s negate=%r type=%r finalized=%r restrictions=%r @%#8x>" % (

diff --git a/src/pkgcore/restrictions/delegated.py 
b/src/pkgcore/restrictions/delegated.py
index ecb6f7d0..219a6e74 100644
--- a/src/pkgcore/restrictions/delegated.py
+++ b/src/pkgcore/restrictions/delegated.py
@@ -30,8 +30,7 @@ class delegate(restriction.base):
         if not callable(transform_func):
             raise TypeError(transform_func)
 
-        object.__setattr__(self, "negate", negate)
-        object.__setattr__(self, "_transform", transform_func)
+        self.negate, self._transform = negate, transform_func
 
     def match(self, pkginst):
         return self._transform(pkginst, "match") != self.negate

diff --git a/src/pkgcore/restrictions/packages.py 
b/src/pkgcore/restrictions/packages.py
index 3b6a48cf..41a63dc7 100644
--- a/src/pkgcore/restrictions/packages.py
+++ b/src/pkgcore/restrictions/packages.py
@@ -45,15 +45,14 @@ class PackageRestriction(restriction.base, 
metaclass=generic_equality):
         """
         if not childrestriction.type == self.subtype:
             raise TypeError("restriction must be of type %r" % (self.subtype,))
-        sf = object.__setattr__
-        sf(self, "negate", negate)
+        self.negate = negate
         self._parse_attr(attr)
-        sf(self, "restriction", childrestriction)
-        sf(self, "ignore_missing", ignore_missing)
+        self.restriction = childrestriction
+        self.ignore_missing = ignore_missing
 
     def _parse_attr(self, attr):
-        object.__setattr__(self, "_pull_attr_func", static_attrgetter(attr))
-        object.__setattr__(self, "_attr_split", attr.split("."))
+        self._pull_attr_func = static_attrgetter(attr)
+        self._attr_split = attr.split(".")
 
     def _pull_attr(self, pkg):
         try:
@@ -171,10 +170,8 @@ class PackageRestrictionMulti(PackageRestriction):
         return tuple(".".join(x) for x in self._attr_split)
 
     def _parse_attr(self, attrs):
-        object.__setattr__(
-            self, "_pull_attr_func", tuple(map(static_attrgetter, attrs))
-        )
-        object.__setattr__(self, "_attr_split", tuple(x.split(".") for x in 
attrs))
+        self._pull_attr_func = tuple(map(static_attrgetter, attrs))
+        self._attr_split = tuple(x.split(".") for x in attrs)
 
     def _pull_attr(self, pkg):
         val = []
@@ -216,7 +213,7 @@ class Conditional(PackageRestriction, 
metaclass=generic_equality):
         :param kwds: additional args to pass to :obj:`PackageRestriction`
         """
         PackageRestriction.__init__(self, attr, childrestriction, **kwds)
-        object.__setattr__(self, "payload", tuple(payload))
+        self.payload = tuple(payload)
 
     def __str__(self):
         s = PackageRestriction.__str__(self)
@@ -287,8 +284,8 @@ class KeyedAndRestriction(boolean.AndRestriction):
         key = kwds.pop("key", None)
         tag = kwds.pop("tag", None)
         boolean.AndRestriction.__init__(self, *a, **kwds)
-        object.__setattr__(self, "key", key)
-        object.__setattr__(self, "tag", tag)
+        self.key = key
+        self.tag = tag
 
     def __str__(self):
         boolean_str = boolean.AndRestriction.__str__(self)

diff --git a/src/pkgcore/restrictions/restriction.py 
b/src/pkgcore/restrictions/restriction.py
index 85265381..3cf74101 100644
--- a/src/pkgcore/restrictions/restriction.py
+++ b/src/pkgcore/restrictions/restriction.py
@@ -6,9 +6,14 @@ from functools import partial
 
 from snakeoil import caching, klass
 from snakeoil.currying import pretty_docs
+from snakeoil.klass import immutable
 
 
-class base(klass.SlotsPicklingMixin, metaclass=caching.WeakInstMeta):
+class base(
+    klass.SlotsPicklingMixin,
+    immutable.Simple,
+    metaclass=caching.WeakInstMeta,
+):
     """base restriction matching object.
 
     all derivatives *should* be __slots__ based (lot of instances may
@@ -21,8 +26,6 @@ class base(klass.SlotsPicklingMixin, 
metaclass=caching.WeakInstMeta):
     __slots__ = ()
     package_matching = False
 
-    klass.inject_immutable_instance(locals())
-
     def match(self, *arg, **kwargs):
         raise NotImplementedError
 
@@ -75,9 +78,7 @@ class AlwaysBool(base):
         return self.negate, self.type
 
     def __setstate__(self, state):
-        negate, node_type = state
-        object.__setattr__(self, "negate", negate)
-        object.__setattr__(self, "type", node_type)
+        self.negate, self.type = state
 
 
 class Negate(base):

diff --git a/src/pkgcore/restrictions/values.py 
b/src/pkgcore/restrictions/values.py
index 91863f0e..ad689107 100644
--- a/src/pkgcore/restrictions/values.py
+++ b/src/pkgcore/restrictions/values.py
@@ -7,6 +7,7 @@ attr from a package instance and hand it to their wrapped 
restriction
 """
 
 import re
+from typing import Any
 
 from snakeoil.klass import generic_equality, reflective_hash
 from snakeoil.sequences import iflatten_instance
@@ -88,23 +89,16 @@ class StrRegex(base, metaclass=hashed_base):
         :param negate: should the match results be negated?
         """
 
-        sf = object.__setattr__
-        sf(self, "regex", regex)
-        sf(self, "ismatch", match)
-        sf(self, "negate", negate)
-        flags = 0
-        if not case_sensitive:
-            flags = re.I
-        sf(self, "flags", flags)
+        self.regex, self.ismatch, self.negate = regex, match, negate
+
+        self.flags = 0 if case_sensitive else re.I
         try:
-            compiled_re = re.compile(regex, flags)
+            self._matchfunc = getattr(
+                re.compile(regex, self.flags), "match" if match else "search"
+            )
         except re.error as e:
             raise ValueError(f"invalid regex: {regex!r}, {e}")
-        if match:
-            sf(self, "_matchfunc", compiled_re.match)
-        else:
-            sf(self, "_matchfunc", compiled_re.search)
-        sf(self, "_hash", hash((self.regex, self.negate, self.flags, 
self.ismatch)))
+        self._hash = hash((self.regex, self.negate, self.flags, self.ismatch))
 
     def match(self, value):
         if not isinstance(value, str):
@@ -144,21 +138,18 @@ class StrExactMatch(base, metaclass=generic_equality):
     __slots__ = __attr_comparison__ = ("_hash", "exact", "case_sensitive", 
"negate")
     __inst_caching__ = True
 
-    def __init__(self, exact, case_sensitive=True, negate=False):
+    def __init__(self, exact: str, case_sensitive=True, negate=False):
         """
         :param exact: exact string to match
         :param case_sensitive: should the match be case sensitive?
         :param negate: should the match results be negated?
         """
 
-        sf = object.__setattr__
-        sf(self, "negate", negate)
-        sf(self, "case_sensitive", case_sensitive)
+        self.negate, self.case_sensitive = negate, case_sensitive
         if not case_sensitive:
-            sf(self, "exact", str(exact).lower())
-        else:
-            sf(self, "exact", str(exact))
-        sf(self, "_hash", hash((self.exact, self.negate, self.case_sensitive)))
+            exact = exact.lower()
+        self.exact = exact
+        self._hash = hash((self.exact, self.negate, self.case_sensitive))
 
     def match(self, value):
         value = str(value)
@@ -209,16 +200,14 @@ class StrGlobMatch(base, metaclass=hashed_base):
         :param negate: should the match results be negated?
         """
 
-        sf = object.__setattr__
-        sf(self, "negate", negate)
+        self.negate = negate
+
         if not case_sensitive:
-            sf(self, "flags", re.I)
-            sf(self, "glob", str(glob).lower())
+            self.flags, self.glob = re.I, glob.lower()
         else:
-            sf(self, "flags", 0)
-            sf(self, "glob", str(glob))
-        sf(self, "prefix", prefix)
-        sf(self, "_hash", hash((self.glob, self.negate, self.flags, 
self.prefix)))
+            self.flags, self.glob = 0, glob
+        self.prefix = prefix
+        self._hash = hash((self.glob, self.negate, self.flags, self.prefix))
 
     def match(self, value):
         value = str(value)
@@ -259,15 +248,12 @@ class EqualityMatch(base, metaclass=generic_equality):
     __slots__ = ("negate", "data")
     __attr_comparison__ = __slots__
 
-    def __init__(self, data, negate=False):
+    def __init__(self, data: Any, negate=False):
         """
         :param data: data to base comparison against
         :param negate: should the results be negated?
         """
-
-        sf = object.__setattr__
-        sf(self, "negate", negate)
-        sf(self, "data", data)
+        self.negate, self.data = negate, data
 
     def __hash__(self):
         return hash((self.__class__, self.negate, self.data))
@@ -302,11 +288,9 @@ class ContainmentMatch(base, metaclass=hashed_base):
         :keyword negate: should the match results be negated?
         """
 
-        sf = object.__setattr__
-        sf(self, "all", bool(match_all))
-        sf(self, "vals", frozenset((vals,) if isinstance(vals, str) else vals))
-        sf(self, "negate", bool(negate))
-        sf(self, "_hash", hash((self.all, self.negate, self.vals)))
+        self.all, self.negate = bool(match_all), bool(negate)
+        self.vals = frozenset((vals,) if isinstance(vals, str) else vals)
+        self._hash = hash((self.all, self.negate, self.vals))
 
     def match(self, val, _values_override=None):
         vals = _values_override
@@ -519,9 +503,9 @@ class FlatteningRestriction(base, 
metaclass=generic_equality):
         :type childrestriction: restriction
         :param childrestriction: restriction applied to the flattened list.
         """
-        object.__setattr__(self, "negate", negate)
-        object.__setattr__(self, "dont_iter", dont_iter)
-        object.__setattr__(self, "restriction", childrestriction)
+        self.negate = negate
+        self.dont_iter = dont_iter
+        self.restriction = childrestriction
 
     def match(self, val):
         return (
@@ -560,8 +544,7 @@ class FunctionRestriction(base, metaclass=generic_equality):
         restriction using this class you should only use it if it is
         very unlikely backend-specific optimizations will be possible.
         """
-        object.__setattr__(self, "negate", negate)
-        object.__setattr__(self, "func", func)
+        self.negate, self.func = negate, func
 
     def match(self, val):
         return self.func(val) != self.negate
@@ -582,7 +565,7 @@ class StrConversion(base, metaclass=generic_equality):
     __attr_comparison__ = __slots__ = ("restrict",)
 
     def __init__(self, restrict):
-        object.__setattr__(self, "restrict", restrict)
+        self.restrict = restrict
 
     def match(self, val):
         return self.restrict.match(str(val))

diff --git a/src/pkgcore/scripts/pquery.py b/src/pkgcore/scripts/pquery.py
index 0d647c17..4dc65614 100644
--- a/src/pkgcore/scripts/pquery.py
+++ b/src/pkgcore/scripts/pquery.py
@@ -29,9 +29,8 @@ from ..fs import fs as fs_module
 from ..repository import multiplex
 from ..repository.util import get_raw_repos, get_virtual_repos
 from ..restrictions import boolean, packages, values
-from ..util import commandline
+from ..util import commandline, parserestrict
 from ..util import packages as pkgutils
-from ..util import parserestrict
 
 
 class DataSourceRestriction(values.base):
@@ -46,8 +45,7 @@ class DataSourceRestriction(values.base):
         **kwargs,
     ):
         super().__init__(**kwargs)
-        object.__setattr__(self, "restriction", childrestriction)
-        object.__setattr__(self, "negate", negate)
+        self.negate, self.restriction = negate, childrestriction
 
     def __str__(self):
         return f"DataSourceRestriction: {self.restriction} 
negate={self.negate}"

Reply via email to