Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pycomposefile for 
openSUSE:Factory checked in at 2026-01-12 11:50:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pycomposefile (Old)
 and      /work/SRC/openSUSE:Factory/.python-pycomposefile.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pycomposefile"

Mon Jan 12 11:50:13 2026 rev:4 rq:1326740 version:0.0.34

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-pycomposefile/python-pycomposefile.changes    
    2025-02-14 19:21:11.047407369 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-pycomposefile.new.1928/python-pycomposefile.changes
      2026-01-12 11:50:31.986673104 +0100
@@ -1,0 +2,14 @@
+Fri Jan  9 13:08:45 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 0.0.34
+  * Add comprehensive test coverage for KVP splitting with multiple equals 
signs
+  * Add LICENSE and sample/ to sdist
+- from version 0.0.33
+  * Bump setuptools from 75.2.0 to 78.1.1
+  * Update service
+  * Fix regex to correctly capture default values in environment variable
+    replacement embed version in sdist and migrate to pyproject.toml
+- Drop p_fix-version-number.patch, fixed upstream
+- Update BuildRequires from pyproject.toml
+
+-------------------------------------------------------------------

Old:
----
  p_fix-version-number.patch
  pycomposefile-0.0.32.tar.gz

New:
----
  pycomposefile-0.0.34.tar.gz

----------(Old B)----------
  Old:    replacement embed version in sdist and migrate to pyproject.toml
- Drop p_fix-version-number.patch, fixed upstream
- Update BuildRequires from pyproject.toml
----------(Old E)----------

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

Other differences:
------------------
++++++ python-pycomposefile.spec ++++++
--- /var/tmp/diff_new_pack.F0A0jR/_old  2026-01-12 11:50:32.826707904 +0100
+++ /var/tmp/diff_new_pack.F0A0jR/_new  2026-01-12 11:50:32.826707904 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pycomposefile
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,15 +18,13 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-pycomposefile
-Version:        0.0.32
+Version:        0.0.34
 Release:        0
 Summary:        Structured deserialization of Docker Compose files
 License:        MIT
 URL:            https://github.com/smurawski/pycomposefile
 Source:         
https://files.pythonhosted.org/packages/source/p/pycomposefile/pycomposefile-%{version}.tar.gz
-# PATCH-FIX-UPSTREAM p_fix-version-number.patch
-# https://github.com/smurawski/pycomposefile/issues/29
-Patch:          p_fix-version-number.patch
+BuildRequires:  %{python_module flit-core >= 3.11}
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module wheel}

++++++ pycomposefile-0.0.32.tar.gz -> pycomposefile-0.0.34.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/LICENSE 
new/pycomposefile-0.0.34/LICENSE
--- old/pycomposefile-0.0.32/LICENSE    1970-01-01 01:00:00.000000000 +0100
+++ new/pycomposefile-0.0.34/LICENSE    2025-07-29 16:13:25.845282800 +0200
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Steven Murawski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/PKG-INFO 
new/pycomposefile-0.0.34/PKG-INFO
--- old/pycomposefile-0.0.32/PKG-INFO   2024-10-22 21:45:10.409924300 +0200
+++ new/pycomposefile-0.0.34/PKG-INFO   1970-01-01 01:00:00.000000000 +0100
@@ -1,13 +1,15 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: pycomposefile
-Version: 0.0.32
+Version: 0.0.34
 Summary: Structured deserialization of Docker Compose files.
-Home-page: https://github.com/smurawski/pycomposefile
-Author: Steven Murawski
-Author-email: [email protected]
-License: MIT
-Requires-Python: >=3.6
+Keywords: docker,compose
+Author-email: Steven Murawski <[email protected]>
+Requires-Python: >=3.9
 Description-Content-Type: text/markdown
+License-Expression: MIT
+License-File: LICENSE
 Requires-Dist: pyyaml
+Project-URL: Homepage, https://github.com/smurawski/pycomposefile
 
 # Pycomposefile
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile/compose_element/compose_datatype_transformer.py
 
