Skip to content
Merged
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 numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
*.pyc
*.pyo
*.egg-info
*.log
*.dev.cfg
__pycache__
bin
build
Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,13 +8,13 @@ clean-build:
rm -fr build/
rm -fr dist/
rm -fr *.egg-info

find . -name '*.log' -exec rm -fr{} \;

clean-pyc:
find . -name '*.pyc' -exec rm -f{} +
find . -name '*.pyo' -exec rm -f{} +
find . -name '*~' -exec rm -f{} +
find . -name '__pycache__' -exec rm -fr{} +
find . -name '*.pyc' -exec rm -f{} \;
find . -name '*.pyo' -exec rm -f{} \;
find . -name '*~' -exec rm -f{} \;
find . -name '__pycache__' -exec rm -fr{} \;

docs:
$(MAKE) -C docs html
Expand Down
Empty file addedfeedbundle/app.cfg
Empty file.
104 changes: 104 additions & 0 deletions feedbundle/app.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import os

from flask import Flask, request
from werkzeug import import_string

from feedbundle.corelib.logging import make_file_handler, make_smtp_handler


class FeedBundle(Flask):
"""The web application."""

CONFIG_ENV = "FEEDBUNDLE_CONFIG"
BUILTIN_CONFIG = "app.cfg"

def __init__(self, import_name=__package__, *args, **kwargs):
super(FeedBundle, self).__init__(import_name, *args, **kwargs)

#: load built-in and local configuration
self.config.from_pyfile(self.get_absolute_path(self.BUILTIN_CONFIG))
self.config.from_envvar(self.CONFIG_ENV)
self.config.setdefault("BUILTIN_BLUEPRINTS", [])
self.config.setdefault("BUILTIN_EXTENSIONS", [])
self.config.setdefault("BLUEPRINTS", [])
self.config.setdefault("EXTENSIONS", [])
self.config.setdefault("LOGGING_FILE", None)
self.config.setdefault("LOGGING_EMAILS", [])

#: initialize the application
self.init_extensions()
self.init_logger()
self.init_blueprints()

def init_extensions(self):
"""Initialize the extensions of the application."""
#: make a set to contain names of the extensions
extensions = set(self.config['BUILTIN_EXTENSIONS'])
extensions.update(self.config['EXTENSIONS'])

#: import and install the extensions
for extension_name in extensions:
extension = import_string(extension_name)
extension.init_app(self)

def init_logger(self):
"""Append more handlers to the application logger."""
#: create a file handler and install it
filepath = self.config['LOGGING_FILE']
if filepath:
file_handler = make_file_handler(filepath)
self.logger.addHandler(file_handler)

#: create a email handler and install it
emails = self.config['LOGGING_EMAILS']
smtp_handler_installed = [False]

@self.before_first_request
def register_smtp_handler():
#: defer initialize because of the 'request.host'
if emails and not smtp_handler_installed[0]:
fromaddr = "applog@%s" % request.host
subject = "FeedBundle Application Log"
smtp_handler = make_smtp_handler(fromaddr, emails, subject)
self.logger.addHandler(smtp_handler)
smtp_handler_installed[0] = True

def init_blueprints(self):
"""Register all blueprints to the application."""
#: make a set to contain names of the blueprints
blueprints = set(self.config['BUILTIN_BLUEPRINTS'])
blueprints.update(self.config['BLUEPRINTS'])

#: import and install all blueprints
for blueprint_name in blueprints:
package_name = blueprint_name.replace(":", ".").rsplit(".", 1)
self.register_blueprint_by_name(blueprint_name, package_name)

def register_blueprint_by_name(self, name, package_name):
"""Register the blueprint by its name."""
#: import the blueprint object and its package
blueprint = import_string(name)
package = import_string(package_name)

#: load the all submodules
for module_name in getattr(package, "__all__", []):
import_string("%s.%s" % (package_name, module_name), silent=True)

#: register the blueprint
self.register_blueprint(blueprint)
self.logger.info("Loaded %r" % name)

def get_absolute_path(self, relative_path):
"""Create a absolute path from a relative path.

Example:
>>> app.root_path
'/home/tonyseek/projects/myapp/myapp'
>>> app.get_full_path("../somefile")
'/home/tonyseek/projects/myapp/somefile'
"""
path = os.path.join(self.root_path, relative_path)
return os.path.abspath(path)
Empty file.
42 changes: 42 additions & 0 deletions feedbundle/corelib/logging.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-

from __future__ import absolute_import

import logging
import logging.handlers


def make_multiline_formatter():
"""Create a logging formatter to dump all information."""
formatter = ["-" * 78,
"Name: %(name)s",
"Message type: %(levelname)s",
"Location: %(pathname)s:%(lineno)d",
"Module: %(module)s",
"Function: %(funcName)s",
"Time: %(asctime)s",
"Message:",
"%(message)s",
"-" * 78]
return logging.Formatter("\n".join(formatter))


def make_file_handler(path, formatter_factory=make_multiline_formatter,
level=logging.DEBUG):
"""Create a file handler to record logging information into a file."""
handler = logging.handlers.WatchedFileHandler(path)
handler.setLevel(level)
handler.setFormatter(formatter_factory())
return handler


def make_smtp_handler(fromaddr, toaddrs, host="127.0.0.1",
subject="Application Log",
formatter_factory=make_multiline_formatter,
level=logging.ERROR):
"""Create a STMP handler to send logging information with email."""
handler = logging.handlers.SMTPHandler(host, fromaddr, toaddrs, subject)
handler.setLevel(level)
handler.setFormatter(formatter_factory())
return handler
22 changes: 22 additions & 0 deletions manage.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import os

from flask.ext.script import Manager

from feedbundle.app import FeedBundle


#: be more convenient for developer,
#: automatic to set configuration environment variable.
if os.path.exists("feedbundle.dev.cfg"):
os.environ['FEEDBUNDLE_CONFIG'] = os.path.abspath("feedbundle.dev.cfg")


app = FeedBundle()
manager = Manager(app)


if __name__ == "__main__":
manager.run()