
Structuring Your Project - ai_ja_nai
https://docs.python-guide.org/writing/structure/
======
lutostag
Always one of the good articles to link to when creating a Python repo from
scratch.

Should mention that __init__.py is not needed for python 3.3+ anymore (just
found that out this week myself to my surprise) so for projects where
backwards compatibility is not required you can stop creating extra blank
files if you don't need them.

[https://stackoverflow.com/questions/37139786/is-init-py-
not-...](https://stackoverflow.com/questions/37139786/is-init-py-not-required-
for-packages-in-python-3-3)

~~~
j88439h84
That's really not recommended. A lot of behaviors are subtly affected by
failing to have init files.

~~~
bobbylarrybobby
Like what?

~~~
samdixon
Not op but I have personally noticed that doing a ‘python setup.py install’
doesn’t correctly import modules unless you have an __init__.py file. It’s
possible I could be doing something wrong however.

------
zomglings
When I'm just learning a new programming language or framework, I prefer to
have something like create-react-app [0], django-admin startproject [1], cargo
new [2], or lein new [3].

Guides like these are just full of (the wrong type of) rabbit holes. Just give
new people something that lets them work productively as soon as possible and
refer them to language documentation to understand how features of the
language or the runtime work - in case they want to dig deeper.

Most people will not want to dig deeper, anyway. They will be happier to just
have boilerplate that works and that they can iterate upon.

