Skip to content
This repository was archived by the owner on Dec 9, 2024. It is now read-only.

Prevent autover from failing when used alongside async frameworks#59

Closed
julioasotodv wants to merge 4 commits into
holoviz-dev:masterfrom
julioasotodv:master
Closed

Prevent autover from failing when used alongside async frameworks#59
julioasotodv wants to merge 4 commits into
holoviz-dev:masterfrom
julioasotodv:master

Conversation

@julioasotodv

@julioasotodv julioasotodv commented Apr 13, 2020

Copy link
Copy Markdown

Basically the same PR as the one I did in param.version: holoviz/param#389

However, according to @ceball autover has tests for that part of param, so we can test it here.

Fixes #62

@ceball

ceball commented Apr 13, 2020

Copy link
Copy Markdown
Contributor

Removed the change just to see if Travis is fooling me

Looks like the travis build of master has been failing since around late 2018 :(

@jbednar

jbednar commented Apr 13, 2020

Copy link
Copy Markdown
Contributor

@jlstevens is looking into it.

@ceball

ceball commented Apr 13, 2020

Copy link
Copy Markdown
Contributor

@jlstevens, looks like the test that's failing (for "depends on autover" tests) fails because of one or more changes to pip over time, meaning something about how the project is set up is no longer correct.

@ceball

ceball commented Apr 14, 2020

Copy link
Copy Markdown
Contributor

Now it's failing at downloading miniconda.

Edit: Hmm. autover is using a very old version of pyctdev, from when it was still called pyct. And pyct(dev) hardcodes the miniconda url. And the miniconda download url has changed from continuum to anaconda.

@ceball

ceball commented Apr 14, 2020

Copy link
Copy Markdown
Contributor

@julioasotodv The existing tests are now fixed, so you could rebase/merge/whatever. Plus a test for your change, if easy. But if you do want to add a test, note that the test framework is a bit tricky, for multiple reasons; if you can suggest a simple test to reproduce the failure you are fixing, I might be able to say how/where to add it.

@julioasotodv

julioasotodv commented Apr 14, 2020

Copy link
Copy Markdown
Author

Hi @ceball I believe tests are still broken, given that this commit: f97d80b

Makes the linter step in Travis complain: https://travis-ci.org/github/pyviz-dev/autover/jobs/674887606

@ceball

ceball commented Apr 14, 2020

Copy link
Copy Markdown
Contributor

Screenshot_20200414-193205

This is showing the "bundled" example/test of autover has not been updated. We check autover works in various installation/usage scenarios, and that's one of them. So looks like you have to make changes twice...

@ceball

ceball commented Apr 14, 2020

Copy link
Copy Markdown
Contributor

Actually, looks like there are two "bundle examples" - so three places to update in total!

I guess the second bundle example is because at some point we discovered a problem with repository name being different from package name, or something like that.

I'm sure we could do better than requiring developers to update three files to get all the tests to pass, but it's a low traffic project...

(Sorry for the giant screenshot - on my phone!)

@julioasotodv

julioasotodv commented Apr 14, 2020

Copy link
Copy Markdown
Author

@ceball no, it’s fine; don’t worry. I’ll try again in a couple of minutes

@julioasotodv

Copy link
Copy Markdown
Author

Finally!

@ceball

ceball commented Apr 14, 2020

Copy link
Copy Markdown
Contributor

Is there a way we can easily test this change, to make sure it does not recur? I.e. how do we trigger the problem in the first place? If you were to paste:

  • a code fragment that triggers the problem
  • how you are using the library that triggers the problem (e.g. you installed a released package using pip? or you installed from a clone of the project's git repository via a pip editable install? or you installed via pip straight from github? or...?)
  • the bad result without the fix applied - an exception, or...?
  • the good result with the fix applied - just getting a __version__ string of "None" or something like that?

then I could probably add it as a test.

It would be great if you could open an issue on this repository with the above info - I've lost track of where the original report was (I'm sure there was one with more detail at some point...)!

Having said all that, I don't think it's necessary, in that I would merge the change here anyway (but @jlstevens will be the one to say what to do).

@julioasotodv

Copy link
Copy Markdown
Author

@ceball I added a new unit test in the PR.

Basically, when autover is used in a Python process created by os.fork() (just like Gunicorn does, for instance), the run_cmd function returned an erroneous exit code when used alongside asyncio. Pretty corner case, but it was driving me crazy...

Comment thread conda.recipe/meta.yaml
source_files:
- tests
commands:
- conda install -y -c conda-forge gunicorn uvicorn starlette

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be possible to declare these dependencies rather than running a command explicitly: https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#test-requirements

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I first thought about that. Unfortunately, apparently the test requirements cannot refer to a library that is not in the same conda channel as the project; and given that uvicorn is not available in the channel, it had no way of satisfying the requirement unless I explicitly conda installed it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha ha, you can't win, sorry. No need to change then.

@jbednar @jlstevens can I change this project to use conda-forge?

Comment thread .travis.yml Outdated
Comment thread tests/test_asgi_server.py

print(autover.__version__)

app = Starlette()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file a "test support file" rather than an actual test? If so, maybe rename it so it's clearly not a file containing tests, and then no need to exclude specially from nose? (Unless there's some reason that's not possible?)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it that way just to make sure that the file got bundled when creating the package (as everything that is named test* inside the tests folder does), but I can just modify setup.py to force the file inclusion there after renaming. I don't know which one is more elegant...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as everything that is named test* inside the tests folder does

Do you happen to know if that is a limitation we have put in somewhere here in autover? I wasn't aware of this as a general thing (in setup tools, tox, etc), and I'm only on my phone just now...

@ceball ceball left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without your fix, the test you added results in an exception? And with the fix, it results in the test passing - but could you add an assertion about what the value of __version__ is when it does pass? (I still don't understand what is being returned by autover for the version in this scenario, although I believe it's something like "None"? That seems wrong to me, but hugely preferable to the current situation, i.e. a crash...)

@ceball

ceball commented Apr 15, 2020

Copy link
Copy Markdown
Contributor

Thanks for all that work! I am impressed you figured out how to modify autover's code, how to contribute to autover plus its tests, and stuck with that process through the delays etc!

Pretty corner case, but it was driving me crazy...

autover in one sentence, ha ha!

But seriously, I believe the work you have done is important. autover causes various problems in real-world environments, and if we don't eliminate them, it's at best just embarrassing for projects like param, panel, holoviews, etc ("You want me to add a package to my production environment that runs git (multiple times!) every time a user imports it? Now why would I want to add a package that does stuff like that?"...).

@julioasotodv

julioasotodv commented Apr 15, 2020

Copy link
Copy Markdown
Author

Without your fix, the test you added results in an exception? And with the fix, it results in the test passing - but could you add an assertion about what the value of __version__ is when it does pass? (I still don't understand what is being returned by autover for the version in this scenario, although I believe it's something like "None"? That seems wrong to me, but hugely preferable to the current situation, i.e. a crash...)

Indeed, the spawned process (for instance by Gunicorn) just chrashes with the following exception (without the fix):

File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/panel/__init__.py", line 5, in <module>
    from . import layout # noqa
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/panel/layout.py", line 21, in <module>
    from .io.model import hold
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/panel/io/__init__.py", line 6, in <module>
    from .embed import embed_state # noqa
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/panel/io/embed.py", line 21, in <module>
    from .model import add_to_doc, diff
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/panel/io/model.py", line 14, in <module>
    from .state import state
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/panel/io/state.py", line 14, in <module>
    from pyviz_comms import CommManager as _CommManager
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/pyviz_comms/__init__.py", line 14, in <module>
    reponame="pyviz_comms"))
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/param/version.py", line 278, in __str__
    known_stale = self._known_stale()
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/param/version.py", line 223, in _known_stale
    commit = self.commit
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/param/version.py", line 133, in commit
    return self.fetch()._commit
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/param/version.py", line 162, in fetch
    self.git_fetch(cmd)
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/param/version.py", line 212, in git_fetch
    self._update_from_vcs(output)
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/param/version.py", line 258, in _update_from_vcs
    self._release = tuple(int(el) for el in dot_split)
  File "/home/julio/anaconda3/envs/bokeh_starlette_server/lib/python3.7/site-packages/param/version.py", line 258, in <genexpr>
    self._release = tuple(int(el) for el in dot_split)
