Better have a damn good reason to import everything into the package level namespace.

The reasoning sqlalchemy has is to prepare beforehand to be able to run in multiple threads without needing to import anything. Importing is slow and should be done up front.

So there is a slight delay when importing sqlalchemy.

Keep in mind, the sqlalchemy author and maintainers are waaaaaaay smarter than you and I. py315 may level the play field ever so slightly.

py315 is supposed to introduce soft import. So wait for that and then everyone jump ship like every previous version has rabies.

  • source
  • [–] 4 points 7 months ago* (last edited 7 months ago)

    right, those names are also useful when importing your package in tests

    you can also create a __version__ string and append it to __all__ to have a mypackage.__version__

    to pull version from pyproject.toml:

    LIB_NAME: str = "mypackage"
    __version__ = importlib.metadata.version(LIB_NAME)
    
    ...
    
    __all__ = [
        "__version__",
        ...
    ]
    
  • source
  • parent
  • context
  • [–] [S] 3 points 7 months ago (1 child)

    I looked at the guide you linked. So in my __init__.py file, I should import each public name I want from my files, then add them to the __all__ list like this? (I want to make sure I understood the guide correctly)

    from file_1 import SomeClass
    from file_2 import AnotherClass
    
    __all__ = [
        "SomeClass",
        "AnotherClass",
    ]
    
  • source
  • parent
  • context
  • [–] 3 points 7 months ago*

    You’re barking up the right tree. Add a relative import call to your top-level __init__.py and they’ll get namespaced in the way you’re wanting.

    E.g. adding from .file import SomethingInFile as Newthing will let you run import package and reference package.Newthing.

    See the docs for the __all__ dunder as well.

  • source
  • [–] 1 point 7 months ago (7 children)

    i'm in love with typing_extensions. Know why? I'm not on the latest greatest Python version. But want to use the usable latest features. As package author/maintainer, upgrading to the latest and greatest is not a viable option.

    in py39, dataclasses lacked critical features that came out later. Especially for a fundamental structure like a dataclass, new features requiring a Python upgrade is a show stopper. On the level of a flaw. Either backport or in a separate package or i don't want to touch it. That's why use attrs and not dataclasses.dataclass

    And so should we all.

    There is always going to be some great features we want to use and then not being able to is not great UX. Every package that matters really must be external, except for Python features like free threading, sub-interpretors, etc.

    There are always many coding languages, unfortunately jumping from one to the next is a pipe dream. So really doesn't matter what Haskell can do. Or how Rust devs all have 10 gfs.

  • source
  • parent
  • context
  • [–] 1 point 7 months ago (10 children)

    You are describing Sentinel. Recommend using attrs.NOTHING. Unfortunately, the static typing, NothingType, is in private API. Until the Python community can settle on the one Sentinel to rule them all, will stick with attrs cuz it's usually already a dependency.

    You can come by my place anytime for beers and pizza. Bitching about static typing should be an Olympic sport. Or at least involve beer.

  • source
  • parent
  • context
  • [–] 1 point 7 months ago (11 children)

    Not sure what you're getting at about Union but it's not an option type either. Option means a value might be present or absent. Like maybe there's a database column that holds an int, but that column is nullable so it has type Optional[int]. Now you might want to read a row from the db and get that column from it, but that row itself might be absent. That is, the value you return has type Optional[Optional[int]]. But if you get back None, does that mean the row was present and the column was nulled, or that the row was absent?

    With a genuine option type you'd return something like Just None (Haskell notation) for the case where the row is present and the column is nulled. C++, Rust, ML, and so on all have versions of this that work. Python's version is sadly broken.

  • source
  • parent
  • context
  • [–] 1 point 7 months ago* (last edited 7 months ago) (12 children)

    kudos for pointing that out. Another reason to dump Optional.

    Union[None] is not ambiguous

    As coders we have the potential to have lots of coder friends. Union[None] is just the sad reality.

    Optional[None] is sorta keeping our hopes up like there is some distant future where the situation improves. Where all these coder fiends come over every night of the week to bitch about static typing issues and running out of beer and pizza. And when that one guy has to bring up politics; everyone will react like he just let out a massive fart in the room, poisoning the air. Suddenly can feel the IQ in the room dramatically drop. Everyone reacts predicatively, spontaneously, and synchronously in disgust; thinking, dude what a tard! And someone will say, lets do this again tomorrow.

    Fck yeah! This is the place where i want to live.

  • source
  • parent
  • context
  • While we are on da topic, always use string notation! My experience, this was really non-obvious.

    With both cast and typing. With cast, can let builtin types, like str or int, be passed in without the string notation.

    This reduces the typing imports bleeding into your runtime code modules and tests.

  • source
  • [–] 2 points 7 months ago*

    As can surmise from my handle, i'm even stricter!

    Use Union, not | or Optional where ever possible.

    Optional does not allow for future expansion of the typing. Optional[int] and then want to add float, so have to rewrite it Union[int, float, None] So write it with Union to begin with.

    Went thru my | stage like everyone else, but grew out of it.

    TypeAlias insists on Union, not |

    So Union everywhere ftw

    Why? If there is a possibility of making a mistake, Murphy's law dictates that it'll occur every damn time. Enough already! KISS principle is in effect.

  • source
  • [–] 5 points 7 months ago (2 children)

    Yeah, if you initialize them to None then for the entire rest of the class you're going to have to account for the possibility that they're None. If it's unavoidable that they might be None, you should type it as such.

    If you type them as like str | None then later when you do like return foo[0] it will warn you that you can't do that with None.

  • source
  • parent
  • context
  • [–] 2 points 7 months ago (13 children)

    If it can be None then the type is Optional[int] or Optional[str] as the case may be. Or I guess now int | None etc. I'm used to older versions of mypy so idk if they support that alternate syntax.

    Optional[int] would seem to be preferable but it turns out it's not really an option type. Like Optional[None] being None is ambiguous.

  • source
  • view more: β€Ή prev next β€Ί