Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ env
__pycache__/
*.DS_Store
_old

activate_venv\.bat
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Scaffold a Flask Project

To create a new project use:

```sh
$ mkvirtualenv flask_scaffold --python=/usr/bin/python3.X
$ pip install -r requirements.txt
$ python flask_skeleton.py new_project -s skeleton -y 'angular, jquery, bootstrap' -g -v
```

If you use Bowern instead of Yarn use -b instead of -y.

This article details how to build a scaffolding tool used to generate a Flask boilerplate.

Blog post: https://realpython.com/blog/python/scaffold-a-flask-project/
Blog post: [Scaffold a Flask Project](https://realpython.com/blog/python/scaffold-a-flask-project/)
225 changes: 173 additions & 52 deletions flask_skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@
import codecs
import subprocess
import shutil
import platform

if sys.version_info < (3, 0):
from shutilwhich import which
else:
from shutil import which

import platform


# Globals #

Expand All @@ -32,6 +31,7 @@ def get_arguments(argv):
parser.add_argument('appname', help='The application name')
parser.add_argument('-s', '--skeleton', help='The skeleton folder to use.')
parser.add_argument('-b', '--bower', help='Install dependencies via bower')
parser.add_argument('-y', '--yarn', help='Install dependencies via bower')
parser.add_argument('-v', '--virtualenv', action='store_true')
parser.add_argument('-g', '--git', action='store_true')
args = parser.parse_args()
Expand All @@ -43,6 +43,7 @@ def generate_brief(args):
'pyversion': platform.python_version(),
'appname': args.appname,
'bower': args.bower,
'yarn': args.yarn,
'virtualenv': args.virtualenv,
'skeleton': args.skeleton,
'path': os.path.join(cwd, args.appname),
Expand All @@ -52,34 +53,99 @@ def generate_brief(args):
return template.render(template_var)


def main(args):

print("\nScaffolding...")

# Variables #

appname = args.appname
fullpath = os.path.join(cwd, appname)
skeleton_dir = args.skeleton
def git_init(arg, fullpath, name=None, email=None):
if arg:
output = subprocess.Popen(
['git', 'init', fullpath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
error = output.communicate()[1]
if error:
with open('git_error.log', 'w') as fd:
fd.write(error.decode('utf-8'))
print("Error with git init")
sys.exit(2)
if name != '':
output.wait()
output2 = subprocess.Popen(
['git', 'config', '--local', 'user.name', name, fullpath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=fullpath
)
error2 = output2.communicate()[1]
if email != '':
if name != '':
output2.wait()
else:
output.wait()
output3 = subprocess.Popen(
['git', 'config', '--local', 'user.email', email, fullpath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=fullpath
)
error3 = output3.communicate()[1]
if (name != '' and error2) or (email != '' and error3):
with open('git_error.log', 'w') as fd:
fd.write(error.decode('utf-8'))
print("Error with git config")
sys.exit(2)
shutil.copyfile(
os.path.join(script_dir, 'templates', '.gitignore'),
os.path.join(fullpath, '.gitignore')
)

# Tasks #

# Copy files and folders
print("Copying files and folders...")
shutil.copytree(os.path.join(script_dir, skeleton_dir), fullpath)
def install_req(venv_bin, fullpath):
print("Install requirements.txt")
output, error = subprocess.Popen(
[
os.path.join(venv_bin, 'pip'),
'install',
'-r',
os.path.join(fullpath, 'requirements.txt')
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
).communicate()
if error:
with open('pip_error.log', 'w') as fd:
fd.write(error.decode('utf-8'))
sys.exit(2)

# Create config.py
print("Creating the config...")
secret_key = codecs.encode(os.urandom(32), 'hex').decode('utf-8')
template = template_env.get_template('config.jinja2')
template_var = {
'secret_key': secret_key,
}
with open(os.path.join(fullpath, 'project', 'config.py'), 'w') as fd:
fd.write(template.render(template_var))

# Add bower dependencies
if args.bower:
def add_yarn_or_bower(args, fullpath):
if args.yarn:
print("Adding yarn dependencies...")
yarn = args.yarn.split(',')
yarn_exe = which('yarn')
if yarn_exe:
os.chdir(os.path.join(fullpath, 'project', 'client', 'static'))
output, error = subprocess.Popen(
[yarn_exe, 'init', '-y'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=fullpath
).communicate()
if error:
print("An error occurred at init Yarn, please check the "
"package.json file.")
print(error.decode('ascii'))
for dependency in yarn:
output, error = subprocess.Popen(
[yarn_exe, 'add', dependency],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=fullpath
).communicate()
if error:
print("An error occurred with Yarn")
print(error.decode('ascii'))
else:
print("Could not find yarn. Ignoring.")
elif args.bower:
print("Adding bower dependencies...")
bower = args.bower.split(',')
bower_exe = which('bower')
Expand All @@ -97,7 +163,12 @@ def main(args):
else:
print("Could not find bower. Ignoring.")

# Add a virtualenv

def add_virtualenv(args, fullpath, appname):
bin_path = 'bin'
if sys.platform == 'win32':
bin_path = 'Scripts'

virtualenv = args.virtualenv
if virtualenv:
print("Adding a virtualenv...")
Expand All @@ -113,48 +184,98 @@ def main(args):
fd.write(error.decode('utf-8'))
print("An error occurred with virtualenv")
sys.exit(2)
venv_bin = os.path.join(fullpath, 'env/bin')
venv_bin = os.path.join(fullpath, 'env', bin_path)
install_req(venv_bin, fullpath)
elif which('venvs'):
print("Could not find virtualenv executable. Try venv")
_, l_appname = os.path.split(appname)
try:
venv_path = os.path.join(os.environ['USERPROFILE'],
'.virtualenvs', l_appname)
except KeyError:
print(80*"*")
print("Please define variable USERPROFILE.")
print(80*"*")
raise
print("venv_path ", venv_path)
output, error = subprocess.Popen(
[
os.path.join(venv_bin, 'pip'),
'install',
'-r',
os.path.join(fullpath, 'requirements.txt')
],
["python.exe", "-m", "venv", venv_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
).communicate()
if error:
with open('pip_error.log', 'w') as fd:
with open('virtualenv_error.log', 'w') as fd:
fd.write(error.decode('utf-8'))
print("An error occurred with virtualenv")
sys.exit(2)
venv_bin = os.path.join(venv_path, bin_path)

if sys.platform == "win32":
output, error = subprocess.Popen(
["cmd", "/c", "mklink", os.path.join(fullpath,
"activate_venv.bat"),
os.path.join(venv_bin, "activate.bat")],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
).communicate()

if error:
print('Couldn\'t create symbolic link')

install_req(venv_bin, fullpath)
else:
print("Could not find virtualenv executable. Ignoring")
print("Could not find virtualenv executable, Try with "
"virtualenvwrapper or other. Ignoring.")


def main(args):

print("\nScaffolding...")

# Variables #

appname = args.appname
fullpath = os.path.join(cwd, appname)
skeleton_dir = args.skeleton

# Tasks #

# Copy files and folders
print("Copying files and folders...")
try:
shutil.copytree(os.path.join(script_dir, skeleton_dir), fullpath)
except FileExistsError:
shutil.rmtree(fullpath)
shutil.copytree(os.path.join(script_dir, skeleton_dir), fullpath)
except Exception:
print("Unexpected error:", sys.exc_info()[0])
raise
# Create config.py
print("Creating the config...")
secret_key = codecs.encode(os.urandom(32), 'hex').decode('utf-8')
template = template_env.get_template('config.jinja2')
template_var = {
'secret_key': secret_key,
}
with open(os.path.join(fullpath, 'project', 'config.py'), 'w') as fd:
fd.write(template.render(template_var))

# Add bower dependencies
add_yarn_or_bower(args, fullpath)
# Add a virtualenv
add_virtualenv(args, fullpath, appname)
# Git init
if args.git:
print("Initializing Git...")
output, error = subprocess.Popen(
['git', 'init', fullpath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
).communicate()
if error:
with open('git_error.log', 'w') as fd:
fd.write(error.decode('utf-8'))
print("Error with git init")
sys.exit(2)
shutil.copyfile(
os.path.join(script_dir, 'templates', '.gitignore'),
os.path.join(fullpath, '.gitignore')
)
git_init(args.git, fullpath, args.name, args.email)


if __name__ == '__main__':
arguments = get_arguments(sys.argv)
print(generate_brief(arguments))
if sys.version_info < (3, 0):
input = raw_input
if arguments.git:
arguments.name = input("\nGive me your full name: (Enter for None) ")
arguments.email = input("\nGive me your email: (Enter for None) ")
proceed = input("\nProceed (yes/no)? ")
valid = ["yes", "y", "no", "n"]
while True:
Expand Down
64 changes: 64 additions & 0 deletions init_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import os
import sys
import subprocess

python_path = 'C:\\python36\\python.exe'

def install_req(venv_bin, fullpath):
print("Install requirements.txt")
output, error = subprocess.Popen(
[
os.path.join(venv_bin, 'pip'),
'install',
'-r',
os.path.join(fullpath, 'requirements.txt')
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
).communicate()
if error:
with open('pip_error.log', 'w') as fd:
fd.write(error.decode('utf-8'))
sys.exit(2)

def init_venv():

bin_path = 'Scripts' if sys.platform == 'win32' else 'bin'

fullpath = os.getcwd()
_, project_name = os.path.split(fullpath)
venv_path = os.path.join(os.environ['USERPROFILE'], '.virtualenvs', project_name)
print("venv_path ", venv_path)

output, error = subprocess.Popen(
[python_path, "-m", "venv", venv_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
).communicate()

if error:
with open('virtualenv_error.log', 'w') as fd:
fd.write(error.decode('utf-8'))
print("An error occurred with virtualenv")
sys.exit(2)


venv_bin = os.path.join(venv_path, bin_path)

print(os.path.join(venv_bin, "activate.bat"))
if sys.platform == "win32":
output, error = subprocess.Popen(
["cmd", "/c", "mklink", "activate_venv.bat", os.path.join(venv_bin, "activate.bat")],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
).communicate()

if error:
print('Couldn\'t create symbolic link')

install_req(venv_bin, fullpath)


if __name__ == "__main__":
print("Start process")
init_venv()
11 changes: 11 additions & 0 deletions skeleton/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.env
env
venv
__pycache__

*.pyc
*.sqlite
*.coverage
.DS_Store
env.sh
migrations
2 changes: 1 addition & 1 deletion skeleton/.python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.5.2
3.6.0
Loading