PMXBOT Log file Viewer

Help | Karma | Search:

#pypa-dev logs for Friday the 10th of January, 2020

(Back to #pypa-dev overview) (Back to channel listing) (Animate logs)
[01:04:01] <toad_polo> I don't know where the office is, I've never been to Plattsburgh.
[01:17:29] <techalchemy> lol
[01:20:07] <techalchemy> it's an old nabisco factory which is now a google office and a bunch of shops + bar at least last I saw
[01:24:09] <TemptorSent> techalchemy: Can you think of any easy way of stripping off the trailing specifier from a Version?
[01:24:24] <techalchemy> TemptorSent, the trailing specifier?
[01:24:32] <techalchemy> can you provide an example?
[01:25:39] <TemptorSent> techalchemy: given 1.2.3, return 1.2 more fun, given 1.2.3dev6, return 1.2.3
[01:26:45] <TemptorSent> So returning the Version with the least-significant non-null specifier nulled
[01:36:32] <techalchemy> TemptorSent, i'm not sure the goal i guess, you just want to chop off a digit?
[01:37:55] <TemptorSent> techalchemy: Digit, dev/pre/post/local specifier, whatever is the least significant specified element of the Version
[01:38:58] <techalchemy> what makes something not significant though? why is it sometimes ok to leave a patch release and sometimes not?
[01:39:16] <techalchemy> i'm just not understanding the use case
[01:39:25] <TemptorSent> techalchemy: Because I'm trying to build intervals from Specifiers :)
[01:40:33] <TemptorSent> Given something like ~=X.Y, this means I need to do >=X.Y, <=X for the interval it matches over.
[01:40:40] <techalchemy> i feel like the level of granularity required to build specifiers that span 1.2.3.dev0-1.2.3.dev6 is causing me to question what purpose it serves
[01:41:33] <TemptorSent> I'm not trying to build anything that doesn't exist, I'm just trying to compare them in a mathematically valid manner.
[01:41:49] <techalchemy> i get the theory behind comparing things etc etc
[01:42:14] <techalchemy> i'm just asking like, what problem is this solving
[01:42:33] <TemptorSent> The way the comparison works, the cmpkey looks like it will give me the right values, I just need to give it the right versions.
[01:42:46] <techalchemy> the nature of comparisons ^
[01:43:12] <TemptorSent> Problem is I can't easily modify Version
[01:43:17] <TemptorSent> or _Version for that matter
[01:43:29] <TemptorSent> The values get baked in in __init__
[01:43:55] <TemptorSent> So I need to get back the same version less the least significant element.
[01:49:55] <techalchemy> TemptorSent:https://bpaste.net/RAKQ
[01:50:51] <techalchemy> similarly v._version = v._version._replace(dev=None) => <Version('1.2.3')>
[01:51:46] <techalchemy> note that you may need to reset v._key after
[01:52:09] <techalchemy> the easier method is to just call str() on the result and make a new one
[01:53:30] <techalchemy> TemptorSent, https://bpaste.net/JCIQ is likely the easiest approach for you
[01:55:03] <TemptorSent> techalchemy: Okay, still need to figure out the correct logic for the ordering of significant entries, but that should help.
[01:57:08] <TemptorSent> Thanks.
[01:57:44] <techalchemy> priority is epoch => postrelease>release>pre>dev>local
[01:58:54] <techalchemy> 1.2.3.post1 > 1.2.3 > 1.2.3.rc1 > 1.2.3.b1 > 1.2.3.a1 > 1.2.3.dev1 > 1.2.3.local1
[02:00:38] <techalchemy> er sorry local versions are designated with a +
[02:00:57] <techalchemy> 1.2.3+local1 e.g. 1.2.3+ubuntu1
[02:02:44] <techalchemy> TemptorSent, https://www.python.org/dev/peps/pep-0440/ should have anything else i missed
[02:06:28] <TemptorSent> techalchemy: Yeah, I was looking at how dev interacts with post/pre
[02:08:25] <TemptorSent> Hmm, are post and pre ever validly populated at the same time?
[02:09:37] <TemptorSent> Like would 1.2.3.post1.a1 be a valid version?
[02:13:38] <techalchemy> TemptorSent, it is technically valid -- and you might want to cut a prerelease before you actually push your postrelease
[02:13:45] <techalchemy> it's not very common
[02:16:34] <TemptorSent> Okay, so epoch,release,post,pre,dev,local is the order of significance then?
[02:17:31] <TemptorSent> Run through those in reverse, find the first that's not None and make it None
[02:18:47] <techalchemy> i mean if you want to make ranges of versions for each package that exists
[02:18:52] <techalchemy> not too sure what that does for you
[02:19:47] <techalchemy> typically things work in the other direction, where a package has a dependency on another package, and at that point you look for a valid matching version
[02:19:51] <TemptorSent> I'm just comparing the version ranges found in metadata with the version ranges requested
[02:21:07] <techalchemy> so far i know that you are trying to support or mirror some legacy packages and I also know you are trying to compare version ranges against other version ranges, but I don't see how those two things relate
[02:21:10] <TemptorSent> But first, I need to make the SpecifierSets into proper ranges (intervals)
[02:24:48] <TemptorSent> Say a packages has "python_version: >=2.7, <3.8, !=3.5.*" in the metadata for some package, and we want to select all packages which have a python_version compatible with <3.5, >=2.7, and place the resulting SpeciferSet, if valid, into the store metadata
[02:25:35] <techalchemy> python version is a bad example though, because it represents a finite, known set of actual versions
[02:26:19] <TemptorSent> techalchemy: True, that happens to be my first application, but it is intended to generalize to other dep requirements
[02:26:22] <techalchemy> the solution to that specific problem is to store all of the actual python versions and check which ones are in the specifierset
[02:26:38] <techalchemy> the problem really only applies to python versions though
[02:27:22] <techalchemy> although in the alternate case you again have a finite, known set of possible versions (available on pypi) and you can just check which ones are members of the specifierset
[02:27:51] <techalchemy> i would recommend caching the available versions so you don't have to query each time
[02:28:31] <TemptorSent> techalchemy: Again, my goal was to generalize the solution into something useful for SpecifierSets in general.
[02:29:25] <TemptorSent> It seems like it would be a fairly common operation to want to use.
[02:30:57] <techalchemy> i've only ever run into the specifier overlap issue when merging specifiersets that were talking about the same referent, like if one clause said "python_version >= 2.7 and python_version not in '3.0, 3.1, 3.2, 3.3'" and another clause said "python_version >= 2.7 and python_version < 3.9 and python_version != '3.0.*' and python_version != '3.1.*'" -- e.g. if you are resolving dependencies and two parents have the
[02:30:58] <techalchemy> same
[02:30:58] <techalchemy> dependency but the parents have different python version specifiers, etc
[02:32:36] <techalchemy> so when reducing candidates it's super necessary, and your approach makes sense, but python doesn't even natively have a dependency solver so it's not really a problem
[02:32:44] <TemptorSent> techalchemy: Right, then you have an actual version to compare to and you're not trying to look at the specifiers themselves.
[02:33:00] <techalchemy> what i'm describing are specifier sets
[02:34:00] <TemptorSent> Right, but you can __and__ the specifier sets and then do .contains(myversion) sanely.
[02:34:11] <TemptorSent> You don't actually have to do the reduction to do the check.
[02:34:39] <techalchemy> but i'm not trying to check, i'm trying to merge without duplication and without repetition
[02:36:23] <TemptorSent> Okay, so you are taking the intersection of the valid versions...
[02:38:31] <techalchemy> lol
[02:41:02] <techalchemy> TemptorSent, I'm actually usually doing a union and then creating a range
[02:42:44] <techalchemy> anyhow, good luck
[02:48:17] <TemptorSent> How do you deal with != and ==X.Y.* forms when creating the ranges?
[19:31:47] <sangy> TemptorSent: not sure how that's being done right now, but it sounds like an job for filter() no? :)
[19:31:55] <sangy> s/an/a/
[19:33:16] <TemptorSent> sangy: Got an example?
[19:34:44] <sangy> not one handy, I'm sorry
[19:35:44] <TemptorSent> sangy: filter appears to filter over versions, I don't see any way to shove a specifier in there cleanly.
[19:40:38] <sangy> my understanding is that you could easily define a lambda that achieves != and ==X.Y.* and pass that to filter. I could also be missing a lot of context and I apologize if that's the case
[19:44:49] <TemptorSent> sangy: The short of it is I'm trying to intersect the (possibly discontinuous due to !=) intervals (range + discontinuities) of two SpecifierSets and yield a minimal specifier set representing that intersection.
[19:45:40] <sangy> oh, and you still have it in a compact form (i.e., not all the actual candidates but just the ranges themselves)
[19:45:51] <TemptorSent> Correct.
[19:47:21] <sangy> right, hmmm..
[19:47:55] <techalchemy> TemptorSent, outside of python versions I never care about actually generating a bunch of numbers because it is always possible to look at the actual list of candidates
[19:48:00] <TemptorSent> Unfortunately, there aren't any comparison functions between Specifiers that are semantically useful.
[19:48:26] <techalchemy> TemptorSent, because it is hard* to write them
[19:48:37] <sangy> TemptorSent: I wonder if one way forward could be to "canonicalize" all the specifier to ranges and go with that
[19:49:27] <TemptorSent> sangy: Essentially a union and evaluation process would get at the same thing.
[19:50:21] <techalchemy> specifiersets can have arbitrary amounts of specifiers in them and can do all sorts of confusing things that would make it difficult to put any simple comparisons on them, if you have two specifiersets they have to be unioned
[19:50:55] <TemptorSent> the corner cases are the only really irritating problem, like !=X.Y intersec >=X.Y needs to give >X.Y, for instance.
[19:51:48] <TemptorSent> You can boil it down to a maxbound, minbound, and exceptions list
[19:52:12] <techalchemy> yeah but that only matters if you plan on actually generating a list of actual numbers that can be the answer, all you really need to do is write a function that can express the min max and execptions and evaluate each candidate
[19:52:51] <TemptorSent> techalchemy: It give back the specifiers directly.
[19:53:13] <techalchemy> what gives back specifiers?
[19:53:29] <TemptorSent> the instersection operation.
[19:53:46] <techalchemy> right specifiersets are made of specifiers
[19:58:37] <TemptorSent> ...anyway, if anyone has a short, clean example of simplifying a union of SpecifierSets to the minimum specifiers, I'd appreciate it.
[19:59:33] <TemptorSent> I have working code for 'normal' cases as it is, it's a clean way of handling the corner cases that I lack.
[20:00:22] <techalchemy> i don't bother removing the != in the case you're describing
[20:01:45] <TemptorSent> Oh, okay.
[20:02:01] <TemptorSent> Do you check if they invalidate the set?
[20:03:40] <TemptorSent> Something like >3.4,<3.6,!=3.5
[20:04:12] <TemptorSent> Those are the cases I'm having trouble with.
[20:05:52] <TemptorSent> It should return empty, but the logic to do so cleanly escapes me.
[20:06:22] <TemptorSent> Version has no notion of "next higher" or "next lower" that would allow such comparisons.
[20:07:40] <TemptorSent> In fact, that facility alone would make both intersections and comparisons much easier.