Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-specfile for openSUSE:Factory 
checked in at 2022-12-15 19:25:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-specfile (Old)
 and      /work/SRC/openSUSE:Factory/.python-specfile.new.1835 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-specfile"

Thu Dec 15 19:25:48 2022 rev:4 rq:1043095 version:0.11.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-specfile/python-specfile.changes  
2022-12-01 16:59:58.615408352 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-specfile.new.1835/python-specfile.changes    
    2022-12-15 19:26:15.996418642 +0100
@@ -1,0 +2,22 @@
+Tue Dec 13 08:20:36 UTC 2022 - David Anes <david.a...@suse.com>
+
+- Add config.cfg improvements to remove deprecation warnings
+  * python-specfile-improve-setup-cfg.patch
+
+- Update to version 0.11.1
+  * Tags enclosed in conditional macro expansions are not ignored 
+    anymore.
+  * Fixed context managers being shared between Specfile instances. 1q
+
+- Update to version 0.11.0 
+  * Context managers (Specfile.sections(), Specfile.tags() etc.) can
+    now be nested and combined together (with one exception - 
+    Specfile.macro_definitions()), and it is also possible to use 
+    tag properties (e.g. Specfile.version, Specfile.license) inside 
+    them. It is also possible to access the data directly, avoiding 
+    the with statement, by using the content property 
+    (e.g. Specfile.tags().content), but be aware that no 
+    modifications done to such data will be preserved. You must use 
+    with to make changes.
+
+-------------------------------------------------------------------

Old:
----
  specfile-0.10.0.tar.gz

New:
----
  python-specfile-improve-setup-cfg.patch
  specfile-0.11.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-specfile.spec ++++++
--- /var/tmp/diff_new_pack.vBl1UV/_old  2022-12-15 19:26:16.568421896 +0100
+++ /var/tmp/diff_new_pack.vBl1UV/_new  2022-12-15 19:26:16.576421942 +0100
@@ -18,7 +18,7 @@
 
 %define skip_python38 1
 Name:           python-specfile
-Version:        0.10.0
+Version:        0.11.1
 Release:        0
 Summary:        A library for parsing and manipulating RPM spec files
 License:        MIT
@@ -38,7 +38,12 @@
 Requires:       python-rpm
 Requires:       python-typing-extensions
 
+# PATCH-SUSE: some improvements that are still pending upstream
+# https://github.com/packit/specfile/pull/162
+Patch0:         python-specfile-improve-setup-cfg.patch
+
 BuildArch:      noarch
+
 %python_subpackages
 
 %description
@@ -46,19 +51,22 @@
 
 %prep
 %autosetup -p1 -n specfile-%{version}
+# we use our own package for "rpm" module (see Requires)
 sed -i '/rpm-py-installer/d' setup.cfg
 
 %build
 %python_build
 
+%check
+# Following tests fail:
+# * test_update_tag
+# * test_macros_reinit
+%pytest -k "not (test_update_tag or test_macros_reinit)"
+
 %install
 %python_install
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
-%check
-# test_macros_reinit fails
-%pytest -k 'not test_macros_reinit'
-
 %files %{python_files}
 %doc CHANGELOG.md README.md
 %license LICENSE

++++++ python-specfile-improve-setup-cfg.patch ++++++
Index: specfile-0.11.1/setup.cfg
===================================================================
--- specfile-0.11.1.orig/setup.cfg
+++ specfile-0.11.1/setup.cfg
@@ -7,7 +7,8 @@ url = https://github.com/packit/specfile
 author = Red Hat
 author_email = user-cont-t...@redhat.com
 license = MIT
-license_file = LICENSE
+license_files =
+       LICENSE
 classifiers = 
        Development Status :: 4 - Beta
        Environment :: Console

++++++ specfile-0.10.0.tar.gz -> specfile-0.11.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/.packit.yaml 
new/specfile-0.11.1/.packit.yaml
--- old/specfile-0.10.0/.packit.yaml    2022-11-30 12:28:29.000000000 +0100
+++ new/specfile-0.11.1/.packit.yaml    2022-12-14 17:34:43.000000000 +0100
@@ -89,6 +89,12 @@
     list_on_homepage: True
     preserve_project: True
 
+  - job: pull_from_upstream
+    trigger: release
+    dist_git_branches:
+      - fedora-all
+      - epel-9
+
   # downstream automation:
   - job: koji_build
     trigger: commit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/CHANGELOG.md 
