Full Code of eoyilmaz/stalker for AI

develop 7de585b84de8 cached
264 files
3.1 MB
832.9k tokens
3120 symbols
1 requests
Download .txt
Showing preview only (3,330K chars total). Download the full file or copy to clipboard to get everything.
Repository: eoyilmaz/stalker
Branch: develop
Commit: 7de585b84de8
Files: 264
Total size: 3.1 MB

Directory structure:
gitextract_k2ghu6v_/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── pytest.yml
├── .gitignore
├── CHANGELOG.rst
├── CHANGELOG_OLD.rst
├── COPYING
├── COPYING.LESSER
├── Dockerfile-py3.5
├── INSTALL
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── TODO.rst
├── alembic/
│   ├── README
│   ├── env.py
│   ├── script.py.mako
│   └── versions/
│       ├── 0063f547dc2e_updated_version_inputs_table.py
│       ├── 019378697b5b_rename_depends_to_to_depends_on.py
│       ├── 101a789e38ad_created_task_responsible.py
│       ├── 1181305d3001_added_client_id_column_to_goods_table.py
│       ├── 130a7697cd79_vacation_user_can_now_be_nullable.py
│       ├── 174567b9c159_note_content.py
│       ├── 182f44ce5f07_added_users_company_and_projects_client.py
│       ├── 1875136a2bfc_removed_version_variant_name_attribute.py
│       ├── 1c9c9c28c102_price_lists_and_goods.py
│       ├── 21b88ed3da95_added_referencemixin.py
│       ├── 2252e51506de_multiple_repositories.py
│       ├── 23dff41c95ff_removed_tasks_is_complete_column.py
│       ├── 255ee1f9c7b3_added_payments_table.py
│       ├── 258985128aff_create_entitygroups_table.py
│       ├── 25b3eba6ffe7_derive_version_from.py
│       ├── 275bdc106fd5_added_ticket_summary.py
│       ├── 2aeab8b376dc_fg_color_bg_color.py
│       ├── 2e4a3813ae76_created_daily_class.py
│       ├── 2f55dc4f199f_wiki_page.py
│       ├── 30c576f3691_budget_and_budget_entry.py
│       ├── 31b1e22b455e_added_exclude_and_check_constraints_to_.py
│       ├── 39d3c16ff005_budget_entries_good_id.py
│       ├── 3be540ad3a93_added_version_revision_number_attribute.py
│       ├── 409d2d73ca30_user_rate.py
│       ├── 433d9caaafab_task_review_status_workflow.py
│       ├── 4400871fa852_scene_is_now_deriving_from_task.py
│       ├── 4664d72ce1e1_renamed_link_path_to_full_path.py
│       ├── 46775e4a3d96_create_enum_types.py
│       ├── 4a836cf73bcf_create_entitytype_accepts_references.py
│       ├── 5078390e5527_shot_scene_relation_is_now_many_to_one.py
│       ├── 5168cc8552a3_html_style_html_class.py
│       ├── 5355b569237b_version_version_of_r.py
│       ├── 53d8127d8560_parent_child_relatio.py
│       ├── 57a5949c7f29_cache_for_total_logged_seconds.py
│       ├── 5814290f49c7_added_shot_source_in_shot_source_out_record_in.py
│       ├── 583875229230_good_task_relation.py
│       ├── 59092d41175c_added_version_created_with.py
│       ├── 5999269aad30_added_generic_text_attribute.py
│       ├── 59bfe820c369_resource_efficiency.py
│       ├── 6297277da38_added_vacation_class.py
│       ├── 644f5251fc0d_remove_project_active_attribute.py
│       ├── 745b210e6907_fix_non_existing_thumbnails.py
│       ├── 856e70016b2_roles.py
│       ├── 91ed52b72b82_created_variant_class.py
│       ├── 92257ba439e1_budget_is_now_statusable.py
│       ├── 9f9b88fef376_link_renamed_to_file.py
│       ├── a2007ad7f535_added_review_version_id_column.py
│       ├── a6598cde6b_versions_are_not_mix.py
│       ├── a9319b19f7be_added_shot_fps.py
│       ├── af869ddfdf9_entity_to_note_relation_is_now_many_to_many.py
│       ├── bf67e6a234b4_added_revision_code_attribute.py
│       ├── c5607b4cfb0a_added_support_for_time_zones.py
│       ├── d8421de6a206_added_project_users_rate_column.py
│       ├── e25ec9930632_shot_sequence_relation_is_now_many_to_.py
│       ├── ea28a39ba3f5_added_invoices_table.py
│       ├── eaed49db6d9_added_position_column_to_Project_Repositories.py
│       ├── ec1eb2151bb9_rename_version_take_name_to_version_.py
│       ├── ed0167fff399_added_workinghours_table.py
│       ├── f16651477e64_added_authenticationlog_class.py
│       ├── f2005d1fbadc_added_projectclients.py
│       └── feca9bac7d5a_renamed_osx_to_macos.py
├── alembic.ini
├── docs/
│   ├── Makefile
│   ├── make.bat
│   ├── make_html.bat
│   └── source/
│       ├── _static/
│       │   └── images/
│       │       ├── Task_Status_Workflow.vue
│       │       └── stalker_design.vue
│       ├── _templates/
│       │   └── autosummary/
│       │       ├── base.rst
│       │       ├── class.rst
│       │       └── module.rst
│       ├── about.rst
│       ├── changelog.rst
│       ├── conf.py
│       ├── configure.rst
│       ├── contents.rst
│       ├── contribute.rst
│       ├── design.rst
│       ├── index.rst
│       ├── inheritance_diagram.rst
│       ├── installation.rst
│       ├── roadmap.rst
│       ├── status_and_status_lists.rst
│       ├── summary.rst
│       ├── task_review_workflow.rst
│       ├── todo.rst
│       ├── tutorial/
│       │   ├── asset_management.rst
│       │   ├── basics.rst
│       │   ├── collaboration.rst
│       │   ├── conclusion.rst
│       │   ├── creating_simple_data.rst
│       │   ├── extending_som.rst
│       │   ├── pipeline.rst
│       │   ├── query_update_delete_data.rst
│       │   ├── scheduling.rst
│       │   ├── task_and_resource_management.rst
│       │   └── tutorial_files/
│       │       └── tutorial.py
│       ├── tutorial.rst
│       └── upgrade_db.rst
├── examples/
│   ├── __init__.py
│   ├── extending/
│   │   ├── __init__.py
│   │   ├── camera_lens.py
│   │   ├── great_entity.py
│   │   └── statused_entity.py
│   └── flat_project_example.py
├── pyproject.toml
├── requirements-dev.txt
├── requirements.txt
├── setup.py
├── src/
│   └── stalker/
│       ├── VERSION
│       ├── __init__.py
│       ├── config.py
│       ├── db/
│       │   ├── __init__.py
│       │   ├── declarative.py
│       │   ├── session.py
│       │   ├── setup.py
│       │   └── types.py
│       ├── exceptions.py
│       ├── log.py
│       ├── models/
│       │   ├── __init__.py
│       │   ├── asset.py
│       │   ├── auth.py
│       │   ├── budget.py
│       │   ├── client.py
│       │   ├── department.py
│       │   ├── entity.py
│       │   ├── enum.py
│       │   ├── file.py
│       │   ├── format.py
│       │   ├── message.py
│       │   ├── mixins.py
│       │   ├── note.py
│       │   ├── project.py
│       │   ├── repository.py
│       │   ├── review.py
│       │   ├── scene.py
│       │   ├── schedulers.py
│       │   ├── sequence.py
│       │   ├── shot.py
│       │   ├── status.py
│       │   ├── structure.py
│       │   ├── studio.py
│       │   ├── tag.py
│       │   ├── task.py
│       │   ├── template.py
│       │   ├── ticket.py
│       │   ├── type.py
│       │   ├── variant.py
│       │   ├── version.py
│       │   └── wiki.py
│       ├── py.typed
│       ├── utils.py
│       └── version.py
├── tests/
│   ├── __init__.py
│   ├── benchmarks/
│   │   ├── __init__.py
│   │   └── task_total_logged_seonds.py
│   ├── config/
│   │   ├── __init__.py
│   │   └── test_config.py
│   ├── conftest.py
│   ├── data/
│   │   ├── project_to_tjp_output.jinja2
│   │   ├── project_to_tjp_output_formatted
│   │   └── project_to_tjp_output_rendered
│   ├── db/
│   │   ├── __init__.py
│   │   ├── test_db.py
│   │   ├── test_dbsession.py
│   │   └── test_types.py
│   ├── mixins/
│   │   ├── __init__.py
│   │   ├── test_acl_mixin.py
│   │   ├── test_amount_mixin.py
│   │   ├── test_code_mixin.py
│   │   ├── test_create_secondary_table.py
│   │   ├── test_dag_mixin.py
│   │   ├── test_date_range_mixin.py
│   │   ├── test_declarative_project_mixin.py
│   │   ├── test_declarative_reference_mixin.py
│   │   ├── test_declarative_schedule_mixin.py
│   │   ├── test_declarative_status_mixin.py
│   │   ├── test_project_mixin.py
│   │   ├── test_reference_mixin.py
│   │   ├── test_schedule_mixin.py
│   │   ├── test_status_mixin.py
│   │   ├── test_target_entity_type_mixin.py
│   │   └── test_unit_mixin.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── test_asset.py
│   │   ├── test_authentication_log.py
│   │   ├── test_budget.py
│   │   ├── test_client.py
│   │   ├── test_client_user.py
│   │   ├── test_daily.py
│   │   ├── test_department.py
│   │   ├── test_department_user.py
│   │   ├── test_dependency_target.py
│   │   ├── test_entity.py
│   │   ├── test_entity_group.py
│   │   ├── test_file.py
│   │   ├── test_filename_template.py
│   │   ├── test_generic.py
│   │   ├── test_good.py
│   │   ├── test_group.py
│   │   ├── test_image_format.py
│   │   ├── test_invoice.py
│   │   ├── test_local_session.py
│   │   ├── test_message.py
│   │   ├── test_note.py
│   │   ├── test_payment.py
│   │   ├── test_permission.py
│   │   ├── test_price_list.py
│   │   ├── test_project.py
│   │   ├── test_project_client.py
│   │   ├── test_project_user.py
│   │   ├── test_repository.py
│   │   ├── test_review.py
│   │   ├── test_role.py
│   │   ├── test_scene.py
│   │   ├── test_schedule_constraint.py
│   │   ├── test_schedule_model.py
│   │   ├── test_schedulers.py
│   │   ├── test_sequence.py
│   │   ├── test_shot.py
│   │   ├── test_simple_entity.py
│   │   ├── test_status.py
│   │   ├── test_status_list.py
│   │   ├── test_structure.py
│   │   ├── test_studio.py
│   │   ├── test_tag.py
│   │   ├── test_task.py
│   │   ├── test_task_dependency.py
│   │   ├── test_task_juggler_scheduler.py
│   │   ├── test_task_status_workflow.py
│   │   ├── test_ticket.py
│   │   ├── test_time_log.py
│   │   ├── test_time_unit.py
│   │   ├── test_traversal_direction.py
│   │   ├── test_type.py
│   │   ├── test_user.py
│   │   ├── test_vacation.py
│   │   ├── test_variant.py
│   │   ├── test_version.py
│   │   ├── test_wiki.py
│   │   └── test_working_hours.py
│   ├── test_exceptions.py
│   ├── test_logging.py
│   ├── test_readme_tutorial.py
│   ├── test_testing.py
│   ├── test_version.py
│   └── utils.py
└── whitelist.txt

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# http://editorconfig.org

root = true

[*]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8
end_of_line = lf

[*.yml]
indent_size = 2

[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

[*.bat]
indent_style = tab
end_of_line = crlf

[LICENSE]
insert_final_newline = false

[Makefile]
indent_style = tab


================================================
FILE: .github/workflows/pytest.yml
================================================
name: Unit Tests
on:
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review, unlabeled]
    branches:
      - develop
  push:
    branches:
      - develop

jobs:
  build:

    name: Python ${{ matrix.python-version }} & PostgreSQL ${{ matrix.postgresql-version }}
    env:
      PGPASSWORD: postgres
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
        postgresql-version: ["14", "15", "16", "17"]

    steps:
    - uses: actions/checkout@v4
    - name: Set Environment Variables
      run: |
        echo "py_version=$(echo ${{ matrix.python-version }} | tr -d .)" >> $GITHUB_ENV
        if [ "${{ matrix.python-version }}" == "3.8" ]; then
          echo "add_dir_str=${{ matrix.python-version }}" >> $GITHUB_ENV
        elif [ "${{ matrix.python-version }}" == "3.9" ]; then
          echo "add_dir_str=${{ matrix.python-version }}" >> $GITHUB_ENV
        elif [ "${{ matrix.python-version }}" == "3.10" ]; then
          echo "add_dir_str=cpython-310" >> $GITHUB_ENV
        elif [ "${{ matrix.python-version }}" == "3.11" ]; then
          echo "add_dir_str=cpython-311" >> $GITHUB_ENV
        elif [ "${{ matrix.python-version }}" == "3.12" ]; then
          echo "add_dir_str=cpython-312" >> $GITHUB_ENV
        elif [ "${{ matrix.python-version }}" == "3.13" ]; then
          echo "add_dir_str=cpython-313" >> $GITHUB_ENV
        fi

    - name: Setup PostgreSQL for Linux/macOS/Windows
      uses: ikalnytskyi/action-setup-postgres@v7
      with:
        # The username of the user to setup.
        username: postgres
        # The password of the user to setup.
        password: postgres
        # The database name to setup and grant permissions to created user.
        database: postgres
        # The server port to listen on.
        port: 5432
        # The PostgreSQL major version to install. Either "14", "15", "16" or "17".
        postgres-version: ${{ matrix.postgresql-version }}
        # When "true", encrypt connections using SSL (TLS).
        ssl: false

    - name: Set up TaskJuggler
      run: |
        sudo gem install taskjuggler

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}

    - name: Update pip
      run: |
        sudo apt-get install -y $(grep -o ^[^#][[:alnum:]-]*.* "packages.list")
        python3 -m pip install --upgrade pip
        pip install wheel

    - name: Install Python dependencies
      run: |
        pip install -r requirements.txt -r requirements-dev.txt

    - name: Build Stalker
      run: |
        python3 -m build
        ls -l dist/
        wheel_file=$(ls dist/stalker-*.whl)
        pip install $wheel_file

    - name: Test with pytest
      run: |
        PYTHONPATH=src python -m pytest

    - name: Archive code coverage results
      uses: actions/upload-artifact@v4
      with:
        name: code-coverage-report-py${{ env.py_version }}-psql${{ matrix.postgresql-version }}
        path: htmlcov
        retention-days: 10

  # windows:
  #   name: Test with Python ${{ matrix.python-version }} on Windows
  #   runs-on: windows-latest

  #   strategy:
  #     fail-fast: false
  #     matrix:
  #       python-version:
  #         - "3.8"
  #         - "3.9"
  #         - "3.10"
  #         - "3.11"

  #   steps:
  #   - uses: actions/checkout@v4

  #   - name: Set Environment Variables
  #     run: |
  #       $py_version = "${{ matrix.python-version }}" -replace '\.', ''
  #       echo "py_version=$py_version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
  #       if ("${{ matrix.python-version }}" -eq "3.8") {
  #         echo "add_dir_str=${{ matrix.python-version }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
  #       } elseif ("${{ matrix.python-version }}" -eq "3.9") {
  #         echo "add_dir_str=${{ matrix.python-version }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
  #       } elseif ("${{ matrix.python-version }}" -eq "3.10") {
  #         echo "add_dir_str=cpython-310" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
  #       } elseif ("${{ matrix.python-version }}" -eq "3.11") {
  #         echo "add_dir_str=cpython-311" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
  #       } elseif ("${{ matrix.python-version }}" -eq "3.12") {
  #         echo "add_dir_str=cpython-312" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
  #       }

  #   - name: Set up Python ${{ matrix.python-version }}
  #     uses: actions/setup-python@v5
  #     with:
  #       python-version: ${{ matrix.python-version }}

  #   - name: Update pip
  #     run: |
  #       python -m pip install --upgrade pip
  #       pip install wheel

  #   - name: Install Python dependencies
  #     run: |
  #       pip install -r requirements-tests.txt -r requirements-dev.txt

  #   - name: Test with pytest
  #     run: |
  #       python -m pytest --verbose -n auto -W ignore --color=yes --cov=. --cov-report html

  #   - name: Archive code coverage results
  #     uses: actions/upload-artifact@v4
  #     with:
  #       name: code-coverage-report-${{ env.py_version }}-windows
  #       path: htmlcov
  #       retention-days: 10


================================================
FILE: .gitignore
================================================
.cache/*
.coverage*
.DS_Store
.env
.mypy_cache/
.pytest_cache
.tox/
.venv/
.vscode/
*.pyc
*.swp
*~*
build/*
dist/
dist/*
docs/build/*
docs/doctrees/*
docs/html/*
docs/latex/*
docs/source/generated/*
docs/source/static/design
docs/source/static/stalker_design*.vue
htmlcov
include/*
local
stalker.db*
stalker.egg-info

================================================
FILE: CHANGELOG.rst
================================================
===============
Stalker Changes
===============

1.0.0
=====

* `Version.take_name` has been renamed to `Version.variant_name` to follow the
  industry standard (and then removed it completely as we now have `Variant`
  class for this).
* `Task.depends` renamed to `Task.depends_on`.
* `TaskDependency.task_depends_to` renamed to `TaskDependency.task_depends_on`.
* Modernized Stalker as a Python project. It is now fully PEP 517 compliant.
* Stalker now supports Python versions from 3.8 to 3.13.
* Stalker is now SQLAlchemy 2.x compliant.
* Stalker is now fully type hinted.
* Added GitHub actions for CI/CD practices.
* Updated validation messages to make them more consistently displaying the
  current type and the value of the validated attribute.
* Added Makefile workflow to help creating a virtualenv, building, installing,
  releasing etc. actions much more easier.
* Added `tox` config to run the test with Python 3.8 to 3.13.
* Increased test coverage to 99.76%.
* Updated documentation theme to `furo`.
* Renamed `OSX` to `macOS` where ever it is mentioned.
* `Scene` is now deriving from `Task`.
* `Shot.sequences` is now `Shot.sequence` and it is many-to-one.
* `Shot.scenes` is now `Shot.scene` and it is many-to-one.
* Added the `Variant` class to allow variants to be approved and managed
  individually.
* Added `Review.version` attribute to relate a `Version` instance to the
  review.
* Removed the `Version.variant_name` attribute. The migration alembic script
  will create `Variant` instances for each `Version.variant_name` under the
  container `Task` to hold the information.
* `Version._template_variables()` now finds the related `Asset`, `Shot` and
  `Sequence` values and passes them in the returned dictionary.
* All the enum values handled with arbitrary string lists or integer values are
  now proper enum classes. As a result we now have `ScheduleConstraint`,
  `TimeUnit`, `ScheduleModel`, `DependencyTarget`, `TraversalDirection`
  enum classes which are removing the need of using fiddly strings as enum
  values.
* `StatusList`s that are created for super classes can now be used with the
  derived classes, i.e. a status list created specifically for `Task` can now
  be used with `Asset`, `Shot`, `Sequence` and `Scenes` and any future `Task`
  derivatives.

0.2.27
======

* Fixed a bug in ``Task.responsible`` attribute. This change has also slightly
  changed how the ``Task.responsible`` attribute works. It still comes from the
  parent if the ``Task.responsible`` is empty or None, but when queried it
  causes the attribute to be filled with parent data. This is a slight change,
  but may break some workflows.

* Added ``ScheduleMixin.to_unit`` that converts the given ``seconds`` to the
  given ``unit`` in consideration of the given ``schedule_model``.

0.2.26
======

* ``Task.percent_complete`` value is now properly calculated for a parent Task
  that contains a mixed type of "effort", "duration" and "length" based tasks.

0.2.25.1
========

* **Update:** Updated the ``.travis.yml`` file to use PostgreSQL 13.3 and
  Ubuntu 20.04 Focal Fossa.
* **Update:** Updated the ``upload_to_pypi`` command to follow the current
  Python packaging guide.
* **Update:** Migrated from ``TravisCI.org`` to ``TravisCI.com``.
* **Update:** Re-enabled concurrent testing in ``.travis.yml``.

0.2.25
======

* **Update:** Stalker is now compatible with SQLAlchemy 1.4,
  psycopg2-binary 2.86 and Python 3.9+. But more work still needs to be done to
  make it SQLAlchemy 2.0 compatible.

0.2.24.3
========

This release is again mainly related to fixing failing tests.

0.2.24.2
========

This release is mainly related to cleaning up some complains that arose while
testing the library.

* **Fix:** Fixed two tests which are testing the ``stalker.db`` module to
  check the system against the correct Alembic revision id.

* **Update:** Removed the unnecessary ``pytest.skip`` commands in the
  ``Repository`` class tests which were shipping the tests if the OS is not
  Windows. But they should work fine under all OSes.

* **Update:** Updated all class documentation and removed the cancellation
  character (which was apparently not good for PEP8)

* **Fix:** Fixed some warnings about some regular expressions.


0.2.24.1
========

* **Fix:** Fixed ``stalker.db`` module to check for the correct Alembic
  revision id.


0.2.24
======

* **New:** ``Repository`` instances now have a ``code`` attribute which is
  used for generating the environment variables where in previous versions the
  ``id`` attribute has been used which caused difficulties in transferring the
  data to a different installation of Stalker. Also to make the system
  backwards compatible, Stalker will still set the old ``id`` based environment
  variables. But when asked for an environment variable it will return the
  ``code`` based one. The ``code`` argument as usual has to be initialized on
  ``Repository`` instance creation. That's why this version is slightly
  backwards incompatible and needs the database to be updated with Alembic
  (with the command ``alembic update head``).

* **Fix:** ``Repository`` methods ``is_in_repo`` and ``find_repo`` are now case
  insensitive for Windows paths.

* **Update:** Updated ``Project`` class documentation and included information
  about what is going to be deleted or how the delete operation will be
  cascaded when a ``Project`` instance is deleted.

0.2.23
======

* **Update:** Updated the ``setup.py`` to require ``psycopg2-binary`` instead
  of ``psycopg2``. Also updated the configuration files for Docker and Travis.
  This changes the requirement of psycopg2 to psycopg2-binary, which will make
  it easier to get the installation to complete on e.g. CentOS 7 without
  requiring pg_config.

0.2.22
======

* **Fix:** Fixed ``TaskJugglerScheduler.schedule()`` method to correctly decode
  byte data from ``sys.stderr`` to string for Python 3.x.

* **Fix:** Fixed a couple of tests for TaskJuggler.

* **Update:** Updated Classifiers information in ``setup.py``, removed Python
  versions 2.6, 3.0, 3.1 and 3.2 from supported Python versions.

* **Fix:** Removed Python 3.3 from TravisCI build which is not supported by
  ``pytest`` apparently.

* **Update:** Updated TravisCI config and removed Python 2.6 and added Python
  3.6.

* **Update:** Added a test case for an edge usage of FilenameTemplate.

* **Update:** Updated .gitignore file to ignore PyTest cache folder.

* **Update:** Updated the License file to correctly reflect the project license
  of LGPLv3.

* **Update:** Update copyright information.

* **New:** Created ``make_html.bat`` for Windows.

* **New:** Added support for Python wheel.


0.2.21
======

* **New:** Switched from ``nose`` + ``unittest`` to ``pytest`` as the main
  testing framework (with ``pytest-xdist`` tests complete 4x faster).

* **New:** Added ``DBSession.save()`` shortcut method for convenience which
  does an ``add`` or ``add_all`` (depending to the input) followed by a
  ``commit`` at once.

* **Update:** Updated the about page for a more appealing introduction to the
  library.

* **New:** Stalker now creates default ``StatusList`` for ``Project`` instances
  on database initialization.

* **Update:** SQLite3 support is back. In fact it was newer gone. For
  simplicity of first time users the default database is again SQLite3. It was
  dropped for the sake of adding more PostgreSQL oriented features. But then it
  is recognized that the system can handle both. Though a two new Variant had
  to be created for JSON and Datetime columns.

* **Update:** With the reintroduction of SQLite3, the new JSON type column in
  ``WorkingHours`` class has been upgraded to support SQLite3. So with SQLite3
  the column stores the data as TEXT but seamlessly convert them to JSON when
  ORM loads or commits the data.

* **New:** Added ``ConfigBase`` as a base class for ``Config`` to let it be
  used in other config classes.

* **Fix:** Fixed ``testing.create_db()`` and ``testing.drop_db()`` to fallback
  to ``subprocess.check_call`` method for Python 2.6.

* **Fix:** Fixed ``stalker.models.auth.User._validate_password()`` method to
  work with Python 2.6.

* **Update:** Updated all of the tests to use ``pytest`` style assertions to
  support Python 2.6 along with 2.7 and 3.0+.

* **Fix:** Fixed ``stalker.db.check_alembic_version()`` function to invalidate
  the connection, so it is not possible to continue with the current session,
  preventing users to ignore the raised ``ValueError`` when the
  ``alembic_version`` of the database is not matching the ``alembic_version``
  of Stalker's current version.


0.2.20
======

* **New:** Added ``goods`` attribute to the ``Client`` class. To allow special
  priced ``Goods`` to be created for individual clients.

* **Fix:** The ``WorkingHours`` class is now derived from ``Entity`` thus it is
  not stored in a ``PickleType`` column in ``Studio`` anymore. (issue: #44)

* **Update:** Updated ``appveyor.yml`` to match ``travis.yml``.


0.2.19
======

* **Update:** Updated the ``stalker.config.Config.database_engine_settings`` to
  point the test database.

* **Fix:** Fixed a bug in ``stalker.testing.UnitTestDBBase.setUp()`` where it
  was not considering the existence of the ``STALKER_PATH`` environment
  variable while doing the tests.

* **Update:** Removed debug message from ``db.setup()`` which was revealing the
  database password.

* **Update:** Updated the ``UnitTestDBBase``, it now creates its own test
  database, which allows all the tests to run in an individual database. Thus,
  the tests can now be run in ``multiprocess`` mode which speeds things a lot.

* **Fix:** Removed any module level imports of ``stalker.defaults`` variable,
  which can be changed by a Studio (or by tests) and should always be
  refreshed.

* **Update:** Removed the module level import of the
  ``stalker.db.session.DBSession`` in ``stalker.db``, so it is not possible to
  use ``db.DBSession`` anymore.

* **Update:** The import statements that imports ``stalker.defaults`` moved to
  local scopes to allow runtime changes to the ``defaults`` to be reflected
  correctly.

* **Update:** Added Python fall back mode to
  ``stalker.shot.Shot._check_code_availability()`` which runs when there is no
  database.

* **Update:** ``stalker.models.task.TimeLog._validate_task()`` is now getting
  the ``Status`` instances from the ``StatusList`` that is attached to the
  ``Task`` instance instead of doing a database query.

* **Update:** ``stalker.models.task.TimeLog._validate_resource()`` is now
  falling back to a Python implementation if there is no database connection.

* **Update:** ``stalker.models.task.Task._total_logged_seconds_getter()`` is
  now hundreds of times faster when there is a lot of ``TimeLog`` instances
  attached to the ``Task``.

* **Update:** In ``stalker.models.task.Task`` class, methods those were doing a
  database query to get the required ``Status`` instances are now using the
  attached ``StatusList`` instance to get them.

* **Fix:** A possible ``auto_flush`` is prevented in ``Ticket`` class.

* **Update:** ``Version.latest_version`` property is now able to fall back to a
  pure Python implementation when there is no database connection.

* **Update:** The default log level has been increased from ``DEBUG`` to
  ``INFO``.

* **Update:** In an attempt to speed up tests, a lot of tests that doesn't need
  an active Database has been updated to use the regular ``unittest.TestCase``
  instead of ``stalker.testing.TestBase`` and as a result running all of the
  tests are now 2x faster.

* **Fix:** ``TimeLogs`` are now correctly reflected in UTC in a tj3 file.

* **Fix:** Fixed a lot of tests which were raising Warnings and surprisingly
  considered as Errors in TravisCI.

* **Fix:** ``to_tjp`` methods of SOM classes that is printing a Datetime object
  are now printing the dates in UTC.

* **Fix:** Fixed ``stalker.models.auth.Permission`` to be hashable for Python
  3.

* **Fix:** Fixed ``stalker.models.auth.AuthenticationLog`` to be sortable for
  Python 3.

* **Fix:** Fixed ``stalker.models.version.Version.latest_version`` property for
  Python 3.

* **Fix:** Fixed tests of ``Permission`` class to check for correct exception
  messages in Python 3.

* **Update:** Replaced the ``assertEquals`` and ``assertNotEquals`` calls which
  are deprecated in Python 3 with ``assertEqual`` and ``assertNotEquals`` calls
  respectively.

* **Fix:** Fixed tests for ``User`` and ``Version`` classes to not to cause the
  ``id column is None`` warnings of SQLAlchemy to be emitted.


0.2.18
======

* **Update:** Support for DB backends other than Postgresql has been dropped.
  This is done to greatly benefit from a code that is highly optimized only
  for one DB backend. With This all of the tests should be inherited from the
  ``stalker.tests.UnitTestDBBase`` class.

* **New:** All the DateTime fields in Stalker are now TimeZone aware and
  Stalker stores the DateTime values in UTC. Naive datetime values are not
  supported anymore. You should use a library like ``pytz`` to supply timezone
  information as shown below::

    import datetime
    import pytz
    from stalker import db, SimpleEntity
    new_simple_entity = SimpleEntity(
        name='New Simple Entity',
        date_created = datetime.datetime.now(tzinfo=pytz.utc)
    )

* **Fix:** The default values for ``date_created`` and ``date_updated`` has now
  been properly set to a partial function that returns the current time.

* **Fix:** Previously it was possible to enter two TimeLogs for the same
  resource in the same datetime range by committing the data from two different
  sessions simultaneously. Thus the database was not aware that it should
  prevent that. Now with the new PostgreSQL only implementation and the
  ``ExcludeConstraint`` of PostgreSQL an ``IntegrityError`` is raised by the
  database backend when something like that happens.

* **Update:** All the tests those are checking the system against an Exception
  is being raised or not are now checking also the exception message.

* **Update:** In the ``TimeLog`` class, the raised ``OverBookedException``
  message has now been made clear by adding the start and end date values of
  the clashing TimeLog instance.

* **Update:** Removed the unnecessary ``computed_start`` and ``computed_end``
  columns from ``Task`` class, which are already defined in the
  ``DateRangeMixin`` which is a super for the Task class.

0.2.17.6
========

* **Fix:** Fixed a bug in ``ProjectMixin`` where a proper cascade was not
  defined and the ``Delete`` operations to the ``Projects`` table were not
  cascaded to the mixed-in classes properly.

0.2.17.5
========

* **Fix:** Fixed the ``image_format`` attribute implementation in ``Shot``
  class. Now it will not copy the value of ``Project.image_format`` directly on
  ``__init__`` but instead will only store the value if the ``image_format``
  argument in ``__init__`` or ``Shot.image_format`` attribute is set to
  something.

0.2.17.4
========

* **Update:** Updated the comment sections of all of the source files to
  correctly show that Stalker is LGPL v3 (not v2.1).

0.2.17.3
========

* **New:** Added ``Shot.fps`` attribute to hold the fps information per shot.
* **Update:** Added the necessary alembic revision to reflect the changes in
  the ``Version_Inputs`` table.

0.2.17.2
========

* **Fix:** Fixed ``Version_Inputs`` table to correctly take care of
  ``DELETE``s on the ``Versions`` table. So now it is possible to delete a
  ``Version`` instance without first cleaning the ``Link`` instances that is
  related to that ``Version`` instance.

* **Update:** Changed the ``id`` attribute name from ``info_id`` to ``log_id``
  in ``AuthenticationLog`` class.

* **Update:** Started moving towards PostgreSQL only implementation. Merged the
  ``DatabaseModelTester`` class and ``DatabaseModelsPostgreSQLTester`` class.

* **Fix:** Fixed an autoflush issue in
  ``stalker.models.review.Review.finalize_review_set()``.

0.2.17.1
========

* **Fix:** Fixed alembic revision

0.2.17
======

* **New:** Added ``AuthenticationLog`` class to hold user login/logout info.
* **New:** Added ``stalker.testing`` module to simplify testing setup.

0.2.16.4
========

* **Fix:** Fixed alembic revision.

0.2.16.3
========

* **New:** ``ProjectUser`` now also holds a new field called ``rate``. The
  default value is equal to the ``ProjectUser.user.rate``. It is a way to hold
  the rate of a user on a specific project.

* **New:** Added the ``Invoice`` class.

* **New:** Added the ``Payment`` class.

* **New:** Added two simple mixins ``AmountMixin`` and ``UnitMixin``.

* **Update:** ``Good`` class is now mixed in with the new ``UnitMixin`` class.

* **Update:** ``BudgetEntry`` class is now mixed in with the new
  ``AmountMixin`` and ``UnitMixin`` classes.

0.2.16.2
========

* **New:** ``Group`` permissions can now be set on ``__init__()`` with the
  ``permissions`` argument.

0.2.16.1
========

* **Fix:** As usual after a new release that changes database schema, fixed the
  corresponding Alembic revision (92257ba439e1).

0.2.16
======

* **New:** ``Budget`` instances are now statusable.

* **Update:** Updated documentation to include database migration instructions
  with Alembic.

0.2.15.2
========

* **Fix:** Fixed a typo in the error message in
  ``User._validate_email_format()`` method.

* **Fix:** Fixed a query-invoked auto-flush problem in
  ``Task.update_parent_statuses()`` method.

0.2.15.1
========

* **Fix:** Fixed alembic revision (f2005d1fbadc), it will now drop any existing
  constraints before re-creating them. And the downgrade function will not
  remove the constraints.

0.2.15
======

* **New:** ``db.setup()`` now checks for ``alembic_version`` before setting up
  a connection to the database and raises a ``ValueError`` if the database
  alembic version is not matching the current implementation of Stalker.

* **Fix:** ``db.init()`` sets the ``created_by`` and ``updated_by``
  attributes to ``admin`` user if there is one while creating entity statuses.

* **New:** Created ``create_sdist.cmd`` and ``upload_to_pypi.cmd`` for Windows.

* **New:** ``Project`` to ``Client`` relation is now a many-to-many relation,
  thus it is possible to set multiple Clients for each project with each client
  having their own roles in a specific project.

* **Update:** ``ScheduleMixin.schedule_timing`` attribute is now Nullable.

* **Update:** ``ScheduleMixin.schedule_unit`` attribute is now Nullable.

0.2.14
======

* **Fix:** Fixed ``Task.path`` to always return a path with forward slashes.

* **New:** Introducing ``EntityGroups`` that lets one to group a bunch of
  ``SimpleEntity`` instances together, it can be used in grouping tasks even if
  they are in different places on the project task hierarchy or even in
  different projects.

* **Update:** ``Task.percent_complete`` is now correctly calculated for a
  ``Duration`` based task by using the ``Task.start`` and ``Task.end``
  attribute values.

* **Fix:** Fixed ``stalker.models.task.update_time_log_task_parents_for_end()``
  event to work with SQLAlchemy v1.0.

* **New:** Added an option called ``__dag_cascade__`` to the ``DAGMixin`` to
  control cascades on mixed in class. The default value is "all, delete".
  Change it to "save-update, merge" if you don't want the children also be
  deleted when the parent is deleted.

* **Fix:** Fixed a bug in ``Version`` class that occurs when a version instance
  that is a parent of other version instances is deleted, the child versions
  are also deleted (fixed through DAGMixin class).

0.2.13.3
========

* **Fix:** Fixed a bug in ``Review.finalize_review_set()`` for tasks that are
  sent to review and still have some extra time were not clamped to their total
  logged seconds when the review set is all approved.

0.2.13.2
========

* **New:** Removed ``msrp``, ``cost`` and ``unit`` arguments from
  ``BudgetEntry.__init__()`` and added a new ``good`` argument to get all of
  the data from the related ``Good`` instance. But the ``msrp``, ``cost`` and
  ``unit`` attributes of ``BudgetEntry`` class are still there to store the
  values that may not correlate with the related ``Good`` in future.

0.2.13.1
========

* **Fix:** Fixed a bug in ``Review.finalize_review_set()`` which causes Task
  instances to not to get any status update if the revised task is a second
  degree dependee to that particular task.

0.2.13
======

* **New:** ``Project`` instances can now have multiple repositories. Thus the
  ``repository`` attribute is renamed to ``repositories``. And the order of the
  items in the ``repositories`` attribute is restored correctly.

* **New:** ``stalker.db.init()`` now automatically creates environment
  variables for each repository in the database.

* **New:** Added a new ``after_insert`` which listens ``Repository`` instance
  ``insert`` instances to automatically add environment variables for the newly
  inserted repositories.

* **Update:** ``Repository.make_relative()`` now handles paths with environment
  variables.

* **Fix:** Fixed ``TaskJugglerScheduler`` to correctly generate task absolute
  paths for PostgreSQL DB.

* **New:** ``Repository.path`` is now writable and sets the correct path
  (``linux_path``, ``windows_path``, or ``osx_path``) according to the current
  system.

* **New:** Setting either of the ``Repository.path``,
  ``Repository.linux_path``, ``Repository.windows_path``,
  ``Repository.osx_path`` attributes will update the related environment
  variable if the system and attribute are matching to each other, setting the
  ``linux_path`` on Linux or setting the ``windows_path`` on Windows or setting
  the ``osx_path`` on OSX will update the environment variable.

* **New:** Added ``Task.good`` attribute to easily connect tasks to ``Good``
  instances.

* **New:** Added new methods to ``Repository`` to help managing paths:

  * ``Repository.find_repo()`` to find a repo from a given path. This is a
    class method so it can be directly used with the Repository class.
  * ``Repository.to_os_independent_path()`` to convert the given path to a OS
    independent path which uses environment variables. Again this is a class
    method too so it can be directly used with the Repository class.
  * ``Repository.env_var`` a new property that returns the related environment
    variable name of a repo instance. This is an instance property::

    .. code=block:: python

      # with default settings
      repo  = Repository(...)
      repo.env_var  # should print something like "REPO131" which will be used
      #               in paths as "$REPO131"

* **Fix:** Fixed ``User.company_role`` attribute which is a relationship to
  the ``ClienUser`` to cascade ``all, delete-orphan`` to prevent
  AssertionErrors when a Client instance is removed from the ``User.companies``
  collection.

0.2.12.1
========

* **Update:** ``Version`` class is now mixed with the ``DAGMixin``, so all the
  parent/child relation is coming from the DAGMixin.

* **Update:** ``DAGMixin.walk_hierarchy()`` is updated to walk the hierarchy in
  ``Depth First`` mode by default (method=0) instead of ``Breadth First`` mode
  (method=1).

* **Fix:** Fixed ``alembic_revision`` on database initialization.

0.2.12
======

* **Fix:** Fixed importing of ``ProjectUser`` directly from ``stalker``
  namespace.

* **Fix:** Fixed importing of ``ClientUser`` directly from ``stalker``
  namespace.

* **New:** Added two new columns to the ``BudgetEntry`` class to allow more
  detailed info to be hold.

* **New:** Added a new Mixin called ``DAGMixin`` to create parent/child
  relation between mixed in class.

* **Update:** The ``Task`` class is now mixed with the ``DAGMixin``, so all the
  parent/child relation is coming from the DAGMixin.

* **New:** Added a new class called ``Good`` to hold details about the
  commercial items/services sold in the Studio.

* **New:** Added a new class called ``PriceList`` to create price lists from
  Goods.

0.2.11
======

* **New:** User instances now have a new attribute called ``rate`` to track
  their cost as a resource.

* **New:** Added two new classes called ``Budget`` and ``BudgetEntry`` to
  record Project budgets in a simple way.

* **New:** Added a new class called **Role** to manage user roles in different
  Departments, Clients and Projects.

* **New:** User and Department relation is updated to include the role of the
  user in that department in a more flexible way by using the newly introduced
  Role class and some association proxy tricks.

* **New:** Also updated the User to Project relation to include the role of the
  user in that Project by using an associated Role class.

* **Update:** Department.members attribute is renamed to **users** (and removed
  the *synonym* property).

* **Update:** Removed ``Project.lead`` attribute use ``Role`` instead.

* **Update:** Removed ``Department.lead`` attribute use ``Role`` instead.

* **Update:** Because the ``Project.lead`` attribute is removed, it is now
  possible to have tasks with no responsible.

* **Update:** Client to User relation is updated to use an association proxy
  which makes it possible to set a Role for each User for each Client it is
  assigned to.

* **Update:** Renamed User.company to User.companies as the relation is now
  able to handle more than one Client instances for the User company.

* **Update:** Task Status Workflow has been updated to convert the status of a
  DREV task to HREV instead of WIP when the dependent tasks has been set to
  CMPL. Also the timing of the task is expanded by the value of
  ``stalker.defaults.timing_resolution`` if it doesn't have any effort left
  (generally true for CMPL tasks) to allow the resource to review and decide if
  he/she needs more time to do any update on the task and also give a chance of
  setting the Task status to WIP by creating a time log.

* **New:** It is now possible to schedule only a desired set of projects by
  passing a **projects** argument to the TaskJugglerScheduler.

* **New:** Task.request_review() and Review.finalize() will not cap the timing
  of the task until it is approved and also Review.finalize() will extend the
  timing of the task if the total timing of the given revisions are not fitting
  in to the left timing.

0.2.10.5
========

* **Update:** TaskJuggler output is now written to debug output once per line.

0.2.10.4
========

* **New:** '@' character is now allowed in Entity nice name.

0.2.10.3
========

* **New:** '@' character is now allowed in Version take names.

0.2.10.2
========

* **Fix:** Fixed a bug in
  ``stalker.models.schedulers.TaskJugglerScheduler._create_tjp_file_content()``
  caused by non-ascii task names.

* **Fix:** Removed the residual ``RootFactory`` class reference from
  documentation.

* **New:** Added to new functions called ``utc_to_local`` and ``local_to_utc``
  for UTC to Local time and vice versa conversion.

0.2.10.1
========

* **Fix:** Fixed a bug where for a WIP Task with no time logs (apparently
  something went wrong) and no dependencies using
  ``Task.update_status_with_dependent_statuses()`` will convert the status to
  RTS.

0.2.10
======

* **New:** It is now possible to track the Edit information per Shot using the
  newly introduced ``source_in``, ``source_out`` and ``record_in`` along with
  existent ``cut_in`` and ``cut_out`` attributes.

0.2.9.2
=======

* **Fix:** Fixed MySQL initialization problem in ``stalker.db.init()``.

0.2.9.1
=======

* **New:** As usual, after a new release, fixed a bug in
  ``stalker.db.create_entity_statuses()`` caused by the behavioral change of
  the ``map`` built-in function in Python 3.

0.2.9
=====

* **New:** Added a new class called ``Daily`` which will help managing
  ``Version`` outputs (Link instances including Versions itself) as a group.

* **New:** Added a new status list for ``Daily`` class which contains two
  statuses called "Open" and "Closed".

* **Update:** Setting the ``Version.take_name`` to a value other than a string
  will now raise a ``TypeError``.

0.2.8.4
=======

* **Fix:** Fixed ``SimpleEntity._validate_name()`` method for unicode strings.

0.2.8.3
=======

* **Fix:** Fixed str/unicode errors due to the code written for Python3
  compatibility.

* **Update:** Removed ``Task.is_complete`` attribute. Use the status "CMPL"
  instead of this attribute.

0.2.8.2
=======

* **Fix:** Fixed ``stalker.db.create_alembic_table()`` again to prevent extra
  row insertion.

0.2.8.1.1
=========

* **Fix:** Fixed ``stalker.db.create_alembic_table()`` function to handle the
  situation where the table is already created.

0.2.8.1
=======

* **Fix:** Fixed ``stalker.db.create_alembic_table()`` function, it is not
  using the ``alembic`` library anymore to create the ``alembic_version``
  table, which was the proper way of doing it but it created a lot of problems
  when Stalker is installed as a package.

0.2.8
=====

* **Update:** Stalker is now Python3 compatible.

* **New:** Added a new class called ``Client`` which can be used to track down
  information about the clients of ``Projects``. Also added ``Project.client``
  and ``User.company`` attributes which are referencing a Client instance
  allowing to add clients as normal users.

* **New:** ``db.init()`` now creates ``alembic_version`` table and stamps the
  most recent version number to that table allowing newly initialized databases
  to be considered in head revision.

* **Fix:** Fixed ``Version._format_take_name()`` method. It is now possible to
  use multiple underscore characters in ``Version.take_name`` attribute.

0.2.7.6
=======

* **Update:** Removed ``TimeLog._expand_task_schedule_timing()`` method which
  was automatically adjusting the ``schedule_timing`` and ``schedule_unit`` of
  a Task to total duration of the TimeLogs of that particular task, thus
  increasing the schedule info with the entered time logs.

  But it was setting the ``schedule_timing`` to 0 in some certain cases and it
  was unnecessary because the main purpose of this method was to prevent
  TaskJuggler to raise any errors related to the inconsistencies between the
  schedule values and the duration of TimeLogs and TaskJuggler has never given
  a real error about that situation.

0.2.7.5
=======

* **Fix:** Fixed Task parent/child relationship, previously setting the parent
  of a task to None was cascading a delete operation due to the
  "all, delete-orphan" setting of the Task parent/child relationship, this is
  updated to be "all, delete" and it is now safe to set the parent to None
  without causing the task to be deleted.

0.2.7.4
=======

* **Fix:** Fixed the following columns column type from String to Text:

    * Permissions.class_name
    * SimpleEntities.description
    * Links.full_path
    * Structures.custom_template
    * FilenameTemplates.path
    * FilenameTemplates.filename
    * Tickets.summary
    * Wiki.title
    * Wiki.content

  and specified a size for the following columns:

    * SimpleEntities.html_class -> String(32)
    * SimpleEntities.html_style -> String(32)
    * FilenameTemplates.target_entity_type -> String(32)

  to be compatible with MySQL.

* **Update:** It is now possible to create TimeLog instances for a Task with
  PREV status.

0.2.7.3
=======

* **Fix:** Fixed ``Task.update_status_with_dependent_statuses()`` method for a
  Task where there is no dependency but the status is DREV. Now calling
  ``Task.update_status_with_dependent_statuses()`` will set the status to RTS
  if there is no ``TimeLog`` for that task and will set the status to WIP if
  the task has time logs.

0.2.7.2
=======

* **Update:** ``TaskJugglerScheduler`` is now 466x faster when dumping all the
  data to TJP file. So with this new update it is taking only 1.5 seconds to
  dump ~20k tasks to a valid TJP file where it was around ~10 minutes in
  previous implementation. The speed enhancements is available only to
  PostgreSQL dialect for now.

0.2.7.1
=======

* **Fix:** Fixed TimeLog output in one line per task in ``Task.to_tjp()``.

* **New:** Added ``TaskJugglerScheduler`` now accepts a new argument called
  ``compute_resources`` which when set to True will also consider
  `Task.alternative_resources` attribute and will fill
  ``Task.computed_resources`` attribute for each Task. With
  ``TaskJugglerScheduler`` when the total number of Task is around 15k it will
  take around 7 minutes to generate this data, so by default it is set to
  False.

0.2.7
=====

* **New:** Added ``efficiency`` attribute to ``User`` class. See User
  documentation for more info.

0.2.6.14
========

* **Fix:** Fixed an **autoflush** problem in ``Studio.schedule()`` method.

0.2.6.13
========

* **New:** Added ``Repository.make_relative()`` method, which makes the given
  path to relative to the repository root. It considers that the path is
  already in the repository. So for now, be careful about not to pass a path
  outside of the repository.

0.2.6.12
========

* **Update:** ``TaskJugglerScheduler.schedule()`` method now uses the
  ``Studio.start`` and ``Studio.end`` values for the scheduling range instead
  of the hardcoded dates.

0.2.6.11
========

* **Update:** ``Task.create_time_log()`` method now returns the created
  ``TimeLog`` instance.

0.2.6.10
========

* **Fix:** Fixed an ``autoflush`` issue in
  ``Task.update_status_with_children_statuses()`` method.

0.2.6.9
=======

* **Update:** ``Studio.is_scheduling`` and ``Studio.is_scheduling_by``
  attributes will not be updated or checked at the beginning of the
  ``Studio.schedule()`` method. It is the duty of the user to check those
  attributes before calling ``Studio.schedule()``. This is done in this way
  because without being able to do a db commit inside ``Studio.schedule()``
  method (which is the case with transaction managers which may be used in web
  applications like **Stalker Pyramid**) it is not possible to persist and thus
  use those variables. So, to be able to use those attributes meaningfully the
  user should set them. Those variables will be set to False and None
  accordingly by the ``Studio.schedule()`` method after the scheduling is done.

0.2.6.8
=======

* **Fix:** Fixed a deadlock in ``TaskJugglerScheduler.schedule()`` method
  related with the ``Popen.stderr.readlines()`` blocking the TaskJuggler
  process without being able to read the output buffer.

0.2.6.7
=======

* **Update:** ``TaskJugglerScheduler.schedule()`` is now using bulk inserts and
  updates which is way faster than doing it with pure Python. Use
  ``parsing_method`` (0: SQL, 1: Python) to choose between SQL or Pure Python
  implementation. Also updated ``Studio.schedule()`` to take in a
  ``parsing_method`` parameter.

0.2.6.6
=======

* **Update:** The ``cut_in``, ``cut_out`` and ``cut_duration`` attribute
  behaviour and the attribute order is updated in ``Shot`` class. So, if three
  of the values are given, then the ``cut_duration`` attribute value will be
  calculated from ``cut_in`` and ``cut_out`` attribute values. In any case
  ``cut_out`` precedes ``cut_duration``, and if none of them given ``cut_in``
  and ``cut_duration`` values will default to 1 and ``cut_out`` will be
  calculated by using ``cut_in`` and ``cut_duration``.

0.2.6.5
=======

* **New:** Entity to Note relation is now Many-to-Many. So one Note can now be
  assigned more than one Entity.

* **New:** Added alembic revision for ``Entity_Notes`` table creation and data
  migration from ``Notes`` table to ``Entity_Notes`` table. So all notes are
  preserved.

* **Fix:** Fixed ``Shot.cut_duration`` attribute initialization on ``Shot``
  instances restored from database.

* **Fix:** Fixed ``Studios.is_scheduling_by`` relationship configuration, which
  was wrongly referencing the ``Studios.last_scheduled_by_id`` column instead
  of ``Studios.is_scheduled_by_id`` column.

0.2.6.4
=======

* **New:** Added a ``Task.review_set(review_number)`` method to get the desired
  set of reviews. It will return the latest set of reviews if ``review_number``
  is skipped or it is None.

* **Update:** Removed ``Task.approve()`` it was making things complex than it
  should be.

0.2.6.3
=======

* **Fix:** Added ``Page`` to ``class_names`` in ``db.init()``.

* **Fix:** Fixed ``TimeLog`` tjp representation to use bot the ``start`` and
  ``end`` date values instead of the ``start`` and ``duration``. This is much
  better because it is independent from the timing resolution settings.

0.2.6.2
=======

* **Fix:** Fixed ``stalker.models.studio.schedule()`` method, and prevented it
  to call ``DBSession.commit()`` which causes errors if there is a transaction
  manager.

* **Fix:** Fixed ``stalker.models._parse_csv_file()`` method for empty
  computed resources list.

0.2.6.1
=======

* **New:** ``stalker.models.task.TimeLog`` instances are now checking if the
  dependency relation between the task that receives the time log and the tasks
  that the task depends on will be violated in terms of the start and end dates
  and raises a ``DependencyViolationError`` if it is the case.

0.2.6
=====

* **New:** Added ``stalker.models.wiki.Page`` class, for holding a per Project
  wiki.

0.2.5.5
=======

* **Fix:** ``Review.task`` attribute now accepts None but this is mainly done
  to allow its relation to the ``Task`` instance can be broken when it needs to
  be deleted without issuing a database commit.

0.2.5.4
=======

* **Update:** The following column names are updated:
  
  * ``Tasks._review_number`` to ``Tasks.review_number``
  * ``Tasks._schedule_seconds`` to ``Tasks.schedule_seconds``
  * ``Tasks._total_logged_seconds`` to ``Tasks.total_logged_seconds``
  * ``Reviews._review_number`` to ``Reviews.review_number``
  * ``Shots._cut_in`` to ``Shots.cut_in``
  * ``Shots._cut_out`` to ``Shots.cut_out``
  
  Also updated alembic migration to create columns with those names.

* **Update:** Updated Alembic revision ``433d9caaafab`` (the one related with
  stalker 2.5 update) to also include following updates:
  
  * Create StatusLists for Tasks, Asset, Shot and Sequences and add all the
    Statuses in the Task Status Workflow.
  * Remove ``NEW`` from all of the status lists of Task, Asset, Shot and
    Sequence.
  * Update all the ``PREV`` tasks to ``WIP`` to let them use the new Review
    Workflow.
  * Update the ``Tasks.review_number`` to 0 for all tasks.
  * Create StatusLists and Statuses (``NEW``, ``RREV``, ``APP``) for Reviews.
  * Remove any other status then defined in the Task Status Workflow from Task,
    Asset, Shot and Sequence status list.

0.2.5.3
=======

* **Fix:** Fixed a bug in ``Task`` class where trying to remove the
  dependencies will raise an ``AttributeError`` caused by the
  ``Task._previously_removed_dependent_tasks`` attribute.

0.2.5.2
=======

* **New:** Task instances now have two new properties called ``path`` and
  ``absolute_path``. As in Version instances, these are the rendered version
  of the related FilenameTemplate object in the related Project. The ``path``
  attribute is Repository root relative and ``absolute_path`` is the absolute
  path including the OS dependent Repository path.

* **Update:** Updated alembic revision with revision number "433d9caaafab" to
  also create Statuses introduced with Stalker v0.2.5.

0.2.5.1
=======

* **Update:** ``Version.__repr__`` results with a more readable string.

* **New:** Added a generalized generator called
  ``stalker.models.walk_hierarchy()`` that walks and yields the entities over
  the given attribute in DFS or BFS fashion.

* **New:** Added ``Task.walk_hierarchy()`` which iterates over the hierarchy of
  the task. It walks in a breadth first fashion. Use ``method=0`` to walk in
  depth first.

* **New:** Added ``Task.walk_dependencies()`` which iterates over the
  dependencies of the task. It walks in a breadth first fashion. Use
  ``method=0`` to walk in depth first.

* **New:** Added ``Version.walk_hierarchy()`` which iterates over the hierarchy
  of the version. It walks in a depth first fashion. Use ``method=1`` to walk
  in breadth first.

* **New:** Added ``Version.walk_inputs()`` which iterates over the inputs of
  the version. It walks in a depth first fashion. Use ``method=1`` to walk in
  breath first.

* **Update:** ``stalker.models.check_circular_dependency()`` function is now
  using ``stalker.models.walk_hierarchy()`` instead of recursion over itself,
  which makes it more robust in deep hierarchies.

* **Fix:** ``db.init()`` now updates the statuses of already created status
  lists for ``Task``, ``Asset``, ``Shot`` and ``Sequence`` classes.

0.2.5
=====

* **Update:** ``Revision`` class is renamed to ``Review`` and introduced a
  couple of new attributes.

* **New:** Added a new workflow called "Task Review Workflow". Please see the
  documentation about the new workflow.

* **Update:** ``Task.responsible`` attribute is now a list which allows
  multiple responsible to be set for a ``Task``.

* **New:** Because of the new "Task Review Workflow" task statuses which are
  normally created in Stalker Pyramid are now automatically created in Stalker
  database initialization. The new statuses are
  **Waiting For Dependency (WFD)**, **Ready To Start (RTS)**,
  **Work In Progress (WIP)**, **Pending Review (PREV)**,
  **Has Revision (HREV)**, **On Hold (OH)**, **Stopped (STOP)** and
  **Completed (CMPL)** are all used in ``Task``, ``Asset``, ``Shot`` and
  ``Sequence`` status lists by default.

* **New:** Because of the new "Task Review Workflow" also a status list for
  ``Review`` class is created by default. It contains the statuses of
  **New (NEW)**, **Requested Revision (RREV)** and **Approved (APP)**.

* **Fix:** ``Users.login`` column is now unique.

* **Update:** Ticket workflow in config is now using the proper status names
  instead of the lower case names of the statuses.

* **New:** Added a new exception called **StatusError** which states the entity
  status is not suitable for the action it is applied to.

* **New:** ``Studio`` instance now stores the scheduling state to the database
  to prevent two scheduling process to override each other. It also stores the
  last schedule message and the last schedule date and the id of the user who
  has done the scheduling.

* **New:** The **Task Dependency** relation is now using an
  **Association Object** instead of just a **Secondary Table**. The
  ``Task.depends`` and ``Task.dependent_of`` attributes are now
  *association_proxies*.

  Also added extra parameters like ``dependency_target``, ``gap_timing``,
  ``gap_unit`` and ``gap_model`` to the dependency relation. So all of the
  dependency relations are now able to hold those extra information.

  Updated the ``task_tjp_template`` to reflect the details of the dependencies
  that a task has.

* **New:** ``ScheduleMixin`` class now has some default class attributes that
  will allow customizations in inherited classes. This is mainly done for
  ``TaskDependency`` class and for ``the gap_timing``, ``gap_unit``,
  ``gap_model`` attributes which are in fact synonyms of ``schedule_timing``,
  ``schedule_unit`` and ``schedule_model`` attributes coming from the
  ``ScheduleMixin`` class. So by using the ``__default_schedule_attr_name__``
  Stalker is able to display error messages complaining about ``gap_timing``
  attribute instead of ``schedule_timing`` etc.

* **New:** Updating a task by calling ``Task.request_revision()`` will now set
  the ``TaskDependency.dependency_target`` to **'onstart'** for tasks those are
  depending to the revised task and updated to have a status of **DREV**,
  **OH** or **STOP**. Thus, TaskJuggler will be able to continue scheduling
  these tasks even if the tasks are now working together.

* **Update:** Updated the TaskJuggler templates to make the tjp output a little
  bit more readable.

* **New:** ``ScheduleMixin`` now creates more localized (to the mixed in class)
  column and enum type names in the mixed in classes.

  For example, it creates the ``TaskScheduleModel`` enum type for ``Task``
  class and for ``TaskDependency`` it creates ``TaskDependencyGapModel`` with
  the same setup following the ``{{class_name}}{{attr_name}}Model`` template.

  Also it creates ``schedule_model`` column for ``Task``, and ``gap_model`` for
  ``TaskDependency`` class.

* **Update:** Renamed the ``TaskScheduleUnit`` enum type name to ``TimeUnit``
  in ``ScheduleMixin``.

0.2.4
=====

* **New:** Added new class called ``Revision`` to hold info about Task
  revisions.

* **Update:** Renamed ``ScheduleMixin`` to ``DateRangeMixin``.

* **New:** Added a new mixin called ``ScheduleMixin`` (replacing the old one)
  which adds attributes like ``schedule_timing``, ``schedule_unit``,
  ``schedule_model`` and ``schedule_constraint``.

* **New:** Added ``Task.tickets`` and ``Task.open_tickets`` properties.

* **Update:** Removed unnecessary arguments (``project_lead``, ``tasks``,
  ``watching``, ``last_login``) from User class.

* **Update:** The ``timing_resolution`` attribute is moved from the
  ``DateRangeMixin`` to ``Studio`` class. So instances of classes like
  ``Project`` or ``Task`` will not have their own timing resolution anymore.

* **New:** The ``Studio`` instance now overrides the values on
  ``stalker.defaults`` on creation and on load, and also the ``db.setup()``
  function lets the first ``Studio`` instance that it finds to update the
  defaults. So it is now possible to use ``stalker.defaults`` all the time
  without worrying about the Studio settings.

* **Update:** The ``Studio.yearly_working_days`` value is now always an
  integer.

* **New:** Added a new method ``ScheduleMixin.least_meaningful_time_unit()`` to
  calculate the most appropriate timing unit and the value of the given seconds
  which represents an interval of time.
  
  So it will convert 3600 seconds to 1 hours, and 8424000 seconds to 1 years if
  it represents working time (``as_working_time=True``) or 2340 hours if it is
  representing the calendar time.

* **New:** Added a new method to ``ScheduleMixin`` called ``to_seconds()``. The
  ``to_seconds()`` method converts the given schedule info values
  (``schedule_timing``, ``schedule_unit``, ``schedule_model``) to seconds
  considering if the given ``schedule_model`` is work time based ('effort' or
  'length') or calendar time based ('duration').

* **New:** Added a new method to ``ScheduleMixin`` called ``schedule_seconds``
  which you may recognise from ``Task`` class. What it does is pretty much the
  same as in the ``Task`` class, it converts the given schedule info values to
  seconds.

* **Update:** In ``DateRangeMixin``, when the ``start``, ``end`` or
  ``duration`` arguments given so that the duration is smaller then the
  ``defaults.timing_resolution`` the ``defaults.timing_resolution`` will be
  used as the ``duration`` and the ``end`` will be recalculated by anchoring
  the ``start`` value.

* **New:** Adding a ``TimeLog`` to a ``Task`` and extending its schedule info
  values now will always use the least meaningful timing unit. So expanding a
  task from 16 hours to 18 hours will result a task with 2 days of schedule
  (considering the ``daily_working_hours = 9``).

* **Update:** Moved the ``daily_working_hours`` attribute from ``Studio`` class
  to ``WorkingHours`` class as it was much related to this one then ``Studio``
  class. Left a property with the same name in the ``Studio`` class, so it will
  still function as it was before but there will be no column in the database
  for that attribute anymore.

0.2.3.5
=======

* **Fix:** Fixed a bug in ``stalker.models.auth.LocalSession`` where stalker
  was complaining about "copy_reg" module, it seems that it is related to
  `this bug`_.

  .. _this bug: http://www.archivum.info/python-bugs-list@python.org/2007-04/msg00222.html

0.2.3.4
=======

* **Update:** Fixed a little bug in Link.extension property setter.

* **New:** Moved the stalker.models.env.EnvironmentBase class to
  "Anima Tools" python module.

* **Fix:** Fixed a bug in stalker.models.task.Task._responsible_getter() where
  it was always returning the greatest parents responsible as the responsible
  for the child task when the responsible is set to None for the child.

* **New:** Added ``stalker.models.version.Version.naming_parents`` which
  returns a list of parents starting from the closest parent Asset, Shot or
  Sequence.

* **New:** ``stalker.models.version.Version.nice_name`` now generates a name
  starting from the closest Asset, Shot or Sequence parent.

0.2.3.3
=======

* **New:** ``Ticket`` action methods (``resolve``, ``accept``, ``reassign``,
  ``reopen``) now return the created ``TicketLog`` instance.

0.2.3.2
=======

* **Update:** Added tests for negative or zero fps value in Project class.

* **Fix:** Minor fix to ``schedule_timing`` argument in Task class, where IDEs
  where assuming that the value passed to the ``schedule_timing`` should be
  integer where as it accepts floats also.

* **Update:** Removed ``bg_color`` and ``fg_color`` attributes (and columns)
  from Status class. Use SimpleEntity.html_class and SimpleEntity.html_style
  attributes instead.

* **New:** Added ``Project.open_tickets`` property.

0.2.3.1
=======

* **Fix:** Fixed an inconvenience in SimpleEntity.__init__() when a
  date_created argument with a value is later than datetime.datetime.now() is
  supplied and the date_updated argument is skipped or given as None, then the
  date_updated attribute value was generated from datetime.datetime.now() this
  was causing an unnecessary ValueError. This is fixed by directly copying the
  date_created value to date_updated value when it is skipped or None.

0.2.3
=====

* **New:** SimpleEntity now have two new attributes called ``html_style`` and
  ``html_class`` which can be used in storing cosmetic html values.

0.2.2.3
=======

* **Update:** Note.content attribute is now a synonym of the Note.description
  attribute.

0.2.2.2
=======

* **Update:** Studio.schedule() now returns information about how much did it
  take to schedule the tasks.

* **Update:** Studio.to_tjp() now returns information about how much did it
  take to complete the conversion.

0.2.2.1
=======

* **Fix:** Task.percent_complete() now calculates the percent complete
  correctly.

0.2.2
=====

* **Update:** Added cascade attributes to all necessary relations for all the
  classes.

* **Update:** The Version class is not mixed with the StatusMixin anymore. So
  the versions are not going to be statusable anymore. Also created alembic
  revision (a6598cde6b) for that update.

0.2.1.2
=======

* **Update:** TaskJugglerScheduler and the Studio classes are now returning the
  stderr message out of their ``schedule()`` methods.

0.2.1.1
=======

* **Fix:** Disabled some deep debug messages on
  TaskJugglerScheduler._parse_csv_file().

* **Fix:** Fixed a flush issue related to the Task.parent attribute which is
  lazily loaded in Task._schedule_seconds_setter().

0.2.1
=====

* **Fix:** As usual distutil thinks ``0.2.0`` is a lower version number than
  ``0.2.0.rc5`` (I should have read the documentation again and used
  ``0.2.0.c5`` instead of ``0.2.0.rc5``) so this is a dummy update to just to
  fix the version number.

0.2.0
=====

* **Update:** Vacation tjp template now includes the time values of the start
  and end dates of the Vacation instance.

0.2.0.rc5
=========

* **Update:** For a container task, ``Task.total_logged_seconds`` and
  ``Task.schedule_seconds`` attributes are now using the info of the child
  tasks. Also these attributes are cached to database, so instead of querying
  the child tasks all the time, the calculated data is cached and whenever a
  TimeLog is created or updated for a child task (which changes the
  ``total_logged_seconds`` for the child task) or the ``schedule_timing`` or
  ``schedule_unit`` attributes are updated, the cached values are updated on
  the parents. Allowing Stalker to display percent_complete info of a container
  task without loading any of its children.

* **New:** Added ``Task.percent_complete`` attribute, which calculates the
  percent of completeness of the task based on the
  ``Task.total_logged_seconds`` and ``Task.schedule_seconds`` attributes.

* **Fix:** Added ``TimeLog.__eq__()`` operator to more robustly check if the
  time logs are overlapping.

* **New:** Added ``Project.percent_complete``,
  ``Percent.total_logged_seconds`` and ``Project.schedule_seconds`` attributes.

* **Update:** ``ScheduleMixin._validate_dates()`` does not set the date values
  anymore, it just return the calculated and validated ``start``, ``end`` and
  ``duration`` values.

* **Update:** ``Vacation`` now can be created without a ``User`` instance,
  effectively making the ``Vacation`` a ``Studio`` wide vacation, which applies
  to all users.

* **Update:** ``Vacation.__strictly_typed__`` is updated to ``False``, so there
  is no need to create a ``Type`` instance to be able to create a ``Vacation``.

* **New:** ``Studio.vacations`` property now returns the ``Vacation`` instances
  which has no *user*.

* **Update:** ``Task.start`` and ``Task.end`` values are no more read from
  children Tasks for a container task over and over again but calculated
  whenever the start and end values of a child task are changed or a new child
  is appended or removed.

* **Update:** ``SimpleEntity.description`` validation routine doesn't convert
  the input to string anymore, but checks the given description value against
  being a string or unicode instance.

* **New:** Added ``Ticket.summary`` field.

* **Fix:** Fixed ``Link.extension``, it is now accepting unicode.

0.2.0.rc4
=========

* **New:** Added a new attribute to ``Version`` class called
  ``latest_version`` which holds the latest version in the version queue.

* **New:** To optimize the database connection times, ``stalker.db.setup()``
  will not try to initialize the database every time it is called anymore. This
  leads a ~4x speed up in database connection setup. To initialize a newly
  created database please use::

    # for a newly created database
    from stalker import db
    db.setup() # connects to database
    db.init()  # fills some default values to be used with Stalker

    # for any subsequent access just use (don't need to call db.init())
    db.setup()

* **Update:** Removed all ``__init_on_load()`` methods from all of the classes.
  It was causing SQLAlchemy to eagerly load relations, thus slowing down
  queries in certain cases (especially in ``Task.parent`` -> ``Task.children``
  relation).

* **Fix:** Fixed ``Vacation`` class tj3 format.

* **Fix:** ``Studio.now`` attribute was not properly working when the
  ``Studio`` instance has been restored from database.

0.2.0.rc3
=========

* **New:** Added a new attribute to ``Task`` class called ``responsible``.

* **Update:** Removed ``Sequence.lead_id`` use ``Task.reponsible`` instead.

* **Update:** Updated documentation to include documentation about
  Configuring Stalker with ``config.py``.

* **Update:** The ``duration`` argument in ``Task`` class is removed. It is
  somehow against the idea of having ``schedule_model`` and ``schedule_timing``
  arguments (``schedule_model='duration'`` is kind of the same).

* **Update:** Updated ``Task`` class documentation.

0.2.0.rc2
=========

* **New:** Added ``Version.created_with`` attribute to track the environment or
  host program name that a particular ``Version`` instance is created with.

0.2.0.rc1
=========

* **Update:** Moved the Pyramid part of the system to another package called
  ``stalker_pyramid``.

* **Fix:** Fixed ``setup.py`` where importing ``stalker`` to get the
  ``__version__`` variable causing problems.

0.2.0.b9
========

* **New:** Added ``Version.latest_published_version`` and
  ``Version.is_latest_published_version()``.

* **Fix:** Fixed ``Version.__eq__()``, now Stalker correctly distinguishes
  different Version instances.

* **New:** Added ``Repository.to_linux_path()``,
  ``Repository.to_windows_path()``, ``Repository.to_osx_path()`` and
  ``Repository.to_native_path()`` to the ``Repository`` class.

* **New:** Added ``Repository.is_in_repo(path)`` which checks if the given
  path is in this repo.

0.2.0.b8
========

* **Update:** Renamed **Version.version_of** attribute to **Version.task**.

* **Fix:** Fixed **Version.version_number** where it was not possible to have
  a version number bigger than 2.

* **Fix:** In **db.setup()** Ticket statuses are only created if there aren't
  any.

* **Fix:** Added **Vacation** class to the registered class list in
  stalker.db.

0.2.0.b7
========

* **Update:** **Task.schedule_constraint** is now reflected to the tjp file
  correctly.

* **Fix:** **check_circular_dependency()** now checks if the **entity** and
  the **other_entity** are the same.

* **Fix:** **Task.to_tjp()** now correctly add the dependent tasks of a
  container task.

* **Fix:** **Task.__eq__()** now correctly considers the parent, depends,
  resources, start and end dates.

* **Update:** **Task.priority** is now reflected in tjp file if it is
  different than the default value (500).

* **New::** Added a new class called **Vacation** to hold user vacations.

* **Update:** Removed dependencies to ``pyramid.security.Allow`` and
  ``pyramid.security.Deny`` in couple of packages.

* **Update:** Changed the way the ``stalker.defaults`` is created.

* **Fix:** **EnvironmentBase.get_version_from_full_path()**,
  **EnvironmentBase.get_versions_from_path()**,
  **EnvironmentBase.trim_repo_path()**, **EnvironmentBase.find_repo** methods
  are now working properly.

* **Update:** Added **Version.absolute_full_path** property which renders the
  absolute full path which also includes the repository path.

* **Update:** Added **Version.absolute_path** property which renders the
  absolute path which also includes the repository path.

0.2.0.b6
========

* **Fix:** Fixed **LocalSession._write_data()**, previously it was not
  creating the local session folder.

* **New:** Added a new method called **LocalSession.delete()** to remove the
  local session file.

* **Update:** **Link.full_path** can now be set to an empty string. This is
  updated in this way for **Version** class.

* **Update:** Updated the formatting of **SimpleEntity.nice_name**, it is now
  possible to have uppercase letters and camel case format will be preserved.

* **Update**: **Version.take_name** formatting is enhanced.

* **New**: **Task** class is now mixed in with **ReferenceMixin** making it
  unnecessary to have **Asset**, **Shot** and **Sequence** classes all mixed
  in individually. Thus removed the **ReferenceMixin** from **Asset**,
  **Shot** and **Sequence** classes.

* **Update**: Added **Task.schedule_model** validation and its tests.

* **New**: Added **ScheduleMixin.total_seconds** and
  **ScheduleMixin.computed_total_seconds**.

0.2.0.b5
========

* **New:** **Version** class now has two new attributes called ``parent`` and
  ``children`` which will be used in tracking of the history of Version
  instances and track which Versions are derived from which Version.

* **New:** **Versions** instances are now derived from **Link** class and not
  **Entity**.

* **Update:** Added new revisions to **alembic** to reflect the change in
  **Versions** table.

* **Update:** **Links.path** is renamed to **Links.full_path** and added
  three new attributes called **path**, **filename** and **extension**.

* **Update:** Added new revisions to alembic to reflect the change in
  **Links** table.

* **New:** Added a new class called **LocalSession** to store session data in
  users local filesystem. It is going to be replaced with some other system
  like **Beaker**.

* **Fix:** Database part of Stalker can now be imported without depending to
  **Pyramid**.

* **Fix:** Fixed documentation errors that **Sphinx** complained about.

0.2.0.b4
========

* No changes in SOM.

0.2.0.b3
========

* **Update:** FilenameTemplate's are not ``strictly typed`` anymore.

* **Update:** Removed the FilenameTemplate type initialization, FilenameTemplates
  do not depend on Types anymore.

* **Update:** Added back the ``plural_class_name`` (previously ``plural_name``)
  property to the ORMClass class, so all the classes in SOM now have this new
  property. 

* **Update:** Added ``accepts_references`` attribute to the EntityType class.

* **New:** The Link class has a new attribute called ``original_filename`` to
  store the original file names of link files.

* **New:** Added **alembic** to the project requirements.

* **New:** Added alembic migrations which adds the ``accepts_references`` column
  to ``EntityTypes`` table and ``original_name`` to the ``Links`` table.

0.2.0.b2
========

* Stalker is now compatible with Python 2.6.
* Task:

  * **Update:** Tasks now have a new attribute called ``watchers`` which holds a
    list of User instances watching the particular Task.

  * **Update:** Users now have a new attribute called ``watching`` which is a
    list of Task instances that this user is watching.

* TimeLog:

  * **Update:** TimeLog instances will expand Task.schedule_timing value
    automatically if the total amount of logged time is more than the
    schedule_timing value.

  * **Update:** TimeLogs are now considered while scheduling the task.

  * **Fix:** TimeLogs raises OverBookedError when appending the same TimeLog
    instance to the same resource.

* Auth:

  * **Fix:** The default ACLs for determining the permissions are now working
    properly.

0.2.0.b1
========

* WorkingHours.is_working_hour() is working now.

* WorkingHours class is moved from stalker.models.project to
  stalker.models.studio module.

* ``daily_working_hours`` attribute is moved from
  stalker.models.project.Project to stalker.models.studio.Studio class.

* Repository path variables now ends with a forward slash even if it is not
  given.

* Updated Project classes validation messages to correlate with Stalker
  standard.

* Implementation of the Studio class is finished. The scheduling works like a
  charm.

* It is now possible to use any characters in SimpleEntity.name and the derived
  classes.

* Booking class is renamed to TimeLog.

0.2.0.a10
=========

* Added new attribute to WorkingHours class called ``weekly_working_hours``,
  which calculates the weekly working hours based on the working hours defined
  in the instance.

* Task class now has a new attribute called ``schedule_timing`` which is
  replacing the ``effort``, ``length`` and ``duration`` attributes. Together
  with the ``schedule_model`` attribute it will be used in scheduling the Task.

* Updated the config system to the one used in oyProjectManager (based on
  Sphinx config system). Now to reach the defaults::

    # instead of doing the following
    from stalker.conf import defaults # not valid anymore
    
    # use this
    from stalker import defaults
  
  If the above idiom is used, the old ``defaults`` module behaviour is
  retained, so no code change is required other than the new lower case config
  variable names.

0.2.0.a9
========

* A new property called ``to_tjp`` added to the SimpleEntity class which needs
  to be implemented in the child and is going to be used in TaskJuggler
  integration.

* A new attribute called ``is_scheduled`` added to Task class and it is going
  to be used in Gantt charts. Where it will lock the class and will not try
  to snap it to anywhere if it is scheduled.

* Changed the ``resolution`` attribute name to ``timing_resolution`` to comply
  with TaskJuggler.

* ScheduleMixin:

  * Updated ScheduleMixin class documentation.

  * There are two new read-only attributes called ``computed_start`` and
    ``computed_end``. These attributes will be used in storing of the values
    calculated by TaskJuggler, and will be used in Gantt Charts if available.

  * Added ``computed_duration``.

* Task:

  * Arranged the TaskJuggler workflow.

  * The task will use the effort > length > duration attributes in `to_tjp`
    property.

* Changed the license of Stalker from BSD-2 to LGPL 2.1. Any version previous
  to 0.2.0.a9 will be still BSD-2 and any version from and including 0.2.0.a9
  will be distributed under LGPL 2.1 license.

* Added new types of classes called Schedulers which are going to be used in
  scheduling the tasks.

* Added TaskJugglerScheduler, it uses the given project and schedules its
  tasks.

0.2.0.a8
========

* TagSelect now can be filled by setting its ``value`` attribute (Ex:
  TagSelect.set('value', data))

* Added a new method called ``is_root`` to Task class. It is true for tasks
  where there are no parents.

* Added a new attribute called ``users`` to the Department class which is a
  synonym for the ``members`` attribute.

* Task:

  * Task class is now preventing one of the dependents to be set as the parent
    of a task.

  * Task class is now preventing one of the parents to be set as the one of the
    dependents of a task.

  * Fixed ``autoflush`` bugs in Task class.

* Fixed `admin` users department initialization.

* Added ``thumbnail`` attribute to the SimpleEntity class which is a reference
  to a Link instance, showing the path of the thumbnail.

* Fixed Circular Dependency bug in Task class, where a parent of a newly
  created task is depending to another task which is set as the dependee for
  this newly created task (T1 -> T3 -> T2 -> T1 (parent relation) -> T3 -> T2
  etc.).

0.2.0.a7
========

* Changed these default setting value names to corresponding new names:

  * ``DEFAULT_TASK_DURATION`` -> ``TASK_DURATION``
  * ``DEFAULT_TASK_PRIORITY`` -> ``TASK_PRIORITY``
  * ``DEFAULT_VERSION_TAKE_NAME`` -> ``VERSION_TAKE_NAME``
  * ``DEFAULT_TICKET_LABEL`` -> ``TICKET_LABEL``
  * ``DEFAULT_ACTIONS`` -> ``ACTIONS``
  * ``DEFAULT_BG_COLOR`` -> ``BG_COLOR``
  * ``DEFAULT_FG_COLOR`` -> ``FG_COLOR``

* stalker.conf.defaults:

  * Added default settings for project working hours (``WORKING_HOURS``,
    ``DAY_ORDER``, ``DAILY_WORKING_HOURS``)

  * Added a new variable for setting the task time resolution called
    ``TIME_RESOLUTION``.

* stalker.models.project.Project:

  * Removed Project.project_tasks attribute, use Project.tasks directly to get
    all the Tasks in that project. For root task you can do a quick query::

      Task.query.filter(Task.project==proj_id).filter(Task.parent==None).all()
    
    This will also return the Assets, Sequences and Shots in that project,
    which are also Tasks.

  * Users are now assigned to Projects by appending them to the Project.users
    list. This is done in this way to allow a reduced list of resources to be
    shown in the Task creation dialogs.

  * Added a new helper class for Project working hour management, called
    WorkingHours.

  * Added a new attribute to Project class called ``working_hours`` which holds
    stalker.models.project.WorkingHours instances to manage the Project working
    hours. It will directly be passed to TaskJuggler.

* stalker.models.task.Task:

  * Removed the Task.task_of attribute, use Task.parent to get the owner of
    this Task.

  * Task now has two new attributes called Task.parent and Task.children which
    allow more complex Task-to-Task relation.

  * Secondary table name for holding Task to Task dependency relation is
    renamed from ``Task_Tasks`` to ``Task_Dependencies``.

  * check_circular_dependency function is now accepting a third argument which
    is the name of the attribute to be investigated for circular relationship.
    It is done in that way to be able to use the same function in searching for
    circular relations both in parent/child and depender/dependee relations.

* ScheduleMixin:

  * Added a new attribute to ScheduleMixin for time resolution adjustment.
    Default value is 1 hour and can be set with
    stalker.conf.defaults.TIME_RESOLUTION. Any finer time than the resolution
    is rounded to the closest multiply of the resolution. It is possible to set
    it from microseconds to years. Although 1 hour is a very reasonable
    resolution which is also the default resolution for TaskJuggler.

  * ScheduleMixin now uses datetime.datetime for the start and end attributes.

  * Renamed the ``start_date`` attribute to ``start``.

  * Renamed the ``end_date`` attribute to ``end``

* Removed the TaskableEntity.

* Asset, Sequence and Shot classes are now derived from Task class allowing
  more complex Task relation combined with the new parent/child relation of
  Tasks. Use Asset.children or Asset.tasks to reach the child tasks of that
  asset (same with Sequence and Shot classes).

* stalker.models.shot.Shot:

  * Removed the sequence and introduced sequences attribute in Shot class. Now
    one shot can be in more than one Sequence. Allowing more complex
    Shot/Sequence relations..

  * Shots can now be created without a Sequence instance. The sequence
    attribute is just used to group the Shots.

  * Shots now have a new attribute called ``scenes``, holding Scene instances.
    It is created to group same shots occurring in the same scenes.

* In tests all the Warnings are now properly handled as Warnings.

* stalker.models.ticket.Ticket:

  * Ticket instances are now tied to Projects and it is now possible to create
    Tickets without supplying a Version. They are free now.

  * It is now possible to link any SimpleEntity to a Ticket.

  * The Ticket Workflow is now fully customizable. Use
    stalker.conf.defaults.TICKET_WORKFLOW dictionary to define the workflow and
    stalker.conf.defaults.TICKET_STATUS_ORDER for the order of the ticket
    statuses.

* Added a new class called ``Scene`` to manage Shots with another property.

* Removed the ``output_path`` attribute in FilenameTemplate class.

* Grouped the templates for each entity under a directory with the entity name.

0.2.0.a6
========

* Users now can have more than one Department.

* User instances now have two new properties for getting the user tickets
  (User.tickets) and the open tickets (User.open_tickets).

* New shortcut Task.project returns the Task.task_of.project value.

* Shot and Asset creation dialogs now automatically updated with the given
  Project instance info.

* User overview page is now reflection the new design.

0.2.0.a5
========

* The ``code`` attribute of the SimpleEntity is now introduced as a separate
  mixin. To let it be used by the classes it is really needed.

* The ``query`` method is now converted to a property so it is now possible to
  use it like a property as in the SQLAlchemy.orm.Session as shown below::

    from stalker import Project
    Project.query.all() # instead of Project.query().all()

* ScheduleMixin.due_date is renamed to ScheduleMixin.end_date.

* Added a new class attribute to SimpleEntity called ``__auto_name__`` which
  controls the naming of the instances and instances derived from SimpleEntity.
  If ``__auto_name__`` is set to True the ``name`` attribute of the instance
  will be automatically generated and it will have the following format::

    {{ClassName}}_{{UUID4}}
    
  Here are a couple of naming examples::

    Ticket_74bb46b0-29de-4f3e-b4e6-8bcf6aed352d
    Version_2fa5749e-8cdb-4887-aef2-6d8cec6a4faa

* Fixed an autoflush issue with SQLAlchemy in StatusList class. Now the status
  column is again not nullable in StatusMixin.

0.2.0.a4
========

* Added a new class called EntityType to hold all the available class names and
  capabilities.

* Version class now has a new attribute called ``inputs`` to hold the inputs of
  the current Version instance. It is a list of Link instances.

* FilenameTemplate classes ``path`` and ``filename`` attributes are no more
  converted to string, so given a non string value will raise TypeError.

* Structure.custom_template now only accepts strings and None, setting it to
  anything else will raise a TypeError.

* Two Type's for FilenameTemplate's are created by default when initializing
  the database, first is called "Version" and it is used to define
  FilenameTemplates which are used for placing Version source files. The second
  one is called "Reference" and it is used when injecting references to a given
  class. Along with the FilenameTemplate.target_entity_type this will allow one
  to create two different FilenameTemplates for one class::

    # first get the Types
    vers_type = Type.query()\
                .filter_by(target_entity_type="FilenameTemplate")\
                .filter_by(type="Version")\
                .first()
    
    ref_type = Type.query()\
               .filter_by(target_entity_type="FilenameTemplate")\
               .filter_by(type="Reference")\
               .first()
    
    # lets create a FilenameTemplate for placing Asset Version files.
    f_ver = FilenameTemplate(
        target_entity_type="Asset",
        type=vers_type,
        path="Assets/{{asset.type.code}}/{{asset.code}}/{{task.type.code}}",
        filename="{{asset.code}}_{{version.take_name}}_{{task.type.code}}_v{{'%03d'|version.version_number}}{{link.extension}}"
        output_path="{{version.path}}/Outputs/{{version.take_name}}"
    )
    
    # and now define a FilenameTemplate for placing Asset Reference files.
    # no need to have an output_path here...
    f_ref = FilenameTemplate(
        target_entity_type="Asset",
        type=ref_type,
        path="Assets/{{asset.type.code}}/{{asset.code}}/References",
        filename="{{link.type.code}}/{{link.id}}{{link.extension}}"
    )

* stalker.db.register() now accepts only real classes instead of class names.
  This way it can store more information about classes.

* Status.bg_color and Status.fg_color attributes are now simple integers. And
  the Color class is removed.

* StatusMixin.status is now a ForeignKey to a the Statuses table, thus it is a
  real Status instance instead of an integer showing the index of the Status in
  the related StatusList. This way the Status of the object will not change if
  the content of the StatusList is changed.

* Added new attribute Project.project_tasks which holds all the direct or
  indirect Tasks created for that project.

* User.login_name is renamed to User.login.

* Removed the ``first_name``, ``last_name`` and ``initials`` attributes from
  User class. Now the ``name`` and ``code`` attributes are going to be used,
  thus the ``name`` attribute is no more the equivalent of ``login`` and the
  ``code`` attribute is doing what was ``initials`` doing previously.

0.2.0.a3
========

* Status class now has two new attributes ``bg_color`` and ``fg_color`` to hold
  the UI colors of the Status instance. The colors are Color instances.

0.2.0.a2
========

* SimpleEntity now has an attribute called ``generic_data`` which can hold any
  kind of ``SOM`` object inside and it is a list.

* Changed the formatting rules for the ``name`` in SimpleEntity class, now it
  can start with a number, and it is not allowed to have multiple whitespace
  characters following each other.

* The ``source`` attribute in Version is renamed to ``source_file``.

* The ``version`` attribute in Version is renamed to ``version_number``.

* The ``take`` attribute in Version is renamed to ``take_name``.

* The ``version_number`` in Version is now generated automatically if it is
  skipped or given as None or it is too low where there is already a version
  number for the same Version series (means attached to the same Task and has
  the same ``take_name``.

* Moved the User class to ``stalker.models.auth module``.

* Removed the ``stalker.ext.auth`` module because it is not necessary anymore.
  Thus the User now handles all the password conversions by itself.

* ``PermissionGroup`` is renamed back to Group
  again to match with the general naming of the authorization concept.

* Created two new classes for the Authorization system, first one is called
  Permission and the second one is a Mixin which is called ACLMixin which adds
  ACLs to the mixed in class. For now, only the User and Group classes are
  mixed with this mixin by default.

* The declarative Base class of SQLAlchemy is now created by binding it to a
  ORMClass (a random name) which lets all the derived class to have a method
  called ``query`` which will bypass the need of calling
  ``DBSession.query(class_)`` but instead just call ``class_.query()``::

    from stalker.models.auth import User
    user_1 = User.query().filter_by(name='a user name').first()


0.2.0.a1
========

* Changed the ``db.setup`` arguments. It is now accepting a dictionary instead
  of just a string to comply with the SQLAlchemy scaffold and this dictionary
  should contain keys for the SQLAlchemy engine setup. There is another utility
  that comes with Pyramid to setup the database under the `scripts` folder, it
  is also working without any problem with stalker.db.

* The ``session`` variable is renamed to ``DBSession`` and is now a scopped
  session, so there is no need to use ``DBSession.commit`` it will be handled
  by the system it self.

* Even though the ``DBSession`` is using the Zope Transaction Manager extension
  normally, in the database tests no extension is used because the transaction
  manager was swallowing all errors and it was a little weird to try to catch
  this errors out of the ``with`` block.

* Refactored the code, all the models are now in separate python files, but can
  be directly imported from the main stalker module as shown::

    from stalker import User, Department, Task
  
  By using this kind of organization, both development and usage will be eased
  out.

* ``task_of`` now only accepts TaskableEntity instances.

* Updated the examples. It is now showing how to extend SOM correctly. 

* Updated the references to the SOM classes in docstrings and rst files.

* Removed the ``Review`` class. And introduced the much handier Ticket class.
  Now reviewing a data is the process of creating Ticket's to that data.

* The database is now initialized with a StatusList and a couple of Statuses
  appropriate for Ticket instances.

* The database is now initialized with two Type instances ('Enhancement' and
  'Defect') suitable for Ticket instances.

* StatusMixin now stores the status attribute as an Integer showing the index
  of the Status in the ``status_list`` attribute but when asked for the value
  of ``StatusMixin.status`` attribute it will return a proper Status instance
  and the attribute can be set with an integer or with a proper Status
  instance.


================================================
FILE: CHANGELOG_OLD.rst
================================================
0.1.2.a5
========

* :class:`~stalker.core.models.SimpleEntity`.\
  :attr:`~stalker.core.models.SimpleEntity.name` attribute doesn't accept
  anything other than a string or unicode anymore.
* All the error messages are now showing both the class and attribute names,
  and for TypeErrors it also shows the current given data type which raised
  the error and the desired type.
* Fixed a bug that causes recursion in queries to
  :class:`~stalker.core.models.StatusList` instances.
* Removed the ``FilenameTemplate.output_file_code`` attribute cause it is not
  needed.
* Removed the ``FilenameTemplate.output_is_relative`` attribute, now all the
  path values are :class:`~stalker.models.repository.Repository` relative.
* Renamed the ``path_code`` to ``path``, ``file_code`` to ``filename`` and
  ``output_path_code`` to ``output_path`` in
  :class:`~stalker.models.template.FilenameTemplate``\ .

0.1.2.a4
========

* Added database tests for:
  * :class:`~stalker.core.models.Review`
  * :class:`~stalker.core.models.Task`
  * :class:`~stalker.core.models.Version`
* The ``published`` attribute in :class:`~stalker.core.models.Version` is
  renamed to :attr:`~stalker.core.models.Version.is_published`.
* :class:`~stalker.core.models.Structure` is not ``strictly_typed`` anymore.
* The initialization of ``status_list`` attribute in classes which are mixed
  with :class:`~stalker.core.models.StatusMixin` is now automatically done if
  there is a database connection (stalker.db.session is not None) and there is
  a suitable :class:`~stalker.core.models.StatusList` instance in the database
  whom :attr:`~stalker.core.models.StatusList.target_entity_type` attribute is
  set to the mixed-in class name.
* Finished the tests for :class:`~stalker.core.models.Booking` class.
* The :class:`~stalker.core.models.Booking` class now checks if there is more
  than one booking is creating with overlapping time interval and issue a
  :class:`~stalker.core.errors.OverBookedWarning`.
* Cleaned up the code style.
* Moved the ``target_entity_type`` functionality to a new mixin class called
  :class:`~stalker.core.models.TargetEntityTypeMixin`\ .
  :class:`~stalker.core.models.StatusList`,
  :class:`~stalker.core.models.FilenameTemplate`, and
  :class:`~stalker.core.models.Type` classes are mixin with this new class.
* Included the ``pyseq`` library to the dependency list.

0.1.2.a3
========

* stalker.__version__ is fixed for PyPI

0.1.2.a2
========

* All the models are now converted to SQLAlchemy's Declarative.
* Because of the move to the SQLAlchemy Declarative extension the
  stalker.etx.ValidatedList is deprecated. SQLAlchemy is doing (in most of the
  aspects) a much better job.
* The ``stalker.core.mixins`` module is merged with :mod:`~stalker.core.models`
  module.
* Becase all the models are declaratively defined and thus they have their
  mappers and tables inside, the ``stalker.db.mapper``, ``stalker.db.tables``
  and the ``stalker.db.mixins`` modules are removed.
* Added the :class:`~stalker.core.models.Version` class with all its tests.
* Fixed :attr:`~stalker.core.models.Project.assets` and
  :attr:`~stalker.core.models.Project.sequences` attributes in
  :class:`~stalker.core.models.Project` class. It is now using the
  ``db.query`` to get the info out of the database, which is much easier than
  setting up a complex relation.
* Fixed the tests for the database. It is now working properly with the SOM
  which is using SQLAlchemy declarative. There are still missing tests though.
* The :class:`~stalker.core.models.Project` and
  :class:`~stalker.core.models.Structure` classes are not
  ``__strictly_typed__`` anymore. It was a bump on the road to make them
  strictly typed.

0.1.2.a1
========

* Started to switch to SQLAlchemy ORM Declarative for SOM, implemented these
  classes successfully:

  SimpleEntity, Type, Tag, Note, ImageFormat, Status, StatusList, Repository,
  Structure, FilenameTemplate, Department, Link, ReferenceMixin, StatusMixin,
  ScheduleMixin, Project, Sequence, Shot, Asset, Review.

* Empty :class:`~stalker.core.models.StatusList`\ s are now allowed. The
  validation overhead is left to the SOM user.
* Removed the ``TaskMixin`` on the way of moving to declarative. It was not
  possible to add a one-to-many relation to the
  :class:`~stalker.core.model.Task`\ s
  :attr:`~stalker.core.models.Task.task_of` attribute from all the mixed-in
  classes. So the solution was to introduce a new
  :class:`~stalker.core.models.TaskableEntity` (yaykh!) inheriting from
  :class:`~stalker.core.models.Entity`.
* The :attr:`~stalker.core.models.SimpleEntity.name` attribute in
  :attr:`~stalker.core.models.SimpleEntity` is no more forced to be unique.
  This releases the :attr:`~stalker.core.models.Shot.name` attribute in the
  :class:`~stalker.core.models.Shot` class to be anything it wants (not just
  uuid4 sequences to get unique names).
* From now on, the :attr:`~stalker.core.models.SimpleEntity.code` attribute in
  :class:`~stalker.core.models.SimpleEntity` class is not going to change when
  the :attr:`~stalker.core.models.SimpleEntity.name` attribute is changed.
* The :attr:`~stalker.core.models.SimpleEntity.name` attribute in
  :class:`~stalker.core.models.SimpleEntity` is going to be copied from the
  :attr:`~stalker.core.models.SimpleEntity.code` attribute if the ``name``
  argument is skipped, None or empty string.
* The ``ReviewMixin`` is removed.
* The :class:`~stalker.core.models.Review` class is now inheriting from the
  :class:`~stalker.core.models.SimpleEntity`.
* The :class:`~stalker.core.models.Entity` now has a new attribute called
  :attr:`~stalker.core.models.Entity.reviews` to store a list of
  :class:`~stalker.core.models.Review` instances.

0.1.1.a10
=========

* :class:`~stalker.core.mixins.TaskMixin` from now on doesn't have a ``tasks``
  argument in its ``__init__`` method.
* Each of the mixin classes now has their own test modules.
* In :class:`~stalker.core.models.Shot`, now the
  :attr:`~stalker.core.models.Shot.cut_out` attribute is mapped to the
  database instead of the :attr:`~stalker.core.models.Shot.cut_duration`.
* In :class:`~stalker.core.models.Task` the ``part_of`` attribute is renamed
  to :attr:`~stalker.core.models.Task.task_of` to reflect its duty clearly.
* Removed the ``ProjectMixin``. The ``project`` attribute has been moved to
  the :class:`~stalker.core.mixins.TaskMixin`. Now anything mixed with the
  :class:`~stalker.core.mixins.TaskMixin` also has a
  :attr:`~stalker.core.mixins.TaskMixin.project` attribute.
* :attr:`~stalker.core.models.Task.task_of` attribute in
  :class:`~stalker.core.models.Task` class now accepts anything that has been
  derived from :class:`~stalker.core.mixins.TaskMixin` or anything that has
  both a ``tasks`` attribute and a ``project`` attribute but use the
  :class:`~stalker.core.mixins.TaskMixin` preferably.
* :class:`~stalker.core.models.Sequence` now doesn't accept any ``shots``
  argument. There is no way to create a :class:`~stalker.core.models.Shot`
  without passing a :class:`~stalker.core.models.Sequence` instance.
* All the classes that needs to be initialized properly now has a method
  called __init_on_load__ which is called by SQLAlchemy on load.
* Fixed the :attr:`~stalker.core.models.Task.task_of` attribute in
  :class:`~stalker.core.models.Task` and
  :attr:`~stalker.core.mixins.TaskMixin.tasks` attribute in
  :class:`~stalker.core.mixins.TaskMixin`, they are now updating each other
  correctly.
* Added :attr:`~stalker.core.models.Shot.assets` to the
  :class:`~stalker.core.models.Shot` class to track down which asset is used
  in this shot.
* Merged the ``ProjectMixinDB`` with ``TaskMixinDB`` and
  removed the ``ProjectMixinDB`` from the database part of the mixins.
* The :class:`~stalker.core.models.Project` doesn't accept an ``assets`` nor
  a ``sequences`` arguments anymore. Which was meaningless previously, cause
  it is not possible to create an :class:`~stalker.core.models.Asset` or a
  :class:`~stalker.core.models.Sequence` without specifying the
  :class:`~stalker.core.models.Project` first.
* From now on it is not possible to create a
  :class:`~stalker.core.models.Project` instance without passing a
  :class:`~stalker.core.models.Repository` instance to it.
* The :class:`~stalker.core.models.Asset` now updates the
  :attr:`~stalker.core.models.Project.assets` attribute in the
  :class:`~stalker.core.models.Project` class.
* From now on none of the tests are using the Mocker library. Thus all the
  little changes to any of the classes are present in all the tests which are
  using those classes. This makes the tests more robust and current.
* Fixed latex PDF output of the documentation, now the formatting is nice and
  correct.
* :class:`~stalker.core.models.Repository` now replaces backward slashes with
  forward slashes in the given path arguments and attributes.
* The ``filename`` attribute has been removed from the
  :class:`~stalker.core.models.Link` class. And it doesn't need an
  ``filename`` argument anymore. The :attr:`~stalker.core.models.Link.path`
  is enough to hold the necessary data.
* The :class:`~stalker.core.models.Link` is not strictly typed anymore. So
  you can skip the ``type`` argument while creating a
  :class:`~stalker.core.models.Link` instance.
* Fixed the ``Mutable Default`` problem in the following classes:
  * :class:`~stalker.core.models.Department` classes ``members`` argument.
  * :class:`~stalker.core.models.Entity` classes ``tags`` and ``notes``
    argument.
  * :class:`~stalker.core.models.StatusList` classes ``statuses`` argument
  * :class:`~stalker.core.models.Project` classes ``assets`` argument
  * :class:`~stalker.core.models.Assets` classes ``shots`` argument
  * :class:`~stalker.core.models.User` classes ``permission_groups``,
    ``projects_lead``, ``sequences_lead`` and tasks attributes.
* The ``milestone`` attribute is renamed to
  :attr:`~stalker.core.models.Task.is_milestone` in
  :class:`~stalker.core.models.Task` class.
* The ``complete`` attribute is renamed to
  :attr:`~stalker.core.models.Task.is_complete`` in
  :class:`~stalker.core.models.Task` class.
* Replaced the python property idiom which uses a function which contains an
  fget, an fset functions and a doc string variable and returns the result of
  locals() with the property idiom that uses @property and @x.setter. Thus
  dropped the support for python versions <= 2.5. This is done to increase the
  PyLint rate. And with its final state, the PyLint rate of Stalker increased
  from around 1 to around 9.
* Reintroduced the :class:`~stalker.core.mixins.ProjectMixin` and the
  :class:`~stalker.core.mixins.TaskMixin` is now inherited from
  :class:`~stalker.core.mixins.ProjectMixin`. It is done in that way to allow
  other types to have relation with a :class:`~stalker.core.models.Project`
  instance. Without the :class:`~stalker.core.mixins.ProjectMixin` it was
  going to introduce some code repetition. Also updated the database part of
  the TaskMixin and created a helper class for the ProjectMixin.
* Added an attribute called "__stalker_version__" to the
  :class:`~stalker.core.models.SimpleEntity` to track down in which version of
  Stalker that data is created. This is mostly related with the database part.
* Renamed ``stalker.db.mixin`` module to :mod:`stalker.db.mixins`.
* Renamed ``stalker.core.models.Comment`` class to
  :class:`~stalker.core.models.Review`.
* The :attr:`~stalker.core.models.Review.to` attribute in
  :class:`~stalker.core.models.Review` class now accepts anything which has a
  list-like attribute called "reviews".
* :class:`~stalker.ext.validatedList.ValidatedList` now works uniquely. Means
  the list of items are always unique.
* The :attr:`~stalker.core.mixins.TaskMixin.tasks` attribute in
  :class:`~stalker.core.mixins.TaskMixin` is not read-only anymore. But will
  produce RuntimeError if removing items will produce orphan children.
* Optimized the back reference update procedure in
  :class:`~stalker.core.models.Task` and
  :class:`~stalker.core.mixins.TaskMixin` classes. They are not touching
  their internal variables anymore.
* Fixed backreference updates of :class:`~stalker.core.models.Task` classes
  :attr:`~stalker.core.models.Task.resources` attribute.
* Fixed ``__setslice__`` method in
  :class:`~stalker.ext.validatedList.ValidatedList`. It is now correctly
  passing the added and removed elements to the given ``validator`` function.

0.1.1.a9
========

* Introduced :class:`~stalker.core.models.Type`. A new class to define
  **types**. With this introduction, all the classes deriving from
  ``TypeEntity`` (and the TypeEntity it self) are removed from Stalker.
* Added an attribute called ``type`` to the
  :class:`~stalker.core.models.SimpleEntity`. Which will be used to create new
  types to the derived classes.
* Introduced a new attribute called ``__strictly_typed__`` to all the classes
  (by the means of the EntityMeta), which will force the class to have a
  proper (not None) ``type``.
* :class:`~stalker.core.models.SimpleEntity` now has its own test module.
* :class:`~stalker.core.models.TypeTemplate` is renamed to
  :class:`~stalker.core.models.FilenameTemplate` to reflect its duty more
  clearly.
* fixed the tests for the :mod:`~stalker.db`. Previously each of the tests
  were creating an instance of a specific class then storing it in the
  database, retrieved it back and then comparing the instances, one just
  created and one queried from the database. The problem was that, SA was
  returning the same instance (can be checked with id(instance)) so in any
  case they were equal, it was not possible to compare them and get a
  meaningful difference to see if the database part worked properly. Now, all
  the attributes of the original instance are stored in new variables and
  then the original instance is deleted, and the a new one is retrieved back
  from the database, and all the attributes are compared with the stored ones.
  (probably there are other good ways)
* fixed :attr:`~stalker.core.models.SimpleEntity.nice_name` in the
  :class:`~stalker.core.models.SimpleEntity`, if the instance is created by
  using ``__new__`` (like in SA) then the
  :attr:`~stalker.core.models.SimpleEntity.nice_name` attribute was not
  initialized correctly.
* fixed mapping of :attr:`~stalker.core.models.Department.lead` attribute in
  :class:`~stalker.core.models.Department` class.
* fixed :attr:`~stalker.core.models.ImageFormat.device_aspect` attribute in
  :class:`~stalker.core.models.ImageFormat`, it is now correctly calculated
  when the instance is created with ``__new__`` instead of ``__init__``
* fixed mapping of :attr:`~stalker.core.models.Project.users` attribute in
  :class:`~stalker.core.models.Project` class.
* fixed mapping of :attr:`~stalker.core.models.Project.duration` attribute in
  :class:`~stalker.core.models.Project` class (also possibly fixed all the
  classes mixed with :class:`~stalker.core.mixins.ScheduleMixin`)
* fixed mapping of :attr:`~stalker.core.models.Sequence.lead` attribute in
  :class:`~stalker.core.models.Sequence` class
* updated the behavior of :attr:`~stalker.core.models.Project.users`
  attribute in :class:`~stalker.core.models.Project` class. Now the list of
  :class:`~stalker.core.models.User`\ s are gathered from the
  :class:`~stalker.core.models.Task`\ s of the
  :class:`~stalker.core.models.Project` and from the
  :class:`~stalker.core.models.Sequence`\ s,
  the :class:`~stalker.core.models.Shot`\ s and
  the :class:`~stalker.core.models.Asset`\ s of the same
  :class:`~stalker.core.models.Project`.
* updated the behavior of :attr:`~stalker.core.models.User.project` attribute
  in class :class:`~stalker.core.models.User` class. Now the list of
  :class:`~stalker.core.models.Project`\ s are gathered from all the
  :class:`~stalker.core.models.Task`\ s assigned to the current
  :class:`~stalker.core.models.User`.
* The ``Group`` class is renamed to ``PermissionGroup``.
* The default duration for the :class:`~stalker.core.mixins.ScheduleMixin`
  is now defined by the :attr:`stalker.conf.defaults.DEFAULT_TASK_DURATION`
  attribute.
* The :class:`~stalker.core.mixins.ScheduleMixin` class now accepts a third
  argument called ``duration``.
* The :attr:`~stalker.core.mixins.ScheduleMixin.duration` attribute in the
  :class:`~stalker.core.mixins.ScheduleMixin` is now a settable. See the
  :class:`~stalker.core.mixins.ScheduleMixin` class documentation for details.
* The :attr:`~stalker.core.mixins.ScheduleMixin.due_date` in
  :class:`~stalker.core.mixins.ScheduleMixin` doesn't accept
  ``datetime.timedelta`` objects anymore.
* The behavior of :attr:`~stalker.core.mixins.ScheduleMixin.start`,
  :attr:`~stalker.core.mixins.ScheduleMixin.due_date` and
  :attr:`~stalker.core.mixins.ScheduleMixin.duration` in
  :class:`~stalker.core.mixins.ScheduleMixin` is updated.
* Added :class:`~stalker.core.errors.CircularDependencyError`.
* All the ``ValueError``\ s are converted to ``TypeError``\ s in the
  :class:`~stalker.ext.validatedList.ValidatedList`.
* Finished the implementation of :class:`~stalker.core.models.Task` class.
* Updated the formatting of the :attr:`~stalker.core.models.SimpleEntity.code`
  attribute in :class:`~stalker.core.models.SimpleEntity` class. See the
  documentation of the :class:`~stalker.core.models.SimpleEntity` class for
  details.
* Updated the :attr:`~stalker.core.models.User.code` attribute in
  :class:`~stalker.core.models.User`.
* Updated all the exceptions raised by the SOM classes. Now they are correctly
  raising ``TypeError`` and ValueError``\ s.
* added a new mixin class called :class:`~stalker.core.mixins.ProjectMixin`.
* :class:`~stalker.core.models.Sequence`,
  :class:`~stalker.core.models.Asset` and :class:`~stalker.core.models.Task`
  classes are now using the
  :class:`~stalker.core.mixins.ProjectMixin` mixin class instead of
  implementing this common feature by them self.
* added :class:`~stalker.db.mixin.ProjectMixinDB` for classes which are mixed
  with :class:`~stalker.core.mixins.ProjectMixin`.
* :class:`~stalker.ext.validatedList.ValidatedList` now accepts a third
  argument called the ``validator`` which should be a callable, which is
  called when any of the methods of the
  :class:`~stalker.ext.validatedList.ValidatedList` is called and the list of
  elements are modified. The list of elements modified will be passed to the
  validator function where the first argument is a list containing the
  elements added and the last argument is a list contatining the elements
  removed.
* :attr:`~stalker.core.models.Task.resources` in
  :class:`~stalker.core.models.Task` is now updating the
  :attr:`~stalker.core.models.User.tasks` attribute in the
  :class:`~stalker.core.models.User` class.
* ``tasks`` is not an argument for the :class:`~stalker.core.models.User`
  anymore. It was meaningles to have the :class:`~stalker.core.models.Task`\ s
  in the initialization of the :class:`~stalker.core.models.User` instances.
* :class:`~stalker.core.models.User` classes
  :attr:`~stalker.core.models.User.projects` attribute is now gathered by
  looking at the :attr:`~stalker.core.models.Task.project` attribute of the
  :class:`~stalker.core.models.Task`\ s in the
  :attr:`~stalker.core.models.User.tasks` attribute.
* :class:`~stalker.core.models.StatusList` now accepts classes for the
  ``target_entity_type`` argument.
* :class:`~stalker.core.mixins.ReferenceMixin` now accepts anything derived
  from the :class:`~stalker.core.models.Entity`.
* :class:`~stalker.core.models.Task` class now has a
  :attr:`~stalker.core.models.Task.part_of` attribute which accepts
  :class:`~stalker.core.models.SimpleEntity` instances and shows which
  entity is this task a part of.

0.1.1.a8
========

* From now on an :class:`~stalker.core.models.Asset` instance can not be
  created without a :class:`~stalker.core.models.AssetType` object defining
  the type of the current :class:`~stalker.core.models.Asset`. This is done to
  prevent creation of :class:`~stalker.core.models.Asset`\ s without a certain
  type.
* Fixed :class:`~stalker.core.models.Project` where it was not raising a
  ValueError properly for :attr:`~stalker.core.models.Project.sequence`,
  :attr:`~stalker.core.models.Project.assets` and
  :attr:`~stalker.core.models.Project.users` attributes when the assigned
  value is not iterable.
* Fixed :class:`~stalker.core.models.Department` where it was not raising a
  ValueError properly for :attr:`~stalker.core.models.Department.members`
  attribute when the assigned value is not iterable.
* Changed the representaion string of the :class:`~stalker.core.models.Shot`
  to <Shot (Shot.code, Shot.code)> because the
  :attr:`~stalker.core.models.Shot.name` is not meaningful.
* Changed the way :class:`~stalker.core.models.EntityMeta` metaclass working.
  It is now using the ``__new__`` method and the ``dict_`` of the class to
  set the attributes.
* The :class:`~stalker.core.models.EntityMeta` now adds another attribute
  called ``plural_name`` to the classes, which shows the plural form of the
  class name. By default it tries to set it to a good name using plural form
  rules of English but if the name has an irregular plural name (or it is not
  in English) you can override this attribute by adding ``plural_name`` to the
  class attributes::

    from stalker.core.models import SimpleEntity

    class MyEntity(SimpleEntity):
        plural_name = "MyEntities"
        pass

* From now on the table names are in the following format:
  * The plural name of the class if the table belongs to one class
  * The class1.__name__ + "_" + class2.plural_name if the table is a join
    table
* Updated the table names in the :mod:`stalker.db.mixin` module

0.1.1.a7
========

* Updated the :ref:`roadmap_toplevel` to reflect the current development
  history and cycle
* Merged all the model classes which were previously in separate files in to
  :mod:`stalker.core.models` module, to make it easy to use (and possibly hard
  to develop)
* All the references to modules or classes or anything in the source codes are
  now represented by an absolute path in the docs (
  :class:`stalker.core.models.User` instead of
  :class:`~stalker.core.models.User`)
* moved the :mod:`stalker.db.auth` to :mod:`stalker.ext.auth`
* :class:`stalker.core.models.User` class now uses the
  :func:`stalker.ext.auth.set_password` and
  :func:`stalker.ext.auth.check_password` utility functions to handle
  passwords. The user passwords are now always hidden, but not strongly
  encrypted.
* The :func:`stalker.ext.auth.session` renamed to
  :func:`stalker.ext.auth.create_session` to reflect its functionality
  properly. And removed the return value from the function. Now it doesn't
  return any bool value but None. To check if the user is already logged in
  use :const:`stalker.ext.auth.SESSION` dictionary as follows::

    from stalker.ext import auth

    # initialize the session
    auth.create_session()

    # check if there is a user
    if auth.SESSION_KEY in auth.SESSION:
        print "There is a logged in user"
    else:
        print "There is no logged in user"

* :func:`stalker.ext.auth.authenticate` updated to use
  :func:`stalker.ext.auth.check_password`
* Fixed the :attr:`~stalker.core.models.User.last_login` attribute in the
  database mapper, it was set as a *synonym* for it self.
* Removed the ``tearDown`` methods in :mod:`tests.db.test_db`, there are
  problems with cleaning the mappers and disposing the engine, so instead of
  killing them the db.setup is called over and over again with different in
  memory databases.
* From now on the :attr:`~stalker.core.models.SimpleEntity.code` attribute
  doesn't format the given string value too heavily, to allow more individual
  naming conventions to work with Stalker.
* Updated :ref:`contribute_toplevel`
* Renamed the :class:`~stalker.core.models.PipelineStep` to
  :class:`~stalker.core.models.TaskType` and changed the idea behind the
  relation between :class:`~stalker.core.models.AssetType` and
  :class:`~stalker.core.models.Task`
* :class:`stalker.core.models.AssetType` classes
  :attr:`~stalker.core.models.AssetType.pipeline_steps` attribute has been
  renamed to :attr:`~stalker.core.models.AssetType.task_types`
* Fixed a little error in the mapper of :class:`stalker.core.models.Structure`
* Re-implemented the :func:`stalker.ext.auth.login` function and updated the
  tests accordingly.
* All the error classes in :mod:`stalker.core.models` moved to
  :mod:`stalker.core.errors`
* Added a new error class called :class:`stalker.core.errors.DBError`
* Fixed a bug in :const:`stalker.db.__mappers__`, it is now possible to add
  new mappers without deleting the previous
  :const:`stalker.conf.defaults.MAPPERS` list.
* Removed the :class:`~stalker.core.models.AssetType` and derived the
  :class:`~stalker.core.models.Shot` and :class:`~stalker.core.models.Asset`
  classes from :class:`~stalker.core.models.Entity`.
* Moved the mixin classes from :mod:`stalker.core.models` to
  :mod:`stalker.core.mixins`
* Introduced the :class:`~stalker.core.mixins.TaskMixin` which gives the
  ability to connect a list of tasks to the mixed in class. Also added the
  mapper setup for this mixin.
* :class:`~stalker.ext.validatedList.ValidatedList` now accepts string values
  for the ``type_`` argument.
* Added :class:`~stalker.core.models.Shot` class and test for it.
* Updated the :class:`~stalker.core.models.Sequence` database tests according
  to new rules introduced with the :class:`~stalker.core.models.Shot` class.
* :class:`~stalker.ext.validatedList.ValidatedList` now imports the given
  types lazily when the type is given as a string path.
* :class:`~stalker.core.models.Sequence` now needs a
  :class:`~stalker.core.models.Project` instance to be created.
* It is now possible to assign :class:`~stalker.core.models.Task`\ s to
  :class:`~stalker.core.models.Project` and
  :class:`~stalker.core.models.Sequence`\ s. Also updated the tests for this
  change.
* Removed the ``shots`` argument from the
  :class:`~stalker.core.models.Sequence` class initialization. Because there
  is no way to create a :class:`~stalker.core.models.Shot` without a
  :class:`~stalker.core.models.Sequence` instance.
* Added tests for mixin initialization for
  :class:`~stalker.core.models.Project`,
  :class:`~stalker.core.models.Sequence`, :class:`~stalker.core.models.Shot`
  and :class:`~stalker.core.models.Asset` classes.
* Fixed a bug in :class:`~stalker.core.models.Project` where it was always
  initializing the references with an empty list no matter what is given.
* Fixed a bug in :class:`~stalker.core.models.Project` where it was always
  initializing the :attr:`~stalker.core.models.Project.start` to
  **datetime.date.today** and the
  :attr:`~stalker.core.models.project.due_date` to 10 days later then the
  :attr:`~stalker.core.models.project.start` no matter what are given.
* Fixed a bug in :class:`~stalker.core.mixins.ReferenceMixin` where it was not
  initializing the reference attribute correctly.
* Fixed a bug in :class:`~stalker.core.models.Asset` where the
  :attr:`~stalker.core.models.Asset.project` attribute was not correctly
  getting the given :class:`~stalker.core.models.Project` instance.
* Added the mappers and tables for :class:`~stalker.core.models.Shot` class.
* Updated database model tests to test all the attributes of the models.

0.1.1.a6
========

* updated/fixed tests for :class:`stalker.ext.validatedList.ValidatedList`
* updated a couple of tests to increase tests coverage
* :class:`stalker.core.models.status.Status` class instances now can be
  compared to string or unicode values
* A :class:`stalker.core.models.status.Status` object in a
  :class:`stalker.core.models.status.StatusList` can now be accessed by its
  name as the index in :class:`stalker.core.models.status.StatusList` only
  while getting the item.
* Added :class:`stalker.core.models.mixin.ScheduleMixin` which introduces date
  variables like, start, due_date and duration to the mixed in class.
* Removed some parts of the :class:`stalker.core.models.project.Project` class
  which are now satisfied by the
  :class:`stalker.core.models.mixin.ScheduleMixin`
* Improved the implementation of the :mod:`stalker.db.auth` module
* removed the ``stalker.db.__setup__`` module which were helping to reference
  the variables in :mod:`stalker.db` module but it is not needed any more
* It is now possible to initialize a
  :class:`stalker.core.models.project.Project` object without a
  :class:`stalker.core.models.repository.Repository`,
  :class:`stalker.core.models.structure.Structure` or an
  :class:`stalker.core.models.imageFormat.ImageFormat` or a
  :class:`stalker.core.models.types.ProjectType`
* Updated the :ref:`tutorial_toplevel`
* From now on, in a :class:`stalker.core.models.entity.SimpleEntity`,
  setting the code attribute to None or empty string will not raise any
  ``ValueError``\ s but will re-initialize the ``code`` value from the
  ``nice_name`` attribute.
* Implemented :class:`stalker.core.models.sequence.Sequence` class along with
  its tests.
* added :class:`stalker.core.models.sequence.Sequence` equality tests.
* improved :class:`stalker.core.models.project.Project` equality tests.
* Implemented :class:`stalker.core.models.assetBase.AssetBase` class along
  with its tests.
* The **index.rst** of the documentation now references the **README** from
  the project root.
* added the basic implementation of :class:`stalker.core.models.task.Task`
  and :class:`stalker.core.models.shot.Shot` and mapped them very basically
  to be able to test the dependent classes like
  :class:`stalker.core.models.assetBase.AssetBase` and
  :class:`stalker.core.models.sequence.Sequence`
* Added mappers and tables for
  :class:`stalker.core.models.assetBase.AssetBase`
* Now all the mixin classes have proper :func:`__init__` methods, and in a
  mixed class, the mixin classes' :func:`__init__` method can be called
  directly by giving the current object instance (*self*) like shown below::

    class ANewEntity(entity.SimpleEntity, mixin.StatusMixin):
        def __init__(self, **kwargs):
            super(ANewEntity, self).__init__(**kwargs)
            mixin.StatusMixin.__init__(self, **kwargs)

  and it can be repeated for any number of mixins in class inheritance path.
* Added the **CHANGELOG** to the documentation, and updated all formating of
  the mentioned references inside the file.

0.1.1.a5
========

* removed the :class:`stalker.core.models.entity.StatusedEntity` and its
  tests, with the introduction of
  :class:`stalker.core.models.mixin.StatusMixin`, it is not necessary any
  more
* added camera_lens.py to the examples, which shows how to extend SOM in its
  very basic form, also added tests testing this example
* changed the database uri for the **DatabaseTester**, it now uses an in
  memory SQLite database instead a file based one.
* Updated the version numbers in the roadmap
* Added ``last_login`` attribute to :class:`stalker.core.models.user.User`
  class tables and mapped it
* because it was taking too much space in the diffs the VUE file which shows
  the design sketches has been removed from the trunk
* added the :class:`stalker.ext.validatedList.ValidatedList` class which is a
  list derivative that accepts only one type of object.
* these SOM classes listed below uses
  :class:`stalker.ext.validatedList.ValidatedList` in their list attributes
  requiring specific types of objects to be assigned:
  * :class:`stalker.core.models.entity.Entity`
  * :class:`stalker.core.models.status.StatusList`
  * :class:`stalker.core.models.structure.Structure`
  * :class:`stalker.core.models.types.AssetType`
  * :class:`stalker.core.models.department.Department`
  * :class:`stalker.core.models.user.User`
  * :class:`stalker.core.models.mixin.ReferenceMixin`
* added tests of the :class:`stalker.core.models.project.Project` class
* completed the first implementation of the
  :class:`stalker.core.models.project.Project` class
* to be able to use *assertIsInstance* method of
  :class:`mocker.MockerTestCase` all the
  :class:`unittest.TestCase` test classes are converted to
  :class:`mocker.MockerTestCase`
* changed the design of the **stalker.db.mixins.ReferenceMixin.setup**
  and **stalker.db.mixins.StatusMixin.setup** to organize the mixin
  classes' database setup helper functions, now they are converted to classes
  with a classmethod called :meth:`stalker.db.mixin.ReferenceMixinDB.setup`
  doing all the functionality of the previous setup function and placed them
  under the :mod:`stalker.db.mixin` module.
* added persistence tests for :class:`stalker.core.models.project.Project`
* fixed secondary table generation for
  :class:`stalker.core.models.mixin.ReferenceMixin`, the table is now
  created only if it doesn't exists already, and it is retrieved from
  :attr:`stalker.db.metadata` if it exists

0.1.1.a4
========

* changed the arguments of the
  :func:`stalker.db.mixins.ReferenceMixin.setup` function, to allow
  carrying the data from one to the next mixin (this part still needs a lot of
  attention)
* removed the unnecessary ``statusedEntity_statuses`` secondary table, because
  one :class:`stalker.core.models.entity.StatusedEntity` owns just one
  :class:`stalker.core.models.status.StatusList` its a **many2one** relation,
  so no need to have a secondary table
* introduced the :class:`stalker.core.models.mixin.StatusMixin` (will replace
  StatusedEntity soon)
* Added a new example for the usage of
  :class:`stalker.core.models.mixin.StatusMixin`
* Updated the :func:`stalker.db.mixins.ReferenceMixin.setup` function, now it
  takes three arguments, the *class*, the *table* and the *mapper_options*
  dictionary.

0.1.1.a3
========

* Removed the included *tests* from the egg build
* Added/fixed equality and inequality operators for classes:
  * :class:`stalker.core.models.department.Department`
  * :class:`stalker.core.models.entity.StatusedEntity`
* :class:`stalker.core.models.entity.SimpleEntity` now has a \*\*kwargs in the
  :func:`__init__` so it doesn't give ``TypeError`` for extra keywords
* added :class:`stalker.core.models.entity.EntityMeta` metaclass which adds
  ``entity_type`` attribute and sets its value to the unicode version of the
  name of the class
* the :class:`stalker.core.models.entity.SimpleEntity` uses the
  :class:`stalker.core.models.entity.EntityMeta` metaclass to automatically
  add all the ``entity_type`` attribute to all the derived classes
* all the mappers now uses the ``ClassName.entity_type`` class attribute as
  the polymorphic discriminator (polymorphic identity)
* instead of *LBYL* moving toward *EAFP* idiom for all the models in the
  :mod:`stalker.core`
* :class:`stalker.core.models.status.StatusList` now supports indexing
* :class:`stalker.core.models.status.StatusList` now has an
  ``target_entity_type`` attribute which accepts strings with the class name
  and shows the compatible class of this
  :class:`stalker.core.models.status.StatusList`
* :meth:`stakler.core.models.status.StatusList.__eq__` now checks for the
  ``target_entity_type`` also
* :class:`stalker.core.models.status.StatusedEntity` now checks for the given
  :attr:`stalker.core.models.StatusList.target_entity_type` for
  compatibility with the current class
* All the validation methods in the :mod:`stalker.core.models` now has the
  **validate** word in their name instead of **check**
* Little fixes:
  * the mapper of :class:`stalker.core.models.types.TypeTemplate` was trying
     to setup a synonym to a parameter with the same name (file_code)
  * :class:`stalker.core.models.user.User` classes ``_sequence_lead``
       attribute renamed to ``_sequences_lead``
* Added persistence tests for
  :class:`stalker.core.models.entity.StatusedEntity`
* Added :func:`stalker.utils.path_to_exec` which converts the given module
  full paths to an executable python code which imports the given python
  object to the current namespace
* Added ``entity_types`` table to hold the possible entity types in Stalker.
  The content of the table comes from the
  :const:`stalker.conf.defaults.CORE_MODEL_CLASSES` list. And possibly going
  to be extended by the users.
* Added :func:`stalker.db.__setup__.__fill_entity_types_table__` which fills
  the ``entity_types`` table with default values.
* :class:`stalker.core.models.user.User` class now has ``initials`` attribute,
  which is automatically calculated from the first and last name if there is
  no one given.
* Started developing the :class:`stalker.core.models.message.Message` class
* Added the :mod:`stalker.core.models.mixin` module which holds the common
  mixins.
* Added the :class:`stalker.core.models.mixin.ReferenceMixin` class which
  gives reference abilities to mixed in classes.
* Added the database part of the
  :class:`stalker.core.models.mixin.ReferenceMixin`. Now it is possible to
  create a new type of entity and mix it with ReferenceMixin and also persist
  it in the database. But it needs a lot of effort before to have something
  usable.
* Added **examples** module, which holds usage examples and recipes
* Added an example about how to create a new mixed in entity type for SOM.

0.1.1.a2
========

* Updated the Tutorial
* Added *code* attribute to :class:`stalker.core.models.entity.SimpleEntity`
* Updated the :class:`stalker.core.models.user.User` class for the new *code*
  attribute, and also updated the tests to add tests for *code* attribute
  (simply copied the test code from ``SimpleEntityTester``, bad code
  repetition, need to change it later, by may be inheriting the test case from
  the other one)
* Updated the database tables and mappers for the new *code* attribute
* Removed the clashing *code* attribute from
  :class:`stalker.core.models.pipelineStep.PipelineStep` class and the tables
  and mappers.
* Added :class:`stalker.core.models.note.Note` class
* Added ``notes`` table and a mapper for
  :class:`stalker.core.models.note.Note` class
* Added *note* attribute to :class:`stalker.core.models.entity.Entity` class
* Fixed ``EntityTester`` in tests
* Added ``__repr__`` to entity classes
* Added tests for persistence of :class:`stalker.core.models.note.Note`` class
* Added equality (__eq__) and inequality (__ne__) operators for classes:
  * :class:`stalker.core.models.user.User`
  * :class:`stalker.core.models.tag.Tag`
  * :class:`stalker.core.models.status.Status`
  * :class:`stalker.core.models.status.StatusList`
  * :class:`stalker.core.models.imageFormat.ImageFormat`
  * :class:`stalker.core.models.repository.Repository`
  * :class:`stalker.core.models.pipelineStep.PipelineStep`
  * :class:`stalker.core.models.structure.Structure`
  * :class:`stalker.core.models.types.AssetType`
  * :class:`stalker.core.models.types.LinkType`
  * :class:`stalker.core.models.entity.TypeEntity`
  * :class:`stalker.core.models.types.ProjectType`
* :class:`stalker.core.models.Status` classes' short_name attribute has been
  removed, from now on the ``code`` attribute will be used, also updated the
  database tables and mappers
* The :attr:`stalker.core.models.user.User.login_name` is now superior to the
  :attr:`stalker.core.models.user.User.name` attribute, giving both of them as
  arguments will lead the ``login_name`` to be used as both the ``login_name``
  and the ``name``

0.1.1.a1
========

* Fixed a couple of documentation errors like:
  * :ref:`inheritance_diagram_toplevel` had references to modules
  * A couple of docstring documentation errors in
     :class:`stalker.core.models.structure.Structure`,
     :class:`stalker.core.models.user.User` and
     :class:`stalker.core.models.types.TypeTemplate` classes
* Updated :ref:`installation_toplevel`
* Added :ref:`tutorial_toplevel` page to the documentation
* All the classes, functions from **SQLAlchemy** are now imported to the
  ``sqlalchemy`` namespace, this will let the **Sphinx** to correctly include
  classes, functions from **Stalker** only
* Removed the ``db.meta module``, now all the functionalities supplied by
  ``stalker.db.meta`` are supplied by ``db`` itself (``db.meta.session`` -->
  ``db.session`` etc.)
* Added ``query`` variable to :mod:`stalker.db` module so instead of
  ``db.session.query`` now ``db.query`` can be used
* Updated :func:`stalker.db.auth.login_required` decorator function, it now
  accepts a ``view`` function
* Added :func:`stalker.db.auth.permission_required` decorator function
* ``name`` attribute of :class:`stalker.core.models.entity.SimpleEntity` is
  not any more forced to start with an upper case letter
* From now on ``login_name`` is now a *synonym* for ``name`` in
  :class:`stalker.core.models.user.User` class and just the ``name`` attribute
  is going to be stored in the database
* To make things simple all the properties with name **type_** is now using
  the name **type** even though it is a Python keyword, Python is clever
  enough to understand what is meant

0.1.1.a0
========

* Changed the version number scheme a little bit to follow the setuptools guide

0.1.0.20110111.1
================

* Persistence tests for Link is now fixed
* Now every table correctly has a ``primary_key``

0.1.0.20110110.1
================

* Added :ref:`installation_toplevel` to the documentation
* Updated **README** file for **PyPI**
* Added the package to **PyPI**
* Fixed ``StatusedEntityTester`` test suit, now it properly creates mock
  :class:`satlker.coer.models.status.StatusList` object for the ``__eq__`` and
  ``__ne__`` tests
* Updated tables and mappers for
  :class:`stalker.core.models.typeEntity.TypeTemplate`
* Updated mappers for :class:`stalker.core.models.typeEntity.AssetType`
* :class:`stalker.core.models.entity.TypeEntity` class is moved to
  ``entity.py``, right beside the other entity classes
* ``typeEntity.py`` renamed to ``types.py``
* Created tables and mappers for:
  * :class:`stalker.core.models.structure.Structure`
  * :class:`stalker.core.models.entity.TypeEntity`
  * :class:`stalker.core.models.types.TypeTemplate`
  * :class:`stalker.core.models.types.AssetType`
  * :class:`stalker.core.models.types.LinkType`
  * :class:`stalker.core.models.types.ProjectType`
* Updated ``simpleEntities`` table, now the ``name`` by itself is not a
  *unique constraint*, but added an explicit ``UniqueConstraint`` on ``name``
  and ``entity_type`` columns to allow entities with different types to have
  the same name, also added test for that.
* Fixed all the errors in ``test_db.py``, there are only failures left.
* Added tests for :class:`stalker.core.models.link.Link`, all the test are
  green for :class:`stalker.core.models.link.Link` except the persistence
  tests.

0.1.0.20110108.1
================

* ``Template`` class is renamed to ``TypeTemplate`` and moved inside
  ``stalker.core.models.typeEntity`` to prevent the name clashing with
  **Jinja2** Template class
* added ``__eq__`` to :class:`stalker.core.models.entity.SimpleEntity` and
  still trying to add it to the derived classes
* organized the project structure to conform setup tools for **PyPI**

0.1.0.20110107.2
================

* updating the db tests
* stalker.core.models.user.User class is now allowed to have its department
  to be set None

0.1.0.20110107.1
================

* organized the existent tests

0.1.0.20110106.2
================

* added nice_name property to the stalker.core.models.entity.SimpleEntity
  class
* added tests for stalker.core.models.structure.Structure class
* implemented the stalker.core.models.structure.Structure class
* added last_login attribute to the stalker.core.models.user.User class and
  added all the tests

0.1.0.20110106.1
================

* re-introduced the link.Link, which has a general meaning than
  reference.Reference (I bet it will be reference again tomorrow)
* stalker.models moved to stalker.core.models
* renamed tests/z_db to tests/db, because the sqlalchemy/mocker problem is
  solved by moving the models to core/models

0.1.0.20110105
==============

* improved the stalker.models.template.Template class documentation, and added
  an example showing the usage of it.

0.1.0.20110104
==============

* removed the link.Link and introduced reference.Reference and
  typeEntity.ReferenceType classes, which I think are more organized then the
  previous design.
* reorganized the AssetType and ReferenceType objects by introducing the new
  TypeEntity class and deriving the AssetType and ReferenceType from this
  class
* added ProjectType class to hold different project types (like Commercial,
  Film, Still etc., it is different than having a Commercial Structure object)
* removed AssetTemplate and ReferenceTemplate concepts and generalized the
  Template class by adding a `type` parameter to it, which accepts TypeEntity
  and classes derived from TypeEntity.

0.1.0.20110103.2
================

* added login_required decorator to the stalker.db.auth module, but the
  implementation is not done yet

0.1.0.20110103
==============

* user.User._password is now scrambled, but the password property uses the raw
  password
* added stalker.db.auth for authentication, removed the db.login function.

0.1.0.20110102
==============

* added the error.LoginError exception for login errors
* started to add tests for db.login function

0.1.0.20101231
==============

* moved the login function to the db.__init__ to let it used just after
  setting up the database without importing any new module
* updated the example in the docstring of the template.AssetTemplate

0.1.0.20101229.3
================

* generalized the Template class. Now every Entity can be assigned to a
  template, it is not limited with Assets or References.

0.1.0.20101229.2
================

* entity.SimpleEntity.name now can have white spaces, but not at the beginning
  or end, just in the middle
* done mapping template.Template class

0.1.0.20101229.1
================

* trying to create a session system with Beaker, to hold user login
  information
* done mapping assetType.AssetType class
* done mapping pipelineStep class

0.1.0.20101228.1
================

* added repositories table and mapper for the repository.Repository class
* added imageFormats table and mapper for the imageFormat.ImageFormat class
* renamed extensions module to ext
* added roadmap to docs

0.1.0.20101228
==============

* created the block of database tests
* added stalker.db.meta.__mappers__ list to hold the mappers and use it to
  check if anything is already mapped
* added tests for db initialization
* removed the whole stalker.models.unit module from SOM, only TimeUnit was
  usable in some cases, but in fact it is also not important, the only object
  using TimeUnit was the Project class and it can go well without it. Don't
  need to make things more complex than it needs to be.
* increased the version number to 0.1.0 to follow the stalker roadmap

0.0.1.20101227
==============

* the test_db is converted to a proper unittest which is testing all the
  models one by one
* test/db renamed to test/z_db to let nose run it latest to solve the problem
  about mocker and sqlalchemy fighting each other.
* Mapping syntax is changed a little bit, now to do the mapping, the
  <mapper>.setup() function needs to be called to be able to do the mapping
  any time
* started adding tests for every class in SOM

0.0.1.20101226
==============

* in user.User the last_name attribute could be an empty string
* removed SimpleEntity, TaggedEntity and introduced StatusedEntity to make the
  inheritance clear and let users to find somebody to blame by moving all the
  audit information to the the SimpleEntity class in which everything is
  inherited from. Now even a Tag has audit information.

0.0.1.20101225
==============

* entity.AuditEntity.created_by can now be None (for now)
* user.User.last_name can now be None, to let users like admin have no last
  name
* creating tables for catch the general inheritance of the entity classes
* entitiy.SimpleEntity.name's first letter is not capitalized any more
* department.Department class now accepts Null for lead attribute (for now
  again)

0.0.1.20101224
==============

* started playing with the SQLAlchemy side of the system

0.0.1.20101223
==============

* updating the documentation
* AuditEntity now accepts None for updated_by attribute when it an object is
  created, but sets it to the same value with created_by attribute

0.0.1.20101219
==============

* started to implement:
  * a database entry point
  * a customizable object model and database tables
  * an automatic mapper to map the objects and tables together according to
     user settings

  things can change a lot in this phase, I'm just trying to figure out the
  best possible way to do it.

* added a new entity type called TaggedEntity which derives from SimpleEntity,
  and moved all the tag related attributes of SimpleEntity to TaggedEntity,
  and all the child classes deriving from SimpleEntity now derives from
  TaggedEntity, also moved the tests related with tag in SimpleEntity to
  TaggedEntity.
* tag.Tag now derives from the SimpleEntity and doesn't add any other
  attribute to its super.
* updated tests for tag.Tag
* updated docs for TaggedEntity
* finished implementing the Department object and its tests
* removed the notes attribute from the Entity class

0.0.1.20101209
==============

* added the inheritance diagram as an rst page to reference it anywhere needed
* added the empty classes for:
  * Asset
  * AssetBase
  * Booking
  * Shot
  * Structure
  * Template
  * Version

* added the Department class
* added inheritance diagrams to the autosummary pages of the classes


================================================
FILE: COPYING
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.


================================================
FILE: COPYING.LESSER
================================================
                   GNU LESSER GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.


  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

  Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.


================================================
FILE: Dockerfile-py3.5
================================================
# This Dockerfile is based on: https://docs.docker.com/examples/postgresql_service/

FROM ubuntu:16.04

MAINTAINER fredrik@averpil.com

# Add the PostgreSQL PGP key to verify their Debian packages.
# It should be the same key as https://www.postgresql.org/media/keys/ACCC4CF8.asc
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8

# Add PostgreSQL's repository. It contains the most recent stable release
#     of PostgreSQL, ``9.3``.
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list

# Install everything in one enormous RUN command
#  There are some warnings (in red) that show up during the build. You can hide
#  them by prefixing each apt-get statement with DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \

    apt-get install -y \
    python3-software-properties python3-pip \
    software-properties-common \
    postgresql-9.3 postgresql-client-9.3 postgresql-contrib-9.3 postgresql-server-dev-9.3 \
    rubygems && \

    gem install taskjuggler && \

    pip3 install -U pip && \
    pip3 install sqlalchemy psycopg2-binary jinja2 alembic mako markupsafe python-editor nose coverage

# Note: The official Debian and Ubuntu images automatically ``apt-get clean``
# after each ``apt-get``

# Run commands as the ``postgres`` user created by the ``postgres-9.3`` package when it was ``apt-get installed``
USER postgres

RUN /etc/init.d/postgresql start && \
    psql -c "CREATE DATABASE stalker_test;" -U postgres && \
    psql -c "CREATE USER stalker_admin WITH PASSWORD 'stalker';" -U postgres && \
    /etc/init.d/postgresql stop

# Adjust PostgreSQL configuration so that remote connections to the
# database are possible.
# RUN echo "host all  all    0.0.0.0/0  md5" >> /etc/postgresql/9.3/main/pg_hba.conf

# And add ``listen_addresses`` to ``/etc/postgresql/9.3/main/postgresql.conf``
# RUN echo "listen_addresses='*'" >> /etc/postgresql/9.3/main/postgresql.conf

# Expose the PostgreSQL port
# EXPOSE 5432

# Add VOLUMEs to allow backup of config, logs and databases
# VOLUME  ["/etc/postgresql", "/var/log/postgresql", "/var/lib/postgresql"]

USER root

# Create symlink to TaskJuggler
# RUN ln -s $(which tj3) /usr/local/bin/tj3

# Set working directory
WORKDIR /workspace

# Embed wait-for-postgres.sh script into Dockerfile
RUN echo '\n\
# wait-for-postgres\n\
\n\

set -e\n\
\n\
cmd="$@"\n\
timer="5"\n\
\n\
until runuser -l postgres -c 'pg_isready' 2>/dev/null; do\n\
    >&2 echo "Postgres is unavailable - sleeping for $timer seconds"\n\
    sleep $timer\n\
done\n\
\n\
>&2 echo "Postgres is up - executing command"\n\
exec $cmd\n'\
>> /workspace/wait-for-postgres.sh

# Make script executable
RUN chmod +x /workspace/wait-for-postgres.sh

# Execute this when running container
ENTRYPOINT \

            # Copy stalker into container's /workspace'
            cp -r /stalker /workspace && \

            # Remove execution permissions within Stalker
            chmod -R -x /workspace/stalker && \

            # Start PostgreSQL
            runuser -l postgres -c '/usr/lib/postgresql/9.3/bin/postgres -D /var/lib/postgresql/9.3/main -c config_file=/etc/postgresql/9.3/main/postgresql.conf & ' && \

            # Wait for PostgresSQL
            ./wait-for-postgres.sh nosetests /workspace/stalker --verbosity=1 --cover-erase --with-coverage --cover-package=stalker && \

            # Cleanly shut down PostgreSQL
            /etc/init.d/postgresql stop


================================================
FILE: INSTALL
================================================
See docs/installation.html.


================================================
FILE: LICENSE
================================================
                   GNU LESSER GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.


  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

  Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.


================================================
FILE: MANIFEST.in
================================================
include *.ini *.cfg

include alembic.ini
include CHANGELOG.rst
include COPYING
include COPYING.LESSER
include INSTALL
include MANIFEST.in
include README.rst
include stalker/VERSION
include TODO
include VERSION

prune docs/build
prune docs/source/generated

================================================
FILE: Makefile
================================================
SHELL:=bash
PACKAGE_NAME=stalker
NUM_CPUS = $(shell nproc ||  grep -c '^processor' /proc/cpuinfo)
SETUP_PY_FLAGS = --use-distutils
VERSION := $(shell cat VERSION)
VERSION_FILE=$(CURDIR)/src/stalker/VERSION
VIRTUALENV_DIR:=.venv
SYSTEM_PYTHON?=python3

all: build FORCE

.PHONY: help
help:
	@echo ""
	@echo "Available targets:"
	@make -qp | grep -o '^[a-z0-9-]\+' | sort

.PHONY: venv
venv:
	@printf "\n\033[36m--- $@: Creating Local virtualenv '$(VIRTUALENV_DIR)' using '$(SYSTEM_PYTHON)' ---\033[0m\n"
	$(SYSTEM_PYTHON) -m venv $(VIRTUALENV_DIR)

build:
	@printf "\n\033[36m--- $@: Building ---\033[0m\n"
	echo -e "\n\033[36m--- $@: Local install into virtualenv '$(VIRTUALENV_DIR)' ---\033[0m\n";
	source ./$(VIRTUALENV_DIR)/bin/activate; \
	echo -e "\n\033[36m--- $@: Using python interpretter '`which python`' ---\033[0m\n"; \
	pip install -r requirements.txt; \
	pip install -r requirements-dev.txt; \
	python -m build;

.PHONY: install
install:
	@printf "\n\033[36m--- $@: Installing $(PACKAGE_NAME) to virtualenv at '$(VIRTUALENV_DIR)' using '$(SYSTEM_PYTHON)' ---\033[0m\n"
	source ./$(VIRTUALENV_DIR)/bin/activate; \
	pip install ./dist/$(PACKAGE_NAME)-$(VERSION)-*.whl --force-reinstall;

clean: FORCE
	@printf "\n\033[36m--- $@: Clean ---\033[0m\n"
	-rm -rf .pytest_cache
	-rm -f .coverage*
	-rm -rf .mypy_cache
	-rm -rf .tox
	-rm -rf dist
	-rm -rf build
	-rm -rf docs/build
	-rm -rf docs/source/generated/*
	-rm -rf htmlcov

clean-all: clean
	@printf "\n\033[36m--- $@: Clean All---\033[0m\n"
	-rm -f INSTALLED_FILES
	-rm -f setuptools-*.egg
	-rm -f use-distutils
	-rm -Rf src/$(PACKAGE_NAME).egg-info
	-rm -Rf $(VIRTUALENV_DIR)

html:
	./setup.py readme

new-release:
	@printf "\n\033[36m--- $@: Generating New Release ---\033[0m\n"
	git add $(VERSION_FILE)
	git commit -m "Version $(VERSION)"
	git push
	git checkout main
	git pull
	git merge develop
	git tag $(VERSION)
	git push origin main --tags
	source ./$(VIRTUALENV_DIR)/bin/activate; \
	echo -e "\n\033[36m--- $@: Using python interpretter '`which python`' ---\033[0m\n"; \
	pip install -r requirements.txt; \
	pip install -r requirements-dev.txt; \
	python -m build; \
	twine check dist/$(PACKAGE_NAME)-$(VERSION).tar.gz; \
	twine upload dist/$(PACKAGE_NAME)-$(VERSION).tar.gz;

.PHONY: tests
tests:
	@printf "\n\033[36m--- $@: Run Tests ---\033[0m\n"
	echo -e "\n\033[36m--- $@: Using virtualenv at '$(VIRTUALENV_DIR)' ---\033[0m\n";
	source ./$(VIRTUALENV_DIR)/bin/activate; \
	echo -e "\n\033[36m--- $@: Using python interpretter '`which python`' ---\033[0m\n"; \
	SQLALCHEMY_WARN_20=1 PYTHONPATH=src pytest -n auto -W ignore -W always::DeprecationWarning --color=yes --cov=src --cov-report term --cov-report html --cov-append --cov-fail-under 99 tests;

.PHONY: docs
docs:
	cd docs && $(MAKE) html

# https://www.gnu.org/software/make/manual/html_node/Force-Targets.html
FORCE:


================================================
FILE: README.md
================================================
[![license](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](http://www.gnu.org/licenses/lgpl-3.0)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/stalker.svg)](https://pypi.python.org/pypi/stalker)
[![Unit Tests](https://github.com/eoyilmaz/stalker/actions/workflows/pytest.yml/badge.svg)](https://github.com/eoyilmaz/stalker/actions/workflows/pytest.yml)
[![PyPI Version](https://img.shields.io/pypi/v/stalker.svg)](https://pypi.python.org/pypi/stalker)
[![PyPI Downloads](https://static.pepy.tech/badge/stalker)](https://pepy.tech/projects/stalker)

About
=====

Stalker is an Open Source Production Asset Management (ProdAM) Library designed 
specifically for Animation and VFX Studios. But it can be used for any kind of
projects from any other industry. Stalker is licensed under LGPL v3.

Features
========

Stalker has the following features:

 * Designed for **Animation and VFX Studios** (but not limited to).
 * OS independent, can work simultaneously with **Windows**, **macOS** and
   **Linux**.
 * Supplies excellent **Project Management** capabilities, i.e. scheduling and
   tracking tasks, milestones and deadlines (via **TaskJuggler**).
 * Powerful **Asset management** capabilities, allows tracking of asset
   references in shots, scenes, sequences and projects.
 * Customizable object model (**Stalker Object Model - SOM**).
 * Uses **TaskJuggler** as the project planing and tracking backend.
 * Mainly developed for **PostgreSQL** in mind but **SQLite3** is also
   supported.
 * Can be connected to all the major 3D animation packages like **Maya,
   Houdini, Nuke, Fusion, DaVinci Resolve, Blender** etc. and any application
   that has a Python API, and for **Adobe Suite** applications like
   **Adobe Photoshop** through ``win32com`` or ``comtypes`` libraries.
 * Developed with religious **TDD** practices.

Stalker is mainly build over the following OpenSource libraries:

 * [Python](https://www.python.org)
 * [PostgreSQL](https://www.postgresql.org/)
 * [SQLAlchemy](https://www.sqlalchemy.org/)
 * [Jinja2](https://jinja.palletsprojects.com/en/stable/)
 * [TaskJuggler](https://taskjuggler.org/)

As Stalker is a Python library and doesn't supply any graphical UI you can use
other tools like [Stalker Pyramid](https://github.com/eoyilmaz/stalker_pyramid)
which is a Pyramid Web Application and [Anima](https://github.com/eoyilmaz/anima)
which has PyQt/PySide UIs for applications like Houdini, Maya, Blender, Nuke,
Fusion, DaVinci Resolve, Photoshop and many more.

Installation
============

Simply use:

```shell
pip install stalker
```

Examples
========

Let's play with **Stalker**.

Because Stalker uses SQLAlchemy, it is very easy to retrieve complex data.
Let's say that you want to query all the Shot Lighting tasks where a specific
asset is referenced:

```python
from stalker import Asset, File, Shot, Version

my_asset = Asset.query.filter_by(name="My Asset").first()
# Let's assume we have multiple Versions created for this Asset already
my_asset_version = my_asset.versions[0]
# get a file from that version
my_asset_version_file = my_asset_version.files[0]
# now get any other Lighting Versions that is referencing this file
refs = (
    Version.query
        .join(File, Version.files)
        .filter(Version.name=="Lighting")
        .filter(File.references.contains(my_asset_version_file))
        .all()
)
```

Let's say you want to get all the tasks assigned to you in a specific Project:

```python
from stalker import Project, Task, User

me = User.query.filter_by(name="Erkan Ozgur Yilmaz").first()
my_project = Project.query.filter_by(name="My Project").first() 
query = Task.query.filter_by(project=my_project).filter(Task.resources.contains(me))
my_tasks = query.all()
```

You can further query let's say your WIP tasks by adding more criteria to the ``query``
object:

```python
from stalker import Status

wip = Status.query.filter_by(code="WIP").first()
query = query.filter_by(status=wip)
my_wip_tasks = query.all()
```

and that's the way to get complex data in Stalker.

See more detailed examples in [API Tutorial](https://pythonhosted.org/stalker/tutorial.html).


================================================
FILE: TODO.rst
================================================
TODO
====

* **Update:** Better support ``duration`` Tasks.

  The current status workflow is not working with **duration** based tasks.
  Task statuses should be updated automatically for duration tasks according to
  their computed start and computed end date values.

* Auto history generation.

  Automatically record all kind of CRUD actions to create a history for any
  attribute present in an entity.

* SCM Integration:

  The repository can be a local path, and the project can be managed with an
  SCM, preferably with Mercurial.

* Per user settings file:

  To let Pipeline TDs easily setup a new workstation with a setup script,
  a predefined file let say with a name of ".strc" can be placed in to the 
  users home folder and Stalker can search for this file and parse it to get 
  things like the database server path, user name and the password.

  There could be also an $STRC environment variable which is showing a common
  place lets say in the fileserver, which also may have a ".strc" file. In 
  this way it will be easy to setup only one ".strc" file for the whole studio.

* ``__tablename__`` and ``__mapper_args__``:
  
  The duty of the ``__tablename__`` and ``__mapper_args__`` variables are 
  very common to any class in the SOM. It can be gathered in a mixin and the
  :class:`~stalker.core.models.SimpleEntity` can be mixed with this class and
  the rest will have their table name and polymorphic identity by default. 

* use pyseq for file sequence handling:

  PySeq is a great, simple library which handles all the file sequence actions.
  It would be great to use it in the :class:`~stalker.core.models.Link` 
  instances. So, the :class:`~stalker.core.models.Link` class can also hold a
  string which can be uncompressed with the pyseq.uncompress function::
    
    from pyseq import uncompress
    seq = uncompress("./tests/012_vb_110_v001.%04d.png 1-10",
                     format="%h%p%t %r")

* Hidden keyword arguments:
  
  Because of the heavy inheritance, it is not very clear what parameters are 
  needed to initialize a class. A simple solution is to repeat all the 
  parameters of the inherited class in the __init__ of the child class.

DONE
====

* Update error messages:

  Not all error message are clear. Generally, because of the heavy
  inheritance, it is not very obvious which class gave the error. Writing down
  the class name should help the user to understand at least what class is
  giving the error message.

* Drop support to any database other 
Download .txt
gitextract_k2ghu6v_/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── pytest.yml
├── .gitignore
├── CHANGELOG.rst
├── CHANGELOG_OLD.rst
├── COPYING
├── COPYING.LESSER
├── Dockerfile-py3.5
├── INSTALL
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── TODO.rst
├── alembic/
│   ├── README
│   ├── env.py
│   ├── script.py.mako
│   └── versions/
│       ├── 0063f547dc2e_updated_version_inputs_table.py
│       ├── 019378697b5b_rename_depends_to_to_depends_on.py
│       ├── 101a789e38ad_created_task_responsible.py
│       ├── 1181305d3001_added_client_id_column_to_goods_table.py
│       ├── 130a7697cd79_vacation_user_can_now_be_nullable.py
│       ├── 174567b9c159_note_content.py
│       ├── 182f44ce5f07_added_users_company_and_projects_client.py
│       ├── 1875136a2bfc_removed_version_variant_name_attribute.py
│       ├── 1c9c9c28c102_price_lists_and_goods.py
│       ├── 21b88ed3da95_added_referencemixin.py
│       ├── 2252e51506de_multiple_repositories.py
│       ├── 23dff41c95ff_removed_tasks_is_complete_column.py
│       ├── 255ee1f9c7b3_added_payments_table.py
│       ├── 258985128aff_create_entitygroups_table.py
│       ├── 25b3eba6ffe7_derive_version_from.py
│       ├── 275bdc106fd5_added_ticket_summary.py
│       ├── 2aeab8b376dc_fg_color_bg_color.py
│       ├── 2e4a3813ae76_created_daily_class.py
│       ├── 2f55dc4f199f_wiki_page.py
│       ├── 30c576f3691_budget_and_budget_entry.py
│       ├── 31b1e22b455e_added_exclude_and_check_constraints_to_.py
│       ├── 39d3c16ff005_budget_entries_good_id.py
│       ├── 3be540ad3a93_added_version_revision_number_attribute.py
│       ├── 409d2d73ca30_user_rate.py
│       ├── 433d9caaafab_task_review_status_workflow.py
│       ├── 4400871fa852_scene_is_now_deriving_from_task.py
│       ├── 4664d72ce1e1_renamed_link_path_to_full_path.py
│       ├── 46775e4a3d96_create_enum_types.py
│       ├── 4a836cf73bcf_create_entitytype_accepts_references.py
│       ├── 5078390e5527_shot_scene_relation_is_now_many_to_one.py
│       ├── 5168cc8552a3_html_style_html_class.py
│       ├── 5355b569237b_version_version_of_r.py
│       ├── 53d8127d8560_parent_child_relatio.py
│       ├── 57a5949c7f29_cache_for_total_logged_seconds.py
│       ├── 5814290f49c7_added_shot_source_in_shot_source_out_record_in.py
│       ├── 583875229230_good_task_relation.py
│       ├── 59092d41175c_added_version_created_with.py
│       ├── 5999269aad30_added_generic_text_attribute.py
│       ├── 59bfe820c369_resource_efficiency.py
│       ├── 6297277da38_added_vacation_class.py
│       ├── 644f5251fc0d_remove_project_active_attribute.py
│       ├── 745b210e6907_fix_non_existing_thumbnails.py
│       ├── 856e70016b2_roles.py
│       ├── 91ed52b72b82_created_variant_class.py
│       ├── 92257ba439e1_budget_is_now_statusable.py
│       ├── 9f9b88fef376_link_renamed_to_file.py
│       ├── a2007ad7f535_added_review_version_id_column.py
│       ├── a6598cde6b_versions_are_not_mix.py
│       ├── a9319b19f7be_added_shot_fps.py
│       ├── af869ddfdf9_entity_to_note_relation_is_now_many_to_many.py
│       ├── bf67e6a234b4_added_revision_code_attribute.py
│       ├── c5607b4cfb0a_added_support_for_time_zones.py
│       ├── d8421de6a206_added_project_users_rate_column.py
│       ├── e25ec9930632_shot_sequence_relation_is_now_many_to_.py
│       ├── ea28a39ba3f5_added_invoices_table.py
│       ├── eaed49db6d9_added_position_column_to_Project_Repositories.py
│       ├── ec1eb2151bb9_rename_version_take_name_to_version_.py
│       ├── ed0167fff399_added_workinghours_table.py
│       ├── f16651477e64_added_authenticationlog_class.py
│       ├── f2005d1fbadc_added_projectclients.py
│       └── feca9bac7d5a_renamed_osx_to_macos.py
├── alembic.ini
├── docs/
│   ├── Makefile
│   ├── make.bat
│   ├── make_html.bat
│   └── source/
│       ├── _static/
│       │   └── images/
│       │       ├── Task_Status_Workflow.vue
│       │       └── stalker_design.vue
│       ├── _templates/
│       │   └── autosummary/
│       │       ├── base.rst
│       │       ├── class.rst
│       │       └── module.rst
│       ├── about.rst
│       ├── changelog.rst
│       ├── conf.py
│       ├── configure.rst
│       ├── contents.rst
│       ├── contribute.rst
│       ├── design.rst
│       ├── index.rst
│       ├── inheritance_diagram.rst
│       ├── installation.rst
│       ├── roadmap.rst
│       ├── status_and_status_lists.rst
│       ├── summary.rst
│       ├── task_review_workflow.rst
│       ├── todo.rst
│       ├── tutorial/
│       │   ├── asset_management.rst
│       │   ├── basics.rst
│       │   ├── collaboration.rst
│       │   ├── conclusion.rst
│       │   ├── creating_simple_data.rst
│       │   ├── extending_som.rst
│       │   ├── pipeline.rst
│       │   ├── query_update_delete_data.rst
│       │   ├── scheduling.rst
│       │   ├── task_and_resource_management.rst
│       │   └── tutorial_files/
│       │       └── tutorial.py
│       ├── tutorial.rst
│       └── upgrade_db.rst
├── examples/
│   ├── __init__.py
│   ├── extending/
│   │   ├── __init__.py
│   │   ├── camera_lens.py
│   │   ├── great_entity.py
│   │   └── statused_entity.py
│   └── flat_project_example.py
├── pyproject.toml
├── requirements-dev.txt
├── requirements.txt
├── setup.py
├── src/
│   └── stalker/
│       ├── VERSION
│       ├── __init__.py
│       ├── config.py
│       ├── db/
│       │   ├── __init__.py
│       │   ├── declarative.py
│       │   ├── session.py
│       │   ├── setup.py
│       │   └── types.py
│       ├── exceptions.py
│       ├── log.py
│       ├── models/
│       │   ├── __init__.py
│       │   ├── asset.py
│       │   ├── auth.py
│       │   ├── budget.py
│       │   ├── client.py
│       │   ├── department.py
│       │   ├── entity.py
│       │   ├── enum.py
│       │   ├── file.py
│       │   ├── format.py
│       │   ├── message.py
│       │   ├── mixins.py
│       │   ├── note.py
│       │   ├── project.py
│       │   ├── repository.py
│       │   ├── review.py
│       │   ├── scene.py
│       │   ├── schedulers.py
│       │   ├── sequence.py
│       │   ├── shot.py
│       │   ├── status.py
│       │   ├── structure.py
│       │   ├── studio.py
│       │   ├── tag.py
│       │   ├── task.py
│       │   ├── template.py
│       │   ├── ticket.py
│       │   ├── type.py
│       │   ├── variant.py
│       │   ├── version.py
│       │   └── wiki.py
│       ├── py.typed
│       ├── utils.py
│       └── version.py
├── tests/
│   ├── __init__.py
│   ├── benchmarks/
│   │   ├── __init__.py
│   │   └── task_total_logged_seonds.py
│   ├── config/
│   │   ├── __init__.py
│   │   └── test_config.py
│   ├── conftest.py
│   ├── data/
│   │   ├── project_to_tjp_output.jinja2
│   │   ├── project_to_tjp_output_formatted
│   │   └── project_to_tjp_output_rendered
│   ├── db/
│   │   ├── __init__.py
│   │   ├── test_db.py
│   │   ├── test_dbsession.py
│   │   └── test_types.py
│   ├── mixins/
│   │   ├── __init__.py
│   │   ├── test_acl_mixin.py
│   │   ├── test_amount_mixin.py
│   │   ├── test_code_mixin.py
│   │   ├── test_create_secondary_table.py
│   │   ├── test_dag_mixin.py
│   │   ├── test_date_range_mixin.py
│   │   ├── test_declarative_project_mixin.py
│   │   ├── test_declarative_reference_mixin.py
│   │   ├── test_declarative_schedule_mixin.py
│   │   ├── test_declarative_status_mixin.py
│   │   ├── test_project_mixin.py
│   │   ├── test_reference_mixin.py
│   │   ├── test_schedule_mixin.py
│   │   ├── test_status_mixin.py
│   │   ├── test_target_entity_type_mixin.py
│   │   └── test_unit_mixin.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── test_asset.py
│   │   ├── test_authentication_log.py
│   │   ├── test_budget.py
│   │   ├── test_client.py
│   │   ├── test_client_user.py
│   │   ├── test_daily.py
│   │   ├── test_department.py
│   │   ├── test_department_user.py
│   │   ├── test_dependency_target.py
│   │   ├── test_entity.py
│   │   ├── test_entity_group.py
│   │   ├── test_file.py
│   │   ├── test_filename_template.py
│   │   ├── test_generic.py
│   │   ├── test_good.py
│   │   ├── test_group.py
│   │   ├── test_image_format.py
│   │   ├── test_invoice.py
│   │   ├── test_local_session.py
│   │   ├── test_message.py
│   │   ├── test_note.py
│   │   ├── test_payment.py
│   │   ├── test_permission.py
│   │   ├── test_price_list.py
│   │   ├── test_project.py
│   │   ├── test_project_client.py
│   │   ├── test_project_user.py
│   │   ├── test_repository.py
│   │   ├── test_review.py
│   │   ├── test_role.py
│   │   ├── test_scene.py
│   │   ├── test_schedule_constraint.py
│   │   ├── test_schedule_model.py
│   │   ├── test_schedulers.py
│   │   ├── test_sequence.py
│   │   ├── test_shot.py
│   │   ├── test_simple_entity.py
│   │   ├── test_status.py
│   │   ├── test_status_list.py
│   │   ├── test_structure.py
│   │   ├── test_studio.py
│   │   ├── test_tag.py
│   │   ├── test_task.py
│   │   ├── test_task_dependency.py
│   │   ├── test_task_juggler_scheduler.py
│   │   ├── test_task_status_workflow.py
│   │   ├── test_ticket.py
│   │   ├── test_time_log.py
│   │   ├── test_time_unit.py
│   │   ├── test_traversal_direction.py
│   │   ├── test_type.py
│   │   ├── test_user.py
│   │   ├── test_vacation.py
│   │   ├── test_variant.py
│   │   ├── test_version.py
│   │   ├── test_wiki.py
│   │   └── test_working_hours.py
│   ├── test_exceptions.py
│   ├── test_logging.py
│   ├── test_readme_tutorial.py
│   ├── test_testing.py
│   ├── test_version.py
│   └── utils.py
└── whitelist.txt
Download .txt
Showing preview only (374K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3120 symbols across 188 files)

FILE: alembic/env.py
  function run_migrations_offline (line 32) | def run_migrations_offline():
  function run_migrations_online (line 51) | def run_migrations_online():

FILE: alembic/versions/0063f547dc2e_updated_version_inputs_table.py
  function upgrade (line 15) | def upgrade():
  function downgrade (line 31) | def downgrade():

FILE: alembic/versions/019378697b5b_rename_depends_to_to_depends_on.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 25) | def downgrade():

FILE: alembic/versions/101a789e38ad_created_task_responsible.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 26) | def downgrade():

FILE: alembic/versions/1181305d3001_added_client_id_column_to_goods_table.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 23) | def downgrade():

FILE: alembic/versions/130a7697cd79_vacation_user_can_now_be_nullable.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/174567b9c159_note_content.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/182f44ce5f07_added_users_company_and_projects_client.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 51) | def downgrade():

FILE: alembic/versions/1875136a2bfc_removed_version_variant_name_attribute.py
  function upgrade (line 20) | def upgrade():
  function downgrade (line 211) | def downgrade():

FILE: alembic/versions/1c9c9c28c102_price_lists_and_goods.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 65) | def downgrade():

FILE: alembic/versions/21b88ed3da95_added_referencemixin.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 43) | def downgrade():

FILE: alembic/versions/2252e51506de_multiple_repositories.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 39) | def downgrade():

FILE: alembic/versions/23dff41c95ff_removed_tasks_is_complete_column.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/255ee1f9c7b3_added_payments_table.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 37) | def downgrade():

FILE: alembic/versions/258985128aff_create_entitygroups_table.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 44) | def downgrade():

FILE: alembic/versions/25b3eba6ffe7_derive_version_from.py
  function upgrade (line 22) | def upgrade():
  function downgrade (line 101) | def downgrade():

FILE: alembic/versions/275bdc106fd5_added_ticket_summary.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/2aeab8b376dc_fg_color_bg_color.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 24) | def downgrade():

FILE: alembic/versions/2e4a3813ae76_created_daily_class.py
  function upgrade (line 20) | def upgrade():
  function downgrade (line 137) | def downgrade():

FILE: alembic/versions/2f55dc4f199f_wiki_page.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 34) | def downgrade():

FILE: alembic/versions/30c576f3691_budget_and_budget_entry.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 50) | def downgrade():

FILE: alembic/versions/31b1e22b455e_added_exclude_and_check_constraints_to_.py
  function upgrade (line 20) | def upgrade():
  function downgrade (line 127) | def downgrade():

FILE: alembic/versions/39d3c16ff005_budget_entries_good_id.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 23) | def downgrade():

FILE: alembic/versions/3be540ad3a93_added_version_revision_number_attribute.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 25) | def downgrade():

FILE: alembic/versions/409d2d73ca30_user_rate.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/433d9caaafab_task_review_status_workflow.py
  function upgrade (line 20) | def upgrade():
  function downgrade (line 468) | def downgrade():

FILE: alembic/versions/4400871fa852_scene_is_now_deriving_from_task.py
  function upgrade (line 20) | def upgrade():
  function downgrade (line 121) | def downgrade():

FILE: alembic/versions/4664d72ce1e1_renamed_link_path_to_full_path.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 57) | def downgrade():

FILE: alembic/versions/46775e4a3d96_create_enum_types.py
  function upgrade (line 15) | def upgrade():
  function downgrade (line 43) | def downgrade():

FILE: alembic/versions/4a836cf73bcf_create_entitytype_accepts_references.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 33) | def downgrade():

FILE: alembic/versions/5078390e5527_shot_scene_relation_is_now_many_to_one.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 39) | def downgrade():

FILE: alembic/versions/5168cc8552a3_html_style_html_class.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 23) | def downgrade():

FILE: alembic/versions/5355b569237b_version_version_of_r.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 38) | def downgrade():

FILE: alembic/versions/53d8127d8560_parent_child_relatio.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 25) | def downgrade():

FILE: alembic/versions/57a5949c7f29_cache_for_total_logged_seconds.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 25) | def downgrade():

FILE: alembic/versions/5814290f49c7_added_shot_source_in_shot_source_out_record_in.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 24) | def downgrade():

FILE: alembic/versions/583875229230_good_task_relation.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 23) | def downgrade():

FILE: alembic/versions/59092d41175c_added_version_created_with.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 27) | def downgrade():

FILE: alembic/versions/5999269aad30_added_generic_text_attribute.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/59bfe820c369_resource_efficiency.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 24) | def downgrade():

FILE: alembic/versions/6297277da38_added_vacation_class.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 25) | def downgrade():

FILE: alembic/versions/644f5251fc0d_remove_project_active_attribute.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 25) | def downgrade():

FILE: alembic/versions/745b210e6907_fix_non_existing_thumbnails.py
  function upgrade (line 15) | def upgrade():
  function downgrade (line 31) | def downgrade():

FILE: alembic/versions/856e70016b2_roles.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 64) | def downgrade():

FILE: alembic/versions/91ed52b72b82_created_variant_class.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 93) | def downgrade():

FILE: alembic/versions/92257ba439e1_budget_is_now_statusable.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 73) | def downgrade():

FILE: alembic/versions/9f9b88fef376_link_renamed_to_file.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 424) | def downgrade():

FILE: alembic/versions/a2007ad7f535_added_review_version_id_column.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 30) | def downgrade():

FILE: alembic/versions/a6598cde6b_versions_are_not_mix.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 23) | def downgrade():

FILE: alembic/versions/a9319b19f7be_added_shot_fps.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/af869ddfdf9_entity_to_note_relation_is_now_many_to_many.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 52) | def downgrade():

FILE: alembic/versions/bf67e6a234b4_added_revision_code_attribute.py
  function upgrade (line 23) | def upgrade():
  function downgrade (line 47) | def downgrade():

FILE: alembic/versions/c5607b4cfb0a_added_support_for_time_zones.py
  function upgrade (line 39) | def upgrade():
  function downgrade (line 79) | def downgrade():

FILE: alembic/versions/d8421de6a206_added_project_users_rate_column.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 22) | def downgrade():

FILE: alembic/versions/e25ec9930632_shot_sequence_relation_is_now_many_to_.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 39) | def downgrade():

FILE: alembic/versions/ea28a39ba3f5_added_invoices_table.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 42) | def downgrade():

FILE: alembic/versions/eaed49db6d9_added_position_column_to_Project_Repositories.py
  function upgrade (line 17) | def upgrade():
  function downgrade (line 31) | def downgrade():

FILE: alembic/versions/ec1eb2151bb9_rename_version_take_name_to_version_.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 23) | def downgrade():

FILE: alembic/versions/ed0167fff399_added_workinghours_table.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 43) | def downgrade():

FILE: alembic/versions/f16651477e64_added_authenticationlog_class.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 43) | def downgrade():

FILE: alembic/versions/f2005d1fbadc_added_projectclients.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 201) | def downgrade():

FILE: alembic/versions/feca9bac7d5a_renamed_osx_to_macos.py
  function upgrade (line 18) | def upgrade():
  function downgrade (line 23) | def downgrade():

FILE: docs/source/conf.py
  function setup (line 455) | def setup(app):

FILE: examples/extending/camera_lens.py
  class Camera (line 55) | class Camera(Entity):
    method __init__ (line 78) | def __init__(
  class Lens (line 99) | class Lens(Entity):
    method __init__ (line 120) | def __init__(

FILE: examples/extending/great_entity.py
  class GreatEntity (line 13) | class GreatEntity(SimpleEntity, ReferenceMixin):

FILE: examples/extending/statused_entity.py
  class NewStatusedEntity (line 11) | class NewStatusedEntity(SimpleEntity, StatusMixin):

FILE: src/stalker/config.py
  class ConfigBase (line 13) | class ConfigBase(object):
    method __init__ (line 21) | def __init__(self) -> None:
    method _parse_settings (line 26) | def _parse_settings(self) -> None:
    method __getattr__ (line 79) | def __getattr__(self, name: str) -> Any:
    method __getitem__ (line 90) | def __getitem__(self, name: str) -> Any:
    method __setitem__ (line 101) | def __setitem__(self, name: str, value: Any) -> None:
    method __delitem__ (line 110) | def __delitem__(self, name: str) -> None:
    method __contains__ (line 118) | def __contains__(self, name: str) -> bool:
  class Config (line 130) | class Config(ConfigBase):

FILE: src/stalker/db/declarative.py
  class ORMClass (line 15) | class ORMClass(object):
    method plural_class_name (line 21) | def plural_class_name(self) -> str:

FILE: src/stalker/db/session.py
  class ExtendedScopedSession (line 15) | class ExtendedScopedSession(scoped_session):
    method save (line 18) | def save(self, data: Union[None, List[Any], "SimpleEntity"] = None) ->...

FILE: src/stalker/db/setup.py
  function setup (line 42) | def setup(settings: Optional[Dict[str, Any]] = None) -> None:
  function update_defaults_with_studio (line 87) | def update_defaults_with_studio() -> None:
  function init (line 101) | def init() -> None:
  function create_repo_vars (line 198) | def create_repo_vars() -> None:
  function get_alembic_version (line 206) | def get_alembic_version() -> Union[None, str]:
  function check_alembic_version (line 226) | def check_alembic_version() -> None:
  function create_alembic_table (line 243) | def create_alembic_table() -> None:
  function __create_admin__ (line 289) | def __create_admin__() -> User:
  function create_ticket_statuses (line 348) | def create_ticket_statuses() -> None:
  function create_entity_statuses (line 394) | def create_entity_statuses(
  function register (line 474) | def register(class_: Type) -> None:

FILE: src/stalker/db/types.py
  class JSONEncodedDict (line 17) | class JSONEncodedDict(TypeDecorator):
    method process_bind_param (line 22) | def process_bind_param(self, value: Union[None, Any], dialect: "Dialec...
    method process_result_value (line 36) | def process_result_value(
  class DateTimeUTC (line 61) | class DateTimeUTC(TypeDecorator):
    method process_bind_param (line 69) | def process_bind_param(self, value: Any, dialect: str) -> datetime.dat...
    method process_result_value (line 85) | def process_result_value(self, value: Any, dialect: str) -> datetime.d...

FILE: src/stalker/exceptions.py
  class LoginError (line 8) | class LoginError(Exception):
    method __init__ (line 11) | def __init__(self, value="") -> None:
    method __str__ (line 15) | def __str__(self) -> str:
  class CircularDependencyError (line 24) | class CircularDependencyError(Exception):
    method __init__ (line 27) | def __init__(self, value="") -> None:
    method __str__ (line 31) | def __str__(self) -> str:
  class OverBookedError (line 40) | class OverBookedError(Exception):
    method __init__ (line 43) | def __init__(self, value="") -> None:
    method __str__ (line 47) | def __str__(self) -> str:
  class StatusError (line 56) | class StatusError(Exception):
    method __init__ (line 59) | def __init__(self, value="") -> None:
    method __str__ (line 63) | def __str__(self) -> str:
  class DependencyViolationError (line 72) | class DependencyViolationError(Exception):
    method __init__ (line 75) | def __init__(self, value="") -> None:
    method __str__ (line 79) | def __str__(self) -> str:

FILE: src/stalker/log.py
  function get_logger (line 16) | def get_logger(name: str) -> logging.Logger:
  function register_logger (line 30) | def register_logger(logger: logging.Logger) -> None:
  function set_level (line 52) | def set_level(level: int) -> None:

FILE: src/stalker/models/asset.py
  class Asset (line 18) | class Asset(Task, CodeMixin):
    method __init__ (line 55) | def __init__(self, code, **kwargs) -> None:
    method __eq__ (line 62) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 77) | def __hash__(self) -> int:

FILE: src/stalker/models/auth.py
  class Permission (line 40) | class Permission(Base):
    method __init__ (line 131) | def __init__(self, access: str, action: str, class_name: str) -> None:
    method __hash__ (line 137) | def __hash__(self) -> int:
    method _validate_access (line 147) | def _validate_access(self, access: str) -> str:
    method _access_getter (line 174) | def _access_getter(self) -> str:
    method _validate_class_name (line 186) | def _validate_class_name(self, class_name: str) -> str:
    method _class_name_getter (line 206) | def _class_name_getter(self) -> str:
    method _validate_action (line 218) | def _validate_action(self, action: str) -> str:
    method _action_getter (line 245) | def _action_getter(self) -> str:
    method __eq__ (line 257) | def __eq__(self, other: Any) -> bool:
  class Group (line 275) | class Group(Entity, ACLMixin):
    method __init__ (line 307) | def __init__(self, name="", users=None, permissions=None, **kwargs) ->...
    method _validate_users (line 321) | def _validate_users(self, key: str, user: "User") -> "User":
    method __hash__ (line 343) | def __hash__(self) -> int:
  class User (line 354) | class User(Entity, ACLMixin):
    method __init__ (line 563) | def __init__(
    method __repr__ (line 605) | def __repr__(self) -> str:
    method __eq__ (line 613) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 631) | def __hash__(self) -> int:
    method _validate_login (line 642) | def _validate_login(self, key: str, login: str) -> str:
    method _validate_email (line 672) | def _validate_email(self, key: str, email: str) -> str:
    method _validate_email_format (line 693) | def _validate_email_format(self, email: str) -> str:
    method _format_login (line 739) | def _format_login(cls, login: str) -> str:
    method _validate_password (line 766) | def _validate_password(self, key: str, password: str) -> str:
    method check_password (line 797) | def check_password(self, raw_password: str) -> bool:
    method _validate_groups (line 820) | def _validate_groups(self, key: str, group: Group) -> Group:
    method _validate_tasks (line 843) | def _validate_tasks(self, key: str, task: "Task") -> "Task":
    method _validate_watching (line 868) | def _validate_watching(self, key: str, task: "Task") -> "Task":
    method _validate_vacations (line 894) | def _validate_vacations(self, key: str, vacation: "Vacation") -> "Vaca...
    method _validate_efficiency (line 920) | def _validate_efficiency(
    method _validate_rate (line 957) | def _validate_rate(self, key: str, rate: Union[int, float]) -> float:
    method tickets (line 990) | def tickets(self) -> List["Ticket"]:
    method open_tickets (line 1003) | def open_tickets(self) -> List["Ticket"]:
    method to_tjp (line 1020) | def to_tjp(self) -> str:
  class LocalSession (line 1037) | class LocalSession(object):
    method __init__ (line 1046) | def __init__(self) -> None:
    method load (line 1052) | def load(self) -> None:
    method logged_in_user (line 1067) | def logged_in_user(self) -> "User":
    method store_user (line 1075) | def store_user(self, user: "User") -> None:
    method save (line 1084) | def save(self) -> None:
    method delete (line 1097) | def delete(self) -> None:
    method session_file_full_path (line 1105) | def session_file_full_path(cls) -> str:
    method _write_data (line 1117) | def _write_data(self, data: str) -> None:
  class Role (line 1138) | class Role(Entity):
    method __init__ (line 1164) | def __init__(self, **kwargs) -> None:
  function create_department_user (line 1168) | def create_department_user(department: "Department") -> "DepartmentUser":
  function create_client_user (line 1184) | def create_client_user(client: "Client") -> "ClientUser":
  function create_project_user (line 1200) | def create_project_user(project: "Project") -> "ProjectUser":
  class AuthenticationLog (line 1225) | class AuthenticationLog(SimpleEntity):
    method __init__ (line 1245) | def __init__(self, user=None, date=None, action=LOGIN, **kwargs) -> None:
    method __lt__ (line 1251) | def __lt__(self, other: "AuthenticationLog") -> bool:
    method __validate_user__ (line 1264) | def __validate_user__(self, key: str, user: "User") -> "User":
    method __validate_action__ (line 1286) | def __validate_action__(self, key: str, action: str) -> str:
    method __validate_date__ (line 1311) | def __validate_date__(self, key: str, date: datetime) -> datetime:

FILE: src/stalker/models/budget.py
  class Good (line 22) | class Good(Entity, UnitMixin):
    method __init__ (line 83) | def __init__(
    method _validate_cost (line 98) | def _validate_cost(self, key: str, cost: Union[int, float]) -> Union[i...
    method _validate_msrp (line 129) | def _validate_msrp(self, key: str, msrp: Union[int, float]) -> Union[i...
    method _validate_client (line 160) | def _validate_client(self, key: str, client: "Client") -> "Client":
  class PriceList (line 186) | class PriceList(Entity):
    method __init__ (line 212) | def __init__(
    method _validate_goods (line 223) | def _validate_goods(self, key: str, good: "Good") -> "Good":
  class Budget (line 253) | class Budget(Entity, ProjectMixin, DAGMixin, StatusMixin):
    method __init__ (line 280) | def __init__(self, **kwargs: Dict[str, Any]) -> None:
    method _validate_entry (line 287) | def _validate_entry(self, key: str, entry: "BudgetEntry") -> "BudgetEn...
  class BudgetEntry (line 309) | class BudgetEntry(Entity, AmountMixin, UnitMixin):
    method __init__ (line 361) | def __init__(
    method _validate_budget (line 387) | def _validate_budget(self, key: str, budget: "Budget") -> "Budget":
    method _validate_cost (line 408) | def _validate_cost(self, key: str, cost: Union[float, int]) -> float:
    method _validate_msrp (line 433) | def _validate_msrp(self, key: str, msrp: Union[float, int]) -> float:
    method _validate_price (line 458) | def _validate_price(self, key: str, price: Union[float, int]) -> float:
    method _validate_realized_total (line 483) | def _validate_realized_total(
    method _validate_good (line 511) | def _validate_good(self, key: str, good: "Good") -> "Good":
  class Invoice (line 534) | class Invoice(Entity, AmountMixin, UnitMixin):
    method __init__ (line 576) | def __init__(
    method _validate_budget (line 591) | def _validate_budget(self, key: str, budget: "Budget") -> "Budget":
    method _validate_client (line 612) | def _validate_client(self, key: str, client: "Client") -> "Client":
  class Payment (line 637) | class Payment(Entity, AmountMixin, UnitMixin):
    method __init__ (line 664) | def __init__(
    method _validate_invoice (line 677) | def _validate_invoice(self, key: str, invoice: "Invoice") -> "Invoice":

FILE: src/stalker/models/client.py
  class Client (line 23) | class Client(Entity):
    method __init__ (line 95) | def __init__(
    method __eq__ (line 112) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 124) | def __hash__(self) -> int:
    method to_tjp (line 135) | def to_tjp(self) -> str:
    method _validate_good (line 144) | def _validate_good(self, key: str, good: "Good") -> "Good":
  class ClientUser (line 170) | class ClientUser(Base):
    method __init__ (line 198) | def __init__(self, client=None, user=None, role=None):
    method _validate_client (line 204) | def _validate_client(self, key: str, client: "Client") -> "Client":
    method _validate_user (line 227) | def _validate_user(self, key: str, user: "User") -> "User":
    method _validate_role (line 253) | def _validate_role(self, key: str, role: "Role") -> "Role":

FILE: src/stalker/models/department.py
  class Department (line 18) | class Department(Entity):
    method __init__ (line 57) | def __init__(
    method __eq__ (line 67) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 79) | def __hash__(self) -> int:
    method _validate_user_role (line 90) | def _validate_user_role(
    method to_tjp (line 105) | def to_tjp(self) -> str:
  class DepartmentUser (line 122) | class DepartmentUser(Base):
    method __init__ (line 148) | def __init__(self, department=None, user=None, role=None):
    method _validate_department (line 154) | def _validate_department(
    method _validate_user (line 180) | def _validate_user(
    method _validate_role (line 206) | def _validate_role(self, key: str, role: Union[None, Role]) -> Union[N...

FILE: src/stalker/models/entity.py
  class SimpleEntity (line 29) | class SimpleEntity(Base):
    method __init__ (line 222) | def __init__(
    method __repr__ (line 263) | def __repr__(self) -> str:
    method __eq__ (line 271) | def __eq__(self, other: Any) -> bool:
    method __ne__ (line 285) | def __ne__(self, other: Any) -> bool:
    method __hash__ (line 298) | def __hash__(self) -> int:
    method _validate_description (line 309) | def _validate_description(self, key: str, description: str) -> str:
    method _validate_generic_text (line 334) | def _validate_generic_text(self, key: str, generic_text: str) -> str:
    method _validate_name (line 361) | def _validate_name(self, key: str, name: str) -> str:
    method _format_name (line 407) | def _format_name(cls, name: str) -> str:
    method _format_nice_name (line 425) | def _format_nice_name(cls, nice_name: str) -> str:
    method nice_name (line 457) | def nice_name(self) -> str:
    method _validate_created_by (line 474) | def _validate_created_by(
    method _validate_updated_by (line 502) | def _validate_updated_by(
    method _validate_date_created (line 534) | def _validate_date_created(self, key: str, date_created: datetime) -> ...
    method _validate_date_updated (line 561) | def _validate_date_updated(self, key: str, date_updated: datetime) -> ...
    method _validate_type (line 598) | def _validate_type(self, key: str, type_: "Type") -> "Type":
    method _validate_thumbnail (line 624) | def _validate_thumbnail(self, key: str, thumb: "File") -> "File":
    method tjp_id (line 650) | def tjp_id(self) -> str:
    method to_tjp (line 659) | def to_tjp(self) -> str:
    method _validate_html_style (line 672) | def _validate_html_style(self, key: str, html_style: str) -> str:
    method _validate_html_class (line 696) | def _validate_html_class(self, key: str, html_class: str) -> str:
  class Entity (line 720) | class Entity(SimpleEntity):
    method __init__ (line 766) | def __init__(
    method _validate_notes (line 781) | def _validate_notes(self, key: str, note: "Note") -> "Note":
    method _validate_tags (line 804) | def _validate_tags(self, key: str, tag: "Tag") -> "Tag":
    method __eq__ (line 826) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 838) | def __hash__(self) -> int:
  class EntityGroup (line 849) | class EntityGroup(Entity):
    method __init__ (line 872) | def __init__(
    method _validate_entities (line 885) | def _validate_entities(self, key: str, entity: SimpleEntity) -> Simple...
    method __eq__ (line 906) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 922) | def __hash__(self) -> int:

FILE: src/stalker/models/enum.py
  class ScheduleConstraint (line 10) | class ScheduleConstraint(IntEnum):
    method __repr__ (line 18) | def __repr__(self) -> str:
    method to_constraint (line 30) | def to_constraint(
  class ScheduleConstraintDecorator (line 79) | class ScheduleConstraintDecorator(TypeDecorator):
    method process_bind_param (line 85) | def process_bind_param(self, value, dialect) -> int:
    method process_result_value (line 98) | def process_result_value(self, value: int, dialect: str) -> ScheduleCo...
  class TimeUnit (line 111) | class TimeUnit(Enum):
    method __str__ (line 121) | def __str__(self) -> str:
    method to_unit (line 130) | def to_unit(cls, unit: Union[str, "TimeUnit"]) -> "TimeUnit":
  class TimeUnitDecorator (line 170) | class TimeUnitDecorator(TypeDecorator):
    method process_bind_param (line 176) | def process_bind_param(self, value: TimeUnit, dialect: str) -> str:
    method process_result_value (line 189) | def process_result_value(self, value: str, dialect: str) -> TimeUnit:
  class ScheduleModel (line 202) | class ScheduleModel(Enum):
    method __str__ (line 209) | def __str__(self) -> str:
    method to_model (line 218) | def to_model(cls, model: Union[str, "ScheduleModel"]) -> "ScheduleModel":
  class ScheduleModelDecorator (line 258) | class ScheduleModelDecorator(TypeDecorator):
    method process_bind_param (line 264) | def process_bind_param(self, value, dialect) -> str:
    method process_result_value (line 277) | def process_result_value(self, value: str, dialect: str) -> ScheduleMo...
  class DependencyTarget (line 290) | class DependencyTarget(Enum):
    method __str__ (line 296) | def __str__(self) -> str:
    method to_target (line 305) | def to_target(cls, target: Union[str, "DependencyTarget"]) -> "Depende...
  class DependencyTargetDecorator (line 345) | class DependencyTargetDecorator(TypeDecorator):
    method process_bind_param (line 351) | def process_bind_param(self, value, dialect) -> str:
    method process_result_value (line 364) | def process_result_value(self, value: str, dialect: str) -> Dependency...
  class TraversalDirection (line 377) | class TraversalDirection(IntEnum):
    method __repr__ (line 383) | def __repr__(self) -> str:
    method to_direction (line 395) | def to_direction(

FILE: src/stalker/models/file.py
  class File (line 20) | class File(Entity, ReferenceMixin):
    method __init__ (line 86) | def __init__(
    method _validate_full_path (line 101) | def _validate_full_path(self, key: str, full_path: Union[None, str]) -...
    method _validate_created_with (line 126) | def _validate_created_with(
    method _validate_original_filename (line 154) | def _validate_original_filename(
    method _format_path (line 185) | def _format_path(path: Union[bytes, str]) -> str:
    method path (line 202) | def path(self) -> str:
    method path (line 211) | def path(self, path: str) -> None:
    method filename (line 238) | def filename(self) -> str:
    method filename (line 247) | def filename(self, filename: Union[None, str]) -> None:
    method extension (line 268) | def extension(self) -> str:
    method extension (line 277) | def extension(self, extension: Union[None, str]) -> None:
    method absolute_full_path (line 302) | def absolute_full_path(self) -> str:
    method absolute_path (line 311) | def absolute_path(self) -> str:
    method walk_references (line 319) | def walk_references(
    method __eq__ (line 335) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 352) | def __hash__(self) -> int:

FILE: src/stalker/models/format.py
  class ImageFormat (line 14) | class ImageFormat(Entity):
    method __init__ (line 81) | def __init__(
    method _validate_width (line 98) | def _validate_width(self, key: str, width: Union[int, float]) -> int:
    method _validate_height (line 126) | def _validate_height(self, key: str, height: Union[int, float]) -> int:
    method _validate_pixel_aspect (line 154) | def _validate_pixel_aspect(
    method _validate_print_resolution (line 185) | def _validate_print_resolution(
    method device_aspect (line 217) | def device_aspect(self) -> float:
    method __eq__ (line 228) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 246) | def __hash__(self) -> int:

FILE: src/stalker/models/message.py
  class Message (line 15) | class Message(Entity, StatusMixin):
    method __init__ (line 42) | def __init__(self, **kwargs: Dict[str, Any]) -> None:

FILE: src/stalker/models/mixins.py
  function create_secondary_table (line 68) | def create_secondary_table(
  class TargetEntityTypeMixin (line 193) | class TargetEntityTypeMixin(object):
    method _target_entity_type (line 231) | def _target_entity_type(cls) -> Mapped[str]:
    method __init__ (line 244) | def __init__(self, target_entity_type: Optional[str] = None, **kwargs)...
    method _validate_target_entity_type (line 247) | def _validate_target_entity_type(self, target_entity_type: Union[str, ...
    method _target_entity_type_getter (line 278) | def _target_entity_type_getter(self) -> str:
    method target_entity_type (line 287) | def target_entity_type(cls) -> Mapped[str]:
  class StatusMixin (line 305) | class StatusMixin(object):
    method __init__ (line 346) | def __init__(
    method status_id (line 356) | def status_id(cls) -> Mapped[int]:
    method status (line 376) | def status(cls) -> Mapped["Status"]:
    method status_list_id (line 394) | def status_list_id(cls) -> Mapped[int]:
    method status_list (line 405) | def status_list(cls) -> Mapped["StatusList"]:
    method _validate_status_list (line 417) | def _validate_status_list(
    method _validate_status (line 486) | def _validate_status(self, key: str, status: "Status") -> "Status":
  class DateRangeMixin (line 544) | class DateRangeMixin(object):
    method __init__ (line 626) | def __init__(
    method _end (line 638) | def _end(cls) -> Mapped[Optional[datetime.datetime]]:
    method _end_getter (line 641) | def _end_getter(self) -> datetime.datetime:
    method _end_setter (line 655) | def _end_setter(self, end: datetime.datetime) -> None:
    method end (line 666) | def end(cls) -> Mapped[Optional[datetime.datetime]]:
    method _start (line 675) | def _start(cls) -> Mapped[Optional[datetime.datetime]]:
    method _start_getter (line 683) | def _start_getter(self) -> datetime.datetime:
    method _start_setter (line 699) | def _start_setter(self, start: datetime.datetime) -> None:
    method start (line 710) | def start(cls) -> Mapped[Optional[datetime.datetime]]:
    method _duration (line 725) | def _duration(cls) -> Mapped[Optional[datetime.timedelta]]:
    method _duration_getter (line 733) | def _duration_getter(self) -> datetime.timedelta:
    method _duration_setter (line 742) | def _duration_setter(self, duration: datetime.timedelta) -> None:
    method duration (line 766) | def duration(self) -> Mapped[Optional[datetime.timedelta]]:
    method _validate_dates (line 785) | def _validate_dates(
    method computed_start (line 864) | def computed_start(cls) -> Mapped[Optional[datetime.datetime]]:
    method computed_end (line 873) | def computed_end(cls) -> Mapped[Optional[datetime.datetime]]:
    method computed_duration (line 882) | def computed_duration(self) -> datetime.timedelta:
    method round_time (line 901) | def round_time(cls, dt: datetime.datetime) -> datetime.datetime:
    method total_seconds (line 932) | def total_seconds(self) -> float:
    method computed_total_seconds (line 941) | def computed_total_seconds(self) -> float:
  class ProjectMixin (line 950) | class ProjectMixin(object):
    method project_id (line 969) | def project_id(cls) -> Mapped[Optional[int]]:
    method project (line 985) | def project(cls) -> Mapped[Optional["Project"]]:
    method __init__ (line 1003) | def __init__(
    method _validate_project (line 1009) | def _validate_project(self, key: str, project: "Project") -> "Project":
  class ReferenceMixin (line 1039) | class ReferenceMixin(object):
    method __init__ (line 1054) | def __init__(
    method references (line 1063) | def references(cls) -> Mapped[Optional[List["File"]]]:
    method _validate_references (line 1094) | def _validate_references(self, key: str, reference: "File") -> "File":
  class ACLMixin (line 1119) | class ACLMixin(object):
    method permissions (line 1131) | def permissions(cls) -> Mapped[List["Permission"]]:
    method _validate_permissions (line 1144) | def _validate_permissions(self, key: str, permission: "Permission") ->...
    method __acl__ (line 1169) | def __acl__(self) -> List[Tuple[str, str, str]]:
  class CodeMixin (line 1200) | class CodeMixin(object):
    method __init__ (line 1219) | def __init__(
    method code (line 1228) | def code(cls) -> Mapped[str]:
    method _validate_code (line 1244) | def _validate_code(self, key: str, code: str) -> str:
  class WorkingHoursMixin (line 1276) | class WorkingHoursMixin(object):
    method __init__ (line 1286) | def __init__(
    method working_hours_id (line 1292) | def working_hours_id(cls) -> Mapped[Optional[int]]:
    method working_hours (line 1301) | def working_hours(cls) -> Mapped[Optional["WorkingHours"]]:
    method _validate_working_hours (line 1314) | def _validate_working_hours(
  class ScheduleMixin (line 1344) | class ScheduleMixin(object):
    method __init__ (line 1360) | def __init__(
    method schedule_timing (line 1374) | def schedule_timing(cls) -> Mapped[Optional[float]]:
    method schedule_unit (line 1398) | def schedule_unit(cls) -> Mapped[Optional[TimeUnit]]:
    method schedule_model (line 1414) | def schedule_model(cls) -> Mapped[ScheduleModel]:
    method schedule_constraint (line 1465) | def schedule_constraint(cls) -> Mapped[ScheduleConstraint]:
    method _validate_schedule_constraint (line 1503) | def _validate_schedule_constraint(
    method _validate_schedule_model (line 1526) | def _validate_schedule_model(
    method _validate_schedule_unit (line 1547) | def _validate_schedule_unit(
    method _validate_schedule_timing (line 1568) | def _validate_schedule_timing(
    method least_meaningful_time_unit (line 1605) | def least_meaningful_time_unit(
    method to_seconds (line 1681) | def to_seconds(
    method to_unit (line 1737) | def to_unit(
    method schedule_seconds (line 1798) | def schedule_seconds(self) -> float:
  class DAGMixin (line 1814) | class DAGMixin(object):
    method parent_id (line 1836) | def parent_id(cls) -> Mapped[Optional[int]]:
    method parent (line 1847) | def parent(cls) -> Mapped[Self]:
    method children (line 1867) | def children(cls) -> Mapped[List[Self]]:
    method __init__ (line 1885) | def __init__(self, parent: Optional[Self] = None, **kwargs: Dict[str, ...
    method _validate_parent (line 1889) | def _validate_parent(
    method _validate_children (line 1922) | def _validate_children(self, key: str, child: Self) -> Self:
    method is_root (line 1949) | def is_root(self) -> bool:
    method is_container (line 1958) | def is_container(self) -> bool:
    method is_leaf (line 1968) | def is_leaf(self) -> bool:
    method parents (line 1977) | def parents(self) -> List[Self]:
    method walk_hierarchy (line 1992) | def walk_hierarchy(
  class AmountMixin (line 2010) | class AmountMixin(object):
    method __init__ (line 2017) | def __init__(self, amount: Union[int, float] = 0, **kwargs: Dict[str, ...
    method amount (line 2021) | def amount(cls) -> Mapped[Optional[float]]:
    method _validate_amount (line 2030) | def _validate_amount(self, key: str, amount: Union[int, float]) -> float:
  class UnitMixin (line 2055) | class UnitMixin(object):
    method __init__ (line 2062) | def __init__(self, unit: str = "", **kwargs: Dict[str, Any]) -> None:
    method unit (line 2066) | def unit(cls) -> Mapped[Optional[str]]:
    method _validate_unit (line 2075) | def _validate_unit(self, key: str, unit: Union[None, str]) -> str:

FILE: src/stalker/models/note.py
  class Note (line 14) | class Note(SimpleEntity):
    method __init__ (line 43) | def __init__(self, content: str = "", **kwargs: Dict[str, Any]) -> None:
    method __eq__ (line 47) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 62) | def __hash__(self) -> int:

FILE: src/stalker/models/project.py
  class ProjectRepository (line 33) | class ProjectRepository(Base):
    method __init__ (line 59) | def __init__(
    method _validate_project (line 70) | def _validate_project(self, key: str, project: "Project") -> "Project":
    method _validate_repository (line 85) | def _validate_repository(
  class Project (line 115) | class Project(Entity, ReferenceMixin, StatusMixin, DateRangeMixin, CodeM...
    method __init__ (line 306) | def __init__(
    method __eq__ (line 353) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 364) | def __hash__(self) -> int:
    method _validate_fps (line 375) | def _validate_fps(self, key: str, fps: Union[int, float]) -> float:
    method _validate_image_format (line 404) | def _validate_image_format(
    method _validate_structure (line 431) | def _validate_structure(
    method _validate_is_stereoscopic (line 460) | def _validate_is_stereoscopic(
    method root_tasks (line 477) | def root_tasks(self) -> List["Task"]:
    method assets (line 495) | def assets(self) -> List["Asset"]:
    method sequences (line 509) | def sequences(self) -> List["Sequence"]:
    method shots (line 521) | def shots(self) -> List["Shot"]:
    method to_tjp (line 533) | def to_tjp(self) -> str:
    method is_active (line 550) | def is_active(self) -> bool:
    method total_logged_seconds (line 563) | def total_logged_seconds(self) -> int:
    method schedule_seconds (line 576) | def schedule_seconds(self) -> int:
    method percent_complete (line 589) | def percent_complete(self) -> float:
    method open_tickets (line 606) | def open_tickets(self) -> List["Ticket"]:
    method repository (line 623) | def repository(self) -> "Repository":
  class ProjectUser (line 637) | class ProjectUser(Base):
    method __init__ (line 668) | def __init__(
    method _validate_user (line 683) | def _validate_user(
    method _validate_project (line 719) | def _validate_project(
    method _validate_role (line 745) | def _validate_role(self, key: str, role: Union[None, "Role"]):
  class ProjectClient (line 773) | class ProjectClient(Base):
    method __init__ (line 809) | def __init__(
    method _validate_client (line 820) | def _validate_client(
    method _validate_project (line 852) | def _validate_project(
    method _validate_role (line 881) | def _validate_role(
  function create_project_client (line 913) | def create_project_client(project: Project) -> ProjectClient:

FILE: src/stalker/models/repository.py
  class Repository (line 22) | class Repository(Entity, CodeMixin):
    method __init__ (line 94) | def __init__(
    method _validate_linux_path (line 111) | def _validate_linux_path(self, key: str, linux_path: str) -> str:
    method _validate_macos_path (line 143) | def _validate_macos_path(self, key: str, macos_path: str) -> str:
    method _validate_windows_path (line 172) | def _validate_windows_path(self, key: str, windows_path: str) -> str:
    method path (line 206) | def path(self) -> str:
    method path (line 223) | def path(self, path: str) -> None:
    method is_in_repo (line 239) | def is_in_repo(self, path: str) -> bool:
    method _to_path (line 255) | def _to_path(self, path: str, replace_with: str) -> str:
    method to_linux_path (line 294) | def to_linux_path(self, path: str) -> str:
    method to_windows_path (line 305) | def to_windows_path(self, path: str) -> str:
    method to_macos_path (line 316) | def to_macos_path(self, path: str) -> str:
    method to_native_path (line 327) | def to_native_path(self, path: str) -> str:
    method make_relative (line 338) | def make_relative(self, path: str) -> str:
    method find_repo (line 351) | def find_repo(cls, path: str) -> "Repository":
    method to_os_independent_path (line 384) | def to_os_independent_path(cls, path: str) -> str:
    method env_var (line 406) | def env_var(self) -> str:
    method __eq__ (line 414) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 433) | def __hash__(self) -> int:
  function receive_after_insert (line 445) | def receive_after_insert(

FILE: src/stalker/models/review.py
  class Review (line 32) | class Review(SimpleEntity, ScheduleMixin, StatusMixin):
    method __init__ (line 135) | def __init__(
    method _validate_task (line 161) | def _validate_task(
    method _validate_version (line 201) | def _validate_version(
    method _validate_reviewer (line 240) | def _validate_reviewer(self, key: str, reviewer: "User") -> "User":
    method _review_number_getter (line 263) | def _review_number_getter(self) -> int:
    method review_set (line 278) | def review_set(self) -> List["Review"]:
    method is_finalized (line 297) | def is_finalized(self) -> bool:
    method request_revision (line 306) | def request_revision(
    method approve (line 336) | def approve(self):
    method finalize_review_set (line 346) | def finalize_review_set(self) -> None:
  class Daily (line 414) | class Daily(Entity, StatusMixin, ProjectMixin):
    method __init__ (line 448) | def __init__(
    method versions (line 463) | def versions(self) -> List["Version"]:
    method tasks (line 481) | def tasks(self) -> List["Task"]:
  class DailyFile (line 501) | class DailyFile(Base):
    method __init__ (line 541) | def __init__(
    method _validate_file (line 551) | def _validate_file(self, key: str, file: Union[None, File]) -> Union[N...
    method _validate_daily (line 576) | def _validate_daily(

FILE: src/stalker/models/scene.py
  class Scene (line 19) | class Scene(Task, CodeMixin):
    method __init__ (line 51) | def __init__(self, shots: Optional[List["Shot"]] = None, **kwargs: Dic...
    method _validate_shots (line 63) | def _validate_shots(self, key: str, shot: "Shot") -> "Shot":
    method __eq__ (line 86) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 97) | def __hash__(self) -> int:

FILE: src/stalker/models/schedulers.py
  class SchedulerBase (line 32) | class SchedulerBase(object):
    method __init__ (line 38) | def __init__(self, studio: Optional["Studio"] = None) -> None:
    method _validate_studio (line 42) | def _validate_studio(self, studio: Union[None, "Studio"]) -> Union[Non...
    method studio (line 67) | def studio(self) -> Union[None, "Studio"]:
    method studio (line 76) | def studio(self, studio: Union[None, "Studio"]) -> None:
    method schedule (line 84) | def schedule(self) -> None:
  class TaskJugglerScheduler (line 93) | class TaskJugglerScheduler(SchedulerBase):
    method __init__ (line 190) | def __init__(
    method _create_tjp_file (line 217) | def _create_tjp_file(self) -> None:
    method _create_tjp_file_content (line 225) | def _create_tjp_file_content(self) -> None:  # noqa: C901
    method _fill_tjp_file (line 525) | def _fill_tjp_file(self) -> None:
    method _delete_tjp_file (line 530) | def _delete_tjp_file(self) -> None:
    method _delete_csv_file (line 537) | def _delete_csv_file(self) -> None:
    method _clean_up (line 544) | def _clean_up(self) -> None:
    method _parse_csv_file (line 549) | def _parse_csv_file(self) -> None:
    method schedule (line 646) | def schedule(self) -> str:
    method _validate_projects (line 731) | def _validate_projects(self, projects: List[Project]) -> List[Project]:
    method projects (line 775) | def projects(self) -> List[Project]:
    method projects (line 784) | def projects(self, projects: List[Project]) -> None:

FILE: src/stalker/models/sequence.py
  class Sequence (line 19) | class Sequence(Task, CodeMixin):
    method __init__ (line 53) | def __init__(self, **kwargs: Dict[str, Any]) -> None:
    method _validate_shots (line 62) | def _validate_shots(self, key: str, shot: "Shot") -> "Shot":
    method __eq__ (line 85) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 97) | def __hash__(self) -> int:

FILE: src/stalker/models/shot.py
  class Shot (line 31) | class Shot(Task, CodeMixin):
    method __init__ (line 241) | def __init__(
    method __init_on_load__ (line 299) | def __init_on_load__(self) -> None:
    method __repr__ (line 304) | def __repr__(self) -> str:
    method __eq__ (line 312) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 328) | def __hash__(self) -> int:
    method _check_code_availability (line 339) | def _check_code_availability(cls, code: str, project: "Project") -> bool:
    method _fps_getter (line 387) | def _fps_getter(self) -> float:
    method _fps_setter (line 398) | def _fps_setter(self, fps: float) -> None:
    method _validate_fps (line 412) | def _validate_fps(self, fps: Union[int, float]) -> float:
    method _validate_cut_in (line 447) | def _validate_cut_in(self, key: str, cut_in: int) -> int:
    method _validate_cut_out (line 476) | def _validate_cut_out(self, key: str, cut_out: int) -> int:
    method _validate_source_in (line 508) | def _validate_source_in(self, key: str, source_in: int) -> int:
    method _validate_source_out (line 569) | def _validate_source_out(self, key: str, source_out: int) -> int:
    method cut_duration (line 636) | def cut_duration(self) -> int:
    method cut_duration (line 645) | def cut_duration(self, cut_duration: int) -> None:
    method _validate_sequence (line 672) | def _validate_sequence(self, key: str, sequence: "Sequence") -> "Seque...
    method _validate_scene (line 696) | def _validate_scene(self, key: str, scene: "Scene") -> "Scene":
    method _image_format_getter (line 719) | def _image_format_getter(self) -> ImageFormat:
    method _image_format_setter (line 731) | def _image_format_setter(self, imf: ImageFormat) -> None:
    method _validate_image_format (line 747) | def _validate_image_format(
    method _validate_code (line 776) | def _validate_code(self, key: str, code: str) -> str:

FILE: src/stalker/models/status.py
  class Status (line 17) | class Status(Entity, CodeMixin):
    method __init__ (line 55) | def __init__(
    method __eq__ (line 67) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 84) | def __hash__(self) -> int:
  class StatusList (line 95) | class StatusList(Entity, TargetEntityTypeMixin):
    method __init__ (line 187) | def __init__(
    method _validate_statuses (line 201) | def _validate_statuses(self, key: str, status: Status) -> Status:
    method __eq__ (line 222) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 239) | def __hash__(self) -> int:
    method __getitem__ (line 249) | def __getitem__(self, key: int) -> Status:
    method __setitem__ (line 270) | def __setitem__(self, key: int, value: Status) -> None:
    method __delitem__ (line 279) | def __delitem__(self, key: int) -> None:
    method __len__ (line 287) | def __len__(self) -> int:

FILE: src/stalker/models/structure.py
  class Structure (line 16) | class Structure(Entity):
    method __init__ (line 121) | def __init__(
    method __eq__ (line 135) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 152) | def __hash__(self) -> int:
    method _validate_custom_template (line 163) | def _validate_custom_template(
    method _validate_templates (line 193) | def _validate_templates(

FILE: src/stalker/models/studio.py
  class Studio (line 37) | class Studio(Entity, DateRangeMixin, WorkingHoursMixin):
    method __init__ (line 147) | def __init__(
    method daily_working_hours (line 167) | def daily_working_hours(self) -> int:
    method daily_working_hours (line 176) | def daily_working_hours(self, daily_working_hours: int) -> None:
    method update_defaults (line 184) | def update_defaults(self) -> None:
    method __init_on_load__ (line 240) | def __init_on_load__(self) -> None:
    method _validate_now (line 244) | def _validate_now(self, now: datetime.datetime) -> datetime.datetime:
    method now (line 272) | def now(self) -> datetime.datetime:
    method now (line 284) | def now(self, now: datetime.datetime) -> None:
    method _validate_scheduler (line 294) | def _validate_scheduler(
    method scheduler (line 321) | def scheduler(self) -> Union[None, SchedulerBase]:
    method scheduler (line 330) | def scheduler(self, scheduler: Union[None, SchedulerBase]):
    method to_tjp (line 340) | def to_tjp(self) -> str:
    method projects (line 379) | def projects(self) -> List[Project]:
    method active_projects (line 388) | def active_projects(self) -> List[Project]:
    method inactive_projects (line 399) | def inactive_projects(self) -> List[Project]:
    method departments (line 410) | def departments(self) -> List[Department]:
    method users (line 419) | def users(self) -> List[User]:
    method vacations (line 428) | def vacations(self) -> List["Vacation"]:
    method schedule (line 436) | def schedule(self, scheduled_by: Optional[User] = None) -> str:
    method weekly_working_hours (line 498) | def weekly_working_hours(self) -> int:
    method weekly_working_days (line 508) | def weekly_working_days(self) -> int:
    method yearly_working_days (line 518) | def yearly_working_days(self) -> int:
    method to_unit (line 527) | def to_unit(
    method _timing_resolution_getter (line 550) | def _timing_resolution_getter(self) -> datetime.timedelta:
    method _timing_resolution_setter (line 558) | def _timing_resolution_setter(self, timing_resolution: datetime.timede...
    method _validate_timing_resolution (line 587) | def _validate_timing_resolution(
  class WorkingHours (line 619) | class WorkingHours(Entity):
    method __init__ (line 692) | def __init__(
    method __eq__ (line 704) | def __eq__(self, other: Any) -> bool:
    method __getitem__ (line 719) | def __getitem__(self, index: Union[int, str]) -> Optional[List]:
    method __setitem__ (line 738) | def __setitem__(self, key: Union[int, str], value: List[List]) -> None:
    method _validate_working_hours (line 763) | def _validate_working_hours(self, key: str, working_hours: Dict[str, L...
    method is_working_hour (line 810) | def is_working_hour(self, check_for_date: datetime.datetime) -> bool:
    method _validate_working_hours_value (line 840) | def _validate_working_hours_value(self, value: List) -> List:
    method to_tjp (line 902) | def to_tjp(self) -> str:
    method weekly_working_hours (line 927) | def weekly_working_hours(self) -> int:
    method weekly_working_days (line 940) | def weekly_working_days(self) -> int:
    method yearly_working_days (line 953) | def yearly_working_days(self) -> int:
    method _validate_daily_working_hours (line 962) | def _validate_daily_working_hours(self, key: str, daily_working_hours:...
    method split_in_to_working_hours (line 996) | def split_in_to_working_hours(
  class Vacation (line 1011) | class Vacation(SimpleEntity, DateRangeMixin):
    method __init__ (line 1048) | def __init__(
    method _validate_user (line 1062) | def _validate_user(self, key: str, user: User) -> User:
    method to_tjp (line 1086) | def to_tjp(self) -> str:

FILE: src/stalker/models/tag.py
  class Tag (line 14) | class Tag(SimpleEntity):
    method __init__ (line 28) | def __init__(self, **kwargs: Dict[str, Any]) -> None:
    method __eq__ (line 31) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 43) | def __hash__(self) -> int:

FILE: src/stalker/models/task.py
  class TimeLog (line 135) | class TimeLog(Entity, DateRangeMixin):
    method __init__ (line 204) | def __init__(
    method _validate_task (line 222) | def _validate_task(self, key: str, task: "Task") -> "Task":
    method _validate_resource (line 312) | def _validate_resource(self, key: str, resource: User) -> User:
    method __eq__ (line 384) | def __eq__(self, other: Any) -> bool:
  class Task (line 410) | class Task(
    method __init__ (line 1152) | def __init__(
    method __init_on_load__ (line 1256) | def __init_on_load__(self) -> None:
    method __eq__ (line 1261) | def __eq__(self, other: Any) -> None:
    method __hash__ (line 1282) | def __hash__(self) -> int:
    method _validate_time_logs (line 1293) | def _validate_time_logs(self, key: str, time_log: TimeLog) -> TimeLog:
    method _validate_reviews (line 1323) | def _validate_reviews(self, key: str, review: Review) -> Review:
    method _validate_task_depends_on (line 1347) | def _validate_task_depends_on(self, key: str, task_depends_on: "Task")...
    method _validate_schedule_timing (line 1437) | def _validate_schedule_timing(
    method _validate_schedule_unit (line 1460) | def _validate_schedule_unit(
    method _reschedule (line 1480) | def _reschedule(
    method _validate_is_milestone (line 1531) | def _validate_is_milestone(self, key: str, is_milestone: Union[None, b...
    method _validate_parent (line 1563) | def _validate_parent(self, key: str, parent: "Task") -> "Task":
    method _validate_project (line 1611) | def _validate_project(self, key: str, project: "Project") -> "Project":
    method _validate_priority (line 1687) | def _validate_priority(self, key: str, priority: Union[int, float]) ->...
    method _validate_children (line 1723) | def _validate_children(self, key: str, child: "Task") -> "Task":
    method _validate_resources (line 1763) | def _validate_resources(self, key: str, resource: User) -> User:
    method _validate_alternative_resources (line 1789) | def _validate_alternative_resources(self, key: str, resource: User) ->...
    method _validate_computed_resources (line 1815) | def _validate_computed_resources(self, key: str, resource: User) -> User:
    method _computed_resources_getter (line 1838) | def _computed_resources_getter(self):
    method _computed_resources_setter (line 1849) | def _computed_resources_setter(self, resources: List[User]) -> None:
    method _validate_allocation_strategy (line 1864) | def _validate_allocation_strategy(self, key: str, strategy: str) -> str:
    method _validate_persistent_allocation (line 1906) | def _validate_persistent_allocation(
    method _validate_watchers (line 1927) | def _validate_watchers(self, key: str, watcher: User) -> User:
    method _validate_versions (line 1953) | def _validate_versions(self, key: str, version: "Version"):
    method _validate_bid_timing (line 1983) | def _validate_bid_timing(
    method _validate_bid_unit (line 2012) | def _validate_bid_unit(self, key: str, bid_unit: Union[str, TimeUnit])...
    method _expand_dates (line 2033) | def _expand_dates(
    method _validate_computed_start (line 2052) | def _validate_computed_start(
    method _validate_computed_end (line 2069) | def _validate_computed_end(
    method _start_getter (line 2085) | def _start_getter(self) -> datetime.datetime:
    method _start_setter (line 2093) | def _start_setter(self, start: datetime.datetime) -> None:
    method _end_getter (line 2104) | def _end_getter(self) -> datetime.datetime:
    method _end_setter (line 2112) | def _end_setter(self, end: datetime.datetime) -> None:
    method _project_getter (line 2124) | def _project_getter(self) -> "Project":
    method tjp_abs_id (line 2144) | def tjp_abs_id(self) -> str:
    method to_tjp (line 2154) | def to_tjp(self) -> str:
    method level (line 2219) | def level(self) -> int:
    method is_scheduled (line 2236) | def is_scheduled(self) -> bool:
    method _total_logged_seconds_getter (line 2245) | def _total_logged_seconds_getter(self) -> int:
    method _total_logged_seconds_setter (line 2316) | def _total_logged_seconds_setter(self, seconds: int) -> None:
    method _schedule_seconds_getter (line 2341) | def _schedule_seconds_getter(self) -> int:
    method _schedule_seconds_setter (line 2359) | def _schedule_seconds_setter(self, seconds: int) -> None:
    method update_schedule_info (line 2385) | def update_schedule_info(self) -> None:
    method percent_complete (line 2419) | def percent_complete(self) -> float:
    method remaining_seconds (line 2438) | def remaining_seconds(self) -> int:
    method _responsible_getter (line 2447) | def _responsible_getter(self) -> List[User]:
    method _responsible_setter (line 2465) | def _responsible_setter(self, responsible: List[User]) -> None:
    method _validate_responsible (line 2475) | def _validate_responsible(self, key, responsible: User) -> User:
    method tickets (line 2516) | def tickets(self) -> List[Ticket]:
    method open_tickets (line 2526) | def open_tickets(self) -> List[Ticket]:
    method walk_dependencies (line 2540) | def walk_dependencies(
    method _validate_good (line 2558) | def _validate_good(self, key: str, good: Good) -> Good:
    method create_time_log (line 2583) | def create_time_log(
    method request_review (line 2604) | def request_review(self, version: Optional["Version"] = None) -> List[...
    method request_revision (line 2653) | def request_revision(
    method hold (line 2736) | def hold(self) -> None:
    method stop (line 2766) | def stop(self) -> None:
    method resume (line 2817) | def resume(self) -> None:
    method review_set (line 2850) | def review_set(self, review_number: Union[None, int] = None) -> List[R...
    method update_status_with_dependent_statuses (line 2896) | def update_status_with_dependent_statuses(
    method update_parent_statuses (line 3033) | def update_parent_statuses(self) -> None:
    method update_status_with_children_statuses (line 3040) | def update_status_with_children_statuses(self) -> None:
    method _review_number_getter (line 3083) | def _review_number_getter(self) -> None:
    method _template_variables (line 3097) | def _template_variables(self) -> dict:
    method path (line 3144) | def path(self) -> str:
    method absolute_path (line 3190) | def absolute_path(self) -> str:
  class TaskDependency (line 3204) | class TaskDependency(Base, ScheduleMixin):
    method __init__ (line 3275) | def __init__(
    method _validate_task (line 3296) | def _validate_task(self, key: str, task: Task) -> Task:
    method _validate_depends_on (line 3321) | def _validate_depends_on(self, key: str, dependency: Task) -> Task:
    method _validate_dependency_target (line 3346) | def _validate_dependency_target(
    method to_tjp (line 3369) | def to_tjp(self) -> str:
  function update_time_log_task_parents_for_start (line 3431) | def update_time_log_task_parents_for_start(
  function update_time_log_task_parents_for_end (line 3455) | def update_time_log_task_parents_for_end(
  function __update_total_logged_seconds__ (line 3482) | def __update_total_logged_seconds__(
  function update_parents_schedule_seconds_with_schedule_timing (line 3521) | def update_parents_schedule_seconds_with_schedule_timing(
  function update_parents_schedule_seconds_with_schedule_unit (line 3556) | def update_parents_schedule_seconds_with_schedule_unit(
  function update_task_date_values (line 3598) | def update_task_date_values(
  function removed_a_dependency (line 3635) | def removed_a_dependency(
  function add_exclude_constraint (line 3653) | def add_exclude_constraint(

FILE: src/stalker/models/template.py
  class FilenameTemplate (line 15) | class FilenameTemplate(Entity, TargetEntityTypeMixin):
    method __init__ (line 94) | def __init__(
    method _validate_path (line 107) | def _validate_path(self, key: str, path: Union[None, str]) -> str:
    method _validate_filename (line 134) | def _validate_filename(self, key: str, filename: Union[None, str]) -> ...
    method __eq__ (line 160) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 178) | def __hash__(self) -> int:

FILE: src/stalker/models/ticket.py
  class Ticket (line 35) | class Ticket(Entity, StatusMixin):
    method __init__ (line 215) | def __init__(
    method _number_getter (line 240) | def _number_getter(self) -> int:
    method _project_getter (line 255) | def _project_getter(self) -> Project:
    method _maximum_number (line 266) | def _maximum_number(cls) -> int:
    method _generate_ticket_number (line 281) | def _generate_ticket_number(self) -> int:
    method _validate_related_tickets (line 291) | def _validate_related_tickets(self, key: str, related_ticket: "Ticket"...
    method _validate_project (line 326) | def _validate_project(
    method _validate_summary (line 352) | def _validate_summary(self, key: str, summary: Union[None, str]) -> str:
    method __action__ (line 376) | def __action__(
    method resolve (line 420) | def resolve(
    method accept (line 434) | def accept(self, created_by: Union[None, User] = None) -> "TicketLog":
    method reassign (line 445) | def reassign(
    method reopen (line 459) | def reopen(self, created_by: Union[None, User] = None) -> "TicketLog":
    method set_owner (line 471) | def set_owner(self, *args) -> None:
    method set_resolution (line 479) | def set_resolution(self, *args) -> None:
    method del_resolution (line 487) | def del_resolution(self, *args) -> None:
    method __eq__ (line 495) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 515) | def __hash__(self) -> int:
  class TicketLog (line 526) | class TicketLog(SimpleEntity):
    method __init__ (line 584) | def __init__(

FILE: src/stalker/models/type.py
  class Type (line 17) | class Type(Entity, TargetEntityTypeMixin, CodeMixin):
    method __init__ (line 73) | def __init__(
    method __eq__ (line 87) | def __eq__(self, other: Any) -> bool:
    method __hash__ (line 103) | def __hash__(self) -> int:
  class EntityType (line 114) | class EntityType(Base):
    method __init__ (line 131) | def __init__(

FILE: src/stalker/models/variant.py
  class Variant (line 10) | class Variant(Task):

FILE: src/stalker/models/version.py
  class Version (line 27) | class Version(Entity, DAGMixin):
    method __init__ (line 161) | def __init__(
    method __repr__ (line 188) | def __repr__(self) -> str:
    method _validate_revision_number (line 203) | def _validate_revision_number(self, revision_number: int) -> int:
    method _revision_number_getter (line 230) | def _revision_number_getter(self) -> int:
    method _revision_number_setter (line 238) | def _revision_number_setter(self, revision_number: int):
    method latest_version (line 279) | def latest_version(self) -> "Version":
    method max_revision_number (line 304) | def max_revision_number(self) -> int:
    method max_version_number (line 320) | def max_version_number(self) -> int:
    method _validate_version_number (line 330) | def _validate_version_number(self, key: str, version_number: int) -> int:
    method _validate_task (line 372) | def _validate_task(self, key, task) -> Task:
    method _validate_files (line 399) | def _validate_files(self, key: str, file: File) -> File:
    method _template_variables (line 422) | def _template_variables(self) -> dict:
    method generate_path (line 435) | def generate_path(self, extension: Optional[str] = None) -> Path:
    method absolute_full_path (line 493) | def absolute_full_path(self) -> str:
    method absolute_path (line 508) | def absolute_path(self) -> str:
    method full_path (line 521) | def full_path(self) -> Path:
    method path (line 533) | def path(self) -> Path:
    method filename (line 542) | def filename(self) -> str:
    method is_latest_published_version (line 550) | def is_latest_published_version(self) -> bool:
    method latest_published_version (line 562) | def latest_published_version(self) -> "Version":
    method __eq__ (line 576) | def __eq__(self, other):
    method __hash__ (line 593) | def __hash__(self):
    method naming_parents (line 604) | def naming_parents(self) -> List[Task]:
    method nice_name (line 626) | def nice_name(self) -> str:
    method request_review (line 636) | def request_review(self) -> List[Review]:

FILE: src/stalker/models/wiki.py
  class Page (line 14) | class Page(Entity, ProjectMixin):
    method __init__ (line 43) | def __init__(
    method _validate_title (line 58) | def _validate_title(self, key: str, title: str) -> str:
    method _validate_content (line 85) | def _validate_content(self, key: str, content: Union[None, str]) -> str:

FILE: src/stalker/utils.py
  function make_plural (line 13) | def make_plural(name: str) -> str:
  function walk_hierarchy (line 36) | def walk_hierarchy(
  function check_circular_dependency (line 75) | def check_circular_dependency(entity: Any, other_entity: Any, attr_name:...
  function utc_to_local (line 105) | def utc_to_local(utc_datetime: datetime) -> datetime:
  function local_to_utc (line 123) | def local_to_utc(local_datetime: datetime) -> datetime:
  function datetime_to_millis (line 140) | def datetime_to_millis(dt: datetime) -> int:
  function millis_to_datetime (line 160) | def millis_to_datetime(millis: int) -> datetime:

FILE: tests/config/test_config.py
  function prepare_config_file (line 21) | def prepare_config_file():
  function test_config_variable_updates_with_user_config (line 34) | def test_config_variable_updates_with_user_config(prepare_config_file):
  function test_config_variable_does_create_new_variables_with_user_config (line 56) | def test_config_variable_does_create_new_variables_with_user_config(
  function test_env_variable_with_vars_module_import_with_shortcuts (line 78) | def test_env_variable_with_vars_module_import_with_shortcuts(prepare_con...
  function test_env_variable_with_deep_vars_module_import_with_shortcuts (line 104) | def test_env_variable_with_deep_vars_module_import_with_shortcuts(prepar...
  function test_non_existing_path_in_environment_variable (line 132) | def test_non_existing_path_in_environment_variable():
  function test_syntax_error_in_settings_file (line 138) | def test_syntax_error_in_settings_file(prepare_config_file):
  function test___setattr___cannot_set_config_values_directly (line 172) | def test___setattr___cannot_set_config_values_directly(prepare_config_fi...
  function test___getattr___is_working_as_expected (line 180) | def test___getattr___is_working_as_expected(prepare_config_file):
  function test___getitem___is_working_as_expected (line 186) | def test___getitem___is_working_as_expected(prepare_config_file):
  function test___setitem__is_working_as_expected (line 192) | def test___setitem__is_working_as_expected(prepare_config_file):
  function test___delitem__is_working_as_expected (line 201) | def test___delitem__is_working_as_expected(prepare_config_file):
  function test___contains___is_working_as_expected (line 209) | def test___contains___is_working_as_expected(prepare_config_file):
  function test_update_with_studio_is_working_as_expected (line 215) | def test_update_with_studio_is_working_as_expected(setup_postgresql_db):
  function test_old_style_repo_env_does_not_exist_anymore (line 230) | def test_old_style_repo_env_does_not_exist_anymore():
  function test_default_working_hours_is_a_dictionary_with_list_values (line 235) | def test_default_working_hours_is_a_dictionary_with_list_values():
  function test_default_filename_template_value (line 248) | def test_default_filename_template_value():

FILE: tests/conftest.py
  function setup_sqlite3 (line 28) | def setup_sqlite3():
  function get_data_file (line 47) | def get_data_file(request):
  function setup_postgresql_db (line 66) | def setup_postgresql_db():

FILE: tests/db/test_db.py
  function auto_crate_admin_on (line 131) | def auto_crate_admin_on():
  function auto_crate_admin_off (line 141) | def auto_crate_admin_off():
  function test_default_admin_creation (line 150) | def test_default_admin_creation(setup_postgresql_db, auto_crate_admin_on):
  function test_default_admin_for_already_created_databases (line 157) | def test_default_admin_for_already_created_databases(
  function test_no_default_admin_creation (line 174) | def test_no_default_admin_creation(setup_postgresql_db, auto_crate_admin...
  function test_non_unique_names_on_different_entity_type (line 207) | def test_non_unique_names_on_different_entity_type(setup_postgresql_db):
  function test_ticket_status_list_initialization (line 236) | def test_ticket_status_list_initialization(setup_postgresql_db):
  function test_daily_status_list_initialization (line 252) | def test_daily_status_list_initialization(setup_postgresql_db):
  function test_variant_status_list_initialization (line 274) | def test_variant_status_list_initialization(setup_postgresql_db):
  function test_register_creates_suitable_permissions (line 283) | def test_register_creates_suitable_permissions(setup_postgresql_db):
  function test_register_raise_type_error_for_wrong_class_name_argument (line 301) | def test_register_raise_type_error_for_wrong_class_name_argument(setup_p...
  function test_register_handles_integrity_errors (line 309) | def test_register_handles_integrity_errors(
  function test_permissions_created_for_all_the_classes (line 344) | def test_permissions_created_for_all_the_classes(setup_postgresql_db):
  function test_permissions_not_created_over_and_over_again (line 353) | def test_permissions_not_created_over_and_over_again(setup_postgresql_db):
  function test_ticket_statuses_are_not_created_over_and_over_again (line 373) | def test_ticket_statuses_are_not_created_over_and_over_again(setup_postg...
  function test_project_status_list_initialization (line 399) | def test_project_status_list_initialization(setup_postgresql_db):
  function test_task_status_list_initialization (line 422) | def test_task_status_list_initialization(setup_postgresql_db):
  function test_asset_status_list_initialization (line 464) | def test_asset_status_list_initialization(setup_postgresql_db):
  function test_shot_status_list_initialization (line 474) | def test_shot_status_list_initialization(setup_postgresql_db):
  function test_sequence_status_list_initialization (line 484) | def test_sequence_status_list_initialization(setup_postgresql_db):
  function test_scene_status_list_initialization (line 494) | def test_scene_status_list_initialization(setup_postgresql_db):
  function test_variant_status_list_initialization (line 504) | def test_variant_status_list_initialization(setup_postgresql_db):
  function test_review_status_list_initialization (line 514) | def test_review_status_list_initialization(setup_postgresql_db):
  function test___create_entity_statuses_no_entity_type_supplied (line 539) | def test___create_entity_statuses_no_entity_type_supplied(setup_postgres...
  function test___create_entity_statuses_no_status_names_supplied (line 548) | def test___create_entity_statuses_no_status_names_supplied(setup_postgre...
  function test___create_entity_statuses_no_status_codes_supplied (line 557) | def test___create_entity_statuses_no_status_codes_supplied(setup_postgre...
  function test_initialization_of_alembic_version_table (line 566) | def test_initialization_of_alembic_version_table(setup_postgresql_db):
  function test_initialization_of_alembic_version_table_multiple_times (line 573) | def test_initialization_of_alembic_version_table_multiple_times(setup_po...
  function test_alembic_version_mismatch (line 590) | def test_alembic_version_mismatch(setup_postgresql_db):
  function test_initialization_of_repo_environment_variables (line 647) | def test_initialization_of_repo_environment_variables(setup_postgresql_db):
  function test_db_init_with_studio_instance (line 684) | def test_db_init_with_studio_instance(setup_postgresql_db):
  function test_get_alembic_version_is_working_as_expected_when_there_is_no_alembic_version_table (line 739) | def test_get_alembic_version_is_working_as_expected_when_there_is_no_ale...
  function test_get_alembic_version_handles_errors (line 752) | def test_get_alembic_version_handles_errors(monkeypatch, error_class):
  function test_create_ticket_statuses_called_multiple_times (line 795) | def test_create_ticket_statuses_called_multiple_times(setup_postgresql_db):
  function test_create_ticket_statuses_handles_integrity_errors (line 802) | def test_create_ticket_statuses_handles_integrity_errors(
  function test_create_entity_statuses_called_multiple_times (line 833) | def test_create_entity_statuses_called_multiple_times(setup_postgresql_db):
  function test_create_entity_statuses_handles_errors (line 844) | def test_create_entity_statuses_handles_errors(
  function test_register_called_multiple_times (line 878) | def test_register_called_multiple_times(setup_postgresql_db):
  function test_setup_without_settings (line 886) | def test_setup_without_settings(setup_postgresql_db):
  function test_setup_with_settings (line 895) | def test_setup_with_settings(setup_postgresql_db):
  function test_persistence_of_asset (line 918) | def test_persistence_of_asset(setup_postgresql_db):
  function test_persistence_of_variant (line 1044) | def test_persistence_of_variant(setup_postgresql_db):
  function test_persistence_of_budget_and_budget_entry (line 1162) | def test_persistence_of_budget_and_budget_entry(setup_postgresql_db):
  function test_persistence_of_invoice (line 1281) | def test_persistence_of_invoice(setup_postgresql_db):
  function test_persistence_of_payment (line 1406) | def test_persistence_of_payment(setup_postgresql_db):
  function test_persistence_of_page (line 1533) | def test_persistence_of_page(setup_postgresql_db):
  function test_persistence_of_timelog (line 1625) | def test_persistence_of_timelog(setup_postgresql_db):
  function test_persistence_of_timelog_raw_sql (line 1678) | def test_persistence_of_timelog_raw_sql(setup_postgresql_db):
  function test_persistence_of_client (line 1734) | def test_persistence_of_client(setup_postgresql_db):
  function test_persistence_of_daily (line 1884) | def test_persistence_of_daily(setup_postgresql_db):
  function test_persistence_of_department (line 2001) | def test_persistence_of_department(setup_postgresql_db):
  function test_persistence_of_entity (line 2113) | def test_persistence_of_entity(setup_postgresql_db):
  function test_persistence_of_entity_group (line 2228) | def test_persistence_of_entity_group(setup_postgresql_db):
  function test_persistence_of_filename_template (line 2351) | def test_persistence_of_filename_template(setup_postgresql_db):
  function test_persistence_of_image_format (line 2409) | def test_persistence_of_image_format(setup_postgresql_db):
  function test_persistence_of_file (line 2469) | def test_persistence_of_file(setup_postgresql_db):
  function test_persistence_of_note (line 2586) | def test_persistence_of_note(setup_postgresql_db):
  function test_persistence_of_good (line 2641) | def test_persistence_of_good(setup_postgresql_db):
  function test_persistence_of_group (line 2683) | def test_persistence_of_group(setup_postgresql_db):
  function test_persistence_of_price_list (line 2705) | def test_persistence_of_price_list(setup_postgresql_db):
  function test_persistence_of_project (line 2746) | def test_persistence_of_project(setup_postgresql_db):
  function test_persistence_of_repository (line 2955) | def test_persistence_of_repository(setup_postgresql_db):
  function test_persistence_of_scene (line 3014) | def test_persistence_of_scene(setup_postgresql_db):
  function test_persistence_of_sequence (line 3103) | def test_persistence_of_sequence(setup_postgresql_db):
  function test_persistence_of_shot (line 3207) | def test_persistence_of_shot(setup_postgresql_db):
  function test_persistence_of_simple_entity (line 3307) | def test_persistence_of_simple_entity(setup_postgresql_db):
  function test_persistence_of_status (line 3362) | def test_persistence_of_status(setup_postgresql_db):
  function test_persistence_of_status_list (line 3409) | def test_persistence_of_status_list(setup_postgresql_db):
  function test_persistence_of_structure (line 3482) | def test_persistence_of_structure(setup_postgresql_db):
  function test_persistence_of_studio (line 3615) | def test_persistence_of_studio(setup_postgresql_db):
  function test_persistence_of_tag (line 3645) | def test_persistence_of_tag(setup_postgresql_db):
  function test_persistence_of_task (line 3688) | def test_persistence_of_task(setup_postgresql_db):
  function test_persistence_of_review (line 3949) | def test_persistence_of_review(setup_postgresql_db):
  function test_persistence_of_ticket (line 4103) | def test_persistence_of_ticket(setup_postgresql_db):
  function test_persistence_of_user (line 4201) | def test_persistence_of_user(setup_postgresql_db):
  function test_persistence_of_authentication_log (line 4341) | def test_persistence_of_authentication_log(setup_postgresql_db):
  function test_persistence_of_vacation (line 4399) | def test_persistence_of_vacation(setup_postgresql_db):
  function test_persistence_of_version (line 4431) | def test_persistence_of_version(setup_postgresql_db):
  function test_persistence_of_working_hours (line 4639) | def test_persistence_of_working_hours(setup_postgresql_db):
  function test_timezones_with_sqlite3 (line 4671) | def test_timezones_with_sqlite3(setup_sqlite3):

FILE: tests/db/test_dbsession.py
  function test_dbsession_save_method_is_correctly_created (line 5) | def test_dbsession_save_method_is_correctly_created(setup_postgresql_db):
  function test_dbsession_save_method_is_working_as_expected_for_single_entity (line 10) | def test_dbsession_save_method_is_working_as_expected_for_single_entity(
  function test_dbsession_save_method_is_working_as_expected_for_multiple_entity (line 24) | def test_dbsession_save_method_is_working_as_expected_for_multiple_entity(
  function test_dbsession_save_method_is_working_as_expected_for_no_entry (line 51) | def test_dbsession_save_method_is_working_as_expected_for_no_entry(setup...

FILE: tests/db/test_types.py
  function setup_db (line 14) | def setup_db(setup_sqlite3):
  function test_json_encoded_dict_with_generic_data_stored (line 37) | def test_json_encoded_dict_with_generic_data_stored(setup_db):
  function test_json_encoded_dict_with_generic_data_none_data_stored (line 49) | def test_json_encoded_dict_with_generic_data_none_data_stored(setup_db):
  function test_json_encoded_dict_with_generic_data_retrieved (line 59) | def test_json_encoded_dict_with_generic_data_retrieved(setup_db):

FILE: tests/mixins/test_acl_mixin.py
  class TestClassForACL (line 13) | class TestClassForACL(Base, ACLMixin):
    method __init__ (line 19) | def __init__(self):
  function acl_mixin_test_setup (line 25) | def acl_mixin_test_setup():
  function test_permission_attribute_accept_permission_instances_only (line 42) | def test_permission_attribute_accept_permission_instances_only(acl_mixin...
  function test_permission_attribute_is_working_as_expected (line 54) | def test_permission_attribute_is_working_as_expected(acl_mixin_test_setup):
  function test_acl_property_returns_a_list (line 60) | def test_acl_property_returns_a_list(acl_mixin_test_setup):
  function test_acl_property_returns_a_proper_ACL_list (line 66) | def test_acl_property_returns_a_proper_ACL_list(acl_mixin_test_setup):

FILE: tests/mixins/test_amount_mixin.py
  class AmountMixinFooMixedInClass (line 12) | class AmountMixinFooMixedInClass(SimpleEntity, AmountMixin):
    method __init__ (line 22) | def __init__(self, **kwargs):
  function test_mixed_in_class_initialization (line 27) | def test_mixed_in_class_initialization():
  function test_amount_argument_is_skipped (line 34) | def test_amount_argument_is_skipped():
  function test_amount_argument_is_set_to_none (line 40) | def test_amount_argument_is_set_to_none():
  function test_amount_attribute_is_set_to_none (line 46) | def test_amount_attribute_is_set_to_none():
  function test_amount_argument_is_not_a_number (line 54) | def test_amount_argument_is_not_a_number():
  function test_amount_attribute_is_not_a_number (line 64) | def test_amount_attribute_is_not_a_number():
  function test_amount_argument_is_working_as_expected (line 75) | def test_amount_argument_is_working_as_expected():
  function test_amount_attribute_is_working_as_expected (line 81) | def test_amount_attribute_is_working_as_expected():

FILE: tests/mixins/test_code_mixin.py
  class CodeMixFooMixedInClass (line 11) | class CodeMixFooMixedInClass(SimpleEntity, CodeMixin):
    method __init__ (line 20) | def __init__(self, **kwargs):
  function code_mixin_tester_setup (line 26) | def code_mixin_tester_setup():
  function test_code_argument_is_skipped (line 44) | def test_code_argument_is_skipped(code_mixin_tester_setup):
  function test_code_argument_is_none (line 54) | def test_code_argument_is_none(code_mixin_tester_setup):
  function test_code_attribute_is_none (line 64) | def test_code_attribute_is_none(code_mixin_tester_setup):
  function test_code_argument_is_not_a_string (line 73) | def test_code_argument_is_not_a_string(code_mixin_tester_setup):
  function test_code_attribute_is_not_a_string (line 85) | def test_code_attribute_is_not_a_string(code_mixin_tester_setup):
  function test_code_argument_is_an_empty_string (line 96) | def test_code_argument_is_an_empty_string(code_mixin_tester_setup):
  function test_code_attribute_is_set_to_an_empty_string (line 106) | def test_code_attribute_is_set_to_an_empty_string(code_mixin_tester_setup):
  function test_code_argument_is_working_as_expected (line 115) | def test_code_argument_is_working_as_expected(code_mixin_tester_setup):
  function test_code_attribute_is_working_as_expected (line 121) | def test_code_attribute_is_working_as_expected(code_mixin_tester_setup):

FILE: tests/mixins/test_create_secondary_table.py
  function setup_test_class (line 13) | def setup_test_class():
  function test_primary_cls_name_is_none (line 29) | def test_primary_cls_name_is_none(setup_test_class):
  function test_primary_cls_name_is_not_a_string (line 47) | def test_primary_cls_name_is_not_a_string(setup_test_class):
  function test_primary_cls_name_is_empty_string (line 65) | def test_primary_cls_name_is_empty_string(setup_test_class):
  function test_secondary_cls_name_is_none (line 82) | def test_secondary_cls_name_is_none(setup_test_class):
  function test_secondary_cls_name_is_not_a_string (line 100) | def test_secondary_cls_name_is_not_a_string(setup_test_class):
  function test_secondary_cls_name_is_empty_string (line 118) | def test_secondary_cls_name_is_empty_string(setup_test_class):
  function test_secondary_cls_name_is_converted_to_plural (line 136) | def test_secondary_cls_name_is_converted_to_plural(setup_test_class):
  function test_primary_cls_table_name_is_none (line 148) | def test_primary_cls_table_name_is_none(setup_test_class):
  function test_primary_cls_table_name_is_not_a_string (line 166) | def test_primary_cls_table_name_is_not_a_string(setup_test_class):
  function test_primary_cls_table_name_is_empty_string (line 184) | def test_primary_cls_table_name_is_empty_string(setup_test_class):
  function test_secondary_cls_table_name_is_none (line 202) | def test_secondary_cls_table_name_is_none(setup_test_class):
  function test_secondary_cls_table_name_is_not_a_string (line 220) | def test_secondary_cls_table_name_is_not_a_string(setup_test_class):
  function test_secondary_cls_table_name_is_empty_string (line 238) | def test_secondary_cls_table_name_is_empty_string(setup_test_class):
  function test_secondary_table_name_can_be_none (line 256) | def test_secondary_table_name_can_be_none(setup_test_class):
  function test_secondary_table_name_is_not_a_str (line 268) | def test_secondary_table_name_is_not_a_str(setup_test_class):
  function test_secondary_table_name_is_an_empty_str (line 285) | def test_secondary_table_name_is_an_empty_str(setup_test_class):
  function test_secondary_table_name_already_exists_in_base_metadata (line 297) | def test_secondary_table_name_already_exists_in_base_metadata(setup_test...
  function test_returns_a_table (line 313) | def test_returns_a_table(setup_test_class):

FILE: tests/mixins/test_dag_mixin.py
  class DAGMixinFooMixedInClass (line 21) | class DAGMixinFooMixedInClass(SimpleEntity, DAGMixin):
    method __init__ (line 31) | def __init__(self, **kwargs):
  function dag_mixin_test_case (line 37) | def dag_mixin_test_case():
  function setup_dag_db (line 48) | def setup_dag_db(setup_postgresql_db):
  function test_parent_argument_is_skipped (line 59) | def test_parent_argument_is_skipped(dag_mixin_test_case):
  function test_parent_argument_is_none (line 67) | def test_parent_argument_is_none(dag_mixin_test_case):
  function test_parent_argument_is_not_a_correct_class_instance (line 76) | def test_parent_argument_is_not_a_correct_class_instance(dag_mixin_test_...
  function test_parent_attribute_is_not_a_correct_class_instance (line 90) | def test_parent_attribute_is_not_a_correct_class_instance(dag_mixin_test...
  function test_parent_attribute_creates_a_cycle (line 104) | def test_parent_attribute_creates_a_cycle(dag_mixin_test_case):
  function test_parent_argument_is_working_as_expected (line 126) | def test_parent_argument_is_working_as_expected(dag_mixin_test_case):
  function test_parent_attribute_is_working_as_expected (line 139) | def test_parent_attribute_is_working_as_expected(dag_mixin_test_case):
  function test_children_attribute_is_an_empty_list_by_default (line 150) | def test_children_attribute_is_an_empty_list_by_default(dag_mixin_test_c...
  function test_children_attribute_is_set_to_none (line 158) | def test_children_attribute_is_set_to_none(dag_mixin_test_case):
  function test_children_attribute_accepts_correct_class_instances_only (line 169) | def test_children_attribute_accepts_correct_class_instances_only(dag_mix...
  function test_children_attribute_is_working_as_expected (line 183) | def test_children_attribute_is_working_as_expected(dag_mixin_test_case):
  function test_is_leaf_attribute_is_read_only (line 201) | def test_is_leaf_attribute_is_read_only(dag_mixin_test_case):
  function test_is_leaf_attribute_is_working_as_expected (line 221) | def test_is_leaf_attribute_is_working_as_expected(dag_mixin_test_case):
  function test_is_root_attribute_is_read_only (line 235) | def test_is_root_attribute_is_read_only(dag_mixin_test_case):
  function test_is_root_attribute_is_working_as_expected (line 255) | def test_is_root_attribute_is_working_as_expected(dag_mixin_test_case):
  function test_is_container_attribute_is_read_only (line 268) | def test_is_container_attribute_is_read_only(dag_mixin_test_case):
  function test_is_container_attribute_working_as_expected (line 288) | def test_is_container_attribute_working_as_expected(dag_mixin_test_case):
  function test_parents_property_is_read_only (line 305) | def test_parents_property_is_read_only(dag_mixin_test_case):
  function test_parents_property_is_working_as_expected (line 325) | def test_parents_property_is_working_as_expected(dag_mixin_test_case):
  function test_walk_hierarchy_is_working_as_expected (line 343) | def test_walk_hierarchy_is_working_as_expected(dag_mixin_test_case):
  function test_committing_data (line 381) | def test_committing_data(setup_dag_db):
  function test_deleting_data (line 407) | def test_deleting_data(setup_dag_db):

FILE: tests/mixins/test_date_range_mixin.py
  class DateRangeMixFooMixedInClass (line 22) | class DateRangeMixFooMixedInClass(SimpleEntity, DateRangeMixin):
    method __init__ (line 31) | def __init__(self, **kwargs):
  function date_range_mixin_tester (line 37) | def date_range_mixin_tester():
  function test_start_argument_is_not_a_date_object (line 65) | def test_start_argument_is_not_a_date_object(test_value, date_range_mixi...
  function test_start_attribute_is_not_a_date_object (line 74) | def test_start_attribute_is_not_a_date_object(test_value, date_range_mix...
  function test_start_attribute_is_set_to_none_use_the_default_value (line 90) | def test_start_attribute_is_set_to_none_use_the_default_value(date_range...
  function test_start_attribute_works_as_expected (line 100) | def test_start_attribute_works_as_expected(date_range_mixin_tester):
  function test_end_argument_is_not_a_date_object (line 111) | def test_end_argument_is_not_a_date_object(test_value, date_range_mixin_...
  function test_end_attribute_is_not_a_date_object (line 122) | def test_end_attribute_is_not_a_date_object(test_value, date_range_mixin...
  function test_end_argument_is_tried_to_set_to_a_time_before_start (line 132) | def test_end_argument_is_tried_to_set_to_a_time_before_start(date_range_...
  function test_end_attribute_is_tried_to_set_to_a_time_before_start (line 140) | def test_end_attribute_is_tried_to_set_to_a_time_before_start(date_range...
  function test_end_attribute_is_shifted_if_start_passes_it (line 151) | def test_end_attribute_is_shifted_if_start_passes_it(date_range_mixin_te...
  function test_duration_argument_is_not_an_instance_of_timedelta_no_problem_if_start_and_end_is_present (line 160) | def test_duration_argument_is_not_an_instance_of_timedelta_no_problem_if...
  function test_duration_argument_is_not_an_instance_of_date_if_start_argument_is_missing (line 171) | def test_duration_argument_is_not_an_instance_of_date_if_start_argument_...
  function test_duration_argument_is_not_an_instance_of_date_if_end_argument_is_missing (line 183) | def test_duration_argument_is_not_an_instance_of_date_if_end_argument_is...
  function test_duration_argument_is_smaller_than_timing_resolution (line 196) | def test_duration_argument_is_smaller_than_timing_resolution(date_range_...
  function test_duration_attribute_is_calculated_correctly (line 206) | def test_duration_attribute_is_calculated_correctly(date_range_mixin_tes...
  function test_duration_attribute_is_set_to_not_an_instance_of_timedelta (line 216) | def test_duration_attribute_is_set_to_not_an_instance_of_timedelta(
  function test_duration_attribute_expands_then_end_shifts (line 231) | def test_duration_attribute_expands_then_end_shifts(date_range_mixin_tes...
  function test_duration_attribute_contracts_then_end_shifts_back (line 252) | def test_duration_attribute_contracts_then_end_shifts_back(date_range_mi...
  function test_duration_attribute_is_smaller_then_timing_resolution (line 273) | def test_duration_attribute_is_smaller_then_timing_resolution(date_range...
  function test_duration_is_a_negative_timedelta (line 280) | def test_duration_is_a_negative_timedelta(date_range_mixin_tester):
  function test_init_all_parameters_skipped (line 289) | def test_init_all_parameters_skipped(date_range_mixin_tester):
  function test_init_only_start_argument_is_given (line 314) | def test_init_only_start_argument_is_given(date_range_mixin_tester):
  function test_init_start_and_end_argument_is_given (line 328) | def test_init_start_and_end_argument_is_given(date_range_mixin_tester):
  function test_init_start_and_end_argument_is_given_but_duration_is_smaller_than_timing_resolution (line 339) | def test_init_start_and_end_argument_is_given_but_duration_is_smaller_th...
  function test_init_start_and_duration_argument_is_given (line 355) | def test_init_start_and_duration_argument_is_given(date_range_mixin_test...
  function test_init_all_arguments_are_given (line 366) | def test_init_all_arguments_are_given(date_range_mixin_tester):
  function test_init_end_and_duration_argument_is_given (line 376) | def test_init_end_and_duration_argument_is_given(date_range_mixin_tester):
  function test_init_only_end_argument_is_given (line 387) | def test_init_only_end_argument_is_given(date_range_mixin_tester):
  function test_init_only_duration_argument_is_given (line 401) | def test_init_only_duration_argument_is_given(date_range_mixin_tester):
  function test_start_end_and_duration_values_are_rounded_to_the_default_timing_resolution (line 421) | def test_start_end_and_duration_values_are_rounded_to_the_default_timing...
  function test_computed_start_is_none_for_a_non_scheduled_class (line 445) | def test_computed_start_is_none_for_a_non_scheduled_class(date_range_mix...
  function test_computed_end_is_none_for_a_non_scheduled_class (line 452) | def test_computed_end_is_none_for_a_non_scheduled_class(date_range_mixin...
  function test_computed_duration_attribute_is_none_if_there_is_no_computed_start_and_no_computed_end (line 459) | def test_computed_duration_attribute_is_none_if_there_is_no_computed_sta...
  function test_computed_duration_attribute_is_none_if_there_is_computed_start_but_no_computed_end (line 470) | def test_computed_duration_attribute_is_none_if_there_is_computed_start_...
  function test_computed_duration_attribute_is_none_if_there_is_no_computed_start_but_computed_end (line 481) | def test_computed_duration_attribute_is_none_if_there_is_no_computed_sta...
  function test_computed_duration_attribute_is_calculated_correctly_if_there_are_both_computed_start_and_computed_end (line 492) | def test_computed_duration_attribute_is_calculated_correctly_if_there_ar...
  function test_computed_duration_is_read_only (line 503) | def test_computed_duration_is_read_only(date_range_mixin_tester):
  function test_total_seconds_attribute_is_read_only (line 523) | def test_total_seconds_attribute_is_read_only(date_range_mixin_tester):
  function test_total_seconds_attribute_is_working_as_expected (line 543) | def test_total_seconds_attribute_is_working_as_expected(date_range_mixin...
  function test_computed_total_seconds_attribute_is_read_only (line 552) | def test_computed_total_seconds_attribute_is_read_only(date_range_mixin_...
  function test_computed_total_seconds_attribute_is_working_as_expected (line 572) | def test_computed_total_seconds_attribute_is_working_as_expected(
  function setup_date_range_mixin_db (line 584) | def setup_date_range_mixin_db(setup_postgresql_db):
  function test_start_end_and_duration_values_are_rounded_to_the_studio_timing_resolution (line 608) | def test_start_end_and_duration_values_are_rounded_to_the_studio_timing_...

FILE: tests/mixins/test_declarative_project_mixin.py
  class DeclProjMixA (line 19) | class DeclProjMixA(SimpleEntity, ProjectMixin):
    method __init__ (line 28) | def __init__(self, **kwargs):
  class DeclProjMixB (line 33) | class DeclProjMixB(SimpleEntity, ProjectMixin):
    method __init__ (line 42) | def __init__(self, **kwargs):
  function setup_project_mixin_tester (line 48) | def setup_project_mixin_tester():
  function test_project_attribute_is_working_as_expected (line 105) | def test_project_attribute_is_working_as_expected(setup_project_mixin_te...

FILE: tests/mixins/test_declarative_reference_mixin.py
  class DeclRefMixA (line 10) | class DeclRefMixA(SimpleEntity, ReferenceMixin):
    method __init__ (line 19) | def __init__(self, **kwargs):
  class DeclRefMixB (line 24) | class DeclRefMixB(SimpleEntity, ReferenceMixin):
    method __init__ (line 33) | def __init__(self, **kwargs):
  function test_reference_mixin_setup (line 38) | def test_reference_mixin_setup():

FILE: tests/mixins/test_declarative_schedule_mixin.py
  class DeclSchedMixA (line 23) | class DeclSchedMixA(SimpleEntity, DateRangeMixin):
    method __init__ (line 32) | def __init__(self, **kwargs):
  class DeclSchedMixB (line 37) | class DeclSchedMixB(SimpleEntity, DateRangeMixin):
    method __init__ (line 46) | def __init__(self, **kwargs):
  function setup_schedule_mixin_tester (line 52) | def setup_schedule_mixin_tester():
  function test_mixin_setup_is_working_as_expected (line 68) | def test_mixin_setup_is_working_as_expected(setup_schedule_mixin_tester):

FILE: tests/mixins/test_declarative_status_mixin.py
  class DeclStatMixA (line 11) | class DeclStatMixA(SimpleEntity, StatusMixin):
    method __init__ (line 20) | def __init__(self, **kwargs):
  class DeclStatMixB (line 25) | class DeclStatMixB(SimpleEntity, StatusMixin):
    method __init__ (line 34) | def __init__(self, **kwargs):
  function setup_status_mixin_tester (line 40) | def setup_status_mixin_tester():
  function test_status_list_argument_not_set (line 64) | def test_status_list_argument_not_set(setup_status_mixin_tester):
  function test_status_list_argument_is_not_correct (line 77) | def test_status_list_argument_is_not_correct(setup_status_mixin_tester):
  function test_status_list_working_as_expected (line 89) | def test_status_list_working_as_expected(setup_status_mixin_tester):

FILE: tests/mixins/test_project_mixin.py
  class ProjMixClass (line 11) | class ProjMixClass(SimpleEntity, ProjectMixin):
    method __init__ (line 20) | def __init__(self, **kwargs):
  function setup_project_mixin_tester (line 26) | def setup_project_mixin_tester():
  function test_project_argument_is_skipped (line 96) | def test_project_argument_is_skipped(setup_project_mixin_tester):
  function test_project_argument_is_none (line 110) | def test_project_argument_is_none(setup_project_mixin_tester):
  function test_project_attribute_is_none (line 124) | def test_project_attribute_is_none(setup_project_mixin_tester):
  function test_project_argument_is_not_a_project_instance (line 137) | def test_project_argument_is_not_a_project_instance(setup_project_mixin_...
  function test_project_attribute_is_not_a_project_instance (line 150) | def test_project_attribute_is_not_a_project_instance(setup_project_mixin...
  function test_project_attribute_is_working_as_expected (line 162) | def test_project_attribute_is_working_as_expected(setup_project_mixin_te...

FILE: tests/mixins/test_reference_mixin.py
  class RefMixFooClass (line 12) | class RefMixFooClass(SimpleEntity, ReferenceMixin):
    method __init__ (line 21) | def __init__(self, **kwargs):
  function setup_reference_mixin_tester (line 26) | def setup_reference_mixin_tester():
  function test_references_attribute_accepting_empty_list (line 88) | def test_references_attribute_accepting_empty_list(setup_reference_mixin...
  function test_references_attribute_only_accepts_list_like_objects (line 94) | def test_references_attribute_only_accepts_list_like_objects(
  function test_references_attribute_accepting_only_lists_of_file_instances (line 105) | def test_references_attribute_accepting_only_lists_of_file_instances(
  function test_references_attribute_elements_accepts_files_only (line 121) | def test_references_attribute_elements_accepts_files_only(setup_referenc...
  function test_references_attribute_is_working_as_expected (line 133) | def test_references_attribute_is_working_as_expected(setup_reference_mix...
  function test_references_application_test (line 146) | def test_references_application_test(setup_reference_mixin_tester):

FILE: tests/mixins/test_schedule_mixin.py
  class MixedInClass (line 16) | class MixedInClass(SimpleEntity, ScheduleMixin):
    method __init__ (line 25) | def __init__(self, **kwargs):
  function setup_schedule_mixin_tests (line 31) | def setup_schedule_mixin_tests():
  function test_schedule_model_attribute_is_effort_by_default (line 53) | def test_schedule_model_attribute_is_effort_by_default(setup_schedule_mi...
  function test_schedule_model_argument_is_none (line 59) | def test_schedule_model_argument_is_none(setup_schedule_mixin_tests):
  function test_schedule_model_attribute_is_set_to_none (line 67) | def test_schedule_model_attribute_is_set_to_none(setup_schedule_mixin_te...
  function test_schedule_model_argument_is_not_a_string (line 74) | def test_schedule_model_argument_is_not_a_string(setup_schedule_mixin_te...
  function test_schedule_model_attribute_is_not_a_string (line 87) | def test_schedule_model_attribute_is_not_a_string(setup_schedule_mixin_t...
  function test_schedule_model_argument_is_not_in_correct_value (line 100) | def test_schedule_model_argument_is_not_in_correct_value(setup_schedule_...
  function test_schedule_model_attribute_is_not_in_correct_value (line 114) | def test_schedule_model_attribute_is_not_in_correct_value(setup_schedule...
  function test_schedule_model_argument_is_working_as_expected (line 128) | def test_schedule_model_argument_is_working_as_expected(
  function test_schedule_model_attribute_is_working_as_expected (line 140) | def test_schedule_model_attribute_is_working_as_expected(
  function test_schedule_constraint_is_0_by_default (line 151) | def test_schedule_constraint_is_0_by_default(setup_schedule_mixin_tests):
  function test_schedule_constraint_argument_is_skipped (line 157) | def test_schedule_constraint_argument_is_skipped(setup_schedule_mixin_te...
  function test_schedule_constraint_argument_is_none (line 168) | def test_schedule_constraint_argument_is_none(setup_schedule_mixin_tests):
  function test_schedule_constraint_attribute_is_set_to_none (line 176) | def test_schedule_constraint_attribute_is_set_to_none(setup_schedule_mix...
  function test_schedule_constraint_argument_is_not_an_integer (line 183) | def test_schedule_constraint_argument_is_not_an_integer(setup_schedule_m...
  function test_schedule_constraint_attribute_is_not_an_integer (line 196) | def test_schedule_constraint_attribute_is_not_an_integer(setup_schedule_...
  function test_schedule_constraint_argument_is_working_as_expected (line 208) | def test_schedule_constraint_argument_is_working_as_expected(
  function test_schedule_constraint_attribute_is_working_as_expected (line 219) | def test_schedule_constraint_attribute_is_working_as_expected(
  function test_schedule_constraint_argument_value_is_out_of_range (line 230) | def test_schedule_constraint_argument_value_is_out_of_range(
  function test_schedule_constraint_attribute_value_is_out_of_range (line 243) | def test_schedule_constraint_attribute_value_is_out_of_range(
  function test_schedule_timing_argument_skipped (line 255) | def test_schedule_timing_argument_skipped(setup_schedule_mixin_tests):
  function test_schedule_timing_argument_is_none (line 264) | def test_schedule_timing_argument_is_none(setup_schedule_mixin_tests):
  function test_schedule_timing_attribute_is_set_to_none (line 273) | def test_schedule_timing_attribute_is_set_to_none(setup_schedule_mixin_t...
  function test_schedule_timing_argument_is_not_an_integer_or_float (line 281) | def test_schedule_timing_argument_is_not_an_integer_or_float(
  function test_schedule_timing_attribute_is_not_an_int_or_float (line 296) | def test_schedule_timing_attribute_is_not_an_int_or_float(
  function test_schedule_timing_attribute_is_working_as_expected (line 310) | def test_schedule_timing_attribute_is_working_as_expected(setup_schedule...
  function test_schedule_unit_argument_skipped (line 318) | def test_schedule_unit_argument_skipped(setup_schedule_mixin_tests):
  function test_schedule_unit_argument_is_none (line 326) | def test_schedule_unit_argument_is_none(setup_schedule_mixin_tests):
  function test_schedule_unit_attribute_is_set_to_none (line 334) | def test_schedule_unit_attribute_is_set_to_none(setup_schedule_mixin_tes...
  function test_schedule_unit_argument_is_not_a_string (line 341) | def test_schedule_unit_argument_is_not_a_string(setup_schedule_mixin_tes...
  function test_schedule_unit_attribute_is_not_a_string (line 354) | def test_schedule_unit_attribute_is_not_a_string(setup_schedule_mixin_te...
  function test_schedule_unit_attribute_is_working_as_expected (line 366) | def test_schedule_unit_attribute_is_working_as_expected(setup_schedule_m...
  function test_schedule_unit_argument_value_is_not_in_defaults_datetime_units (line 374) | def test_schedule_unit_argument_value_is_not_in_defaults_datetime_units(
  function test_schedule_unit_attribute_value_is_not_in_defaults_datetime_units (line 390) | def test_schedule_unit_attribute_value_is_not_in_defaults_datetime_units(
  function test_least_meaningful_time_unit_is_working_as_expected (line 438) | def test_least_meaningful_time_unit_is_working_as_expected(
  function test_to_seconds_is_working_as_expected (line 532) | def test_to_seconds_is_working_as_expected(
  function test_to_unit_unit_is_none (line 557) | def test_to_unit_unit_is_none(setup_schedule_mixin_tests):
  function test_to_unit_is_working_as_expected (line 604) | def test_to_unit_is_working_as_expected(
  function test_schedule_seconds_is_working_as_expected (line 646) | def test_schedule_seconds_is_working_as_expected(

FILE: tests/mixins/test_status_mixin.py
  class StatMixClass (line 13) | class StatMixClass(SimpleEntity, StatusMixin):
    method __init__ (line 22) | def __init__(self, **kwargs):
  class StatMixDerivedClass (line 27) | class StatMixDerivedClass(StatMixClass):
  function status_mixin_tests (line 42) | def status_mixin_tests():
  function test_status_list_arg_is_not_a_status_list_instance (line 100) | def test_status_list_arg_is_not_a_status_list_instance(status_mixin_tests):
  function test_status_list_attr_is_not_a_status_list (line 113) | def test_status_list_attr_is_not_a_status_list(status_mixin_tests):
  function test_status_list_arg_is_not_suitable_for_the_current_class (line 125) | def test_status_list_arg_is_not_suitable_for_the_current_class(status_mi...
  function test_status_list_attr_is_not_suitable_for_the_current_class (line 152) | def test_status_list_attr_is_not_suitable_for_the_current_class(status_m...
  function test_status_list_arg_is_suitable_for_the_super (line 177) | def test_status_list_arg_is_suitable_for_the_super(status_mixin_tests):
  function test_status_list_attr_is_working_as_expected (line 187) | def test_status_list_attr_is_working_as_expected(status_mixin_tests):
  function test_status_arg_set_to_none (line 204) | def test_status_arg_set_to_none(status_mixin_tests):
  function test_status_attr_set_to_none (line 212) | def test_status_attr_set_to_none(status_mixin_tests):
  function test_status_arg_is_not_a_status_instance_or_integer (line 219) | def test_status_arg_is_not_a_status_instance_or_integer(status_mixin_tes...
  function test_status_attr_is_not_a_status_or_integer (line 233) | def test_status_attr_is_not_a_status_or_integer(
  function test_status_attr_is_set_to_a_status_which_is_not_in_the_status_list (line 248) | def test_status_attr_is_set_to_a_status_which_is_not_in_the_status_list(
  function test_status_arg_is_working_as_expected_with_status_instances (line 263) | def test_status_arg_is_working_as_expected_with_status_instances(
  function test_status_attr_is_working_as_expected_with_status_instances (line 274) | def test_status_attr_is_working_as_expected_with_status_instances(
  function test_status_arg_is_working_as_expected_with_integers (line 284) | def test_status_arg_is_working_as_expected_with_integers(status_mixin_te...
  function test_status_attr_is_working_as_expected_with_integers (line 293) | def test_status_attr_is_working_as_expected_with_integers(status_mixin_t...
  function test_status_arg_is_an_integer_but_out_of_range (line 303) | def test_status_arg_is_an_integer_but_out_of_range(status_mixin_tests):
  function test_status_attr_set_to_an_integer_but_out_of_range (line 316) | def test_status_attr_set_to_an_integer_but_out_of_range(status_mixin_tes...
  function test_status_arg_is_a_negative_integer (line 328) | def test_status_arg_is_a_negative_integer(status_mixin_tests):
  function test_status_attr_set_to_an_negative_integer (line 338) | def test_status_attr_set_to_an_negative_integer(status_mixin_tests):
  class StatusListAutoAddClass (line 347) | class StatusListAutoAddClass(SimpleEntity, StatusMixin):
    method __init__ (line 356) | def __init__(self, **kwargs):
  class StatusListAutoAddDerivedClass (line 361) | class StatusListAutoAddDerivedClass(StatusListAutoAddClass):
  class StatusListNoAutoAddClass (line 371) | class StatusListNoAutoAddClass(SimpleEntity, StatusMixin):
    method __init__ (line 380) | def __init__(self, **kwargs):
  function setup_status_mixin_db_tests (line 386) | def setup_status_mixin_db_tests(setup_postgresql_db):
  function test_status_list_arg_is_skipped_and_there_is_a_db_setup (line 444) | def test_status_list_arg_is_skipped_and_there_is_a_db_setup(
  function test_status_list_arg_is_skipped_and_there_is_a_db_setup_but_no_suitable_status_list (line 473) | def test_status_list_arg_is_skipped_and_there_is_a_db_setup_but_no_suita...
  function test_status_list_arg_is_none (line 507) | def test_status_list_arg_is_none(setup_status_mixin_db_tests):
  function test_status_list_arg_skipped (line 523) | def test_status_list_arg_skipped(setup_status_mixin_db_tests):
  function test_status_list_attr_set_to_none (line 539) | def test_status_list_attr_set_to_none(setup_status_mixin_db_tests):
  function test_status_list_is_found_automatically_for_derived_class (line 554) | def test_status_list_is_found_automatically_for_derived_class(

FILE: tests/mixins/test_target_entity_type_mixin.py
  class TestClass (line 14) | class TestClass(object):
  class TargetEntityTypeMixedClass (line 20) | class TargetEntityTypeMixedClass(SimpleEntity, TargetEntityTypeMixin):
    method __init__ (line 29) | def __init__(self, **kwargs):
  function setup_target_entity_mixin_tests (line 35) | def setup_target_entity_mixin_tests():
  function test_target_entity_type_argument_is_skipped (line 47) | def test_target_entity_type_argument_is_skipped(setup_target_entity_mixi...
  function test_target_entity_type_argument_being_empty_string (line 59) | def test_target_entity_type_argument_being_empty_string(
  function test_target_entity_type_argument_being_none (line 72) | def test_target_entity_type_argument_being_none(setup_target_entity_mixi...
  function test_target_entity_type_attribute_is_read_only (line 83) | def test_target_entity_type_attribute_is_read_only(setup_target_entity_m...
  function test_target_entity_type_argument_accepts_classes (line 105) | def test_target_entity_type_argument_accepts_classes(setup_target_entity...

FILE: tests/mixins/test_unit_mixin.py
  class UnitMixinFooMixedInClass (line 12) | class UnitMixinFooMixedInClass(SimpleEntity, UnitMixin):
    method __init__ (line 22) | def __init__(self, **kwargs):
  function test_mixed_in_class_initialization (line 27) | def test_mixed_in_class_initialization():
  function test_unit_argument_is_skipped (line 34) | def test_unit_argument_is_skipped():
  function test_unit_argument_is_none (line 40) | def test_unit_argument_is_none():
  function test_unit_attribute_is_set_to_none (line 46) | def test_unit_attribute_is_set_to_none():
  function test_unit_argument_is_not_a_string (line 54) | def test_unit_argument_is_not_a_string():
  function test_unit_attribute_is_not_a_string (line 64) | def test_unit_attribute_is_not_a_string():
  function test_unit_argument_is_working_as_expected (line 75) | def test_unit_argument_is_working_as_expected():
  function test_unit_attribute_is_working_as_expected (line 82) | def test_unit_attribute_is_working_as_expected():

FILE: tests/models/test_asset.py
  function setup_asset_tests (line 24) | def setup_asset_tests(setup_postgresql_db):
  function test_auto_name_class_attribute_is_set_to_false (line 151) | def test_auto_name_class_attribute_is_set_to_false():
  function test_name_cannot_be_set_to_none (line 156) | def test_name_cannot_be_set_to_none(setup_asset_tests):
  function test_name_cannot_be_set_to_empty_string (line 166) | def test_name_cannot_be_set_to_empty_string(setup_asset_tests):
  function test_equality (line 176) | def test_equality(setup_asset_tests):
  function test_inequality (line 193) | def test_inequality(setup_asset_tests):
  function test_reference_mixin_initialization (line 210) | def test_reference_mixin_initialization(setup_asset_tests):
  function test_status_mixin_initialization (line 233) | def test_status_mixin_initialization(setup_asset_tests):
  function test_task_mixin_initialization (line 244) | def test_task_mixin_initialization(setup_asset_tests):
  function test_plural_class_name (line 277) | def test_plural_class_name(setup_asset_tests):
  function test_strictly_typed_is_true (line 283) | def test_strictly_typed_is_true():
  function test_hash_value (line 288) | def test_hash_value(setup_asset_tests):
  function test_template_variables_for_asset_related_task (line 295) | def test_template_variables_for_asset_related_task(setup_asset_tests):
  function test_template_variables_for_asset_itself (line 310) | def test_template_variables_for_asset_itself(setup_asset_tests):
  function test_assets_can_use_task_status_list (line 325) | def test_assets_can_use_task_status_list():

FILE: tests/models/test_authentication_log.py
  function setup_authentication_log_tests (line 14) | def setup_authentication_log_tests():
  function test_user_argument_is_skipped (line 36) | def test_user_argument_is_skipped(setup_authentication_log_tests):
  function test_user_argument_is_none (line 45) | def test_user_argument_is_none(setup_authentication_log_tests):
  function test_user_argument_is_not_a_user_instance (line 54) | def test_user_argument_is_not_a_user_instance(setup_authentication_log_t...
  function test_user_attribute_is_not_a_user_instance (line 68) | def test_user_attribute_is_not_a_user_instance(setup_authentication_log_...
  function test_user_argument_is_working_as_expected (line 83) | def test_user_argument_is_working_as_expected(setup_authentication_log_t...
  function test_user_attribute_is_working_as_expected (line 92) | def test_user_attribute_is_working_as_expected(setup_authentication_log_...
  function test_action_argument_is_skipped (line 103) | def test_action_argument_is_skipped(setup_authentication_log_tests):
  function test_action_argument_is_none (line 112) | def test_action_argument_is_none(setup_authentication_log_tests):
  function test_action_argument_value_is_not_login_or_logout (line 121) | def test_action_argument_value_is_not_login_or_logout(setup_authenticati...
  function test_action_attribute_value_is_not_login_or_logout (line 137) | def test_action_attribute_value_is_not_login_or_logout(setup_authenticat...
  function test_action_argument_is_working_as_expected (line 152) | def test_action_argument_is_working_as_expected(setup_authentication_log...
  function test_action_attribute_is_working_as_expected (line 165) | def test_action_attribute_is_working_as_expected(setup_authentication_lo...
  function test_date_argument_is_skipped (line 176) | def test_date_argument_is_skipped(setup_authentication_log_tests):
  function test_date_argument_is_none (line 184) | def test_date_argument_is_none(setup_authentication_log_tests):
  function test_date_attribute_is_none (line 192) | def test_date_attribute_is_none(setup_authentication_log_tests):
  function test_date_argument_is_not_a_datetime_instance (line 208) | def test_date_argument_is_not_a_datetime_instance(setup_authentication_l...
  function test_date_attribute_is_not_a_datetime_instance (line 221) | def test_date_attribute_is_not_a_datetime_instance(setup_authentication_...
  function test_date_argument_is_working_as_expected (line 236) | def test_date_argument_is_working_as_expected(setup_authentication_log_t...
  function test_date_attribute_is_working_as_expected (line 245) | def test_date_attribute_is_working_as_expected(setup_authentication_log_...
  function test_date_argument_is_working_as_expected2 (line 256) | def test_date_argument_is_working_as_expected2(setup_authentication_log_...
  function test_authentication_log_is_orderable_for_some_reason (line 264) | def test_authentication_log_is_orderable_for_some_reason(

FILE: tests/models/test_budget.py
  function setup_budget_test_base (line 20) | def setup_budget_test_base():
  function test_entries_attribute_is_set_to_a_list_of_other_instances_than_a_budget_entry (line 110) | def test_entries_attribute_is_set_to_a_list_of_other_instances_than_a_bu...
  function test_entries_attribute_is_working_as_expected (line 123) | def test_entries_attribute_is_working_as_expected(setup_budget_test_base):
  function test_statuses_is_working_as_expected (line 143) | def test_statuses_is_working_as_expected(setup_budget_test_base):
  function test_budget_argument_is_skipped (line 154) | def test_budget_argument_is_skipped(setup_budget_test_base):
  function test_budget_argument_is_none (line 163) | def test_budget_argument_is_none(setup_budget_test_base):
  function test_budget_attribute_is_set_to_none (line 172) | def test_budget_attribute_is_set_to_none(setup_budget_test_base):
  function test_budget_argument_is_not_a_budget_instance (line 186) | def test_budget_argument_is_not_a_budget_instance(setup_budget_test_base):
  function test_budget_attribute_is_not_a_budget_instance (line 195) | def test_budget_attribute_is_not_a_budget_instance(setup_budget_test_base):
  function test_budget_argument_is_working_as_expected (line 207) | def test_budget_argument_is_working_as_expected(setup_budget_test_base):
  function test_budget_attribute_is_working_as_expected (line 214) | def test_budget_attribute_is_working_as_expected(setup_budget_test_base):
  function test_cost_attribute_value_will_be_copied_from_the_supplied_good_argument (line 228) | def test_cost_attribute_value_will_be_copied_from_the_supplied_good_argu...
  function test_cost_attribute_is_set_to_none (line 238) | def test_cost_attribute_is_set_to_none(setup_budget_test_base):
  function test_cost_attribute_is_not_a_number (line 250) | def test_cost_attribute_is_not_a_number(setup_budget_test_base):
  function test_cost_attribute_is_working_as_expected (line 264) | def test_cost_attribute_is_working_as_expected(setup_budget_test_base):
  function test_msrp_attribute_is_set_to_none (line 277) | def test_msrp_attribute_is_set_to_none(setup_budget_test_base):
  function test_msrp_attribute_is_not_a_number (line 289) | def test_msrp_attribute_is_not_a_number(setup_budget_test_base):
  function test_msrp_attribute_is_working_as_expected (line 303) | def test_msrp_attribute_is_working_as_expected(setup_budget_test_base):
  function test_msrp_attribute_value_will_be_copied_from_the_supplied_good_argument (line 316) | def test_msrp_attribute_value_will_be_copied_from_the_supplied_good_argu...
  function test_price_argument_is_skipped (line 325) | def test_price_argument_is_skipped(setup_budget_test_base):
  function test_price_argument_is_set_to_none (line 335) | def test_price_argument_is_set_to_none(setup_budget_test_base):
  function test_price_attribute_is_set_to_none (line 342) | def test_price_attribute_is_set_to_none(setup_budget_test_base):
  function test_price_argument_is_not_a_number (line 351) | def test_price_argument_is_not_a_number(setup_budget_test_base):
  function test_price_attribute_is_not_a_number (line 363) | def test_price_attribute_is_not_a_number(setup_budget_test_base):
  function test_price_argument_is_working_as_expected (line 374) | def test_price_argument_is_working_as_expected(setup_budget_test_base):
  function test_price_attribute_is_working_as_expected (line 381) | def test_price_attribute_is_working_as_expected(setup_budget_test_base):
  function test_realized_total_argument_is_skipped (line 391) | def test_realized_total_argument_is_skipped(setup_budget_test_base):
  function test_realized_total_argument_is_set_to_none (line 398) | def test_realized_total_argument_is_set_to_none(setup_budget_test_base):
  function test_realized_total_attribute_is_set_to_none (line 407) | def test_realized_total_attribute_is_set_to_none(setup_budget_test_base):
  function test_realized_total_argument_is_not_a_number (line 418) | def test_realized_total_argument_is_not_a_number(setup_budget_test_base):
  function test_realized_total_attribute_is_not_a_number (line 433) | def test_realized_total_attribute_is_not_a_number(setup_budget_test_base):
  function test_realized_total_argument_is_working_as_expected (line 446) | def test_realized_total_argument_is_working_as_expected(setup_budget_tes...
  function test_realized_total_attribute_is_working_as_expected (line 455) | def test_realized_total_attribute_is_working_as_expected(setup_budget_te...
  function test_unit_attribute_is_set_to_none (line 467) | def test_unit_attribute_is_set_to_none(setup_budget_test_base):
  function test_unit_attribute_is_not_a_string (line 476) | def test_unit_attribute_is_not_a_string(setup_budget_test_base):
  function test_unit_attribute_is_working_as_expected (line 487) | def test_unit_attribute_is_working_as_expected(setup_budget_test_base):
  function test_unit_attribute_value_will_be_copied_from_the_supplied_good (line 497) | def test_unit_attribute_value_will_be_copied_from_the_supplied_good(
  function test_amount_argument_is_skipped (line 509) | def test_amount_argument_is_skipped(setup_budget_test_base):
  function test_amount_argument_is_set_to_none (line 516) | def test_amount_argument_is_set_to_none(setup_budget_test_base):
  function test_amount_attribute_is_set_to_none (line 523) | def test_amount_attribute_is_set_to_none(setup_budget_test_base):
  function test_amount_argument_is_not_a_number (line 532) | def test_amount_argument_is_not_a_number(setup_budget_test_base):
  function test_amount_attribute_is_not_a_number (line 544) | def test_amount_attribute_is_not_a_number(setup_budget_test_base):
  function test_amount_argument_is_working_as_expected (line 555) | def test_amount_argument_is_working_as_expected(setup_budget_test_base):
  function test_amount_attribute_is_working_as_expected (line 562) | def test_amount_attribute_is_working_as_expected(setup_budget_test_base):
  function test_good_argument_is_skipped (line 572) | def test_good_argument_is_skipped(setup_budget_test_base):
  function test_good_argument_is_none (line 583) | def test_good_argument_is_none(setup_budget_test_base):
  function test_good_attribute_is_set_to_none (line 598) | def test_good_attribute_is_set_to_none(setup_budget_test_base):
  function test_good_argument_is_not_a_good_instance (line 612) | def test_good_argument_is_not_a_good_instance(setup_budget_test_base):
  function test_good_attribute_is_not_a_good_instance (line 627) | def test_good_attribute_is_not_a_good_instance(setup_budget_test_base):
  function test_good_argument_is_working_as_expected (line 643) | def test_good_argument_is_working_as_expected(setup_budget_test_base):
  function test_good_attribute_is_working_as_expected (line 655) | def test_good_attribute_is_working_as_expected(setup_budget_test_base):
  function test_parent_child_relation (line 665) | def test_parent_child_relation(setup_budget_test_base):

FILE: tests/models/test_client.py
  function setup_client_tests (line 13) | def setup_client_tests():
  function test___auto_name__class_attribute_is_set_to_false (line 109) | def test___auto_name__class_attribute_is_set_to_false():
  function test_users_argument_accepts_an_empty_list (line 114) | def test_users_argument_accepts_an_empty_list(setup_client_tests):
  function test_users_attribute_accepts_an_empty_list (line 123) | def test_users_attribute_accepts_an_empty_list(setup_client_tests):
  function test_users_argument_accepts_only_a_list_of_user_objects (line 130) | def test_users_argument_accepts_only_a_list_of_user_objects(setup_client...
  function test_users_attribute_accepts_only_a_list_of_user_objects (line 145) | def test_users_attribute_accepts_only_a_list_of_user_objects(setup_clien...
  function test_users_attribute_elements_accepts_user_only_append (line 159) | def test_users_attribute_elements_accepts_user_only_append(setup_client_...
  function test_users_attribute_elements_accepts_user_only_setitem (line 172) | def test_users_attribute_elements_accepts_user_only_setitem(setup_client...
  function test_users_argument_is_not_iterable (line 185) | def test_users_argument_is_not_iterable(setup_client_tests):
  function test_users_attribute_is_not_iterable (line 198) | def test_users_attribute_is_not_iterable(setup_client_tests):
  function test_users_attribute_defaults_to_empty_list (line 211) | def test_users_attribute_defaults_to_empty_list(setup_client_tests):
  function test_users_attribute_set_to_none (line 219) | def test_users_attribute_set_to_none(setup_client_tests):
  function test_projects_argument_accepts_an_empty_list (line 227) | def test_projects_argument_accepts_an_empty_list(setup_client_tests):
  function test_projects_attribute_accepts_an_empty_list (line 236) | def test_projects_attribute_accepts_an_empty_list(setup_client_tests):
  function test_projects_argument_accepts_only_a_list_of_project_objects (line 243) | def test_projects_argument_accepts_only_a_list_of_project_objects(setup_...
  function test_projects_attribute_accepts_only_a_list_of_project_objects (line 258) | def test_projects_attribute_accepts_only_a_list_of_project_objects(setup...
  function test_projects_attribute_elements_accepts_project_only_append (line 272) | def test_projects_attribute_elements_accepts_project_only_append(setup_c...
  function test_projects_attribute_elements_accepts_project_only_setitem (line 285) | def test_projects_attribute_elements_accepts_project_only_setitem(setup_...
  function test_projects_argument_is_not_iterable (line 298) | def test_projects_argument_is_not_iterable(setup_client_tests):
  function test_projects_attribute_is_not_iterable (line 311) | def test_projects_attribute_is_not_iterable(setup_client_tests):
  function test_projects_attribute_defaults_to_empty_list (line 324) | def test_projects_attribute_defaults_to_empty_list(setup_client_tests):
  function test_projects_attribute_set_to_none (line 332) | def test_projects_attribute_set_to_none(setup_client_tests):
  function test_user_remove_also_removes_client_from_user (line 341) | def test_user_remove_also_removes_client_from_user(setup_client_tests):
  function test_equality (line 380) | def test_equality(setup_client_tests):
  function test_inequality (line 399) | def test_inequality(setup_client_tests):
  function test_to_tjp_method_is_working_as_expected (line 418) | def test_to_tjp_method_is_working_as_expected(setup_client_tests):
  function test_hash_is_correctly_calculated (line 425) | def test_hash_is_correctly_calculated(setup_client_tests):
  function test_goods_attribute_is_set_to_none (line 434) | def test_goods_attribute_is_set_to_none(setup_client_tests):
  function test_goods_attribute_is_set_to_a_list_of_non_good_instances (line 444) | def test_goods_attribute_is_set_to_a_list_of_non_good_instances(setup_cl...
  function test_goods_attribute_is_working_as_expected (line 457) | def test_goods_attribute_is_working_as_expected(setup_client_tests):

FILE: tests/models/test_client_user.py
  function test_role_argument_is_not_a_role_instance (line 9) | def test_role_argument_is_not_a_role_instance():

FILE: tests/models/test_daily.py
  function setup_daily_tests (line 21) | def setup_daily_tests():
  function test_daily_instance_creation (line 105) | def test_daily_instance_creation(setup_daily_tests):
  function test_files_argument_is_skipped (line 116) | def test_files_argument_is_skipped(setup_daily_tests):
  function test_files_argument_is_none (line 127) | def test_files_argument_is_none(setup_daily_tests):
  function test_files_attribute_is_set_to_none (line 139) | def test_files_attribute_is_set_to_none(setup_daily_tests):
  function test_files_argument_is_not_a_list_instance (line 151) | def test_files_argument_is_not_a_list_instance(setup_daily_tests):
  function test_files_argument_is_not_a_list_of_file_instances (line 168) | def test_files_argument_is_not_a_list_of_file_instances(setup_daily_tests):
  function test_files_argument_is_working_as_expected (line 185) | def test_files_argument_is_working_as_expected(setup_daily_tests):
  function test_files_attribute_is_working_as_expected (line 198) | def test_files_attribute_is_working_as_expected(setup_daily_tests):
  function test_versions_attribute_is_read_only (line 211) | def test_versions_attribute_is_read_only(setup_daily_tests):
  function setup_daily_db_tests (line 224) | def setup_daily_db_tests(setup_postgresql_db):
  function test_tasks_attribute_will_return_a_list_of_tasks (line 314) | def test_tasks_attribute_will_return_a_list_of_tasks(setup_daily_db_tests):
  function test_versions_attribute_will_return_a_list_of_versions (line 328) | def test_versions_attribute_will_return_a_list_of_versions(setup_daily_d...
  function test_rank_argument_is_skipped (line 342) | def test_rank_argument_is_skipped():
  function test_daily_argument_is_not_a_daily_instance (line 348) | def test_daily_argument_is_not_a_daily_instance(setup_daily_tests):

FILE: tests/models/test_department.py
  function setup_department_tests (line 15) | def setup_department_tests():
  function test___auto_name__class_attribute_is_set_to_false (line 86) | def test___auto_name__class_attribute_is_set_to_false():
  function test___hash___value_is_correctly_calculated (line 91) | def test___hash___value_is_correctly_calculated(setup_department_tests):
  function test_users_argument_accepts_an_empty_list (line 103) | def test_users_argument_accepts_an_empty_list(setup_department_tests):
  function test_users_attribute_accepts_an_empty_list (line 112) | def test_users_attribute_accepts_an_empty_list(setup_department_tests):
  function test_users_argument_accepts_only_a_list_of_user_objects (line 119) | def test_users_argument_accepts_only_a_list_of_user_objects(setup_depart...
  function test_users_attribute_accepts_only_a_list_of_user_objects (line 134) | def test_users_attribute_accepts_only_a_list_of_user_objects(setup_depar...
  function test_users_attribute_elements_accepts_user_only_1 (line 148) | def test_users_attribute_elements_accepts_user_only_1(setup_department_t...
  function test_users_attribute_elements_accepts_user_only_2 (line 161) | def test_users_attribute_elements_accepts_user_only_2(setup_department_t...
  function test_users_argument_is_not_iterable (line 174) | def test_users_argument_is_not_iterable(setup_department_tests):
  function test_users_attribute_is_not_iterable (line 187) | def test_users_attribute_is_not_iterable(setup_department_tests):
  function test_users_attribute_defaults_to_empty_list (line 199) | def test_users_attribute_defaults_to_empty_list(setup_department_tests):
  function test_users_attribute_set_to_none (line 207) | def test_users_attribute_set_to_none(setup_department_tests):
  function test_equality (line 216) | def test_equality(setup_department_tests):
  function test_inequality (line 234) | def test_inequality(setup_department_tests):
  function setup_department_db_tests (line 253) | def setup_department_db_tests(setup_postgresql_db):
  function test_user_role_attribute (line 325) | def test_user_role_attribute(setup_department_db_tests):
  function test_tjp_id_is_working_as_expected (line 348) | def test_tjp_id_is_working_as_expected(setup_department_db_tests):
  function test_to_tjp_is_working_as_expected (line 355) | def test_to_tjp_is_working_as_expected(setup_department_db_tests):

FILE: tests/models/test_department_user.py
  function test_role_argument_is_not_a_role_instance (line 9) | def test_role_argument_is_not_a_role_instance():

FILE: tests/models/test_dependency_target.py
  function test_it_is_an_enum (line 18) | def test_it_is_an_enum(target):
  function test_enum_values (line 30) | def test_enum_values(target, expected_value):
  function test_enum_names (line 42) | def test_enum_names(target, expected_name):
  function test_enum_as_str (line 54) | def test_enum_as_str(target, expected_value):
  function test_to_target_target_is_skipped (line 59) | def test_to_target_target_is_skipped():
  function test_to_target_target_is_none (line 75) | def test_to_target_target_is_none():
  function test_to_target_target_is_not_a_str (line 84) | def test_to_target_target_is_not_a_str():
  function test_to_target_target_is_not_a_valid_str (line 94) | def test_to_target_target_is_not_a_valid_str():
  function test_to_target_is_working_properly (line 121) | def test_to_target_is_working_properly(target_name, target):
  function test_cache_ok_is_true_in_type_decorator (line 126) | def test_cache_ok_is_true_in_type_decorator():

FILE: tests/models/test_entity.py
  function setup_entity_tests (line 12) | def setup_entity_tests():
  function test___auto_name__class_attribute_is_set_to_true (line 49) | def test___auto_name__class_attribute_is_set_to_true():
  function test_notes_argument_being_omitted (line 54) | def test_notes_argument_being_omitted(setup_entity_tests):
  function test_notes_argument_is_set_to_none (line 63) | def test_notes_argument_is_set_to_none(setup_entity_tests):
  function test_notes_attribute_is_set_to_none (line 72) | def test_notes_attribute_is_set_to_none(setup_entity_tests):
  function test_notes_argument_set_to_something_other_than_a_list (line 81) | def test_notes_argument_set_to_something_other_than_a_list(setup_entity_...
  function test_notes_attribute_set_to_something_other_than_a_list (line 95) | def test_notes_attribute_set_to_something_other_than_a_list(setup_entity...
  function test_notes_argument_set_to_a_list_of_other_objects (line 107) | def test_notes_argument_set_to_a_list_of_other_objects(setup_entity_tests):
  function test_notes_attribute_set_to_a_list_of_other_objects (line 121) | def test_notes_attribute_set_to_a_list_of_other_objects(setup_entity_tes...
  function test_notes_attribute_works_as_expected (line 133) | def test_notes_attribute_works_as_expected(setup_entity_tests):
  function test_notes_attribute_element_is_set_to_non_note_object (line 141) | def test_notes_attribute_element_is_set_to_non_note_object(setup_entity_...
  function test_tags_argument_being_omitted (line 152) | def test_tags_argument_being_omitted(setup_entity_tests):
  function test_tags_argument_being_initialized_as_an_empty_list (line 162) | def test_tags_argument_being_initialized_as_an_empty_list(setup_entity_t...
  function test_tags_argument_set_to_something_other_than_a_list (line 173) | def test_tags_argument_set_to_something_other_than_a_list(setup_entity_t...
  function test_tags_attribute_works_as_expected (line 186) | def test_tags_attribute_works_as_expected(setup_entity_tests):
  function test_tags_attribute_element_is_set_to_non_tag_object (line 194) | def test_tags_attribute_element_is_set_to_non_tag_object(setup_entity_te...
  function test_tags_attribute_set_to_none (line 205) | def test_tags_attribute_set_to_none(setup_entity_tests):
  function test_equality (line 214) | def test_equality(setup_entity_tests):
  function test_inequality (line 232) | def test_inequality(setup_entity_tests):

FILE: tests/models/test_entity_group.py
  function setup_entity_group_tests (line 21) | def setup_entity_group_tests():
  function test_entities_argument_is_skipped (line 157) | def test_entities_argument_is_skipped():
  function test_entities_argument_is_none (line 163) | def test_entities_argument_is_none():
  function test_entities_argument_is_not_a_list (line 169) | def test_entities_argument_is_not_a_list():
  function test_entities_argument_is_not_a_list_of_simple_entity_instances (line 177) | def test_entities_argument_is_not_a_list_of_simple_entity_instances():
  function test_entities_argument_is_working_as_expected (line 187) | def test_entities_argument_is_working_as_expected(setup_entity_group_tes...
  function test__eq__is_working_as_expected_with_same_data (line 195) | def test__eq__is_working_as_expected_with_same_data(setup_entity_group_t...
  function test__eq__is_working_as_expected_with_different_data (line 204) | def test__eq__is_working_as_expected_with_different_data(setup_entity_gr...
  function test__hash__is_working_as_expected (line 217) | def test__hash__is_working_as_expected(setup_entity_group_tests):

FILE: tests/models/test_file.py
  function setup_file_tests (line 13) | def setup_file_tests():
  function test___auto_name__class_attribute_is_set_to_true (line 63) | def test___auto_name__class_attribute_is_set_to_true():
  function test_full_path_argument_is_none (line 68) | def test_full_path_argument_is_none(setup_file_tests):
  function test_full_path_attribute_is_set_to_none (line 76) | def test_full_path_attribute_is_set_to_none(setup_file_tests):
  function test_full_path_argument_is_empty_an_empty_string (line 82) | def test_full_path_argument_is_empty_an_empty_string(setup_file_tests):
  function test_full_path_attribute_is_set_to_empty_string (line 90) | def test_full_path_attribute_is_set_to_empty_string(setup_file_tests):
  function test_full_path_argument_is_not_a_string (line 97) | def test_full_path_argument_is_not_a_string(setup_file_tests):
  function test_full_path_attribute_is_not_a_string (line 107) | def test_full_path_attribute_is_not_a_string(setup_file_tests):
  function test_full_path_windows_to_other_conversion (line 117) | def test_full_path_windows_to_other_conversion(setup_file_tests):
  function test_original_filename_argument_is_none (line 126) | def test_original_filename_argument_is_none(setup_file_tests):
  function test_original_filename_attribute_is_set_to_none (line 135) | def test_original_filename_attribute_is_set_to_none(setup_file_tests):
  function test_original_filename_argument_is_empty_string (line 143) | def test_original_filename_argument_is_empty_string(setup_file_tests):
  function test_original_filename_attribute_set_to_empty_string (line 152) | def test_original_filename_attribute_set_to_empty_string(setup_file_tests):
  function test_original_filename_argument_accepts_string_only (line 160) | def test_original_filename_argument_accepts_string_only(setup_file_tests):
  function test_original_filename_attribute_accepts_string_only (line 171) | def test_original_filename_attribute_accepts_string_only(setup_file_tests):
  function test_original_filename_argument_is_working_as_expected (line 181) | def test_original_filename_argument_is_working_as_expected(setup_file_te...
  function test_original_filename_attribute_is_working_as_expected (line 187) | def test_original_filename_attribute_is_working_as_expected(setup_file_t...
  function test_equality_of_two_files (line 196) | def test_equality_of_two_files(setup_file_tests):
  function test_inequality_of_two_files (line 210) | def test_inequality_of_two_files(setup_file_tests):
  function test_plural_class_name (line 225) | def test_plural_class_name(setup_file_tests):
  function test_path_attribute_is_set_to_none (line 231) | def test_path_attribute_is_set_to_none(setup_file_tests):
  function test_path_attribute_is_set_to_empty_string (line 239) | def test_path_attribute_is_set_to_empty_string(setup_file_tests):
  function test_path_attribute_is_set_to_a_value_other_then_string (line 247) | def test_path_attribute_is_set_to_a_value_other_then_string(setup_file_t...
  function test_path_attribute_value_comes_from_full_path (line 255) | def test_path_attribute_value_comes_from_full_path(setup_file_tests):
  function test_path_attribute_updates_the_full_path_attribute (line 261) | def test_path_attribute_updates_the_full_path_attribute(setup_file_tests):
  function test_filename_attribute_is_set_to_none (line 273) | def test_filename_attribute_is_set_to_none(setup_file_tests):
  function test_filename_attribute_is_set_to_a_value_other_then_string (line 280) | def test_filename_attribute_is_set_to_a_value_other_then_string(setup_fi...
  function test_filename_attribute_is_set_to_empty_string (line 288) | def test_filename_attribute_is_set_to_empty_string(setup_file_tests):
  function test_filename_attribute_value_comes_from_full_path (line 295) | def test_filename_attribute_value_comes_from_full_path(setup_file_tests):
  function test_filename_attribute_updates_the_full_path_attribute (line 301) | def test_filename_attribute_updates_the_full_path_attribute(setup_file_t...
  function test_filename_attribute_changes_also_the_extension (line 311) | def test_filename_attribute_changes_also_the_extension(setup_file_tests):
  function test_extension_attribute_is_set_to_none (line 319) | def test_extension_attribute_is_set_to_none(setup_file_tests):
  function test_extension_attribute_is_set_to_empty_string (line 326) | def test_extension_attribute_is_set_to_empty_string(setup_file_tests):
  function test_extension_attribute_is_set_to_a_value_other_then_string (line 333) | def test_extension_attribute_is_set_to_a_value_other_then_string(setup_f...
  function test_extension_attribute_value_comes_from_full_path (line 341) | def test_extension_attribute_value_comes_from_full_path(setup_file_tests):
  function test_extension_attribute_updates_the_full_path_attribute (line 347) | def test_extension_attribute_updates_the_full_path_attribute(setup_file_...
  function test_extension_attribute_updates_the_full_path_attribute_with_the_dot (line 360) | def test_extension_attribute_updates_the_full_path_attribute_with_the_dot(
  function test_extension_attribute_is_also_change_the_filename_attribute (line 376) | def test_extension_attribute_is_also_change_the_filename_attribute(setup...
  function test_format_path_converts_bytes_to_strings (line 386) | def test_format_path_converts_bytes_to_strings(setup_file_tests):
  function test__hash__is_working_as_expected (line 395) | def test__hash__is_working_as_expected(setup_file_tests):
  function test_references_arg_is_skipped (line 403) | def test_references_arg_is_skipped(setup_file_tests):
  function test_references_arg_is_none (line 411) | def test_references_arg_is_none(setup_file_tests):
  function test_references_attr_is_none (line 419) | def test_references_attr_is_none(setup_file_tests):
  function test_references_arg_is_not_a_list_of_file_instances (line 427) | def test_references_arg_is_not_a_list_of_file_instances(setup_file_tests):
  function test_references_attr_is_not_a_list_of_file_instances (line 441) | def test_references_attr_is_not_a_list_of_file_instances(setup_file_tests):
  function test_references_attr_is_working_as_expected (line 454) | def test_references_attr_is_working_as_expected(setup_file_tests):
  function test_created_with_argument_can_be_skipped (line 467) | def test_created_with_argument_can_be_skipped(setup_file_tests):
  function test_created_with_argument_can_be_none (line 474) | def test_created_with_argument_can_be_none(setup_file_tests):
  function test_created_with_attribute_can_be_set_to_none (line 481) | def test_created_with_attribute_can_be_set_to_none(setup_file_tests):
  function test_created_with_argument_accepts_only_string_or_none (line 487) | def test_created_with_argument_accepts_only_string_or_none(setup_file_te...
  function test_created_with_attribute_accepts_only_string_or_none (line 498) | def test_created_with_attribute_accepts_only_string_or_none(setup_file_t...
  function test_created_with_argument_is_working_as_expected (line 509) | def test_created_with_argument_is_working_as_expected(setup_file_tests):
  function test_created_with_attribute_is_working_as_expected (line 518) | def test_created_with_attribute_is_working_as_expected(setup_file_tests):
  function test_walk_references_is_working_as_expected_in_dfs_mode (line 527) | def test_walk_references_is_working_as_expected_in_dfs_mode(setup_file_t...
  function test_absolute_path_is_read_only (line 598) | def test_absolute_path_is_read_only(setup_file_tests):
  function test_absolute_path_returns_the_absolute_path (line 612) | def test_absolute_path_returns_the_absolute_path(setup_file_tests):
  function test_absolute_full_path_is_read_only (line 622) | def test_absolute_full_path_is_read_only(setup_file_tests):
  function test_absolute_full_path_returns_the_absolute_full_path (line 636) | def test_absolute_full_path_returns_the_absolute_full_path(setup_file_te...

FILE: tests/models/test_filename_template.py
  function setup_filename_template_tests (line 22) | def setup_filename_template_tests():
  function test___auto_name__class_attribute_is_set_to_false (line 40) | def test___auto_name__class_attribute_is_set_to_false():
  function test_filename_template_is_not_strictly_typed (line 45) | def test_filename_template_is_not_strictly_typed(setup_filename_template...
  function test_target_entity_type_argument_is_skipped (line 54) | def test_target_entity_type_argument_is_skipped(setup_filename_template_...
  function test_target_entity_type_argument_is_none (line 64) | def test_target_entity_type_argument_is_none(setup_filename_template_tes...
  function test_target_entity_type_attribute_is_read_only (line 74) | def test_target_entity_type_attribute_is_read_only(setup_filename_templa...
  function test_target_entity_type_argument_accepts_classes (line 95) | def test_target_entity_type_argument_accepts_classes(setup_filename_temp...
  function test_target_entity_type_attribute_is_converted_to_a_string_if_given_as_a_class (line 102) | def test_target_entity_type_attribute_is_converted_to_a_string_if_given_...
  function test_path_argument_is_skipped (line 112) | def test_path_argument_is_skipped(setup_filename_template_tests):
  function test_path_argument_skipped_path_attribute_is_empty_string (line 120) | def test_path_argument_skipped_path_attribute_is_empty_string(
  function test_path_argument_is_none_path_attribute_is_empty_string (line 130) | def test_path_argument_is_none_path_attribute_is_empty_string(
  function test_path_argument_is_empty_string (line 140) | def test_path_argument_is_empty_string(setup_filename_template_tests):
  function test_path_attribute_is_empty_string (line 148) | def test_path_attribute_is_empty_string(setup_filename_template_tests):
  function test_path_argument_is_not_string (line 154) | def test_path_argument_is_not_string(setup_filename_template_tests):
  function test_path_attribute_is_not_string (line 169) | def test_path_attribute_is_not_string(setup_filename_template_tests):
  function test_filename_argument_is_skipped (line 183) | def test_filename_argument_is_skipped(setup_filename_template_tests):
  function test_filename_argument_skipped_filename_attribute_is_empty_string (line 191) | def test_filename_argument_skipped_filename_attribute_is_empty_string(
  function test_filename_argument_is_none_filename_attribute_is_empty_string (line 201) | def test_filename_argument_is_none_filename_attribute_is_empty_string(
  function test_filename_argument_is_empty_string (line 211) | def test_filename_argument_is_empty_string(setup_filename_template_tests):
  function test_filename_attribute_is_empty_string (line 219) | def test_filename_attribute_is_empty_string(setup_filename_template_tests):
  function test_filename_argument_is_not_string (line 225) | def test_filename_argument_is_not_string(setup_filename_template_tests):
  function test_filename_attribute_is_not_string (line 240) | def test_filename_attribute_is_not_string(setup_filename_template_tests):
  function test_equality (line 254) | def test_equality(setup_filename_template_tests):
  function test_inequality (line 277) | def test_inequality(setup_filename_template_tests):
  function test_naming_case (line 300) | def test_naming_case(setup_postgresql_db):
  function test__hash__is_working_as_expected (line 361) | def test__hash__is_working_as_expected(setup_filename_template_tests):

FILE: tests/models/test_generic.py
  function test_make_plural_is_working_as_expected (line 45) | def test_make_plural_is_working_as_expected(test_value, expected):
  function test_utc_to_local_is_working_as_expected (line 50) | def test_utc_to_local_is_working_as_expected():
  function test_local_to_utc_is_working_as_expected (line 71) | def test_local_to_utc_is_working_as_expected():

FILE: tests/models/test_good.py
  function setup_good_tests (line 10) | def setup_good_tests():
  function test_cost_argument_is_skipped (line 17) | def test_cost_argument_is_skipped(setup_good_tests):
  function test_cost_argument_is_none (line 25) | def test_cost_argument_is_none(setup_good_tests):
  function test_cost_attribute_is_none (line 33) | def test_cost_attribute_is_none(setup_good_tests):
  function test_cost_argument_is_not_a_number (line 42) | def test_cost_argument_is_not_a_number(setup_good_tests):
  function test_cost_attribute_is_not_a_number (line 54) | def test_cost_attribute_is_not_a_number(setup_good_tests):
  function test_cost_argument_is_zero (line 66) | def test_cost_argument_is_zero(setup_good_tests):
  function test_cost_attribute_is_zero (line 74) | def test_cost_attribute_is_zero(setup_good_tests):
  function test_cost_argument_is_negative (line 83) | def test_cost_argument_is_negative(setup_good_tests):
  function test_cost_attribute_is_negative (line 93) | def test_cost_attribute_is_negative(setup_good_tests):
  function test_cost_argument_is_working_as_expected (line 103) | def test_cost_argument_is_working_as_expected(setup_good_tests):
  function test_cost_attribute_is_working_as_expected (line 112) | def test_cost_attribute_is_working_as_expected(setup_good_tests):
  function test_msrp_argument_is_skipped (line 123) | def test_msrp_argument_is_skipped(setup_good_tests):
  function test_msrp_argument_is_none (line 131) | def test_msrp_argument_is_none(setup_good_tests):
  function test_msrp_attribute_is_none (line 139) | def test_msrp_attribute_is_none(setup_good_tests):
  function test_msrp_argument_is_not_a_number (line 148) | def test_msrp_argument_is_not_a_number(setup_good_tests):
  function test_msrp_attribute_is_not_a_number (line 160) | def test_msrp_attribute_is_not_a_number(setup_good_tests):
  function test_msrp_argument_is_zero (line 172) | def test_msrp_argument_is_zero(setup_good_tests):
  function test_msrp_attribute_is_zero (line 180) | def test_msrp_attribute_is_zero(setup_good_tests):
  function test_msrp_argument_is_negative (line 189) | def test_msrp_argument_is_negative(setup_good_tests):
  function test_msrp_attribute_is_negative (line 199) | def test_msrp_attribute_is_negative(setup_good_tests):
  function test_msrp_argument_is_working_as_expected (line 209) | def test_msrp_argument_is_working_as_expected(setup_good_tests):
  function test_msrp_attribute_is_working_as_expected (line 218) | def test_msrp_attribute_is_working_as_expected(setup_good_tests):
  function test_unit_argument_is_skipped (line 229) | def test_unit_argument_is_skipped(setup_good_tests):
  function test_unit_argument_is_none (line 237) | def test_unit_argument_is_none(setup_good_tests):
  function test_unit_attribute_is_set_to_none (line 245) | def test_unit_attribute_is_set_to_none(setup_good_tests):
  function test_unit_argument_is_not_a_string (line 254) | def test_unit_argument_is_not_a_string(setup_good_tests):
  function test_unit_attribute_is_not_a_string (line 264) | def test_unit_attribute_is_not_a_string(setup_good_tests):
  function test_unit_argument_is_working_as_expected (line 274) | def test_unit_argument_is_working_as_expected(setup_good_tests):
  function test_unit_attribute_is_working_as_expected (line 283) | def test_unit_attribute_is_working_as_expected(setup_good_tests):
  function test_client_argument_is_skipped (line 293) | def test_client_argument_is_skipped(setup_good_tests):
  function test_client_argument_is_none (line 302) | def test_client_argument_is_none(setup_good_tests):
  function test_client_argument_is_not_a_client_instance (line 311) | def test_client_argument_is_not_a_client_instance(setup_good_tests):
  function test_client_attribute_is_set_to_a_value_other_than_a_client (line 324) | def test_client_attribute_is_set_to_a_value_other_than_a_client(setup_go...
  function test_client_argument_is_working_as_expected (line 337) | def test_client_argument_is_working_as_expected(setup_good_tests):
  function test_client_attribute_is_working_as_expected (line 346) | def test_client_attribute_is_working_as_expected(setup_good_tests):

FILE: tests/models/test_group.py
  function setup_group_tests (line 10) | def setup_group_tests():
  function test___auto_name__class_attribute_is_set_to_false (line 45) | def test___auto_name__class_attribute_is_set_to_false():
  function test_users_argument_is_skipped (line 50) | def test_users_argument_is_skipped(setup_group_tests):
  function test_users_argument_is_not_a_list_of_user_instances (line 58) | def test_users_argument_is_not_a_list_of_user_instances(setup_group_tests):
  function test_users_attribute_is_not_a_list_of_user_instances (line 71) | def test_users_attribute_is_not_a_list_of_user_instances(setup_group_tes...
  function test_users_argument_updates_the_groups_attribute_in_the_given_user_instances (line 83) | def test_users_argument_updates_the_groups_attribute_in_the_given_user_i...
  function test_users_attribute_updates_the_groups_attribute_in_the_given_user_instances (line 94) | def test_users_attribute_updates_the_groups_attribute_in_the_given_user_...
  function test_permissions_argument_is_working_as_expected (line 105) | def test_permissions_argument_is_working_as_expected(setup_group_tests):
  function test_hash_value (line 122) | def test_hash_value(setup_group_tests):

FILE: tests/models/test_image_format.py
  function setup_image_format_tests (line 11) | def setup_image_format_tests():
  function test___auto_name__class_attribute_is_set_to_false (line 28) | def test___auto_name__class_attribute_is_set_to_false():
  function test_width_argument_accepts_int_or_float_only (line 33) | def test_width_argument_accepts_int_or_float_only(setup_image_format_tes...
  function test_width_attribute_int_or_float (line 48) | def test_width_attribute_int_or_float(setup_image_format_tests):
  function test_width_argument_float_to_int_conversion (line 61) | def test_width_argument_float_to_int_conversion(setup_image_format_tests):
  function test_width_attribute_float_to_int_conversion (line 70) | def test_width_attribute_float_to_int_conversion(setup_image_format_tests):
  function test_width_argument_being_zero (line 78) | def test_width_argument_being_zero(setup_image_format_tests):
  function test_width_attribute_being_zero (line 89) | def test_width_attribute_being_zero(setup_image_format_tests):
  function test_width_argument_being_negative (line 99) | def test_width_argument_being_negative(setup_image_format_tests):
  function test_width_attribute_being_negative (line 109) | def test_width_attribute_being_negative(setup_image_format_tests):
  function test_height_argument_int_or_float (line 119) | def test_height_argument_int_or_float(setup_image_format_tests):
  function test_height_attribute_int_or_float (line 132) | def test_height_attribute_int_or_float(setup_image_format_tests):
  function test_height_argument_float_to_int_conversion (line 145) | def test_height_argument_float_to_int_conversion(setup_image_format_tests):
  function test_height_attribute_float_to_int_conversion (line 153) | def test_height_attribute_float_to_int_conversion(setup_image_format_tes...
  function test_height_argument_being_zero (line 161) | def test_height_argument_being_zero(setup_image_format_tests):
  function test_height_attribute_being_zero (line 170) | def test_height_attribute_being_zero(setup_image_format_tests):
  function test_height_argument_being_negative (line 178) | def test_height_argument_being_negative(setup_image_format_tests):
  function test_height_attribute_being_negative (line 187) | def test_height_attribute_being_negative(setup_image_format_tests):
  function test_device_aspect_attribute_float (line 195) | def test_device_aspect_attribute_float(setup_image_format_tests):
  function test_device_aspect_ratio_correctly_calculated_1 (line 201) | def test_device_aspect_ratio_correctly_calculated_1(setup_image_format_t...
  function test_device_aspect_ratio_correctly_calculated_2 (line 224) | def test_device_aspect_ratio_correctly_calculated_2(setup_image_format_t...
  function test_device_aspect_attribute_updates (line 245) | def test_device_aspect_attribute_updates(setup_image_format_tests):
  function test_device_aspect_attribute_write_protected (line 273) | def test_device_aspect_attribute_write_protected(setup_image_format_tests):
  function test_pixel_aspect_int_float (line 292) | def test_pixel_aspect_int_float(setup_image_format_tests):
  function test_pixel_aspect_int_float_2 (line 307) | def test_pixel_aspect_int_float_2(setup_image_format_tests):
  function test_pixel_aspect_int_float_3 (line 315) | def test_pixel_aspect_int_float_3(setup_image_format_tests):
  function test_pixel_aspect_float_conversion (line 323) | def test_pixel_aspect_float_conversion(setup_image_format_tests):
  function test_pixel_aspect_argument_zero (line 333) | def test_pixel_aspect_argument_zero(setup_image_format_tests):
  function test_pixel_aspect_attribute_zero (line 345) | def test_pixel_aspect_attribute_zero(setup_image_format_tests):
  function test_pixel_aspect_argument_negative_float (line 355) | def test_pixel_aspect_argument_negative_float(setup_image_format_tests):
  function test_pixel_aspect_argument_negative_int (line 367) | def test_pixel_aspect_argument_negative_int(setup_image_format_tests):
  function test_pixel_aspect_attribute_negative_integer (line 379) | def test_pixel_aspect_attribute_negative_integer(setup_image_format_tests):
  function test_pixel_aspect_attribute_negative_float (line 390) | def test_pixel_aspect_attribute_negative_float(setup_image_format_tests):
  function test_pixel_aspect_attribute_if_being_initialized_correctly (line 400) | def test_pixel_aspect_attribute_if_being_initialized_correctly(
  function test_print_resolution_omit (line 411) | def test_print_resolution_omit(setup_image_format_tests):
  function test_print_resolution_argument_accepts_int_float_only (line 422) | def test_print_resolution_argument_accepts_int_float_only(setup_image_fo...
  function test_print_resolution_argument_accepts_int_float_only_2 (line 437) | def test_print_resolution_argument_accepts_int_float_only_2(setup_image_...
  function test_print_resolution_argument_accepts_int_float_only_3 (line 446) | def test_print_resolution_argument_accepts_int_float_only_3(setup_image_...
  function test_print_resolution_argument_zero (line 456) | def test_print_resolution_argument_zero(setup_image_format_tests):
  function test_print_resolution_attribute_zero (line 468) | def test_print_resolution_attribute_zero(setup_image_format_tests):
  function test_print_resolution_argument_negative_int (line 478) | def test_print_resolution_argument_negative_int(setup_image_format_tests):
  function test_print_resolution_argument_negative_float (line 489) | def test_print_resolution_argument_negative_float(setup_image_format_tes...
  function test_print_resolution_attribute_negative_int (line 500) | def test_print_resolution_attribute_negative_int(setup_image_format_tests):
  function test_print_resolution_attribute_negative_float (line 509) | def test_print_resolution_attribute_negative_float(setup_image_format_te...
  function test_equality (line 518) | def test_equality(setup_image_format_tests):
  function test_inequality (line 537) | def test_inequality(setup_image_format_tests):
  function test_plural_class_name (line 558) | def test_plural_class_name(setup_image_format_tests):
  function test_hash_value (line 564) | def test_hash_value(setup_image_format_tests):

FILE: tests/models/test_invoice.py
  function setup_invoice_tests (line 24) | def setup_invoice_tests():
  function test_creating_an_invoice_instance (line 127) | def test_creating_an_invoice_instance(setup_invoice_tests):
  function test_budget_argument_is_skipped (line 140) | def test_budget_argument_is_skipped(setup_invoice_tests):
  function test_budget_argument_is_none (line 151) | def test_budget_argument_is_none(setup_invoice_tests):
  function test_budget_attribute_is_set_to_none (line 161) | def test_budget_attribute_is_set_to_none(setup_invoice_tests):
  function test_budget_argument_is_not_a_budget_instance (line 175) | def test_budget_argument_is_not_a_budget_instance(setup_invoice_tests):
  function test_budget_attribute_is_set_to_a_value_other_than_a_budget_instance (line 190) | def test_budget_attribute_is_set_to_a_value_other_than_a_budget_instance(
  function test_budget_argument_is_working_as_expected (line 206) | def test_budget_argument_is_working_as_expected(setup_invoice_tests):
  function test_client_argument_is_skipped (line 215) | def test_client_argument_is_skipped(setup_invoice_tests):
  function test_client_argument_is_none (line 225) | def test_client_argument_is_none(setup_invoice_tests):
  function test_client_attribute_is_set_to_none (line 235) | def test_client_attribute_is_set_to_none(setup_invoice_tests):
  function test_client_argument_is_not_a_client_instance (line 248) | def test_client_argument_is_not_a_client_instance(setup_invoice_tests):
  function test_client_attribute_is_set_to_a_value_other_than_a_client_instance (line 263) | def test_client_attribute_is_set_to_a_value_other_than_a_client_instance(
  function test_client_argument_is_working_as_expected (line 278) | def test_client_argument_is_working_as_expected(setup_invoice_tests):
  function test_client_attribute_is_working_as_expected (line 287) | def test_client_attribute_is_working_as_expected(setup_invoice_tests):

FILE: tests/models/test_local_session.py
  function setup_local_session_tester (line 20) | def setup_local_session_tester():
  function test_save_serializes_the_class_itself (line 27) | def test_save_serializes_the_class_itself(setup_local_session_tester):
  function test_save_serializes_the_class_itself_with_real_data (line 38) | def test_save_serializes_the_class_itself_with_real_data(setup_local_ses...
  function test_local_session_initialized_with_previous_session_data (line 50) | def test_local_session_initialized_with_previous_session_data(
  function test_delete_will_delete_the_session_cache (line 71) | def test_delete_will_delete_the_session_cache(setup_local_session_tester):
  function test_local_session_will_not_use_the_stored_data_if_it_is_invalid (line 112) | def test_local_session_will_not_use_the_stored_data_if_it_is_invalid(
  function test_logged_in_user_returns_the_stored_user_instance_from_last_time (line 155) | def test_logged_in_user_returns_the_stored_user_instance_from_last_time(

FILE: tests/models/test_message.py
  function test_message_instance_creation (line 7) | def test_message_instance_creation():

FILE: tests/models/test_note.py
  function setup_note_tests (line 10) | def setup_note_tests():
  function test___auto_name__class_attribute_is_set_to_true (line 23) | def test___auto_name__class_attribute_is_set_to_true():
  function test_content_argument_is_missing (line 28) | def test_content_argument_is_missing(setup_note_tests):
  function test_content_argument_is_set_to_none (line 36) | def test_content_argument_is_set_to_none(setup_note_tests):
  function test_content_attribute_is_set_to_none (line 44) | def test_content_attribute_is_set_to_none(setup_note_tests):
  function test_content_argument_is_set_to_empty_string (line 51) | def test_content_argument_is_set_to_empty_string(setup_note_tests):
  function test_content_attribute_is_set_to_empty_string (line 58) | def test_content_attribute_is_set_to_empty_string(setup_note_tests):
  function test_content_argument_is_set_to_something_other_than_a_string (line 65) | def test_content_argument_is_set_to_something_other_than_a_string(setup_...
  function test_content_attribute_is_set_to_something_other_than_a_string (line 75) | def test_content_attribute_is_set_to_something_other_than_a_string(setup...
  function test_content_attribute_is_working_as_expected (line 84) | def test_content_attribute_is_working_as_expected(setup_note_tests):
  function test_equality_operator (line 95) | def test_equality_operator(setup_note_tests):
  function test_inequality_operator (line 106) | def test_inequality_operator(setup_note_tests):
  function test_plural_class_name (line 117) | def test_plural_class_name(setup_note_tests):
  function test__hash__is_working_as_expected (line 123) | def test__hash__is_working_as_expected(setup_note_tests):

FILE: tests/models/test_payment.py
  function setup_payment_tests (line 21) | def setup_payment_tests():
  function test_creating_a_payment_instance (line 128) | def test_creating_a_payment_instance(setup_payment_tests):
  function test_invoice_argument_is_skipped (line 135) | def test_invoice_argument_is_skipped(setup_payment_tests):
  function test_invoice_argument_is_none (line 146) | def test_invoice_argument_is_none(setup_payment_tests):
  function test_invoice_attribute_is_none (line 156) | def test_invoice_attribute_is_none(setup_payment_tests):
  function test_invoice_argument_is_not_an_invoice_instance (line 169) | def test_invoice_argument_is_not_an_invoice_instance():
  function test_invoice_attribute_is_set_to_a_value_other_than_an_invoice_instance (line 180) | def test_invoice_attribute_is_set_to_a_value_other_than_an_invoice_insta...
  function test_invoice_argument_is_working_as_expected (line 196) | def test_invoice_argument_is_working_as_expected(setup_payment_tests):
  function test_invoice_attribute_is_working_as_expected (line 203) | def test_invoice_attribute_is_working_as_expected(setup_payment_tests):

FILE: tests/models/test_permission.py
  function setup_permission_tests (line 12) | def setup_permission_tests():
  function test_access_argument_is_skipped (line 20) | def test_access_argument_is_skipped(setup_permission_tests):
  function test_access_argument_is_none (line 32) | def test_access_argument_is_none(setup_permission_tests):
  function test_access_argument_accepts_only_allow_or_deny_as_value (line 44) | def test_access_argument_accepts_only_allow_or_deny_as_value(setup_permi...
  function test_access_argument_is_setting_access_attribute_value (line 53) | def test_access_argument_is_setting_access_attribute_value(setup_permiss...
  function test_access_attribute_is_read_only (line 59) | def test_access_attribute_is_read_only(setup_permission_tests):
  function test_action_argument_is_skipped_will_raise_a_type_error (line 79) | def test_action_argument_is_skipped_will_raise_a_type_error(setup_permis...
  function test_action_argument_is_none (line 91) | def test_action_argument_is_none(setup_permission_tests):
  function test_action_argument_accepts_default_values_only (line 103) | def test_action_argument_accepts_default_values_only(setup_permission_te...
  function test_action_argument_is_setting_the_argument_attribute (line 116) | def test_action_argument_is_setting_the_argument_attribute(setup_permiss...
  function test_action_attribute_is_read_only (line 122) | def test_action_attribute_is_read_only(setup_permission_tests):
  function test_class_name_argument_skipped (line 142) | def test_class_name_argument_skipped(setup_permission_tests):
  function test_class_name_argument_is_none (line 155) | def test_class_name_argument_is_none(setup_permission_tests):
  function test_class_name_argument_is_not_a_string (line 167) | def test_class_name_argument_is_not_a_string(setup_permission_tests):
  function test_class_name_argument_is_setting_the_class_name_attribute_value (line 179) | def test_class_name_argument_is_setting_the_class_name_attribute_value(
  function test_class_name_attribute_is_read_only (line 187) | def test_class_name_attribute_is_read_only(setup_permission_tests):
  function test_hash_value (line 207) | def test_hash_value(setup_permission_tests):

FILE: tests/models/test_price_list.py
  function setup_price_list_tests (line 10) | def setup_price_list_tests():
  function test_goods_argument_is_skipped (line 19) | def test_goods_argument_is_skipped(setup_price_list_tests):
  function test_goods_argument_is_none (line 26) | def test_goods_argument_is_none(setup_price_list_tests):
  function test_goods_attribute_is_none (line 34) | def test_goods_attribute_is_none(setup_price_list_tests):
  function test_goods_argument_is_not_a_list (line 48) | def test_goods_argument_is_not_a_list(setup_price_list_tests):
  function test_goods_attribute_is_not_a_list (line 58) | def test_goods_attribute_is_not_a_list(setup_price_list_tests):
  function test_goods_argument_is_a_list_of_objects_which_are_not_goods (line 70) | def test_goods_argument_is_a_list_of_objects_which_are_not_goods(
  function test_good_attribute_is_a_list_of_objects_which_are_not_goods (line 85) | def test_good_attribute_is_a_list_of_objects_which_are_not_goods(
  function test_good_argument_is_working_as_expected (line 100) | def test_good_argument_is_working_as_expected(setup_price_list_tests):
  function test_good_attribute_is_working_as_expected (line 112) | def test_good_attribute_is_working_as_expected(setup_price_list_tests):

FILE: tests/models/test_project.py
  function condition_tjp_output (line 40) | def condition_tjp_output(data: str) -> str:
  function test_condition_tjp_output_is_working_as_expected (line 59) | def test_condition_tjp_output_is_working_as_expected(get_data_file):
  function setup_project_db_test (line 73) | def setup_project_db_test(setup_postgresql_db):
  function test___auto_name__class_attribute_is_set_to_false (line 632) | def test___auto_name__class_attribute_is_set_to_false():
  function test_setup_is_working_correctly (line 637) | def test_setup_is_working_correctly(setup_project_db_test):
  function test_sequences_attribute_is_read_only (line 644) | def test_sequences_attribute_is_read_only(setup_project_db_test):
  function test_assets_attribute_is_read_only (line 661) | def test_assets_attribute_is_read_only(setup_project_db_test):
  function test_image_format_argument_is_skipped (line 668) | def test_image_format_argument_is_skipped(setup_project_db_test):
  function test_image_format_argument_is_none (line 676) | def test_image_format_argument_is_none(setup_project_db_test):
  function test_image_format_attribute_is_set_to_none (line 684) | def test_image_format_attribute_is_set_to_none(setup_project_db_test):
  function test_image_format_argument_accepts_image_format_only (line 690) | def test_image_format_argument_accepts_image_format_only(setup_project_d...
  function test_image_format_argument_is_working_as_expected (line 703) | def test_image_format_argument_is_working_as_expected(setup_project_db_t...
  function test_image_format_attribute_accepts_image_format_only (line 713) | def test_image_format_attribute_accepts_image_format_only(
  function test_image_format_attribute_works_as_expected (line 725) | def test_image_format_attribute_works_as_expected(setup_project_db_test):
  function test_fps_argument_is_skipped (line 733) | def test_fps_argument_is_skipped(setup_project_db_test):
  function test_fps_attribute_is_set_to_none (line 741) | def test_fps_attribute_is_set_to_none(setup_project_db_test):
  function test_fps_argument_is_given_as_non_float_or_integer_1 (line 753) | def test_fps_argument_is_given_as_non_float_or_integer_1(setup_project_d...
  function test_fps_argument_is_given_as_non_float_or_integer_2 (line 765) | def test_fps_argument_is_given_as_non_float_or_integer_2(setup_project_d...
  function test_fps_attribute_is_given_as_non_float_or_integer_1 (line 777) | def test_fps_attribute_is_given_as_non_float_or_integer_1(setup_project_...
  function test_fps_attribute_is_given_as_non_float_or_integer_2 (line 788) | def test_fps_attribute_is_given_as_non_float_or_integer_2(setup_project_...
  function test_fps_argument_string_to_float_conversion (line 799) | def test_fps_argument_string_to_float_conversion(setup_project_db_test):
  function test_fps_attribute_string_to_float_conversion (line 811) | def test_fps_attribute_string_to_float_conversion(setup_project_db_test):
  function test_fps_attribute_float_conversion (line 822) | def test_fps_attribute_float_conversion(setup_project_db_test):
  function test_fps_attribute_float_conversion_2 (line 832) | def test_fps_attribute_float_conversion_2(setup_project_db_test):
  function test_fps_argument_is_zero (line 841) | def test_fps_argument_is_zero(setup_project_db_test):
  function test_fps_attribute_is_set_to_zero (line 850) | def test_fps_attribute_is_set_to_zero(setup_project_db_test):
  function test_fps_argument_is_negative (line 858) | def test_fps_argument_is_negative(setup_project_db_test):
  function test_fps_attribute_is_negative (line 867) | def test_fps_attribute_is_negative(setup_project_db_test):
  function test_repositories_argument_is_skipped (line 875) | def test_repositories_argument_is_skipped(setup_project_db_test):
  function test_repositories_argument_is_none (line 883) | def test_repositories_argument_is_none(setup_project_db_test):
  function test_repositories_attribute_is_set_to_none (line 891) | def test_repositories_attribute_is_set_to_none(setup_project_db_test):
  function test_repositories_argument_is_not_a_list (line 900) | def test_repositories_argument_is_not_a_list(setup_project_db_test):
  function test_repositories_attribute_is_not_a_list (line 914) | def test_repositories_attribute_is_not_a_list(setup_project_db_test):
  function test_repositories_argument_is_not_a_list_of_repository_instances (line 927) | def test_repositories_argument_is_not_a_list_of_repository_instances(
  function test_repositories_attribute_is_not_a_list_of_repository_instances (line 943) | def test_repositories_attribute_is_not_a_list_of_repository_instances(
  function test_repositories_argument_is_working_as_expected (line 964) | def test_repositories_argument_is_working_as_expected(setup_project_db_t...
  function test_repositories_attribute_is_working_as_expected (line 970) | def test_repositories_attribute_is_working_as_expected(setup_project_db_...
  function test_repositories_attribute_value_order_is_not_changing (line 986) | def test_repositories_attribute_value_order_is_not_changing(setup_projec...
  function test_is_stereoscopic_argument_skipped (line 1006) | def test_is_stereoscopic_argument_skipped(setup_project_db_test):
  function test_is_stereoscopic_argument_bool_conversion (line 1015) | def test_is_stereoscopic_argument_bool_conversion(test_value, setup_proj...
  function test_is_stereoscopic_attribute_bool_conversion (line 1024) | def test_is_stereoscopic_attribute_bool_conversion(test_value, setup_pro...
  function test_structure_argument_is_none (line 1031) | def test_structure_argument_is_none(setup_project_db_test):
  function test_structure_attribute_is_none (line 1039) | def test_structure_attribute_is_none(setup_project_db_test):
  function test_structure_argument_not_instance_of_structure (line 1045) | def test_structure_argument_not_instance_of_structure(setup_project_db_t...
  function test_structure_attribute_not_instance_of_structure (line 1058) | def test_structure_attribute_not_instance_of_structure(setup_project_db_...
  function test_structure_attribute_is_working_as_expected (line 1070) | def test_structure_attribute_is_working_as_expected(setup_project_db_test):
  function test_equality (line 1077) | def test_equality(setup_project_db_test):
  function test_inequality (line 1095) | def test_inequality(setup_project_db_test):
  function test_reference_mixin_initialization (line 1113) | def test_reference_mixin_initialization(setup_project_db_test):
  function test_status_mixin_initialization (line 1139) | def test_status_mixin_initialization(setup_project_db_test):
  function test_schedule_mixin_initialization (line 1149) | def test_schedule_mixin_initialization(setup_project_db_test):
  function test___strictly_typed___is_false (line 1166) | def test___strictly_typed___is_false(setup_project_db_test):
  function test___strictly_typed___not_forces_type_initialization (line 1171) | def test___strictly_typed___not_forces_type_initialization(setup_project...
  function test_tasks_attribute_returns_the_tasks_instances_related_to_this_project (line 1226) | def test_tasks_attribute_returns_the_tasks_instances_related_to_this_pro...
  function test_root_tasks_attribute_returns_the_tasks_instances_with_no_parent_in_this_project (line 1260) | def test_root_tasks_attribute_returns_the_tasks_instances_with_no_parent...
  function test_users_argument_is_skipped (line 1271) | def test_users_argument_is_skipped(setup_project_db_test):
  function test_users_argument_is_none (line 1283) | def test_users_argument_is_none(setup_project_db_test):
  function test_users_attribute_is_set_to_none (line 1292) | def test_users_attribute_is_set_to_none(setup_project_db_test):
  function test_users_argument_is_not_a_list_of_user_instances (line 1301) | def test_users_argument_is_not_a_list_of_user_instances(setup_project_db...
  function test_users_attribute_is_set_to_a_value_which_is_not_a_list_of_User_instances (line 1315) | def test_users_attribute_is_set_to_a_value_which_is_not_a_list_of_User_i...
  function test_users_argument_is_working_as_expected (line 1329) | def test_users_argument_is_working_as_expected(setup_project_db_test):
  function test_users_attribute_is_working_as_expected (line 1343) | def test_users_attribute_is_working_as_expected(setup_project_db_test):
  function test_tjp_id_is_working_as_expected (line 1353) | def test_tjp_id_is_working_as_expected(setup_project_db_test):
  function test_to_tjp_is_working_as_expected (line 1408) | def test_to_tjp_is_working_as_expected(setup_project_db_test, entity_name):
  function test_project_instance_does_not_have_active_attribute (line 1425) | def test_project_instance_does_not_have_active_attribute(setup_project_d...
  function test_is_active_property_depends_on_the_status (line 1440) | def test_is_active_property_depends_on_the_status(
  function test_is_active_is_read_only (line 1452) | def test_is_active_is_read_only(setup_project_db_test):
  function test_total_logged_seconds_attribute_is_read_only (line 1469) | def test_total_logged_seconds_attribute_is_read_only(setup_project_db_te...
  function test_total_logged_seconds_is_0_for_a_project_with_no_child_tasks (line 1487) | def test_total_logged_seconds_is_0_for_a_project_with_no_child_tasks(
  function test_total_logged_seconds_attribute_is_working_as_expected (line 1497) | def test_total_logged_seconds_attribute_is_working_as_expected(setup_pro...
  function test_schedule_seconds_attribute_is_read_only (line 1541) | def test_schedule_seconds_attribute_is_read_only(setup_project_db_test):
  function test_schedule_seconds_attribute_value_is_0_for_a_project_with_no_tasks (line 1559) | def test_schedule_seconds_attribute_value_is_0_for_a_project_with_no_tasks(
  function test_schedule_seconds_attribute_is_working_as_expected (line 1619) | def test_schedule_seconds_attribute_is_working_as_expected(
  function test_percent_complete_attribute_is_read_only (line 1630) | def test_percent_complete_attribute_is_read_only(setup_project_db_test):
  function test_percent_complete_is_0_for_a_project_with_no_tasks (line 1648) | def test_percent_complete_is_0_for_a_project_with_no_tasks(setup_project...
  function test_percent_complete_attribute_is_working_as_expected (line 1657) | def test_percent_complete_attribute_is_working_as_expected(setup_project...
  function test_clients_argument_is_skipped (line 1681) | def test_clients_argument_is_skipped(setup_project_db_test):
  function test_clients_argument_is_none (line 1693) | def test_clients_argument_is_none(setup_project_db_test):
  function test_clients_attribute_is_set_to_none (line 1701) | def test_clients_attribute_is_set_to_none(setup_project_db_test):
  function test_clients_argument_is_given_as_something_other_than_a_client (line 1710) | def test_clients_argument_is_given_as_something_other_than_a_client(
  function test_clients_attribute_is_not_a_client_instance (line 1725) | def test_clients_attribute_is_not_a_client_instance(setup_project_db_test):
  function test_clients_attribute_is_working_as_expected (line 1743) | def test_clients_attribute_is_working_as_expected(setup_project_db_test):
  function setup_project_tickets_db_tests (line 1753) | def setup_project_tickets_db_tests(setup_postgresql_db):
  function test_tickets_attribute_is_an_empty_list_by_default (line 1953) | def test_tickets_attribute_is_an_empty_list_by_default(setup_project_tic...
  function test_open_tickets_attribute_is_an_empty_list_by_default (line 1960) | def test_open_tickets_attribute_is_an_empty_list_by_default(
  function test_open_tickets_attribute_is_read_only (line 1971) | def test_open_tickets_attribute_is_read_only(setup_project_tickets_db_te...
  function test_tickets_attribute_returns_all_tickets_in_this_project (line 1989) | def test_tickets_attribute_returns_all_tickets_in_this_project(
  function test_open_tickets_attribute_returns_all_open_tickets_owned_by_this_user (line 2017) | def test_open_tickets_attribute_returns_all_open_tickets_owned_by_this_u...
  function test__hash__is_working_as_expected (line 2081) | def test__hash__is_working_as_expected(setup_project_db_test):

FILE: tests/models/test_project_client.py
  function setup_project_client_db_test (line 10) | def setup_project_client_db_test(setup_postgresql_db):
  function test_project_client_creation (line 37) | def test_project_client_creation(setup_project_client_db_test):
  function test_role_argument_is_not_a_role_instance (line 47) | def test_role_argument_is_not_a_role_instance(setup_project_client_db_te...

FILE: tests/models/test_project_user.py
  function setup_project_user_db_tests (line 11) | def setup_project_user_db_tests(setup_postgresql_db):
  function test_project_user_creation (line 40) | def test_project_user_creation(setup_project_user_db_tests):
  function test_role_argument_is_not_a_role_instance (line 50) | def test_role_argument_is_not_a_role_instance(setup_project_user_db_tests):
  function test_rate_attribute_is_copied_from_user (line 66) | def test_rate_attribute_is_copied_from_user(setup_project_user_db_tests):
  function test_rate_attribute_initialization_through_user (line 76) | def test_rate_attribute_initialization_through_user(setup_project_user_d...
  function test_rate_attribute_initialization_through_project (line 84) | def test_rate_attribute_initialization_through_project(setup_project_use...

FILE: tests/models/test_repository.py
  function setup_repository_db_tests (line 16) | def setup_repository_db_tests(setup_postgresql_db):
  function test_code_mixin_as_super (line 43) | def test_code_mixin_as_super(setup_repository_db_tests):
  function test___auto_name__class_attribute_is_set_to_false (line 50) | def test___auto_name__class_attribute_is_set_to_false():
  function test_linux_path_argument_accepts_only_strings (line 56) | def test_linux_path_argument_accepts_only_strings(
  function test_linux_path_attribute_accepts_only_strings (line 67) | def test_linux_path_attribute_accepts_only_strings(
  function test_linux_path_attribute_is_working_as_expected (line 76) | def test_linux_path_attribute_is_working_as_expected(setup_repository_db...
  function test_linux_path_attribute_finishes_with_a_slash (line 84) | def test_linux_path_attribute_finishes_with_a_slash(setup_repository_db_...
  function test_windows_path_argument_accepts_only_strings (line 94) | def test_windows_path_argument_accepts_only_strings(
  function test_windows_path_attribute_accepts_only_strings (line 104) | def test_windows_path_attribute_accepts_only_strings(setup_repository_db...
  function test_windows_path_attribute_is_working_as_expected (line 115) | def test_windows_path_attribute_is_working_as_expected(setup_repository_...
  function test_windows_path_attribute_finishes_with_a_slash (line 123) | def test_windows_path_attribute_finishes_with_a_slash(setup_repository_d...
  function test_macos_path_argument_accepts_only_strings (line 132) | def test_macos_path_argument_accepts_only_strings(setup_repository_db_te...
  function test_macos_path_attribute_accepts_only_strings (line 144) | def test_macos_path_attribute_accepts_only_strings(setup_repository_db_t...
  function test_macos_path_attribute_is_working_as_expected (line 155) | def test_macos_path_attribute_is_working_as_expected(setup_repository_db...
  function test_macos_path_attribute_finishes_with_a_slash (line 163) | def test_macos_path_attribute_finishes_with_a_slash(setup_repository_db_...
  function test_path_returns_properly_for_windows (line 172) | def test_path_returns_properly_for_windows(setup_repository_db_tests):
  function test_path_returns_properly_for_linux (line 179) | def test_path_returns_properly_for_linux(setup_repository_db_tests):
  function test_path_returns_properly_for_macos (line 186) | def test_path_returns_properly_for_macos(setup_repository_db_tests):
  function test_path_attribute_sets_correct_path_for_windows (line 193) | def test_path_attribute_sets_correct_path_for_windows(setup_repository_d...
  function test_path_attribute_sets_correct_path_for_linux (line 205) | def test_path_attribute_sets_correct_path_for_linux(setup_repository_db_...
  function test_path_attribute_sets_correct_path_for_macos (line 217) | def test_path_attribute_sets_correct_path_for_macos(setup_repository_db_...
  function test_equality (line 229) | def test_equality(setup_repository_db_tests):
  function test_inequality (line 251) | def test_inequality(setup_repository_db_tests):
  function test_plural_class_name (line 273) | def test_plural_class_name(setup_repository_db_tests):
  function test_linux_path_argument_backward_slashes_are_converted_to_forward_slashes (line 279) | def test_linux_path_argument_backward_slashes_are_converted_to_forward_s...
  function test_linux_path_attribute_backward_slashes_are_converted_to_forward_slashes (line 290) | def test_linux_path_attribute_backward_slashes_are_converted_to_forward_...
  function test_macos_path_argument_backward_slashes_are_converted_to_forward_slashes (line 300) | def test_macos_path_argument_backward_slashes_are_converted_to_forward_s...
  function test_macos_path_attribute_backward_slashes_are_converted_to_forward_slashes (line 311) | def test_macos_path_attribute_backward_slashes_are_converted_to_forward_...
  function test_windows_path_argument_backward_slashes_are_converted_to_forward_slashes (line 321) | def test_windows_path_argument_backward_slashes_are_converted_to_forward...
  function test_windows_path_attribute_backward_slashes_are_converted_to_forward_slashes (line 332) | def test_windows_path_attribute_backward_slashes_are_converted_to_forwar...
  function test_windows_path_with_more_than_one_slashes_converted_to_single_slash_1 (line 342) | def test_windows_path_with_more_than_one_slashes_converted_to_single_sla...
  function test_windows_path_with_more_than_one_slashes_converted_to_single_slash_2 (line 351) | def test_windows_path_with_more_than_one_slashes_converted_to_single_sla...
  function test_to_linux_path_returns_the_linux_version_of_the_given_windows_path (line 360) | def test_to_linux_path_returns_the_linux_version_of_the_given_windows_path(
  function test_to_linux_path_returns_the_linux_version_of_the_given_linux_path (line 372) | def test_to_linux_path_returns_the_linux_version_of_the_given_linux_path(
  function test_to_linux_path_returns_the_linux_version_of_the_given_macos_path (line 382) | def test_to_linux_path_returns_the_linux_version_of_the_given_macos_path(
  function test_to_linux_path_returns_the_linux_version_of_the_given_reverse_windows_path (line 394) | def test_to_linux_path_returns_the_linux_version_of_the_given_reverse_wi...
  function test_to_linux_path_returns_the_linux_version_of_the_given_reverse_linux_path (line 408) | def test_to_linux_path_returns_the_linux_version_of_the_given_reverse_li...
  function test_to_linux_path_returns_the_linux_version_of_the_given_reverse_macos_path (line 421) | def test_to_linux_path_returns_the_linux_version_of_the_given_reverse_ma...
  function test_to_linux_path_returns_the_linux_version_of_the_given_path_with_env_vars (line 435) | def test_to_linux_path_returns_the_linux_version_of_the_given_path_with_...
  function test_to_linux_path_raises_type_error_if_path_is_none (line 448) | def test_to_linux_path_raises_type_error_if_path_is_none(setup_repositor...
  function test_to_linux_path_raises_type_error_if_path_is_not_a_string (line 458) | def test_to_linux_path_raises_type_error_if_path_is_not_a_string(
  function test_to_windows_path_returns_the_windows_version_of_the_given_windows_path (line 470) | def test_to_windows_path_returns_the_windows_version_of_the_given_window...
  function test_to_windows_path_returns_the_windows_version_of_the_given_linux_path (line 480) | def test_to_windows_path_returns_the_windows_version_of_the_given_linux_...
  function test_to_windows_path_returns_the_windows_version_of_the_given_macos_path (line 492) | def test_to_windows_path_returns_the_windows_version_of_the_given_macos_...
  function test_to_windows_path_returns_the_windows_version_of_the_given_reverse_windows_path (line 504) | def test_to_windows_path_returns_the_windows_version_of_the_given_revers...
  function test_to_windows_path_returns_the_windows_version_of_the_given_reverse_linux_path (line 520) | def test_to_windows_path_returns_the_windows_version_of_the_given_revers...
  function test_to_windows_path_returns_the_windows_version_of_the_given_reverse_macos_path (line 536) | def test_to_windows_path_returns_the_windows_version_of_the_given_revers...
  function test_to_windows_path_returns_the_windows_version_of_the_given_path_with_env_vars (line 552) | def test_to_windows_path_returns_the_windows_version_of_the_given_path_w...
  function test_to_windows_path_raises_type_error_if_path_is_none (line 568) | def test_to_windows_path_raises_type_error_if_path_is_none(setup_reposit...
  function test_to_windows_path_raises_type_error_if_path_is_not_a_string (line 578) | def test_to_windows_path_raises_type_error_if_path_is_not_a_string(
  function test_to_macos_path_returns_the_macos_version_of_the_given_windows_path (line 590) | def test_to_macos_path_returns_the_macos_version_of_the_given_windows_path(
  function test_to_macos_path_returns_the_macos_version_of_the_given_linux_path (line 602) | def test_to_macos_path_returns_the_macos_version_of_the_given_linux_path(
  function test_to_macos_path_returns_the_macos_version_of_the_given_macos_path (line 614) | def test_to_macos_path_returns_the_macos_version_of_the_given_macos_path(
  function test_to_macos_path_returns_the_macos_version_of_the_given_reverse_windows_path (line 624) | def test_to_macos_path_returns_the_macos_version_of_the_given_reverse_wi...
  function test_to_macos_path_returns_the_macos_version_of_the_given_reverse_linux_path (line 638) | def test_to_macos_path_returns_the_macos_version_of_the_given_reverse_li...
  function test_to_macos_path_returns_the_macos_version_of_the_given_reverse_macos_path (line 652) | def test_to_macos_path_returns_the_macos_version_of_the_given_reverse_ma...
  function test_to_macos_path_returns_the_macos_version_of_the_given_path (line 665) | def test_to_macos_path_returns_the_macos_version_of_the_given_path(
  function test_to_macos_path_returns_the_macos_version_of_the_given_path_with_env_vars (line 696) | def test_to_macos_path_returns_the_macos_version_of_the_given_path_with_...
  function test_to_macos_path_raises_type_error_if_path_is_none (line 711) | def test_to_macos_path_raises_type_error_if_path_is_none(setup_repositor...
  function test_to_macos_path_raises_type_error_if_path_is_not_a_string (line 721) | def test_to_macos_path_raises_type_error_if_path_is_not_a_string(
  function test_to_native_path_returns_the_native_version_of_the_given_linux_path (line 733) | def test_to_native_path_returns_the_native_version_of_the_given_linux_path(
  function test_to_native_path_returns_the_native_version_of_the_given_windows_path (line 746) | def test_to_native_path_returns_the_native_version_of_the_given_windows_...
  function test_to_native_path_returns_the_native_version_of_the_given_macos_path (line 762) | def test_to_native_path_returns_the_native_version_of_the_given_macos_path(
  function test_to_native_path_returns_the_native_version_of_the_given_reverse_windows_path (line 775) | def test_to_native_path_returns_the_native_version_of_the_given_reverse_...
  function test_to_native_path_returns_the_native_version_of_the_given_reverse_linux_path (line 792) | def test_to_native_path_returns_the_native_version_of_the_given_reverse_...
  function test_to_native_path_returns_the_native_version_of_the_given_reverse_macos_path (line 806) | def test_to_native_path_returns_the_native_version_of_the_given_reverse_...
  function test_to_native_path_raises_type_error_if_path_is_none (line 821) | def test_to_native_path_raises_type_error_if_path_is_none(setup_reposito...
  function test_to_native_path_raises_type_error_if_path_is_not_a_string (line 831) | def test_to_native_path_raises_type_error_if_path_is_not_a_string(
  function test_is_in_repo_returns_true_if_the_given_linux_path_is_in_this_repo (line 843) | def test_is_in_repo_returns_true_if_the_given_linux_path_is_in_this_repo(
  function test_is_in_repo_returns_true_if_the_given_linux_reverse_path_is_in_this_repo (line 853) | def test_is_in_repo_returns_true_if_the_given_linux_reverse_path_is_in_t...
  function test_is_in_repo_returns_false_if_the_given_linux_path_is_not_in_this_repo (line 865) | def test_is_in_repo_returns_false_if_the_given_linux_path_is_not_in_this...
  function test_is_in_repo_returns_true_if_the_given_windows_path_is_in_this_repo (line 877) | def test_is_in_repo_returns_true_if_the_given_windows_path_is_in_this_repo(
  function test_is_in_repo_returns_true_if_the_given_windows_reverse_path_is_in_this_repo (line 887) | def test_is_in_repo_returns_true_if_the_given_windows_reverse_path_is_in...
  function test_is_in_repo_is_case_insensitive_under_windows (line 899) | def test_is_in_repo_is_case_insensitive_under_windows(setup_repository_d...
  function test_is_in_repo_returns_false_if_the_given_windows_path_is_not_in_this_repo (line 909) | def test_is_in_repo_returns_false_if_the_given_windows_path_is_not_in_th...
  function test_is_in_repo_returns_true_if_the_given_macos_path_is_in_this_repo (line 919) | def test_is_in_repo_returns_true_if_the_given_macos_path_is_in_this_repo(
  function test_is_in_repo_returns_true_if_the_given_macos_reverse_path_is_in_this_repo (line 929) | def test_is_in_repo_returns_true_if_the_given_macos_reverse_path_is_in_t...
  function test_is_in_repo_returns_false_if_the_given_macos_path_is_not_in_this_repo (line 941) | def test_is_in_repo_returns_false_if_the_given_macos_path_is_not_in_this...
  function test_make_relative_converts_the_given_linux_path_to_relative_to_repo_root (line 953) | def test_make_relative_converts_the_given_linux_path_to_relative_to_repo...
  function test_make_relative_converts_the_given_macos_path_to_relative_to_repo_root (line 967) | def test_make_relative_converts_the_given_macos_path_to_relative_to_repo...
  function test_make_relative_converts_the_given_windows_path_to_relative_to_repo_root (line 979) | def test_make_relative_converts_the_given_windows_path_to_relative_to_re...
  function test_make_relative_converts_the_given_path_with_env_variable_to_native_path (line 991) | def test_make_relative_converts_the_given_path_with_env_variable_to_nati...
  function test_to_os_independent_path_is_working_as_expected (line 1003) | def test_to_os_independent_path_is_working_as_expected(setup_repository_...
  function test_to_os_independent_path_converts_the_given_linux_path_to_universal (line 1016) | def test_to_os_independent_path_converts_the_given_linux_path_to_universal(
  function test_to_os_independent_path_converts_the_given_macos_path_to_universal (line 1032) | def test_to_os_independent_path_converts_the_given_macos_path_to_universal(
  function test_to_os_independent_path_converts_the_given_windows_path_to_universal (line 1046) | def test_to_os_independent_path_converts_the_given_windows_path_to_unive...
  function test_to_os_independent_path_not_change_the_path_with_env_variable (line 1060) | def test_to_os_independent_path_not_change_the_path_with_env_variable(
  function test_to_os_independent_path_cannot_convert_the_given_path_with_old_env_variable_new_env_variable (line 1074) | def test_to_os_independent_path_cannot_convert_the_given_path_with_old_e...
  function test_to_os_independent_path_repo_cannot_be_found (line 1088) | def test_to_os_independent_path_repo_cannot_be_found(setup_repository_db...
  function test_find_repo_is_working_as_expected (line 1096) | def test_find_repo_is_working_as_expected(setup_repository_db_tests):
  function test_find_repo_is_case_insensitive_under_windows (line 1120) | def test_find_repo_is_case_insensitive_under_windows(
  function test_find_repo_is_working_as_expected_with_reverse_slashes (line 1155) | def test_find_repo_is_working_as_expected_with_reverse_slashes(
  function test_find_repo_is_working_as_expected_with_env_vars (line 1183) | def test_find_repo_is_working_as_expected_with_env_vars(setup_repository...
  function test_find_repo_returns_none_if_a_repo_cannot_be_found (line 1208) | def test_find_repo_returns_none_if_a_repo_cannot_be_found(setup_reposito...
  function test_env_var_property_is_working_as_expected (line 1215) | def test_env_var_property_is_working_as_expected(setup_repository_db_tes...
  function test_creating_and_committing_a_new_repository_instance_will_create_env_var (line 1221) | def test_creating_and_committing_a_new_repository_instance_will_create_e...
  function test_updating_a_repository_will_update_repo_path (line 1238) | def test_updating_a_repository_will_update_repo_path(setup_repository_db...
  function test_updating_windows_path_only_update_repo_path_if_on_windows (line 1262) | def test_updating_windows_path_only_update_repo_path_if_on_windows(
  function test_updating_macos_path_only_update_repo_path_if_on_macos (line 1310) | def test_updating_macos_path_only_update_repo_path_if_on_macos(
  function test_updating_linux_path_only_update_repo_path_if_on_linux (line 1359) | def test_updating_linux_path_only_update_repo_path_if_on_linux(
  function test_to_path_path_is_none (line 1408) | def test_to_path_path_is_none(setup_repository_db_tests):
  function test_to_path_path_is_not_a_str (line 1419) | def test_to_path_path_is_not_a_str(setup_repository_db_tests):
  function test_to_path_path_is_not_starting_with_a_repo_path_returns_the_path (line 1430) | def test_to_path_path_is_not_starting_with_a_repo_path_returns_the_path(
  function test_to_path_replace_with_is_none (line 1440) | def test_to_path_replace_with_is_none(setup_repository_db_tests):
  function test_to_path_replace_with_is_not_a_str (line 1451) | def test_to_path_replace_with_is_not_a_str(setup_repository_db_tests):
 
Condensed preview — 264 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,486K chars).
[
  {
    "path": ".editorconfig",
    "chars": 387,
    "preview": "# http://editorconfig.org\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 4\ntrim_trailing_whitespace = true\ninsert_"
  },
  {
    "path": ".github/workflows/pytest.yml",
    "chars": 5343,
    "preview": "name: Unit Tests\non:\n  pull_request:\n    types: [opened, synchronize, reopened, ready_for_review, unlabeled]\n    branche"
  },
  {
    "path": ".gitignore",
    "chars": 316,
    "preview": ".cache/*\n.coverage*\n.DS_Store\n.env\n.mypy_cache/\n.pytest_cache\n.tox/\n.venv/\n.vscode/\n*.pyc\n*.swp\n*~*\nbuild/*\ndist/\ndist/*"
  },
  {
    "path": "CHANGELOG.rst",
    "chars": 78675,
    "preview": "===============\nStalker Changes\n===============\n\n1.0.0\n=====\n\n* `Version.take_name` has been renamed to `Version.variant"
  },
  {
    "path": "CHANGELOG_OLD.rst",
    "chars": 49827,
    "preview": "0.1.2.a5\n========\n\n* :class:`~stalker.core.models.SimpleEntity`.\\\n  :attr:`~stalker.core.models.SimpleEntity.name` attri"
  },
  {
    "path": "COPYING",
    "chars": 35147,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "COPYING.LESSER",
    "chars": 7651,
    "preview": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007"
  },
  {
    "path": "Dockerfile-py3.5",
    "chars": 3516,
    "preview": "# This Dockerfile is based on: https://docs.docker.com/examples/postgresql_service/\n\nFROM ubuntu:16.04\n\nMAINTAINER fredr"
  },
  {
    "path": "INSTALL",
    "chars": 28,
    "preview": "See docs/installation.html.\n"
  },
  {
    "path": "LICENSE",
    "chars": 7651,
    "preview": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007"
  },
  {
    "path": "MANIFEST.in",
    "chars": 255,
    "preview": "include *.ini *.cfg\n\ninclude alembic.ini\ninclude CHANGELOG.rst\ninclude COPYING\ninclude COPYING.LESSER\ninclude INSTALL\nin"
  },
  {
    "path": "Makefile",
    "chars": 2855,
    "preview": "SHELL:=bash\nPACKAGE_NAME=stalker\nNUM_CPUS = $(shell nproc ||  grep -c '^processor' /proc/cpuinfo)\nSETUP_PY_FLAGS = --use"
  },
  {
    "path": "README.md",
    "chars": 4165,
    "preview": "[![license](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](http://www.gnu.org/licenses/lgpl-3.0)\n[![Supported"
  },
  {
    "path": "TODO.rst",
    "chars": 7856,
    "preview": "TODO\n====\n\n* **Update:** Better support ``duration`` Tasks.\n\n  The current status workflow is not working with **duratio"
  },
  {
    "path": "alembic/README",
    "chars": 38,
    "preview": "Generic single-database configuration."
  },
  {
    "path": "alembic/env.py",
    "chars": 2007,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Setup environment for migration.\"\"\"\nfrom logging.config import fileConfig\n\nfrom alembic impor"
  },
  {
    "path": "alembic/script.py.mako",
    "chars": 476,
    "preview": "\"\"\"${message}\n\nRevision ID: ${up_revision}\nRevises: ${down_revision}\nCreate Date: ${create_date}\n\"\"\"\n\nfrom alembic impor"
  },
  {
    "path": "alembic/versions/0063f547dc2e_updated_version_inputs_table.py",
    "chars": 822,
    "preview": "\"\"\"updated version_inputs table.\n\nRevision ID: 0063f547dc2e\nRevises: a9319b19f7be\nCreate Date: 2016-11-29 14:08:41.33500"
  },
  {
    "path": "alembic/versions/019378697b5b_rename_depends_to_to_depends_on.py",
    "chars": 585,
    "preview": "\"\"\"Rename depends_to to depends_on\n\nRevision ID: 019378697b5b\nRevises: feca9bac7d5a\nCreate Date: 2024-11-01 13:59:11.513"
  },
  {
    "path": "alembic/versions/101a789e38ad_created_task_responsible.py",
    "chars": 768,
    "preview": "\"\"\"Created \"Task.responsible\" attribute.\n\nRevision ID: 101a789e38ad\nRevises: 59092d41175c\nCreate Date: 2013-06-24 12:32:"
  },
  {
    "path": "alembic/versions/1181305d3001_added_client_id_column_to_goods_table.py",
    "chars": 635,
    "preview": "\"\"\"Added client_id column to Goods table.\n\nRevision ID: 1181305d3001\nRevises: 31b1e22b455e\nCreate Date: 2017-05-17 18:17"
  },
  {
    "path": "alembic/versions/130a7697cd79_vacation_user_can_now_be_nullable.py",
    "chars": 552,
    "preview": "\"\"\"Vacation.user can now be nullable.\n\nRevision ID: 130a7697cd79\nRevises: 57a5949c7f29\nCreate Date: 2013-08-02 19:58:59."
  },
  {
    "path": "alembic/versions/174567b9c159_note_content.py",
    "chars": 510,
    "preview": "\"\"\"'Note.content' is now a synonym of 'Note.description'.\n\nRevision ID: 174567b9c159\nRevises: a6598cde6b\nCreate Date: 20"
  },
  {
    "path": "alembic/versions/182f44ce5f07_added_users_company_and_projects_client.py",
    "chars": 1335,
    "preview": "\"\"\"added \"Users.company\" and \"Projects.client\" columns and a new Clients table.\n\nRevision ID: 182f44ce5f07\nRevises: 59bf"
  },
  {
    "path": "alembic/versions/1875136a2bfc_removed_version_variant_name_attribute.py",
    "chars": 10737,
    "preview": "\"\"\"Removed Version.variant_name attribute\n\nRevision ID: 1875136a2bfc\nRevises: a2007ad7f535\nCreate Date: 2024-11-28 10:18"
  },
  {
    "path": "alembic/versions/1c9c9c28c102_price_lists_and_goods.py",
    "chars": 2536,
    "preview": "\"\"\"Add PriceLists and Goods.\n\nRevision ID: 1c9c9c28c102\nRevises: 856e70016b2\nCreate Date: 2015-01-26 13:05:50.050345\n\"\"\""
  },
  {
    "path": "alembic/versions/21b88ed3da95_added_referencemixin.py",
    "chars": 2766,
    "preview": "\"\"\"Added ReferenceMixin to Task.\n\nRevision ID: 21b88ed3da95\nRevises: 4664d72ce1e1\nCreate Date: 2013-05-31 12:08:59.42553"
  },
  {
    "path": "alembic/versions/2252e51506de_multiple_repositories.py",
    "chars": 1728,
    "preview": "\"\"\"Multiple Repositories per Project.\n\nRevision ID: 2252e51506de\nRevises: 1c9c9c28c102\nCreate Date: 2015-01-28 00:46:29."
  },
  {
    "path": "alembic/versions/23dff41c95ff_removed_tasks_is_complete_column.py",
    "chars": 501,
    "preview": "\"\"\"Removed Tasks.is_complete column.\n\nRevision ID: 23dff41c95ff\nRevises: 5999269aad30\nCreate Date: 2014-06-11 14:00:00.5"
  },
  {
    "path": "alembic/versions/255ee1f9c7b3_added_payments_table.py",
    "chars": 911,
    "preview": "\"\"\"Added Payments table.\n\nRevision ID: 255ee1f9c7b3\nRevises: ea28a39ba3f5\nCreate Date: 2016-08-18 03:19:22.301000\n\"\"\"\n\nf"
  },
  {
    "path": "alembic/versions/258985128aff_create_entitygroups_table.py",
    "chars": 1171,
    "preview": "\"\"\"create EntityGroups table.\n\nRevision ID: 258985128aff\nRevises: 39d3c16ff005\nCreate Date: 2016-05-16 16:06:39.389000\n\""
  },
  {
    "path": "alembic/versions/25b3eba6ffe7_derive_version_from.py",
    "chars": 4029,
    "preview": "\"\"\"Derive Version from Link instead of Entity.\n\nRevision ID: 25b3eba6ffe7\nRevises: 53d8127d8560\nCreate Date: 2013-05-22 "
  },
  {
    "path": "alembic/versions/275bdc106fd5_added_ticket_summary.py",
    "chars": 486,
    "preview": "\"\"\"Added \"Ticket.summary\".\n\nRevision ID: 275bdc106fd5\nRevises: 130a7697cd79\nCreate Date: 2013-08-07 00:19:39.414232\n\"\"\"\n"
  },
  {
    "path": "alembic/versions/2aeab8b376dc_fg_color_bg_color.py",
    "chars": 649,
    "preview": "\"\"\"Remove Statuses.bg_color and Statuses.fg_color columns.\n\nRevision ID: 2aeab8b376dc\nRevises: 5168cc8552a3\nCreate Date:"
  },
  {
    "path": "alembic/versions/2e4a3813ae76_created_daily_class.py",
    "chars": 5299,
    "preview": "\"\"\"Created Daily class and the \"Daily Statuses\" status list and the status Open.\n\nRevision ID: 2e4a3813ae76\nRevises: 23d"
  },
  {
    "path": "alembic/versions/2f55dc4f199f_wiki_page.py",
    "chars": 882,
    "preview": "\"\"\"Add Wiki Page.\n\nRevision ID: 2f55dc4f199f\nRevises: 433d9caaafab\nCreate Date: 2014-03-24 16:52:45.127579\n\"\"\"\n\nfrom ale"
  },
  {
    "path": "alembic/versions/30c576f3691_budget_and_budget_entry.py",
    "chars": 1292,
    "preview": "\"\"\"Added Budget and BudgetEntry tables.\n\nRevision ID: 30c576f3691\nRevises: 409d2d73ca30\nCreate Date: 2014-11-20 22:49:37"
  },
  {
    "path": "alembic/versions/31b1e22b455e_added_exclude_and_check_constraints_to_.py",
    "chars": 5082,
    "preview": "\"\"\"Added exclude and check constraints to TimeLogs table.\n\nRevision ID: 31b1e22b455e\nRevises: c5607b4cfb0a\nCreate Date: "
  },
  {
    "path": "alembic/versions/39d3c16ff005_budget_entries_good_id.py",
    "chars": 634,
    "preview": "\"\"\"Added BudgetEntries.good_id.\n\nRevision ID: 39d3c16ff005\nRevises: eaed49db6d9\nCreate Date: 2015-02-15 02:29:26.301437\n"
  },
  {
    "path": "alembic/versions/3be540ad3a93_added_version_revision_number_attribute.py",
    "chars": 867,
    "preview": "\"\"\"Added Version.revision_number attribute\n\nRevision ID: 3be540ad3a93\nRevises: 1875136a2bfc\nCreate Date: 2024-12-04 17:0"
  },
  {
    "path": "alembic/versions/409d2d73ca30_user_rate.py",
    "chars": 471,
    "preview": "\"\"\"Added \"Users.rate\".\n\nRevision ID: 409d2d73ca30\nRevises: 5814290f49c7\nCreate Date: 2014-11-20 22:47:56.013644\n\"\"\"\n\nfro"
  },
  {
    "path": "alembic/versions/433d9caaafab_task_review_status_workflow.py",
    "chars": 20735,
    "preview": "\"\"\"Task review/status workflow.\n\nRevision ID: 433d9caaafab\nRevises: 46775e4a3d96\nCreate Date: 2014-01-31 01:51:08.457109"
  },
  {
    "path": "alembic/versions/4400871fa852_scene_is_now_deriving_from_task.py",
    "chars": 5098,
    "preview": "\"\"\"Scene is now deriving from Task\n\nRevision ID: 4400871fa852\nRevises: ec1eb2151bb9\nCreate Date: 2024-11-15 13:16:53.885"
  },
  {
    "path": "alembic/versions/4664d72ce1e1_renamed_link_path_to_full_path.py",
    "chars": 3058,
    "preview": "\"\"\"Renamed \"Link.path\" to\" Link.full_path\".\n\nRevision ID: 4664d72ce1e1\nRevises: 25b3eba6ffe7\nCreate Date: 2013-05-23 18:"
  },
  {
    "path": "alembic/versions/46775e4a3d96_create_enum_types.py",
    "chars": 1993,
    "preview": "\"\"\"Create enum types.\n\nRevision ID: 46775e4a3d96\nRevises: 2aeab8b376dc\nCreate Date: 2014-01-31 03:08:36.445876\n\"\"\"\n\nfrom"
  },
  {
    "path": "alembic/versions/4a836cf73bcf_create_entitytype_accepts_references.py",
    "chars": 968,
    "preview": "\"\"\"Create EntityType.accepts_references.\n\nRevision ID: 4a836cf73bcf\nRevises: None\nCreate Date: 2013-05-15 16:27:05.98384"
  },
  {
    "path": "alembic/versions/5078390e5527_shot_scene_relation_is_now_many_to_one.py",
    "chars": 1672,
    "preview": "\"\"\"Shot Scene relation is now many-to-one\n\nRevision ID: 5078390e5527\nRevises: e25ec9930632\nCreate Date: 2024-11-18 11:35"
  },
  {
    "path": "alembic/versions/5168cc8552a3_html_style_html_class.py",
    "chars": 681,
    "preview": "\"\"\"Added html_style and html_class columns to SimpleEntities.\n\nRevision ID: 5168cc8552a3\nRevises: 174567b9c159\nCreate Da"
  },
  {
    "path": "alembic/versions/5355b569237b_version_version_of_r.py",
    "chars": 1494,
    "preview": "\"\"\"'Version.version_of' renamed to \"Version.task\".\n\nRevision ID: 5355b569237b\nRevises: 6297277da38\nCreate Date: 2013-06-"
  },
  {
    "path": "alembic/versions/53d8127d8560_parent_child_relatio.py",
    "chars": 590,
    "preview": "\"\"\"parent child relation in Versions.\n\nRevision ID: 53d8127d8560\nRevises: 4a836cf73bcf\nCreate Date: 2013-05-22 12:44:05."
  },
  {
    "path": "alembic/versions/57a5949c7f29_cache_for_total_logged_seconds.py",
    "chars": 718,
    "preview": "\"\"\"Created cache columns for total_logged_seconds and schedule_seconds attributes.\n\nRevision ID: 57a5949c7f29\nRevises: 1"
  },
  {
    "path": "alembic/versions/5814290f49c7_added_shot_source_in_shot_source_out_record_in.py",
    "chars": 776,
    "preview": "\"\"\"Added Shot.source_in, Shot.source_out and Shot.record_in attributes.\n\nRevision ID: 5814290f49c7\nRevises: 2e4a3813ae76"
  },
  {
    "path": "alembic/versions/583875229230_good_task_relation.py",
    "chars": 619,
    "preview": "\"\"\"Added Tasks.good_id column.\n\nRevision ID: 583875229230\nRevises: 2252e51506de\nCreate Date: 2015-02-07 18:53:04.343928\n"
  },
  {
    "path": "alembic/versions/59092d41175c_added_version_created_with.py",
    "chars": 658,
    "preview": "\"\"\"Added Version.created_with.\n\nRevision ID: 59092d41175c\nRevises: 5355b569237b\nCreate Date: 2013-06-19 15:31:53.547392\n"
  },
  {
    "path": "alembic/versions/5999269aad30_added_generic_text_attribute.py",
    "chars": 515,
    "preview": "\"\"\"Added generic_text attribute on SimpleEntity.\n\nRevision ID: 5999269aad30\nRevises: 182f44ce5f07\nCreate Date: 2014-06-0"
  },
  {
    "path": "alembic/versions/59bfe820c369_resource_efficiency.py",
    "chars": 571,
    "preview": "\"\"\"Added \"User.efficiency\" column.\n\nRevision ID: 59bfe820c369\nRevises: af869ddfdf9\nCreate Date: 2014-04-26 23:50:53.8802"
  },
  {
    "path": "alembic/versions/6297277da38_added_vacation_class.py",
    "chars": 1014,
    "preview": "\"\"\"Added Vacation class.\n\nRevision ID: 6297277da38\nRevises: 21b88ed3da95\nCreate Date: 2013-06-07 16:03:08.412610\n\"\"\"\n\nfr"
  },
  {
    "path": "alembic/versions/644f5251fc0d_remove_project_active_attribute.py",
    "chars": 1132,
    "preview": "\"\"\"Remove Project.active attribute\n\nRevision ID: 644f5251fc0d\nRevises: 5078390e5527\nCreate Date: 2024-11-18 12:47:09.673"
  },
  {
    "path": "alembic/versions/745b210e6907_fix_non_existing_thumbnails.py",
    "chars": 766,
    "preview": "\"\"\"Fix none-existing thumbnails.\n\nRevision ID: 745b210e6907\nRevises: f2005d1fbadc\nCreate Date: 2016-06-27 17:52:24.38100"
  },
  {
    "path": "alembic/versions/856e70016b2_roles.py",
    "chars": 2127,
    "preview": "\"\"\"Added Roles.\n\nRevision ID: 856e70016b2\nRevises: 30c576f3691\nCreate Date: 2014-11-26 00:25:29.543411\n\"\"\"\n\nfrom alembic"
  },
  {
    "path": "alembic/versions/91ed52b72b82_created_variant_class.py",
    "chars": 3746,
    "preview": "\"\"\"Created Variant class.\n\nRevision ID: 91ed52b72b82\nRevises: 644f5251fc0d\nCreate Date: 2024-11-22 07:57:46.848687\n\"\"\"\n\n"
  },
  {
    "path": "alembic/versions/92257ba439e1_budget_is_now_statusable.py",
    "chars": 3657,
    "preview": "\"\"\"Budget is now statusable.\n\nRevision ID: 92257ba439e1\nRevises: f2005d1fbadc\nCreate Date: 2016-07-28 13:20:27.397000\n\"\""
  },
  {
    "path": "alembic/versions/9f9b88fef376_link_renamed_to_file.py",
    "chars": 21040,
    "preview": "\"\"\"Link renamed to File\n\nRevision ID: 9f9b88fef376\nRevises: 3be540ad3a93\nCreate Date: 2025-01-14 15:37:15.746961\n\"\"\"\n\nfr"
  },
  {
    "path": "alembic/versions/a2007ad7f535_added_review_version_id_column.py",
    "chars": 729,
    "preview": "\"\"\"Added Review.version_id column\n\nRevision ID: a2007ad7f535\nRevises: 91ed52b72b82\nCreate Date: 2024-11-26 11:36:07.7761"
  },
  {
    "path": "alembic/versions/a6598cde6b_versions_are_not_mix.py",
    "chars": 653,
    "preview": "\"\"\"Versions are not mixed with StatusMixin anymore.\n\nRevision ID: a6598cde6b\nRevises: 275bdc106fd5\nCreate Date: 2013-10-"
  },
  {
    "path": "alembic/versions/a9319b19f7be_added_shot_fps.py",
    "chars": 478,
    "preview": "\"\"\"Added \"shot.fps\".\n\nRevision ID: a9319b19f7be\nRevises: f16651477e64\nCreate Date: 2016-11-29 13:38:22.380000\n\"\"\"\n\nfrom "
  },
  {
    "path": "alembic/versions/af869ddfdf9_entity_to_note_relation_is_now_many_to_many.py",
    "chars": 1644,
    "preview": "\"\"\"Entity to note relation is now many-to-many.\n\nRevision ID: af869ddfdf9\nRevises: 2f55dc4f199f\nCreate Date: 2014-04-06 "
  },
  {
    "path": "alembic/versions/bf67e6a234b4_added_revision_code_attribute.py",
    "chars": 1227,
    "preview": "\"\"\"Added \"Repository.code\" attribute.\n\nRevision ID: bf67e6a234b4\nRevises: ed0167fff399\nCreate Date: 2020-01-01 09:50:19."
  },
  {
    "path": "alembic/versions/c5607b4cfb0a_added_support_for_time_zones.py",
    "chars": 3562,
    "preview": "\"\"\"Added support for time zones.\n\nRevision ID: c5607b4cfb0a\nRevises: 0063f547dc2e\nCreate Date: 2017-03-09 02:17:08.20900"
  },
  {
    "path": "alembic/versions/d8421de6a206_added_project_users_rate_column.py",
    "chars": 536,
    "preview": "\"\"\"Added \"Project_Users.rate\".\n\nRevision ID: d8421de6a206\nRevises: 92257ba439e1\nCreate Date: 2016-08-17 19:27:00.358000\n"
  },
  {
    "path": "alembic/versions/e25ec9930632_shot_sequence_relation_is_now_many_to_.py",
    "chars": 1725,
    "preview": "\"\"\"Shot Sequence relation is now many-to-one\n\nRevision ID: e25ec9930632\nRevises: 4400871fa852\nCreate Date: 2024-11-16 00"
  },
  {
    "path": "alembic/versions/ea28a39ba3f5_added_invoices_table.py",
    "chars": 1068,
    "preview": "\"\"\"Added Invoices table.\n\nRevision ID: ea28a39ba3f5\nRevises: 92257ba439e1\nCreate Date: 2016-08-17 19:21:40.428000\n\"\"\"\n\nf"
  },
  {
    "path": "alembic/versions/eaed49db6d9_added_position_column_to_Project_Repositories.py",
    "chars": 962,
    "preview": "\"\"\"Added position column to Project_Repositories table.\n\nRevision ID: eaed49db6d9\nRevises: 583875229230\nCreate Date: 201"
  },
  {
    "path": "alembic/versions/ec1eb2151bb9_rename_version_take_name_to_version_.py",
    "chars": 546,
    "preview": "\"\"\"Rename Version.take_name to Version.variant_name\n\nRevision ID: ec1eb2151bb9\nRevises: 019378697b5b\nCreate Date: 2024-1"
  },
  {
    "path": "alembic/versions/ed0167fff399_added_workinghours_table.py",
    "chars": 1953,
    "preview": "\"\"\"Added WorkingHours table.\n\nRevision ID: ed0167fff399\nRevises: 1181305d3001\nCreate Date: 2017-05-20 14:32:48.388000\n\"\""
  },
  {
    "path": "alembic/versions/f16651477e64_added_authenticationlog_class.py",
    "chars": 1260,
    "preview": "\"\"\"Added AuthenticationLog class.\n\nRevision ID: f16651477e64\nRevises: 255ee1f9c7b3\nCreate Date: 2016-11-15 00:22:16.4380"
  },
  {
    "path": "alembic/versions/f2005d1fbadc_added_projectclients.py",
    "chars": 7021,
    "preview": "\"\"\"Added ProjectClients.\n\nRevision ID: f2005d1fbadc\nRevises: 258985128aff\nCreate Date: 2016-06-27 14:33:10.642000\n\"\"\"\n\nf"
  },
  {
    "path": "alembic/versions/feca9bac7d5a_renamed_osx_to_macos.py",
    "chars": 520,
    "preview": "\"\"\"Renamed OSX to macOS\n\nRevision ID: feca9bac7d5a\nRevises: bf67e6a234b4\nCreate Date: 2024-11-01 12:22:24.818481\n\"\"\"\n\nfr"
  },
  {
    "path": "alembic.ini",
    "chars": 949,
    "preview": "# A generic, single database configuration.\n\n[alembic]\n# path to migration scripts\nscript_location = alembic\n\n# template"
  },
  {
    "path": "docs/Makefile",
    "chars": 7681,
    "preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD "
  },
  {
    "path": "docs/make.bat",
    "chars": 7524,
    "preview": "@ECHO OFF\n\nREM Command file for Sphinx documentation\n\nset SPHINXBUILD=..\\..\\Scripts\\sphinx-build.exe\n\nif \"%SPHINXBUILD%\""
  },
  {
    "path": "docs/make_html.bat",
    "chars": 74,
    "preview": "..\\..\\sphinx-build.exe -b html -D graphviz_dot=\"dot.exe\" source build\\html"
  },
  {
    "path": "docs/source/_static/images/Task_Status_Workflow.vue",
    "chars": 56362,
    "preview": "<!-- Tufts VUE 3.2.2 concept-map (Task_Status_Workflow.vue) 2015-06-18 -->\n<!-- Tufts VUE: http://vue.tufts.edu/ -->\n<!-"
  },
  {
    "path": "docs/source/_static/images/stalker_design.vue",
    "chars": 532641,
    "preview": "<!-- Tufts VUE 3.3.0 concept-map (stalker_design.vue) 2016-12-24 -->\n<!-- Tufts VUE: http://vue.tufts.edu/ -->\n<!-- Do N"
  },
  {
    "path": "docs/source/_templates/autosummary/base.rst",
    "chars": 102,
    "preview": "{{ fullname }}\n{{ underline }}\n\n.. currentmodule:: {{ module }}\n\n.. auto{{ objtype }}:: {{ objname }}\n"
  },
  {
    "path": "docs/source/_templates/autosummary/class.rst",
    "chars": 633,
    "preview": "{{ fullname }}\n{{ underline }}\n\n.. inheritance-diagram::\n     {{ fullname }}\n     :parts: 1\n\n.. currentmodule:: {{ modul"
  },
  {
    "path": "docs/source/_templates/autosummary/module.rst",
    "chars": 635,
    "preview": "{{ fullname }}\n{{ underline }}\n\n.. automodule:: {{ fullname }}\n\n   {% block functions %}\n   {% if functions %}\n   .. rub"
  },
  {
    "path": "docs/source/about.rst",
    "chars": 59,
    "preview": ".. about_toplevel:\n\n.. include:: source/../../../README.rst"
  },
  {
    "path": "docs/source/changelog.rst",
    "chars": 67,
    "preview": ".. _changelog_toplevel:\n\n.. include:: source/../../../CHANGELOG.rst"
  },
  {
    "path": "docs/source/conf.py",
    "chars": 13228,
    "preview": "# -*- coding: utf-8 -*-\n#\n# Stalker documentation build configuration file, created by\n# sphinx-quickstart on Tue Jul 26"
  },
  {
    "path": "docs/source/configure.rst",
    "chars": 21703,
    "preview": ".. _configuration_toplevel:\n\n.. _configuring_stalker:\n\nConfiguring Stalker\n===================\n\nTo configure Stalker and"
  },
  {
    "path": "docs/source/contents.rst",
    "chars": 268,
    "preview": ".. _contents:\n\nTable of Contents\n=================\n\n.. toctree::\n    :maxdepth: 3\n\n    about.rst\n    installation.rst\n  "
  },
  {
    "path": "docs/source/contribute.rst",
    "chars": 7084,
    "preview": ".. _contribute_toplevel:\n\n=================\nHow To Contribute\n=================\n\nStalker started as an Open Source proje"
  },
  {
    "path": "docs/source/design.rst",
    "chars": 6213,
    "preview": ".. _design_toplevel:\n\n======\nDesign\n======\n\nThis document explores Stalker, an open-source Python library designed for\np"
  },
  {
    "path": "docs/source/index.rst",
    "chars": 229,
    "preview": ".. _index_toplevel:\n\n=====================\nStalker Documentation\n=====================\n\n.. include:: about.rst\n\n.. inclu"
  },
  {
    "path": "docs/source/inheritance_diagram.rst",
    "chars": 2524,
    "preview": ".. _inheritance_diagram_toplevel:\n\nInheritance Diagram\n===================\n\n.. inheritance-diagram::\n   stalker.exceptio"
  },
  {
    "path": "docs/source/installation.rst",
    "chars": 3361,
    "preview": ".. _installation_toplevel:\n\n============\nInstallation\n============\n\n\nHow to Install Stalker\n======================\n\n\nThi"
  },
  {
    "path": "docs/source/roadmap.rst",
    "chars": 488,
    "preview": ".. _roadmap_toplevel:\n\n===========================\nStalker Development Roadmap\n===========================\n\nThis section"
  },
  {
    "path": "docs/source/status_and_status_lists.rst",
    "chars": 633,
    "preview": ".. _status_and_status_lists_toplevel:\n\nStatuses and Status Lists\n=========================\n\nIn Stalker, classes mixed wi"
  },
  {
    "path": "docs/source/summary.rst",
    "chars": 2542,
    "preview": ".. _summary_toplevel:\n\nSummary\n=======\n\n.. autosummary::\n   :toctree: generated/\n   :nosignatures:\n   \n   stalker.db\n   "
  },
  {
    "path": "docs/source/task_review_workflow.rst",
    "chars": 5566,
    "preview": ".. _task_review_workflow_toplevel:\n\n====================\nTask Review Workflow\n====================\n\nIntroduction\n======="
  },
  {
    "path": "docs/source/todo.rst",
    "chars": 58,
    "preview": ".. _todo_toplevel:\n\n.. include:: source/../../../TODO.rst\n"
  },
  {
    "path": "docs/source/tutorial/asset_management.rst",
    "chars": 9520,
    "preview": ".. _tutorial_asset_management_toplevel:\n\nAsset Management\n================\n\nNow that we've created projects, tasks and r"
  },
  {
    "path": "docs/source/tutorial/basics.rst",
    "chars": 4808,
    "preview": ".. _tutorial_basics_toplevel:\n\nBasics\n======\n\nImagine you've just installed Stalker and want to integrate it into your f"
  },
  {
    "path": "docs/source/tutorial/collaboration.rst",
    "chars": 1023,
    "preview": ".. _tutorial_collaboration_toplevel:\n\nCollaboration in Stalker\n========================\n\nWhile we've covered the core fu"
  },
  {
    "path": "docs/source/tutorial/conclusion.rst",
    "chars": 1469,
    "preview": ".. _tutorial_toplevel:\n\nConclusion\n==========\n\nIn this tutorial, you have nearly learned a quarter of what Stalker suppl"
  },
  {
    "path": "docs/source/tutorial/creating_simple_data.rst",
    "chars": 4994,
    "preview": ".. _tutorial_creating_simple_data_toplevel:\n\nCreating Simple Data\n====================\n\nLet's imagine you're starting a "
  },
  {
    "path": "docs/source/tutorial/extending_som.rst",
    "chars": 116,
    "preview": ".. _tutorial_extending_som_toplevel:\n\nExtending SOM (coming)\n======================\n\nThis part will be covered soon\n"
  },
  {
    "path": "docs/source/tutorial/pipeline.rst",
    "chars": 1459,
    "preview": ".. _tutorial_pipeline_toplevel:\n\nPipeline\n========\n\nSo far, we've covered the basics of creating data in Stalker. Howeve"
  },
  {
    "path": "docs/source/tutorial/query_update_delete_data.rst",
    "chars": 1711,
    "preview": ".. _tutorial_query_update_delete_data_toplevel:\n\nQuerying, Updating and Deleting Data\n=================================="
  },
  {
    "path": "docs/source/tutorial/scheduling.rst",
    "chars": 3407,
    "preview": ".. _tutorial_scheduling_toplevel:\n\nScheduling\n==========\n\nNow that we've defined tasks, resources, and dependencies, let"
  },
  {
    "path": "docs/source/tutorial/task_and_resource_management.rst",
    "chars": 1468,
    "preview": ".. _tutorial_task_resource_management_toplevel:\n\nTask and Resource Management\n============================\n\nNow that we "
  },
  {
    "path": "docs/source/tutorial/tutorial_files/tutorial.py",
    "chars": 8288,
    "preview": "# -*- coding: utf-8 -*-\n\nimport os\n\nimport stalker.db.setup\n\nstalker.db.setup.setup({\"sqlalchemy.url\": \"sqlite:///\"})\nst"
  },
  {
    "path": "docs/source/tutorial.rst",
    "chars": 941,
    "preview": ".. _tutorial_toplevel:\n\n============\nAPI Tutorial\n============\n\n.. _tutorial_contents:\n\nTable of Contents\n=============="
  },
  {
    "path": "docs/source/upgrade_db.rst",
    "chars": 999,
    "preview": ".. upgrade_db_toplevel:\n\n==================\nUpgrading Database\n==================\n\nIntroduction\n============\n\nFrom time "
  },
  {
    "path": "examples/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/extending/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/extending/camera_lens.py",
    "chars": 4820,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"\nIn this example we are going to extend the Stalker Object Model (SOM) with two\nnew type of c"
  },
  {
    "path": "examples/extending/great_entity.py",
    "chars": 700,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"\nIn this example we are going to extend stalker with a new entity type, which\nis also mixed i"
  },
  {
    "path": "examples/extending/statused_entity.py",
    "chars": 746,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"\nIn this example we are going to extend Stalker with a new entity type, which\nis also mixed i"
  },
  {
    "path": "examples/flat_project_example.py",
    "chars": 5161,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"This is an example which uses two different folder structure in two\ndifferent projects.\n\nThe "
  },
  {
    "path": "pyproject.toml",
    "chars": 2913,
    "preview": "[build-system]\nrequires = [\"setuptools\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nauthors = [\n    {name = \"Erk"
  },
  {
    "path": "requirements-dev.txt",
    "chars": 307,
    "preview": "\nblack\ncoverage\ndarglint\nflake8\nflake8-bugbear\nflake8-docstrings\nflake8-import-order\nflake8-mutable\nflake8-pep3101\nflake"
  },
  {
    "path": "requirements.txt",
    "chars": 69,
    "preview": "alembic\nbuild\njinja2\npsycopg2-binary\npytz\nsix\nsqlalchemy >= 2\ntzlocal"
  },
  {
    "path": "setup.py",
    "chars": 62,
    "preview": "# -*- coding: utf-8 -*-\nfrom setuptools import setup\n\nsetup()\n"
  },
  {
    "path": "src/stalker/VERSION",
    "chars": 7,
    "preview": "1.1.2.1"
  },
  {
    "path": "src/stalker/__init__.py",
    "chars": 3316,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Stalker is a Production Asset Management (ProdAM) designed for Animation/VFX Studios.\n\nSee do"
  },
  {
    "path": "src/stalker/config.py",
    "chars": 12501,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Config related functions and classes are situated here.\"\"\"\nimport datetime\nimport os\nimport s"
  },
  {
    "path": "src/stalker/db/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/stalker/db/declarative.py",
    "chars": 714,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"The declarative base class is situated here.\"\"\"\nimport logging\nfrom typing import Any, Type\n\n"
  },
  {
    "path": "src/stalker/db/session.py",
    "chars": 1044,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"The venerable DBSession is situated here.\n\nThis is a runtime storage for the DB session. Grea"
  },
  {
    "path": "src/stalker/db/setup.py",
    "chars": 17589,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Database module of Stalker.\n\nWhenever stalker.db or something under it imported, the :func:`s"
  },
  {
    "path": "src/stalker/db/types.py",
    "chars": 3125,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Stalker specific data types are situated here.\"\"\"\nimport datetime\nimport json\nfrom typing imp"
  },
  {
    "path": "src/stalker/exceptions.py",
    "chars": 2347,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Errors for the system.\n\nThis module contains the Errors in Stalker.\n\"\"\"\n\n\nclass LoginError(Ex"
  },
  {
    "path": "src/stalker/log.py",
    "chars": 2421,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Logging related functions are situated here.\n\nThis module allows registering any number of lo"
  },
  {
    "path": "src/stalker/models/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/stalker/models/asset.py",
    "chars": 2802,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Asset related classes.\"\"\"\n\nimport logging\nfrom typing import Any\n\nfrom sqlalchemy import Fore"
  },
  {
    "path": "src/stalker/models/auth.py",
    "chars": 44095,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Authentication related classes and functions situated here.\"\"\"\nimport base64\nimport copy\nimpo"
  },
  {
    "path": "src/stalker/models/budget.py",
    "chars": 23551,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Budget related classes and functions are situated here.\"\"\"\nfrom typing import Any, Dict, List"
  },
  {
    "path": "src/stalker/models/client.py",
    "chars": 9258,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Client related classes and functions are situated here.\"\"\"\n\nfrom typing import Any, Dict, Lis"
  },
  {
    "path": "src/stalker/models/department.py",
    "chars": 7525,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Department related classes and functions are situated here.\"\"\"\n\nfrom typing import Any, Dict,"
  },
  {
    "path": "src/stalker/models/entity.py",
    "chars": 32561,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"SimpleEntity, Entity, EntityGroup and other related functions are situated here.\"\"\"\n\nimport f"
  },
  {
    "path": "src/stalker/models/enum.py",
    "chars": 13859,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Enum classes are situated here.\"\"\"\n\nfrom enum import Enum, IntEnum\nfrom typing import Union\n\n"
  },
  {
    "path": "src/stalker/models/file.py",
    "chars": 11754,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"File related classes and utility functions are situated here.\"\"\"\n\nimport os\nfrom typing impor"
  },
  {
    "path": "src/stalker/models/format.py",
    "chars": 8607,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Image format related classes and utility functions are situated here.\"\"\"\nfrom typing import A"
  },
  {
    "path": "src/stalker/models/message.py",
    "chars": 1642,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"The Message related classes and functions are situated here.\"\"\"\nfrom typing import Any, Dict\n"
  },
  {
    "path": "src/stalker/models/mixins.py",
    "chars": 75939,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Mixins are situated here.\"\"\"\n\nimport datetime\nfrom typing import (\n    Any,\n    Dict,\n    Gen"
  },
  {
    "path": "src/stalker/models/note.py",
    "chars": 1873,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Note class lies here.\"\"\"\nfrom typing import Any, Dict, Optional\n\nfrom sqlalchemy import Forei"
  },
  {
    "path": "src/stalker/models/project.py",
    "chars": 30266,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Project related classes and functions are situated here.\"\"\"\n\nfrom typing import Any, List, Op"
  },
  {
    "path": "src/stalker/models/repository.py",
    "chars": 15453,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Repository related functionality is situated here.\"\"\"\nimport os\nimport platform\nfrom typing i"
  },
  {
    "path": "src/stalker/models/review.py",
    "chars": 20457,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Review related classes and functions are situated here.\"\"\"\n\nfrom typing import Any, Dict, Lis"
  },
  {
    "path": "src/stalker/models/scene.py",
    "chars": 3170,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Scene related classes and functions are situated here.\"\"\"\n\nfrom typing import Any, Dict, List"
  },
  {
    "path": "src/stalker/models/schedulers.py",
    "chars": 27454,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Scheduler related function and classes are situated here.\"\"\"\n\nimport csv\nimport datetime\nimpo"
  },
  {
    "path": "src/stalker/models/sequence.py",
    "chars": 3065,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Sequence related function and classes are situated here.\"\"\"\n\nfrom typing import Any, Dict, Li"
  },
  {
    "path": "src/stalker/models/shot.py",
    "chars": 27245,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Shot related functions and classes are situated here.\"\"\"\n\nfrom typing import Any, Dict, Optio"
  },
  {
    "path": "src/stalker/models/status.py",
    "chars": 9757,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Status and StatusList related functions and classes are situated here.\"\"\"\nfrom typing import "
  },
  {
    "path": "src/stalker/models/structure.py",
    "chars": 8795,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Structure related functions and classes are situated here.\"\"\"\nfrom typing import Any, Dict, L"
  },
  {
    "path": "src/stalker/models/studio.py",
    "chars": 38967,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Studio, WorkingHours and Vacation related functions and classes are situated here.\"\"\"\n\nimport"
  },
  {
    "path": "src/stalker/models/tag.py",
    "chars": 1363,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Tag related functions and classes are situated here.\"\"\"\nfrom typing import Any, Dict\n\nfrom sq"
  },
  {
    "path": "src/stalker/models/task.py",
    "chars": 144673,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Task related functions and classes are situated here.\"\"\"\nimport copy\nimport datetime\nimport o"
  },
  {
    "path": "src/stalker/models/template.py",
    "chars": 6756,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"FilenameTemplate related functions and classes are situated here.\"\"\"\nfrom typing import Any, "
  },
  {
    "path": "src/stalker/models/ticket.py",
    "chars": 21565,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Ticket related functions and classes are situated here.\"\"\"\nimport uuid\nfrom typing import Any"
  },
  {
    "path": "src/stalker/models/type.py",
    "chars": 4431,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Type related functions and classes are situated here.\"\"\"\n\nfrom typing import Any, Dict, Optio"
  },
  {
    "path": "src/stalker/models/variant.py",
    "chars": 1331,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Variant related functions and classes are situated here.\"\"\"\n\nfrom sqlalchemy import ForeignKe"
  },
  {
    "path": "src/stalker/models/version.py",
    "chars": 22559,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Version related functions and classes are situated here.\"\"\"\n\nimport os\nfrom pathlib import Pa"
  },
  {
    "path": "src/stalker/models/wiki.py",
    "chars": 3323,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Wiki related functions and classes are situated here.\"\"\"\nfrom typing import Any, Dict, Option"
  },
  {
    "path": "src/stalker/py.typed",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/stalker/utils.py",
    "chars": 5998,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Utilities are situated here.\"\"\"\nimport calendar\nfrom datetime import datetime, timedelta\nfrom"
  },
  {
    "path": "src/stalker/version.py",
    "chars": 423,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Provides functionality to parse the version number from the VERSION file.\"\"\"\nimport os\nfrom t"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/benchmarks/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/benchmarks/task_total_logged_seonds.py",
    "chars": 6559,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Benchmark total logged session computation.\"\"\"\nimport datetime\nimport logging\nimport os\nimpor"
  },
  {
    "path": "tests/config/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/config/test_config.py",
    "chars": 8576,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"stalker.config module.\"\"\"\nimport datetime\nimport logging\nimport os\nimport shutil\nimport sys\ni"
  },
  {
    "path": "tests/conftest.py",
    "chars": 2645,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Configure tests.\"\"\"\nimport datetime\nimport logging\nimport os\nfrom subprocess import CalledPro"
  },
  {
    "path": "tests/data/project_to_tjp_output.jinja2",
    "chars": 5120,
    "preview": "task Project_{{project.id}} \"Project_{{project.id}}\" {\n    task Sequence_{{sequence1.id}} \"Sequence_{{sequence1.id}}\" {\n"
  },
  {
    "path": "tests/data/project_to_tjp_output_formatted",
    "chars": 2339,
    "preview": "task Project_1 \"Project_1\" { task Sequence_2 \"Sequence_2\" { effort 1.0h allocate User_3 } task Sequence_4 \"Sequence_4\" {"
  },
  {
    "path": "tests/data/project_to_tjp_output_rendered",
    "chars": 3547,
    "preview": "task Project_1 \"Project_1\" {\n    task Sequence_2 \"Sequence_2\" {\n        effort 1.0h\n        allocate User_3\n    }\n    ta"
  },
  {
    "path": "tests/db/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/db/test_db.py",
    "chars": 145206,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"Database and connection to the database.\"\"\"\nimport datetime\nimport json\nimport logging\nimport"
  },
  {
    "path": "tests/db/test_dbsession.py",
    "chars": 1967,
    "preview": "from stalker import User\nfrom stalker.db.session import DBSession, ExtendedScopedSession\n\n\ndef test_dbsession_save_metho"
  },
  {
    "path": "tests/db/test_types.py",
    "chars": 1812,
    "preview": "# -*- coding: utf-8 -*-\n\nimport pytest\n\nfrom sqlalchemy import Column, ForeignKey, Integer\n\nfrom stalker.db.setup import"
  },
  {
    "path": "tests/mixins/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/mixins/test_acl_mixin.py",
    "chars": 2156,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"ACLMixin related tests.\"\"\"\n\nimport pytest\n\nfrom sqlalchemy import Column, Integer\nfrom sqlalc"
  },
  {
    "path": "tests/mixins/test_amount_mixin.py",
    "chars": 2869,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"AmountMixin related tests.\"\"\"\n\nimport pytest\n\nfrom sqlalchemy import ForeignKey, Integer\nfrom"
  },
  {
    "path": "tests/mixins/test_code_mixin.py",
    "chars": 4244,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"CodeMixin related tests.\"\"\"\nimport pytest\n\nfrom sqlalchemy import ForeignKey, Integer\nfrom sq"
  },
  {
    "path": "tests/mixins/test_create_secondary_table.py",
    "chars": 9529,
    "preview": "# -*- coding: utf-8 -*-\n\nimport pytest\n\nfrom sqlalchemy import Column, ForeignKey, Integer, Table\n\nfrom stalker import S"
  },
  {
    "path": "tests/mixins/test_dag_mixin.py",
    "chars": 13486,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"DAGMixin related tests.\"\"\"\n\nimport copy\nimport sys\n\nimport pytest\n\nfrom sqlalchemy import For"
  },
  {
    "path": "tests/mixins/test_date_range_mixin.py",
    "chars": 24769,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"DateRangeMixin class related tests.\"\"\"\nimport datetime\nimport logging\nimport sys\n\nimport pyte"
  },
  {
    "path": "tests/mixins/test_declarative_project_mixin.py",
    "chars": 2998,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"ProjectMixin related tests.\"\"\"\nimport pytest\n\nfrom sqlalchemy import Column, ForeignKey, Inte"
  },
  {
    "path": "tests/mixins/test_declarative_reference_mixin.py",
    "chars": 1545,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"ReferenceMixin related tests.\"\"\"\nfrom sqlalchemy import ForeignKey\nfrom sqlalchemy.orm import"
  },
  {
    "path": "tests/mixins/test_declarative_schedule_mixin.py",
    "chars": 3584,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"DateRangeMixin related tests.\"\"\"\n\nimport datetime\nimport logging\n\nimport pytest\n\nimport pytz\n"
  },
  {
    "path": "tests/mixins/test_declarative_status_mixin.py",
    "chars": 3434,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"StatusMixin class related tests.\"\"\"\nimport pytest\n\nfrom sqlalchemy import Column, ForeignKey,"
  },
  {
    "path": "tests/mixins/test_project_mixin.py",
    "chars": 5073,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"ProjectMixin related tests.\"\"\"\nimport pytest\n\nfrom sqlalchemy import Column, ForeignKey, Inte"
  },
  {
    "path": "tests/mixins/test_reference_mixin.py",
    "chars": 5085,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"ReferenceMixin related tests.\"\"\"\n\nimport pytest\n\nfrom sqlalchemy import Column, ForeignKey, I"
  },
  {
    "path": "tests/mixins/test_schedule_mixin.py",
    "chars": 25338,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"ScheduleMixin related tests.\"\"\"\nimport datetime\n\nimport pytest\n\nfrom sqlalchemy import Foreig"
  },
  {
    "path": "tests/mixins/test_status_mixin.py",
    "chars": 19914,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"StatusMixin class related tests.\"\"\"\n\nimport pytest\n\nfrom sqlalchemy import ForeignKey\nfrom sq"
  },
  {
    "path": "tests/mixins/test_target_entity_type_mixin.py",
    "chars": 3805,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"TargetEntityTypeMixin related tests.\"\"\"\n\nimport sys\nimport pytest\n\nfrom sqlalchemy import For"
  },
  {
    "path": "tests/mixins/test_unit_mixin.py",
    "chars": 2718,
    "preview": "# -*- coding: utf-8 -*-\n\"\"\"UnitMixin class related tests.\"\"\"\n\nimport pytest\n\nfrom sqlalchemy import ForeignKey\nfrom sqla"
  },
  {
    "path": "tests/models/__init__.py",
    "chars": 0,
    "preview": ""
  }
]

// ... and 64 more files (download for full content)

About this extraction

This page contains the full source code of the eoyilmaz/stalker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 264 files (3.1 MB), approximately 832.9k tokens, and a symbol index with 3120 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!