Description: Remove code from Stack Overflow

Stack Overflow content is CC-BY-SA licensed,
which this package is not supposed to be.  These snippets may be
too small to be copyrightable, but removing them to be safe.

Author: Rebecca N. Palmer <rebecca_palmer@zoho.com>
Forwarded: no - one part needs Python 3.6+

--- a/snakemake/remote/S3Mocked.py
+++ b/snakemake/remote/S3Mocked.py
@@ -9,6 +9,7 @@ from contextlib import contextmanager
 import pickle
 import time
 import functools
+import pathlib
 
 # intra-module
 from snakemake.remote.S3 import (
@@ -120,26 +121,19 @@ class RemoteObject(S3RemoteObject):
 # ====== Helpers =====
 
 
-def touch(fname, mode=0o666, dir_fd=None, **kwargs):
-    # create lock file faster
-    # https://stackoverflow.com/a/1160227
-    flags = os.O_CREAT | os.O_APPEND
-    with os.fdopen(os.open(fname, flags=flags, mode=mode, dir_fd=dir_fd)) as f:
-        os.utime(
-            f.fileno() if os.utime in os.supports_fd else fname,
-            dir_fd=None if os.supports_fd else dir_fd,
-            **kwargs
-        )
-
+def touch(fname, mode=0o666):
+    pathlib.Path(fname).touch(mode=mode, exist_ok=True)
 
 @contextmanager
 def file_lock(filepath):
     lock_file = filepath + ".lock"
 
-    while os.path.isfile(lock_file):
-        time.sleep(2)
-
-    touch(lock_file)
+    while True:
+        try:
+            pathlib.Path(lock_file).touch(exist_ok=False)
+            break
+        except FileExistsError:
+            time.sleep(2)
 
     try:
         yield
--- a/snakemake/utils.py
+++ b/snakemake/utils.py
@@ -481,32 +481,21 @@ def min_version(version):
 def update_config(config, overwrite_config):
     """Recursively update dictionary config with overwrite_config in-place.
 
-    See
-    https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth
-    for details.
-
     Args:
       config (dict): dictionary to update
       overwrite_config (dict): dictionary whose items will overwrite those in config
     """
 
-    def _update_config(config, overwrite_config):
-        """Necessary as recursive calls require a return value,
-        but `update_config()` has no return value.
-        """
-        for key, value in overwrite_config.items():
-            if not isinstance(config, collections.abc.Mapping):
-                # the config cannot be updated as it is no dict
-                # -> just overwrite it with the new value
-                config = {}
-            if isinstance(value, collections.abc.Mapping):
-                sub_config = config.get(key, {})
-                config[key] = _update_config(sub_config, value)
+    def nestedupdate(old_d, new_d):
+        for k, v in new_d.items():
+            if isinstance(v, collections.abc.Mapping):
+                if k not in old_d or old_d[k] is None:
+                    old_d[k] = {}
+                nestedupdate(old_d[k], v)
             else:
-                config[key] = value
-        return config
+                old_d[k] = v
 
-    _update_config(config, overwrite_config)
+    nestedupdate(config, overwrite_config)
 
 
 def available_cpu_count():
--- a/tests/test_static_remote/S3MockedForStaticTest.py
+++ b/tests/test_static_remote/S3MockedForStaticTest.py
@@ -10,6 +10,7 @@ import pickle
 import time
 import threading
 import functools
+import pathlib
 
 # intra-module
 from snakemake.remote.S3 import (
@@ -133,26 +134,20 @@ class RemoteObject(S3RemoteObject):
 # ====== Helpers =====
 
 
-def touch(fname, mode=0o666, dir_fd=None, **kwargs):
-    # create lock file faster
-    # https://stackoverflow.com/a/1160227
-    flags = os.O_CREAT | os.O_APPEND
-    with os.fdopen(os.open(fname, flags=flags, mode=mode, dir_fd=dir_fd)) as f:
-        os.utime(
-            f.fileno() if os.utime in os.supports_fd else fname,
-            dir_fd=None if os.supports_fd else dir_fd,
-            **kwargs
-        )
+def touch(fname, mode=0o666):
+    pathlib.Path(fname).touch(mode=mode, exist_ok=True)
 
 
 @contextmanager
 def file_lock(filepath):
     lock_file = filepath + ".lock"
 
-    while os.path.isfile(lock_file):
-        time.sleep(2)
-
-    touch(lock_file)
+    while True:
+        try:
+            pathlib.Path(lock_file).touch(exist_ok=False)
+            break
+        except FileExistsError:
+            time.sleep(2)
 
     try:
         yield
