-
Notifications
You must be signed in to change notification settings - Fork 647
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[E602] Don't compare to empty string - what's a better way? #457
Comments
For reference, original discussion was from: #450 |
So another workaround could be to use the
Is that the preferred way rather than a string comparison? I still don't think it's important / best-practice-y enough to force one way over the other, but that's a better compromise than the length filter at least—it makes more semantic sense. |
Hmm... but with the |
|
How about providing a "default wrapper" for the variable? when: my_var|d() That should behave as expected during Ansible execution and not trigger the E602 rule. |
I for myself do not understand the rationale behind this rule... Using the same example as Jeff Geerling above with
IMHO this rule should just be dropped. Or at least not flagged as error importing roles into Ansible Galaxy. And finally - up to now no member of the Ansible team has come up with a explanation for this rule and the things it tries to solve... |
Using Having said that, using This also illustrates that some rules are missing tests! |
How about making |
When Ansible would be changed to work that way ( |
Looks like it works now but only for hash variables. Using simple variables in conditionals causes trouble So, the good workaround for now is avoid using simple variables in string conditionals like |
@tgadiev - That workaround doesn't seem very helpful for this use case though; I often try to split my variables into simpler individual variables so if I want to override one in a playbook I don't have to end up overriding an entire hash/object with 3, 5, 10, or dozens of variables. |
@geerlingguy Are you talking about overriding single key-value item of an entire hash? It's quite simple using |
In the generalized use case of targeting an Ansible beginner, I do not like requiring them to use filters to change a simple string variable. And even in the use case of someone who knows how to merge and adjust hashes, it adds more complexity for no good reason (in the case of this lint rule). Why require me to compare a variable of (Don't want to get this issue off-track—but basically that is a valid workaround, but my strong opinion is that unless there's a demonstrably simpler way of doing a boolean |
@geerlingguy There's no simpler way of doing such comparison to check for empty variable's value than Let's see if it works in practice. We have several variable types in Ansible:
With first four ones you can use simple comparison With string variable there can be 4 possible ways of comparison:
First three cases work as expected. Empty string value treated as False, non-empty as True. The only issue is the last case when comparison to non-empty string causes exception of undefined variable. Yes, it's a bug and there are issues raised in Ansible for that. See ansible/ansible#39414 for example. There are workarounds which can be used in case of checking non-empty string condition:
Do you think that it would be good approach to drop the rule just because of one use-case scenario which is not working as expected because of known bug while several workarounds are available at the moment? |
That particular bug report's been open for almost a year, and the bug has existed for at least a couple years, so yes, I believe this rule can and should be dropped unless that bug is actually fixed. On a separate level (but again, unrelated to the discussion here), I don't particularly like duck typing, so explicitly comparing to a string is something I often do in any non-strict language (like PHP as well), and I'm not sure why there's a rule saying that is a bad thing... |
@geerlingguy , even in PHP there is a method to check if string is empty |
@geerlingguy,
And below:
I guess Ansible code should also follow these recommendations. If you don't like it and prefer other program language code style - it's up to you. Ansible is quite flexible and allows various code styles. If you prefer php-like conditionals for string variables and you're happy with that approach - it's ok, your code will work. But why do you need ansible-lint for that? You can drop any rule you don't like on your own level just disabling it in config. Why do you ask to drop it on general level? |
@tgadiev Thanks for your explanations of python code style... Just to summaries this:
Most simple solution: Second solution: Third solution: I definitely prefer the first one... |
So do I |
Ditto. I don’t care if we prefer that style, but if Ansible breaks if we follow that style and this lint rule slaps me on the wrist if I don’t follow that style (I know I can disable it... in all my 150+ roles and 500+ playbooks individually; that’s a lot of (meaningless) toil), then I agree either that bug needs to be elevated in priority or this rule is toothless. |
Looks like the fixes are coming. Let's wait for related PR #51030 to be merged. |
+1, just had to fix the error with the aforementioned |
Related PR #51030 has been merged to develop. |
Who wants to test? |
* Update kolla-ansible from branch 'master' - Merge "CI: Add ansible-lint to tox" - CI: Add ansible-lint to tox * Reworked tox pep8 into linters job, that runs: - pep8 - bandit - bashate - doc8 - yamllint - ansible-lint (validate-all-files.py + ansible-lint) * Skip E701 - missing galaxy_info in meta and E602 see [1]. * Skip E301 and E503 - followup later in a separate change * Added ansible-role-jobs to zuul.d/project.yaml which will run openstack-tox-linters job in check queue * Fixed remaining style issue * Made tox and docs reference the new env for linters * Dropped pype environment (not supported) [1]: ansible/ansible-lint#457 Change-Id: I494b4b151804aac8173120e6c6e42bc2fdb00234
* Reworked tox pep8 into linters job, that runs: - pep8 - bandit - bashate - doc8 - yamllint - ansible-lint (validate-all-files.py + ansible-lint) * Skip E701 - missing galaxy_info in meta and E602 see [1]. * Skip E301 and E503 - followup later in a separate change * Added ansible-role-jobs to zuul.d/project.yaml which will run openstack-tox-linters job in check queue * Fixed remaining style issue * Made tox and docs reference the new env for linters * Dropped pype environment (not supported) [1]: ansible/ansible-lint#457 Change-Id: I494b4b151804aac8173120e6c6e42bc2fdb00234
It seems the best way to deal with this instead is to just go for the direct check: ansible/ansible-lint#457 Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Except its not really a big miss seeing as this seems to be totally undocumented! |
@geerlingguy Do you think we have any chance to come to some conclusions on this famous ticket? I would really want to close it and while removal of the rule is a quick way to achieve it, I am bit worried that this rule prevented introduction of some bugs in the past. |
In my own work, I can't think of a time when this rule ever helped prevent a mistake. It only annoyed me because there are many times where a comparison to empty string is the only possible way to do it right because of Python's duck typing. I just add it to the skip list on all my playbooks now :( |
Why is this so controversial? This should be the way to be able to check if a value exists/is empty or not. when: MyString This is functionally the same as the very common python usage of See this how to do it right(the way python does it): https://docs.python.org/3/library/stdtypes.html#truth-value-testing |
See #457 (comment) |
Maybe we could get a filter to make things "truthy" or "falsy" like python does... this way, we could abstract that problem away and get people to be explicit. Something like
or even
|
Does anyone have examples where the I asked in chat to understand why comparing with an empty string is dangerous, as described in @ssbarnea's comment above:
My question:
@ssbarnea said:
So, can we create such a document together? What are the pros/cons of various string comparison alternatives? What bugs are possible (or common) with each alternative? |
My two cents on the topic is that this rule should be removed. It makes an assumption that the user is an experienced Python user who knows that |
@awcrosby @sivel @bcoca Can you please help us make a decision regarding this confusing rule? While I do know for sure that it did catch some bugs in the past it also seems to give false recommendations in some cases. Unless we can fix it by getting a recommended use pattern that is safe to use I would see it demoting it to an opt-in in upcoming v6. |
opt-in seems best, there are many cases you want to be specific and compare to empty string (also confirms 'type') |
v6 already does this as opt-in but I think that we should look into improving the rule with positive and negative cases and look into getting it out of opt-in once we address these. |
Ansible-lint on Galaxy generates a warning "empty-string-compare Don't compare to empty string" The current version ansible-lint 6.14.2 does not generate this warning, but Ansible Galaxy may be using an older version. To avoid this warning, the comparison when: var | trim =='' was changed to when: var | length See issue ansible/ansible-lint#457
Issue Type
Ansible and Ansible Lint details
Desired Behaviour
Using a string comparison to check for a string being empty should be A-OK:
ansible-lint should throw no errors for this code.
Actual Behaviour (Bug report only)
ansible-lint throws the following:
The problem is, if I set it to:
Then I get the error:
So I'm wondering—if we're not supposed to compare to empty strings in a duck-typed language like Python, what are we supposed to do? There are a ton of use cases for comparison to an empty string.
Workarounds
Currently there are two ways to get past this:
Head-in-the-sand:
Add
.ansible-lint
file in your role/playbook.Add the following to skip the rule entirely:
Bypass the rule's regex:
Number 1 is just ignoring the issue. Number 2 is more obtuse and makes for more unreadable code (at least IMO)... but is that preferred if we truly need to check if a string has a value?
The text was updated successfully, but these errors were encountered: