Skip to content

Commit

Permalink
Merge pull request #7 from jirikuncar/tests-and-improvements
Browse files Browse the repository at this point in the history
File storage tests
  • Loading branch information
klen committed Oct 7, 2014
2 parents 9f080dc + 2ab2c58 commit ecd3e59
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 45 deletions.
4 changes: 4 additions & 0 deletions docs/index.rst
Expand Up @@ -7,6 +7,10 @@ Welcome to Flask-Collect's documentation.

.. == description ==
.. _description:

Flask-Collect
-------------

.. automodule:: flask.ext.collect

.. == badges ==
Expand Down
16 changes: 5 additions & 11 deletions flask_collect/__init__.py
@@ -1,19 +1,13 @@
# -*- coding: utf-8 -*-
"""
Flask-Collect
=============
Flack-Collect is simply application for collect static files in Flask_
project.
Serve static files with Flask_ -- bad idea for production, with this you
will can collect them in one command.
This extension checks application blueprints for static files and copy it
to specific folder (saves related paths).
**Flask-Collect** is an extension for Flask that helps collecting static files.
Serving static files with *Flask* -- bad idea for production, this tool will
help you collect them in one command. It checks application and blueprints for
static files and copy them to specific folder (saves related paths).
"""

from .collect import Collect # noqa
from .collect import Collect # noqa

__author__ = "Kirill Klenov <horneds@gmail.com>"
__license__ = "BSD"
Expand Down
29 changes: 16 additions & 13 deletions flask_collect/collect.py
@@ -1,23 +1,27 @@
# coding: utf-8

"""Define *Flask* extension."""

from flask._compat import string_types
from werkzeug.utils import import_string
from os import path as op


class Collect:
class Collect(object):

"""This class is used for integration to one or more Flask applications.
"""Extension object for integration to one or more Flask applications.
:param app: Flask application
::
.. code-block:: python
app = Flask(__name__)
collect = Collect(app)
The second possibility is to create the object once and configure the
application later to support it::
application later to support it:
.. code-block:: python
collect = Collect()
...
Expand All @@ -26,6 +30,8 @@ class Collect:
"""

def __init__(self, app=None):
"""Initilize the extension object."""
self.app = None
self.static_root = None
self.static_url = None
self.storage = None
Expand All @@ -35,13 +41,11 @@ def __init__(self, app=None):
self.init_app(app)

def init_app(self, app):
"""This callback can be used to initialize an application for the
use with this collect setup.
"""Initialize an application for the use with this collect setup.
See :ref:`configuration`.
:param app: Flask application
"""
if not hasattr(app, 'extensions'):
app.extensions = dict()
Expand All @@ -67,12 +71,13 @@ def init_app(self, app):
self.blueprints = app.blueprints

def init_script(self, manager):
"""This callback can be used to initialize collect scripts with
`Flask-Script`_ manager instance.
"""Initialize collect scripts with `Flask-Script`_ manager instance.
:param manager: `Flask-Script`_ manager
This added manager collect command: ::
This added manager collect command:
.. code-block:: console
$ ./manage.py collect -h
usage: ./manage.py collect [-h] [-v]
Expand All @@ -84,10 +89,9 @@ def init_script(self, manager):
-v, --verbose
.. _Flask-Script: http://packages.python.org/Flask-Script/
"""
def collect(verbose=True):
""" Collect static from blueprints. """
"""Collect static from blueprints."""
return self.collect(verbose=verbose)

manager.command(collect)
Expand All @@ -96,7 +100,6 @@ def collect(self, verbose=False):
"""Collect static files from blueprints.
:param verbose: Show debug information.
"""
mod = import_string(self.storage)
cls = getattr(mod, 'Storage')
Expand Down
11 changes: 11 additions & 0 deletions flask_collect/storage/__init__.py
@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
#
# This file is part of Flask-Collect.
# Copyright (C) 2012 Kirill Klenov.
# Copyright (C) 2014 CERN.
#
# Flask-Collect is free software; you can redistribute it and/or modify it
# under the terms of the Revised BSD License; see LICENSE file for
# more details.

"""File storage definitions."""
31 changes: 22 additions & 9 deletions flask_collect/storage/base.py
@@ -1,22 +1,33 @@
""" Abstract Storage. """
# -*- coding: utf-8 -*-
#
# This file is part of Flask-Collect.
# Copyright (C) 2012, 2013 Kirill Klenov.
# Copyright (C) 2014 CERN.
#
# Flask-Collect is free software; you can redistribute it and/or modify it
# under the terms of the Revised BSD License; see LICENSE file for
# more details.

"""Abstract File Storage."""

from __future__ import print_function

from os import path as op, walk


class BaseStorage():
class BaseStorage(object):

""" Base class for storages. """
"""Base class for storages."""

def __init__(self, collect, verbose=False):
"""Initialize base storage."""
self.verbose = verbose
self.collect = collect

def __iter__(self):
""" Seek static files and result full and relative paths.
"""Seek static files and result full and relative paths.
:return generator: Walk files
"""
app_and_blueprints = self.collect.filter(
[self.collect.app] + list(self.collect.blueprints.values()))
Expand All @@ -26,16 +37,18 @@ def __iter__(self):
for f in files:
fpath = op.join(root, f)
opath = op.relpath(fpath, bp.static_folder.rstrip('/'))
if bp.static_url_path and self.collect.static_url and \
bp.static_url_path.startswith(
op.join(self.collect.static_url, '')): # noqa
relative = (bp.static_url_path and
self.collect.static_url and
bp.static_url_path.startswith(op.join(
self.collect.static_url, ''))) # noqa
if relative:
opath = op.join(
op.relpath(
bp.static_url_path,
self.collect.static_url), opath)
yield bp, fpath, opath

def log(self, msg):
""" Log message. """
"""Log message."""
if self.verbose:
print(msg)
24 changes: 21 additions & 3 deletions flask_collect/storage/file.py
@@ -1,3 +1,15 @@
# -*- coding: utf-8 -*-
#
# This file is part of Flask-Collect.
# Copyright (C) 2012, 2014 Kirill Klenov.
# Copyright (C) 2014 CERN.
#
# Flask-Collect is free software; you can redistribute it and/or modify it
# under the terms of the Revised BSD License; see LICENSE file for
# more details.

"""Copy files from all static folders to root folder."""

from os import path as op, makedirs
from shutil import copy

Expand All @@ -6,7 +18,10 @@

class Storage(BaseStorage):

"""Storage that copies static files."""

def run(self):
"""Collect static files from blueprints."""
self.log("Collect static from blueprints.")
destination_list = set()
for bp, f, o in self:
Expand All @@ -16,8 +31,11 @@ def run(self):
makedirs(destination_dir)
if destination in destination_list:
self.log("{0} already copied".format(destination))
if not op.exists(destination) or op.getmtime(destination) < op.getmtime(f):
elif not op.exists(destination) or \
op.getmtime(destination) < op.getmtime(f):
copy(f, destination)
self.log(
"Copied: [%s] '%s'" % (bp.name, op.join(self.collect.static_url, destination)))
destination_list.add(destination)
"Copied: [%s] '%s'" % (
bp.name,
op.join(self.collect.static_url, destination)))
destination_list.add(destination)
7 changes: 6 additions & 1 deletion flask_collect/storage/link.py
Expand Up @@ -29,18 +29,23 @@ def run(self):
"""
self.log("Collect static from blueprints")
skipped, total = 0, 0
destination_list = set()
for bp, f, o in self:
destination = os.path.join(self.collect.static_root, o)
destination_dir = os.path.dirname(destination)
if not os.path.exists(destination_dir):
os.makedirs(destination_dir)

if not os.path.exists(destination):
if destination in destination_list:
self.log("{0} already linked".format(destination))
skipped += 1
elif not os.path.exists(destination):
# the path is a link, but points to invalid location
if os.path.islink(destination):
os.remove(destination)
os.symlink(f, destination)
self.log("{0}:{1} symbolink link created".format(bp.name, o))
destination_list.add(destination)
else:
skipped += 1
total += 1
Expand Down
15 changes: 15 additions & 0 deletions flask_collect/storage/test.py
@@ -1,7 +1,22 @@
# -*- coding: utf-8 -*-
#
# This file is part of Flask-Collect.
# Copyright (C) 2012, 2013 Kirill Klenov.
# Copyright (C) 2014 CERN.
#
# Flask-Collect is free software; you can redistribute it and/or modify it
# under the terms of the Revised BSD License; see LICENSE file for
# more details.

"""List files from all static folders."""

from .base import BaseStorage


class Storage(BaseStorage):

"""Dummy storage engine."""

def run(self):
"""List all file paths."""
return [f for f in self]

0 comments on commit ecd3e59

Please sign in to comment.