new/pycomposefile-0.0.34/pycomposefile/compose_element/compose_datatype_transformer.py
--- 
old/pycomposefile-0.0.32/pycomposefile/compose_element/compose_datatype_transformer.py
      2024-10-22 21:45:01.000000000 +0200
+++ 
new/pycomposefile-0.0.34/pycomposefile/compose_element/compose_datatype_transformer.py
      2025-07-29 16:13:25.845282800 +0200
@@ -11,7 +11,7 @@
         return f"Failed to evaluate mandatory variable {self.variable_name}"
 
 
-class ComposeDataTypeTransformer():
+class ComposeDataTypeTransformer:
     transform = str
     valid_values = None
 
@@ -59,7 +59,7 @@
         return re.sub(env_variable_name, env_variable_value, source_string)
 
     def replace_environment_variables_with_empty_unset(self, value):
-        capture = 
re.compile(r"(\$+)\{(?P<variablename>\w+)\:-(?P<defaultvalue>.+)\}")
+        capture = 
re.compile(r"(\$+)\{(?P<variablename>\w+)\:-(?P<defaultvalue>[^$]*?)\}")
         matches = capture.search(value)
         if matches is not None and matches[1] == "$$":
             return value
@@ -68,7 +68,8 @@
             default_value = matches.group("defaultvalue")
             if env_var is None or len(env_var) == 0:
                 env_var = default_value
-            value = 
self.update_value_with_resolved_environment(f"\\{matches[0]}", env_var, value)
+            escaped = re.sub(r"([*+?{}])", r"\\\1", matches[0])  # escape 
special characters
+            value = 
self.update_value_with_resolved_environment(f"\\{escaped}", env_var, value)
             matches = capture.search(value)
         return value
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile/secrets/__init__.py 
new/pycomposefile-0.0.34/pycomposefile/secrets/__init__.py
--- old/pycomposefile-0.0.32/pycomposefile/secrets/__init__.py  2024-10-22 
21:45:01.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile/secrets/__init__.py  2025-07-29 
16:13:25.846283000 +0200
@@ -3,7 +3,7 @@
 
 class SecretFile(str):
     def readFile(self):
-        with open(self, "r") as f:
+        with open(self) as f:
             secret = f.read()
         return secret
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile/service/service.py 
new/pycomposefile-0.0.34/pycomposefile/service/service.py
--- old/pycomposefile-0.0.32/pycomposefile/service/service.py   2024-10-22 
21:45:01.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile/service/service.py   2025-07-29 
16:13:25.846283000 +0200
@@ -91,7 +91,6 @@
         "networks": (Networks, 
"https://github.com/compose-spec/compose-spec/blob/master/spec.md#networks";),
         "mac_address": (str, 
"https://github.com/compose-spec/compose-spec/blob/master/spec.md#mac_address";),
         "mem_limit": (ComposeByteValue, 
"https://github.com/compose-spec/compose-spec/blob/master/spec.md#mem_limit";),
-        "mem_reservation": (ComposeByteValue, 
"https://github.com/compose-spec/compose-spec/blob/master/spec.md#mem_reservation";),
         "mem_swappiness": ((int, [0, 100]), 
"https://github.com/compose-spec/compose-spec/blob/master/spec.md#mem_swappiness";),
         "memswap_limit": (ComposeByteValue, 
"https://github.com/compose-spec/compose-spec/blob/master/spec.md#memswap_limit";),
         "oom_kill_disable": (bool, 
"https://github.com/compose-spec/compose-spec/blob/master/spec.md#oom_kill_disable";),
@@ -138,7 +137,7 @@
     def resolve_environment_hierarchy(self):
         if self.env_file is not None:
             env_file = self.env_file.readFile()
-            env_file.update(self.environment)
+            env_file.update(self.environment or [])
             return env_file
         else:
             return self.environment
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile/service/service_environment.py 
new/pycomposefile-0.0.34/pycomposefile/service/service_environment.py
--- old/pycomposefile-0.0.32/pycomposefile/service/service_environment.py       
2024-10-22 21:45:01.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile/service/service_environment.py       
2025-07-29 16:13:25.846283000 +0200
@@ -11,7 +11,7 @@
         env_array = []
 
         for file_name in self:
