Repository: pksol/mock_autogen (language: python)

Issue:
Pyperclip does not add output to clipboard
I receive the following error on a Linux system when I use the mock_autogen.generate_uut_mocks(function_name) function.

`
------------------------------------------------------------------------------------------------------------------------------------------------- Captured log call -------------------------------------------------------------------------------------------------------------------------------------------------
WARNING  mock_autogen.utils:utils.py:28 Could not copy func results to clipboard
Traceback (most recent call last):
  File "/home/username/Documents/code/test_mock_gen/.envtest/lib/python3.6/site-packages/mock_autogen/utils.py", line 25, in to_clipboard
    pyperclip.copy(result)
  File "/home/username/Documents/code/test_mock_gen/.envtest/lib/python3.6/site-packages/pyperclip/__init__.py", line 659, in lazy_load_stub_copy
    return copy(text)
  File "/home/username/Documents/code/test_mock_gen/.envtest/lib/python3.6/site-packages/pyperclip/__init__.py", line 336, in __call__
    raise PyperclipException(EXCEPT_MSG)
pyperclip.PyperclipException: 
    Pyperclip could not find a copy/paste mechanism for your system.
    For more information, please visit https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error
`


Discussion / hints:
I did find additional instructions on the paperclip link provided in the error. Not sure if adding a dependency for linux systems on the install of the package or update the doco to include this dependency would work best.
I'm also running this via bash terminal so it's possible that is another reason for it not working.
Installing additional low-level dependencies is something I want to avoid at this stage since every distribution has its quirks. 

Instead, this error and basic instructions can be added to the "Troubleshooting" section of the documentation.
> Installing additional low-level dependencies is something I want to avoid at this stage since every distribution has its quirks.
> 
> Instead, this error and basic instructions can be added to the "Troubleshooting" section of the documentation.

That sounds reasonable. I did find afterwards that it appears you need some type of windowing environment in unix for pyperclip to work. Or least that's what I gathered when trying to get it working and installing the various libraries it's documentation suggested. I'm not sure if there is a way to add clipboard functionality to a terminal. In my case I'm using VScode on a Windows 10 host and connect to a unix server to develop using the remote ssh extension.
So digging into this a bit more, I found this particular issue explains in detail the issue I'm having and appears to be well known with VSCode Remote SSH. When I get a working config I will post it in here. My contribution to the troubleshooting guide.
https://github.com/microsoft/vscode-remote-release/issues/4600

Fix patch:
diff --git a/README.md b/README.md
index 47674b6..eef2ae3 100644
--- a/README.md
+++ b/README.md
@@ -203,6 +203,31 @@ PytestMocker(a_module_or_a_class_you_test_and_want_to_mock_its_dependencies).moc
 `PytestMocker` class has many options to produce different kind of mocks.
 See its documentation for further details.
 
