diff --git a/.gitignore b/.gitignore
index 49bad4a9adcf19af864a6aa517c80ff8317c99d8..b7522274b68c279154e6049d7fef8a887b10c1f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,14 +165,13 @@ var
 sdist
 develop-eggs
 .installed.cfg
-
+test_files/
 # Installer logs
 pip-log.txt
 
 # Unit test / coverage reports
 .coverage
 .tox
-
 #Translations
 *.mo
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e8dc83ada9ea563d0d413fb26a84e920eba7fd56..f7902b9f3a8e78391e3287e505962ea4253d3594 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,3 +2,5 @@
 
 * add JSONAbleDataObject
 * improved typing for reraise_as
+* added weak_refs to SingletonWithRegardsTo
+* added jump_to_directory
diff --git a/docs/files.rst b/docs/files.rst
index 7f2b1b01b59dc72cd52a9a21f03a9e1f7c26f7ab..718dc9220820f313a32584fec1f57eed2c4fc97a 100644
--- a/docs/files.rst
+++ b/docs/files.rst
@@ -9,6 +9,14 @@ A file-like object that will dispose of your content.
 .. autoclass:: satella.files.DevNullFilelikeObject
     :members:
 
+
+jump_to_directory
+-----------------
+
+.. autofunction:: jump_to_directory
+    :members:
+
+
 safe_listdir
 ------------
 
diff --git a/satella/__init__.py b/satella/__init__.py
index 66d2dcd3f0a45fb4b85fc5ce1cffddbfadcb3b11..b0f93f54dca729afce51939170ad8d7a63e2c0b3 100644
--- a/satella/__init__.py
+++ b/satella/__init__.py
@@ -1 +1 @@
-__version__ = '2.25.4a3'
+__version__ = '2.25.4'
diff --git a/satella/coding/structures/singleton.py b/satella/coding/structures/singleton.py
index 3dc9e83169f44234ac86e7e1ee41708856a7fa92..0a7609d8cfbbf1cbd65bc7f89bdb8ed9f4bfaf92 100644
--- a/satella/coding/structures/singleton.py
+++ b/satella/coding/structures/singleton.py
@@ -1,4 +1,5 @@
 import typing as tp
+import weakref
 
 from satella.coding.decorators.decorators import wraps
 
@@ -36,7 +37,7 @@ def Singleton(cls):
 
 
 # noinspection PyPep8Naming
-def SingletonWithRegardsTo(num_args: int):
+def SingletonWithRegardsTo(num_args: int, weak_refs: bool = False):
     """
     Make a memoized singletion depending on the arguments.
 
@@ -55,6 +56,12 @@ def SingletonWithRegardsTo(num_args: int):
     >>> c = MyClass('dev1')
     >>> assert a is c
     >>> assert b is not c
+
+    :param num_args: number of arguments to consume
+    :param weak_refs: if True, then singleton will be stored within a weak dictionary, so that it cleans up after itself
+                      when the values are gone.
+
+    .. warning:: If you set weak_refs to False and have a potentially unbounded number of arguments, you better watch out.
     """
 
     def inner(cls):
@@ -65,7 +72,10 @@ def SingletonWithRegardsTo(num_args: int):
         def singleton_new(cls, *args, **kw):
             it = cls.__dict__.get('__it__')
             if it is None:
-                it = cls.__it__ = {}
+                if weak_refs:
+                    it = cls.__it__ = weakref.WeakValueDictionary()
+                else:
+                    it = cls.__it__ = {}
 
             key = args[:num_args]
             if key in it:
diff --git a/satella/files.py b/satella/files.py
index 2fb00052dfeab4fc9881ab6fd202a396e2cb66cb..04a5b488da4a1c1342a04c6e04910265d515e2fd 100644
--- a/satella/files.py
+++ b/satella/files.py
@@ -10,7 +10,8 @@ import typing as tp
 
 __all__ = ['read_re_sub_and_write', 'find_files', 'split', 'read_in_file', 'write_to_file',
            'write_out_file_if_different', 'make_noncolliding_name', 'try_unlink',
-           'DevNullFilelikeObject', 'read_lines', 'AutoflushFile']
+           'DevNullFilelikeObject', 'read_lines', 'AutoflushFile',
+           'jump_to_directory']
 
 from satella.coding import wraps
 from satella.coding.recast_exceptions import silence_excs, reraise_as
