We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
inheritance strategy can not load  parameter file shared from base class
<!-- 


## Describe your environment

  * Operating system: ubuntu
  * Python Version: 3.8.10`
  * CCXT version: _1.74.63
  * Freqtrade Version: fraqtrade develop
  

## Describe the problem:

if StragegyA derived from StragegyB written in same .py file, 
then both of them share the same json file generated by Hyperopt.

They would could conflict with each other when using Hyperopt to optimize one of them after the other Strategy was optimized.


### Steps to reproduce:

  1. StragegyB derived from  StragegyA and they are in one .py file
  2. optimize StragegyA using Hyperopt ( get file A.json)
  3. optimize StragegyB using Hyperopt 
  4. switching step3 and step2 is the same result
  
### Observed Results:
load file A.json as StragegyB  parameter file, then ERROR

### Relevant code exceptions or logs

2022-03-20 00:59:44,224 - freqtrade.optimize.hyperopt_tools - INFO - Dumping parameters to /home/bourne/freqtrade-develop/user_data/strategies/AStrategy.json

...

2022-03-20 01:01:06,082 - freqtrade.resolvers.iresolver - INFO - Using resolved strategy BStrategy from '/home/bourne/freqtrade-develop/user_data/strategies/AStrategy.py'...
2022-03-20 01:01:06,082 - freqtrade.strategy.hyper - INFO - Loading parameters from file /home/bourne/freqtrade-develop/user_data/strategies/AStrategy.json
2022-03-20 01:01:06,082 - freqtrade - ERROR - Invalid parameter file provided.





--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `freqtrade/resolvers/iresolver.py`
Content:
```
1 # pragma pylint: disable=attribute-defined-outside-init
2 
3 """
4 This module load custom objects
5 """
6 import importlib.util
7 import inspect
8 import logging
9 from pathlib import Path
10 from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union
11 
12 from freqtrade.exceptions import OperationalException
13 
14 
15 logger = logging.getLogger(__name__)
16 
17 
18 class IResolver:
19     """
20     This class contains all the logic to load custom classes
21     """
22     # Childclasses need to override this
23     object_type: Type[Any]
24     object_type_str: str
25     user_subdir: Optional[str] = None
26     initial_search_path: Optional[Path]
27 
28     @classmethod
29     def build_search_paths(cls, config: Dict[str, Any], user_subdir: Optional[str] = None,
30                            extra_dir: Optional[str] = None) -> List[Path]:
31 
32         abs_paths: List[Path] = []
33         if cls.initial_search_path:
34             abs_paths.append(cls.initial_search_path)
35 
36         if user_subdir:
37             abs_paths.insert(0, config['user_data_dir'].joinpath(user_subdir))
38 
39         if extra_dir:
40             # Add extra directory to the top of the search paths
41             abs_paths.insert(0, Path(extra_dir).resolve())
42 
43         return abs_paths
44 
45     @classmethod
46     def _get_valid_object(cls, module_path: Path, object_name: Optional[str],
47                           enum_failed: bool = False) -> Iterator[Any]:
48         """
49         Generator returning objects with matching object_type and object_name in the path given.
50         :param module_path: absolute path to the module
51         :param object_name: Class name of the object
52         :param enum_failed: If True, will return None for modules which fail.
53             Otherwise, failing modules are skipped.
54         :return: generator containing tuple of matching objects
55              Tuple format: [Object, source]
56         """
57 
58         # Generate spec based on absolute path
59         # Pass object_name as first argument to have logging print a reasonable name.
60         spec = importlib.util.spec_from_file_location(object_name or "", str(module_path))
61         if not spec:
62             return iter([None])
63 
64         module = importlib.util.module_from_spec(spec)
65         try:
66             spec.loader.exec_module(module)  # type: ignore # importlib does not use typehints
67         except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err:
68             # Catch errors in case a specific module is not installed
69             logger.warning(f"Could not import {module_path} due to '{err}'")
70             if enum_failed:
71                 return iter([None])
72 
73         valid_objects_gen = (
74             (obj, inspect.getsource(module)) for
75             name, obj in inspect.getmembers(
76                 module, inspect.isclass) if ((object_name is None or object_name == name)
77                                              and issubclass(obj, cls.object_type)
78                                              and obj is not cls.object_type)
79         )
80         return valid_objects_gen
81 
82     @classmethod
83     def _search_object(cls, directory: Path, *, object_name: str, add_source: bool = False
84                        ) -> Union[Tuple[Any, Path], Tuple[None, None]]:
85         """
86         Search for the objectname in the given directory
87         :param directory: relative or absolute directory path
88         :param object_name: ClassName of the object to load
89         :return: object class
90         """
91         logger.debug(f"Searching for {cls.object_type.__name__} {object_name} in '{directory}'")
92         for entry in directory.iterdir():
93             # Only consider python files
94             if entry.suffix != '.py':
95                 logger.debug('Ignoring %s', entry)
96                 continue
97             if entry.is_symlink() and not entry.is_file():
98                 logger.debug('Ignoring broken symlink %s', entry)
99                 continue
100             module_path = entry.resolve()
101 
102             obj = next(cls._get_valid_object(module_path, object_name), None)
103 
104             if obj:
105                 obj[0].__file__ = str(entry)
106                 if add_source:
107                     obj[0].__source__ = obj[1]
108                 return (obj[0], module_path)
109         return (None, None)
110 
111     @classmethod
112     def _load_object(cls, paths: List[Path], *, object_name: str, add_source: bool = False,
113                      kwargs: dict = {}) -> Optional[Any]:
114         """
115         Try to load object from path list.
116         """
117 
118         for _path in paths:
119             try:
120                 (module, module_path) = cls._search_object(directory=_path,
121                                                            object_name=object_name,
122                                                            add_source=add_source)
123                 if module:
124                     logger.info(
125                         f"Using resolved {cls.object_type.__name__.lower()[1:]} {object_name} "
126                         f"from '{module_path}'...")
127                     return module(**kwargs)
128             except FileNotFoundError:
129                 logger.warning('Path "%s" does not exist.', _path.resolve())
130 
131         return None
132 
133     @classmethod
134     def load_object(cls, object_name: str, config: dict, *, kwargs: dict,
135                     extra_dir: Optional[str] = None) -> Any:
136         """
137         Search and loads the specified object as configured in hte child class.
138         :param object_name: name of the module to import
139         :param config: configuration dictionary
140         :param extra_dir: additional directory to search for the given pairlist
141         :raises: OperationalException if the class is invalid or does not exist.
142         :return: Object instance or None
143         """
144 
145         abs_paths = cls.build_search_paths(config,
146                                            user_subdir=cls.user_subdir,
147                                            extra_dir=extra_dir)
148 
149         found_object = cls._load_object(paths=abs_paths, object_name=object_name,
150                                         kwargs=kwargs)
151         if found_object:
152             return found_object
153         raise OperationalException(
154             f"Impossible to load {cls.object_type_str} '{object_name}'. This class does not exist "
155             "or contains Python code errors."
156         )
157 
158     @classmethod
159     def search_all_objects(cls, directory: Path,
160                            enum_failed: bool) -> List[Dict[str, Any]]:
161         """
162         Searches a directory for valid objects
163         :param directory: Path to search
164         :param enum_failed: If True, will return None for modules which fail.
165             Otherwise, failing modules are skipped.
166         :return: List of dicts containing 'name', 'class' and 'location' entries
167         """
168         logger.debug(f"Searching for {cls.object_type.__name__} '{directory}'")
169         objects = []
170         for entry in directory.iterdir():
171             # Only consider python files
172             if entry.suffix != '.py':
173                 logger.debug('Ignoring %s', entry)
174                 continue
175             module_path = entry.resolve()
176             logger.debug(f"Path {module_path}")
177             for obj in cls._get_valid_object(module_path, object_name=None,
178                                              enum_failed=enum_failed):
179                 objects.append(
180                     {'name': obj[0].__name__ if obj is not None else '',
181                      'class': obj[0] if obj is not None else None,
182                      'location': entry,
183                      })
184         return objects
185
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py
--- a/freqtrade/resolvers/iresolver.py
+++ b/freqtrade/resolvers/iresolver.py
@@ -6,6 +6,7 @@
 import importlib.util
 import inspect
 import logging