+## Troubleshooting
+### No output is printed to the console when running Pytest
+Be sure to run Pytest with appropriate flags to print the output: `pytest -rA`.
+
+### No output is copied to the clipboard
+Mock Generator uses [pyperclip](https://github.com/asweigart/pyperclip) for clipboard 
+manipulations, look for errors / warnings printed in the console, similar to this one: 
+```commandline
+WARNING mock_autogen.utils:utils.py:28 
+Could not copy func results to clipboard Traceback (most recent call last): 
+    File "/home/username/Documents/code/test_mock_gen/.envtest/lib/python3.6/site-packages/mock_autogen/utils.py", line 25, in to_clipboard 
+        pyperclip.copy(result) 
+    File "/home/username/Documents/code/test_mock_gen/.envtest/lib/python3.6/site-packages/pyperclip/__init__.py", line 659, in lazy_load_stub_copy 
+        return copy(text) 
+    File "/home/username/Documents/code/test_mock_gen/.envtest/lib/python3.6/site-packages/pyperclip/__init__.py", line 336, in __call__
+        raise PyperclipException(EXCEPT_MSG) pyperclip.PyperclipException: 
+        
+    Pyperclip could not find a copy/paste mechanism for your system. 
+    For more information, please visit https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error
+```
+
+It's possible that your system lacks some dependency, visit 
+https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error for 
+additional troubleshooting steps.
+
 ## Wrapping up
 I hope that you were convinced that this tool can save you a lot of time. 
 
diff --git a/mock_autogen/generator.py b/mock_autogen/generator.py
index 365f7d1..8ec468f 100644
--- a/mock_autogen/generator.py
+++ b/mock_autogen/generator.py
@@ -29,7 +29,9 @@ def generate_mocks(framework,
                    mock_classes=False,
                    mock_referenced_classes=True,
                    mock_classes_static=False,
-                   prepare_asserts_calls=True):
+                   prepare_asserts_calls=True,
+                   include_mock_autogen_import=True,
+                   mock_autogen_alias="mock_autogen"):
     """
     Generates the list of mocks in order to mock the dependant modules and the
     functions of a given module, class or object instance.
@@ -69,6 +71,9 @@ def generate_mocks(framework,
             Ignored if this is a plain instance
         prepare_asserts_calls (bool): whether to generate the subsequent calls
             to `generate_asserts` for the mocks generated by this call
+        include_mock_autogen_import (bool): whether to include an import to mock_autogen
+            in the generated code
+        mock_autogen_alias (str): the alias for import / prefix for mock_autogen calls
 
     Returns:
         str: the initial code to put in your test to mock the desired behaviour
@@ -134,7 +139,8 @@ def generate_mocks(framework,
 
         return "\n".join(
             deps_lister.warnings) + _pytest_mock_dependencies_generate(
-                deps_lister.dependencies_found, prepare_asserts_calls)
+                deps_lister.dependencies_found, prepare_asserts_calls,
+                include_mock_autogen_import, mock_autogen_alias)
     # we're mocking a regular instance
     else:
         name = name if name else _guess_var_name(name)
@@ -150,14 +156,18 @@ def generate_mocks(framework,
     if MockingFramework.PYTEST_MOCK == framework:
         return _pytest_mock_generate(name, modules, functions, methods,
                                      classes, mock_classes_static,
-                                     prepare_asserts_calls)
+                                     prepare_asserts_calls,
+                                     include_mock_autogen_import,
+                                     mock_autogen_alias)
     else:
         raise ValueError(
             "Unsupported mocking framework: {0}. "
             "You are welcome to add code to support it :)".format(framework))
 
 
-def _pytest_mock_dependencies_generate(dependencies, prepare_asserts_calls):
+def _pytest_mock_dependencies_generate(dependencies, prepare_asserts_calls,
+                                       include_mock_autogen_import,
+                                       mock_autogen_alias):
     generated_code = ""
     unique_dependencies = set()
     mock_names = []
@@ -177,16 +187,19 @@ def _pytest_mock_dependencies_generate(dependencies, prepare_asserts_calls):
 
     if prepare_asserts_calls and mock_names:
         generated_code += "# calls to generate_asserts, " \
-                          "put this after the 'act'\n" \
-                          "import mock_autogen\n"
+                          "put this after the 'act'\n"
+        generated_code = generated_code if not include_mock_autogen_import else \
+            generated_code + f"import {mock_autogen_alias}\n"
         for mock_name in mock_names:
-            generated_code += _single_call_to_generate_asserts(mock_name)
+            generated_code += _single_call_to_generate_asserts(
+                mock_name, mock_autogen_alias)
 
     return generated_code
 
 
 def _pytest_mock_generate(mocked_name, modules, functions, methods, classes,
-                          mock_classes_static, prepare_asserts_calls):
+                          mock_classes_static, prepare_asserts_calls,
+                          include_mock_autogen_import, mock_autogen_alias):
     generated_code = ""
     mock_names = []
     if modules:
@@ -223,10 +236,12 @@ def _pytest_mock_generate(mocked_name, modules, functions, methods, classes,
                 generated_code += generated_mock_code
     if prepare_asserts_calls and mock_names:
         generated_code += "# calls to generate_asserts, " \
-                          "put this after the 'act'\n" \
-                          "import mock_autogen\n"
+                          "put this after the 'act'\n"
+        generated_code = generated_code if not include_mock_autogen_import else \
+            generated_code + f"import {mock_autogen_alias}\n"
         for mock_name in mock_names:
-            generated_code += _single_call_to_generate_asserts(mock_name)
+            generated_code += _single_call_to_generate_asserts(
+                mock_name, mock_autogen_alias)
 
     return generated_code
 
@@ -276,9 +291,8 @@ def __new__(cls, *args, **kwargs):
 """).format(class_name, mocked_name)
 
 
-def _single_call_to_generate_asserts(mock_name):
-    return "mock_autogen.generate_asserts(" \
-           "{0}, name='{0}')\n".format(mock_name)
+def _single_call_to_generate_asserts(mock_name, mock_autogen_alias):
+    return f"{mock_autogen_alias}.generate_asserts({mock_name}, name='{mock_name}')\n"
 
 
 @copy_result_to_clipboard