@@ -37,6 +38,36 @@ def value_error_on_closed_file(getter):
 closed_devnull = value_error_on_closed_file(lambda y: y.is_closed)
 
 
+class jump_to_directory(object):
+    """
+    This will temporarily change current working directory. Note however is doesn't proof you against deliberately
+    changing the working directory by the user.
+
+    Non existing directories will be created.
+
+    :ivar path: (str) target path
+    :ivar prev_path: (str) path that was here before this was called.
+    """
+
+    __slots__ = 'path', 'prev_path'
+
+    def __init__(self, path: tp.Optional[str], mode=0o777):
+        self.path = path
+        self.prev_path = None
+        os.makedirs(self.path, mode=mode, exist_ok=True)
+
+    def __enter__(self):
+        self.prev_path = os.getcwd()
+        os.chdir(self.path)
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        assert self.prev_path is not None
+        with reraise_as(FileNotFoundError):
+            os.chdir(self.prev_path)
+        return False
+
+
 class DevNullFilelikeObject(io.FileIO):
     """
     A /dev/null filelike object. For multiple uses.
diff --git a/tests/test_coding/test_singleton.py b/tests/test_coding/test_singleton.py
index d4079f1e8d7cebb36d5acc832aef29769343f305..91ea5188dc60653b36d3957f5fbe6819d37078dc 100644
--- a/tests/test_coding/test_singleton.py
+++ b/tests/test_coding/test_singleton.py
@@ -1,3 +1,4 @@
+import gc
 import queue
 import unittest
 
@@ -57,3 +58,24 @@ class TestSingleton(unittest.TestCase):
         self.assertEqual(set(get_instances_for_singleton(MyClass)), {('a',), ('b',)})
         delete_singleton_for(MyClass, 'a')
         self.assertEqual(set(get_instances_for_singleton(MyClass)), {('b',)})
+
+    def test_singleton_with_regards_to_weak_refs(self):
+        instantiations = 0
+        @SingletonWithRegardsTo(num_args=1, weak_refs=True)
+        class MyClass:
+            def __init__(self, device_id: str):
+                nonlocal instantiations
+                self.device_id = device_id
+                instantiations += 1
+
+        a = MyClass('a')
+        b = MyClass('b')
+        c = MyClass('a')
+        self.assertEqual(instantiations, 2)
+        del a
+        a = MyClass('a')
+        self.assertEqual(instantiations, 2)
+        del b
+        gc.collect()
+        b = MyClass('b')
+        self.assertEqual(instantiations, 3)
diff --git a/tests/test_files.py b/tests/test_files.py
index 7bc2a6416729bbe39ca47fd19f9824213f6cf7da..e0de6d7b3af889e13600995e9fa735c8cabb0a1c 100644
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -6,7 +6,7 @@ import unittest
 import shutil
 from satella.files import read_re_sub_and_write, find_files, split, read_in_file, write_to_file, \
     write_out_file_if_different, make_noncolliding_name, try_unlink, DevNullFilelikeObject, \
-    read_lines, AutoflushFile
+    read_lines, AutoflushFile, jump_to_directory
 
 
 def putfile(path: str) -> None:
@@ -16,6 +16,12 @@ def putfile(path: str) -> None:
 
 class TestFiles(unittest.TestCase):
 
+    def test_monotonous(self):
+        with jump_to_directory('test/path'):
+            path = os.getcwd()
+            self.assertTrue(path.endswith('path'))
+            self.assertTrue(os.path.exists('path'))
+
     def test_read_nonexistent_file(self):
         self.assertRaises(FileNotFoundError, lambda: read_in_file('moot'))