+import sys
 from pathlib import Path
 from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union
 
@@ -15,6 +16,22 @@
 logger = logging.getLogger(__name__)
 
 
+class PathModifier:
+    def __init__(self, path: Path):
+        self.path = path
+
+    def __enter__(self):
+        """Inject path to allow importing with relative imports."""
+        sys.path.insert(0, str(self.path))
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        """Undo insertion of local path."""
+        str_path = str(self.path)
+        if str_path in sys.path:
+            sys.path.remove(str_path)
+
+
 class IResolver:
     """
     This class contains all the logic to load custom classes
@@ -57,27 +74,32 @@
 
         # Generate spec based on absolute path
         # Pass object_name as first argument to have logging print a reasonable name.
-        spec = importlib.util.spec_from_file_location(object_name or "", str(module_path))
-        if not spec:
-            return iter([None])
-
-        module = importlib.util.module_from_spec(spec)
-        try:
-            spec.loader.exec_module(module)  # type: ignore # importlib does not use typehints
-        except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err:
-            # Catch errors in case a specific module is not installed
-            logger.warning(f"Could not import {module_path} due to '{err}'")
-            if enum_failed:
+        with PathModifier(module_path.parent):
+            module_name = module_path.stem or ""
+            spec = importlib.util.spec_from_file_location(module_name, str(module_path))
+            if not spec:
                 return iter([None])
 
-        valid_objects_gen = (
-            (obj, inspect.getsource(module)) for
-            name, obj in inspect.getmembers(
-                module, inspect.isclass) if ((object_name is None or object_name == name)
-                                             and issubclass(obj, cls.object_type)
-                                             and obj is not cls.object_type)
-        )
-        return valid_objects_gen
+            module = importlib.util.module_from_spec(spec)
+            try:
+                spec.loader.exec_module(module)  # type: ignore # importlib does not use typehints
+            except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err:
+                # Catch errors in case a specific module is not installed
+                logger.warning(f"Could not import {module_path} due to '{err}'")
+                if enum_failed:
+                    return iter([None])
+
+            valid_objects_gen = (
+                (obj, inspect.getsource(module)) for
+                name, obj in inspect.getmembers(
+                    module, inspect.isclass) if ((object_name is None or object_name == name)
+                                                 and issubclass(obj, cls.object_type)
+                                                 and obj is not cls.object_type
+                                                 and obj.__module__ == module_name
+                                                 )
+            )
+            # The __module__ check ensures we only use strategies that are defined in this folder.
+            return valid_objects_gen
 
     @classmethod
     def _search_object(cls, directory: Path, *, object_name: str, add_source: bool = False

{"golden_diff": "diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py\n--- a/freqtrade/resolvers/iresolver.py\n+++ b/freqtrade/resolvers/iresolver.py\n@@ -6,6 +6,7 @@\n import importlib.util\n import inspect\n import logging\n+import sys\n from pathlib import Path\n from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union\n \n@@ -15,6 +16,22 @@\n logger = logging.getLogger(__name__)\n \n \n+class PathModifier:\n+    def __init__(self, path: Path):\n+        self.path = path\n+\n+    def __enter__(self):\n+        \"\"\"Inject path to allow importing with relative imports.\"\"\"\n+        sys.path.insert(0, str(self.path))\n+        return self\n+\n+    def __exit__(self, exc_type, exc_val, exc_tb):\n+        \"\"\"Undo insertion of local path.\"\"\"\n+        str_path = str(self.path)\n+        if str_path in sys.path:\n+            sys.path.remove(str_path)\n+\n+\n class IResolver:\n     \"\"\"\n     This class contains all the logic to load custom classes\n@@ -57,27 +74,32 @@\n \n         # Generate spec based on absolute path\n         # Pass object_name as first argument to have logging print a reasonable name.\n-        spec = importlib.util.spec_from_file_location(object_name or \"\", str(module_path))\n-        if not spec:\n-            return iter([None])\n-\n-        module = importlib.util.module_from_spec(spec)\n-        try:\n-            spec.loader.exec_module(module)  # type: ignore # importlib does not use typehints\n-        except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err:\n-            # Catch errors in case a specific module is not installed\n-            logger.warning(f\"Could not import {module_path} due to '{err}'\")\n-            if enum_failed:\n+        with PathModifier(module_path.parent):\n+            module_name = module_path.stem or \"\"\n+            spec = importlib.util.spec_from_file_location(module_name, str(module_path))\n+            if not spec:\n                 return iter([None])\n \n-        valid_objects_gen = (\n-            (obj, inspect.getsource(module)) for\n-            name, obj in inspect.getmembers(\n-                module, inspect.isclass) if ((object_name is None or object_name == name)\n-                                             and issubclass(obj, cls.object_type)\n-                                             and obj is not cls.object_type)\n-        )\n-        return valid_objects_gen\n+            module = importlib.util.module_from_spec(spec)\n+            try:\n+                spec.loader.exec_module(module)  # type: ignore # importlib does not use typehints\n+            except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err:\n+                # Catch errors in case a specific module is not installed\n+                logger.warning(f\"Could not import {module_path} due to '{err}'\")\n+                if enum_failed:\n+                    return iter([None])\n+\n+            valid_objects_gen = (\n+                (obj, inspect.getsource(module)) for\n+                name, obj in inspect.getmembers(\n+                    module, inspect.isclass) if ((object_name is None or object_name == name)\n+                                                 and issubclass(obj, cls.object_type)\n+                                                 and obj is not cls.object_type\n+                                                 and obj.__module__ == module_name\n+                                                 )\n+            )\n+            # The __module__ check ensures we only use strategies that are defined in this folder.\n+            return valid_objects_gen\n \n     @classmethod\n     def _search_object(cls, directory: Path, *, object_name: str, add_source: bool = False\n", "issue": "inheritance strategy can not load  parameter file shared from base class\n<!-- \r\n\r\n\r\n## Describe your environment\r\n\r\n  * Operating system: ubuntu\r\n  * Python Version: 3.8.10`\r\n  * CCXT version: _1.74.63\r\n  * Freqtrade Version: fraqtrade develop\r\n  \r\n\r\n## Describe the problem:\r\n\r\nif StragegyA derived from StragegyB written in same .py file, \r\nthen both of them share the same json file generated by Hyperopt.\r\n\r\nThey would could conflict with each other when using Hyperopt to optimize one of them after the other Strategy was optimized.\r\n\r\n\r\n### Steps to reproduce:\r\n\r\n  1. StragegyB derived from  StragegyA and they are in one .py file\r\n  2. optimize StragegyA using Hyperopt ( get file A.json)\r\n  3. optimize StragegyB using Hyperopt \r\n  4. switching step3 and step2 is the same result\r\n  \r\n### Observed Results:\r\nload file A.json as StragegyB  parameter file, then ERROR\r\n\r\n### Relevant code exceptions or logs\r\n\r\n2022-03-20 00:59:44,224 - freqtrade.optimize.hyperopt_tools - INFO - Dumping parameters to /home/bourne/freqtrade-develop/user_data/strategies/AStrategy.json\r\n\r\n...\r\n\r\n2022-03-20 01:01:06,082 - freqtrade.resolvers.iresolver - INFO - Using resolved strategy BStrategy from '/home/bourne/freqtrade-develop/user_data/strategies/AStrategy.py'...\r\n2022-03-20 01:01:06,082 - freqtrade.strategy.hyper - INFO - Loading parameters from file /home/bourne/freqtrade-develop/user_data/strategies/AStrategy.json\r\n2022-03-20 01:01:06,082 - freqtrade - ERROR - Invalid parameter file provided.\r\n\r\n\r\n\r\n\n", "before_files": [{"content": "# pragma pylint: disable=attribute-defined-outside-init\n\n\"\"\"\nThis module load custom objects\n\"\"\"\nimport importlib.util\nimport inspect\nimport logging\nfrom pathlib import Path\nfrom typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union\n\nfrom freqtrade.exceptions import OperationalException\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass IResolver:\n    \"\"\"\n    This class contains all the logic to load custom classes\n    \"\"\"\n    # Childclasses need to override this\n    object_type: Type[Any]\n    object_type_str: str\n    user_subdir: Optional[str] = None\n    initial_search_path: Optional[Path]\n\n    @classmethod\n    def build_search_paths(cls, config: Dict[str, Any], user_subdir: Optional[str] = None,\n                           extra_dir: Optional[str] = None) -> List[Path]:\n\n        abs_paths: List[Path] = []\n        if cls.initial_search_path:\n            abs_paths.append(cls.initial_search_path)\n\n        if user_subdir:\n            abs_paths.insert(0, config['user_data_dir'].joinpath(user_subdir))\n\n        if extra_dir:\n            # Add extra directory to the top of the search paths\n            abs_paths.insert(0, Path(extra_dir).resolve())\n\n        return abs_paths\n\n    @classmethod\n    def _get_valid_object(cls, module_path: Path, object_name: Optional[str],\n                          enum_failed: bool = False) -> Iterator[Any]:\n        \"\"\"\n        Generator returning objects with matching object_type and object_name in the path given.\n        :param module_path: absolute path to the module\n        :param object_name: Class name of the object\n        :param enum_failed: If True, will return None for modules which fail.\n            Otherwise, failing modules are skipped.\n        :return: generator containing tuple of matching objects\n             Tuple format: [Object, source]\n        \"\"\"\n\n        # Generate spec based on absolute path\n        # Pass object_name as first argument to have logging print a reasonable name.\n        spec = importlib.util.spec_from_file_location(object_name or \"\", str(module_path))\n        if not spec:\n            return iter([None])\n\n        module = importlib.util.module_from_spec(spec)\n        try:\n            spec.loader.exec_module(module)  # type: ignore # importlib does not use typehints\n        except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err:\n            # Catch errors in case a specific module is not installed\n            logger.warning(f\"Could not import {module_path} due to '{err}'\")\n            if enum_failed:\n                return iter([None])\n\n        valid_objects_gen = (\n            (obj, inspect.getsource(module)) for\n            name, obj in inspect.getmembers(\n                module, inspect.isclass) if ((object_name is None or object_name == name)\n                                             and issubclass(obj, cls.object_type)\n                                             and obj is not cls.object_type)\n        )\n        return valid_objects_gen\n\n    @classmethod\n    def _search_object(cls, directory: Path, *, object_name: str, add_source: bool = False\n                       ) -> Union[Tuple[Any, Path], Tuple[None, None]]:\n        \"\"\"\n        Search for the objectname in the given directory\n        :param directory: relative or absolute directory path\n        :param object_name: ClassName of the object to load\n        :return: object class\n        \"\"\"\n        logger.debug(f\"Searching for {cls.object_type.__name__} {object_name} in '{directory}'\")\n        for entry in directory.iterdir():\n            # Only consider python files\n            if entry.suffix != '.py':\n                logger.debug('Ignoring %s', entry)\n                continue\n            if entry.is_symlink() and not entry.is_file():\n                logger.debug('Ignoring broken symlink %s', entry)\n                continue\n            module_path = entry.resolve()\n\n            obj = next(cls._get_valid_object(module_path, object_name), None)\n\n            if obj:\n                obj[0].__file__ = str(entry)\n                if add_source:\n                    obj[0].__source__ = obj[1]\n                return (obj[0], module_path)\n        return (None, None)\n\n    @classmethod\n    def _load_object(cls, paths: List[Path], *, object_name: str, add_source: bool = False,\n                     kwargs: dict = {}) -> Optional[Any]:\n        \"\"\"\n        Try to load object from path list.\n        \"\"\"\n\n        for _path in paths:\n            try:\n                (module, module_path) = cls._search_object(directory=_path,\n                                                           object_name=object_name,\n                                                           add_source=add_source)\n                if module:\n                    logger.info(\n                        f\"Using resolved {cls.object_type.__name__.lower()[1:]} {object_name} \"\n                        f\"from '{module_path}'...\")\n                    return module(**kwargs)\n            except FileNotFoundError:\n                logger.warning('Path \"%s\" does not exist.', _path.resolve())\n\n        return None\n\n    @classmethod\n    def load_object(cls, object_name: str, config: dict, *, kwargs: dict,\n                    extra_dir: Optional[str] = None) -> Any:\n        \"\"\"\n        Search and loads the specified object as configured in hte child class.\n        :param object_name: name of the module to import\n        :param config: configuration dictionary\n        :param extra_dir: additional directory to search for the given pairlist\n        :raises: OperationalException if the class is invalid or does not exist.\n        :return: Object instance or None\n        \"\"\"\n\n        abs_paths = cls.build_search_paths(config,\n                                           user_subdir=cls.user_subdir,\n                                           extra_dir=extra_dir)\n\n        found_object = cls._load_object(paths=abs_paths, object_name=object_name,\n                                        kwargs=kwargs)\n        if found_object:\n            return found_object\n        raise OperationalException(\n            f\"Impossible to load {cls.object_type_str} '{object_name}'. This class does not exist \"\n            \"or contains Python code errors.\"\n        )\n\n    @classmethod\n    def search_all_objects(cls, directory: Path,\n                           enum_failed: bool) -> List[Dict[str, Any]]:\n        \"\"\"\n        Searches a directory for valid objects\n        :param directory: Path to search\n        :param enum_failed: If True, will return None for modules which fail.\n            Otherwise, failing modules are skipped.\n        :return: List of dicts containing 'name', 'class' and 'location' entries\n        \"\"\"\n        logger.debug(f\"Searching for {cls.object_type.__name__} '{directory}'\")\n        objects = []\n        for entry in directory.iterdir():\n            # Only consider python files\n            if entry.suffix != '.py':\n                logger.debug('Ignoring %s', entry)\n                continue\n            module_path = entry.resolve()\n            logger.debug(f\"Path {module_path}\")\n            for obj in cls._get_valid_object(module_path, object_name=None,\n                                             enum_failed=enum_failed):\n                objects.append(\n                    {'name': obj[0].__name__ if obj is not None else '',\n                     'class': obj[0] if obj is not None else None,\n                     'location': entry,\n                     })\n        return objects\n", "path": "freqtrade/resolvers/iresolver.py"}], "after_files": [{"content": "# pragma pylint: disable=attribute-defined-outside-init\n\n\"\"\"\nThis module load custom objects\n\"\"\"\nimport importlib.util\nimport inspect\nimport logging\nimport sys\nfrom pathlib import Path\nfrom typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union\n\nfrom freqtrade.exceptions import OperationalException\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass PathModifier:\n    def __init__(self, path: Path):\n        self.path = path\n\n    def __enter__(self):\n        \"\"\"Inject path to allow importing with relative imports.\"\"\"\n        sys.path.insert(0, str(self.path))\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        \"\"\"Undo insertion of local path.\"\"\"\n        str_path = str(self.path)\n        if str_path in sys.path:\n            sys.path.remove(str_path)\n\n\nclass IResolver:\n    \"\"\"\n    This class contains all the logic to load custom classes\n    \"\"\"\n    # Childclasses need to override this\n    object_type: Type[Any]\n    object_type_str: str\n    user_subdir: Optional[str] = None\n    initial_search_path: Optional[Path]\n\n    @classmethod\n    def build_search_paths(cls, config: Dict[str, Any], user_subdir: Optional[str] = None,\n                           extra_dir: Optional[str] = None) -> List[Path]:\n\n        abs_paths: List[Path] = []\n        if cls.initial_search_path:\n            abs_paths.append(cls.initial_search_path)\n\n        if user_subdir:\n            abs_paths.insert(0, config['user_data_dir'].joinpath(user_subdir))\n\n        if extra_dir:\n            # Add extra directory to the top of the search paths\n            abs_paths.insert(0, Path(extra_dir).resolve())\n\n        return abs_paths\n\n    @classmethod\n    def _get_valid_object(cls, module_path: Path, object_name: Optional[str],\n                          enum_failed: bool = False) -> Iterator[Any]:\n        \"\"\"\n        Generator returning objects with matching object_type and object_name in the path given.\n        :param module_path: absolute path to the module\n        :param object_name: Class name of the object\n        :param enum_failed: If True, will return None for modules which fail.\n            Otherwise, failing modules are skipped.\n        :return: generator containing tuple of matching objects\n             Tuple format: [Object, source]\n        \"\"\"\n\n        # Generate spec based on absolute path\n        # Pass object_name as first argument to have logging print a reasonable name.\n        with PathModifier(module_path.parent):\n            module_name = module_path.stem or \"\"\n            spec = importlib.util.spec_from_file_location(module_name, str(module_path))\n            if not spec:\n                return iter([None])\n\n            module = importlib.util.module_from_spec(spec)\n            try:\n                spec.loader.exec_module(module)  # type: ignore # importlib does not use typehints\n            except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err:\n                # Catch errors in case a specific module is not installed\n                logger.warning(f\"Could not import {module_path} due to '{err}'\")\n                if enum_failed:\n                    return iter([None])\n\n            valid_objects_gen = (\n                (obj, inspect.getsource(module)) for\n                name, obj in inspect.getmembers(\n                    module, inspect.isclass) if ((object_name is None or object_name == name)\n                                                 and issubclass(obj, cls.object_type)\n                                                 and obj is not cls.object_type\n                                                 and obj.__module__ == module_name\n                                                 )\n            )\n            # The __module__ check ensures we only use strategies that are defined in this folder.\n            return valid_objects_gen\n\n    @classmethod\n    def _search_object(cls, directory: Path, *, object_name: str, add_source: bool = False\n                       ) -> Union[Tuple[Any, Path], Tuple[None, None]]:\n        \"\"\"\n        Search for the objectname in the given directory\n        :param directory: relative or absolute directory path\n        :param object_name: ClassName of the object to load\n        :return: object class\n        \"\"\"\n        logger.debug(f\"Searching for {cls.object_type.__name__} {object_name} in '{directory}'\")\n        for entry in directory.iterdir():\n            # Only consider python files\n            if entry.suffix != '.py':\n                logger.debug('Ignoring %s', entry)\n                continue\n            if entry.is_symlink() and not entry.is_file():\n                logger.debug('Ignoring broken symlink %s', entry)\n                continue\n            module_path = entry.resolve()\n\n            obj = next(cls._get_valid_object(module_path, object_name), None)\n\n            if obj:\n                obj[0].__file__ = str(entry)\n                if add_source:\n                    obj[0].__source__ = obj[1]\n                return (obj[0], module_path)\n        return (None, None)\n\n    @classmethod\n    def _load_object(cls, paths: List[Path], *, object_name: str, add_source: bool = False,\n                     kwargs: dict = {}) -> Optional[Any]:\n        \"\"\"\n        Try to load object from path list.\n        \"\"\"\n\n        for _path in paths:\n            try:\n                (module, module_path) = cls._search_object(directory=_path,\n                                                           object_name=object_name,\n                                                           add_source=add_source)\n                if module:\n                    logger.info(\n                        f\"Using resolved {cls.object_type.__name__.lower()[1:]} {object_name} \"\n                        f\"from '{module_path}'...\")\n                    return module(**kwargs)\n            except FileNotFoundError:\n                logger.warning('Path \"%s\" does not exist.', _path.resolve())\n\n        return None\n\n    @classmethod\n    def load_object(cls, object_name: str, config: dict, *, kwargs: dict,\n                    extra_dir: Optional[str] = None) -> Any:\n        \"\"\"\n        Search and loads the specified object as configured in hte child class.\n        :param object_name: name of the module to import\n        :param config: configuration dictionary\n        :param extra_dir: additional directory to search for the given pairlist\n        :raises: OperationalException if the class is invalid or does not exist.\n        :return: Object instance or None\n        \"\"\"\n\n        abs_paths = cls.build_search_paths(config,\n                                           user_subdir=cls.user_subdir,\n                                           extra_dir=extra_dir)\n\n        found_object = cls._load_object(paths=abs_paths, object_name=object_name,\n                                        kwargs=kwargs)\n        if found_object:\n            return found_object\n        raise OperationalException(\n            f\"Impossible to load {cls.object_type_str} '{object_name}'. This class does not exist \"\n            \"or contains Python code errors.\"\n        )\n\n    @classmethod\n    def search_all_objects(cls, directory: Path,\n                           enum_failed: bool) -> List[Dict[str, Any]]:\n        \"\"\"\n        Searches a directory for valid objects\n        :param directory: Path to search\n        :param enum_failed: If True, will return None for modules which fail.\n            Otherwise, failing modules are skipped.\n        :return: List of dicts containing 'name', 'class' and 'location' entries\n        \"\"\"\n        logger.debug(f\"Searching for {cls.object_type.__name__} '{directory}'\")\n        objects = []\n        for entry in directory.iterdir():\n            # Only consider python files\n            if entry.suffix != '.py':\n                logger.debug('Ignoring %s', entry)\n                continue\n            module_path = entry.resolve()\n            logger.debug(f\"Path {module_path}\")\n            for obj in cls._get_valid_object(module_path, object_name=None,\n                                             enum_failed=enum_failed):\n                objects.append(\n                    {'name': obj[0].__name__ if obj is not None else '',\n                     'class': obj[0] if obj is not None else None,\n                     'location': entry,\n                     })\n        return objects\n", "path": "freqtrade/resolvers/iresolver.py"}]}