diff --git a/requirements.txt b/requirements.txt
index 7b8fd91..1d00872 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,2 @@
 mock>=3.0.5
-pyperclip==1.8.1
+pyperclip==1.8.2
diff --git a/setup.py b/setup.py
index 9c01003..7fecb48 100644
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,7 @@
 
 # This call to setup() does all the work
 setup(name="mock-generator",
-      version="2.3.0",
+      version="2.3.1",
       description="Generate python mocks and assertions quickly",
       long_description=README,
       long_description_content_type="text/markdown",


Test patch:
diff --git a/tests/test_generator.py b/tests/test_generator.py
index 658c688..78eaf2f 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -1468,40 +1468,53 @@ def test_generate_asserts_invalid_object():
 
 def test__single_call_to_generate_asserts():
     assert "mock_autogen.generate_asserts(mock_name, name='mock_name')\n" == \
-           mock_autogen.generator._single_call_to_generate_asserts("mock_name")
+           mock_autogen.generator._single_call_to_generate_asserts("mock_name", "mock_autogen")
+
+
+def test__single_call_to_generate_asserts_with_another_alias():
+    assert "mg.generate_asserts(mock_name, name='mock_name')\n" == \
+           mock_autogen.generator._single_call_to_generate_asserts("mock_name", "mg")
 
 
 @pytest.mark.parametrize('prepare_asserts_calls', [True, False])
+@pytest.mark.parametrize('include_mock_autogen_import', [True, False])
+@pytest.mark.parametrize('mock_autogen_alias', ["mock_autogen", "mg"])
 def test__pytest_mock_dependencies_generate_no_functions(
-        prepare_asserts_calls):
+        prepare_asserts_calls, include_mock_autogen_import, mock_autogen_alias):
     generated = mock_autogen.generator._pytest_mock_dependencies_generate(
-        set(), prepare_asserts_calls)
+        set(), prepare_asserts_calls, include_mock_autogen_import, mock_autogen_alias)
 
     assert "" == generated
 
 
 @pytest.mark.parametrize('prepare_asserts_calls', [True, False])
+@pytest.mark.parametrize('include_mock_autogen_import', [True, False])
+@pytest.mark.parametrize('mock_autogen_alias', ["mock_autogen", "mg"])
 def test__pytest_mock_dependencies_generate_one_function(
-        prepare_asserts_calls):
+        prepare_asserts_calls, include_mock_autogen_import, mock_autogen_alias):
     expected = """# mocked dependencies
 mock_first_function = mocker.MagicMock(name='first_function')
 mocker.patch('one.object.first_function', new=mock_first_function)
 """
     if prepare_asserts_calls:
-        expected += """# calls to generate_asserts, put this after the 'act'
-import mock_autogen
-mock_autogen.generate_asserts(mock_first_function, name='mock_first_function')
-"""
+        expected += "# calls to generate_asserts, put this after the 'act'\n"
+        if include_mock_autogen_import:
+            expected += f"import {mock_autogen_alias}\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_first_function, name='mock_first_function')\n"
 
     generated = mock_autogen.generator._pytest_mock_dependencies_generate(
-        [('one.object', 'first_function')], prepare_asserts_calls)
+        [('one.object', 'first_function')], prepare_asserts_calls,
+        include_mock_autogen_import, mock_autogen_alias)
 
     assert expected == generated
 
 
 @pytest.mark.parametrize('prepare_asserts_calls', [True, False])
+@pytest.mark.parametrize('include_mock_autogen_import', [True, False])
+@pytest.mark.parametrize('mock_autogen_alias', ["mock_autogen", "mg"])
 def test__pytest_mock_dependencies_generate_two_functions(
-        prepare_asserts_calls):
+        prepare_asserts_calls, include_mock_autogen_import, mock_autogen_alias):
     expected = """# mocked dependencies
 mock_first_function = mocker.MagicMock(name='first_function')
 mocker.patch('one.object.first_function', new=mock_first_function)
@@ -1509,22 +1522,27 @@ def test__pytest_mock_dependencies_generate_two_functions(
 mocker.patch('second.object.second_function', new=mock_second_function)
 """
     if prepare_asserts_calls:
-        expected += """# calls to generate_asserts, put this after the 'act'
-import mock_autogen
-mock_autogen.generate_asserts(mock_first_function, name='mock_first_function')
-mock_autogen.generate_asserts(mock_second_function, name='mock_second_function')
-"""
+        expected += "# calls to generate_asserts, put this after the 'act'\n"
+        if include_mock_autogen_import:
+            expected += f"import {mock_autogen_alias}\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_first_function, name='mock_first_function')\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_second_function, name='mock_second_function')\n"
 
     generated = mock_autogen.generator._pytest_mock_dependencies_generate(
         [('one.object', 'first_function'),
-         ('second.object', 'second_function')], prepare_asserts_calls)
+         ('second.object', 'second_function')], prepare_asserts_calls,
+        include_mock_autogen_import, mock_autogen_alias)
 
     assert expected == generated
 
 
 @pytest.mark.parametrize('prepare_asserts_calls', [True, False])
+@pytest.mark.parametrize('include_mock_autogen_import', [True, False])
+@pytest.mark.parametrize('mock_autogen_alias', ["mock_autogen", "mg"])
 def test__pytest_mock_dependencies_generate_two_functions_duplicate(
-        prepare_asserts_calls):
+        prepare_asserts_calls, include_mock_autogen_import, mock_autogen_alias):
     expected = """# mocked dependencies
 mock_first_function = mocker.MagicMock(name='first_function')
 mocker.patch('one.object.first_function', new=mock_first_function)
@@ -1532,22 +1550,27 @@ def test__pytest_mock_dependencies_generate_two_functions_duplicate(
 mocker.patch('second.object.first_function', new=mock_first_function_2)
 """
     if prepare_asserts_calls:
-        expected += """# calls to generate_asserts, put this after the 'act'
-import mock_autogen
-mock_autogen.generate_asserts(mock_first_function, name='mock_first_function')
-mock_autogen.generate_asserts(mock_first_function_2, name='mock_first_function_2')
-"""
+        expected += "# calls to generate_asserts, put this after the 'act'\n"
+        if include_mock_autogen_import:
+            expected += f"import {mock_autogen_alias}\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_first_function, name='mock_first_function')\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_first_function_2, name='mock_first_function_2')\n"
 
     generated = mock_autogen.generator._pytest_mock_dependencies_generate(
         [('one.object', 'first_function'),
-         ('second.object', 'first_function')], prepare_asserts_calls)
+         ('second.object', 'first_function')], prepare_asserts_calls,
+        include_mock_autogen_import, mock_autogen_alias)
 
     assert expected == generated
 
 
 @pytest.mark.parametrize('prepare_asserts_calls', [True, False])
+@pytest.mark.parametrize('include_mock_autogen_import', [True, False])
+@pytest.mark.parametrize('mock_autogen_alias', ["mock_autogen", "mg"])
 def test__pytest_mock_dependencies_generate_four_functions_duplicate(
-        prepare_asserts_calls):
+        prepare_asserts_calls, include_mock_autogen_import, mock_autogen_alias):
     expected = """# mocked dependencies
 mock_first_function = mocker.MagicMock(name='first_function')
 mocker.patch('one.object.first_function', new=mock_first_function)
@@ -1559,18 +1582,22 @@ def test__pytest_mock_dependencies_generate_four_functions_duplicate(
 mocker.patch('fourth.first_function', new=mock_first_function_3)
 """
     if prepare_asserts_calls:
-        expected += """# calls to generate_asserts, put this after the 'act'
-import mock_autogen
-mock_autogen.generate_asserts(mock_first_function, name='mock_first_function')
-mock_autogen.generate_asserts(mock_second_function, name='mock_second_function')
-mock_autogen.generate_asserts(mock_first_function_2, name='mock_first_function_2')
-mock_autogen.generate_asserts(mock_first_function_3, name='mock_first_function_3')
-"""
+        expected += "# calls to generate_asserts, put this after the 'act'\n"
+        if include_mock_autogen_import:
+            expected += f"import {mock_autogen_alias}\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_first_function, name='mock_first_function')\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_second_function, name='mock_second_function')\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_first_function_2, name='mock_first_function_2')\n"
+        expected += f"{mock_autogen_alias}.generate_asserts" \
+                    f"(mock_first_function_3, name='mock_first_function_3')\n"
 
     generated = mock_autogen.generator._pytest_mock_dependencies_generate(
         [('one.object', 'first_function'),
          ('second.object', 'second_function'),
          ('third.sub.module', 'first_function'), ('fourth', 'first_function')],
-        prepare_asserts_calls)
+        prepare_asserts_calls, include_mock_autogen_import, mock_autogen_alias)
 
     assert expected == generated