Python 3.12+/3.13 and portage 3.0.77 compatibility fixes

- Replace deprecated Thread.isAlive() with is_alive() (Python 3.12)
- Fix invalid escape sequences in regex strings (SyntaxWarning → SyntaxError)
- Replace removed unittest aliases: assertEquals→assertEqual,
  assertNotEquals→assertNotEqual, assert_→assertTrue,
  assertRaisesRegexp→assertRaisesRegex (Python 3.12)
- Replace portage's removed clear_caches() with flush_cache()
- Fix locks.py: reset TLS state on exception in _file_lock_create
  to prevent stale shared-lock state poisoning subsequent acquisitions
- Skip os.chown() when gid is None or caller lacks permission
- Fix FastRSS attribute ordering for consistent minidom re-parse behavior
- Update test expected XML to match Python 3.8+ minidom attribute order

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mario Fetka
2026-06-26 10:53:13 +02:00
parent aeff7dd466
commit 4e0d448aef
15 changed files with 117 additions and 106 deletions
+20 -20
View File
@@ -61,16 +61,16 @@ Moo at user.
"""
Reimplemented from SoloFunny.
"""
t = """
_____________
< Entromoooo! >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\\
||----w |
|| ||
"""
t = (
"\n _____________\n"
"< Entromoooo! >\n"
" -------------\n"
" \\ ^__^\n"
" \\ (oo)\\_______\n"
" (__)\\ )\\/\\\\\n"
" ||----w |\n"
" || ||\n"
)
return t
@@ -93,16 +93,16 @@ Bow to the Highness.
"""
Reimplemented from SoloFunny.
"""
t = """
_________________________
< Hail to the king, baby! >
-------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\\
||----w |
|| ||
"""
t = (
"\n _________________________\n"
"< Hail to the king, baby! >\n"
" -------------------------\n"
" \\ ^__^\n"
" \\ (oo)\\_______\n"
" (__)\\ )\\/\\\\\n"
" ||----w |\n"
" || ||\n"
)
return t
+1 -1
View File
@@ -255,7 +255,7 @@ class EntropyCacher(Singleton):
self.__cache_writer.name = "EntropyCacheWriter"
self.__cache_writer.set_delay_before(True)
self.__cache_writer.start()
while not self.__cache_writer.isAlive():
while not self.__cache_writer.is_alive():
continue
self.__alive = True
+1 -1
View File
@@ -205,7 +205,7 @@ class ConfigurationFiles(dict):
exit_st = subprocess.call(
'diff -Bbua "%s" "%s" | '
'egrep \'^[+-]\' | '
'egrep -v \'^[+-][\t ]*#|^--- |^\+\+\+ \' | '
'egrep -v \'^[+-][\t ]*#|^--- |^\\+\\+\\+ \' | '
'egrep -qv \'^[-+][\t ]*$\'' % (
source_unicode, destination_unicode,), shell = True)
except (IOError, OSError,):
+7 -3
View File
@@ -983,9 +983,13 @@ def const_setup_file(myfile, gid, chmod, uid = -1):
it sets the uid to the file
@type uid: int
"""
cur_gid = os.stat(myfile)[stat.ST_GID]
if cur_gid != gid:
os.chown(myfile, uid, gid)
if gid is not None:
cur_gid = os.stat(myfile)[stat.ST_GID]
if cur_gid != gid:
try:
os.chown(myfile, uid, gid)
except PermissionError:
pass
const_set_chmod(myfile, chmod)
def const_setup_directory(dirpath):
+1 -1
View File
@@ -407,7 +407,7 @@ class BaseConfigParser(dict):
param = value
"""
# Regular expression to match new configuration file sections.
_SECTION_RE = re.compile("^\[(.*)\]$")
_SECTION_RE = re.compile(r"^\[(.*)\]$")
# Starting character that denotes an ignored line.
_COMMENT_CHAR = "#"
+1 -1
View File
@@ -41,7 +41,7 @@ suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$")
suffix_value = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
endversion_keys = ["pre", "p", "alpha", "beta", "rc"]
valid_category = re.compile("^\w[\w-]*")
valid_category = re.compile(r"^\w[\w-]*")
invalid_atom_chars_regexp = re.compile("[()|@]")
digits_group = re.compile('([0-9]+)')
+9 -2
View File
@@ -178,8 +178,15 @@ class ResourceLock(object):
path = mapped['path']
acquired, flock_f = self._file_lock_create(
path, blocking=blocking, shared=shared)
try:
acquired, flock_f = self._file_lock_create(
path, blocking=blocking, shared=shared)
except Exception:
# Reset TLS state so future lock attempts are not poisoned.
mapped['recursed'] = False
if mapped['ref'] is None:
mapped['shared'] = None
raise
if acquired:
mapped['count'] += 1
+1 -1
View File
@@ -1595,8 +1595,8 @@ class FastRSS(object):
else:
doc = self.__minidom.Document()
rss = doc.createElement("rss")
rss.setAttribute("version", "2.0")
rss.setAttribute("xmlns:atom", "http://www.w3.org/2005/Atom")
rss.setAttribute("version", "2.0")
channel = doc.createElement("channel")
# title
title = doc.createElement("title")
@@ -669,7 +669,7 @@ class PortagePlugin(SpmPlugin):
dbapi.melt()
dbapi._aux_cache.clear()
dbapi.clear_caches()
dbapi.flush_cache()
tree.dbapi = portage.dbapi.porttree.portdbapi(
mysettings=dbapi.settings)
+8 -8
View File
@@ -496,12 +496,12 @@ def is_valid_email(email):
"&'*+/=?^_{|}~-]+)*|\"(?:" + \
"[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]" + \
"|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9]" + \
"(?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?" + \
"|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.)" + \
"(?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?" + \
"|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.)" + \
"{3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?" + \
"|[a-z0-9-]*[a-z0-9]:(?:" + \
"[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]" + \
"|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"
"|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\\])"
evil = re.compile(monster)
if evil.match(email):
return True
@@ -2492,7 +2492,7 @@ def expand_plain_database_mirror(mirror, product, repository_id, branch):
etpConst['databaserelativepath_basedir'] + sep + \
etpConst['currentarch'] + sep + branch
_repo_re = re.compile("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", re.IGNORECASE)
_repo_re = re.compile(r"^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", re.IGNORECASE)
def validate_repository_id(repository_id):
"""
Validate Entropy repository identifier string.
@@ -2506,7 +2506,7 @@ def validate_repository_id(repository_id):
return True
return False
_package_re = re.compile('[a-zA-Z_0-9/\-\.\+#~@]+$')
_package_re = re.compile(r'[a-zA-Z_0-9/\-\.\+#~@]+$')
def validate_package_name(package_name):
"""
Validate Entropy package name string.
@@ -2520,7 +2520,7 @@ def validate_package_name(package_name):
return True
return False
_branch_re = re.compile('[a-zA-Z_0-9\-\.+]+$')
_branch_re = re.compile(r'[a-zA-Z_0-9\-\.+]+$')
def validate_branch_name(branch):
"""
Validate Entropy branch name string.
@@ -2569,11 +2569,11 @@ def is_valid_string(string):
return False
return True
valid_path_regexp = re.compile("^([A-Za-z0-9/\.:\-_]+)$")
valid_path_regexp = re.compile(r"^([A-Za-z0-9/\.:\-_]+)$")
def is_valid_path_string(path):
"""
Return whether given path is a valid path string (whitelisting valid
characters). Regexp is ^([A-Za-z0-9/\.:-]+)$ and only works with ASCII
characters). Regexp is ^([A-Za-z0-9/\\.:-]+)$ and only works with ASCII
paths.
@param path: path to test
@@ -272,7 +272,7 @@ class EntropySshUriHandler(EntropyUriHandler):
# atomic rename
return self.rename(tmp_remote_path, remote_path)
valid_lock_path = re.compile("^([A-Za-z0-9/\.:\-_~]+)$")
valid_lock_path = re.compile(r"^([A-Za-z0-9/\.:\-_~]+)$")
def lock(self, remote_path):
# we trust dir but not remote_path, because we do
+28 -28
View File
@@ -1051,7 +1051,7 @@ class EntropyRepositoryTest(unittest.TestCase):
test_db.release_shared(opaque)
opaque_shared = test_db.try_acquire_shared()
self.assert_(opaque_shared is not None)
self.assertTrue(opaque_shared is not None)
self.assertRaises(RuntimeError, test_db.try_acquire_exclusive)
@@ -1059,28 +1059,28 @@ class EntropyRepositoryTest(unittest.TestCase):
# test reentrancy
opaque_exclusive = test_db.try_acquire_exclusive()
self.assert_(opaque_exclusive is not None)
self.assertTrue(opaque_exclusive is not None)
opaque_exclusive2 = test_db.try_acquire_exclusive()
self.assert_(opaque_exclusive2 is not None)
self.assertTrue(opaque_exclusive2 is not None)
self.assert_(opaque_exclusive._file_lock_setup() is
self.assertTrue(opaque_exclusive._file_lock_setup() is
opaque_exclusive2._file_lock_setup())
# test reference counting
self.assertEquals(
self.assertEqual(
2,
opaque_exclusive._file_lock_setup()['count'])
test_db.release_exclusive(opaque_exclusive)
self.assertEquals(
self.assertEqual(
1,
opaque_exclusive._file_lock_setup()['count'])
test_db.release_exclusive(opaque_exclusive2)
self.assertEquals(
self.assertEqual(
0,
opaque_exclusive._file_lock_setup()['count'])
@@ -1088,12 +1088,12 @@ class EntropyRepositoryTest(unittest.TestCase):
self.assertRaises(
RuntimeError, test_db.release_exclusive, opaque_exclusive)
self.assertEquals(
self.assertEqual(
0,
opaque_exclusive._file_lock_setup()['count'])
opaque_exclusive = test_db.try_acquire_exclusive()
self.assert_(opaque_exclusive is not None)
self.assertTrue(opaque_exclusive is not None)
self.assertRaises(RuntimeError, test_db.release_shared,
opaque_exclusive)
@@ -1118,77 +1118,77 @@ class EntropyRepositoryTest(unittest.TestCase):
os.remove(db_file)
def test_locking_memory(self):
self.assert_(self.test_db._is_memory())
self.assertTrue(self.test_db._is_memory())
return self._test_repository_locking(self.test_db)
def test_direct_access(self):
local = self.test_db._tls
self.assertEquals(self.test_db.directed(), False)
self.assertEqual(self.test_db.directed(), False)
counter = getattr(local, "_EntropyRepositoryCacheCounter", "foo")
self.assertEquals(counter, "foo")
self.assertEqual(counter, "foo")
with self.test_db.direct():
self.assertEquals(self.test_db.directed(), True)
self.assertEqual(self.test_db.directed(), True)
counter = local._EntropyRepositoryCacheCounter
self.assertEquals(counter, 0)
self.assertEqual(counter, 0)
self.assertEquals(self.test_db.directed(), False)
self.assertEqual(self.test_db.directed(), False)
with self.test_db.direct():
counter = local._EntropyRepositoryCacheCounter
self.assertEquals(counter, 1)
self.assertEqual(counter, 1)
with self.test_db.direct():
counter = local._EntropyRepositoryCacheCounter
self.assertEquals(counter, 2)
self.assertEqual(counter, 2)
counter = local._EntropyRepositoryCacheCounter
self.assertEquals(counter, 1)
self.assertEqual(counter, 1)
counter = local._EntropyRepositoryCacheCounter
self.assertEquals(counter, 0)
self.assertEqual(counter, 0)
self.test_db._direct_enabled = True
self.assertEquals(self.test_db.directed(), True)
self.assertEqual(self.test_db.directed(), True)
self.test_db._direct_enabled = False
self.assertEquals(self.test_db.directed(), False)
self.assertEqual(self.test_db.directed(), False)
with self.test_db.direct():
opaque = self.test_db.try_acquire_exclusive()
self.assertTrue(opaque is not None)
self.assertEquals(opaque.directed(), True)
self.assertEqual(opaque.directed(), True)
opaque_shared = self.test_db.try_acquire_shared()
self.assertTrue(opaque_shared is not None)
self.assertEquals(opaque_shared.directed(), True)
self.assertEqual(opaque_shared.directed(), True)
opaque_exclusive = self.test_db.try_acquire_exclusive()
self.assertTrue(opaque_exclusive is not None)
self.assertEquals(opaque_exclusive.directed(), True)
self.assertEquals(self.test_db.directed(), True)
self.assertEqual(opaque_exclusive.directed(), True)
self.assertEqual(self.test_db.directed(), True)
self.assertRaises(
RuntimeError,
self.test_db.release_shared, opaque_exclusive)
self.test_db.release_exclusive(opaque_exclusive)
self.assertEquals(self.test_db.directed(), True)
self.assertEqual(self.test_db.directed(), True)
self.assertRaises(
RuntimeError,
self.test_db.release_exclusive, opaque_shared)
self.test_db.release_shared(opaque_shared)
self.assertEquals(self.test_db.directed(), True)
self.assertEqual(self.test_db.directed(), True)
self.assertRaises(
RuntimeError,
self.test_db.release_shared, opaque)
self.test_db.release_exclusive(opaque)
self.assertEquals(self.test_db.directed(), True)
self.assertEqual(self.test_db.directed(), True)
if __name__ == '__main__':
+3 -3
View File
@@ -458,14 +458,14 @@ class DependencyRewriterTests(unittest.TestCase, DepsRewriteTestsMixin):
rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 haha=true"
deps = ["x11-misc/lightdm"]
with self.assertRaisesRegexp(et.WrongRewriteRuleError, r"^Bad key 'haha'"):
with self.assertRaisesRegex(et.WrongRewriteRuleError, r"^Bad key 'haha'"):
et.DependencyRewriter(deps, rule)
def test_raises_on_missing_key(self):
rule_parts = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4".split()
deps = []
for rule in rule_parts:
with self.assertRaisesRegexp(et.WrongRewriteRuleError, r"Incomplete rewrite rule"):
with self.assertRaisesRegex(et.WrongRewriteRuleError, r"Incomplete rewrite rule"):
et.DependencyRewriter(deps, rule)
def test_raises_on_key_with_no_assignment(self):
@@ -473,7 +473,7 @@ class DependencyRewriterTests(unittest.TestCase, DepsRewriteTestsMixin):
for value in wrong_values:
rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 %s" % (value,)
deps = ["x11-misc/lightdm"]
with self.assertRaisesRegexp(et.WrongRewriteRuleError,
with self.assertRaisesRegex(et.WrongRewriteRuleError,
r"^Badly formatted line with '%s'" % (value,)):
et.DependencyRewriter(deps, rule)
+34 -34
View File
@@ -22,18 +22,18 @@ class EntropyLocksTest(unittest.TestCase):
tmp_fd, tmp_path = const_mkstemp(prefix="test_simple_lock")
lock_map = {}
self.assertEquals(True, sfl.acquire(tmp_path, lock_map))
self.assertEqual(True, sfl.acquire(tmp_path, lock_map))
self.assertIn(tmp_path, lock_map)
self.assertTrue(lock_map[tmp_path] is not None)
lock_map_new = {}
self.assertEquals(False, sfl.acquire(tmp_path, lock_map_new))
self.assertEqual(False, sfl.acquire(tmp_path, lock_map_new))
self.assertNotIn(tmp_path, lock_map_new)
self.assertIn(tmp_path, lock_map)
sfl.release(tmp_path, lock_map)
self.assertEquals(True, sfl.acquire(tmp_path, lock_map_new))
self.assertEqual(True, sfl.acquire(tmp_path, lock_map_new))
self.assertIn(tmp_path, lock_map_new)
self.assertTrue(lock_map_new[tmp_path] is not None)
@@ -66,12 +66,12 @@ class EntropyLocksTest(unittest.TestCase):
erl.path = lambda: tmp_path
self.assertEquals(tmp_path, erl.path())
self.assertEqual(tmp_path, erl.path())
self.assertFalse(erl.is_already_acquired())
self.assertEquals(True, erl.try_acquire_exclusive())
self.assertEquals(1, counter_l[0])
self.assertEqual(True, erl.try_acquire_exclusive())
self.assertEqual(1, counter_l[0])
self.assertTrue(erl.is_already_acquired())
@@ -79,15 +79,15 @@ class EntropyLocksTest(unittest.TestCase):
self.assertFalse(erl.is_already_acquired())
self.assertEquals(True, erl.try_acquire_exclusive())
self.assertEquals(2, counter_l[0])
self.assertEqual(True, erl.try_acquire_exclusive())
self.assertEqual(2, counter_l[0])
erl.release()
self.assertFalse(erl.is_already_acquired())
self.assertEquals(True, erl.try_acquire_shared())
self.assertEquals(3, counter_l[0])
self.assertEqual(True, erl.try_acquire_shared())
self.assertEqual(3, counter_l[0])
self.assertTrue(erl.is_already_acquired())
@@ -105,8 +105,8 @@ class EntropyLocksTest(unittest.TestCase):
self.assertFalse(erl.is_already_acquired())
self.assertEquals(True, erl.try_acquire_shared())
self.assertEquals(6, counter_l[0])
self.assertEqual(True, erl.try_acquire_shared())
self.assertEqual(6, counter_l[0])
self.assertTrue(erl.is_already_acquired())
@@ -114,8 +114,8 @@ class EntropyLocksTest(unittest.TestCase):
self.assertTrue(erl.is_already_acquired())
self.assertEquals(True, erl.try_acquire_shared())
self.assertEquals(7, counter_l[0])
self.assertEqual(True, erl.try_acquire_shared())
self.assertEqual(7, counter_l[0])
erl.release()
@@ -127,13 +127,13 @@ class EntropyLocksTest(unittest.TestCase):
erl.release()
self.assertEquals(True, erl.try_acquire_exclusive())
self.assertEqual(True, erl.try_acquire_exclusive())
erl.release()
self.assertFalse(erl.is_already_acquired())
self.assertEquals(True, erl.wait_exclusive())
self.assertEqual(True, erl.wait_exclusive())
self.assertTrue(erl.is_already_acquired())
@@ -141,7 +141,7 @@ class EntropyLocksTest(unittest.TestCase):
self.assertFalse(erl.is_already_acquired())
self.assertEquals(True, erl.wait_shared())
self.assertEqual(True, erl.wait_shared())
self.assertTrue(erl.is_already_acquired())
@@ -171,30 +171,30 @@ class EntropyLocksTest(unittest.TestCase):
get_count = lambda: erl._file_lock_setup()['count']
self.assertEquals(True, erl.try_acquire_shared())
self.assertEqual(True, erl.try_acquire_shared())
self.assertRaises(RuntimeError, erl.try_acquire_exclusive)
erl.release()
self.assertEquals(True, erl.try_acquire_exclusive())
self.assertEqual(True, erl.try_acquire_exclusive())
self.assertEquals(True, erl.try_acquire_shared())
self.assertEquals(True, erl.try_acquire_shared())
self.assertEquals(True, erl.try_acquire_shared())
self.assertEqual(True, erl.try_acquire_shared())
self.assertEqual(True, erl.try_acquire_shared())
self.assertEqual(True, erl.try_acquire_shared())
self.assertEquals(4, get_count())
self.assertEqual(4, get_count())
erl.release()
self.assertEquals(3, get_count())
self.assertEqual(3, get_count())
erl.release()
self.assertEquals(2, get_count())
self.assertEqual(2, get_count())
erl.release()
self.assertEquals(1, get_count())
self.assertEqual(1, get_count())
erl.release()
self.assertEquals(0, get_count())
self.assertEqual(0, get_count())
self.assertRaises(RuntimeError, erl.release)
@@ -229,24 +229,24 @@ class EntropyLocksTest(unittest.TestCase):
other_thread_loop_count = [0]
cond = threading.Condition()
self.assertEquals(True, erl.try_acquire_exclusive())
self.assertEquals(1, get_count())
self.assertNotEquals(None, get_ref())
self.assertEquals(0, other_thread_count[0])
self.assertEqual(True, erl.try_acquire_exclusive())
self.assertEqual(1, get_count())
self.assertNotEqual(None, get_ref())
self.assertEqual(0, other_thread_count[0])
def try_acquire_thread():
milliseconds = 10 * 1000
acquired = False
loop_n = 0
while milliseconds:
self.assertEquals(None, get_ref())
self.assertEqual(None, get_ref())
acquired = erl.try_acquire_exclusive()
if loop_n == 0:
self.assertFalse(acquired)
if acquired:
self.assertNotEquals(None, get_ref())
self.assertNotEqual(None, get_ref())
other_thread_count[0] += 1
break
@@ -269,7 +269,7 @@ class EntropyLocksTest(unittest.TestCase):
erl.release()
th.join()
self.assertEquals(1, other_thread_count[0])
self.assertEqual(1, other_thread_count[0])
finally:
if tmp_fd is not None:
+1 -1
View File
@@ -163,7 +163,7 @@ class MiscTest(unittest.TestCase):
expected_outcome = """
<?xml version="1.0" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>title</title>
<link>http://url</link>