ValueError: invalid literal for int() with base 10: ''

That's why in the tests we record what the spawned process logs, and we ensure its stderr is empty.

@ceball

ceball commented Apr 15, 2020

Copy link
Copy Markdown
Contributor

But what is the value of __version__ going to be now with your fix? (sorry that I don't know this, but I don't know autover's code...)

@ceball

ceball commented Apr 15, 2020

Copy link
Copy Markdown
Contributor

It looks like you print it, but I can't find the test in the travis job logs - at least, not on my phone 😂

@julioasotodv

julioasotodv commented Apr 15, 2020

Copy link
Copy Markdown
Author

But what is the value of __version__ going to be now with your fix? (sorry that I don't know this, but I don't know autover's code...)

So, the issue came back from https://github.com/holoviz/param. Some other holoviz projects (such as HoloViews and Panel) make use of param.version in order to generate the version attribute for those libraries. And it turns out that param.version is an exact copy (AFAIK) of this project.

So basically the issue prevents me from using HoloViews/Panel in a async (asgi) web application, since the version generated attribute for those libraries was generated at runtime, and the runtime crashed.

Since param.version does not have any tests whatsoever, I decided to port the patch here in order to see that it does not break compatibility with the rest of param.version workflow.

As for why my test decides to print version, it is just a way to force its generation. It could very well be:

_ = autover.__version__

@ceball

ceball commented Apr 15, 2020

Copy link
Copy Markdown
Contributor

I'm only asking, what does it end up being set to in this scenario, after your fix? I realize it won't be the correct version, but what is it?

I'd like to put something like this in:

assert autover.__version__ is "None" # TODO this is not the correct version, but we are at least checking it does not crash; see https://github.com/pyviz-dev/autover/issues/62 for details.

I.e. I'm not asking for any more changes to the code, just to record what the situation is in the tests. Does it make sense?

Sorry for not being clear!

@ceball

ceball commented Apr 15, 2020

Copy link
Copy Markdown
Contributor

I now found the new test running on travis (I'm on a computer now :) ), but unfortunately the print is swallowed so I can't see for myself what __version__ is coming back as.

https://travis-ci.org/github/pyviz-dev/autover/jobs/675250008#L243

@julioasotodv

julioasotodv commented Apr 15, 2020

Copy link
Copy Markdown
Author

I'm only asking, what does it end up being set to in this scenario, after your fix? I realize it won't be the correct version, but what is it?

I'd like to put something like this in:

assert autover.__version__ is "None" # TODO this is not the correct version, but we are at least checking it does not crash; see https://github.com/pyviz-dev/autover/issues/62 for details.

I.e. I'm not asking for any more changes to the code, just to record what the situation is in the tests. Does it make sense?

Sorry for not being clear!

No problem, it was just to give you some context.

The problem won't be that autover.version will become None, but rather that the whole Python Process will crash. The assertion in the test checks whether that Python process outputs stuff to its stderr before crashing or not. If there's nothing in that stderr, that means that there is no crash (the goal of the patch).

However, I will try to document the test and test_asgi_server.py to make it clearer

@ceball

ceball commented Apr 15, 2020

Copy link
Copy Markdown
Contributor

Sorry, we are misunderstanding each other here. I am asking you to say what the value of __version__ is after your fix. I.e. now it does not crash (great!!) but presumably the reported version is not correct and is just something weird like "None"? We should record that fact, is what I am getting at.

@ceball

ceball commented Apr 15, 2020

Copy link
Copy Markdown
Contributor

If you also have no idea what it is after your fix, no problem. (I just assumed you would know, because you have been running it.)

@ceball

ceball commented Apr 16, 2020

Copy link
Copy Markdown
Contributor

I got your PR and tried it on my own machine. If I run your test without your version.py code change, the test still passes - which it presumably should not do. I assume that is happening because the test is running in a git repo, and there is actually no trouble getting the version in such a scenario - right? And instead the test needs to mimic what would happen for an installed package? Or am I wrong? (If so, maybe it's down to a difference of platform/software versions?)

Anyway, early on, I asked for a few bits of info:

Is there a way we can easily test this change, to make sure it does not recur? I.e. how do we trigger the problem in the first place? If you were to paste:

  • a code fragment that triggers the problem
  • how you are using the library that triggers the problem (e.g. you installed a released package using pip? or you installed from a clone of the project's git repository via a pip editable install? or you installed via pip straight from github? or...?)
  • the bad result without the fix applied - an exception, or...?
  • the good result with the fix applied - just getting a __version__ string of "None" or something like that?

then I could probably add it as a test.

You have supplied the first one (the code fragment) - thanks!

I still need an answer to the second one (i.e. when do you get the problem? e.g. you pip install panel from pypi, and then when you use panel in your app, you get the crash?).

The third one (what happens without your fix?), I see you previously answered in a comment on your original pyviz_comms issue (thanks!).

The fourth one I can find out for myself if you answer the second one, above.

I can then move your test to the appropriate place, so that it has the right environment to trigger the problem in the first place.

It's also possible that I could convert your test into a simpler case that will work in a unit test, but I don't want to think about that until I can first actually reproduce your problem.

Thanks!

Comment thread tests/testversion.py
with open(logfile_path, "r") as gunicorn_log_file:
stderr_log = gunicorn_log_file.read()

subprocess.Popen(["pkill", "-f", "gunicorn"])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would be better to kill exactly the pid that was created, in case there are other things running. But we might be able to create an entirely simpler test (we'll see once I can reproduce), so let's wait and see.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess you are right. Fortunately, Gunicorn can output the PID that launches, so can be retreived by Python and be killed.

@julioasotodv

julioasotodv commented Apr 16, 2020

Copy link
Copy Markdown
Author

I got your PR and tried it on my own machine. If I run your test without your version.py code change, the test still passes - which it presumably should not do. I assume that is happening because the test is running in a git repo

Exactly. The error happened either:

  1. When the library comes from package without git repo (pip, conda...)
  2. When git is unavailable

You can try it for instance if you temporarily add something like alias git=asdf to your ~/.bashrc, for instance, and then try to run the test.

With that said, when installed as package (with the patch), the __version__ is displayed correctly, as first the git command is issued, and if it fails (gracefully) it tries to get package info.

@jlstevens

jlstevens commented Feb 5, 2021

Copy link
Copy Markdown
Contributor

The changes to version.py look simple and safe to me so I am happy to merge as long as the tests go green. Right now I am seeing an error about uvloop missing so I've opened #67 to try and fix it (I would push to this PR but I don't have access to the fork).

@jlstevens

Copy link
Copy Markdown
Contributor

In #67 the uvloop dependency is no longer complaining but test_run_asgi_server is failing: https://travis-ci.org/github/pyviz-dev/autover/jobs/757680271#L245

@jlstevens

Copy link
Copy Markdown
Contributor

Tests are now passing in #67 after a rebase. @jbednar I am now in favor of merging that and closing this PR.

@jbednar

jbednar commented Feb 15, 2021

Copy link
Copy Markdown
Contributor

Thanks for the PR! The underlying code change has now been merged as PR #67, so closing this version. The tests here haven't been merged, but they should no longer be necessary once we merge #66, since released packages won't be calling subprocess at all at that point.

@jbednar jbednar closed this Feb 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash while getting version when used alongside async frameworks

5 participants