Repository: ansible/ansible-lint

Issue:
proposal: reinstate editable installs on ansible-lint
During the last year the `setup.py` was silently removed from `ansible-lint` project. This had a side-effect that made impossible to perform editable installs of the project, something that works very fine with other ansible projects.

Editable installs are essential for anyone that does **development and contributions**. Without `-e` mode,  making changes to a python library becomes a serious inconvenience. Developer has to repackage and reinstall the library before running any code again. Even debugging becomes a struggle as you often discover that the code you run is not the one you modified.

ansible-lint is the first python package I encountered that removed `setup.py`. The deprecation of setup.py is planned by PEP-518 but effective removal of the file was a long-term plan.

As a **community project**, ansible-lint needs to **ease contributions** from developers, not introducing additional contribution barriers.  I am more than willing to help with the additional maintenance needed for keeping the editable mode working.

I was told that the original decision was made after an unrecorded discussion made on irc (outside of a meeting). Due to this, I want to reopen the subject and give opportunity to gather feedback from users and developers, especially those that made or wanted to contribute to ansible-lint in the past.

Should we reinstate editable installs with ansible-lint? **Click on the bar to vote, keep in mind that you cannot undo your vote.**

[![](https://api.gh-polls.com/poll/01E504FSJ085KQZB408HF2TXYB/yes)](https://api.gh-polls.com/poll/01E504FSJ085KQZB408HF2TXYB/yes/vote)
[![](https://api.gh-polls.com/poll/01E504FSJ085KQZB408HF2TXYB/no)](https://api.gh-polls.com/poll/01E504FSJ085KQZB408HF2TXYB/no/vote)
[![](https://api.gh-polls.com/poll/01E504FSJ085KQZB408HF2TXYB/not%20sure)](https://api.gh-polls.com/poll/01E504FSJ085KQZB408HF2TXYB/not%20sure/vote)

Make ansible-lint installable in editable mode
The change is also adding a regression protection in CI jobs by testing that editable installation is possible after it runs the normal tox environments.

Considering the CI determines what is supported or not I see no reason for not fixing this issue. 
When most (in not all) python development tools like tox, pytest, flake8, pre-commit, black are installable in editable mode, I am confident to challenge the reasons for preventing ansible-lint from doing the same.

Fixes: #653
Fixes: #716


Discussion:
> silently removed

This is not true. It was a part of getting rid of packaging shims.


> Editable installs are essential for anyone that does **development and contributions**.

Not true.


> Developer has to repackage and reinstall the library before running any code again. Even debugging becomes a struggle as you often discover that the code you run is not the one you modified.

Nope. Use `PYTHONPATH=lib`.


> Should we reinstate editable installs with ansible-lint?

I think you're trying to solve other problems while using it as an excuse to squeeze in `setup.py`. You'd better explain what the real problems are.
> > Developer has to repackage and reinstall the library before running any code again. Even debugging becomes a struggle as you often discover that the code you run is not the one you modified.
> 
> Nope. Use `PYTHONPATH=lib`.

From my perspective this is better (more easily) solved when editable is an option; it follows a fairly typical developer workflow and doesn't require me to mess with environment variables. I personally use venvs for everything I work on and leverage editable quite a lot, anything that makes an editable installation a reality would be great IMO.
@cloudnull can you show how exactly you're using editable with ansible-lint *and* run tests?
> @cloudnull can you show how exactly you're using editable with ansible-lint _and_ run tests?

At this point I'm not using `editable` with *ansible-lint* because its broken. However, its usage is fairly well documented [here](https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs).

If `editable` were to work, my workflow would generally be something like this; assuming I am running with a new checkout from the head of master...

``` zsh
╭─kecarter@KE-RH-T580 ~  
╰─➤  python3.9 -m venv test-ansible-lint
╭─kecarter@KE-RH-T580 ~
╰─➤  ./test-ansible-lint/bin/pip install --editable git+https://github.com/ansible/ansible-lint#egg=ansible-lint
```

Due to the missing `setup.py` or a suitable way to support `editable` we run into the following issues...

``` zsh
Obtaining ansible-lint from git+https://github.com/ansible/ansible-lint#egg=ansible-lint
  Cloning https://github.com/ansible/ansible-lint to ./test-ansible-lint/src/ansible-lint
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done
Collecting pyyaml (from ansible-lint)
  Downloading https://files.pythonhosted.org/packages/64/c2/b80047c7ac2478f9501676c988a5411ed5572f35d1beff9cae07d321512c/PyYAML-5.3.1.tar.gz (269kB)
    100% |████████████████████████████████| 276kB 3.3MB/s
Collecting ansible>=2.7 (from ansible-lint)
  Downloading https://files.pythonhosted.org/packages/ae/b7/c717363f767f7af33d90af9458d5f1e0960db9c2393a6c221c2ce97ad1aa/ansible-2.9.6.tar.gz (14.2MB)
    100% |████████████████████████████████| 14.2MB 4.3MB/s
Collecting ruamel.yaml<1,>=0.15.37; python_version >= "3.7" (from ansible-lint)
  Downloading https://files.pythonhosted.org/packages/a6/92/59af3e38227b9cc14520bf1e59516d99ceca53e3b8448094248171e9432b/ruamel.yaml-0.16.10-py2.py3-none-any.whl (111kB)
    100% |████████████████████████████████| 112kB 22.6MB/s
Collecting jinja2 (from ansible>=2.7->ansible-lint)
  Using cached https://files.pythonhosted.org/packages/27/24/4f35961e5c669e96f6559760042a55b9bcfcdb82b9bdb3c8753dbe042e35/Jinja2-2.11.1-py2.py3-none-any.whl
Collecting cryptography (from ansible>=2.7->ansible-lint)
  Downloading https://files.pythonhosted.org/packages/8f/2d/29d2638b8df016526182594166c220913dafba3da0019b0776ff1bbc8ede/cryptography-2.9-cp35-abi3-manylinux2010_x86_64.whl (2.7MB)
    100% |████████████████████████████████| 2.7MB 21.6MB/s
Collecting MarkupSafe>=0.23 (from jinja2->ansible>=2.7->ansible-lint)
  Downloading https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz
Collecting six>=1.4.1 (from cryptography->ansible>=2.7->ansible-lint)
  Using cached https://files.pythonhosted.org/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Collecting cffi!=1.11.3,>=1.8 (from cryptography->ansible>=2.7->ansible-lint)
  Downloading https://files.pythonhosted.org/packages/05/54/3324b0c46340c31b909fcec598696aaec7ddc8c18a63f2db352562d3354c/cffi-1.14.0.tar.gz (463kB)
    100% |████████████████████████████████| 471kB 14.6MB/s
Collecting pycparser (from cffi!=1.11.3,>=1.8->cryptography->ansible>=2.7->ansible-lint)
  Downloading https://files.pythonhosted.org/packages/ae/e7/d9c3a176ca4b02024debf82342dab36efadfc5776f9c8db077e8f6e71821/pycparser-2.20-py2.py3-none-any.whl (112kB)
    100% |████████████████████████████████| 112kB 15.7MB/s
Installing collected packages: pyyaml, MarkupSafe, jinja2, six, pycparser, cffi, cryptography, ansible, ruamel.yaml, ansible-lint
  Running setup.py install for pyyaml ... done
  Running setup.py install for MarkupSafe ... done
  Running setup.py install for cffi ... done
  Running setup.py install for ansible ... done
  Running setup.py develop for ansible-lint
    Complete output from command /home/kecarter/test-ansible-lint/bin/python3.9 -c "import setuptools, tokenize;__file__='/home/kecarter/test-ansible-lint/src/ansible-lint/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" develop --no-deps:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/usr/lib64/python3.9/tokenize.py", line 392, in open
        buffer = _builtin_open(filename, 'rb')
    FileNotFoundError: [Errno 2] No such file or directory: '/home/kecarter/test-ansible-lint/src/ansible-lint/setup.py'
```

So I can't actually answer the question *"can you show how exactly you're using editable with ansible-lint and run tests?"* because there's no way to make it work without creating my own `setup.py` file.
> I think you're trying to solve other problems while using it as an excuse to squeeze in `setup.py`. You'd better explain what the real problems are.

I think the problems are fairly well articulated in the original message, *"As a community project, ansible-lint needs to ease contributions from developers, not introducing additional contribution barriers"* and the lack of support for `editable` is, in my opinion, a barrier.

> So I can't actually answer the question _"can you show how exactly you're using editable with ansible-lint and run tests?"_ because there's no way to make it work without creating my own `setup.py` file.

What I mean is how did you use it when there was this file present. Like with v4.1.0. You can add `setup.py` containing `from setuptools import setup; setup()` and show me with it in place.

Currently, from your logs, I see some amount of misunderstanding of the purpose of editable install mode — for contributing you should work with your local git clone and push changes from there.

> I think the problems are fairly well articulated

I disagree, what's articulated is the desired solution, not an underlying problem. Why is it so hard for anyone to show a complete workflow? Even with imaginary commands, that would do — I'm just trying to understand *how exactly* editable installs affects things.
> What I mean is how did you use it when there was this file present. Like with v4.1.0.

Really hard to say exactly as I don’t remember everything I would have run when I did it, however, I have to assume I had done it once over the years. I think this is especially true when I started and worked on the openstack-ansible project. The OSA project was a very early adopter of ansible-lint and that community contributed regularly to the code base and the custom lint rules used by the project (at least early on).

> You can add `setup.py` containing `from setuptools import setup; setup()` and show me with it in place.

I think this highlights the simplicity of the change being proposed by @ssbarnea which is confusing.  I don’t understand why you’d want to block the request, especially since more than one person is asking for it to be resorted and @ssbarnea has offered to maintain it if needed. I think this is the question that need be answered, not so much how we’d use it. Also I’m not sure what you want to see, are you looking for a string of commands, besides the ones I already provided? Editable (developer mode) installations have wide range of uses outside of the narrow scope that you seem to think things are operated within. It may be worth your time to have a look into this python packaging [thread](https://discuss.python.org/t/specification-of-editable-installation/1564) as a specification is being developed which may be helpful when understanding how editable is used and impacts various developers.

> Currently, from your logs, I see some amount of misunderstanding of the purpose of editable install mode — for contributing you should work with your local git clone and push changes from there.

There’s no misunderstanding here, I fully understand what editable is and how to use it. My output simply shows a master checkout from source does not work with editable using an example form the [documentation](https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs). I appreciate you attempting to teach me about working with local checkouts, but it’s not needed, nor relevant to this conversation. This does however highlight the fact ansible-lint doesn’t work with the above mentioned command, which is a good example of a barrier for developers as “developer mode” is effectively broken.

> Why is it so hard for anyone to show a complete workflow? Even with imaginary commands, that would do — I'm just trying to understand how exactly editable installs affects things.

I did provide commands, using the pip documentation, which shows how editable is currently broken and highlights breakage in a developer workflow, even though it may not be your own. I think you’re looking for a reason why other developer workflows don’t match your own. That said, I also think your right in that the stated problem is a “desire” and not something fundamentally wrong with the project. The lack of editable installations should be considered a bug, it’s clearly broken, but this bug doesn’t indicate anything wrong with the core project and I believe @ssbarnea coveys that message fairly well.
I think we need to step back and ask, is this proposal beneficial for developers? From the poll it seems 12 people (at the time of this writing) say **yes**. How this (installation) feature is used by individuals is largely irrelevant If it provides value to the folks that may want to leverage, or contribute to, ansible-lint.
I'll provision a simple minimalist `setup.py` to fulfill the request of the 60%
of the poll participants, it's possible without lowering the supported packaging tools requirements.

----------------------

@cloudnull thanks for taking time to write such a detailed response.
I agree with most of the points and I want to comment on some:

> I don’t understand why you’d want to block the request

Well, maybe it's my perception but usually when people can misuse something they do so, and then come and report that as a bug. There's a number of uses for editable installs I just don't want folks to misjudge its support as a recommended way of installing the software.
I think that only one way of doing things should be mainly/officially supported, otherwise it's a mess.


> It may be worth your time to have a look into this python packaging [thread](https://discuss.python.org/t/specification-of-editable-installation/1564) as a specification is being developed which may be helpful when understanding how editable is used and impacts various developers.

Right, thanks for reminding me about that thread, I need to revise it. I actually observed the initial discussion IRL at PyCon last year and probably added some comments during sprints. Too bad that folks don't have time atm to implement the PoC.
@webknjaz what is the cost of supporting such a mode? I found very useful editable installation, it makes my development of modules much more faster and convenient. And testing others PRs as well. Can we consider to add this option for ansible-lint? What is required to move on in this case?
Thanks
@sshnaidm the cost is more than a zero-maintainer team can afford. I'd like to be unbound from the old tech as much as possible.

I'm pretty sure that this is solvable w/o adding `setup.py`.

I haven't seen any compelling evidence that it's needed. "I want this command to work" is not a use-case.

@ssbarnea @sshnaidm please record your workflows using https://asciinema.org/ explaining what you're missing and I'll try to take this into account (I have a hunch that your cases are easy to work around). (Pro tip: asciinema records your terminal so make sure that no secrets appear in the recording + also it doesn't have sound but you can add explanations by typing in comments as in `# I'm demonstrating X and you're observing Y`)
@webknjaz well, as I wrote before I found `pip -e` very useful for development, especially for ansible related stuff. 

>  "I want this command to work" is not a use-case.

But I really want it to work :smile: My use case is pretty simple, I develop python modules and most of them are from TripleO in Openstack or Ansible modules or plugins, running `pip -e` and linking source directory to my `sources` directory which has IDE coverage and allow me to develop and test immediately and not to deal with code, build, install, try, clean, ouch.. not cleaned enough, etc etc.
Maybe I do it wrong way, but I used to it :smile: If you have the better workflow when I can use module and develop its sources with IDE and try without install, I'd like to know of course, always happy to learn.
I mean there are a lot of developers and many workflows, `pip -e` has its own case and I personally and a lot of my colleagues use it, I can't say we want something bizarre and unusual. In our cases it allows to develop easier and it means more involvment in projects and more tested and qualified code. If this mode will allow more people to install ansible-lint, make change and test easily - would it be a good trade of for code maintenance?
Of course we can discuss details and how to do it separately if there is a general agreement about this feature.
You still haven't answered what commands you run. Clicking "some buttons" in IDE is not going to be a supported workflow. We need something actionable.
I was thinking about it and I think I'd settle for a compromise.

So modern setuptools injects a `setup.py` file (in-memory) containing exactly `import setuptools; setuptools.setup()`. That's it.

This got me thinking:
1. The main idea is not to have `setup.py` in the repo and it should stay that way.
2. To ensure this, we need to add it to `.gitignore`.
3. Once it's there, it's safe to create `setup.py` with whatever contents you want on the dev machine.
4. So we could do that and document something like `echo 'import setuptools; setuptools.setup()' > setup.py` in dev docs/readme.
5. If that's too complex, we could add a tox env that would do this.
That is not what I would call a compromise. A compromise would be to require a minimal version of pip or setuptools for the edit to work, which could be seen acceptable for development mode. Still, requiring that kind of hack does clearly not count as making easy to contribute.

Please do accept this and let's move on, the project needs more attention and that issue is clearly not helping it.
Should I also mention that due to this marveleus change I takes >25s to run a single test with tox?
```
tox -e py38-ansible29 -- -k test_run_single_role_path_no_trailing_slash
```
This is because every time you run tox, it will repackage and install the module. 
This change would be very helpful for projects development IMO.

Please find a quick and fair compromise and lets putting things forward!
While I personally like to use `editable` all the time and find it very useful, I can completely understand @webknjaz point about reducing any and all maintenance burdens. Even though this change is tiny, and *shouldn't* incur any maintenance burdens, there is a risk that something could change in upstream setuptools which will force the noted "zero-maintainer team" to fix whatever is broken. I'm :+1:  on the content of this change, however, I'm hesitant to approve it until something can be worked out that satisfies both sides.
Please review https://github.com/ansible/ansible-lint/pull/697 which has the side effect of also addressing most of this ticket.

Resolving patch:
diff --git a/setup.py b/setup.py
new file mode 100755
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,9 @@
+#! /usr/bin/env python3
+"""Ansible-lint distribution package setuptools installer.
+
+The presence of this file ensures the support
+of pip editable mode *with setuptools only*.
+"""
+from setuptools import setup
+
+__name__ == '__main__' and setup()  # pylint: disable=expression-not-assigned


Test patch: