Repository: getgauge/gauge-python

Issue:
Issue in loading step impls from another project using relative paths since a past update
Hello,

A couple of months back I had submitted a PR to add the feature for "[Correctly loading the methods from relatively imported classes](https://github.com/getgauge/gauge-python/pull/364)" and updated "[getgauge/impl_loader.py](https://github.com/getgauge/gauge-python/pull/364/files/b5ea2aa089f23837e5075673c16b37c587254fda#diff-c9dc1215211a60bca5268dc0950879e5cc6c4a13e2b475a343b7e252609853ef)" file's `update_step_resgistry_with_class(instance, file_path)` method to check if the `file_path` had ".." and resolve it to its absolute path. This check was added for efficiency to reduce execution time.

The check was kept as `if '..' in file_path` because we give the relative paths in the `python.properties` file (`../common_project/step_imp`) of the project which when passed to the `impl_loader` file is prepended with the project folder name and ultimately becomes like: `<CURRET_PROJECT_DIR>/../common_project/step_impl` (For detailed project structure info and values of python.properties file please refer issue #359 

But apparently this check was changed to `if str(file_path).startswith("..")` in the following PR - [Enable test coverage report according to README](https://github.com/getgauge/gauge-python/pull/399/files#diff-c9dc1215211a60bca5268dc0950879e5cc6c4a13e2b475a343b7e252609853efR101) which returns false for the above mentioned scenario due to which the step implementations from other projects are unable to load

This issue sneaked past the unit tests of `impl_loader` too as there was no test to cover the scenario where the file name was like `<CURRET_PROJECT_DIR>/../common_project/step_impl`

I'll create a PR with the fix for this issue and updating the unit tests to handle this scenario as well.


Thanks! 😄

Hints from issue comments:

Solution patch:
diff --git a/getgauge/impl_loader.py b/getgauge/impl_loader.py
index e887501..d3614a8 100644
--- a/getgauge/impl_loader.py
+++ b/getgauge/impl_loader.py
@@ -98,7 +98,8 @@ def _import_file(base_dir, file_path):
 # Inject instance in each class method (hook/step)
 def update_step_registry_with_class(instance, file_path):
     # Resolve the absolute path from relative path
-    file_path = os.path.abspath(file_path) if str(file_path).startswith("..") else file_path
+    # Note: relative path syntax ".." can appear in between the file_path too like "<Project_Root>/../../Other_Project/src/step_impl/file.py"
+    file_path = os.path.abspath(file_path) if ".." in str(file_path) else file_path
     method_list = registry.get_all_methods_in(file_path)
     for info in method_list:
         class_methods = [x[0] for x in inspect.getmembers(instance, inspect.ismethod)]
diff --git a/python.json b/python.json
index b21d717..ae58d42 100644
--- a/python.json
+++ b/python.json
@@ -1,6 +1,6 @@
 {
   "id": "python",
-  "version": "0.4.8",
+  "version": "0.4.9",
   "description": "Python support for gauge",
   "run": {
     "windows": [


Test patch:
diff --git a/tests/test_impl_loader.py b/tests/test_impl_loader.py
index f59df52..d14afc8 100644
--- a/tests/test_impl_loader.py
+++ b/tests/test_impl_loader.py
@@ -7,13 +7,21 @@ from test_relative_import.relative_import_class import Sample
 
 class ImplLoaderTest(unittest.TestCase):
     def setUp(self):
+        self.curr_dir = os.getcwd()
         self.relative_file_path = os.path.join('..', 'test_relative_import', 'relative_import_class.py')
+        self.relative_file_path_one_level_above = os.path.join('tests', '..', 'test_relative_import', 'relative_import_class.py')
 
     def test_update_step_registry_with_class(self):
-        curr_dir = os.getcwd()
         os.chdir('tests')
         method_list = update_step_registry_with_class(Sample(), self.relative_file_path)
-        os.chdir(curr_dir)
+        os.chdir(self.curr_dir)
+        self.assertEqual(["Greet <name> from inside the class", 
+                          "Greet <name> from outside the class"], 
+                          [method.step_text for method in method_list])
+
+    def test_update_step_registry_with_class_one_level_above(self):
+        os.chdir(self.curr_dir)
+        method_list = update_step_registry_with_class(Sample(), self.relative_file_path_one_level_above)
         self.assertEqual(["Greet <name> from inside the class", 
                           "Greet <name> from outside the class"], 
                           [method.step_text for method in method_list])