[00:22:55] <dstufft> lifeless: sorry was picking up my dog from the groomer
[00:33:45] <dstufft> trying to figure out the best way for me to review this refactor, this code is fiddly and the (reasonable) indentation change makes it slightly harder, maybe I'll fake a commit locally that reindents it with a no-op loop
[01:49:05] <dstufft> what you're looking at is a recent change which was designed to make it so pip install foo==1.0 didn't hit PyPI if foo 1.0 was already installed
[01:49:39] <dstufft> it sounds like maybe there's still edge cases that we need to work out with that PR
[01:50:59] <lifeless> I think it works because -U implies --force-reinstall essentially
[01:51:22] <lifeless> I was asking because it was an opportunity to converge locate and prepare
[01:51:47] <dstufft> -U doesn't imply --force-reinstall, -U on it's own won't uninstall + install something, it'll see the version we've discovered is already installed and skip it
[01:52:42] <lifeless> I meant the other way around
[01:53:09] <lifeless> and that from a code perspective, a check for -U will always pass where a check for force-reinstall might also be done, pragmatically speaking
[01:53:24] <lifeless> (in terms of assessing whethe rforce-reinstall works for a use case)
[01:53:32] <lifeless> I'm explaining my mental state badly, I'm sure
[01:53:57] <dstufft> ah, --force-reinstall is actually just a no-op if you don't have -U
[01:58:38] <dstufft> the workflow for --no-download was: "first do pip install --no-install ..." which will download the thing, and compile it in a staticly named temporary directory, then copy that temp dir onto your prod machines and do ``pip install --no-download ...`` which will "finish" the install
[01:58:49] <dstufft> it was basically a terrible hack that only exists because we didn't have a binary format
[02:39:18] <sigmavirus24> dstufft: we were having problems where people were using requests in `python setup.py test` what was happening was that our modifications to sys.meta_path were lingering even though the module (requests and the vendored packages) had been gc'd
[02:39:33] <sigmavirus24> That tends to come back as an attribute error though in so much as NoneType not having an attribute "X"
[02:39:52] <sigmavirus24> Not being able to import some module sounds like the fix that I made to both pip and requests which is a bit more complicated to explain
[02:40:37] <sigmavirus24> What was happening was that a deferred import was happening on py2.x and was being executed as an implicit relative import so people were seeing errors as "failed to import requests.packages.chardet.sys"
[02:41:22] <sigmavirus24> That's fixed in both pip and requests in so much as the VendorAlias now properly knows what modules have been vendored (explicitly) and knows how to say "the import you're looking for needs to be provided by something else"
[02:41:24] <lifeless> sigmavirus24: if you want to poke around, I can give you reproduction instructions
[02:41:41] <sigmavirus24> lifeless: sure. I just read far enough back to get a gist of the conversation
[02:41:48] <sigmavirus24> I'm not entirely clear how __builtins__ is failing
[02:42:00] <dstufft> I managed to trick sigmavirus24 into maintaining my horrible import hack code
[02:42:12] <sigmavirus24> dstufft: doesn't take much
[02:42:17] <dstufft> "just put this in requests, it'll be fiiiine"
[02:42:32] <sigmavirus24> one of my coworkers was complaining about something in neutron tonight and I kept itching to pull out my laptop at the bar and look into it
[02:42:51] <sigmavirus24> dstufft: this is why I work so passionately on urllib3 and maintain chardet
[02:43:01] <sigmavirus24> requests depends on it? well someone has to make it work
[02:43:10] <sigmavirus24> not that chardet is good
[02:43:11] <dstufft> sigmavirus24: so all I need is to bundle pip inside of requests
[02:43:32] <lifeless> sigmavirus24: sec, let me make an issue
[02:44:12] <sigmavirus24> lifeless: while we're here, question for you. Does testr always import all of the discoverable test modules even if you specify a specific one?
[02:45:55] <lifeless> sigmavirus24: testr doesn't import anything. "python -m subunit.run discover ... --load-list X" does unit test upstream discovery, and then filters the result down by the list (set intersection)
[02:46:05] <lifeless> sigmavirus24: so yes, if you have many thousands of packages, this can be slow
[21:07:50] <qwcode> lifeless, is there a master plan where you're headed? some feature you're trying to add?
[21:08:28] <lifeless> qwcode: yes, there was a long thread recently on distutils-sig :)
[21:09:00] <qwcode> lifeless, so a setup_requires solution?
[21:10:14] <lifeless> qwcode: I started poking directly at that, but in discussion here with dstufft realised that fixing the awfulness of the code first was a good idea
[21:12:14] <qwcode> lifeless, for the abstraction classes, you said "may grow, or be subsumed into someting else in time".... in your time in working on this feature you mean?
[21:13:22] <qwcode> lifeless, so you're done with those classes right now? just wanted just enough to clear up that routine?
[21:13:52] <lifeless> not yet, the routine is still awful.
[21:14:08] <lifeless> I mean, if you want to move or adjust or whatever we can collaborate together
[21:18:44] <qwcode> everything you're doing looks sharp, just trying to understand if you had master domain model in mind yet. sounds like right now it's more based on what's required to clean up the routine
[21:25:50] <qwcode> lifeless, is this the "pip take over setup_requires" idea... is that the plan?
[21:25:50] <lifeless> we have a awkward thing where we track with unrelated variables the result from finder.find_requirement
[21:26:15] <lifeless> qwcode: thats the patch I want to be able to write, which this work is cleanup to prepare for
[21:27:27] <qwcode> lifeless, got it. that helps. that would be nice. do you expect to have to add a flag to setuptools to *not* double do what pip is taking over, or would it all work it due to setuptools detecting it's already done?
[21:27:55] <lifeless> qwcode: I think we can let setuptools users decide themselves
[21:28:12] <qwcode> lifeless, but pip is running setuptools
[21:28:12] <lifeless> qwcode: for instance, if you are happy with easy_install
[21:28:19] <lifeless> then you put setup_requires in setup.py too.
[21:28:40] <qwcode> lifeless, maybe I'll just wait for the feature... I won't get ahead of myself here...
[21:28:42] <dstufft> I'd have to think about memoizing find_requirements, off top of my head it sounds like a reasonable thing to do with just a lru cache or something
[21:28:43] <lifeless> if you hate the idea of easy_install, you don't, and your setup.py can avoid all the shenanigans needed to work
[21:30:11] <dstufft> I think it's a reasonable thing, I just don't know offhand if we ever expect find_requirement to return a different result, I can't imagine a sitaution where we do though
[21:30:27] <lifeless> we explicitly try to avoid different results ;)
[21:31:36] <lifeless> dstufft: grep for not_found in req_set to see why
[21:31:49] <lifeless> dstufft: so, I propose to move the not_found caching logic into find_requirement fo rnow
[21:32:01] <lifeless> and we can decorator-enable that as a future step when we need it in more than one place
[21:36:53] <qwcode> dstufft, indirectly related, can the PyPI cdn give different results right after uploads... https://github.com/pypa/pip/issues/2408
[21:37:25] <dstufft> qwcode: sure, after the upload happens we trigger a purge
[21:37:34] <dstufft> but fastly is a distributed global object store basically
[21:37:51] <dstufft> the purge doesn't happen in lock step across the entire cluster
[21:38:58] <qwcode> dstufft, I mean back and forth from the old and new on successive installs, until the upload stabilizes across the CDN
[21:39:19] <qwcode> dstufft, the "random" version the guys was seeing in the issue
[21:40:14] <qwcode> "purge doesn't happen in lock step across the entire cluster", ok then that probably explains what he saw, then?
[21:40:38] <dstufft> if it happened immediately after an upload yea
[21:40:47] <dstufft> also it's possible a cache node got stuck
[21:40:59] <dstufft> and was serving an old copy long past the purge
[21:41:10] <qwcode> he apparently uploaded a series of *many* versions... and then saw "random" versions installed
[21:42:00] <qwcode> any way, just remembered that, and wanted to know.... not that it means we shouldn't cache find_requirement results
[21:43:20] <lifeless> [we already do :)] - I'm just moving the cache into find_requirement itself
[21:54:38] <qwcode> ok, I'm slow, why a lru cache beyond the web cache thing we have?
[21:56:25] <qwcode> ok, I'm too slow to understand your answer... : )
[22:03:36] <dstufft> it's just avoiding the expense of recomputing find_requirements
[22:04:10] <dstufft> the HTTP access will be cached (assuming the correct headers) but we still execute a bunch of machinaery that we don't need to (including parsing HTML)
[22:21:14] <lifeless> dstufft: want to pull https://github.com/pypa/pip/pull/2576 across ?
[22:27:16] <qwcode> seems like for pip to take over setup_requires, it will end up having to pass some kind of "--no-setup-requires" to "python setup.py" (assuming it's using setuptools to parse setup_requires)
[22:29:17] <xafer> lifeless, thanks for the nice refactors in req_set.py :)
[22:34:55] <lifeless> qwcode: making existing projects Just Work better is possibly doable in a couple of evil ways
[22:35:21] <lifeless> qwcode: we could compile but not run and attempt a constant fold back from the setup() call in the bytecode.
[22:35:54] <lifeless> qwcode: or we could run it with import knobbled and magic mock objects everywhere and setup stubbed out and use that to figure out the setup_requires
[22:37:04] <lifeless> qwcode: but the basic problem is that executable code has no business installing its own requirements
[22:37:06] <dstufft> I'm still on the fence if the general idea is a good idea for a project to use it, but since it's opt in and when we switch to metabuild system we can just tie it as another legacy quirk of the setuptools builder I don't feel too bad about having the feature
[22:37:09] <qwcode> or add a new command or flag to setuptools, and have pip run setup.py 3 times, instead of just 2... the extra run to get the setup_requires information, but without running the logic to process setup_requires
[22:37:19] <lifeless> qwcode: a new flag won't help.
[22:37:39] <qwcode> a new flag that tells setuptools not to run easy_install....
[22:37:45] <lifeless> qwcode: the canonical example would be this - setuptools is a setup_requires for setuptools.
[22:37:56] <lifeless> qwcode: its implicit, so most folk don't think about it, but it is.
[22:39:38] <dstufft> On the other wise there's always some setup_requires dependency you can't really express
[22:40:23] <lifeless> within the universe of pip installable things
[22:40:34] <lifeless> and excluding circular setup_requires dependencies
[22:40:43] <lifeless> which I really don't want to think about
[22:40:54] <lifeless> qwcode: how will 1) work if setup.py isn't importable
[22:41:12] <dstufft> qwcode: you're thinking similar to what I thought, that's the best way if people want to maintain compatability with easy_install and ``setup.py build`` with a clean environment
[22:41:35] <dstufft> apparently people don't care so much about maintaing compat with those things, but they care a lot that having to defer imports in the setup.py makes it harder to write setup.py's
[22:41:56] <qwcode> dstufft yes, I recall you referring to some "3 time execution plan"... maybe in the thread the other day
[22:41:58] <lifeless> in OpenStack for instance we explicitly don't support 'setup.py develop'
[22:42:43] <dstufft> (realistcally easy_install could read the setup.cfg setup_requires too, in which case you'd only be breaking the case where you want to execute setup.py directly
[22:45:16] <dstufft> in a way it's somewhat of an extension of how I've told people to think about setup.py's for awhile now: setup.py isn't for you to execute, it's for the packaging tools
[22:51:59] <lifeless> so my take here is I think very straight forward: I want pip to be able to figure out what to install without executing any in-tree code. Thats derived from a) don't install /anything/ until all deps are known, b) don't waste a bunch of cycles installing temp environments left right and centre, c) setuptools knows about /building/, pip knows about /installing/
[23:02:59] <qwcode> I agree with a/b/c, at least eventually. also agree that it's mind boggling that setup_requires was a setup arg in the first place. setup.cfg would have made more sense. But just trying to think about existing projects too. maybe do both solutions... something for old and new
[23:05:34] <qwcode> so build_requires no good for this... still a setup.py import issue?
[23:05:49] <dstufft> PEP 426 handles it on the installer side, because it eliminates the need for setup.py all together when you're installing a package (much like wheel does)
[23:06:10] <dstufft> but it doesn't effect pip install -e from a git repo
[23:11:28] <lifeless> anything where egg_info has not yet been output by a build tool
[23:13:14] <dstufft> yea, PEP 426 solves it at a later stage in the "pipeline"
[23:16:45] <lifeless> also as ncoghlan noted, I'm not aiming at ideal here: just *something* thats unambiguously better, which we can hide under an abstraction later if we don't like it. And folk can opt-in.
[23:22:31] <lifeless> dstufft: why is download_dir distinct from wheel_download_dir ?
[23:35:42] <qwcode> lifeless, when doing "pip wheel", wheel deps may be found that should prevent building them... so they get downloaded into the wheelhouse. although I'm not clear atm, why download_dir wasn't reused
[23:55:32] <lifeless> (twice the testing - test the decorator, and test that its used on find_requirements)
[23:56:34] <dstufft> tbh find_requirements should probably return a sentinal value instead of raise exceptions, but that's probably a hard change since I think we use find_requirements all over