-            f = open(file_name, "r")
+            f = open(file_name)
 
             for line in f.readlines():
                 if not line.startswith("#"):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile/service/service_misc.py 
new/pycomposefile-0.0.34/pycomposefile/service/service_misc.py
--- old/pycomposefile-0.0.32/pycomposefile/service/service_misc.py      
2024-10-22 21:45:01.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile/service/service_misc.py      
2025-07-29 16:13:25.847283000 +0200
@@ -17,7 +17,7 @@
             condition = detail["condition"]
         else:
             name = config
-        ob = super(Dependency, cls).__new__(cls, name)
+        ob = super().__new__(cls, name)
         ob.__setattr__('condition', condition)
         return ob
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/pycomposefile.egg-info/PKG-INFO 
new/pycomposefile-0.0.34/pycomposefile.egg-info/PKG-INFO
--- old/pycomposefile-0.0.32/pycomposefile.egg-info/PKG-INFO    2024-10-22 
21:45:10.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile.egg-info/PKG-INFO    1970-01-01 
01:00:00.000000000 +0100
@@ -1,13 +0,0 @@
-Metadata-Version: 2.1
-Name: pycomposefile
-Version: 0.0.32
-Summary: Structured deserialization of Docker Compose files.
-Home-page: https://github.com/smurawski/pycomposefile
-Author: Steven Murawski
-Author-email: [email protected]
-License: MIT
-Requires-Python: >=3.6
-Description-Content-Type: text/markdown
-Requires-Dist: pyyaml
-
-# Pycomposefile
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile.egg-info/SOURCES.txt 
new/pycomposefile-0.0.34/pycomposefile.egg-info/SOURCES.txt
--- old/pycomposefile-0.0.32/pycomposefile.egg-info/SOURCES.txt 2024-10-22 
21:45:10.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile.egg-info/SOURCES.txt 1970-01-01 
01:00:00.000000000 +0100
@@ -1,50 +0,0 @@
-README.md
-setup.py
-pycomposefile/__init__.py
-pycomposefile/compose_file.py
-pycomposefile.egg-info/PKG-INFO
-pycomposefile.egg-info/SOURCES.txt
-pycomposefile.egg-info/dependency_links.txt
-pycomposefile.egg-info/requires.txt
-pycomposefile.egg-info/top_level.txt
-pycomposefile/compose_element/__init__.py
-pycomposefile/compose_element/compose_datatype_transformer.py
-pycomposefile/compose_element/compose_element.py
-pycomposefile/compose_element/compose_list_or_map.py
-pycomposefile/compose_element/compose_string_or_list.py
-pycomposefile/secrets/__init__.py
-pycomposefile/service/__init__.py
-pycomposefile/service/service.py
-pycomposefile/service/service_blkio_config.py
-pycomposefile/service/service_build.py
-pycomposefile/service/service_cap.py
-pycomposefile/service/service_command.py
-pycomposefile/service/service_configs.py
-pycomposefile/service/service_credential_spec.py
-pycomposefile/service/service_deploy.py
-pycomposefile/service/service_environment.py
-pycomposefile/service/service_healthcheck.py
-pycomposefile/service/service_logging.py
-pycomposefile/service/service_misc.py
-pycomposefile/service/service_networks.py
-pycomposefile/service/service_ports.py
-pycomposefile/service/service_volumes.py
-tests/__init__.py
-tests/compose_file/__init__.py
-tests/compose_file/test_service_order.py
-tests/compose_file/test_version.py
-tests/compose_generator/__init__.py
-tests/environment_variable_evaluation/__init__.py
-tests/environment_variable_evaluation/test_environment_variables_braces.py
-tests/environment_variable_evaluation/test_environment_variables_no_braces.py
-tests/service/__init__.py
-tests/service/test_service.py
-tests/service/test_service_blkio_config.py
-tests/service/test_service_build.py
-tests/service/test_service_configs.py
-tests/service/test_service_credential_spec.py
-tests/service/test_service_deploy.py
-tests/service/test_service_environment.py
-tests/service/test_service_environment_file.py
-tests/service/test_service_network.py
-tests/service/test_service_secret_file.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile.egg-info/dependency_links.txt 
new/pycomposefile-0.0.34/pycomposefile.egg-info/dependency_links.txt
--- old/pycomposefile-0.0.32/pycomposefile.egg-info/dependency_links.txt        
2024-10-22 21:45:10.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile.egg-info/dependency_links.txt        
1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile.egg-info/requires.txt 
new/pycomposefile-0.0.34/pycomposefile.egg-info/requires.txt
--- old/pycomposefile-0.0.32/pycomposefile.egg-info/requires.txt        
2024-10-22 21:45:10.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile.egg-info/requires.txt        
1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-pyyaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/pycomposefile.egg-info/top_level.txt 
new/pycomposefile-0.0.34/pycomposefile.egg-info/top_level.txt
--- old/pycomposefile-0.0.32/pycomposefile.egg-info/top_level.txt       
2024-10-22 21:45:10.000000000 +0200
+++ new/pycomposefile-0.0.34/pycomposefile.egg-info/top_level.txt       
1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-pycomposefile
-tests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/pyproject.toml 
new/pycomposefile-0.0.34/pyproject.toml
--- old/pycomposefile-0.0.32/pyproject.toml     1970-01-01 01:00:00.000000000 
+0100
+++ new/pycomposefile-0.0.34/pyproject.toml     2025-07-29 16:13:30.947512400 
+0200
@@ -0,0 +1,34 @@
+[project]
+name = "pycomposefile"
+version = "0.0.34"
+description = "Structured deserialization of Docker Compose files."
+readme = "README.md"
+authors = [
+    { name = "Steven Murawski", email = "[email protected]" },
+]
+requires-python = ">=3.9"
+dependencies = ["pyyaml"]
+keywords = ["docker", "compose"]
+license = "MIT"
+license-files = ["LICENSE"]
+
+[project.urls]
+Homepage = "https://github.com/smurawski/pycomposefile";
+
+[dependency-groups]
+dev = ["pyyaml>=6.0", "build>=0.7", "ruff==0.12.5", "timeout-decorator==0.5.0"]
+
+[tool.flit.sdist]
+include = ["sample/", "tests/"]
+
+[tool.ruff]
+line-length = 120
+
+[tool.ruff.lint]
+select = ["C9", "E", "F", "UP", "W"]
+ignore = ["C901", "E501", "E722", "F401", "F811"]
+mccabe = { max-complexity = 10 }
+
+[build-system]
+requires = ["flit_core >=3.11,<4"]
+build-backend = "flit_core.buildapi"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/sample/apps/web.env 
new/pycomposefile-0.0.34/sample/apps/web.env
--- old/pycomposefile-0.0.32/sample/apps/web.env        1970-01-01 
01:00:00.000000000 +0100
+++ new/pycomposefile-0.0.34/sample/apps/web.env        2025-07-29 
16:13:25.847283000 +0200
@@ -0,0 +1,5 @@
+# Web Environment Vars
+RACK_ENV=development
+VAR="quoted"
+FOO="bar"
+BAZ=foobar
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/sample/common.env 
new/pycomposefile-0.0.34/sample/common.env
--- old/pycomposefile-0.0.32/sample/common.env  1970-01-01 01:00:00.000000000 
+0100
+++ new/pycomposefile-0.0.34/sample/common.env  2025-07-29 16:13:25.847283000 
+0200
@@ -0,0 +1,4 @@
+# Web Environment Vars
+RACK_ENV=production
+VAR="quotation"
+BAR=foo
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/sample/my_secret.txt 
new/pycomposefile-0.0.34/sample/my_secret.txt
--- old/pycomposefile-0.0.32/sample/my_secret.txt       1970-01-01 
01:00:00.000000000 +0100
+++ new/pycomposefile-0.0.34/sample/my_secret.txt       2025-07-29 
16:13:25.847283000 +0200
@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor 
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis 
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in 
culpa qui officia deserunt mollit anim id est laborum.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/sample/opt/runtime_opts.env 
new/pycomposefile-0.0.34/sample/opt/runtime_opts.env
--- old/pycomposefile-0.0.32/sample/opt/runtime_opts.env        1970-01-01 
01:00:00.000000000 +0100
+++ new/pycomposefile-0.0.34/sample/opt/runtime_opts.env        2025-07-29 
16:13:25.847283000 +0200
@@ -0,0 +1,5 @@
+#Runtime Opts
+BAR=faz
+STAGE=dev
+BAZ=snafu
+SHOW=false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/sample/test.env 
new/pycomposefile-0.0.34/sample/test.env
--- old/pycomposefile-0.0.32/sample/test.env    1970-01-01 01:00:00.000000000 
+0100
+++ new/pycomposefile-0.0.34/sample/test.env    2025-07-29 16:13:25.847283000 
+0200
@@ -0,0 +1,4 @@
+# Set Rails/Rack environment
+RACK_ENV=development
+VAR="quoted"
+SOME_VAR="value with equals=sign"
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/setup.cfg 
new/pycomposefile-0.0.34/setup.cfg
--- old/pycomposefile-0.0.32/setup.cfg  2024-10-22 21:45:10.409924300 +0200
+++ new/pycomposefile-0.0.34/setup.cfg  1970-01-01 01:00:00.000000000 +0100
@@ -1,4 +0,0 @@
-[egg_info]
-tag_build = 
-tag_date = 0
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycomposefile-0.0.32/setup.py 
new/pycomposefile-0.0.34/setup.py
--- old/pycomposefile-0.0.32/setup.py   2024-10-22 21:45:01.000000000 +0200
+++ new/pycomposefile-0.0.34/setup.py   1970-01-01 01:00:00.000000000 +0100
@@ -1,22 +0,0 @@
-import setuptools
-import os
-
-long_desc = open("README.md").read()
-required = ['pyyaml']  # Comma seperated dependent libraries name
-version = os.environ.get("BUILD_TAG", "0.0.1a1").lstrip("v")
-
-setuptools.setup(
-    name="pycomposefile",
-    version=version,
-    author="Steven Murawski",
-    author_email="[email protected]",
-    license="MIT",
-    description="Structured deserialization of Docker Compose files.",
-    long_description=long_desc,
-    long_description_content_type="text/markdown",
-    url="https://github.com/smurawski/pycomposefile";,
-    packages=setuptools.find_packages(),
-    key_words="docker compose",
-    install_requires=required,
-    python_requires=">=3.6",
-)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/tests/compose_generator/__init__.py 
new/pycomposefile-0.0.34/tests/compose_generator/__init__.py
--- old/pycomposefile-0.0.32/tests/compose_generator/__init__.py        
2024-10-22 21:45:01.000000000 +0200
+++ new/pycomposefile-0.0.34/tests/compose_generator/__init__.py        
2025-07-29 16:13:25.848283000 +0200
@@ -556,7 +556,7 @@
 services:
   frontend:
     image: awesome/webapp
