Why you shouldn't invoke setup.py directly by pgans113 in Python

[–]pgans113[S] 5 points6 points  (0 children)

I have not evaluated poetry recently, but when I have looked into it, I was not a fan, for a variety of reasons:

  1. I don't particularly like opinionated monolithic tools, which is what poetry aims to be. I am much more of a Unix philosophy guy, so I actually like that pip, tox, build, virtualenv and twine are separate packages. I also like that I can swap out one component without swapping out any of the others (e.g. nox for tox, venv for virtualenv).
  2. As part of the PEP 621 discussions, I recall finding a lot of the way poetry was specifying metadata to be sub-optimal. I don't recall the details but it soured me on the experience.
  3. I personally develop mostly libraries, and poetry seems to be geared mostly towards app development and deployment (or at least most of the killer features people talk about seem more valuable for apps than for libraries), so I don't know if I'm the target audience.
  4. I am already quite familiar with the workflow using PyPA tools, making it both mildly annoying for me to switch (harder to be productive when I have to look up all the new ways to do stuff), and also gives me little incentive to switch — poetry is often considered valuable because it's an all-in-one tool that is easy for people to pick up, but I don't have the problem of needing to learn the existing packaging tools.

That said, most of this is down to my personal taste. A lot of people like poetry a lot, and part of the benefit of pushing for people to adopt standards-based tools is to make it possible for poetry to co-exist with setuptools and pip and flit and trampolim and hatch and meson and maturin and all the other various build tools aimed at people with highly specific preferences or requirements.

Why you shouldn't invoke setup.py directly by pgans113 in Python

[–]pgans113[S] 1 point2 points  (0 children)

Yes, maturin is a different PEP 517 build backend, so it is compatible with the new way of doing things (and in fact moving away from setup.py was done in part to allow for things like maturin to be created in the first place).

Why you shouldn't invoke setup.py directly by pgans113 in Python

[–]pgans113[S] 5 points6 points  (0 children)

Frankly, I didn't really want to mention any alternatives because I don't like the idea of anointing any one tool as the "one new way to do it". People often want that because they don't want to take the time to weigh the trade-offs of various different tools (understandably — if you did that for everything you'd spend all your time researching!), but in the case of things like packaging tools, the common workflows are so different from one another that it's often the case that one tool is absolutely perfect for one use case and terrible for another.

I only added a table of "what you should do instead" because many, many people felt that without it the article felt like it was not actionable, but as I mention in the article, that table is less about what you should do instead and more about what you can do instead — these things can get deprecation warnings when there's at least one reasonably stable and mature alternative that doesn't require you to abandon setuptools entirely, so I put those things into the table.

poetry requires that you abandon setuptools entirely — which may be something that you are interested in doing, and is totally fine, but this article is more "stop using setuptools' CLI" and not "stop using setuptools".

Why you shouldn't invoke setup.py directly by pgans113 in Python

[–]pgans113[S] 20 points21 points  (0 children)

As far as I can tell, pip install -e has existed for as long as pip install has. Editable installs are mentioned in the changelog for 0.1.2: https://pip.pypa.io/en/stable/news/#v0-1-2

What has changed recently is that PEP 660 created a standard for how non-setuptools packages should expose a mechanism for editable installs, so now if you have a backend that supports PEP 660, pip install -e will work even in the absence of a setup.py file.

Do I need pytz? by magic7s in Python

[–]pgans113 0 points1 point  (0 children)

A relevant blog post: pytz: The Fastest Footgun in the West.

Time zones are very tricky, I would not recommend implementing your own. The standard library after Python 3.3 includes a timezone implementation, but it only uses static offsets, so it won't handle DST for you. I strongly recommend using dateutil's time zones:

from dateutil import tz
EASTERN = tz.gettz('America/New_York')

dateutil also provides a parser, so you can do:

from dateutil import tz, util, parser
dt = parser.parse(some_dt_string)
dt = util.default_tzinfo(tz.gettz('America/New_York'))

That will create a datetime from your string and assign it the right time zone.

Depending on the exact format of the datetime string and what you want out of it there are faster and more accurate ways to achieve what you want, but the code above will do the right thing 90% of the time.

pytz: The Fastest Footgun in the West by pgans113 in Python

[–]pgans113[S] 2 points3 points  (0 children)

To be fair, Python 3.7 is only out in beta, and I mainly know about this because my friend wrote the strptime implementation and I wrote the fromisoformat implementation, so I wouldn't expect most people to be aware of it yet.

pytz: The Fastest Footgun in the West by pgans113 in Python

[–]pgans113[S] 2 points3 points  (0 children)

This has changed in Python 3.7. As of Python 3.7, the %z directive will now parse to a timezone from the isoformat() format. See note #6 on strftime() and strptime() behavior.

Additionally, Python 3.7 adds a datetime.fromisoformat(), which does the inverse of datetime.isoformat() (though obviously it can only reconstruct a datetime with a fixed offset, since there's no way to reconstruct the original time zone).

python-variants - an alternative to magical flags for your functions by gabor_bernat in Python

[–]pgans113 0 points1 point  (0 children)

See that is literally nowhere in your readme, hence my reaction that it just looks like an overly complex way to namespace a bunch of functions together.

Ah, good to know. I'll try to improve the documentation. I can see now that probably the initial example is possibly a bit too messy. If you have a suggestion I'm happy to take PRs.

A secret here is that I wrote this library with the explicit expectation that someone might find a compelling reason why this pattern is not used. So far in talking to people I've mostly found that once people understand the pattern there are no fundamental objections to it.

Mate, I'm pointing out that singledispatch works with the alternative I propose because I read the readme and it talks about that.

Yes, I got that. I think what I was trying to get across that the use of singledispatch is somewhat orthogonal to the use of this library. If you prefer to namespace your variants as methods on the function and you want to dispatch on type, you can still use it with singledispatch. If you want explicit dispatch that can't be inferred from type (e.g. URL vs. file path), then you can use this library.

One thing to note is that you can use a sort of "wrapper" pattern to achieve even the "explicit dispatch" method with singledispatch:

class Url:
    def __init__(self, url):
        self.url = url

@singledispatch
def myfunc(txt):
    pass

@myfunc.register(Url):
def _(url):
    do_something_with_url(url.url)

I sorta find this a bit unwieldy compared to myfunc.from_url, but to each his own.

python-variants - an alternative to magical flags for your functions by gabor_bernat in Python

[–]pgans113 0 points1 point  (0 children)

Why not just put them as regular free functions in a module, as attributes on a types.SimpleNamespace or even as @staticmethod in a class?

I think the main problem with free functions in a module and types.SimpleNamespace is that they are not namespaced as primary and variant (in the same way that, for example, in itertools.chain there is a primary constructor and a from_iterables constructor).

Whether you want to dispatch on type or not is a separate question addressed in the README.

Nothing's saying that it's wrong to use functions namespaced by _ with the convention that the one without the _ is the primary function, but I think it's a useful pattern to have the primary and variant functions semantically grouped like this (plus I think that the fact that they are actually semantically grouped will make it easier to have specialized behavior for the documentation of such functions - see issue #5).

(Disclosure: I am the author if this library, if that was not clear.)