Hacker News new | ask | show | jobs
by takeda 1434 days ago
Keep in mind that Python is 31 year old (it's even older than Java) it was created around the same time as world wide web. So it started when no one even knew they would need dependency management and evolved over time from people posting packages on their home pages, to a central website to what we now call PyPI. Similarly the tooling and way of packaging the code evolved.

What you described are multiple tools that also target different areas:

> - poetry

from what you listed this seems like the only tool that actually takes care of dependency management

> - "Just pin the dependencies and use Docker"

this is standard fallback for all languages when people are lazy and don't want to figure out how to handle the dependencies

> - pip freeze

all this does it just lists currently installed packages in a form that can be automatically read by pip

> - Vendoring in dependency code

this again is just a way that applies to all languages, and it is still necessary even if there's a robust dependency management as there are some cases where bundling everything together is preferred

> - pipreqs

this is just a tool that scans your code and tells you what dependencies you are using. You are really lost if you need a tool to tell you what packages is your application is using, but I suppose it can be useful for one offs if you inherit some python code that wasn't using any dependence management.

> - virtualenv

this is just a method to have dependencies installed locally in project directory instead per system. This was created especially for development (although it can be used for deployment as well) as people started working on multiple services with different dependencies. It's now included in python so it's more like a feature of the language.

2 comments

Being 31 years old doesn't preclude having a decent, official and reproducible way of installing packages in 2022. That's just a bad excuse to justify subpar package managers and terrible governance around this problem.

Package management is pretty much a solved problem, no matter how old is your language. It smells to an outsider like me like a lot of bike-shedding and not enough pragmatism is going on in Python land over this issue. Has a new BDFL stepped up after Guido left?

But Python has a decent and a reproducible way of installing packages. The problem python has is that things evolved over time, so you can find on the net plenty of outdated information. There is also a lot of blogs and articles with bad practices, most written by people that got something working.

I think also a lot of issues with packaging is ironically because of PyPA that supposed to work on a standard, but in reality instead of embracing and promoting something that works they just pushes half-assed solutions because author is one of the members. Kind of like they were pushing failed Pipenv "for humans". Seems like Poetry is generally popular and devs are happy with it, so of course PyPA started pushing their own Hatch project, because python packaging was finally getting too straight forward.

I think Python would benefit as a whole if PyPA was just dissolved.

>But Python has a decent and a reproducible way of installing packages.

Reading the comment thread it's not immediately clear what the answer is - it seems implied that the proper way is using Poetry, is that the case?

To me, yes. Poetry for me has been fairly straightforward, in anything I needed to do (dependency management, package publishing, etc).
Poetry has been the one I've settled on as well. It "Just Works™" for everything I've used it for thus far, and it's even been easy to convert older methods I've tried to the Poetry way of doing things.
It's not.

See https://imgs.xkcd.com/comics/python_environment_2x.png

Or sometime the computer is haunted and my colleague had problems installing tensorflow. To this day he has no working tensorflow.

I suppose we can follow memes or facts.

Please note I never used tensorflow on that computer in fact I never used tensorflow, but this is my experience: https://gist.github.com/takeda/89ec29501b6e8641415668f22f3e9...

It succeeded after first try.

I do see that in their repo[1] they use a non standard way to build the package. They use Bazel, but that's Google for you. They never do things everyone else is doing. I'm not sure why this is Python problem rather than package problem.

They have tons of open issues around building: [2]

[1] https://github.com/tensorflow/tensorflow

[2] https://github.com/tensorflow/tensorflow/labels/type%3Abuild...

That's the thing. It's not a meme. It's a joke, that rings true.

It works fine for me.

Not for him. Same package, nearly identical laptops, different outcomes.

And I as newcomer to Python, there are like four (pip, venv, brew, conda) cli APIs that I had to learn just to get working on some Python file.

> I think Python would benefit as a whole if PyPA was just dissolved

STRONG agree. And I hate the cult of personality that was previously (still?) strong.

I think we can get a good package management system for Python if we get rid of PyPA.
Yup. Java is 27 years and has a splendid package management system (Maven Central) which is so well designed that you can use it from two different tools that are extremely different (Maven and Gradle).
No but there’s a walrus operator!

Not sure anyone was asking for that, unlike a fix for packaging issues.

I really like the walrus operator. It's helped me to create more straightforward if/elif blocks and loops. Effective python has some pretty good examples. https://effectivepython.com/2020/02/02/prevent-repetition-wi...
This really isn't a good argument though: it's an extra, extremely specific use case for assignment that looks visually very similar.

And worse, effects code maintainability - if you need that assignment higher up, you're now editing the if statement, adding an assignment, plus whatever your interstitial code is.

Python doesn't have block scoping so the argument for it is weak.

It's not for extremely specific use-case, unless you consider using variables as a condition of an if statement or loop extremely specific.

> And worse, effects code maintainability - if you need that assignment higher up, you're now editing the if statement, adding an assignment, plus whatever your interstitial code is.

How is that different than variables declared without the walrus operator? If you declare a variable with the walrus operator and decide to move its declaration you can still continue to reference that variable in the same spot, just like any other variable. Do you have an example you can share to demonstrate this? I'm not sure I understand what you mean.

> Python doesn't have block scoping so the argument for it is weak.

The walrus operator another way to define variables, not change how they behave. It's just another addition to the "pythonic" way of coding. It's helped me to write more concise and even clearer code. I suggest reading the Effective Python link I provided for some examples of how you can benefit from it.

So by way of example - suppose I have this:

  # some other code
  
  if determined_value := some_function_call():
      do_action(determined_value)
  
and then I change it to this:

  # some other code
  
  determined_value = some_function_call()
  logger.info("Determined value was %s", determined_value)
  validate(determined_value)
  
  if determined_value:
      do_action(determined_value)
  
and determined_value is a reasonably expensive operation (at the very least I would never want to redundantly do it twice) - then in this case my diff for this looks like:

  --- <unnamed>
  +++ <unnamed>
  @@ -1,5 +1,8 @@
  -
   # some other code
   
  -if determined_value := some_function_call():
  +determined_value = some_function_call()
  +logger.info("Determined value was %s", determined_value)
  +validate(determined_value)
  +
  +if determined_value:
       do_action(determined_value)
whereas if I wrote it without walrus originally:

  --- <unnamed>
  +++ <unnamed>
  @@ -1,5 +1,8 @@
   # some other code
   
   determined_value = some_function_call()
  +logger.info("Determined value was %s", determined_value)
  +validate(determined_value)
  +
   if determined_value:
       do_action(determined_value)
  
then the diff is easier to read, and the intent is clearer because diff can simply infer that what's happening is the semantic addition of two lines.

Code is read more then it's written, and changed more then originally created, and making the change case clearer makes sense.

An example where I have wanted this many times before it existed is in something like:

while (n := s.read(buffer)) != 0:

    #do something with first n bytes of buffer
Without the walrus operator you either have to duplicate the read operation before the loop and at the end of the loop, or use while True with a break if n is zero. Both of which are ugly IMO.
It’s really handy in comprehensions to do assignments outside the normal syntax.
I used to think this and rage at the current state of Python dependency management. Then I just buckled down and learned the various tools. It's honestly fine.
> > - pip freeze

> all this does it just lists currently installed packages in a form that can be automatically read by pip

Are you referring to version specifiers[1] being optional or is there something more to versions that I don't understand? PEP 440 is a wall of text, maybe I should get around to reading it sometime.

[1] https://packaging.python.org/en/latest/glossary/#term-Versio...

I mean pip freeze outputs packages and their versions in machine readable form that can be read and installed by pip install -r requirements.txt
This whole chain started with someone pointing out the author doesn't seem to realize you can pin versions[1]. I'm just confused how people seemed to end up questioning what pip freeze does.

[1] https://news.ycombinator.com/item?id=32141573#32142190

Perhaps I was just proving author's point.

I tried to say that from mentioned tools only poetry can be called as a dependency management.

The other tools are used for different purposes, but perhaps could be used as a piece of package management in some way. The mentioned docker and vendoring is irrelevant to Python and it even applies to Go.