Look at the golang version of this guide: [https://github.com/golang-
standards/project-layout](https://github.com/golang-standards/project-layout)

How many programmers new to go are going to want to wade through all of that?
Especially when they're probably starting out with projects for which most of
those conventions don't even apply!

It's surprising to me that Python, as focused as its philosophy is on
providing canonical solutions to problems, doesn't have a "python -m
newproject". There must be a good reason. Will try making one in my free time
to find out.

[0] [https://github.com/facebook/create-react-
app](https://github.com/facebook/create-react-app)

[1] [https://docs.djangoproject.com/en/2.2/ref/django-
admin/#star...](https://docs.djangoproject.com/en/2.2/ref/django-
admin/#startproject)

[2] [https://doc.rust-lang.org/cargo/guide/creating-a-new-
project...](https://doc.rust-lang.org/cargo/guide/creating-a-new-project.html)

[3]
[https://github.com/technomancy/leiningen/blob/master/doc/TUT...](https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#creating-
a-project)

~~~
Datenstrom
`poetry new`[0] is what you are looking for, previously I have used
pyscaffold[1] but I like the pyproject.toml from PEP 518[2] better than all
the old stuff. Unfortunately poetry does not set up docs like pyscaffold does
though.

[0]: [https://poetry.eustace.io/](https://poetry.eustace.io/)

[1]: [https://pyscaffold.org/en/latest/](https://pyscaffold.org/en/latest/)

[2]:
[https://www.python.org/dev/peps/pep-0518/](https://www.python.org/dev/peps/pep-0518/)

~~~
ptx
I never tried Poetry because of this somewhat worrying part of installation
instructions: "The installer installs the poetry tool to Poetry's bin
directory ... located at $HOME/.poetry/bin ...This directory will be in your
$PATH environment variable".

The directory _will be_ in my PATH? That makes me wonder what else it might
take the liberty to reconfigure on my system.

But, reading the installer script, it seems like it at least prompts you for
confirmation first, so perhaps I'll try it.

------
trinovantes
This is the kind of documentation I wish every language/framework provided.
Every time I try to learn a new language/framework, I just see code fragments
with no idea how to organize them coherently.

This month I'm working on a side project and learning to use sequelize (a SQL
ORM for node). All the examples [1] just seem to assume my entire project live
in a single file.

[1] [https://sequelize.org/master/manual/models-
definition.html](https://sequelize.org/master/manual/models-definition.html)

~~~
avip
The most frustrating part of learning new tech stack is the implicitly assumed
tribal knowledge.

ex. s.o answers start with _np.yada_ without the _import numpy as np_ part.

------
raziel2p
Most of the advice here seems okay but this stuck out to me:

    
    
        foo += 'ooo'  # This is bad, instead you should do:
        foo = ''.join([foo, 'ooo'])
    

This seems like such a silly micro-optimization. I also have to question its
validity, even in scenarios where you're working with huge strings.

~~~
lifeisstillgood
I would agree with you.

The only reason I can see for the advice is that the first line does not
handle that foo (#) might be other than a string - for example if foo was
[1,2,3] you just got [1,2,3,'ooo']. the second line would barf on that. But if
that was the case it is waaaay more readable to explicitly test for that

so yeah, generally not great advice

(#) Holy moly how many times will autocorrect change foo to too!!! stop it!

------
avip
Nitpick: I'd rather use the _python -m pytest_ way than modify sys.path (AKA
"the django way").

Modifying sys.path is an ugly hack which makes python look like some... idk.
matlab?

~~~
raziel2p
I don't understand what the author has against requiring a pip install -e .

You're requiring contributors to install dependencies anyway.

If you're using pytest (I think the article assumes you're only using the
standard library unittest which I wouldn't personally recommend) there is
pytest-pythonpath which at least makes this invisible to the user.

------
j88439h84
The best answer in 2020 is to use poetry.

[http://poetry.eustace.io](http://poetry.eustace.io)

------
gonational
Whenever I start a new Django / Python project I come up with a short and
generic(ish) internal name, like “pluto” - then, the repo is structured like
this:

    
    
        README.md
        runtime.txt
        requirements.txt
        pluto
          wsgi.py
          manage.py
          urls.py
          - conf
            - common.py
            - prod.py
            - local.py
          - static
          - templates
          - apps
            - accounts
              - models.py
              - etc
            - users
            - etc
    

In a case like this, the repo is named “pluto” in GitHub, but I clone it as
“src”; so, the project locally looks like this:

    
    
        pluto
         \ src
            \ pluto
    

I CD to the root (pluto/src) and work from there.

I also use relative imports from within the “apps” directory:

    
    
        # e.g., inside pluto/apps/accounts/views.py
        from ..users.models import User
    

I’ve used this pattern for years now. It feels so much cleaner than any other
pattern I’ve ever used, and it also makes my projects much more reusable (if I
want to copy my latest project as a skeleton for the next, etc.).

------
bvrmn

      To give the individual tests import context, create a  tests/context.py file:
      import os
      import sys
      sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
    

Or you can convert your tests directory to package by placing __init__.py.
It's pretty amazing that Kenneth Reitz uses this ugly solution.

------
buschkowitz
I find myself coming back to this guide whenever I set up a new project:
[https://sourcery.ai/blog/python-best-
practices/](https://sourcery.ai/blog/python-best-practices/)

~~~
calpaterson
A general ignore_missing_imports=True in mypy.ini is very bad advice. This
will hide lots of real errors. It's surprisingly easy to set up mypy such that
it will silently not check types in many files.

Additionally I can't be the only person who utterly despises pipenv. It is
confusing for most people who don't know python packaging internals,
phenonomially slow for everyone else and besides discourages building proper
distributables (or:wheels).

~~~
greymalik
What do you do instead of pipenv?

~~~
calpaterson
Pipenvs attempts to replace all other tooling to the answer is: all other
tooling. Specifically, setuptools via either setup.py or setup.cfg. pbr,
virtualenvs, tox, pip-tools, pip, etc are all useful. Anything that does not
take 5-10 minutes to recompute dependencies basically!

~~~
buschkowitz
That is a big weakness, I agree. But the mental tax of having to remember how
to use >5 cli tools vs one is definitely pro pipenv for me.

------
cfors
For all the grief Kenneth Reitz gets... gotta give him credit for his emphasis
on usability and professional presentation.

~~~
greymalik
Why does he get grief?

~~~
blattimwind
[https://news.ycombinator.com/item?id=19826680](https://news.ycombinator.com/item?id=19826680)

