1- #!/usr/bin/env python
21from __future__ import annotations
32
3+ import os
4+ import pathlib
45import shlex
56import subprocess
67import sys
8+ import venv
79from pathlib import Path
810
911ERROR_MSG = "Error occured while running command"
1012PRETTY_LINES = "*" * 80
13+ PROJECT_NAME = "{{ cookiecutter.project_slug }}"
14+ # TODO: Can allow user to pass it in through cookiecutter.json
15+ VENV_NAME = ".venv"
16+ VIRTUAL_ENV = "VIRTUAL_ENV"
17+
18+ SUBPROCESS_PARAMS = {
19+ "stdout" : subprocess .PIPE ,
20+ "stderr" : subprocess .PIPE ,
21+ "check" : True ,
22+ }
1123
1224
1325def main () -> int :
@@ -19,7 +31,12 @@ def main() -> int:
1931
2032 if return_code_one == 0 :
2133 return_code_two = setup_environment ()
22- return 0 or return_code_one or return_code_two
34+
35+ if return_code_two == 0 :
36+ return_code_three = _rename_pyproject_toml_file ()
37+ print (f"New project { PROJECT_NAME !r} is setup." )
38+
39+ return 0 or return_code_one or return_code_two or return_code_three
2340
2441
2542def initialize_git () -> int :
@@ -30,14 +47,14 @@ def initialize_git() -> int:
3047 ),
3148 "init_git" : (
3249 shlex .split ("git init" ),
33- "Initializing an empty git repository locally. You will have to create a repo "
50+ "Initializing an empty git repository locally. You will have to create a repository "
3451 "on remote.\n " ,
3552 ),
3653 }
3754 for cmds , message in COMMANDS_AND_MESSAGE .values ():
3855 print (message )
3956 try :
40- subprocess .run (cmds , check = True )
57+ subprocess .run (cmds , ** SUBPROCESS_PARAMS )
4158 except subprocess .CalledProcessError as e :
4259 print (ERROR_MSG , e )
4360 return e .returncode
@@ -46,26 +63,87 @@ def initialize_git() -> int:
4663
4764
4865def setup_environment () -> int :
66+ return_code = 0
67+ try :
68+ # Always create a new environment in the project dir
69+ python_venv_path = _create_new_environment ()
70+ system_type , python_executable_path , python_activate_script_path = _get_python_paths (venv_path = python_venv_path )
71+ _activate_environment (system_type , python_activate_script_path )
72+ except Exception :
73+ return_code = - 1
74+ return_code = _install_requirements (python_executable_path )
75+ return 0 or return_code
4976
50- COMMANDS_AND_MESSAGE = {
51- "install_poetry" : (
52- shlex .split ("poetry install" ),
53- f"\n { PRETTY_LINES } \n Installing poetry virtual environment" ,
54- ),
55- "install_pre_commit" : (
56- shlex .split (
57- "poetry run pre-commit install --hook-type pre-commit --hook-type pre-push"
58- ),
59- f"\n { PRETTY_LINES } \n Installing pre-commit hooks" ,
60- ),
61- }
62- for cmds , message in COMMANDS_AND_MESSAGE .values ():
63- print (message )
64- try :
65- subprocess .run (cmds , check = True )
66- except subprocess .CalledProcessError as e :
67- print (ERROR_MSG , e )
68- return e .returncode
77+
78+ def _create_new_environment () -> str :
79+ parent_dir = pathlib .Path (os .getcwd ()).parent .resolve ()
80+ project_name = PROJECT_NAME .strip ()
81+ python_venv_path = str (parent_dir / project_name / VENV_NAME )
82+
83+ print (PRETTY_LINES )
84+ print (f"Attempting to create a new virtual env at { python_venv_path } " )
85+ try :
86+ venv .create (env_dir = python_venv_path , with_pip = True )
87+ except Exception :
88+ print ("An unexpected error has occured" )
89+ raise
90+
91+ print (f"Successfully created virtualenv at: { python_venv_path !r} " )
92+ return python_venv_path
93+
94+
95+ def _get_python_paths (venv_path : str ) -> tuple [str , str , str ]:
96+ sys_type = sys .platform
97+ if sys_type == "win32" :
98+ python_executable_path = pathlib .Path (venv_path , "Scripts" , "python.exe" )
99+ activate_script_path = pathlib .Path (venv_path , "Scripts" , "activate" )
100+ elif sys_type in ("darwin" , "linux" , "linux2" ):
101+ python_executable_path = pathlib .Path (venv_path , "bin" , "python" )
102+ activate_script_path = pathlib .Path (venv_path , "bin" , "activate" )
103+ else :
104+ raise OSError (f"Unsupported platform: { sys_type !r} " )
105+ return sys_type , str (python_executable_path ), str (activate_script_path )
106+
107+
108+ def _activate_environment (system_type : str , activate_script_path : str ) -> None :
109+ if system_type == "win32" :
110+ subprocess .call (["cmd.exe" , "c" , activate_script_path ])
111+ elif system_type in ("darwin" , "linux" , "linux2" ):
112+ subprocess .call (f"source { activate_script_path } " , shell = True )
113+
114+ print ("Successfully activated virtualenv." )
115+ print (f"\n { PRETTY_LINES } " )
116+
117+
118+ def _install_requirements (python_executable_path : str ) -> int :
119+ print ("Installing all dependencies from the requirements.txt file.\n " )
120+ try :
121+ subprocess .run (
122+ [python_executable_path , "-m" , "pip" , "install" , "-r" , "requirements.txt" ],
123+ ** SUBPROCESS_PARAMS ,
124+ )
125+ if "{{ cookiecutter.project_slug }}" :
126+ subprocess .run (
127+ [python_executable_path , "-m" , "pip" , "install" , "-r" , "dev-requirements.txt" ],
128+ ** SUBPROCESS_PARAMS ,
129+ )
130+ except subprocess .CalledProcessError as e :
131+ print (ERROR_MSG , e )
132+ return e .returncode
133+
134+ print (PRETTY_LINES )
135+ return 0
136+
137+
138+ def _rename_pyproject_toml_file () -> int :
139+ try :
140+ os .rename (
141+ "template-pyproject.toml" ,
142+ "pyproject.toml" ,
143+ )
144+ except subprocess .CalledProcessError as e :
145+ print (ERROR_MSG , e )
146+ return e .returncode
69147
70148 return 0
71149
0 commit comments