new/specfile-0.11.1/CHANGELOG.md
--- old/specfile-0.10.0/CHANGELOG.md    2022-11-30 12:28:29.000000000 +0100
+++ new/specfile-0.11.1/CHANGELOG.md    2022-12-14 17:34:43.000000000 +0100
@@ -1,3 +1,12 @@
+# 0.11.1
+
+- Tags enclosed in conditional macro expansions are not ignored anymore. (#156)
+- Fixed context managers being shared between Specfile instances. (#157)
+
+# 0.11.0
+
+- Context managers (`Specfile.sections()`, `Specfile.tags()` etc.) can now be 
nested and combined together (with one exception - 
`Specfile.macro_definitions()`), and it is also possible to use tag properties 
(e.g. `Specfile.version`, `Specfile.license`) inside them. It is also possible 
to access the data directly, avoiding the `with` statement, by using the 
`content` property (e.g. `Specfile.tags().content`), but be aware that no 
modifications done to such data will be preserved. You must use `with` to make 
changes. (#153)
+
 # 0.10.0
 
 - Fixed an issue that caused empty lines originally inside changelog entries 
to appear at the end. (#140)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/PKG-INFO new/specfile-0.11.1/PKG-INFO
--- old/specfile-0.10.0/PKG-INFO        2022-11-30 12:28:42.548678900 +0100
+++ new/specfile-0.11.1/PKG-INFO        2022-12-14 17:34:55.061271700 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: specfile
-Version: 0.10.0
+Version: 0.11.1
 Summary: A library for parsing and manipulating RPM spec files.
 Home-page: https://github.com/packit/specfile
 Author: Red Hat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/fedora/python-specfile.spec 
new/specfile-0.11.1/fedora/python-specfile.spec
--- old/specfile-0.10.0/fedora/python-specfile.spec     2022-11-30 
12:28:29.000000000 +0100
+++ new/specfile-0.11.1/fedora/python-specfile.spec     2022-12-14 
17:34:43.000000000 +0100
@@ -13,7 +13,7 @@
 
 
 Name:           python-specfile
-Version:        0.10.0
+Version:        0.11.1
 Release:        1%{?dist}
 
 Summary:        A library for parsing and manipulating RPM spec files
@@ -69,6 +69,12 @@
 
 
 %changelog
+* Wed Dec 14 2022 Packit Team <he...@packit.dev> - 0.11.1-1
+- New upstream release 0.11.1
+
+* Fri Dec 09 2022 Packit Team <he...@packit.dev> - 0.11.0-1
+- New upstream release 0.11.0
+
 * Sat Nov 26 2022 Packit Team <he...@packit.dev> - 0.10.0-1
 - New upstream release 0.10.0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/setup.cfg 
new/specfile-0.11.1/setup.cfg
--- old/specfile-0.10.0/setup.cfg       2022-11-30 12:28:42.548678900 +0100
+++ new/specfile-0.11.1/setup.cfg       2022-12-14 17:34:55.061271700 +0100
@@ -48,6 +48,9 @@
 exclude = 
        tests*
 
+[options.package_data]
+* = py.typed
+
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/context_management.py 
new/specfile-0.11.1/specfile/context_management.py
--- old/specfile-0.10.0/specfile/context_management.py  1970-01-01 
01:00:00.000000000 +0100
+++ new/specfile-0.11.1/specfile/context_management.py  2022-12-14 
17:34:43.000000000 +0100
@@ -0,0 +1,142 @@
+# Copyright Contributors to the Packit project.
+# SPDX-License-Identifier: MIT
+
+import collections
+import contextlib
+import io
+import os
+import pickle
+import sys
+import tempfile
+import types
+from typing import Any, Callable, Dict, Generator, List, Optional, overload
+
+
+@contextlib.contextmanager
+def capture_stderr() -> Generator[List[bytes], None, None]:
+    """
+    Context manager for capturing output to stderr. A stderr output of 
anything run
+    in its context will be captured in the target variable of the with 
statement.
+
+    Yields:
+        List of captured lines.
+    """
+    fileno = sys.__stderr__.fileno()
+    with tempfile.TemporaryFile() as stderr, os.fdopen(os.dup(fileno)) as 
backup:
+        sys.stderr.flush()
+        os.dup2(stderr.fileno(), fileno)
+        data: List[bytes] = []
+        try:
+            yield data
+        finally:
+            sys.stderr.flush()
+            os.dup2(backup.fileno(), fileno)
+            stderr.flush()
+            stderr.seek(0, io.SEEK_SET)
+            data.extend(stderr.readlines())
+
+
+class GeneratorContextManager(contextlib._GeneratorContextManager):
+    """
+    Extended contextlib._GeneratorContextManager that provides get() method.
+    """
+
+    def __init__(self, function: Callable) -> None:
+        super().__init__(function, tuple(), {})
+
+    def __del__(self) -> None:
+        # make sure the generator is fully consumed, as it is possible
+        # that neither __enter__() nor content() have been called
+        collections.deque(self.gen, maxlen=0)
+
+    @property
+    def content(self) -> Any:
+        """
+        Fully consumes the underlying generator and returns the yielded value.
+
+        Returns:
+            Value that would normally be the target variable of an associated 
with statement.
+
+        Raises:
+            StopIteration if the underlying generator is already exhausted.
+        """
+        result = next(self.gen)
+        next(self.gen, None)
+        return result
+
+
+class ContextManager:
+    """
+    Class for decorating generator functions that should act as a context 
manager.
+
+    Just like with contextlib.contextmanager, the generator returned from the 
decorated function
+    must yield exactly one value that will be used as the target variable of 
the with statement.
+    If the same function with the same arguments is called again from within 
previously generated
+    context, the generator will be ignored and the target variable will be 
reused.
+
+    Attributes:
+        function: Decorated generator function.
+        generators: Mapping of serialized function arguments to generators.
+        values: Mapping of serialized function arguments to yielded values.
+    """
+
+    def __init__(self, function: Callable) -> None:
+        self.function = function
+        self.is_bound = False
+        self.generators: Dict[bytes, Generator[Any, None, None]] = {}
+        self.values: Dict[bytes, Any] = {}
+
+    @overload
+    def __get__(self, obj: None, objtype: Optional[type] = None) -> 
"ContextManager":
+        pass
+
+    @overload
+    def __get__(self, obj: object, objtype: Optional[type] = None) -> 
types.MethodType:
+        pass
+
+    # implementing __get__() makes the class a non-data descriptor,
+    # so it can be used as method decorator
+    def __get__(self, obj, objtype=None):
+        if obj is None:
+            return self
+        self.is_bound = True
+        return types.MethodType(self, obj)
+
+    def __call__(self, *args: Any, **kwargs: Any) -> GeneratorContextManager:
+        # serialize the passed arguments
+        payload = list(args) + sorted(kwargs.items())
+        if payload and self.is_bound:
+            # do not attempt to pickle self/cls
+            payload[0] = (type(payload[0]), id(payload[0]))
+        key = pickle.dumps(payload, protocol=pickle.HIGHEST_PROTOCOL)
+        if (
+            key in self.generators
+            # gi_frame is None only in case generator is exhausted
+            and self.generators[key].gi_frame is not None  # type: 
ignore[attr-defined]
+        ):
+            # generator is suspended, use existing value
+            def existing_value():
+                try:
+                    yield self.values[key]
+                except KeyError:
+                    # if the generator is being consumed in 
GeneratorContextManager destructor,
+                    # self.values[key] could have already been deleted
+                    pass
+
+            return GeneratorContextManager(existing_value)
+        # create the generator
+        self.generators[key] = self.function(*args, **kwargs)
+        # first iteration yields the value
+        self.values[key] = next(self.generators[key])
+
+        def new_value():
+            try:
+                yield self.values[key]
+            finally:
+                # second iteration wraps things up
+                next(self.generators[key], None)
+                # the generator is now exhausted and the value is no longer 
valid
+                del self.generators[key]
+                del self.values[key]
+
+        return GeneratorContextManager(new_value)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/macro_definitions.py 
new/specfile-0.11.1/specfile/macro_definitions.py
--- old/specfile-0.10.0/specfile/macro_definitions.py   2022-11-30 
12:28:29.000000000 +0100
+++ new/specfile-0.11.1/specfile/macro_definitions.py   2022-12-14 
17:34:43.000000000 +0100
@@ -37,6 +37,20 @@
         macro = "%global" if self.is_global else "%define"
         return f"{ws[0]}{macro}{ws[1]}{self.name}{ws[2]}{self.body}{ws[3]}"
 
+    def get_position(self, container: "MacroDefinitions") -> int:
+        """
+        Gets position of this macro definition in the spec file.
+
+        Args:
+            container: `MacroDefinitions` instance that contains this macro 
definition.
+
+        Returns:
+            Position expressed as line number (starting from 0).
+        """
+        return sum(
+            len(md.get_raw_data()) for md in container[: container.index(self)]
+        ) + len(self._preceding_lines)
+
     def get_raw_data(self) -> List[str]:
         result = self._preceding_lines.copy()
         ws = self._whitespace
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/macros.py 
new/specfile-0.11.1/specfile/macros.py
--- old/specfile-0.10.0/specfile/macros.py      2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/specfile/macros.py      2022-12-14 17:34:43.000000000 
+0100
@@ -8,8 +8,8 @@
 
 import rpm
 
+from specfile.context_management import capture_stderr
 from specfile.exceptions import MacroRemovalException, RPMException
-from specfile.utils import capture_stderr
 
 MAX_REMOVAL_RETRIES = 20
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/prep.py 
new/specfile-0.11.1/specfile/prep.py
--- old/specfile-0.10.0/specfile/prep.py        2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/specfile/prep.py        2022-12-14 17:34:43.000000000 
+0100
@@ -8,6 +8,7 @@
 
 from specfile.macro_options import MacroOptions
 from specfile.sections import Section
+from specfile.utils import split_conditional_macro_expansion
 
 
 class PrepMacro(ABC):
@@ -330,18 +331,13 @@
         Returns:
             Constructed instance of `Prep` class.
         """
-        # match also macros enclosed in conditionalized macro expansion
-        # e.g.: %{?with_system_nss:%patch30 -p3 -b .nss_pkcs11_v3}
         macro_regex = re.compile(
-            r"(?P<c>%{!?\?\w+:)?.*?"
-            r"(?P<m>%(setup|patch\d*|autopatch|autosetup))"
-            r"(?P<d>\s*)"
-            r"(?P<o>.*?)"
-            r"(?(c)}|$)"
+            
r"(?P<m>%(setup|patch\d*|autopatch|autosetup))(?P<d>\s*)(?P<o>.*?)$"
         )
         data = []
         buffer: List[str] = []
         for line in section:
+            line, prefix, suffix = split_conditional_macro_expansion(line)
             m = macro_regex.search(line)
             if m:
                 name, delimiter, option_string = (
@@ -349,7 +345,8 @@
                     m.group("d"),
                     m.group("o"),
                 )
-                prefix, suffix = line[: m.start("m")], line[m.end("o") :]
+                prefix += line[: m.start("m")]
+                suffix = line[m.end("o") :] + suffix
                 klass = next(
                     (
                         klass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/sources.py 
new/specfile-0.11.1/specfile/sources.py
--- old/specfile-0.10.0/specfile/sources.py     2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/specfile/sources.py     2022-12-14 17:34:43.000000000 
+0100
@@ -38,7 +38,7 @@
 
     @property
     @abstractmethod
-    def expanded_location(self) -> str:
+    def expanded_location(self) -> Optional[str]:
         """Location of the source after expanding macros."""
         ...
 
@@ -56,7 +56,7 @@
 
     @property
     @abstractmethod
-    def expanded_filename(self) -> str:
+    def expanded_filename(self) -> Optional[str]:
         """Filename of the source after expanding macros."""
         ...
 
@@ -86,7 +86,9 @@
 
     def __repr__(self) -> str:
         tag = repr(self._tag)
-        return f"TagSource({tag}, {self._number})"
+        # determine class name dynamically so that inherited classes
+        # don't have to reimplement __repr__()
+        return f"{self.__class__.__name__}({tag}, {self._number})"
 
     def _extract_number(self) -> Optional[str]:
         """
@@ -133,7 +135,7 @@
         self._tag.value = value
 
     @property
-    def expanded_location(self) -> str:
+    def expanded_location(self) -> Optional[str]:
         """Location of the source after expanding macros."""
         return self._tag.expanded_value
 
@@ -143,8 +145,10 @@
         return get_filename_from_location(self._tag.value)
 
     @property
-    def expanded_filename(self) -> str:
+    def expanded_filename(self) -> Optional[str]:
         """Filename of the source after expanding macros."""
+        if self._tag.expanded_value is None:
+            return None
         return get_filename_from_location(self._tag.expanded_value)
 
     @property
@@ -154,7 +158,7 @@
 
 
 class ListSource(Source):
-    """Class that represents a source backed by a line in a 
%sourcelist/%patchlist section."""
+    """Class that represents a source backed by a line in a %sourcelist 
section."""
 
     def __init__(self, source: SourcelistEntry, number: int) -> None:
         """
@@ -172,7 +176,9 @@
 
     def __repr__(self) -> str:
         source = repr(self._source)
-        return f"ListSource({source}, {self._number})"
+        # determine class name dynamically so that inherited classes
+        # don't have to reimplement __repr__()
+        return f"{self.__class__.__name__}({source}, {self._number})"
 
     @property
     def number(self) -> int:
@@ -212,7 +218,9 @@
 class Sources(collections.abc.MutableSequence):
     """Class that represents a sequence of all sources."""
 
-    PREFIX: str = "Source"
+    prefix: str = "Source"
+    tag_class: type = TagSource
+    list_class: type = ListSource
 
     def __init__(
         self,
@@ -330,11 +338,11 @@
         result = []
         last_number = -1
         for i, tag in enumerate(self._tags):
-            if tag.name.capitalize() == self.PREFIX.capitalize():
+            if tag.normalized_name == self.prefix:
                 last_number += 1
-                ts = TagSource(tag, last_number)
-            elif tag.name.capitalize().startswith(self.PREFIX.capitalize()):
-                ts = TagSource(tag)
+                ts = self.tag_class(tag, last_number)
+            elif tag.normalized_name.startswith(self.prefix):
+                ts = self.tag_class(tag)
                 last_number = ts.number
             else:
                 continue
@@ -356,7 +364,7 @@
         )
         last_number = result[-1][0].number if result else -1
         result.extend(
-            (ListSource(sl[i], last_number + 1 + i), sl, i)
+            (self.list_class(sl[i], last_number + 1 + i), sl, i)
             for sl in self._sourcelists
             for i in range(len(sl))
         )
@@ -399,7 +407,6 @@
         Returns:
             Tuple in the form of (name, separator).
         """
-        prefix = self.PREFIX.capitalize()
         if number_digits_override is not None:
             number_digits = number_digits_override
         else:
@@ -408,7 +415,7 @@
             suffix = ""
         else:
             suffix = f"{number:0{number_digits}}"
-        name = f"{prefix}{suffix}"
+        name = f"{self.prefix}{suffix}"
         diff = len(reference._tag.name) - len(name)
         if diff >= 0:
             return name, reference._tag._separator + " " * diff
@@ -426,7 +433,6 @@
         Returns:
             Tuple in the form of (index, name, separator).
         """
-        prefix = self.PREFIX.capitalize()
         if (
             self._default_to_implicit_numbering
             or self._default_source_number_digits == 0
@@ -434,7 +440,7 @@
             suffix = ""
         else:
             suffix = f"{number:0{self._default_source_number_digits}}"
-        return len(self._tags) if self._tags else 0, f"{prefix}{suffix}", ": "
+        return len(self._tags) if self._tags else 0, f"{self.prefix}{suffix}", 
": "
 
     def _deduplicate_tag_names(self, start: int = 0) -> None:
         """
@@ -469,7 +475,7 @@
               already is a source with the same location.
         """
         if not self._allow_duplicates and location in self:
-            raise DuplicateSourceException(f"Source '{location}' already 
exists")
+            raise DuplicateSourceException(f"{self.prefix} '{location}' 
already exists")
         items = self._get_items()
         if i > len(items):
             i = len(items)
@@ -481,8 +487,8 @@
             else:
                 source, container, index = items[i]
                 number = source.number
-            if isinstance(source, TagSource):
-                name, separator = self._get_tag_format(source, number)
+            if isinstance(source, self.tag_class):
+                name, separator = self._get_tag_format(cast(TagSource, 
source), number)
                 container.insert(
                     index,
                     Tag(name, location, self._expand(location), separator, 
Comments()),
@@ -518,7 +524,7 @@
               already is a source with the same location.
         """
         if not self._allow_duplicates and location in self:
-            raise DuplicateSourceException(f"Source '{location}' already 
exists")
+            raise DuplicateSourceException(f"{self.prefix} '{location}' 
already exists")
         tags = self._get_tags()
         if tags:
             # find the nearest source tag
@@ -580,10 +586,24 @@
         return len([s for s in list(zip(*items))[0] if s.location == location])
 
 
+class Patch(Source):
+    """Class that represents a patch."""
+
+
+class TagPatch(TagSource, Patch):
+    """Class that represents a patch backed by a spec file tag."""
+
+
+class ListPatch(ListSource, Patch):
+    """Class that represents a patch backed by a line in a %patchlist 
section."""
+
+
 class Patches(Sources):
     """Class that represents a sequence of all patches."""
 
-    PREFIX: str = "Patch"
+    prefix: str = "Patch"
+    tag_class: type = TagPatch
+    list_class: type = ListPatch
 
     def _get_initial_tag_setup(self, number: int = 0) -> Tuple[int, str, str]:
         """
@@ -599,9 +619,9 @@
         """
         try:
             index, source = [
-                (i, TagSource(t))
+                (i, Sources.tag_class(t))
                 for i, t in enumerate(self._tags)
-                if t.name.capitalize().startswith("Source")
+                if t.normalized_name.startswith(Sources.prefix)
             ][-1]
         except IndexError:
             return super()._get_initial_tag_setup(number)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/spec_parser.py 
new/specfile-0.11.1/specfile/spec_parser.py
--- old/specfile-0.10.0/specfile/spec_parser.py 2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/specfile/spec_parser.py 2022-12-14 17:34:43.000000000 
+0100
@@ -11,11 +11,12 @@
 
 import rpm
 
+from specfile.context_management import capture_stderr
 from specfile.exceptions import RPMException
 from specfile.macros import Macros
 from specfile.sections import Section
 from specfile.tags import Tags
-from specfile.utils import capture_stderr, get_filename_from_location
+from specfile.utils import get_filename_from_location
 from specfile.value_parser import ConditionalMacroExpansion, ShellExpansion, 
ValueParser
 
 logger = logging.getLogger(__name__)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/specfile.py 
new/specfile-0.11.1/specfile/specfile.py
--- old/specfile-0.10.0/specfile/specfile.py    2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/specfile/specfile.py    2022-12-14 17:34:43.000000000 
+0100
@@ -1,18 +1,18 @@
 # Copyright Contributors to the Packit project.
 # SPDX-License-Identifier: MIT
 
-import contextlib
 import datetime
 import re
 import subprocess
 import types
 from dataclasses import dataclass
 from pathlib import Path
-from typing import Iterator, List, Optional, Tuple, Type, Union
+from typing import Generator, List, Optional, Tuple, Type, Union
 
 import rpm
 
 from specfile.changelog import Changelog, ChangelogEntry
+from specfile.context_management import ContextManager
 from specfile.exceptions import SourceNumberException, SpecfileException
 from specfile.macro_definitions import MacroDefinition, MacroDefinitions
 from specfile.macros import Macro, Macros
@@ -148,8 +148,8 @@
         self._parser.parse(str(self))
         return Macros.dump()
 
-    @contextlib.contextmanager
-    def lines(self) -> Iterator[List[str]]:
+    @ContextManager
+    def lines(self) -> Generator[List[str], None, None]:
         """
         Context manager for accessing spec file lines.
 
@@ -163,8 +163,8 @@
             if self.autosave:
                 self.save()
 
-    @contextlib.contextmanager
-    def macro_definitions(self) -> Iterator[MacroDefinitions]:
+    @ContextManager
+    def macro_definitions(self) -> Generator[MacroDefinitions, None, None]:
         """
         Context manager for accessing macro definitions.
 
@@ -178,8 +178,8 @@
             finally:
                 lines[:] = macro_definitions.get_raw_data()
 
-    @contextlib.contextmanager
-    def sections(self) -> Iterator[Sections]:
+    @ContextManager
+    def sections(self) -> Generator[Sections, None, None]:
         """
         Context manager for accessing spec file sections.
 
@@ -200,8 +200,10 @@
             return None
         return Sections.parse(self._parser.spec.parsed.splitlines())
 
-    @contextlib.contextmanager
-    def tags(self, section: Union[str, Section] = "package") -> Iterator[Tags]:
+    @ContextManager
+    def tags(
+        self, section: Union[str, Section] = "package"
+    ) -> Generator[Tags, None, None]:
         """
         Context manager for accessing tags in a specified section.
 
@@ -212,26 +214,21 @@
         Yields:
             Tags in the section as `Tags` object.
         """
-        if isinstance(section, Section):
-            raw_section = section
-            parsed_section = getattr(self.parsed_sections, section.name, None)
+        with self.sections() as sections:
+            if isinstance(section, Section):
+                raw_section = section
+                parsed_section = getattr(self.parsed_sections, section.name, 
None)
+            else:
+                raw_section = getattr(sections, section)
+                parsed_section = getattr(self.parsed_sections, section, None)
             tags = Tags.parse(raw_section, parsed_section)
             try:
                 yield tags
             finally:
                 raw_section.data = tags.get_raw_section_data()
-        else:
-            with self.sections() as sections:
-                raw_section = getattr(sections, section)
-                parsed_section = getattr(self.parsed_sections, section, None)
-                tags = Tags.parse(raw_section, parsed_section)
-                try:
-                    yield tags
-                finally:
-                    raw_section.data = tags.get_raw_section_data()
 
-    @contextlib.contextmanager
-    def changelog(self) -> Iterator[Optional[Changelog]]:
+    @ContextManager
+    def changelog(self) -> Generator[Optional[Changelog], None, None]:
         """
         Context manager for accessing changelog.
 
@@ -250,8 +247,8 @@
                 finally:
                     section.data = changelog.get_raw_section_data()
 
-    @contextlib.contextmanager
-    def prep(self) -> Iterator[Optional[Prep]]:
+    @ContextManager
+    def prep(self) -> Generator[Optional[Prep], None, None]:
         """
         Context manager for accessing %prep section.
 
@@ -270,13 +267,13 @@
                 finally:
                     section.data = prep.get_raw_section_data()
 
-    @contextlib.contextmanager
+    @ContextManager
     def sources(
         self,
         allow_duplicates: bool = False,
         default_to_implicit_numbering: bool = False,
         default_source_number_digits: int = 1,
-    ) -> Iterator[Sources]:
+    ) -> Generator[Sources, None, None]:
         """
         Context manager for accessing sources.
 
@@ -288,7 +285,7 @@
         Yields:
             Spec file sources as `Sources` object.
         """
-        with self.sections() as sections, self.tags(sections.package) as tags:
+        with self.sections() as sections, self.tags() as tags:
             sourcelists = [
                 (s, Sourcelist.parse(s, context=self))
                 for s in sections
@@ -307,13 +304,13 @@
                 for section, sourcelist in sourcelists:
                     section.data = sourcelist.get_raw_section_data()
 
-    @contextlib.contextmanager
+    @ContextManager
     def patches(
         self,
         allow_duplicates: bool = False,
         default_to_implicit_numbering: bool = False,
         default_source_number_digits: int = 1,
-    ) -> Iterator[Patches]:
+    ) -> Generator[Patches, None, None]:
         """
         Context manager for accessing patches.
 
@@ -325,7 +322,7 @@
         Yields:
             Spec file patches as `Patches` object.
         """
-        with self.sections() as sections, self.tags(sections.package) as tags:
+        with self.sections() as sections, self.tags() as tags:
             patchlists = [
                 (s, Sourcelist.parse(s, context=self))
                 for s in sections
@@ -530,7 +527,7 @@
     @property
     def expanded_release(self) -> str:
         """Release string without the dist suffix with macros expanded."""
-        return self.expand(self.release)
+        return self.expand(self.release, extra_macros=[("dist", "")])
 
     def set_version_and_release(self, version: str, release: str = "1") -> 
None:
         """
@@ -581,7 +578,11 @@
                 patches[index].comments.extend(comment.splitlines())
 
     def update_value(
-        self, value: str, requested_value: str, protected_entities: 
Optional[str] = None
+        self,
+        value: str,
+        requested_value: str,
+        position: int,
+        protected_entities: Optional[str] = None,
     ) -> str:
         """
         Updates a value from within the context of the spec file with a new 
value,
@@ -591,6 +592,7 @@
         Args:
             value: Value to update.
             requested_value: Requested new value.
+            position: Position (line number) of the value in the spec file.
             protected_entities: Regular expression specifying protected tags 
and macro definitions,
               ensuring their values won't be updated.
 
@@ -600,8 +602,10 @@
 
         @dataclass
         class Entity:
+            name: str
             value: str
             type: Type
+            position: int
             locked: bool = False
             updated: bool = False
 
@@ -611,32 +615,38 @@
             re.IGNORECASE,
         )
         # collect modifiable entities
-        entities = {}
+        entities = []
         with self.macro_definitions() as macro_definitions:
-            entities.update(
-                {
-                    md.name: Entity(md.body, type(md))
+            entities.extend(
+                [
+                    Entity(
+                        md.name, md.body, type(md), 
md.get_position(macro_definitions)
+                    )
                     for md in macro_definitions
                     if not protected_regex.match(md.name)
                     and not md.name.endswith(")")  # skip macro definitions 
with options
-                }
+                ]
             )
-        # order matters here - if there is a macro definition redefining a tag,
-        # we want to update the tag, not the macro definition
         with self.tags() as tags:
-            entities.update(
-                {
-                    t.name.lower(): Entity(t.value, type(t))
+            entities.extend(
+                [
+                    Entity(t.name.lower(), t.value, type(t), 
t.get_position(tags))
                     for t in tags
                     if not protected_regex.match(t.name)
-                }
+                ]
             )
-        # tags can be referenced as %{tag} or %{TAG}
-        entities.update({k.upper(): v for k, v in entities.items() if v.type 
== Tag})
+        entities.sort(key=lambda e: e.position)
 
-        def update(value, requested_value):
+        def update(value, requested_value, position):
+            modifiable_entities = {e.name for e in entities if e.position < 
position}
+            # tags can be referenced as %{tag} or %{TAG}
+            modifiable_entities.update(
+                e.name.upper()
+                for e in entities
+                if e.position < position and e.type == Tag
+            )
             regex, template = ValueParser.construct_regex(
-                value, entities.keys(), context=self
+                value, modifiable_entities, context=self
             )
             m = regex.match(requested_value)
             if m:
@@ -644,33 +654,41 @@
                 for grp, val in d.items():
                     if grp.startswith(SUBSTITUTION_GROUP_PREFIX):
                         continue
-                    if entities[grp].locked:
+                    # find the closest matching entity
+                    entity = [
+                        e
+                        for e in entities
+                        if e.position < position
+                        and (
+                            e.name == grp
+                            and e.type == MacroDefinition
+                            or e.name == grp.lower()
+                            and e.type == Tag
+                        )
+                    ][-1]
+                    if entity.locked:
                         # avoid infinite recursion
                         return requested_value
-                    entities[grp].locked = True
+                    entity.locked = True
                     try:
-                        entities[grp].value = update(entities[grp].value, val)
+                        entity.value = update(entity.value, val, 
entity.position)
                     finally:
-                        entities[grp].locked = False
-                        entities[grp].updated = True
+                        entity.locked = False
+                        entity.updated = True
                 return template.substitute(d)
             # no match, simply return the requested value
             return requested_value
 
-        result = update(value, requested_value)
+        result = update(value, requested_value, position)
         # synchronize back any changes
         with self.macro_definitions() as macro_definitions:
-            for n, v in [
-                (n, v)
-                for n, v in entities.items()
-                if v.updated and v.type == MacroDefinition
+            for entity in [
+                e for e in entities if e.updated and e.type == MacroDefinition
             ]:
-                getattr(macro_definitions, n).body = v.value
+                getattr(macro_definitions, entity.name).body = entity.value
         with self.tags() as tags:
-            for n, v in [
-                (n, v) for n, v in entities.items() if v.updated and v.type == 
Tag
-            ]:
-                getattr(tags, n).value = v.value
+            for entity in [e for e in entities if e.updated and e.type == Tag]:
+                getattr(tags, entity.name).value = entity.value
         return result
 
     def update_tag(
@@ -688,11 +706,13 @@
               ensuring their values won't be updated.
         """
         with self.tags() as tags:
-            original_value = getattr(tags, name).value
+            tag = getattr(tags, name)
+            original_value = tag.value
+            position = tag.get_position(tags)
         # we can't use update_value() within the context manager, because any 
changes
         # made by it to tags or macro definitions would be thrown away
         updated_value = self.update_value(
-            original_value, value, protected_entities=protected_entities
+            original_value, value, position, 
protected_entities=protected_entities
         )
         with self.tags() as tags:
             getattr(tags, name).value = updated_value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/tags.py 
new/specfile-0.11.1/specfile/tags.py
--- old/specfile-0.10.0/specfile/tags.py        2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/specfile/tags.py        2022-12-14 17:34:43.000000000 
+0100
@@ -8,6 +8,7 @@
 
 from specfile.constants import TAG_NAMES, TAGS_WITH_ARG
 from specfile.sections import Section
+from specfile.utils import split_conditional_macro_expansion
 
 
 def get_tag_name_regex(name: str) -> str:
@@ -187,9 +188,11 @@
         self,
         name: str,
         value: str,
-        expanded_value: str,
+        expanded_value: Optional[str],
         separator: str,
         comments: Comments,
+        prefix: Optional[str] = None,
+        suffix: Optional[str] = None,
     ) -> None:
         """
         Constructs a `Tag` object.
@@ -202,6 +205,8 @@
               Separator between name and literal value (colon usually 
surrounded by some
               amount of whitespace).
             comments: List of comments associated with the tag.
+            prefix: Characters preceding the tag on a line.
+            suffix: Characters following the tag on a line.
 
         Returns:
             Constructed instance of `Tag` class.
@@ -216,6 +221,8 @@
         self._expanded_value = expanded_value
         self._separator = separator
         self.comments = comments.copy()
+        self._prefix = prefix or ""
+        self._suffix = suffix or ""
 
     def __eq__(self, other: object) -> bool:
         if not isinstance(other, Tag):
@@ -226,13 +233,16 @@
             and self._expanded_value == other._expanded_value
             and self._separator == other._separator
             and self.comments == other.comments
+            and self._prefix == other._prefix
+            and self._suffix == other._suffix
         )
 
     def __repr__(self) -> str:
         comments = repr(self.comments)
+        expanded_value = repr(self._expanded_value)
         return (
-            f"Tag('{self.name}', '{self.value}', '{self._expanded_value}', "
-            f"'{self._separator}', {comments})"
+            f"Tag('{self.name}', '{self.value}', {expanded_value}, "
+            f"'{self._separator}', {comments}, '{self._prefix}', 
'{self._suffix}')"
         )
 
     @property
@@ -249,10 +259,25 @@
         return self._expanded_value is not None
 
     @property
-    def expanded_value(self) -> str:
+    def expanded_value(self) -> Optional[str]:
         """Value of the tag after expanding macros and evaluating all 
conditions."""
         return self._expanded_value
 
+    def get_position(self, container: "Tags") -> int:
+        """
+        Gets position of this tag in a section.
+
+        Args:
+            container: `Tags` instance that contains this tag.
+
+        Returns:
+            Position expressed as line number (starting from 0).
+        """
+        return sum(
+            len(t.comments.get_raw_data()) + 1
+            for t in container[: container.index(self)]
+        ) + len(self.comments.get_raw_data())
+
 
 class Tags(collections.UserList):
     """
@@ -426,6 +451,7 @@
         data = []
         buffer: List[str] = []
         for line in raw_section:
+            line, prefix, suffix = split_conditional_macro_expansion(line)
             # find out if there is a match for one of the tag regexes
             m = next((m for m in (r.match(line) for r in tag_regexes) if m), 
None)
             if m:
@@ -447,6 +473,8 @@
                         expanded_value,
                         m.group("s"),
                         Comments.parse(buffer),
+                        prefix,
+                        suffix,
                     )
                 )
                 buffer = []
@@ -464,6 +492,8 @@
         result = []
         for tag in self.data:
             result.extend(tag.comments.get_raw_data())
-            result.append(f"{tag.name}{tag._separator}{tag.value}")
+            result.append(
+                
f"{tag._prefix}{tag.name}{tag._separator}{tag.value}{tag._suffix}"
+            )
         result.extend(self._remainder)
         return result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/utils.py 
new/specfile-0.11.1/specfile/utils.py
--- old/specfile-0.10.0/specfile/utils.py       2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/specfile/utils.py       2022-12-14 17:34:43.000000000 
+0100
@@ -2,16 +2,12 @@
 # SPDX-License-Identifier: MIT
 
 import collections
-import contextlib
-import io
-import os
 import re
-import sys
-import tempfile
-from typing import Iterator, List
+from typing import Tuple
 
 from specfile.constants import ARCH_NAMES
-from specfile.exceptions import SpecfileException
+from specfile.exceptions import SpecfileException, UnterminatedMacroException
+from specfile.value_parser import ConditionalMacroExpansion, ValueParser
 
 
 class EVR(collections.abc.Hashable):
@@ -120,30 +116,6 @@
         return cls(name=n, epoch=int(e) if e else 0, version=v, release=r, 
arch=a)
 
 
-@contextlib.contextmanager
-def capture_stderr() -> Iterator[List[bytes]]:
-    """
-    Context manager for capturing output to stderr. A stderr output of 
anything run
-    in its context will be captured in the target variable of the with 
statement.
-
-    Yields:
-        List of captured lines.
-    """
-    fileno = sys.__stderr__.fileno()
-    with tempfile.TemporaryFile() as stderr, os.fdopen(os.dup(fileno)) as 
backup:
-        sys.stderr.flush()
-        os.dup2(stderr.fileno(), fileno)
-        data: List[bytes] = []
-        try:
-            yield data
-        finally:
-            sys.stderr.flush()
-            os.dup2(backup.fileno(), fileno)
-            stderr.flush()
-            stderr.seek(0, io.SEEK_SET)
-            data.extend(stderr.readlines())
-
-
 def get_filename_from_location(location: str) -> str:
     """
     Extracts filename from given source location.
@@ -160,3 +132,27 @@
     if slash < 0:
         return location
     return location[slash + 1 :].split("=")[-1]
+
+
+def split_conditional_macro_expansion(value: str) -> Tuple[str, str, str]:
+    """
+    Splits conditional macro expansion into its body and prefix and suffix of 
it.
+    If the passed string isn't a conditional macro expansion, returns it as it 
is.
+
+    Args:
+        value: String to be split.
+
+    Returns:
+        Tuple of body, prefix, suffix. Prefix and suffix will be empty if the 
passed string
+        isn't a conditional macro expansion.
+    """
+    try:
+        nodes = ValueParser.parse(value)
+    except UnterminatedMacroException:
+        return value, "", ""
+    if len(nodes) != 1:
+        return value, "", ""
+    node = nodes[0]
+    if not isinstance(node, ConditionalMacroExpansion):
+        return value, "", ""
+    return "".join(str(n) for n in node.body), 
f"%{{{node.prefix}{node.name}:", "}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile/value_parser.py 
new/specfile-0.11.1/specfile/value_parser.py
--- old/specfile-0.10.0/specfile/value_parser.py        2022-11-30 
12:28:29.000000000 +0100
+++ new/specfile-0.11.1/specfile/value_parser.py        2022-12-14 
17:34:43.000000000 +0100
@@ -5,7 +5,7 @@
 import re
 from abc import ABC
 from string import Template
-from typing import TYPE_CHECKING, List, Optional, Pattern, Tuple
+from typing import TYPE_CHECKING, List, Optional, Pattern, Set, Tuple
 
 from specfile.exceptions import UnterminatedMacroException
 from specfile.macros import Macros
@@ -254,7 +254,7 @@
     def construct_regex(
         cls,
         value: str,
-        modifiable_entities: List[str],
+        modifiable_entities: Set[str],
         context: Optional["Specfile"] = None,
     ) -> Tuple[Pattern, Template]:
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile.egg-info/PKG-INFO 
new/specfile-0.11.1/specfile.egg-info/PKG-INFO
--- old/specfile-0.10.0/specfile.egg-info/PKG-INFO      2022-11-30 
12:28:42.000000000 +0100
+++ new/specfile-0.11.1/specfile.egg-info/PKG-INFO      2022-12-14 
17:34:54.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: specfile
-Version: 0.10.0
+Version: 0.11.1
 Summary: A library for parsing and manipulating RPM spec files.
 Home-page: https://github.com/packit/specfile
 Author: Red Hat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/specfile.egg-info/SOURCES.txt 
new/specfile-0.11.1/specfile.egg-info/SOURCES.txt
--- old/specfile-0.10.0/specfile.egg-info/SOURCES.txt   2022-11-30 
12:28:42.000000000 +0100
+++ new/specfile-0.11.1/specfile.egg-info/SOURCES.txt   2022-12-14 
17:34:55.000000000 +0100
@@ -35,11 +35,13 @@
 specfile/__init__.py
 specfile/changelog.py
 specfile/constants.py
+specfile/context_management.py
 specfile/exceptions.py
 specfile/macro_definitions.py
 specfile/macro_options.py
 specfile/macros.py
 specfile/prep.py
+specfile/py.typed
 specfile/sections.py
 specfile/sourcelist.py
 specfile/sources.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/tests/data/spec_macros/test.spec 
new/specfile-0.11.1/tests/data/spec_macros/test.spec
--- old/specfile-0.10.0/tests/data/spec_macros/test.spec        2022-11-30 
12:28:29.000000000 +0100
+++ new/specfile-0.11.1/tests/data/spec_macros/test.spec        2022-12-14 
17:34:43.000000000 +0100
@@ -3,11 +3,12 @@
 %global patchver 2
 %global prever rc2
 %global package_version %{majorver}.%{minorver}.%{patchver}
+%global release 1%{?dist}
 
 
 Name:           test
 Version:        %{package_version}%{?prever:~%{prever}}
-Release:        1%{?dist}
+Release:        %{release}
 Summary:        Test package
 
 License:        MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/tests/integration/test_specfile.py 
new/specfile-0.11.1/tests/integration/test_specfile.py
--- old/specfile-0.10.0/tests/integration/test_specfile.py      2022-11-30 
12:28:29.000000000 +0100
+++ new/specfile-0.11.1/tests/integration/test_specfile.py      2022-12-14 
17:34:43.000000000 +0100
@@ -311,6 +311,10 @@
         assert md.prever.body == "alpha1"
         assert md.package_version.body == "4.0"
     assert spec.version == "5.3.3"
+    spec.update_tag("Release", "2%{?dist}")
+    assert spec.raw_release == "%{release}"
+    with spec.macro_definitions() as md:
+        assert md.release.body == "2%{?dist}"
     spec.update_tag(
         "Source0",
         "https://example.com/archived_releases/test/v6.0.0/test-v6.0.0.tar.xz";,
@@ -387,3 +391,25 @@
     spec = Specfile(spec_shell_expansions)
     assert spec.expanded_version == "1035.4200"
     assert "C.UTF-8" in spec.expand("%numeric_locale")
+
+
+def test_context_management(spec_autosetup, spec_traditional):
+    spec = Specfile(spec_autosetup)
+    with spec.tags() as tags:
+        tags.license.value = "BSD"
+        assert spec.license == "BSD"
+        spec.license = "BSD-3-Clause"
+        tags.patch0.value = "first_patch.patch"
+        with spec.patches() as patches:
+            assert patches[0].location == "first_patch.patch"
+            patches[0].location = "patch_0.patch"
+    assert spec.license == "BSD-3-Clause"
+    with spec.patches() as patches:
+        assert patches[0].location == "patch_0.patch"
+    spec1 = Specfile(spec_autosetup)
+    spec2 = Specfile(spec_traditional)
+    with spec1.sections() as sections1, spec2.sections() as sections2:
+        assert sections1 is not sections2
+    with spec1.tags() as tags1, spec2.tags() as tags2:
+        assert tags1 is not tags2
+        assert tags1 == tags2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/tests/unit/test_sources.py 
new/specfile-0.11.1/tests/unit/test_sources.py
--- old/specfile-0.10.0/tests/unit/test_sources.py      2022-11-30 
12:28:29.000000000 +0100
+++ new/specfile-0.11.1/tests/unit/test_sources.py      2022-12-14 
17:34:43.000000000 +0100
@@ -246,7 +246,7 @@
             for sl in sourcelists
         ],
     )
-    if location in [v for t, v in tags if t.startswith(Sources.PREFIX)] + [
+    if location in [v for t, v in tags if t.startswith(Sources.prefix)] + [
         s for sl in sourcelists for s in sl
     ]:
         with pytest.raises(SpecfileException):
@@ -333,7 +333,7 @@
 )
 def test_sources_insert_numbered(tags, number, location, index):
     sources = Sources(Tags([Tag(t, v, v, ": ", Comments()) for t, v in tags]), 
[])
-    if location in [v for t, v in tags if t.startswith(Sources.PREFIX)]:
+    if location in [v for t, v in tags if t.startswith(Sources.prefix)]:
         with pytest.raises(SpecfileException):
             sources.insert_numbered(number, location)
     else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/specfile-0.10.0/tests/unit/test_tags.py 
new/specfile-0.11.1/tests/unit/test_tags.py
--- old/specfile-0.10.0/tests/unit/test_tags.py 2022-11-30 12:28:29.000000000 
+0100
+++ new/specfile-0.11.1/tests/unit/test_tags.py 2022-12-14 17:34:43.000000000 
+0100
@@ -43,6 +43,8 @@
                 "",
                 "Requires:          make",
                 "Requires(post):    bash",
+                "",
+                "%{?fedora:Suggests:          diffutils}",
             ],
         ),
         Section(
@@ -64,6 +66,8 @@
                 "",
                 "Requires:          make",
                 "Requires(post):    bash",
+                "",
+                "Suggests:          diffutils",
             ],
         ),
     )
@@ -80,7 +84,9 @@
     assert not tags.epoch.valid
     assert tags.requires.value == "make"
     assert "requires(post)" in tags
-    assert tags[-1].name == "Requires(post)"
+    assert tags[-2].name == "Requires(post)"
+    assert tags[-1].name == "Suggests"
+    assert tags.suggests.value == "diffutils"
 
 
 def test_get_raw_section_data():
@@ -112,6 +118,15 @@
                 "Requires", "make", "make", ":          ", Comments([], 
["%endif", ""])
             ),
             Tag("Requires(post)", "bash", "bash", ":    ", Comments()),
+            Tag(
+                "Suggests",
+                "diffutils",
+                "diffutils",
+                ":          ",
+                Comments([], [""]),
+                "%{?fedora:",
+                "}",
+            ),
         ],
         [],
     )
@@ -132,6 +147,8 @@
         "",
         "Requires:          make",
         "Requires(post):    bash",
+        "",
+        "%{?fedora:Suggests:          diffutils}",
     ]
 
 

Reply via email to