-    build: 
+    build:
       context: ./webapp
 """
         return ComposeGenerator.convert_yaml_to_compose_file(compose)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/tests/environment_variable_evaluation/test_environment_variables_braces.py
 
new/pycomposefile-0.0.34/tests/environment_variable_evaluation/test_environment_variables_braces.py
--- 
old/pycomposefile-0.0.32/tests/environment_variable_evaluation/test_environment_variables_braces.py
 2024-10-22 21:45:01.000000000 +0200
+++ 
new/pycomposefile-0.0.34/tests/environment_variable_evaluation/test_environment_variables_braces.py
 2025-07-29 16:13:25.848283000 +0200
@@ -2,7 +2,7 @@
 import os
 from ..compose_generator import ComposeGenerator
 from pycomposefile.compose_element import EmptyOrUnsetException
-
+import timeout_decorator
 
 class TestBracesNoUnderscoreNoDigitVariableInterpolation(TestCase):
 
@@ -19,6 +19,21 @@
         compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
         self.assertEqual(compose_file.services["frontend"].image, 
"awesome/bob")
 
+    def test_uppercase_without_default_when_unset_in_string_value(self):
+        env_var = "DEFAULTUNSET"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/")
+
+    @timeout_decorator.timeout(5)
+    def test_uppercase_with_nested_default_when_unset_in_string_value(self):
+        env_var = "DEFAULTUNSET"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-${CHILDUNSET:-bob}}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, 
"awesome/bob")
+
     @mock.patch.dict(os.environ, {"TESTCPUCOUNT": "1.5"})
     def test_uppercase_in_decimal_value(self):
         braced_env_var = "{TESTCPUCOUNT}"
@@ -48,6 +63,21 @@
         compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
         self.assertEqual(compose_file.services["frontend"].image, 
"awesome/bob")
 
+    def test_lowercase_without_default_when_unset_in_string_value(self):
+        env_var = "defaultunset"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/")
+
+    @timeout_decorator.timeout(5)
+    def test_lowercase_with_nested_default_when_unset_in_string_value(self):
+        env_var = "defaultunset"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-${childunset:-bob}}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, 
"awesome/bob")
+
     @mock.patch.dict(os.environ, {"testcpucount": "1.5"})
     def test_lowercase_in_decimal_value(self):
         braced_env_var = "{testcpucount}"
@@ -88,3 +118,86 @@
         compose_file = 
ComposeGenerator.get_compose_with_double_dollar_sign_env_vars()
 
         
self.assertEqual(compose_file.services["frontend"].environment["ENVIRONMENT"], 
"$ENVIRONMENT")
+
+    @timeout_decorator.timeout(5)
+    def test_uppercase_with_asterisk_as_default(self):
+        env_var = "DEFAULTUNSET"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-*}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/*")
+
+    @timeout_decorator.timeout(5)
+    def test_uppercase_with_plus_as_default(self):
+        env_var = "DEFAULTUNSET"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-+}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/+")
+
+    @timeout_decorator.timeout(5)
+    def test_uppercase_with_question_as_default(self):
+        env_var = "DEFAULTUNSET"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-?}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/?")
+
+    @timeout_decorator.timeout(5)
+    def test_uppercase_with_rightbrace_as_default(self):
+        env_var = "DEFAULTUNSET"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-a}-}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, 
"awesome/a-}")
+
+    @timeout_decorator.timeout(5)
+    def test_lowercase_with_asterisk_as_default(self):
+        env_var = "defaultunset"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-*}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/*")
+
+    @timeout_decorator.timeout(5)
+    def test_lowercase_with_plus_as_default(self):
+        env_var = "defaultunset"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-+}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/+")
+
+    @timeout_decorator.timeout(5)
+    def test_lowercase_with_question_as_default(self):
+        env_var = "defaultunset"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-?}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/?")
+
+    @timeout_decorator.timeout(5)
+    def test_lowercase_with_rightbrace_as_default(self):
+        env_var = "defaultunset"
+        os.unsetenv(env_var)
+        braced_env_with_default_unset = "{" + env_var + ":-}}"
+        compose_file = 
ComposeGenerator.get_compose_with_string_value(braced_env_with_default_unset)
+        self.assertEqual(compose_file.services["frontend"].image, "awesome/}")
+
+    @timeout_decorator.timeout(5)
+    def test_uppercase_two_variables_with_default_in_string_value(self):
+        braced_first_env_var = "{HOSTPORT:-8080}"
+        braced_second_env_var = "{CONTAINERPORT:-80}"
+        compose_file = 
ComposeGenerator.get_with_two_environment_variables_in_string_value(braced_first_env_var,
 braced_second_env_var)
+        self.assertEqual(f"{compose_file.services['frontend'].ports[0]}", 
"8080:80/tcp")
+        self.assertEqual(compose_file.services['frontend'].ports[0].published, 
"8080")
+        self.assertEqual(compose_file.services['frontend'].ports[0].target, 
"80")
+
+    @timeout_decorator.timeout(5)
+    def test_lowercase_two_variables_with_default_in_string_value(self):
+        braced_first_env_var = "{httpport:-8080}"
+        braced_second_env_var = "{containerport:-80}"
+        compose_file = 
ComposeGenerator.get_with_two_environment_variables_in_string_value(braced_first_env_var,
 braced_second_env_var)
+        self.assertEqual(f"{compose_file.services['frontend'].ports[0]}", 
"8080:80/tcp")
+        self.assertEqual(compose_file.services['frontend'].ports[0].published, 
"8080")
+        self.assertEqual(compose_file.services['frontend'].ports[0].target, 
"80")
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pycomposefile-0.0.32/tests/service/test_service_environment.py 
new/pycomposefile-0.0.34/tests/service/test_service_environment.py
--- old/pycomposefile-0.0.32/tests/service/test_service_environment.py  
2024-10-22 21:45:01.000000000 +0200
+++ new/pycomposefile-0.0.34/tests/service/test_service_environment.py  
2025-07-29 16:13:25.848283000 +0200
@@ -1,6 +1,7 @@
 from unittest import TestCase
 
 from pycomposefile import compose_file
+from pycomposefile.compose_element.compose_list_or_map import 
ComposeListOrMapElement
 
 from ..compose_generator import ComposeGenerator
 
@@ -19,3 +20,38 @@
         
self.assertEqual(compose_file.services["frontend"].environment["RACK_ENV"], 
"development")
         
self.assertEqual(compose_file.services["frontend"].environment["SHOW"], "true")
         
self.assertIsNone(compose_file.services["frontend"].environment["USER_INPUT"])
+
+    def test_kvp_with_multiple_equals_issue_35(self):
+        """Test for issue #35: KVP strings with multiple '=' should split on 
first '=' only"""
+        # Test the exact scenario from the issue
+        element = ComposeListOrMapElement("JAVA_OPTS=foo=bar&&baz=buzz")
+        self.assertEqual(element["JAVA_OPTS"], "foo=bar&&baz=buzz")
+
+    def test_kvp_splitting_edge_cases(self):
+        """Test various edge cases for KVP splitting to prevent regression"""
+        test_cases = [
+            # (input_string, expected_key, expected_value)
+            ("KEY=value", "KEY", "value"),
+            ("KEY=value=extra", "KEY", "value=extra"),
+            ("KEY=a=b=c=d", "KEY", "a=b=c=d"),
+            ("URL=http://example.com:8080/path?param=value";, "URL", 
"http://example.com:8080/path?param=value";),
+            ("CONFIG=key1=val1,key2=val2", "CONFIG", "key1=val1,key2=val2"),
+            ("COMPLEX=a=b&c=d&e=f", "COMPLEX", "a=b&c=d&e=f"),
+            ("NO_VALUE", "NO_VALUE", None),
+        ]
+
+        for input_string, expected_key, expected_value in test_cases:
+            with self.subTest(input=input_string):
+                element = ComposeListOrMapElement(input_string)
+                self.assertEqual(element[expected_key], expected_value)
+
+    def test_empty_value_handling(self):
+        """Test handling of empty values - this is existing behavior that 
should be preserved"""
+        # EMPTY= should result in None (existing behavior)
+        element = ComposeListOrMapElement("EMPTY=")
+        self.assertIsNone(element["EMPTY"])
+
+        # Test the isValueEmpty method directly
+        element_test = ComposeListOrMapElement(None)
+        self.assertTrue(element_test.isValueEmpty("KEY="))
+        self.assertFalse(element_test.isValueEmpty("KEY=value"))

Reply via email to