diff --git a/.flake8 b/.flake8 index 1c2c768d1f..18c72168cb 100644 --- a/.flake8 +++ b/.flake8 @@ -10,4 +10,8 @@ ignore = E402, # E722 do not use bare except E722, + # flake8 and black disagree about + # W503 line break before binary operator + # E203 whitespace before ':' + W503,E203 doctests = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..facf16e431 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Tests of static file handling assume unix-style line endings. +tornado/test/static/*.txt text eol=lf +tornado/test/static/dir/*.html text eol=lf +tornado/test/templates/*.html text eol=lf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..fdf7784580 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,99 @@ +# The "build" workflow produces wheels (and the sdist) for all python +# versions/platforms. Where possible (i.e. the build is not a cross-compile), +# the test suite is also run for the wheel (this test covers fewer +# configurations than the "test" workflow and tox.ini). +name: Build + +on: + push: + branches: + # Run on release branches. + - "branch[0-9]*" + # Also run on certain other branches for testing. + - "build-workflow*" + tags: + - "v*" + +env: + python-version: '3.9' + +jobs: + build_sdist: + name: Build sdist + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: ${{ env.python-version }} + + - name: Check metadata + run: "python setup.py check" + - name: Build sdist + run: "python setup.py sdist && ls -l dist" + + - uses: actions/upload-artifact@v3 + with: + path: ./dist/tornado-*.tar.gz + + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, windows-2022, macos-12] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: ${{ env.python-version }} + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v2 + with: + platforms: all + + - name: Build wheels + uses: pypa/cibuildwheel@v2.12.1 + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + + upload_pypi_test: + name: Upload to PyPI (test) + needs: [build_wheels, build_sdist] + runs-on: ubuntu-22.04 + if: github.repository == 'tornadoweb/tornado' && github.event_name == 'push' && startsWith(github.ref_name, 'build-workflow') + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@v1.5.0 + with: + user: __token__ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + skip_existing: true + + upload_pypi: + name: Upload to PyPI (prod) + needs: [build_wheels, build_sdist] + runs-on: ubuntu-22.04 + if: github.repository == 'tornadoweb/tornado' && github.event_name == 'push' && github.ref_type == 'tag' && startsWith(github.ref_name, 'v') + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@v1.5.0 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..4064fd6925 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,78 @@ +# The "test" workflow is run on every PR and runs tests across all +# supported python versions and a range of configurations +# specified in tox.ini. Also see the "build" workflow which is only +# run for release branches and covers platforms other than linux-amd64 +# (Platform-specific issues are rare these days so we don't want to +# take that time on every build). + +name: Test + +on: pull_request + +jobs: + # Before starting the full build matrix, run one test configuration + # and the linter (the `black` linter is especially likely to catch + # first-time contributors). + test_quick: + name: Run quick tests + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + name: Install Python + with: + # Lint python version must be synced with tox.ini + python-version: '3.8' + - name: Install tox + run: python -m pip install tox -c requirements.txt + + - name: Run test suite + run: python -m tox -e py38,lint + + test_tox: + name: Run full tests + needs: test_quick + runs-on: ubuntu-22.04 + strategy: + matrix: + include: + - python: '3.8' + tox_env: py38-full + - python: '3.9' + tox_env: py39-full + - python: '3.10' + tox_env: py310-full + - python: '3.10.8' + # Early versions of 3.10 and 3.11 had different deprecation + # warnings in asyncio. Test with them too to make sure everything + # works the same way. + tox_env: py310-full + - python: '3.11' + tox_env: py311-full + - python: '3.11.0' + tox_env: py311-full + # py312 testing is disabled in branch6.3; full support is coming in tornado 6.4 + #- python: '3.12.0-alpha - 3.12' + # tox_env: py312-full + - python: 'pypy-3.8' + # Pypy is a lot slower due to jit warmup costs, so don't run the + # "full" test config there. + tox_env: pypy3 + - python: '3.8' + # Docs python version must be synced with tox.ini + tox_env: docs + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: ${{ matrix.python}} + - name: Install apt packages + run: sudo apt-get update && sudo apt-get install libcurl4-openssl-dev + - name: Install tox + run: python -m pip install tox -c requirements.txt + + - name: Run test suite + run: python -m tox -e ${{ matrix.tox_env }} + diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000000..d9b6cb21ba --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,17 @@ +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.8" + +sphinx: + configuration: docs/conf.py + +formats: + - pdf + - epub + +python: + install: + - requirements: requirements.txt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5b5faa660f..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,89 +0,0 @@ -# https://travis-ci.org/tornadoweb/tornado -dist: trusty - -# Use containers instead of full VMs for faster startup. -sudo: false - -matrix: - fast_finish: true - -language: python -# For a list of available versions, run -# aws s3 ls s3://travis-python-archives/binaries/ubuntu/14.04/x86_64/ -python: - - 2.7 - - pypy2.7-5.8.0 - - 3.4 - - 3.5 - - 3.6 - - nightly - - pypy3.5-5.8.0 - -install: - # On nightly, upgrade setuptools first to work around - # https://github.com/pypa/setuptools/issues/1257 - - if [[ $TRAVIS_PYTHON_VERSION == 'nightly' ]]; then travis_retry pip install -U setuptools; fi - - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then travis_retry pip install mock monotonic; fi - - if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then travis_retry pip install mock; fi - # TODO(bdarnell): pycares tests are currently disabled on travis due to ipv6 issues. - #- if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then travis_retry pip install pycares; fi - - if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then travis_retry pip install pycurl; fi - # Twisted runs on 2.x and 3.3+, but is flaky on pypy. - - if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then travis_retry pip install Twisted; fi - - if [[ $TRAVIS_PYTHON_VERSION == '2.7' || $TRAVIS_PYTHON_VERSION == '3.6' ]]; then travis_retry pip install sphinx sphinx_rtd_theme; fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then travis_retry pip install flake8; fi - # On travis the extension should always be built - - if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then export TORNADO_EXTENSION=1; fi - - travis_retry python setup.py install - - travis_retry pip install codecov virtualenv - # Create a separate no-dependencies virtualenv to make sure all imports - # of optional-dependencies are guarded. - - virtualenv ./nodeps - - ./nodeps/bin/python -VV - - ./nodeps/bin/python setup.py install - - curl-config --version; pip freeze - -script: - # Run the tests once from the source directory to detect issues - # involving relative __file__ paths; see - # https://github.com/tornadoweb/tornado/issues/1780 - - unset TORNADO_EXTENSION && python -m tornado.test - # For all other test variants, get out of the source directory before - # running tests to ensure that we get the installed speedups module - # instead of the source directory which doesn't have it. - - cd maint - # Copy the coveragerc down so coverage.py can find it. - - cp ../.coveragerc . - - if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then export TORNADO_EXTENSION=1; fi - - export TARGET="-m tornado.test.runtests" - # Travis workers are often overloaded and cause our tests to exceed - # the default timeout of 5s. - - export ASYNC_TEST_TIMEOUT=15 - # We use "python -m coverage" instead of the "bin/coverage" script - # so we can pass additional arguments to python. - # coverage needs a function that was removed in python 3.6 so we can't - # run it with nightly cpython. Coverage is very slow on pypy. - - if [[ $TRAVIS_PYTHON_VERSION != nightly && $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then export RUN_COVERAGE=1; fi - - if [[ "$RUN_COVERAGE" == 1 ]]; then export TARGET="-m coverage run $TARGET"; fi - - python $TARGET - - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then python $TARGET --ioloop=tornado.platform.select.SelectIOLoop; fi - - python -O $TARGET - - LANG=C python $TARGET - - LANG=en_US.utf-8 python $TARGET - - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then python -bb $TARGET; fi - - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then python $TARGET --httpclient=tornado.curl_httpclient.CurlAsyncHTTPClient; fi - - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then python $TARGET --ioloop=tornado.platform.twisted.TwistedIOLoop; fi - - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then python $TARGET --resolver=tornado.platform.twisted.TwistedResolver; fi - - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then python $TARGET --ioloop=tornado.ioloop.PollIOLoop --ioloop_time_monotonic; fi - #- if [[ $TRAVIS_PYTHON_VERSION != pypy* ]]; then python $TARGET --resolver=tornado.platform.caresresolver.CaresResolver; fi - - if [[ $TRAVIS_PYTHON_VERSION != 'pypy3' ]]; then ../nodeps/bin/python -m tornado.test.runtests; fi - # make coverage reports for Codecov to find - - if [[ "$RUN_COVERAGE" == 1 ]]; then coverage xml; fi - - export TORNADO_EXTENSION=0 - - if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then cd ../docs && mkdir sphinx-out && sphinx-build -E -n -W -b html . sphinx-out; fi - - if [[ $TRAVIS_PYTHON_VERSION == '2.7' || $TRAVIS_PYTHON_VERSION == 3.6 ]]; then cd ../docs && mkdir sphinx-doctest-out && sphinx-build -E -n -b doctest . sphinx-out; fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then flake8; fi - -after_success: - # call codecov from project root - - if [[ "$RUN_COVERAGE" == 1 ]]; then cd ../ && codecov; fi diff --git a/MANIFEST.in b/MANIFEST.in index 2ef76aefd9..d99e4bb930 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ recursive-include demos *.py *.yaml *.html *.css *.js *.xml *.sql README recursive-include docs * prune docs/build +include tornado/py.typed include tornado/speedups.c include tornado/test/README include tornado/test/csv_translations/fr_FR.csv diff --git a/README.rst b/README.rst index c177ef1291..1c689f5c15 100644 --- a/README.rst +++ b/README.rst @@ -20,8 +20,8 @@ Here is a simple "Hello, world" example web app for Tornado: .. code-block:: python - import tornado.ioloop - import tornado.web + import asyncio + import tornado class MainHandler(tornado.web.RequestHandler): def get(self): @@ -32,10 +32,13 @@ Here is a simple "Hello, world" example web app for Tornado: (r"/", MainHandler), ]) - if __name__ == "__main__": + async def main(): app = make_app() app.listen(8888) - tornado.ioloop.IOLoop.current().start() + await asyncio.Event().wait() + + if __name__ == "__main__": + asyncio.run(main()) This example does not use any of Tornado's asynchronous features; for that see this `simple chat room @@ -45,4 +48,4 @@ Documentation ------------- Documentation and links to additional resources are available at -http://www.tornadoweb.org +https://www.tornadoweb.org diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..5cd35cdfce --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + +## Supported Versions + +In general, due to limited maintainer bandwidth, only the latest version of +Tornado is supported with patch releases. Exceptions may be made depending +on the severity of the bug and the feasibility of backporting a fix to +older releases. + +## Reporting a Vulnerability + +Tornado uses GitHub's security advisory functionality for private vulnerability +reports. To make a private report, use the "Report a vulnerability" button on +https://github.com/tornadoweb/tornado/security/advisories diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 620c338b99..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,76 +0,0 @@ -# Appveyor is Windows CI: https://ci.appveyor.com/project/bdarnell/tornado -environment: - global: - TORNADO_EXTENSION: "1" - - # We only build with 3.5+ because it works out of the box, while other - # versions require lots of machinery. - # - # We produce binary wheels for 32- and 64-bit builds, but because - # the tests are so slow on Windows (6 minutes vs 15 seconds on Linux - # or MacOS), we don't want to test the full matrix. We do full - # tests on a couple of configurations and on the others we limit - # the tests to the websocket module (which, because it exercises the - # C extension module, is most likely to exhibit differences between - # 32- and 64-bits) - matrix: - - PYTHON: "C:\\Python35" - PYTHON_VERSION: "3.5.x" - PYTHON_ARCH: "32" - TOX_ENV: "py35" - TOX_ARGS: "" - - - PYTHON: "C:\\Python35-x64" - PYTHON_VERSION: "3.5.x" - PYTHON_ARCH: "64" - TOX_ENV: "py35" - TOX_ARGS: "tornado.test.websocket_test" - - - PYTHON: "C:\\Python36" - PYTHON_VERSION: "3.6.x" - PYTHON_ARCH: "32" - TOX_ENV: "py36" - TOX_ARGS: "tornado.test.websocket_test" - - - PYTHON: "C:\\Python36-x64" - PYTHON_VERSION: "3.6.x" - PYTHON_ARCH: "64" - TOX_ENV: "py36" - TOX_ARGS: "" - -install: - # Make sure the right python version is first on the PATH. - - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - - # Check that we have the expected version and architecture for Python - - "python --version" - - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - # Upgrade to the latest version of pip to avoid it displaying warnings - # about it being out of date. - - "pip install --disable-pip-version-check --user --upgrade pip" - - - "pip install tox wheel" - -build: false # Not a C# project, build stuff at the test step instead. - -test_script: - # Build the compiled extension and run the project tests. - # This is a bit of a hack that doesn't scale with new python versions, - # but for now it lets us avoid duplication with .travis.yml and tox.ini. - # Running "py3x-full" would be nice but it's failing on installing - # dependencies with no useful logs. - - "tox -e %TOX_ENV% -- %TOX_ARGS%" - -after_test: - # If tests are successful, create binary packages for the project. - - "python setup.py bdist_wheel" - - ps: "ls dist" - -artifacts: - # Archive the generated packages in the ci.appveyor.com build report. - - path: dist\* - -#on_success: -# - TODO: upload the content of dist/*.whl to a public wheelhouse -# diff --git a/demos/README.rst b/demos/README.rst new file mode 100644 index 0000000000..1021254792 --- /dev/null +++ b/demos/README.rst @@ -0,0 +1,40 @@ +Tornado Demo Apps +----------------- + +This directory contains several example apps that illustrate the usage of +various Tornado features. If you're not sure where to start, try the ``chat``, +``blog``, or ``websocket`` demos. + +.. note:: + + These applications require features due to be introduced in Tornado 6.3 + which is not yet released. Unless you are testing the new release, + use the GitHub branch selector to access the ``stable`` branch + (or the ``branchX.y`` branch corresponding to the version of Tornado you + are using) to get a suitable version of the demos. + + TODO: remove this when 6.3 ships. + +Web Applications +~~~~~~~~~~~~~~~~ + +- ``blog``: A simple database-backed blogging platform, including + HTML templates and authentication. +- ``chat``: A chat room demonstrating live updates via long polling. +- ``websocket``: Similar to ``chat`` but with WebSockets instead of + long polling. +- ``helloworld``: The simplest possible Tornado web page. +- ``s3server``: Implements a basic subset of the Amazon S3 API. + +Feature demos +~~~~~~~~~~~~~ + +- ``facebook``: Authentication with the Facebook Graph API. +- ``twitter``: Authentication with the Twitter API. +- ``file_upload``: Client and server support for streaming HTTP request + payloads. +- ``tcpecho``: Using the lower-level ``IOStream`` interfaces for non-HTTP + networking. +- ``webspider``: Concurrent usage of ``AsyncHTTPClient``, using queues and + semaphores. + diff --git a/demos/appengine/README b/demos/appengine/README deleted file mode 100644 index e4aead6701..0000000000 --- a/demos/appengine/README +++ /dev/null @@ -1,48 +0,0 @@ -Running the Tornado AppEngine example -===================================== -This example is designed to run in Google AppEngine, so there are a couple -of steps to get it running. You can download the Google AppEngine Python -development environment at http://code.google.com/appengine/downloads.html. - -1. Link or copy the tornado code directory into this directory: - - ln -s ../../tornado tornado - - AppEngine doesn't use the Python modules installed on this machine. - You need to have the 'tornado' module copied or linked for AppEngine - to find it. - -3. Install and run dev_appserver - - If you don't already have the App Engine SDK, download it from - http://code.google.com/appengine/downloads.html - - To start the tornado demo, run the dev server on this directory: - - dev_appserver.py . - -4. Visit http://localhost:8080/ in your browser - - If you sign in as an administrator, you will be able to create and - edit blog posts. If you sign in as anybody else, you will only see - the existing blog posts. - - -If you want to deploy the blog in production: - -1. Register a new appengine application and put its id in app.yaml - - First register a new application at http://appengine.google.com/. - Then edit app.yaml in this directory and change the "application" - setting from "tornado-appenginge" to your new application id. - -2. Deploy to App Engine - - If you registered an application id, you can now upload your new - Tornado blog by running this command: - - appcfg update . - - After that, visit application_id.appspot.com, where application_id - is the application you registered. - diff --git a/demos/appengine/app.yaml b/demos/appengine/app.yaml deleted file mode 100644 index c90cecdba1..0000000000 --- a/demos/appengine/app.yaml +++ /dev/null @@ -1,12 +0,0 @@ -application: tornado-appengine -version: 2 -runtime: python27 -api_version: 1 -threadsafe: yes - -handlers: -- url: /static/ - static_dir: static - -- url: /.* - script: blog.application diff --git a/demos/appengine/blog.py b/demos/appengine/blog.py deleted file mode 100644 index e2b2ef5042..0000000000 --- a/demos/appengine/blog.py +++ /dev/null @@ -1,166 +0,0 @@ -# -# Copyright 2009 Facebook -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import functools -import os.path -import re -import tornado.escape -import tornado.web -import tornado.wsgi -import unicodedata - -from google.appengine.api import users -from google.appengine.ext import db - - -class Entry(db.Model): - """A single blog entry.""" - author = db.UserProperty() - title = db.StringProperty(required=True) - slug = db.StringProperty(required=True) - body_source = db.TextProperty(required=True) - html = db.TextProperty(required=True) - published = db.DateTimeProperty(auto_now_add=True) - updated = db.DateTimeProperty(auto_now=True) - - -def administrator(method): - """Decorate with this method to restrict to site admins.""" - @functools.wraps(method) - def wrapper(self, *args, **kwargs): - if not self.current_user: - if self.request.method == "GET": - self.redirect(self.get_login_url()) - return - raise tornado.web.HTTPError(403) - elif not self.current_user.administrator: - if self.request.method == "GET": - self.redirect("/") - return - raise tornado.web.HTTPError(403) - else: - return method(self, *args, **kwargs) - return wrapper - - -class BaseHandler(tornado.web.RequestHandler): - """Implements Google Accounts authentication methods.""" - def get_current_user(self): - user = users.get_current_user() - if user: - user.administrator = users.is_current_user_admin() - return user - - def get_login_url(self): - return users.create_login_url(self.request.uri) - - def get_template_namespace(self): - # Let the templates access the users module to generate login URLs - ns = super(BaseHandler, self).get_template_namespace() - ns['users'] = users - return ns - - -class HomeHandler(BaseHandler): - def get(self): - entries = db.Query(Entry).order('-published').fetch(limit=5) - if not entries: - if not self.current_user or self.current_user.administrator: - self.redirect("/compose") - return - self.render("home.html", entries=entries) - - -class EntryHandler(BaseHandler): - def get(self, slug): - entry = db.Query(Entry).filter("slug =", slug).get() - if not entry: - raise tornado.web.HTTPError(404) - self.render("entry.html", entry=entry) - - -class ArchiveHandler(BaseHandler): - def get(self): - entries = db.Query(Entry).order('-published') - self.render("archive.html", entries=entries) - - -class FeedHandler(BaseHandler): - def get(self): - entries = db.Query(Entry).order('-published').fetch(limit=10) - self.set_header("Content-Type", "application/atom+xml") - self.render("feed.xml", entries=entries) - - -class ComposeHandler(BaseHandler): - @administrator - def get(self): - key = self.get_argument("key", None) - entry = Entry.get(key) if key else None - self.render("compose.html", entry=entry) - - @administrator - def post(self): - key = self.get_argument("key", None) - if key: - entry = Entry.get(key) - entry.title = self.get_argument("title") - entry.body_source = self.get_argument("body_source") - entry.html = tornado.escape.linkify( - self.get_argument("body_source")) - else: - title = self.get_argument("title") - slug = unicodedata.normalize("NFKD", title).encode( - "ascii", "ignore") - slug = re.sub(r"[^\w]+", " ", slug) - slug = "-".join(slug.lower().strip().split()) - if not slug: - slug = "entry" - while True: - existing = db.Query(Entry).filter("slug =", slug).get() - if not existing or str(existing.key()) == key: - break - slug += "-2" - entry = Entry( - author=self.current_user, - title=title, - slug=slug, - body_source=self.get_argument("body_source"), - html=tornado.escape.linkify(self.get_argument("body_source")), - ) - entry.put() - self.redirect("/entry/" + entry.slug) - - -class EntryModule(tornado.web.UIModule): - def render(self, entry): - return self.render_string("modules/entry.html", entry=entry) - - -settings = { - "blog_title": u"Tornado Blog", - "template_path": os.path.join(os.path.dirname(__file__), "templates"), - "ui_modules": {"Entry": EntryModule}, - "xsrf_cookies": True, -} -application = tornado.web.Application([ - (r"/", HomeHandler), - (r"/archive", ArchiveHandler), - (r"/feed", FeedHandler), - (r"/entry/([^/]+)", EntryHandler), - (r"/compose", ComposeHandler), -], **settings) - -application = tornado.wsgi.WSGIAdapter(application) diff --git a/demos/appengine/static/blog.css b/demos/appengine/static/blog.css deleted file mode 100644 index 3ebef875e8..0000000000 --- a/demos/appengine/static/blog.css +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2009 Facebook - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -body { - background: white; - color: black; - margin: 15px; - margin-top: 0; -} - -body, -input, -textarea { - font-family: Georgia, serif; - font-size: 12pt; -} - -table { - border-collapse: collapse; - border: 0; -} - -td { - border: 0; - padding: 0; -} - -h1, -h2, -h3, -h4 { - font-family: "Helvetica Nue", Helvetica, Arial, sans-serif; - margin: 0; -} - -h1 { - font-size: 20pt; -} - -pre, -code { - font-family: monospace; - color: #060; -} - -pre { - margin-left: 1em; - padding-left: 1em; - border-left: 1px solid silver; - line-height: 14pt; -} - -a, -a code { - color: #00c; -} - -#body { - max-width: 800px; - margin: auto; -} - -#header { - background-color: #3b5998; - padding: 5px; - padding-left: 10px; - padding-right: 10px; - margin-bottom: 1em; -} - -#header, -#header a { - color: white; -} - -#header h1 a { - text-decoration: none; -} - -#footer, -#content { - margin-left: 10px; - margin-right: 10px; -} - -#footer { - margin-top: 3em; -} - -.entry h1 a { - color: black; - text-decoration: none; -} - -.entry { - margin-bottom: 2em; -} - -.entry .date { - margin-top: 3px; -} - -.entry p { - margin: 0; - margin-bottom: 1em; -} - -.entry .body { - margin-top: 1em; - line-height: 16pt; -} - -.compose td { - vertical-align: middle; - padding-bottom: 5px; -} - -.compose td.field { - padding-right: 10px; -} - -.compose .title, -.compose .submit { - font-family: "Helvetica Nue", Helvetica, Arial, sans-serif; - font-weight: bold; -} - -.compose .title { - font-size: 20pt; -} - -.compose .title, -.compose .body_source { - width: 100%; -} - -.compose .body_source { - height: 500px; - line-height: 16pt; -} diff --git a/demos/appengine/templates/archive.html b/demos/appengine/templates/archive.html deleted file mode 100644 index d501464976..0000000000 --- a/demos/appengine/templates/archive.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - -{% end %} - -{% block body %} -