├── .gitignore ├── .hgignore ├── AUTHORS.txt ├── LICENSE.txt ├── MANIFEST.in ├── README.txt ├── VERSION.txt ├── buildout.cfg ├── docs ├── Makefile ├── README.txt └── source │ ├── _static │ └── .hidden │ ├── _templates │ └── layout.html │ ├── api │ ├── fixture.base.rst │ ├── fixture.dataset.converter.rst │ ├── fixture.dataset.rst │ ├── fixture.django_testcase.rst │ ├── fixture.exc.rst │ ├── fixture.io.rst │ ├── fixture.loadable.django_loadable.rst │ ├── fixture.loadable.google_datastore_loadable.rst │ ├── fixture.loadable.rst │ ├── fixture.loadable.sqlalchemy_loadable.rst │ ├── fixture.loadable.sqlobject_loadable.rst │ ├── fixture.loadable.storm_loadable.rst │ ├── fixture.style.rst │ └── fixture.util.rst │ ├── conf.py │ ├── index.rst │ ├── using-dataset.rst │ ├── using-fixture-cmd.rst │ ├── using-fixture-with-appengine.rst │ ├── using-fixture-with-django.rst │ ├── using-fixture-with-pylons.rst │ ├── using-loadable-fixture.rst │ └── using-temp-io.rst ├── fixture ├── __init__.py ├── base.py ├── command │ ├── __init__.py │ └── generate │ │ ├── __init__.py │ │ ├── generate.py │ │ ├── generate_sqlalchemy.py │ │ ├── generate_sqlobject.py │ │ └── template.py ├── dataset │ ├── __init__.py │ ├── converter.py │ └── dataset.py ├── django_testcase.py ├── docs.py ├── examples │ ├── __init__.py │ ├── db │ │ ├── __init__.py │ │ ├── sqlalchemy_examples.py │ │ ├── sqlobject_examples.py │ │ └── storm_examples.py │ ├── django_example │ │ ├── app │ │ │ ├── __init__.py │ │ │ ├── apps.py │ │ │ ├── migrations │ │ │ │ ├── 0001_initial.py │ │ │ │ └── __init__.py │ │ │ └── models.py │ │ ├── blog │ │ │ ├── __init__.py │ │ │ ├── apps.py │ │ │ ├── datasets │ │ │ │ ├── __init__.py │ │ │ │ ├── blog_data.py │ │ │ │ └── user_data.py │ │ │ ├── migrations │ │ │ │ ├── 0001_initial.py │ │ │ │ └── __init__.py │ │ │ ├── models.py │ │ │ └── tests.py │ │ ├── django_example │ │ │ ├── __init__.py │ │ │ ├── settings.py │ │ │ ├── urls.py │ │ │ └── wsgi.py │ │ └── manage.py │ ├── google_appengine_example │ │ ├── app.yaml │ │ ├── gblog │ │ │ ├── __init__.py │ │ │ ├── handlers.py │ │ │ ├── models.py │ │ │ └── templates │ │ │ │ └── list_entries.html │ │ ├── index.yaml │ │ ├── load_data_locally.py │ │ ├── setup.cfg │ │ └── tests │ │ │ ├── __init__.py │ │ │ ├── datasets.py │ │ │ └── test_list_entries.py │ └── pylons_example │ │ └── addressbook │ │ ├── MANIFEST.in │ │ ├── README.txt │ │ ├── addressbook.egg-info │ │ └── SOURCES.txt │ │ ├── addressbook │ │ ├── __init__.py │ │ ├── config │ │ │ ├── __init__.py │ │ │ ├── deployment.ini_tmpl │ │ │ ├── environment.py │ │ │ ├── middleware.py │ │ │ └── routing.py │ │ ├── controllers │ │ │ ├── __init__.py │ │ │ ├── book.py │ │ │ └── error.py │ │ ├── datasets │ │ │ └── __init__.py │ │ ├── lib │ │ │ ├── __init__.py │ │ │ ├── app_globals.py │ │ │ ├── base.py │ │ │ └── helpers.py │ │ ├── model │ │ │ ├── __init__.py │ │ │ └── meta.py │ │ ├── public │ │ │ ├── bg.png │ │ │ ├── favicon.ico │ │ │ └── pylons-logo.gif │ │ ├── templates │ │ │ └── book.mako │ │ ├── tests │ │ │ ├── __init__.py │ │ │ ├── functional │ │ │ │ ├── __init__.py │ │ │ │ └── test_book.py │ │ │ └── test_models.py │ │ └── websetup.py │ │ ├── development.ini │ │ ├── docs │ │ └── index.txt │ │ ├── setup.cfg │ │ ├── setup.py │ │ └── test.ini ├── exc.py ├── io.py ├── loadable │ ├── __init__.py │ ├── django_loadable.py │ ├── google_datastore_loadable.py │ ├── loadable.py │ ├── sqlalchemy_loadable.py │ ├── sqlobject_loadable.py │ └── storm_loadable.py ├── setup_cmd │ ├── __init__.py │ └── apidocs.py ├── style.py ├── test │ ├── __init__.py │ ├── conf.py │ ├── env_supports.py │ ├── profile │ │ ├── full.sh │ │ └── quick.sh │ ├── test_base.py │ ├── test_command │ │ ├── __init__.py │ │ └── test_generate │ │ │ ├── __init__.py │ │ │ ├── test_generate.py │ │ │ ├── test_generate_sqlalchemy.py │ │ │ └── test_generate_sqlobject.py │ ├── test_dataset │ │ ├── test_converter.py │ │ └── test_dataset.py │ ├── test_io.py │ └── test_loadable │ │ ├── __init__.py │ │ ├── test_django │ │ ├── __init__.py │ │ ├── fixtures.py │ │ ├── test_djangoenv.py │ │ ├── test_djangomeduim.py │ │ ├── test_loading.py │ │ ├── test_wrong_declarations.py │ │ └── util.py │ │ ├── test_google_datastore_loadable.py │ │ ├── test_loadable.py │ │ ├── test_loadable_queue.py │ │ ├── test_sqlalchemy_loadable.py │ │ ├── test_sqlobject_loadable.py │ │ └── test_storm_loadable.py └── util.py ├── presentations ├── pycon2007-fixture-talk-OLD.key.zip ├── pycon2007-fixture-talk-lowres.pdf ├── pycon2007-fixture-talk-notes.pdf └── pycon2007-fixture-talk.pdf ├── run_tests.sh ├── setup.cfg ├── setup.py └── src ├── .hidden └── nosedjango-for-fixture ├── AUTHORS ├── README.txt ├── nosedjango ├── __init__.py └── nosedjango.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | *.sw[po] 3 | build 4 | eggs 5 | *.egg-info 6 | bin 7 | .installed.cfg 8 | develop-eggs 9 | _build 10 | _env 11 | _tmp_src 12 | env-* 13 | .DS_Store 14 | .noseids 15 | .tox 16 | docs/_build/* 17 | *~ 18 | *.mo 19 | *.db 20 | dist 21 | src/django 22 | fixture/examples/pylons_example/addressbook/data 23 | fixture/examples/pylons_example/addressbook/development.db 24 | fixture/examples/pylons_example/addressbook/tests.db 25 | fixture/examples/pylons_example/addressbook/Paste* 26 | fixture/examples/django_example/project.db 27 | fixture/examples/pylons_example/addressbook/testdb.sqlite 28 | /fixture/examples/django_example/db.sqlite3 29 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.pyc 3 | *.pyo 4 | build 5 | eggs 6 | bin 7 | .installed.cfg 8 | develop-eggs 9 | _build 10 | _env 11 | env-* 12 | *~ 13 | .DS_Store 14 | *.egg-info 15 | _tmp_src 16 | dist 17 | src/django 18 | fixture/examples/pylons_example/addressbook/data 19 | fixture/examples/pylons_example/addressbook/development.db 20 | fixture/examples/pylons_example/addressbook/tests.db 21 | fixture/examples/pylons_example/addressbook/Paste* 22 | fixture/examples/django_example/project.db 23 | fixture/examples/pylons_example/addressbook/testdb.sqlite 24 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Author / Maintainer 2 | ------------------- 3 | 4 | Kumar McMillan 5 | 6 | Contributors 7 | ------------ 8 | 9 | - Allen Bierbaum 10 | - Jeffrey Cousens 11 | - Manuel Aristarán 12 | - Alex Marandon 13 | - Tomas Holas 14 | - Ben Ford 15 | - Bozo Dragojevic 16 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | fixture 2 | Copyright (C) 2006 Kumar McMillan 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | prune presentations 2 | include VERSION.txt 3 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | For docs see docs/index.rst or http://farmdev.com/projects/fixture/ 2 | 3 | To build docs run :: 4 | 5 | $ make -C docs html 6 | 7 | To run tests, just use `nosetests`. 8 | -------------------------------------------------------------------------------- /VERSION.txt: -------------------------------------------------------------------------------- 1 | 1.5.11 -------------------------------------------------------------------------------- /buildout.cfg: -------------------------------------------------------------------------------- 1 | [buildout] 2 | develop = . 3 | fixture/examples/pylons_example/addressbook 4 | src/nosedjango-for-fixture 5 | parts = test interpreter 6 | 7 | [test] 8 | recipe = pbp.recipe.noserunner 9 | eggs = 10 | Routes==1.10.3 11 | Pylons==0.9.7 12 | django>=1.1 13 | fixture 14 | NoseDjango 15 | testtools 16 | SQLObject==0.8 17 | Elixir>=0.5 18 | simplejson 19 | SQLAlchemy==0.4.8 20 | Sphinx>=0.4 21 | storm>=0.15 22 | psycopg2 23 | defaults = -v --with-doctest --doctest-extension=rst -i examples -i pylons_example -i addressbook --with-pylons=${buildout:directory}/fixture/examples/pylons_example/addressbook/test.ini --with-django --django-settings-path=${buildout:directory}/fixture/examples/django_example/ 24 | #working-directory = ${buildout:directory}/fixture/ 25 | extra_path = = ${buildout:directory}/fixture/fixture/test/test_loadable/test_django/ 26 | script = test-fixture 27 | initialization = import os 28 | os.environ['DJANGO_SETTINGS_MODULE'] = 'fixture.examples.django_example.settings' 29 | import sys 30 | # hmmmmm, I don't know why develop= does not solve this. One idea is that 31 | # nose is changing directories before importing addressbook and perhaps that 32 | # nullifies the develop egg 33 | sys.path.append('${buildout:directory}/fixture/examples/pylons_example/addressbook') 34 | 35 | [interpreter] 36 | recipe = zc.recipe.egg 37 | eggs = ${test:eggs} 38 | interlude 39 | entry-points = 40 | manage=fixture.examples.django_example.manage:main 41 | initialization = ${test:initialization} 42 | 43 | interpreter = python 44 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = PATH=../bin sphinx-build 7 | PAPER = 8 | 9 | # Internal variables. 10 | PAPEROPT_a4 = -D latex_paper_size=a4 11 | PAPEROPT_letter = -D latex_paper_size=letter 12 | ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 13 | 14 | .PHONY: help clean html web pickle htmlhelp latex changes linkcheck 15 | 16 | test: 17 | cd ..; nosetests 18 | 19 | docs_live: 20 | tar -czf ./build/fixture-docs.tgz build/html 21 | scp ./build/fixture-docs.tgz fisk.rcache.com:~/www/farmdev/projects/fixture/ 22 | @echo "uploaded docs" 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " pickle to make pickle files (usable by e.g. sphinx-web)" 28 | @echo " htmlhelp to make HTML files and a HTML help project" 29 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 30 | @echo " changes to make an overview over all changed/added/deprecated items" 31 | @echo " linkcheck to check all external links for integrity" 32 | 33 | clean: 34 | -rm -rf build/* 35 | 36 | html: 37 | mkdir -p build/html build/doctrees 38 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html 39 | @echo 40 | @echo "Build finished. The HTML pages are in build/html." 41 | 42 | doctest: 43 | mkdir -p build/html build/doctrees 44 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) build/html 45 | @echo 46 | @echo "Doctest finished." 47 | 48 | pickle: 49 | mkdir -p build/pickle build/doctrees 50 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle 51 | @echo 52 | @echo "Build finished; now you can process the pickle files or run" 53 | @echo " sphinx-web build/pickle" 54 | @echo "to start the sphinx-web server." 55 | 56 | web: pickle 57 | 58 | htmlhelp: 59 | mkdir -p build/htmlhelp build/doctrees 60 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp 61 | @echo 62 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 63 | ".hhp project file in build/htmlhelp." 64 | 65 | latex: 66 | mkdir -p build/latex build/doctrees 67 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex 68 | @echo 69 | @echo "Build finished; the LaTeX files are in build/latex." 70 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 71 | "run these through (pdf)latex." 72 | 73 | changes: 74 | mkdir -p build/changes build/doctrees 75 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes 76 | @echo 77 | @echo "The overview file is in build/changes." 78 | 79 | linkcheck: 80 | mkdir -p build/linkcheck build/doctrees 81 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck 82 | @echo 83 | @echo "Link check complete; look for any errors in the above output " \ 84 | "or in build/linkcheck/output.txt." 85 | -------------------------------------------------------------------------------- /docs/README.txt: -------------------------------------------------------------------------------- 1 | 2 | To build docs, install http://sphinx.pocoo.org/ and type `make html doctest` 3 | 4 | Docs are available online at http://farmdev.com/projects/fixture/docs/ 5 | 6 | -------------------------------------------------------------------------------- /docs/source/_static/.hidden: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/docs/source/_static/.hidden -------------------------------------------------------------------------------- /docs/source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% block rootrellink %} 3 |
  • Farm Development »
  • 4 | {{ super() }} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /docs/source/api/fixture.base.rst: -------------------------------------------------------------------------------- 1 | 2 | ------------ 3 | fixture.base 4 | ------------ 5 | 6 | .. automodule:: fixture.base 7 | 8 | .. autoclass:: fixture.base.Fixture 9 | :members: data, with_data 10 | 11 | .. autoclass:: fixture.base.FixtureData 12 | :members: -------------------------------------------------------------------------------- /docs/source/api/fixture.dataset.converter.rst: -------------------------------------------------------------------------------- 1 | 2 | ------------------------- 3 | fixture.dataset.converter 4 | ------------------------- 5 | 6 | .. automodule:: fixture.dataset.converter 7 | 8 | .. autofunction:: fixture.dataset.converter.dataset_to_json 9 | -------------------------------------------------------------------------------- /docs/source/api/fixture.dataset.rst: -------------------------------------------------------------------------------- 1 | 2 | --------------- 3 | fixture.dataset 4 | --------------- 5 | 6 | .. automodule:: fixture.dataset 7 | 8 | .. autoclass:: fixture.dataset.DataSet 9 | :show-inheritance: 10 | :members: __iter__, data, shared_instance 11 | 12 | .. autoclass:: fixture.dataset.DataSetMeta 13 | :show-inheritance: 14 | :members: storable, storable_name, primary_key 15 | 16 | .. autoclass:: fixture.dataset.SuperSet 17 | :show-inheritance: 18 | :members: 19 | 20 | .. autoclass:: fixture.dataset.MergedSuperSet 21 | :show-inheritance: 22 | :members: 23 | 24 | .. autoclass:: fixture.dataset.DataType 25 | :show-inheritance: 26 | :members: decorate_row 27 | 28 | .. autoclass:: fixture.dataset.DataRow 29 | :show-inheritance: 30 | :members: 31 | 32 | .. autoclass:: fixture.dataset.Ref 33 | :show-inheritance: 34 | :members: __call__ 35 | 36 | .. autoclass:: fixture.dataset.RefValue 37 | :show-inheritance: 38 | :members: 39 | 40 | .. autoclass:: fixture.dataset.DataContainer 41 | :show-inheritance: 42 | :members: 43 | 44 | .. autoclass:: fixture.dataset.DataSetContainer 45 | :show-inheritance: 46 | :members: -------------------------------------------------------------------------------- /docs/source/api/fixture.django_testcase.rst: -------------------------------------------------------------------------------- 1 | ------------------------------------------ 2 | fixture.django_testcase 3 | ------------------------------------------ 4 | 5 | .. automodule:: fixture.django_testcase 6 | 7 | .. autoclass:: fixture.django_testcase.FixtureTestCase 8 | :show-inheritance: 9 | :members: _fixture_setup, _fixture_teardown 10 | 11 | .. attribute:: datasets 12 | 13 | This is a list of :class:`DataSets ` that will be created and destroyed for each test method. 14 | The result of setting them up will be referenced by the :attr:`data` 15 | 16 | .. attribute:: data 17 | 18 | Any :attr:`datasets` found are loaded and refereneced here for later teardown 19 | -------------------------------------------------------------------------------- /docs/source/api/fixture.exc.rst: -------------------------------------------------------------------------------- 1 | 2 | ----------- 3 | fixture.exc 4 | ----------- 5 | 6 | .. automodule:: fixture.exc 7 | 8 | .. autoexception:: fixture.exc.UninitializedError 9 | :show-inheritance: 10 | 11 | .. autoexception:: fixture.exc.DataSetActionException 12 | :show-inheritance: 13 | 14 | .. autoexception:: fixture.exc.LoadError 15 | :show-inheritance: 16 | 17 | .. autoexception:: fixture.exc.UnloadError 18 | :show-inheritance: 19 | 20 | .. autoexception:: fixture.exc.StorageMediaNotFound 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/api/fixture.io.rst: -------------------------------------------------------------------------------- 1 | 2 | ---------- 3 | fixture.io 4 | ---------- 5 | 6 | .. automodule:: fixture.io 7 | 8 | .. autofunction:: fixture.io.TempIO 9 | 10 | .. autoclass:: fixture.io.DeletableDirPath 11 | :show-inheritance: 12 | :members: __del__, rmtree 13 | 14 | .. autoclass:: fixture.io.DirPath 15 | :members: 16 | -------------------------------------------------------------------------------- /docs/source/api/fixture.loadable.django_loadable.rst: -------------------------------------------------------------------------------- 1 | ------------------------------------------ 2 | fixture.loadable.django_loadable 3 | ------------------------------------------ 4 | 5 | .. automodule:: fixture.loadable.django_loadable 6 | 7 | 8 | .. autoclass:: DjangoEnv 9 | 10 | .. automethod:: get 11 | 12 | 13 | .. autoclass:: fixture.loadable.django_loadable.DjangoFixture 14 | :show-inheritance: 15 | :members: create_transaction, then_finally, attach_storage_medium 16 | 17 | Django's transaction management is implemented as a module, which is returned by :meth:`create_transaction`. This means the the :meth:`~fixture.loadable.loadable.DBLoadableFixture.commit` and :meth:`~fixture.loadable.loadable.DBLoadableFixture.rollback` remain unchanged from :class:`fixture.loadable.loadable.DBLoadableFixture`. 18 | 19 | As far as mapping DataSets to models, if you don't supply an env kwarg you'll get the :class:`~DjangoEnv` class. This simply provides a :meth:`get method ` that proxies through to :meth:`django.db.models.get_model`. 20 | Alternatively you can use an inner :class:`Meta ` with the following attribute: 21 | 22 | .. attribute:: django_model 23 | 24 | Use this on an inner :class:`Meta ` class to specify the model. 25 | It must be of a form that can be passed to ``get_model`` after being split on a ``'.'`` e.g: 26 | 27 | .. code-block:: python 28 | 29 | class Meta: 30 | django_model = 'auth.User' 31 | 32 | .. autoclass:: fixture.loadable.django_loadable.DjangoMedium 33 | :show-inheritance: 34 | 35 | For now we're going to say that a Fixture can only define relations 36 | and fields defined locally to the target model. So given the :ref:`example models `, Where Book has a ForeignKey to Author, then you'll have a fixture like: 37 | 38 | .. code-block:: python 39 | 40 | class BookData(DataSet): 41 | class Meta: 42 | django_model = 'app.Book' 43 | class book1: 44 | # ... 45 | author = AuthorData.some_author 46 | 47 | and not like this: 48 | 49 | .. code-block:: python 50 | 51 | class AuthorData(DataSet): 52 | class Meta: 53 | django_model = 'app.Author' 54 | class author1: 55 | # ... 56 | books = [BookData.book1, BookData.book2] 57 | 58 | .. note:: This might change in future as it looks like it should be possible to be able to do it the other way round (if desirable). 59 | 60 | .. automethod:: save 61 | 62 | Validates first with :meth:`_check_schema` 63 | 64 | .. automethod:: _check_schema 65 | 66 | .. note:: see the internal function ``column_vals`` inside :meth:`fixture.loadable.LoadableFixture.load_dataset` for more info 67 | 68 | .. warning:: This will check the field names and related model types only - it won't validate field types 69 | 70 | See the :ref:`example models ` 71 | 72 | -------------------------------------------------------------------------------- /docs/source/api/fixture.loadable.google_datastore_loadable.rst: -------------------------------------------------------------------------------- 1 | 2 | ------------------------------------------ 3 | fixture.loadable.google_datastore_loadable 4 | ------------------------------------------ 5 | 6 | .. automodule:: fixture.loadable.google_datastore_loadable 7 | 8 | .. autoclass:: fixture.loadable.google_datastore_loadable.GoogleDatastoreFixture 9 | :show-inheritance: 10 | 11 | .. autoclass:: fixture.loadable.google_datastore_loadable.EntityMedium 12 | :show-inheritance: 13 | :members: save, clear -------------------------------------------------------------------------------- /docs/source/api/fixture.loadable.rst: -------------------------------------------------------------------------------- 1 | 2 | ---------------- 3 | fixture.loadable 4 | ---------------- 5 | 6 | .. automodule:: fixture.loadable 7 | 8 | .. autoclass:: fixture.loadable.LoadableFixture 9 | :show-inheritance: 10 | :members: begin, commit, load, load_dataset, resolve_row_references, rollback, then_finally, unload, unload_dataset, wrap_in_transaction 11 | 12 | .. autoclass:: fixture.loadable.loadable.EnvLoadableFixture 13 | :show-inheritance: 14 | :members: 15 | 16 | .. autoclass:: fixture.loadable.loadable.DBLoadableFixture 17 | :show-inheritance: 18 | :members: 19 | 20 | .. autoclass:: fixture.loadable.loadable.StorageMediumAdapter 21 | :members: -------------------------------------------------------------------------------- /docs/source/api/fixture.loadable.sqlalchemy_loadable.rst: -------------------------------------------------------------------------------- 1 | 2 | ------------------------------------ 3 | fixture.loadable.sqlalchemy_loadable 4 | ------------------------------------ 5 | 6 | .. automodule:: fixture.loadable.sqlalchemy_loadable 7 | 8 | .. autoclass:: fixture.loadable.sqlalchemy_loadable.SQLAlchemyFixture 9 | :show-inheritance: 10 | :members: 11 | 12 | .. autoclass:: fixture.loadable.sqlalchemy_loadable.MappedClassMedium 13 | :show-inheritance: 14 | :members: 15 | 16 | .. autoclass:: fixture.loadable.sqlalchemy_loadable.TableMedium 17 | :show-inheritance: 18 | :members: -------------------------------------------------------------------------------- /docs/source/api/fixture.loadable.sqlobject_loadable.rst: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------- 3 | fixture.loadable.sqlobject_loadable 4 | ----------------------------------- 5 | 6 | .. automodule:: fixture.loadable.sqlobject_loadable 7 | 8 | .. autoclass:: fixture.loadable.sqlobject_loadable.SQLObjectFixture 9 | :show-inheritance: 10 | :members: create_transaction, commit, then_finally, rollback 11 | 12 | .. autoclass:: fixture.loadable.sqlobject_loadable.SQLObjectMedium 13 | :show-inheritance: 14 | :members: -------------------------------------------------------------------------------- /docs/source/api/fixture.loadable.storm_loadable.rst: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------- 3 | fixture.loadable.storm_loadable 4 | ----------------------------------- 5 | 6 | .. automodule:: fixture.loadable.storm_loadable 7 | 8 | .. autoclass:: fixture.loadable.storm_loadable.StormFixture 9 | :show-inheritance: 10 | :members: 11 | 12 | .. autoclass:: fixture.loadable.storm_loadable.StormMedium 13 | :show-inheritance: 14 | :members: -------------------------------------------------------------------------------- /docs/source/api/fixture.style.rst: -------------------------------------------------------------------------------- 1 | 2 | -------------- 3 | fixture.style 4 | -------------- 5 | 6 | .. automodule:: fixture.style 7 | 8 | .. autoclass:: fixture.style.Style 9 | :members: 10 | 11 | .. autoclass:: fixture.style.OriginalStyle 12 | :show-inheritance: 13 | :members: 14 | 15 | .. autoclass:: fixture.style.NamedDataStyle 16 | :show-inheritance: 17 | :members: 18 | 19 | .. autoclass:: fixture.style.TrimmedNameStyle 20 | :show-inheritance: 21 | :members: 22 | 23 | .. autoclass:: fixture.style.PaddedNameStyle 24 | :show-inheritance: 25 | :members: 26 | 27 | .. autoclass:: fixture.style.CamelAndUndersStyle 28 | :show-inheritance: 29 | :members: -------------------------------------------------------------------------------- /docs/source/api/fixture.util.rst: -------------------------------------------------------------------------------- 1 | 2 | ------------ 3 | fixture.util 4 | ------------ 5 | 6 | .. automodule:: fixture.util 7 | 8 | .. autoclass:: fixture.util.DataTestCase 9 | :show-inheritance: 10 | :members: 11 | 12 | .. autofunction:: fixture.util.with_debug 13 | 14 | .. autofunction:: fixture.util.reset_log_level 15 | 16 | .. autofunction:: fixture.util.start_debug 17 | 18 | .. autofunction:: fixture.util.stop_debug -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # fixture documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Jun 3 14:50:30 2008. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # The contents of this file are pickled, so don't put values in the namespace 9 | # that aren't pickleable (module imports are okay, they're removed automatically). 10 | # 11 | # All configuration values have a default value; values that are commented out 12 | # serve to show the default value. 13 | 14 | import sys, os 15 | # for doctests of Django examples to work 16 | sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'fixture', 'examples', 'django_example')) 17 | 18 | # register some docutils directives 19 | # (there's probably a better way to do this) 20 | import fixture.docs 21 | # for version number: 22 | import fixture 23 | 24 | # If your extensions are in another directory, add it here. If the directory 25 | # is relative to the documentation root, use os.path.abspath to make it 26 | # absolute, like shown here. 27 | #sys.path.append(os.path.abspath('some/directory')) 28 | 29 | # General configuration 30 | # --------------------- 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be extensions 33 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 34 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ['_templates'] 38 | 39 | # The suffix of source filenames. 40 | source_suffix = '.rst' 41 | 42 | # The master toctree document. 43 | master_doc = 'index' 44 | 45 | # General substitutions. 46 | project = 'fixture' 47 | copyright = '2008, Kumar McMillan' 48 | 49 | # The default replacements for |version| and |release|, also used in various 50 | # other places throughout the built documents. 51 | # 52 | # The short X.Y version. 53 | version = fixture.__version__ 54 | # The full version, including alpha/beta/rc tags. 55 | release = fixture.__version__ 56 | 57 | # There are two options for replacing |today|: either, you set today to some 58 | # non-false value, then it is used: 59 | #today = '' 60 | # Else, today_fmt is used as the format for a strftime call. 61 | today_fmt = '%B %d, %Y' 62 | 63 | # List of documents that shouldn't be included in the build. 64 | #unused_docs = [] 65 | 66 | # List of directories, relative to source directories, that shouldn't be searched 67 | # for source files. 68 | #exclude_dirs = [] 69 | 70 | # If true, '()' will be appended to :func: etc. cross-reference text. 71 | #add_function_parentheses = True 72 | 73 | # If true, the current module name will be prepended to all description 74 | # unit titles (such as .. function::). 75 | #add_module_names = True 76 | 77 | # If true, sectionauthor and moduleauthor directives will be shown in the 78 | # output. They are ignored by default. 79 | #show_authors = False 80 | 81 | # The name of the Pygments (syntax highlighting) style to use. 82 | pygments_style = 'sphinx' 83 | 84 | 85 | # Options for HTML output 86 | # ----------------------- 87 | 88 | # The style sheet to use for HTML and HTML Help pages. A file of that name 89 | # must exist either in Sphinx' static/ path, or in one of the custom paths 90 | # given in html_static_path. 91 | html_style = 'default.css' 92 | 93 | # The name for this set of Sphinx documents. If None, it defaults to 94 | # " v documentation". 95 | #html_title = None 96 | 97 | # The name of an image file (within the static path) to place at the top of 98 | # the sidebar. 99 | #html_logo = None 100 | 101 | # Add any paths that contain custom static files (such as style sheets) here, 102 | # relative to this directory. They are copied after the builtin static files, 103 | # so a file named "default.css" will overwrite the builtin "default.css". 104 | html_static_path = ['_static'] 105 | 106 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 107 | # using the given strftime format. 108 | html_last_updated_fmt = '%b %d, %Y' 109 | 110 | # If true, SmartyPants will be used to convert quotes and dashes to 111 | # typographically correct entities. 112 | #html_use_smartypants = True 113 | 114 | # Custom sidebar templates, maps document names to template names. 115 | #html_sidebars = {} 116 | 117 | # Additional templates that should be rendered to pages, maps page names to 118 | # template names. 119 | #html_additional_pages = {} 120 | 121 | # If false, no module index is generated. 122 | #html_use_modindex = True 123 | 124 | # If true, the reST sources are included in the HTML build as _sources/. 125 | html_copy_source = False 126 | 127 | # If true, an OpenSearch description file will be output, and all pages will 128 | # contain a tag referring to it. The value of this option must be the 129 | # base URL from which the finished HTML is served. 130 | #html_use_opensearch = '' 131 | 132 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 133 | #html_file_suffix = '' 134 | 135 | # Output file base name for HTML help builder. 136 | htmlhelp_basename = 'fixturedoc' 137 | 138 | 139 | # Options for LaTeX output 140 | # ------------------------ 141 | 142 | # The paper size ('letter' or 'a4'). 143 | #latex_paper_size = 'letter' 144 | 145 | # The font size ('10pt', '11pt' or '12pt'). 146 | #latex_font_size = '10pt' 147 | 148 | # Grouping the document tree into LaTeX files. List of tuples 149 | # (source start file, target name, title, author, document class [howto/manual]). 150 | latex_documents = [ 151 | ('index', 'fixture.tex', 'fixture Documentation', 'Kumar McMillan', 'manual'), 152 | ] 153 | 154 | # The name of an image file (relative to this directory) to place at the top of 155 | # the title page. 156 | #latex_logo = None 157 | 158 | # For "manual" documents, if this is true, then toplevel headings are parts, 159 | # not chapters. 160 | #latex_use_parts = False 161 | 162 | # Additional stuff for the LaTeX preamble. 163 | #latex_preamble = '' 164 | 165 | # Documents to append as an appendix to all manuals. 166 | #latex_appendices = [] 167 | 168 | # If false, no module index is generated. 169 | #latex_use_modindex = True 170 | -------------------------------------------------------------------------------- /docs/source/using-fixture-cmd.rst: -------------------------------------------------------------------------------- 1 | .. _using-fixture-command: 2 | 3 | ------------------------- 4 | Using the fixture command 5 | ------------------------- 6 | 7 | .. contents:: :local: 8 | 9 | There are several issues you may run into while working with fixtures: 10 | 11 | 1. The data model of a program is usually an implementation detail. It's bad practice to "know" about implementation details in tests because it means you have to update your tests when those details change; you should only have to update your tests when an interface changes. 12 | 2. Data accumulates very fast and there is already a useful tool for slicing and dicing data: the database! Hand-coding DataSet classes is not always the way to go. 13 | 3. When regression testing or when trying to reproduce a bug, you may want to grab a "snapshot" of the existing data. 14 | 15 | ``fixture`` is a shell command to address these and other issues. It gets installed along with this module. Specifically, the ``fixture`` command accepts a path to a single object and queries that object using the command options. The output is python code that you can use in a test to reload the data retrieved by the query. 16 | 17 | .. note:: WARNING: This feature is not fully implemented and doesn't support all backends. 18 | 19 | Usage 20 | ~~~~~ 21 | 22 | .. shell:: 23 | :run_on_method: fixture.command.generate.main 24 | 25 | fixture --help 26 | 27 | An Example With SQLAlchemy 28 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | 30 | Here is a data model defined in `SQLAlchemy `_ code. (For complete code see ``fixture/examples/db/sqlalchemy_examples.py``.) 31 | 32 | .. doctest:: command 33 | 34 | >>> from sqlalchemy import * 35 | >>> from sqlalchemy.orm import * 36 | >>> metadata = MetaData() 37 | >>> authors = Table('authors', metadata, 38 | ... Column('id', Integer, primary_key=True), 39 | ... Column('first_name', String(100)), 40 | ... Column('last_name', String(100))) 41 | ... 42 | >>> class Author(object): 43 | ... pass 44 | ... 45 | >>> books = Table('books', metadata, 46 | ... Column('id', Integer, primary_key=True), 47 | ... Column('title', String(100)), 48 | ... Column('author_id', Integer, ForeignKey('authors.id'))) 49 | ... 50 | >>> class Book(object): 51 | ... pass 52 | ... 53 | >>> def setup_mappers(): 54 | ... mapper(Author, authors) 55 | ... mapper(Book, books, properties={ 56 | ... 'author': relation(Author) 57 | ... }) 58 | ... 59 | >>> def connect(dsn): 60 | ... metadata.bind = create_engine(dsn) 61 | ... 62 | >>> 63 | 64 | After inserting some data, it would be possible to run a command that points at the ``Book`` object. The above command uses ``Book`` to send a select query with a where clause ``WHERE title='Dune'``, and turns the record sets into ``DataSet`` classes: 65 | 66 | .. shell:: 67 | :setup: fixture.docs.setup_command_data 68 | :teardown: fixture.test.teardown_examples 69 | 70 | fixture fixture.examples.db.sqlalchemy_examples.Book \ 71 | --dsn=sqlite:////tmp/fixture_example.db \ 72 | --where="title='Dune'" \ 73 | --connect=fixture.examples.db.sqlalchemy_examples:connect \ 74 | --setup=fixture.examples.db.sqlalchemy_examples:setup_mappers 75 | 76 | Notice that we queried the ``Book`` object but got back Table objects. Also notice that all foreign keys were followed to reproduce the complete chain of data (in this case, the ``authors`` table data). 77 | 78 | Also notice that several hooks were used, one to connect the ``metadata`` object by DSN and another to setup the mappers. See *Usage* above for more information on the ``--connect`` and ``--setup`` options. 79 | 80 | Creating a custom data handler 81 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 82 | 83 | No documentation yet 84 | -------------------------------------------------------------------------------- /docs/source/using-fixture-with-django.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _using-fixture-with-django: 3 | 4 | ===================================== 5 | Using Fixture To Test Django 6 | ===================================== 7 | 8 | .. contents:: :local: 9 | 10 | The `Django's ORM `_ already has its own `data loading mechanism`_ for testing but you can use the Fixture module as an alternative. When using Fixture, you don't have to deal with JSON or XML, you simply create :class:`DataSet ` objects in Python code and load them with an instance of :class:`DjangoFixture `. Using Python code helps you share objects and common field definitions whereas in Django you might have many JSON files with the same field definitions in separate places. Using Python code also allows you to represent test data alongside your test code, take advantage of inheritance, and improve readability. 11 | 12 | However, unlike Django, Fixture does not currently provide a way to auto generate DataSet classes from a real database. It is safe to mix Fixture style data loading and Django style data loading if desired. 13 | 14 | This feature was contributed by `Ben Ford `_. 15 | 16 | .. note:: Fixture can only be used with `Django version 1.0.2 `_ and greater. 17 | 18 | .. _django-models: 19 | 20 | Example Django application 21 | --------------------------- 22 | 23 | Here's a simple blog application written in Django. The data model consists of Post objects that belong to Category objects. 24 | 25 | .. literalinclude:: ../../fixture/examples/django_example/blog/models.py 26 | :language: python 27 | 28 | .. currentmodule:: fixture.loadable.django_loadable 29 | 30 | .. note:: 31 | 32 | A complete version of this blog app with fixtures and tests can be found in fixture/examples/django_example/blog/ 33 | 34 | .. _django-fixtures: 35 | 36 | Defining datasets 37 | ----------------- 38 | 39 | To load data into the test database, you first create some :class:`DataSet ` subclasses in Python code: 40 | 41 | .. code-block:: python 42 | 43 | class UserData(DataSet): 44 | class Meta: 45 | django_model = 'auth.User' 46 | class ben: 47 | first_name = 'Ben' 48 | last_name = 'Ford' 49 | # ... 50 | 51 | In this example, the nested class ``ben`` will be used to create a row in django's ``auth.User`` model. Fixture knows to load into that model because of the ``django_model`` attribute of the inner :class:`Meta ` class. A couple other ways to link each DataSet to a specfic Django model are shown later on. 52 | 53 | Defining relationships between models 54 | -------------------------------------- 55 | 56 | More realistically you would need to load one or more foreign key dependencies as part of each DataSet. Here are the DataSets for testing the blog application, taken from ``fixture/examples/django_example/blog/datasets/blog_data.py`` 57 | 58 | .. literalinclude:: ../../fixture/examples/django_example/blog/datasets/blog_data.py 59 | :language: python 60 | 61 | Here ``first_post`` is a blog entry posted in the Python category and authored by Ben (notice the UserData class has been imported from the user_data module). 62 | 63 | In this style, each DataSet class name starts with that of the Django model it should be loaded into and a shared class BlogMeta has the attribute ``django_app_label='blog'`` to tell the loader which app to find models in. 64 | 65 | .. note:: 66 | In the current release of fixture you can only specify a relationship from the direction that the field is defined, *not* from the reverse (see :class:`DjangoMedium ` for more details). 67 | 68 | Loading some data 69 | ------------------ 70 | 71 | 72 | .. doctest:: 73 | :hide: 74 | 75 | >>> import os 76 | >>> os.environ['DJANGO_SETTINGS_MODULE'] = 'fixture.examples.django_example.settings' 77 | >>> from django.core.management import call_command 78 | >>> call_command('syncdb', interactive=False) 79 | >>> call_command('reset', 'blog', interactive=False) 80 | ... 81 | >>> from fixture.examples.django_example.blog.datasets.blog_data import CategoryData, PostData 82 | >>> from fixture.examples.django_example.blog.models import Post 83 | 84 | To load these records programatically you'd use a :class:`DjangoFixture ` instance and a :class:`NamedDataStyle ` instance: 85 | 86 | .. doctest:: 87 | 88 | >>> from fixture import DjangoFixture 89 | >>> from fixture.style import NamedDataStyle 90 | >>> db_fixture = DjangoFixture(style=NamedDataStyle()) 91 | 92 | You would insert each defined row into its target database table via setup() : 93 | 94 | .. doctest:: 95 | 96 | >>> data = db_fixture.data(CategoryData, PostData) 97 | >>> data.setup() 98 | >>> Post.objects.filter(author__first_name='Ben').count() 99 | 3 100 | >>> data.teardown() 101 | >>> Post.objects.all() 102 | [] 103 | 104 | Foreign DataSet classes like UserData need not be mentioned in data() since they are loaded automatically when referenced. 105 | 106 | Loading data in a test 107 | ----------------------- 108 | 109 | Here is an example of how to create a unittest style class to test with data. This is taken directly from ``fixture.examples.django_example.blog.tests``: 110 | 111 | .. literalinclude:: ../../fixture/examples/django_example/blog/tests.py 112 | :language: python 113 | 114 | .. note:: This test case uses Django's fast data loading strategy introduced in 1.1 whereby data is removed by rolling back the transaction. If you need to test specific transactional behavior in your code then don't use this test case. 115 | 116 | See :class:`fixture.django_testcase.FixtureTestCase` for details on how to configure the test case. 117 | 118 | For further reading, check the API docs for :mod:`fixture.django_testcase` and :mod:`fixture.loadable.django_loadable` 119 | 120 | .. _data loading mechanism: http://docs.djangoproject.com/en/dev/topics/testing/ 121 | .. _django's testing framework: http://docs.djangoproject.com/en/dev/topics/testing/ -------------------------------------------------------------------------------- /docs/source/using-temp-io.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _using-temp-io: 3 | 4 | ------------------------------- 5 | TempIO: A Temporary File System 6 | ------------------------------- 7 | 8 | This object is useful for tests that need to set up a directory structure 9 | and work with files and paths. Once you instantiate it, you have a temporary 10 | directory that will self-destruct when it falls out of scope: 11 | 12 | .. doctest:: 13 | 14 | >>> from fixture import TempIO 15 | >>> tmp = TempIO() 16 | >>> tmp #doctest: +ELLIPSIS 17 | '/.../tmp_fixture...' 18 | 19 | Add sub-directories by simply assigning an attribute the basename of the new 20 | subdirectory, like so: 21 | 22 | .. doctest:: 23 | 24 | >>> tmp.incoming = "incoming" 25 | >>> import os 26 | >>> os.path.exists(tmp.incoming) 27 | True 28 | 29 | The new attribute is now an absolute path to a subdirectory, "incoming", of 30 | the tmp root, as well as an object itself. Note that tmp and tmp.incoming are 31 | just string objects, but with several os.path methods mixed in for convenience. 32 | See the :class:`fixture.io.DeletableDirPath` API for details. However, you can pass it to other objects and 33 | it will represent itself as its absolute path. 34 | 35 | Putting Files 36 | ------------- 37 | 38 | You can also insert files to the directory with putfile(): 39 | 40 | .. doctest:: 41 | 42 | >>> foopath = tmp.incoming.putfile("foo.txt", "contents of foo") 43 | >>> tmp.incoming.join("foo.txt").exists() 44 | True 45 | 46 | Removing The Temp Dir 47 | --------------------- 48 | 49 | The directory root will self-destruct when it goes out of scope or ``atexit``. 50 | You can explicitly delete the object at your test's teardown if you like: 51 | 52 | .. doctest:: 53 | 54 | >>> tmpdir = str(tmp) # copy the directory path 55 | >>> del tmp 56 | >>> os.path.exists(tmpdir) 57 | False 58 | 59 | API Documentation 60 | ----------------- 61 | 62 | - :mod:`fixture.io` 63 | 64 | .. _DirPath: ../apidocs/fixture.io.DirPath.html -------------------------------------------------------------------------------- /fixture/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """fixture is a python module for loading and referencing test data 3 | 4 | It provides several utilities for achieving a *fixed state* when testing 5 | Python programs. Specifically, these utilities setup / teardown databases and 6 | work with temporary file systems. 7 | 8 | You may want to start by reading the `End User Documentation`_. 9 | 10 | .. _End User Documentation: http://farmdev.com/projects/fixture/docs/ 11 | 12 | If you are reading this from a `source checkout`_ then you may want to build the documentation locally. Install `Sphinx`_ then run:: 13 | 14 | cd /path/to/fixture/source 15 | cd docs 16 | make html 17 | 18 | Then open ``build/html/index.html`` in your web browser. If that fails, you can read the reST files starting at ``docs/source/index.rst`` 19 | 20 | .. _source checkout: http://fixture.googlecode.com/hg/#egg=fixture-dev 21 | .. _Sphinx: http://sphinx.pocoo.org/ 22 | 23 | """ 24 | 25 | from pkg_resources import get_distribution 26 | 27 | __version__ = get_distribution("fixture").version 28 | 29 | import logging 30 | import sys 31 | 32 | from fixture.dataset import * 33 | from fixture.io import * 34 | from fixture.loadable import * 35 | from fixture.style import * 36 | from fixture.util import * 37 | 38 | 39 | def setup_test_not_supported(): 40 | """hook for setup for the test command.""" 41 | raise NotImplementedError("use: `python setup.py nosetests` instead") 42 | setup_test_not_supported.__test__ = False 43 | 44 | -------------------------------------------------------------------------------- /fixture/command/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """The fixture command""" -------------------------------------------------------------------------------- /fixture/command/generate/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | class code_str(str): 3 | """string that reproduces without quotes. 4 | 5 | """ 6 | def __repr__(self): 7 | return str.__repr__(self)[1:-1] 8 | 9 | from fixture.command.generate import generate 10 | __doc__ = generate.__doc__ 11 | from fixture.command.generate.generate import * 12 | 13 | # load modules so they can register themselves (better way?) 14 | try: 15 | from fixture.command.generate import generate_sqlobject 16 | except ImportError: 17 | pass 18 | try: 19 | from fixture.command.generate import generate_sqlalchemy 20 | except ImportError: 21 | pass -------------------------------------------------------------------------------- /fixture/command/generate/template.py: -------------------------------------------------------------------------------- 1 | 2 | """templates that generate fixture modules.""" 3 | 4 | from fixture.command.generate import code_str 5 | import pprint 6 | 7 | def _addto(val, list_): 8 | if val not in list_: 9 | list_.append(val) 10 | 11 | class _TemplateRegistry(object): 12 | def __init__(self): 13 | self.templates = [] 14 | self.lookup = {} 15 | self._default = None 16 | 17 | def __iter__(self): 18 | for tpl in self.templates: 19 | yield tpl 20 | 21 | def find(self, name): 22 | return self.templates[self.lookup[name]] 23 | 24 | def default(self): 25 | if self._default is None: 26 | raise LookupError("no default template has been set") 27 | return self.templates[self._default] 28 | 29 | def register(self, template, default=False): 30 | name = template.__class__.__name__ 31 | if name in self.lookup: 32 | raise ValueError("cannot re-register %s with object %s" % ( 33 | name, template)) 34 | self.templates.append(template) 35 | id = len(self.templates)-1 36 | self.lookup[name] = id 37 | 38 | if default: 39 | self._default = id 40 | 41 | templates = _TemplateRegistry() 42 | 43 | class Template(object): 44 | """knows how to render fixture code. 45 | """ 46 | class dict(dict): 47 | def __repr__(self): 48 | s = ["dict("] 49 | for k,v in self.iteritems(): 50 | s.append(" %s = %s," % ( 51 | k, repr(v))) 52 | s[-1] = s[-1] + ")" 53 | return "\n".join(s) 54 | 55 | class tuple(tuple): 56 | def __repr__(self): 57 | s = ["("] 58 | for item in self: 59 | s.append(" %s," % repr(item)) 60 | return "\n".join(s) + ")" 61 | 62 | class DataDef: 63 | def __init__(self): 64 | self.data_header = [] # vars at top of data() method 65 | 66 | def add_header(self, hdr): 67 | if hdr not in self.data_header: 68 | self.data_header.append(hdr) 69 | 70 | def meta(self, fxt_class): 71 | """returns list of lines to add to the fixture class's meta. 72 | """ 73 | return ['pass'] 74 | 75 | class data(tuple): 76 | pass 77 | 78 | metabase = """ 79 | class metabase: 80 | pass""" 81 | 82 | fixture = None 83 | 84 | def __init__(self): 85 | self.import_header = [] # lines of import statements 86 | self.meta_header = [] # lines of attributes for inner meta class 87 | 88 | def __repr__(self): 89 | return "'%s'" % self.__class__.__name__ 90 | 91 | def add_import(self, _import): 92 | _addto(_import, self.import_header) 93 | 94 | def begin(self): 95 | pass 96 | 97 | def header(self, handler): 98 | return self.metabase 99 | 100 | def render(self, tpl): 101 | if self.fixture is None: 102 | raise NotImplementedError 103 | return self.fixture % tpl 104 | 105 | def is_template(obj): 106 | return isinstance(obj, Template) 107 | 108 | class fixture(Template): 109 | """renders DataSet objects for the fixture interface.""" 110 | 111 | class DataDef(Template.DataDef): 112 | def __init__(self, *a,**kw): 113 | Template.DataDef.__init__(self, *a,**kw) 114 | self.requires = [] 115 | 116 | def add_reference(self, fxt_class, fxt_var=None): 117 | _addto(code_str(fxt_class), self.requires) 118 | 119 | def fset_to_attr(self, fset, fxt_class): 120 | # do we need to check for MergedSuperSet ? 121 | # attribute needs key only 122 | return code_str("%s.%s.ref(%s)" % ( 123 | fxt_class, fset.mk_key(), repr(fset.get_id_attr()))) 124 | 125 | def meta(self, fxt_class): 126 | return "" 127 | # if len(self.requires): 128 | # return ["requires = %s" % str(tuple(self.requires))] 129 | # else: 130 | # return ["pass"] 131 | 132 | fixture = """ 133 | class %(fxt_class)s(DataSet): 134 | %(meta)s\ 135 | %(data)s""" 136 | 137 | metabase = "" 138 | 139 | def begin(self): 140 | self.add_import('import datetime') 141 | self.add_import("from fixture import DataSet") 142 | 143 | class data(object): 144 | def __init__(self, elements): 145 | self.elements = elements 146 | def __repr__(self): 147 | o = [] 148 | for class_, dict_ in self.elements: 149 | o.append(" class %s:" % class_) 150 | for k,v in dict_.iteritems(): 151 | o.append(" %s = %s" % (k,repr(v))) 152 | return "\n".join(o) 153 | 154 | def header(self, handler): 155 | return "\n".join(Template.header(self, handler)) 156 | 157 | templates.register(fixture(), default=True) 158 | 159 | class testtools(Template): 160 | """renders Fixture objects for the legacy testtools interface. 161 | """ 162 | class DataDef(Template.DataDef): 163 | def add_reference(self, fxt_class, fxt_var=None): 164 | self.add_header('r = self.meta.req') 165 | self.add_header("r.%s = %s()" % (fxt_var, fxt_class)) 166 | 167 | def fset_to_attr(self, fset, fxt_class): 168 | return code_str("r.%s.%s.%s" % ( 169 | fset.mk_var_name(), fset.mk_key(), fset.get_id_attr())) 170 | 171 | def meta(self, fxt_class): 172 | """returns list of lines to add to the fixture class's meta. 173 | """ 174 | return ["so_class = %s" % fxt_class] 175 | 176 | fixture = """ 177 | class %(fxt_class)s(%(fxt_type)s): 178 | class meta(metabase): 179 | %(meta)s 180 | def data(self): 181 | %(data_header)s\ 182 | return %(data)s""" 183 | 184 | def begin(self): 185 | self.add_import('import datetime') 186 | self.add_import('from testtools.fixtures import SOFixture') 187 | 188 | templates.register(testtools()) -------------------------------------------------------------------------------- /fixture/dataset/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = ['DataSet'] 3 | 4 | from fixture.dataset.dataset import * -------------------------------------------------------------------------------- /fixture/dataset/converter.py: -------------------------------------------------------------------------------- 1 | 2 | """Utilities for converting datasets.""" 3 | 4 | import datetime 5 | import decimal 6 | import types 7 | from fixture.dataset import DataSet, DataRow 8 | json = None 9 | try: 10 | # 2.6 11 | import json 12 | except ImportError: 13 | try: 14 | import simplejson as json 15 | except ImportError: 16 | pass 17 | 18 | def _obj_items(obj): 19 | for name in dir(obj): 20 | if name.startswith('__'): 21 | continue 22 | yield name, getattr(obj, name) 23 | 24 | def default_json_converter(obj): 25 | """converts obj to a value safe for JSON serialization.""" 26 | if isinstance(obj, (datetime.date, datetime.datetime, decimal.Decimal, float)): 27 | return str(obj) 28 | raise TypeError("%r is not JSON serializable" % (obj,)) 29 | 30 | def dataset_to_json(dataset, fp=None, default=default_json_converter, wrap=None): 31 | """Converts a :class:`DataSet ` class or 32 | instance to JSON (JavaScript Object Notation). 33 | 34 | See :ref:`using-dataset-to-json` for detailed usage. 35 | 36 | Keyword Arguments 37 | 38 | **fp** 39 | An optional file-like object (must implement ``fp.write()``). When 40 | this is not None, the output is written to the fp object, otherwise 41 | the output is returned 42 | 43 | **default** 44 | A callable that takes one argument (an object) and returns output 45 | suitable for JSON serialization. This will *only* be called if the 46 | object cannot be serialized. For example:: 47 | 48 | >>> def encode_complex(obj): 49 | ... if isinstance(obj, complex): 50 | ... return [obj.real, obj.imag] 51 | ... raise TypeError("%r is not JSON serializable" % (o,)) 52 | ... 53 | >>> from fixture import DataSet 54 | >>> class ComplexData(DataSet): 55 | ... class math_stuff: 56 | ... complex = 2 + 1j 57 | ... 58 | >>> dataset_to_json(ComplexData, default=encode_complex) 59 | '[{"complex": [2.0, 1.0]}]' 60 | 61 | **wrap** 62 | A callable that takes one argument, the list of dictionaries before 63 | they are converted to JSON. For example:: 64 | 65 | >>> def wrap_in_dict(objects): 66 | ... return {'data': objects} 67 | ... 68 | >>> from fixture import DataSet 69 | >>> class ColorData(DataSet): 70 | ... class red: 71 | ... color = "red" 72 | ... 73 | >>> dataset_to_json(ColorData, wrap=wrap_in_dict) 74 | '{"data": [{"color": "red"}]}' 75 | 76 | Returns a JSON encoded string unless you specified the **fp** keyword 77 | 78 | """ 79 | assert json, ( 80 | "You must have the simplejson or json module installed. " 81 | "Neither could be imported") 82 | if isinstance(dataset, type): 83 | # we got a class so make it an instance 84 | # so that rows are resolved 85 | dataset = dataset() 86 | if not isinstance(dataset, DataSet): 87 | raise TypeError("First argument must be a class or instance of a DataSet") 88 | objects = [] 89 | for name, row in _obj_items(dataset): 90 | try: 91 | if not issubclass(row, DataRow): 92 | continue 93 | except TypeError: 94 | continue 95 | row_dict = {} 96 | for col, val in _obj_items(row): 97 | if col=='_reserved_attr' or callable(val): 98 | continue 99 | row_dict[col] = val 100 | objects.append(row_dict) 101 | if wrap: 102 | objects = wrap(objects) 103 | if fp: 104 | return json.dump(objects, fp, default=default) 105 | else: 106 | return json.dumps(objects, default=default) 107 | 108 | if __name__ == '__main__': 109 | import doctest 110 | doctest.testmod() -------------------------------------------------------------------------------- /fixture/django_testcase.py: -------------------------------------------------------------------------------- 1 | from django.test.testcases import TestCase 2 | 3 | from fixture import DjangoFixture 4 | 5 | 6 | class FixtureTestCase(TestCase): 7 | """ 8 | Overrides django's fixture setup and teardown code to use DataSets. 9 | 10 | See :ref:`Using Fixture With Django ` for a 11 | complete example. 12 | 13 | """ 14 | 15 | @classmethod 16 | def setUpTestData(cls): 17 | super(FixtureTestCase, cls).setUpTestData() 18 | fixture = DjangoFixture() 19 | cls.data = fixture.data(*cls.datasets) 20 | cls.data.setup() 21 | 22 | @classmethod 23 | def tearDownClass(cls): 24 | cls.data.teardown() 25 | super(FixtureTestCase, cls).tearDownClass() 26 | -------------------------------------------------------------------------------- /fixture/docs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """fixture documentation utilities 4 | """ 5 | 6 | import subprocess 7 | import sys 8 | 9 | import re 10 | from docutils import statemachine 11 | from docutils.parsers.rst import directives 12 | from os import path 13 | from six import StringIO 14 | 15 | 16 | heredir = path.dirname(__file__) 17 | srcdir = path.join(heredir, '..', 'docs') 18 | builddir = path.abspath(path.join(srcdir, '..', 'build')) 19 | 20 | def get_object_from_path(rawpath): 21 | parts = rawpath.split(u':') 22 | if len(parts) > 1: 23 | modpath, obj = parts 24 | else: 25 | modpath = parts[0] 26 | obj = None 27 | 28 | dot = modpath.rfind(u'.') 29 | if dot != -1: 30 | fromlist = [str(modpath[dot+1:])] 31 | mod = str(modpath[:dot]) 32 | else: 33 | fromlist = [] 34 | mod = str(modpath) 35 | 36 | # print mod, fromlist 37 | mod = __import__(mod, globals(), locals(), fromlist) 38 | if len(fromlist): 39 | mod = getattr(mod, fromlist[0]) 40 | if obj: 41 | if obj.find('.') != -1: 42 | raise NotImplementedError( 43 | "todo: need to split the object in a getattr loop") 44 | obj = getattr(mod, obj) 45 | else: 46 | obj = mod 47 | return obj 48 | 49 | def shell( 50 | name, arguments, options, content, lineno, 51 | content_offset, block_text, state, state_machine): 52 | """insert a shell command's raw output in a pre block, like:: 53 | 54 | | .. shell:: 55 | | :run_on_method: some.module.main 56 | | 57 | | mycmd --arg 1 58 | 59 | Also: 60 | 61 | | .. shell:: 62 | | :setup: some.module.setup 63 | | :teardown: some.module.teardown 64 | | 65 | | mycmd --arg 1 66 | 67 | """ 68 | printable_cmd_parts = content 69 | cmd = ' '.join([c.replace("\\", "") for c in content]) 70 | 71 | if options.get('setup'): 72 | setup = get_object_from_path(options['setup']) 73 | setup() 74 | 75 | if options.get('run_on_method'): 76 | main = get_object_from_path(options['run_on_method']) 77 | 78 | def decode(s): 79 | if isinstance(s, unicode): 80 | s = str(s.decode()) 81 | return s 82 | def unquot(s): 83 | if s[0] in ('"', "'"): 84 | s = s[1:-1] 85 | return s 86 | cmdlist = [] 87 | # get args with whitespace normalized: 88 | for part in re.split(r'\s*', cmd.strip()): 89 | part = decode(part) 90 | part = unquot(part) 91 | e = part.find('=') 92 | if e != -1: 93 | # i.e. --where="title='Dune'" 94 | part = "%s=%s" % (part[:e], unquot(part[e+1:])) 95 | cmdlist.append(part) 96 | 97 | stdout = StringIO() 98 | stderr = StringIO() 99 | sys.stdout = stdout 100 | sys.stderr = stderr 101 | _program = sys.argv[0] 102 | sys.argv[0] = cmdlist[0] 103 | try: 104 | try: 105 | main(cmdlist[1:]) 106 | except SystemExit as e: 107 | returncode = e.code 108 | else: 109 | returncode = 0 110 | finally: 111 | sys.stdout = sys.__stdout__ 112 | sys.stderr = sys.__stderr__ 113 | stdout.seek(0) 114 | stderr.seek(0) 115 | sys.argv[0] = _program 116 | else: 117 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 118 | stderr=subprocess.PIPE, close_fds=True, shell=True) 119 | 120 | returncode = p.wait() 121 | stdout, stderr = p.stdout, p.stderr 122 | 123 | if returncode != 0: 124 | raise RuntimeError("%s\n%s (exit: %s)" % ( 125 | stderr.read(), cmd, returncode)) 126 | 127 | if options.get('teardown'): 128 | setup = get_object_from_path(options['teardown']) 129 | setup() 130 | 131 | # just create a pre block and fill it with command output... 132 | pad = " " 133 | output = ["\n::\n\n"] 134 | output.append(pad + "$ " + ("%s\n" % pad).join(printable_cmd_parts) + "\n") 135 | while 1: 136 | line = stdout.readline() 137 | if not line: 138 | break 139 | output.append(pad + line) 140 | output.append("\n") 141 | 142 | output = "".join(output) 143 | 144 | include_lines = statemachine.string2lines(output) 145 | state_machine.insert_input(include_lines, None) 146 | return [] 147 | 148 | shell.arguments = (0, 0, 1) 149 | shell.options = { 150 | # 'doctest_module_first': str, 151 | 'setup': str, 152 | 'teardown': str, 153 | 'run_on_method': str} 154 | shell.content = 1 155 | 156 | directives.register_directive('shell', shell) 157 | 158 | def setup_command_data(): 159 | import os 160 | 161 | if os.path.exists('/tmp/fixture_example.db'): 162 | os.unlink('/tmp/fixture_example.db') 163 | if os.path.exists('/tmp/fixture_generate.db'): 164 | os.unlink('/tmp/fixture_generate.db') 165 | 166 | import sqlalchemy as sa 167 | from sqlalchemy import orm 168 | from fixture.examples.db.sqlalchemy_examples import ( 169 | Author, authors, Book, books, metadata) 170 | metadata.bind = sa.create_engine('sqlite:////tmp/fixture_example.db') 171 | metadata.create_all() 172 | orm.mapper(Book, books) 173 | orm.mapper(Author, authors, properties={'books': orm.relation(Book, backref='author')}) 174 | Session = orm.sessionmaker(bind=metadata.bind, autoflush=True, transactional=True) 175 | session = Session() 176 | 177 | frank = Author() 178 | frank.first_name = "Frank" 179 | frank.last_name = "Herbert" 180 | session.save(frank) 181 | 182 | dune = Book() 183 | dune.title = "Dune" 184 | dune.author = frank 185 | session.save(dune) 186 | 187 | session.commit() 188 | 189 | -------------------------------------------------------------------------------- /fixture/examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/__init__.py -------------------------------------------------------------------------------- /fixture/examples/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/db/__init__.py -------------------------------------------------------------------------------- /fixture/examples/db/sqlalchemy_examples.py: -------------------------------------------------------------------------------- 1 | 2 | """Examples for using sqlalchemy fixtures. 3 | 4 | See a complete, more accurate example in http://farmdev.com/projects/fixture/docs/ 5 | 6 | """ 7 | 8 | try: 9 | import sqlalchemy 10 | except ImportError: 11 | sqlalchemy = None 12 | 13 | Category, Product, Offer = None, None, None 14 | 15 | if sqlalchemy: 16 | from sqlalchemy import * 17 | from sqlalchemy.orm import * 18 | metadata = MetaData() 19 | 20 | categories = Table("fixture_sqlalchemy_category", 21 | metadata, 22 | Column("id", INT, primary_key=True), 23 | Column("name", String(100) ) 24 | ) 25 | class Category(object): 26 | pass 27 | 28 | products = Table("fixture_sqlalchemy_product", 29 | metadata, 30 | Column("id", INT, primary_key=True), 31 | Column("name", String(100) ), 32 | Column("category_id", INT, 33 | ForeignKey("fixture_sqlalchemy_category.id")), 34 | ) 35 | class Product(object): 36 | pass 37 | 38 | offers = Table("fixture_sqlalchemy_offer", 39 | metadata, 40 | Column("id", INT, primary_key=True), 41 | Column("name", String(100) ), 42 | Column("category_id", INT, 43 | ForeignKey("fixture_sqlalchemy_category.id")), 44 | Column("product_id", INT, 45 | ForeignKey("fixture_sqlalchemy_product.id")), 46 | ) 47 | class Offer(object): 48 | pass 49 | 50 | authors = Table('authors', metadata, 51 | Column('id', Integer, primary_key=True), 52 | Column('first_name', String(100)), 53 | Column('last_name', String(100))) 54 | 55 | class Author(object): 56 | pass 57 | 58 | books = Table('books', metadata, 59 | Column('id', Integer, primary_key=True), 60 | Column('title', String(100)), 61 | Column('author_id', Integer, ForeignKey('authors.id'))) 62 | 63 | class Book(object): 64 | pass 65 | 66 | def connect(dsn): 67 | metadata.bind = create_engine(dsn) 68 | 69 | def setup_mappers(): 70 | mapper(Category, categories) 71 | mapper(Product, products, properties={ 72 | 'category': relation(Category), 73 | }) 74 | mapper(Offer, offers, properties={ 75 | 'category': relation(Category, backref='products'), 76 | 'product': relation(Product) 77 | }) 78 | mapper(Author, authors) 79 | mapper(Book, books, properties={ 80 | 'author': relation(Author) 81 | }) 82 | 83 | if __name__ == '__main__': 84 | import doctest 85 | doctest.testmod() -------------------------------------------------------------------------------- /fixture/examples/db/sqlobject_examples.py: -------------------------------------------------------------------------------- 1 | 2 | """examples for using SQLObject fixtures.""" 3 | 4 | try: 5 | import sqlobject 6 | except ImportError: 7 | sqlobject = None 8 | 9 | Category, Product, Offer = None, None, None 10 | 11 | if sqlobject: 12 | from sqlobject import * 13 | 14 | class Category(SQLObject): 15 | class sqlmeta: 16 | table = 'fixture_sqlobject_category' 17 | name = StringCol() 18 | 19 | class Product(SQLObject): 20 | class sqlmeta: 21 | table = 'fixture_sqlobject_product' 22 | name = StringCol() 23 | category = ForeignKey('Category') 24 | 25 | class Offer(SQLObject): 26 | class sqlmeta: 27 | table = 'fixture_sqlobject_offer' 28 | name = StringCol() 29 | category = ForeignKey('Category') 30 | product = ForeignKey('Product') 31 | 32 | def setup_db(conn): 33 | assert conn is not None 34 | Category.createTable(connection=conn) 35 | Product.createTable(connection=conn) 36 | Offer.createTable(connection=conn) 37 | 38 | def teardown_db(conn): 39 | assert conn is not None 40 | 41 | ## apparently, this causes a deadlock if *all* sqlobject 42 | ## interaction is not inside a transaction. excellent! 43 | ## as a workaround, loader's accept use_transaction = True 44 | for tb in (Offer, Product, Category): 45 | tb.dropTable(connection=conn) 46 | -------------------------------------------------------------------------------- /fixture/examples/db/storm_examples.py: -------------------------------------------------------------------------------- 1 | 2 | """examples for using Storm fixtures.""" 3 | 4 | try: 5 | import storm 6 | except ImportError: 7 | storm = None 8 | 9 | Category, Product, Offer = None, None, None 10 | 11 | if storm: 12 | from storm.locals import * 13 | 14 | class Category(Storm): 15 | __storm_table__ = 'fixture_storm_category' 16 | id = Int(primary=True) 17 | name = RawStr() 18 | 19 | class Product(Storm): 20 | __storm_table__ = 'fixture_storm_product' 21 | id = Int(primary=True) 22 | name = RawStr() 23 | category_id = Int() 24 | category = Reference(category_id, Category.id) 25 | 26 | class Offer(Storm): 27 | __storm_table__ = 'fixture_storm_offer' 28 | id = Int(primary=True) 29 | name = RawStr() 30 | category_id = Int() 31 | category = Reference(category_id, Category.id) 32 | product_id = Int() 33 | product = Reference(product_id, Product.id) 34 | 35 | def setup_db(conn): 36 | assert conn is not None 37 | conn.rollback() 38 | backend = conn._connection.__class__.__name__ 39 | tmpl = { 40 | 'pk': {'PostgresConnection' : 'serial primary key', 41 | }.get(backend, 'integer primary key'), 42 | 'str_type': {'PostgresConnection' : 'bytea', 43 | }.get(backend, 'text collate binary') 44 | } 45 | # NOTE: this SQL works in postgres and sqlite: 46 | conn.execute(SQL("""DROP TABLE IF EXISTS fixture_storm_category""")) 47 | conn.execute(SQL("""CREATE TABLE fixture_storm_category ( 48 | id %(pk)s, 49 | name %(str_type)s 50 | )""" % tmpl)) 51 | assert conn.find(Category).count() == 0 52 | conn.execute(SQL("""CREATE TABLE fixture_storm_product ( 53 | id %(pk)s, 54 | name %(str_type)s, 55 | category_id integer 56 | )""" % tmpl)) 57 | assert conn.find(Product).count() == 0 58 | conn.execute(SQL("""DROP TABLE IF EXISTS fixture_storm_offer""")) 59 | conn.execute(SQL("""CREATE TABLE fixture_storm_offer ( 60 | id %(pk)s, 61 | name %(str_type)s, 62 | category_id integer, 63 | product_id integer 64 | )""" % tmpl)) 65 | assert conn.find(Offer).count() == 0 66 | conn.commit() 67 | 68 | def teardown_db(conn): 69 | assert conn is not None 70 | 71 | conn.rollback() 72 | for tb in (Offer, Product, Category): 73 | conn.execute(SQL('drop table '+tb.__storm_table__)) 74 | conn.commit() 75 | -------------------------------------------------------------------------------- /fixture/examples/django_example/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/django_example/app/__init__.py -------------------------------------------------------------------------------- /fixture/examples/django_example/app/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class AppConfig(AppConfig): 7 | name = 'app' 8 | -------------------------------------------------------------------------------- /fixture/examples/django_example/app/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-23 15:55 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Author', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('first_name', models.CharField(max_length=100)), 22 | ('last_name', models.CharField(max_length=100)), 23 | ], 24 | ), 25 | migrations.CreateModel( 26 | name='Book', 27 | fields=[ 28 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 29 | ('title', models.CharField(max_length=10)), 30 | ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='books', to='app.Author')), 31 | ], 32 | ), 33 | migrations.CreateModel( 34 | name='Reviewer', 35 | fields=[ 36 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 37 | ('name', models.CharField(max_length=100)), 38 | ('reviewed', models.ManyToManyField(related_name='reviewers', to='app.Book')), 39 | ], 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /fixture/examples/django_example/app/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/django_example/app/migrations/__init__.py -------------------------------------------------------------------------------- /fixture/examples/django_example/app/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from django.db import models 3 | 4 | 5 | class Author(models.Model): 6 | first_name = models.CharField(max_length=100) 7 | last_name = models.CharField(max_length=100) 8 | 9 | 10 | class Book(models.Model): 11 | title = models.CharField(max_length=10) 12 | author = models.ForeignKey(Author, related_name='books') 13 | 14 | 15 | class Reviewer(models.Model): 16 | name = models.CharField(max_length=100) 17 | reviewed = models.ManyToManyField(Book, related_name='reviewers') 18 | -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/django_example/blog/__init__.py -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class BlogConfig(AppConfig): 7 | name = 'blog' 8 | -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/datasets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/django_example/blog/datasets/__init__.py -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/datasets/blog_data.py: -------------------------------------------------------------------------------- 1 | from blog.datasets.user_data import UserData 2 | 3 | from fixture import DataSet 4 | 5 | 6 | class CategoryData(DataSet): 7 | class Meta: 8 | django_model = 'blog.Category' 9 | 10 | class python: 11 | title = 'python' 12 | slug = 'py' 13 | 14 | class testing: 15 | title = 'testing' 16 | slug = 'test' 17 | 18 | 19 | class PostData(DataSet): 20 | class Meta: 21 | django_model = 'blog.Post' 22 | 23 | class first_post: 24 | title = "1st test post" 25 | body = "this one's about python" 26 | author = UserData.ben 27 | categories = [CategoryData.python] 28 | 29 | class second_post(first_post): 30 | title = "2nd test post" 31 | body = "this one's also about python" 32 | 33 | class third_post(first_post): 34 | title = "3rd test post" 35 | body = "this one's about both" 36 | categories = [CategoryData.python, CategoryData.testing] 37 | -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/datasets/user_data.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from fixture import DataSet 4 | 5 | 6 | class UserData(DataSet): 7 | 8 | class Meta: 9 | django_model = 'auth.User' 10 | 11 | class ben: 12 | first_name = 'Ben' 13 | last_name = 'Ford' 14 | username = 'ben' 15 | email = 'ben@ben.com' 16 | password = 'sha1$3f491$e891eaf8c62bfcd37ee2b70cea0b2491941fd134' 17 | is_staff = True 18 | is_active = True 19 | is_superuser = True 20 | date_joined = datetime(2009, 3, 5) 21 | -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-23 15:55 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='Category', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('title', models.CharField(max_length=100, verbose_name='title')), 24 | ('slug', models.SlugField(unique=True, verbose_name='slug')), 25 | ], 26 | ), 27 | migrations.CreateModel( 28 | name='Post', 29 | fields=[ 30 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 31 | ('title', models.CharField(max_length=200, verbose_name='title')), 32 | ('body', models.TextField(verbose_name='body')), 33 | ('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), 34 | ('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), 35 | ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 36 | ('categories', models.ManyToManyField(blank=True, to='blog.Category')), 37 | ], 38 | ), 39 | ] 40 | -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/django_example/blog/migrations/__init__.py -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.db import models 3 | from django.utils.translation import ugettext_lazy as _ 4 | 5 | 6 | class Category(models.Model): 7 | title = models.CharField(_('title'), max_length=100) 8 | slug = models.SlugField(_('slug'), unique=True) 9 | 10 | def __unicode__(self): 11 | return u'%s' % self.title 12 | 13 | 14 | class Post(models.Model): 15 | title = models.CharField(_('title'), max_length=200) 16 | author = models.ForeignKey(User, blank=True, null=True) 17 | body = models.TextField(_('body')) 18 | created = models.DateTimeField(_('created'), auto_now_add=True) 19 | modified = models.DateTimeField(_('modified'), auto_now=True) 20 | categories = models.ManyToManyField(Category, blank=True) 21 | 22 | def __unicode__(self): 23 | return u'%s' % self.title 24 | -------------------------------------------------------------------------------- /fixture/examples/django_example/blog/tests.py: -------------------------------------------------------------------------------- 1 | 2 | from django.contrib.auth.models import User 3 | 4 | from fixture.django_testcase import FixtureTestCase 5 | from blog.datasets.blog_data import UserData, PostData, CategoryData 6 | from blog.models import Post, Category 7 | 8 | 9 | class TestBlogWithData(FixtureTestCase): 10 | 11 | datasets = [PostData] 12 | 13 | def test_blog_posts(self): 14 | self.assertEquals(Post.objects.all().count(), 3, 15 | "There are 3 blog posts") 16 | post = Post.objects.get(title=PostData.third_post.title) 17 | self.assertEquals(post.categories.count(), 2, 18 | "The 3rd test post is in 2 categories") 19 | 20 | def test_posts_by_category(self): 21 | py = Category.objects.get(title=CategoryData.python.title) 22 | self.assertEquals(py.post_set.count(), 3, 23 | "There are 3 posts in python category") 24 | 25 | def test_posts_by_author(self): 26 | ben = User.objects.get(username=UserData.ben.username) 27 | self.assertEquals(ben.post_set.all().count(), 3, 28 | "Ben has published 3 posts") 29 | -------------------------------------------------------------------------------- /fixture/examples/django_example/django_example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/django_example/django_example/__init__.py -------------------------------------------------------------------------------- /fixture/examples/django_example/django_example/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for django_example project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.9.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.9/ref/settings/ 11 | """ 12 | from tempfile import NamedTemporaryFile 13 | 14 | import os 15 | 16 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = '^18nv9#)@tm-#k73!zwqoqs%7z4&pmo4bnds+7s9f(*)86zx$#' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = [] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | 'app', 42 | 'blog' 43 | ] 44 | 45 | MIDDLEWARE_CLASSES = [ 46 | 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | 'django.middleware.common.CommonMiddleware', 49 | 'django.middleware.csrf.CsrfViewMiddleware', 50 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 51 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 52 | 'django.contrib.messages.middleware.MessageMiddleware', 53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 54 | ] 55 | 56 | ROOT_URLCONF = 'django_example.urls' 57 | 58 | TEMPLATES = [ 59 | { 60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 61 | 'DIRS': [], 62 | 'APP_DIRS': True, 63 | 'OPTIONS': { 64 | 'context_processors': [ 65 | 'django.template.context_processors.debug', 66 | 'django.template.context_processors.request', 67 | 'django.contrib.auth.context_processors.auth', 68 | 'django.contrib.messages.context_processors.messages', 69 | ], 70 | }, 71 | }, 72 | ] 73 | 74 | WSGI_APPLICATION = 'django_example.wsgi.application' 75 | 76 | 77 | # Database 78 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases 79 | 80 | def _generate_temporary_file_path(): 81 | temp_file = NamedTemporaryFile(delete=False) 82 | return temp_file.name 83 | 84 | 85 | DATABASES = { 86 | 'default': { 87 | 'ENGINE': 'django.db.backends.sqlite3', 88 | 'NAME': _generate_temporary_file_path(), 89 | } 90 | } 91 | 92 | 93 | # Password validation 94 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 95 | 96 | AUTH_PASSWORD_VALIDATORS = [ 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 105 | }, 106 | { 107 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 108 | }, 109 | ] 110 | 111 | 112 | # Internationalization 113 | # https://docs.djangoproject.com/en/1.9/topics/i18n/ 114 | 115 | LANGUAGE_CODE = 'en-us' 116 | 117 | TIME_ZONE = 'UTC' 118 | 119 | USE_I18N = True 120 | 121 | USE_L10N = True 122 | 123 | USE_TZ = True 124 | 125 | 126 | # Static files (CSS, JavaScript, Images) 127 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 128 | 129 | STATIC_URL = '/static/' 130 | -------------------------------------------------------------------------------- /fixture/examples/django_example/django_example/urls.py: -------------------------------------------------------------------------------- 1 | """django_example URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.9/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | ] 22 | -------------------------------------------------------------------------------- /fixture/examples/django_example/django_example/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_example project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_example.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /fixture/examples/django_example/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | import fixture.examples 6 | 7 | _EXAMPLE_PROJECT_DIR = os.path.dirname(fixture.examples.__file__) 8 | 9 | _EXAMPLE_PROJECT_PATH = os.path.join(_EXAMPLE_PROJECT_DIR, 'django_example') 10 | 11 | sys.path.append(_EXAMPLE_PROJECT_PATH) 12 | 13 | 14 | if __name__ == "__main__": 15 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_example.settings") 16 | 17 | from django.core.management import execute_from_command_line, call_command 18 | import django 19 | django.setup() 20 | call_command('migrate', interactive=False, verbosity=0) 21 | 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/app.yaml: -------------------------------------------------------------------------------- 1 | application: pypi 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | handlers: 7 | - url: .* 8 | script: gblog/__init__.py -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/gblog/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | import logging 3 | import wsgiref.handlers 4 | from google.appengine.ext import webapp 5 | from gblog.handlers import * 6 | 7 | log = logging.getLogger() 8 | 9 | application = webapp.WSGIApplication([ 10 | (r'/', ListEntries), 11 | ], debug=True) 12 | 13 | def main(): 14 | wsgiref.handlers.CGIHandler().run(application) 15 | 16 | if __name__ == "__main__": 17 | main() -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/gblog/handlers.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import logging 4 | from google.appengine.ext import webapp 5 | from google.appengine.ext.webapp import template 6 | from gblog.models import * 7 | 8 | log = logging.getLogger() 9 | 10 | def tpl_path(template_file_name): 11 | return os.path.join(os.path.dirname(__file__), 'templates', template_file_name) 12 | 13 | class ListEntries(webapp.RequestHandler): 14 | def get(self): 15 | entries = Entry.all() 16 | entries_comments = [(e, [c for c in Comment.all().filter("entry =", e)]) for e in entries] 17 | log.info(entries_comments) 18 | tpl = { 19 | 'entries_comments': entries_comments, 20 | } 21 | self.response.out.write(template.render(tpl_path('list_entries.html'), tpl)) -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/gblog/models.py: -------------------------------------------------------------------------------- 1 | 2 | import logging 3 | from google.appengine.ext import db 4 | 5 | log = logging.getLogger() 6 | 7 | class Entry(db.Model): 8 | title = db.StringProperty() 9 | body = db.TextProperty() 10 | added_on = db.DateTimeProperty(auto_now_add=True) 11 | 12 | class Comment(db.Model): 13 | entry = db.ReferenceProperty(Entry) 14 | comment = db.TextProperty() 15 | added_on = db.DateTimeProperty(auto_now_add=True) 16 | 17 | -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/gblog/templates/list_entries.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Welcome To My Blog 5 | 6 | 7 | {% for entry_comments in entries_comments %} 8 |

    {{ entry_comments.0.title }}

    9 |

    Posted {{ entry_comments.0.added_on|date:"D N jS \a\t P" }}

    10 |

    {{ entry_comments.0.body }}

    11 |

    Comments

    12 | {% for comment in entry_comments.1 %} 13 |

    {{ comment.comment }}

    14 |

    Posted {{ comment.added_on|date:"D N jS \a\t P" }}

    15 | {% endfor %} 16 | {% endfor %} 17 | 18 | -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | 3 | # AUTOGENERATED 4 | 5 | # This index.yaml is automatically updated whenever the dev_appserver 6 | # detects that a new type of query is run. If you want to manage the 7 | # index.yaml file manually, remove the above marker line (the line 8 | # saying "# AUTOGENERATED"). If you want to manage some indexes 9 | # manually, move them above the marker line. The index.yaml file is 10 | # automatically uploaded to the admin console when you next deploy 11 | # your application using appcfg.py. 12 | -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/load_data_locally.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import os 4 | import optparse 5 | from fixture import GoogleDatastoreFixture 6 | from fixture.style import NamedDataStyle 7 | 8 | def main(): 9 | p = optparse.OptionParser(usage="%prog [options]") 10 | default = "/tmp/dev_appserver.datastore" 11 | p.add_option("--datastore_path", default=default, help=( 12 | "Path to datastore file. This must match the value used for " 13 | "the same option when running dev_appserver.py if you want to view the data. " 14 | "Default: %s" % default)) 15 | default = "/tmp/dev_appserver.datastore.history" 16 | p.add_option("--history_path", default=default, help=( 17 | "Path to datastore history file. This doesn't need to match the one you use for " 18 | "dev_appserver.py. Default: %s" % default)) 19 | default = "/usr/local/google_appengine" 20 | p.add_option("--google_path", default=default, help=( 21 | "Path to google module directory. Default: %s" % default)) 22 | (options, args) = p.parse_args() 23 | 24 | if not os.path.exists(options.google_path): 25 | p.error("Could not find google module path at %s. You'll need to specify the path" % options.google_path) 26 | 27 | groot = options.google_path 28 | sys.path.append(groot) 29 | sys.path.append(os.path.join(groot, "lib/django")) 30 | sys.path.append(os.path.join(groot, "lib/webob")) 31 | sys.path.append(os.path.join(groot, "lib/yaml/lib")) 32 | 33 | from google.appengine.tools import dev_appserver 34 | from gblog import models 35 | from tests import datasets 36 | 37 | config, explicit_matcher = dev_appserver.LoadAppConfig(os.path.dirname(__file__), {}) 38 | dev_appserver.SetupStubs( 39 | config.application, 40 | clear_datastore = False, # just removes the files when True 41 | datastore_path = options.datastore_path, 42 | history_path = options.history_path, 43 | login_url = None) 44 | 45 | datafixture = GoogleDatastoreFixture(env=models, style=NamedDataStyle()) 46 | 47 | data = datafixture.data(datasets.CommentData, datasets.EntryData) 48 | data.setup() 49 | print "Data loaded into datastore %s" % (options.datastore_path or "[default]") 50 | 51 | if __name__ == '__main__': 52 | main() -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/setup.cfg: -------------------------------------------------------------------------------- 1 | 2 | # sets options for nosetests automatically: 3 | 4 | [nosetests] 5 | with-gae=1 -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/google_appengine_example/tests/__init__.py -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/tests/datasets.py: -------------------------------------------------------------------------------- 1 | 2 | from fixture import DataSet 3 | 4 | __all__ = ['EntryData', 'CommentData'] 5 | 6 | class EntryData(DataSet): 7 | class great_monday: 8 | title = "Monday Was Great" 9 | body = """\ 10 | Monday was the best day ever. I got up (a little late, but that's OK) then I ground some coffee. Mmmm ... coffee! I love coffee. Do you know about Metropolis coffee? It's amazing. Delicious. I drank a beautiful cup of french pressed Spice Island, had a shave and went to work. What a day! 11 | """ 12 | 13 | class CommentData(DataSet): 14 | class monday_liked_it: 15 | entry = EntryData.great_monday 16 | comment = """\ 17 | I'm so glad you have a blog because I want to know what you are doing everyday. Heh, that sounds creepy. What I mean is it's so COOL that you had a great Monday. I like Mondays too. 18 | """ 19 | class monday_sucked: 20 | entry = EntryData.great_monday 21 | comment = """\ 22 | Are you serious? Mannnnnn, Monday really sucked. 23 | """ -------------------------------------------------------------------------------- /fixture/examples/google_appengine_example/tests/test_list_entries.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | from fixture import GoogleDatastoreFixture, DataSet 4 | from fixture.style import NamedDataStyle 5 | from gblog import application, models 6 | from webtest import TestApp 7 | from datasets import CommentData, EntryData 8 | 9 | datafixture = GoogleDatastoreFixture(env=models, style=NamedDataStyle()) 10 | 11 | class TestListEntries(unittest.TestCase): 12 | def setUp(self): 13 | self.app = TestApp(application) 14 | self.data = datafixture.data(CommentData, EntryData) 15 | self.data.setup() 16 | 17 | def tearDown(self): 18 | self.data.teardown() 19 | 20 | def test_entries(self): 21 | response = self.app.get("/") 22 | print response 23 | 24 | assert EntryData.great_monday.title in response 25 | assert EntryData.great_monday.body in response 26 | 27 | assert CommentData.monday_liked_it.comment in response 28 | assert CommentData.monday_sucked.comment in response -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include addressbook/config/deployment.ini_tmpl 2 | recursive-include addressbook/public * 3 | recursive-include addressbook/templates * 4 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/README.txt: -------------------------------------------------------------------------------- 1 | This file is for you to describe the addressbook application. Typically 2 | you would include information such as the information below: 3 | 4 | Installation and Setup 5 | ====================== 6 | 7 | Install ``addressbook`` using easy_install:: 8 | 9 | easy_install addressbook 10 | 11 | Make a config file as follows:: 12 | 13 | paster make-config addressbook config.ini 14 | 15 | Tweak the config file as appropriate and then setup the application:: 16 | 17 | paster setup-app config.ini 18 | 19 | Then you are ready to go. 20 | 21 | About This Example App 22 | ====================== 23 | 24 | SQLAlchemy support added by following prompts on the command line of paster create. Note that the requirement has been decremented to ==0.4.8 since fixture does not support 0.5+ yet. -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | MANIFEST.in 2 | README.txt 3 | setup.cfg 4 | setup.py 5 | addressbook/__init__.py 6 | addressbook/websetup.py 7 | addressbook.egg-info/PKG-INFO 8 | addressbook.egg-info/SOURCES.txt 9 | addressbook.egg-info/dependency_links.txt 10 | addressbook.egg-info/entry_points.txt 11 | addressbook.egg-info/not-zip-safe 12 | addressbook.egg-info/paster_plugins.txt 13 | addressbook.egg-info/requires.txt 14 | addressbook.egg-info/top_level.txt 15 | addressbook/config/__init__.py 16 | addressbook/config/deployment.ini_tmpl 17 | addressbook/config/environment.py 18 | addressbook/config/middleware.py 19 | addressbook/config/routing.py 20 | addressbook/controllers/__init__.py 21 | addressbook/controllers/book.py 22 | addressbook/controllers/error.py 23 | addressbook/datasets/__init__.py 24 | addressbook/lib/__init__.py 25 | addressbook/lib/app_globals.py 26 | addressbook/lib/base.py 27 | addressbook/lib/helpers.py 28 | addressbook/model/__init__.py 29 | addressbook/model/meta.py 30 | addressbook/public/bg.png 31 | addressbook/public/favicon.ico 32 | addressbook/public/pylons-logo.gif 33 | addressbook/templates/book.mako 34 | addressbook/tests/__init__.py 35 | addressbook/tests/test_models.py 36 | addressbook/tests/functional/__init__.py 37 | addressbook/tests/functional/test_book.py -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/__init__.py -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/config/__init__.py -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/config/deployment.ini_tmpl: -------------------------------------------------------------------------------- 1 | # 2 | # addressbook - Pylons configuration 3 | # 4 | # The %(here)s variable will be replaced with the parent directory of this file 5 | # 6 | [DEFAULT] 7 | debug = true 8 | email_to = you@yourdomain.com 9 | smtp_server = localhost 10 | error_email_from = paste@localhost 11 | 12 | [server:main] 13 | use = egg:Paste#http 14 | host = 0.0.0.0 15 | port = 5000 16 | 17 | [app:main] 18 | use = egg:addressbook 19 | full_stack = true 20 | static_files = true 21 | 22 | cache_dir = %(here)s/data 23 | beaker.session.key = addressbook 24 | beaker.session.secret = ${app_instance_secret} 25 | app_instance_uuid = ${app_instance_uuid} 26 | 27 | # If you'd like to fine-tune the individual locations of the cache data dirs 28 | # for the Cache data, or the Session saves, un-comment the desired settings 29 | # here: 30 | #beaker.cache.data_dir = %(here)s/data/cache 31 | #beaker.session.data_dir = %(here)s/data/sessions 32 | 33 | # SQLAlchemy database URL 34 | sqlalchemy.url = sqlite:///production.db 35 | 36 | # WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* 37 | # Debug mode will enable the interactive debugging tool, allowing ANYONE to 38 | # execute malicious code after an exception is raised. 39 | set debug = false 40 | 41 | 42 | # Logging configuration 43 | [loggers] 44 | keys = root 45 | 46 | [handlers] 47 | keys = console 48 | 49 | [formatters] 50 | keys = generic 51 | 52 | [logger_root] 53 | level = INFO 54 | handlers = console 55 | 56 | [handler_console] 57 | class = StreamHandler 58 | args = (sys.stderr,) 59 | level = NOTSET 60 | formatter = generic 61 | 62 | [formatter_generic] 63 | format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s 64 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/config/environment.py: -------------------------------------------------------------------------------- 1 | """Pylons environment configuration""" 2 | import os 3 | 4 | from mako.lookup import TemplateLookup 5 | from pylons import config 6 | from pylons.error import handle_mako_error 7 | from sqlalchemy import engine_from_config 8 | 9 | import addressbook.lib.app_globals as app_globals 10 | import addressbook.lib.helpers 11 | from addressbook.config.routing import make_map 12 | from addressbook.model import init_model 13 | 14 | def load_environment(global_conf, app_conf): 15 | """Configure the Pylons environment via the ``pylons.config`` 16 | object 17 | """ 18 | # Pylons paths 19 | root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 20 | paths = dict(root=root, 21 | controllers=os.path.join(root, 'controllers'), 22 | static_files=os.path.join(root, 'public'), 23 | templates=[os.path.join(root, 'templates')]) 24 | 25 | # Initialize config with the basic options 26 | config.init_app(global_conf, app_conf, package='addressbook', paths=paths) 27 | 28 | config['routes.map'] = make_map() 29 | config['pylons.app_globals'] = app_globals.Globals() 30 | config['pylons.h'] = addressbook.lib.helpers 31 | 32 | # Create the Mako TemplateLookup, with the default auto-escaping 33 | config['pylons.app_globals'].mako_lookup = TemplateLookup( 34 | directories=paths['templates'], 35 | error_handler=handle_mako_error, 36 | module_directory=os.path.join(app_conf['cache_dir'], 'templates'), 37 | input_encoding='utf-8', default_filters=['escape'], 38 | imports=['from webhelpers.html import escape']) 39 | 40 | # Setup the SQLAlchemy database engine 41 | engine = engine_from_config(config, 'sqlalchemy.') 42 | init_model(engine) 43 | 44 | # CONFIGURATION OPTIONS HERE (note: all config options will override 45 | # any Pylons config options) 46 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/config/middleware.py: -------------------------------------------------------------------------------- 1 | """Pylons middleware initialization""" 2 | from beaker.middleware import CacheMiddleware, SessionMiddleware 3 | from paste.cascade import Cascade 4 | from paste.registry import RegistryManager 5 | from paste.urlparser import StaticURLParser 6 | from paste.deploy.converters import asbool 7 | from pylons import config 8 | from pylons.middleware import ErrorHandler, StatusCodeRedirect 9 | from pylons.wsgiapp import PylonsApp 10 | from routes.middleware import RoutesMiddleware 11 | 12 | from addressbook.config.environment import load_environment 13 | 14 | def make_app(global_conf, full_stack=True, static_files=True, **app_conf): 15 | """Create a Pylons WSGI application and return it 16 | 17 | ``global_conf`` 18 | The inherited configuration for this application. Normally from 19 | the [DEFAULT] section of the Paste ini file. 20 | 21 | ``full_stack`` 22 | Whether this application provides a full WSGI stack (by default, 23 | meaning it handles its own exceptions and errors). Disable 24 | full_stack when this application is "managed" by another WSGI 25 | middleware. 26 | 27 | ``static_files`` 28 | Whether this application serves its own static files; disable 29 | when another web server is responsible for serving them. 30 | 31 | ``app_conf`` 32 | The application's local configuration. Normally specified in 33 | the [app:] section of the Paste ini file (where 34 | defaults to main). 35 | 36 | """ 37 | # Configure the Pylons environment 38 | load_environment(global_conf, app_conf) 39 | 40 | # The Pylons WSGI app 41 | app = PylonsApp() 42 | 43 | # Routing/Session/Cache Middleware 44 | app = RoutesMiddleware(app, config['routes.map']) 45 | app = SessionMiddleware(app, config) 46 | app = CacheMiddleware(app, config) 47 | 48 | # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares) 49 | 50 | if asbool(full_stack): 51 | # Handle Python exceptions 52 | app = ErrorHandler(app, global_conf, **config['pylons.errorware']) 53 | 54 | # Display error documents for 401, 403, 404 status codes (and 55 | # 500 when debug is disabled) 56 | if asbool(config['debug']): 57 | app = StatusCodeRedirect(app) 58 | else: 59 | app = StatusCodeRedirect(app, [400, 401, 403, 404, 500]) 60 | 61 | # Establish the Registry for this application 62 | app = RegistryManager(app) 63 | 64 | if asbool(static_files): 65 | # Serve static files 66 | static_app = StaticURLParser(config['pylons.paths']['static_files']) 67 | app = Cascade([static_app, app]) 68 | 69 | return app 70 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/config/routing.py: -------------------------------------------------------------------------------- 1 | """Routes configuration 2 | 3 | The more specific and detailed routes should be defined first so they 4 | may take precedent over the more generic routes. For more information 5 | refer to the routes manual at http://routes.groovie.org/docs/ 6 | """ 7 | from pylons import config 8 | from routes import Mapper 9 | 10 | def make_map(): 11 | """Create, configure and return the routes Mapper""" 12 | map = Mapper(directory=config['pylons.paths']['controllers'], 13 | always_scan=config['debug']) 14 | map.minimization = False 15 | 16 | # The ErrorController route (handles 404/500 error pages); it should 17 | # likely stay at the top, ensuring it can always be resolved 18 | map.connect('/error/{action}', controller='error') 19 | map.connect('/error/{action}/{id}', controller='error') 20 | 21 | # CUSTOM ROUTES HERE 22 | map.connect('/', controller='book', action='index') 23 | 24 | map.connect('/{controller}/{action}') 25 | map.connect('/{controller}/{action}/{id}') 26 | 27 | return map 28 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/controllers/__init__.py -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/controllers/book.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from pylons import request, response, session, tmpl_context as c 4 | from pylons.controllers.util import abort, redirect_to 5 | 6 | from addressbook.lib.base import BaseController, render 7 | from addressbook.model import meta, Person 8 | 9 | log = logging.getLogger(__name__) 10 | 11 | class BookController(BaseController): 12 | 13 | def index(self): 14 | # c, imported from addressbook/lib/base.py, is automatically 15 | # available in your template 16 | c.persons = meta.Session.query(Person).join('my_addresses') 17 | return render("/book.mako") 18 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/controllers/error.py: -------------------------------------------------------------------------------- 1 | import cgi 2 | 3 | from paste.urlparser import PkgResourcesParser 4 | from pylons import request 5 | from pylons.controllers.util import forward 6 | from pylons.middleware import error_document_template 7 | from webhelpers.html.builder import literal 8 | 9 | from addressbook.lib.base import BaseController 10 | 11 | class ErrorController(BaseController): 12 | 13 | """Generates error documents as and when they are required. 14 | 15 | The ErrorDocuments middleware forwards to ErrorController when error 16 | related status codes are returned from the application. 17 | 18 | This behaviour can be altered by changing the parameters to the 19 | ErrorDocuments middleware in your config/middleware.py file. 20 | 21 | """ 22 | 23 | def document(self): 24 | """Render the error document""" 25 | resp = request.environ.get('pylons.original_response') 26 | content = literal(resp.body) or cgi.escape(request.GET.get('message', '')) 27 | page = error_document_template % \ 28 | dict(prefix=request.environ.get('SCRIPT_NAME', ''), 29 | code=cgi.escape(request.GET.get('code', str(resp.status_int))), 30 | message=content) 31 | return page 32 | 33 | def img(self, id): 34 | """Serve Pylons' stock images""" 35 | return self._serve_file('/'.join(['media/img', id])) 36 | 37 | def style(self, id): 38 | """Serve Pylons' stock stylesheets""" 39 | return self._serve_file('/'.join(['media/style', id])) 40 | 41 | def _serve_file(self, path): 42 | """Call Paste's FileApp (a WSGI application) to serve the file 43 | at the specified path 44 | """ 45 | request.environ['PATH_INFO'] = '/%s' % path 46 | return forward(PkgResourcesParser('pylons', 'pylons')) 47 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from fixture import DataSet 3 | 4 | class AddressData(DataSet): 5 | class joe_in_montego: 6 | address = "111 St. James St, Montego Bay, Jamaica" 7 | class joe_in_ny: 8 | address = "111 S. 2nd Ave, New York, NY" 9 | 10 | class PersonData(DataSet): 11 | class joe_gibbs: 12 | name = "Joe Gibbs" 13 | email = "joe@joegibbs.com" 14 | my_addresses = [ 15 | AddressData.joe_in_montego, 16 | AddressData.joe_in_ny] -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/lib/__init__.py -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/lib/app_globals.py: -------------------------------------------------------------------------------- 1 | """The application's Globals object""" 2 | 3 | class Globals(object): 4 | 5 | """Globals acts as a container for objects available throughout the 6 | life of the application 7 | 8 | """ 9 | 10 | def __init__(self): 11 | """One instance of Globals is created during application 12 | initialization and is available during requests via the 13 | 'app_globals' variable 14 | 15 | """ 16 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/lib/base.py: -------------------------------------------------------------------------------- 1 | """The base Controller API 2 | 3 | Provides the BaseController class for subclassing. 4 | """ 5 | from pylons.controllers import WSGIController 6 | from pylons.templating import render_mako as render 7 | 8 | from addressbook.model import meta 9 | 10 | class BaseController(WSGIController): 11 | 12 | def __call__(self, environ, start_response): 13 | """Invoke the Controller""" 14 | # WSGIController.__call__ dispatches to the Controller method 15 | # the request is routed to. This routing information is 16 | # available in environ['pylons.routes_dict'] 17 | try: 18 | return WSGIController.__call__(self, environ, start_response) 19 | finally: 20 | meta.Session.remove() 21 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/lib/helpers.py: -------------------------------------------------------------------------------- 1 | """Helper functions 2 | 3 | Consists of functions to typically be used within templates, but also 4 | available to Controllers. This module is available to templates as 'h'. 5 | """ 6 | # Import helpers as desired, or define your own, ie: 7 | #from webhelpers.html.tags import checkbox, password 8 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/model/__init__.py: -------------------------------------------------------------------------------- 1 | """The application's model objects""" 2 | import sqlalchemy as sa 3 | from sqlalchemy import orm 4 | 5 | from addressbook.model import meta 6 | 7 | def init_model(engine): 8 | """Call me before using any of the tables or classes in the model""" 9 | meta.Session.configure(bind=engine) 10 | meta.engine = engine 11 | 12 | t_people = sa.Table('people', meta.metadata, 13 | sa.Column('id', sa.types.Integer, primary_key=True), 14 | sa.Column('name', sa.types.String(100)), 15 | sa.Column('email', sa.types.String(100)) 16 | ) 17 | 18 | t_addresses_people = sa.Table('addresses_people', meta.metadata, 19 | sa.Column('id', sa.types.Integer, primary_key=True), 20 | sa.Column('person_id', sa.types.Integer, sa.ForeignKey('people.id')), 21 | sa.Column('address_id', sa.types.Integer, sa.ForeignKey('addresses.id')) 22 | ) 23 | 24 | t_addresses = sa.Table('addresses', meta.metadata, 25 | sa.Column('id', sa.types.Integer, primary_key=True), 26 | sa.Column('address', sa.types.String(100)) 27 | ) 28 | 29 | class Person(object): 30 | pass 31 | 32 | class Address(object): 33 | pass 34 | 35 | orm.mapper(Address, t_addresses) 36 | orm.mapper(Person, t_people, properties = { 37 | 'my_addresses' : orm.relation(Address, secondary = t_addresses_people), 38 | }) 39 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/model/meta.py: -------------------------------------------------------------------------------- 1 | """SQLAlchemy Metadata and Session object""" 2 | from sqlalchemy import MetaData 3 | from sqlalchemy.orm import scoped_session, sessionmaker 4 | 5 | __all__ = ['Session', 'engine', 'metadata'] 6 | 7 | # SQLAlchemy database engine. Updated by model.init_model() 8 | engine = None 9 | 10 | # SQLAlchemy session manager. Updated by model.init_model() 11 | Session = scoped_session(sessionmaker()) 12 | 13 | # Global metadata. If you have multiple databases with overlapping table 14 | # names, you'll need a metadata for each database 15 | metadata = MetaData() 16 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/public/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/public/bg.png -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/public/favicon.ico -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/public/pylons-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/public/pylons-logo.gif -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/templates/book.mako: -------------------------------------------------------------------------------- 1 |

    2 | Address Book 3 |

    4 | 5 | % for person in c.persons: 6 |

    ${person.name}

    7 |

    ${person.email}

    8 | % for address in person.my_addresses: 9 |

    ${address.address}

    10 | % endfor 11 | % endfor 12 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Pylons application test package 2 | 3 | This package assumes the Pylons environment is already loaded, such as 4 | when this script is imported from the `nosetests --with-pylons=test.ini` 5 | command. 6 | 7 | This module initializes the application via ``websetup`` (`paster 8 | setup-app`) and provides the base testing objects. 9 | """ 10 | from unittest import TestCase 11 | 12 | from paste.deploy import loadapp 13 | from paste.script.appinstall import SetupCommand 14 | from pylons import config, url 15 | from routes.util import URLGenerator 16 | from webtest import TestApp 17 | 18 | # additional imports ... 19 | from paste.deploy import appconfig 20 | from addressbook.config.environment import load_environment 21 | 22 | import pylons.test 23 | 24 | # export dbfixture here for tests : 25 | __all__ = ['environ', 'url', 'TestController', 'dbfixture'] 26 | 27 | # Invoke websetup with the current config file 28 | ##### comment this out so that initial data isn't loaded: 29 | # SetupCommand('setup-app').run([config['__file__']]) 30 | 31 | ##### but add this so that your models get configured: 32 | appconf = appconfig('config:' + config['__file__']) 33 | load_environment(appconf.global_conf, appconf.local_conf) 34 | 35 | environ = {} 36 | 37 | from addressbook import model 38 | from addressbook.model import meta 39 | from fixture import SQLAlchemyFixture 40 | from fixture.style import NamedDataStyle 41 | 42 | dbfixture = SQLAlchemyFixture( 43 | env=model, 44 | engine=meta.engine, 45 | style=NamedDataStyle() 46 | ) 47 | 48 | def setup(): 49 | meta.metadata.create_all(meta.engine) 50 | 51 | def teardown(): 52 | meta.metadata.drop_all(meta.engine) 53 | 54 | class TestController(TestCase): 55 | 56 | def __init__(self, *args, **kwargs): 57 | if pylons.test.pylonsapp: 58 | wsgiapp = pylons.test.pylonsapp 59 | else: 60 | wsgiapp = loadapp('config:%s' % config['__file__']) 61 | self.app = TestApp(wsgiapp) 62 | url._push_object(URLGenerator(config['routes.map'], environ)) 63 | TestCase.__init__(self, *args, **kwargs) 64 | 65 | def setUp(self): 66 | # remove the session once per test so that 67 | # objects do not leak from test to test 68 | meta.Session.remove() 69 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/tests/functional/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/tests/functional/__init__.py -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/tests/functional/test_book.py: -------------------------------------------------------------------------------- 1 | 2 | from addressbook.model import meta, Person 3 | from addressbook.datasets import PersonData, AddressData 4 | from addressbook.tests import * 5 | 6 | class TestBookController(TestController): 7 | 8 | def setUp(self): 9 | super(TestBookController, self).setUp() 10 | self.data = dbfixture.data(PersonData) # AddressData loads implicitly 11 | self.data.setup() 12 | 13 | def tearDown(self): 14 | self.data.teardown() 15 | super(TestBookController, self).tearDown() 16 | 17 | def test_index(self): 18 | response = self.app.get(url(controller='book')) 19 | print response 20 | assert PersonData.joe_gibbs.name in response 21 | assert PersonData.joe_gibbs.email in response 22 | assert AddressData.joe_in_montego.address in response 23 | assert AddressData.joe_in_ny.address in response -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/tests/test_models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/examples/pylons_example/addressbook/addressbook/tests/test_models.py -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/addressbook/websetup.py: -------------------------------------------------------------------------------- 1 | """Setup the addressbook application""" 2 | import logging 3 | 4 | from addressbook.config.environment import load_environment 5 | from addressbook.model import meta 6 | 7 | from addressbook import model 8 | from fixture import SQLAlchemyFixture 9 | from fixture.style import NamedDataStyle 10 | from addressbook.datasets import PersonData 11 | 12 | log = logging.getLogger(__name__) 13 | 14 | def setup_app(command, conf, vars): 15 | """Place any commands to setup addressbook here""" 16 | load_environment(conf.global_conf, conf.local_conf) 17 | 18 | log.info("Creating tables") 19 | # Create the tables if they don't already exist 20 | meta.metadata.create_all(bind=meta.engine) 21 | log.info("Successfully setup") 22 | 23 | # load some initial data during setup-app : 24 | 25 | db = SQLAlchemyFixture( 26 | env=model, style=NamedDataStyle(), 27 | engine=meta.engine) 28 | 29 | data = db.data(PersonData) 30 | log.info("Inserting initial data") 31 | data.setup() 32 | log.info("Done") 33 | 34 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/development.ini: -------------------------------------------------------------------------------- 1 | # 2 | # addressbook - Pylons development environment configuration 3 | # 4 | # The %(here)s variable will be replaced with the parent directory of this file 5 | # 6 | [DEFAULT] 7 | debug = true 8 | # Uncomment and replace with the address which should receive any error reports 9 | #email_to = you@yourdomain.com 10 | smtp_server = localhost 11 | error_email_from = paste@localhost 12 | 13 | [server:main] 14 | use = egg:Paste#http 15 | host = 127.0.0.1 16 | port = 5000 17 | 18 | [app:main] 19 | use = egg:addressbook 20 | full_stack = true 21 | static_files = true 22 | 23 | cache_dir = %(here)s/data 24 | beaker.session.key = addressbook 25 | beaker.session.secret = somesecret 26 | 27 | # If you'd like to fine-tune the individual locations of the cache data dirs 28 | # for the Cache data, or the Session saves, un-comment the desired settings 29 | # here: 30 | #beaker.cache.data_dir = %(here)s/data/cache 31 | #beaker.session.data_dir = %(here)s/data/sessions 32 | 33 | # SQLAlchemy database URL 34 | sqlalchemy.url = sqlite:///%(here)s/development.db 35 | 36 | # WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* 37 | # Debug mode will enable the interactive debugging tool, allowing ANYONE to 38 | # execute malicious code after an exception is raised. 39 | #set debug = false 40 | 41 | 42 | # Logging configuration 43 | [loggers] 44 | keys = root, routes, addressbook, sqlalchemy 45 | 46 | [handlers] 47 | keys = console 48 | 49 | [formatters] 50 | keys = generic 51 | 52 | [logger_root] 53 | level = INFO 54 | handlers = console 55 | 56 | [logger_routes] 57 | level = INFO 58 | handlers = 59 | qualname = routes.middleware 60 | # "level = DEBUG" logs the route matched and routing variables. 61 | 62 | [logger_addressbook] 63 | level = DEBUG 64 | handlers = 65 | qualname = addressbook 66 | 67 | [logger_sqlalchemy] 68 | level = INFO 69 | handlers = 70 | qualname = sqlalchemy.engine 71 | # "level = INFO" logs SQL queries. 72 | # "level = DEBUG" logs SQL queries and results. 73 | # "level = WARN" logs neither. (Recommended for production systems.) 74 | 75 | [handler_console] 76 | class = StreamHandler 77 | args = (sys.stderr,) 78 | level = NOTSET 79 | formatter = generic 80 | 81 | [formatter_generic] 82 | format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s 83 | datefmt = %H:%M:%S 84 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/docs/index.txt: -------------------------------------------------------------------------------- 1 | addressbook 2 | +++++++++++ 3 | 4 | This is the main index page of your documentation. It should be written in 5 | `reStructuredText format `_. 6 | 7 | You can generate your documentation in HTML format by running this command:: 8 | 9 | setup.py pudge 10 | 11 | For this to work you will need to download and install ``buildutils`` and 12 | ``pudge``. 13 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_build = dev 3 | tag_svn_revision = true 4 | 5 | [easy_install] 6 | find_links = http://www.pylonshq.com/download/ 7 | 8 | [nosetests] 9 | with-pylons = test.ini 10 | 11 | # Babel configuration 12 | [compile_catalog] 13 | domain = addressbook 14 | directory = addressbook/i18n 15 | statistics = true 16 | 17 | [extract_messages] 18 | add_comments = TRANSLATORS: 19 | output_file = addressbook/i18n/addressbook.pot 20 | width = 80 21 | 22 | [init_catalog] 23 | domain = addressbook 24 | input_file = addressbook/i18n/addressbook.pot 25 | output_dir = addressbook/i18n 26 | 27 | [update_catalog] 28 | domain = addressbook 29 | input_file = addressbook/i18n/addressbook.pot 30 | output_dir = addressbook/i18n 31 | previous = true 32 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | setup( 5 | name='addressbook', 6 | version='0.1', 7 | description='', 8 | author='', 9 | author_email='', 10 | url='', 11 | install_requires=[ 12 | "Routes==1.10.3", 13 | "Pylons==0.9.7", 14 | "SQLAlchemy==0.4.8", 15 | ], 16 | setup_requires=["PasteScript>=1.6.3"], 17 | packages=find_packages(exclude=['ez_setup']), 18 | include_package_data=True, 19 | test_suite='nose.collector', 20 | package_data={'addressbook': ['i18n/*/LC_MESSAGES/*.mo']}, 21 | #message_extractors={'addressbook': [ 22 | # ('**.py', 'python', None), 23 | # ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}), 24 | # ('public/**', 'ignore', None)]}, 25 | zip_safe=False, 26 | paster_plugins=['PasteScript', 'Pylons'], 27 | entry_points=""" 28 | [paste.app_factory] 29 | main = addressbook.config.middleware:make_app 30 | 31 | [paste.app_install] 32 | main = pylons.util:PylonsInstaller 33 | """, 34 | ) 35 | -------------------------------------------------------------------------------- /fixture/examples/pylons_example/addressbook/test.ini: -------------------------------------------------------------------------------- 1 | # 2 | # addressbook - Pylons testing environment configuration 3 | # 4 | # The %(here)s variable will be replaced with the parent directory of this file 5 | # 6 | [DEFAULT] 7 | debug = true 8 | # Uncomment and replace with the address which should receive any error reports 9 | #email_to = you@yourdomain.com 10 | smtp_server = localhost 11 | error_email_from = paste@localhost 12 | 13 | [server:main] 14 | use = egg:Paste#http 15 | host = 127.0.0.1 16 | port = 5000 17 | 18 | [app:main] 19 | use = config:development.ini 20 | 21 | # Add additional test specific configuration options as necessary. 22 | sqlalchemy.url = sqlite:///%(here)s/tests.db -------------------------------------------------------------------------------- /fixture/exc.py: -------------------------------------------------------------------------------- 1 | 2 | """Fixture exceptions""" 3 | 4 | class UninitializedError(Exception): 5 | pass 6 | 7 | class DataSetActionException(Exception): 8 | """ 9 | An exception while performing some action with a DataSet. 10 | 11 | In addtion to ``etype`` and ``val`` adds these properties: 12 | 13 | ``dataset`` 14 | :class:`DataSet ` that caused the exception 15 | 16 | ``key`` 17 | Key on DataSet row if there is one 18 | 19 | ``row`` 20 | :class:`DataRow ` if there is one 21 | 22 | ``stored_object`` 23 | Stored object if there is one 24 | 25 | used by :mod:`fixture.loadable` classes 26 | """ 27 | def __init__(self, etype, val, dataset, 28 | key=None, row=None, stored_object=None): 29 | msg = "in %s" % dataset 30 | if key or row: 31 | msg = "with '%s' of '%s' %s" % (key, row, msg) 32 | elif stored_object: 33 | msg = "with %s %s" % (stored_object, msg) 34 | 35 | Exception.__init__(self, "%s: %s (%s)" % (etype.__name__, val, msg)) 36 | 37 | class LoadError(DataSetActionException): 38 | """ 39 | An exception while loading data in DataSet. 40 | 41 | used by :mod:`fixture.loadable` classes 42 | """ 43 | pass 44 | class UnloadError(DataSetActionException): 45 | """ 46 | An exception while unloading data from a DataSet. 47 | 48 | used by :mod:`fixture.loadable` classes 49 | """ 50 | pass 51 | 52 | class StorageMediaNotFound(LookupError): 53 | """ 54 | Looking up a storable object failed. 55 | 56 | used by :mod:`fixture.loadable` classes 57 | """ 58 | pass -------------------------------------------------------------------------------- /fixture/loadable/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """Loadable fixture components""" 3 | 4 | __all__ = ['SQLAlchemyFixture', 'SQLObjectFixture', 'GoogleDatastoreFixture', 5 | 'DjangoFixture', 'StormFixture'] 6 | from fixture.loadable import loadable 7 | __doc__ = loadable.__doc__ 8 | from fixture.loadable.loadable import * 9 | from fixture.loadable.sqlalchemy_loadable import SQLAlchemyFixture 10 | from fixture.loadable.sqlobject_loadable import SQLObjectFixture 11 | from fixture.loadable.google_datastore_loadable import GoogleDatastoreFixture 12 | from fixture.loadable.django_loadable import DjangoFixture 13 | from fixture.loadable.storm_loadable import StormFixture 14 | -------------------------------------------------------------------------------- /fixture/loadable/google_datastore_loadable.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components for loading and unloading data using the Google App Engine `Datastore`_. 3 | 4 | Added in version 1.1 5 | 6 | .. _Datastore: http://code.google.com/appengine/docs/datastore/ 7 | 8 | """ 9 | 10 | from fixture.loadable import EnvLoadableFixture 11 | 12 | class EntityMedium(EnvLoadableFixture.StorageMediumAdapter): 13 | """ 14 | Adapts google.appengine.api.datastore.Entity objects and any 15 | other object that is an instance of Entity 16 | """ 17 | def _entities_to_keys(self, mylist): 18 | """Converts an array of datastore objects to an array of keys. 19 | 20 | if the value passed in is not a list, this passes it through as is 21 | """ 22 | if type(mylist)==type([]): 23 | if all(map(lambda x: hasattr(x,'key'),mylist)): 24 | return [ent.key() for ent in mylist] 25 | else: # ...no type checks... 26 | return mylist 27 | else: 28 | return mylist 29 | 30 | def clear(self, obj): 31 | """Delete this entity from the Datastore""" 32 | obj.delete() 33 | 34 | def save(self, row, column_vals): 35 | """Save this entity to the Datastore""" 36 | gen=[(k,self._entities_to_keys(v)) for k,v in column_vals] 37 | entity = self.medium( 38 | **dict(gen) 39 | ) 40 | entity.put() 41 | return entity 42 | 43 | class GoogleDatastoreFixture(EnvLoadableFixture): 44 | """ 45 | A fixture that knows how to load DataSet objects into Google Datastore `Entity`_ objects. 46 | 47 | >>> from fixture import GoogleDatastoreFixture 48 | 49 | See :ref:`Using Fixture With Google App Engine ` for a complete example. 50 | 51 | .. _Entity: http://code.google.com/appengine/docs/datastore/entitiesandmodels.html 52 | 53 | Keyword Arguments: 54 | 55 | ``style`` 56 | A :class:`Style ` object to translate names with 57 | 58 | ``env`` 59 | A dict or module that contains Entity classes. This will be searched when 60 | :class:`Style ` translates DataSet names into 61 | storage media. See :meth:`EnvLoadableFixture.attach_storage_medium ` for details on 62 | how ``env`` works. 63 | 64 | ``dataclass`` 65 | :class:`SuperSet ` class to represent loaded data with 66 | 67 | ``medium`` 68 | A custom :class:`StorageMediumAdapter ` 69 | class to instantiate when storing a DataSet. 70 | By default, an Entity adapter will be used so you should only set a custom medium 71 | if you know what you doing. 72 | 73 | Added in version 1.1 74 | """ 75 | Medium = EntityMedium 76 | 77 | def commit(self): 78 | pass 79 | 80 | def rollback(self): 81 | pass 82 | -------------------------------------------------------------------------------- /fixture/loadable/sqlobject_loadable.py: -------------------------------------------------------------------------------- 1 | 2 | """Components for loading and unloading data using `SQLObject`_. 3 | 4 | See :ref:`Using LoadableFixture` for examples. 5 | 6 | .. _SQLObject: http://www.sqlobject.org/ 7 | 8 | """ 9 | 10 | from fixture.loadable import DBLoadableFixture 11 | 12 | class SQLObjectMedium(DBLoadableFixture.StorageMediumAdapter): 13 | """ 14 | Adapter for storing data using `SQLObject`_ classes 15 | """ 16 | def clear(self, obj): 17 | """Delete this object from the DB""" 18 | obj.destroySelf() 19 | 20 | def save(self, row, column_vals): 21 | """Save this row to the DB""" 22 | from sqlobject.styles import getStyle 23 | so_style = getStyle(self.medium) 24 | 25 | if hasattr(row, 'connection'): 26 | raise ValueError( 27 | "cannot name a key 'connection' in row %s" % row) 28 | dbvals = dict([(so_style.dbColumnToPythonAttr(k), v) 29 | for k,v in column_vals]) 30 | dbvals['connection'] = self.transaction 31 | return self.medium(**dbvals) 32 | 33 | def visit_loader(self, loader): 34 | """Visit the loader and store a reference to the transaction connection""" 35 | self.transaction = loader.transaction 36 | 37 | class SQLObjectFixture(DBLoadableFixture): 38 | """ 39 | A fixture that knows how to load DataSet objects via `SQLObject`_ classes. 40 | 41 | >>> from fixture import SQLObjectFixture 42 | 43 | Keyword Arguments: 44 | 45 | ``style`` 46 | A :class:`Style ` object to translate names with 47 | 48 | ``env`` 49 | A dict or module that contains `SQLObject`_ classes. The :class:`Style ` object will 50 | look here when translating DataSet names into `SQLObject`_ class names. 51 | See :meth:`EnvLoadableFixture.attach_storage_medium ` for details on 52 | how ``env`` works. 53 | 54 | ``dsn`` 55 | A dsn to create a connection with. 56 | 57 | ``dataclass`` 58 | :class:`SuperSet ` class to represent loaded data with 59 | 60 | ``medium`` 61 | A custom :class:`StorageMediumAdapter ` to instantiate when storing a DataSet. 62 | 63 | ``use_transaction`` 64 | If this is true (default), data will be loaded or torn down inside a 65 | transaction. You may have to set this to false to avoid deadlocks. 66 | However, setting it to false may leave partially loaded data behind 67 | if you create an error with your DataSet. 68 | 69 | ``close_conn`` 70 | True if the connection can be closed, helpful for releasing connections. 71 | If you are passing in a connection object this will be False by default. 72 | 73 | """ 74 | 75 | def __init__(self, connection=None, use_transaction=True, 76 | close_conn=False, **kw ): 77 | DBLoadableFixture.__init__(self, **kw) 78 | self.connection = connection 79 | self.close_conn = close_conn 80 | self.use_transaction = use_transaction 81 | 82 | SQLObjectMedium = SQLObjectMedium 83 | Medium = SQLObjectMedium 84 | 85 | def create_transaction(self): 86 | """Return a new transaction for connection""" 87 | from sqlobject import connectionForURI 88 | if not self.connection: 89 | self.connection = connectionForURI(self.dsn) 90 | self.close_conn = True # because we made it 91 | if self.use_transaction: 92 | return self.connection.transaction() 93 | else: 94 | return self.connection 95 | 96 | def commit(self): 97 | """Commit transaction""" 98 | if self.use_transaction: 99 | DBLoadableFixture.commit(self) 100 | 101 | def then_finally(self, unloading=False): 102 | """Unconditionally close the transaction (if configured to do so) after loading data""" 103 | if unloading and self.close_conn: 104 | self.connection.close() 105 | self.connection = None # necessary for gc 106 | 107 | def rollback(self): 108 | """Rollback the transaction""" 109 | if self.use_transaction: 110 | DBLoadableFixture.rollback(self) 111 | -------------------------------------------------------------------------------- /fixture/loadable/storm_loadable.py: -------------------------------------------------------------------------------- 1 | 2 | """Components for loading and unloading data using `Storm`_. 3 | 4 | See :ref:`Using LoadableFixture` for examples. 5 | 6 | .. _Storm: https://storm.canonical.com/ 7 | 8 | """ 9 | 10 | from fixture.loadable import DBLoadableFixture 11 | from fixture.util import _mklog 12 | 13 | stlog = _mklog('fixture.loadable.storm') 14 | 15 | class StormMedium(DBLoadableFixture.StorageMediumAdapter): 16 | 17 | def clear(self, obj): 18 | self.transaction.remove(obj) 19 | 20 | def save(self, row, column_vals): 21 | from storm.info import get_cls_info 22 | from storm.locals import ReferenceSet, Store 23 | 24 | cls_info = get_cls_info(self.medium) 25 | 26 | column_vals = list(column_vals) 27 | pk = [] 28 | for n, v in column_vals: 29 | propid = id(getattr(self.medium, n)) 30 | if propid in cls_info.primary_key_idx: 31 | pk.append((cls_info.primary_key_idx[propid], v, n)) 32 | 33 | assert len(pk) == 0 or len(pk) == len(cls_info.primary_key), ( 34 | "Incomplete primary key see %s need %s" % ( 35 | [x[2] for x in pk], [x.name for x in cls_info.primary_key])) 36 | 37 | if pk: 38 | obj = self.transaction.get(self.medium, tuple([x[1] for x in sorted(pk)])) 39 | else: 40 | obj = None 41 | 42 | if obj is None: 43 | obj = self.medium() 44 | self.transaction.add(obj) 45 | 46 | assert Store.of(obj) is self.transaction 47 | 48 | for n, v in column_vals: 49 | if isinstance(getattr(self.medium,n), ReferenceSet): 50 | getattr(obj, n).add(v) 51 | else: 52 | setattr(obj, n, v) 53 | 54 | self.transaction.flush() 55 | stlog.info("%s %s", obj, [(n,getattr(obj,n)) for n in row.columns()]) 56 | 57 | return obj 58 | 59 | def visit_loader(self, loader): 60 | """Visit the loader and store a reference to the transaction connection""" 61 | self.transaction = loader.transaction 62 | 63 | 64 | pass 65 | 66 | class StormFixture(DBLoadableFixture): 67 | StormMedium = StormMedium 68 | Medium = StormMedium 69 | 70 | def __init__(self, store=None, use_transaction=True, 71 | close_store=False, **kw ): 72 | DBLoadableFixture.__init__(self, **kw) 73 | self.store = store 74 | self.close_store = close_store 75 | self.use_transaction = use_transaction 76 | 77 | def create_transaction(self): 78 | return self.store 79 | 80 | 81 | 82 | pass 83 | -------------------------------------------------------------------------------- /fixture/setup_cmd/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/setup_cmd/__init__.py -------------------------------------------------------------------------------- /fixture/setup_cmd/apidocs.py: -------------------------------------------------------------------------------- 1 | from distutils.cmd import Command 2 | import os, sys, shutil 3 | from os import path 4 | import optparse 5 | from fixture import docs 6 | from fixture.test import teardown_examples 7 | from docutils.core import ( 8 | publish_file, publish_string, publish_doctree, publish_from_doctree) 9 | 10 | 11 | class apidocs(Command): 12 | description = "create API documentation" 13 | user_options = [ 14 | # ('optname=', None, ""), 15 | ] 16 | # boolean_options = ['update'] 17 | 18 | def initialize_options(self): 19 | pass 20 | 21 | def finalize_options(self): 22 | pass 23 | 24 | def run(self): 25 | """build API documentation.""" 26 | 27 | # if options.build_dir: 28 | # docs.builddir = options.build_dir 29 | if not path.exists(docs.builddir): 30 | os.mkdir(docs.builddir) 31 | docs.state_is_api = True 32 | from pydoctor.driver import main 33 | argv = [ 34 | '--html-output=%s/apidocs' % docs.builddir, '--project-name=fixture', 35 | '--docformat=restructuredtext', 36 | '--project-url=http://code.google.com/p/fixture/', '--make-html', 37 | '--add-package=fixture', '--verbose', '--verbose'] 38 | 39 | sys.argv[0] = ['pydoctor'] # can't remember why 40 | main(argv) -------------------------------------------------------------------------------- /fixture/style.py: -------------------------------------------------------------------------------- 1 | 2 | """Utilities for deriving new names from existing names. 3 | 4 | Style objects are used to customize how :ref:`storable objects are found for DataSet objects ` 5 | """ 6 | 7 | __all__ = [ 8 | 'CamelAndUndersStyle', 'TrimmedNameStyle', 'NamedDataStyle', 9 | 'PaddedNameStyle', 'ChainedStyle'] 10 | 11 | class Style(object): 12 | """ 13 | Utility for deriving new names from existing names. 14 | 15 | each method receives a name and returns a new name. 16 | """ 17 | def __add__(self, newstyle): 18 | return ChainedStyle(self, newstyle) 19 | 20 | def to_attr(self, name): 21 | """converts name to a new name suitable for an attribute.""" 22 | raise NotImplementedError 23 | 24 | def guess_storable_name(self, name): 25 | """converts a dataset class name to a storage class name.""" 26 | return name 27 | 28 | def __repr__(self): 29 | return "<%s at %s>" % (self.__class__.__name__, hex(id(self))) 30 | 31 | class ChainedStyle(Style): 32 | """ 33 | Combination of two styles, piping first translation 34 | into second translation. 35 | """ 36 | def __init__(self, first_style, next_style): 37 | self.first_style = first_style 38 | self.next_style = next_style 39 | 40 | def __getattribute__(self, c): 41 | def assert_callable(attr): 42 | if not callable(attr): 43 | raise AttributeError( 44 | "%s cannot chain %s" % (self.__class__, attr)) 45 | def chained_call(name): 46 | f = object.__getattribute__(self, 'first_style') 47 | first_call = getattr(f, c) 48 | assert_callable(first_call) 49 | 50 | n = object.__getattribute__(self, 'next_style') 51 | next_call = getattr(n, c) 52 | assert_callable(next_call) 53 | 54 | return next_call(first_call(name)) 55 | return chained_call 56 | 57 | def __repr__(self): 58 | return "%s + %s" % (self.first_style, self.next_style) 59 | 60 | class OriginalStyle(Style): 61 | """ 62 | Style that honors all original names. 63 | """ 64 | def to_attr(self, name): 65 | return name 66 | def guess_storable_name(self, name): 67 | return name 68 | 69 | class CamelAndUndersStyle(Style): 70 | """ 71 | Style that assumes classes are already in came case 72 | but attributes should be underscore separated 73 | """ 74 | def to_attr(self, name): 75 | """ 76 | Derives lower case, underscored names from camel case class names. 77 | 78 | i.e. EmployeeData translates to employee_data 79 | """ 80 | return camel_to_under(name) 81 | 82 | def guess_storable_name(self, name): 83 | """ 84 | Assume a storage name is the same as original. 85 | 86 | i.e. Employee becomes Employee 87 | """ 88 | return name 89 | 90 | class TrimmedNameStyle(Style): 91 | """ 92 | Derives new names from trimming off prefixes/suffixes. 93 | """ 94 | def __init__(self, prefix=None, suffix=None): 95 | self.prefix = prefix 96 | self.suffix = suffix 97 | 98 | def _trim(self, name): 99 | def assert_s(s, name_contains): 100 | assert name_contains(s), ( 101 | "%s expected that '%s' %s '%s'" % ( 102 | self, name, name_contains.__name__, s)) 103 | if self.prefix: 104 | assert_s(self.prefix, name.startswith) 105 | name = name[len(self.prefix):] 106 | if self.suffix: 107 | assert_s(self.suffix, name.endswith) 108 | name = name[0:-len(self.suffix)] 109 | 110 | return name 111 | 112 | def to_attr(self, name): 113 | return self._trim(name) 114 | 115 | def guess_storable_name(self, name): 116 | return self._trim(name) 117 | 118 | class PaddedNameStyle(Style): 119 | """ 120 | Derives new names from padding names with prefixes/suffixes. 121 | """ 122 | def __init__(self, prefix=None, suffix=None): 123 | self.prefix = prefix 124 | self.suffix = suffix 125 | 126 | def _pad(self, name): 127 | if self.prefix: 128 | name = "%s%s" % (self.prefix, name) 129 | if self.suffix: 130 | name = "%s%s" % (name, self.suffix) 131 | return name 132 | 133 | def to_attr(self, name): 134 | return self._pad(name) 135 | 136 | def guess_storable_name(self, name): 137 | return self._pad(name) 138 | 139 | class NamedDataStyle(TrimmedNameStyle): 140 | """ 141 | Derives names from datasets assuming "Data" as a suffix. 142 | 143 | for example, consider this data object and this DataSet:: 144 | 145 | >>> class Author(object): 146 | ... name = None 147 | ... 148 | >>> from fixture import DataSet 149 | >>> class AuthorData(DataSet): 150 | ... class freude: 151 | ... name = "Sigmund Freude" 152 | ... 153 | 154 | if a LoadableFixture is configured with style=NamedDataStyle() then it will 155 | automatically look in its env for the object "Author" when loading the 156 | DataSet named "AuthorData" 157 | 158 | """ 159 | def __init__(self): 160 | TrimmedNameStyle.__init__(self, suffix='Data') 161 | 162 | def camel_to_under(s): 163 | chunks = [] 164 | chkid = None 165 | def newchunk(): 166 | chunks.append('') 167 | return len(chunks)-1 168 | for ltr in s: 169 | if ord(ltr) < 97: 170 | # capital letter : 171 | chkid = newchunk() 172 | if chkid is None: 173 | chkid = newchunk() 174 | 175 | chunks[chkid] = chunks[chkid] + ltr 176 | return '_'.join([c.lower() for c in chunks]) 177 | 178 | if __name__ == '__main__': 179 | import doctest 180 | doctest.testmod() 181 | 182 | -------------------------------------------------------------------------------- /fixture/test/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """The fixture test suite. 3 | 4 | 5 | Environment Variables 6 | --------------------- 7 | 8 | The test suite is affected by several environment variables: 9 | 10 | - FIXTURE_TEST_HEAVY_DSN 11 | 12 | - a database connection that can support operations like foreign key relations 13 | (sqlite won't through foreign key errors) 14 | - defaults to None. 15 | - typically this would be a postgres connection where temp tables can be 16 | created and destroyed 17 | - a special DSN, "sqlite:///:tmp:", will create a connection to a temporary 18 | file-based sqlite db. This is necessary because :memory: dbs can't be 19 | shared easily using sqlalchemy (connections are not pooled) 20 | 21 | - FIXTURE_TEST_LITE_DSN 22 | 23 | - a database as lite as possible, for speed 24 | - defaults to sqlite:///:memory: 25 | 26 | As a shortcut, you can run this to set these variables in your shell :: 27 | 28 | $ source fixture/test/profile/full.sh 29 | 30 | """ 31 | 32 | import os 33 | import unittest 34 | 35 | from six import reraise 36 | 37 | from fixture.test import conf 38 | 39 | 40 | def setup(): 41 | # super hack: 42 | if conf.HEAVY_DSN == 'sqlite:///:tmp:': 43 | conf.HEAVY_DSN_IS_TEMPIO = True 44 | conf.reset_heavy_dsn() 45 | 46 | # this is here because the doc generator also runs doctests. 47 | # should fix that to use proper _test() methods for a module 48 | teardown_examples() 49 | 50 | def teardown(): 51 | teardown_examples() 52 | 53 | def teardown_examples(): 54 | if os.path.exists('/tmp/fixture_example.db'): 55 | os.unlink('/tmp/fixture_example.db') 56 | if os.path.exists('/tmp/fixture_generate.db'): 57 | os.unlink('/tmp/fixture_generate.db') 58 | 59 | 60 | class PrudentTestResult(unittest.TestResult): 61 | """A test result that raises an exception immediately""" 62 | def _raise_err(self, err): 63 | exctype, value, tb = err 64 | reraise(Exception, Exception("%s: %s" % (exctype, value)), tb) 65 | 66 | def addFailure(self, test, err): 67 | self._raise_err(err) 68 | def addError(self, test, err): 69 | self._raise_err(err) 70 | 71 | class _SilentTestResult(PrudentTestResult): 72 | def printErrors(self): 73 | pass 74 | def printErrorList(self, flavour, errors): 75 | pass 76 | 77 | class SilentTestRunner(unittest.TextTestRunner): 78 | """a test runner that doesn't print output but raises 79 | exceptions immediately 80 | """ 81 | def _makeResult(self): 82 | return _SilentTestResult() 83 | 84 | def run(self, test): 85 | "Run the given test case or test suite." 86 | result = self._makeResult() 87 | test(result) 88 | return result 89 | 90 | def attr(**kwargs): 91 | """Add attributes to a test function/method/class""" 92 | def wrap(func): 93 | func.__dict__.update(kwargs) 94 | return func 95 | return wrap 96 | 97 | 98 | -------------------------------------------------------------------------------- /fixture/test/conf.py: -------------------------------------------------------------------------------- 1 | 2 | from fixture import TempIO 3 | import os 4 | 5 | LITE_DSN = os.environ.get('FIXTURE_TEST_LITE_DSN', 'sqlite:///:memory:') 6 | HEAVY_DSN = os.environ.get('FIXTURE_TEST_HEAVY_DSN', None) 7 | HEAVY_DSN_IS_TEMPIO = False 8 | 9 | def reset_heavy_dsn(): 10 | global HEAVY_DSN 11 | if HEAVY_DSN_IS_TEMPIO: 12 | tmp = TempIO(deferred=True) 13 | HEAVY_DSN = 'sqlite:///%s' % tmp.join("tmp.db") -------------------------------------------------------------------------------- /fixture/test/env_supports.py: -------------------------------------------------------------------------------- 1 | 2 | """each attribute indicates a supported module or feature.""" 3 | 4 | import os 5 | import sys 6 | 7 | def module_exists(mod): 8 | try: 9 | __import__(mod) 10 | except ImportError: 11 | return False 12 | else: 13 | return True 14 | 15 | sqlobject = module_exists('sqlobject') 16 | sqlalchemy = module_exists('sqlalchemy') 17 | elixir = module_exists('elixir') 18 | storm = module_exists('storm') 19 | -------------------------------------------------------------------------------- /fixture/test/profile/full.sh: -------------------------------------------------------------------------------- 1 | 2 | # profile for running tests as complete as possible 3 | export FIXTURE_TEST_LITE_DSN="sqlite:///:memory:" 4 | export FIXTURE_TEST_HEAVY_DSN="postgres://$USER@localhost/$USER" 5 | 6 | # some django setup stuff 7 | ## is this solved by the NoseDjango plugin? 8 | # export PYTHONPATH=../../test_loadable/test_django:$PYTHONPATH 9 | # export DJANGO_SETTINGS_MODULE='project.settings' -------------------------------------------------------------------------------- /fixture/test/profile/quick.sh: -------------------------------------------------------------------------------- 1 | 2 | # profile for running tests as quick as possible 3 | export FIXTURE_TEST_LITE_DSN="sqlite:///:memory:" 4 | export FIXTURE_TEST_HEAVY_DSN="sqlite:///:tmp:" -------------------------------------------------------------------------------- /fixture/test/test_command/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/fixture/test/test_command/__init__.py -------------------------------------------------------------------------------- /fixture/test/test_command/test_generate/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from fixture.command.generate import dataset_generator 4 | from fixture.test import conf 5 | from nose.exc import SkipTest 6 | from nose.tools import eq_ 7 | from six import print_ 8 | 9 | 10 | def setup(): 11 | # every tests needs a real db conn : 12 | if not conf.HEAVY_DSN: 13 | raise SkipTest 14 | 15 | def compile_(code): 16 | """compiles code string for a module. 17 | 18 | returns dict w/ attributes of that module. 19 | """ 20 | mod = {} 21 | eval(compile(code, 'stdout', 'exec'), mod) 22 | return mod 23 | 24 | class GenerateTest(object): 25 | """tests that a fixture code generator can run with the specified arguments 26 | and produce a loadable fixture. 27 | 28 | the details of which arguments, how that fixture loads data, and how the 29 | data load is proven is defined in the concrete implementation of this test 30 | class 31 | 32 | """ 33 | args = [] 34 | 35 | def __init__(self, *a, **kw): 36 | super(GenerateTest, self).__init__(*a, **kw) 37 | self.env = None 38 | 39 | def assert_env_is_clean(self): 40 | raise NotImplementedError 41 | 42 | def assert_env_generated_ok(self, env): 43 | raise NotImplementedError 44 | 45 | def assert_data_loaded(self, data): 46 | raise NotImplementedError 47 | 48 | def create_fixture(self): 49 | raise NotImplementedError("must return a concrete LoadableFixture instance, i.e. SQLAlchemyFixture") 50 | 51 | def load_env(self, module): 52 | raise NotImplementedError 53 | 54 | def dataset_generator(self, extra_args=[]): 55 | args = [a for a in self.args] 56 | if extra_args: 57 | args.extend(extra_args) 58 | 59 | self.assert_env_is_clean() 60 | code = dataset_generator(args) 61 | try: 62 | self.env = compile_(code) 63 | self.assert_env_generated_ok(self.env) 64 | data = self.load_env(self.env) 65 | self.assert_data_loaded(data) 66 | except: 67 | print_(code) 68 | raise 69 | 70 | def test_query(self): 71 | self.dataset_generator(['-w', "name = 'super cash back!'"]) 72 | 73 | def test_query_no_data(self): 74 | _stderr = sys.stderr 75 | sys.stderr = sys.stdout 76 | def wrong_exc(exc=None): 77 | raise AssertionError("expected exit 2 %s" % ( 78 | exc and ("(raised: %s: %s)" % (exc.__class__, exc)) or "")) 79 | try: 80 | try: 81 | self.dataset_generator(['-w', "name = 'fooobzarius'"]) 82 | except SystemExit as e: 83 | eq_(e.code, 2) 84 | except Exception as e: 85 | wrong_exc(e) 86 | else: 87 | wrong_exc() 88 | finally: 89 | sys.stderr = _stderr 90 | 91 | 92 | class UsingTesttoolsTemplate(object): 93 | def __init__(self, *a,**kw): 94 | super(UsingTesttoolsTemplate, self).__init__(*a,**kw) 95 | self.args = [a for a in self.args] + ["--template=testtools"] 96 | 97 | def load_datasets(self, module, datasets): 98 | from testtools.fixtures import affix 99 | fxt = affix(*[d() for d in datasets]) 100 | return fxt 101 | 102 | class UsingFixtureTemplate(object): 103 | def __init__(self, *a,**kw): 104 | super(UsingFixtureTemplate, self).__init__(*a,**kw) 105 | self.args = [a for a in self.args] + ["--template=fixture"] 106 | 107 | def visit_loader(self, loader): 108 | pass 109 | 110 | def load_datasets(self, module, datasets): 111 | fixture = self.create_fixture() 112 | self.visit_loader(fixture.loader) 113 | d = fixture.data(*datasets) 114 | d.setup() 115 | return d -------------------------------------------------------------------------------- /fixture/test/test_command/test_generate/test_generate.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | from nose.tools import eq_, raises, with_setup 4 | from fixture.test import attr 5 | from fixture.command.generate import * 6 | 7 | class Stranger(object): 8 | """something that cannot produce data.""" 9 | pass 10 | 11 | @raises(UnrecognizedObject) 12 | @attr(unit=True) 13 | def test_unhandlable_object(): 14 | generate = DataSetGenerator({}) 15 | generate(".".join([Stranger.__module__, Stranger.__name__])) 16 | 17 | class MyHandler(DataHandler): 18 | @staticmethod 19 | def recognizes(obj_path, obj=None): 20 | if obj_path == "myhandler.object_path": 21 | return True 22 | 23 | def register_myhandler(): 24 | register_handler(MyHandler) 25 | 26 | _saved_registry = [h for h in handler_registry] 27 | def reset_handlers(): 28 | handler_registry[:] = [h for h in _saved_registry] 29 | 30 | @attr(unit=True) 31 | @with_setup(setup=register_myhandler, teardown=reset_handlers) 32 | def test_dataset_handler(): 33 | g = DataSetGenerator({}) 34 | hnd = g.get_handler("myhandler.object_path") 35 | assert isinstance(hnd, MyHandler) 36 | 37 | 38 | @attr(unit=True) 39 | @raises(UnrecognizedObject) 40 | @with_setup(setup=register_myhandler, teardown=reset_handlers) 41 | def test_unrecognized_dataset_handler(): 42 | g = DataSetGenerator({}) 43 | hnd = g.get_handler("NOTHONG") 44 | 45 | @attr(unit=True) 46 | def test_requires_option(): 47 | required_idents = [] 48 | def mock_require(ident): 49 | required_idents.append(ident) 50 | import pkg_resources 51 | orig_require = pkg_resources.require 52 | pkg_resources.require = mock_require 53 | sys.stderr = sys.stdout 54 | try: 55 | try: 56 | dataset_generator([ 'bad.object.path', 57 | '--require-egg=foo==1.0', '--require-egg=baz>=2.0b']) 58 | except SystemExit: 59 | pass 60 | finally: 61 | pkg_resources.require = orig_require 62 | sys.stderr = sys.__stderr__ 63 | eq_(required_idents, ['foo==1.0', 'baz>=2.0b']) 64 | 65 | def some_function(): 66 | pass 67 | 68 | class SomeClass(object): 69 | def some_method(self): 70 | pass 71 | 72 | @attr(unit=1) 73 | def test_resolve_path_to_function(): 74 | eq_(resolve_function_path("%s:some_function" % __name__), some_function) 75 | 76 | @attr(unit=1) 77 | def test_resolve_path_to_method(): 78 | eq_(resolve_function_path("%s:SomeClass.some_method" % __name__), SomeClass.some_method) 79 | 80 | @attr(unit=1) 81 | def test_resolve_path_to_module(): 82 | # Note that this is not realistic. I think we'd always want a callable 83 | eq_(resolve_function_path("%s" % __name__), sys.modules[__name__]) 84 | 85 | @attr(unit=1) 86 | @raises(ImportError) 87 | def test_resolve_bad_path(): 88 | resolve_function_path("nomoduleshouldbenamedthis.nowhere:Babu") 89 | -------------------------------------------------------------------------------- /fixture/test/test_command/test_generate/test_generate_sqlobject.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | from nose.tools import eq_ 4 | from nose.exc import SkipTest 5 | from fixture import SQLObjectFixture 6 | from fixture.command.generate import DataSetGenerator, dataset_generator 7 | from fixture.dataset import MergedSuperSet 8 | from fixture.style import NamedDataStyle 9 | from fixture.test.test_command.test_generate import ( 10 | compile_, GenerateTest, UsingTesttoolsTemplate, UsingFixtureTemplate) 11 | from fixture.test import env_supports, conf 12 | from fixture.examples.db.sqlobject_examples import ( 13 | Category, Product, Offer, setup_db, teardown_db) 14 | 15 | sqlhub = None 16 | realconn = None 17 | memconn = None 18 | 19 | def setup(): 20 | global memconn, realconn, sqlhub 21 | if not env_supports.sqlobject: 22 | raise SkipTest 23 | 24 | from sqlobject import connectionForURI, sqlhub 25 | 26 | realconn = connectionForURI(conf.HEAVY_DSN) 27 | memconn = connectionForURI("sqlite:/:memory:") 28 | 29 | def teardown(): 30 | realconn.close() 31 | globals()['realconn'] = None 32 | memconn.close() 33 | globals()['memconn'] = None 34 | 35 | class SQLObjectGenerateTest(GenerateTest): 36 | args = [ 37 | "fixture.examples.db.sqlobject_examples.Offer", 38 | "--dsn", str(conf.HEAVY_DSN) ] 39 | 40 | def assert_data_loaded(self, fxt): 41 | rs = Category.select() 42 | eq_(rs.count(), 2) 43 | parkas = rs[0] 44 | rebates = rs[1] 45 | eq_(parkas.name, "parkas") 46 | eq_(rebates.name, "rebates") 47 | 48 | rs = Product.select() 49 | eq_(rs.count(), 1) 50 | eq_(rs[0].name, "jersey") 51 | 52 | rs = Offer.select() 53 | eq_(rs.count(), 1) 54 | eq_(rs[0].name, "super cash back!") 55 | 56 | # note that here we test that colliding fixture key links 57 | # got resolved correctly : 58 | eq_(Category.get(fxt.product_1.category_id), parkas) 59 | eq_(Category.get(fxt.offer_1.category_id), rebates) 60 | 61 | def assert_env_is_clean(self): 62 | # sanity check : 63 | assert Product.select(connection=realconn).count() 64 | assert not Product.select(connection=memconn).count() 65 | 66 | def assert_env_generated_ok(self, e): 67 | CategoryData = e['CategoryData'] 68 | ProductData = e['ProductData'] 69 | OfferData = e['OfferData'] 70 | 71 | # another sanity check, wipe out the source data 72 | Offer.clearTable(connection=realconn) 73 | Product.clearTable(connection=realconn) 74 | Category.clearTable(connection=realconn) 75 | 76 | def create_fixture(self): 77 | return SQLObjectFixture( 78 | env = self.env, 79 | style = NamedDataStyle(), 80 | dataclass = MergedSuperSet, 81 | ) 82 | 83 | def load_datasets(self, module, conn, datasets): 84 | raise NotImplementedError 85 | 86 | def load_env(self, env): 87 | # set our conn back to memory then load the fixture. 88 | # hmm, seems hoky 89 | sqlhub.processConnection = memconn 90 | data = self.load_datasets(env, 91 | [env['CategoryData'], env['ProductData'], env['OfferData']]) 92 | return data 93 | 94 | def setUp(self): 95 | setup_db(realconn) 96 | sqlhub.processConnection = realconn 97 | 98 | parkas = Category(name="parkas") 99 | jersey = Product(name="jersey", category=parkas) 100 | rebates = Category(name="rebates") 101 | super_cashback = Offer( name="super cash back!", 102 | product=jersey, category=rebates) 103 | sqlhub.processConnection = None 104 | 105 | # now get the loading db as a sqlite mem connection : 106 | setup_db(memconn) 107 | 108 | def tearDown(self): 109 | sqlhub.processConnection = None 110 | teardown_db(realconn) 111 | teardown_db(memconn) 112 | 113 | class TestSQLObjectTesttools(UsingTesttoolsTemplate, SQLObjectGenerateTest): 114 | pass 115 | 116 | class TestSQLObjectFixture(UsingFixtureTemplate, SQLObjectGenerateTest): 117 | def visit_loader(self, loader): 118 | loader.connection = memconn 119 | 120 | -------------------------------------------------------------------------------- /fixture/test/test_dataset/test_converter.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | 3 | from fixture.dataset.converter import * 4 | from fixture.test import attr 5 | from nose.tools import eq_, raises 6 | from six import StringIO 7 | 8 | 9 | try: 10 | import json 11 | except ImportError: 12 | import simplejson as json 13 | 14 | 15 | class FooData(DataSet): 16 | class bar: 17 | name = "call me bar" 18 | is_alive = False 19 | 20 | class foo: 21 | name = "name's foo" 22 | is_alive = True 23 | 24 | 25 | class MuchoData(DataSet): 26 | class mucho: 27 | d = datetime.date(2008, 1, 1) 28 | dt = datetime.datetime(2008, 1, 1, 2, 30, 59) 29 | dec = Decimal("1.45667") 30 | fl = float(1.45667) 31 | 32 | 33 | class DummyError(Exception): 34 | pass 35 | 36 | 37 | class TestDatasetToJson(object): 38 | @attr(unit=1) 39 | @raises(TypeError) 40 | def test_must_be_dataset(self): 41 | class NotADataSet(object): 42 | pass 43 | 44 | dataset_to_json(NotADataSet) 45 | 46 | def _sorted_eq(self, a, b, msg=None): 47 | eq_(sorted(a), sorted(b), msg) 48 | 49 | @attr(unit=1) 50 | def test_convert_cls(self): 51 | self._sorted_eq( 52 | dataset_to_json(FooData), 53 | json.dumps( 54 | [{ 55 | 'name': "call me bar", 56 | 'is_alive': False, 57 | }, 58 | { 59 | 'name': "name's foo", 60 | 'is_alive': True, 61 | }] 62 | ) 63 | ) 64 | 65 | @attr(unit=1) 66 | def test_convert_instance(self): 67 | foo = FooData() 68 | self._sorted_eq( 69 | dataset_to_json(foo), 70 | json.dumps( 71 | [{ 72 | 'name': "call me bar", 73 | 'is_alive': False 74 | }, 75 | { 76 | 'name': "name's foo", 77 | 'is_alive': True 78 | }] 79 | ) 80 | ) 81 | 82 | @attr(unit=1) 83 | def test_dump_to_file(self): 84 | fp = StringIO() 85 | dataset_to_json(FooData, fp=fp) 86 | self._sorted_eq( 87 | fp.getvalue(), 88 | json.dumps( 89 | [{ 90 | 'name': "call me bar", 91 | 'is_alive': False 92 | }, 93 | { 94 | 'name': "name's foo", 95 | 'is_alive': True 96 | }] 97 | ) 98 | ) 99 | 100 | @attr(unit=1) 101 | def test_types(self): 102 | self._sorted_eq( 103 | json.loads(dataset_to_json(MuchoData)), 104 | [{ 105 | 'd': "2008-01-01", 106 | "dt": "2008-01-01 02:30:59", 107 | "dec": "1.45667", 108 | "fl": 1.45667 109 | }] 110 | ) 111 | 112 | @attr(unit=1) 113 | @raises(DummyError) 114 | def test_custom_converter(self): 115 | def my_default(obj): 116 | raise DummyError() 117 | 118 | ds = dataset_to_json(MuchoData, default=my_default) 119 | assert not ds, ( 120 | "dataset_to_json() should have died but it returned: %s" % ds) 121 | 122 | @attr(unit=1) 123 | def test_wrap(self): 124 | def wrap_in_dict(objects): 125 | return {'data': objects} 126 | 127 | self._sorted_eq( 128 | dataset_to_json(FooData, wrap=wrap_in_dict), 129 | json.dumps({ 130 | 'data': 131 | [{ 132 | 'name': "call me bar", 133 | 'is_alive': False 134 | }, 135 | { 136 | 'name': "name's foo", 137 | 'is_alive': True 138 | }] 139 | }) 140 | ) 141 | -------------------------------------------------------------------------------- /fixture/test/test_io.py: -------------------------------------------------------------------------------- 1 | # -*- coding: latin_1 -*- 2 | 3 | import os 4 | from nose.tools import eq_ 5 | from os.path import join, exists, isdir, basename 6 | from os import path 7 | from copy import copy 8 | from nose.tools import eq_, raises 9 | from fixture import TempIO 10 | from fixture.io import mkdirall, putfile 11 | from fixture.test import attr 12 | 13 | french = "tu pense qu'on peut m'utiliser comme ça?" 14 | 15 | @attr(unit=True) 16 | def test_mkdirall(): 17 | tmp = TempIO() 18 | cwd = os.getcwd() 19 | try: 20 | mkdirall(join(tmp, 'blah/blah/')) 21 | assert exists(join(tmp, 'blah/blah')) 22 | 23 | # relative too ... 24 | os.chdir(tmp) 25 | mkdirall('ici/ou/la') 26 | assert exists('ici') 27 | assert exists('ici/ou') 28 | assert exists('ici/ou/la') 29 | 30 | finally: 31 | del tmp 32 | os.chdir(cwd) 33 | 34 | @attr(unit=True) 35 | def test_putfile(): 36 | tmp = TempIO() 37 | cwd = os.getcwd() 38 | try: 39 | 40 | fname = join(tmp, 'french.txt') 41 | putfile(fname, french) 42 | 43 | assert exists(fname) 44 | 45 | f = open(fname, 'r') 46 | contents = f.read() 47 | f.close() 48 | assert contents == french 49 | 50 | # can make lazy dirs .. 51 | fname = join(tmp, 'ou/est/tu/frenchy.txt') 52 | putfile(fname, "") 53 | assert exists(fname) 54 | 55 | # relative : 56 | os.chdir(tmp) 57 | putfile('bahh', '') 58 | assert exists(join(tmp, 'bahh')) 59 | 60 | finally: 61 | del tmp 62 | os.chdir(cwd) 63 | 64 | @attr(unit=True) 65 | def test_del_self_destructs(): 66 | """asserts that a module level reference self destructs 67 | without exception.""" 68 | global _TMP 69 | _TMP = TempIO() 70 | 71 | class TestTempIO(object): 72 | def setUp(self): 73 | self.tmp = TempIO() 74 | 75 | def tearDown(self): 76 | if hasattr(self, 'tmp'): 77 | del self.tmp 78 | 79 | @attr(unit=True) 80 | def test_deferred(self): 81 | tmp = TempIO(deferred=True) 82 | root = str(tmp) 83 | assert exists(root) 84 | del tmp 85 | assert exists(root) 86 | 87 | tmp2 = TempIO(deferred=False) 88 | root = str(tmp2) 89 | assert exists(root) 90 | del tmp2 91 | assert not exists(root) 92 | 93 | @attr(unit=True) 94 | def test_del(self): 95 | root = copy(self.tmp) 96 | del self.tmp 97 | assert not exists(root) 98 | 99 | @attr(unit=True) 100 | def test_keywords(self): 101 | self.tmp_custom = TempIO(prefix='foobar_', dir=self.tmp) 102 | try: 103 | assert exists(join(self.tmp, basename(self.tmp_custom))) 104 | assert basename(self.tmp_custom).startswith('foobar_') 105 | finally: 106 | del self.tmp_custom 107 | 108 | @attr(unit=True) 109 | def test_mkdir(self): 110 | base1 = self.tmp.mkdir('base1') 111 | assert exists(join(self.tmp, base1)) 112 | base2 = self.tmp.mkdir('base2') 113 | assert exists(join(self.tmp, base2)) 114 | 115 | @attr(unit=True) 116 | def test_newdir(self): 117 | self.tmp.rick_james = "rick_james" 118 | assert exists(self.tmp.rick_james) 119 | assert self.tmp.rick_james.startswith(self.tmp) 120 | assert self.tmp.rick_james.endswith("rick_james") 121 | 122 | self.tmp.rick_james = "rick james" 123 | assert exists(self.tmp.rick_james) 124 | assert self.tmp.rick_james.startswith(self.tmp) 125 | assert self.tmp.rick_james.endswith("rick james") 126 | 127 | self.tmp.rick_james = "rick_james/i/love/you" 128 | assert exists(self.tmp.rick_james) 129 | assert self.tmp.rick_james.startswith(self.tmp) 130 | assert self.tmp.rick_james.endswith("rick_james/i/love/you") 131 | 132 | @attr(unit=True) 133 | def test_path_interface(self): 134 | self.tmp.dupes = "processed/dupes" 135 | def endswith(p, end): 136 | assert p.endswith(end), "%s did not end in %s" % (p,end) 137 | 138 | eq_(self.tmp.dupes, path.join(self.tmp, "processed/dupes")) 139 | eq_(self.tmp.dupes.abspath(), 140 | path.abspath(path.join(self.tmp, "processed/dupes"))) 141 | eq_(self.tmp.dupes.basename(), "dupes") 142 | eq_(self.tmp.dupes.dirname(), path.join(self.tmp, "processed")) 143 | eq_(self.tmp.dupes.normpath(), path.normpath(self.tmp.dupes)) 144 | eq_(self.tmp.dupes.exists(), True) 145 | eq_(self.tmp.dupes.join("foo", "bar"), path.abspath(path.join( 146 | self.tmp, "processed/dupes/foo/bar"))) 147 | eq_(self.tmp.dupes.join("foo", "bar").exists(), False) 148 | 149 | self.tmp.dupes.more = "foo/bar" 150 | eq_(path.exists(path.join(self.tmp.dupes, "foo", "bar")), True) 151 | eq_(self.tmp.dupes.join("foo", "bar").exists(), True) 152 | 153 | eq_(self.tmp.dupes.realpath(), 154 | path.realpath(path.join(self.tmp, "processed/dupes"))) 155 | eq_(self.tmp.dupes.splitpath(), path.split(self.tmp.dupes)) 156 | eq_(self.tmp.dupes.splitext(), (path.realpath(path.join(self.tmp, 157 | "processed/dupes")), "")) 158 | 159 | @attr(unit=True) 160 | def test_putfile(self): 161 | self.tmp.putfile('frenchy.txt', french) 162 | 163 | assert exists(join(self.tmp, 'frenchy.txt')) 164 | assert open(join(self.tmp, 'frenchy.txt'), 'r').read() == french 165 | 166 | abspath = self.tmp.putfile('petite/grenouille/frenchy.txt', french) 167 | exppath = join(self.tmp, 'petite/grenouille/frenchy.txt') 168 | assert exists(exppath) 169 | eq_(abspath, exppath) 170 | 171 | # check laziness of putfile's mkdir'ing : 172 | self.tmp.putfile('petite/grenouille/ribbit/frenchy.txt', french) 173 | assert exists(join(self.tmp, 174 | 'petite/grenouille/ribbit/frenchy.txt')) 175 | # make sure that a second call will only create directories necessary: 176 | self.tmp.putfile('petite/grenouille/ribbit/foo.txt', "foo") 177 | 178 | @attr(unit=True) 179 | def test_putfile_mode(self): 180 | self.tmp.putfile('frenchy.txt', b"", 'wb') 181 | f = open(join(self.tmp, 'frenchy.txt'), 'rb') 182 | f.read() 183 | 184 | @attr(unit=True) 185 | @raises(TypeError) 186 | def test_putfile_accepts_only_relative_paths(self): 187 | self.tmp.putfile('/petite/grenouille/ribbit/frenchy.txt', "franch") 188 | 189 | @attr(unit=True) 190 | def test_rmtree(self): 191 | root = str(self.tmp) 192 | self.tmp.rmtree() 193 | assert not exists(root) 194 | 195 | @attr(unit=True) 196 | def test_root(self): 197 | assert isdir(self.tmp) 198 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from fixture.test.test_loadable.test_loadable import * -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_django/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | import django 5 | from django.core.management import call_command 6 | 7 | import fixture.examples 8 | 9 | 10 | _EXAMPLE_PROJECT_DIR = os.path.dirname(fixture.examples.__file__) 11 | 12 | _EXAMPLE_PROJECT_PATH = os.path.join(_EXAMPLE_PROJECT_DIR, 'django_example') 13 | 14 | sys.path.append(_EXAMPLE_PROJECT_PATH) 15 | os.environ['DJANGO_SETTINGS_MODULE'] = 'django_example.settings' 16 | django.setup() 17 | 18 | call_command('migrate', interactive=False, verbosity=0) 19 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_django/fixtures.py: -------------------------------------------------------------------------------- 1 | from fixture import DataSet 2 | 3 | 4 | class ValidNoRelationsData(DataSet): 5 | class one: 6 | char = "one" 7 | num = 1 8 | 9 | class two: 10 | char = "two" 11 | num = 2 12 | 13 | 14 | class InvalidNoRelationsData(DataSet): 15 | class one: 16 | char = "one" 17 | invalid = 'test' 18 | 19 | class two: 20 | char = "two" 21 | some_other = 2 22 | 23 | 24 | class AuthorData(DataSet): 25 | class Meta: 26 | django_model = 'app.Author' 27 | 28 | class frank_herbert: 29 | first_name = "Frank" 30 | last_name = "Herbert" 31 | 32 | class guido: 33 | first_name = "Guido" 34 | last_name = "Van rossum" 35 | 36 | 37 | class BookData(DataSet): 38 | class Meta: 39 | django_model = 'app.Book' 40 | 41 | class dune: 42 | title = "Dune" 43 | author = AuthorData.frank_herbert 44 | 45 | class python: 46 | title = 'Python' 47 | author = AuthorData.guido 48 | 49 | 50 | class ReviewerData(DataSet): 51 | class Meta: 52 | django_model = 'app.Reviewer' 53 | 54 | class ben: 55 | name = 'ben' 56 | reviewed = [BookData.dune, BookData.python] 57 | 58 | 59 | class DjangoDataSetWithMeta(DataSet): 60 | class Meta: 61 | django_model = 'app.Author' 62 | 63 | class frank_herbert: 64 | first_name = "Frank" 65 | last_name = "Herbert" 66 | 67 | class guido: 68 | first_name = "Guido" 69 | last_name = "Van rossum" 70 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_django/test_djangoenv.py: -------------------------------------------------------------------------------- 1 | from blog.models import Post 2 | from nose.tools import raises, assert_equal 3 | 4 | from fixture import DataSet 5 | from fixture.exc import StorageMediaNotFound 6 | from fixture.loadable.django_loadable import DjangoEnv, DjangoFixture 7 | from fixture.style import NamedDataStyle 8 | 9 | 10 | @raises(ValueError) 11 | def test_unsplittable_name(): 12 | DjangoEnv.get('blog_Post') 13 | 14 | 15 | def test_invalid_app_returns_none(): 16 | assert_equal(None, DjangoEnv.get('no_such_app__Post')) 17 | 18 | 19 | def test_invalid_model_returns_none(): 20 | assert_equal(None, DjangoEnv.get('blog__NoSuchModel')) 21 | 22 | 23 | def test_model_lookup_by_qualified_model_name(): 24 | class SomeDataset(DataSet): 25 | class Meta: 26 | django_model = "blog.Post" 27 | 28 | class foo: 29 | foo = 1 30 | 31 | fixture = DjangoFixture() 32 | ds = SomeDataset() 33 | fixture.attach_storage_medium(ds) 34 | assert_equal(ds.meta.storage_medium.medium, Post) 35 | 36 | 37 | @raises(ValueError) 38 | def test_dataset_with_malformed_model_name(): 39 | class SomeDataset(DataSet): 40 | class Meta: 41 | django_model = "not_dot_separated_model_name" 42 | 43 | class foo: 44 | foo = 1 45 | 46 | fixture = DjangoFixture() 47 | ds = SomeDataset() 48 | fixture.attach_storage_medium(ds) 49 | 50 | 51 | @raises(StorageMediaNotFound) 52 | def test_dataset_without_resolvable_model_name(): 53 | class UnknownData(DataSet): 54 | class foo: 55 | foo = 1 56 | 57 | fixture = DjangoFixture(style=NamedDataStyle()) 58 | ds = UnknownData() 59 | fixture.attach_storage_medium(ds) 60 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_django/test_djangomeduim.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from django.db import models as django_models 4 | from fixture import DjangoFixture 5 | from fixture.loadable.django_loadable import field_is_required 6 | from fixture.test.test_loadable.test_django.fixtures import \ 7 | InvalidNoRelationsData 8 | from fixture.test.test_loadable.test_django.fixtures import ValidNoRelationsData 9 | from fixture.test.test_loadable.test_django.util import get_column_vals 10 | from nose.tools import raises 11 | 12 | 13 | def _check_row(medium, column_vals): 14 | medium._check_schema(column_vals) 15 | 16 | 17 | def test_schema_conformance(): 18 | valid_rels = ValidNoRelationsData() 19 | invalid_rels = InvalidNoRelationsData() 20 | 21 | class NoRelations(django_models.Model): 22 | char = django_models.CharField(max_length=10) 23 | num = django_models.IntegerField() 24 | 25 | class Meta: 26 | app_label = 'tests' 27 | 28 | for dataset, model, callable in \ 29 | [ 30 | (valid_rels, NoRelations, _check_row), 31 | (invalid_rels, NoRelations, 32 | raises(ValueError)(_check_row)) 33 | ]: 34 | djm = DjangoFixture.Medium(NoRelations, dataset) 35 | rows = [(row[0], list(get_column_vals(row[1]))) for row in dataset] 36 | for row in rows: 37 | callable.description = "schema.conformance: %s %s in %s" % ( 38 | row[0], row[1], 39 | dataset.__class__.__name__) 40 | yield callable, djm, row[1] 41 | 42 | 43 | def test_is_field_required(): 44 | from django.db import models 45 | class TestMod(models.Model): 46 | 47 | pk = models.CharField(primary_key=True) 48 | req = models.CharField() 49 | default_char = models.CharField(default='default_val') 50 | null = models.CharField(null=True) 51 | date = models.DateTimeField(auto_now=True) 52 | req_date = models.DateTimeField() 53 | nullable_date = models.DateTimeField(null=True, auto_now_add=True) 54 | default_date = models.DateTimeField(default=datetime.now) 55 | 56 | class Meta: 57 | app_label = 'tests' 58 | 59 | required_matrix = dict( 60 | pk=False, 61 | req=True, 62 | default_char=False, 63 | null=False, 64 | date=False, 65 | req_date=True, 66 | nullable_date=False, 67 | default_date=False, 68 | ) 69 | 70 | def check_field_required(fld, result): 71 | msg = "field '%s': null=%s, primary_key=%s, auto_now=%s, " \ 72 | "auto_now_add=%s " \ 73 | "should be %s" 74 | auto_now = getattr(fld, 'auto_now', None) 75 | auto_now_add = getattr(fld, 'auto_now_add', None) 76 | assert field_is_required(fld) == result, msg % (fld.name, fld.null, 77 | fld.primary_key, 78 | auto_now, auto_now_add, 79 | result) 80 | 81 | for item in required_matrix.items(): 82 | fld, result = item 83 | check_field_required.description = "%s required? %s" % item 84 | yield check_field_required, TestMod._meta.get_field(fld), result 85 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_django/test_loading.py: -------------------------------------------------------------------------------- 1 | from app.models import Author, Book, Reviewer 2 | from fixture import DjangoFixture 3 | from fixture.test.test_loadable.test_django.util import assert_empty 4 | from fixture.test.test_loadable.test_django.fixtures import DjangoDataSetWithMeta, AuthorData, BookData, ReviewerData 5 | 6 | 7 | dj_fixture = DjangoFixture() 8 | 9 | 10 | def test_fk_rels(): 11 | assert_empty('app') 12 | try: 13 | data = dj_fixture.data(AuthorData, BookData) 14 | data.setup() 15 | assert Author.objects.get(first_name='Frank').books.count() == 1 16 | finally: 17 | data.teardown() 18 | assert_empty('app') 19 | 20 | 21 | def test_m2m(): 22 | assert_empty('app') 23 | try: 24 | data = dj_fixture.data(AuthorData, BookData, ReviewerData) 25 | data.setup() 26 | ben = Reviewer.objects.all()[0] 27 | # Reviewed have been added as a list 28 | assert ben.reviewed.count() == 2 29 | dune = Book.objects.get(title='Dune') 30 | # Reverse relations work 31 | assert ben in dune.reviewers.all() 32 | # A single object passed to a many to many also works 33 | frank = Author.objects.get(first_name='Frank') 34 | assert frank.books.count() == 1 35 | assert dune in frank.books.all() 36 | finally: 37 | data.teardown() 38 | assert_empty('app') 39 | 40 | 41 | def test_dataset_with_meta(): 42 | assert_empty('app') 43 | try: 44 | data = dj_fixture.data(DjangoDataSetWithMeta) 45 | data.setup() 46 | assert Author.objects.count() == 2 47 | finally: 48 | data.teardown() 49 | assert_empty('app') 50 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_django/test_wrong_declarations.py: -------------------------------------------------------------------------------- 1 | from nose.tools import assert_raises 2 | from fixture.test.test_loadable.test_django.util import assert_empty 3 | 4 | from fixture import DjangoFixture, DataSet, style 5 | from app import models 6 | from fixture.exc import LoadError 7 | 8 | 9 | class ReviewerData(DataSet): 10 | class ben: 11 | name = 'ben' 12 | 13 | 14 | class BookData(DataSet): 15 | class dune: 16 | title = "Dune" 17 | reviewers = [ReviewerData.ben] 18 | 19 | 20 | class AuthorData(DataSet): 21 | class frank_herbert: 22 | first_name = "Frank" 23 | last_name = "Herbert" 24 | books = BookData.dune 25 | 26 | 27 | dj_fixture = DjangoFixture(env=models, style=style.NamedDataStyle()) 28 | 29 | 30 | def test_wrong_relation_declaration(): 31 | assert_empty('app') 32 | assert 'reviewers' in {f.name for f in models.Book._meta.get_fields()} 33 | data = dj_fixture.data(BookData) 34 | assert_raises(LoadError, data.setup) 35 | data.teardown() 36 | assert_empty('app') 37 | 38 | 39 | def test_invalid_m2m(): 40 | class ReviewerData(DataSet): 41 | class ben: 42 | name = 'ben' 43 | reviewed = [BookData.dune, AuthorData.frank_herbert] 44 | 45 | assert_empty('app') 46 | data = dj_fixture.data(ReviewerData) 47 | assert_raises(LoadError, data.setup) 48 | data.teardown() 49 | assert_empty('app') 50 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_django/util.py: -------------------------------------------------------------------------------- 1 | """This is mostly a copy of methods and internal classes from loadable""" 2 | from django.apps import apps 3 | from fixture.loadable.loadable import DeferredStoredObject 4 | 5 | 6 | def assert_empty(app_label): 7 | app = apps.get_app_config(app_label) 8 | for model in app.get_models(): 9 | model_count = model.objects.count() 10 | assert model_count == 0, \ 11 | 'Found {} instances of {}'.format(model_count, model) 12 | 13 | 14 | def resolve_stored_object(column_val): 15 | if type(column_val) == DeferredStoredObject: 16 | return column_val.get_stored_object_from_loader(self) 17 | else: 18 | return column_val 19 | 20 | 21 | def get_column_vals(row): 22 | for c in row.columns(): 23 | yield (c, resolve_stored_object(getattr(row, c))) 24 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_google_datastore_loadable.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import os 4 | from nose.exc import SkipTest 5 | from nose.tools import eq_ 6 | import unittest 7 | 8 | from six import print_ 9 | 10 | from fixture import DataSet, TempIO, GoogleDatastoreFixture 11 | from fixture.util import reset_log_level 12 | from fixture.test import conf, attr 13 | 14 | tmp = TempIO() 15 | 16 | def setup(): 17 | # for prying eyes: NoseGAE http://code.google.com/p/nose-gae/ does this better 18 | groot = "/usr/local/google_appengine" 19 | if os.path.exists(groot): 20 | sys.path.append(groot) 21 | sys.path.append(os.path.join(groot, "lib/django")) 22 | sys.path.append(os.path.join(groot, "lib/webob")) 23 | sys.path.append(os.path.join(groot, "lib/yaml/lib")) 24 | sys.path.insert(0, os.path.join(groot, "lib/antlr3")) 25 | import google.appengine 26 | import webob 27 | import yaml 28 | import django 29 | import antlr3 30 | 31 | from google.appengine.tools import dev_appserver 32 | 33 | appid = "" 34 | dev_appserver.SetupStubs(appid, 35 | clear_datastore = False, # just removes the files when True 36 | datastore_path = tmp.join("datastore.data"), 37 | blobstore_path = tmp.join("blobstore.data"), 38 | history_path = tmp.join("history.data"), 39 | login_url = None) 40 | else: 41 | raise SkipTest 42 | 43 | def teardown(): 44 | # dev_appserver messes with the root logger... 45 | reset_log_level() 46 | 47 | def clear_datastore(): 48 | for basename in ("datastore.data", "history.data"): 49 | if os.path.exists(tmp.join(basename)): 50 | os.unlink(tmp.join(basename)) 51 | 52 | class TestSetupTeardown(unittest.TestCase): 53 | 54 | class CategoryData(DataSet): 55 | class cars: 56 | name = 'cars' 57 | class free_stuff: 58 | name = 'get free stuff' 59 | 60 | def setUp(self): 61 | from google.appengine.ext import db 62 | 63 | class Category(db.Model): 64 | name = db.StringProperty() 65 | self.Category = Category 66 | 67 | self.fixture = GoogleDatastoreFixture(env={'CategoryData': self.Category}) 68 | 69 | def tearDown(self): 70 | clear_datastore() 71 | 72 | @attr(functional=1) 73 | def test_setup_then_teardown(self): 74 | 75 | eq_(list(self.Category.all()), []) 76 | 77 | data = self.fixture.data(self.CategoryData) 78 | data.setup() 79 | 80 | cats = self.Category.all().order('name') 81 | 82 | eq_(cats[0].name, 'cars') 83 | eq_(cats[1].name, 'get free stuff') 84 | 85 | data.teardown() 86 | 87 | eq_(list(self.Category.all()), []) 88 | 89 | 90 | class TestRelationships(unittest.TestCase): 91 | 92 | def setUp(self): 93 | from google.appengine.ext import db 94 | 95 | class CategoryData(DataSet): 96 | class red: 97 | color = 'red' 98 | 99 | class ProductData(DataSet): 100 | class red_truck: 101 | category = CategoryData.red 102 | sale_tag = "Big, Shiny Red Truck" 103 | self.ProductData = ProductData 104 | 105 | class Category(db.Model): 106 | color = db.StringProperty() 107 | self.Category = Category 108 | 109 | class Product(db.Model): 110 | category = db.ReferenceProperty(Category) 111 | sale_tag = db.StringProperty() 112 | self.Product = Product 113 | 114 | self.fixture = GoogleDatastoreFixture(env={ 115 | 'CategoryData': self.Category, 116 | 'ProductData': self.Product, 117 | }) 118 | 119 | def tearDown(self): 120 | clear_datastore() 121 | 122 | @attr(functional=1) 123 | def test_setup_then_teardown(self): 124 | 125 | eq_(list(self.Category.all()), []) 126 | eq_(list(self.Product.all()), []) 127 | 128 | data = self.fixture.data(self.ProductData) 129 | data.setup() 130 | 131 | products = self.Product.all() 132 | 133 | eq_(products[0].sale_tag, "Big, Shiny Red Truck") 134 | eq_(products[0].category.color, "red") 135 | 136 | data.teardown() 137 | 138 | eq_(list(self.Category.all()), []) 139 | eq_(list(self.Product.all()), []) 140 | 141 | class TestListOfRelationships(unittest.TestCase): 142 | 143 | def setUp(self): 144 | from google.appengine.ext import db 145 | 146 | class Author(db.Model): 147 | name = db.StringProperty() 148 | self.Author = Author 149 | 150 | class Book(db.Model): 151 | title = db.StringProperty() 152 | authors = db.ListProperty(db.Key) 153 | self.Book = Book 154 | 155 | class AuthorData(DataSet): 156 | class frank_herbert: 157 | name = "Frank Herbert" 158 | class brian_herbert: 159 | name = "Brian Herbert" 160 | 161 | class BookData(DataSet): 162 | class two_worlds: 163 | title = "Man of Two Worlds" 164 | authors = [AuthorData.frank_herbert, AuthorData.brian_herbert] 165 | self.BookData = BookData 166 | 167 | self.fixture = GoogleDatastoreFixture(env={ 168 | 'BookData': self.Book, 169 | 'AuthorData': self.Author 170 | }) 171 | 172 | def tearDown(self): 173 | clear_datastore() 174 | 175 | @attr(functional=1) 176 | def test_setup_then_teardown(self): 177 | 178 | eq_(list(self.Author.all()), []) 179 | eq_(list(self.Book.all()), []) 180 | 181 | data = self.fixture.data(self.BookData) 182 | data.setup() 183 | 184 | books = self.Book.all() 185 | 186 | eq_(books[0].title, "Man of Two Worlds") 187 | authors = [self.Author.get(k) for k in books[0].authors] 188 | print_(authors) 189 | eq_(len(authors), 2) 190 | authors.sort(key=lambda a:a.name ) 191 | eq_(authors[0].name, "Brian Herbert") 192 | eq_(authors[1].name, "Frank Herbert") 193 | 194 | data.teardown() 195 | 196 | eq_(list(self.Author.all()), []) 197 | eq_(list(self.Book.all()), []) 198 | 199 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_sqlobject_loadable.py: -------------------------------------------------------------------------------- 1 | 2 | import os, sys 3 | from nose.tools import eq_ 4 | from nose.exc import SkipTest 5 | from fixture import SQLObjectFixture 6 | from fixture.test import env_supports 7 | from fixture import ( 8 | SQLObjectFixture, NamedDataStyle, PaddedNameStyle, CamelAndUndersStyle, 9 | DataSet) 10 | from fixture.dataset import MergedSuperSet 11 | from fixture.test.test_loadable import * 12 | from fixture.examples.db.sqlobject_examples import * 13 | from fixture.test import conf 14 | 15 | def setup(): 16 | if not env_supports.sqlobject: raise SkipTest 17 | 18 | class SQLObjectFixtureTest: 19 | fixture = SQLObjectFixture( 20 | style=( NamedDataStyle() + CamelAndUndersStyle()), 21 | dsn=conf.LITE_DSN, env=globals(), 22 | use_transaction=False, 23 | dataclass=MergedSuperSet ) 24 | 25 | def setUp(self, dsn=conf.LITE_DSN): 26 | """should load the dataset""" 27 | from sqlobject import connectionForURI 28 | self.conn = connectionForURI(dsn) 29 | self.fixture.connection = self.conn 30 | 31 | from sqlobject import sqlhub 32 | sqlhub.processConnection = self.conn 33 | 34 | setup_db(self.conn) 35 | 36 | def tearDown(self): 37 | """should unload the dataset.""" 38 | conn = self.conn 39 | teardown_db(conn) 40 | conn.close() 41 | conf.reset_heavy_dsn() 42 | 43 | class SQLObjectCategoryTest(SQLObjectFixtureTest): 44 | def assert_data_loaded(self, dataset): 45 | """assert that the dataset was loaded.""" 46 | eq_(Category.get( dataset.gray_stuff.id).name, 47 | dataset.gray_stuff.name) 48 | eq_(Category.get( dataset.yellow_stuff.id).name, 49 | dataset.yellow_stuff.name) 50 | 51 | def assert_data_torndown(self): 52 | """assert that the dataset was torn down.""" 53 | eq_(Category.select().count(), 0) 54 | 55 | class TestSQLObjectCategory( 56 | HavingCategoryData, SQLObjectCategoryTest, LoadableTest): 57 | pass 58 | 59 | class HavingCategoryDataStorable: 60 | """mixin that adds data to a LoadableTest.""" 61 | def datasets(self): 62 | class WhateverIWantToCallIt(DataSet): 63 | class Meta: 64 | storable = Category 65 | class gray_stuff: 66 | id=1 67 | name='gray' 68 | class yellow_stuff: 69 | id=2 70 | name='yellow' 71 | return [WhateverIWantToCallIt] 72 | 73 | class TestSQLObjectCategoryStorable( 74 | HavingCategoryDataStorable, SQLObjectCategoryTest, LoadableTest): 75 | pass 76 | class TestSQLObjectCategoryAsDataType( 77 | HavingCategoryAsDataType, SQLObjectCategoryTest, LoadableTest): 78 | pass 79 | 80 | class TestSQLObjectPartialLoad( 81 | SQLObjectFixtureTest, LoaderPartialRecoveryTest): 82 | def assert_partial_load_aborted(self): 83 | raise SkipTest("I don't think sqlobject can support this feature") 84 | 85 | # t = self.conn.transaction() 86 | # eq_(Category.select(connection=t).count(), 0) 87 | 88 | class SQLObjectFixtureCascadeTest(SQLObjectFixtureTest): 89 | def assert_data_loaded(self, dataset): 90 | """assert that the dataset was loaded.""" 91 | eq_(Offer.get(dataset.free_truck.id).name, dataset.free_truck.name) 92 | 93 | eq_(Product.get( 94 | dataset.truck.id).name, 95 | dataset.truck.name) 96 | 97 | eq_(Category.get( 98 | dataset.cars.id).name, 99 | dataset.cars.name) 100 | eq_(Category.get( 101 | dataset.free_stuff.id).name, 102 | dataset.free_stuff.name) 103 | 104 | def assert_data_torndown(self): 105 | """assert that the dataset was torn down.""" 106 | eq_(Category.select().count(), 0) 107 | eq_(Offer.select().count(), 0) 108 | eq_(Product.select().count(), 0) 109 | 110 | class SQLObjectFixtureCascadeTestWithHeavyDB(SQLObjectFixtureCascadeTest): 111 | def setUp(self): 112 | if not conf.HEAVY_DSN: 113 | raise SkipTest 114 | 115 | SQLObjectFixtureCascadeTest.setUp(self, dsn=conf.HEAVY_DSN) 116 | 117 | class TestSQLObjectFixtureCascade( 118 | HavingOfferProductData, SQLObjectFixtureCascadeTest, 119 | LoadableTest): 120 | pass 121 | class TestSQLObjectFixtureCascadeWithHeavyDB( 122 | HavingOfferProductData, SQLObjectFixtureCascadeTestWithHeavyDB, 123 | LoadableTest): 124 | pass 125 | class TestSQLObjectFixtureCascadeAsType( 126 | HavingOfferProductAsDataType, SQLObjectFixtureCascadeTest, 127 | LoadableTest): 128 | pass 129 | class TestSQLObjectFixtureCascadeAsRef( 130 | HavingReferencedOfferProduct, SQLObjectFixtureCascadeTest, 131 | LoadableTest): 132 | pass 133 | class TestSQLObjectFixtureCascadeAsRefInherit( 134 | HavingRefInheritedOfferProduct, SQLObjectFixtureCascadeTest, 135 | LoadableTest): 136 | pass 137 | class TestSQLObjectFixtureCascadeAsRefInheritWithHeavyDB( 138 | HavingRefInheritedOfferProduct, SQLObjectFixtureCascadeTestWithHeavyDB, 139 | LoadableTest): 140 | pass 141 | -------------------------------------------------------------------------------- /fixture/test/test_loadable/test_storm_loadable.py: -------------------------------------------------------------------------------- 1 | 2 | import os, sys 3 | from nose.tools import eq_ 4 | from nose.exc import SkipTest 5 | from fixture import StormFixture 6 | from fixture.test import env_supports 7 | from fixture import ( 8 | StormFixture, NamedDataStyle, PaddedNameStyle, CamelAndUndersStyle, 9 | DataSet) 10 | from fixture.dataset import MergedSuperSet 11 | from fixture.test.test_loadable import * 12 | from fixture.examples.db.storm_examples import * 13 | from fixture.test import conf 14 | 15 | 16 | 17 | 18 | from fixture.util import start_debug, stop_debug 19 | #start_debug("fixture.loadable") 20 | #start_debug("fixture.loadable.tree") 21 | #start_debug("fixture.loadable.storm") 22 | 23 | 24 | 25 | def setup(): 26 | if not env_supports.storm: raise SkipTest 27 | 28 | class StormFixtureTest: 29 | fixture = StormFixture( 30 | style=( NamedDataStyle() + CamelAndUndersStyle()), 31 | dsn=conf.LITE_DSN, env=globals(), 32 | use_transaction=True, 33 | dataclass=MergedSuperSet ) 34 | 35 | def setUp(self, dsn=conf.LITE_DSN): 36 | """should load the dataset""" 37 | from storm.uri import URI 38 | from storm.locals import create_database, Store 39 | from storm.tracer import debug 40 | #debug(1) 41 | self.store = Store(create_database(URI(dsn))) 42 | self.fixture.store = self.store 43 | 44 | setup_db(self.store) 45 | 46 | def tearDown(self): 47 | """should unload the dataset.""" 48 | store = self.store 49 | teardown_db(store) 50 | store.close() 51 | conf.reset_heavy_dsn() 52 | 53 | class StormCategoryTest(StormFixtureTest): 54 | def assert_data_loaded(self, dataset): 55 | """assert that the dataset was loaded.""" 56 | eq_(self.store.get(Category, dataset.gray_stuff.id).name, 57 | dataset.gray_stuff.name) 58 | eq_(self.store.get(Category, dataset.yellow_stuff.id).name, 59 | dataset.yellow_stuff.name) 60 | 61 | def assert_data_torndown(self): 62 | """assert that the dataset was torn down.""" 63 | eq_(self.store.find(Category).count(), 0) 64 | 65 | class TestStormCategory( 66 | HavingCategoryData, StormCategoryTest, LoadableTest): 67 | pass 68 | 69 | class HavingCategoryDataStorable: 70 | """mixin that adds data to a LoadableTest.""" 71 | def datasets(self): 72 | class WhateverIWantToCallIt(DataSet): 73 | class Meta: 74 | storable = Category 75 | class gray_stuff: 76 | id=1 77 | name='gray' 78 | class yellow_stuff: 79 | id=2 80 | name='yellow' 81 | return [WhateverIWantToCallIt] 82 | 83 | class TestStormCategoryStorable( 84 | HavingCategoryDataStorable, StormCategoryTest, LoadableTest): 85 | pass 86 | class TestStormCategoryAsDataType( 87 | HavingCategoryAsDataType, StormCategoryTest, LoadableTest): 88 | pass 89 | 90 | class TestStormPartialLoad( 91 | StormFixtureTest, LoaderPartialRecoveryTest): 92 | def assert_partial_load_aborted(self): 93 | raise SkipTest("I don't think storm can support this feature") 94 | 95 | # t = self.conn.transaction() 96 | # eq_(Category.select(connection=t).count(), 0) 97 | 98 | class StormFixtureCascadeTest(StormFixtureTest): 99 | def assert_data_loaded(self, dataset): 100 | """assert that the dataset was loaded.""" 101 | eq_(self.store.get(Offer,dataset.free_truck.id).name, dataset.free_truck.name) 102 | 103 | eq_(self.store.get(Product, 104 | dataset.truck.id).name, 105 | dataset.truck.name) 106 | 107 | eq_(self.store.get(Category, 108 | dataset.cars.id).name, 109 | dataset.cars.name) 110 | eq_(self.store.get(Category, 111 | dataset.free_stuff.id).name, 112 | dataset.free_stuff.name) 113 | 114 | def assert_data_torndown(self): 115 | """assert that the dataset was torn down.""" 116 | eq_(self.store.find(Category).count(), 0) 117 | eq_(self.store.find(Offer).count(), 0) 118 | eq_(self.store.find(Product).count(), 0) 119 | 120 | class StormFixtureCascadeTestWithHeavyDB(StormFixtureCascadeTest): 121 | def setUp(self): 122 | if not conf.HEAVY_DSN: 123 | raise SkipTest 124 | 125 | StormFixtureCascadeTest.setUp(self, dsn=conf.HEAVY_DSN) 126 | 127 | class TestStormFixtureCascade( 128 | HavingOfferProductData, StormFixtureCascadeTest, 129 | LoadableTest): 130 | pass 131 | class TestStormFixtureCascadeWithHeavyDB( 132 | HavingOfferProductData, StormFixtureCascadeTestWithHeavyDB, 133 | LoadableTest): 134 | pass 135 | class TestStormFixtureCascadeAsType( 136 | HavingOfferProductAsDataType, StormFixtureCascadeTest, 137 | LoadableTest): 138 | pass 139 | class TestStormFixtureCascadeAsRef( 140 | HavingReferencedOfferProduct, StormFixtureCascadeTest, 141 | LoadableTest): 142 | pass 143 | class TestStormFixtureCascadeAsRefInherit( 144 | HavingRefInheritedOfferProduct, StormFixtureCascadeTest, 145 | LoadableTest): 146 | pass 147 | class TestStormFixtureCascadeAsRefInheritWithHeavyDB( 148 | HavingRefInheritedOfferProduct, StormFixtureCascadeTestWithHeavyDB, 149 | LoadableTest): 150 | pass 151 | 152 | -------------------------------------------------------------------------------- /fixture/util.py: -------------------------------------------------------------------------------- 1 | 2 | """Fixture utilties.""" 3 | 4 | import sys 5 | import types 6 | import logging 7 | 8 | from six import reraise 9 | 10 | 11 | __all__ = ['DataTestCase'] 12 | 13 | class DataTestCase(object): 14 | """ 15 | A mixin to use with unittest.TestCase. 16 | 17 | Upon setUp() the TestCase will load the DataSet classes using your Fixture, 18 | specified in class variables. At tearDown(), all loaded data will be 19 | removed. During your test, you will have ``self.data``, a SuperSet instance 20 | to reference loaded data 21 | 22 | Class Attributes: 23 | 24 | ``fixture`` 25 | the :class:`Fixture ` instance to load :class:`DataSet ` classes with 26 | 27 | ``datasets`` 28 | A list of :class:`DataSet ` classes to load 29 | 30 | ``data`` 31 | ``self.data``, a :class:`Fixture.Data ` instance populated for you after ``setUp()`` 32 | 33 | """ 34 | fixture = None 35 | data = None 36 | datasets = [] 37 | def setUp(self): 38 | if self.fixture is None: 39 | raise NotImplementedError("no concrete fixture to load data with") 40 | if not self.datasets: 41 | raise ValueError("there are no datasets to load") 42 | self.data = self.fixture.data(*self.datasets) 43 | self.data.setup() 44 | 45 | def tearDown(self): 46 | self.data.teardown() 47 | 48 | class ObjRegistry: 49 | """registers objects by class. 50 | 51 | all lookup methods expect to get either an instance or a class type. 52 | """ 53 | def __init__(self): 54 | self.registry = {} 55 | 56 | def __repr__(self): 57 | return repr(self.registry) 58 | 59 | def __getitem__(self, obj): 60 | try: 61 | return self.registry[self.id(obj)] 62 | except KeyError: 63 | reraise(KeyError, KeyError("object %s is not in registry" % obj)) 64 | 65 | def __contains__(self, object): 66 | return self.has(object) 67 | 68 | def clear(self): 69 | self.registry = {} 70 | 71 | def has(self, object): 72 | return self.id(object) in self.registry 73 | 74 | def id(self, object): 75 | if hasattr(object, '__class__'): 76 | if issubclass(object.__class__, type): 77 | # then it's a class... 78 | cls = object 79 | else: 80 | # instance ... 81 | cls = object.__class__ 82 | elif type(object)==types.ClassType: 83 | # then it's a classic class (no metaclass)... 84 | cls = object 85 | else: 86 | raise ValueError( 87 | "cannot identify object %s because it isn't an " 88 | "instance or a class" % object) 89 | return id(cls) 90 | 91 | def register(self, object): 92 | id = self.id(object) 93 | self.registry[id] = object 94 | return id 95 | 96 | def with_debug(*channels, **kw): 97 | """ 98 | A `nose`_ decorator calls :func:`start_debug` / :func:`start_debug` before and after the 99 | decorated method. 100 | 101 | All positional arguments are considered channels that should be debugged. 102 | Keyword arguments are passed to :func:`start_debug` 103 | 104 | .. _nose: http://somethingaboutorange.com/mrl/projects/nose/ 105 | 106 | """ 107 | from nose.tools import with_setup 108 | def setup(): 109 | for ch in channels: 110 | start_debug(ch, **kw) 111 | def teardown(): 112 | for ch in channels: 113 | stop_debug(ch) 114 | return with_setup(setup=setup, teardown=teardown) 115 | 116 | def reset_log_level(level=logging.CRITICAL, channels=( 117 | "fixture.loadable", 118 | "fixture.loadable.tree")): 119 | """ 120 | Resets the level on all fixture logs. 121 | 122 | You may need to call this when other applications 123 | reset the root logger's log level. 124 | 125 | Calling this with no args sets all logs to logging.CRITICAL 126 | which should keep them quiet 127 | 128 | Added in version 1.1 129 | """ 130 | for ch in channels: 131 | logging.getLogger(ch).setLevel(level) 132 | 133 | def start_debug(channel, stream=sys.stdout, handler=None, level=logging.DEBUG): 134 | """ 135 | A shortcut to start logging a channel to a stream. 136 | 137 | For example:: 138 | 139 | >>> from fixture.util import start_debug, stop_debug 140 | >>> start_debug("fixture.loadable") 141 | 142 | starts logging messages from the fixture.loadable channel to the stream. 143 | Then... :: 144 | 145 | >>> stop_debug("fixture.loadable") 146 | 147 | ...turns it off. 148 | 149 | Available Channels: 150 | 151 | ``fixture.loadable`` 152 | logs LOAD and CLEAR messages, referring to dataset actions 153 | 154 | ``fixture.loadable.tree`` 155 | logs a tree view of datasets loaded by datasets (recursion) 156 | 157 | 158 | Keyword Arguments: 159 | 160 | ``stream`` 161 | stream to create a loggin.StreamHandler with. defaults to stdout. 162 | 163 | ``handler`` 164 | a preconfigured handler to add to the log 165 | 166 | ``level`` 167 | a logging level to set, default is logging.DEBUG 168 | 169 | 170 | .. note:: 171 | Other applications might add a handler to the root logger, 172 | in which case you can't turn off debug output without messing 173 | with the root logger. 174 | 175 | 176 | """ 177 | log = logging.getLogger(channel) 178 | if not handler: 179 | handler = logging.StreamHandler(stream) 180 | handler.setFormatter(logging.Formatter('%(name)s: %(message)s')) 181 | for h in log.handlers: 182 | log.removeHandler(h) 183 | log.addHandler(handler) 184 | log.setLevel(level) 185 | 186 | def stop_debug(channel=None): 187 | """The reverse of :func:`start_debug`.""" 188 | reset_log_level(channels=[channel]) 189 | 190 | class _dummy_stream(object): 191 | def write(self, *a,**kw): pass 192 | def flush(self, *a, **kw): pass 193 | 194 | def _mklog(channel, default_level=logging.CRITICAL, default_stream=None): 195 | """ 196 | returns a log object that does nothing until something 197 | calls start_debug() 198 | """ 199 | log = logging.getLogger(channel) 200 | log.setLevel(default_level) 201 | if not default_stream: 202 | default_stream = logging.StreamHandler(_dummy_stream()) 203 | log.addHandler(default_stream) 204 | return log 205 | 206 | try: 207 | any = any 208 | except NameError: 209 | # 2.4- 210 | def any(iterable): 211 | for element in iterable: 212 | if element: 213 | return True 214 | return False 215 | 216 | -------------------------------------------------------------------------------- /presentations/pycon2007-fixture-talk-OLD.key.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/presentations/pycon2007-fixture-talk-OLD.key.zip -------------------------------------------------------------------------------- /presentations/pycon2007-fixture-talk-lowres.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/presentations/pycon2007-fixture-talk-lowres.pdf -------------------------------------------------------------------------------- /presentations/pycon2007-fixture-talk-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/presentations/pycon2007-fixture-talk-notes.pdf -------------------------------------------------------------------------------- /presentations/pycon2007-fixture-talk.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/presentations/pycon2007-fixture-talk.pdf -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source fixture/test/profile/full.sh 4 | # also see setup.cfg for more options 5 | 6 | make -C docs doctest 7 | 8 | # there is a bug in zc.buildout which needs to 9 | # be fixed before make will exit non-zero 10 | # https://bugs.launchpad.net/zc.buildout/+bug/164629/ 11 | if [ $? -ne 0 ]; then 12 | exit $? 13 | fi 14 | 15 | # this is created by bin/buildout: 16 | ./bin/test-fixture -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | release = sdist bdist_egg upload 3 | 4 | # also see run_tests.sh 5 | [global] 6 | command_packages = fixture.setup_cmd 7 | 8 | [nosetests] 9 | verbosity=2 10 | detailed-errors=0 11 | with-doctest=1 12 | doctest-extension=rst 13 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from setuptools import setup, find_packages 4 | 5 | 6 | _CURRENT_DIR_PATH = os.path.abspath(os.path.dirname(__file__)) 7 | _VERSION = \ 8 | open(os.path.join(_CURRENT_DIR_PATH, 'VERSION.txt')).readline().rstrip() 9 | 10 | _LONG_DESCRIPTION = """ 11 | It provides several utilities for achieving a *fixed state* when testing 12 | Python programs. Specifically, these utilities setup / teardown databases and 13 | work with temporary file systems. 14 | 15 | You may want to start by reading the `End User Documentation`_. 16 | 17 | .. _End User Documentation: http://farmdev.com/projects/fixture/docs/ 18 | """ 19 | 20 | 21 | setup( 22 | name='fixture', 23 | version=_VERSION, 24 | author='Kumar McMillan', 25 | author_email='kumar dot mcmillan / gmail.com', 26 | description='fixture is a package for loading and referencing test data', 27 | classifiers=['Environment :: Other Environment', 28 | 'Intended Audience :: Developers', 29 | ('License :: OSI Approved :: GNU Library or Lesser ' 30 | 'General Public License (LGPL)'), 31 | 'Natural Language :: English', 32 | 'Operating System :: OS Independent', 33 | 'Programming Language :: Python', 34 | 'Topic :: Software Development :: Testing', 35 | 'Topic :: Software Development :: Quality Assurance', 36 | 'Topic :: Utilities'], 37 | long_description=_LONG_DESCRIPTION, 38 | license='GNU Lesser General Public License (LGPL)', 39 | keywords=('test testing tools unittest fixtures setup teardown ' 40 | 'database stubs IO tempfile'), 41 | url='http://farmdev.com/projects/fixture/', 42 | 43 | packages=find_packages(), 44 | 45 | test_suite="fixture.setup_test_not_supported", 46 | entry_points={ 47 | 'console_scripts': ['fixture = fixture.command.generate:main'] 48 | }, 49 | install_requires=[ 50 | 'six >= 1.10.0', 51 | ], 52 | # the following allows e.g. easy_install fixture[django] 53 | extras_require={ 54 | 'decorators': ['nose>=0.9.2'], 55 | 'sqlalchemy': ['SQLAlchemy>=0.4'], 56 | 'sqlobject': ['SQLObject==0.8'], 57 | 'django': ['django>=1.8'], 58 | }, 59 | ) 60 | -------------------------------------------------------------------------------- /src/.hidden: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixture-py/fixture/bdf33197d447265533391edbb00fb035f52c00b8/src/.hidden -------------------------------------------------------------------------------- /src/nosedjango-for-fixture/AUTHORS: -------------------------------------------------------------------------------- 1 | Jason Pellerin 2 | Bjorn Stabell 3 | Victor Ng 4 | -------------------------------------------------------------------------------- /src/nosedjango-for-fixture/README.txt: -------------------------------------------------------------------------------- 1 | 2 | This is a temporary, impatient hack of the NoseDjango plugin purely to allow for testing of fixture's Django functionality. It is a fork of VictorNG's latest plugin but removes most of the functionality. 3 | 4 | The original lives on at http://www.assembla.com/spaces/nosedjango 5 | 6 | - Kumar McMillan -------------------------------------------------------------------------------- /src/nosedjango-for-fixture/nosedjango/__init__.py: -------------------------------------------------------------------------------- 1 | # Just a place holder for Windows. 2 | __version__ = (0, 6) 3 | -------------------------------------------------------------------------------- /src/nosedjango-for-fixture/nosedjango/nosedjango.py: -------------------------------------------------------------------------------- 1 | """ 2 | nose plugin for easy testing of django projects and apps. Sets up a test 3 | database (or schema) and installs apps from test settings file before tests 4 | are run, and tears the test database (or schema) down after all tests are run. 5 | """ 6 | 7 | import os, sys 8 | import re 9 | 10 | from nose.plugins import Plugin 11 | import nose.case 12 | 13 | from nose.importer import add_path 14 | os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' 15 | 16 | SETTINGS_PATH = None 17 | 18 | class NoseDjango(Plugin): 19 | """ 20 | Enable to set up django test environment before running all tests, and 21 | tear it down after all tests. If the django database engine in use is not 22 | sqlite3, one or both of --django-test-db or django-test-schema must be 23 | specified. 24 | 25 | Note that your django project must be on PYTHONPATH for the settings file 26 | to be loaded. The plugin will help out by placing the nose working dir 27 | into sys.path if it isn't already there, unless the -P 28 | (--no-path-adjustment) argument is set. 29 | """ 30 | name = 'django' 31 | 32 | def configure(self, options, conf): 33 | Plugin.configure(self, options, conf) 34 | self.verbosity = conf.verbosity 35 | self.options = options 36 | 37 | def begin(self): 38 | """Create the test database and schema, if needed, and switch the 39 | connection over to that database. Then call install() to install 40 | all apps listed in the loaded settings module. 41 | """ 42 | global SETTINGS_PATH 43 | # Add the working directory (and any package parents) to sys.path 44 | # before trying to import django modules; otherwise, they won't be 45 | # able to find project.settings if the working dir is project/ or 46 | # project/.. 47 | 48 | if self.options.django_settings_path: 49 | SETTINGS_PATH = self.options.django_settings_path 50 | 51 | if not SETTINGS_PATH: 52 | sys.stderr.write("Can't find Django settings file!\n") 53 | # short circuit if no settings file can be found 54 | return 55 | 56 | if self.conf.addPaths: 57 | list(map(add_path, self.conf.where)) 58 | 59 | add_path(SETTINGS_PATH) 60 | sys.path.append(SETTINGS_PATH) 61 | import settings 62 | 63 | # Some Django code paths evaluate differently 64 | # between DEBUG and not DEBUG. Example of this include the url 65 | # dispatcher when 404's are hit. Django's own test runner forces DEBUG 66 | # to be off. 67 | settings.DEBUG = False 68 | 69 | from django.core import mail 70 | self.mail = mail 71 | from django.conf import settings 72 | from django.test.utils import setup_test_environment 73 | from django.db import connection 74 | 75 | self.old_db = settings.DATABASE_NAME 76 | 77 | # setup the test env for each test case 78 | setup_test_environment() 79 | connection.creation.create_test_db(verbosity=self.verbosity) 80 | 81 | # exit the setup phase and let nose do it's thing 82 | 83 | def options(self, parser, env=os.environ): 84 | Plugin.options(self, parser, env) 85 | parser.add_option('--django-settings-path', action="store", help=( 86 | "Path to where your app's settings.py is stored. I.E. the directory settings.py lives in." 87 | )) 88 | 89 | def beforeTest(self, test): 90 | 91 | if not SETTINGS_PATH: 92 | # short circuit if no settings file can be found 93 | return 94 | 95 | # This is a distinctive difference between the NoseDjango 96 | # test runner compared to the plain Django test runner. 97 | # Django uses the standard unittest framework and resets the 98 | # database between each test *suite*. That usually resolves 99 | # into a test module. 100 | # 101 | # The NoseDjango test runner will reset the database between *every* 102 | # test case. This is more in the spirit of unittesting where there is 103 | # no state information passed between individual tests. 104 | 105 | ## this is done in TestCase objects 106 | 107 | # from django.core.management import call_command 108 | # from django.core.urlresolvers import clear_url_caches 109 | # from django.conf import settings 110 | # call_command('flush', verbosity=0, interactive=False) 111 | # 112 | # if isinstance(test, nose.case.Test) and \ 113 | # isinstance(test.test, nose.case.MethodTestCase) and \ 114 | # hasattr(test.context, 'fixtures'): 115 | # # We have to use this slightly awkward syntax due to the fact 116 | # # that we're using *args and **kwargs together. 117 | # call_command('loaddata', *test.context.fixtures, **{'verbosity': 0}) 118 | # 119 | # if isinstance(test, nose.case.Test) and \ 120 | # isinstance(test.test, nose.case.MethodTestCase) and \ 121 | # hasattr(test.context, 'urls'): 122 | # # We have to use this slightly awkward syntax due to the fact 123 | # # that we're using *args and **kwargs together. 124 | # self.old_urlconf = settings.ROOT_URLCONF 125 | # settings.ROOT_URLCONF = self.urls 126 | # clear_url_caches() 127 | # 128 | # self.mail.outbox = [] 129 | 130 | def finalize(self, result=None): 131 | """ 132 | Clean up any created database and schema. 133 | """ 134 | if not SETTINGS_PATH: 135 | # short circuit if no settings file can be found 136 | return 137 | 138 | from django.test.utils import teardown_test_environment 139 | from django.db import connection 140 | from django.conf import settings 141 | connection.creation.destroy_test_db(self.old_db, verbosity=self.verbosity) 142 | teardown_test_environment() 143 | 144 | if hasattr(self, 'old_urlconf'): 145 | settings.ROOT_URLCONF = self.old_urlconf 146 | clear_url_caches() 147 | 148 | -------------------------------------------------------------------------------- /src/nosedjango-for-fixture/setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_build = 3 | tag_date = 0 4 | tag_svn_revision = 0 5 | 6 | -------------------------------------------------------------------------------- /src/nosedjango-for-fixture/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='NoseDjango', 5 | version='0.6', 6 | author='', 7 | author_email = '', 8 | description = '', 9 | install_requires='nose>=0.10', 10 | url = "", 11 | license = '', 12 | packages = find_packages(), 13 | zip_safe = False, 14 | include_package_data = True, 15 | entry_points = { 16 | 'nose.plugins': [ 17 | 'django = nosedjango.nosedjango:NoseDjango', 18 | ] 19 | } 20 | ) 21 | 22 | --------------------------------------------------------------------------------