[16:53:42] <Mathuin> I am looking for 'best practices' on using virtualenv with a Django app via mod_wsgi on Apache. The best I've found is a howto by DigitalOcean. Is there anything better?
[16:59:26] <mgedmin> I see it was updated for https://code.google.com/p/modwsgi/downloads/detail?name=mod_wsgi-pycon-sydney-2011.pdf, but that link is blue in my browser
[16:59:50] <mgedmin> http://blog.dscpl.com.au/2014/12/hosting-python-wsgi-applications-using.html is probably the latest from Graham
[17:00:14] <mgedmin> I saw some people on IRC digging into the Dockerfile to find and look at the apache config bits
[17:00:43] <Mathuin> While it would be nice to go to Docker with this, I'm afraid we're a few months short of that here.
[17:03:05] <mgedmin> hm, it's probably not applicable
[17:05:23] <mgedmin> anyway, the digitalocean tutorial is basically good, afaics
[17:08:42] <Mathuin> The reason I'm asking is because I'm seeing MemoryErrors without supplied exceptions when /usr/lib64/python2.7/ctypes/__init__.py does something with CFUNCTYPE(c_int)(lambda: None) and I didn't expect the process to bother with the root installation.
[17:09:13] <Mathuin> I thought everything would stay under ~/.virtualenvs/pgd-staging when I created the virtualenv using 1.11.6 and the default stetings.
[17:10:47] <mgedmin> that's fine, virtualenv doesn't copy all the stdlib files, it uses symlinks
[17:15:18] <Mathuin> Huh! There's like 25 files symlinked. I figured it wouldn't do that, since it breaks the mental model of isolation -- updating python 2.7 on this machine would change the virtualenv which is counter to expectations.
[17:15:22] <carljm> mgedmin: It copies and modifies a few, symlinks a few more (just the ones necessary to bootstrap site.py), and then the rest are used without copying or symlinking, from their original location, due to site.py modifying sys.path.
[17:15:51] <Mathuin> carljm: so seeing a bunch of /usr/lib64/python2.7 references in PYTHONPATH is nothing to worry about?
[17:16:09] <mgedmin> it's a (not-well-enough) known gotcha with virtualenvs: if you upgrade the system python, expect virtualenvs to break until you update the copy of the python binary in each
[17:16:10] <carljm> Mathuin: Yes, updating the Python installation underlying a virtualenv will effectively update its stdlib, without updating the Python binary in the virtualenv. This has caused problems in the past.
[17:16:43] <carljm> Mathuin: nope, that's normal -- that's how virtualenv works.
[17:16:46] <Mathuin> carljm: I think I'm experiencing one of those problems now. Any suggestions on how best to handle it?
[17:16:46] <mgedmin> the error messages you get in this condition are often very obscure
[17:17:12] <mgedmin> https://github.com/ProgrammersOfVilnius/pov-check-health/blob/master/check-virtualenvs.sh is what I use
[17:17:59] <carljm> mgedmin: Since an in-place-upgrade is usually a bugfix release, often only the stdlib changed and not the binary anyway, so often it works without issue. But sometimes it breaks, and when it does it is usually quite obscure, yeah
[17:18:02] <mgedmin> my script probably won't work for you -- /usr/lib64 is not something I'm familiar with, being an Ubuntu user
[17:18:27] <Mathuin> *nod* I use Ubuntu normally myself, but this is work and this is Gentoo. :-(
[17:18:34] <mgedmin> Mathuin, the breakage is usually about Python being unable to import modules like 'random' or '_base64'
[17:18:46] <mgedmin> I wouldn't expect segfaults in ctypes from _that_
[17:18:47] <Mathuin> Regardless, any of these subtle obscure issues would go away if I nuked the virtualenv and rebuilt it, right?
[17:19:03] <mgedmin> but ctypes is like touching a live wire: it can easily cause segfaults if used with some incorrect assumptions
[17:19:10] <carljm> My solution is to not create virtualenvs with the system Python(s) at all; I compile all my own Pythons in /opt/ under version-specific paths, and never do in-place upgrades
[17:19:52] <mgedmin> yeah, nuking and recreating a virtualenv works, but cp'ing /usr/bin/python2.x over the copy in virtualenv's bin/ is sufficient
[17:20:31] <Mathuin> I nuked and created and am getting problems like this MemoryError or another one -- an ImportError from a relative import line _within_ a package that's in the virtualenv.
[17:20:48] <Mathuin> Stuff works when imported from the shell I start with "python manage.py shell", but fails when I visit the webpage.
[17:21:53] <carljm> Mathuin: The MemoryError seems unlikely to be related to virtualenv (although I suppose it could be related to mod_wsgi -- I find mod_wsgi's process model quite hard to understand)
[17:21:53] <Mathuin> So I'm pulling my hair out. :-)
[17:22:14] <carljm> the relative import error could certainly be related to incorrect path setup for using a virtualenv under mod_wsgi
[17:22:43] <carljm> when you use mod_wsgi with a virtualenv, you aren't using the virtualenv in the normal way (by executing the virtualenv's python binary)
[17:22:44] <mgedmin> Mathuin, add a debugging somewhere: print('\n'.join(sys.path))
[17:22:54] <Mathuin> That's why I came here to ask about best practices. I hoped that if I could at least start from a known good place, I'd be able to move forward.
[17:22:55] <mgedmin> compare python manage.py shell with mod_wsgi's environment
[17:23:09] <carljm> you instead have to manually add the virtualenv's site-packages directory to the front of sys.path
[17:23:17] <Mathuin> carljm: my #! uses the virtualenv's binary, isn't that enough?
[17:23:20] <carljm> and you can't get isolation from system site-packages either
[17:23:27] <Mathuin> Lemme pastebin my WSGI script.
[17:23:34] <mgedmin> mod_wsgi won't let you write to stdout so better use with open('/tmp/wsgipath.txt', 'w') as f: f.write('\n'.join(sys.path))
[17:23:45] <mgedmin> Mathuin, no, #! is not enough
[17:24:01] <carljm> Mathuin: mod_wsgi won't pay any attention to a shebang line in your WSGI script file
[17:24:24] <mgedmin> your wsgi script needs to manipulate sys.path (execfile'ing activate_script.py, like the mod_wsgi wiki suggests) OR you need to add the path to the WSGI directive (like the DigitalOcean tutorial suggests)
[17:24:40] <Mathuin> I reference the binary, I runt he activate_this, I sys.path.insert() like the older docs suggest.
[17:25:31] <mgedmin> can't resist pointing ot that line 4 can be replaced with path = os.path.dirname(path)
[17:25:32] <carljm> Mathuin: you definitely should not sys.path.insert overlapping paths like that
[17:26:01] <carljm> not sure it's related to your problem, but it allows the same modules to be imported twice under different names, which can cause a variety of obscure issues
[17:26:20] <Mathuin> carljm: https://code.google.com/p/modwsgi/wiki/IntegrationWithDjango that is recommended here.
[17:26:58] <carljm> Mathuin: searching for 'insert' on that page yields no results?
[17:27:35] <mgedmin> heh, it uses sys.path.append() with overlapping paths :)
[17:27:39] <carljm> Old versions of Django (pre 1.4) encouraged that, and sometimes projects written for those old Django versions required it (because they were inconsistent with their imports)
[17:27:52] <Mathuin> carljm: please don't hate me, but this app is currently running 1.3.7
[17:28:13] <carljm> heh. Ok then, that's too bad, but you may need those overlapping paths then, unfortunately.
[17:28:27] <Mathuin> We had a GSoC student update it to 1.6 but until the principal investigator validates the science, I can't upgrade Django. :-)
[17:28:42] <mgedmin> anyway, I think the most productive avenue would be to compare sys.path of the mod_wsgi environment with what you get from manage.py
[17:28:51] <carljm> Mathuin: I'm obligated to remind you that 1.3 is no longer receiving security support and you should upgrade ASAP, but I'm sure you know that already :-)
[17:29:40] <Mathuin> carljm: Yep, and I've passed it up the chain, where it collided with some bizarro ad-hoc "change control" issues for the past ... year?
[17:29:55] <Mathuin> Should be better soon, since the blocking individual suddenly discovered changes he wants to make. :-)
[17:30:29] <willingc> carljm: this discussion is great content. is your configuration and process documented on your blog or somewhere else?
[17:31:39] <carljm> mgedmin: They will almost certainly be different (at least the mod_wsgi path will include system site-packages, where the manage.py one won't unless the venv was created with --system-site-packages)
[17:31:52] <carljm> but yes, that comparison would still be a good place to start
[17:32:07] <Mathuin> mgedmin: Would sys.path of the mod_wsgi environment be the same thing as the Python Path reported by Django's debug page?
[17:35:32] <carljm> willingc: Yeah, the upgrade issues with virtualenv definitely deserve to be more widely known.
[17:35:56] <mgedmin> https://pypi.python.org/pypi/virtualenv has a big red "Warning" about those
[17:35:56] <carljm> Especially because it's one of the (few) virtualenv issues that is still a problem with pyvenv in Python 3.3+ as well.
[17:36:35] <mgedmin> it only mentions 'import random' failures, while the error I last encountered was about something else... maybe not _base64, maybe _sha256? can't remember :/
[17:36:44] <willingc> carljm: :) This part "updating the Python installation underlying a virtualenv will effectively update its stdlib, without updating the Python binary in the virtualenv. This has caused problems in the past."
[17:37:09] <willingc> carljm: I'm pretty sure most do not realize that.
[17:37:18] <carljm> mgedmin: Yeah... I wrote the text of that warning :-) Tried to convince python-dev to fix the issue, but they were understandably reluctant to adopt a policy of forwards- and backwards-compatibility between any Python binary and stdlib in the same release series.
[17:38:26] <carljm> That particular fix wouldn't have been hard, but they didn't want to even set the precedent.
[17:39:13] <carljm> willingc: Yeah. I'll put it on my list of blog posts I ought to write :-) Thanks.
[17:39:47] <mgedmin> stale python binaries in old virtualenvs are a potential security vulnerability anyway
[17:40:00] <mgedmin> shame the binary has to be copied and cannot be symlinked :(
[17:40:25] <carljm> actually now that I think about it, pyvenv does solve this issue in many cases
[17:40:39] <carljm> I forgot that we were able to make it symlink the binary by default (I think? need to check)
[17:40:53] <carljm> except on some platforms (cough OS X) where that doesn't work.
[17:41:06] <carljm> and Windows, where symlinks aren't a usable thing.
[17:42:35] <carljm> yep, pyvenv does symlink the binary by default on Linux, so the problem will be solved there once everyone upgrades to Python 3.3+ for everything and drops virtualenv in favor of pyvenv
[17:51:45] <carljm> Mathuin: I note that your path from manage.py doesn't actually have the outer of the two overlapping paths, so you should be able to remove that from your mod_wsgi config
[17:53:04] <Mathuin> carljm: I think it's to catch the settings as 'pgd.settings', so I'm going to leave it in.
[18:11:59] <carljm> Mathuin: FWIW, it is possible to clean up your imports and make them consistent (so they no longer require those overlapping paths) even on Django 1.3. All you have to do is switch to the Django 1.4+ version of manage.py, and make all your imports consistent (either they all need to use the "pgd." prefix, or none of them). More details in the Django 1.4 release notes.
[18:15:13] <Mathuin> carljm: Yeah, I read that, but it's sufficiently fragile that I'll wait to fix it right soon.
[18:30:40] <Mathuin> Created a venv, sourced it, imported ctypes, it imported ctypes from the system python. Is that normal?
[18:33:51] <carljm> Mathuin: When you say "sourced it" you mean "source venv/bin/activate"?
[18:34:13] <carljm> No, that's not normal, unless you're using a very old version of virtualenv, or you created the virtualenv with the --system-site-packages flag
[18:35:27] <carljm> Mathuin: Note, however, that that _is_ normal for using a virtualenv from within mod_wsgi; unlike using a virtualenv from the shell, with activate_this you never get isolation from system python packages.
[18:36:10] <carljm> (Well, it's normal if ctypes isn't installed in the virtualenv. If it is installed in the virtualenv, the virtualenv one _should_ take precedence over the system one, even under mod_wsgi using activate_this)
[18:52:52] <Mathuin> carljm: yes, that's what I mean by sourcing it. sigh.
[18:54:32] <Mathuin> So. Umm. Further research on stackexchange shows these two errors occurring since 2009 with the failure in ctypes itself.
[18:55:13] <Mathuin> Turns out the very end of the file is the problem line, with a comment that makes me wonder who in the world thought it was a good idea.