diff --git a/docs/tutorial/css.rst b/docs/tutorial/css.rst index 3f0e932a..ea461a89 100644 --- a/docs/tutorial/css.rst +++ b/docs/tutorial/css.rst @@ -1,11 +1,11 @@ .. _tutorial-css: -Step 7: Adding Style +Step 9: Adding Style ==================== Now that everything else works, it's time to add some style to the application. Just create a stylesheet called :file:`style.css` in the -:file:`static` folder we created before: +:file:`static` folder: .. sourcecode:: css diff --git a/docs/tutorial/dbcon.rst b/docs/tutorial/dbcon.rst index 4b5b0915..9f4428b9 100644 --- a/docs/tutorial/dbcon.rst +++ b/docs/tutorial/dbcon.rst @@ -1,25 +1,23 @@ .. _tutorial-dbcon: -Step 3: Database Connections +Step 4: Database Connections ---------------------------- -We have created a function for establishing a database connection with -`connect_db`, but by itself, that's not particularly useful. Creating and -closing database connections all the time is very inefficient, so we want -to keep it around for longer. Because database connections encapsulate a -transaction, we also need to make sure that only one request at the time -uses the connection. How can we elegantly do that with Flask? +You now have a function for establishing a database connection with +`connect_db`, but by itself, it is not particularly useful. Creating and +closing database connections all the time is very inefficient, so you will +need to keep it around for longer. Because database connections +encapsulate a transaction, you will need to make sure that only one +request at a time uses the connection. An elegant way to do this is by +utilizing the *application context*. -This is where the application context comes into play, so let's start -there. - -Flask provides us with two contexts: the application context and the -request context. For the time being, all you have to know is that there +Flask provides two contexts: the *application context* and the +*request context*. For the time being, all you have to know is that there are special variables that use these. For instance, the :data:`~flask.request` variable is the request object associated with the current request, whereas :data:`~flask.g` is a general purpose -variable associated with the current application context. We will go into -the details of this a bit later. +variable associated with the current application context. The tutorial +will cover some more details of this later on. For the time being, all you have to know is that you can store information safely on the :data:`~flask.g` object. @@ -37,7 +35,7 @@ already established connection:: g.sqlite_db = connect_db() return g.sqlite_db -So now we know how to connect, but how do we properly disconnect? For +Now you know how to connect, but how can you properly disconnect? For that, Flask provides us with the :meth:`~flask.Flask.teardown_appcontext` decorator. It's executed every time the application context tears down:: diff --git a/docs/tutorial/dbinit.rst b/docs/tutorial/dbinit.rst index 2c26dd1a..09997906 100644 --- a/docs/tutorial/dbinit.rst +++ b/docs/tutorial/dbinit.rst @@ -1,6 +1,6 @@ .. _tutorial-dbinit: -Step 4: Creating The Database +Step 5: Creating The Database ============================= As outlined earlier, Flaskr is a database powered application, and more @@ -16,13 +16,14 @@ Such a schema can be created by piping the ``schema.sql`` file into the The downside of this is that it requires the ``sqlite3`` command to be installed, which is not necessarily the case on every system. This also -requires that we provide the path to the database, which can introduce +requires that you provide the path to the database, which can introduce errors. It's a good idea to add a function that initializes the database -for you to the application. +for you, to the application. -To do this, we can create a function and hook it into the :command:`flask` -command that initializes the database. Let me show you the code first. Just -add this function below the `connect_db` function in :file:`flaskr.py`:: +To do this, you can create a function and hook it into a :command:`flask` +command that initializes the database. For now just take a look at the +code segment below. A good place to add this function, and command, is +just below the `connect_db` function in :file:`flaskr.py`:: def init_db(): db = get_db() @@ -38,23 +39,23 @@ add this function below the `connect_db` function in :file:`flaskr.py`:: The ``app.cli.command()`` decorator registers a new command with the :command:`flask` script. When the command executes, Flask will automatically -create an application context for us bound to the right application. -Within the function, we can then access :attr:`flask.g` and other things as -we would expect. When the script ends, the application context tears down +create an application context which is bound to the right application. +Within the function, you can then access :attr:`flask.g` and other things as +you might expect. When the script ends, the application context tears down and the database connection is released. -We want to keep an actual function around that initializes the database, +You will want to keep an actual function around that initializes the database, though, so that we can easily create databases in unit tests later on. (For more information see :ref:`testing`.) The :func:`~flask.Flask.open_resource` method of the application object is a convenient helper function that will open a resource that the application provides. This function opens a file from the resource -location (your ``flaskr`` folder) and allows you to read from it. We are -using this here to execute a script on the database connection. +location (the :file:`flaskr/flaskr` folder) and allows you to read from it. +It is used in this example to execute a script on the database connection. -The connection object provided by SQLite can give us a cursor object. -On that cursor, there is a method to execute a complete script. Finally, we +The connection object provided by SQLite can give you a cursor object. +On that cursor, there is a method to execute a complete script. Finally, you only have to commit the changes. SQLite3 and other transactional databases will not commit unless you explicitly tell it to. diff --git a/docs/tutorial/folders.rst b/docs/tutorial/folders.rst index fba19d72..4e117d1f 100644 --- a/docs/tutorial/folders.rst +++ b/docs/tutorial/folders.rst @@ -3,21 +3,25 @@ Step 0: Creating The Folders ============================ -Before we get started, let's create the folders needed for this +Before getting started, you will need to create the folders needed for this application:: /flaskr - /static - /templates + /flaskr + /static + /templates -The ``flaskr`` folder is not a Python package, but just something where we -drop our files. Later on, we will put our database schema as well as main -module into this folder. It is done in the following way. The files inside -the :file:`static` folder are available to users of the application via HTTP. -This is the place where CSS and Javascript files go. Inside the -:file:`templates` folder, Flask will look for `Jinja2`_ templates. The -templates you create later on in the tutorial will go in this directory. +The application will be installed and run as Python package. This is the +recommended way to install and run Flask applications. You will see exactly +how to run ``flaskr`` later on in this tutorial. For now go ahead and create +the applications directory structure. In the next few steps you will be +creating the database schema as well as the main module. -Continue with :ref:`tutorial-schema`. +As a quick side note, the files inside of the :file:`static` folder are +available to users of the application via HTTP. This is the place where CSS and +Javascript files go. Inside the :file:`templates` folder, Flask will look for +`Jinja2`_ templates. You will see examples of this later on. + +For now you should continue with :ref:`tutorial-schema`. .. _Jinja2: http://jinja.pocoo.org/ diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst index 80b9fc28..ccd4e7d2 100644 --- a/docs/tutorial/index.rst +++ b/docs/tutorial/index.rst @@ -24,6 +24,7 @@ the `example source`_. folders schema setup + setuptools dbcon dbinit views diff --git a/docs/tutorial/introduction.rst b/docs/tutorial/introduction.rst index e3da4b97..dd46628b 100644 --- a/docs/tutorial/introduction.rst +++ b/docs/tutorial/introduction.rst @@ -3,8 +3,9 @@ Introducing Flaskr ================== -We will call our blogging application Flaskr, but feel free to choose your own -less Web-2.0-ish name ;) Essentially, we want it to do the following things: +This tutorial will demonstrate a blogging application named Flaskr, but feel +free to choose your own less Web-2.0-ish name ;) Essentially, it will do the +following things: 1. Let the user sign in and out with credentials specified in the configuration. Only one user is supported. @@ -14,8 +15,8 @@ less Web-2.0-ish name ;) Essentially, we want it to do the following things: 3. The index page shows all entries so far in reverse chronological order (newest on top) and the user can add new ones from there if logged in. -We will be using SQLite3 directly for this application because it's good -enough for an application of this size. For larger applications, however, +SQLite3 will be used directly for this application because it's good enough +for an application of this size. For larger applications, however, it makes a lot of sense to use `SQLAlchemy`_, as it handles database connections in a more intelligent way, allowing you to target different relational databases at once and more. You might also want to consider diff --git a/docs/tutorial/schema.rst b/docs/tutorial/schema.rst index b164b94c..00f56f09 100644 --- a/docs/tutorial/schema.rst +++ b/docs/tutorial/schema.rst @@ -3,10 +3,10 @@ Step 1: Database Schema ======================= -First, we want to create the database schema. Only a single table is needed -for this application and we only want to support SQLite, so creating the -database schema is quite easy. Just put the following contents into a file -named `schema.sql` in the just created `flaskr` folder: +In this step, you will create the database schema. Only a single table is +needed for this application and it will only support SQLite. All you need to do +is put the following contents into a file named :file:`schema.sql` in the +:file:`flaskr/flaskr` folder: .. sourcecode:: sql @@ -17,7 +17,7 @@ named `schema.sql` in the just created `flaskr` folder: 'text' text not null ); -This schema consists of a single table called ``entries``. Each row in +This schema consists of a single table called ``entries``. Each row in this table has an ``id``, a ``title``, and a ``text``. The ``id`` is an automatically incrementing integer and a primary key, the other two are strings that must not be null. diff --git a/docs/tutorial/setup.rst b/docs/tutorial/setup.rst index fef71722..78b6390a 100644 --- a/docs/tutorial/setup.rst +++ b/docs/tutorial/setup.rst @@ -3,15 +3,16 @@ Step 2: Application Setup Code ============================== -Now that we have the schema in place, we can create the application module. -Let's call it ``flaskr.py``. We will place this file inside the ``flaskr`` -folder. We will begin by adding the imports we need and by adding the config -section. For small applications, it is possible to drop the configuration -directly into the module, and this is what we will be doing here. However, -a cleaner solution would be to create a separate ``.ini`` or ``.py`` file, -load that, and import the values from there. +Now that the schema is in place, you can create the application module, +:file:`flaskr.py`. This file should be placed inside of the +:file:`flaskr/flaskr` folder. The first several lines of code in the +application module are the needed import statements. After that there will be a +few lines of configuration code. For small applications like ``flaskr``, it is +possible to drop the configuration directly into the module. However, a cleaner +solution is to create a separate ``.ini`` or ``.py`` file, load that, and +import the values from there. -First, we add the imports in :file:`flaskr.py`:: +Here are the import statements (in :file:`flaskr.py`):: # all the imports import os @@ -19,12 +20,13 @@ First, we add the imports in :file:`flaskr.py`:: from flask import Flask, request, session, g, redirect, url_for, abort, \ render_template, flash -Next, we can create our actual application and initialize it with the -config from the same file in :file:`flaskr.py`:: +The next couple lines will create the actual application instance and +initialize it with the config from the same file in :file:`flaskr.py`: - # create our little application :) - app = Flask(__name__) - app.config.from_object(__name__) +.. sourcecode:: python + + app = Flask(__name__) # create the application instance :) + app.config.from_object(__name__) # load config from this file , flaskr.py # Load default config and override config from an environment variable app.config.update(dict( @@ -35,8 +37,8 @@ config from the same file in :file:`flaskr.py`:: )) app.config.from_envvar('FLASKR_SETTINGS', silent=True) -The :class:`~flask.Config` object works similarly to a dictionary so we -can update it with new values. +The :class:`~flask.Config` object works similarly to a dictionary, so it can be +updated with new values. .. admonition:: Database Path @@ -55,10 +57,10 @@ can update it with new values. Usually, it is a good idea to load a separate, environment-specific configuration file. Flask allows you to import multiple configurations and it -will use the setting defined in the last import. This enables robust +will use the setting defined in the last import. This enables robust configuration setups. :meth:`~flask.Config.from_envvar` can help achieve this. -.. code-block:: python +.. sourcecode:: python app.config.from_envvar('FLASKR_SETTINGS', silent=True) @@ -74,15 +76,15 @@ that in all cases, only variable names that are uppercase are considered. The ``SECRET_KEY`` is needed to keep the client-side sessions secure. Choose that key wisely and as hard to guess and complex as possible. -We will also add a method that allows for easy connections to the -specified database. This can be used to open a connection on request and +Lastly, you will add a method that allows for easy connections to the +specified database. This can be used to open a connection on request and also from the interactive Python shell or a script. This will come in -handy later. We create a simple database connection through SQLite and +handy later. You can create a simple database connection through SQLite and then tell it to use the :class:`sqlite3.Row` object to represent rows. -This allows us to treat the rows as if they were dictionaries instead of +This allows the rows to be treated as if they were dictionaries instead of tuples. -:: +.. sourcecode:: python def connect_db(): """Connects to the specific database.""" @@ -90,29 +92,6 @@ tuples. rv.row_factory = sqlite3.Row return rv -With that out of the way, you should be able to start up the application -without problems. Do this with the following commands:: - - export FLASK_APP=flaskr - export FLASK_DEBUG=1 - flask run - -(In case you are on Windows you need to use `set` instead of `export`). -The :envvar:`FLASK_DEBUG` flag enables or disables the interactive debugger. -*Never leave debug mode activated in a production system*, because it will -allow users to execute code on the server! - -You will see a message telling you that server has started along with -the address at which you can access it. - -When you head over to the server in your browser, you will get a 404 error -because we don't have any views yet. We will focus on that a little later, -but first, we should get the database working. - -.. admonition:: Externally Visible Server - - Want your server to be publicly available? Check out the - :ref:`externally visible server ` section for more - information. +In the next section you will see how to run the application. -Continue with :ref:`tutorial-dbcon`. +Continue with :ref:`tutorial-setuptools`. diff --git a/docs/tutorial/setuptools.rst b/docs/tutorial/setuptools.rst new file mode 100644 index 00000000..306d94d3 --- /dev/null +++ b/docs/tutorial/setuptools.rst @@ -0,0 +1,89 @@ +.. _tutorial-setuptools: + +Step 3: Installing flaskr with setuptools +========================================= + +Flask is now shipped with built-in support for `Click`_. Click provides +Flask with enhanced and extensible command line utilities. Later in this +tutorial you will see exactly how to extend the ``flask`` command line +interface (CLI). + +A useful pattern to manage a Flask application is to install your app +using `setuptools`_. This involves creating a :file:`setup.py` +in the projects root directory. You also need to add an empty +:file:`__init__.py` file to make the :file:`flaskr/flaskr` directory +a package. The code structure at this point should be:: + + /flaskr + /flaskr + __init__.py + /static + /templates + setup.py + +The content of the ``setup.py`` file for ``flaskr`` is: + +.. sourcecode:: python + + from setuptools import setup + + setup( + name='flaskr', + packages=['flaskr'], + include_package_data=True, + install_requires=[ + 'flask', + ], + ) + +When using setuptools, it is also necessary to specify any special files +that should be included in your package (in the :file:`MANIFEST.in`). +In this case, the static and templates directories need to be included, +as well as the schema. Create the :file:`MANIFEST.in` and add the +following lines:: + + graft flaskr/templates + graft flaskr/static + include flaskr/schema.sql + +At this point you should be able to install the application. As usual, it +is recommended to install your Flask application within a `virtualenv`_. +With that said, go ahead and install the application with:: + + pip install --editable . + +.. note:: The above installation command assumes that it is run within the + projects root directory, `flaskr/`. Also, the `editable` flag allows + editing source code without having to reinstall the Flask app each time + you make changes. + +With that out of the way, you should be able to start up the application. +Do this with the following commands:: + + export FLASK_APP=flaskr.flaskr + export FLASK_DEBUG=1 + flask run + +(In case you are on Windows you need to use `set` instead of `export`). +The :envvar:`FLASK_DEBUG` flag enables or disables the interactive debugger. +*Never leave debug mode activated in a production system*, because it will +allow users to execute code on the server! + +You will see a message telling you that server has started along with +the address at which you can access it. + +When you head over to the server in your browser, you will get a 404 error +because we don't have any views yet. That will be addressed a little later, +but first, you should get the database working. + +.. admonition:: Externally Visible Server + + Want your server to be publicly available? Check out the + :ref:`externally visible server ` section for more + information. + +Continue with :ref:`tutorial-dbcon`. + +.. _Click: http://click.pocoo.org +.. _setuptools: https://setuptools.readthedocs.io +.. _virtualenv: https://virtualenv.pypa.io diff --git a/docs/tutorial/templates.rst b/docs/tutorial/templates.rst index 77991893..d6558233 100644 --- a/docs/tutorial/templates.rst +++ b/docs/tutorial/templates.rst @@ -1,11 +1,12 @@ .. _tutorial-templates: -Step 6: The Templates +Step 8: The Templates ===================== -Now we should start working on the templates. If we were to request the URLs -now, we would only get an exception that Flask cannot find the templates. The -templates are using `Jinja2`_ syntax and have autoescaping enabled by +Now it is time to start working on the templates. As you may have +noticed, if you make requests with the app running, you will get +an exception that Flask cannot find the templates. The templates +are using `Jinja2`_ syntax and have autoescaping enabled by default. This means that unless you mark a value in the code with :class:`~flask.Markup` or with the ``|safe`` filter in the template, Jinja2 will ensure that special characters such as ``<`` or ``>`` are @@ -57,9 +58,9 @@ show_entries.html This template extends the :file:`layout.html` template from above to display the messages. Note that the ``for`` loop iterates over the messages we passed -in with the :func:`~flask.render_template` function. We also tell the -form to submit to your `add_entry` function and use ``POST`` as HTTP -method: +in with the :func:`~flask.render_template` function. Notice that the form is +configured to to submit to the `add_entry` view function and use ``POST`` as +HTTP method: .. sourcecode:: html+jinja diff --git a/docs/tutorial/testing.rst b/docs/tutorial/testing.rst index d70b4abe..c5ecf7dd 100644 --- a/docs/tutorial/testing.rst +++ b/docs/tutorial/testing.rst @@ -8,3 +8,81 @@ expected, it's probably not a bad idea to add automated tests to simplify modifications in the future. The application above is used as a basic example of how to perform unit testing in the :ref:`testing` section of the documentation. Go there to see how easy it is to test Flask applications. + +Adding Tests to flaskr +====================== + +Assuming you have seen the testing section above and have either written +your own tests for ``flaskr`` or have followed along with the examples +provided, you might be wondering about ways to organize the project. + +One possible and recommended project structure is:: + + flaskr/ + flaskr/ + __init__.py + static/ + templates/ + tests/ + context.py + test_flaskr.py + setup.py + MANIFEST.in + +For now go ahead a create the :file:`tests/` directory as well as the +:file:`context.py` and :file:`test_flaskr.py` files, if you haven't +already. The context file is used as an import helper. The contents +of that file are:: + + import sys, os + + basedir = os.path.dirname(os.path.abspath(__file__)) + sys.path.insert(0, basedir + '/../') + + from flaskr import flaskr + +Testing + Setuptools +==================== + +One way to handle testing is to integrate it with ``setuptools``. All it +requires is adding a couple of lines to the :file:`setup.py` file and +creating a new file :file:`setup.cfg`. Go ahead and update the +:file:`setup.py` to contain:: + + from setuptools import setup + + setup( + name='flaskr', + packages=['flaskr'], + include_package_data=True, + install_requires=[ + 'flask', + ], + ) + setup_requires=[ + 'pytest-runner', + ], + tests_require=[ + 'pytest', + ], + ) +Now create :file:`setup.cfg` in the project root (alongside +:file:`setup.py`):: + + [aliases] + test=pytest + +Now you can run:: + + python setup.py test + +This calls on the alias created in :file:`setup.cfg` which in turn runs +``pytest`` via ``pytest-runner``, as the :file:`setup.py` script has +been called. (Recall the `setup_requires` argument in :file:`setup.py`) +Following the standard rules of test-discovery your tests will be +found, run, and hopefully pass. + +This is one possible way to run and manage testing. Here ``pytest`` is +used, but there are other options such as ``nose``. Integrating testing +with ``setuptools`` is convenient because it is not necessary to actually +download ``pytest`` or any other testing framework one might use. \ No newline at end of file diff --git a/docs/tutorial/views.rst b/docs/tutorial/views.rst index 618c97c6..d9838073 100644 --- a/docs/tutorial/views.rst +++ b/docs/tutorial/views.rst @@ -1,10 +1,10 @@ .. _tutorial-views: -Step 5: The View Functions +Step 7: The View Functions ========================== -Now that the database connections are working, we can start writing the -view functions. We will need four of them: +Now that the database connections are working, you can start writing the +view functions. You will need four of them: Show Entries ------------ @@ -30,7 +30,7 @@ Add New Entry This view lets the user add new entries if they are logged in. This only responds to ``POST`` requests; the actual form is shown on the -`show_entries` page. If everything worked out well, we will +`show_entries` page. If everything worked out well, it will :func:`~flask.flash` an information message to the next request and redirect back to the `show_entries` page:: @@ -45,8 +45,8 @@ redirect back to the `show_entries` page:: flash('New entry was successfully posted') return redirect(url_for('show_entries')) -Note that we check that the user is logged in here (the `logged_in` key is -present in the session and ``True``). +Note that this view checks that the user is logged in (that is, if the +`logged_in` key is present in the session and ``True``). .. admonition:: Security Note @@ -81,11 +81,11 @@ notified about that, and the user is asked again:: return render_template('login.html', error=error) The `logout` function, on the other hand, removes that key from the session -again. We use a neat trick here: if you use the :meth:`~dict.pop` method +again. There is a neat trick here: if you use the :meth:`~dict.pop` method of the dict and pass a second parameter to it (the default), the method will delete the key from the dictionary if present or do nothing when that -key is not in there. This is helpful because now we don't have to check -if the user was logged in. +key is not in there. This is helpful because now it is not necessary to +check if the user was logged in. :: @@ -94,11 +94,24 @@ if the user was logged in. session.pop('logged_in', None) flash('You were logged out') return redirect(url_for('show_entries')) - -Note that it is not a good idea to store passwords in plain text. You want to -protect login credentials if someone happens to have access to your database. -One way to do this is to use Security Helpers from Werkzeug to hash the -password. However, the emphasis of this tutorial is to demonstrate the basics -of Flask and plain text passwords are used for simplicity. + +.. admonition:: Security Note + + Passwords should never be stored in plain text in a production + system. This tutorial uses plain text passwords for simplicity. If you + plan to release a project based off this tutorial out into the world, + passwords should be both `hashed and salted`_ before being stored in a + database or file. + + Fortunately, there are Flask extensions for the purpose of + hashing passwords and verifying passwords against hashes, so adding + this functionality is fairly straight forward. There are also + many general python libraries that can be used for hashing. + + You can find a list of recommended Flask extensions + `here `_ + Continue with :ref:`tutorial-templates`. + +.. _hashed and salted: https://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/ diff --git a/examples/flaskr/.gitignore b/examples/flaskr/.gitignore index fb46a3af..8d567f84 100644 --- a/examples/flaskr/.gitignore +++ b/examples/flaskr/.gitignore @@ -1 +1,2 @@ flaskr.db +.eggs/ diff --git a/examples/flaskr/MANIFEST.in b/examples/flaskr/MANIFEST.in new file mode 100644 index 00000000..efbd93df --- /dev/null +++ b/examples/flaskr/MANIFEST.in @@ -0,0 +1,3 @@ +graft flaskr/templates +graft flaskr/static +include flaskr/schema.sql diff --git a/examples/flaskr/README b/examples/flaskr/README index bdf91983..3cb021e7 100644 --- a/examples/flaskr/README +++ b/examples/flaskr/README @@ -13,15 +13,19 @@ export an FLASKR_SETTINGS environment variable pointing to a configuration file. - 2. Instruct flask to use the right application + 2. install the app from the root of the project directory - export FLASK_APP=flaskr + pip install --editable . - 3. initialize the database with this command: + 3. Instruct flask to use the right application + + export FLASK_APP=flaskr.flaskr + + 4. initialize the database with this command: flask initdb - 4. now you can run flaskr: + 5. now you can run flaskr: flask run @@ -30,5 +34,5 @@ ~ Is it tested? - You betcha. Run the `test_flaskr.py` file to see + You betcha. Run `python setup.py test` to see the tests pass. diff --git a/examples/flaskr/flaskr/__init__.py b/examples/flaskr/flaskr/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/flaskr/flaskr.py b/examples/flaskr/flaskr/flaskr.py similarity index 100% rename from examples/flaskr/flaskr.py rename to examples/flaskr/flaskr/flaskr.py diff --git a/examples/flaskr/schema.sql b/examples/flaskr/flaskr/schema.sql similarity index 100% rename from examples/flaskr/schema.sql rename to examples/flaskr/flaskr/schema.sql diff --git a/examples/flaskr/static/style.css b/examples/flaskr/flaskr/static/style.css similarity index 100% rename from examples/flaskr/static/style.css rename to examples/flaskr/flaskr/static/style.css diff --git a/examples/flaskr/templates/layout.html b/examples/flaskr/flaskr/templates/layout.html similarity index 100% rename from examples/flaskr/templates/layout.html rename to examples/flaskr/flaskr/templates/layout.html diff --git a/examples/flaskr/templates/login.html b/examples/flaskr/flaskr/templates/login.html similarity index 100% rename from examples/flaskr/templates/login.html rename to examples/flaskr/flaskr/templates/login.html diff --git a/examples/flaskr/templates/show_entries.html b/examples/flaskr/flaskr/templates/show_entries.html similarity index 100% rename from examples/flaskr/templates/show_entries.html rename to examples/flaskr/flaskr/templates/show_entries.html diff --git a/examples/flaskr/setup.cfg b/examples/flaskr/setup.cfg new file mode 100644 index 00000000..b7e47898 --- /dev/null +++ b/examples/flaskr/setup.cfg @@ -0,0 +1,2 @@ +[aliases] +test=pytest diff --git a/examples/flaskr/setup.py b/examples/flaskr/setup.py new file mode 100644 index 00000000..910f23ac --- /dev/null +++ b/examples/flaskr/setup.py @@ -0,0 +1,16 @@ +from setuptools import setup + +setup( + name='flaskr', + packages=['flaskr'], + include_package_data=True, + install_requires=[ + 'flask', + ], + setup_requires=[ + 'pytest-runner', + ], + tests_require=[ + 'pytest', + ], +) diff --git a/examples/flaskr/tests/context.py b/examples/flaskr/tests/context.py new file mode 100644 index 00000000..3c773332 --- /dev/null +++ b/examples/flaskr/tests/context.py @@ -0,0 +1,6 @@ +import sys, os + +basedir = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, basedir + '/../') + +from flaskr import flaskr \ No newline at end of file diff --git a/examples/flaskr/test_flaskr.py b/examples/flaskr/tests/test_flaskr.py similarity index 98% rename from examples/flaskr/test_flaskr.py rename to examples/flaskr/tests/test_flaskr.py index 084f13f4..4715c417 100644 --- a/examples/flaskr/test_flaskr.py +++ b/examples/flaskr/tests/test_flaskr.py @@ -10,11 +10,10 @@ """ import pytest - import os -import flaskr import tempfile +from context import flaskr @pytest.fixture def client(request):