0

I wrote many scripts to help me manage my django projects. One of them, cr_app.py creates a new app:

#!/usr/bin/env python3

from subprocess import run
def main():
  create_app()
   
def create_app():
  name = input("The name of the app?\n")
  run(f"""python3 manage.py startapp {name}""", shell=True)

if __name__ == "__main__":
  main()

When I am inside of my virtual envirnment's project directory, having activated it with . bin/activate, and, following the tutorial, I run manually python3 manage.py startapp polls then I find models.py already created inside of polls/. But this does not happen, models.py does not get created, when I run cr_app.py and create a new app polls even though I run this script while being in the projects activated virtual environment (although cr_app.py is not, it is located in a different, remote directory). The directory app, polls/ gets created but without models.py inside of it. Activating the environment from within the script with run(f""". bin/activate && python3 manage.py startapp {name}""", shell=True) fixes the issue, and models.py gets created. Why do I have to activate my virtual environment for the second time - i.e. from within a script, after having it already activated?

John Smith
  • 835
  • 1
  • 7
  • 19
  • Are you sure this code snippet runs? – EDG956 Mar 23 '23 at 09:38
  • `subprocess.check_call([sys.executable, 'manage.py', 'startapp', name], shell=True)` – sinoroc Mar 23 '23 at 09:41
  • @EDG956 Yes it runs. I already modified the snippet in response to your comment. It was originally a much larger script and I had to abridge it for the sake of brevity. – John Smith Mar 23 '23 at 09:48
  • @sinoroc Your code leads me to Python's REPL. I have found that replacing the line in question with `run(f""". bin/activate && python3 manage.py startapp {name}""", shell=True)` solves the matter. It seems that I have to activate the environment once again when I execute an external script. – John Smith Mar 23 '23 at 10:00
  • I did not check what `shell=True` does, I just copy-pasted from your question. And as it turns out, it seems to me like it should be `False` (or omitted, since it is false by default). Your newer suggestion `. bin/activate && python3 ...` is a big red flag from my point of view. `sys.executable` (without `shell=True`) is much more reliable and accurate from my point of view. – sinoroc Mar 23 '23 at 10:45
  • Also, a probably easier way of achieving a similar, simplified UX is using shell aliases. i.e: `alias cr_app="python3 manage.py startapp"` (or `alias cr_app="echo 'The name of the app?' && read NAME && python3 manage.py startapp \$NAME"` if you really want to make it interactive). – EDG956 Mar 23 '23 at 11:31
  • @sinoroc Why is `. bin/activate && python3 ...` a red flag? – John Smith Mar 23 '23 at 19:28
  • It is a red flag for me. From my point of view, activating a Python virtual environment makes sense only for interactive shell sessions on the terminal (as opposed to in scripts, programs, etc.). And because it just does not seem right to have this kind of composed (with `&&`) command as a *sub-process*. -- Shell aliases are also a very bad idea as well for this use case. Shell aliases have lots of hidden complexities, I would not trust a shell alias for such a thing, it is a big red flag from my point of view. -- What is wrong with my suggestion? Have you tried it? – sinoroc Mar 23 '23 at 19:35
  • @sinoroc `check_call([executable, 'manage.py', 'startapp', name])` works fine. I wonder whether I could rewrite it with `run()` instead of `check_call()` - as the documentation at `python.org` suggests. – John Smith Mar 23 '23 at 21:03
  • I had in mind that `check_call` was the recommended way, but I can find a reference to this anymore right now. Anyway, yes, seems like it can be slightly re-arranged for `subprocess.run()` instead. Your call. – sinoroc Mar 23 '23 at 21:46

0 Answers0